DeferredAttr.java revision 4038:95c92c634f60
1/*
2 * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.tools.javac.comp;
27
28import com.sun.source.tree.LambdaExpressionTree.BodyKind;
29import com.sun.source.tree.NewClassTree;
30import com.sun.tools.javac.code.*;
31import com.sun.tools.javac.code.Type.StructuralTypeMapping;
32import com.sun.tools.javac.code.Types.TypeMapping;
33import com.sun.tools.javac.comp.ArgumentAttr.LocalCacheContext;
34import com.sun.tools.javac.comp.Resolve.ResolveError;
35import com.sun.tools.javac.resources.CompilerProperties.Fragments;
36import com.sun.tools.javac.tree.*;
37import com.sun.tools.javac.util.*;
38import com.sun.tools.javac.util.DefinedBy.Api;
39import com.sun.tools.javac.util.GraphUtils.DependencyKind;
40import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
41import com.sun.tools.javac.code.Symbol.*;
42import com.sun.tools.javac.comp.Attr.ResultInfo;
43import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
44import com.sun.tools.javac.tree.JCTree.*;
45import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType;
46import com.sun.tools.javac.util.Log.DeferredDiagnosticHandler;
47
48import java.util.ArrayList;
49import java.util.Collection;
50import java.util.Collections;
51import java.util.EnumSet;
52import java.util.HashSet;
53import java.util.LinkedHashSet;
54import java.util.Map;
55import java.util.Set;
56import java.util.WeakHashMap;
57import java.util.function.Function;
58
59import static com.sun.tools.javac.code.TypeTag.*;
60import static com.sun.tools.javac.tree.JCTree.Tag.*;
61
62/**
63 * This is an helper class that is used to perform deferred type-analysis.
64 * Each time a poly expression occurs in argument position, javac attributes it
65 * with a temporary 'deferred type' that is checked (possibly multiple times)
66 * against an expected formal type.
67 *
68 *  <p><b>This is NOT part of any supported API.
69 *  If you write code that depends on this, you do so at your own risk.
70 *  This code and its internal interfaces are subject to change or
71 *  deletion without notice.</b>
72 */
73public class DeferredAttr extends JCTree.Visitor {
74    protected static final Context.Key<DeferredAttr> deferredAttrKey = new Context.Key<>();
75
76    final Attr attr;
77    final ArgumentAttr argumentAttr;
78    final Check chk;
79    final JCDiagnostic.Factory diags;
80    final Enter enter;
81    final Infer infer;
82    final Resolve rs;
83    final Log log;
84    final Symtab syms;
85    final TreeMaker make;
86    final TreeCopier<Void> treeCopier;
87    final TypeMapping<Void> deferredCopier;
88    final Types types;
89    final Flow flow;
90    final Names names;
91    final TypeEnvs typeEnvs;
92
93    public static DeferredAttr instance(Context context) {
94        DeferredAttr instance = context.get(deferredAttrKey);
95        if (instance == null)
96            instance = new DeferredAttr(context);
97        return instance;
98    }
99
100    protected DeferredAttr(Context context) {
101        context.put(deferredAttrKey, this);
102        attr = Attr.instance(context);
103        argumentAttr = ArgumentAttr.instance(context);
104        chk = Check.instance(context);
105        diags = JCDiagnostic.Factory.instance(context);
106        enter = Enter.instance(context);
107        infer = Infer.instance(context);
108        rs = Resolve.instance(context);
109        log = Log.instance(context);
110        syms = Symtab.instance(context);
111        make = TreeMaker.instance(context);
112        types = Types.instance(context);
113        flow = Flow.instance(context);
114        names = Names.instance(context);
115        stuckTree = make.Ident(names.empty).setType(Type.stuckType);
116        typeEnvs = TypeEnvs.instance(context);
117        emptyDeferredAttrContext =
118            new DeferredAttrContext(AttrMode.CHECK, null, MethodResolutionPhase.BOX, infer.emptyContext, null, null) {
119                @Override
120                void addDeferredAttrNode(DeferredType dt, ResultInfo ri, DeferredStuckPolicy deferredStuckPolicy) {
121                    Assert.error("Empty deferred context!");
122                }
123                @Override
124                void complete() {
125                    Assert.error("Empty deferred context!");
126                }
127
128                @Override
129                public String toString() {
130                    return "Empty deferred context!";
131                }
132            };
133
134        // For speculative attribution, skip the class definition in <>.
135        treeCopier =
136            new TreeCopier<Void>(make) {
137                @Override @DefinedBy(Api.COMPILER_TREE)
138                public JCTree visitNewClass(NewClassTree node, Void p) {
139                    JCNewClass t = (JCNewClass) node;
140                    if (TreeInfo.isDiamond(t)) {
141                        JCExpression encl = copy(t.encl, p);
142                        List<JCExpression> typeargs = copy(t.typeargs, p);
143                        JCExpression clazz = copy(t.clazz, p);
144                        List<JCExpression> args = copy(t.args, p);
145                        JCClassDecl def = null;
146                        return make.at(t.pos).NewClass(encl, typeargs, clazz, args, def);
147                    } else {
148                        return super.visitNewClass(node, p);
149                    }
150                }
151            };
152        deferredCopier = new TypeMapping<Void> () {
153                @Override
154                public Type visitType(Type t, Void v) {
155                    if (t.hasTag(DEFERRED)) {
156                        DeferredType dt = (DeferredType) t;
157                        return new DeferredType(treeCopier.copy(dt.tree), dt.env);
158                    }
159                    return t;
160                }
161            };
162    }
163
164    /** shared tree for stuck expressions */
165    final JCTree stuckTree;
166
167    /**
168     * This type represents a deferred type. A deferred type starts off with
169     * no information on the underlying expression type. Such info needs to be
170     * discovered through type-checking the deferred type against a target-type.
171     * Every deferred type keeps a pointer to the AST node from which it originated.
172     */
173    public class DeferredType extends Type {
174
175        public JCExpression tree;
176        Env<AttrContext> env;
177        AttrMode mode;
178        boolean pertinentToApplicability = true;
179        SpeculativeCache speculativeCache;
180
181        DeferredType(JCExpression tree, Env<AttrContext> env) {
182            super(null, TypeMetadata.EMPTY);
183            this.tree = tree;
184            this.env = attr.copyEnv(env);
185            this.speculativeCache = new SpeculativeCache();
186        }
187
188        @Override
189        public DeferredType cloneWithMetadata(TypeMetadata md) {
190            throw new AssertionError("Cannot add metadata to a deferred type");
191        }
192
193        @Override
194        public TypeTag getTag() {
195            return DEFERRED;
196        }
197
198        @Override @DefinedBy(Api.LANGUAGE_MODEL)
199        public String toString() {
200            return "DeferredType";
201        }
202
203        /**
204         * A speculative cache is used to keep track of all overload resolution rounds
205         * that triggered speculative attribution on a given deferred type. Each entry
206         * stores a pointer to the speculative tree and the resolution phase in which the entry
207         * has been added.
208         */
209        class SpeculativeCache {
210
211            private Map<Symbol, List<Entry>> cache = new WeakHashMap<>();
212
213            class Entry {
214                JCTree speculativeTree;
215                ResultInfo resultInfo;
216
217                public Entry(JCTree speculativeTree, ResultInfo resultInfo) {
218                    this.speculativeTree = speculativeTree;
219                    this.resultInfo = resultInfo;
220                }
221
222                boolean matches(MethodResolutionPhase phase) {
223                    return resultInfo.checkContext.deferredAttrContext().phase == phase;
224                }
225            }
226
227            /**
228             * Retrieve a speculative cache entry corresponding to given symbol
229             * and resolution phase
230             */
231            Entry get(Symbol msym, MethodResolutionPhase phase) {
232                List<Entry> entries = cache.get(msym);
233                if (entries == null) return null;
234                for (Entry e : entries) {
235                    if (e.matches(phase)) return e;
236                }
237                return null;
238            }
239
240            /**
241             * Stores a speculative cache entry corresponding to given symbol
242             * and resolution phase
243             */
244            void put(JCTree speculativeTree, ResultInfo resultInfo) {
245                Symbol msym = resultInfo.checkContext.deferredAttrContext().msym;
246                List<Entry> entries = cache.get(msym);
247                if (entries == null) {
248                    entries = List.nil();
249                }
250                cache.put(msym, entries.prepend(new Entry(speculativeTree, resultInfo)));
251            }
252        }
253
254        /**
255         * Get the type that has been computed during a speculative attribution round
256         */
257        Type speculativeType(Symbol msym, MethodResolutionPhase phase) {
258            SpeculativeCache.Entry e = speculativeCache.get(msym, phase);
259            return e != null ? e.speculativeTree.type : Type.noType;
260        }
261
262        JCTree speculativeTree(DeferredAttrContext deferredAttrContext) {
263            DeferredType.SpeculativeCache.Entry e = speculativeCache.get(deferredAttrContext.msym, deferredAttrContext.phase);
264            return e != null ? e.speculativeTree : stuckTree;
265        }
266
267        DeferredTypeCompleter completer() {
268            return basicCompleter;
269        }
270
271        /**
272         * Check a deferred type against a potential target-type. Depending on
273         * the current attribution mode, a normal vs. speculative attribution
274         * round is performed on the underlying AST node. There can be only one
275         * speculative round for a given target method symbol; moreover, a normal
276         * attribution round must follow one or more speculative rounds.
277         */
278        Type check(ResultInfo resultInfo) {
279            DeferredStuckPolicy deferredStuckPolicy;
280            if (resultInfo.pt.hasTag(NONE) || resultInfo.pt.isErroneous()) {
281                deferredStuckPolicy = dummyStuckPolicy;
282            } else if (resultInfo.checkContext.deferredAttrContext().mode == AttrMode.SPECULATIVE ||
283                    resultInfo.checkContext.deferredAttrContext().insideOverloadPhase()) {
284                deferredStuckPolicy = new OverloadStuckPolicy(resultInfo, this);
285            } else {
286                deferredStuckPolicy = new CheckStuckPolicy(resultInfo, this);
287            }
288            return check(resultInfo, deferredStuckPolicy, completer());
289        }
290
291        private Type check(ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy,
292                DeferredTypeCompleter deferredTypeCompleter) {
293            DeferredAttrContext deferredAttrContext =
294                    resultInfo.checkContext.deferredAttrContext();
295            Assert.check(deferredAttrContext != emptyDeferredAttrContext);
296            if (deferredStuckPolicy.isStuck()) {
297                pertinentToApplicability = false;
298                deferredAttrContext.addDeferredAttrNode(this, resultInfo, deferredStuckPolicy);
299                return Type.noType;
300            } else {
301                try {
302                    return deferredTypeCompleter.complete(this, resultInfo, deferredAttrContext);
303                } finally {
304                    mode = deferredAttrContext.mode;
305                }
306            }
307        }
308    }
309
310    /**
311     * A completer for deferred types. Defines an entry point for type-checking
312     * a deferred type.
313     */
314    interface DeferredTypeCompleter {
315        /**
316         * Entry point for type-checking a deferred type. Depending on the
317         * circumstances, type-checking could amount to full attribution
318         * or partial structural check (aka potential applicability).
319         */
320        Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext);
321    }
322
323
324    /**
325     * A basic completer for deferred types. This completer type-checks a deferred type
326     * using attribution; depending on the attribution mode, this could be either standard
327     * or speculative attribution.
328     */
329    DeferredTypeCompleter basicCompleter = new DeferredTypeCompleter() {
330        public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
331            switch (deferredAttrContext.mode) {
332                case SPECULATIVE:
333                    //Note: if a symbol is imported twice we might do two identical
334                    //speculative rounds...
335                    Assert.check(dt.mode == null || dt.mode == AttrMode.SPECULATIVE);
336                    JCTree speculativeTree = attribSpeculative(dt.tree, dt.env, resultInfo);
337                    dt.speculativeCache.put(speculativeTree, resultInfo);
338                    return speculativeTree.type;
339                case CHECK:
340                    Assert.check(dt.mode != null);
341                    return attr.attribTree(dt.tree, dt.env, resultInfo);
342            }
343            Assert.error();
344            return null;
345        }
346    };
347
348    /**
349     * Policy for detecting stuck expressions. Different criteria might cause
350     * an expression to be judged as stuck, depending on whether the check
351     * is performed during overload resolution or after most specific.
352     */
353    interface DeferredStuckPolicy {
354        /**
355         * Has the policy detected that a given expression should be considered stuck?
356         */
357        boolean isStuck();
358        /**
359         * Get the set of inference variables a given expression depends upon.
360         */
361        Set<Type> stuckVars();
362        /**
363         * Get the set of inference variables which might get new constraints
364         * if a given expression is being type-checked.
365         */
366        Set<Type> depVars();
367    }
368
369    /**
370     * Basic stuck policy; an expression is never considered to be stuck.
371     */
372    DeferredStuckPolicy dummyStuckPolicy = new DeferredStuckPolicy() {
373        @Override
374        public boolean isStuck() {
375            return false;
376        }
377        @Override
378        public Set<Type> stuckVars() {
379            return Collections.emptySet();
380        }
381        @Override
382        public Set<Type> depVars() {
383            return Collections.emptySet();
384        }
385    };
386
387    /**
388     * The 'mode' in which the deferred type is to be type-checked
389     */
390    public enum AttrMode {
391        /**
392         * A speculative type-checking round is used during overload resolution
393         * mainly to generate constraints on inference variables. Side-effects
394         * arising from type-checking the expression associated with the deferred
395         * type are reversed after the speculative round finishes. This means the
396         * expression tree will be left in a blank state.
397         */
398        SPECULATIVE,
399        /**
400         * This is the plain type-checking mode. Produces side-effects on the underlying AST node
401         */
402        CHECK
403    }
404
405    /**
406     * Performs speculative attribution of a lambda body and returns the speculative lambda tree,
407     * in the absence of a target-type. Since {@link Attr#visitLambda(JCLambda)} cannot type-check
408     * lambda bodies w/o a suitable target-type, this routine 'unrolls' the lambda by turning it
409     * into a regular block, speculatively type-checks the block and then puts back the pieces.
410     */
411    JCLambda attribSpeculativeLambda(JCLambda that, Env<AttrContext> env, ResultInfo resultInfo) {
412        ListBuffer<JCStatement> stats = new ListBuffer<>();
413        stats.addAll(that.params);
414        if (that.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
415            stats.add(make.Return((JCExpression)that.body));
416        } else {
417            stats.add((JCBlock)that.body);
418        }
419        JCBlock lambdaBlock = make.Block(0, stats.toList());
420        Env<AttrContext> localEnv = attr.lambdaEnv(that, env);
421        try {
422            localEnv.info.returnResult = resultInfo;
423            JCBlock speculativeTree = (JCBlock)attribSpeculative(lambdaBlock, localEnv, resultInfo);
424            List<JCVariableDecl> args = speculativeTree.getStatements().stream()
425                    .filter(s -> s.hasTag(Tag.VARDEF))
426                    .map(t -> (JCVariableDecl)t)
427                    .collect(List.collector());
428            JCTree lambdaBody = speculativeTree.getStatements().last();
429            if (lambdaBody.hasTag(Tag.RETURN)) {
430                lambdaBody = ((JCReturn)lambdaBody).expr;
431            }
432            JCLambda speculativeLambda = make.Lambda(args, lambdaBody);
433            attr.preFlow(speculativeLambda);
434            flow.analyzeLambda(env, speculativeLambda, make, false);
435            return speculativeLambda;
436        } finally {
437            localEnv.info.scope.leave();
438        }
439    }
440
441    /**
442     * Routine that performs speculative type-checking; the input AST node is
443     * cloned (to avoid side-effects cause by Attr) and compiler state is
444     * restored after type-checking. All diagnostics (but critical ones) are
445     * disabled during speculative type-checking.
446     */
447    JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
448        return attribSpeculative(tree, env, resultInfo, treeCopier,
449                (newTree)->new DeferredAttrDiagHandler(log, newTree));
450    }
451
452    <Z> JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo, TreeCopier<Z> deferredCopier,
453                                 Function<JCTree, DeferredDiagnosticHandler> diagHandlerCreator) {
454        final JCTree newTree = deferredCopier.copy(tree);
455        Env<AttrContext> speculativeEnv = env.dup(newTree, env.info.dup(env.info.scope.dupUnshared(env.info.scope.owner)));
456        speculativeEnv.info.isSpeculative = true;
457        Log.DeferredDiagnosticHandler deferredDiagnosticHandler = diagHandlerCreator.apply(newTree);
458        try {
459            attr.attribTree(newTree, speculativeEnv, resultInfo);
460            return newTree;
461        } finally {
462            new UnenterScanner(env.toplevel.modle).scan(newTree);
463            log.popDiagnosticHandler(deferredDiagnosticHandler);
464        }
465    }
466    //where
467
468        class UnenterScanner extends TreeScanner {
469            private final ModuleSymbol msym;
470
471            public UnenterScanner(ModuleSymbol msym) {
472                this.msym = msym;
473            }
474
475            @Override
476            public void visitClassDef(JCClassDecl tree) {
477                ClassSymbol csym = tree.sym;
478                //if something went wrong during method applicability check
479                //it is possible that nested expressions inside argument expression
480                //are left unchecked - in such cases there's nothing to clean up.
481                if (csym == null) return;
482                typeEnvs.remove(csym);
483                chk.removeCompiled(csym);
484                chk.clearLocalClassNameIndexes(csym);
485                syms.removeClass(msym, csym.flatname);
486                super.visitClassDef(tree);
487            }
488        }
489
490        static class DeferredAttrDiagHandler extends Log.DeferredDiagnosticHandler {
491
492            static class PosScanner extends TreeScanner {
493                DiagnosticPosition pos;
494                boolean found = false;
495
496                PosScanner(DiagnosticPosition pos) {
497                    this.pos = pos;
498                }
499
500                @Override
501                public void scan(JCTree tree) {
502                    if (tree != null &&
503                            tree.pos() == pos) {
504                        found = true;
505                    }
506                    super.scan(tree);
507                }
508            }
509
510            DeferredAttrDiagHandler(Log log, JCTree newTree) {
511                super(log, d -> {
512                    PosScanner posScanner = new PosScanner(d.getDiagnosticPosition());
513                    posScanner.scan(newTree);
514                    return posScanner.found;
515                });
516            }
517        }
518
519    /**
520     * A deferred context is created on each method check. A deferred context is
521     * used to keep track of information associated with the method check, such as
522     * the symbol of the method being checked, the overload resolution phase,
523     * the kind of attribution mode to be applied to deferred types and so forth.
524     * As deferred types are processed (by the method check routine) stuck AST nodes
525     * are added (as new deferred attribution nodes) to this context. The complete()
526     * routine makes sure that all pending nodes are properly processed, by
527     * progressively instantiating all inference variables on which one or more
528     * deferred attribution node is stuck.
529     */
530    class DeferredAttrContext {
531
532        /** attribution mode */
533        final AttrMode mode;
534
535        /** symbol of the method being checked */
536        final Symbol msym;
537
538        /** method resolution step */
539        final Resolve.MethodResolutionPhase phase;
540
541        /** inference context */
542        final InferenceContext inferenceContext;
543
544        /** parent deferred context */
545        final DeferredAttrContext parent;
546
547        /** Warner object to report warnings */
548        final Warner warn;
549
550        /** list of deferred attribution nodes to be processed */
551        ArrayList<DeferredAttrNode> deferredAttrNodes = new ArrayList<>();
552
553        DeferredAttrContext(AttrMode mode, Symbol msym, MethodResolutionPhase phase,
554                InferenceContext inferenceContext, DeferredAttrContext parent, Warner warn) {
555            this.mode = mode;
556            this.msym = msym;
557            this.phase = phase;
558            this.parent = parent;
559            this.warn = warn;
560            this.inferenceContext = inferenceContext;
561        }
562
563        /**
564         * Adds a node to the list of deferred attribution nodes - used by Resolve.rawCheckArgumentsApplicable
565         * Nodes added this way act as 'roots' for the out-of-order method checking process.
566         */
567        void addDeferredAttrNode(final DeferredType dt, ResultInfo resultInfo,
568                DeferredStuckPolicy deferredStuckPolicy) {
569            deferredAttrNodes.add(new DeferredAttrNode(dt, resultInfo, deferredStuckPolicy));
570        }
571
572        /**
573         * Incrementally process all nodes, by skipping 'stuck' nodes and attributing
574         * 'unstuck' ones. If at any point no progress can be made (no 'unstuck' nodes)
575         * some inference variable might get eagerly instantiated so that all nodes
576         * can be type-checked.
577         */
578        void complete() {
579            while (!deferredAttrNodes.isEmpty()) {
580                boolean progress = false;
581                //scan a defensive copy of the node list - this is because a deferred
582                //attribution round can add new nodes to the list
583                for (DeferredAttrNode deferredAttrNode : List.from(deferredAttrNodes)) {
584                    if (deferredAttrNode.process(this)) {
585                        deferredAttrNodes.remove(deferredAttrNode);
586                        progress = true;
587                    }
588                }
589                if (!progress) {
590                    if (insideOverloadPhase()) {
591                        for (DeferredAttrNode deferredNode: deferredAttrNodes) {
592                            deferredNode.dt.tree.type = Type.noType;
593                        }
594                        return;
595                    }
596                    //remove all variables that have already been instantiated
597                    //from the list of stuck variables
598                    try {
599                        //find stuck expression to unstuck
600                        DeferredAttrNode toUnstuck = pickDeferredNode();
601                        inferenceContext.solveAny(List.from(toUnstuck.deferredStuckPolicy.stuckVars()), warn);
602                        inferenceContext.notifyChange();
603                    } catch (Infer.GraphStrategy.NodeNotFoundException ex) {
604                        //this means that we are in speculative mode and the
605                        //set of contraints are too tight for progess to be made.
606                        //Just leave the remaining expressions as stuck.
607                        break;
608                    }
609                }
610            }
611        }
612
613        public boolean insideOverloadPhase() {
614            DeferredAttrContext dac = this;
615            if (dac == emptyDeferredAttrContext) {
616                return false;
617            }
618            if (dac.mode == AttrMode.SPECULATIVE) {
619                return true;
620            }
621            return dac.parent.insideOverloadPhase();
622        }
623
624        /**
625         * Pick the deferred node to be unstuck. The chosen node is the first strongly connected
626         * component containing exactly one node found in the dependency graph induced by deferred nodes.
627         * If no such component is found, the first deferred node is returned.
628         */
629        DeferredAttrNode pickDeferredNode() {
630            List<StuckNode> nodes = deferredAttrNodes.stream()
631                    .map(StuckNode::new)
632                    .collect(List.collector());
633            //init stuck expression graph; a deferred node A depends on a deferred node B iff
634            //the intersection between A's input variable and B's output variable is non-empty.
635            for (StuckNode sn1 : nodes) {
636                for (Type t : sn1.data.deferredStuckPolicy.stuckVars()) {
637                    for (StuckNode sn2 : nodes) {
638                        if (sn1 != sn2 && sn2.data.deferredStuckPolicy.depVars().contains(t)) {
639                            sn1.deps.add(sn2);
640                        }
641                    }
642                }
643            }
644            //compute tarjan on the stuck graph
645            List<? extends StuckNode> csn = GraphUtils.tarjan(nodes).get(0);
646            return csn.length() == 1 ? csn.get(0).data : deferredAttrNodes.get(0);
647        }
648
649        class StuckNode extends GraphUtils.TarjanNode<DeferredAttrNode, StuckNode> {
650
651            Set<StuckNode> deps = new HashSet<>();
652
653            StuckNode(DeferredAttrNode data) {
654                super(data);
655            }
656
657            @Override
658            public DependencyKind[] getSupportedDependencyKinds() {
659                return new DependencyKind[] { Infer.DependencyKind.STUCK };
660            }
661
662            @Override
663            public Collection<? extends StuckNode> getDependenciesByKind(DependencyKind dk) {
664                if (dk == Infer.DependencyKind.STUCK) {
665                    return deps;
666                } else {
667                    throw new IllegalStateException();
668                }
669            }
670
671            @Override
672            public Iterable<? extends StuckNode> getAllDependencies() {
673                return deps;
674            }
675        }
676    }
677
678    /**
679     * Class representing a deferred attribution node. It keeps track of
680     * a deferred type, along with the expected target type information.
681     */
682    class DeferredAttrNode {
683
684        /** underlying deferred type */
685        DeferredType dt;
686
687        /** underlying target type information */
688        ResultInfo resultInfo;
689
690        /** stuck policy associated with this node */
691        DeferredStuckPolicy deferredStuckPolicy;
692
693        DeferredAttrNode(DeferredType dt, ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy) {
694            this.dt = dt;
695            this.resultInfo = resultInfo;
696            this.deferredStuckPolicy = deferredStuckPolicy;
697        }
698
699        /**
700         * Process a deferred attribution node.
701         * Invariant: a stuck node cannot be processed.
702         */
703        @SuppressWarnings("fallthrough")
704        boolean process(final DeferredAttrContext deferredAttrContext) {
705            switch (deferredAttrContext.mode) {
706                case SPECULATIVE:
707                    if (deferredStuckPolicy.isStuck()) {
708                        dt.check(resultInfo, dummyStuckPolicy, new StructuralStuckChecker());
709                        return true;
710                    } else {
711                        Assert.error("Cannot get here");
712                    }
713                case CHECK:
714                    if (deferredStuckPolicy.isStuck()) {
715                        //stuck expression - see if we can propagate
716                        if (deferredAttrContext.parent != emptyDeferredAttrContext &&
717                                Type.containsAny(deferredAttrContext.parent.inferenceContext.inferencevars,
718                                        List.from(deferredStuckPolicy.stuckVars()))) {
719                            deferredAttrContext.parent.addDeferredAttrNode(dt,
720                                    resultInfo.dup(new Check.NestedCheckContext(resultInfo.checkContext) {
721                                @Override
722                                public InferenceContext inferenceContext() {
723                                    return deferredAttrContext.parent.inferenceContext;
724                                }
725                                @Override
726                                public DeferredAttrContext deferredAttrContext() {
727                                    return deferredAttrContext.parent;
728                                }
729                            }), deferredStuckPolicy);
730                            dt.tree.type = Type.stuckType;
731                            return true;
732                        } else {
733                            return false;
734                        }
735                    } else {
736                        Assert.check(!deferredAttrContext.insideOverloadPhase(),
737                                "attribution shouldn't be happening here");
738                        ResultInfo instResultInfo =
739                                resultInfo.dup(deferredAttrContext.inferenceContext.asInstType(resultInfo.pt));
740                        dt.check(instResultInfo, dummyStuckPolicy, basicCompleter);
741                        return true;
742                    }
743                default:
744                    throw new AssertionError("Bad mode");
745            }
746        }
747
748        /**
749         * Structural checker for stuck expressions
750         */
751        class StructuralStuckChecker extends TreeScanner implements DeferredTypeCompleter {
752
753            ResultInfo resultInfo;
754            InferenceContext inferenceContext;
755            Env<AttrContext> env;
756
757            public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
758                this.resultInfo = resultInfo;
759                this.inferenceContext = deferredAttrContext.inferenceContext;
760                this.env = dt.env;
761                dt.tree.accept(this);
762                dt.speculativeCache.put(stuckTree, resultInfo);
763                return Type.noType;
764            }
765
766            @Override
767            public void visitLambda(JCLambda tree) {
768                Check.CheckContext checkContext = resultInfo.checkContext;
769                Type pt = resultInfo.pt;
770                if (!inferenceContext.inferencevars.contains(pt)) {
771                    //must be a functional descriptor
772                    Type descriptorType = null;
773                    try {
774                        descriptorType = types.findDescriptorType(pt);
775                    } catch (Types.FunctionDescriptorLookupError ex) {
776                        checkContext.report(null, ex.getDiagnostic());
777                    }
778
779                    if (descriptorType.getParameterTypes().length() != tree.params.length()) {
780                        checkContext.report(tree,
781                                diags.fragment("incompatible.arg.types.in.lambda"));
782                    }
783
784                    Type currentReturnType = descriptorType.getReturnType();
785                    boolean returnTypeIsVoid = currentReturnType.hasTag(VOID);
786                    if (tree.getBodyKind() == BodyKind.EXPRESSION) {
787                        boolean isExpressionCompatible = !returnTypeIsVoid ||
788                            TreeInfo.isExpressionStatement((JCExpression)tree.getBody());
789                        if (!isExpressionCompatible) {
790                            resultInfo.checkContext.report(tree.pos(),
791                                diags.fragment("incompatible.ret.type.in.lambda",
792                                    diags.fragment("missing.ret.val", currentReturnType)));
793                        }
794                    } else {
795                        LambdaBodyStructChecker lambdaBodyChecker =
796                                new LambdaBodyStructChecker();
797
798                        tree.body.accept(lambdaBodyChecker);
799                        boolean isVoidCompatible = lambdaBodyChecker.isVoidCompatible;
800
801                        if (returnTypeIsVoid) {
802                            if (!isVoidCompatible) {
803                                resultInfo.checkContext.report(tree.pos(),
804                                    diags.fragment("unexpected.ret.val"));
805                            }
806                        } else {
807                            boolean isValueCompatible = lambdaBodyChecker.isPotentiallyValueCompatible
808                                && !canLambdaBodyCompleteNormally(tree);
809                            if (!isValueCompatible && !isVoidCompatible) {
810                                log.error(tree.body.pos(),
811                                    "lambda.body.neither.value.nor.void.compatible");
812                            }
813
814                            if (!isValueCompatible) {
815                                resultInfo.checkContext.report(tree.pos(),
816                                    diags.fragment("incompatible.ret.type.in.lambda",
817                                        diags.fragment("missing.ret.val", currentReturnType)));
818                            }
819                        }
820                    }
821                }
822            }
823
824            boolean canLambdaBodyCompleteNormally(JCLambda tree) {
825                List<JCVariableDecl> oldParams = tree.params;
826                LocalCacheContext localCacheContext = argumentAttr.withLocalCacheContext();
827                try {
828                    tree.params = tree.params.stream()
829                            .map(vd -> make.VarDef(vd.mods, vd.name, make.Erroneous(), null))
830                            .collect(List.collector());
831                    return attribSpeculativeLambda(tree, env, attr.unknownExprInfo).canCompleteNormally;
832                } finally {
833                    localCacheContext.leave();
834                    tree.params = oldParams;
835                }
836            }
837
838            @Override
839            public void visitNewClass(JCNewClass tree) {
840                //do nothing
841            }
842
843            @Override
844            public void visitApply(JCMethodInvocation tree) {
845                //do nothing
846            }
847
848            @Override
849            public void visitReference(JCMemberReference tree) {
850                Check.CheckContext checkContext = resultInfo.checkContext;
851                Type pt = resultInfo.pt;
852                if (!inferenceContext.inferencevars.contains(pt)) {
853                    try {
854                        types.findDescriptorType(pt);
855                    } catch (Types.FunctionDescriptorLookupError ex) {
856                        checkContext.report(null, ex.getDiagnostic());
857                    }
858                    Env<AttrContext> localEnv = env.dup(tree);
859                    JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv,
860                            attr.memberReferenceQualifierResult(tree));
861                    ListBuffer<Type> argtypes = new ListBuffer<>();
862                    for (Type t : types.findDescriptorType(pt).getParameterTypes()) {
863                        argtypes.append(Type.noType);
864                    }
865                    JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree);
866                    mref2.expr = exprTree;
867                    Symbol lookupSym =
868                            rs.resolveMemberReference(localEnv, mref2, exprTree.type,
869                                    tree.name, argtypes.toList(), List.nil(), rs.arityMethodCheck,
870                                    inferenceContext, rs.structuralReferenceChooser).fst;
871                    switch (lookupSym.kind) {
872                        case WRONG_MTH:
873                        case WRONG_MTHS:
874                            //note: as argtypes are erroneous types, type-errors must
875                            //have been caused by arity mismatch
876                            checkContext.report(tree, diags.fragment(Fragments.IncompatibleArgTypesInMref));
877                            break;
878                        case ABSENT_MTH:
879                        case STATICERR:
880                            //if no method found, or method found with wrong staticness, report better message
881                            checkContext.report(tree, ((ResolveError)lookupSym).getDiagnostic(DiagnosticType.FRAGMENT,
882                                    tree, exprTree.type.tsym, exprTree.type, tree.name, argtypes.toList(), List.nil()));
883                            break;
884                    }
885                }
886            }
887        }
888
889        /* This visitor looks for return statements, its analysis will determine if
890         * a lambda body is void or value compatible. We must analyze return
891         * statements contained in the lambda body only, thus any return statement
892         * contained in an inner class or inner lambda body, should be ignored.
893         */
894        class LambdaBodyStructChecker extends TreeScanner {
895            boolean isVoidCompatible = true;
896            boolean isPotentiallyValueCompatible = true;
897
898            @Override
899            public void visitClassDef(JCClassDecl tree) {
900                // do nothing
901            }
902
903            @Override
904            public void visitLambda(JCLambda tree) {
905                // do nothing
906            }
907
908            @Override
909            public void visitNewClass(JCNewClass tree) {
910                // do nothing
911            }
912
913            @Override
914            public void visitReturn(JCReturn tree) {
915                if (tree.expr != null) {
916                    isVoidCompatible = false;
917                } else {
918                    isPotentiallyValueCompatible = false;
919                }
920            }
921        }
922    }
923
924    /** an empty deferred attribution context - all methods throw exceptions */
925    final DeferredAttrContext emptyDeferredAttrContext;
926
927    /**
928     * Map a list of types possibly containing one or more deferred types
929     * into a list of ordinary types. Each deferred type D is mapped into a type T,
930     * where T is computed by retrieving the type that has already been
931     * computed for D during a previous deferred attribution round of the given kind.
932     */
933    class DeferredTypeMap extends StructuralTypeMapping<Void> {
934        DeferredAttrContext deferredAttrContext;
935
936        protected DeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
937            this.deferredAttrContext = new DeferredAttrContext(mode, msym, phase,
938                    infer.emptyContext, emptyDeferredAttrContext, types.noWarnings);
939        }
940
941        @Override
942        public Type visitType(Type t, Void _unused) {
943            if (!t.hasTag(DEFERRED)) {
944                return super.visitType(t, null);
945            } else {
946                DeferredType dt = (DeferredType)t;
947                return typeOf(dt);
948            }
949        }
950
951        protected Type typeOf(DeferredType dt) {
952            switch (deferredAttrContext.mode) {
953                case CHECK:
954                    return dt.tree.type == null ? Type.noType : dt.tree.type;
955                case SPECULATIVE:
956                    return dt.speculativeType(deferredAttrContext.msym, deferredAttrContext.phase);
957            }
958            Assert.error();
959            return null;
960        }
961    }
962
963    /**
964     * Specialized recovery deferred mapping.
965     * Each deferred type D is mapped into a type T, where T is computed either by
966     * (i) retrieving the type that has already been computed for D during a previous
967     * attribution round (as before), or (ii) by synthesizing a new type R for D
968     * (the latter step is useful in a recovery scenario).
969     */
970    public class RecoveryDeferredTypeMap extends DeferredTypeMap {
971
972        public RecoveryDeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
973            super(mode, msym, phase != null ? phase : MethodResolutionPhase.BOX);
974        }
975
976        @Override
977        protected Type typeOf(DeferredType dt) {
978            Type owntype = super.typeOf(dt);
979            return owntype == Type.noType ?
980                        recover(dt) : owntype;
981        }
982
983        /**
984         * Synthesize a type for a deferred type that hasn't been previously
985         * reduced to an ordinary type. Functional deferred types and conditionals
986         * are mapped to themselves, in order to have a richer diagnostic
987         * representation. Remaining deferred types are attributed using
988         * a default expected type (j.l.Object).
989         */
990        private Type recover(DeferredType dt) {
991            dt.check(attr.new RecoveryInfo(deferredAttrContext) {
992                @Override
993                protected Type check(DiagnosticPosition pos, Type found) {
994                    return chk.checkNonVoid(pos, super.check(pos, found));
995                }
996            });
997            return super.visit(dt);
998        }
999    }
1000
1001    /**
1002     * A special tree scanner that would only visit portions of a given tree.
1003     * The set of nodes visited by the scanner can be customized at construction-time.
1004     */
1005    abstract static class FilterScanner extends com.sun.tools.javac.tree.TreeScanner {
1006
1007        final Filter<JCTree> treeFilter;
1008
1009        FilterScanner(final Set<JCTree.Tag> validTags) {
1010            this.treeFilter = t -> validTags.contains(t.getTag());
1011        }
1012
1013        @Override
1014        public void scan(JCTree tree) {
1015            if (tree != null) {
1016                if (treeFilter.accepts(tree)) {
1017                    super.scan(tree);
1018                } else {
1019                    skip(tree);
1020                }
1021            }
1022        }
1023
1024        /**
1025         * handler that is executed when a node has been discarded
1026         */
1027        void skip(JCTree tree) {}
1028    }
1029
1030    /**
1031     * A tree scanner suitable for visiting the target-type dependent nodes of
1032     * a given argument expression.
1033     */
1034    static class PolyScanner extends FilterScanner {
1035
1036        PolyScanner() {
1037            super(EnumSet.of(CONDEXPR, PARENS, LAMBDA, REFERENCE));
1038        }
1039    }
1040
1041    /**
1042     * A tree scanner suitable for visiting the target-type dependent nodes nested
1043     * within a lambda expression body.
1044     */
1045    static class LambdaReturnScanner extends FilterScanner {
1046
1047        LambdaReturnScanner() {
1048            super(EnumSet.of(BLOCK, CASE, CATCH, DOLOOP, FOREACHLOOP,
1049                    FORLOOP, IF, RETURN, SYNCHRONIZED, SWITCH, TRY, WHILELOOP));
1050        }
1051    }
1052
1053    /**
1054     * This visitor is used to check that structural expressions conform
1055     * to their target - this step is required as inference could end up
1056     * inferring types that make some of the nested expressions incompatible
1057     * with their corresponding instantiated target
1058     */
1059    class CheckStuckPolicy extends PolyScanner implements DeferredStuckPolicy, Infer.FreeTypeListener {
1060
1061        Type pt;
1062        InferenceContext inferenceContext;
1063        Set<Type> stuckVars = new LinkedHashSet<>();
1064        Set<Type> depVars = new LinkedHashSet<>();
1065
1066        @Override
1067        public boolean isStuck() {
1068            return !stuckVars.isEmpty();
1069        }
1070
1071        @Override
1072        public Set<Type> stuckVars() {
1073            return stuckVars;
1074        }
1075
1076        @Override
1077        public Set<Type> depVars() {
1078            return depVars;
1079        }
1080
1081        public CheckStuckPolicy(ResultInfo resultInfo, DeferredType dt) {
1082            this.pt = resultInfo.pt;
1083            this.inferenceContext = resultInfo.checkContext.inferenceContext();
1084            scan(dt.tree);
1085            if (!stuckVars.isEmpty()) {
1086                resultInfo.checkContext.inferenceContext()
1087                        .addFreeTypeListener(List.from(stuckVars), this);
1088            }
1089        }
1090
1091        @Override
1092        public void typesInferred(InferenceContext inferenceContext) {
1093            stuckVars.clear();
1094        }
1095
1096        @Override
1097        public void visitLambda(JCLambda tree) {
1098            if (inferenceContext.inferenceVars().contains(pt)) {
1099                stuckVars.add(pt);
1100            }
1101            if (!types.isFunctionalInterface(pt)) {
1102                return;
1103            }
1104            Type descType = types.findDescriptorType(pt);
1105            List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
1106            if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT &&
1107                    freeArgVars.nonEmpty()) {
1108                stuckVars.addAll(freeArgVars);
1109                depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType()));
1110            }
1111            scanLambdaBody(tree, descType.getReturnType());
1112        }
1113
1114        @Override
1115        public void visitReference(JCMemberReference tree) {
1116            scan(tree.expr);
1117            if (inferenceContext.inferenceVars().contains(pt)) {
1118                stuckVars.add(pt);
1119                return;
1120            }
1121            if (!types.isFunctionalInterface(pt)) {
1122                return;
1123            }
1124
1125            Type descType = types.findDescriptorType(pt);
1126            List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
1127            if (freeArgVars.nonEmpty() &&
1128                    tree.overloadKind == JCMemberReference.OverloadKind.OVERLOADED) {
1129                stuckVars.addAll(freeArgVars);
1130                depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType()));
1131            }
1132        }
1133
1134        void scanLambdaBody(JCLambda lambda, final Type pt) {
1135            if (lambda.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) {
1136                Type prevPt = this.pt;
1137                try {
1138                    this.pt = pt;
1139                    scan(lambda.body);
1140                } finally {
1141                    this.pt = prevPt;
1142                }
1143            } else {
1144                LambdaReturnScanner lambdaScanner = new LambdaReturnScanner() {
1145                    @Override
1146                    public void visitReturn(JCReturn tree) {
1147                        if (tree.expr != null) {
1148                            Type prevPt = CheckStuckPolicy.this.pt;
1149                            try {
1150                                CheckStuckPolicy.this.pt = pt;
1151                                CheckStuckPolicy.this.scan(tree.expr);
1152                            } finally {
1153                                CheckStuckPolicy.this.pt = prevPt;
1154                            }
1155                        }
1156                    }
1157                };
1158                lambdaScanner.scan(lambda.body);
1159            }
1160        }
1161    }
1162
1163    /**
1164     * This visitor is used to check that structural expressions conform
1165     * to their target - this step is required as inference could end up
1166     * inferring types that make some of the nested expressions incompatible
1167     * with their corresponding instantiated target
1168     */
1169    class OverloadStuckPolicy extends CheckStuckPolicy implements DeferredStuckPolicy {
1170
1171        boolean stuck;
1172
1173        @Override
1174        public boolean isStuck() {
1175            return super.isStuck() || stuck;
1176        }
1177
1178        public OverloadStuckPolicy(ResultInfo resultInfo, DeferredType dt) {
1179            super(resultInfo, dt);
1180        }
1181
1182        @Override
1183        public void visitLambda(JCLambda tree) {
1184            super.visitLambda(tree);
1185            if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT) {
1186                stuck = true;
1187            }
1188        }
1189
1190        @Override
1191        public void visitReference(JCMemberReference tree) {
1192            super.visitReference(tree);
1193            if (tree.overloadKind == JCMemberReference.OverloadKind.OVERLOADED) {
1194                stuck = true;
1195            }
1196        }
1197    }
1198}
1199