1 /*
   2  * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.tools.javac.comp;
  27 
  28 import com.sun.tools.javac.code.Type.UndetVar.UndetVarListener;
  29 import com.sun.tools.javac.code.Types.TypeMapping;
  30 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
  31 import com.sun.tools.javac.resources.CompilerProperties.Notes;
  32 import com.sun.tools.javac.tree.JCTree;
  33 import com.sun.tools.javac.tree.JCTree.JCTypeCast;
  34 import com.sun.tools.javac.tree.TreeInfo;
  35 import com.sun.tools.javac.util.*;
  36 import com.sun.tools.javac.util.GraphUtils.DottableNode;
  37 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  38 import com.sun.tools.javac.util.JCDiagnostic.Fragment;
  39 import com.sun.tools.javac.util.List;
  40 import com.sun.tools.javac.code.*;
  41 import com.sun.tools.javac.code.Type.*;
  42 import com.sun.tools.javac.code.Type.UndetVar.InferenceBound;
  43 import com.sun.tools.javac.code.Symbol.*;
  44 import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
  45 import com.sun.tools.javac.comp.DeferredAttr.DeferredAttrContext;
  46 import com.sun.tools.javac.comp.Infer.GraphSolver.InferenceGraph;
  47 import com.sun.tools.javac.comp.Infer.GraphSolver.InferenceGraph.Node;
  48 import com.sun.tools.javac.comp.Resolve.InapplicableMethodException;
  49 import com.sun.tools.javac.comp.Resolve.VerboseResolutionMode;
  50 
  51 import java.io.IOException;
  52 import java.io.Writer;
  53 import java.nio.file.Files;
  54 import java.nio.file.Path;
  55 import java.nio.file.Paths;
  56 import java.util.ArrayList;
  57 import java.util.Collection;
  58 import java.util.Collections;
  59 import java.util.EnumSet;
  60 import java.util.HashMap;
  61 import java.util.HashSet;
  62 import java.util.LinkedHashSet;
  63 import java.util.Map;
  64 import java.util.Optional;
  65 import java.util.Properties;
  66 import java.util.Set;
  67 import java.util.function.BiFunction;
  68 import java.util.function.BiPredicate;
  69 import java.util.function.Predicate;
  70 
  71 import static com.sun.tools.javac.code.TypeTag.*;
  72 
  73 /** Helper class for type parameter inference, used by the attribution phase.
  74  *
  75  *  <p><b>This is NOT part of any supported API.
  76  *  If you write code that depends on this, you do so at your own risk.
  77  *  This code and its internal interfaces are subject to change or
  78  *  deletion without notice.</b>
  79  */
  80 public class Infer {
  81     protected static final Context.Key<Infer> inferKey = new Context.Key<>();
  82 
  83     Resolve rs;
  84     Check chk;
  85     Symtab syms;
  86     Types types;
  87     JCDiagnostic.Factory diags;
  88     Log log;
  89 
  90     /**
  91      * folder in which the inference dependency graphs should be written.
  92      */
  93     private final String dependenciesFolder;
  94 
  95     /**
  96      * List of graphs awaiting to be dumped to a file.
  97      */
  98     private List<String> pendingGraphs;
  99 
 100     public static Infer instance(Context context) {
 101         Infer instance = context.get(inferKey);
 102         if (instance == null)
 103             instance = new Infer(context);
 104         return instance;
 105     }
 106 
 107     protected Infer(Context context) {
 108         context.put(inferKey, this);
 109 
 110         rs = Resolve.instance(context);
 111         chk = Check.instance(context);
 112         syms = Symtab.instance(context);
 113         types = Types.instance(context);
 114         diags = JCDiagnostic.Factory.instance(context);
 115         log = Log.instance(context);
 116         Options options = Options.instance(context);
 117         dependenciesFolder = options.get("debug.dumpInferenceGraphsTo");
 118         pendingGraphs = List.nil();
 119 
 120         emptyContext = new InferenceContext(this, List.nil());
 121     }
 122 
 123     /** A value for prototypes that admit any type, including polymorphic ones. */
 124     public static final Type anyPoly = new JCNoType();
 125 
 126    /**
 127     * This exception class is design to store a list of diagnostics corresponding
 128     * to inference errors that can arise during a method applicability check.
 129     */
 130     public static class InferenceException extends InapplicableMethodException {
 131         private static final long serialVersionUID = 0;
 132 
 133         transient List<JCDiagnostic> messages = List.nil();
 134 
 135         InferenceException() {
 136             super(null);
 137         }
 138 
 139         @Override
 140         public JCDiagnostic getDiagnostic() {
 141             return messages.head;
 142         }
 143     }
 144 
 145     InferenceException error(JCDiagnostic diag) {
 146         InferenceException result = new InferenceException();
 147         if (diag != null) {
 148             result.messages = result.messages.append(diag);
 149         }
 150         return result;
 151     }
 152 
 153     // <editor-fold defaultstate="collapsed" desc="Inference routines">
 154     /**
 155      * Main inference entry point - instantiate a generic method type
 156      * using given argument types and (possibly) an expected target-type.
 157      */
 158     Type instantiateMethod( Env<AttrContext> env,
 159                             List<Type> tvars,
 160                             MethodType mt,
 161                             Attr.ResultInfo resultInfo,
 162                             MethodSymbol msym,
 163                             List<Type> argtypes,
 164                             boolean allowBoxing,
 165                             boolean useVarargs,
 166                             Resolve.MethodResolutionContext resolveContext,
 167                             Warner warn) throws InferenceException {
 168         //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG
 169         final InferenceContext inferenceContext = new InferenceContext(this, tvars);  //B0
 170         try {
 171             DeferredAttr.DeferredAttrContext deferredAttrContext =
 172                         resolveContext.deferredAttrContext(msym, inferenceContext, resultInfo, warn);
 173 
 174             resolveContext.methodCheck.argumentsAcceptable(env, deferredAttrContext,   //B2
 175                     argtypes, mt.getParameterTypes(), warn);
 176 
 177             if (resultInfo != null && resultInfo.pt == anyPoly) {
 178                 doIncorporation(inferenceContext, warn);
 179                 //we are inside method attribution - just return a partially inferred type
 180                 return new PartiallyInferredMethodType(mt, inferenceContext, env, warn);
 181             } else if (resultInfo != null) {
 182 
 183                 //inject return constraints earlier
 184                 doIncorporation(inferenceContext, warn); //propagation
 185 
 186                 if (!warn.hasNonSilentLint(Lint.LintCategory.UNCHECKED)) {
 187                     boolean shouldPropagate = shouldPropagate(mt.getReturnType(), resultInfo, inferenceContext);
 188 
 189                     InferenceContext minContext = shouldPropagate ?
 190                             inferenceContext.min(roots(mt, deferredAttrContext), true, warn) :
 191                             inferenceContext;
 192 
 193                     Type newRestype = generateReturnConstraints(env.tree, resultInfo,  //B3
 194                             mt, minContext);
 195                     mt = (MethodType)types.createMethodTypeWithReturn(mt, newRestype);
 196 
 197                     //propagate outwards if needed
 198                     if (shouldPropagate) {
 199                         //propagate inference context outwards and exit
 200                         minContext.dupTo(resultInfo.checkContext.inferenceContext());
 201                         deferredAttrContext.complete();
 202                         return mt;
 203                     }
 204                 }
 205             }
 206 
 207             deferredAttrContext.complete();
 208 
 209             // minimize as yet undetermined type variables
 210             inferenceContext.solve(warn);
 211             mt = (MethodType)inferenceContext.asInstType(mt);
 212 
 213             if (resultInfo != null && rs.verboseResolutionMode.contains(VerboseResolutionMode.DEFERRED_INST)) {
 214                 log.note(env.tree.pos, Notes.DeferredMethodInst(msym, mt, resultInfo.pt));
 215             }
 216 
 217             // return instantiated version of method type
 218             return mt;
 219         } finally {
 220             if (resultInfo != null) {
 221                 inferenceContext.notifyChange();
 222             } else {
 223                 inferenceContext.notifyChange(inferenceContext.boundedVars());
 224             }
 225             if (resultInfo == null) {
 226                 /* if the is no result info then we can clear the capture types
 227                  * cache without affecting any result info check
 228                  */
 229                 inferenceContext.captureTypeCache.clear();
 230             }
 231             dumpGraphsIfNeeded(env.tree, msym, resolveContext);
 232         }
 233     }
 234     //where
 235         private boolean shouldPropagate(Type restype, Attr.ResultInfo target, InferenceContext inferenceContext) {
 236             return target.checkContext.inferenceContext() != emptyContext && //enclosing context is a generic method
 237                         inferenceContext.free(restype) && //return type contains inference vars
 238                         (!inferenceContext.inferencevars.contains(restype) || //no eager instantiation is required (as per 18.5.2)
 239                                 !needsEagerInstantiation((UndetVar)inferenceContext.asUndetVar(restype), target.pt, inferenceContext));
 240         }
 241 
 242         private List<Type> roots(MethodType mt, DeferredAttrContext deferredAttrContext) {
 243             if (deferredAttrContext != null && deferredAttrContext.mode == AttrMode.CHECK) {
 244                 ListBuffer<Type> roots = new ListBuffer<>();
 245                 roots.add(mt.getReturnType());
 246                 for (DeferredAttr.DeferredAttrNode n : deferredAttrContext.deferredAttrNodes) {
 247                     roots.addAll(n.deferredStuckPolicy.stuckVars());
 248                     roots.addAll(n.deferredStuckPolicy.depVars());
 249                 }
 250                 List<Type> thrownVars = deferredAttrContext.inferenceContext.inferencevars.stream()
 251                                 .filter(tv -> (tv.tsym.flags() & Flags.THROWS) != 0).collect(List.collector());
 252                 List<Type> result = roots.toList();
 253                 result = result.appendList(thrownVars.diff(result));
 254                 return result;
 255             } else {
 256                 return List.of(mt.getReturnType());
 257             }
 258         }
 259 
 260     /**
 261      * A partially inferred method/constructor type; such a type can be checked multiple times
 262      * against different targets.
 263      */
 264     public class PartiallyInferredMethodType extends MethodType {
 265         public PartiallyInferredMethodType(MethodType mtype, InferenceContext inferenceContext, Env<AttrContext> env, Warner warn) {
 266             super(mtype.getParameterTypes(), mtype.getReturnType(), mtype.getThrownTypes(), mtype.tsym);
 267             this.inferenceContext = inferenceContext;
 268             this.env = env;
 269             this.warn = warn;
 270         }
 271 
 272         /** The inference context. */
 273         final InferenceContext inferenceContext;
 274 
 275         /** The attribution environment. */
 276         Env<AttrContext> env;
 277 
 278         /** The warner. */
 279         final Warner warn;
 280 
 281         @Override
 282         public boolean isPartial() {
 283             return true;
 284         }
 285 
 286         /**
 287          * Checks this type against a target; this means generating return type constraints, solve
 288          * and then roll back the results (to avoid polluting the context).
 289          */
 290         Type check(Attr.ResultInfo resultInfo) {
 291             Warner noWarnings = new Warner(null);
 292             List<Type> saved_undet = null;
 293             try {
 294                 /** we need to save the inference context before generating target type constraints.
 295                  *  This constraints may pollute the inference context and make it useless in case we
 296                  *  need to use it several times: with several targets.
 297                  */
 298                 saved_undet = inferenceContext.save();
 299                 boolean unchecked = warn.hasNonSilentLint(Lint.LintCategory.UNCHECKED);
 300                 if (!unchecked) {
 301                     boolean shouldPropagate = shouldPropagate(getReturnType(), resultInfo, inferenceContext);
 302 
 303                     InferenceContext minContext = shouldPropagate ?
 304                             inferenceContext.min(roots(asMethodType(), null), false, warn) :
 305                             inferenceContext;
 306 
 307                     MethodType other = (MethodType)minContext.update(asMethodType());
 308                     Type newRestype = generateReturnConstraints(env.tree, resultInfo,  //B3
 309                             other, minContext);
 310 
 311                     if (shouldPropagate) {
 312                         //propagate inference context outwards and exit
 313                         minContext.dupTo(resultInfo.checkContext.inferenceContext(),
 314                                 resultInfo.checkContext.deferredAttrContext().insideOverloadPhase());
 315                         return newRestype;
 316                     }
 317                 }
 318                 inferenceContext.solve(noWarnings);
 319                 Type ret = inferenceContext.asInstType(this).getReturnType();
 320                 if (unchecked) {
 321                     //inline logic from Attr.checkMethod - if unchecked conversion was required, erase
 322                     //return type _after_ resolution, and check against target
 323                     ret = types.erasure(ret);
 324                 }
 325                 return resultInfo.check(env.tree, ret);
 326             } catch (InferenceException ex) {
 327                 resultInfo.checkContext.report(null, ex.getDiagnostic());
 328                 Assert.error(); //cannot get here (the above should throw)
 329                 return null;
 330             } finally {
 331                 if (saved_undet != null) {
 332                     inferenceContext.rollback(saved_undet);
 333                 }
 334             }
 335         }
 336     }
 337 
 338     private void dumpGraphsIfNeeded(DiagnosticPosition pos, Symbol msym, Resolve.MethodResolutionContext rsContext) {
 339         int round = 0;
 340         try {
 341             for (String graph : pendingGraphs.reverse()) {
 342                 Assert.checkNonNull(dependenciesFolder);
 343                 Name name = msym.name.table.names.isInitOrVNew(msym.name) ?
 344                         msym.owner.name : msym.name;
 345                 String filename = String.format("%s@%s[mode=%s,step=%s]_%d.dot",
 346                         name,
 347                         pos.getStartPosition(),
 348                         rsContext.attrMode(),
 349                         rsContext.step,
 350                         round);
 351                 Path dotFile = Paths.get(dependenciesFolder, filename);
 352                 try (Writer w = Files.newBufferedWriter(dotFile)) {
 353                     w.append(graph);
 354                 }
 355                 round++;
 356             }
 357         } catch (IOException ex) {
 358             Assert.error("Error occurred when dumping inference graph: " + ex.getMessage());
 359         } finally {
 360             pendingGraphs = List.nil();
 361         }
 362     }
 363 
 364     /**
 365      * Generate constraints from the generic method's return type. If the method
 366      * call occurs in a context where a type T is expected, use the expected
 367      * type to derive more constraints on the generic method inference variables.
 368      */
 369     Type generateReturnConstraints(JCTree tree, Attr.ResultInfo resultInfo,
 370             MethodType mt, InferenceContext inferenceContext) {
 371         InferenceContext rsInfoInfContext = resultInfo.checkContext.inferenceContext();
 372         Type from = mt.getReturnType();
 373         if (mt.getReturnType().containsAny(inferenceContext.inferencevars) &&
 374                 rsInfoInfContext != emptyContext) {
 375             from = types.capture(from);
 376             //add synthetic captured ivars
 377             for (Type t : from.getTypeArguments()) {
 378                 if (t.hasTag(TYPEVAR) && ((TypeVar)t).isCaptured()) {
 379                     inferenceContext.addVar((TypeVar)t);
 380                 }
 381             }
 382         }
 383         Type qtype = inferenceContext.asUndetVar(from);
 384         Type to = resultInfo.pt;
 385 
 386         if (qtype.hasTag(VOID)) {
 387             to = syms.voidType;
 388         } else if (to.hasTag(NONE)) {
 389             to = from.isPrimitive() ? from : syms.objectType;
 390         } else if (qtype.hasTag(UNDETVAR)) {
 391             if (needsEagerInstantiation((UndetVar)qtype, to, inferenceContext)) {
 392                 to = generateReferenceToTargetConstraint(tree, (UndetVar)qtype, to, resultInfo, inferenceContext);
 393             }
 394         } else if (rsInfoInfContext.free(resultInfo.pt)) {
 395             //propagation - cache captured vars
 396             qtype = inferenceContext.asUndetVar(rsInfoInfContext.cachedCapture(tree, from, !resultInfo.checkMode.updateTreeType()));
 397         }
 398         //we need to skip capture?
 399         Warner retWarn = new Warner();
 400         if (!resultInfo.checkContext.compatible(qtype, rsInfoInfContext.asUndetVar(to), retWarn)) {
 401             throw error(diags.fragment(Fragments.InferNoConformingInstanceExists(inferenceContext.restvars(), mt.getReturnType(), to)));
 402         }
 403         return from;
 404     }
 405 
 406     private boolean needsEagerInstantiation(UndetVar from, Type to, InferenceContext inferenceContext) {
 407         if (to.isPrimitive()) {
 408             /* T is a primitive type, and one of the primitive wrapper classes is an instantiation,
 409              * upper bound, or lower bound for alpha in B2.
 410              */
 411             for (Type t : from.getBounds(InferenceBound.values())) {
 412                 Type boundAsPrimitive = types.unboxedType(t);
 413                 if (boundAsPrimitive == null || boundAsPrimitive.hasTag(NONE)) {
 414                     continue;
 415                 }
 416                 return true;
 417             }
 418             return false;
 419         }
 420 
 421         Type captureOfTo = types.capture(to);
 422         /* T is a reference type, but is not a wildcard-parameterized type, and either
 423          */
 424         if (captureOfTo == to) { //not a wildcard parameterized type
 425             /* i) B2 contains a bound of one of the forms alpha = S or S <: alpha,
 426              *      where S is a wildcard-parameterized type, or
 427              */
 428             for (Type t : from.getBounds(InferenceBound.EQ, InferenceBound.LOWER)) {
 429                 Type captureOfBound = types.capture(t);
 430                 if (captureOfBound != t) {
 431                     return true;
 432                 }
 433             }
 434 
 435             /* ii) B2 contains two bounds of the forms S1 <: alpha and S2 <: alpha,
 436              * where S1 and S2 have supertypes that are two different
 437              * parameterizations of the same generic class or interface.
 438              */
 439             for (Type aLowerBound : from.getBounds(InferenceBound.LOWER)) {
 440                 for (Type anotherLowerBound : from.getBounds(InferenceBound.LOWER)) {
 441                     if (aLowerBound != anotherLowerBound &&
 442                             !inferenceContext.free(aLowerBound) &&
 443                             !inferenceContext.free(anotherLowerBound) &&
 444                             commonSuperWithDiffParameterization(aLowerBound, anotherLowerBound)) {
 445                         return true;
 446                     }
 447                 }
 448             }
 449         }
 450 
 451         /* T is a parameterization of a generic class or interface, G,
 452          * and B2 contains a bound of one of the forms alpha = S or S <: alpha,
 453          * where there exists no type of the form G<...> that is a
 454          * supertype of S, but the raw type G is a supertype of S
 455          */
 456         if (to.isParameterized()) {
 457             for (Type t : from.getBounds(InferenceBound.EQ, InferenceBound.LOWER)) {
 458                 Type sup = types.asSuper(t, to.tsym);
 459                 if (sup != null && sup.isRaw()) {
 460                     return true;
 461                 }
 462             }
 463         }
 464         return false;
 465     }
 466 
 467     private boolean commonSuperWithDiffParameterization(Type t, Type s) {
 468         for (Pair<Type, Type> supers : getParameterizedSupers(t, s)) {
 469             if (!types.isSameType(supers.fst, supers.snd)) return true;
 470         }
 471         return false;
 472     }
 473 
 474     private Type generateReferenceToTargetConstraint(JCTree tree, UndetVar from,
 475             Type to, Attr.ResultInfo resultInfo,
 476             InferenceContext inferenceContext) {
 477         inferenceContext.solve(List.of(from.qtype), new Warner());
 478         inferenceContext.notifyChange();
 479         Type capturedType = resultInfo.checkContext.inferenceContext()
 480                 .cachedCapture(tree, from.getInst(), !resultInfo.checkMode.updateTreeType());
 481         if (types.isConvertible(capturedType,
 482                 resultInfo.checkContext.inferenceContext().asUndetVar(to))) {
 483             //effectively skip additional return-type constraint generation (compatibility)
 484             return syms.objectType;
 485         }
 486         return to;
 487     }
 488 
 489     /**
 490       * Infer cyclic inference variables as described in 15.12.2.8.
 491       */
 492     void instantiateAsUninferredVars(List<Type> vars, InferenceContext inferenceContext) {
 493         ListBuffer<Type> todo = new ListBuffer<>();
 494         //step 1 - create fresh tvars
 495         for (Type t : vars) {
 496             UndetVar uv = (UndetVar)inferenceContext.asUndetVar(t);
 497             List<Type> upperBounds = uv.getBounds(InferenceBound.UPPER);
 498             if (Type.containsAny(upperBounds, vars)) {
 499                 TypeSymbol fresh_tvar = new TypeVariableSymbol(Flags.SYNTHETIC, uv.qtype.tsym.name, null, uv.qtype.tsym.owner);
 500                 fresh_tvar.type = new TypeVar(fresh_tvar, types.makeIntersectionType(uv.getBounds(InferenceBound.UPPER)), syms.botType);
 501                 todo.append(uv);
 502                 uv.setInst(fresh_tvar.type);
 503             } else if (upperBounds.nonEmpty()) {
 504                 uv.setInst(types.glb(upperBounds));
 505             } else {
 506                 uv.setInst(syms.objectType);
 507             }
 508         }
 509         //step 2 - replace fresh tvars in their bounds
 510         List<Type> formals = vars;
 511         for (Type t : todo) {
 512             UndetVar uv = (UndetVar)t;
 513             TypeVar ct = (TypeVar)uv.getInst();
 514             ct.setUpperBound( types.glb(inferenceContext.asInstTypes(types.getBounds(ct))) );
 515             if (ct.getUpperBound().isErroneous()) {
 516                 //report inference error if glb fails
 517                 reportBoundError(uv, InferenceBound.UPPER);
 518             }
 519             formals = formals.tail;
 520         }
 521     }
 522 
 523     /**
 524      * Compute a synthetic method type corresponding to the requested polymorphic
 525      * method signature. The target return type is computed from the immediately
 526      * enclosing scope surrounding the polymorphic-signature call.
 527      */
 528     Type instantiatePolymorphicSignatureInstance(Env<AttrContext> env,
 529                                             MethodSymbol spMethod,  // sig. poly. method or null if none
 530                                             Resolve.MethodResolutionContext resolveContext,
 531                                             List<Type> argtypes) {
 532         final Type restype;
 533 
 534         Type spType = spMethod == null ? syms.objectType : spMethod.getReturnType();
 535 
 536         switch (env.next.tree.getTag()) {
 537             case TYPECAST:
 538                 JCTypeCast castTree = (JCTypeCast)env.next.tree;
 539                 restype = (TreeInfo.skipParens(castTree.expr) == env.tree) ?
 540                           castTree.clazz.type :
 541                           spType;
 542                 break;
 543             case EXEC:
 544                 JCTree.JCExpressionStatement execTree =
 545                         (JCTree.JCExpressionStatement)env.next.tree;
 546                 restype = (TreeInfo.skipParens(execTree.expr) == env.tree) ?
 547                           syms.voidType :
 548                           spType;
 549                 break;
 550             default:
 551                 restype = spType;
 552         }
 553 
 554         List<Type> paramtypes = argtypes.map(new ImplicitArgType(spMethod, resolveContext.step));
 555         List<Type> exType = spMethod != null ?
 556             spMethod.getThrownTypes() :
 557             List.of(syms.throwableType); // make it throw all exceptions
 558 
 559         MethodType mtype = new MethodType(paramtypes,
 560                                           restype,
 561                                           exType,
 562                                           syms.methodClass);
 563         return mtype;
 564     }
 565     //where
 566         class ImplicitArgType extends DeferredAttr.DeferredTypeMap<Void> {
 567 
 568             public ImplicitArgType(Symbol msym, Resolve.MethodResolutionPhase phase) {
 569                 (rs.deferredAttr).super(AttrMode.SPECULATIVE, msym, phase);
 570             }
 571 
 572             @Override
 573             public Type visitClassType(ClassType t, Void aVoid) {
 574                 return types.erasure(t);
 575             }
 576 
 577             @Override
 578             public Type visitType(Type t, Void _unused) {
 579                 if (t.hasTag(DEFERRED)) {
 580                     return visit(super.visitType(t, null));
 581                 } else if (t.hasTag(BOT))
 582                     // nulls type as the marker type Null (which has no instances)
 583                     // infer as java.lang.Void for now
 584                     t = types.boxedClass(syms.voidType).type;
 585                 return t;
 586             }
 587         }
 588 
 589     TypeMapping<Void> fromTypeVarFun = new StructuralTypeMapping<Void>() {
 590         @Override
 591         public Type visitTypeVar(TypeVar tv, Void aVoid) {
 592             UndetVar uv = new UndetVar(tv, incorporationEngine, types);
 593             if ((tv.tsym.flags() & Flags.THROWS) != 0) {
 594                 uv.setThrow();
 595             }
 596             return uv;
 597         }
 598     };
 599 
 600     /**
 601       * This method is used to infer a suitable target SAM in case the original
 602       * SAM type contains one or more wildcards. An inference process is applied
 603       * so that wildcard bounds, as well as explicit lambda/method ref parameters
 604       * (where applicable) are used to constraint the solution.
 605       */
 606     public Type instantiateFunctionalInterface(DiagnosticPosition pos, Type funcInterface,
 607             List<Type> paramTypes, Check.CheckContext checkContext) {
 608         if (types.capture(funcInterface) == funcInterface) {
 609             //if capture doesn't change the type then return the target unchanged
 610             //(this means the target contains no wildcards!)
 611             return funcInterface;
 612         } else {
 613             Type formalInterface = funcInterface.tsym.type;
 614             InferenceContext funcInterfaceContext =
 615                     new InferenceContext(this, funcInterface.tsym.type.getTypeArguments());
 616 
 617             Assert.check(paramTypes != null);
 618             //get constraints from explicit params (this is done by
 619             //checking that explicit param types are equal to the ones
 620             //in the functional interface descriptors)
 621             List<Type> descParameterTypes = types.findDescriptorType(formalInterface).getParameterTypes();
 622             if (descParameterTypes.size() != paramTypes.size()) {
 623                 checkContext.report(pos, diags.fragment(Fragments.IncompatibleArgTypesInLambda));
 624                 return types.createErrorType(funcInterface);
 625             }
 626             for (Type p : descParameterTypes) {
 627                 if (!types.isSameType(funcInterfaceContext.asUndetVar(p), paramTypes.head)) {
 628                     checkContext.report(pos, diags.fragment(Fragments.NoSuitableFunctionalIntfInst(funcInterface)));
 629                     return types.createErrorType(funcInterface);
 630                 }
 631                 paramTypes = paramTypes.tail;
 632             }
 633 
 634             List<Type> actualTypeargs = funcInterface.getTypeArguments();
 635             for (Type t : funcInterfaceContext.undetvars) {
 636                 UndetVar uv = (UndetVar)t;
 637                 Optional<Type> inst = uv.getBounds(InferenceBound.EQ).stream()
 638                         .filter(b -> !b.containsAny(formalInterface.getTypeArguments())).findFirst();
 639                 uv.setInst(inst.orElse(actualTypeargs.head));
 640                 actualTypeargs = actualTypeargs.tail;
 641             }
 642 
 643             Type owntype = funcInterfaceContext.asInstType(formalInterface);
 644             if (!chk.checkValidGenericType(owntype)) {
 645                 //if the inferred functional interface type is not well-formed,
 646                 //or if it's not a subtype of the original target, issue an error
 647                 checkContext.report(pos, diags.fragment(Fragments.NoSuitableFunctionalIntfInst(funcInterface)));
 648             }
 649             //propagate constraints as per JLS 18.2.1
 650             checkContext.compatible(owntype, funcInterface, types.noWarnings);
 651             return owntype;
 652         }
 653     }
 654     // </editor-fold>
 655 
 656     // <editor-fold defaultstate="collapsed" desc="Incorporation">
 657 
 658     /**
 659      * This class is the root of all incorporation actions.
 660      */
 661     public abstract class IncorporationAction {
 662         UndetVar uv;
 663         Type t;
 664 
 665         IncorporationAction(UndetVar uv, Type t) {
 666             this.uv = uv;
 667             this.t = t;
 668         }
 669 
 670         public abstract IncorporationAction dup(UndetVar that);
 671 
 672         /**
 673          * Incorporation action entry-point. Subclasses should define the logic associated with
 674          * this incorporation action.
 675          */
 676         abstract void apply(InferenceContext ic, Warner warn);
 677 
 678         /**
 679          * Helper function: perform subtyping through incorporation cache.
 680          */
 681         boolean isSubtype(Type s, Type t, Warner warn) {
 682             return doIncorporationOp(IncorporationBinaryOpKind.IS_SUBTYPE, s, t, warn);
 683         }
 684 
 685         /**
 686          * Helper function: perform type-equivalence through incorporation cache.
 687          */
 688         boolean isSameType(Type s, Type t) {
 689             return doIncorporationOp(IncorporationBinaryOpKind.IS_SAME_TYPE, s, t, null);
 690         }
 691 
 692         @Override
 693         public String toString() {
 694             return String.format("%s[undet=%s,t=%s]", getClass().getSimpleName(), uv.qtype, t);
 695         }
 696     }
 697 
 698     /**
 699      * Bound-check incorporation action. A newly added bound is checked against existing bounds,
 700      * to verify its compatibility; each bound is checked using either subtyping or type equivalence.
 701      */
 702     class CheckBounds extends IncorporationAction {
 703 
 704         InferenceBound from;
 705         BiFunction<InferenceContext, Type, Type> typeFunc;
 706         BiPredicate<InferenceContext, Type> optFilter;
 707 
 708         CheckBounds(UndetVar uv, Type t, InferenceBound from) {
 709             this(uv, t, InferenceContext::asUndetVar, null, from);
 710         }
 711 
 712         CheckBounds(UndetVar uv, Type t, BiFunction<InferenceContext, Type, Type> typeFunc,
 713                     BiPredicate<InferenceContext, Type> typeFilter, InferenceBound from) {
 714             super(uv, t);
 715             this.from = from;
 716             this.typeFunc = typeFunc;
 717             this.optFilter = typeFilter;
 718         }
 719 
 720         @Override
 721         public IncorporationAction dup(UndetVar that) {
 722             return new CheckBounds(that, t, typeFunc, optFilter, from);
 723         }
 724 
 725         @Override
 726         void apply(InferenceContext inferenceContext, Warner warn) {
 727             t = typeFunc.apply(inferenceContext, t);
 728             if (optFilter != null && optFilter.test(inferenceContext, t)) return;
 729             for (InferenceBound to : boundsToCheck()) {
 730                 for (Type b : uv.getBounds(to)) {
 731                     b = typeFunc.apply(inferenceContext, b);
 732                     if (optFilter != null && optFilter.test(inferenceContext, b)) continue;
 733                     boolean success = checkBound(t, b, from, to, warn);
 734                     if (!success) {
 735                         report(from, to);
 736                     }
 737                 }
 738             }
 739         }
 740 
 741         /**
 742          * The list of bound kinds to be checked.
 743          */
 744         EnumSet<InferenceBound> boundsToCheck() {
 745             return (from == InferenceBound.EQ) ?
 746                             EnumSet.allOf(InferenceBound.class) :
 747                             EnumSet.complementOf(EnumSet.of(from));
 748         }
 749 
 750         /**
 751          * Is source type 's' compatible with target type 't' given source and target bound kinds?
 752          */
 753         boolean checkBound(Type s, Type t, InferenceBound ib_s, InferenceBound ib_t, Warner warn) {
 754             if (ib_s.lessThan(ib_t)) {
 755                 return isSubtype(s, t, warn);
 756             } else if (ib_t.lessThan(ib_s)) {
 757                 return isSubtype(t, s, warn);
 758             } else {
 759                 return isSameType(s, t);
 760             }
 761         }
 762 
 763         /**
 764          * Report a bound check error.
 765          */
 766         void report(InferenceBound from, InferenceBound to) {
 767             //this is a workaround to preserve compatibility with existing messages
 768             if (from == to) {
 769                 reportBoundError(uv, from);
 770             } else if (from == InferenceBound.LOWER || to == InferenceBound.EQ) {
 771                 reportBoundError(uv, to, from);
 772             } else {
 773                 reportBoundError(uv, from, to);
 774             }
 775         }
 776 
 777         @Override
 778         public String toString() {
 779             return String.format("%s[undet=%s,t=%s,bound=%s]", getClass().getSimpleName(), uv.qtype, t, from);
 780         }
 781     }
 782 
 783     /**
 784      * Check that the inferred type conforms to all bounds.
 785      */
 786     class CheckInst extends CheckBounds {
 787 
 788         EnumSet<InferenceBound> to;
 789 
 790         CheckInst(UndetVar uv, InferenceBound ib, InferenceBound... rest) {
 791             this(uv, EnumSet.of(ib, rest));
 792         }
 793 
 794         CheckInst(UndetVar uv, EnumSet<InferenceBound> to) {
 795             super(uv, uv.getInst(), InferenceBound.EQ);
 796             this.to = to;
 797         }
 798 
 799         @Override
 800         public IncorporationAction dup(UndetVar that) {
 801             return new CheckInst(that, to);
 802         }
 803 
 804         @Override
 805         EnumSet<InferenceBound> boundsToCheck() {
 806             return to;
 807         }
 808 
 809         @Override
 810         void report(InferenceBound from, InferenceBound to) {
 811             reportInstError(uv, to);
 812         }
 813     }
 814 
 815     /**
 816      * Replace undetvars in bounds and check that the inferred type conforms to all bounds.
 817      */
 818     class SubstBounds extends CheckInst {
 819         SubstBounds(UndetVar uv) {
 820             super(uv, InferenceBound.LOWER, InferenceBound.EQ, InferenceBound.UPPER);
 821         }
 822 
 823         @Override
 824         public IncorporationAction dup(UndetVar that) {
 825             return new SubstBounds(that);
 826         }
 827 
 828         @Override
 829         void apply(InferenceContext inferenceContext, Warner warn) {
 830             for (Type undet : inferenceContext.undetvars) {
 831                 //we could filter out variables not mentioning uv2...
 832                 UndetVar uv2 = (UndetVar)undet;
 833                 uv2.substBounds(List.of(uv.qtype), List.of(uv.getInst()), types);
 834                 checkCompatibleUpperBounds(uv2, inferenceContext);
 835             }
 836             super.apply(inferenceContext, warn);
 837         }
 838 
 839         /**
 840          * Make sure that the upper bounds we got so far lead to a solvable inference
 841          * variable by making sure that a glb exists.
 842          */
 843         void checkCompatibleUpperBounds(UndetVar uv, InferenceContext inferenceContext) {
 844             List<Type> hibounds =
 845                     Type.filter(uv.getBounds(InferenceBound.UPPER), new BoundFilter(inferenceContext));
 846             final Type hb;
 847             if (hibounds.isEmpty())
 848                 hb = syms.objectType;
 849             else if (hibounds.tail.isEmpty())
 850                 hb = hibounds.head;
 851             else
 852                 hb = types.glb(hibounds);
 853             if (hb == null || hb.isErroneous())
 854                 reportBoundError(uv, InferenceBound.UPPER);
 855         }
 856     }
 857 
 858     /**
 859      * Perform pairwise comparison between common generic supertypes of two upper bounds.
 860      */
 861     class CheckUpperBounds extends IncorporationAction {
 862 
 863         public CheckUpperBounds(UndetVar uv, Type t) {
 864             super(uv, t);
 865         }
 866 
 867         @Override
 868         public IncorporationAction dup(UndetVar that) {
 869             return new CheckUpperBounds(that, t);
 870         }
 871 
 872         @Override
 873         void apply(InferenceContext inferenceContext, Warner warn) {
 874             List<Type> boundList = uv.getBounds(InferenceBound.UPPER).stream()
 875                     .collect(types.closureCollector(true, types::isSameType));
 876             for (Type b2 : boundList) {
 877                 if (t == b2) continue;
 878                     /* This wildcard check is temporary workaround. This code may need to be
 879                      * revisited once spec bug JDK-7034922 is fixed.
 880                      */
 881                 if (t != b2 && !t.hasTag(WILDCARD) && !b2.hasTag(WILDCARD)) {
 882                     for (Pair<Type, Type> commonSupers : getParameterizedSupers(t, b2)) {
 883                         List<Type> allParamsSuperBound1 = commonSupers.fst.allparams();
 884                         List<Type> allParamsSuperBound2 = commonSupers.snd.allparams();
 885                         while (allParamsSuperBound1.nonEmpty() && allParamsSuperBound2.nonEmpty()) {
 886                             //traverse the list of all params comparing them
 887                             if (!allParamsSuperBound1.head.hasTag(WILDCARD) &&
 888                                     !allParamsSuperBound2.head.hasTag(WILDCARD)) {
 889                                 if (!isSameType(inferenceContext.asUndetVar(allParamsSuperBound1.head),
 890                                         inferenceContext.asUndetVar(allParamsSuperBound2.head))) {
 891                                     reportBoundError(uv, InferenceBound.UPPER);
 892                                 }
 893                             }
 894                             allParamsSuperBound1 = allParamsSuperBound1.tail;
 895                             allParamsSuperBound2 = allParamsSuperBound2.tail;
 896                         }
 897                         Assert.check(allParamsSuperBound1.isEmpty() && allParamsSuperBound2.isEmpty());
 898                     }
 899                 }
 900             }
 901         }
 902     }
 903 
 904     /**
 905      * Perform propagation of bounds. Given a constraint of the kind {@code alpha <: T}, three
 906      * kind of propagation occur:
 907      *
 908      * <li>T is copied into all matching bounds (i.e. lower/eq bounds) B of alpha such that B=beta (forward propagation)</li>
 909      * <li>if T=beta, matching bounds (i.e. upper bounds) of beta are copied into alpha (backwards propagation)</li>
 910      * <li>if T=beta, sets a symmetric bound on beta (i.e. beta :> alpha) (symmetric propagation) </li>
 911      */
 912     class PropagateBounds extends IncorporationAction {
 913 
 914         InferenceBound ib;
 915 
 916         public PropagateBounds(UndetVar uv, Type t, InferenceBound ib) {
 917             super(uv, t);
 918             this.ib = ib;
 919         }
 920 
 921         @Override
 922         public IncorporationAction dup(UndetVar that) {
 923             return new PropagateBounds(that, t, ib);
 924         }
 925 
 926         void apply(InferenceContext inferenceContext, Warner warner) {
 927             Type undetT = inferenceContext.asUndetVar(t);
 928             if (undetT.hasTag(UNDETVAR) && !((UndetVar)undetT).isCaptured()) {
 929                 UndetVar uv2 = (UndetVar)undetT;
 930                 //symmetric propagation
 931                 uv2.addBound(ib.complement(), uv, types);
 932                 //backwards propagation
 933                 for (InferenceBound ib2 : backwards()) {
 934                     for (Type b : uv2.getBounds(ib2)) {
 935                         uv.addBound(ib2, b, types);
 936                     }
 937                 }
 938             }
 939             //forward propagation
 940             for (InferenceBound ib2 : forward()) {
 941                 for (Type l : uv.getBounds(ib2)) {
 942                     Type undet = inferenceContext.asUndetVar(l);
 943                     if (undet.hasTag(TypeTag.UNDETVAR) && !((UndetVar)undet).isCaptured()) {
 944                         UndetVar uv2 = (UndetVar)undet;
 945                         uv2.addBound(ib, inferenceContext.asInstType(t), types);
 946                     }
 947                 }
 948             }
 949         }
 950 
 951         EnumSet<InferenceBound> forward() {
 952             return (ib == InferenceBound.EQ) ?
 953                     EnumSet.of(InferenceBound.EQ) : EnumSet.complementOf(EnumSet.of(ib));
 954         }
 955 
 956         EnumSet<InferenceBound> backwards() {
 957             return (ib == InferenceBound.EQ) ?
 958                     EnumSet.allOf(InferenceBound.class) : EnumSet.of(ib);
 959         }
 960 
 961         @Override
 962         public String toString() {
 963             return String.format("%s[undet=%s,t=%s,bound=%s]", getClass().getSimpleName(), uv.qtype, t, ib);
 964         }
 965     }
 966 
 967     /**
 968      * This class models an incorporation engine. The engine is responsible for listening to
 969      * changes in inference variables and register incorporation actions accordingly.
 970      */
 971     class IncorporationEngine implements UndetVarListener {
 972 
 973         @Override
 974         public void varInstantiated(UndetVar uv) {
 975             uv.incorporationActions.addFirst(new SubstBounds(uv));
 976         }
 977 
 978         @Override
 979         public void varBoundChanged(UndetVar uv, InferenceBound ib, Type bound, boolean update) {
 980             if (uv.isCaptured()) return;
 981             uv.incorporationActions.addAll(getIncorporationActions(uv, ib, bound, update));
 982         }
 983 
 984         List<IncorporationAction> getIncorporationActions(UndetVar uv, InferenceBound ib, Type t, boolean update) {
 985             ListBuffer<IncorporationAction> actions = new ListBuffer<>();
 986             Type inst = uv.getInst();
 987             if (inst != null) {
 988                 actions.add(new CheckInst(uv, ib));
 989             }
 990             actions.add(new CheckBounds(uv, t, ib));
 991 
 992             if (update) {
 993                 return actions.toList();
 994             }
 995 
 996             if (ib == InferenceBound.UPPER) {
 997                 actions.add(new CheckUpperBounds(uv, t));
 998             }
 999 
1000             actions.add(new PropagateBounds(uv, t, ib));
1001 
1002             return actions.toList();
1003         }
1004     }
1005 
1006     IncorporationEngine incorporationEngine = new IncorporationEngine();
1007 
1008     /** max number of incorporation rounds. */
1009     static final int MAX_INCORPORATION_STEPS = 10000;
1010 
1011     /**
1012      * Check bounds and perform incorporation.
1013      */
1014     void doIncorporation(InferenceContext inferenceContext, Warner warn) throws InferenceException {
1015         try {
1016             boolean progress = true;
1017             int round = 0;
1018             while (progress && round < MAX_INCORPORATION_STEPS) {
1019                 progress = false;
1020                 for (Type t : inferenceContext.undetvars) {
1021                     UndetVar uv = (UndetVar)t;
1022                     if (!uv.incorporationActions.isEmpty()) {
1023                         progress = true;
1024                         uv.incorporationActions.removeFirst().apply(inferenceContext, warn);
1025                     }
1026                 }
1027                 round++;
1028             }
1029         } finally {
1030             incorporationCache.clear();
1031         }
1032     }
1033 
1034     /* If for two types t and s there is a least upper bound that contains
1035      * parameterized types G1, G2 ... Gn, then there exists supertypes of 't' of the form
1036      * G1<T1, ..., Tn>, G2<T1, ..., Tn>, ... Gn<T1, ..., Tn> and supertypes of 's' of the form
1037      * G1<S1, ..., Sn>, G2<S1, ..., Sn>, ... Gn<S1, ..., Sn> which will be returned by this method.
1038      * If no such common supertypes exists then an empty list is returned.
1039      *
1040      * As an example for the following input:
1041      *
1042      * t = java.util.ArrayList<java.lang.String>
1043      * s = java.util.List<T>
1044      *
1045      * we get this output (singleton list):
1046      *
1047      * [Pair[java.util.List<java.lang.String>,java.util.List<T>]]
1048      */
1049     private List<Pair<Type, Type>> getParameterizedSupers(Type t, Type s) {
1050         Type lubResult = types.lub(t, s);
1051         if (lubResult == syms.errType || lubResult == syms.botType) {
1052             return List.nil();
1053         }
1054         List<Type> supertypesToCheck = lubResult.isIntersection() ?
1055                 ((IntersectionClassType)lubResult).getComponents() :
1056                 List.of(lubResult);
1057         ListBuffer<Pair<Type, Type>> commonSupertypes = new ListBuffer<>();
1058         for (Type sup : supertypesToCheck) {
1059             if (sup.isParameterized()) {
1060                 Type asSuperOfT = asSuper(t, sup);
1061                 Type asSuperOfS = asSuper(s, sup);
1062                 commonSupertypes.add(new Pair<>(asSuperOfT, asSuperOfS));
1063             }
1064         }
1065         return commonSupertypes.toList();
1066     }
1067     //where
1068         private Type asSuper(Type t, Type sup) {
1069             return (sup.hasTag(ARRAY)) ?
1070                     new ArrayType(asSuper(types.elemtype(t), types.elemtype(sup)), syms.arrayClass) :
1071                     types.asSuper(t, sup.tsym);
1072         }
1073 
1074     boolean doIncorporationOp(IncorporationBinaryOpKind opKind, Type op1, Type op2, Warner warn) {
1075             IncorporationBinaryOp newOp = new IncorporationBinaryOp(opKind, op1, op2);
1076             Boolean res = incorporationCache.get(newOp);
1077             if (res == null) {
1078                 incorporationCache.put(newOp, res = newOp.apply(warn));
1079             }
1080             return res;
1081         }
1082 
1083     /**
1084      * Three kinds of basic operation are supported as part of an incorporation step:
1085      * (i) subtype check, (ii) same type check and (iii) bound addition (either
1086      * upper/lower/eq bound).
1087      */
1088     enum IncorporationBinaryOpKind {
1089         IS_SUBTYPE() {
1090             @Override
1091             boolean apply(Type op1, Type op2, Warner warn, Types types) {
1092                 return types.isSubtypeUnchecked(op1, op2, warn);
1093             }
1094         },
1095         IS_SAME_TYPE() {
1096             @Override
1097             boolean apply(Type op1, Type op2, Warner warn, Types types) {
1098                 return types.isSameType(op1, op2);
1099             }
1100         };
1101 
1102         abstract boolean apply(Type op1, Type op2, Warner warn, Types types);
1103     }
1104 
1105     /**
1106      * This class encapsulates a basic incorporation operation; incorporation
1107      * operations takes two type operands and a kind. Each operation performed
1108      * during an incorporation round is stored in a cache, so that operations
1109      * are not executed unnecessarily (which would potentially lead to adding
1110      * same bounds over and over).
1111      */
1112     class IncorporationBinaryOp {
1113 
1114         IncorporationBinaryOpKind opKind;
1115         Type op1;
1116         Type op2;
1117 
1118         IncorporationBinaryOp(IncorporationBinaryOpKind opKind, Type op1, Type op2) {
1119             this.opKind = opKind;
1120             this.op1 = op1;
1121             this.op2 = op2;
1122         }
1123 
1124         @Override
1125         public boolean equals(Object o) {
1126             return (o instanceof IncorporationBinaryOp incorporationBinaryOp)
1127                     && opKind == incorporationBinaryOp.opKind
1128                     && types.isSameType(op1, incorporationBinaryOp.op1)
1129                     && types.isSameType(op2, incorporationBinaryOp.op2);
1130         }
1131 
1132         @Override
1133         public int hashCode() {
1134             int result = opKind.hashCode();
1135             result *= 127;
1136             result += types.hashCode(op1);
1137             result *= 127;
1138             result += types.hashCode(op2);
1139             return result;
1140         }
1141 
1142         boolean apply(Warner warn) {
1143             return opKind.apply(op1, op2, warn, types);
1144         }
1145     }
1146 
1147     /** an incorporation cache keeps track of all executed incorporation-related operations */
1148     Map<IncorporationBinaryOp, Boolean> incorporationCache = new HashMap<>();
1149 
1150     protected static class BoundFilter implements Predicate<Type> {
1151 
1152         InferenceContext inferenceContext;
1153 
1154         public BoundFilter(InferenceContext inferenceContext) {
1155             this.inferenceContext = inferenceContext;
1156         }
1157 
1158         @Override
1159         public boolean test(Type t) {
1160             return !t.isErroneous() && !inferenceContext.free(t) &&
1161                     !t.hasTag(BOT);
1162         }
1163     }
1164 
1165     /**
1166      * Incorporation error: mismatch between inferred type and given bound.
1167      */
1168     void reportInstError(UndetVar uv, InferenceBound ib) {
1169         switch (ib) {
1170             case EQ:
1171                 throw error(diags.fragment(Fragments.InferredDoNotConformToEqBounds(uv.getInst(), uv.getBounds(ib))));
1172             case LOWER:
1173                 throw error(diags.fragment(Fragments.InferredDoNotConformToLowerBounds(uv.getInst(), uv.getBounds(ib))));
1174             case UPPER:
1175                 throw error(diags.fragment(Fragments.InferredDoNotConformToUpperBounds(uv.getInst(), uv.getBounds(ib))));
1176         }
1177     }
1178 
1179     /**
1180      * Incorporation error: mismatch between two (or more) bounds of same kind.
1181      */
1182     void reportBoundError(UndetVar uv, InferenceBound ib) {
1183         switch (ib) {
1184             case EQ:
1185                 throw error(diags.fragment(Fragments.IncompatibleEqBounds(uv.qtype, uv.getBounds(ib))));
1186             case UPPER:
1187                 throw error(diags.fragment(Fragments.IncompatibleUpperBounds(uv.qtype, uv.getBounds(ib))));
1188             case LOWER:
1189                 throw new AssertionError("this case shouldn't happen");
1190         }
1191     }
1192 
1193     /**
1194      * Incorporation error: mismatch between two (or more) bounds of different kinds.
1195      */
1196     void reportBoundError(UndetVar uv, InferenceBound ib1, InferenceBound ib2) {
1197         throw error(diags.fragment(Fragments.IncompatibleBounds(
1198                 uv.qtype,
1199                 getBoundFragment(ib1, uv.getBounds(ib1)),
1200                 getBoundFragment(ib2, uv.getBounds(ib2)))));
1201     }
1202 
1203     Fragment getBoundFragment(InferenceBound ib, List<Type> types) {
1204         switch (ib) {
1205             case EQ: return Fragments.EqBounds(types);
1206             case LOWER: return Fragments.LowerBounds(types);
1207             case UPPER: return Fragments.UpperBounds(types);
1208         }
1209         throw new AssertionError("can't get to this place");
1210     }
1211 
1212     // </editor-fold>
1213 
1214     // <editor-fold defaultstate="collapsed" desc="Inference engine">
1215     /**
1216      * Graph inference strategy - act as an input to the inference solver; a strategy is
1217      * composed of two ingredients: (i) find a node to solve in the inference graph,
1218      * and (ii) tell th engine when we are done fixing inference variables
1219      */
1220     interface GraphStrategy {
1221 
1222         /**
1223          * A NodeNotFoundException is thrown whenever an inference strategy fails
1224          * to pick the next node to solve in the inference graph.
1225          */
1226         public static class NodeNotFoundException extends RuntimeException {
1227             private static final long serialVersionUID = 0;
1228 
1229             transient InferenceGraph graph;
1230 
1231             public NodeNotFoundException(InferenceGraph graph) {
1232                 this.graph = graph;
1233             }
1234 
1235             @Override
1236             public Throwable fillInStackTrace() {
1237                 // This is an internal exception; the stack trace is irrelevant.
1238                 return this;
1239             }
1240         }
1241         /**
1242          * Pick the next node (leaf) to solve in the graph
1243          */
1244         Node pickNode(InferenceGraph g) throws NodeNotFoundException;
1245         /**
1246          * Is this the last step?
1247          */
1248         boolean done();
1249     }
1250 
1251     /**
1252      * Simple solver strategy class that locates all leaves inside a graph
1253      * and picks the first leaf as the next node to solve
1254      */
1255     abstract class LeafSolver implements GraphStrategy {
1256         public Node pickNode(InferenceGraph g) {
1257             if (g.nodes.isEmpty()) {
1258                 //should not happen
1259                 throw new NodeNotFoundException(g);
1260             }
1261             return g.nodes.get(0);
1262         }
1263     }
1264 
1265     /**
1266      * This solver uses an heuristic to pick the best leaf - the heuristic
1267      * tries to select the node that has maximal probability to contain one
1268      * or more inference variables in a given list
1269      */
1270     abstract class BestLeafSolver extends LeafSolver {
1271 
1272         /** list of ivars of which at least one must be solved */
1273         List<Type> varsToSolve;
1274 
1275         BestLeafSolver(List<Type> varsToSolve) {
1276             this.varsToSolve = varsToSolve;
1277         }
1278 
1279         /**
1280          * Computes a path that goes from a given node to the leaves in the graph.
1281          * Typically this will start from a node containing a variable in
1282          * {@code varsToSolve}. For any given path, the cost is computed as the total
1283          * number of type-variables that should be eagerly instantiated across that path.
1284          */
1285         Pair<List<Node>, Integer> computeTreeToLeafs(Node n) {
1286             Pair<List<Node>, Integer> cachedPath = treeCache.get(n);
1287             if (cachedPath == null) {
1288                 //cache miss
1289                 if (n.isLeaf()) {
1290                     //if leaf, stop
1291                     cachedPath = new Pair<>(List.of(n), n.data.length());
1292                 } else {
1293                     //if non-leaf, proceed recursively
1294                     Pair<List<Node>, Integer> path = new Pair<>(List.of(n), n.data.length());
1295                     for (Node n2 : n.getAllDependencies()) {
1296                         if (n2 == n) continue;
1297                         Pair<List<Node>, Integer> subpath = computeTreeToLeafs(n2);
1298                         path = new Pair<>(path.fst.prependList(subpath.fst),
1299                                           path.snd + subpath.snd);
1300                     }
1301                     cachedPath = path;
1302                 }
1303                 //save results in cache
1304                 treeCache.put(n, cachedPath);
1305             }
1306             return cachedPath;
1307         }
1308 
1309         /** cache used to avoid redundant computation of tree costs */
1310         final Map<Node, Pair<List<Node>, Integer>> treeCache = new HashMap<>();
1311 
1312         /** constant value used to mark non-existent paths */
1313         final Pair<List<Node>, Integer> noPath = new Pair<>(null, Integer.MAX_VALUE);
1314 
1315         /**
1316          * Pick the leaf that minimize cost
1317          */
1318         @Override
1319         public Node pickNode(final InferenceGraph g) {
1320             treeCache.clear(); //graph changes at every step - cache must be cleared
1321             Pair<List<Node>, Integer> bestPath = noPath;
1322             for (Node n : g.nodes) {
1323                 if (!Collections.disjoint(n.data, varsToSolve)) {
1324                     Pair<List<Node>, Integer> path = computeTreeToLeafs(n);
1325                     //discard all paths containing at least a node in the
1326                     //closure computed above
1327                     if (path.snd < bestPath.snd) {
1328                         bestPath = path;
1329                     }
1330                 }
1331             }
1332             if (bestPath == noPath) {
1333                 //no path leads there
1334                 throw new NodeNotFoundException(g);
1335             }
1336             return bestPath.fst.head;
1337         }
1338     }
1339 
1340     /**
1341      * The inference process can be thought of as a sequence of steps. Each step
1342      * instantiates an inference variable using a subset of the inference variable
1343      * bounds, if certain condition are met. Decisions such as the sequence in which
1344      * steps are applied, or which steps are to be applied are left to the inference engine.
1345      */
1346     enum InferenceStep {
1347 
1348         /**
1349          * Instantiate an inference variables using one of its (ground) equality
1350          * constraints
1351          */
1352         EQ(InferenceBound.EQ) {
1353             @Override
1354             Type solve(UndetVar uv, InferenceContext inferenceContext) {
1355                 return filterBounds(uv, inferenceContext).head;
1356             }
1357         },
1358         /**
1359          * Instantiate an inference variables using its (ground) lower bounds. Such
1360          * bounds are merged together using lub().
1361          */
1362         LOWER(InferenceBound.LOWER) {
1363             @Override
1364             Type solve(UndetVar uv, InferenceContext inferenceContext) {
1365                 Infer infer = inferenceContext.infer;
1366                 List<Type> lobounds = filterBounds(uv, inferenceContext);
1367                 //note: lobounds should have at least one element
1368                 Type owntype = lobounds.tail.tail == null  ? lobounds.head : infer.types.lub(lobounds);
1369                 if (owntype.isPrimitive() || owntype.hasTag(ERROR)) {
1370                     throw infer.error(infer.diags.fragment(Fragments.NoUniqueMinimalInstanceExists(uv.qtype, lobounds)));
1371                 } else {
1372                     return owntype;
1373                 }
1374             }
1375         },
1376         /**
1377          * Infer uninstantiated/unbound inference variables occurring in 'throws'
1378          * clause as RuntimeException
1379          */
1380         THROWS(InferenceBound.UPPER) {
1381             @Override
1382             public boolean accepts(UndetVar t, InferenceContext inferenceContext) {
1383                 if (!t.isThrows()) {
1384                     //not a throws undet var
1385                     return false;
1386                 }
1387                 Types types = inferenceContext.types;
1388                 Symtab syms = inferenceContext.infer.syms;
1389                 return t.getBounds(InferenceBound.UPPER).stream()
1390                         .filter(b -> !inferenceContext.free(b))
1391                         .allMatch(u -> types.isSubtype(syms.runtimeExceptionType, u));
1392             }
1393 
1394             @Override
1395             Type solve(UndetVar uv, InferenceContext inferenceContext) {
1396                 return inferenceContext.infer.syms.runtimeExceptionType;
1397             }
1398         },
1399         /**
1400          * Instantiate an inference variables using its (ground) upper bounds. Such
1401          * bounds are merged together using glb().
1402          */
1403         UPPER(InferenceBound.UPPER) {
1404             @Override
1405             Type solve(UndetVar uv, InferenceContext inferenceContext) {
1406                 Infer infer = inferenceContext.infer;
1407                 List<Type> hibounds = filterBounds(uv, inferenceContext);
1408                 //note: hibounds should have at least one element
1409                 Type owntype = hibounds.tail.tail == null  ? hibounds.head : infer.types.glb(hibounds);
1410                 if (owntype.isPrimitive() || owntype.hasTag(ERROR)) {
1411                     throw infer.error(infer.diags.fragment(Fragments.NoUniqueMaximalInstanceExists(uv.qtype, hibounds)));
1412                 } else {
1413                     return owntype;
1414                 }
1415             }
1416         },
1417         /**
1418          * Like the former; the only difference is that this step can only be applied
1419          * if all upper/lower bounds are ground.
1420          */
1421         CAPTURED(InferenceBound.UPPER) {
1422             @Override
1423             public boolean accepts(UndetVar t, InferenceContext inferenceContext) {
1424                 return t.isCaptured() &&
1425                         !inferenceContext.free(t.getBounds(InferenceBound.UPPER, InferenceBound.LOWER));
1426             }
1427 
1428             @Override
1429             Type solve(UndetVar uv, InferenceContext inferenceContext) {
1430                 Infer infer = inferenceContext.infer;
1431                 Type upper = UPPER.filterBounds(uv, inferenceContext).nonEmpty() ?
1432                         UPPER.solve(uv, inferenceContext) :
1433                         infer.syms.objectType;
1434                 Type lower = LOWER.filterBounds(uv, inferenceContext).nonEmpty() ?
1435                         LOWER.solve(uv, inferenceContext) :
1436                         infer.syms.botType;
1437                 CapturedType prevCaptured = (CapturedType)uv.qtype;
1438                 return new CapturedType(prevCaptured.tsym.name, prevCaptured.tsym.owner,
1439                                         upper, lower, prevCaptured.wildcard);
1440             }
1441         };
1442 
1443         final InferenceBound ib;
1444 
1445         InferenceStep(InferenceBound ib) {
1446             this.ib = ib;
1447         }
1448 
1449         /**
1450          * Find an instantiated type for a given inference variable within
1451          * a given inference context
1452          */
1453         abstract Type solve(UndetVar uv, InferenceContext inferenceContext);
1454 
1455         /**
1456          * Can the inference variable be instantiated using this step?
1457          */
1458         public boolean accepts(UndetVar t, InferenceContext inferenceContext) {
1459             return filterBounds(t, inferenceContext).nonEmpty() && !t.isCaptured();
1460         }
1461 
1462         /**
1463          * Return the subset of ground bounds in a given bound set (i.e. eq/lower/upper)
1464          */
1465         List<Type> filterBounds(UndetVar uv, InferenceContext inferenceContext) {
1466             return Type.filter(uv.getBounds(ib), new BoundFilter(inferenceContext));
1467         }
1468     }
1469 
1470     /**
1471      * This enumeration defines the sequence of steps to be applied when the
1472      * graph solver is used. This order is defined so as to maximize compatibility
1473      * w.r.t. old inference routine (see JLS SE 7 15.12.2.7/15.12.2.8).
1474      */
1475     enum GraphInferenceSteps {
1476 
1477         EQ(EnumSet.of(InferenceStep.EQ)),
1478         EQ_LOWER(EnumSet.of(InferenceStep.EQ, InferenceStep.LOWER)),
1479         EQ_LOWER_THROWS_UPPER_CAPTURED(EnumSet.of(InferenceStep.EQ, InferenceStep.LOWER, InferenceStep.UPPER, InferenceStep.THROWS, InferenceStep.CAPTURED));
1480 
1481         final EnumSet<InferenceStep> steps;
1482 
1483         GraphInferenceSteps(EnumSet<InferenceStep> steps) {
1484             this.steps = steps;
1485         }
1486     }
1487 
1488     /**
1489      * There are two kinds of dependencies between inference variables. The basic
1490      * kind of dependency (or bound dependency) arises when a variable mention
1491      * another variable in one of its bounds. There's also a more subtle kind
1492      * of dependency that arises when a variable 'might' lead to better constraints
1493      * on another variable (this is typically the case with variables holding up
1494      * stuck expressions).
1495      */
1496     enum DependencyKind implements GraphUtils.DependencyKind {
1497 
1498         /** bound dependency */
1499         BOUND("dotted"),
1500         /** stuck dependency */
1501         STUCK("dashed");
1502 
1503         final String dotStyle;
1504 
1505         private DependencyKind(String dotStyle) {
1506             this.dotStyle = dotStyle;
1507         }
1508     }
1509 
1510     /**
1511      * This is the graph inference solver - the solver organizes all inference variables in
1512      * a given inference context by bound dependencies - in the general case, such dependencies
1513      * would lead to a cyclic directed graph (hence the name); the dependency info is used to build
1514      * an acyclic graph, where all cyclic variables are bundled together. An inference
1515      * step corresponds to solving a node in the acyclic graph - this is done by
1516      * relying on a given strategy (see GraphStrategy).
1517      */
1518     class GraphSolver {
1519 
1520         InferenceContext inferenceContext;
1521         Warner warn;
1522 
1523         GraphSolver(InferenceContext inferenceContext, Warner warn) {
1524             this.inferenceContext = inferenceContext;
1525             this.warn = warn;
1526         }
1527 
1528         /**
1529          * Solve variables in a given inference context. The amount of variables
1530          * to be solved, and the way in which the underlying acyclic graph is explored
1531          * depends on the selected solver strategy.
1532          */
1533         void solve(GraphStrategy sstrategy) {
1534             doIncorporation(inferenceContext, warn); //initial propagation of bounds
1535             InferenceGraph inferenceGraph = new InferenceGraph();
1536             while (!sstrategy.done()) {
1537                 if (dependenciesFolder != null) {
1538                     //add this graph to the pending queue
1539                     pendingGraphs = pendingGraphs.prepend(inferenceGraph.toDot());
1540                 }
1541                 InferenceGraph.Node nodeToSolve = sstrategy.pickNode(inferenceGraph);
1542                 List<Type> varsToSolve = List.from(nodeToSolve.data);
1543                 List<Type> saved_undet = inferenceContext.save();
1544                 try {
1545                     //repeat until all variables are solved
1546                     outer: while (Type.containsAny(inferenceContext.restvars(), varsToSolve)) {
1547                         //for each inference phase
1548                         for (GraphInferenceSteps step : GraphInferenceSteps.values()) {
1549                             if (inferenceContext.solveBasic(varsToSolve, step.steps).nonEmpty()) {
1550                                 doIncorporation(inferenceContext, warn);
1551                                 continue outer;
1552                             }
1553                         }
1554                         //no progress
1555                         throw error(null);
1556                     }
1557                 }
1558                 catch (InferenceException ex) {
1559                     //did we fail because of interdependent ivars?
1560                     inferenceContext.rollback(saved_undet);
1561                     instantiateAsUninferredVars(varsToSolve, inferenceContext);
1562                     doIncorporation(inferenceContext, warn);
1563                 }
1564                 inferenceGraph.deleteNode(nodeToSolve);
1565             }
1566         }
1567 
1568         /**
1569          * The dependencies between the inference variables that need to be solved
1570          * form a (possibly cyclic) graph. This class reduces the original dependency graph
1571          * to an acyclic version, where cyclic nodes are folded into a single 'super node'.
1572          */
1573         class InferenceGraph {
1574 
1575             /**
1576              * This class represents a node in the graph. Each node corresponds
1577              * to an inference variable and has edges (dependencies) on other
1578              * nodes. The node defines an entry point that can be used to receive
1579              * updates on the structure of the graph this node belongs to (used to
1580              * keep dependencies in sync).
1581              */
1582             class Node extends GraphUtils.TarjanNode<ListBuffer<Type>, Node> implements DottableNode<ListBuffer<Type>, Node> {
1583 
1584                 /** node dependencies */
1585                 Set<Node> deps;
1586 
1587                 Node(Type ivar) {
1588                     super(ListBuffer.of(ivar));
1589                     this.deps = new LinkedHashSet<>();
1590                 }
1591 
1592                 @Override
1593                 public GraphUtils.DependencyKind[] getSupportedDependencyKinds() {
1594                     return new GraphUtils.DependencyKind[] { DependencyKind.BOUND };
1595                 }
1596 
1597                 public Iterable<? extends Node> getAllDependencies() {
1598                     return deps;
1599                 }
1600 
1601                 @Override
1602                 public Collection<? extends Node> getDependenciesByKind(GraphUtils.DependencyKind dk) {
1603                     if (dk == DependencyKind.BOUND) {
1604                         return deps;
1605                     } else {
1606                         throw new IllegalStateException();
1607                     }
1608                 }
1609 
1610                 /**
1611                  * Adds dependency with given kind.
1612                  */
1613                 protected void addDependency(Node depToAdd) {
1614                     deps.add(depToAdd);
1615                 }
1616 
1617                 /**
1618                  * Add multiple dependencies of same given kind.
1619                  */
1620                 protected void addDependencies(Set<Node> depsToAdd) {
1621                     for (Node n : depsToAdd) {
1622                         addDependency(n);
1623                     }
1624                 }
1625 
1626                 /**
1627                  * Remove a dependency, regardless of its kind.
1628                  */
1629                 protected boolean removeDependency(Node n) {
1630                     return deps.remove(n);
1631                 }
1632 
1633                 /**
1634                  * Compute closure of a give node, by recursively walking
1635                  * through all its dependencies.
1636                  */
1637                 protected Set<Node> closure() {
1638                     Set<Node> closure = new HashSet<>();
1639                     closureInternal(closure);
1640                     return closure;
1641                 }
1642 
1643                 private void closureInternal(Set<Node> closure) {
1644                     if (closure.add(this)) {
1645                         for (Node n : deps) {
1646                             n.closureInternal(closure);
1647                         }
1648                     }
1649                 }
1650 
1651                 /**
1652                  * Is this node a leaf? This means either the node has no dependencies,
1653                  * or it just has self-dependencies.
1654                  */
1655                 protected boolean isLeaf() {
1656                     //no deps, or only one self dep
1657                     if (deps.isEmpty()) return true;
1658                     for (Node n : deps) {
1659                         if (n != this) {
1660                             return false;
1661                         }
1662                     }
1663                     return true;
1664                 }
1665 
1666                 /**
1667                  * Merge this node with another node, acquiring its dependencies.
1668                  * This routine is used to merge all cyclic node together and
1669                  * form an acyclic graph.
1670                  */
1671                 protected void mergeWith(List<? extends Node> nodes) {
1672                     for (Node n : nodes) {
1673                         Assert.check(n.data.length() == 1, "Attempt to merge a compound node!");
1674                         data.appendList(n.data);
1675                         addDependencies(n.deps);
1676                     }
1677                     //update deps
1678                     Set<Node> deps2 = new LinkedHashSet<>();
1679                     for (Node d : deps) {
1680                         if (data.contains(d.data.first())) {
1681                             deps2.add(this);
1682                         } else {
1683                             deps2.add(d);
1684                         }
1685                     }
1686                     deps = deps2;
1687                 }
1688 
1689                 /**
1690                  * Notify all nodes that something has changed in the graph
1691                  * topology.
1692                  */
1693                 private void graphChanged(Node from, Node to) {
1694                     if (removeDependency(from)) {
1695                         if (to != null) {
1696                             addDependency(to);
1697                         }
1698                     }
1699                 }
1700 
1701                 @Override
1702                 public Properties nodeAttributes() {
1703                     Properties p = new Properties();
1704                     p.put("label", "\"" + toString() + "\"");
1705                     return p;
1706                 }
1707 
1708                 @Override
1709                 public Properties dependencyAttributes(Node sink, GraphUtils.DependencyKind dk) {
1710                     Properties p = new Properties();
1711                     p.put("style", ((DependencyKind)dk).dotStyle);
1712                     StringBuilder buf = new StringBuilder();
1713                     String sep = "";
1714                     for (Type from : data) {
1715                         UndetVar uv = (UndetVar)inferenceContext.asUndetVar(from);
1716                         for (Type bound : uv.getBounds(InferenceBound.values())) {
1717                             if (bound.containsAny(List.from(sink.data))) {
1718                                 buf.append(sep);
1719                                 buf.append(bound);
1720                                 sep = ",";
1721                             }
1722                         }
1723                     }
1724                     p.put("label", "\"" + buf.toString() + "\"");
1725                     return p;
1726                 }
1727             }
1728 
1729             /** the nodes in the inference graph */
1730             ArrayList<Node> nodes;
1731 
1732             InferenceGraph() {
1733                 initNodes();
1734             }
1735 
1736             /**
1737              * Basic lookup helper for retrieving a graph node given an inference
1738              * variable type.
1739              */
1740             public Node findNode(Type t) {
1741                 for (Node n : nodes) {
1742                     if (n.data.contains(t)) {
1743                         return n;
1744                     }
1745                 }
1746                 return null;
1747             }
1748 
1749             /**
1750              * Delete a node from the graph. This update the underlying structure
1751              * of the graph (including dependencies) via listeners updates.
1752              */
1753             public void deleteNode(Node n) {
1754                 Assert.check(nodes.contains(n));
1755                 nodes.remove(n);
1756                 notifyUpdate(n, null);
1757             }
1758 
1759             /**
1760              * Notify all nodes of a change in the graph. If the target node is
1761              * {@code null} the source node is assumed to be removed.
1762              */
1763             void notifyUpdate(Node from, Node to) {
1764                 for (Node n : nodes) {
1765                     n.graphChanged(from, to);
1766                 }
1767             }
1768 
1769             /**
1770              * Create the graph nodes. First a simple node is created for every inference
1771              * variables to be solved. Then Tarjan is used to found all connected components
1772              * in the graph. For each component containing more than one node, a super node is
1773              * created, effectively replacing the original cyclic nodes.
1774              */
1775             void initNodes() {
1776                 //add nodes
1777                 nodes = new ArrayList<>();
1778                 for (Type t : inferenceContext.restvars()) {
1779                     nodes.add(new Node(t));
1780                 }
1781                 //add dependencies
1782                 for (Node n_i : nodes) {
1783                     Type i = n_i.data.first();
1784                     for (Node n_j : nodes) {
1785                         Type j = n_j.data.first();
1786                         // don't compare a variable to itself
1787                         if (i != j) {
1788                             UndetVar uv_i = (UndetVar)inferenceContext.asUndetVar(i);
1789                             if (Type.containsAny(uv_i.getBounds(InferenceBound.values()), List.of(j))) {
1790                                 //update i's bound dependencies
1791                                 n_i.addDependency(n_j);
1792                             }
1793                         }
1794                     }
1795                 }
1796                 //merge cyclic nodes
1797                 ArrayList<Node> acyclicNodes = new ArrayList<>();
1798                 for (List<? extends Node> conSubGraph : GraphUtils.tarjan(nodes)) {
1799                     if (conSubGraph.length() > 1) {
1800                         Node root = conSubGraph.head;
1801                         root.mergeWith(conSubGraph.tail);
1802                         for (Node n : conSubGraph) {
1803                             notifyUpdate(n, root);
1804                         }
1805                     }
1806                     acyclicNodes.add(conSubGraph.head);
1807                 }
1808                 nodes = acyclicNodes;
1809             }
1810 
1811             /**
1812              * Debugging: dot representation of this graph
1813              */
1814             String toDot() {
1815                 StringBuilder buf = new StringBuilder();
1816                 for (Type t : inferenceContext.undetvars) {
1817                     UndetVar uv = (UndetVar)t;
1818                     buf.append(String.format("var %s - upper bounds = %s, lower bounds = %s, eq bounds = %s\\n",
1819                             uv.qtype, uv.getBounds(InferenceBound.UPPER), uv.getBounds(InferenceBound.LOWER),
1820                             uv.getBounds(InferenceBound.EQ)));
1821                 }
1822                 return GraphUtils.toDot(nodes, "inferenceGraph" + hashCode(), buf.toString());
1823             }
1824         }
1825     }
1826     // </editor-fold>
1827 
1828     // <editor-fold defaultstate="collapsed" desc="Inference context">
1829     /**
1830      * Functional interface for defining inference callbacks. Certain actions
1831      * (i.e. subtyping checks) might need to be redone after all inference variables
1832      * have been fixed.
1833      */
1834     interface FreeTypeListener {
1835         void typesInferred(InferenceContext inferenceContext);
1836     }
1837 
1838     final InferenceContext emptyContext;
1839     // </editor-fold>
1840 }