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

Fri, 05 Oct 2012 14:35:24 +0100

author
mcimadamore
date
Fri, 05 Oct 2012 14:35:24 +0100
changeset 1348
573ceb23beeb
parent 1347
1408af4cd8b0
child 1357
c75be5bc5283
permissions
-rw-r--r--

7177385: Add attribution support for lambda expressions
Summary: Add support for function descriptor lookup, functional interface inference and lambda expression type-checking
Reviewed-by: jjg, dlsmith

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

mercurial