src/share/classes/com/sun/tools/javac/comp/Infer.java

Tue, 09 Oct 2012 19:10:00 -0700

author
jjg
date
Tue, 09 Oct 2012 19:10:00 -0700
changeset 1357
c75be5bc5283
parent 1348
573ceb23beeb
child 1374
c002fdee76fd
permissions
-rw-r--r--

8000663: clean up langtools imports
Reviewed-by: darcy

duke@1 1 /*
mcimadamore@1178 2 * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
duke@1 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@1 4 *
duke@1 5 * This code is free software; you can redistribute it and/or modify it
duke@1 6 * under the terms of the GNU General Public License version 2 only, as
ohair@554 7 * published by the Free Software Foundation. Oracle designates this
duke@1 8 * particular file as subject to the "Classpath" exception as provided
ohair@554 9 * by Oracle in the LICENSE file that accompanied this code.
duke@1 10 *
duke@1 11 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@1 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@1 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@1 14 * version 2 for more details (a copy is included in the LICENSE file that
duke@1 15 * accompanied this code).
duke@1 16 *
duke@1 17 * You should have received a copy of the GNU General Public License version
duke@1 18 * 2 along with this work; if not, write to the Free Software Foundation,
duke@1 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@1 20 *
ohair@554 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@554 22 * or visit www.oracle.com if you need additional information or have any
ohair@554 23 * questions.
duke@1 24 */
duke@1 25
duke@1 26 package com.sun.tools.javac.comp;
duke@1 27
mcimadamore@1337 28 import com.sun.tools.javac.code.*;
mcimadamore@1337 29 import com.sun.tools.javac.code.Symbol.*;
mcimadamore@1337 30 import com.sun.tools.javac.code.Type.*;
mcimadamore@1338 31 import com.sun.tools.javac.code.Type.UndetVar.InferenceBound;
mcimadamore@1347 32 import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
mcimadamore@1337 33 import com.sun.tools.javac.comp.Resolve.InapplicableMethodException;
mcimadamore@1337 34 import com.sun.tools.javac.comp.Resolve.VerboseResolutionMode;
mcimadamore@674 35 import com.sun.tools.javac.tree.JCTree;
mcimadamore@674 36 import com.sun.tools.javac.tree.JCTree.JCTypeCast;
mcimadamore@820 37 import com.sun.tools.javac.tree.TreeInfo;
duke@1 38 import com.sun.tools.javac.util.*;
duke@1 39 import com.sun.tools.javac.util.List;
mcimadamore@1114 40 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
duke@1 41
mcimadamore@1337 42 import java.util.HashMap;
mcimadamore@1337 43 import java.util.Map;
mcimadamore@1337 44
duke@1 45 import static com.sun.tools.javac.code.TypeTags.*;
duke@1 46
duke@1 47 /** Helper class for type parameter inference, used by the attribution phase.
duke@1 48 *
jjg@581 49 * <p><b>This is NOT part of any supported API.
jjg@581 50 * If you write code that depends on this, you do so at your own risk.
duke@1 51 * This code and its internal interfaces are subject to change or
duke@1 52 * deletion without notice.</b>
duke@1 53 */
duke@1 54 public class Infer {
duke@1 55 protected static final Context.Key<Infer> inferKey =
duke@1 56 new Context.Key<Infer>();
duke@1 57
duke@1 58 /** A value for prototypes that admit any type, including polymorphic ones. */
duke@1 59 public static final Type anyPoly = new Type(NONE, null);
duke@1 60
duke@1 61 Symtab syms;
duke@1 62 Types types;
mcimadamore@396 63 Check chk;
mcimadamore@299 64 Resolve rs;
mcimadamore@1347 65 DeferredAttr deferredAttr;
mcimadamore@1114 66 Log log;
mcimadamore@89 67 JCDiagnostic.Factory diags;
duke@1 68
duke@1 69 public static Infer instance(Context context) {
duke@1 70 Infer instance = context.get(inferKey);
duke@1 71 if (instance == null)
duke@1 72 instance = new Infer(context);
duke@1 73 return instance;
duke@1 74 }
duke@1 75
duke@1 76 protected Infer(Context context) {
duke@1 77 context.put(inferKey, this);
duke@1 78 syms = Symtab.instance(context);
duke@1 79 types = Types.instance(context);
mcimadamore@299 80 rs = Resolve.instance(context);
mcimadamore@1347 81 deferredAttr = DeferredAttr.instance(context);
mcimadamore@1114 82 log = Log.instance(context);
mcimadamore@396 83 chk = Check.instance(context);
mcimadamore@89 84 diags = JCDiagnostic.Factory.instance(context);
mcimadamore@1298 85 inferenceException = new InferenceException(diags);
duke@1 86 }
duke@1 87
mcimadamore@1337 88 /**
mcimadamore@1337 89 * This exception class is design to store a list of diagnostics corresponding
mcimadamore@1337 90 * to inference errors that can arise during a method applicability check.
mcimadamore@1337 91 */
mcimadamore@1186 92 public static class InferenceException extends InapplicableMethodException {
duke@1 93 private static final long serialVersionUID = 0;
duke@1 94
mcimadamore@1337 95 List<JCDiagnostic> messages = List.nil();
mcimadamore@1337 96
mcimadamore@299 97 InferenceException(JCDiagnostic.Factory diags) {
mcimadamore@689 98 super(diags);
duke@1 99 }
mcimadamore@1337 100
mcimadamore@1337 101 @Override
mcimadamore@1337 102 InapplicableMethodException setMessage(JCDiagnostic diag) {
mcimadamore@1337 103 messages = messages.append(diag);
mcimadamore@1337 104 return this;
mcimadamore@1337 105 }
mcimadamore@1337 106
mcimadamore@1337 107 @Override
mcimadamore@1337 108 public JCDiagnostic getDiagnostic() {
mcimadamore@1337 109 return messages.head;
mcimadamore@1337 110 }
mcimadamore@1337 111
mcimadamore@1337 112 void clear() {
mcimadamore@1337 113 messages = List.nil();
mcimadamore@1337 114 }
mcimadamore@299 115 }
mcimadamore@299 116
mcimadamore@1298 117 private final InferenceException inferenceException;
duke@1 118
duke@1 119 /***************************************************************************
duke@1 120 * Mini/Maximization of UndetVars
duke@1 121 ***************************************************************************/
duke@1 122
duke@1 123 /** Instantiate undetermined type variable to its minimal upper bound.
duke@1 124 * Throw a NoInstanceException if this not possible.
duke@1 125 */
mcimadamore@1337 126 void maximizeInst(UndetVar that, Warner warn) throws InferenceException {
mcimadamore@1338 127 List<Type> hibounds = Type.filter(that.getBounds(InferenceBound.UPPER), boundFilter);
mcimadamore@1338 128 if (that.getBounds(InferenceBound.EQ).isEmpty()) {
mcimadamore@828 129 if (hibounds.isEmpty())
duke@1 130 that.inst = syms.objectType;
mcimadamore@828 131 else if (hibounds.tail.isEmpty())
mcimadamore@828 132 that.inst = hibounds.head;
mcimadamore@210 133 else
mcimadamore@828 134 that.inst = types.glb(hibounds);
mcimadamore@1251 135 } else {
mcimadamore@1338 136 that.inst = that.getBounds(InferenceBound.EQ).head;
duke@1 137 }
mcimadamore@210 138 if (that.inst == null ||
mcimadamore@298 139 that.inst.isErroneous())
mcimadamore@1298 140 throw inferenceException
mcimadamore@210 141 .setMessage("no.unique.maximal.instance.exists",
mcimadamore@828 142 that.qtype, hibounds);
duke@1 143 }
duke@1 144
mcimadamore@1337 145 private Filter<Type> boundFilter = new Filter<Type>() {
mcimadamore@828 146 @Override
mcimadamore@828 147 public boolean accepts(Type t) {
mcimadamore@1337 148 return !t.isErroneous() && t.tag != BOT;
mcimadamore@828 149 }
mcimadamore@828 150 };
mcimadamore@828 151
jjg@110 152 /** Instantiate undetermined type variable to the lub of all its lower bounds.
duke@1 153 * Throw a NoInstanceException if this not possible.
duke@1 154 */
mcimadamore@1298 155 void minimizeInst(UndetVar that, Warner warn) throws InferenceException {
mcimadamore@1338 156 List<Type> lobounds = Type.filter(that.getBounds(InferenceBound.LOWER), boundFilter);
mcimadamore@1338 157 if (that.getBounds(InferenceBound.EQ).isEmpty()) {
mcimadamore@1337 158 if (lobounds.isEmpty()) {
mcimadamore@1337 159 //do nothing - the inference variable is under-constrained
mcimadamore@1337 160 return;
mcimadamore@1337 161 } else if (lobounds.tail.isEmpty())
mcimadamore@828 162 that.inst = lobounds.head.isPrimitive() ? syms.errType : lobounds.head;
duke@1 163 else {
mcimadamore@828 164 that.inst = types.lub(lobounds);
mcimadamore@5 165 }
jjg@110 166 if (that.inst == null || that.inst.tag == ERROR)
mcimadamore@1298 167 throw inferenceException
duke@1 168 .setMessage("no.unique.minimal.instance.exists",
mcimadamore@828 169 that.qtype, lobounds);
mcimadamore@1251 170 } else {
mcimadamore@1338 171 that.inst = that.getBounds(InferenceBound.EQ).head;
duke@1 172 }
duke@1 173 }
duke@1 174
duke@1 175 /***************************************************************************
duke@1 176 * Exported Methods
duke@1 177 ***************************************************************************/
duke@1 178
mcimadamore@1337 179 /**
mcimadamore@1337 180 * Instantiate uninferred inference variables (JLS 15.12.2.8). First
mcimadamore@1337 181 * if the method return type is non-void, we derive constraints from the
mcimadamore@1337 182 * expected type - then we use declared bound well-formedness to derive additional
mcimadamore@1337 183 * constraints. If no instantiation exists, or if several incomparable
mcimadamore@1337 184 * best instantiations exist throw a NoInstanceException.
duke@1 185 */
mcimadamore@1337 186 public void instantiateUninferred(DiagnosticPosition pos,
mcimadamore@1337 187 InferenceContext inferenceContext,
mcimadamore@1337 188 MethodType mtype,
mcimadamore@1337 189 Attr.ResultInfo resultInfo,
mcimadamore@1337 190 Warner warn) throws InferenceException {
mcimadamore@1268 191 Type to = resultInfo.pt;
mcimadamore@1347 192 if (to.tag == NONE || resultInfo.checkContext.inferenceContext().free(resultInfo.pt)) {
mcimadamore@1268 193 to = mtype.getReturnType().tag <= VOID ?
mcimadamore@1268 194 mtype.getReturnType() : syms.objectType;
mcimadamore@1268 195 }
mcimadamore@1337 196 Type qtype1 = inferenceContext.asFree(mtype.getReturnType(), types);
mcimadamore@753 197 if (!types.isSubtype(qtype1,
mcimadamore@753 198 qtype1.tag == UNDETVAR ? types.boxedTypeOrType(to) : to)) {
mcimadamore@1298 199 throw inferenceException
mcimadamore@1337 200 .setMessage("infer.no.conforming.instance.exists",
mcimadamore@1337 201 inferenceContext.restvars(), mtype.getReturnType(), to);
duke@1 202 }
duke@1 203
mcimadamore@1251 204 while (true) {
mcimadamore@1251 205 boolean stuck = true;
mcimadamore@1337 206 for (Type t : inferenceContext.undetvars) {
mcimadamore@1251 207 UndetVar uv = (UndetVar)t;
mcimadamore@1338 208 if (uv.inst == null && (uv.getBounds(InferenceBound.EQ).nonEmpty() ||
mcimadamore@1338 209 !inferenceContext.free(uv.getBounds(InferenceBound.UPPER)))) {
mcimadamore@1251 210 maximizeInst((UndetVar)t, warn);
mcimadamore@1251 211 stuck = false;
mcimadamore@1251 212 }
mcimadamore@1251 213 }
mcimadamore@1337 214 if (inferenceContext.restvars().isEmpty()) {
mcimadamore@1251 215 //all variables have been instantiated - exit
mcimadamore@1251 216 break;
mcimadamore@1251 217 } else if (stuck) {
mcimadamore@1251 218 //some variables could not be instantiated because of cycles in
mcimadamore@1251 219 //upper bounds - provide a (possibly recursive) default instantiation
mcimadamore@1337 220 instantiateAsUninferredVars(inferenceContext);
mcimadamore@1251 221 break;
mcimadamore@1251 222 } else {
mcimadamore@1251 223 //some variables have been instantiated - replace newly instantiated
mcimadamore@1251 224 //variables in remaining upper bounds and continue
mcimadamore@1337 225 for (Type t : inferenceContext.undetvars) {
mcimadamore@1251 226 UndetVar uv = (UndetVar)t;
mcimadamore@1338 227 uv.substBounds(inferenceContext.inferenceVars(), inferenceContext.instTypes(), types);
mcimadamore@1251 228 }
mcimadamore@1251 229 }
mcimadamore@635 230 }
duke@1 231 }
mcimadamore@1251 232
mcimadamore@1251 233 /**
mcimadamore@1251 234 * Infer cyclic inference variables as described in 15.12.2.8.
mcimadamore@1251 235 */
mcimadamore@1337 236 private void instantiateAsUninferredVars(InferenceContext inferenceContext) {
mcimadamore@1251 237 ListBuffer<Type> todo = ListBuffer.lb();
mcimadamore@1251 238 //step 1 - create fresh tvars
mcimadamore@1337 239 for (Type t : inferenceContext.undetvars) {
mcimadamore@635 240 UndetVar uv = (UndetVar)t;
mcimadamore@1251 241 if (uv.inst == null) {
mcimadamore@1251 242 TypeSymbol fresh_tvar = new TypeSymbol(Flags.SYNTHETIC, uv.qtype.tsym.name, null, uv.qtype.tsym.owner);
mcimadamore@1338 243 fresh_tvar.type = new TypeVar(fresh_tvar, types.makeCompoundType(uv.getBounds(InferenceBound.UPPER)), null);
mcimadamore@1251 244 todo.append(uv);
mcimadamore@1251 245 uv.inst = fresh_tvar.type;
mcimadamore@1251 246 }
mcimadamore@635 247 }
mcimadamore@1251 248 //step 2 - replace fresh tvars in their bounds
mcimadamore@1337 249 List<Type> formals = inferenceContext.inferenceVars();
mcimadamore@1251 250 for (Type t : todo) {
mcimadamore@1251 251 UndetVar uv = (UndetVar)t;
mcimadamore@1251 252 TypeVar ct = (TypeVar)uv.inst;
mcimadamore@1337 253 ct.bound = types.glb(inferenceContext.asInstTypes(types.getBounds(ct), types));
mcimadamore@1251 254 if (ct.bound.isErroneous()) {
mcimadamore@1251 255 //report inference error if glb fails
mcimadamore@1251 256 reportBoundError(uv, BoundErrorKind.BAD_UPPER);
mcimadamore@1251 257 }
mcimadamore@1178 258 formals = formals.tail;
mcimadamore@635 259 }
mcimadamore@635 260 }
duke@1 261
mcimadamore@1337 262 /** Instantiate a generic method type by finding instantiations for all its
mcimadamore@1337 263 * inference variables so that it can be applied to a given argument type list.
duke@1 264 */
mcimadamore@1268 265 public Type instantiateMethod(Env<AttrContext> env,
mcimadamore@547 266 List<Type> tvars,
duke@1 267 MethodType mt,
mcimadamore@1268 268 Attr.ResultInfo resultInfo,
mcimadamore@1268 269 Symbol msym,
mcimadamore@1268 270 List<Type> argtypes,
mcimadamore@1268 271 boolean allowBoxing,
mcimadamore@1268 272 boolean useVarargs,
mcimadamore@1347 273 Resolve.MethodResolutionContext resolveContext,
mcimadamore@1268 274 Warner warn) throws InferenceException {
duke@1 275 //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG
mcimadamore@1348 276 final InferenceContext inferenceContext = new InferenceContext(tvars, this, true);
mcimadamore@1337 277 inferenceException.clear();
mcimadamore@689 278
mcimadamore@1337 279 try {
mcimadamore@1347 280 rs.checkRawArgumentsAcceptable(env, msym, resolveContext.attrMode(), inferenceContext,
mcimadamore@1347 281 argtypes, mt.getParameterTypes(), allowBoxing, useVarargs, warn,
mcimadamore@1347 282 new InferenceCheckHandler(inferenceContext));
duke@1 283
mcimadamore@1337 284 // minimize as yet undetermined type variables
mcimadamore@1337 285 for (Type t : inferenceContext.undetvars) {
mcimadamore@1337 286 minimizeInst((UndetVar)t, warn);
mcimadamore@1337 287 }
duke@1 288
mcimadamore@1337 289 checkWithinBounds(inferenceContext, warn);
duke@1 290
mcimadamore@1337 291 mt = (MethodType)inferenceContext.asInstType(mt, types);
mcimadamore@396 292
mcimadamore@1337 293 List<Type> restvars = inferenceContext.restvars();
duke@1 294
mcimadamore@1337 295 if (!restvars.isEmpty()) {
mcimadamore@1338 296 if (resultInfo != null && !warn.hasNonSilentLint(Lint.LintCategory.UNCHECKED)) {
mcimadamore@1337 297 instantiateUninferred(env.tree.pos(), inferenceContext, mt, resultInfo, warn);
mcimadamore@1337 298 checkWithinBounds(inferenceContext, warn);
mcimadamore@1337 299 mt = (MethodType)inferenceContext.asInstType(mt, types);
mcimadamore@1337 300 if (rs.verboseResolutionMode.contains(VerboseResolutionMode.DEFERRED_INST)) {
mcimadamore@1337 301 log.note(env.tree.pos, "deferred.method.inst", msym, mt, resultInfo.pt);
mcimadamore@1337 302 }
mcimadamore@1337 303 }
mcimadamore@1337 304 }
duke@1 305
mcimadamore@1337 306 // return instantiated version of method type
mcimadamore@1337 307 return mt;
mcimadamore@1337 308 } finally {
mcimadamore@1337 309 inferenceContext.notifyChange(types);
duke@1 310 }
duke@1 311 }
duke@1 312 //where
duke@1 313
mcimadamore@1186 314 /** inference check handler **/
mcimadamore@1186 315 class InferenceCheckHandler implements Resolve.MethodCheckHandler {
mcimadamore@1186 316
mcimadamore@1337 317 InferenceContext inferenceContext;
mcimadamore@1186 318
mcimadamore@1337 319 public InferenceCheckHandler(InferenceContext inferenceContext) {
mcimadamore@1337 320 this.inferenceContext = inferenceContext;
mcimadamore@1186 321 }
mcimadamore@1186 322
mcimadamore@1186 323 public InapplicableMethodException arityMismatch() {
mcimadamore@1337 324 return inferenceException.setMessage("infer.arg.length.mismatch", inferenceContext.inferenceVars());
mcimadamore@1186 325 }
mcimadamore@1296 326 public InapplicableMethodException argumentMismatch(boolean varargs, JCDiagnostic details) {
mcimadamore@1186 327 String key = varargs ?
mcimadamore@1296 328 "infer.varargs.argument.mismatch" :
mcimadamore@1296 329 "infer.no.conforming.assignment.exists";
mcimadamore@1298 330 return inferenceException.setMessage(key,
mcimadamore@1337 331 inferenceContext.inferenceVars(), details);
mcimadamore@1186 332 }
mcimadamore@1186 333 public InapplicableMethodException inaccessibleVarargs(Symbol location, Type expected) {
mcimadamore@1298 334 return inferenceException.setMessage("inaccessible.varargs.type",
mcimadamore@1186 335 expected, Kinds.kindName(location), location);
mcimadamore@1186 336 }
mcimadamore@1186 337 }
mcimadamore@1186 338
mcimadamore@1251 339 /** check that type parameters are within their bounds.
mcimadamore@895 340 */
mcimadamore@1337 341 void checkWithinBounds(InferenceContext inferenceContext,
mcimadamore@1338 342 Warner warn) throws InferenceException {
mcimadamore@1338 343 //step 1 - check compatibility of instantiated type w.r.t. initial bounds
mcimadamore@1337 344 for (Type t : inferenceContext.undetvars) {
mcimadamore@1251 345 UndetVar uv = (UndetVar)t;
mcimadamore@1338 346 uv.substBounds(inferenceContext.inferenceVars(), inferenceContext.instTypes(), types);
mcimadamore@1337 347 checkCompatibleUpperBounds(uv, inferenceContext.inferenceVars());
mcimadamore@1338 348 if (!inferenceContext.restvars().contains(uv.qtype)) {
mcimadamore@1337 349 Type inst = inferenceContext.asInstType(t, types);
mcimadamore@1338 350 for (Type u : uv.getBounds(InferenceBound.UPPER)) {
mcimadamore@1337 351 if (!types.isSubtypeUnchecked(inst, inferenceContext.asFree(u, types), warn)) {
mcimadamore@1251 352 reportBoundError(uv, BoundErrorKind.UPPER);
mcimadamore@1251 353 }
mcimadamore@1251 354 }
mcimadamore@1338 355 for (Type l : uv.getBounds(InferenceBound.LOWER)) {
mcimadamore@1338 356 Assert.check(!inferenceContext.free(l));
mcimadamore@1338 357 if (!types.isSubtypeUnchecked(l, inst, warn)) {
mcimadamore@1251 358 reportBoundError(uv, BoundErrorKind.LOWER);
mcimadamore@1251 359 }
mcimadamore@1251 360 }
mcimadamore@1338 361 for (Type e : uv.getBounds(InferenceBound.EQ)) {
mcimadamore@1338 362 Assert.check(!inferenceContext.free(e));
mcimadamore@1338 363 if (!types.isSameType(inst, e)) {
mcimadamore@1251 364 reportBoundError(uv, BoundErrorKind.EQ);
mcimadamore@1251 365 }
mcimadamore@1251 366 }
mcimadamore@1251 367 }
mcimadamore@1338 368 }
mcimadamore@1338 369
mcimadamore@1338 370 //step 2 - check that eq bounds are consistent w.r.t. eq/lower bounds
mcimadamore@1338 371 for (Type t : inferenceContext.undetvars) {
mcimadamore@1338 372 UndetVar uv = (UndetVar)t;
mcimadamore@1338 373 //check eq bounds consistency
mcimadamore@1338 374 Type eq = null;
mcimadamore@1338 375 for (Type e : uv.getBounds(InferenceBound.EQ)) {
mcimadamore@1338 376 Assert.check(!inferenceContext.free(e));
mcimadamore@1338 377 if (eq != null && !types.isSameType(e, eq)) {
mcimadamore@1338 378 reportBoundError(uv, BoundErrorKind.EQ);
mcimadamore@1338 379 }
mcimadamore@1338 380 eq = e;
mcimadamore@1338 381 for (Type l : uv.getBounds(InferenceBound.LOWER)) {
mcimadamore@1338 382 Assert.check(!inferenceContext.free(l));
mcimadamore@1338 383 if (!types.isSubtypeUnchecked(l, e, warn)) {
mcimadamore@1338 384 reportBoundError(uv, BoundErrorKind.BAD_EQ_LOWER);
mcimadamore@1338 385 }
mcimadamore@1338 386 }
mcimadamore@1338 387 for (Type u : uv.getBounds(InferenceBound.UPPER)) {
mcimadamore@1338 388 if (inferenceContext.free(u)) continue;
mcimadamore@1338 389 if (!types.isSubtypeUnchecked(e, u, warn)) {
mcimadamore@1338 390 reportBoundError(uv, BoundErrorKind.BAD_EQ_UPPER);
mcimadamore@1338 391 }
mcimadamore@1338 392 }
mcimadamore@1338 393 }
duke@1 394 }
mcimadamore@895 395 }
duke@1 396
mcimadamore@1251 397 void checkCompatibleUpperBounds(UndetVar uv, List<Type> tvars) {
mcimadamore@1251 398 // VGJ: sort of inlined maximizeInst() below. Adding
mcimadamore@1251 399 // bounds can cause lobounds that are above hibounds.
mcimadamore@1251 400 ListBuffer<Type> hiboundsNoVars = ListBuffer.lb();
mcimadamore@1338 401 for (Type t : Type.filter(uv.getBounds(InferenceBound.UPPER), boundFilter)) {
mcimadamore@1251 402 if (!t.containsAny(tvars)) {
mcimadamore@1251 403 hiboundsNoVars.append(t);
mcimadamore@1251 404 }
duke@1 405 }
mcimadamore@1251 406 List<Type> hibounds = hiboundsNoVars.toList();
mcimadamore@1251 407 Type hb = null;
mcimadamore@1251 408 if (hibounds.isEmpty())
mcimadamore@1251 409 hb = syms.objectType;
mcimadamore@1251 410 else if (hibounds.tail.isEmpty())
mcimadamore@1251 411 hb = hibounds.head;
mcimadamore@1251 412 else
mcimadamore@1251 413 hb = types.glb(hibounds);
mcimadamore@1251 414 if (hb == null || hb.isErroneous())
mcimadamore@1251 415 reportBoundError(uv, BoundErrorKind.BAD_UPPER);
mcimadamore@1251 416 }
mcimadamore@1251 417
mcimadamore@1251 418 enum BoundErrorKind {
mcimadamore@1251 419 BAD_UPPER() {
mcimadamore@1251 420 @Override
mcimadamore@1251 421 InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
mcimadamore@1338 422 return ex.setMessage("incompatible.upper.bounds", uv.qtype,
mcimadamore@1338 423 uv.getBounds(InferenceBound.UPPER));
mcimadamore@1338 424 }
mcimadamore@1338 425 },
mcimadamore@1338 426 BAD_EQ_UPPER() {
mcimadamore@1338 427 @Override
mcimadamore@1338 428 InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
mcimadamore@1338 429 return ex.setMessage("incompatible.eq.upper.bounds", uv.qtype,
mcimadamore@1338 430 uv.getBounds(InferenceBound.EQ), uv.getBounds(InferenceBound.UPPER));
mcimadamore@1338 431 }
mcimadamore@1338 432 },
mcimadamore@1338 433 BAD_EQ_LOWER() {
mcimadamore@1338 434 @Override
mcimadamore@1338 435 InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
mcimadamore@1338 436 return ex.setMessage("incompatible.eq.lower.bounds", uv.qtype,
mcimadamore@1338 437 uv.getBounds(InferenceBound.EQ), uv.getBounds(InferenceBound.LOWER));
mcimadamore@1251 438 }
mcimadamore@1251 439 },
mcimadamore@1251 440 UPPER() {
mcimadamore@1251 441 @Override
mcimadamore@1251 442 InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
mcimadamore@1338 443 return ex.setMessage("inferred.do.not.conform.to.upper.bounds", uv.inst,
mcimadamore@1338 444 uv.getBounds(InferenceBound.UPPER));
mcimadamore@1251 445 }
mcimadamore@1251 446 },
mcimadamore@1251 447 LOWER() {
mcimadamore@1251 448 @Override
mcimadamore@1251 449 InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
mcimadamore@1338 450 return ex.setMessage("inferred.do.not.conform.to.lower.bounds", uv.inst,
mcimadamore@1338 451 uv.getBounds(InferenceBound.LOWER));
mcimadamore@1251 452 }
mcimadamore@1251 453 },
mcimadamore@1251 454 EQ() {
mcimadamore@1251 455 @Override
mcimadamore@1251 456 InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
mcimadamore@1338 457 return ex.setMessage("inferred.do.not.conform.to.eq.bounds", uv.inst,
mcimadamore@1338 458 uv.getBounds(InferenceBound.EQ));
mcimadamore@1251 459 }
mcimadamore@1251 460 };
mcimadamore@1251 461
mcimadamore@1251 462 abstract InapplicableMethodException setMessage(InferenceException ex, UndetVar uv);
mcimadamore@1251 463 }
mcimadamore@1251 464 //where
mcimadamore@1251 465 void reportBoundError(UndetVar uv, BoundErrorKind bk) {
mcimadamore@1298 466 throw bk.setMessage(inferenceException, uv);
duke@1 467 }
mcimadamore@674 468
mcimadamore@1348 469 // <editor-fold desc="functional interface instantiation">
mcimadamore@1348 470 /**
mcimadamore@1348 471 * This method is used to infer a suitable target functional interface in case
mcimadamore@1348 472 * the original parameterized interface contains wildcards. An inference process
mcimadamore@1348 473 * is applied so that wildcard bounds, as well as explicit lambda/method ref parameters
mcimadamore@1348 474 * (where applicable) are used to constraint the solution.
mcimadamore@1348 475 */
mcimadamore@1348 476 public Type instantiateFunctionalInterface(DiagnosticPosition pos, Type funcInterface,
mcimadamore@1348 477 List<Type> paramTypes, Check.CheckContext checkContext) {
mcimadamore@1348 478 if (types.capture(funcInterface) == funcInterface) {
mcimadamore@1348 479 //if capture doesn't change the type then return the target unchanged
mcimadamore@1348 480 //(this means the target contains no wildcards!)
mcimadamore@1348 481 return funcInterface;
mcimadamore@1348 482 } else {
mcimadamore@1348 483 Type formalInterface = funcInterface.tsym.type;
mcimadamore@1348 484 InferenceContext funcInterfaceContext =
mcimadamore@1348 485 new InferenceContext(funcInterface.tsym.type.getTypeArguments(), this, false);
mcimadamore@1348 486 if (paramTypes != null) {
mcimadamore@1348 487 //get constraints from explicit params (this is done by
mcimadamore@1348 488 //checking that explicit param types are equal to the ones
mcimadamore@1348 489 //in the functional interface descriptors)
mcimadamore@1348 490 List<Type> descParameterTypes = types.findDescriptorType(formalInterface).getParameterTypes();
mcimadamore@1348 491 if (descParameterTypes.size() != paramTypes.size()) {
mcimadamore@1348 492 checkContext.report(pos, diags.fragment("incompatible.arg.types.in.lambda"));
mcimadamore@1348 493 return types.createErrorType(funcInterface);
mcimadamore@1348 494 }
mcimadamore@1348 495 for (Type p : descParameterTypes) {
mcimadamore@1348 496 if (!types.isSameType(funcInterfaceContext.asFree(p, types), paramTypes.head)) {
mcimadamore@1348 497 checkContext.report(pos, diags.fragment("no.suitable.functional.intf.inst", funcInterface));
mcimadamore@1348 498 return types.createErrorType(funcInterface);
mcimadamore@1348 499 }
mcimadamore@1348 500 paramTypes = paramTypes.tail;
mcimadamore@1348 501 }
mcimadamore@1348 502 for (Type t : funcInterfaceContext.undetvars) {
mcimadamore@1348 503 UndetVar uv = (UndetVar)t;
mcimadamore@1348 504 minimizeInst(uv, Warner.noWarnings);
mcimadamore@1348 505 if (uv.inst == null &&
mcimadamore@1348 506 Type.filter(uv.getBounds(InferenceBound.UPPER), boundFilter).nonEmpty()) {
mcimadamore@1348 507 maximizeInst(uv, Warner.noWarnings);
mcimadamore@1348 508 }
mcimadamore@1348 509 }
mcimadamore@1348 510
mcimadamore@1348 511 formalInterface = funcInterfaceContext.asInstType(formalInterface, types);
mcimadamore@1348 512 }
mcimadamore@1348 513 ListBuffer<Type> typeargs = ListBuffer.lb();
mcimadamore@1348 514 List<Type> actualTypeargs = funcInterface.getTypeArguments();
mcimadamore@1348 515 //for remaining uninferred type-vars in the functional interface type,
mcimadamore@1348 516 //simply replace the wildcards with its bound
mcimadamore@1348 517 for (Type t : formalInterface.getTypeArguments()) {
mcimadamore@1348 518 if (actualTypeargs.head.tag == WILDCARD) {
mcimadamore@1348 519 WildcardType wt = (WildcardType)actualTypeargs.head;
mcimadamore@1348 520 typeargs.append(wt.type);
mcimadamore@1348 521 } else {
mcimadamore@1348 522 typeargs.append(actualTypeargs.head);
mcimadamore@1348 523 }
mcimadamore@1348 524 actualTypeargs = actualTypeargs.tail;
mcimadamore@1348 525 }
mcimadamore@1348 526 Type owntype = types.subst(formalInterface, funcInterfaceContext.inferenceVars(), typeargs.toList());
mcimadamore@1348 527 if (!chk.checkValidGenericType(owntype)) {
mcimadamore@1348 528 //if the inferred functional interface type is not well-formed,
mcimadamore@1348 529 //or if it's not a subtype of the original target, issue an error
mcimadamore@1348 530 checkContext.report(pos, diags.fragment("no.suitable.functional.intf.inst", funcInterface));
mcimadamore@1348 531 return types.createErrorType(funcInterface);
mcimadamore@1348 532 }
mcimadamore@1348 533 return owntype;
mcimadamore@1348 534 }
mcimadamore@1348 535 }
mcimadamore@1348 536 // </editor-fold>
mcimadamore@1348 537
mcimadamore@674 538 /**
mcimadamore@674 539 * Compute a synthetic method type corresponding to the requested polymorphic
mcimadamore@820 540 * method signature. The target return type is computed from the immediately
mcimadamore@820 541 * enclosing scope surrounding the polymorphic-signature call.
mcimadamore@674 542 */
mcimadamore@1239 543 Type instantiatePolymorphicSignatureInstance(Env<AttrContext> env,
mcimadamore@674 544 MethodSymbol spMethod, // sig. poly. method or null if none
mcimadamore@1347 545 Resolve.MethodResolutionContext resolveContext,
mcimadamore@820 546 List<Type> argtypes) {
mcimadamore@674 547 final Type restype;
mcimadamore@716 548
mcimadamore@820 549 //The return type for a polymorphic signature call is computed from
mcimadamore@820 550 //the enclosing tree E, as follows: if E is a cast, then use the
mcimadamore@820 551 //target type of the cast expression as a return type; if E is an
mcimadamore@820 552 //expression statement, the return type is 'void' - otherwise the
mcimadamore@820 553 //return type is simply 'Object'. A correctness check ensures that
mcimadamore@820 554 //env.next refers to the lexically enclosing environment in which
mcimadamore@820 555 //the polymorphic signature call environment is nested.
mcimadamore@820 556
mcimadamore@820 557 switch (env.next.tree.getTag()) {
jjg@1127 558 case TYPECAST:
mcimadamore@820 559 JCTypeCast castTree = (JCTypeCast)env.next.tree;
mcimadamore@820 560 restype = (TreeInfo.skipParens(castTree.expr) == env.tree) ?
mcimadamore@820 561 castTree.clazz.type :
mcimadamore@820 562 syms.objectType;
mcimadamore@820 563 break;
jjg@1127 564 case EXEC:
mcimadamore@820 565 JCTree.JCExpressionStatement execTree =
mcimadamore@820 566 (JCTree.JCExpressionStatement)env.next.tree;
mcimadamore@820 567 restype = (TreeInfo.skipParens(execTree.expr) == env.tree) ?
mcimadamore@820 568 syms.voidType :
mcimadamore@820 569 syms.objectType;
mcimadamore@820 570 break;
mcimadamore@820 571 default:
mcimadamore@820 572 restype = syms.objectType;
mcimadamore@674 573 }
mcimadamore@674 574
mcimadamore@1347 575 List<Type> paramtypes = Type.map(argtypes, new ImplicitArgType(spMethod, resolveContext.step));
mcimadamore@674 576 List<Type> exType = spMethod != null ?
mcimadamore@674 577 spMethod.getThrownTypes() :
mcimadamore@674 578 List.of(syms.throwableType); // make it throw all exceptions
mcimadamore@674 579
mcimadamore@674 580 MethodType mtype = new MethodType(paramtypes,
mcimadamore@674 581 restype,
mcimadamore@674 582 exType,
mcimadamore@674 583 syms.methodClass);
mcimadamore@674 584 return mtype;
mcimadamore@674 585 }
mcimadamore@674 586 //where
mcimadamore@1347 587 class ImplicitArgType extends DeferredAttr.DeferredTypeMap {
mcimadamore@1347 588
mcimadamore@1347 589 public ImplicitArgType(Symbol msym, Resolve.MethodResolutionPhase phase) {
mcimadamore@1347 590 deferredAttr.super(AttrMode.SPECULATIVE, msym, phase);
mcimadamore@1347 591 }
mcimadamore@1347 592
mcimadamore@1347 593 public Type apply(Type t) {
mcimadamore@1347 594 t = types.erasure(super.apply(t));
mcimadamore@1347 595 if (t.tag == BOT)
mcimadamore@1347 596 // nulls type as the marker type Null (which has no instances)
mcimadamore@1347 597 // infer as java.lang.Void for now
mcimadamore@1347 598 t = types.boxedClass(syms.voidType).type;
mcimadamore@1347 599 return t;
mcimadamore@1347 600 }
mcimadamore@1347 601 }
mcimadamore@1337 602
mcimadamore@1337 603 /**
mcimadamore@1337 604 * Mapping that turns inference variables into undet vars
mcimadamore@1337 605 * (used by inference context)
mcimadamore@1337 606 */
mcimadamore@1348 607 class FromTypeVarFun extends Mapping {
mcimadamore@1348 608
mcimadamore@1348 609 boolean includeBounds;
mcimadamore@1348 610
mcimadamore@1348 611 FromTypeVarFun(boolean includeBounds) {
mcimadamore@1348 612 super("fromTypeVarFunWithBounds");
mcimadamore@1348 613 this.includeBounds = includeBounds;
mcimadamore@1348 614 }
mcimadamore@1348 615
mcimadamore@1337 616 public Type apply(Type t) {
mcimadamore@1348 617 if (t.tag == TYPEVAR) return new UndetVar((TypeVar)t, types, includeBounds);
mcimadamore@1337 618 else return t.map(this);
mcimadamore@1337 619 }
mcimadamore@1337 620 };
mcimadamore@1337 621
mcimadamore@1337 622 /**
mcimadamore@1337 623 * An inference context keeps track of the set of variables that are free
mcimadamore@1337 624 * in the current context. It provides utility methods for opening/closing
mcimadamore@1337 625 * types to their corresponding free/closed forms. It also provide hooks for
mcimadamore@1337 626 * attaching deferred post-inference action (see PendingCheck). Finally,
mcimadamore@1337 627 * it can be used as an entry point for performing upper/lower bound inference
mcimadamore@1337 628 * (see InferenceKind).
mcimadamore@1337 629 */
mcimadamore@1337 630 static class InferenceContext {
mcimadamore@1337 631
mcimadamore@1337 632 /**
mcimadamore@1337 633 * Single-method-interface for defining inference callbacks. Certain actions
mcimadamore@1337 634 * (i.e. subtyping checks) might need to be redone after all inference variables
mcimadamore@1337 635 * have been fixed.
mcimadamore@1337 636 */
mcimadamore@1337 637 interface FreeTypeListener {
mcimadamore@1337 638 void typesInferred(InferenceContext inferenceContext);
mcimadamore@1337 639 }
mcimadamore@1337 640
mcimadamore@1337 641 /** list of inference vars as undet vars */
mcimadamore@1337 642 List<Type> undetvars;
mcimadamore@1337 643
mcimadamore@1337 644 /** list of inference vars in this context */
mcimadamore@1337 645 List<Type> inferencevars;
mcimadamore@1337 646
mcimadamore@1337 647 java.util.Map<FreeTypeListener, List<Type>> freeTypeListeners =
mcimadamore@1337 648 new java.util.HashMap<FreeTypeListener, List<Type>>();
mcimadamore@1337 649
mcimadamore@1337 650 List<FreeTypeListener> freetypeListeners = List.nil();
mcimadamore@1337 651
mcimadamore@1348 652 public InferenceContext(List<Type> inferencevars, Infer infer, boolean includeBounds) {
mcimadamore@1348 653 this.undetvars = Type.map(inferencevars, infer.new FromTypeVarFun(includeBounds));
mcimadamore@1337 654 this.inferencevars = inferencevars;
mcimadamore@1337 655 }
mcimadamore@1337 656
mcimadamore@1337 657 /**
mcimadamore@1337 658 * returns the list of free variables (as type-variables) in this
mcimadamore@1337 659 * inference context
mcimadamore@1337 660 */
mcimadamore@1337 661 List<Type> inferenceVars() {
mcimadamore@1337 662 return inferencevars;
mcimadamore@1337 663 }
mcimadamore@1337 664
mcimadamore@1337 665 /**
mcimadamore@1337 666 * returns the list of uninstantiated variables (as type-variables) in this
mcimadamore@1337 667 * inference context (usually called after instantiate())
mcimadamore@1337 668 */
mcimadamore@1337 669 List<Type> restvars() {
mcimadamore@1337 670 List<Type> undetvars = this.undetvars;
mcimadamore@1337 671 ListBuffer<Type> restvars = ListBuffer.lb();
mcimadamore@1337 672 for (Type t : instTypes()) {
mcimadamore@1337 673 UndetVar uv = (UndetVar)undetvars.head;
mcimadamore@1337 674 if (uv.qtype == t) {
mcimadamore@1337 675 restvars.append(t);
mcimadamore@1337 676 }
mcimadamore@1337 677 undetvars = undetvars.tail;
mcimadamore@1337 678 }
mcimadamore@1337 679 return restvars.toList();
mcimadamore@1337 680 }
mcimadamore@1337 681
mcimadamore@1337 682 /**
mcimadamore@1337 683 * is this type free?
mcimadamore@1337 684 */
mcimadamore@1337 685 final boolean free(Type t) {
mcimadamore@1337 686 return t.containsAny(inferencevars);
mcimadamore@1337 687 }
mcimadamore@1337 688
mcimadamore@1337 689 final boolean free(List<Type> ts) {
mcimadamore@1337 690 for (Type t : ts) {
mcimadamore@1337 691 if (free(t)) return true;
mcimadamore@1337 692 }
mcimadamore@1337 693 return false;
mcimadamore@1337 694 }
mcimadamore@1337 695
mcimadamore@1337 696 /**
mcimadamore@1337 697 * Returns a list of free variables in a given type
mcimadamore@1337 698 */
mcimadamore@1337 699 final List<Type> freeVarsIn(Type t) {
mcimadamore@1337 700 ListBuffer<Type> buf = ListBuffer.lb();
mcimadamore@1337 701 for (Type iv : inferenceVars()) {
mcimadamore@1337 702 if (t.contains(iv)) {
mcimadamore@1337 703 buf.add(iv);
mcimadamore@1337 704 }
mcimadamore@1337 705 }
mcimadamore@1337 706 return buf.toList();
mcimadamore@1337 707 }
mcimadamore@1337 708
mcimadamore@1337 709 final List<Type> freeVarsIn(List<Type> ts) {
mcimadamore@1337 710 ListBuffer<Type> buf = ListBuffer.lb();
mcimadamore@1337 711 for (Type t : ts) {
mcimadamore@1337 712 buf.appendList(freeVarsIn(t));
mcimadamore@1337 713 }
mcimadamore@1337 714 ListBuffer<Type> buf2 = ListBuffer.lb();
mcimadamore@1337 715 for (Type t : buf) {
mcimadamore@1337 716 if (!buf2.contains(t)) {
mcimadamore@1337 717 buf2.add(t);
mcimadamore@1337 718 }
mcimadamore@1337 719 }
mcimadamore@1337 720 return buf2.toList();
mcimadamore@1337 721 }
mcimadamore@1337 722
mcimadamore@1337 723 /**
mcimadamore@1337 724 * Replace all free variables in a given type with corresponding
mcimadamore@1337 725 * undet vars (used ahead of subtyping/compatibility checks to allow propagation
mcimadamore@1337 726 * of inference constraints).
mcimadamore@1337 727 */
mcimadamore@1337 728 final Type asFree(Type t, Types types) {
mcimadamore@1337 729 return types.subst(t, inferencevars, undetvars);
mcimadamore@1337 730 }
mcimadamore@1337 731
mcimadamore@1337 732 final List<Type> asFree(List<Type> ts, Types types) {
mcimadamore@1337 733 ListBuffer<Type> buf = ListBuffer.lb();
mcimadamore@1337 734 for (Type t : ts) {
mcimadamore@1337 735 buf.append(asFree(t, types));
mcimadamore@1337 736 }
mcimadamore@1337 737 return buf.toList();
mcimadamore@1337 738 }
mcimadamore@1337 739
mcimadamore@1337 740 List<Type> instTypes() {
mcimadamore@1337 741 ListBuffer<Type> buf = ListBuffer.lb();
mcimadamore@1337 742 for (Type t : undetvars) {
mcimadamore@1337 743 UndetVar uv = (UndetVar)t;
mcimadamore@1337 744 buf.append(uv.inst != null ? uv.inst : uv.qtype);
mcimadamore@1337 745 }
mcimadamore@1337 746 return buf.toList();
mcimadamore@1337 747 }
mcimadamore@1337 748
mcimadamore@1337 749 /**
mcimadamore@1337 750 * Replace all free variables in a given type with corresponding
mcimadamore@1337 751 * instantiated types - if one or more free variable has not been
mcimadamore@1337 752 * fully instantiated, it will still be available in the resulting type.
mcimadamore@1337 753 */
mcimadamore@1337 754 Type asInstType(Type t, Types types) {
mcimadamore@1337 755 return types.subst(t, inferencevars, instTypes());
mcimadamore@1337 756 }
mcimadamore@1337 757
mcimadamore@1337 758 List<Type> asInstTypes(List<Type> ts, Types types) {
mcimadamore@1337 759 ListBuffer<Type> buf = ListBuffer.lb();
mcimadamore@1337 760 for (Type t : ts) {
mcimadamore@1337 761 buf.append(asInstType(t, types));
mcimadamore@1337 762 }
mcimadamore@1337 763 return buf.toList();
mcimadamore@1337 764 }
mcimadamore@1337 765
mcimadamore@1337 766 /**
mcimadamore@1337 767 * Add custom hook for performing post-inference action
mcimadamore@1337 768 */
mcimadamore@1337 769 void addFreeTypeListener(List<Type> types, FreeTypeListener ftl) {
mcimadamore@1337 770 freeTypeListeners.put(ftl, freeVarsIn(types));
mcimadamore@1337 771 }
mcimadamore@1337 772
mcimadamore@1337 773 /**
mcimadamore@1337 774 * Mark the inference context as complete and trigger evaluation
mcimadamore@1337 775 * of all deferred checks.
mcimadamore@1337 776 */
mcimadamore@1337 777 void notifyChange(Types types) {
mcimadamore@1337 778 InferenceException thrownEx = null;
mcimadamore@1337 779 for (Map.Entry<FreeTypeListener, List<Type>> entry :
mcimadamore@1337 780 new HashMap<FreeTypeListener, List<Type>>(freeTypeListeners).entrySet()) {
mcimadamore@1337 781 if (!Type.containsAny(entry.getValue(), restvars())) {
mcimadamore@1337 782 try {
mcimadamore@1337 783 entry.getKey().typesInferred(this);
mcimadamore@1337 784 freeTypeListeners.remove(entry.getKey());
mcimadamore@1337 785 } catch (InferenceException ex) {
mcimadamore@1337 786 if (thrownEx == null) {
mcimadamore@1337 787 thrownEx = ex;
mcimadamore@1337 788 }
mcimadamore@1337 789 }
mcimadamore@1337 790 }
mcimadamore@1337 791 }
mcimadamore@1337 792 //inference exception multiplexing - present any inference exception
mcimadamore@1337 793 //thrown when processing listeners as a single one
mcimadamore@1337 794 if (thrownEx != null) {
mcimadamore@1337 795 throw thrownEx;
mcimadamore@1337 796 }
mcimadamore@1337 797 }
mcimadamore@1347 798
mcimadamore@1347 799 void solveAny(List<Type> varsToSolve, Types types, Infer infer) {
mcimadamore@1347 800 boolean progress = false;
mcimadamore@1347 801 for (Type t : varsToSolve) {
mcimadamore@1347 802 UndetVar uv = (UndetVar)asFree(t, types);
mcimadamore@1347 803 if (uv.inst == null) {
mcimadamore@1347 804 infer.minimizeInst(uv, Warner.noWarnings);
mcimadamore@1347 805 if (uv.inst != null) {
mcimadamore@1347 806 progress = true;
mcimadamore@1347 807 }
mcimadamore@1347 808 }
mcimadamore@1347 809 }
mcimadamore@1347 810 if (!progress) {
mcimadamore@1347 811 throw infer.inferenceException.setMessage("cyclic.inference", varsToSolve);
mcimadamore@1347 812 }
mcimadamore@1347 813 }
mcimadamore@895 814 }
mcimadamore@1337 815
mcimadamore@1348 816 final InferenceContext emptyContext = new InferenceContext(List.<Type>nil(), this, false);
mcimadamore@1337 817 }

mercurial