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