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