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