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