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