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