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