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