DeferredAttr.java revision 2994:dd96ac308ab8
1/*
2 * Copyright (c) 2012, 2015, 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.source.tree.LambdaExpressionTree.BodyKind;
29import com.sun.source.tree.NewClassTree;
30import com.sun.tools.javac.code.*;
31import com.sun.tools.javac.code.Type.TypeMapping;
32import com.sun.tools.javac.comp.Resolve.ResolveError;
33import com.sun.tools.javac.resources.CompilerProperties.Fragments;
34import com.sun.tools.javac.tree.*;
35import com.sun.tools.javac.util.*;
36import com.sun.tools.javac.util.DefinedBy.Api;
37import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
38import com.sun.tools.javac.code.Symbol.*;
39import com.sun.tools.javac.code.Type.*;
40import com.sun.tools.javac.comp.Attr.ResultInfo;
41import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
42import com.sun.tools.javac.tree.JCTree.*;
43import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType;
44import com.sun.tools.javac.util.Log.DeferredDiagnosticHandler;
45
46import java.util.ArrayList;
47import java.util.Collections;
48import java.util.EnumSet;
49import java.util.LinkedHashMap;
50import java.util.LinkedHashSet;
51import java.util.Map;
52import java.util.Set;
53import java.util.WeakHashMap;
54import java.util.function.Function;
55
56import static com.sun.tools.javac.code.TypeTag.*;
57import static com.sun.tools.javac.tree.JCTree.Tag.*;
58import static com.sun.tools.javac.code.Kinds.*;
59import static com.sun.tools.javac.code.Kinds.Kind.*;
60
61/**
62 * This is an helper class that is used to perform deferred type-analysis.
63 * Each time a poly expression occurs in argument position, javac attributes it
64 * with a temporary 'deferred type' that is checked (possibly multiple times)
65 * against an expected formal type.
66 *
67 *  <p><b>This is NOT part of any supported API.
68 *  If you write code that depends on this, you do so at your own risk.
69 *  This code and its internal interfaces are subject to change or
70 *  deletion without notice.</b>
71 */
72public class DeferredAttr extends JCTree.Visitor {
73    protected static final Context.Key<DeferredAttr> deferredAttrKey = new Context.Key<>();
74
75    final Attr attr;
76    final Check chk;
77    final JCDiagnostic.Factory diags;
78    final Enter enter;
79    final Infer infer;
80    final Resolve rs;
81    final Log log;
82    final Symtab syms;
83    final TreeMaker make;
84    final TreeCopier<Void> treeCopier;
85    final TypeMapping<Void> deferredCopier;
86    final Types types;
87    final Flow flow;
88    final Names names;
89    final TypeEnvs typeEnvs;
90
91    public static DeferredAttr instance(Context context) {
92        DeferredAttr instance = context.get(deferredAttrKey);
93        if (instance == null)
94            instance = new DeferredAttr(context);
95        return instance;
96    }
97
98    protected DeferredAttr(Context context) {
99        context.put(deferredAttrKey, this);
100        attr = Attr.instance(context);
101        chk = Check.instance(context);
102        diags = JCDiagnostic.Factory.instance(context);
103        enter = Enter.instance(context);
104        infer = Infer.instance(context);
105        rs = Resolve.instance(context);
106        log = Log.instance(context);
107        syms = Symtab.instance(context);
108        make = TreeMaker.instance(context);
109        types = Types.instance(context);
110        flow = Flow.instance(context);
111        names = Names.instance(context);
112        stuckTree = make.Ident(names.empty).setType(Type.stuckType);
113        typeEnvs = TypeEnvs.instance(context);
114        emptyDeferredAttrContext =
115            new DeferredAttrContext(AttrMode.CHECK, null, MethodResolutionPhase.BOX, infer.emptyContext, null, null) {
116                @Override
117                void addDeferredAttrNode(DeferredType dt, ResultInfo ri, DeferredStuckPolicy deferredStuckPolicy) {
118                    Assert.error("Empty deferred context!");
119                }
120                @Override
121                void complete() {
122                    Assert.error("Empty deferred context!");
123                }
124
125                @Override
126                public String toString() {
127                    return "Empty deferred context!";
128                }
129            };
130
131        // For speculative attribution, skip the class definition in <>.
132        treeCopier =
133            new TreeCopier<Void>(make) {
134                @Override @DefinedBy(Api.COMPILER_TREE)
135                public JCTree visitNewClass(NewClassTree node, Void p) {
136                    JCNewClass t = (JCNewClass) node;
137                    if (TreeInfo.isDiamond(t)) {
138                        JCExpression encl = copy(t.encl, p);
139                        List<JCExpression> typeargs = copy(t.typeargs, p);
140                        JCExpression clazz = copy(t.clazz, p);
141                        List<JCExpression> args = copy(t.args, p);
142                        JCClassDecl def = null;
143                        return make.at(t.pos).NewClass(encl, typeargs, clazz, args, def);
144                    } else {
145                        return super.visitNewClass(node, p);
146                    }
147                }
148            };
149        deferredCopier = new TypeMapping<Void> () {
150                @Override
151                public Type visitType(Type t, Void v) {
152                    if (t.hasTag(DEFERRED)) {
153                        DeferredType dt = (DeferredType) t;
154                        return new DeferredType(treeCopier.copy(dt.tree), dt.env);
155                    }
156                    return t;
157                }
158            };
159    }
160
161    /** shared tree for stuck expressions */
162    final JCTree stuckTree;
163
164    /**
165     * This type represents a deferred type. A deferred type starts off with
166     * no information on the underlying expression type. Such info needs to be
167     * discovered through type-checking the deferred type against a target-type.
168     * Every deferred type keeps a pointer to the AST node from which it originated.
169     */
170    public class DeferredType extends Type {
171
172        public JCExpression tree;
173        Env<AttrContext> env;
174        AttrMode mode;
175        SpeculativeCache speculativeCache;
176
177        DeferredType(JCExpression tree, Env<AttrContext> env) {
178            super(null, TypeMetadata.EMPTY);
179            this.tree = tree;
180            this.env = attr.copyEnv(env);
181            this.speculativeCache = new SpeculativeCache();
182        }
183
184        @Override
185        public DeferredType cloneWithMetadata(TypeMetadata md) {
186            throw new AssertionError("Cannot add metadata to a deferred type");
187        }
188
189        @Override
190        public TypeTag getTag() {
191            return DEFERRED;
192        }
193
194        @Override @DefinedBy(Api.LANGUAGE_MODEL)
195        public String toString() {
196            return "DeferredType";
197        }
198
199        /**
200         * A speculative cache is used to keep track of all overload resolution rounds
201         * that triggered speculative attribution on a given deferred type. Each entry
202         * stores a pointer to the speculative tree and the resolution phase in which the entry
203         * has been added.
204         */
205        class SpeculativeCache {
206
207            private Map<Symbol, List<Entry>> cache = new WeakHashMap<>();
208
209            class Entry {
210                JCTree speculativeTree;
211                ResultInfo resultInfo;
212
213                public Entry(JCTree speculativeTree, ResultInfo resultInfo) {
214                    this.speculativeTree = speculativeTree;
215                    this.resultInfo = resultInfo;
216                }
217
218                boolean matches(MethodResolutionPhase phase) {
219                    return resultInfo.checkContext.deferredAttrContext().phase == phase;
220                }
221            }
222
223            /**
224             * Retrieve a speculative cache entry corresponding to given symbol
225             * and resolution phase
226             */
227            Entry get(Symbol msym, MethodResolutionPhase phase) {
228                List<Entry> entries = cache.get(msym);
229                if (entries == null) return null;
230                for (Entry e : entries) {
231                    if (e.matches(phase)) return e;
232                }
233                return null;
234            }
235
236            /**
237             * Stores a speculative cache entry corresponding to given symbol
238             * and resolution phase
239             */
240            void put(JCTree speculativeTree, ResultInfo resultInfo) {
241                Symbol msym = resultInfo.checkContext.deferredAttrContext().msym;
242                List<Entry> entries = cache.get(msym);
243                if (entries == null) {
244                    entries = List.nil();
245                }
246                cache.put(msym, entries.prepend(new Entry(speculativeTree, resultInfo)));
247            }
248        }
249
250        /**
251         * Get the type that has been computed during a speculative attribution round
252         */
253        Type speculativeType(Symbol msym, MethodResolutionPhase phase) {
254            SpeculativeCache.Entry e = speculativeCache.get(msym, phase);
255            return e != null ? e.speculativeTree.type : Type.noType;
256        }
257
258        /**
259         * Check a deferred type against a potential target-type. Depending on
260         * the current attribution mode, a normal vs. speculative attribution
261         * round is performed on the underlying AST node. There can be only one
262         * speculative round for a given target method symbol; moreover, a normal
263         * attribution round must follow one or more speculative rounds.
264         */
265        Type check(ResultInfo resultInfo) {
266            DeferredStuckPolicy deferredStuckPolicy;
267            if (resultInfo.pt.hasTag(NONE) || resultInfo.pt.isErroneous()) {
268                deferredStuckPolicy = dummyStuckPolicy;
269            } else if (resultInfo.checkContext.deferredAttrContext().mode == AttrMode.SPECULATIVE ||
270                    resultInfo.checkContext.deferredAttrContext().insideOverloadPhase()) {
271                deferredStuckPolicy = new OverloadStuckPolicy(resultInfo, this);
272            } else {
273                deferredStuckPolicy = new CheckStuckPolicy(resultInfo, this);
274            }
275            return check(resultInfo, deferredStuckPolicy, basicCompleter);
276        }
277
278        private Type check(ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy,
279                DeferredTypeCompleter deferredTypeCompleter) {
280            DeferredAttrContext deferredAttrContext =
281                    resultInfo.checkContext.deferredAttrContext();
282            Assert.check(deferredAttrContext != emptyDeferredAttrContext);
283            if (deferredStuckPolicy.isStuck()) {
284                deferredAttrContext.addDeferredAttrNode(this, resultInfo, deferredStuckPolicy);
285                return Type.noType;
286            } else {
287                try {
288                    return deferredTypeCompleter.complete(this, resultInfo, deferredAttrContext);
289                } finally {
290                    mode = deferredAttrContext.mode;
291                }
292            }
293        }
294    }
295
296    /**
297     * A completer for deferred types. Defines an entry point for type-checking
298     * a deferred type.
299     */
300    interface DeferredTypeCompleter {
301        /**
302         * Entry point for type-checking a deferred type. Depending on the
303         * circumstances, type-checking could amount to full attribution
304         * or partial structural check (aka potential applicability).
305         */
306        Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext);
307    }
308
309
310    /**
311     * A basic completer for deferred types. This completer type-checks a deferred type
312     * using attribution; depending on the attribution mode, this could be either standard
313     * or speculative attribution.
314     */
315    DeferredTypeCompleter basicCompleter = new DeferredTypeCompleter() {
316        public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
317            switch (deferredAttrContext.mode) {
318                case SPECULATIVE:
319                    //Note: if a symbol is imported twice we might do two identical
320                    //speculative rounds...
321                    Assert.check(dt.mode == null || dt.mode == AttrMode.SPECULATIVE);
322                    JCTree speculativeTree = attribSpeculative(dt.tree, dt.env, resultInfo);
323                    dt.speculativeCache.put(speculativeTree, resultInfo);
324                    return speculativeTree.type;
325                case CHECK:
326                    Assert.check(dt.mode != null);
327                    return attr.attribTree(dt.tree, dt.env, resultInfo);
328            }
329            Assert.error();
330            return null;
331        }
332    };
333
334    /**
335     * Policy for detecting stuck expressions. Different criteria might cause
336     * an expression to be judged as stuck, depending on whether the check
337     * is performed during overload resolution or after most specific.
338     */
339    interface DeferredStuckPolicy {
340        /**
341         * Has the policy detected that a given expression should be considered stuck?
342         */
343        boolean isStuck();
344        /**
345         * Get the set of inference variables a given expression depends upon.
346         */
347        Set<Type> stuckVars();
348        /**
349         * Get the set of inference variables which might get new constraints
350         * if a given expression is being type-checked.
351         */
352        Set<Type> depVars();
353    }
354
355    /**
356     * Basic stuck policy; an expression is never considered to be stuck.
357     */
358    DeferredStuckPolicy dummyStuckPolicy = new DeferredStuckPolicy() {
359        @Override
360        public boolean isStuck() {
361            return false;
362        }
363        @Override
364        public Set<Type> stuckVars() {
365            return Collections.emptySet();
366        }
367        @Override
368        public Set<Type> depVars() {
369            return Collections.emptySet();
370        }
371    };
372
373    /**
374     * The 'mode' in which the deferred type is to be type-checked
375     */
376    public enum AttrMode {
377        /**
378         * A speculative type-checking round is used during overload resolution
379         * mainly to generate constraints on inference variables. Side-effects
380         * arising from type-checking the expression associated with the deferred
381         * type are reversed after the speculative round finishes. This means the
382         * expression tree will be left in a blank state.
383         */
384        SPECULATIVE,
385        /**
386         * This is the plain type-checking mode. Produces side-effects on the underlying AST node
387         */
388        CHECK
389    }
390
391    /**
392     * Routine that performs speculative type-checking; the input AST node is
393     * cloned (to avoid side-effects cause by Attr) and compiler state is
394     * restored after type-checking. All diagnostics (but critical ones) are
395     * disabled during speculative type-checking.
396     */
397    JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
398        return attribSpeculative(tree, env, resultInfo, treeCopier,
399                (newTree)->new DeferredAttrDiagHandler(log, newTree));
400    }
401
402    <Z> JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo, TreeCopier<Z> deferredCopier,
403                                 Function<JCTree, DeferredDiagnosticHandler> diagHandlerCreator) {
404        final JCTree newTree = deferredCopier.copy(tree);
405        Env<AttrContext> speculativeEnv = env.dup(newTree, env.info.dup(env.info.scope.dupUnshared(env.info.scope.owner)));
406        speculativeEnv.info.isSpeculative = true;
407        Log.DeferredDiagnosticHandler deferredDiagnosticHandler = diagHandlerCreator.apply(newTree);
408        try {
409            attr.attribTree(newTree, speculativeEnv, resultInfo);
410            unenterScanner.scan(newTree);
411            return newTree;
412        } finally {
413            unenterScanner.scan(newTree);
414            log.popDiagnosticHandler(deferredDiagnosticHandler);
415        }
416    }
417    //where
418        protected UnenterScanner unenterScanner = new UnenterScanner();
419
420        class UnenterScanner extends TreeScanner {
421            @Override
422            public void visitClassDef(JCClassDecl tree) {
423                ClassSymbol csym = tree.sym;
424                //if something went wrong during method applicability check
425                //it is possible that nested expressions inside argument expression
426                //are left unchecked - in such cases there's nothing to clean up.
427                if (csym == null) return;
428                typeEnvs.remove(csym);
429                chk.compiled.remove(csym.flatname);
430                syms.classes.remove(csym.flatname);
431                super.visitClassDef(tree);
432            }
433        }
434
435        static class DeferredAttrDiagHandler extends Log.DeferredDiagnosticHandler {
436
437            static class PosScanner extends TreeScanner {
438                DiagnosticPosition pos;
439                boolean found = false;
440
441                PosScanner(DiagnosticPosition pos) {
442                    this.pos = pos;
443                }
444
445                @Override
446                public void scan(JCTree tree) {
447                    if (tree != null &&
448                            tree.pos() == pos) {
449                        found = true;
450                    }
451                    super.scan(tree);
452                }
453            }
454
455            DeferredAttrDiagHandler(Log log, JCTree newTree) {
456                super(log, new Filter<JCDiagnostic>() {
457                    public boolean accepts(JCDiagnostic d) {
458                        PosScanner posScanner = new PosScanner(d.getDiagnosticPosition());
459                        posScanner.scan(newTree);
460                        return posScanner.found;
461                    }
462                });
463            }
464        }
465
466    /**
467     * A deferred context is created on each method check. A deferred context is
468     * used to keep track of information associated with the method check, such as
469     * the symbol of the method being checked, the overload resolution phase,
470     * the kind of attribution mode to be applied to deferred types and so forth.
471     * As deferred types are processed (by the method check routine) stuck AST nodes
472     * are added (as new deferred attribution nodes) to this context. The complete()
473     * routine makes sure that all pending nodes are properly processed, by
474     * progressively instantiating all inference variables on which one or more
475     * deferred attribution node is stuck.
476     */
477    class DeferredAttrContext {
478
479        /** attribution mode */
480        final AttrMode mode;
481
482        /** symbol of the method being checked */
483        final Symbol msym;
484
485        /** method resolution step */
486        final Resolve.MethodResolutionPhase phase;
487
488        /** inference context */
489        final InferenceContext inferenceContext;
490
491        /** parent deferred context */
492        final DeferredAttrContext parent;
493
494        /** Warner object to report warnings */
495        final Warner warn;
496
497        /** list of deferred attribution nodes to be processed */
498        ArrayList<DeferredAttrNode> deferredAttrNodes = new ArrayList<>();
499
500        DeferredAttrContext(AttrMode mode, Symbol msym, MethodResolutionPhase phase,
501                InferenceContext inferenceContext, DeferredAttrContext parent, Warner warn) {
502            this.mode = mode;
503            this.msym = msym;
504            this.phase = phase;
505            this.parent = parent;
506            this.warn = warn;
507            this.inferenceContext = inferenceContext;
508        }
509
510        /**
511         * Adds a node to the list of deferred attribution nodes - used by Resolve.rawCheckArgumentsApplicable
512         * Nodes added this way act as 'roots' for the out-of-order method checking process.
513         */
514        void addDeferredAttrNode(final DeferredType dt, ResultInfo resultInfo,
515                DeferredStuckPolicy deferredStuckPolicy) {
516            deferredAttrNodes.add(new DeferredAttrNode(dt, resultInfo, deferredStuckPolicy));
517        }
518
519        /**
520         * Incrementally process all nodes, by skipping 'stuck' nodes and attributing
521         * 'unstuck' ones. If at any point no progress can be made (no 'unstuck' nodes)
522         * some inference variable might get eagerly instantiated so that all nodes
523         * can be type-checked.
524         */
525        void complete() {
526            while (!deferredAttrNodes.isEmpty()) {
527                Map<Type, Set<Type>> depVarsMap = new LinkedHashMap<>();
528                List<Type> stuckVars = List.nil();
529                boolean progress = false;
530                //scan a defensive copy of the node list - this is because a deferred
531                //attribution round can add new nodes to the list
532                for (DeferredAttrNode deferredAttrNode : List.from(deferredAttrNodes)) {
533                    if (!deferredAttrNode.process(this)) {
534                        List<Type> restStuckVars =
535                                List.from(deferredAttrNode.deferredStuckPolicy.stuckVars())
536                                .intersect(inferenceContext.restvars());
537                        stuckVars = stuckVars.prependList(restStuckVars);
538                        //update dependency map
539                        for (Type t : List.from(deferredAttrNode.deferredStuckPolicy.depVars())
540                                .intersect(inferenceContext.restvars())) {
541                            Set<Type> prevDeps = depVarsMap.get(t);
542                            if (prevDeps == null) {
543                                prevDeps = new LinkedHashSet<>();
544                                depVarsMap.put(t, prevDeps);
545                            }
546                            prevDeps.addAll(restStuckVars);
547                        }
548                    } else {
549                        deferredAttrNodes.remove(deferredAttrNode);
550                        progress = true;
551                    }
552                }
553                if (!progress) {
554                    if (insideOverloadPhase()) {
555                        for (DeferredAttrNode deferredNode: deferredAttrNodes) {
556                            deferredNode.dt.tree.type = Type.noType;
557                        }
558                        return;
559                    }
560                    //remove all variables that have already been instantiated
561                    //from the list of stuck variables
562                    try {
563                        inferenceContext.solveAny(stuckVars, depVarsMap, warn);
564                        inferenceContext.notifyChange();
565                    } catch (Infer.GraphStrategy.NodeNotFoundException ex) {
566                        //this means that we are in speculative mode and the
567                        //set of contraints are too tight for progess to be made.
568                        //Just leave the remaining expressions as stuck.
569                        break;
570                    }
571                }
572            }
573        }
574
575        private boolean insideOverloadPhase() {
576            DeferredAttrContext dac = this;
577            if (dac == emptyDeferredAttrContext) {
578                return false;
579            }
580            if (dac.mode == AttrMode.SPECULATIVE) {
581                return true;
582            }
583            return dac.parent.insideOverloadPhase();
584        }
585    }
586
587    /**
588     * Class representing a deferred attribution node. It keeps track of
589     * a deferred type, along with the expected target type information.
590     */
591    class DeferredAttrNode {
592
593        /** underlying deferred type */
594        DeferredType dt;
595
596        /** underlying target type information */
597        ResultInfo resultInfo;
598
599        /** stuck policy associated with this node */
600        DeferredStuckPolicy deferredStuckPolicy;
601
602        DeferredAttrNode(DeferredType dt, ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy) {
603            this.dt = dt;
604            this.resultInfo = resultInfo;
605            this.deferredStuckPolicy = deferredStuckPolicy;
606        }
607
608        /**
609         * Process a deferred attribution node.
610         * Invariant: a stuck node cannot be processed.
611         */
612        @SuppressWarnings("fallthrough")
613        boolean process(final DeferredAttrContext deferredAttrContext) {
614            switch (deferredAttrContext.mode) {
615                case SPECULATIVE:
616                    if (deferredStuckPolicy.isStuck()) {
617                        dt.check(resultInfo, dummyStuckPolicy, new StructuralStuckChecker());
618                        return true;
619                    } else {
620                        Assert.error("Cannot get here");
621                    }
622                case CHECK:
623                    if (deferredStuckPolicy.isStuck()) {
624                        //stuck expression - see if we can propagate
625                        if (deferredAttrContext.parent != emptyDeferredAttrContext &&
626                                Type.containsAny(deferredAttrContext.parent.inferenceContext.inferencevars,
627                                        List.from(deferredStuckPolicy.stuckVars()))) {
628                            deferredAttrContext.parent.addDeferredAttrNode(dt,
629                                    resultInfo.dup(new Check.NestedCheckContext(resultInfo.checkContext) {
630                                @Override
631                                public InferenceContext inferenceContext() {
632                                    return deferredAttrContext.parent.inferenceContext;
633                                }
634                                @Override
635                                public DeferredAttrContext deferredAttrContext() {
636                                    return deferredAttrContext.parent;
637                                }
638                            }), deferredStuckPolicy);
639                            dt.tree.type = Type.stuckType;
640                            return true;
641                        } else {
642                            return false;
643                        }
644                    } else {
645                        Assert.check(!deferredAttrContext.insideOverloadPhase(),
646                                "attribution shouldn't be happening here");
647                        ResultInfo instResultInfo =
648                                resultInfo.dup(deferredAttrContext.inferenceContext.asInstType(resultInfo.pt));
649                        dt.check(instResultInfo, dummyStuckPolicy, basicCompleter);
650                        return true;
651                    }
652                default:
653                    throw new AssertionError("Bad mode");
654            }
655        }
656
657        /**
658         * Structural checker for stuck expressions
659         */
660        class StructuralStuckChecker extends TreeScanner implements DeferredTypeCompleter {
661
662            ResultInfo resultInfo;
663            InferenceContext inferenceContext;
664            Env<AttrContext> env;
665
666            public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
667                this.resultInfo = resultInfo;
668                this.inferenceContext = deferredAttrContext.inferenceContext;
669                this.env = dt.env;
670                dt.tree.accept(this);
671                dt.speculativeCache.put(stuckTree, resultInfo);
672                return Type.noType;
673            }
674
675            @Override
676            public void visitLambda(JCLambda tree) {
677                Check.CheckContext checkContext = resultInfo.checkContext;
678                Type pt = resultInfo.pt;
679                if (!inferenceContext.inferencevars.contains(pt)) {
680                    //must be a functional descriptor
681                    Type descriptorType = null;
682                    try {
683                        descriptorType = types.findDescriptorType(pt);
684                    } catch (Types.FunctionDescriptorLookupError ex) {
685                        checkContext.report(null, ex.getDiagnostic());
686                    }
687
688                    if (descriptorType.getParameterTypes().length() != tree.params.length()) {
689                        checkContext.report(tree,
690                                diags.fragment("incompatible.arg.types.in.lambda"));
691                    }
692
693                    Type currentReturnType = descriptorType.getReturnType();
694                    boolean returnTypeIsVoid = currentReturnType.hasTag(VOID);
695                    if (tree.getBodyKind() == BodyKind.EXPRESSION) {
696                        boolean isExpressionCompatible = !returnTypeIsVoid ||
697                            TreeInfo.isExpressionStatement((JCExpression)tree.getBody());
698                        if (!isExpressionCompatible) {
699                            resultInfo.checkContext.report(tree.pos(),
700                                diags.fragment("incompatible.ret.type.in.lambda",
701                                    diags.fragment("missing.ret.val", currentReturnType)));
702                        }
703                    } else {
704                        LambdaBodyStructChecker lambdaBodyChecker =
705                                new LambdaBodyStructChecker();
706
707                        tree.body.accept(lambdaBodyChecker);
708                        boolean isVoidCompatible = lambdaBodyChecker.isVoidCompatible;
709
710                        if (returnTypeIsVoid) {
711                            if (!isVoidCompatible) {
712                                resultInfo.checkContext.report(tree.pos(),
713                                    diags.fragment("unexpected.ret.val"));
714                            }
715                        } else {
716                            boolean isValueCompatible = lambdaBodyChecker.isPotentiallyValueCompatible
717                                && !canLambdaBodyCompleteNormally(tree);
718                            if (!isValueCompatible && !isVoidCompatible) {
719                                log.error(tree.body.pos(),
720                                    "lambda.body.neither.value.nor.void.compatible");
721                            }
722
723                            if (!isValueCompatible) {
724                                resultInfo.checkContext.report(tree.pos(),
725                                    diags.fragment("incompatible.ret.type.in.lambda",
726                                        diags.fragment("missing.ret.val", currentReturnType)));
727                            }
728                        }
729                    }
730                }
731            }
732
733            boolean canLambdaBodyCompleteNormally(JCLambda tree) {
734                JCLambda newTree = new TreeCopier<>(make).copy(tree);
735                /* attr.lambdaEnv will create a meaningful env for the
736                 * lambda expression. This is specially useful when the
737                 * lambda is used as the init of a field. But we need to
738                 * remove any added symbol.
739                 */
740                Env<AttrContext> localEnv = attr.lambdaEnv(newTree, env);
741                try {
742                    List<JCVariableDecl> tmpParams = newTree.params;
743                    while (tmpParams.nonEmpty()) {
744                        tmpParams.head.vartype = make.at(tmpParams.head).Type(syms.errType);
745                        tmpParams = tmpParams.tail;
746                    }
747
748                    attr.attribStats(newTree.params, localEnv);
749
750                    /* set pt to Type.noType to avoid generating any bound
751                     * which may happen if lambda's return type is an
752                     * inference variable
753                     */
754                    Attr.ResultInfo bodyResultInfo = attr.new ResultInfo(KindSelector.VAL, Type.noType);
755                    localEnv.info.returnResult = bodyResultInfo;
756
757                    // discard any log output
758                    Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
759                    try {
760                        JCBlock body = (JCBlock)newTree.body;
761                        /* we need to attribute the lambda body before
762                         * doing the aliveness analysis. This is because
763                         * constant folding occurs during attribution
764                         * and the reachability of some statements depends
765                         * on constant values, for example:
766                         *
767                         *     while (true) {...}
768                         */
769                        attr.attribStats(body.stats, localEnv);
770
771                        attr.preFlow(newTree);
772                        /* make an aliveness / reachability analysis of the lambda
773                         * to determine if it can complete normally
774                         */
775                        flow.analyzeLambda(localEnv, newTree, make, true);
776                    } finally {
777                        log.popDiagnosticHandler(diagHandler);
778                    }
779                    return newTree.canCompleteNormally;
780                } finally {
781                    JCBlock body = (JCBlock)newTree.body;
782                    unenterScanner.scan(body.stats);
783                    localEnv.info.scope.leave();
784                }
785            }
786
787            @Override
788            public void visitNewClass(JCNewClass tree) {
789                //do nothing
790            }
791
792            @Override
793            public void visitApply(JCMethodInvocation tree) {
794                //do nothing
795            }
796
797            @Override
798            public void visitReference(JCMemberReference tree) {
799                Check.CheckContext checkContext = resultInfo.checkContext;
800                Type pt = resultInfo.pt;
801                if (!inferenceContext.inferencevars.contains(pt)) {
802                    try {
803                        types.findDescriptorType(pt);
804                    } catch (Types.FunctionDescriptorLookupError ex) {
805                        checkContext.report(null, ex.getDiagnostic());
806                    }
807                    Env<AttrContext> localEnv = env.dup(tree);
808                    JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv,
809                            attr.memberReferenceQualifierResult(tree));
810                    ListBuffer<Type> argtypes = new ListBuffer<>();
811                    for (Type t : types.findDescriptorType(pt).getParameterTypes()) {
812                        argtypes.append(Type.noType);
813                    }
814                    JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree);
815                    mref2.expr = exprTree;
816                    Symbol lookupSym =
817                            rs.resolveMemberReference(localEnv, mref2, exprTree.type,
818                                    tree.name, argtypes.toList(), List.nil(), rs.arityMethodCheck,
819                                    inferenceContext, rs.structuralReferenceChooser).fst;
820                    switch (lookupSym.kind) {
821                        case WRONG_MTH:
822                        case WRONG_MTHS:
823                            //note: as argtypes are erroneous types, type-errors must
824                            //have been caused by arity mismatch
825                            checkContext.report(tree, diags.fragment(Fragments.IncompatibleArgTypesInMref));
826                            break;
827                        case ABSENT_MTH:
828                        case STATICERR:
829                            //if no method found, or method found with wrong staticness, report better message
830                            checkContext.report(tree, ((ResolveError)lookupSym).getDiagnostic(DiagnosticType.FRAGMENT,
831                                    tree, exprTree.type.tsym, exprTree.type, tree.name, argtypes.toList(), List.nil()));
832                            break;
833                    }
834                }
835            }
836        }
837
838        /* This visitor looks for return statements, its analysis will determine if
839         * a lambda body is void or value compatible. We must analyze return
840         * statements contained in the lambda body only, thus any return statement
841         * contained in an inner class or inner lambda body, should be ignored.
842         */
843        class LambdaBodyStructChecker extends TreeScanner {
844            boolean isVoidCompatible = true;
845            boolean isPotentiallyValueCompatible = true;
846
847            @Override
848            public void visitClassDef(JCClassDecl tree) {
849                // do nothing
850            }
851
852            @Override
853            public void visitLambda(JCLambda tree) {
854                // do nothing
855            }
856
857            @Override
858            public void visitNewClass(JCNewClass tree) {
859                // do nothing
860            }
861
862            @Override
863            public void visitReturn(JCReturn tree) {
864                if (tree.expr != null) {
865                    isVoidCompatible = false;
866                } else {
867                    isPotentiallyValueCompatible = false;
868                }
869            }
870        }
871    }
872
873    /** an empty deferred attribution context - all methods throw exceptions */
874    final DeferredAttrContext emptyDeferredAttrContext;
875
876    /**
877     * Map a list of types possibly containing one or more deferred types
878     * into a list of ordinary types. Each deferred type D is mapped into a type T,
879     * where T is computed by retrieving the type that has already been
880     * computed for D during a previous deferred attribution round of the given kind.
881     */
882    class DeferredTypeMap extends TypeMapping<Void> {
883        DeferredAttrContext deferredAttrContext;
884
885        protected DeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
886            this.deferredAttrContext = new DeferredAttrContext(mode, msym, phase,
887                    infer.emptyContext, emptyDeferredAttrContext, types.noWarnings);
888        }
889
890        @Override
891        public Type visitType(Type t, Void _unused) {
892            if (!t.hasTag(DEFERRED)) {
893                return super.visitType(t, null);
894            } else {
895                DeferredType dt = (DeferredType)t;
896                return typeOf(dt);
897            }
898        }
899
900        protected Type typeOf(DeferredType dt) {
901            switch (deferredAttrContext.mode) {
902                case CHECK:
903                    return dt.tree.type == null ? Type.noType : dt.tree.type;
904                case SPECULATIVE:
905                    return dt.speculativeType(deferredAttrContext.msym, deferredAttrContext.phase);
906            }
907            Assert.error();
908            return null;
909        }
910    }
911
912    /**
913     * Specialized recovery deferred mapping.
914     * Each deferred type D is mapped into a type T, where T is computed either by
915     * (i) retrieving the type that has already been computed for D during a previous
916     * attribution round (as before), or (ii) by synthesizing a new type R for D
917     * (the latter step is useful in a recovery scenario).
918     */
919    public class RecoveryDeferredTypeMap extends DeferredTypeMap {
920
921        public RecoveryDeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
922            super(mode, msym, phase != null ? phase : MethodResolutionPhase.BOX);
923        }
924
925        @Override
926        protected Type typeOf(DeferredType dt) {
927            Type owntype = super.typeOf(dt);
928            return owntype == Type.noType ?
929                        recover(dt) : owntype;
930        }
931
932        /**
933         * Synthesize a type for a deferred type that hasn't been previously
934         * reduced to an ordinary type. Functional deferred types and conditionals
935         * are mapped to themselves, in order to have a richer diagnostic
936         * representation. Remaining deferred types are attributed using
937         * a default expected type (j.l.Object).
938         */
939        private Type recover(DeferredType dt) {
940            dt.check(attr.new RecoveryInfo(deferredAttrContext) {
941                @Override
942                protected Type check(DiagnosticPosition pos, Type found) {
943                    return chk.checkNonVoid(pos, super.check(pos, found));
944                }
945            });
946            return super.visit(dt);
947        }
948    }
949
950    /**
951     * A special tree scanner that would only visit portions of a given tree.
952     * The set of nodes visited by the scanner can be customized at construction-time.
953     */
954    abstract static class FilterScanner extends TreeScanner {
955
956        final Filter<JCTree> treeFilter;
957
958        FilterScanner(final Set<JCTree.Tag> validTags) {
959            this.treeFilter = new Filter<JCTree>() {
960                public boolean accepts(JCTree t) {
961                    return validTags.contains(t.getTag());
962                }
963            };
964        }
965
966        @Override
967        public void scan(JCTree tree) {
968            if (tree != null) {
969                if (treeFilter.accepts(tree)) {
970                    super.scan(tree);
971                } else {
972                    skip(tree);
973                }
974            }
975        }
976
977        /**
978         * handler that is executed when a node has been discarded
979         */
980        void skip(JCTree tree) {}
981    }
982
983    /**
984     * A tree scanner suitable for visiting the target-type dependent nodes of
985     * a given argument expression.
986     */
987    static class PolyScanner extends FilterScanner {
988
989        PolyScanner() {
990            super(EnumSet.of(CONDEXPR, PARENS, LAMBDA, REFERENCE));
991        }
992    }
993
994    /**
995     * A tree scanner suitable for visiting the target-type dependent nodes nested
996     * within a lambda expression body.
997     */
998    static class LambdaReturnScanner extends FilterScanner {
999
1000        LambdaReturnScanner() {
1001            super(EnumSet.of(BLOCK, CASE, CATCH, DOLOOP, FOREACHLOOP,
1002                    FORLOOP, IF, RETURN, SYNCHRONIZED, SWITCH, TRY, WHILELOOP));
1003        }
1004    }
1005
1006    /**
1007     * This visitor is used to check that structural expressions conform
1008     * to their target - this step is required as inference could end up
1009     * inferring types that make some of the nested expressions incompatible
1010     * with their corresponding instantiated target
1011     */
1012    class CheckStuckPolicy extends PolyScanner implements DeferredStuckPolicy, Infer.FreeTypeListener {
1013
1014        Type pt;
1015        InferenceContext inferenceContext;
1016        Set<Type> stuckVars = new LinkedHashSet<>();
1017        Set<Type> depVars = new LinkedHashSet<>();
1018
1019        @Override
1020        public boolean isStuck() {
1021            return !stuckVars.isEmpty();
1022        }
1023
1024        @Override
1025        public Set<Type> stuckVars() {
1026            return stuckVars;
1027        }
1028
1029        @Override
1030        public Set<Type> depVars() {
1031            return depVars;
1032        }
1033
1034        public CheckStuckPolicy(ResultInfo resultInfo, DeferredType dt) {
1035            this.pt = resultInfo.pt;
1036            this.inferenceContext = resultInfo.checkContext.inferenceContext();
1037            scan(dt.tree);
1038            if (!stuckVars.isEmpty()) {
1039                resultInfo.checkContext.inferenceContext()
1040                        .addFreeTypeListener(List.from(stuckVars), this);
1041            }
1042        }
1043
1044        @Override
1045        public void typesInferred(InferenceContext inferenceContext) {
1046            stuckVars.clear();
1047        }
1048
1049        @Override
1050        public void visitLambda(JCLambda tree) {
1051            if (inferenceContext.inferenceVars().contains(pt)) {
1052                stuckVars.add(pt);
1053            }
1054            if (!types.isFunctionalInterface(pt)) {
1055                return;
1056            }
1057            Type descType = types.findDescriptorType(pt);
1058            List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
1059            if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT &&
1060                    freeArgVars.nonEmpty()) {
1061                stuckVars.addAll(freeArgVars);
1062                depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType()));
1063            }
1064            scanLambdaBody(tree, descType.getReturnType());
1065        }
1066
1067        @Override
1068        public void visitReference(JCMemberReference tree) {
1069            scan(tree.expr);
1070            if (inferenceContext.inferenceVars().contains(pt)) {
1071                stuckVars.add(pt);
1072                return;
1073            }
1074            if (!types.isFunctionalInterface(pt)) {
1075                return;
1076            }
1077
1078            Type descType = types.findDescriptorType(pt);
1079            List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
1080            if (freeArgVars.nonEmpty() &&
1081                    tree.overloadKind == JCMemberReference.OverloadKind.OVERLOADED) {
1082                stuckVars.addAll(freeArgVars);
1083                depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType()));
1084            }
1085        }
1086
1087        void scanLambdaBody(JCLambda lambda, final Type pt) {
1088            if (lambda.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) {
1089                Type prevPt = this.pt;
1090                try {
1091                    this.pt = pt;
1092                    scan(lambda.body);
1093                } finally {
1094                    this.pt = prevPt;
1095                }
1096            } else {
1097                LambdaReturnScanner lambdaScanner = new LambdaReturnScanner() {
1098                    @Override
1099                    public void visitReturn(JCReturn tree) {
1100                        if (tree.expr != null) {
1101                            Type prevPt = CheckStuckPolicy.this.pt;
1102                            try {
1103                                CheckStuckPolicy.this.pt = pt;
1104                                CheckStuckPolicy.this.scan(tree.expr);
1105                            } finally {
1106                                CheckStuckPolicy.this.pt = prevPt;
1107                            }
1108                        }
1109                    }
1110                };
1111                lambdaScanner.scan(lambda.body);
1112            }
1113        }
1114    }
1115
1116    /**
1117     * This visitor is used to check that structural expressions conform
1118     * to their target - this step is required as inference could end up
1119     * inferring types that make some of the nested expressions incompatible
1120     * with their corresponding instantiated target
1121     */
1122    class OverloadStuckPolicy extends CheckStuckPolicy implements DeferredStuckPolicy {
1123
1124        boolean stuck;
1125
1126        @Override
1127        public boolean isStuck() {
1128            return super.isStuck() || stuck;
1129        }
1130
1131        public OverloadStuckPolicy(ResultInfo resultInfo, DeferredType dt) {
1132            super(resultInfo, dt);
1133        }
1134
1135        @Override
1136        public void visitLambda(JCLambda tree) {
1137            super.visitLambda(tree);
1138            if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT) {
1139                stuck = true;
1140            }
1141        }
1142
1143        @Override
1144        public void visitReference(JCMemberReference tree) {
1145            super.visitReference(tree);
1146            if (tree.overloadKind == JCMemberReference.OverloadKind.OVERLOADED) {
1147                stuck = true;
1148            }
1149        }
1150    }
1151
1152    /**
1153     * Does the argument expression {@code expr} need speculative type-checking?
1154     */
1155    boolean isDeferred(Env<AttrContext> env, JCExpression expr) {
1156        DeferredChecker dc = new DeferredChecker(env);
1157        dc.scan(expr);
1158        return dc.result.isPoly();
1159    }
1160
1161    /**
1162     * The kind of an argument expression. This is used by the analysis that
1163     * determines as to whether speculative attribution is necessary.
1164     */
1165    enum ArgumentExpressionKind {
1166
1167        /** kind that denotes poly argument expression */
1168        POLY,
1169        /** kind that denotes a standalone expression */
1170        NO_POLY,
1171        /** kind that denotes a primitive/boxed standalone expression */
1172        PRIMITIVE;
1173
1174        /**
1175         * Does this kind denote a poly argument expression
1176         */
1177        public final boolean isPoly() {
1178            return this == POLY;
1179        }
1180
1181        /**
1182         * Does this kind denote a primitive standalone expression
1183         */
1184        public final boolean isPrimitive() {
1185            return this == PRIMITIVE;
1186        }
1187
1188        /**
1189         * Compute the kind of a standalone expression of a given type
1190         */
1191        static ArgumentExpressionKind standaloneKind(Type type, Types types) {
1192            return types.unboxedTypeOrType(type).isPrimitive() ?
1193                    ArgumentExpressionKind.PRIMITIVE :
1194                    ArgumentExpressionKind.NO_POLY;
1195        }
1196
1197        /**
1198         * Compute the kind of a method argument expression given its symbol
1199         */
1200        static ArgumentExpressionKind methodKind(Symbol sym, Types types) {
1201            Type restype = sym.type.getReturnType();
1202            if (sym.type.hasTag(FORALL) &&
1203                    restype.containsAny(((ForAll)sym.type).tvars)) {
1204                return ArgumentExpressionKind.POLY;
1205            } else {
1206                return ArgumentExpressionKind.standaloneKind(restype, types);
1207            }
1208        }
1209    }
1210
1211    /**
1212     * Tree scanner used for checking as to whether an argument expression
1213     * requires speculative attribution
1214     */
1215    final class DeferredChecker extends FilterScanner {
1216
1217        Env<AttrContext> env;
1218        ArgumentExpressionKind result;
1219
1220        public DeferredChecker(Env<AttrContext> env) {
1221            super(deferredCheckerTags);
1222            this.env = env;
1223        }
1224
1225        @Override
1226        public void visitLambda(JCLambda tree) {
1227            //a lambda is always a poly expression
1228            result = ArgumentExpressionKind.POLY;
1229        }
1230
1231        @Override
1232        public void visitReference(JCMemberReference tree) {
1233            //perform arity-based check
1234            Env<AttrContext> localEnv = env.dup(tree);
1235            JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv,
1236                    attr.memberReferenceQualifierResult(tree));
1237            JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree);
1238            mref2.expr = exprTree;
1239            Symbol res =
1240                    rs.getMemberReference(tree, localEnv, mref2,
1241                        exprTree.type, tree.name);
1242            tree.sym = res;
1243            if (res.kind.isResolutionTargetError() ||
1244                    res.type != null && res.type.hasTag(FORALL) ||
1245                    (res.flags() & Flags.VARARGS) != 0 ||
1246                    (TreeInfo.isStaticSelector(exprTree, tree.name.table.names) &&
1247                    exprTree.type.isRaw())) {
1248                tree.overloadKind = JCMemberReference.OverloadKind.OVERLOADED;
1249            } else {
1250                tree.overloadKind = JCMemberReference.OverloadKind.UNOVERLOADED;
1251            }
1252            //a method reference is always a poly expression
1253            result = ArgumentExpressionKind.POLY;
1254        }
1255
1256        @Override
1257        public void visitTypeCast(JCTypeCast tree) {
1258            //a cast is always a standalone expression
1259            result = ArgumentExpressionKind.NO_POLY;
1260        }
1261
1262        @Override
1263        public void visitConditional(JCConditional tree) {
1264            scan(tree.truepart);
1265            if (!result.isPrimitive()) {
1266                result = ArgumentExpressionKind.POLY;
1267                return;
1268            }
1269            scan(tree.falsepart);
1270            result = reduce(ArgumentExpressionKind.PRIMITIVE).isPrimitive() ?
1271                    ArgumentExpressionKind.PRIMITIVE :
1272                    ArgumentExpressionKind.POLY;
1273
1274        }
1275
1276        @Override
1277        public void visitNewClass(JCNewClass tree) {
1278            result = TreeInfo.isDiamond(tree) ?
1279                    ArgumentExpressionKind.POLY : ArgumentExpressionKind.NO_POLY;
1280        }
1281
1282        @Override
1283        public void visitApply(JCMethodInvocation tree) {
1284            Name name = TreeInfo.name(tree.meth);
1285
1286            //fast path
1287            if (tree.typeargs.nonEmpty() ||
1288                    name == name.table.names._this ||
1289                    name == name.table.names._super) {
1290                result = ArgumentExpressionKind.NO_POLY;
1291                return;
1292            }
1293
1294            //slow path
1295            Symbol sym = quicklyResolveMethod(env, tree);
1296
1297            if (sym == null) {
1298                result = ArgumentExpressionKind.POLY;
1299                return;
1300            }
1301
1302            result = analyzeCandidateMethods(sym, ArgumentExpressionKind.PRIMITIVE,
1303                    argumentKindAnalyzer);
1304        }
1305        //where
1306            private boolean isSimpleReceiver(JCTree rec) {
1307                switch (rec.getTag()) {
1308                    case IDENT:
1309                        return true;
1310                    case SELECT:
1311                        return isSimpleReceiver(((JCFieldAccess)rec).selected);
1312                    case TYPEAPPLY:
1313                    case TYPEARRAY:
1314                        return true;
1315                    case ANNOTATED_TYPE:
1316                        return isSimpleReceiver(((JCAnnotatedType)rec).underlyingType);
1317                    case APPLY:
1318                        return true;
1319                    case NEWCLASS:
1320                        JCNewClass nc = (JCNewClass) rec;
1321                        return nc.encl == null && nc.def == null && !TreeInfo.isDiamond(nc);
1322                    default:
1323                        return false;
1324                }
1325            }
1326            private ArgumentExpressionKind reduce(ArgumentExpressionKind kind) {
1327                return argumentKindAnalyzer.reduce(result, kind);
1328            }
1329            MethodAnalyzer<ArgumentExpressionKind> argumentKindAnalyzer =
1330                    new MethodAnalyzer<ArgumentExpressionKind>() {
1331                @Override
1332                public ArgumentExpressionKind process(MethodSymbol ms) {
1333                    return ArgumentExpressionKind.methodKind(ms, types);
1334                }
1335                @Override
1336                public ArgumentExpressionKind reduce(ArgumentExpressionKind kind1,
1337                                                     ArgumentExpressionKind kind2) {
1338                    switch (kind1) {
1339                        case PRIMITIVE: return kind2;
1340                        case NO_POLY: return kind2.isPoly() ? kind2 : kind1;
1341                        case POLY: return kind1;
1342                        default:
1343                            Assert.error();
1344                            return null;
1345                    }
1346                }
1347                @Override
1348                public boolean shouldStop(ArgumentExpressionKind result) {
1349                    return result.isPoly();
1350                }
1351            };
1352
1353        @Override
1354        public void visitLiteral(JCLiteral tree) {
1355            Type litType = attr.litType(tree.typetag);
1356            result = ArgumentExpressionKind.standaloneKind(litType, types);
1357        }
1358
1359        @Override
1360        void skip(JCTree tree) {
1361            result = ArgumentExpressionKind.NO_POLY;
1362        }
1363
1364        private Symbol quicklyResolveMethod(Env<AttrContext> env, final JCMethodInvocation tree) {
1365            final JCExpression rec = tree.meth.hasTag(SELECT) ?
1366                    ((JCFieldAccess)tree.meth).selected :
1367                    null;
1368
1369            if (rec != null && !isSimpleReceiver(rec)) {
1370                return null;
1371            }
1372
1373            Type site;
1374
1375            if (rec != null) {
1376                switch (rec.getTag()) {
1377                    case APPLY:
1378                        Symbol recSym = quicklyResolveMethod(env, (JCMethodInvocation) rec);
1379                        if (recSym == null)
1380                            return null;
1381                        Symbol resolvedReturnType =
1382                                analyzeCandidateMethods(recSym, syms.errSymbol, returnSymbolAnalyzer);
1383                        if (resolvedReturnType == null)
1384                            return null;
1385                        site = resolvedReturnType.type;
1386                        break;
1387                    case NEWCLASS:
1388                        JCNewClass nc = (JCNewClass) rec;
1389                        site = attribSpeculative(nc.clazz, env, attr.unknownTypeExprInfo).type;
1390                        break;
1391                    default:
1392                        site = attribSpeculative(rec, env, attr.unknownTypeExprInfo).type;
1393                        break;
1394                }
1395            } else {
1396                site = env.enclClass.sym.type;
1397            }
1398
1399            site = types.skipTypeVars(site, true);
1400
1401            List<Type> args = rs.dummyArgs(tree.args.length());
1402            Name name = TreeInfo.name(tree.meth);
1403
1404            Resolve.LookupHelper lh = rs.new LookupHelper(name, site, args, List.<Type>nil(), MethodResolutionPhase.VARARITY) {
1405                @Override
1406                Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
1407                    return rec == null ?
1408                        rs.findFun(env, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()) :
1409                        rs.findMethod(env, site, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired());
1410                }
1411                @Override
1412                Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
1413                    return sym;
1414                }
1415            };
1416
1417            return rs.lookupMethod(env, tree, site.tsym, rs.arityMethodCheck, lh);
1418        }
1419        //where:
1420            MethodAnalyzer<Symbol> returnSymbolAnalyzer = new MethodAnalyzer<Symbol>() {
1421                @Override
1422                public Symbol process(MethodSymbol ms) {
1423                    ArgumentExpressionKind kind = ArgumentExpressionKind.methodKind(ms, types);
1424                    if (kind == ArgumentExpressionKind.POLY || ms.getReturnType().hasTag(TYPEVAR))
1425                        return null;
1426                    return ms.getReturnType().tsym;
1427                }
1428                @Override
1429                public Symbol reduce(Symbol s1, Symbol s2) {
1430                    return s1 == syms.errSymbol ? s2 : s1 == s2 ? s1 : null;
1431                }
1432                @Override
1433                public boolean shouldStop(Symbol result) {
1434                    return result == null;
1435                }
1436            };
1437
1438        /**
1439         * Process the result of Resolve.lookupMethod. If sym is a method symbol, the result of
1440         * MethodAnalyzer.process is returned. If sym is an ambiguous symbol, all the candidate
1441         * methods are inspected one by one, using MethodAnalyzer.process. The outcomes are
1442         * reduced using MethodAnalyzer.reduce (using defaultValue as the first value over which
1443         * the reduction runs). MethodAnalyzer.shouldStop can be used to stop the inspection early.
1444         */
1445        <E> E analyzeCandidateMethods(Symbol sym, E defaultValue, MethodAnalyzer<E> analyzer) {
1446            switch (sym.kind) {
1447                case MTH:
1448                    return analyzer.process((MethodSymbol) sym);
1449                case AMBIGUOUS:
1450                    Resolve.AmbiguityError err = (Resolve.AmbiguityError)sym.baseSymbol();
1451                    E res = defaultValue;
1452                    for (Symbol s : err.ambiguousSyms) {
1453                        if (s.kind == MTH) {
1454                            res = analyzer.reduce(res, analyzer.process((MethodSymbol) s));
1455                            if (analyzer.shouldStop(res))
1456                                return res;
1457                        }
1458                    }
1459                    return res;
1460                default:
1461                    return defaultValue;
1462            }
1463        }
1464    }
1465
1466    /** Analyzer for methods - used by analyzeCandidateMethods. */
1467    interface MethodAnalyzer<E> {
1468        E process(MethodSymbol ms);
1469        E reduce(E e1, E e2);
1470        boolean shouldStop(E result);
1471    }
1472
1473    //where
1474    private EnumSet<JCTree.Tag> deferredCheckerTags =
1475            EnumSet.of(LAMBDA, REFERENCE, PARENS, TYPECAST,
1476                    CONDEXPR, NEWCLASS, APPLY, LITERAL);
1477}
1478