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