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