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