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