1 /* 2 * Copyright (c) 2012, 2024, 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 super(log, 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 }