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