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