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