DeferredAttr.java revision 2819:b93a15ac3bde
1193326Sed/* 2193326Sed * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. 3193326Sed * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4193326Sed * 5193326Sed * This code is free software; you can redistribute it and/or modify it 6193326Sed * under the terms of the GNU General Public License version 2 only, as 7193326Sed * published by the Free Software Foundation. Oracle designates this 8193326Sed * particular file as subject to the "Classpath" exception as provided 9193326Sed * by Oracle in the LICENSE file that accompanied this code. 10193326Sed * 11193326Sed * This code is distributed in the hope that it will be useful, but WITHOUT 12193326Sed * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13193326Sed * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14193326Sed * version 2 for more details (a copy is included in the LICENSE file that 15193326Sed * accompanied this code). 16249423Sdim * 17249423Sdim * You should have received a copy of the GNU General Public License version 18249423Sdim * 2 along with this work; if not, write to the Free Software Foundation, 19193326Sed * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20193326Sed * 21249423Sdim * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22226633Sdim * or visit www.oracle.com if you need additional information or have any 23249423Sdim * questions. 24193326Sed */ 25193326Sed 26226633Sdimpackage com.sun.tools.javac.comp; 27226633Sdim 28226633Sdimimport com.sun.source.tree.LambdaExpressionTree.BodyKind; 29226633Sdimimport com.sun.tools.javac.code.*; 30226633Sdimimport com.sun.tools.javac.comp.Resolve.ResolveError; 31226633Sdimimport com.sun.tools.javac.resources.CompilerProperties; 32226633Sdimimport com.sun.tools.javac.resources.CompilerProperties.Fragments; 33226633Sdimimport com.sun.tools.javac.tree.*; 34226633Sdimimport com.sun.tools.javac.util.*; 35226633Sdimimport com.sun.tools.javac.util.DefinedBy.Api; 36226633Sdimimport com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; 37226633Sdimimport com.sun.tools.javac.code.Symbol.*; 38226633Sdimimport com.sun.tools.javac.code.Type.*; 39226633Sdimimport com.sun.tools.javac.comp.Attr.ResultInfo; 40226633Sdimimport com.sun.tools.javac.comp.Infer.InferenceContext; 41226633Sdimimport com.sun.tools.javac.comp.Resolve.MethodResolutionPhase; 42226633Sdimimport com.sun.tools.javac.tree.JCTree.*; 43226633Sdimimport com.sun.tools.javac.util.JCDiagnostic.DiagnosticType; 44226633Sdimimport com.sun.tools.javac.util.Log.DeferredDiagnosticHandler; 45243830Sdim 46243830Sdimimport java.util.ArrayList; 47243830Sdimimport java.util.Collections; 48243830Sdimimport java.util.EnumMap; 49243830Sdimimport java.util.EnumSet; 50243830Sdimimport java.util.LinkedHashMap; 51243830Sdimimport java.util.LinkedHashSet; 52243830Sdimimport java.util.Map; 53243830Sdimimport java.util.Set; 54243830Sdimimport java.util.WeakHashMap; 55243830Sdimimport java.util.function.Function; 56243830Sdim 57243830Sdimimport static com.sun.tools.javac.code.TypeTag.*; 58243830Sdimimport static com.sun.tools.javac.tree.JCTree.Tag.*; 59243830Sdimimport static com.sun.tools.javac.code.Kinds.*; 60243830Sdimimport static com.sun.tools.javac.code.Kinds.Kind.*; 61243830Sdim 62243830Sdim/** 63243830Sdim * This is an helper class that is used to perform deferred type-analysis. 64243830Sdim * Each time a poly expression occurs in argument position, javac attributes it 65243830Sdim * with a temporary 'deferred type' that is checked (possibly multiple times) 66243830Sdim * against an expected formal type. 67243830Sdim * 68243830Sdim * <p><b>This is NOT part of any supported API. 69243830Sdim * If you write code that depends on this, you do so at your own risk. 70243830Sdim * This code and its internal interfaces are subject to change or 71243830Sdim * deletion without notice.</b> 72243830Sdim */ 73243830Sdimpublic class DeferredAttr extends JCTree.Visitor { 74243830Sdim protected static final Context.Key<DeferredAttr> deferredAttrKey = new Context.Key<>(); 75193326Sed 76193326Sed final Attr attr; 77243830Sdim final Check chk; 78243830Sdim final JCDiagnostic.Factory diags; 79193326Sed final Enter enter; 80226633Sdim final Infer infer; 81243830Sdim final Resolve rs; 82243830Sdim final Log log; 83243830Sdim final Symtab syms; 84243830Sdim final TreeMaker make; 85193326Sed final Types types; 86193326Sed final Flow flow; 87193326Sed final Names names; 88193326Sed final TypeEnvs typeEnvs; 89193326Sed 90193326Sed public static DeferredAttr instance(Context context) { 91193326Sed DeferredAttr instance = context.get(deferredAttrKey); 92193326Sed if (instance == null) 93193326Sed instance = new DeferredAttr(context); 94198092Srdivacky return instance; 95193326Sed } 96193326Sed 97193326Sed protected DeferredAttr(Context context) { 98193326Sed context.put(deferredAttrKey, this); 99193326Sed attr = Attr.instance(context); 100193326Sed chk = Check.instance(context); 101193326Sed diags = JCDiagnostic.Factory.instance(context); 102193326Sed enter = Enter.instance(context); 103193326Sed infer = Infer.instance(context); 104218893Sdim rs = Resolve.instance(context); 105243830Sdim log = Log.instance(context); 106243830Sdim syms = Symtab.instance(context); 107193326Sed make = TreeMaker.instance(context); 108193326Sed types = Types.instance(context); 109194179Sed flow = Flow.instance(context); 110218893Sdim names = Names.instance(context); 111243830Sdim stuckTree = make.Ident(names.empty).setType(Type.stuckType); 112243830Sdim typeEnvs = TypeEnvs.instance(context); 113194179Sed emptyDeferredAttrContext = 114194179Sed new DeferredAttrContext(AttrMode.CHECK, null, MethodResolutionPhase.BOX, infer.emptyContext, null, null) { 115193326Sed @Override 116193326Sed void addDeferredAttrNode(DeferredType dt, ResultInfo ri, DeferredStuckPolicy deferredStuckPolicy) { 117193326Sed Assert.error("Empty deferred context!"); 118193326Sed } 119193326Sed @Override 120193326Sed void complete() { 121193326Sed Assert.error("Empty deferred context!"); 122193326Sed } 123193326Sed 124193326Sed @Override 125193326Sed public String toString() { 126193326Sed return "Empty deferred context!"; 127193326Sed } 128193326Sed }; 129193326Sed } 130193326Sed 131193326Sed /** shared tree for stuck expressions */ 132249423Sdim final JCTree stuckTree; 133218893Sdim 134243830Sdim /** 135249423Sdim * This type represents a deferred type. A deferred type starts off with 136193326Sed * no information on the underlying expression type. Such info needs to be 137193326Sed * discovered through type-checking the deferred type against a target-type. 138193326Sed * Every deferred type keeps a pointer to the AST node from which it originated. 139198092Srdivacky */ 140193326Sed public class DeferredType extends Type { 141193326Sed 142193326Sed public JCExpression tree; 143249423Sdim Env<AttrContext> env; 144193326Sed AttrMode mode; 145193326Sed SpeculativeCache speculativeCache; 146193326Sed 147193326Sed DeferredType(JCExpression tree, Env<AttrContext> env) { 148193326Sed super(null, TypeMetadata.empty); 149193326Sed this.tree = tree; 150193326Sed this.env = attr.copyEnv(env); 151193326Sed this.speculativeCache = new SpeculativeCache(); 152193326Sed } 153193326Sed 154193326Sed @Override 155193326Sed public DeferredType clone(TypeMetadata md) { 156198092Srdivacky throw new AssertionError("Cannot add metadata to a deferred type"); 157193326Sed } 158218893Sdim 159243830Sdim @Override 160243830Sdim public TypeTag getTag() { 161193326Sed return DEFERRED; 162193326Sed } 163193326Sed 164193326Sed @Override @DefinedBy(Api.LANGUAGE_MODEL) 165193326Sed public String toString() { 166193326Sed return "DeferredType"; 167193326Sed } 168193326Sed 169193326Sed /** 170193326Sed * A speculative cache is used to keep track of all overload resolution rounds 171193326Sed * that triggered speculative attribution on a given deferred type. Each entry 172193326Sed * stores a pointer to the speculative tree and the resolution phase in which the entry 173193326Sed * has been added. 174193326Sed */ 175193326Sed class SpeculativeCache { 176193326Sed 177193326Sed private Map<Symbol, List<Entry>> cache = new WeakHashMap<>(); 178198092Srdivacky 179193326Sed class Entry { 180193326Sed JCTree speculativeTree; 181218893Sdim ResultInfo resultInfo; 182243830Sdim 183243830Sdim public Entry(JCTree speculativeTree, ResultInfo resultInfo) { 184193326Sed this.speculativeTree = speculativeTree; 185193326Sed this.resultInfo = resultInfo; 186193326Sed } 187193326Sed 188198092Srdivacky boolean matches(MethodResolutionPhase phase) { 189193326Sed return resultInfo.checkContext.deferredAttrContext().phase == phase; 190193326Sed } 191193326Sed } 192218893Sdim 193243830Sdim /** 194243830Sdim * Retrieve a speculative cache entry corresponding to given symbol 195243830Sdim * and resolution phase 196193326Sed */ 197193326Sed Entry get(Symbol msym, MethodResolutionPhase phase) { 198218893Sdim List<Entry> entries = cache.get(msym); 199208600Srdivacky if (entries == null) return null; 200243830Sdim for (Entry e : entries) { 201249423Sdim if (e.matches(phase)) return e; 202243830Sdim } 203243830Sdim return null; 204243830Sdim } 205193326Sed 206243830Sdim /** 207243830Sdim * Stores a speculative cache entry corresponding to given symbol 208243830Sdim * and resolution phase 209193326Sed */ 210193326Sed void put(JCTree speculativeTree, ResultInfo resultInfo) { 211198092Srdivacky Symbol msym = resultInfo.checkContext.deferredAttrContext().msym; 212193326Sed List<Entry> entries = cache.get(msym); 213193326Sed if (entries == null) { 214193326Sed entries = List.nil(); 215193326Sed } 216218893Sdim cache.put(msym, entries.prepend(new Entry(speculativeTree, resultInfo))); 217234353Sdim } 218234353Sdim } 219218893Sdim 220226633Sdim /** 221234353Sdim * Get the type that has been computed during a speculative attribution round 222234353Sdim */ 223234353Sdim Type speculativeType(Symbol msym, MethodResolutionPhase phase) { 224198092Srdivacky SpeculativeCache.Entry e = speculativeCache.get(msym, phase); 225193326Sed return e != null ? e.speculativeTree.type : Type.noType; 226193326Sed } 227193326Sed 228249423Sdim /** 229218893Sdim * Check a deferred type against a potential target-type. Depending on 230243830Sdim * the current attribution mode, a normal vs. speculative attribution 231249423Sdim * round is performed on the underlying AST node. There can be only one 232218893Sdim * speculative round for a given target method symbol; moreover, a normal 233193326Sed * attribution round must follow one or more speculative rounds. 234218893Sdim */ 235212904Sdim Type check(ResultInfo resultInfo) { 236218893Sdim DeferredStuckPolicy deferredStuckPolicy; 237249423Sdim if (resultInfo.pt.hasTag(NONE) || resultInfo.pt.isErroneous()) { 238193326Sed deferredStuckPolicy = dummyStuckPolicy; 239193326Sed } else if (resultInfo.checkContext.deferredAttrContext().mode == AttrMode.SPECULATIVE || 240193326Sed resultInfo.checkContext.deferredAttrContext().insideOverloadPhase()) { 241193326Sed deferredStuckPolicy = new OverloadStuckPolicy(resultInfo, this); 242193326Sed } else { 243218893Sdim deferredStuckPolicy = new CheckStuckPolicy(resultInfo, this); 244243830Sdim } 245243830Sdim return check(resultInfo, deferredStuckPolicy, basicCompleter); 246243830Sdim } 247218893Sdim 248193326Sed private Type check(ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy, 249234353Sdim DeferredTypeCompleter deferredTypeCompleter) { 250234353Sdim DeferredAttrContext deferredAttrContext = 251234353Sdim resultInfo.checkContext.deferredAttrContext(); 252234353Sdim Assert.check(deferredAttrContext != emptyDeferredAttrContext); 253218893Sdim if (deferredStuckPolicy.isStuck()) { 254243830Sdim deferredAttrContext.addDeferredAttrNode(this, resultInfo, deferredStuckPolicy); 255243830Sdim return Type.noType; 256218893Sdim } else { 257218893Sdim try { 258234353Sdim return deferredTypeCompleter.complete(this, resultInfo, deferredAttrContext); 259234353Sdim } finally { 260234353Sdim mode = deferredAttrContext.mode; 261234353Sdim } 262234353Sdim } 263249423Sdim } 264234353Sdim } 265234353Sdim 266234353Sdim /** 267243830Sdim * A completer for deferred types. Defines an entry point for type-checking 268243830Sdim * a deferred type. 269243830Sdim */ 270243830Sdim interface DeferredTypeCompleter { 271234353Sdim /** 272243830Sdim * Entry point for type-checking a deferred type. Depending on the 273243830Sdim * circumstances, type-checking could amount to full attribution 274243830Sdim * or partial structural check (aka potential applicability). 275234353Sdim */ 276234353Sdim Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext); 277234353Sdim } 278234353Sdim 279234353Sdim 280243830Sdim /** 281243830Sdim * A basic completer for deferred types. This completer type-checks a deferred type 282249423Sdim * using attribution; depending on the attribution mode, this could be either standard 283243830Sdim * or speculative attribution. 284218893Sdim */ 285218893Sdim DeferredTypeCompleter basicCompleter = new DeferredTypeCompleter() { 286218893Sdim public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) { 287239462Sdim switch (deferredAttrContext.mode) { 288239462Sdim case SPECULATIVE: 289239462Sdim //Note: if a symbol is imported twice we might do two identical 290239462Sdim //speculative rounds... 291239462Sdim Assert.check(dt.mode == null || dt.mode == AttrMode.SPECULATIVE); 292239462Sdim JCTree speculativeTree = attribSpeculative(dt.tree, dt.env, resultInfo); 293239462Sdim dt.speculativeCache.put(speculativeTree, resultInfo); 294239462Sdim return speculativeTree.type; 295239462Sdim case CHECK: 296239462Sdim Assert.check(dt.mode != null); 297239462Sdim return attr.attribTree(dt.tree, dt.env, resultInfo); 298239462Sdim } 299239462Sdim Assert.error(); 300239462Sdim return null; 301239462Sdim } 302239462Sdim }; 303239462Sdim 304239462Sdim DeferredTypeCompleter dummyCompleter = new DeferredTypeCompleter() { 305239462Sdim public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) { 306239462Sdim Assert.check(deferredAttrContext.mode == AttrMode.CHECK); 307239462Sdim return dt.tree.type = Type.stuckType; 308239462Sdim } 309239462Sdim }; 310239462Sdim 311239462Sdim /** 312239462Sdim * Policy for detecting stuck expressions. Different criteria might cause 313239462Sdim * an expression to be judged as stuck, depending on whether the check 314239462Sdim * is performed during overload resolution or after most specific. 315239462Sdim */ 316239462Sdim interface DeferredStuckPolicy { 317239462Sdim /** 318239462Sdim * Has the policy detected that a given expression should be considered stuck? 319239462Sdim */ 320218893Sdim boolean isStuck(); 321218893Sdim /** 322218893Sdim * Get the set of inference variables a given expression depends upon. 323218893Sdim */ 324234353Sdim Set<Type> stuckVars(); 325234353Sdim /** 326218893Sdim * Get the set of inference variables which might get new constraints 327226633Sdim * if a given expression is being type-checked. 328226633Sdim */ 329218893Sdim Set<Type> depVars(); 330218893Sdim } 331218893Sdim 332218893Sdim /** 333234353Sdim * Basic stuck policy; an expression is never considered to be stuck. 334234353Sdim */ 335239462Sdim DeferredStuckPolicy dummyStuckPolicy = new DeferredStuckPolicy() { 336193326Sed @Override 337193326Sed public boolean isStuck() { 338218893Sdim return false; 339226633Sdim } 340226633Sdim @Override 341218893Sdim public Set<Type> stuckVars() { 342226633Sdim return Collections.emptySet(); 343226633Sdim } 344218893Sdim @Override 345226633Sdim public Set<Type> depVars() { 346234353Sdim return Collections.emptySet(); 347234353Sdim } 348234353Sdim }; 349234353Sdim 350234353Sdim /** 351226633Sdim * The 'mode' in which the deferred type is to be type-checked 352226633Sdim */ 353226633Sdim public enum AttrMode { 354226633Sdim /** 355234353Sdim * A speculative type-checking round is used during overload resolution 356234353Sdim * mainly to generate constraints on inference variables. Side-effects 357234353Sdim * arising from type-checking the expression associated with the deferred 358234353Sdim * type are reversed after the speculative round finishes. This means the 359239462Sdim * expression tree will be left in a blank state. 360234353Sdim */ 361234353Sdim SPECULATIVE, 362218893Sdim /** 363218893Sdim * This is the plain type-checking mode. Produces side-effects on the underlying AST node 364218893Sdim */ 365234353Sdim CHECK 366218893Sdim } 367234353Sdim 368234353Sdim /** 369234353Sdim * Routine that performs speculative type-checking; the input AST node is 370212904Sdim * cloned (to avoid side-effects cause by Attr) and compiler state is 371212904Sdim * restored after type-checking. All diagnostics (but critical ones) are 372226633Sdim * disabled during speculative type-checking. 373226633Sdim */ 374226633Sdim JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) { 375193326Sed return attribSpeculative(tree, env, resultInfo, new TreeCopier<>(make), 376193326Sed (newTree)->new DeferredAttrDiagHandler(log, newTree)); 377193326Sed } 378198092Srdivacky 379193326Sed <Z> JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo, TreeCopier<Z> deferredCopier, 380193326Sed Function<JCTree, DeferredDiagnosticHandler> diagHandlerCreator) { 381193326Sed final JCTree newTree = deferredCopier.copy(tree); 382193326Sed Env<AttrContext> speculativeEnv = env.dup(newTree, env.info.dup(env.info.scope.dupUnshared(env.info.scope.owner))); 383193326Sed speculativeEnv.info.isSpeculative = true; 384193326Sed Log.DeferredDiagnosticHandler deferredDiagnosticHandler = diagHandlerCreator.apply(newTree); 385193326Sed try { 386193326Sed attr.attribTree(newTree, speculativeEnv, resultInfo); 387193326Sed unenterScanner.scan(newTree); 388193326Sed return newTree; 389193326Sed } finally { 390198092Srdivacky unenterScanner.scan(newTree); 391193326Sed log.popDiagnosticHandler(deferredDiagnosticHandler); 392193326Sed } 393198092Srdivacky } 394193326Sed //where 395193326Sed protected UnenterScanner unenterScanner = new UnenterScanner(); 396198092Srdivacky 397193326Sed class UnenterScanner extends TreeScanner { 398193326Sed @Override 399193326Sed public void visitClassDef(JCClassDecl tree) { 400193326Sed ClassSymbol csym = tree.sym; 401193326Sed //if something went wrong during method applicability check 402243830Sdim //it is possible that nested expressions inside argument expression 403243830Sdim //are left unchecked - in such cases there's nothing to clean up. 404243830Sdim if (csym == null) return; 405243830Sdim typeEnvs.remove(csym); 406193326Sed chk.compiled.remove(csym.flatname); 407193326Sed syms.classes.remove(csym.flatname); 408193326Sed super.visitClassDef(tree); 409193326Sed } 410193326Sed } 411193326Sed 412193326Sed static class DeferredAttrDiagHandler extends Log.DeferredDiagnosticHandler { 413193326Sed 414193326Sed static class PosScanner extends TreeScanner { 415193326Sed DiagnosticPosition pos; 416234353Sdim boolean found = false; 417234353Sdim 418234353Sdim PosScanner(DiagnosticPosition pos) { 419234353Sdim this.pos = pos; 420198092Srdivacky } 421193326Sed 422193326Sed @Override 423198092Srdivacky public void scan(JCTree tree) { 424193326Sed if (tree != null && 425193326Sed tree.pos() == pos) { 426198092Srdivacky found = true; 427193326Sed } 428193326Sed super.scan(tree); 429193326Sed } 430193326Sed } 431193326Sed 432193326Sed DeferredAttrDiagHandler(Log log, JCTree newTree) { 433193326Sed super(log, new Filter<JCDiagnostic>() { 434193326Sed public boolean accepts(JCDiagnostic d) { 435193326Sed PosScanner posScanner = new PosScanner(d.getDiagnosticPosition()); 436193326Sed posScanner.scan(newTree); 437193326Sed return posScanner.found; 438193326Sed } 439193326Sed }); 440193326Sed } 441193326Sed } 442193326Sed 443193326Sed /** 444193326Sed * A deferred context is created on each method check. A deferred context is 445193326Sed * used to keep track of information associated with the method check, such as 446193326Sed * the symbol of the method being checked, the overload resolution phase, 447193326Sed * the kind of attribution mode to be applied to deferred types and so forth. 448198092Srdivacky * As deferred types are processed (by the method check routine) stuck AST nodes 449193326Sed * are added (as new deferred attribution nodes) to this context. The complete() 450193326Sed * routine makes sure that all pending nodes are properly processed, by 451193326Sed * progressively instantiating all inference variables on which one or more 452193326Sed * deferred attribution node is stuck. 453193326Sed */ 454243830Sdim class DeferredAttrContext { 455243830Sdim 456243830Sdim /** attribution mode */ 457243830Sdim final AttrMode mode; 458198092Srdivacky 459193326Sed /** symbol of the method being checked */ 460193326Sed final Symbol msym; 461193326Sed 462193326Sed /** method resolution step */ 463249423Sdim final Resolve.MethodResolutionPhase phase; 464198092Srdivacky 465243830Sdim /** inference context */ 466193326Sed final InferenceContext inferenceContext; 467193326Sed 468234353Sdim /** parent deferred context */ 469193326Sed final DeferredAttrContext parent; 470193326Sed 471193326Sed /** Warner object to report warnings */ 472193326Sed final Warner warn; 473193326Sed 474198092Srdivacky /** list of deferred attribution nodes to be processed */ 475193326Sed ArrayList<DeferredAttrNode> deferredAttrNodes = new ArrayList<>(); 476198092Srdivacky 477193326Sed DeferredAttrContext(AttrMode mode, Symbol msym, MethodResolutionPhase phase, 478193326Sed InferenceContext inferenceContext, DeferredAttrContext parent, Warner warn) { 479193326Sed this.mode = mode; 480193326Sed this.msym = msym; 481193326Sed this.phase = phase; 482193326Sed this.parent = parent; 483193326Sed this.warn = warn; 484193326Sed this.inferenceContext = inferenceContext; 485193326Sed } 486249423Sdim 487243830Sdim /** 488226633Sdim * Adds a node to the list of deferred attribution nodes - used by Resolve.rawCheckArgumentsApplicable 489193326Sed * Nodes added this way act as 'roots' for the out-of-order method checking process. 490193326Sed */ 491193326Sed void addDeferredAttrNode(final DeferredType dt, ResultInfo resultInfo, 492193326Sed DeferredStuckPolicy deferredStuckPolicy) { 493193326Sed deferredAttrNodes.add(new DeferredAttrNode(dt, resultInfo, deferredStuckPolicy)); 494193326Sed } 495198092Srdivacky 496193326Sed /** 497193326Sed * Incrementally process all nodes, by skipping 'stuck' nodes and attributing 498193326Sed * 'unstuck' ones. If at any point no progress can be made (no 'unstuck' nodes) 499193326Sed * some inference variable might get eagerly instantiated so that all nodes 500193326Sed * can be type-checked. 501193326Sed */ 502193326Sed void complete() { 503193326Sed while (!deferredAttrNodes.isEmpty()) { 504193326Sed Map<Type, Set<Type>> depVarsMap = new LinkedHashMap<>(); 505243830Sdim List<Type> stuckVars = List.nil(); 506193326Sed boolean progress = false; 507193326Sed //scan a defensive copy of the node list - this is because a deferred 508193326Sed //attribution round can add new nodes to the list 509193326Sed for (DeferredAttrNode deferredAttrNode : List.from(deferredAttrNodes)) { 510193326Sed if (!deferredAttrNode.process(this)) { 511193326Sed List<Type> restStuckVars = 512193326Sed List.from(deferredAttrNode.deferredStuckPolicy.stuckVars()) 513193326Sed .intersect(inferenceContext.restvars()); 514198092Srdivacky stuckVars = stuckVars.prependList(restStuckVars); 515193326Sed //update dependency map 516193326Sed for (Type t : List.from(deferredAttrNode.deferredStuckPolicy.depVars()) 517193326Sed .intersect(inferenceContext.restvars())) { 518198092Srdivacky Set<Type> prevDeps = depVarsMap.get(t); 519193326Sed if (prevDeps == null) { 520193326Sed prevDeps = new LinkedHashSet<>(); 521193326Sed depVarsMap.put(t, prevDeps); 522193326Sed } 523193326Sed prevDeps.addAll(restStuckVars); 524193326Sed } 525193326Sed } else { 526193326Sed deferredAttrNodes.remove(deferredAttrNode); 527193326Sed progress = true; 528193326Sed } 529193326Sed } 530193326Sed if (!progress) { 531193326Sed if (insideOverloadPhase()) { 532193326Sed for (DeferredAttrNode deferredNode: deferredAttrNodes) { 533193326Sed deferredNode.dt.tree.type = Type.noType; 534193326Sed } 535193326Sed return; 536193326Sed } 537193326Sed //remove all variables that have already been instantiated 538193326Sed //from the list of stuck variables 539198092Srdivacky try { 540193326Sed inferenceContext.solveAny(stuckVars, depVarsMap, warn); 541193326Sed inferenceContext.notifyChange(); 542193326Sed } catch (Infer.GraphStrategy.NodeNotFoundException ex) { 543193326Sed //this means that we are in speculative mode and the 544193326Sed //set of contraints are too tight for progess to be made. 545193326Sed //Just leave the remaining expressions as stuck. 546193326Sed break; 547193326Sed } 548193326Sed } 549193326Sed } 550218893Sdim } 551234353Sdim 552202879Srdivacky private boolean insideOverloadPhase() { 553199990Srdivacky DeferredAttrContext dac = this; 554193326Sed if (dac == emptyDeferredAttrContext) { 555198092Srdivacky return false; 556198092Srdivacky } 557198092Srdivacky if (dac.mode == AttrMode.SPECULATIVE) { 558198092Srdivacky return true; 559198092Srdivacky } 560199990Srdivacky return dac.parent.insideOverloadPhase(); 561198092Srdivacky } 562199990Srdivacky } 563218893Sdim 564218893Sdim /** 565218893Sdim * Class representing a deferred attribution node. It keeps track of 566218893Sdim * a deferred type, along with the expected target type information. 567199990Srdivacky */ 568199990Srdivacky class DeferredAttrNode { 569218893Sdim 570218893Sdim /** underlying deferred type */ 571218893Sdim DeferredType dt; 572218893Sdim 573198092Srdivacky /** underlying target type information */ 574199990Srdivacky ResultInfo resultInfo; 575198092Srdivacky 576199990Srdivacky /** stuck policy associated with this node */ 577218893Sdim DeferredStuckPolicy deferredStuckPolicy; 578218893Sdim 579218893Sdim DeferredAttrNode(DeferredType dt, ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy) { 580218893Sdim this.dt = dt; 581218893Sdim this.resultInfo = resultInfo; 582199990Srdivacky this.deferredStuckPolicy = deferredStuckPolicy; 583198092Srdivacky } 584199990Srdivacky 585218893Sdim /** 586218893Sdim * Process a deferred attribution node. 587218893Sdim * Invariant: a stuck node cannot be processed. 588218893Sdim */ 589218893Sdim @SuppressWarnings("fallthrough") 590199990Srdivacky boolean process(final DeferredAttrContext deferredAttrContext) { 591198092Srdivacky switch (deferredAttrContext.mode) { 592198092Srdivacky case SPECULATIVE: 593198092Srdivacky if (deferredStuckPolicy.isStuck()) { 594198092Srdivacky dt.check(resultInfo, dummyStuckPolicy, new StructuralStuckChecker()); 595193326Sed return true; 596193326Sed } else { 597193326Sed Assert.error("Cannot get here"); 598193326Sed } 599193326Sed case CHECK: 600193326Sed if (deferredStuckPolicy.isStuck()) { 601243830Sdim //stuck expression - see if we can propagate 602193326Sed if (deferredAttrContext.parent != emptyDeferredAttrContext && 603193326Sed Type.containsAny(deferredAttrContext.parent.inferenceContext.inferencevars, 604193326Sed List.from(deferredStuckPolicy.stuckVars()))) { 605193326Sed deferredAttrContext.parent.addDeferredAttrNode(dt, 606234353Sdim resultInfo.dup(new Check.NestedCheckContext(resultInfo.checkContext) { 607193326Sed @Override 608193326Sed public InferenceContext inferenceContext() { 609198092Srdivacky return deferredAttrContext.parent.inferenceContext; 610193326Sed } 611249423Sdim @Override 612234353Sdim public DeferredAttrContext deferredAttrContext() { 613234353Sdim return deferredAttrContext.parent; 614234353Sdim } 615234353Sdim }), deferredStuckPolicy); 616234353Sdim dt.tree.type = Type.stuckType; 617234353Sdim return true; 618234353Sdim } else { 619243830Sdim return false; 620193326Sed } 621193326Sed } else { 622226633Sdim Assert.check(!deferredAttrContext.insideOverloadPhase(), 623193326Sed "attribution shouldn't be happening here"); 624193326Sed ResultInfo instResultInfo = 625193326Sed resultInfo.dup(deferredAttrContext.inferenceContext.asInstType(resultInfo.pt)); 626193326Sed dt.check(instResultInfo, dummyStuckPolicy, basicCompleter); 627193326Sed return true; 628193326Sed } 629193326Sed default: 630193326Sed throw new AssertionError("Bad mode"); 631198092Srdivacky } 632193326Sed } 633193326Sed 634193326Sed /** 635193326Sed * Structural checker for stuck expressions 636198092Srdivacky */ 637193326Sed class StructuralStuckChecker extends TreeScanner implements DeferredTypeCompleter { 638249423Sdim 639193326Sed ResultInfo resultInfo; 640193326Sed InferenceContext inferenceContext; 641193326Sed Env<AttrContext> env; 642193326Sed 643234353Sdim public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) { 644193326Sed this.resultInfo = resultInfo; 645193326Sed this.inferenceContext = deferredAttrContext.inferenceContext; 646193326Sed this.env = dt.env; 647193326Sed dt.tree.accept(this); 648193326Sed dt.speculativeCache.put(stuckTree, resultInfo); 649234353Sdim return Type.noType; 650193326Sed } 651234353Sdim 652193326Sed @Override 653234353Sdim public void visitLambda(JCLambda tree) { 654234353Sdim Check.CheckContext checkContext = resultInfo.checkContext; 655243830Sdim Type pt = resultInfo.pt; 656234353Sdim if (!inferenceContext.inferencevars.contains(pt)) { 657234353Sdim //must be a functional descriptor 658234353Sdim Type descriptorType = null; 659234353Sdim try { 660234353Sdim descriptorType = types.findDescriptorType(pt); 661193326Sed } catch (Types.FunctionDescriptorLookupError ex) { 662198092Srdivacky checkContext.report(null, ex.getDiagnostic()); 663226633Sdim } 664193326Sed 665193326Sed if (descriptorType.getParameterTypes().length() != tree.params.length()) { 666193326Sed checkContext.report(tree, 667193326Sed diags.fragment("incompatible.arg.types.in.lambda")); 668193326Sed } 669193326Sed 670193326Sed Type currentReturnType = descriptorType.getReturnType(); 671193326Sed boolean returnTypeIsVoid = currentReturnType.hasTag(VOID); 672193326Sed if (tree.getBodyKind() == BodyKind.EXPRESSION) { 673193326Sed boolean isExpressionCompatible = !returnTypeIsVoid || 674193326Sed TreeInfo.isExpressionStatement((JCExpression)tree.getBody()); 675193326Sed if (!isExpressionCompatible) { 676198092Srdivacky resultInfo.checkContext.report(tree.pos(), 677234353Sdim diags.fragment("incompatible.ret.type.in.lambda", 678193326Sed diags.fragment("missing.ret.val", currentReturnType))); 679193326Sed } 680193326Sed } else { 681193326Sed LambdaBodyStructChecker lambdaBodyChecker = 682193326Sed new LambdaBodyStructChecker(); 683193326Sed 684193326Sed tree.body.accept(lambdaBodyChecker); 685193326Sed boolean isVoidCompatible = lambdaBodyChecker.isVoidCompatible; 686198092Srdivacky 687193326Sed if (returnTypeIsVoid) { 688193326Sed if (!isVoidCompatible) { 689193326Sed resultInfo.checkContext.report(tree.pos(), 690193326Sed diags.fragment("unexpected.ret.val")); 691193326Sed } 692193326Sed } else { 693193326Sed boolean isValueCompatible = lambdaBodyChecker.isPotentiallyValueCompatible 694193326Sed && !canLambdaBodyCompleteNormally(tree); 695193326Sed if (!isValueCompatible && !isVoidCompatible) { 696193326Sed log.error(tree.body.pos(), 697249423Sdim "lambda.body.neither.value.nor.void.compatible"); 698193326Sed } 699226633Sdim 700193326Sed if (!isValueCompatible) { 701193326Sed resultInfo.checkContext.report(tree.pos(), 702193326Sed diags.fragment("incompatible.ret.type.in.lambda", 703193326Sed diags.fragment("missing.ret.val", currentReturnType))); 704193326Sed } 705198092Srdivacky } 706193326Sed } 707193326Sed } 708198092Srdivacky } 709193326Sed 710193326Sed boolean canLambdaBodyCompleteNormally(JCLambda tree) { 711193326Sed JCLambda newTree = new TreeCopier<>(make).copy(tree); 712193326Sed /* attr.lambdaEnv will create a meaningful env for the 713193326Sed * lambda expression. This is specially useful when the 714198092Srdivacky * lambda is used as the init of a field. But we need to 715193326Sed * remove any added symbol. 716193326Sed */ 717249423Sdim Env<AttrContext> localEnv = attr.lambdaEnv(newTree, env); 718193326Sed try { 719193326Sed List<JCVariableDecl> tmpParams = newTree.params; 720193326Sed while (tmpParams.nonEmpty()) { 721193326Sed tmpParams.head.vartype = make.at(tmpParams.head).Type(syms.errType); 722193326Sed tmpParams = tmpParams.tail; 723193326Sed } 724198092Srdivacky 725193326Sed attr.attribStats(newTree.params, localEnv); 726193326Sed 727249423Sdim /* set pt to Type.noType to avoid generating any bound 728193326Sed * which may happen if lambda's return type is an 729226633Sdim * inference variable 730193326Sed */ 731193326Sed Attr.ResultInfo bodyResultInfo = attr.new ResultInfo(KindSelector.VAL, Type.noType); 732193326Sed localEnv.info.returnResult = bodyResultInfo; 733198092Srdivacky 734193326Sed // discard any log output 735193326Sed Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log); 736193326Sed try { 737193326Sed JCBlock body = (JCBlock)newTree.body; 738193326Sed /* we need to attribute the lambda body before 739193326Sed * doing the aliveness analysis. This is because 740193326Sed * constant folding occurs during attribution 741193326Sed * and the reachability of some statements depends 742193326Sed * on constant values, for example: 743193326Sed * 744193326Sed * while (true) {...} 745193326Sed */ 746193326Sed attr.attribStats(body.stats, localEnv); 747193326Sed 748193326Sed attr.preFlow(newTree); 749193326Sed /* make an aliveness / reachability analysis of the lambda 750198092Srdivacky * to determine if it can complete normally 751193326Sed */ 752193326Sed flow.analyzeLambda(localEnv, newTree, make, true); 753193326Sed } finally { 754193326Sed log.popDiagnosticHandler(diagHandler); 755193326Sed } 756193326Sed return newTree.canCompleteNormally; 757193326Sed } finally { 758243830Sdim JCBlock body = (JCBlock)newTree.body; 759243830Sdim unenterScanner.scan(body.stats); 760243830Sdim localEnv.info.scope.leave(); 761243830Sdim } 762243830Sdim } 763243830Sdim 764243830Sdim @Override 765243830Sdim public void visitNewClass(JCNewClass tree) { 766243830Sdim //do nothing 767243830Sdim } 768243830Sdim 769243830Sdim @Override 770243830Sdim public void visitApply(JCMethodInvocation tree) { 771243830Sdim //do nothing 772193326Sed } 773193326Sed 774193326Sed @Override 775193326Sed public void visitReference(JCMemberReference tree) { 776193326Sed Check.CheckContext checkContext = resultInfo.checkContext; 777193326Sed Type pt = resultInfo.pt; 778193326Sed if (!inferenceContext.inferencevars.contains(pt)) { 779193326Sed try { 780193326Sed types.findDescriptorType(pt); 781193326Sed } catch (Types.FunctionDescriptorLookupError ex) { 782193326Sed checkContext.report(null, ex.getDiagnostic()); 783243830Sdim } 784243830Sdim Env<AttrContext> localEnv = env.dup(tree); 785193326Sed JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv, 786243830Sdim attr.memberReferenceQualifierResult(tree)); 787249423Sdim ListBuffer<Type> argtypes = new ListBuffer<>(); 788193326Sed for (Type t : types.findDescriptorType(pt).getParameterTypes()) { 789193326Sed argtypes.append(Type.noType); 790193326Sed } 791193326Sed JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree); 792193326Sed mref2.expr = exprTree; 793193326Sed Symbol lookupSym = 794193326Sed rs.resolveMemberReference(localEnv, mref2, exprTree.type, 795193326Sed tree.name, argtypes.toList(), List.nil(), rs.arityMethodCheck, 796243830Sdim inferenceContext, rs.structuralReferenceChooser).fst; 797193326Sed switch (lookupSym.kind) { 798193326Sed case WRONG_MTH: 799193326Sed case WRONG_MTHS: 800193326Sed //note: as argtypes are erroneous types, type-errors must 801198092Srdivacky //have been caused by arity mismatch 802193326Sed checkContext.report(tree, diags.fragment(Fragments.IncompatibleArgTypesInMref)); 803243830Sdim break; 804249423Sdim case ABSENT_MTH: 805198092Srdivacky case STATICERR: 806193326Sed //if no method found, or method found with wrong staticness, report better message 807193326Sed checkContext.report(tree, ((ResolveError)lookupSym).getDiagnostic(DiagnosticType.FRAGMENT, 808198092Srdivacky tree, exprTree.type.tsym, exprTree.type, tree.name, argtypes.toList(), List.nil())); 809193326Sed break; 810198092Srdivacky } 811193326Sed } 812193326Sed } 813193326Sed } 814193326Sed 815193326Sed /* This visitor looks for return statements, its analysis will determine if 816193326Sed * a lambda body is void or value compatible. We must analyze return 817193326Sed * statements contained in the lambda body only, thus any return statement 818193326Sed * contained in an inner class or inner lambda body, should be ignored. 819193326Sed */ 820193326Sed class LambdaBodyStructChecker extends TreeScanner { 821193326Sed boolean isVoidCompatible = true; 822193326Sed boolean isPotentiallyValueCompatible = true; 823193326Sed 824193326Sed @Override 825193326Sed public void visitClassDef(JCClassDecl tree) { 826193326Sed // do nothing 827201361Srdivacky } 828201361Srdivacky 829193326Sed @Override 830198092Srdivacky public void visitLambda(JCLambda tree) { 831198092Srdivacky // do nothing 832201361Srdivacky } 833201361Srdivacky 834193326Sed @Override 835193326Sed public void visitNewClass(JCNewClass tree) { 836193326Sed // do nothing 837239462Sdim } 838234353Sdim 839234353Sdim @Override 840234353Sdim public void visitReturn(JCReturn tree) { 841234353Sdim if (tree.expr != null) { 842234353Sdim isVoidCompatible = false; 843226633Sdim } else { 844226633Sdim isPotentiallyValueCompatible = false; 845226633Sdim } 846226633Sdim } 847226633Sdim } 848226633Sdim } 849226633Sdim 850226633Sdim /** an empty deferred attribution context - all methods throw exceptions */ 851226633Sdim final DeferredAttrContext emptyDeferredAttrContext; 852226633Sdim 853226633Sdim /** The AttrMode to descriptive name mapping */ 854226633Sdim private static final EnumMap<AttrMode, String> deferredTypeMapDescriptions; 855234353Sdim static { 856226633Sdim deferredTypeMapDescriptions = new EnumMap<>(AttrMode.class); 857226633Sdim deferredTypeMapDescriptions.put(AttrMode.CHECK, "deferredTypeMap[CHECK]"); 858226633Sdim deferredTypeMapDescriptions.put(AttrMode.SPECULATIVE, "deferredTypeMap[SPECULATIVE]"); 859226633Sdim } 860226633Sdim 861226633Sdim /** 862226633Sdim * Map a list of types possibly containing one or more deferred types 863226633Sdim * into a list of ordinary types. Each deferred type D is mapped into a type T, 864226633Sdim * where T is computed by retrieving the type that has already been 865226633Sdim * computed for D during a previous deferred attribution round of the given kind. 866226633Sdim */ 867226633Sdim class DeferredTypeMap extends Type.Mapping { 868234353Sdim DeferredAttrContext deferredAttrContext; 869226633Sdim 870226633Sdim protected DeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) { 871226633Sdim super(deferredTypeMapDescriptions.get(mode)); 872226633Sdim this.deferredAttrContext = new DeferredAttrContext(mode, msym, phase, 873239462Sdim infer.emptyContext, emptyDeferredAttrContext, types.noWarnings); 874226633Sdim } 875193326Sed 876226633Sdim @Override 877226633Sdim public Type apply(Type t) { 878234353Sdim if (!t.hasTag(DEFERRED)) { 879193326Sed return t.map(this); 880198092Srdivacky } else { 881226633Sdim DeferredType dt = (DeferredType)t; 882198092Srdivacky return typeOf(dt); 883234353Sdim } 884234353Sdim } 885234353Sdim 886234353Sdim protected Type typeOf(DeferredType dt) { 887226633Sdim switch (deferredAttrContext.mode) { 888226633Sdim case CHECK: 889226633Sdim return dt.tree.type == null ? Type.noType : dt.tree.type; 890193326Sed case SPECULATIVE: 891193326Sed return dt.speculativeType(deferredAttrContext.msym, deferredAttrContext.phase); 892193326Sed } 893193326Sed Assert.error(); 894234353Sdim return null; 895234353Sdim } 896234353Sdim } 897234353Sdim 898234353Sdim /** 899234353Sdim * Specialized recovery deferred mapping. 900234353Sdim * Each deferred type D is mapped into a type T, where T is computed either by 901234353Sdim * (i) retrieving the type that has already been computed for D during a previous 902234353Sdim * attribution round (as before), or (ii) by synthesizing a new type R for D 903234353Sdim * (the latter step is useful in a recovery scenario). 904234353Sdim */ 905234353Sdim public class RecoveryDeferredTypeMap extends DeferredTypeMap { 906234353Sdim 907234353Sdim public RecoveryDeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) { 908198092Srdivacky super(mode, msym, phase != null ? phase : MethodResolutionPhase.BOX); 909221345Sdim } 910193326Sed 911193326Sed @Override 912193326Sed protected Type typeOf(DeferredType dt) { 913193326Sed Type owntype = super.typeOf(dt); 914193326Sed return owntype == Type.noType ? 915193326Sed recover(dt) : owntype; 916193326Sed } 917193326Sed 918193326Sed /** 919234353Sdim * Synthesize a type for a deferred type that hasn't been previously 920234353Sdim * reduced to an ordinary type. Functional deferred types and conditionals 921234353Sdim * are mapped to themselves, in order to have a richer diagnostic 922234353Sdim * representation. Remaining deferred types are attributed using 923198092Srdivacky * a default expected type (j.l.Object). 924234353Sdim */ 925234353Sdim private Type recover(DeferredType dt) { 926234353Sdim dt.check(attr.new RecoveryInfo(deferredAttrContext) { 927234353Sdim @Override 928234353Sdim protected Type check(DiagnosticPosition pos, Type found) { 929234353Sdim return chk.checkNonVoid(pos, super.check(pos, found)); 930234353Sdim } 931234353Sdim }); 932234353Sdim return super.apply(dt); 933234353Sdim } 934234353Sdim } 935234353Sdim 936234353Sdim /** 937218893Sdim * A special tree scanner that would only visit portions of a given tree. 938234353Sdim * The set of nodes visited by the scanner can be customized at construction-time. 939234353Sdim */ 940234353Sdim abstract static class FilterScanner extends TreeScanner { 941234353Sdim 942234353Sdim final Filter<JCTree> treeFilter; 943234353Sdim 944234353Sdim FilterScanner(final Set<JCTree.Tag> validTags) { 945234353Sdim this.treeFilter = new Filter<JCTree>() { 946234353Sdim public boolean accepts(JCTree t) { 947234353Sdim return validTags.contains(t.getTag()); 948234353Sdim } 949234353Sdim }; 950234353Sdim } 951234353Sdim 952234353Sdim @Override 953234353Sdim public void scan(JCTree tree) { 954234353Sdim if (tree != null) { 955234353Sdim if (treeFilter.accepts(tree)) { 956234353Sdim super.scan(tree); 957234353Sdim } else { 958234353Sdim skip(tree); 959234353Sdim } 960234353Sdim } 961234353Sdim } 962234353Sdim 963234353Sdim /** 964234353Sdim * handler that is executed when a node has been discarded 965234353Sdim */ 966234353Sdim void skip(JCTree tree) {} 967234353Sdim } 968218893Sdim 969234353Sdim /** 970234353Sdim * A tree scanner suitable for visiting the target-type dependent nodes of 971234353Sdim * a given argument expression. 972234353Sdim */ 973234353Sdim static class PolyScanner extends FilterScanner { 974234353Sdim 975226633Sdim PolyScanner() { 976218893Sdim super(EnumSet.of(CONDEXPR, PARENS, LAMBDA, REFERENCE)); 977234353Sdim } 978234353Sdim } 979218893Sdim 980234353Sdim /** 981234353Sdim * A tree scanner suitable for visiting the target-type dependent nodes nested 982234353Sdim * within a lambda expression body. 983234353Sdim */ 984234353Sdim static class LambdaReturnScanner extends FilterScanner { 985234353Sdim 986234353Sdim LambdaReturnScanner() { 987234353Sdim super(EnumSet.of(BLOCK, CASE, CATCH, DOLOOP, FOREACHLOOP, 988234353Sdim FORLOOP, IF, RETURN, SYNCHRONIZED, SWITCH, TRY, WHILELOOP)); 989234353Sdim } 990234353Sdim } 991243830Sdim 992234353Sdim /** 993193326Sed * This visitor is used to check that structural expressions conform 994234353Sdim * to their target - this step is required as inference could end up 995234353Sdim * inferring types that make some of the nested expressions incompatible 996193326Sed * with their corresponding instantiated target 997234353Sdim */ 998234353Sdim class CheckStuckPolicy extends PolyScanner implements DeferredStuckPolicy, Infer.FreeTypeListener { 999243830Sdim 1000243830Sdim Type pt; 1001243830Sdim Infer.InferenceContext inferenceContext; 1002234353Sdim Set<Type> stuckVars = new LinkedHashSet<>(); 1003193326Sed Set<Type> depVars = new LinkedHashSet<>(); 1004193326Sed 1005234353Sdim @Override 1006234353Sdim public boolean isStuck() { 1007193326Sed return !stuckVars.isEmpty(); 1008234353Sdim } 1009226633Sdim 1010234353Sdim @Override 1011234353Sdim public Set<Type> stuckVars() { 1012234353Sdim return stuckVars; 1013193326Sed } 1014193326Sed 1015234353Sdim @Override 1016193326Sed public Set<Type> depVars() { 1017198092Srdivacky return depVars; 1018198092Srdivacky } 1019193326Sed 1020234353Sdim public CheckStuckPolicy(ResultInfo resultInfo, DeferredType dt) { 1021234353Sdim this.pt = resultInfo.pt; 1022234353Sdim this.inferenceContext = resultInfo.checkContext.inferenceContext(); 1023234353Sdim scan(dt.tree); 1024234353Sdim if (!stuckVars.isEmpty()) { 1025234353Sdim resultInfo.checkContext.inferenceContext() 1026234353Sdim .addFreeTypeListener(List.from(stuckVars), this); 1027234353Sdim } 1028234353Sdim } 1029234353Sdim 1030234353Sdim @Override 1031234353Sdim public void typesInferred(InferenceContext inferenceContext) { 1032234353Sdim stuckVars.clear(); 1033234353Sdim } 1034234353Sdim 1035234353Sdim @Override 1036234353Sdim public void visitLambda(JCLambda tree) { 1037234353Sdim if (inferenceContext.inferenceVars().contains(pt)) { 1038234353Sdim stuckVars.add(pt); 1039234353Sdim } 1040234353Sdim if (!types.isFunctionalInterface(pt)) { 1041234353Sdim return; 1042193326Sed } 1043193326Sed Type descType = types.findDescriptorType(pt); 1044198092Srdivacky List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes()); 1045193326Sed if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT && 1046193326Sed freeArgVars.nonEmpty()) { 1047193326Sed stuckVars.addAll(freeArgVars); 1048193326Sed depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType())); 1049226633Sdim } 1050234353Sdim scanLambdaBody(tree, descType.getReturnType()); 1051193326Sed } 1052193326Sed 1053193326Sed @Override 1054239462Sdim public void visitReference(JCMemberReference tree) { 1055226633Sdim scan(tree.expr); 1056226633Sdim if (inferenceContext.inferenceVars().contains(pt)) { 1057226633Sdim stuckVars.add(pt); 1058226633Sdim return; 1059226633Sdim } 1060226633Sdim if (!types.isFunctionalInterface(pt)) { 1061226633Sdim return; 1062226633Sdim } 1063193326Sed 1064193326Sed Type descType = types.findDescriptorType(pt); 1065193326Sed List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes()); 1066193326Sed if (freeArgVars.nonEmpty() && 1067226633Sdim tree.overloadKind == JCMemberReference.OverloadKind.OVERLOADED) { 1068226633Sdim stuckVars.addAll(freeArgVars); 1069226633Sdim depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType())); 1070193326Sed } 1071226633Sdim } 1072226633Sdim 1073226633Sdim void scanLambdaBody(JCLambda lambda, final Type pt) { 1074226633Sdim if (lambda.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) { 1075226633Sdim Type prevPt = this.pt; 1076226633Sdim try { 1077226633Sdim this.pt = pt; 1078226633Sdim scan(lambda.body); 1079226633Sdim } finally { 1080226633Sdim this.pt = prevPt; 1081226633Sdim } 1082226633Sdim } else { 1083226633Sdim LambdaReturnScanner lambdaScanner = new LambdaReturnScanner() { 1084226633Sdim @Override 1085226633Sdim public void visitReturn(JCReturn tree) { 1086226633Sdim if (tree.expr != null) { 1087226633Sdim Type prevPt = CheckStuckPolicy.this.pt; 1088226633Sdim try { 1089226633Sdim CheckStuckPolicy.this.pt = pt; 1090226633Sdim CheckStuckPolicy.this.scan(tree.expr); 1091226633Sdim } finally { 1092226633Sdim CheckStuckPolicy.this.pt = prevPt; 1093226633Sdim } 1094226633Sdim } 1095226633Sdim } 1096226633Sdim }; 1097226633Sdim lambdaScanner.scan(lambda.body); 1098226633Sdim } 1099226633Sdim } 1100226633Sdim } 1101193326Sed 1102193326Sed /** 1103193326Sed * This visitor is used to check that structural expressions conform 1104193326Sed * to their target - this step is required as inference could end up 1105193326Sed * inferring types that make some of the nested expressions incompatible 1106239462Sdim * with their corresponding instantiated target 1107193326Sed */ 1108193326Sed class OverloadStuckPolicy extends CheckStuckPolicy implements DeferredStuckPolicy { 1109193326Sed 1110218893Sdim boolean stuck; 1111234353Sdim 1112223017Sdim @Override 1113226633Sdim public boolean isStuck() { 1114226633Sdim return super.isStuck() || stuck; 1115218893Sdim } 1116218893Sdim 1117218893Sdim public OverloadStuckPolicy(ResultInfo resultInfo, DeferredType dt) { 1118218893Sdim super(resultInfo, dt); 1119223017Sdim } 1120223017Sdim 1121239462Sdim @Override 1122239462Sdim public void visitLambda(JCLambda tree) { 1123223017Sdim super.visitLambda(tree); 1124193326Sed if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT) { 1125193326Sed stuck = true; 1126193326Sed } 1127193326Sed } 1128223017Sdim 1129193326Sed @Override 1130223017Sdim public void visitReference(JCMemberReference tree) { 1131193326Sed super.visitReference(tree); 1132226633Sdim if (tree.overloadKind == JCMemberReference.OverloadKind.OVERLOADED) { 1133198092Srdivacky stuck = true; 1134193326Sed } 1135193326Sed } 1136193326Sed } 1137193326Sed 1138193326Sed /** 1139239462Sdim * Does the argument expression {@code expr} need speculative type-checking? 1140239462Sdim */ 1141223017Sdim boolean isDeferred(Env<AttrContext> env, JCExpression expr) { 1142193326Sed DeferredChecker dc = new DeferredChecker(env); 1143193326Sed dc.scan(expr); 1144223017Sdim return dc.result.isPoly(); 1145193326Sed } 1146198092Srdivacky 1147193326Sed /** 1148198092Srdivacky * The kind of an argument expression. This is used by the analysis that 1149193326Sed * determines as to whether speculative attribution is necessary. 1150198092Srdivacky */ 1151226633Sdim enum ArgumentExpressionKind { 1152226633Sdim 1153226633Sdim /** kind that denotes poly argument expression */ 1154226633Sdim POLY, 1155226633Sdim /** kind that denotes a standalone expression */ 1156226633Sdim NO_POLY, 1157226633Sdim /** kind that denotes a primitive/boxed standalone expression */ 1158243830Sdim PRIMITIVE; 1159226633Sdim 1160226633Sdim /** 1161226633Sdim * Does this kind denote a poly argument expression 1162226633Sdim */ 1163193326Sed public final boolean isPoly() { 1164193326Sed return this == POLY; 1165193326Sed } 1166193326Sed 1167198092Srdivacky /** 1168193326Sed * Does this kind denote a primitive standalone expression 1169198092Srdivacky */ 1170226633Sdim public final boolean isPrimitive() { 1171226633Sdim return this == PRIMITIVE; 1172226633Sdim } 1173226633Sdim 1174198092Srdivacky /** 1175193326Sed * Compute the kind of a standalone expression of a given type 1176193326Sed */ 1177226633Sdim static ArgumentExpressionKind standaloneKind(Type type, Types types) { 1178198092Srdivacky return types.unboxedTypeOrType(type).isPrimitive() ? 1179193326Sed ArgumentExpressionKind.PRIMITIVE : 1180193326Sed ArgumentExpressionKind.NO_POLY; 1181198092Srdivacky } 1182193326Sed 1183234353Sdim /** 1184193326Sed * Compute the kind of a method argument expression given its symbol 1185198092Srdivacky */ 1186193326Sed static ArgumentExpressionKind methodKind(Symbol sym, Types types) { 1187193326Sed Type restype = sym.type.getReturnType(); 1188193326Sed if (sym.type.hasTag(FORALL) && 1189198092Srdivacky restype.containsAny(((ForAll)sym.type).tvars)) { 1190193326Sed return ArgumentExpressionKind.POLY; 1191198092Srdivacky } else { 1192234353Sdim return ArgumentExpressionKind.standaloneKind(restype, types); 1193234353Sdim } 1194193326Sed } 1195193326Sed } 1196193326Sed 1197193326Sed /** 1198193326Sed * Tree scanner used for checking as to whether an argument expression 1199205219Srdivacky * requires speculative attribution 1200218893Sdim */ 1201218893Sdim final class DeferredChecker extends FilterScanner { 1202218893Sdim 1203239462Sdim Env<AttrContext> env; 1204239462Sdim ArgumentExpressionKind result; 1205205219Srdivacky 1206234353Sdim public DeferredChecker(Env<AttrContext> env) { 1207234353Sdim super(deferredCheckerTags); 1208234353Sdim this.env = env; 1209234353Sdim } 1210234353Sdim 1211234353Sdim @Override 1212234353Sdim public void visitLambda(JCLambda tree) { 1213234353Sdim //a lambda is always a poly expression 1214234353Sdim result = ArgumentExpressionKind.POLY; 1215234353Sdim } 1216234353Sdim 1217234353Sdim @Override 1218234353Sdim public void visitReference(JCMemberReference tree) { 1219234353Sdim //perform arity-based check 1220234353Sdim Env<AttrContext> localEnv = env.dup(tree); 1221234353Sdim JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv, 1222234353Sdim attr.memberReferenceQualifierResult(tree)); 1223234353Sdim JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree); 1224234353Sdim mref2.expr = exprTree; 1225234353Sdim Symbol res = 1226234353Sdim rs.getMemberReference(tree, localEnv, mref2, 1227234353Sdim exprTree.type, tree.name); 1228234353Sdim tree.sym = res; 1229234353Sdim if (res.kind.isOverloadError() || 1230234353Sdim res.type.hasTag(FORALL) || 1231234353Sdim (res.flags() & Flags.VARARGS) != 0 || 1232234353Sdim (TreeInfo.isStaticSelector(exprTree, tree.name.table.names) && 1233234353Sdim exprTree.type.isRaw())) { 1234234353Sdim tree.overloadKind = JCMemberReference.OverloadKind.OVERLOADED; 1235234353Sdim } else { 1236234353Sdim tree.overloadKind = JCMemberReference.OverloadKind.UNOVERLOADED; 1237234353Sdim } 1238234353Sdim //a method reference is always a poly expression 1239234353Sdim result = ArgumentExpressionKind.POLY; 1240234353Sdim } 1241234353Sdim 1242193326Sed @Override 1243198092Srdivacky public void visitTypeCast(JCTypeCast tree) { 1244226633Sdim //a cast is always a standalone expression 1245226633Sdim result = ArgumentExpressionKind.NO_POLY; 1246193326Sed } 1247226633Sdim 1248226633Sdim @Override 1249226633Sdim public void visitConditional(JCConditional tree) { 1250212904Sdim scan(tree.truepart); 1251198092Srdivacky if (!result.isPrimitive()) { 1252226633Sdim result = ArgumentExpressionKind.POLY; 1253226633Sdim return; 1254226633Sdim } 1255198092Srdivacky scan(tree.falsepart); 1256226633Sdim result = reduce(ArgumentExpressionKind.PRIMITIVE).isPrimitive() ? 1257226633Sdim ArgumentExpressionKind.PRIMITIVE : 1258193326Sed ArgumentExpressionKind.POLY; 1259226633Sdim 1260198092Srdivacky } 1261234353Sdim 1262234353Sdim @Override 1263234353Sdim public void visitNewClass(JCNewClass tree) { 1264226633Sdim result = TreeInfo.isDiamond(tree) ? 1265226633Sdim ArgumentExpressionKind.POLY : ArgumentExpressionKind.NO_POLY; 1266243830Sdim } 1267243830Sdim 1268243830Sdim @Override 1269226633Sdim public void visitApply(JCMethodInvocation tree) { 1270239462Sdim Name name = TreeInfo.name(tree.meth); 1271239462Sdim 1272239462Sdim //fast path 1273239462Sdim if (tree.typeargs.nonEmpty() || 1274239462Sdim name == name.table.names._this || 1275226633Sdim name == name.table.names._super) { 1276226633Sdim result = ArgumentExpressionKind.NO_POLY; 1277226633Sdim return; 1278226633Sdim } 1279226633Sdim 1280226633Sdim //slow path 1281226633Sdim Symbol sym = quicklyResolveMethod(env, tree); 1282226633Sdim 1283226633Sdim if (sym == null) { 1284193326Sed result = ArgumentExpressionKind.POLY; 1285226633Sdim return; 1286226633Sdim } 1287226633Sdim 1288226633Sdim result = analyzeCandidateMethods(sym, ArgumentExpressionKind.PRIMITIVE, 1289198092Srdivacky argumentKindAnalyzer); 1290226633Sdim } 1291226633Sdim //where 1292226633Sdim private boolean isSimpleReceiver(JCTree rec) { 1293226633Sdim switch (rec.getTag()) { 1294226633Sdim case IDENT: 1295226633Sdim return true; 1296226633Sdim case SELECT: 1297226633Sdim return isSimpleReceiver(((JCFieldAccess)rec).selected); 1298226633Sdim case TYPEAPPLY: 1299243830Sdim case TYPEARRAY: 1300243830Sdim return true; 1301243830Sdim case ANNOTATED_TYPE: 1302226633Sdim return isSimpleReceiver(((JCAnnotatedType)rec).underlyingType); 1303193326Sed case APPLY: 1304226633Sdim return true; 1305226633Sdim default: 1306234353Sdim return false; 1307234353Sdim } 1308234353Sdim } 1309226633Sdim private ArgumentExpressionKind reduce(ArgumentExpressionKind kind) { 1310226633Sdim return argumentKindAnalyzer.reduce(result, kind); 1311226633Sdim } 1312226633Sdim MethodAnalyzer<ArgumentExpressionKind> argumentKindAnalyzer = 1313226633Sdim new MethodAnalyzer<ArgumentExpressionKind>() { 1314243830Sdim @Override 1315226633Sdim public ArgumentExpressionKind process(MethodSymbol ms) { 1316243830Sdim return ArgumentExpressionKind.methodKind(ms, types); 1317198092Srdivacky } 1318234353Sdim @Override 1319234353Sdim public ArgumentExpressionKind reduce(ArgumentExpressionKind kind1, 1320234353Sdim ArgumentExpressionKind kind2) { 1321234353Sdim switch (kind1) { 1322234353Sdim case PRIMITIVE: return kind2; 1323234353Sdim case NO_POLY: return kind2.isPoly() ? kind2 : kind1; 1324234353Sdim case POLY: return kind1; 1325234353Sdim default: 1326234353Sdim Assert.error(); 1327234353Sdim return null; 1328234353Sdim } 1329234353Sdim } 1330234353Sdim @Override 1331234353Sdim public boolean shouldStop(ArgumentExpressionKind result) { 1332234353Sdim return result.isPoly(); 1333234353Sdim } 1334193326Sed }; 1335193326Sed 1336193326Sed @Override 1337198092Srdivacky public void visitLiteral(JCLiteral tree) { 1338193326Sed Type litType = attr.litType(tree.typetag); 1339234353Sdim result = ArgumentExpressionKind.standaloneKind(litType, types); 1340234353Sdim } 1341234353Sdim 1342234353Sdim @Override 1343234353Sdim void skip(JCTree tree) { 1344234353Sdim result = ArgumentExpressionKind.NO_POLY; 1345234353Sdim } 1346234353Sdim 1347234353Sdim private Symbol quicklyResolveMethod(Env<AttrContext> env, final JCMethodInvocation tree) { 1348234353Sdim final JCExpression rec = tree.meth.hasTag(SELECT) ? 1349234353Sdim ((JCFieldAccess)tree.meth).selected : 1350234353Sdim null; 1351234353Sdim 1352234353Sdim if (rec != null && !isSimpleReceiver(rec)) { 1353193326Sed return null; 1354193326Sed } 1355218893Sdim 1356243830Sdim Type site; 1357243830Sdim 1358218893Sdim if (rec != null) { 1359218893Sdim if (rec.hasTag(APPLY)) { 1360218893Sdim Symbol recSym = quicklyResolveMethod(env, (JCMethodInvocation) rec); 1361226633Sdim if (recSym == null) 1362193326Sed return null; 1363193326Sed Symbol resolvedReturnType = 1364218893Sdim analyzeCandidateMethods(recSym, syms.errSymbol, returnSymbolAnalyzer); 1365212904Sdim if (resolvedReturnType == null) 1366218893Sdim return null; 1367243830Sdim site = resolvedReturnType.type; 1368212904Sdim } else { 1369243830Sdim site = attribSpeculative(rec, env, attr.unknownTypeExprInfo).type; 1370218893Sdim } 1371212904Sdim } else { 1372218893Sdim site = env.enclClass.sym.type; 1373212904Sdim } 1374212904Sdim 1375193326Sed while (site.hasTag(TYPEVAR)) { 1376193326Sed site = site.getUpperBound(); 1377193326Sed } 1378243830Sdim 1379243830Sdim site = types.capture(site); 1380243830Sdim 1381243830Sdim List<Type> args = rs.dummyArgs(tree.args.length()); 1382243830Sdim Name name = TreeInfo.name(tree.meth); 1383243830Sdim 1384243830Sdim Resolve.LookupHelper lh = rs.new LookupHelper(name, site, args, List.<Type>nil(), MethodResolutionPhase.VARARITY) { 1385226633Sdim @Override 1386226633Sdim Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) { 1387243830Sdim return rec == null ? 1388243830Sdim rs.findFun(env, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()) : 1389243830Sdim rs.findMethod(env, site, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired(), false); 1390243830Sdim } 1391243830Sdim @Override 1392243830Sdim Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) { 1393243830Sdim return sym; 1394243830Sdim } 1395243830Sdim }; 1396243830Sdim 1397234353Sdim return rs.lookupMethod(env, tree, site.tsym, rs.arityMethodCheck, lh); 1398234353Sdim } 1399234353Sdim //where: 1400234353Sdim MethodAnalyzer<Symbol> returnSymbolAnalyzer = new MethodAnalyzer<Symbol>() { 1401243830Sdim @Override 1402243830Sdim public Symbol process(MethodSymbol ms) { 1403243830Sdim ArgumentExpressionKind kind = ArgumentExpressionKind.methodKind(ms, types); 1404243830Sdim if (kind == ArgumentExpressionKind.POLY || ms.getReturnType().hasTag(TYPEVAR)) 1405243830Sdim return null; 1406243830Sdim return ms.getReturnType().tsym; 1407243830Sdim } 1408243830Sdim @Override 1409243830Sdim public Symbol reduce(Symbol s1, Symbol s2) { 1410243830Sdim return s1 == syms.errSymbol ? s2 : s1 == s2 ? s1 : null; 1411243830Sdim } 1412243830Sdim @Override 1413243830Sdim public boolean shouldStop(Symbol result) { 1414243830Sdim return result == null; 1415243830Sdim } 1416243830Sdim }; 1417243830Sdim 1418243830Sdim /** 1419243830Sdim * Process the result of Resolve.lookupMethod. If sym is a method symbol, the result of 1420243830Sdim * MethodAnalyzer.process is returned. If sym is an ambiguous symbol, all the candidate 1421243830Sdim * methods are inspected one by one, using MethodAnalyzer.process. The outcomes are 1422243830Sdim * reduced using MethodAnalyzer.reduce (using defaultValue as the first value over which 1423243830Sdim * the reduction runs). MethodAnalyzer.shouldStop can be used to stop the inspection early. 1424243830Sdim */ 1425243830Sdim <E> E analyzeCandidateMethods(Symbol sym, E defaultValue, MethodAnalyzer<E> analyzer) { 1426243830Sdim switch (sym.kind) { 1427243830Sdim case MTH: 1428243830Sdim return analyzer.process((MethodSymbol) sym); 1429243830Sdim case AMBIGUOUS: 1430243830Sdim Resolve.AmbiguityError err = (Resolve.AmbiguityError)sym.baseSymbol(); 1431243830Sdim E res = defaultValue; 1432243830Sdim for (Symbol s : err.ambiguousSyms) { 1433234353Sdim if (s.kind == MTH) { 1434234353Sdim res = analyzer.reduce(res, analyzer.process((MethodSymbol) s)); 1435226633Sdim if (analyzer.shouldStop(res)) 1436239462Sdim return res; 1437239462Sdim } 1438239462Sdim } 1439239462Sdim return res; 1440239462Sdim default: 1441239462Sdim return defaultValue; 1442193326Sed } 1443193326Sed } 1444193326Sed } 1445193326Sed 1446218893Sdim /** Analyzer for methods - used by analyzeCandidateMethods. */ 1447193326Sed interface MethodAnalyzer<E> { 1448234353Sdim E process(MethodSymbol ms); 1449193326Sed E reduce(E e1, E e2); 1450198092Srdivacky boolean shouldStop(E result); 1451205219Srdivacky } 1452193326Sed 1453218893Sdim //where 1454218893Sdim private EnumSet<JCTree.Tag> deferredCheckerTags = 1455218893Sdim EnumSet.of(LAMBDA, REFERENCE, PARENS, TYPECAST, 1456205219Srdivacky CONDEXPR, NEWCLASS, APPLY, LITERAL); 1457193326Sed} 1458239462Sdim