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