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 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 = 66 new Context.Key<DeferredAttr>(); 67 68 final Attr attr; 69 final Check chk; 70 final JCDiagnostic.Factory diags; 71 final Enter enter; 72 final Infer infer; 73 final Resolve rs; 74 final Log log; 75 final Symtab syms; 76 final TreeMaker make; 77 final Types types; 78 final Flow flow; 79 final Names names; 80 final TypeEnvs typeEnvs; 81 instance(Context context)82 public static DeferredAttr instance(Context context) { 83 DeferredAttr instance = context.get(deferredAttrKey); 84 if (instance == null) 85 instance = new DeferredAttr(context); 86 return instance; 87 } 88 DeferredAttr(Context context)89 protected DeferredAttr(Context context) { 90 context.put(deferredAttrKey, this); 91 attr = Attr.instance(context); 92 chk = Check.instance(context); 93 diags = JCDiagnostic.Factory.instance(context); 94 enter = Enter.instance(context); 95 infer = Infer.instance(context); 96 rs = Resolve.instance(context); 97 log = Log.instance(context); 98 syms = Symtab.instance(context); 99 make = TreeMaker.instance(context); 100 types = Types.instance(context); 101 flow = Flow.instance(context); 102 names = Names.instance(context); 103 stuckTree = make.Ident(names.empty).setType(Type.stuckType); 104 typeEnvs = TypeEnvs.instance(context); 105 emptyDeferredAttrContext = 106 new DeferredAttrContext(AttrMode.CHECK, null, MethodResolutionPhase.BOX, infer.emptyContext, null, null) { 107 @Override 108 void addDeferredAttrNode(DeferredType dt, ResultInfo ri, DeferredStuckPolicy deferredStuckPolicy) { 109 Assert.error("Empty deferred context!"); 110 } 111 @Override 112 void complete() { 113 Assert.error("Empty deferred context!"); 114 } 115 116 @Override 117 public String toString() { 118 return "Empty deferred context!"; 119 } 120 }; 121 } 122 123 /** shared tree for stuck expressions */ 124 final JCTree stuckTree; 125 126 /** 127 * This type represents a deferred type. A deferred type starts off with 128 * no information on the underlying expression type. Such info needs to be 129 * discovered through type-checking the deferred type against a target-type. 130 * Every deferred type keeps a pointer to the AST node from which it originated. 131 */ 132 public class DeferredType extends Type { 133 134 public JCExpression tree; 135 Env<AttrContext> env; 136 AttrMode mode; 137 SpeculativeCache speculativeCache; 138 DeferredType(JCExpression tree, Env<AttrContext> env)139 DeferredType(JCExpression tree, Env<AttrContext> env) { 140 super(null); 141 this.tree = tree; 142 this.env = attr.copyEnv(env); 143 this.speculativeCache = new SpeculativeCache(); 144 } 145 146 @Override getTag()147 public TypeTag getTag() { 148 return DEFERRED; 149 } 150 151 @Override toString()152 public String toString() { 153 return "DeferredType"; 154 } 155 156 /** 157 * A speculative cache is used to keep track of all overload resolution rounds 158 * that triggered speculative attribution on a given deferred type. Each entry 159 * stores a pointer to the speculative tree and the resolution phase in which the entry 160 * has been added. 161 */ 162 class SpeculativeCache { 163 164 private Map<Symbol, List<Entry>> cache = 165 new WeakHashMap<Symbol, List<Entry>>(); 166 167 class Entry { 168 JCTree speculativeTree; 169 ResultInfo resultInfo; 170 Entry(JCTree speculativeTree, ResultInfo resultInfo)171 public Entry(JCTree speculativeTree, ResultInfo resultInfo) { 172 this.speculativeTree = speculativeTree; 173 this.resultInfo = resultInfo; 174 } 175 matches(MethodResolutionPhase phase)176 boolean matches(MethodResolutionPhase phase) { 177 return resultInfo.checkContext.deferredAttrContext().phase == phase; 178 } 179 } 180 181 /** 182 * Retrieve a speculative cache entry corresponding to given symbol 183 * and resolution phase 184 */ get(Symbol msym, MethodResolutionPhase phase)185 Entry get(Symbol msym, MethodResolutionPhase phase) { 186 List<Entry> entries = cache.get(msym); 187 if (entries == null) return null; 188 for (Entry e : entries) { 189 if (e.matches(phase)) return e; 190 } 191 return null; 192 } 193 194 /** 195 * Stores a speculative cache entry corresponding to given symbol 196 * and resolution phase 197 */ put(JCTree speculativeTree, ResultInfo resultInfo)198 void put(JCTree speculativeTree, ResultInfo resultInfo) { 199 Symbol msym = resultInfo.checkContext.deferredAttrContext().msym; 200 List<Entry> entries = cache.get(msym); 201 if (entries == null) { 202 entries = List.nil(); 203 } 204 cache.put(msym, entries.prepend(new Entry(speculativeTree, resultInfo))); 205 } 206 } 207 208 /** 209 * Get the type that has been computed during a speculative attribution round 210 */ speculativeType(Symbol msym, MethodResolutionPhase phase)211 Type speculativeType(Symbol msym, MethodResolutionPhase phase) { 212 SpeculativeCache.Entry e = speculativeCache.get(msym, phase); 213 return e != null ? e.speculativeTree.type : Type.noType; 214 } 215 216 /** 217 * Check a deferred type against a potential target-type. Depending on 218 * the current attribution mode, a normal vs. speculative attribution 219 * round is performed on the underlying AST node. There can be only one 220 * speculative round for a given target method symbol; moreover, a normal 221 * attribution round must follow one or more speculative rounds. 222 */ check(ResultInfo resultInfo)223 Type check(ResultInfo resultInfo) { 224 DeferredStuckPolicy deferredStuckPolicy; 225 if (resultInfo.pt.hasTag(NONE) || resultInfo.pt.isErroneous()) { 226 deferredStuckPolicy = dummyStuckPolicy; 227 } else if (resultInfo.checkContext.deferredAttrContext().mode == AttrMode.SPECULATIVE || 228 resultInfo.checkContext.deferredAttrContext().insideOverloadPhase()) { 229 deferredStuckPolicy = new OverloadStuckPolicy(resultInfo, this); 230 } else { 231 deferredStuckPolicy = new CheckStuckPolicy(resultInfo, this); 232 } 233 return check(resultInfo, deferredStuckPolicy, basicCompleter); 234 } 235 check(ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy, DeferredTypeCompleter deferredTypeCompleter)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 */ complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext)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 */ isStuck()308 boolean isStuck(); 309 /** 310 * Get the set of inference variables a given expression depends upon. 311 */ stuckVars()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 */ depVars()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 */ attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo)362 JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) { 363 final JCTree newTree = new TreeCopier<Object>(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 visitClassDef(JCClassDecl tree)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 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<DeferredAttrNode>(); 446 DeferredAttrContext(AttrMode mode, Symbol msym, MethodResolutionPhase phase, InferenceContext inferenceContext, DeferredAttrContext parent, Warner warn)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 */ addDeferredAttrNode(final DeferredType dt, ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy)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 */ complete()472 void complete() { 473 while (!deferredAttrNodes.isEmpty()) { 474 Map<Type, Set<Type>> depVarsMap = new LinkedHashMap<Type, Set<Type>>(); 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<Type>(); 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 if (insideOverloadPhase()) { 502 for (DeferredAttrNode deferredNode: deferredAttrNodes) { 503 deferredNode.dt.tree.type = Type.noType; 504 } 505 return; 506 } 507 //remove all variables that have already been instantiated 508 //from the list of stuck variables 509 try { 510 inferenceContext.solveAny(stuckVars, depVarsMap, warn); 511 inferenceContext.notifyChange(); 512 } catch (Infer.GraphStrategy.NodeNotFoundException ex) { 513 //this means that we are in speculative mode and the 514 //set of contraints are too tight for progess to be made. 515 //Just leave the remaining expressions as stuck. 516 break; 517 } 518 } 519 } 520 } 521 insideOverloadPhase()522 private boolean insideOverloadPhase() { 523 DeferredAttrContext dac = this; 524 if (dac == emptyDeferredAttrContext) { 525 return false; 526 } 527 if (dac.mode == AttrMode.SPECULATIVE) { 528 return true; 529 } 530 return dac.parent.insideOverloadPhase(); 531 } 532 } 533 534 /** 535 * Class representing a deferred attribution node. It keeps track of 536 * a deferred type, along with the expected target type information. 537 */ 538 class DeferredAttrNode { 539 540 /** underlying deferred type */ 541 DeferredType dt; 542 543 /** underlying target type information */ 544 ResultInfo resultInfo; 545 546 /** stuck policy associated with this node */ 547 DeferredStuckPolicy deferredStuckPolicy; 548 DeferredAttrNode(DeferredType dt, ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy)549 DeferredAttrNode(DeferredType dt, ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy) { 550 this.dt = dt; 551 this.resultInfo = resultInfo; 552 this.deferredStuckPolicy = deferredStuckPolicy; 553 } 554 555 /** 556 * Process a deferred attribution node. 557 * Invariant: a stuck node cannot be processed. 558 */ 559 @SuppressWarnings("fallthrough") process(final DeferredAttrContext deferredAttrContext)560 boolean process(final DeferredAttrContext deferredAttrContext) { 561 switch (deferredAttrContext.mode) { 562 case SPECULATIVE: 563 if (deferredStuckPolicy.isStuck()) { 564 dt.check(resultInfo, dummyStuckPolicy, new StructuralStuckChecker()); 565 return true; 566 } else { 567 Assert.error("Cannot get here"); 568 } 569 case CHECK: 570 if (deferredStuckPolicy.isStuck()) { 571 //stuck expression - see if we can propagate 572 if (deferredAttrContext.parent != emptyDeferredAttrContext && 573 Type.containsAny(deferredAttrContext.parent.inferenceContext.inferencevars, 574 List.from(deferredStuckPolicy.stuckVars()))) { 575 deferredAttrContext.parent.addDeferredAttrNode(dt, 576 resultInfo.dup(new Check.NestedCheckContext(resultInfo.checkContext) { 577 @Override 578 public InferenceContext inferenceContext() { 579 return deferredAttrContext.parent.inferenceContext; 580 } 581 @Override 582 public DeferredAttrContext deferredAttrContext() { 583 return deferredAttrContext.parent; 584 } 585 }), deferredStuckPolicy); 586 dt.tree.type = Type.stuckType; 587 return true; 588 } else { 589 return false; 590 } 591 } else { 592 Assert.check(!deferredAttrContext.insideOverloadPhase(), 593 "attribution shouldn't be happening here"); 594 ResultInfo instResultInfo = 595 resultInfo.dup(deferredAttrContext.inferenceContext.asInstType(resultInfo.pt)); 596 dt.check(instResultInfo, dummyStuckPolicy, basicCompleter); 597 return true; 598 } 599 default: 600 throw new AssertionError("Bad mode"); 601 } 602 } 603 604 /** 605 * Structural checker for stuck expressions 606 */ 607 class StructuralStuckChecker extends TreeScanner implements DeferredTypeCompleter { 608 609 ResultInfo resultInfo; 610 InferenceContext inferenceContext; 611 Env<AttrContext> env; 612 complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext)613 public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) { 614 this.resultInfo = resultInfo; 615 this.inferenceContext = deferredAttrContext.inferenceContext; 616 this.env = dt.env; 617 dt.tree.accept(this); 618 dt.speculativeCache.put(stuckTree, resultInfo); 619 return Type.noType; 620 } 621 622 @Override visitLambda(JCLambda tree)623 public void visitLambda(JCLambda tree) { 624 Check.CheckContext checkContext = resultInfo.checkContext; 625 Type pt = resultInfo.pt; 626 if (!inferenceContext.inferencevars.contains(pt)) { 627 //must be a functional descriptor 628 Type descriptorType = null; 629 try { 630 descriptorType = types.findDescriptorType(pt); 631 } catch (Types.FunctionDescriptorLookupError ex) { 632 checkContext.report(null, ex.getDiagnostic()); 633 } 634 635 if (descriptorType.getParameterTypes().length() != tree.params.length()) { 636 checkContext.report(tree, 637 diags.fragment("incompatible.arg.types.in.lambda")); 638 } 639 640 Type currentReturnType = descriptorType.getReturnType(); 641 boolean returnTypeIsVoid = currentReturnType.hasTag(VOID); 642 if (tree.getBodyKind() == BodyKind.EXPRESSION) { 643 boolean isExpressionCompatible = !returnTypeIsVoid || 644 TreeInfo.isExpressionStatement((JCExpression)tree.getBody()); 645 if (!isExpressionCompatible) { 646 resultInfo.checkContext.report(tree.pos(), 647 diags.fragment("incompatible.ret.type.in.lambda", 648 diags.fragment("missing.ret.val", currentReturnType))); 649 } 650 } else { 651 LambdaBodyStructChecker lambdaBodyChecker = 652 new LambdaBodyStructChecker(); 653 654 tree.body.accept(lambdaBodyChecker); 655 boolean isVoidCompatible = lambdaBodyChecker.isVoidCompatible; 656 657 if (returnTypeIsVoid) { 658 if (!isVoidCompatible) { 659 resultInfo.checkContext.report(tree.pos(), 660 diags.fragment("unexpected.ret.val")); 661 } 662 } else { 663 boolean isValueCompatible = lambdaBodyChecker.isPotentiallyValueCompatible 664 && !canLambdaBodyCompleteNormally(tree); 665 if (!isValueCompatible && !isVoidCompatible) { 666 log.error(tree.body.pos(), 667 "lambda.body.neither.value.nor.void.compatible"); 668 } 669 670 if (!isValueCompatible) { 671 resultInfo.checkContext.report(tree.pos(), 672 diags.fragment("incompatible.ret.type.in.lambda", 673 diags.fragment("missing.ret.val", currentReturnType))); 674 } 675 } 676 } 677 } 678 } 679 canLambdaBodyCompleteNormally(JCLambda tree)680 boolean canLambdaBodyCompleteNormally(JCLambda tree) { 681 JCLambda newTree = new TreeCopier<>(make).copy(tree); 682 /* attr.lambdaEnv will create a meaningful env for the 683 * lambda expression. This is specially useful when the 684 * lambda is used as the init of a field. But we need to 685 * remove any added symbol. 686 */ 687 Env<AttrContext> localEnv = attr.lambdaEnv(newTree, env); 688 try { 689 List<JCVariableDecl> tmpParams = newTree.params; 690 while (tmpParams.nonEmpty()) { 691 tmpParams.head.vartype = make.at(tmpParams.head).Type(syms.errType); 692 tmpParams = tmpParams.tail; 693 } 694 695 attr.attribStats(newTree.params, localEnv); 696 697 /* set pt to Type.noType to avoid generating any bound 698 * which may happen if lambda's return type is an 699 * inference variable 700 */ 701 Attr.ResultInfo bodyResultInfo = attr.new ResultInfo(VAL, Type.noType); 702 localEnv.info.returnResult = bodyResultInfo; 703 704 // discard any log output 705 Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log); 706 try { 707 JCBlock body = (JCBlock)newTree.body; 708 /* we need to attribute the lambda body before 709 * doing the aliveness analysis. This is because 710 * constant folding occurs during attribution 711 * and the reachability of some statements depends 712 * on constant values, for example: 713 * 714 * while (true) {...} 715 */ 716 attr.attribStats(body.stats, localEnv); 717 718 attr.preFlow(newTree); 719 /* make an aliveness / reachability analysis of the lambda 720 * to determine if it can complete normally 721 */ 722 flow.analyzeLambda(localEnv, newTree, make, true); 723 } finally { 724 log.popDiagnosticHandler(diagHandler); 725 } 726 return newTree.canCompleteNormally; 727 } finally { 728 JCBlock body = (JCBlock)newTree.body; 729 unenterScanner.scan(body.stats); 730 localEnv.info.scope.leave(); 731 } 732 } 733 734 @Override visitNewClass(JCNewClass tree)735 public void visitNewClass(JCNewClass tree) { 736 //do nothing 737 } 738 739 @Override visitApply(JCMethodInvocation tree)740 public void visitApply(JCMethodInvocation tree) { 741 //do nothing 742 } 743 744 @Override visitReference(JCMemberReference tree)745 public void visitReference(JCMemberReference tree) { 746 Check.CheckContext checkContext = resultInfo.checkContext; 747 Type pt = resultInfo.pt; 748 if (!inferenceContext.inferencevars.contains(pt)) { 749 try { 750 types.findDescriptorType(pt); 751 } catch (Types.FunctionDescriptorLookupError ex) { 752 checkContext.report(null, ex.getDiagnostic()); 753 } 754 Env<AttrContext> localEnv = env.dup(tree); 755 JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv, 756 attr.memberReferenceQualifierResult(tree)); 757 ListBuffer<Type> argtypes = new ListBuffer<>(); 758 for (Type t : types.findDescriptorType(pt).getParameterTypes()) { 759 argtypes.append(Type.noType); 760 } 761 JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree); 762 mref2.expr = exprTree; 763 Symbol lookupSym = 764 rs.resolveMemberReferenceByArity(localEnv, mref2, exprTree.type, 765 tree.name, argtypes.toList(), inferenceContext); 766 switch (lookupSym.kind) { 767 //note: as argtypes are erroneous types, type-errors must 768 //have been caused by arity mismatch 769 case Kinds.ABSENT_MTH: 770 case Kinds.WRONG_MTH: 771 case Kinds.WRONG_MTHS: 772 case Kinds.WRONG_STATICNESS: 773 checkContext.report(tree, diags.fragment("incompatible.arg.types.in.mref")); 774 } 775 } 776 } 777 } 778 779 /* This visitor looks for return statements, its analysis will determine if 780 * a lambda body is void or value compatible. We must analyze return 781 * statements contained in the lambda body only, thus any return statement 782 * contained in an inner class or inner lambda body, should be ignored. 783 */ 784 class LambdaBodyStructChecker extends TreeScanner { 785 boolean isVoidCompatible = true; 786 boolean isPotentiallyValueCompatible = true; 787 788 @Override visitClassDef(JCClassDecl tree)789 public void visitClassDef(JCClassDecl tree) { 790 // do nothing 791 } 792 793 @Override visitLambda(JCLambda tree)794 public void visitLambda(JCLambda tree) { 795 // do nothing 796 } 797 798 @Override visitNewClass(JCNewClass tree)799 public void visitNewClass(JCNewClass tree) { 800 // do nothing 801 } 802 803 @Override visitReturn(JCReturn tree)804 public void visitReturn(JCReturn tree) { 805 if (tree.expr != null) { 806 isVoidCompatible = false; 807 } else { 808 isPotentiallyValueCompatible = false; 809 } 810 } 811 } 812 } 813 814 /** an empty deferred attribution context - all methods throw exceptions */ 815 final DeferredAttrContext emptyDeferredAttrContext; 816 817 /** 818 * Map a list of types possibly containing one or more deferred types 819 * into a list of ordinary types. Each deferred type D is mapped into a type T, 820 * where T is computed by retrieving the type that has already been 821 * computed for D during a previous deferred attribution round of the given kind. 822 */ 823 class DeferredTypeMap extends Type.Mapping { 824 825 DeferredAttrContext deferredAttrContext; 826 DeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase)827 protected DeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) { 828 super(String.format("deferredTypeMap[%s]", mode)); 829 this.deferredAttrContext = new DeferredAttrContext(mode, msym, phase, 830 infer.emptyContext, emptyDeferredAttrContext, types.noWarnings); 831 } 832 833 @Override apply(Type t)834 public Type apply(Type t) { 835 if (!t.hasTag(DEFERRED)) { 836 return t.map(this); 837 } else { 838 DeferredType dt = (DeferredType)t; 839 return typeOf(dt); 840 } 841 } 842 typeOf(DeferredType dt)843 protected Type typeOf(DeferredType dt) { 844 switch (deferredAttrContext.mode) { 845 case CHECK: 846 return dt.tree.type == null ? Type.noType : dt.tree.type; 847 case SPECULATIVE: 848 return dt.speculativeType(deferredAttrContext.msym, deferredAttrContext.phase); 849 } 850 Assert.error(); 851 return null; 852 } 853 } 854 855 /** 856 * Specialized recovery deferred mapping. 857 * Each deferred type D is mapped into a type T, where T is computed either by 858 * (i) retrieving the type that has already been computed for D during a previous 859 * attribution round (as before), or (ii) by synthesizing a new type R for D 860 * (the latter step is useful in a recovery scenario). 861 */ 862 public class RecoveryDeferredTypeMap extends DeferredTypeMap { 863 RecoveryDeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase)864 public RecoveryDeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) { 865 super(mode, msym, phase != null ? phase : MethodResolutionPhase.BOX); 866 } 867 868 @Override typeOf(DeferredType dt)869 protected Type typeOf(DeferredType dt) { 870 Type owntype = super.typeOf(dt); 871 return owntype == Type.noType ? 872 recover(dt) : owntype; 873 } 874 875 /** 876 * Synthesize a type for a deferred type that hasn't been previously 877 * reduced to an ordinary type. Functional deferred types and conditionals 878 * are mapped to themselves, in order to have a richer diagnostic 879 * representation. Remaining deferred types are attributed using 880 * a default expected type (j.l.Object). 881 */ recover(DeferredType dt)882 private Type recover(DeferredType dt) { 883 dt.check(attr.new RecoveryInfo(deferredAttrContext) { 884 @Override 885 protected Type check(DiagnosticPosition pos, Type found) { 886 return chk.checkNonVoid(pos, super.check(pos, found)); 887 } 888 }); 889 return super.apply(dt); 890 } 891 } 892 893 /** 894 * A special tree scanner that would only visit portions of a given tree. 895 * The set of nodes visited by the scanner can be customized at construction-time. 896 */ 897 abstract static class FilterScanner extends TreeScanner { 898 899 final Filter<JCTree> treeFilter; 900 FilterScanner(final Set<JCTree.Tag> validTags)901 FilterScanner(final Set<JCTree.Tag> validTags) { 902 this.treeFilter = new Filter<JCTree>() { 903 public boolean accepts(JCTree t) { 904 return validTags.contains(t.getTag()); 905 } 906 }; 907 } 908 909 @Override scan(JCTree tree)910 public void scan(JCTree tree) { 911 if (tree != null) { 912 if (treeFilter.accepts(tree)) { 913 super.scan(tree); 914 } else { 915 skip(tree); 916 } 917 } 918 } 919 920 /** 921 * handler that is executed when a node has been discarded 922 */ skip(JCTree tree)923 void skip(JCTree tree) {} 924 } 925 926 /** 927 * A tree scanner suitable for visiting the target-type dependent nodes of 928 * a given argument expression. 929 */ 930 static class PolyScanner extends FilterScanner { 931 PolyScanner()932 PolyScanner() { 933 super(EnumSet.of(CONDEXPR, PARENS, LAMBDA, REFERENCE)); 934 } 935 } 936 937 /** 938 * A tree scanner suitable for visiting the target-type dependent nodes nested 939 * within a lambda expression body. 940 */ 941 static class LambdaReturnScanner extends FilterScanner { 942 LambdaReturnScanner()943 LambdaReturnScanner() { 944 super(EnumSet.of(BLOCK, CASE, CATCH, DOLOOP, FOREACHLOOP, 945 FORLOOP, IF, RETURN, SYNCHRONIZED, SWITCH, TRY, WHILELOOP)); 946 } 947 } 948 949 /** 950 * This visitor is used to check that structural expressions conform 951 * to their target - this step is required as inference could end up 952 * inferring types that make some of the nested expressions incompatible 953 * with their corresponding instantiated target 954 */ 955 class CheckStuckPolicy extends PolyScanner implements DeferredStuckPolicy, Infer.FreeTypeListener { 956 957 Type pt; 958 Infer.InferenceContext inferenceContext; 959 Set<Type> stuckVars = new LinkedHashSet<Type>(); 960 Set<Type> depVars = new LinkedHashSet<Type>(); 961 962 @Override isStuck()963 public boolean isStuck() { 964 return !stuckVars.isEmpty(); 965 } 966 967 @Override stuckVars()968 public Set<Type> stuckVars() { 969 return stuckVars; 970 } 971 972 @Override depVars()973 public Set<Type> depVars() { 974 return depVars; 975 } 976 CheckStuckPolicy(ResultInfo resultInfo, DeferredType dt)977 public CheckStuckPolicy(ResultInfo resultInfo, DeferredType dt) { 978 this.pt = resultInfo.pt; 979 this.inferenceContext = resultInfo.checkContext.inferenceContext(); 980 scan(dt.tree); 981 if (!stuckVars.isEmpty()) { 982 resultInfo.checkContext.inferenceContext() 983 .addFreeTypeListener(List.from(stuckVars), this); 984 } 985 } 986 987 @Override typesInferred(InferenceContext inferenceContext)988 public void typesInferred(InferenceContext inferenceContext) { 989 stuckVars.clear(); 990 } 991 992 @Override visitLambda(JCLambda tree)993 public void visitLambda(JCLambda tree) { 994 if (inferenceContext.inferenceVars().contains(pt)) { 995 stuckVars.add(pt); 996 } 997 if (!types.isFunctionalInterface(pt)) { 998 return; 999 } 1000 Type descType = types.findDescriptorType(pt); 1001 List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes()); 1002 if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT && 1003 freeArgVars.nonEmpty()) { 1004 stuckVars.addAll(freeArgVars); 1005 depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType())); 1006 } 1007 scanLambdaBody(tree, descType.getReturnType()); 1008 } 1009 1010 @Override visitReference(JCMemberReference tree)1011 public void visitReference(JCMemberReference tree) { 1012 scan(tree.expr); 1013 if (inferenceContext.inferenceVars().contains(pt)) { 1014 stuckVars.add(pt); 1015 return; 1016 } 1017 if (!types.isFunctionalInterface(pt)) { 1018 return; 1019 } 1020 1021 Type descType = types.findDescriptorType(pt); 1022 List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes()); 1023 if (freeArgVars.nonEmpty() && 1024 tree.overloadKind == JCMemberReference.OverloadKind.OVERLOADED) { 1025 stuckVars.addAll(freeArgVars); 1026 depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType())); 1027 } 1028 } 1029 scanLambdaBody(JCLambda lambda, final Type pt)1030 void scanLambdaBody(JCLambda lambda, final Type pt) { 1031 if (lambda.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) { 1032 Type prevPt = this.pt; 1033 try { 1034 this.pt = pt; 1035 scan(lambda.body); 1036 } finally { 1037 this.pt = prevPt; 1038 } 1039 } else { 1040 LambdaReturnScanner lambdaScanner = new LambdaReturnScanner() { 1041 @Override 1042 public void visitReturn(JCReturn tree) { 1043 if (tree.expr != null) { 1044 Type prevPt = CheckStuckPolicy.this.pt; 1045 try { 1046 CheckStuckPolicy.this.pt = pt; 1047 CheckStuckPolicy.this.scan(tree.expr); 1048 } finally { 1049 CheckStuckPolicy.this.pt = prevPt; 1050 } 1051 } 1052 } 1053 }; 1054 lambdaScanner.scan(lambda.body); 1055 } 1056 } 1057 } 1058 1059 /** 1060 * This visitor is used to check that structural expressions conform 1061 * to their target - this step is required as inference could end up 1062 * inferring types that make some of the nested expressions incompatible 1063 * with their corresponding instantiated target 1064 */ 1065 class OverloadStuckPolicy extends CheckStuckPolicy implements DeferredStuckPolicy { 1066 1067 boolean stuck; 1068 1069 @Override isStuck()1070 public boolean isStuck() { 1071 return super.isStuck() || stuck; 1072 } 1073 OverloadStuckPolicy(ResultInfo resultInfo, DeferredType dt)1074 public OverloadStuckPolicy(ResultInfo resultInfo, DeferredType dt) { 1075 super(resultInfo, dt); 1076 } 1077 1078 @Override visitLambda(JCLambda tree)1079 public void visitLambda(JCLambda tree) { 1080 super.visitLambda(tree); 1081 if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT) { 1082 stuck = true; 1083 } 1084 } 1085 1086 @Override visitReference(JCMemberReference tree)1087 public void visitReference(JCMemberReference tree) { 1088 super.visitReference(tree); 1089 if (tree.overloadKind == JCMemberReference.OverloadKind.OVERLOADED) { 1090 stuck = true; 1091 } 1092 } 1093 } 1094 1095 /** 1096 * Does the argument expression {@code expr} need speculative type-checking? 1097 */ isDeferred(Env<AttrContext> env, JCExpression expr)1098 boolean isDeferred(Env<AttrContext> env, JCExpression expr) { 1099 DeferredChecker dc = new DeferredChecker(env); 1100 dc.scan(expr); 1101 return dc.result.isPoly(); 1102 } 1103 1104 /** 1105 * The kind of an argument expression. This is used by the analysis that 1106 * determines as to whether speculative attribution is necessary. 1107 */ 1108 enum ArgumentExpressionKind { 1109 1110 /** kind that denotes poly argument expression */ 1111 POLY, 1112 /** kind that denotes a standalone expression */ 1113 NO_POLY, 1114 /** kind that denotes a primitive/boxed standalone expression */ 1115 PRIMITIVE; 1116 1117 /** 1118 * Does this kind denote a poly argument expression 1119 */ isPoly()1120 public final boolean isPoly() { 1121 return this == POLY; 1122 } 1123 1124 /** 1125 * Does this kind denote a primitive standalone expression 1126 */ isPrimitive()1127 public final boolean isPrimitive() { 1128 return this == PRIMITIVE; 1129 } 1130 1131 /** 1132 * Compute the kind of a standalone expression of a given type 1133 */ standaloneKind(Type type, Types types)1134 static ArgumentExpressionKind standaloneKind(Type type, Types types) { 1135 return types.unboxedTypeOrType(type).isPrimitive() ? 1136 ArgumentExpressionKind.PRIMITIVE : 1137 ArgumentExpressionKind.NO_POLY; 1138 } 1139 1140 /** 1141 * Compute the kind of a method argument expression given its symbol 1142 */ methodKind(Symbol sym, Types types)1143 static ArgumentExpressionKind methodKind(Symbol sym, Types types) { 1144 Type restype = sym.type.getReturnType(); 1145 if (sym.type.hasTag(FORALL) && 1146 restype.containsAny(((ForAll)sym.type).tvars)) { 1147 return ArgumentExpressionKind.POLY; 1148 } else { 1149 return ArgumentExpressionKind.standaloneKind(restype, types); 1150 } 1151 } 1152 } 1153 1154 /** 1155 * Tree scanner used for checking as to whether an argument expression 1156 * requires speculative attribution 1157 */ 1158 final class DeferredChecker extends FilterScanner { 1159 1160 Env<AttrContext> env; 1161 ArgumentExpressionKind result; 1162 DeferredChecker(Env<AttrContext> env)1163 public DeferredChecker(Env<AttrContext> env) { 1164 super(deferredCheckerTags); 1165 this.env = env; 1166 } 1167 1168 @Override visitLambda(JCLambda tree)1169 public void visitLambda(JCLambda tree) { 1170 //a lambda is always a poly expression 1171 result = ArgumentExpressionKind.POLY; 1172 } 1173 1174 @Override visitReference(JCMemberReference tree)1175 public void visitReference(JCMemberReference tree) { 1176 //perform arity-based check 1177 Env<AttrContext> localEnv = env.dup(tree); 1178 JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv, 1179 attr.memberReferenceQualifierResult(tree)); 1180 JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree); 1181 mref2.expr = exprTree; 1182 Symbol res = 1183 rs.getMemberReference(tree, localEnv, mref2, 1184 exprTree.type, tree.name); 1185 tree.sym = res; 1186 if (res.kind >= Kinds.ERRONEOUS || 1187 res.type.hasTag(FORALL) || 1188 (res.flags() & Flags.VARARGS) != 0 || 1189 (TreeInfo.isStaticSelector(exprTree, tree.name.table.names) && 1190 exprTree.type.isRaw())) { 1191 tree.overloadKind = JCMemberReference.OverloadKind.OVERLOADED; 1192 } else { 1193 tree.overloadKind = JCMemberReference.OverloadKind.UNOVERLOADED; 1194 } 1195 //a method reference is always a poly expression 1196 result = ArgumentExpressionKind.POLY; 1197 } 1198 1199 @Override visitTypeCast(JCTypeCast tree)1200 public void visitTypeCast(JCTypeCast tree) { 1201 //a cast is always a standalone expression 1202 result = ArgumentExpressionKind.NO_POLY; 1203 } 1204 1205 @Override visitConditional(JCConditional tree)1206 public void visitConditional(JCConditional tree) { 1207 scan(tree.truepart); 1208 if (!result.isPrimitive()) { 1209 result = ArgumentExpressionKind.POLY; 1210 return; 1211 } 1212 scan(tree.falsepart); 1213 result = reduce(ArgumentExpressionKind.PRIMITIVE); 1214 } 1215 1216 @Override visitNewClass(JCNewClass tree)1217 public void visitNewClass(JCNewClass tree) { 1218 result = (TreeInfo.isDiamond(tree) || attr.findDiamonds) ? 1219 ArgumentExpressionKind.POLY : ArgumentExpressionKind.NO_POLY; 1220 } 1221 1222 @Override visitApply(JCMethodInvocation tree)1223 public void visitApply(JCMethodInvocation tree) { 1224 Name name = TreeInfo.name(tree.meth); 1225 1226 //fast path 1227 if (tree.typeargs.nonEmpty() || 1228 name == name.table.names._this || 1229 name == name.table.names._super) { 1230 result = ArgumentExpressionKind.NO_POLY; 1231 return; 1232 } 1233 1234 //slow path 1235 Symbol sym = quicklyResolveMethod(env, tree); 1236 1237 if (sym == null) { 1238 result = ArgumentExpressionKind.POLY; 1239 return; 1240 } 1241 1242 result = analyzeCandidateMethods(sym, ArgumentExpressionKind.PRIMITIVE, 1243 argumentKindAnalyzer); 1244 } 1245 //where isSimpleReceiver(JCTree rec)1246 private boolean isSimpleReceiver(JCTree rec) { 1247 switch (rec.getTag()) { 1248 case IDENT: 1249 return true; 1250 case SELECT: 1251 return isSimpleReceiver(((JCFieldAccess)rec).selected); 1252 case TYPEAPPLY: 1253 case TYPEARRAY: 1254 return true; 1255 case ANNOTATED_TYPE: 1256 return isSimpleReceiver(((JCAnnotatedType)rec).underlyingType); 1257 case APPLY: 1258 return true; 1259 case NEWCLASS: 1260 JCNewClass nc = (JCNewClass) rec; 1261 return nc.encl == null && nc.def == null && !TreeInfo.isDiamond(nc); 1262 default: 1263 return false; 1264 } 1265 } reduce(ArgumentExpressionKind kind)1266 private ArgumentExpressionKind reduce(ArgumentExpressionKind kind) { 1267 return argumentKindAnalyzer.reduce(result, kind); 1268 } 1269 MethodAnalyzer<ArgumentExpressionKind> argumentKindAnalyzer = 1270 new MethodAnalyzer<ArgumentExpressionKind>() { 1271 @Override 1272 public ArgumentExpressionKind process(MethodSymbol ms) { 1273 return ArgumentExpressionKind.methodKind(ms, types); 1274 } 1275 @Override 1276 public ArgumentExpressionKind reduce(ArgumentExpressionKind kind1, 1277 ArgumentExpressionKind kind2) { 1278 switch (kind1) { 1279 case PRIMITIVE: return kind2; 1280 case NO_POLY: return kind2.isPoly() ? kind2 : kind1; 1281 case POLY: return kind1; 1282 default: 1283 Assert.error(); 1284 return null; 1285 } 1286 } 1287 @Override 1288 public boolean shouldStop(ArgumentExpressionKind result) { 1289 return result.isPoly(); 1290 } 1291 }; 1292 1293 @Override visitLiteral(JCLiteral tree)1294 public void visitLiteral(JCLiteral tree) { 1295 Type litType = attr.litType(tree.typetag); 1296 result = ArgumentExpressionKind.standaloneKind(litType, types); 1297 } 1298 1299 @Override skip(JCTree tree)1300 void skip(JCTree tree) { 1301 result = ArgumentExpressionKind.NO_POLY; 1302 } 1303 quicklyResolveMethod(Env<AttrContext> env, final JCMethodInvocation tree)1304 private Symbol quicklyResolveMethod(Env<AttrContext> env, final JCMethodInvocation tree) { 1305 final JCExpression rec = tree.meth.hasTag(SELECT) ? 1306 ((JCFieldAccess)tree.meth).selected : 1307 null; 1308 1309 if (rec != null && !isSimpleReceiver(rec)) { 1310 return null; 1311 } 1312 1313 Type site; 1314 1315 if (rec != null) { 1316 switch (rec.getTag()) { 1317 case APPLY: 1318 Symbol recSym = quicklyResolveMethod(env, (JCMethodInvocation) rec); 1319 if (recSym == null) 1320 return null; 1321 Symbol resolvedReturnType = 1322 analyzeCandidateMethods(recSym, syms.errSymbol, returnSymbolAnalyzer); 1323 if (resolvedReturnType == null) 1324 return null; 1325 site = resolvedReturnType.type; 1326 break; 1327 case NEWCLASS: 1328 JCNewClass nc = (JCNewClass) rec; 1329 site = attribSpeculative(nc.clazz, env, attr.unknownTypeExprInfo).type; 1330 break; 1331 default: 1332 site = attribSpeculative(rec, env, attr.unknownTypeExprInfo).type; 1333 break; 1334 } 1335 } else { 1336 site = env.enclClass.sym.type; 1337 } 1338 1339 while (site.hasTag(TYPEVAR)) { 1340 site = site.getUpperBound(); 1341 } 1342 1343 site = types.capture(site); 1344 1345 List<Type> args = rs.dummyArgs(tree.args.length()); 1346 Name name = TreeInfo.name(tree.meth); 1347 1348 Resolve.LookupHelper lh = rs.new LookupHelper(name, site, args, List.<Type>nil(), MethodResolutionPhase.VARARITY) { 1349 @Override 1350 Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) { 1351 return rec == null ? 1352 rs.findFun(env, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()) : 1353 rs.findMethod(env, site, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired(), false); 1354 } 1355 @Override 1356 Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) { 1357 return sym; 1358 } 1359 }; 1360 1361 return rs.lookupMethod(env, tree, site.tsym, rs.arityMethodCheck, lh); 1362 } 1363 //where: 1364 MethodAnalyzer<Symbol> returnSymbolAnalyzer = new MethodAnalyzer<Symbol>() { 1365 @Override 1366 public Symbol process(MethodSymbol ms) { 1367 ArgumentExpressionKind kind = ArgumentExpressionKind.methodKind(ms, types); 1368 if (kind == ArgumentExpressionKind.POLY || ms.getReturnType().hasTag(TYPEVAR)) 1369 return null; 1370 return ms.getReturnType().tsym; 1371 } 1372 @Override 1373 public Symbol reduce(Symbol s1, Symbol s2) { 1374 return s1 == syms.errSymbol ? s2 : s1 == s2 ? s1 : null; 1375 } 1376 @Override 1377 public boolean shouldStop(Symbol result) { 1378 return result == null; 1379 } 1380 }; 1381 1382 /** 1383 * Process the result of Resolve.lookupMethod. If sym is a method symbol, the result of 1384 * MethodAnalyzer.process is returned. If sym is an ambiguous symbol, all the candidate 1385 * methods are inspected one by one, using MethodAnalyzer.process. The outcomes are 1386 * reduced using MethodAnalyzer.reduce (using defaultValue as the first value over which 1387 * the reduction runs). MethodAnalyzer.shouldStop can be used to stop the inspection early. 1388 */ analyzeCandidateMethods(Symbol sym, E defaultValue, MethodAnalyzer<E> analyzer)1389 <E> E analyzeCandidateMethods(Symbol sym, E defaultValue, MethodAnalyzer<E> analyzer) { 1390 switch (sym.kind) { 1391 case Kinds.MTH: 1392 return analyzer.process((MethodSymbol) sym); 1393 case Kinds.AMBIGUOUS: 1394 Resolve.AmbiguityError err = (Resolve.AmbiguityError)sym.baseSymbol(); 1395 E res = defaultValue; 1396 for (Symbol s : err.ambiguousSyms) { 1397 if (s.kind == Kinds.MTH) { 1398 res = analyzer.reduce(res, analyzer.process((MethodSymbol) s)); 1399 if (analyzer.shouldStop(res)) 1400 return res; 1401 } 1402 } 1403 return res; 1404 default: 1405 return defaultValue; 1406 } 1407 } 1408 } 1409 1410 /** Analyzer for methods - used by analyzeCandidateMethods. */ 1411 interface MethodAnalyzer<E> { process(MethodSymbol ms)1412 E process(MethodSymbol ms); reduce(E e1, E e2)1413 E reduce(E e1, E e2); shouldStop(E result)1414 boolean shouldStop(E result); 1415 } 1416 1417 //where 1418 private EnumSet<JCTree.Tag> deferredCheckerTags = 1419 EnumSet.of(LAMBDA, REFERENCE, PARENS, TYPECAST, 1420 CONDEXPR, NEWCLASS, APPLY, LITERAL); 1421 } 1422