DeferredAttr.java revision 2793:ab5991ac1286
133965Sjdp/*
2130570Sobrien * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
3218822Sdim * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
433965Sjdp *
5130570Sobrien * This code is free software; you can redistribute it and/or modify it
633965Sjdp * under the terms of the GNU General Public License version 2 only, as
7130570Sobrien * published by the Free Software Foundation.  Oracle designates this
8130570Sobrien * particular file as subject to the "Classpath" exception as provided
9130570Sobrien * by Oracle in the LICENSE file that accompanied this code.
10130570Sobrien *
1133965Sjdp * This code is distributed in the hope that it will be useful, but WITHOUT
12130570Sobrien * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13130570Sobrien * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14130570Sobrien * version 2 for more details (a copy is included in the LICENSE file that
15130570Sobrien * accompanied this code).
1633965Sjdp *
17130570Sobrien * You should have received a copy of the GNU General Public License version
18130570Sobrien * 2 along with this work; if not, write to the Free Software Foundation,
19218822Sdim * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2033965Sjdp *
21218822Sdim * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2233965Sjdp * or visit www.oracle.com if you need additional information or have any
2333965Sjdp * questions.
2433965Sjdp */
2533965Sjdp
26218822Sdimpackage com.sun.tools.javac.comp;
2733965Sjdp
28130570Sobrienimport com.sun.source.tree.LambdaExpressionTree.BodyKind;
29130570Sobrienimport com.sun.tools.javac.code.*;
30104840Sobrienimport com.sun.tools.javac.comp.Resolve.ResolveError;
3160509Sobrienimport com.sun.tools.javac.resources.CompilerProperties;
3233965Sjdpimport com.sun.tools.javac.resources.CompilerProperties.Fragments;
3333965Sjdpimport com.sun.tools.javac.tree.*;
3433965Sjdpimport com.sun.tools.javac.util.*;
35130570Sobrienimport com.sun.tools.javac.util.DefinedBy.Api;
3677302Sobrienimport com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
37130570Sobrienimport com.sun.tools.javac.code.Symbol.*;
38130570Sobrienimport com.sun.tools.javac.code.Type.*;
3977302Sobrienimport com.sun.tools.javac.comp.Attr.ResultInfo;
40130570Sobrienimport com.sun.tools.javac.comp.Infer.InferenceContext;
41130570Sobrienimport com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
4277302Sobrienimport com.sun.tools.javac.tree.JCTree.*;
43130570Sobrienimport com.sun.tools.javac.util.JCDiagnostic.DiagnosticType;
44130570Sobrienimport com.sun.tools.javac.util.Log.DeferredDiagnosticHandler;
4577302Sobrien
46130570Sobrienimport java.util.ArrayList;
47130570Sobrienimport java.util.Collections;
4877302Sobrienimport java.util.EnumMap;
49130570Sobrienimport java.util.EnumSet;
50130570Sobrienimport java.util.LinkedHashMap;
5177302Sobrienimport java.util.LinkedHashSet;
52130570Sobrienimport java.util.Map;
53130570Sobrienimport java.util.Set;
5477302Sobrienimport java.util.WeakHashMap;
55130570Sobrienimport java.util.function.Function;
56130570Sobrien
5777302Sobrienimport static com.sun.tools.javac.code.TypeTag.*;
58130570Sobrienimport static com.sun.tools.javac.tree.JCTree.Tag.*;
59130570Sobrienimport static com.sun.tools.javac.code.Kinds.*;
6077302Sobrienimport static com.sun.tools.javac.code.Kinds.Kind.*;
61130570Sobrien
62130570Sobrien/**
6377302Sobrien * This is an helper class that is used to perform deferred type-analysis.
64130570Sobrien * Each time a poly expression occurs in argument position, javac attributes it
65130570Sobrien * with a temporary 'deferred type' that is checked (possibly multiple times)
6677302Sobrien * against an expected formal type.
67130570Sobrien *
6877302Sobrien *  <p><b>This is NOT part of any supported API.
6977302Sobrien *  If you write code that depends on this, you do so at your own risk.
7077302Sobrien *  This code and its internal interfaces are subject to change or
7177302Sobrien *  deletion without notice.</b>
7277302Sobrien */
73130570Sobrienpublic class DeferredAttr extends JCTree.Visitor {
74130570Sobrien    protected static final Context.Key<DeferredAttr> deferredAttrKey = new Context.Key<>();
7577302Sobrien
76104840Sobrien    final Attr attr;
77130570Sobrien    final Check chk;
78104840Sobrien    final JCDiagnostic.Factory diags;
79130570Sobrien    final Enter enter;
80130570Sobrien    final Infer infer;
81104840Sobrien    final Resolve rs;
82130570Sobrien    final Log log;
83130570Sobrien    final Symtab syms;
84104840Sobrien    final TreeMaker make;
85130570Sobrien    final Types types;
86130570Sobrien    final Flow flow;
87104840Sobrien    final Names names;
88130570Sobrien    final TypeEnvs typeEnvs;
89130570Sobrien
90104840Sobrien    public static DeferredAttr instance(Context context) {
91130570Sobrien        DeferredAttr instance = context.get(deferredAttrKey);
92130570Sobrien        if (instance == null)
93104840Sobrien            instance = new DeferredAttr(context);
94130570Sobrien        return instance;
95130570Sobrien    }
9677302Sobrien
97130570Sobrien    protected DeferredAttr(Context context) {
98130570Sobrien        context.put(deferredAttrKey, this);
9977302Sobrien        attr = Attr.instance(context);
100130570Sobrien        chk = Check.instance(context);
101130570Sobrien        diags = JCDiagnostic.Factory.instance(context);
10277302Sobrien        enter = Enter.instance(context);
103130570Sobrien        infer = Infer.instance(context);
104130570Sobrien        rs = Resolve.instance(context);
10577302Sobrien        log = Log.instance(context);
106130570Sobrien        syms = Symtab.instance(context);
10733965Sjdp        make = TreeMaker.instance(context);
108130570Sobrien        types = Types.instance(context);
109130570Sobrien        flow = Flow.instance(context);
110104840Sobrien        names = Names.instance(context);
111130570Sobrien        stuckTree = make.Ident(names.empty).setType(Type.stuckType);
112104840Sobrien        typeEnvs = TypeEnvs.instance(context);
113130570Sobrien        emptyDeferredAttrContext =
114130570Sobrien            new DeferredAttrContext(AttrMode.CHECK, null, MethodResolutionPhase.BOX, infer.emptyContext, null, null) {
115104840Sobrien                @Override
116130570Sobrien                void addDeferredAttrNode(DeferredType dt, ResultInfo ri, DeferredStuckPolicy deferredStuckPolicy) {
117130570Sobrien                    Assert.error("Empty deferred context!");
118104840Sobrien                }
119130570Sobrien                @Override
120130570Sobrien                void complete() {
121104840Sobrien                    Assert.error("Empty deferred context!");
122130570Sobrien                }
123130570Sobrien
124104840Sobrien                @Override
125130570Sobrien                public String toString() {
126130570Sobrien                    return "Empty deferred context!";
127104840Sobrien                }
128130570Sobrien            };
129218822Sdim    }
130218822Sdim
131218822Sdim    /** shared tree for stuck expressions */
132218822Sdim    final JCTree stuckTree;
133218822Sdim
134218822Sdim    /**
135218822Sdim     * This type represents a deferred type. A deferred type starts off with
136218822Sdim     * no information on the underlying expression type. Such info needs to be
137218822Sdim     * discovered through type-checking the deferred type against a target-type.
138218822Sdim     * Every deferred type keeps a pointer to the AST node from which it originated.
13977302Sobrien     */
140104840Sobrien    public class DeferredType extends Type {
141218822Sdim
142130570Sobrien        public JCExpression tree;
143104840Sobrien        Env<AttrContext> env;
14460509Sobrien        AttrMode mode;
14560509Sobrien        SpeculativeCache speculativeCache;
14660509Sobrien
14760509Sobrien        DeferredType(JCExpression tree, Env<AttrContext> env) {
14860509Sobrien            super(null, TypeMetadata.empty);
149130570Sobrien            this.tree = tree;
15060509Sobrien            this.env = attr.copyEnv(env);
15160509Sobrien            this.speculativeCache = new SpeculativeCache();
15260509Sobrien        }
15360509Sobrien
154130570Sobrien        @Override
15560509Sobrien        public DeferredType clone(TypeMetadata md) {
15660509Sobrien            throw new AssertionError("Cannot add metadata to a deferred type");
157130570Sobrien        }
15860509Sobrien
15960509Sobrien        @Override
16060509Sobrien        public TypeTag getTag() {
16160509Sobrien            return DEFERRED;
16260509Sobrien        }
16360509Sobrien
164130570Sobrien        @Override @DefinedBy(Api.LANGUAGE_MODEL)
16560509Sobrien        public String toString() {
16660509Sobrien            return "DeferredType";
16760509Sobrien        }
16860509Sobrien
169130570Sobrien        /**
17060509Sobrien         * A speculative cache is used to keep track of all overload resolution rounds
17160509Sobrien         * that triggered speculative attribution on a given deferred type. Each entry
172130570Sobrien         * stores a pointer to the speculative tree and the resolution phase in which the entry
17360509Sobrien         * has been added.
174130570Sobrien         */
17577302Sobrien        class SpeculativeCache {
17677302Sobrien
17777302Sobrien            private Map<Symbol, List<Entry>> cache = new WeakHashMap<>();
17833965Sjdp
179130570Sobrien            class Entry {
180130570Sobrien                JCTree speculativeTree;
18133965Sjdp                ResultInfo resultInfo;
18233965Sjdp
18333965Sjdp                public Entry(JCTree speculativeTree, ResultInfo resultInfo) {
18433965Sjdp                    this.speculativeTree = speculativeTree;
18533965Sjdp                    this.resultInfo = resultInfo;
186130570Sobrien                }
187130570Sobrien
18833965Sjdp                boolean matches(MethodResolutionPhase phase) {
18933965Sjdp                    return resultInfo.checkContext.deferredAttrContext().phase == phase;
19033965Sjdp                }
19133965Sjdp            }
19233965Sjdp
193130570Sobrien            /**
19433965Sjdp             * Retrieve a speculative cache entry corresponding to given symbol
19533965Sjdp             * and resolution phase
19633965Sjdp             */
197130570Sobrien            Entry get(Symbol msym, MethodResolutionPhase phase) {
19833965Sjdp                List<Entry> entries = cache.get(msym);
19960509Sobrien                if (entries == null) return null;
20060509Sobrien                for (Entry e : entries) {
201130570Sobrien                    if (e.matches(phase)) return e;
20260509Sobrien                }
20333965Sjdp                return null;
20433965Sjdp            }
205130570Sobrien
20633965Sjdp            /**
20733965Sjdp             * Stores a speculative cache entry corresponding to given symbol
20833965Sjdp             * and resolution phase
209130570Sobrien             */
21033965Sjdp            void put(JCTree speculativeTree, ResultInfo resultInfo) {
21133965Sjdp                Symbol msym = resultInfo.checkContext.deferredAttrContext().msym;
21233965Sjdp                List<Entry> entries = cache.get(msym);
213130570Sobrien                if (entries == null) {
21433965Sjdp                    entries = List.nil();
21533965Sjdp                }
21633965Sjdp                cache.put(msym, entries.prepend(new Entry(speculativeTree, resultInfo)));
217130570Sobrien            }
21833965Sjdp        }
21933965Sjdp
22033965Sjdp        /**
221130570Sobrien         * Get the type that has been computed during a speculative attribution round
22233965Sjdp         */
22333965Sjdp        Type speculativeType(Symbol msym, MethodResolutionPhase phase) {
22433965Sjdp            SpeculativeCache.Entry e = speculativeCache.get(msym, phase);
225130570Sobrien            return e != null ? e.speculativeTree.type : Type.noType;
22633965Sjdp        }
22733965Sjdp
22833965Sjdp        /**
229130570Sobrien         * Check a deferred type against a potential target-type. Depending on
23033965Sjdp         * the current attribution mode, a normal vs. speculative attribution
23133965Sjdp         * round is performed on the underlying AST node. There can be only one
23233965Sjdp         * speculative round for a given target method symbol; moreover, a normal
233130570Sobrien         * attribution round must follow one or more speculative rounds.
23433965Sjdp         */
23533965Sjdp        Type check(ResultInfo resultInfo) {
23633965Sjdp            DeferredStuckPolicy deferredStuckPolicy;
237130570Sobrien            if (resultInfo.pt.hasTag(NONE) || resultInfo.pt.isErroneous()) {
23833965Sjdp                deferredStuckPolicy = dummyStuckPolicy;
239104840Sobrien            } else if (resultInfo.checkContext.deferredAttrContext().mode == AttrMode.SPECULATIVE) {
240104840Sobrien                deferredStuckPolicy = new OverloadStuckPolicy(resultInfo, this);
241104840Sobrien            } else {
242130570Sobrien                deferredStuckPolicy = new CheckStuckPolicy(resultInfo, this);
243104840Sobrien            }
244104840Sobrien            return check(resultInfo, deferredStuckPolicy, basicCompleter);
245104840Sobrien        }
246130570Sobrien
247104840Sobrien        private Type check(ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy,
248104840Sobrien                DeferredTypeCompleter deferredTypeCompleter) {
249104840Sobrien            DeferredAttrContext deferredAttrContext =
250130570Sobrien                    resultInfo.checkContext.deferredAttrContext();
251104840Sobrien            Assert.check(deferredAttrContext != emptyDeferredAttrContext);
252104840Sobrien            if (deferredStuckPolicy.isStuck()) {
253104840Sobrien                deferredAttrContext.addDeferredAttrNode(this, resultInfo, deferredStuckPolicy);
254130570Sobrien                return Type.noType;
255104840Sobrien            } else {
256104840Sobrien                try {
257104840Sobrien                    return deferredTypeCompleter.complete(this, resultInfo, deferredAttrContext);
258130570Sobrien                } finally {
259104840Sobrien                    mode = deferredAttrContext.mode;
260104840Sobrien                }
261104840Sobrien            }
262130570Sobrien        }
263104840Sobrien    }
26433965Sjdp
26533965Sjdp    /**
266130570Sobrien     * A completer for deferred types. Defines an entry point for type-checking
26733965Sjdp     * a deferred type.
26833965Sjdp     */
26933965Sjdp    interface DeferredTypeCompleter {
270130570Sobrien        /**
27133965Sjdp         * Entry point for type-checking a deferred type. Depending on the
27233965Sjdp         * circumstances, type-checking could amount to full attribution
27333965Sjdp         * or partial structural check (aka potential applicability).
274130570Sobrien         */
27533965Sjdp        Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext);
27633965Sjdp    }
27733965Sjdp
278130570Sobrien
27933965Sjdp    /**
280104840Sobrien     * A basic completer for deferred types. This completer type-checks a deferred type
281104840Sobrien     * using attribution; depending on the attribution mode, this could be either standard
282104840Sobrien     * or speculative attribution.
283130570Sobrien     */
284104840Sobrien    DeferredTypeCompleter basicCompleter = new DeferredTypeCompleter() {
285104840Sobrien        public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
286104840Sobrien            switch (deferredAttrContext.mode) {
287130570Sobrien                case SPECULATIVE:
288104840Sobrien                    //Note: if a symbol is imported twice we might do two identical
289104840Sobrien                    //speculative rounds...
290104840Sobrien                    Assert.check(dt.mode == null || dt.mode == AttrMode.SPECULATIVE);
291130570Sobrien                    JCTree speculativeTree = attribSpeculative(dt.tree, dt.env, resultInfo);
292104840Sobrien                    dt.speculativeCache.put(speculativeTree, resultInfo);
293104840Sobrien                    return speculativeTree.type;
294104840Sobrien                case CHECK:
295130570Sobrien                    Assert.check(dt.mode != null);
296104840Sobrien                    return attr.attribTree(dt.tree, dt.env, resultInfo);
297104840Sobrien            }
298104840Sobrien            Assert.error();
299130570Sobrien            return null;
300104840Sobrien        }
301104840Sobrien    };
302104840Sobrien
303130570Sobrien    DeferredTypeCompleter dummyCompleter = new DeferredTypeCompleter() {
304104840Sobrien        public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
305218822Sdim            Assert.check(deferredAttrContext.mode == AttrMode.CHECK);
306218822Sdim            return dt.tree.type = Type.stuckType;
307218822Sdim        }
308218822Sdim    };
309218822Sdim
310218822Sdim    /**
311218822Sdim     * Policy for detecting stuck expressions. Different criteria might cause
312218822Sdim     * an expression to be judged as stuck, depending on whether the check
313218822Sdim     * is performed during overload resolution or after most specific.
314218822Sdim     */
315218822Sdim    interface DeferredStuckPolicy {
316218822Sdim        /**
31760509Sobrien         * Has the policy detected that a given expression should be considered stuck?
31860509Sobrien         */
319130570Sobrien        boolean isStuck();
32060509Sobrien        /**
32160509Sobrien         * Get the set of inference variables a given expression depends upon.
32260509Sobrien         */
323130570Sobrien        Set<Type> stuckVars();
32460509Sobrien        /**
32533965Sjdp         * Get the set of inference variables which might get new constraints
32633965Sjdp         * if a given expression is being type-checked.
32733965Sjdp         */
32833965Sjdp        Set<Type> depVars();
32933965Sjdp    }
33033965Sjdp
33133965Sjdp    /**
33233965Sjdp     * Basic stuck policy; an expression is never considered to be stuck.
333218822Sdim     */
334218822Sdim    DeferredStuckPolicy dummyStuckPolicy = new DeferredStuckPolicy() {
335218822Sdim        @Override
336218822Sdim        public boolean isStuck() {
337218822Sdim            return false;
338218822Sdim        }
339218822Sdim        @Override
340218822Sdim        public Set<Type> stuckVars() {
341218822Sdim            return Collections.emptySet();
342218822Sdim        }
343218822Sdim        @Override
344218822Sdim        public Set<Type> depVars() {
345218822Sdim            return Collections.emptySet();
346218822Sdim        }
34733965Sjdp    };
348130570Sobrien
349130570Sobrien    /**
350130570Sobrien     * The 'mode' in which the deferred type is to be type-checked
35133965Sjdp     */
35277302Sobrien    public enum AttrMode {
35377302Sobrien        /**
35433965Sjdp         * A speculative type-checking round is used during overload resolution
35577302Sobrien         * mainly to generate constraints on inference variables. Side-effects
35677302Sobrien         * arising from type-checking the expression associated with the deferred
35777302Sobrien         * type are reversed after the speculative round finishes. This means the
358104840Sobrien         * expression tree will be left in a blank state.
359104840Sobrien         */
360104840Sobrien        SPECULATIVE,
361104840Sobrien        /**
36260509Sobrien         * This is the plain type-checking mode. Produces side-effects on the underlying AST node
363218822Sdim         */
364218822Sdim        CHECK
365130570Sobrien    }
36660509Sobrien
36777302Sobrien    /**
36833965Sjdp     * Routine that performs speculative type-checking; the input AST node is
36933965Sjdp     * cloned (to avoid side-effects cause by Attr) and compiler state is
37033965Sjdp     * restored after type-checking. All diagnostics (but critical ones) are
37133965Sjdp     * disabled during speculative type-checking.
37233965Sjdp     */
37333965Sjdp    JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
37433965Sjdp        return attribSpeculative(tree, env, resultInfo, new TreeCopier<>(make),
37533965Sjdp                (newTree)->new DeferredAttrDiagHandler(log, newTree));
376130570Sobrien    }
377130570Sobrien
37833965Sjdp    <Z> JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo, TreeCopier<Z> deferredCopier,
37933965Sjdp                                 Function<JCTree, DeferredDiagnosticHandler> diagHandlerCreator) {
380130570Sobrien        final JCTree newTree = deferredCopier.copy(tree);
38133965Sjdp        Env<AttrContext> speculativeEnv = env.dup(newTree, env.info.dup(env.info.scope.dupUnshared(env.info.scope.owner)));
38233965Sjdp        speculativeEnv.info.isSpeculative = true;
38333965Sjdp        Log.DeferredDiagnosticHandler deferredDiagnosticHandler = diagHandlerCreator.apply(newTree);
38433965Sjdp        try {
38589861Sobrien            attr.attribTree(newTree, speculativeEnv, resultInfo);
386130570Sobrien            unenterScanner.scan(newTree);
387130570Sobrien            return newTree;
388130570Sobrien        } finally {
38989861Sobrien            unenterScanner.scan(newTree);
39089861Sobrien            log.popDiagnosticHandler(deferredDiagnosticHandler);
391218822Sdim        }
39233965Sjdp    }
393130570Sobrien    //where
39489861Sobrien        protected UnenterScanner unenterScanner = new UnenterScanner();
395130570Sobrien
39689861Sobrien        class UnenterScanner extends TreeScanner {
397130570Sobrien            @Override
398130570Sobrien            public void visitClassDef(JCClassDecl tree) {
39989861Sobrien                ClassSymbol csym = tree.sym;
400130570Sobrien                //if something went wrong during method applicability check
401130570Sobrien                //it is possible that nested expressions inside argument expression
40289861Sobrien                //are left unchecked - in such cases there's nothing to clean up.
403130570Sobrien                if (csym == null) return;
404130570Sobrien                typeEnvs.remove(csym);
40589861Sobrien                chk.compiled.remove(csym.flatname);
406130570Sobrien                syms.classes.remove(csym.flatname);
407130570Sobrien                super.visitClassDef(tree);
408218822Sdim            }
40989861Sobrien        }
410130570Sobrien
411130570Sobrien        static class DeferredAttrDiagHandler extends Log.DeferredDiagnosticHandler {
412130570Sobrien
413130570Sobrien            static class PosScanner extends TreeScanner {
414130570Sobrien                DiagnosticPosition pos;
415130570Sobrien                boolean found = false;
41689861Sobrien
417130570Sobrien                PosScanner(DiagnosticPosition pos) {
418130570Sobrien                    this.pos = pos;
419130570Sobrien                }
420130570Sobrien
421130570Sobrien                @Override
422130570Sobrien                public void scan(JCTree tree) {
423130570Sobrien                    if (tree != null &&
424130570Sobrien                            tree.pos() == pos) {
425130570Sobrien                        found = true;
426218822Sdim                    }
427130570Sobrien                    super.scan(tree);
428130570Sobrien                }
429130570Sobrien            }
430130570Sobrien
431130570Sobrien            DeferredAttrDiagHandler(Log log, JCTree newTree) {
43289861Sobrien                super(log, new Filter<JCDiagnostic>() {
43389861Sobrien                    public boolean accepts(JCDiagnostic d) {
434218822Sdim                        PosScanner posScanner = new PosScanner(d.getDiagnosticPosition());
43589861Sobrien                        posScanner.scan(newTree);
43689861Sobrien                        return posScanner.found;
437130570Sobrien                    }
438130570Sobrien                });
43989861Sobrien            }
440130570Sobrien        }
44189861Sobrien
442130570Sobrien    /**
44389861Sobrien     * A deferred context is created on each method check. A deferred context is
444130570Sobrien     * used to keep track of information associated with the method check, such as
445130570Sobrien     * the symbol of the method being checked, the overload resolution phase,
446130570Sobrien     * the kind of attribution mode to be applied to deferred types and so forth.
447130570Sobrien     * As deferred types are processed (by the method check routine) stuck AST nodes
448130570Sobrien     * are added (as new deferred attribution nodes) to this context. The complete()
449130570Sobrien     * routine makes sure that all pending nodes are properly processed, by
450130570Sobrien     * progressively instantiating all inference variables on which one or more
45189861Sobrien     * deferred attribution node is stuck.
452130570Sobrien     */
453130570Sobrien    class DeferredAttrContext {
454130570Sobrien
455130570Sobrien        /** attribution mode */
456130570Sobrien        final AttrMode mode;
457130570Sobrien
45889861Sobrien        /** symbol of the method being checked */
459130570Sobrien        final Symbol msym;
460130570Sobrien
461130570Sobrien        /** method resolution step */
462130570Sobrien        final Resolve.MethodResolutionPhase phase;
463130570Sobrien
464130570Sobrien        /** inference context */
465130570Sobrien        final InferenceContext inferenceContext;
466130570Sobrien
46789861Sobrien        /** parent deferred context */
46889861Sobrien        final DeferredAttrContext parent;
46989861Sobrien
47089861Sobrien        /** Warner object to report warnings */
47189861Sobrien        final Warner warn;
47289861Sobrien
47389861Sobrien        /** list of deferred attribution nodes to be processed */
47489861Sobrien        ArrayList<DeferredAttrNode> deferredAttrNodes = new ArrayList<>();
47589861Sobrien
47689861Sobrien        DeferredAttrContext(AttrMode mode, Symbol msym, MethodResolutionPhase phase,
47789861Sobrien                InferenceContext inferenceContext, DeferredAttrContext parent, Warner warn) {
478130570Sobrien            this.mode = mode;
47989861Sobrien            this.msym = msym;
48089861Sobrien            this.phase = phase;
48189861Sobrien            this.parent = parent;
48289861Sobrien            this.warn = warn;
48389861Sobrien            this.inferenceContext = inferenceContext;
48489861Sobrien        }
48589861Sobrien
48689861Sobrien        /**
48789861Sobrien         * Adds a node to the list of deferred attribution nodes - used by Resolve.rawCheckArgumentsApplicable
48889861Sobrien         * Nodes added this way act as 'roots' for the out-of-order method checking process.
48989861Sobrien         */
49089861Sobrien        void addDeferredAttrNode(final DeferredType dt, ResultInfo resultInfo,
49189861Sobrien                DeferredStuckPolicy deferredStuckPolicy) {
49289861Sobrien            deferredAttrNodes.add(new DeferredAttrNode(dt, resultInfo, deferredStuckPolicy));
49389861Sobrien        }
49489861Sobrien
49533965Sjdp        /**
49633965Sjdp         * Incrementally process all nodes, by skipping 'stuck' nodes and attributing
49733965Sjdp         * 'unstuck' ones. If at any point no progress can be made (no 'unstuck' nodes)
49868769Sobrien         * some inference variable might get eagerly instantiated so that all nodes
49933965Sjdp         * can be type-checked.
500130570Sobrien         */
501130570Sobrien        void complete() {
502130570Sobrien            while (!deferredAttrNodes.isEmpty()) {
503130570Sobrien                Map<Type, Set<Type>> depVarsMap = new LinkedHashMap<>();
504130570Sobrien                List<Type> stuckVars = List.nil();
505130570Sobrien                boolean progress = false;
50633965Sjdp                //scan a defensive copy of the node list - this is because a deferred
50733965Sjdp                //attribution round can add new nodes to the list
50833965Sjdp                for (DeferredAttrNode deferredAttrNode : List.from(deferredAttrNodes)) {
50933965Sjdp                    if (!deferredAttrNode.process(this)) {
51033965Sjdp                        List<Type> restStuckVars =
511218822Sdim                                List.from(deferredAttrNode.deferredStuckPolicy.stuckVars())
512218822Sdim                                .intersect(inferenceContext.restvars());
51333965Sjdp                        stuckVars = stuckVars.prependList(restStuckVars);
514218822Sdim                        //update dependency map
51533965Sjdp                        for (Type t : List.from(deferredAttrNode.deferredStuckPolicy.depVars())
51633965Sjdp                                .intersect(inferenceContext.restvars())) {
51733965Sjdp                            Set<Type> prevDeps = depVarsMap.get(t);
51833965Sjdp                            if (prevDeps == null) {
519218822Sdim                                prevDeps = new LinkedHashSet<>();
52033965Sjdp                                depVarsMap.put(t, prevDeps);
52133965Sjdp                            }
52233965Sjdp                            prevDeps.addAll(restStuckVars);
52333965Sjdp                        }
52433965Sjdp                    } else {
52533965Sjdp                        deferredAttrNodes.remove(deferredAttrNode);
52633965Sjdp                        progress = true;
52733965Sjdp                    }
52833965Sjdp                }
52933965Sjdp                if (!progress) {
53033965Sjdp                    if (insideOverloadPhase()) {
53133965Sjdp                        for (DeferredAttrNode deferredNode: deferredAttrNodes) {
53233965Sjdp                            deferredNode.dt.tree.type = Type.noType;
53333965Sjdp                        }
53433965Sjdp                        return;
535218822Sdim                    }
536218822Sdim                    //remove all variables that have already been instantiated
53733965Sjdp                    //from the list of stuck variables
538218822Sdim                    try {
53933965Sjdp                        inferenceContext.solveAny(stuckVars, depVarsMap, warn);
54033965Sjdp                        inferenceContext.notifyChange();
541218822Sdim                    } catch (Infer.GraphStrategy.NodeNotFoundException ex) {
54233965Sjdp                        //this means that we are in speculative mode and the
54333965Sjdp                        //set of contraints are too tight for progess to be made.
54433965Sjdp                        //Just leave the remaining expressions as stuck.
54533965Sjdp                        break;
54633965Sjdp                    }
54733965Sjdp                }
54833965Sjdp            }
54933965Sjdp        }
55033965Sjdp
55133965Sjdp        private boolean insideOverloadPhase() {
55233965Sjdp            DeferredAttrContext dac = this;
55333965Sjdp            if (dac == emptyDeferredAttrContext) {
55433965Sjdp                return false;
55533965Sjdp            }
556218822Sdim            if (dac.mode == AttrMode.SPECULATIVE) {
557218822Sdim                return true;
558218822Sdim            }
559218822Sdim            return dac.parent.insideOverloadPhase();
560218822Sdim        }
561218822Sdim    }
56233965Sjdp
56389861Sobrien    /**
56489861Sobrien     * Class representing a deferred attribution node. It keeps track of
56589861Sobrien     * a deferred type, along with the expected target type information.
56689861Sobrien     */
56733965Sjdp    class DeferredAttrNode {
56889861Sobrien
56989861Sobrien        /** underlying deferred type */
57089861Sobrien        DeferredType dt;
57133965Sjdp
57289861Sobrien        /** underlying target type information */
57389861Sobrien        ResultInfo resultInfo;
57489861Sobrien
57589861Sobrien        /** stuck policy associated with this node */
57633965Sjdp        DeferredStuckPolicy deferredStuckPolicy;
57789861Sobrien
57889861Sobrien        DeferredAttrNode(DeferredType dt, ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy) {
57989861Sobrien            this.dt = dt;
58033965Sjdp            this.resultInfo = resultInfo;
58133965Sjdp            this.deferredStuckPolicy = deferredStuckPolicy;
58233965Sjdp        }
58333965Sjdp
58433965Sjdp        /**
58533965Sjdp         * Process a deferred attribution node.
58689861Sobrien         * Invariant: a stuck node cannot be processed.
58733965Sjdp         */
58889861Sobrien        @SuppressWarnings("fallthrough")
58989861Sobrien        boolean process(final DeferredAttrContext deferredAttrContext) {
590104840Sobrien            switch (deferredAttrContext.mode) {
591104840Sobrien                case SPECULATIVE:
592104840Sobrien                    if (deferredStuckPolicy.isStuck()) {
593104840Sobrien                        dt.check(resultInfo, dummyStuckPolicy, new StructuralStuckChecker());
594104840Sobrien                        return true;
595104840Sobrien                    } else {
596104840Sobrien                        Assert.error("Cannot get here");
597104840Sobrien                    }
598218822Sdim                case CHECK:
599218822Sdim                    if (deferredStuckPolicy.isStuck()) {
600218822Sdim                        //stuck expression - see if we can propagate
601218822Sdim                        if (deferredAttrContext.parent != emptyDeferredAttrContext &&
602218822Sdim                                Type.containsAny(deferredAttrContext.parent.inferenceContext.inferencevars,
603218822Sdim                                        List.from(deferredStuckPolicy.stuckVars()))) {
604218822Sdim                            deferredAttrContext.parent.addDeferredAttrNode(dt,
605218822Sdim                                    resultInfo.dup(new Check.NestedCheckContext(resultInfo.checkContext) {
606218822Sdim                                @Override
607104840Sobrien                                public InferenceContext inferenceContext() {
608218822Sdim                                    return deferredAttrContext.parent.inferenceContext;
609218822Sdim                                }
610218822Sdim                                @Override
611218822Sdim                                public DeferredAttrContext deferredAttrContext() {
61233965Sjdp                                    return deferredAttrContext.parent;
61333965Sjdp                                }
614104840Sobrien                            }), deferredStuckPolicy);
615104840Sobrien                            dt.tree.type = Type.stuckType;
616104840Sobrien                            return true;
617104840Sobrien                        } else {
618104840Sobrien                            return false;
619104840Sobrien                        }
620104840Sobrien                    } else {
621104840Sobrien                        Assert.check(!deferredAttrContext.insideOverloadPhase(),
622218822Sdim                                "attribution shouldn't be happening here");
623218822Sdim                        ResultInfo instResultInfo =
624218822Sdim                                resultInfo.dup(deferredAttrContext.inferenceContext.asInstType(resultInfo.pt));
625104840Sobrien                        dt.check(instResultInfo, dummyStuckPolicy, basicCompleter);
626104840Sobrien                        return true;
627104840Sobrien                    }
628104840Sobrien                default:
629104840Sobrien                    throw new AssertionError("Bad mode");
630104840Sobrien            }
631104840Sobrien        }
632104840Sobrien
633218822Sdim        /**
634218822Sdim         * Structural checker for stuck expressions
635218822Sdim         */
636130570Sobrien        class StructuralStuckChecker extends TreeScanner implements DeferredTypeCompleter {
637130570Sobrien
638104840Sobrien            ResultInfo resultInfo;
639104840Sobrien            InferenceContext inferenceContext;
640218822Sdim            Env<AttrContext> env;
641218822Sdim
642218822Sdim            public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
643218822Sdim                this.resultInfo = resultInfo;
644218822Sdim                this.inferenceContext = deferredAttrContext.inferenceContext;
645218822Sdim                this.env = dt.env;
646218822Sdim                dt.tree.accept(this);
647104840Sobrien                dt.speculativeCache.put(stuckTree, resultInfo);
648104840Sobrien                return Type.noType;
64933965Sjdp            }
65033965Sjdp
65133965Sjdp            @Override
65233965Sjdp            public void visitLambda(JCLambda tree) {
65389861Sobrien                Check.CheckContext checkContext = resultInfo.checkContext;
65433965Sjdp                Type pt = resultInfo.pt;
65589861Sobrien                if (!inferenceContext.inferencevars.contains(pt)) {
65689861Sobrien                    //must be a functional descriptor
65789861Sobrien                    Type descriptorType = null;
65889861Sobrien                    try {
65989861Sobrien                        descriptorType = types.findDescriptorType(pt);
66089861Sobrien                    } catch (Types.FunctionDescriptorLookupError ex) {
66189861Sobrien                        checkContext.report(null, ex.getDiagnostic());
66289861Sobrien                    }
66333965Sjdp
664218822Sdim                    if (descriptorType.getParameterTypes().length() != tree.params.length()) {
665218822Sdim                        checkContext.report(tree,
666218822Sdim                                diags.fragment("incompatible.arg.types.in.lambda"));
667218822Sdim                    }
668218822Sdim
669218822Sdim                    Type currentReturnType = descriptorType.getReturnType();
670218822Sdim                    boolean returnTypeIsVoid = currentReturnType.hasTag(VOID);
671218822Sdim                    if (tree.getBodyKind() == BodyKind.EXPRESSION) {
672218822Sdim                        boolean isExpressionCompatible = !returnTypeIsVoid ||
673218822Sdim                            TreeInfo.isExpressionStatement((JCExpression)tree.getBody());
674218822Sdim                        if (!isExpressionCompatible) {
675218822Sdim                            resultInfo.checkContext.report(tree.pos(),
676104840Sobrien                                diags.fragment("incompatible.ret.type.in.lambda",
677104840Sobrien                                    diags.fragment("missing.ret.val", currentReturnType)));
678104840Sobrien                        }
679104840Sobrien                    } else {
680104840Sobrien                        LambdaBodyStructChecker lambdaBodyChecker =
681218822Sdim                                new LambdaBodyStructChecker();
682218822Sdim
683218822Sdim                        tree.body.accept(lambdaBodyChecker);
684218822Sdim                        boolean isVoidCompatible = lambdaBodyChecker.isVoidCompatible;
68589861Sobrien
68689861Sobrien                        if (returnTypeIsVoid) {
68789861Sobrien                            if (!isVoidCompatible) {
68833965Sjdp                                resultInfo.checkContext.report(tree.pos(),
68933965Sjdp                                    diags.fragment("unexpected.ret.val"));
69033965Sjdp                            }
69133965Sjdp                        } else {
69233965Sjdp                            boolean isValueCompatible = lambdaBodyChecker.isPotentiallyValueCompatible
69333965Sjdp                                && !canLambdaBodyCompleteNormally(tree);
694218822Sdim                            if (!isValueCompatible && !isVoidCompatible) {
695218822Sdim                                log.error(tree.body.pos(),
696218822Sdim                                    "lambda.body.neither.value.nor.void.compatible");
69733965Sjdp                            }
69833965Sjdp
69933965Sjdp                            if (!isValueCompatible) {
700130570Sobrien                                resultInfo.checkContext.report(tree.pos(),
701130570Sobrien                                    diags.fragment("incompatible.ret.type.in.lambda",
702130570Sobrien                                        diags.fragment("missing.ret.val", currentReturnType)));
70333965Sjdp                            }
70433965Sjdp                        }
70533965Sjdp                    }
70689861Sobrien                }
70789861Sobrien            }
70889861Sobrien
70989861Sobrien            boolean canLambdaBodyCompleteNormally(JCLambda tree) {
71089861Sobrien                JCLambda newTree = new TreeCopier<>(make).copy(tree);
71189861Sobrien                /* attr.lambdaEnv will create a meaningful env for the
71289861Sobrien                 * lambda expression. This is specially useful when the
71333965Sjdp                 * lambda is used as the init of a field. But we need to
71433965Sjdp                 * remove any added symbol.
71589861Sobrien                 */
71689861Sobrien                Env<AttrContext> localEnv = attr.lambdaEnv(newTree, env);
71733965Sjdp                try {
71889861Sobrien                    List<JCVariableDecl> tmpParams = newTree.params;
71989861Sobrien                    while (tmpParams.nonEmpty()) {
72089861Sobrien                        tmpParams.head.vartype = make.at(tmpParams.head).Type(syms.errType);
72189861Sobrien                        tmpParams = tmpParams.tail;
722104840Sobrien                    }
723218822Sdim
72433965Sjdp                    attr.attribStats(newTree.params, localEnv);
72533965Sjdp
72689861Sobrien                    /* set pt to Type.noType to avoid generating any bound
72733965Sjdp                     * which may happen if lambda's return type is an
72833965Sjdp                     * inference variable
72933965Sjdp                     */
73033965Sjdp                    Attr.ResultInfo bodyResultInfo = attr.new ResultInfo(KindSelector.VAL, Type.noType);
73133965Sjdp                    localEnv.info.returnResult = bodyResultInfo;
732130570Sobrien
73333965Sjdp                    // discard any log output
73433965Sjdp                    Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
73589861Sobrien                    try {
73633965Sjdp                        JCBlock body = (JCBlock)newTree.body;
737130570Sobrien                        /* we need to attribute the lambda body before
73889861Sobrien                         * doing the aliveness analysis. This is because
73933965Sjdp                         * constant folding occurs during attribution
74033965Sjdp                         * and the reachability of some statements depends
741218822Sdim                         * on constant values, for example:
742218822Sdim                         *
74333965Sjdp                         *     while (true) {...}
744104840Sobrien                         */
74533965Sjdp                        attr.attribStats(body.stats, localEnv);
74633965Sjdp
74733965Sjdp                        attr.preFlow(newTree);
74889861Sobrien                        /* make an aliveness / reachability analysis of the lambda
74989861Sobrien                         * to determine if it can complete normally
75089861Sobrien                         */
75189861Sobrien                        flow.analyzeLambda(localEnv, newTree, make, true);
75289861Sobrien                    } finally {
75389861Sobrien                        log.popDiagnosticHandler(diagHandler);
75489861Sobrien                    }
755104840Sobrien                    return newTree.canCompleteNormally;
756218822Sdim                } finally {
757218822Sdim                    JCBlock body = (JCBlock)newTree.body;
75889861Sobrien                    unenterScanner.scan(body.stats);
759218822Sdim                    localEnv.info.scope.leave();
760218822Sdim                }
761218822Sdim            }
76289861Sobrien
76389861Sobrien            @Override
76433965Sjdp            public void visitNewClass(JCNewClass tree) {
76533965Sjdp                //do nothing
76689861Sobrien            }
76789861Sobrien
76889861Sobrien            @Override
769130570Sobrien            public void visitApply(JCMethodInvocation tree) {
770130570Sobrien                //do nothing
77189861Sobrien            }
77289861Sobrien
77389861Sobrien            @Override
77489861Sobrien            public void visitReference(JCMemberReference tree) {
775130570Sobrien                Check.CheckContext checkContext = resultInfo.checkContext;
77689861Sobrien                Type pt = resultInfo.pt;
77789861Sobrien                if (!inferenceContext.inferencevars.contains(pt)) {
77889861Sobrien                    try {
77989861Sobrien                        types.findDescriptorType(pt);
78089861Sobrien                    } catch (Types.FunctionDescriptorLookupError ex) {
78189861Sobrien                        checkContext.report(null, ex.getDiagnostic());
78289861Sobrien                    }
783218822Sdim                    Env<AttrContext> localEnv = env.dup(tree);
784218822Sdim                    JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv,
785218822Sdim                            attr.memberReferenceQualifierResult(tree));
786218822Sdim                    ListBuffer<Type> argtypes = new ListBuffer<>();
787218822Sdim                    for (Type t : types.findDescriptorType(pt).getParameterTypes()) {
788218822Sdim                        argtypes.append(Type.noType);
78989861Sobrien                    }
79089861Sobrien                    JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree);
791130570Sobrien                    mref2.expr = exprTree;
792130570Sobrien                    Symbol lookupSym =
79389861Sobrien                            rs.resolveMemberReference(localEnv, mref2, exprTree.type,
79489861Sobrien                                    tree.name, argtypes.toList(), List.nil(), rs.arityMethodCheck,
79589861Sobrien                                    inferenceContext, rs.structuralReferenceChooser).fst;
79689861Sobrien                    switch (lookupSym.kind) {
79789861Sobrien                        case WRONG_MTH:
79889861Sobrien                        case WRONG_MTHS:
799130570Sobrien                            //note: as argtypes are erroneous types, type-errors must
800130570Sobrien                            //have been caused by arity mismatch
80189861Sobrien                            checkContext.report(tree, diags.fragment(Fragments.IncompatibleArgTypesInMref));
80289861Sobrien                            break;
80389861Sobrien                        case ABSENT_MTH:
80489861Sobrien                        case STATICERR:
80589861Sobrien                            //if no method found, or method found with wrong staticness, report better message
806130570Sobrien                            checkContext.report(tree, ((ResolveError)lookupSym).getDiagnostic(DiagnosticType.FRAGMENT,
80789861Sobrien                                    tree, exprTree.type.tsym, exprTree.type, tree.name, argtypes.toList(), List.nil()));
80889861Sobrien                            break;
809130570Sobrien                    }
81089861Sobrien                }
81189861Sobrien            }
81289861Sobrien        }
81389861Sobrien
81489861Sobrien        /* This visitor looks for return statements, its analysis will determine if
81589861Sobrien         * a lambda body is void or value compatible. We must analyze return
81689861Sobrien         * statements contained in the lambda body only, thus any return statement
81789861Sobrien         * contained in an inner class or inner lambda body, should be ignored.
81889861Sobrien         */
81989861Sobrien        class LambdaBodyStructChecker extends TreeScanner {
82089861Sobrien            boolean isVoidCompatible = true;
821218822Sdim            boolean isPotentiallyValueCompatible = true;
822218822Sdim
823218822Sdim            @Override
824218822Sdim            public void visitClassDef(JCClassDecl tree) {
825130570Sobrien                // do nothing
82689861Sobrien            }
82789861Sobrien
82889861Sobrien            @Override
82989861Sobrien            public void visitLambda(JCLambda tree) {
83089861Sobrien                // do nothing
831218822Sdim            }
832130570Sobrien
833130570Sobrien            @Override
83489861Sobrien            public void visitNewClass(JCNewClass tree) {
83589861Sobrien                // do nothing
83689861Sobrien            }
83789861Sobrien
83889861Sobrien            @Override
83989861Sobrien            public void visitReturn(JCReturn tree) {
84089861Sobrien                if (tree.expr != null) {
84189861Sobrien                    isVoidCompatible = false;
84289861Sobrien                } else {
84389861Sobrien                    isPotentiallyValueCompatible = false;
84489861Sobrien                }
84589861Sobrien            }
84689861Sobrien        }
847218822Sdim    }
84889861Sobrien
84989861Sobrien    /** an empty deferred attribution context - all methods throw exceptions */
85089861Sobrien    final DeferredAttrContext emptyDeferredAttrContext;
85189861Sobrien
85289861Sobrien    /** The AttrMode to descriptive name mapping */
85389861Sobrien    private static final EnumMap<AttrMode, String> deferredTypeMapDescriptions;
85489861Sobrien    static {
85589861Sobrien        deferredTypeMapDescriptions = new EnumMap<>(AttrMode.class);
85689861Sobrien        deferredTypeMapDescriptions.put(AttrMode.CHECK, "deferredTypeMap[CHECK]");
85789861Sobrien        deferredTypeMapDescriptions.put(AttrMode.SPECULATIVE, "deferredTypeMap[SPECULATIVE]");
85889861Sobrien    }
85989861Sobrien
86089861Sobrien    /**
86189861Sobrien     * Map a list of types possibly containing one or more deferred types
86289861Sobrien     * into a list of ordinary types. Each deferred type D is mapped into a type T,
86389861Sobrien     * where T is computed by retrieving the type that has already been
86489861Sobrien     * computed for D during a previous deferred attribution round of the given kind.
86589861Sobrien     */
86689861Sobrien    class DeferredTypeMap extends Type.Mapping {
86789861Sobrien        DeferredAttrContext deferredAttrContext;
86889861Sobrien
86989861Sobrien        protected DeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
87089861Sobrien            super(deferredTypeMapDescriptions.get(mode));
871104840Sobrien            this.deferredAttrContext = new DeferredAttrContext(mode, msym, phase,
872104840Sobrien                    infer.emptyContext, emptyDeferredAttrContext, types.noWarnings);
873104840Sobrien        }
874104840Sobrien
875104840Sobrien        @Override
876104840Sobrien        public Type apply(Type t) {
877130570Sobrien            if (!t.hasTag(DEFERRED)) {
878130570Sobrien                return t.map(this);
879130570Sobrien            } else {
880218822Sdim                DeferredType dt = (DeferredType)t;
881218822Sdim                return typeOf(dt);
882218822Sdim            }
883218822Sdim        }
884218822Sdim
885218822Sdim        protected Type typeOf(DeferredType dt) {
886218822Sdim            switch (deferredAttrContext.mode) {
887218822Sdim                case CHECK:
888218822Sdim                    return dt.tree.type == null ? Type.noType : dt.tree.type;
889218822Sdim                case SPECULATIVE:
890218822Sdim                    return dt.speculativeType(deferredAttrContext.msym, deferredAttrContext.phase);
891130570Sobrien            }
892218822Sdim            Assert.error();
89389861Sobrien            return null;
89489861Sobrien        }
895104840Sobrien    }
896130570Sobrien
897104840Sobrien    /**
898104840Sobrien     * Specialized recovery deferred mapping.
899104840Sobrien     * Each deferred type D is mapped into a type T, where T is computed either by
900104840Sobrien     * (i) retrieving the type that has already been computed for D during a previous
901104840Sobrien     * attribution round (as before), or (ii) by synthesizing a new type R for D
902104840Sobrien     * (the latter step is useful in a recovery scenario).
903104840Sobrien     */
904218822Sdim    public class RecoveryDeferredTypeMap extends DeferredTypeMap {
905218822Sdim
906104840Sobrien        public RecoveryDeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
907104840Sobrien            super(mode, msym, phase != null ? phase : MethodResolutionPhase.BOX);
908104840Sobrien        }
909104840Sobrien
910104840Sobrien        @Override
911104840Sobrien        protected Type typeOf(DeferredType dt) {
912104840Sobrien            Type owntype = super.typeOf(dt);
913104840Sobrien            return owntype == Type.noType ?
914104840Sobrien                        recover(dt) : owntype;
915104840Sobrien        }
916104840Sobrien
917104840Sobrien        /**
918104840Sobrien         * Synthesize a type for a deferred type that hasn't been previously
919104840Sobrien         * reduced to an ordinary type. Functional deferred types and conditionals
920104840Sobrien         * are mapped to themselves, in order to have a richer diagnostic
921104840Sobrien         * representation. Remaining deferred types are attributed using
92233965Sjdp         * a default expected type (j.l.Object).
92389861Sobrien         */
92489861Sobrien        private Type recover(DeferredType dt) {
92533965Sjdp            dt.check(attr.new RecoveryInfo(deferredAttrContext) {
926130570Sobrien                @Override
927130570Sobrien                protected Type check(DiagnosticPosition pos, Type found) {
928130570Sobrien                    return chk.checkNonVoid(pos, super.check(pos, found));
929130570Sobrien                }
930130570Sobrien            });
93133965Sjdp            return super.apply(dt);
93289861Sobrien        }
93333965Sjdp    }
93433965Sjdp
93533965Sjdp    /**
93633965Sjdp     * A special tree scanner that would only visit portions of a given tree.
93733965Sjdp     * The set of nodes visited by the scanner can be customized at construction-time.
93833965Sjdp     */
939130570Sobrien    abstract static class FilterScanner extends TreeScanner {
940130570Sobrien
94133965Sjdp        final Filter<JCTree> treeFilter;
94289861Sobrien
94333965Sjdp        FilterScanner(final Set<JCTree.Tag> validTags) {
94433965Sjdp            this.treeFilter = new Filter<JCTree>() {
94533965Sjdp                public boolean accepts(JCTree t) {
94633965Sjdp                    return validTags.contains(t.getTag());
94733965Sjdp                }
94833965Sjdp            };
94933965Sjdp        }
95033965Sjdp
951104840Sobrien        @Override
95233965Sjdp        public void scan(JCTree tree) {
95333965Sjdp            if (tree != null) {
95433965Sjdp                if (treeFilter.accepts(tree)) {
95533965Sjdp                    super.scan(tree);
956104840Sobrien                } else {
95733965Sjdp                    skip(tree);
95878832Sobrien                }
95978832Sobrien            }
960218822Sdim        }
961218822Sdim
96289861Sobrien        /**
963130570Sobrien         * handler that is executed when a node has been discarded
96478832Sobrien         */
96578832Sobrien        void skip(JCTree tree) {}
96633965Sjdp    }
96733965Sjdp
96833965Sjdp    /**
969218822Sdim     * A tree scanner suitable for visiting the target-type dependent nodes of
970218822Sdim     * a given argument expression.
971218822Sdim     */
972218822Sdim    static class PolyScanner extends FilterScanner {
973218822Sdim
974218822Sdim        PolyScanner() {
97533965Sjdp            super(EnumSet.of(CONDEXPR, PARENS, LAMBDA, REFERENCE));
976104840Sobrien        }
977104840Sobrien    }
978104840Sobrien
97933965Sjdp    /**
980104840Sobrien     * A tree scanner suitable for visiting the target-type dependent nodes nested
981104840Sobrien     * within a lambda expression body.
982104840Sobrien     */
983104840Sobrien    static class LambdaReturnScanner extends FilterScanner {
984104840Sobrien
985104840Sobrien        LambdaReturnScanner() {
986104840Sobrien            super(EnumSet.of(BLOCK, CASE, CATCH, DOLOOP, FOREACHLOOP,
987104840Sobrien                    FORLOOP, IF, RETURN, SYNCHRONIZED, SWITCH, TRY, WHILELOOP));
988104840Sobrien        }
989104840Sobrien    }
990104840Sobrien
991104840Sobrien    /**
992104840Sobrien     * This visitor is used to check that structural expressions conform
993104840Sobrien     * to their target - this step is required as inference could end up
994104840Sobrien     * inferring types that make some of the nested expressions incompatible
995104840Sobrien     * with their corresponding instantiated target
996104840Sobrien     */
997218822Sdim    class CheckStuckPolicy extends PolyScanner implements DeferredStuckPolicy, Infer.FreeTypeListener {
998104840Sobrien
999104840Sobrien        Type pt;
1000104840Sobrien        Infer.InferenceContext inferenceContext;
1001104840Sobrien        Set<Type> stuckVars = new LinkedHashSet<>();
1002104840Sobrien        Set<Type> depVars = new LinkedHashSet<>();
1003104840Sobrien
1004104840Sobrien        @Override
1005104840Sobrien        public boolean isStuck() {
1006104840Sobrien            return !stuckVars.isEmpty();
1007104840Sobrien        }
100833965Sjdp
1009104840Sobrien        @Override
1010218822Sdim        public Set<Type> stuckVars() {
1011218822Sdim            return stuckVars;
101233965Sjdp        }
1013104840Sobrien
1014104840Sobrien        @Override
101589861Sobrien        public Set<Type> depVars() {
1016104840Sobrien            return depVars;
1017104840Sobrien        }
1018104840Sobrien
1019104840Sobrien        public CheckStuckPolicy(ResultInfo resultInfo, DeferredType dt) {
1020104840Sobrien            this.pt = resultInfo.pt;
1021218822Sdim            this.inferenceContext = resultInfo.checkContext.inferenceContext();
1022218822Sdim            scan(dt.tree);
1023218822Sdim            if (!stuckVars.isEmpty()) {
1024104840Sobrien                resultInfo.checkContext.inferenceContext()
1025104840Sobrien                        .addFreeTypeListener(List.from(stuckVars), this);
1026104840Sobrien            }
1027104840Sobrien        }
1028104840Sobrien
1029104840Sobrien        @Override
1030104840Sobrien        public void typesInferred(InferenceContext inferenceContext) {
1031104840Sobrien            stuckVars.clear();
1032104840Sobrien        }
1033104840Sobrien
1034104840Sobrien        @Override
1035104840Sobrien        public void visitLambda(JCLambda tree) {
103633965Sjdp            if (inferenceContext.inferenceVars().contains(pt)) {
1037104840Sobrien                stuckVars.add(pt);
1038104840Sobrien            }
1039104840Sobrien            if (!types.isFunctionalInterface(pt)) {
1040104840Sobrien                return;
1041104840Sobrien            }
1042104840Sobrien            Type descType = types.findDescriptorType(pt);
1043104840Sobrien            List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
1044104840Sobrien            if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT &&
1045104840Sobrien                    freeArgVars.nonEmpty()) {
1046104840Sobrien                stuckVars.addAll(freeArgVars);
1047104840Sobrien                depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType()));
1048104840Sobrien            }
1049104840Sobrien            scanLambdaBody(tree, descType.getReturnType());
1050104840Sobrien        }
1051104840Sobrien
1052104840Sobrien        @Override
1053218822Sdim        public void visitReference(JCMemberReference tree) {
1054218822Sdim            scan(tree.expr);
1055130570Sobrien            if (inferenceContext.inferenceVars().contains(pt)) {
1056104840Sobrien                stuckVars.add(pt);
1057130570Sobrien                return;
1058104840Sobrien            }
1059218822Sdim            if (!types.isFunctionalInterface(pt)) {
1060218822Sdim                return;
1061104840Sobrien            }
1062218822Sdim
1063104840Sobrien            Type descType = types.findDescriptorType(pt);
1064104840Sobrien            List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
1065104840Sobrien            if (freeArgVars.nonEmpty() &&
1066104840Sobrien                    tree.overloadKind == JCMemberReference.OverloadKind.OVERLOADED) {
1067104840Sobrien                stuckVars.addAll(freeArgVars);
1068104840Sobrien                depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType()));
1069104840Sobrien            }
1070104840Sobrien        }
1071104840Sobrien
1072104840Sobrien        void scanLambdaBody(JCLambda lambda, final Type pt) {
1073218822Sdim            if (lambda.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) {
1074104840Sobrien                Type prevPt = this.pt;
1075104840Sobrien                try {
1076218822Sdim                    this.pt = pt;
1077104840Sobrien                    scan(lambda.body);
1078218822Sdim                } finally {
1079218822Sdim                    this.pt = prevPt;
1080218822Sdim                }
1081104840Sobrien            } else {
1082104840Sobrien                LambdaReturnScanner lambdaScanner = new LambdaReturnScanner() {
1083104840Sobrien                    @Override
1084218822Sdim                    public void visitReturn(JCReturn tree) {
1085130570Sobrien                        if (tree.expr != null) {
1086218822Sdim                            Type prevPt = CheckStuckPolicy.this.pt;
1087104840Sobrien                            try {
1088130570Sobrien                                CheckStuckPolicy.this.pt = pt;
1089104840Sobrien                                CheckStuckPolicy.this.scan(tree.expr);
1090104840Sobrien                            } finally {
1091104840Sobrien                                CheckStuckPolicy.this.pt = prevPt;
1092104840Sobrien                            }
1093104840Sobrien                        }
1094104840Sobrien                    }
1095104840Sobrien                };
1096104840Sobrien                lambdaScanner.scan(lambda.body);
1097104840Sobrien            }
1098104840Sobrien        }
1099104840Sobrien    }
110089861Sobrien
110133965Sjdp    /**
110289861Sobrien     * This visitor is used to check that structural expressions conform
110389861Sobrien     * to their target - this step is required as inference could end up
1104104840Sobrien     * inferring types that make some of the nested expressions incompatible
110589861Sobrien     * with their corresponding instantiated target
110689861Sobrien     */
110789861Sobrien    class OverloadStuckPolicy extends CheckStuckPolicy implements DeferredStuckPolicy {
110889861Sobrien
110989861Sobrien        boolean stuck;
1110130570Sobrien
111133965Sjdp        @Override
1112104840Sobrien        public boolean isStuck() {
1113104840Sobrien            return super.isStuck() || stuck;
1114104840Sobrien        }
111533965Sjdp
1116104840Sobrien        public OverloadStuckPolicy(ResultInfo resultInfo, DeferredType dt) {
1117104840Sobrien            super(resultInfo, dt);
1118104840Sobrien        }
1119104840Sobrien
1120130570Sobrien        @Override
1121130570Sobrien        public void visitLambda(JCLambda tree) {
112233965Sjdp            super.visitLambda(tree);
112333965Sjdp            if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT) {
112433965Sjdp                stuck = true;
112589861Sobrien            }
112689861Sobrien        }
112789861Sobrien
112889861Sobrien        @Override
112989861Sobrien        public void visitReference(JCMemberReference tree) {
113089861Sobrien            super.visitReference(tree);
113189861Sobrien            if (tree.overloadKind == JCMemberReference.OverloadKind.OVERLOADED) {
113289861Sobrien                stuck = true;
1133218822Sdim            }
113460509Sobrien        }
113589861Sobrien    }
113689861Sobrien
113789861Sobrien    /**
1138130570Sobrien     * Does the argument expression {@code expr} need speculative type-checking?
1139218822Sdim     */
114089861Sobrien    boolean isDeferred(Env<AttrContext> env, JCExpression expr) {
114189861Sobrien        DeferredChecker dc = new DeferredChecker(env);
114233965Sjdp        dc.scan(expr);
114377302Sobrien        return dc.result.isPoly();
114477302Sobrien    }
114577302Sobrien
114677302Sobrien    /**
114777302Sobrien     * The kind of an argument expression. This is used by the analysis that
114877302Sobrien     * determines as to whether speculative attribution is necessary.
114977302Sobrien     */
115077302Sobrien    enum ArgumentExpressionKind {
115177302Sobrien
115277302Sobrien        /** kind that denotes poly argument expression */
115389861Sobrien        POLY,
115477302Sobrien        /** kind that denotes a standalone expression */
115577302Sobrien        NO_POLY,
115677302Sobrien        /** kind that denotes a primitive/boxed standalone expression */
115789861Sobrien        PRIMITIVE;
115889861Sobrien
115989861Sobrien        /**
116089861Sobrien         * Does this kind denote a poly argument expression
116189861Sobrien         */
116289861Sobrien        public final boolean isPoly() {
116389861Sobrien            return this == POLY;
116489861Sobrien        }
1165104840Sobrien
116689861Sobrien        /**
1167218822Sdim         * Does this kind denote a primitive standalone expression
116889861Sobrien         */
1169218822Sdim        public final boolean isPrimitive() {
1170130570Sobrien            return this == PRIMITIVE;
1171130570Sobrien        }
117289861Sobrien
117389861Sobrien        /**
117489861Sobrien         * Compute the kind of a standalone expression of a given type
1175218822Sdim         */
117633965Sjdp        static ArgumentExpressionKind standaloneKind(Type type, Types types) {
117789861Sobrien            return types.unboxedTypeOrType(type).isPrimitive() ?
117889861Sobrien                    ArgumentExpressionKind.PRIMITIVE :
117989861Sobrien                    ArgumentExpressionKind.NO_POLY;
118089861Sobrien        }
118189861Sobrien
118289861Sobrien        /**
118333965Sjdp         * Compute the kind of a method argument expression given its symbol
118433965Sjdp         */
118533965Sjdp        static ArgumentExpressionKind methodKind(Symbol sym, Types types) {
118689861Sobrien            Type restype = sym.type.getReturnType();
118794543Sobrien            if (sym.type.hasTag(FORALL) &&
118894543Sobrien                    restype.containsAny(((ForAll)sym.type).tvars)) {
118933965Sjdp                return ArgumentExpressionKind.POLY;
119094543Sobrien            } else {
119133965Sjdp                return ArgumentExpressionKind.standaloneKind(restype, types);
1192130570Sobrien            }
119333965Sjdp        }
1194218822Sdim    }
119577302Sobrien
119677302Sobrien    /**
119777302Sobrien     * Tree scanner used for checking as to whether an argument expression
119889861Sobrien     * requires speculative attribution
1199218822Sdim     */
1200218822Sdim    final class DeferredChecker extends FilterScanner {
120178832Sobrien
120233965Sjdp        Env<AttrContext> env;
120389861Sobrien        ArgumentExpressionKind result;
120489861Sobrien
120589861Sobrien        public DeferredChecker(Env<AttrContext> env) {
120689861Sobrien            super(deferredCheckerTags);
120733965Sjdp            this.env = env;
120833965Sjdp        }
120933965Sjdp
121033965Sjdp        @Override
121133965Sjdp        public void visitLambda(JCLambda tree) {
121233965Sjdp            //a lambda is always a poly expression
121333965Sjdp            result = ArgumentExpressionKind.POLY;
121433965Sjdp        }
121533965Sjdp
1216218822Sdim        @Override
1217218822Sdim        public void visitReference(JCMemberReference tree) {
1218218822Sdim            //perform arity-based check
121933965Sjdp            Env<AttrContext> localEnv = env.dup(tree);
122033965Sjdp            JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv,
1221130570Sobrien                    attr.memberReferenceQualifierResult(tree));
122233965Sjdp            JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree);
122389861Sobrien            mref2.expr = exprTree;
122433965Sjdp            Symbol res =
122533965Sjdp                    rs.getMemberReference(tree, localEnv, mref2,
122689861Sobrien                        exprTree.type, tree.name);
122789861Sobrien            tree.sym = res;
122889861Sobrien            if (res.kind.isOverloadError() ||
122933965Sjdp                    res.type.hasTag(FORALL) ||
123089861Sobrien                    (res.flags() & Flags.VARARGS) != 0 ||
123189861Sobrien                    (TreeInfo.isStaticSelector(exprTree, tree.name.table.names) &&
123289861Sobrien                    exprTree.type.isRaw())) {
123389861Sobrien                tree.overloadKind = JCMemberReference.OverloadKind.OVERLOADED;
1234218822Sdim            } else {
123589861Sobrien                tree.overloadKind = JCMemberReference.OverloadKind.UNOVERLOADED;
123689861Sobrien            }
123789861Sobrien            //a method reference is always a poly expression
123833965Sjdp            result = ArgumentExpressionKind.POLY;
123989861Sobrien        }
124089861Sobrien
124189861Sobrien        @Override
124289861Sobrien        public void visitTypeCast(JCTypeCast tree) {
1243130570Sobrien            //a cast is always a standalone expression
124433965Sjdp            result = ArgumentExpressionKind.NO_POLY;
1245218822Sdim        }
1246218822Sdim
124789861Sobrien        @Override
124833965Sjdp        public void visitConditional(JCConditional tree) {
124989861Sobrien            scan(tree.truepart);
125089861Sobrien            if (!result.isPrimitive()) {
125189861Sobrien                result = ArgumentExpressionKind.POLY;
125289861Sobrien                return;
1253130570Sobrien            }
125433965Sjdp            scan(tree.falsepart);
1255130570Sobrien            result = reduce(ArgumentExpressionKind.PRIMITIVE).isPrimitive() ?
125689861Sobrien                    ArgumentExpressionKind.PRIMITIVE :
125789861Sobrien                    ArgumentExpressionKind.POLY;
125889861Sobrien
125989861Sobrien        }
126089861Sobrien
126189861Sobrien        @Override
126233965Sjdp        public void visitNewClass(JCNewClass tree) {
126389861Sobrien            result = TreeInfo.isDiamond(tree) ?
1264104840Sobrien                    ArgumentExpressionKind.POLY : ArgumentExpressionKind.NO_POLY;
126589861Sobrien        }
126633965Sjdp
126733965Sjdp        @Override
126833965Sjdp        public void visitApply(JCMethodInvocation tree) {
126960509Sobrien            Name name = TreeInfo.name(tree.meth);
127060509Sobrien
127160509Sobrien            //fast path
1272130570Sobrien            if (tree.typeargs.nonEmpty() ||
1273130570Sobrien                    name == name.table.names._this ||
127460509Sobrien                    name == name.table.names._super) {
127560509Sobrien                result = ArgumentExpressionKind.NO_POLY;
127660509Sobrien                return;
127760509Sobrien            }
127860509Sobrien
1279130570Sobrien            //slow path
1280130570Sobrien            Symbol sym = quicklyResolveMethod(env, tree);
128160509Sobrien
128260509Sobrien            if (sym == null) {
128333965Sjdp                result = ArgumentExpressionKind.POLY;
128433965Sjdp                return;
128533965Sjdp            }
128633965Sjdp
128733965Sjdp            result = analyzeCandidateMethods(sym, ArgumentExpressionKind.PRIMITIVE,
1288130570Sobrien                    argumentKindAnalyzer);
128933965Sjdp        }
129033965Sjdp        //where
129160509Sobrien            private boolean isSimpleReceiver(JCTree rec) {
129260509Sobrien                switch (rec.getTag()) {
129360509Sobrien                    case IDENT:
129460509Sobrien                        return true;
1295130570Sobrien                    case SELECT:
1296218822Sdim                        return isSimpleReceiver(((JCFieldAccess)rec).selected);
1297130570Sobrien                    case TYPEAPPLY:
1298130570Sobrien                    case TYPEARRAY:
1299130570Sobrien                        return true;
130060509Sobrien                    case ANNOTATED_TYPE:
130160509Sobrien                        return isSimpleReceiver(((JCAnnotatedType)rec).underlyingType);
1302218822Sdim                    case APPLY:
1303218822Sdim                        return true;
1304218822Sdim                    default:
1305218822Sdim                        return false;
1306218822Sdim                }
1307218822Sdim            }
130860509Sobrien            private ArgumentExpressionKind reduce(ArgumentExpressionKind kind) {
1309218822Sdim                return argumentKindAnalyzer.reduce(result, kind);
131060509Sobrien            }
131160509Sobrien            MethodAnalyzer<ArgumentExpressionKind> argumentKindAnalyzer =
131260509Sobrien                    new MethodAnalyzer<ArgumentExpressionKind>() {
131360509Sobrien                @Override
1314130570Sobrien                public ArgumentExpressionKind process(MethodSymbol ms) {
1315130570Sobrien                    return ArgumentExpressionKind.methodKind(ms, types);
1316130570Sobrien                }
1317130570Sobrien                @Override
1318130570Sobrien                public ArgumentExpressionKind reduce(ArgumentExpressionKind kind1,
131960509Sobrien                                                     ArgumentExpressionKind kind2) {
132077302Sobrien                    switch (kind1) {
132177302Sobrien                        case PRIMITIVE: return kind2;
132277302Sobrien                        case NO_POLY: return kind2.isPoly() ? kind2 : kind1;
132377302Sobrien                        case POLY: return kind1;
132460509Sobrien                        default:
132589861Sobrien                            Assert.error();
132689861Sobrien                            return null;
132777302Sobrien                    }
132877302Sobrien                }
132977302Sobrien                @Override
133077302Sobrien                public boolean shouldStop(ArgumentExpressionKind result) {
133177302Sobrien                    return result.isPoly();
133277302Sobrien                }
1333130570Sobrien            };
1334130570Sobrien
1335130570Sobrien        @Override
1336130570Sobrien        public void visitLiteral(JCLiteral tree) {
1337104840Sobrien            Type litType = attr.litType(tree.typetag);
1338130570Sobrien            result = ArgumentExpressionKind.standaloneKind(litType, types);
1339130570Sobrien        }
1340130570Sobrien
1341130570Sobrien        @Override
1342130570Sobrien        void skip(JCTree tree) {
1343130570Sobrien            result = ArgumentExpressionKind.NO_POLY;
134477302Sobrien        }
1345130570Sobrien
1346218822Sdim        private Symbol quicklyResolveMethod(Env<AttrContext> env, final JCMethodInvocation tree) {
1347218822Sdim            final JCExpression rec = tree.meth.hasTag(SELECT) ?
1348218822Sdim                    ((JCFieldAccess)tree.meth).selected :
1349130570Sobrien                    null;
1350104840Sobrien
1351130570Sobrien            if (rec != null && !isSimpleReceiver(rec)) {
1352130570Sobrien                return null;
1353130570Sobrien            }
1354130570Sobrien
1355130570Sobrien            Type site;
1356130570Sobrien
1357130570Sobrien            if (rec != null) {
1358130570Sobrien                if (rec.hasTag(APPLY)) {
135989861Sobrien                    Symbol recSym = quicklyResolveMethod(env, (JCMethodInvocation) rec);
1360130570Sobrien                    if (recSym == null)
1361130570Sobrien                        return null;
1362130570Sobrien                    Symbol resolvedReturnType =
1363130570Sobrien                            analyzeCandidateMethods(recSym, syms.errSymbol, returnSymbolAnalyzer);
1364130570Sobrien                    if (resolvedReturnType == null)
1365130570Sobrien                        return null;
1366130570Sobrien                    site = resolvedReturnType.type;
1367130570Sobrien                } else {
136889861Sobrien                    site = attribSpeculative(rec, env, attr.unknownTypeExprInfo).type;
1369130570Sobrien                }
1370218822Sdim            } else {
1371218822Sdim                site = env.enclClass.sym.type;
1372130570Sobrien            }
1373130570Sobrien
1374130570Sobrien            while (site.hasTag(TYPEVAR)) {
1375130570Sobrien                site = site.getUpperBound();
1376130570Sobrien            }
1377130570Sobrien
1378130570Sobrien            site = types.capture(site);
1379130570Sobrien
1380130570Sobrien            List<Type> args = rs.dummyArgs(tree.args.length());
1381130570Sobrien            Name name = TreeInfo.name(tree.meth);
1382130570Sobrien
1383130570Sobrien            Resolve.LookupHelper lh = rs.new LookupHelper(name, site, args, List.<Type>nil(), MethodResolutionPhase.VARARITY) {
1384130570Sobrien                @Override
1385130570Sobrien                Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
1386130570Sobrien                    return rec == null ?
138789861Sobrien                        rs.findFun(env, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()) :
1388130570Sobrien                        rs.findMethod(env, site, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired(), false);
1389130570Sobrien                }
1390130570Sobrien                @Override
1391130570Sobrien                Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
1392130570Sobrien                    return sym;
139389861Sobrien                }
1394130570Sobrien            };
1395130570Sobrien
1396130570Sobrien            return rs.lookupMethod(env, tree, site.tsym, rs.arityMethodCheck, lh);
1397130570Sobrien        }
1398130570Sobrien        //where:
1399130570Sobrien            MethodAnalyzer<Symbol> returnSymbolAnalyzer = new MethodAnalyzer<Symbol>() {
1400130570Sobrien                @Override
140189861Sobrien                public Symbol process(MethodSymbol ms) {
1402130570Sobrien                    ArgumentExpressionKind kind = ArgumentExpressionKind.methodKind(ms, types);
1403130570Sobrien                    if (kind == ArgumentExpressionKind.POLY || ms.getReturnType().hasTag(TYPEVAR))
1404130570Sobrien                        return null;
1405130570Sobrien                    return ms.getReturnType().tsym;
140677302Sobrien                }
1407130570Sobrien                @Override
140860509Sobrien                public Symbol reduce(Symbol s1, Symbol s2) {
140960509Sobrien                    return s1 == syms.errSymbol ? s2 : s1 == s2 ? s1 : null;
141033965Sjdp                }
141133965Sjdp                @Override
141233965Sjdp                public boolean shouldStop(Symbol result) {
141333965Sjdp                    return result == null;
141433965Sjdp                }
141533965Sjdp            };
1416130570Sobrien
1417130570Sobrien        /**
1418130570Sobrien         * Process the result of Resolve.lookupMethod. If sym is a method symbol, the result of
141933965Sjdp         * MethodAnalyzer.process is returned. If sym is an ambiguous symbol, all the candidate
142089861Sobrien         * methods are inspected one by one, using MethodAnalyzer.process. The outcomes are
142133965Sjdp         * reduced using MethodAnalyzer.reduce (using defaultValue as the first value over which
142233965Sjdp         * the reduction runs). MethodAnalyzer.shouldStop can be used to stop the inspection early.
142333965Sjdp         */
142433965Sjdp        <E> E analyzeCandidateMethods(Symbol sym, E defaultValue, MethodAnalyzer<E> analyzer) {
142533965Sjdp            switch (sym.kind) {
142633965Sjdp                case MTH:
1427218822Sdim                    return analyzer.process((MethodSymbol) sym);
142833965Sjdp                case AMBIGUOUS:
142989861Sobrien                    Resolve.AmbiguityError err = (Resolve.AmbiguityError)sym.baseSymbol();
1430130570Sobrien                    E res = defaultValue;
1431130570Sobrien                    for (Symbol s : err.ambiguousSyms) {
1432130570Sobrien                        if (s.kind == MTH) {
143333965Sjdp                            res = analyzer.reduce(res, analyzer.process((MethodSymbol) s));
143433965Sjdp                            if (analyzer.shouldStop(res))
143577302Sobrien                                return res;
143677302Sobrien                        }
143777302Sobrien                    }
143877302Sobrien                    return res;
143977302Sobrien                default:
1440218822Sdim                    return defaultValue;
144133965Sjdp            }
144233965Sjdp        }
1443130570Sobrien    }
144433965Sjdp
144589861Sobrien    /** Analyzer for methods - used by analyzeCandidateMethods. */
144689861Sobrien    interface MethodAnalyzer<E> {
144789861Sobrien        E process(MethodSymbol ms);
144889861Sobrien        E reduce(E e1, E e2);
144989861Sobrien        boolean shouldStop(E result);
145089861Sobrien    }
145189861Sobrien
145233965Sjdp    //where
145333965Sjdp    private EnumSet<JCTree.Tag> deferredCheckerTags =
145433965Sjdp            EnumSet.of(LAMBDA, REFERENCE, PARENS, TYPECAST,
145533965Sjdp                    CONDEXPR, NEWCLASS, APPLY, LITERAL);
1456218822Sdim}
145733965Sjdp