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