Infer.java revision 3528:5538ba41cb97
1212795Sdim/* 2212795Sdim * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. 3212795Sdim * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4212795Sdim * 5212795Sdim * This code is free software; you can redistribute it and/or modify it 6212795Sdim * under the terms of the GNU General Public License version 2 only, as 7212795Sdim * published by the Free Software Foundation. Oracle designates this 8212795Sdim * particular file as subject to the "Classpath" exception as provided 9212795Sdim * by Oracle in the LICENSE file that accompanied this code. 10212795Sdim * 11212795Sdim * This code is distributed in the hope that it will be useful, but WITHOUT 12212795Sdim * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13212795Sdim * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14212795Sdim * version 2 for more details (a copy is included in the LICENSE file that 15249423Sdim * accompanied this code). 16218893Sdim * 17234982Sdim * You should have received a copy of the GNU General Public License version 18212795Sdim * 2 along with this work; if not, write to the Free Software Foundation, 19212795Sdim * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20249423Sdim * 21212795Sdim * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22212795Sdim * or visit www.oracle.com if you need additional information or have any 23249423Sdim * questions. 24212795Sdim */ 25249423Sdim 26249423Sdimpackage com.sun.tools.javac.comp; 27249423Sdim 28239462Sdimimport com.sun.tools.javac.code.Type.UndetVar.UndetVarListener; 29212795Sdimimport com.sun.tools.javac.tree.JCTree; 30212795Sdimimport com.sun.tools.javac.tree.JCTree.JCTypeCast; 31212795Sdimimport com.sun.tools.javac.tree.TreeInfo; 32212795Sdimimport com.sun.tools.javac.util.*; 33212795Sdimimport com.sun.tools.javac.util.GraphUtils.DottableNode; 34212795Sdimimport com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; 35212795Sdimimport com.sun.tools.javac.util.List; 36212795Sdimimport com.sun.tools.javac.code.*; 37212795Sdimimport com.sun.tools.javac.code.Type.*; 38212795Sdimimport com.sun.tools.javac.code.Type.UndetVar.InferenceBound; 39234353Sdimimport com.sun.tools.javac.code.Symbol.*; 40212795Sdimimport com.sun.tools.javac.comp.DeferredAttr.AttrMode; 41234353Sdimimport com.sun.tools.javac.comp.DeferredAttr.DeferredAttrContext; 42218893Sdimimport com.sun.tools.javac.comp.Infer.GraphSolver.InferenceGraph; 43218893Sdimimport com.sun.tools.javac.comp.Infer.GraphSolver.InferenceGraph.Node; 44212795Sdimimport com.sun.tools.javac.comp.Resolve.InapplicableMethodException; 45212795Sdimimport com.sun.tools.javac.comp.Resolve.VerboseResolutionMode; 46221345Sdim 47243830Sdimimport java.io.IOException; 48243830Sdimimport java.io.Writer; 49212795Sdimimport java.nio.file.Files; 50226633Sdimimport java.nio.file.Path; 51218893Sdimimport java.nio.file.Paths; 52218893Sdimimport java.util.ArrayList; 53218893Sdimimport java.util.Collection; 54226633Sdimimport java.util.Collections; 55218893Sdimimport java.util.EnumSet; 56218893Sdimimport java.util.HashMap; 57218893Sdimimport java.util.HashSet; 58226633Sdimimport java.util.Map; 59218893Sdimimport java.util.Optional; 60218893Sdimimport java.util.Properties; 61218893Sdimimport java.util.Set; 62226633Sdimimport java.util.function.BiFunction; 63226633Sdimimport java.util.function.BiPredicate; 64226633Sdim 65226633Sdimimport com.sun.tools.javac.main.Option; 66226633Sdim 67226633Sdimimport static com.sun.tools.javac.code.TypeTag.*; 68226633Sdim 69226633Sdim/** Helper class for type parameter inference, used by the attribution phase. 70226633Sdim * 71226633Sdim * <p><b>This is NOT part of any supported API. 72226633Sdim * If you write code that depends on this, you do so at your own risk. 73226633Sdim * This code and its internal interfaces are subject to change or 74226633Sdim * deletion without notice.</b> 75226633Sdim */ 76218893Sdimpublic class Infer { 77218893Sdim protected static final Context.Key<Infer> inferKey = new Context.Key<>(); 78218893Sdim 79218893Sdim Resolve rs; 80226633Sdim Check chk; 81218893Sdim Symtab syms; 82218893Sdim Types types; 83218893Sdim JCDiagnostic.Factory diags; 84218893Sdim Log log; 85226633Sdim 86218893Sdim /** should the graph solver be used? */ 87218893Sdim boolean allowGraphInference; 88218893Sdim 89218893Sdim /** 90212795Sdim * folder in which the inference dependency graphs should be written. 91234353Sdim */ 92234353Sdim private final String dependenciesFolder; 93234353Sdim 94234353Sdim /** 95234353Sdim * List of graphs awaiting to be dumped to a file. 96234353Sdim */ 97234353Sdim private List<String> pendingGraphs; 98234353Sdim 99234353Sdim public static Infer instance(Context context) { 100234353Sdim Infer instance = context.get(inferKey); 101234353Sdim if (instance == null) 102234353Sdim instance = new Infer(context); 103218893Sdim return instance; 104218893Sdim } 105218893Sdim 106234353Sdim protected Infer(Context context) { 107234353Sdim context.put(inferKey, this); 108234353Sdim 109234353Sdim rs = Resolve.instance(context); 110234353Sdim chk = Check.instance(context); 111234353Sdim syms = Symtab.instance(context); 112234353Sdim types = Types.instance(context); 113234353Sdim diags = JCDiagnostic.Factory.instance(context); 114234353Sdim log = Log.instance(context); 115234353Sdim inferenceException = new InferenceException(diags); 116249423Sdim Options options = Options.instance(context); 117234353Sdim allowGraphInference = Source.instance(context).allowGraphInference() 118243830Sdim && options.isUnset("useLegacyInference"); 119234353Sdim dependenciesFolder = options.get("debug.dumpInferenceGraphsTo"); 120234353Sdim pendingGraphs = List.nil(); 121249423Sdim 122249423Sdim emptyContext = new InferenceContext(this, List.<Type>nil()); 123249423Sdim } 124234353Sdim 125234353Sdim /** A value for prototypes that admit any type, including polymorphic ones. */ 126249423Sdim public static final Type anyPoly = new JCNoType(); 127249423Sdim 128234353Sdim /** 129234353Sdim * This exception class is design to store a list of diagnostics corresponding 130234353Sdim * to inference errors that can arise during a method applicability check. 131234353Sdim */ 132234353Sdim public static class InferenceException extends InapplicableMethodException { 133249423Sdim private static final long serialVersionUID = 0; 134249423Sdim 135234353Sdim List<JCDiagnostic> messages = List.nil(); 136234353Sdim 137234353Sdim InferenceException(JCDiagnostic.Factory diags) { 138234353Sdim super(diags); 139234353Sdim } 140234353Sdim 141234353Sdim @Override 142234353Sdim InapplicableMethodException setMessage() { 143234353Sdim //no message to set 144234353Sdim return this; 145234353Sdim } 146234353Sdim 147249423Sdim @Override 148234353Sdim InapplicableMethodException setMessage(JCDiagnostic diag) { 149234353Sdim messages = messages.append(diag); 150234353Sdim return this; 151234353Sdim } 152234353Sdim 153234353Sdim @Override 154234353Sdim public JCDiagnostic getDiagnostic() { 155234353Sdim return messages.head; 156234353Sdim } 157234353Sdim 158234353Sdim void clear() { 159243830Sdim messages = List.nil(); 160234353Sdim } 161234353Sdim } 162234353Sdim 163234353Sdim protected final InferenceException inferenceException; 164234353Sdim 165234353Sdim // <editor-fold defaultstate="collapsed" desc="Inference routines"> 166234353Sdim /** 167234353Sdim * Main inference entry point - instantiate a generic method type 168234353Sdim * using given argument types and (possibly) an expected target-type. 169234353Sdim */ 170234353Sdim Type instantiateMethod( Env<AttrContext> env, 171234353Sdim List<Type> tvars, 172234353Sdim MethodType mt, 173234353Sdim Attr.ResultInfo resultInfo, 174234353Sdim MethodSymbol msym, 175234353Sdim List<Type> argtypes, 176234353Sdim boolean allowBoxing, 177234353Sdim boolean useVarargs, 178234353Sdim Resolve.MethodResolutionContext resolveContext, 179234353Sdim Warner warn) throws InferenceException { 180234353Sdim //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG 181234353Sdim final InferenceContext inferenceContext = new InferenceContext(this, tvars); //B0 182234353Sdim inferenceException.clear(); 183234353Sdim try { 184234353Sdim DeferredAttr.DeferredAttrContext deferredAttrContext = 185234353Sdim resolveContext.deferredAttrContext(msym, inferenceContext, resultInfo, warn); 186234353Sdim 187234353Sdim resolveContext.methodCheck.argumentsAcceptable(env, deferredAttrContext, //B2 188234353Sdim argtypes, mt.getParameterTypes(), warn); 189212795Sdim 190234353Sdim if (allowGraphInference && resultInfo != null && resultInfo.pt == anyPoly) { 191243830Sdim doIncorporation(inferenceContext, warn); 192234353Sdim //we are inside method attribution - just return a partially inferred type 193218893Sdim return new PartiallyInferredMethodType(mt, inferenceContext, env, warn); 194243830Sdim } else if (allowGraphInference && 195234353Sdim resultInfo != null && 196243830Sdim !warn.hasNonSilentLint(Lint.LintCategory.UNCHECKED)) { 197212795Sdim //inject return constraints earlier 198218893Sdim doIncorporation(inferenceContext, warn); //propagation 199234353Sdim 200218893Sdim boolean shouldPropagate = shouldPropagate(mt.getReturnType(), resultInfo, inferenceContext); 201243830Sdim 202243830Sdim InferenceContext minContext = shouldPropagate ? 203243830Sdim inferenceContext.min(roots(mt, deferredAttrContext), true, warn) : 204212795Sdim inferenceContext; 205212795Sdim 206234353Sdim Type newRestype = generateReturnConstraints(env.tree, resultInfo, //B3 207221345Sdim mt, minContext); 208218893Sdim mt = (MethodType)types.createMethodTypeWithReturn(mt, newRestype); 209226633Sdim 210226633Sdim //propagate outwards if needed 211226633Sdim if (shouldPropagate) { 212226633Sdim //propagate inference context outwards and exit 213226633Sdim minContext.dupTo(resultInfo.checkContext.inferenceContext()); 214212795Sdim deferredAttrContext.complete(); 215212795Sdim return mt; 216212795Sdim } 217218893Sdim } 218212795Sdim 219212795Sdim deferredAttrContext.complete(); 220212795Sdim 221212795Sdim // minimize as yet undetermined type variables 222234353Sdim if (allowGraphInference) { 223212795Sdim inferenceContext.solve(warn); 224221345Sdim } else { 225212795Sdim inferenceContext.solveLegacy(true, warn, LegacyInferenceSteps.EQ_LOWER.steps); //minimizeInst 226263508Sdim } 227212795Sdim 228263508Sdim mt = (MethodType)inferenceContext.asInstType(mt); 229263508Sdim 230263508Sdim if (!allowGraphInference && 231263508Sdim inferenceContext.restvars().nonEmpty() && 232263508Sdim resultInfo != null && 233263508Sdim !warn.hasNonSilentLint(Lint.LintCategory.UNCHECKED)) { 234212795Sdim generateReturnConstraints(env.tree, resultInfo, mt, inferenceContext); 235263508Sdim inferenceContext.solveLegacy(false, warn, LegacyInferenceSteps.EQ_UPPER.steps); //maximizeInst 236263508Sdim mt = (MethodType)inferenceContext.asInstType(mt); 237263508Sdim } 238212795Sdim 239212795Sdim if (resultInfo != null && rs.verboseResolutionMode.contains(VerboseResolutionMode.DEFERRED_INST)) { 240226633Sdim log.note(env.tree.pos, "deferred.method.inst", msym, mt, resultInfo.pt); 241226633Sdim } 242263508Sdim 243263508Sdim // return instantiated version of method type 244263508Sdim return mt; 245263508Sdim } finally { 246263508Sdim if (resultInfo != null || !allowGraphInference) { 247263508Sdim inferenceContext.notifyChange(); 248263508Sdim } else { 249212795Sdim inferenceContext.notifyChange(inferenceContext.boundedVars()); 250212795Sdim } 251212795Sdim if (resultInfo == null) { 252212795Sdim /* if the is no result info then we can clear the capture types 253212795Sdim * cache without affecting any result info check 254212795Sdim */ 255212795Sdim inferenceContext.captureTypeCache.clear(); 256212795Sdim } 257212795Sdim dumpGraphsIfNeeded(env.tree, msym, resolveContext); 258212795Sdim } 259212795Sdim } 260251662Sdim //where 261218893Sdim private boolean shouldPropagate(Type restype, Attr.ResultInfo target, InferenceContext inferenceContext) { 262263508Sdim return target.checkContext.inferenceContext() != emptyContext && //enclosing context is a generic method 263263508Sdim inferenceContext.free(restype) && //return type contains inference vars 264212795Sdim (!inferenceContext.inferencevars.contains(restype) || //no eager instantiation is required (as per 18.5.2) 265212795Sdim !needsEagerInstantiation((UndetVar)inferenceContext.asUndetVar(restype), target.pt, inferenceContext)); 266212795Sdim } 267212795Sdim 268234353Sdim private List<Type> roots(MethodType mt, DeferredAttrContext deferredAttrContext) { 269212795Sdim ListBuffer<Type> roots = new ListBuffer<>(); 270263508Sdim roots.add(mt.getReturnType()); 271212795Sdim if (deferredAttrContext != null && deferredAttrContext.mode == AttrMode.CHECK) { 272212795Sdim roots.addAll(mt.getThrownTypes()); 273223017Sdim for (DeferredAttr.DeferredAttrNode n : deferredAttrContext.deferredAttrNodes) { 274212795Sdim roots.addAll(n.deferredStuckPolicy.stuckVars()); 275212795Sdim roots.addAll(n.deferredStuckPolicy.depVars()); 276212795Sdim } 277212795Sdim } 278234353Sdim return roots.toList(); 279212795Sdim } 280212795Sdim 281212795Sdim /** 282212795Sdim * A partially infered method/constructor type; such a type can be checked multiple times 283212795Sdim * against different targets. 284251662Sdim */ 285249423Sdim public class PartiallyInferredMethodType extends MethodType { 286212795Sdim public PartiallyInferredMethodType(MethodType mtype, InferenceContext inferenceContext, Env<AttrContext> env, Warner warn) { 287212795Sdim super(mtype.getParameterTypes(), mtype.getReturnType(), mtype.getThrownTypes(), mtype.tsym); 288234353Sdim this.inferenceContext = inferenceContext; 289234353Sdim this.env = env; 290234353Sdim this.warn = warn; 291212795Sdim } 292234353Sdim 293234353Sdim /** The inference context. */ 294263508Sdim final InferenceContext inferenceContext; 295263508Sdim 296263508Sdim /** The attribution environment. */ 297263508Sdim Env<AttrContext> env; 298263508Sdim 299263508Sdim /** The warner. */ 300263508Sdim final Warner warn; 301263508Sdim 302212795Sdim @Override 303212795Sdim public boolean isPartial() { 304212795Sdim return true; 305212795Sdim } 306212795Sdim 307212795Sdim /** 308212795Sdim * Checks this type against a target; this means generating return type constraints, solve 309212795Sdim * and then roll back the results (to avoid poolluting the context). 310212795Sdim */ 311212795Sdim Type check(Attr.ResultInfo resultInfo) { 312212795Sdim Warner noWarnings = new Warner(null); 313212795Sdim inferenceException.clear(); 314212795Sdim List<Type> saved_undet = null; 315212795Sdim try { 316249423Sdim /** we need to save the inference context before generating target type constraints. 317212795Sdim * This constraints may pollute the inference context and make it useless in case we 318212795Sdim * need to use it several times: with several targets. 319212795Sdim */ 320212795Sdim saved_undet = inferenceContext.save(); 321226633Sdim if (allowGraphInference && !warn.hasNonSilentLint(Lint.LintCategory.UNCHECKED)) { 322212795Sdim boolean shouldPropagate = shouldPropagate(getReturnType(), resultInfo, inferenceContext); 323212795Sdim 324212795Sdim InferenceContext minContext = shouldPropagate ? 325212795Sdim inferenceContext.min(roots(asMethodType(), null), false, warn) : 326212795Sdim inferenceContext; 327223017Sdim 328223017Sdim MethodType other = (MethodType)minContext.update(asMethodType()); 329223017Sdim Type newRestype = generateReturnConstraints(env.tree, resultInfo, //B3 330223017Sdim other, minContext); 331223017Sdim 332223017Sdim if (shouldPropagate) { 333223017Sdim //propagate inference context outwards and exit 334223017Sdim minContext.dupTo(resultInfo.checkContext.inferenceContext(), 335223017Sdim resultInfo.checkContext.deferredAttrContext().insideOverloadPhase()); 336223017Sdim return newRestype; 337223017Sdim } 338223017Sdim } 339212795Sdim inferenceContext.solve(noWarnings); 340212795Sdim return inferenceContext.asInstType(this).getReturnType(); 341218893Sdim } catch (InferenceException ex) { 342234353Sdim resultInfo.checkContext.report(null, ex.getDiagnostic()); 343234353Sdim Assert.error(); //cannot get here (the above should throw) 344234353Sdim return null; 345212795Sdim } finally { 346212795Sdim if (saved_undet != null) { 347243830Sdim inferenceContext.rollback(saved_undet); 348243830Sdim } 349243830Sdim } 350243830Sdim } 351243830Sdim } 352243830Sdim 353243830Sdim private void dumpGraphsIfNeeded(DiagnosticPosition pos, Symbol msym, Resolve.MethodResolutionContext rsContext) { 354243830Sdim int round = 0; 355212795Sdim try { 356212795Sdim for (String graph : pendingGraphs.reverse()) { 357212795Sdim Assert.checkNonNull(dependenciesFolder); 358212795Sdim Name name = msym.name == msym.name.table.names.init ? 359221345Sdim msym.owner.name : msym.name; 360221345Sdim String filename = String.format("%s@%s[mode=%s,step=%s]_%d.dot", 361221345Sdim name, 362221345Sdim pos.getStartPosition(), 363221345Sdim rsContext.attrMode(), 364249423Sdim rsContext.step, 365249423Sdim round); 366249423Sdim Path dotFile = Paths.get(dependenciesFolder, filename); 367249423Sdim try (Writer w = Files.newBufferedWriter(dotFile)) { 368249423Sdim w.append(graph); 369226633Sdim } 370221345Sdim round++; 371234353Sdim } 372234353Sdim } catch (IOException ex) { 373263508Sdim Assert.error("Error occurred when dumping inference graph: " + ex.getMessage()); 374234353Sdim } finally { 375234353Sdim pendingGraphs = List.nil(); 376263508Sdim } 377263508Sdim } 378221345Sdim 379234353Sdim /** 380212795Sdim * Generate constraints from the generic method's return type. If the method 381218893Sdim * call occurs in a context where a type T is expected, use the expected 382212795Sdim * type to derive more constraints on the generic method inference variables. 383218893Sdim */ 384234353Sdim Type generateReturnConstraints(JCTree tree, Attr.ResultInfo resultInfo, 385234353Sdim MethodType mt, InferenceContext inferenceContext) { 386234353Sdim InferenceContext rsInfoInfContext = resultInfo.checkContext.inferenceContext(); 387212795Sdim Type from = mt.getReturnType(); 388212795Sdim if (mt.getReturnType().containsAny(inferenceContext.inferencevars) && 389263508Sdim rsInfoInfContext != emptyContext) { 390221345Sdim from = types.capture(from); 391234353Sdim //add synthetic captured ivars 392212795Sdim for (Type t : from.getTypeArguments()) { 393226633Sdim if (t.hasTag(TYPEVAR) && ((TypeVar)t).isCaptured()) { 394234353Sdim inferenceContext.addVar((TypeVar)t); 395234353Sdim } 396234353Sdim } 397234353Sdim } 398234353Sdim Type qtype = inferenceContext.asUndetVar(from); 399234353Sdim Type to = resultInfo.pt; 400234353Sdim 401234353Sdim if (qtype.hasTag(VOID)) { 402234353Sdim to = syms.voidType; 403234353Sdim } else if (to.hasTag(NONE)) { 404234353Sdim to = from.isPrimitive() ? from : syms.objectType; 405234353Sdim } else if (qtype.hasTag(UNDETVAR)) { 406234353Sdim if (resultInfo.pt.isReference()) { 407234353Sdim if (needsEagerInstantiation((UndetVar)qtype, to, inferenceContext)) { 408234353Sdim to = generateReferenceToTargetConstraint(tree, (UndetVar)qtype, to, resultInfo, inferenceContext); 409234353Sdim } 410234353Sdim } else { 411234353Sdim if (to.isPrimitive()) { 412234353Sdim to = generateReturnConstraintsPrimitive(tree, (UndetVar)qtype, to, 413234353Sdim resultInfo, inferenceContext); 414234353Sdim } 415234353Sdim } 416234353Sdim } else if (rsInfoInfContext.free(resultInfo.pt)) { 417212795Sdim //propagation - cache captured vars 418212795Sdim qtype = inferenceContext.asUndetVar(rsInfoInfContext.cachedCapture(tree, from, false)); 419212795Sdim } 420226633Sdim Assert.check(allowGraphInference || !rsInfoInfContext.free(to), 421212795Sdim "legacy inference engine cannot handle constraints on both sides of a subtyping assertion"); 422212795Sdim //we need to skip capture? 423212795Sdim Warner retWarn = new Warner(); 424212795Sdim if (!resultInfo.checkContext.compatible(qtype, rsInfoInfContext.asUndetVar(to), retWarn) || 425226633Sdim //unchecked conversion is not allowed in source 7 mode 426212795Sdim (!allowGraphInference && retWarn.hasLint(Lint.LintCategory.UNCHECKED))) { 427212795Sdim throw inferenceException 428212795Sdim .setMessage("infer.no.conforming.instance.exists", 429212795Sdim inferenceContext.restvars(), mt.getReturnType(), to); 430221345Sdim } 431212795Sdim return from; 432226633Sdim } 433212795Sdim 434212795Sdim private Type generateReturnConstraintsPrimitive(JCTree tree, UndetVar from, 435234353Sdim Type to, Attr.ResultInfo resultInfo, InferenceContext inferenceContext) { 436234353Sdim if (!allowGraphInference) { 437212795Sdim //if legacy, just return boxed type 438263508Sdim return types.boxedClass(to).type; 439263508Sdim } 440263508Sdim //if graph inference we need to skip conflicting boxed bounds... 441263508Sdim for (Type t : from.getBounds(InferenceBound.EQ, InferenceBound.UPPER, 442263508Sdim InferenceBound.LOWER)) { 443263508Sdim Type boundAsPrimitive = types.unboxedType(t); 444234353Sdim if (boundAsPrimitive == null || boundAsPrimitive.hasTag(NONE)) { 445212795Sdim continue; 446212795Sdim } 447234353Sdim return generateReferenceToTargetConstraint(tree, from, to, 448234353Sdim resultInfo, inferenceContext); 449234353Sdim } 450234353Sdim return types.boxedClass(to).type; 451221345Sdim } 452234353Sdim 453221345Sdim private boolean needsEagerInstantiation(UndetVar from, Type to, InferenceContext inferenceContext) { 454221345Sdim Type captureOfTo = types.capture(to); 455263508Sdim /* T is a reference type, but is not a wildcard-parameterized type, and either 456234353Sdim */ 457212795Sdim if (captureOfTo == to) { //not a wildcard parameterized type 458234353Sdim /* i) B2 contains a bound of one of the forms alpha = S or S <: alpha, 459212795Sdim * where S is a wildcard-parameterized type, or 460212795Sdim */ 461226633Sdim for (Type t : from.getBounds(InferenceBound.EQ, InferenceBound.LOWER)) { 462212795Sdim Type captureOfBound = types.capture(t); 463226633Sdim if (captureOfBound != t) { 464263508Sdim return true; 465218893Sdim } 466234353Sdim } 467218893Sdim 468226633Sdim /* ii) B2 contains two bounds of the forms S1 <: alpha and S2 <: alpha, 469218893Sdim * where S1 and S2 have supertypes that are two different 470263508Sdim * parameterizations of the same generic class or interface. 471218893Sdim */ 472263508Sdim for (Type aLowerBound : from.getBounds(InferenceBound.LOWER)) { 473234353Sdim for (Type anotherLowerBound : from.getBounds(InferenceBound.LOWER)) { 474263508Sdim if (aLowerBound != anotherLowerBound && 475263508Sdim !inferenceContext.free(aLowerBound) && 476212795Sdim !inferenceContext.free(anotherLowerBound) && 477212795Sdim commonSuperWithDiffParameterization(aLowerBound, anotherLowerBound)) { 478212795Sdim return true; 479212795Sdim } 480218893Sdim } 481218893Sdim } 482218893Sdim } 483226633Sdim 484226633Sdim /* T is a parameterization of a generic class or interface, G, 485212795Sdim * and B2 contains a bound of one of the forms alpha = S or S <: alpha, 486212795Sdim * where there exists no type of the form G<...> that is a 487218893Sdim * supertype of S, but the raw type G is a supertype of S 488218893Sdim */ 489218893Sdim if (to.isParameterized()) { 490234353Sdim for (Type t : from.getBounds(InferenceBound.EQ, InferenceBound.LOWER)) { 491263508Sdim Type sup = types.asSuper(t, to.tsym); 492263508Sdim if (sup != null && sup.isRaw()) { 493263508Sdim return true; 494263508Sdim } 495263508Sdim } 496263508Sdim } 497263508Sdim return false; 498263508Sdim } 499263508Sdim 500263508Sdim private boolean commonSuperWithDiffParameterization(Type t, Type s) { 501263508Sdim for (Pair<Type, Type> supers : getParameterizedSupers(t, s)) { 502263508Sdim if (!types.isSameType(supers.fst, supers.snd)) return true; 503263508Sdim } 504234353Sdim return false; 505234353Sdim } 506234353Sdim 507234353Sdim private Type generateReferenceToTargetConstraint(JCTree tree, UndetVar from, 508234353Sdim Type to, Attr.ResultInfo resultInfo, 509234353Sdim InferenceContext inferenceContext) { 510212795Sdim inferenceContext.solve(List.of(from.qtype), new Warner()); 511212795Sdim inferenceContext.notifyChange(); 512263508Sdim Type capturedType = resultInfo.checkContext.inferenceContext() 513263508Sdim .cachedCapture(tree, from.getInst(), false); 514263508Sdim if (types.isConvertible(capturedType, 515212795Sdim resultInfo.checkContext.inferenceContext().asUndetVar(to))) { 516212795Sdim //effectively skip additional return-type constraint generation (compatibility) 517212795Sdim return syms.objectType; 518249423Sdim } 519263508Sdim return to; 520212795Sdim } 521212795Sdim 522212795Sdim /** 523212795Sdim * Infer cyclic inference variables as described in 15.12.2.8. 524226633Sdim */ 525212795Sdim void instantiateAsUninferredVars(List<Type> vars, InferenceContext inferenceContext) { 526212795Sdim ListBuffer<Type> todo = new ListBuffer<>(); 527212795Sdim //step 1 - create fresh tvars 528212795Sdim for (Type t : vars) { 529212795Sdim UndetVar uv = (UndetVar)inferenceContext.asUndetVar(t); 530218893Sdim List<Type> upperBounds = uv.getBounds(InferenceBound.UPPER); 531212795Sdim if (Type.containsAny(upperBounds, vars)) { 532263508Sdim TypeSymbol fresh_tvar = new TypeVariableSymbol(Flags.SYNTHETIC, uv.qtype.tsym.name, null, uv.qtype.tsym.owner); 533212795Sdim fresh_tvar.type = new TypeVar(fresh_tvar, types.makeIntersectionType(uv.getBounds(InferenceBound.UPPER)), null); 534212795Sdim todo.append(uv); 535212795Sdim uv.setInst(fresh_tvar.type); 536212795Sdim } else if (upperBounds.nonEmpty()) { 537221345Sdim uv.setInst(types.glb(upperBounds)); 538218893Sdim } else { 539218893Sdim uv.setInst(syms.objectType); 540226633Sdim } 541218893Sdim } 542218893Sdim //step 2 - replace fresh tvars in their bounds 543223017Sdim List<Type> formals = vars; 544212795Sdim for (Type t : todo) { 545212795Sdim UndetVar uv = (UndetVar)t; 546212795Sdim TypeVar ct = (TypeVar)uv.getInst(); 547234353Sdim ct.bound = types.glb(inferenceContext.asInstTypes(types.getBounds(ct))); 548212795Sdim if (ct.bound.isErroneous()) { 549212795Sdim //report inference error if glb fails 550218893Sdim reportBoundError(uv, InferenceBound.UPPER); 551212795Sdim } 552234353Sdim formals = formals.tail; 553234353Sdim } 554234353Sdim } 555249423Sdim 556234353Sdim /** 557234353Sdim * Compute a synthetic method type corresponding to the requested polymorphic 558234353Sdim * method signature. The target return type is computed from the immediately 559234353Sdim * enclosing scope surrounding the polymorphic-signature call. 560234353Sdim */ 561234353Sdim Type instantiatePolymorphicSignatureInstance(Env<AttrContext> env, 562234353Sdim MethodSymbol spMethod, // sig. poly. method or null if none 563234353Sdim Resolve.MethodResolutionContext resolveContext, 564234353Sdim List<Type> argtypes) { 565234353Sdim final Type restype; 566234353Sdim 567234353Sdim if (spMethod == null || types.isSameType(spMethod.getReturnType(), syms.objectType, true)) { 568234353Sdim // The return type of the polymorphic signature is polymorphic, 569249423Sdim // and is computed from the enclosing tree E, as follows: 570263508Sdim // if E is a cast, then use the target type of the cast expression 571263508Sdim // as a return type; if E is an expression statement, the return 572234353Sdim // type is 'void'; otherwise 573234353Sdim // the return type is simply 'Object'. A correctness check ensures 574212795Sdim // that env.next refers to the lexically enclosing environment in 575212795Sdim // which the polymorphic signature call environment is nested. 576234353Sdim 577212795Sdim switch (env.next.tree.getTag()) { 578212795Sdim case TYPECAST: 579226633Sdim JCTypeCast castTree = (JCTypeCast)env.next.tree; 580226633Sdim restype = (TreeInfo.skipParens(castTree.expr) == env.tree) ? 581212795Sdim castTree.clazz.type : 582212795Sdim syms.objectType; 583226633Sdim break; 584212795Sdim case EXEC: 585218893Sdim JCTree.JCExpressionStatement execTree = 586226633Sdim (JCTree.JCExpressionStatement)env.next.tree; 587212795Sdim restype = (TreeInfo.skipParens(execTree.expr) == env.tree) ? 588212795Sdim syms.voidType : 589212795Sdim syms.objectType; 590212795Sdim break; 591226633Sdim default: 592226633Sdim restype = syms.objectType; 593212795Sdim } 594212795Sdim } else { 595212795Sdim // The return type of the polymorphic signature is fixed 596226633Sdim // (not polymorphic) 597218893Sdim restype = spMethod.getReturnType(); 598212795Sdim } 599212795Sdim 600226633Sdim List<Type> paramtypes = argtypes.map(new ImplicitArgType(spMethod, resolveContext.step)); 601212795Sdim List<Type> exType = spMethod != null ? 602226633Sdim spMethod.getThrownTypes() : 603226633Sdim List.of(syms.throwableType); // make it throw all exceptions 604212795Sdim 605212795Sdim MethodType mtype = new MethodType(paramtypes, 606212795Sdim restype, 607212795Sdim exType, 608218893Sdim syms.methodClass); 609212795Sdim return mtype; 610218893Sdim } 611218893Sdim //where 612212795Sdim class ImplicitArgType extends DeferredAttr.DeferredTypeMap { 613212795Sdim 614218893Sdim public ImplicitArgType(Symbol msym, Resolve.MethodResolutionPhase phase) { 615212795Sdim (rs.deferredAttr).super(AttrMode.SPECULATIVE, msym, phase); 616226633Sdim } 617218893Sdim 618218893Sdim @Override 619226633Sdim public Type visitClassType(ClassType t, Void aVoid) { 620218893Sdim return types.erasure(t); 621226633Sdim } 622218893Sdim 623218893Sdim @Override 624218893Sdim public Type visitType(Type t, Void _unused) { 625226633Sdim if (t.hasTag(DEFERRED)) { 626226633Sdim return visit(super.visitType(t, null)); 627218893Sdim } else if (t.hasTag(BOT)) 628218893Sdim // nulls type as the marker type Null (which has no instances) 629218893Sdim // infer as java.lang.Void for now 630218893Sdim t = types.boxedClass(syms.voidType).type; 631218893Sdim return t; 632218893Sdim } 633226633Sdim } 634218893Sdim 635218893Sdim TypeMapping<Void> fromTypeVarFun = new TypeMapping<Void>() { 636218893Sdim @Override 637218893Sdim public Type visitTypeVar(TypeVar tv, Void aVoid) { 638218893Sdim return new UndetVar(tv, incorporationEngine(), types); 639218893Sdim } 640218893Sdim 641218893Sdim @Override 642218893Sdim public Type visitCapturedType(CapturedType t, Void aVoid) { 643263508Sdim return new CapturedUndetVar(t, incorporationEngine(), types); 644263508Sdim } 645243830Sdim }; 646263508Sdim 647263508Sdim /** 648263508Sdim * This method is used to infer a suitable target SAM in case the original 649263508Sdim * SAM type contains one or more wildcards. An inference process is applied 650263508Sdim * so that wildcard bounds, as well as explicit lambda/method ref parameters 651263508Sdim * (where applicable) are used to constraint the solution. 652263508Sdim */ 653218893Sdim public Type instantiateFunctionalInterface(DiagnosticPosition pos, Type funcInterface, 654212795Sdim List<Type> paramTypes, Check.CheckContext checkContext) { 655212795Sdim if (types.capture(funcInterface) == funcInterface) { 656212795Sdim //if capture doesn't change the type then return the target unchanged 657212795Sdim //(this means the target contains no wildcards!) 658212795Sdim return funcInterface; 659212795Sdim } else { 660212795Sdim Type formalInterface = funcInterface.tsym.type; 661226633Sdim InferenceContext funcInterfaceContext = 662212795Sdim new InferenceContext(this, funcInterface.tsym.type.getTypeArguments()); 663212795Sdim 664212795Sdim Assert.check(paramTypes != null); 665212795Sdim //get constraints from explicit params (this is done by 666212795Sdim //checking that explicit param types are equal to the ones 667218893Sdim //in the functional interface descriptors) 668218893Sdim List<Type> descParameterTypes = types.findDescriptorType(formalInterface).getParameterTypes(); 669218893Sdim if (descParameterTypes.size() != paramTypes.size()) { 670212795Sdim checkContext.report(pos, diags.fragment("incompatible.arg.types.in.lambda")); 671226633Sdim return types.createErrorType(funcInterface); 672212795Sdim } 673212795Sdim for (Type p : descParameterTypes) { 674212795Sdim if (!types.isSameType(funcInterfaceContext.asUndetVar(p), paramTypes.head)) { 675212795Sdim checkContext.report(pos, diags.fragment("no.suitable.functional.intf.inst", funcInterface)); 676212795Sdim return types.createErrorType(funcInterface); 677212795Sdim } 678212795Sdim paramTypes = paramTypes.tail; 679226633Sdim } 680212795Sdim 681212795Sdim List<Type> actualTypeargs = funcInterface.getTypeArguments(); 682226633Sdim for (Type t : funcInterfaceContext.undetvars) { 683226633Sdim UndetVar uv = (UndetVar)t; 684212795Sdim Optional<Type> inst = uv.getBounds(InferenceBound.EQ).stream() 685212795Sdim .filter(b -> !b.containsAny(formalInterface.getTypeArguments())).findFirst(); 686212795Sdim uv.setInst(inst.orElse(actualTypeargs.head)); 687212795Sdim actualTypeargs = actualTypeargs.tail; 688212795Sdim } 689243830Sdim 690243830Sdim Type owntype = funcInterfaceContext.asInstType(formalInterface); 691243830Sdim if (!chk.checkValidGenericType(owntype)) { 692243830Sdim //if the inferred functional interface type is not well-formed, 693226633Sdim //or if it's not a subtype of the original target, issue an error 694226633Sdim checkContext.report(pos, diags.fragment("no.suitable.functional.intf.inst", funcInterface)); 695212795Sdim } 696212795Sdim //propagate constraints as per JLS 18.2.1 697212795Sdim checkContext.compatible(owntype, funcInterface, types.noWarnings); 698243830Sdim return owntype; 699212795Sdim } 700239462Sdim } 701249423Sdim // </editor-fold> 702226633Sdim 703226633Sdim // <editor-fold defaultstate="collapsed" desc="Incorporation"> 704226633Sdim 705226633Sdim /** 706226633Sdim * This class is the root of all incorporation actions. 707226633Sdim */ 708226633Sdim public abstract class IncorporationAction { 709212795Sdim UndetVar uv; 710212795Sdim Type t; 711223017Sdim 712226633Sdim IncorporationAction(UndetVar uv, Type t) { 713218893Sdim this.uv = uv; 714239462Sdim this.t = t; 715212795Sdim } 716226633Sdim 717212795Sdim public abstract IncorporationAction dup(UndetVar that); 718212795Sdim 719226633Sdim /** 720226633Sdim * Incorporation action entry-point. Subclasses should define the logic associated with 721226633Sdim * this incorporation action. 722226633Sdim */ 723226633Sdim abstract void apply(InferenceContext ic, Warner warn); 724226633Sdim 725226633Sdim /** 726226633Sdim * Helper function: perform subtyping through incorporation cache. 727226633Sdim */ 728226633Sdim boolean isSubtype(Type s, Type t, Warner warn) { 729212795Sdim return doIncorporationOp(IncorporationBinaryOpKind.IS_SUBTYPE, s, t, warn); 730212795Sdim } 731212795Sdim 732212795Sdim /** 733226633Sdim * Helper function: perform type-equivalence through incorporation cache. 734226633Sdim */ 735212795Sdim boolean isSameType(Type s, Type t) { 736212795Sdim return doIncorporationOp(IncorporationBinaryOpKind.IS_SAME_TYPE, s, t, null); 737212795Sdim } 738234353Sdim 739212795Sdim @Override 740234353Sdim public String toString() { 741234353Sdim return String.format("%s[undet=%s,t=%s]", getClass().getSimpleName(), uv.qtype, t); 742212795Sdim } 743234353Sdim } 744234353Sdim 745234353Sdim /** 746234353Sdim * Bound-check incorporation action. A newly added bound is checked against existing bounds, 747234353Sdim * to verify its compatibility; each bound is checked using either subtyping or type equivalence. 748234353Sdim */ 749234353Sdim class CheckBounds extends IncorporationAction { 750234353Sdim 751234353Sdim InferenceBound from; 752234353Sdim BiFunction<InferenceContext, Type, Type> typeFunc; 753234353Sdim BiPredicate<InferenceContext, Type> optFilter; 754234353Sdim 755234353Sdim CheckBounds(UndetVar uv, Type t, InferenceBound from) { 756234353Sdim this(uv, t, InferenceContext::asUndetVar, null, from); 757234353Sdim } 758234353Sdim 759234353Sdim CheckBounds(UndetVar uv, Type t, BiFunction<InferenceContext, Type, Type> typeFunc, 760234353Sdim BiPredicate<InferenceContext, Type> typeFilter, InferenceBound from) { 761234353Sdim super(uv, t); 762234353Sdim this.from = from; 763234353Sdim this.typeFunc = typeFunc; 764234353Sdim this.optFilter = typeFilter; 765234353Sdim } 766234353Sdim 767234353Sdim @Override 768234353Sdim public IncorporationAction dup(UndetVar that) { 769234353Sdim return new CheckBounds(that, t, typeFunc, optFilter, from); 770234353Sdim } 771212795Sdim 772234353Sdim @Override 773234353Sdim void apply(InferenceContext inferenceContext, Warner warn) { 774234353Sdim t = typeFunc.apply(inferenceContext, t); 775234353Sdim if (optFilter != null && optFilter.test(inferenceContext, t)) return; 776234353Sdim for (InferenceBound to : boundsToCheck()) { 777234353Sdim for (Type b : uv.getBounds(to)) { 778234353Sdim b = typeFunc.apply(inferenceContext, b); 779234353Sdim if (optFilter != null && optFilter.test(inferenceContext, b)) continue; 780212795Sdim boolean success = checkBound(t, b, from, to, warn); 781234353Sdim if (!success) { 782234353Sdim report(from, to); 783234353Sdim } 784234353Sdim } 785234353Sdim } 786234353Sdim } 787234353Sdim 788234353Sdim /** 789234353Sdim * The list of bound kinds to be checked. 790234353Sdim */ 791234353Sdim EnumSet<InferenceBound> boundsToCheck() { 792212795Sdim return (from == InferenceBound.EQ) ? 793212795Sdim EnumSet.allOf(InferenceBound.class) : 794212795Sdim EnumSet.complementOf(EnumSet.of(from)); 795212795Sdim } 796212795Sdim 797212795Sdim /** 798212795Sdim * Is source type 's' compatible with target type 't' given source and target bound kinds? 799212795Sdim */ 800212795Sdim boolean checkBound(Type s, Type t, InferenceBound ib_s, InferenceBound ib_t, Warner warn) { 801263508Sdim if (ib_s.lessThan(ib_t)) { 802263508Sdim return isSubtype(s, t, warn); 803212795Sdim } else if (ib_t.lessThan(ib_s)) { 804212795Sdim return isSubtype(t, s, warn); 805212795Sdim } else { 806234353Sdim return isSameType(s, t); 807212795Sdim } 808234353Sdim } 809234353Sdim 810234353Sdim /** 811234353Sdim * Report a bound check error. 812234353Sdim */ 813234353Sdim void report(InferenceBound from, InferenceBound to) { 814234353Sdim //this is a workaround to preserve compatibility with existing messages 815234353Sdim if (from == to) { 816234353Sdim reportBoundError(uv, from); 817234353Sdim } else if (from == InferenceBound.LOWER || to == InferenceBound.EQ) { 818234353Sdim reportBoundError(uv, to, from); 819234353Sdim } else { 820234353Sdim reportBoundError(uv, from, to); 821234353Sdim } 822234353Sdim } 823234353Sdim 824234353Sdim @Override 825234353Sdim public String toString() { 826234353Sdim return String.format("%s[undet=%s,t=%s,bound=%s]", getClass().getSimpleName(), uv.qtype, t, from); 827234353Sdim } 828234353Sdim } 829234353Sdim 830234353Sdim /** 831234353Sdim * Custom check executed by the legacy incorporation engine. Newly added bounds are checked 832234353Sdim * against existing eq bounds. 833234353Sdim */ 834234353Sdim class EqCheckLegacy extends CheckBounds { 835212795Sdim EqCheckLegacy(UndetVar uv, Type t, InferenceBound from) { 836212795Sdim super(uv, t, InferenceContext::asInstType, InferenceContext::free, from); 837212795Sdim } 838212795Sdim 839212795Sdim @Override 840212795Sdim public IncorporationAction dup(UndetVar that) { 841212795Sdim return new EqCheckLegacy(that, t, from); 842212795Sdim } 843234353Sdim 844234353Sdim @Override 845234353Sdim EnumSet<InferenceBound> boundsToCheck() { 846234353Sdim return (from == InferenceBound.EQ) ? 847234353Sdim EnumSet.allOf(InferenceBound.class) : 848234353Sdim EnumSet.of(InferenceBound.EQ); 849234353Sdim } 850234353Sdim } 851234353Sdim 852226633Sdim /** 853212795Sdim * Check that the inferred type conforms to all bounds. 854226633Sdim */ 855212795Sdim class CheckInst extends CheckBounds { 856212795Sdim 857226633Sdim EnumSet<InferenceBound> to; 858226633Sdim 859212795Sdim CheckInst(UndetVar uv, InferenceBound ib, InferenceBound... rest) { 860212795Sdim this(uv, EnumSet.of(ib, rest)); 861218893Sdim } 862212795Sdim 863226633Sdim CheckInst(UndetVar uv, EnumSet<InferenceBound> to) { 864212795Sdim super(uv, uv.getInst(), InferenceBound.EQ); 865212795Sdim this.to = to; 866212795Sdim } 867212795Sdim 868226633Sdim @Override 869212795Sdim public IncorporationAction dup(UndetVar that) { 870212795Sdim return new CheckInst(that, to); 871212795Sdim } 872212795Sdim 873218893Sdim @Override 874234353Sdim EnumSet<InferenceBound> boundsToCheck() { 875218893Sdim return to; 876212795Sdim } 877212795Sdim 878212795Sdim @Override 879212795Sdim void report(InferenceBound from, InferenceBound to) { 880212795Sdim reportInstError(uv, to); 881212795Sdim } 882212795Sdim } 883212795Sdim 884226633Sdim /** 885226633Sdim * Replace undetvars in bounds and check that the inferred type conforms to all bounds. 886226633Sdim */ 887226633Sdim class SubstBounds extends CheckInst { 888226633Sdim SubstBounds(UndetVar uv) { 889212795Sdim super(uv, InferenceBound.LOWER, InferenceBound.EQ, InferenceBound.UPPER); 890212795Sdim } 891212795Sdim 892212795Sdim @Override 893226633Sdim public IncorporationAction dup(UndetVar that) { 894212795Sdim return new SubstBounds(that); 895212795Sdim } 896212795Sdim 897212795Sdim @Override 898226633Sdim void apply(InferenceContext inferenceContext, Warner warn) { 899234353Sdim for (Type undet : inferenceContext.undetvars) { 900212795Sdim //we could filter out variables not mentioning uv2... 901212795Sdim UndetVar uv2 = (UndetVar)undet; 902212795Sdim uv2.substBounds(List.of(uv.qtype), List.of(uv.getInst()), types); 903212795Sdim checkCompatibleUpperBounds(uv2, inferenceContext); 904226633Sdim } 905251662Sdim super.apply(inferenceContext, warn); 906234353Sdim } 907234353Sdim 908243830Sdim /** 909243830Sdim * Make sure that the upper bounds we got so far lead to a solvable inference 910212795Sdim * variable by making sure that a glb exists. 911218893Sdim */ 912212795Sdim void checkCompatibleUpperBounds(UndetVar uv, InferenceContext inferenceContext) { 913212795Sdim List<Type> hibounds = 914212795Sdim Type.filter(uv.getBounds(InferenceBound.UPPER), new BoundFilter(inferenceContext)); 915212795Sdim final Type hb; 916212795Sdim if (hibounds.isEmpty()) 917218893Sdim hb = syms.objectType; 918226633Sdim else if (hibounds.tail.isEmpty()) 919226633Sdim hb = hibounds.head; 920218893Sdim else 921218893Sdim hb = types.glb(hibounds); 922218893Sdim if (hb == null || hb.isErroneous()) 923212795Sdim reportBoundError(uv, InferenceBound.UPPER); 924212795Sdim } 925212795Sdim } 926212795Sdim 927239462Sdim /** 928239462Sdim * Perform pairwise comparison between common generic supertypes of two upper bounds. 929239462Sdim */ 930239462Sdim class CheckUpperBounds extends IncorporationAction { 931239462Sdim 932212795Sdim public CheckUpperBounds(UndetVar uv, Type t) { 933226633Sdim super(uv, t); 934226633Sdim } 935212795Sdim 936263508Sdim @Override 937212795Sdim public IncorporationAction dup(UndetVar that) { 938212795Sdim return new CheckUpperBounds(that, t); 939251662Sdim } 940251662Sdim 941251662Sdim @Override 942251662Sdim void apply(InferenceContext inferenceContext, Warner warn) { 943251662Sdim List<Type> boundList = uv.getBounds(InferenceBound.UPPER).stream() 944251662Sdim .collect(types.closureCollector(true, types::isSameType)); 945218893Sdim for (Type b2 : boundList) { 946218893Sdim if (t == b2) continue; 947218893Sdim /* This wildcard check is temporary workaround. This code may need to be 948218893Sdim * revisited once spec bug JDK-7034922 is fixed. 949218893Sdim */ 950226633Sdim if (t != b2 && !t.hasTag(WILDCARD) && !b2.hasTag(WILDCARD)) { 951218893Sdim for (Pair<Type, Type> commonSupers : getParameterizedSupers(t, b2)) { 952218893Sdim List<Type> allParamsSuperBound1 = commonSupers.fst.allparams(); 953226633Sdim List<Type> allParamsSuperBound2 = commonSupers.snd.allparams(); 954218893Sdim while (allParamsSuperBound1.nonEmpty() && allParamsSuperBound2.nonEmpty()) { 955218893Sdim //traverse the list of all params comparing them 956263508Sdim if (!allParamsSuperBound1.head.hasTag(WILDCARD) && 957234353Sdim !allParamsSuperBound2.head.hasTag(WILDCARD)) { 958212795Sdim if (!isSameType(inferenceContext.asUndetVar(allParamsSuperBound1.head), 959249423Sdim inferenceContext.asUndetVar(allParamsSuperBound2.head))) { 960221345Sdim reportBoundError(uv, InferenceBound.UPPER); 961251662Sdim } 962234353Sdim } 963221345Sdim allParamsSuperBound1 = allParamsSuperBound1.tail; 964221345Sdim allParamsSuperBound2 = allParamsSuperBound2.tail; 965221345Sdim } 966224145Sdim Assert.check(allParamsSuperBound1.isEmpty() && allParamsSuperBound2.isEmpty()); 967243830Sdim } 968263508Sdim } 969263508Sdim } 970263508Sdim } 971263508Sdim } 972263508Sdim 973263508Sdim /** 974278788Sdim * Perform propagation of bounds. Given a constraint of the kind {@code alpha <: T}, three 975263508Sdim * kind of propagation occur: 976263508Sdim * 977263508Sdim * <li>T is copied into all matching bounds (i.e. lower/eq bounds) B of alpha such that B=beta (forward propagation)</li> 978234353Sdim * <li>if T=beta, matching bounds (i.e. upper bounds) of beta are copied into alpha (backwards propagation)</li> 979263508Sdim * <li>if T=beta, sets a symmetric bound on beta (i.e. beta :> alpha) (symmetric propagation) </li> 980234353Sdim */ 981234353Sdim class PropagateBounds extends IncorporationAction { 982234353Sdim 983218893Sdim InferenceBound ib; 984234353Sdim 985234353Sdim public PropagateBounds(UndetVar uv, Type t, InferenceBound ib) { 986234353Sdim super(uv, t); 987234353Sdim this.ib = ib; 988234353Sdim } 989234353Sdim 990212795Sdim @Override 991263508Sdim public IncorporationAction dup(UndetVar that) { 992263508Sdim return new PropagateBounds(that, t, ib); 993263508Sdim } 994263508Sdim 995263508Sdim void apply(InferenceContext inferenceContext, Warner warner) { 996263508Sdim Type undetT = inferenceContext.asUndetVar(t); 997263508Sdim if (undetT.hasTag(UNDETVAR) && !((UndetVar)undetT).isCaptured()) { 998263508Sdim UndetVar uv2 = (UndetVar)undetT; 999263508Sdim //symmetric propagation 1000263508Sdim uv2.addBound(ib.complement(), uv, types); 1001226633Sdim //backwards propagation 1002212795Sdim for (InferenceBound ib2 : backwards()) { 1003218893Sdim for (Type b : uv2.getBounds(ib2)) { 1004226633Sdim uv.addBound(ib2, b, types); 1005263508Sdim } 1006212795Sdim } 1007263508Sdim } 1008263508Sdim //forward propagation 1009263508Sdim for (InferenceBound ib2 : forward()) { 1010212795Sdim for (Type l : uv.getBounds(ib2)) { 1011212795Sdim Type undet = inferenceContext.asUndetVar(l); 1012212795Sdim if (undet.hasTag(TypeTag.UNDETVAR) && !((UndetVar)undet).isCaptured()) { 1013212795Sdim UndetVar uv2 = (UndetVar)undet; 1014212795Sdim uv2.addBound(ib, inferenceContext.asInstType(t), types); 1015212795Sdim } 1016212795Sdim } 1017212795Sdim } 1018221345Sdim } 1019221345Sdim 1020221345Sdim EnumSet<InferenceBound> forward() { 1021221345Sdim return (ib == InferenceBound.EQ) ? 1022221345Sdim EnumSet.of(InferenceBound.EQ) : EnumSet.complementOf(EnumSet.of(ib)); 1023221345Sdim } 1024221345Sdim 1025221345Sdim EnumSet<InferenceBound> backwards() { 1026221345Sdim return (ib == InferenceBound.EQ) ? 1027221345Sdim EnumSet.allOf(InferenceBound.class) : EnumSet.of(ib); 1028221345Sdim } 1029221345Sdim 1030221345Sdim @Override 1031212795Sdim public String toString() { 1032218893Sdim return String.format("%s[undet=%s,t=%s,bound=%s]", getClass().getSimpleName(), uv.qtype, t, ib); 1033263508Sdim } 1034263508Sdim } 1035263508Sdim 1036212795Sdim /** 1037212795Sdim * This class models an incorporation engine. The engine is responsible for listening to 1038212795Sdim * changes in inference variables and register incorporation actions accordingly. 1039212795Sdim */ 1040218893Sdim abstract class AbstractIncorporationEngine implements UndetVarListener { 1041221345Sdim 1042212795Sdim @Override 1043212795Sdim public void varInstantiated(UndetVar uv) { 1044212795Sdim uv.incorporationActions.addFirst(new SubstBounds(uv)); 1045212795Sdim } 1046218893Sdim 1047218893Sdim @Override 1048212795Sdim public void varBoundChanged(UndetVar uv, InferenceBound ib, Type bound, boolean update) { 1049226633Sdim if (uv.isCaptured()) return; 1050212795Sdim uv.incorporationActions.addAll(getIncorporationActions(uv, ib, bound, update)); 1051212795Sdim } 1052226633Sdim 1053226633Sdim abstract List<IncorporationAction> getIncorporationActions(UndetVar uv, InferenceBound ib, Type t, boolean update); 1054218893Sdim } 1055234982Sdim 1056234982Sdim /** 1057234982Sdim * A legacy incorporation engine. Used for source <= 7. 1058234982Sdim */ 1059218893Sdim AbstractIncorporationEngine legacyEngine = new AbstractIncorporationEngine() { 1060218893Sdim 1061226633Sdim List<IncorporationAction> getIncorporationActions(UndetVar uv, InferenceBound ib, Type t, boolean update) { 1062218893Sdim ListBuffer<IncorporationAction> actions = new ListBuffer<>(); 1063218893Sdim Type inst = uv.getInst(); 1064226633Sdim if (inst != null) { 1065218893Sdim actions.add(new CheckInst(uv, ib)); 1066218893Sdim } 1067218893Sdim actions.add(new EqCheckLegacy(uv, t, ib)); 1068218893Sdim return actions.toList(); 1069218893Sdim } 1070218893Sdim }; 1071218893Sdim 1072226633Sdim /** 1073218893Sdim * The standard incorporation engine. Used for source >= 8. 1074212795Sdim */ 1075212795Sdim AbstractIncorporationEngine graphEngine = new AbstractIncorporationEngine() { 1076251662Sdim 1077251662Sdim @Override 1078251662Sdim List<IncorporationAction> getIncorporationActions(UndetVar uv, InferenceBound ib, Type t, boolean update) { 1079251662Sdim ListBuffer<IncorporationAction> actions = new ListBuffer<>(); 1080251662Sdim Type inst = uv.getInst(); 1081251662Sdim if (inst != null) { 1082251662Sdim actions.add(new CheckInst(uv, ib)); 1083212795Sdim } 1084212795Sdim actions.add(new CheckBounds(uv, t, ib)); 1085212795Sdim 1086221345Sdim if (update) { 1087221345Sdim return actions.toList(); 1088212795Sdim } 1089212795Sdim 1090218893Sdim if (ib == InferenceBound.UPPER) { 1091218893Sdim actions.add(new CheckUpperBounds(uv, t)); 1092221345Sdim } 1093218893Sdim 1094218893Sdim actions.add(new PropagateBounds(uv, t, ib)); 1095218893Sdim 1096212795Sdim return actions.toList(); 1097234353Sdim } 1098212795Sdim }; 1099234353Sdim 1100221345Sdim /** 1101221345Sdim * Get the incorporation engine to be used in this compilation. 1102263508Sdim */ 1103234353Sdim AbstractIncorporationEngine incorporationEngine() { 1104212795Sdim return allowGraphInference ? graphEngine : legacyEngine; 1105234353Sdim } 1106234353Sdim 1107234353Sdim /** max number of incorporation rounds. */ 1108234353Sdim static final int MAX_INCORPORATION_STEPS = 10000; 1109234353Sdim 1110234353Sdim /** 1111234353Sdim * Check bounds and perform incorporation. 1112234353Sdim */ 1113234353Sdim void doIncorporation(InferenceContext inferenceContext, Warner warn) throws InferenceException { 1114234353Sdim try { 1115263508Sdim boolean progress = true; 1116234353Sdim int round = 0; 1117212795Sdim while (progress && round < MAX_INCORPORATION_STEPS) { 1118212795Sdim progress = false; 1119212795Sdim for (Type t : inferenceContext.undetvars) { 1120212795Sdim UndetVar uv = (UndetVar)t; 1121218893Sdim if (!uv.incorporationActions.isEmpty()) { 1122218893Sdim progress = true; 1123219077Sdim uv.incorporationActions.removeFirst().apply(inferenceContext, warn); 1124226633Sdim } 1125212795Sdim } 1126212795Sdim round++; 1127212795Sdim } 1128212795Sdim } finally { 1129263508Sdim incorporationCache.clear(); 1130219077Sdim } 1131218893Sdim } 1132234353Sdim 1133263508Sdim /* If for two types t and s there is a least upper bound that contains 1134226633Sdim * parameterized types G1, G2 ... Gn, then there exists supertypes of 't' of the form 1135226633Sdim * G1<T1, ..., Tn>, G2<T1, ..., Tn>, ... Gn<T1, ..., Tn> and supertypes of 's' of the form 1136212795Sdim * G1<S1, ..., Sn>, G2<S1, ..., Sn>, ... Gn<S1, ..., Sn> which will be returned by this method. 1137212795Sdim * If no such common supertypes exists then an empty list is returned. 1138212795Sdim * 1139263508Sdim * As an example for the following input: 1140212795Sdim * 1141226633Sdim * t = java.util.ArrayList<java.lang.String> 1142226633Sdim * s = java.util.List<T> 1143226633Sdim * 1144212795Sdim * we get this ouput (singleton list): 1145226633Sdim * 1146263508Sdim * [Pair[java.util.List<java.lang.String>,java.util.List<T>]] 1147212795Sdim */ 1148212795Sdim private List<Pair<Type, Type>> getParameterizedSupers(Type t, Type s) { 1149212795Sdim Type lubResult = types.lub(t, s); 1150212795Sdim if (lubResult == syms.errType || lubResult == syms.botType) { 1151218893Sdim return List.nil(); 1152218893Sdim } 1153219077Sdim List<Type> supertypesToCheck = lubResult.isIntersection() ? 1154226633Sdim ((IntersectionClassType)lubResult).getComponents() : 1155226633Sdim List.of(lubResult); 1156212795Sdim ListBuffer<Pair<Type, Type>> commonSupertypes = new ListBuffer<>(); 1157212795Sdim for (Type sup : supertypesToCheck) { 1158212795Sdim if (sup.isParameterized()) { 1159212795Sdim Type asSuperOfT = asSuper(t, sup); 1160218893Sdim Type asSuperOfS = asSuper(s, sup); 1161219077Sdim commonSupertypes.add(new Pair<>(asSuperOfT, asSuperOfS)); 1162218893Sdim } 1163212795Sdim } 1164212795Sdim return commonSupertypes.toList(); 1165212795Sdim } 1166212795Sdim //where 1167212795Sdim private Type asSuper(Type t, Type sup) { 1168218893Sdim return (sup.hasTag(ARRAY)) ? 1169219077Sdim new ArrayType(asSuper(types.elemtype(t), types.elemtype(sup)), syms.arrayClass) : 1170212795Sdim types.asSuper(t, sup.tsym); 1171212795Sdim } 1172218893Sdim 1173218893Sdim boolean doIncorporationOp(IncorporationBinaryOpKind opKind, Type op1, Type op2, Warner warn) { 1174218893Sdim IncorporationBinaryOp newOp = new IncorporationBinaryOp(opKind, op1, op2); 1175234353Sdim Boolean res = incorporationCache.get(newOp); 1176218893Sdim if (res == null) { 1177249423Sdim incorporationCache.put(newOp, res = newOp.apply(warn)); 1178218893Sdim } 1179218893Sdim return res; 1180218893Sdim } 1181218893Sdim 1182218893Sdim /** 1183221345Sdim * Three kinds of basic operation are supported as part of an incorporation step: 1184221345Sdim * (i) subtype check, (ii) same type check and (iii) bound addition (either 1185221345Sdim * upper/lower/eq bound). 1186221345Sdim */ 1187221345Sdim enum IncorporationBinaryOpKind { 1188223017Sdim IS_SUBTYPE() { 1189234353Sdim @Override 1190239462Sdim boolean apply(Type op1, Type op2, Warner warn, Types types) { 1191249423Sdim return types.isSubtypeUnchecked(op1, op2, warn); 1192249423Sdim } 1193249423Sdim }, 1194249423Sdim IS_SAME_TYPE() { 1195249423Sdim @Override 1196249423Sdim boolean apply(Type op1, Type op2, Warner warn, Types types) { 1197249423Sdim return types.isSameType(op1, op2); 1198249423Sdim } 1199249423Sdim }; 1200226633Sdim 1201234353Sdim abstract boolean apply(Type op1, Type op2, Warner warn, Types types); 1202234353Sdim } 1203221345Sdim 1204218893Sdim /** 1205223017Sdim * This class encapsulates a basic incorporation operation; incorporation 1206249423Sdim * operations takes two type operands and a kind. Each operation performed 1207249423Sdim * during an incorporation round is stored in a cache, so that operations 1208249423Sdim * are not executed unnecessarily (which would potentially lead to adding 1209249423Sdim * same bounds over and over). 1210249423Sdim */ 1211218893Sdim class IncorporationBinaryOp { 1212218893Sdim 1213218893Sdim IncorporationBinaryOpKind opKind; 1214226633Sdim Type op1; 1215218893Sdim Type op2; 1216218893Sdim 1217226633Sdim IncorporationBinaryOp(IncorporationBinaryOpKind opKind, Type op1, Type op2) { 1218218893Sdim this.opKind = opKind; 1219226633Sdim this.op1 = op1; 1220226633Sdim this.op2 = op2; 1221218893Sdim } 1222263508Sdim 1223263508Sdim @Override 1224234353Sdim public boolean equals(Object o) { 1225234353Sdim if (!(o instanceof IncorporationBinaryOp)) { 1226234353Sdim return false; 1227234353Sdim } else { 1228234353Sdim IncorporationBinaryOp that = (IncorporationBinaryOp)o; 1229263508Sdim return opKind == that.opKind && 1230263508Sdim types.isSameType(op1, that.op1, true) && 1231234353Sdim types.isSameType(op2, that.op2, true); 1232234353Sdim } 1233234353Sdim } 1234234353Sdim 1235234353Sdim @Override 1236234353Sdim public int hashCode() { 1237234353Sdim int result = opKind.hashCode(); 1238243830Sdim result *= 127; 1239234353Sdim result += types.hashCode(op1); 1240234353Sdim result *= 127; 1241234353Sdim result += types.hashCode(op2); 1242234353Sdim return result; 1243263508Sdim } 1244263508Sdim 1245263508Sdim boolean apply(Warner warn) { 1246263508Sdim return opKind.apply(op1, op2, warn, types); 1247263508Sdim } 1248263508Sdim } 1249263508Sdim 1250263508Sdim /** an incorporation cache keeps track of all executed incorporation-related operations */ 1251263508Sdim Map<IncorporationBinaryOp, Boolean> incorporationCache = new HashMap<>(); 1252263508Sdim 1253263508Sdim protected static class BoundFilter implements Filter<Type> { 1254218893Sdim 1255212795Sdim InferenceContext inferenceContext; 1256218893Sdim 1257212795Sdim public BoundFilter(InferenceContext inferenceContext) { 1258263508Sdim this.inferenceContext = inferenceContext; 1259263508Sdim } 1260263508Sdim 1261212795Sdim @Override 1262226633Sdim public boolean accepts(Type t) { 1263263508Sdim return !t.isErroneous() && !inferenceContext.free(t) && 1264263508Sdim !t.hasTag(BOT); 1265234353Sdim } 1266234353Sdim } 1267234353Sdim 1268234353Sdim /** 1269243830Sdim * Incorporation error: mismatch between inferred type and given bound. 1270263508Sdim */ 1271263508Sdim void reportInstError(UndetVar uv, InferenceBound ib) { 1272234353Sdim reportInferenceError( 1273234353Sdim String.format("inferred.do.not.conform.to.%s.bounds", StringUtils.toLowerCase(ib.name())), 1274263508Sdim uv.getInst(), 1275263508Sdim uv.getBounds(ib)); 1276263508Sdim } 1277234353Sdim 1278234353Sdim /** 1279263508Sdim * Incorporation error: mismatch between two (or more) bounds of same kind. 1280263508Sdim */ 1281263508Sdim void reportBoundError(UndetVar uv, InferenceBound ib) { 1282263508Sdim reportInferenceError( 1283263508Sdim String.format("incompatible.%s.bounds", StringUtils.toLowerCase(ib.name())), 1284263508Sdim uv.qtype, 1285263508Sdim uv.getBounds(ib)); 1286263508Sdim } 1287263508Sdim 1288263508Sdim /** 1289263508Sdim * Incorporation error: mismatch between two (or more) bounds of different kinds. 1290263508Sdim */ 1291263508Sdim void reportBoundError(UndetVar uv, InferenceBound ib1, InferenceBound ib2) { 1292263508Sdim reportInferenceError( 1293263508Sdim String.format("incompatible.%s.%s.bounds", 1294263508Sdim StringUtils.toLowerCase(ib1.name()), 1295263508Sdim StringUtils.toLowerCase(ib2.name())), 1296263508Sdim uv.qtype, 1297263508Sdim uv.getBounds(ib1), 1298263508Sdim uv.getBounds(ib2)); 1299234353Sdim } 1300234353Sdim 1301263508Sdim /** 1302234353Sdim * Helper method: reports an inference error. 1303212795Sdim */ 1304212795Sdim void reportInferenceError(String key, Object... args) { 1305212795Sdim throw inferenceException.setMessage(key, args); 1306212795Sdim } 1307212795Sdim // </editor-fold> 1308212795Sdim 1309212795Sdim // <editor-fold defaultstate="collapsed" desc="Inference engine"> 1310212795Sdim /** 1311226633Sdim * Graph inference strategy - act as an input to the inference solver; a strategy is 1312212795Sdim * composed of two ingredients: (i) find a node to solve in the inference graph, 1313212795Sdim * and (ii) tell th engine when we are done fixing inference variables 1314226633Sdim */ 1315212795Sdim interface GraphStrategy { 1316218893Sdim 1317218893Sdim /** 1318218893Sdim * A NodeNotFoundException is thrown whenever an inference strategy fails 1319218893Sdim * to pick the next node to solve in the inference graph. 1320212795Sdim */ 1321212795Sdim public static class NodeNotFoundException extends RuntimeException { 1322212795Sdim private static final long serialVersionUID = 0; 1323218893Sdim 1324263508Sdim InferenceGraph graph; 1325218893Sdim 1326263508Sdim public NodeNotFoundException(InferenceGraph graph) { 1327263508Sdim this.graph = graph; 1328263508Sdim } 1329263508Sdim } 1330218893Sdim /** 1331263508Sdim * Pick the next node (leaf) to solve in the graph 1332263508Sdim */ 1333212795Sdim Node pickNode(InferenceGraph g) throws NodeNotFoundException; 1334212795Sdim /** 1335212795Sdim * Is this the last step? 1336212795Sdim */ 1337212795Sdim boolean done(); 1338212795Sdim } 1339212795Sdim 1340212795Sdim /** 1341226633Sdim * Simple solver strategy class that locates all leaves inside a graph 1342226633Sdim * and picks the first leaf as the next node to solve 1343212795Sdim */ 1344212795Sdim abstract class LeafSolver implements GraphStrategy { 1345212795Sdim public Node pickNode(InferenceGraph g) { 1346212795Sdim if (g.nodes.isEmpty()) { 1347212795Sdim //should not happen 1348212795Sdim throw new NodeNotFoundException(g); 1349212795Sdim } 1350218893Sdim return g.nodes.get(0); 1351218893Sdim } 1352212795Sdim } 1353212795Sdim 1354212795Sdim /** 1355212795Sdim * This solver uses an heuristic to pick the best leaf - the heuristic 1356212795Sdim * tries to select the node that has maximal probability to contain one 1357226633Sdim * or more inference variables in a given list 1358212795Sdim */ 1359212795Sdim abstract class BestLeafSolver extends LeafSolver { 1360212795Sdim 1361212795Sdim /** list of ivars of which at least one must be solved */ 1362212795Sdim List<Type> varsToSolve; 1363212795Sdim 1364212795Sdim BestLeafSolver(List<Type> varsToSolve) { 1365234353Sdim this.varsToSolve = varsToSolve; 1366234353Sdim } 1367234353Sdim 1368234353Sdim /** 1369234353Sdim * Computes a path that goes from a given node to the leafs in the graph. 1370234353Sdim * Typically this will start from a node containing a variable in 1371234353Sdim * {@code varsToSolve}. For any given path, the cost is computed as the total 1372243830Sdim * number of type-variables that should be eagerly instantiated across that path. 1373234353Sdim */ 1374234353Sdim Pair<List<Node>, Integer> computeTreeToLeafs(Node n) { 1375212795Sdim Pair<List<Node>, Integer> cachedPath = treeCache.get(n); 1376212795Sdim if (cachedPath == null) { 1377218893Sdim //cache miss 1378212795Sdim if (n.isLeaf()) { 1379212795Sdim //if leaf, stop 1380212795Sdim cachedPath = new Pair<>(List.of(n), n.data.length()); 1381212795Sdim } else { 1382249423Sdim //if non-leaf, proceed recursively 1383249423Sdim Pair<List<Node>, Integer> path = new Pair<>(List.of(n), n.data.length()); 1384249423Sdim for (Node n2 : n.getAllDependencies()) { 1385218893Sdim if (n2 == n) continue; 1386249423Sdim Pair<List<Node>, Integer> subpath = computeTreeToLeafs(n2); 1387249423Sdim path = new Pair<>(path.fst.prependList(subpath.fst), 1388263508Sdim path.snd + subpath.snd); 1389218893Sdim } 1390218893Sdim cachedPath = path; 1391212795Sdim } 1392212795Sdim //save results in cache 1393212795Sdim treeCache.put(n, cachedPath); 1394212795Sdim } 1395212795Sdim return cachedPath; 1396212795Sdim } 1397212795Sdim 1398212795Sdim /** cache used to avoid redundant computation of tree costs */ 1399218893Sdim final Map<Node, Pair<List<Node>, Integer>> treeCache = new HashMap<>(); 1400212795Sdim 1401226633Sdim /** constant value used to mark non-existent paths */ 1402212795Sdim final Pair<List<Node>, Integer> noPath = new Pair<>(null, Integer.MAX_VALUE); 1403218893Sdim 1404218893Sdim /** 1405212795Sdim * Pick the leaf that minimize cost 1406212795Sdim */ 1407212795Sdim @Override 1408212795Sdim public Node pickNode(final InferenceGraph g) { 1409212795Sdim treeCache.clear(); //graph changes at every step - cache must be cleared 1410226633Sdim Pair<List<Node>, Integer> bestPath = noPath; 1411212795Sdim for (Node n : g.nodes) { 1412218893Sdim if (!Collections.disjoint(n.data, varsToSolve)) { 1413212795Sdim Pair<List<Node>, Integer> path = computeTreeToLeafs(n); 1414263508Sdim //discard all paths containing at least a node in the 1415263508Sdim //closure computed above 1416263508Sdim if (path.snd < bestPath.snd) { 1417212795Sdim bestPath = path; 1418212795Sdim } 1419234353Sdim } 1420234353Sdim } 1421234353Sdim if (bestPath == noPath) { 1422212795Sdim //no path leads there 1423234353Sdim throw new NodeNotFoundException(g); 1424234353Sdim } 1425234353Sdim return bestPath.fst.head; 1426234353Sdim } 1427234353Sdim } 1428234353Sdim 1429234353Sdim /** 1430234353Sdim * The inference process can be thought of as a sequence of steps. Each step 1431234353Sdim * instantiates an inference variable using a subset of the inference variable 1432234353Sdim * bounds, if certain condition are met. Decisions such as the sequence in which 1433234353Sdim * steps are applied, or which steps are to be applied are left to the inference engine. 1434234353Sdim */ 1435212795Sdim enum InferenceStep { 1436226633Sdim 1437212795Sdim /** 1438212795Sdim * Instantiate an inference variables using one of its (ground) equality 1439234353Sdim * constraints 1440212795Sdim */ 1441212795Sdim EQ(InferenceBound.EQ) { 1442212795Sdim @Override 1443212795Sdim Type solve(UndetVar uv, InferenceContext inferenceContext) { 1444243830Sdim return filterBounds(uv, inferenceContext).head; 1445218893Sdim } 1446218893Sdim }, 1447243830Sdim /** 1448243830Sdim * Instantiate an inference variables using its (ground) lower bounds. Such 1449243830Sdim * bounds are merged together using lub(). 1450263508Sdim */ 1451263508Sdim LOWER(InferenceBound.LOWER) { 1452263508Sdim @Override 1453263508Sdim Type solve(UndetVar uv, InferenceContext inferenceContext) { 1454263508Sdim Infer infer = inferenceContext.infer; 1455234353Sdim List<Type> lobounds = filterBounds(uv, inferenceContext); 1456212795Sdim //note: lobounds should have at least one element 1457212795Sdim Type owntype = lobounds.tail.tail == null ? lobounds.head : infer.types.lub(lobounds); 1458212795Sdim if (owntype.isPrimitive() || owntype.hasTag(ERROR)) { 1459234353Sdim throw infer.inferenceException 1460212795Sdim .setMessage("no.unique.minimal.instance.exists", 1461234353Sdim uv.qtype, lobounds); 1462218893Sdim } else { 1463218893Sdim return owntype; 1464226633Sdim } 1465218893Sdim } 1466218893Sdim }, 1467218893Sdim /** 1468218893Sdim * Infer uninstantiated/unbound inference variables occurring in 'throws' 1469218893Sdim * clause as RuntimeException 1470226633Sdim */ 1471226633Sdim THROWS(InferenceBound.UPPER) { 1472212795Sdim @Override 1473218893Sdim public boolean accepts(UndetVar t, InferenceContext inferenceContext) { 1474218893Sdim if ((t.qtype.tsym.flags() & Flags.THROWS) == 0) { 1475218893Sdim //not a throws undet var 1476226633Sdim return false; 1477226633Sdim } 1478212795Sdim Infer infer = inferenceContext.infer; 1479243830Sdim for (Type db : t.getBounds(InferenceBound.UPPER)) { 1480218893Sdim if (t.isInterface()) continue; 1481218893Sdim if (infer.types.asSuper(infer.syms.runtimeExceptionType, db.tsym) == null) { 1482218893Sdim //upper bound is not a supertype of RuntimeException - give up 1483234353Sdim return false; 1484218893Sdim } 1485226633Sdim } 1486218893Sdim 1487218893Sdim return true; 1488218893Sdim } 1489218893Sdim 1490243830Sdim @Override 1491212795Sdim Type solve(UndetVar uv, InferenceContext inferenceContext) { 1492212795Sdim return inferenceContext.infer.syms.runtimeExceptionType; 1493212795Sdim } 1494263508Sdim }, 1495263508Sdim /** 1496263508Sdim * Instantiate an inference variables using its (ground) upper bounds. Such 1497263508Sdim * bounds are merged together using glb(). 1498263508Sdim */ 1499263508Sdim UPPER(InferenceBound.UPPER) { 1500263508Sdim @Override 1501263508Sdim Type solve(UndetVar uv, InferenceContext inferenceContext) { 1502263508Sdim Infer infer = inferenceContext.infer; 1503263508Sdim List<Type> hibounds = filterBounds(uv, inferenceContext); 1504263508Sdim //note: hibounds should have at least one element 1505263508Sdim Type owntype = hibounds.tail.tail == null ? hibounds.head : infer.types.glb(hibounds); 1506263508Sdim if (owntype.isPrimitive() || owntype.hasTag(ERROR)) { 1507263508Sdim throw infer.inferenceException 1508263508Sdim .setMessage("no.unique.maximal.instance.exists", 1509263508Sdim uv.qtype, hibounds); 1510263508Sdim } else { 1511263508Sdim return owntype; 1512263508Sdim } 1513263508Sdim } 1514263508Sdim }, 1515263508Sdim /** 1516263508Sdim * Like the former; the only difference is that this step can only be applied 1517263508Sdim * if all upper bounds are ground. 1518263508Sdim */ 1519263508Sdim UPPER_LEGACY(InferenceBound.UPPER) { 1520263508Sdim @Override 1521263508Sdim public boolean accepts(UndetVar t, InferenceContext inferenceContext) { 1522263508Sdim return !inferenceContext.free(t.getBounds(ib)) && !t.isCaptured(); 1523263508Sdim } 1524263508Sdim 1525263508Sdim @Override 1526263508Sdim Type solve(UndetVar uv, InferenceContext inferenceContext) { 1527263508Sdim return UPPER.solve(uv, inferenceContext); 1528263508Sdim } 1529263508Sdim }, 1530263508Sdim /** 1531263508Sdim * Like the former; the only difference is that this step can only be applied 1532263508Sdim * if all upper/lower bounds are ground. 1533263508Sdim */ 1534263508Sdim CAPTURED(InferenceBound.UPPER) { 1535218893Sdim @Override 1536226633Sdim public boolean accepts(UndetVar t, InferenceContext inferenceContext) { 1537226633Sdim return t.isCaptured() && 1538212795Sdim !inferenceContext.free(t.getBounds(InferenceBound.UPPER, InferenceBound.LOWER)); 1539218893Sdim } 1540212795Sdim 1541226633Sdim @Override 1542218893Sdim Type solve(UndetVar uv, InferenceContext inferenceContext) { 1543218893Sdim Infer infer = inferenceContext.infer; 1544218893Sdim Type upper = UPPER.filterBounds(uv, inferenceContext).nonEmpty() ? 1545218893Sdim UPPER.solve(uv, inferenceContext) : 1546218893Sdim infer.syms.objectType; 1547218893Sdim Type lower = LOWER.filterBounds(uv, inferenceContext).nonEmpty() ? 1548218893Sdim LOWER.solve(uv, inferenceContext) : 1549218893Sdim infer.syms.botType; 1550218893Sdim CapturedType prevCaptured = (CapturedType)uv.qtype; 1551218893Sdim return new CapturedType(prevCaptured.tsym.name, prevCaptured.tsym.owner, 1552218893Sdim upper, lower, prevCaptured.wildcard); 1553212795Sdim } 1554212795Sdim }; 1555212795Sdim 1556226633Sdim final InferenceBound ib; 1557218893Sdim 1558218893Sdim InferenceStep(InferenceBound ib) { 1559218893Sdim this.ib = ib; 1560218893Sdim } 1561218893Sdim 1562243830Sdim /** 1563243830Sdim * Find an instantiated type for a given inference variable within 1564243830Sdim * a given inference context 1565226633Sdim */ 1566243830Sdim abstract Type solve(UndetVar uv, InferenceContext inferenceContext); 1567263508Sdim 1568263508Sdim /** 1569263508Sdim * Can the inference variable be instantiated using this step? 1570263508Sdim */ 1571263508Sdim public boolean accepts(UndetVar t, InferenceContext inferenceContext) { 1572263508Sdim return filterBounds(t, inferenceContext).nonEmpty() && !t.isCaptured(); 1573243830Sdim } 1574263508Sdim 1575263508Sdim /** 1576243830Sdim * Return the subset of ground bounds in a given bound set (i.e. eq/lower/upper) 1577263508Sdim */ 1578263508Sdim List<Type> filterBounds(UndetVar uv, InferenceContext inferenceContext) { 1579263508Sdim return Type.filter(uv.getBounds(ib), new BoundFilter(inferenceContext)); 1580263508Sdim } 1581263508Sdim } 1582263508Sdim 1583263508Sdim /** 1584263508Sdim * This enumeration defines the sequence of steps to be applied when the 1585263508Sdim * solver works in legacy mode. The steps in this enumeration reflect 1586263508Sdim * the behavior of old inference routine (see JLS SE 7 15.12.2.7/15.12.2.8). 1587263508Sdim */ 1588263508Sdim enum LegacyInferenceSteps { 1589263508Sdim 1590263508Sdim EQ_LOWER(EnumSet.of(InferenceStep.EQ, InferenceStep.LOWER)), 1591263508Sdim EQ_UPPER(EnumSet.of(InferenceStep.EQ, InferenceStep.UPPER_LEGACY)); 1592263508Sdim 1593263508Sdim final EnumSet<InferenceStep> steps; 1594263508Sdim 1595263508Sdim LegacyInferenceSteps(EnumSet<InferenceStep> steps) { 1596212795Sdim this.steps = steps; 1597212795Sdim } 1598263508Sdim } 1599263508Sdim 1600263508Sdim /** 1601263508Sdim * This enumeration defines the sequence of steps to be applied when the 1602263508Sdim * graph solver is used. This order is defined so as to maximize compatibility 1603263508Sdim * w.r.t. old inference routine (see JLS SE 7 15.12.2.7/15.12.2.8). 1604263508Sdim */ 1605263508Sdim enum GraphInferenceSteps { 1606263508Sdim 1607263508Sdim EQ(EnumSet.of(InferenceStep.EQ)), 1608263508Sdim EQ_LOWER(EnumSet.of(InferenceStep.EQ, InferenceStep.LOWER)), 1609263508Sdim EQ_LOWER_THROWS_UPPER_CAPTURED(EnumSet.of(InferenceStep.EQ, InferenceStep.LOWER, InferenceStep.UPPER, InferenceStep.THROWS, InferenceStep.CAPTURED)); 1610212795Sdim 1611212795Sdim final EnumSet<InferenceStep> steps; 1612212795Sdim 1613212795Sdim GraphInferenceSteps(EnumSet<InferenceStep> steps) { 1614263508Sdim this.steps = steps; 1615212795Sdim } 1616218893Sdim } 1617263508Sdim 1618218893Sdim /** 1619212795Sdim * There are two kinds of dependencies between inference variables. The basic 1620263508Sdim * kind of dependency (or bound dependency) arises when a variable mention 1621218893Sdim * another variable in one of its bounds. There's also a more subtle kind 1622226633Sdim * of dependency that arises when a variable 'might' lead to better constraints 1623218893Sdim * on another variable (this is typically the case with variables holding up 1624212795Sdim * stuck expressions). 1625212795Sdim */ 1626212795Sdim enum DependencyKind implements GraphUtils.DependencyKind { 1627226633Sdim 1628226633Sdim /** bound dependency */ 1629226633Sdim BOUND("dotted"), 1630226633Sdim /** stuck dependency */ 1631226633Sdim STUCK("dashed"); 1632226633Sdim 1633212795Sdim final String dotSyle; 1634234353Sdim 1635212795Sdim private DependencyKind(String dotSyle) { 1636234353Sdim this.dotSyle = dotSyle; 1637212795Sdim } 1638212795Sdim } 1639263508Sdim 1640263508Sdim /** 1641263508Sdim * This is the graph inference solver - the solver organizes all inference variables in 1642263508Sdim * a given inference context by bound dependencies - in the general case, such dependencies 1643263508Sdim * would lead to a cyclic directed graph (hence the name); the dependency info is used to build 1644263508Sdim * an acyclic graph, where all cyclic variables are bundled together. An inference 1645263508Sdim * step corresponds to solving a node in the acyclic graph - this is done by 1646263508Sdim * relying on a given strategy (see GraphStrategy). 1647263508Sdim */ 1648263508Sdim class GraphSolver { 1649263508Sdim 1650212795Sdim InferenceContext inferenceContext; 1651212795Sdim Warner warn; 1652212795Sdim 1653263508Sdim GraphSolver(InferenceContext inferenceContext, Warner warn) { 1654263508Sdim this.inferenceContext = inferenceContext; 1655263508Sdim this.warn = warn; 1656263508Sdim } 1657263508Sdim 1658263508Sdim /** 1659263508Sdim * Solve variables in a given inference context. The amount of variables 1660263508Sdim * to be solved, and the way in which the underlying acyclic graph is explored 1661263508Sdim * depends on the selected solver strategy. 1662263508Sdim */ 1663263508Sdim void solve(GraphStrategy sstrategy) { 1664263508Sdim doIncorporation(inferenceContext, warn); //initial propagation of bounds 1665263508Sdim InferenceGraph inferenceGraph = new InferenceGraph(); 1666263508Sdim while (!sstrategy.done()) { 1667263508Sdim if (dependenciesFolder != null) { 1668263508Sdim //add this graph to the pending queue 1669263508Sdim pendingGraphs = pendingGraphs.prepend(inferenceGraph.toDot()); 1670263508Sdim } 1671263508Sdim InferenceGraph.Node nodeToSolve = sstrategy.pickNode(inferenceGraph); 1672263508Sdim List<Type> varsToSolve = List.from(nodeToSolve.data); 1673263508Sdim List<Type> saved_undet = inferenceContext.save(); 1674263508Sdim try { 1675263508Sdim //repeat until all variables are solved 1676263508Sdim outer: while (Type.containsAny(inferenceContext.restvars(), varsToSolve)) { 1677263508Sdim //for each inference phase 1678263508Sdim for (GraphInferenceSteps step : GraphInferenceSteps.values()) { 1679263508Sdim if (inferenceContext.solveBasic(varsToSolve, step.steps).nonEmpty()) { 1680263508Sdim doIncorporation(inferenceContext, warn); 1681263508Sdim continue outer; 1682263508Sdim } 1683263508Sdim } 1684263508Sdim //no progress 1685263508Sdim throw inferenceException.setMessage(); 1686263508Sdim } 1687263508Sdim } 1688263508Sdim catch (InferenceException ex) { 1689263508Sdim //did we fail because of interdependent ivars? 1690263508Sdim inferenceContext.rollback(saved_undet); 1691263508Sdim instantiateAsUninferredVars(varsToSolve, inferenceContext); 1692263508Sdim doIncorporation(inferenceContext, warn); 1693263508Sdim } 1694263508Sdim inferenceGraph.deleteNode(nodeToSolve); 1695263508Sdim } 1696263508Sdim } 1697263508Sdim 1698263508Sdim /** 1699263508Sdim * The dependencies between the inference variables that need to be solved 1700263508Sdim * form a (possibly cyclic) graph. This class reduces the original dependency graph 1701263508Sdim * to an acyclic version, where cyclic nodes are folded into a single 'super node'. 1702263508Sdim */ 1703263508Sdim class InferenceGraph { 1704263508Sdim 1705263508Sdim /** 1706263508Sdim * This class represents a node in the graph. Each node corresponds 1707263508Sdim * to an inference variable and has edges (dependencies) on other 1708263508Sdim * nodes. The node defines an entry point that can be used to receive 1709263508Sdim * updates on the structure of the graph this node belongs to (used to 1710263508Sdim * keep dependencies in sync). 1711263508Sdim */ 1712263508Sdim class Node extends GraphUtils.TarjanNode<ListBuffer<Type>, Node> implements DottableNode<ListBuffer<Type>, Node> { 1713263508Sdim 1714263508Sdim /** node dependencies */ 1715263508Sdim Set<Node> deps; 1716263508Sdim 1717263508Sdim Node(Type ivar) { 1718263508Sdim super(ListBuffer.of(ivar)); 1719263508Sdim this.deps = new HashSet<>(); 1720263508Sdim } 1721263508Sdim 1722263508Sdim @Override 1723263508Sdim public GraphUtils.DependencyKind[] getSupportedDependencyKinds() { 1724263508Sdim return new GraphUtils.DependencyKind[] { DependencyKind.BOUND }; 1725263508Sdim } 1726263508Sdim 1727263508Sdim public Iterable<? extends Node> getAllDependencies() { 1728263508Sdim return deps; 1729263508Sdim } 1730263508Sdim 1731263508Sdim @Override 1732263508Sdim public Collection<? extends Node> getDependenciesByKind(GraphUtils.DependencyKind dk) { 1733263508Sdim if (dk == DependencyKind.BOUND) { 1734263508Sdim return deps; 1735263508Sdim } else { 1736212795Sdim throw new IllegalStateException(); 1737212795Sdim } 1738212795Sdim } 1739212795Sdim 1740212795Sdim /** 1741212795Sdim * Adds dependency with given kind. 1742218893Sdim */ 1743212795Sdim protected void addDependency(Node depToAdd) { 1744212795Sdim deps.add(depToAdd); 1745212795Sdim } 1746212795Sdim 1747218893Sdim /** 1748212795Sdim * Add multiple dependencies of same given kind. 1749212795Sdim */ 1750212795Sdim protected void addDependencies(Set<Node> depsToAdd) { 1751218893Sdim for (Node n : depsToAdd) { 1752218893Sdim addDependency(n); 1753218893Sdim } 1754226633Sdim } 1755218893Sdim 1756218893Sdim /** 1757218893Sdim * Remove a dependency, regardless of its kind. 1758218893Sdim */ 1759218893Sdim protected boolean removeDependency(Node n) { 1760218893Sdim return deps.remove(n); 1761218893Sdim } 1762218893Sdim 1763218893Sdim /** 1764218893Sdim * Compute closure of a give node, by recursively walking 1765218893Sdim * through all its dependencies (of given kinds) 1766212795Sdim */ 1767212795Sdim protected Set<Node> closure() { 1768212795Sdim boolean progress = true; 1769212795Sdim Set<Node> closure = new HashSet<>(); 1770212795Sdim closure.add(this); 1771212795Sdim while (progress) { 1772212795Sdim progress = false; 1773243830Sdim for (Node n1 : new HashSet<>(closure)) { 1774243830Sdim progress = closure.addAll(n1.deps); 1775243830Sdim } 1776243830Sdim } 1777243830Sdim return closure; 1778243830Sdim } 1779243830Sdim 1780243830Sdim /** 1781243830Sdim * Is this node a leaf? This means either the node has no dependencies, 1782243830Sdim * or it just has self-dependencies. 1783243830Sdim */ 1784243830Sdim protected boolean isLeaf() { 1785212795Sdim //no deps, or only one self dep 1786212795Sdim if (deps.isEmpty()) return true; 1787223017Sdim for (Node n : deps) { 1788223017Sdim if (n != this) { 1789223017Sdim return false; 1790223017Sdim } 1791212795Sdim } 1792212795Sdim return true; 1793239462Sdim } 1794239462Sdim 1795218893Sdim /** 1796221345Sdim * Merge this node with another node, acquiring its dependencies. 1797212795Sdim * This routine is used to merge all cyclic node together and 1798212795Sdim * form an acyclic graph. 1799249423Sdim */ 1800249423Sdim protected void mergeWith(List<? extends Node> nodes) { 1801249423Sdim for (Node n : nodes) { 1802249423Sdim Assert.check(n.data.length() == 1, "Attempt to merge a compound node!"); 1803212795Sdim data.appendList(n.data); 1804212795Sdim addDependencies(n.deps); 1805212795Sdim } 1806212795Sdim //update deps 1807212795Sdim Set<Node> deps2 = new HashSet<>(); 1808212795Sdim for (Node d : deps) { 1809212795Sdim if (data.contains(d.data.first())) { 1810212795Sdim deps2.add(this); 1811234353Sdim } else { 1812234353Sdim deps2.add(d); 1813234353Sdim } 1814234353Sdim } 1815234353Sdim deps = deps2; 1816234353Sdim } 1817234353Sdim 1818234353Sdim /** 1819234353Sdim * Notify all nodes that something has changed in the graph 1820234353Sdim * topology. 1821234353Sdim */ 1822218893Sdim private void graphChanged(Node from, Node to) { 1823218893Sdim if (removeDependency(from)) { 1824218893Sdim if (to != null) { 1825218893Sdim addDependency(to); 1826239462Sdim } 1827234353Sdim } 1828234353Sdim } 1829234353Sdim 1830234353Sdim @Override 1831234353Sdim public Properties nodeAttributes() { 1832234353Sdim Properties p = new Properties(); 1833234353Sdim p.put("label", "\"" + toString() + "\""); 1834249423Sdim return p; 1835249423Sdim } 1836234353Sdim 1837212795Sdim @Override 1838234353Sdim public Properties dependencyAttributes(Node sink, GraphUtils.DependencyKind dk) { 1839234353Sdim Properties p = new Properties(); 1840234353Sdim p.put("style", ((DependencyKind)dk).dotSyle); 1841263508Sdim StringBuilder buf = new StringBuilder(); 1842234353Sdim String sep = ""; 1843234353Sdim for (Type from : data) { 1844234353Sdim UndetVar uv = (UndetVar)inferenceContext.asUndetVar(from); 1845212795Sdim for (Type bound : uv.getBounds(InferenceBound.values())) { 1846263508Sdim if (bound.containsAny(List.from(sink.data))) { 1847263508Sdim buf.append(sep); 1848263508Sdim buf.append(bound); 1849263508Sdim sep = ","; 1850263508Sdim } 1851263508Sdim } 1852263508Sdim } 1853263508Sdim p.put("label", "\"" + buf.toString() + "\""); 1854263508Sdim return p; 1855263508Sdim } 1856263508Sdim } 1857263508Sdim 1858263508Sdim /** the nodes in the inference graph */ 1859263508Sdim ArrayList<Node> nodes; 1860263508Sdim 1861263508Sdim InferenceGraph() { 1862263508Sdim initNodes(); 1863263508Sdim } 1864263508Sdim 1865263508Sdim /** 1866263508Sdim * Basic lookup helper for retrieving a graph node given an inference 1867263508Sdim * variable type. 1868263508Sdim */ 1869263508Sdim public Node findNode(Type t) { 1870234353Sdim for (Node n : nodes) { 1871263508Sdim if (n.data.contains(t)) { 1872263508Sdim return n; 1873263508Sdim } 1874263508Sdim } 1875263508Sdim return null; 1876263508Sdim } 1877263508Sdim 1878263508Sdim /** 1879263508Sdim * Delete a node from the graph. This update the underlying structure 1880263508Sdim * of the graph (including dependencies) via listeners updates. 1881263508Sdim */ 1882263508Sdim public void deleteNode(Node n) { 1883263508Sdim Assert.check(nodes.contains(n)); 1884263508Sdim nodes.remove(n); 1885263508Sdim notifyUpdate(n, null); 1886263508Sdim } 1887263508Sdim 1888263508Sdim /** 1889263508Sdim * Notify all nodes of a change in the graph. If the target node is 1890263508Sdim * {@code null} the source node is assumed to be removed. 1891263508Sdim */ 1892263508Sdim void notifyUpdate(Node from, Node to) { 1893263508Sdim for (Node n : nodes) { 1894263508Sdim n.graphChanged(from, to); 1895263508Sdim } 1896263508Sdim } 1897263508Sdim 1898263508Sdim /** 1899263508Sdim * Create the graph nodes. First a simple node is created for every inference 1900263508Sdim * variables to be solved. Then Tarjan is used to found all connected components 1901212795Sdim * in the graph. For each component containing more than one node, a super node is 1902212795Sdim * created, effectively replacing the original cyclic nodes. 1903212795Sdim */ 1904263508Sdim void initNodes() { 1905263508Sdim //add nodes 1906263508Sdim nodes = new ArrayList<>(); 1907263508Sdim for (Type t : inferenceContext.restvars()) { 1908263508Sdim nodes.add(new Node(t)); 1909263508Sdim } 1910263508Sdim //add dependencies 1911263508Sdim for (Node n_i : nodes) { 1912263508Sdim Type i = n_i.data.first(); 1913263508Sdim for (Node n_j : nodes) { 1914263508Sdim Type j = n_j.data.first(); 1915263508Sdim UndetVar uv_i = (UndetVar)inferenceContext.asUndetVar(i); 1916263508Sdim if (Type.containsAny(uv_i.getBounds(InferenceBound.values()), List.of(j))) { 1917263508Sdim //update i's bound dependencies 1918263508Sdim n_i.addDependency(n_j); 1919263508Sdim } 1920263508Sdim } 1921263508Sdim } 1922263508Sdim //merge cyclic nodes 1923263508Sdim ArrayList<Node> acyclicNodes = new ArrayList<>(); 1924263508Sdim for (List<? extends Node> conSubGraph : GraphUtils.tarjan(nodes)) { 1925263508Sdim if (conSubGraph.length() > 1) { 1926249423Sdim Node root = conSubGraph.head; 1927249423Sdim root.mergeWith(conSubGraph.tail); 1928249423Sdim for (Node n : conSubGraph) { 1929263508Sdim notifyUpdate(n, root); 1930249423Sdim } 1931249423Sdim } 1932263508Sdim acyclicNodes.add(conSubGraph.head); 1933249423Sdim } 1934249423Sdim nodes = acyclicNodes; 1935249423Sdim } 1936249423Sdim 1937212795Sdim /** 1938212795Sdim * Debugging: dot representation of this graph 1939212795Sdim */ 1940212795Sdim String toDot() { 1941212795Sdim StringBuilder buf = new StringBuilder(); 1942234353Sdim for (Type t : inferenceContext.undetvars) { 1943218893Sdim UndetVar uv = (UndetVar)t; 1944218893Sdim buf.append(String.format("var %s - upper bounds = %s, lower bounds = %s, eq bounds = %s\\n", 1945212795Sdim uv.qtype, uv.getBounds(InferenceBound.UPPER), uv.getBounds(InferenceBound.LOWER), 1946212795Sdim uv.getBounds(InferenceBound.EQ))); 1947226633Sdim } 1948212795Sdim return GraphUtils.toDot(nodes, "inferenceGraph" + hashCode(), buf.toString()); 1949212795Sdim } 1950212795Sdim } 1951212795Sdim } 1952212795Sdim // </editor-fold> 1953212795Sdim 1954212795Sdim // <editor-fold defaultstate="collapsed" desc="Inference context"> 1955212795Sdim /** 1956212795Sdim * Functional interface for defining inference callbacks. Certain actions 1957212795Sdim * (i.e. subtyping checks) might need to be redone after all inference variables 1958212795Sdim * have been fixed. 1959212795Sdim */ 1960212795Sdim interface FreeTypeListener { 1961212795Sdim void typesInferred(InferenceContext inferenceContext); 1962212795Sdim } 1963212795Sdim 1964212795Sdim final InferenceContext emptyContext; 1965212795Sdim // </editor-fold> 1966212795Sdim} 1967212795Sdim