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