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