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