DeferredAttr.java revision 2793:ab5991ac1286
133965Sjdp/* 2130570Sobrien * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. 3218822Sdim * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 433965Sjdp * 5130570Sobrien * This code is free software; you can redistribute it and/or modify it 633965Sjdp * under the terms of the GNU General Public License version 2 only, as 7130570Sobrien * published by the Free Software Foundation. Oracle designates this 8130570Sobrien * particular file as subject to the "Classpath" exception as provided 9130570Sobrien * by Oracle in the LICENSE file that accompanied this code. 10130570Sobrien * 1133965Sjdp * This code is distributed in the hope that it will be useful, but WITHOUT 12130570Sobrien * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13130570Sobrien * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14130570Sobrien * version 2 for more details (a copy is included in the LICENSE file that 15130570Sobrien * accompanied this code). 1633965Sjdp * 17130570Sobrien * You should have received a copy of the GNU General Public License version 18130570Sobrien * 2 along with this work; if not, write to the Free Software Foundation, 19218822Sdim * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2033965Sjdp * 21218822Sdim * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2233965Sjdp * or visit www.oracle.com if you need additional information or have any 2333965Sjdp * questions. 2433965Sjdp */ 2533965Sjdp 26218822Sdimpackage com.sun.tools.javac.comp; 2733965Sjdp 28130570Sobrienimport com.sun.source.tree.LambdaExpressionTree.BodyKind; 29130570Sobrienimport com.sun.tools.javac.code.*; 30104840Sobrienimport com.sun.tools.javac.comp.Resolve.ResolveError; 3160509Sobrienimport com.sun.tools.javac.resources.CompilerProperties; 3233965Sjdpimport com.sun.tools.javac.resources.CompilerProperties.Fragments; 3333965Sjdpimport com.sun.tools.javac.tree.*; 3433965Sjdpimport com.sun.tools.javac.util.*; 35130570Sobrienimport com.sun.tools.javac.util.DefinedBy.Api; 3677302Sobrienimport com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; 37130570Sobrienimport com.sun.tools.javac.code.Symbol.*; 38130570Sobrienimport com.sun.tools.javac.code.Type.*; 3977302Sobrienimport com.sun.tools.javac.comp.Attr.ResultInfo; 40130570Sobrienimport com.sun.tools.javac.comp.Infer.InferenceContext; 41130570Sobrienimport com.sun.tools.javac.comp.Resolve.MethodResolutionPhase; 4277302Sobrienimport com.sun.tools.javac.tree.JCTree.*; 43130570Sobrienimport com.sun.tools.javac.util.JCDiagnostic.DiagnosticType; 44130570Sobrienimport com.sun.tools.javac.util.Log.DeferredDiagnosticHandler; 4577302Sobrien 46130570Sobrienimport java.util.ArrayList; 47130570Sobrienimport java.util.Collections; 4877302Sobrienimport java.util.EnumMap; 49130570Sobrienimport java.util.EnumSet; 50130570Sobrienimport java.util.LinkedHashMap; 5177302Sobrienimport java.util.LinkedHashSet; 52130570Sobrienimport java.util.Map; 53130570Sobrienimport java.util.Set; 5477302Sobrienimport java.util.WeakHashMap; 55130570Sobrienimport java.util.function.Function; 56130570Sobrien 5777302Sobrienimport static com.sun.tools.javac.code.TypeTag.*; 58130570Sobrienimport static com.sun.tools.javac.tree.JCTree.Tag.*; 59130570Sobrienimport static com.sun.tools.javac.code.Kinds.*; 6077302Sobrienimport static com.sun.tools.javac.code.Kinds.Kind.*; 61130570Sobrien 62130570Sobrien/** 6377302Sobrien * This is an helper class that is used to perform deferred type-analysis. 64130570Sobrien * Each time a poly expression occurs in argument position, javac attributes it 65130570Sobrien * with a temporary 'deferred type' that is checked (possibly multiple times) 6677302Sobrien * against an expected formal type. 67130570Sobrien * 6877302Sobrien * <p><b>This is NOT part of any supported API. 6977302Sobrien * If you write code that depends on this, you do so at your own risk. 7077302Sobrien * This code and its internal interfaces are subject to change or 7177302Sobrien * deletion without notice.</b> 7277302Sobrien */ 73130570Sobrienpublic class DeferredAttr extends JCTree.Visitor { 74130570Sobrien protected static final Context.Key<DeferredAttr> deferredAttrKey = new Context.Key<>(); 7577302Sobrien 76104840Sobrien final Attr attr; 77130570Sobrien final Check chk; 78104840Sobrien final JCDiagnostic.Factory diags; 79130570Sobrien final Enter enter; 80130570Sobrien final Infer infer; 81104840Sobrien final Resolve rs; 82130570Sobrien final Log log; 83130570Sobrien final Symtab syms; 84104840Sobrien final TreeMaker make; 85130570Sobrien final Types types; 86130570Sobrien final Flow flow; 87104840Sobrien final Names names; 88130570Sobrien final TypeEnvs typeEnvs; 89130570Sobrien 90104840Sobrien public static DeferredAttr instance(Context context) { 91130570Sobrien DeferredAttr instance = context.get(deferredAttrKey); 92130570Sobrien if (instance == null) 93104840Sobrien instance = new DeferredAttr(context); 94130570Sobrien return instance; 95130570Sobrien } 9677302Sobrien 97130570Sobrien protected DeferredAttr(Context context) { 98130570Sobrien context.put(deferredAttrKey, this); 9977302Sobrien attr = Attr.instance(context); 100130570Sobrien chk = Check.instance(context); 101130570Sobrien diags = JCDiagnostic.Factory.instance(context); 10277302Sobrien enter = Enter.instance(context); 103130570Sobrien infer = Infer.instance(context); 104130570Sobrien rs = Resolve.instance(context); 10577302Sobrien log = Log.instance(context); 106130570Sobrien syms = Symtab.instance(context); 10733965Sjdp make = TreeMaker.instance(context); 108130570Sobrien types = Types.instance(context); 109130570Sobrien flow = Flow.instance(context); 110104840Sobrien names = Names.instance(context); 111130570Sobrien stuckTree = make.Ident(names.empty).setType(Type.stuckType); 112104840Sobrien typeEnvs = TypeEnvs.instance(context); 113130570Sobrien emptyDeferredAttrContext = 114130570Sobrien new DeferredAttrContext(AttrMode.CHECK, null, MethodResolutionPhase.BOX, infer.emptyContext, null, null) { 115104840Sobrien @Override 116130570Sobrien void addDeferredAttrNode(DeferredType dt, ResultInfo ri, DeferredStuckPolicy deferredStuckPolicy) { 117130570Sobrien Assert.error("Empty deferred context!"); 118104840Sobrien } 119130570Sobrien @Override 120130570Sobrien void complete() { 121104840Sobrien Assert.error("Empty deferred context!"); 122130570Sobrien } 123130570Sobrien 124104840Sobrien @Override 125130570Sobrien public String toString() { 126130570Sobrien return "Empty deferred context!"; 127104840Sobrien } 128130570Sobrien }; 129218822Sdim } 130218822Sdim 131218822Sdim /** shared tree for stuck expressions */ 132218822Sdim final JCTree stuckTree; 133218822Sdim 134218822Sdim /** 135218822Sdim * This type represents a deferred type. A deferred type starts off with 136218822Sdim * no information on the underlying expression type. Such info needs to be 137218822Sdim * discovered through type-checking the deferred type against a target-type. 138218822Sdim * Every deferred type keeps a pointer to the AST node from which it originated. 13977302Sobrien */ 140104840Sobrien public class DeferredType extends Type { 141218822Sdim 142130570Sobrien public JCExpression tree; 143104840Sobrien Env<AttrContext> env; 14460509Sobrien AttrMode mode; 14560509Sobrien SpeculativeCache speculativeCache; 14660509Sobrien 14760509Sobrien DeferredType(JCExpression tree, Env<AttrContext> env) { 14860509Sobrien super(null, TypeMetadata.empty); 149130570Sobrien this.tree = tree; 15060509Sobrien this.env = attr.copyEnv(env); 15160509Sobrien this.speculativeCache = new SpeculativeCache(); 15260509Sobrien } 15360509Sobrien 154130570Sobrien @Override 15560509Sobrien public DeferredType clone(TypeMetadata md) { 15660509Sobrien throw new AssertionError("Cannot add metadata to a deferred type"); 157130570Sobrien } 15860509Sobrien 15960509Sobrien @Override 16060509Sobrien public TypeTag getTag() { 16160509Sobrien return DEFERRED; 16260509Sobrien } 16360509Sobrien 164130570Sobrien @Override @DefinedBy(Api.LANGUAGE_MODEL) 16560509Sobrien public String toString() { 16660509Sobrien return "DeferredType"; 16760509Sobrien } 16860509Sobrien 169130570Sobrien /** 17060509Sobrien * A speculative cache is used to keep track of all overload resolution rounds 17160509Sobrien * that triggered speculative attribution on a given deferred type. Each entry 172130570Sobrien * stores a pointer to the speculative tree and the resolution phase in which the entry 17360509Sobrien * has been added. 174130570Sobrien */ 17577302Sobrien class SpeculativeCache { 17677302Sobrien 17777302Sobrien private Map<Symbol, List<Entry>> cache = new WeakHashMap<>(); 17833965Sjdp 179130570Sobrien class Entry { 180130570Sobrien JCTree speculativeTree; 18133965Sjdp ResultInfo resultInfo; 18233965Sjdp 18333965Sjdp public Entry(JCTree speculativeTree, ResultInfo resultInfo) { 18433965Sjdp this.speculativeTree = speculativeTree; 18533965Sjdp this.resultInfo = resultInfo; 186130570Sobrien } 187130570Sobrien 18833965Sjdp boolean matches(MethodResolutionPhase phase) { 18933965Sjdp return resultInfo.checkContext.deferredAttrContext().phase == phase; 19033965Sjdp } 19133965Sjdp } 19233965Sjdp 193130570Sobrien /** 19433965Sjdp * Retrieve a speculative cache entry corresponding to given symbol 19533965Sjdp * and resolution phase 19633965Sjdp */ 197130570Sobrien Entry get(Symbol msym, MethodResolutionPhase phase) { 19833965Sjdp List<Entry> entries = cache.get(msym); 19960509Sobrien if (entries == null) return null; 20060509Sobrien for (Entry e : entries) { 201130570Sobrien if (e.matches(phase)) return e; 20260509Sobrien } 20333965Sjdp return null; 20433965Sjdp } 205130570Sobrien 20633965Sjdp /** 20733965Sjdp * Stores a speculative cache entry corresponding to given symbol 20833965Sjdp * and resolution phase 209130570Sobrien */ 21033965Sjdp void put(JCTree speculativeTree, ResultInfo resultInfo) { 21133965Sjdp Symbol msym = resultInfo.checkContext.deferredAttrContext().msym; 21233965Sjdp List<Entry> entries = cache.get(msym); 213130570Sobrien if (entries == null) { 21433965Sjdp entries = List.nil(); 21533965Sjdp } 21633965Sjdp cache.put(msym, entries.prepend(new Entry(speculativeTree, resultInfo))); 217130570Sobrien } 21833965Sjdp } 21933965Sjdp 22033965Sjdp /** 221130570Sobrien * Get the type that has been computed during a speculative attribution round 22233965Sjdp */ 22333965Sjdp Type speculativeType(Symbol msym, MethodResolutionPhase phase) { 22433965Sjdp SpeculativeCache.Entry e = speculativeCache.get(msym, phase); 225130570Sobrien return e != null ? e.speculativeTree.type : Type.noType; 22633965Sjdp } 22733965Sjdp 22833965Sjdp /** 229130570Sobrien * Check a deferred type against a potential target-type. Depending on 23033965Sjdp * the current attribution mode, a normal vs. speculative attribution 23133965Sjdp * round is performed on the underlying AST node. There can be only one 23233965Sjdp * speculative round for a given target method symbol; moreover, a normal 233130570Sobrien * attribution round must follow one or more speculative rounds. 23433965Sjdp */ 23533965Sjdp Type check(ResultInfo resultInfo) { 23633965Sjdp DeferredStuckPolicy deferredStuckPolicy; 237130570Sobrien if (resultInfo.pt.hasTag(NONE) || resultInfo.pt.isErroneous()) { 23833965Sjdp deferredStuckPolicy = dummyStuckPolicy; 239104840Sobrien } else if (resultInfo.checkContext.deferredAttrContext().mode == AttrMode.SPECULATIVE) { 240104840Sobrien deferredStuckPolicy = new OverloadStuckPolicy(resultInfo, this); 241104840Sobrien } else { 242130570Sobrien deferredStuckPolicy = new CheckStuckPolicy(resultInfo, this); 243104840Sobrien } 244104840Sobrien return check(resultInfo, deferredStuckPolicy, basicCompleter); 245104840Sobrien } 246130570Sobrien 247104840Sobrien private Type check(ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy, 248104840Sobrien DeferredTypeCompleter deferredTypeCompleter) { 249104840Sobrien DeferredAttrContext deferredAttrContext = 250130570Sobrien resultInfo.checkContext.deferredAttrContext(); 251104840Sobrien Assert.check(deferredAttrContext != emptyDeferredAttrContext); 252104840Sobrien if (deferredStuckPolicy.isStuck()) { 253104840Sobrien deferredAttrContext.addDeferredAttrNode(this, resultInfo, deferredStuckPolicy); 254130570Sobrien return Type.noType; 255104840Sobrien } else { 256104840Sobrien try { 257104840Sobrien return deferredTypeCompleter.complete(this, resultInfo, deferredAttrContext); 258130570Sobrien } finally { 259104840Sobrien mode = deferredAttrContext.mode; 260104840Sobrien } 261104840Sobrien } 262130570Sobrien } 263104840Sobrien } 26433965Sjdp 26533965Sjdp /** 266130570Sobrien * A completer for deferred types. Defines an entry point for type-checking 26733965Sjdp * a deferred type. 26833965Sjdp */ 26933965Sjdp interface DeferredTypeCompleter { 270130570Sobrien /** 27133965Sjdp * Entry point for type-checking a deferred type. Depending on the 27233965Sjdp * circumstances, type-checking could amount to full attribution 27333965Sjdp * or partial structural check (aka potential applicability). 274130570Sobrien */ 27533965Sjdp Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext); 27633965Sjdp } 27733965Sjdp 278130570Sobrien 27933965Sjdp /** 280104840Sobrien * A basic completer for deferred types. This completer type-checks a deferred type 281104840Sobrien * using attribution; depending on the attribution mode, this could be either standard 282104840Sobrien * or speculative attribution. 283130570Sobrien */ 284104840Sobrien DeferredTypeCompleter basicCompleter = new DeferredTypeCompleter() { 285104840Sobrien public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) { 286104840Sobrien switch (deferredAttrContext.mode) { 287130570Sobrien case SPECULATIVE: 288104840Sobrien //Note: if a symbol is imported twice we might do two identical 289104840Sobrien //speculative rounds... 290104840Sobrien Assert.check(dt.mode == null || dt.mode == AttrMode.SPECULATIVE); 291130570Sobrien JCTree speculativeTree = attribSpeculative(dt.tree, dt.env, resultInfo); 292104840Sobrien dt.speculativeCache.put(speculativeTree, resultInfo); 293104840Sobrien return speculativeTree.type; 294104840Sobrien case CHECK: 295130570Sobrien Assert.check(dt.mode != null); 296104840Sobrien return attr.attribTree(dt.tree, dt.env, resultInfo); 297104840Sobrien } 298104840Sobrien Assert.error(); 299130570Sobrien return null; 300104840Sobrien } 301104840Sobrien }; 302104840Sobrien 303130570Sobrien DeferredTypeCompleter dummyCompleter = new DeferredTypeCompleter() { 304104840Sobrien public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) { 305218822Sdim Assert.check(deferredAttrContext.mode == AttrMode.CHECK); 306218822Sdim return dt.tree.type = Type.stuckType; 307218822Sdim } 308218822Sdim }; 309218822Sdim 310218822Sdim /** 311218822Sdim * Policy for detecting stuck expressions. Different criteria might cause 312218822Sdim * an expression to be judged as stuck, depending on whether the check 313218822Sdim * is performed during overload resolution or after most specific. 314218822Sdim */ 315218822Sdim interface DeferredStuckPolicy { 316218822Sdim /** 31760509Sobrien * Has the policy detected that a given expression should be considered stuck? 31860509Sobrien */ 319130570Sobrien boolean isStuck(); 32060509Sobrien /** 32160509Sobrien * Get the set of inference variables a given expression depends upon. 32260509Sobrien */ 323130570Sobrien Set<Type> stuckVars(); 32460509Sobrien /** 32533965Sjdp * Get the set of inference variables which might get new constraints 32633965Sjdp * if a given expression is being type-checked. 32733965Sjdp */ 32833965Sjdp Set<Type> depVars(); 32933965Sjdp } 33033965Sjdp 33133965Sjdp /** 33233965Sjdp * Basic stuck policy; an expression is never considered to be stuck. 333218822Sdim */ 334218822Sdim DeferredStuckPolicy dummyStuckPolicy = new DeferredStuckPolicy() { 335218822Sdim @Override 336218822Sdim public boolean isStuck() { 337218822Sdim return false; 338218822Sdim } 339218822Sdim @Override 340218822Sdim public Set<Type> stuckVars() { 341218822Sdim return Collections.emptySet(); 342218822Sdim } 343218822Sdim @Override 344218822Sdim public Set<Type> depVars() { 345218822Sdim return Collections.emptySet(); 346218822Sdim } 34733965Sjdp }; 348130570Sobrien 349130570Sobrien /** 350130570Sobrien * The 'mode' in which the deferred type is to be type-checked 35133965Sjdp */ 35277302Sobrien public enum AttrMode { 35377302Sobrien /** 35433965Sjdp * A speculative type-checking round is used during overload resolution 35577302Sobrien * mainly to generate constraints on inference variables. Side-effects 35677302Sobrien * arising from type-checking the expression associated with the deferred 35777302Sobrien * type are reversed after the speculative round finishes. This means the 358104840Sobrien * expression tree will be left in a blank state. 359104840Sobrien */ 360104840Sobrien SPECULATIVE, 361104840Sobrien /** 36260509Sobrien * This is the plain type-checking mode. Produces side-effects on the underlying AST node 363218822Sdim */ 364218822Sdim CHECK 365130570Sobrien } 36660509Sobrien 36777302Sobrien /** 36833965Sjdp * Routine that performs speculative type-checking; the input AST node is 36933965Sjdp * cloned (to avoid side-effects cause by Attr) and compiler state is 37033965Sjdp * restored after type-checking. All diagnostics (but critical ones) are 37133965Sjdp * disabled during speculative type-checking. 37233965Sjdp */ 37333965Sjdp JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) { 37433965Sjdp return attribSpeculative(tree, env, resultInfo, new TreeCopier<>(make), 37533965Sjdp (newTree)->new DeferredAttrDiagHandler(log, newTree)); 376130570Sobrien } 377130570Sobrien 37833965Sjdp <Z> JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo, TreeCopier<Z> deferredCopier, 37933965Sjdp Function<JCTree, DeferredDiagnosticHandler> diagHandlerCreator) { 380130570Sobrien final JCTree newTree = deferredCopier.copy(tree); 38133965Sjdp Env<AttrContext> speculativeEnv = env.dup(newTree, env.info.dup(env.info.scope.dupUnshared(env.info.scope.owner))); 38233965Sjdp speculativeEnv.info.isSpeculative = true; 38333965Sjdp Log.DeferredDiagnosticHandler deferredDiagnosticHandler = diagHandlerCreator.apply(newTree); 38433965Sjdp try { 38589861Sobrien attr.attribTree(newTree, speculativeEnv, resultInfo); 386130570Sobrien unenterScanner.scan(newTree); 387130570Sobrien return newTree; 388130570Sobrien } finally { 38989861Sobrien unenterScanner.scan(newTree); 39089861Sobrien log.popDiagnosticHandler(deferredDiagnosticHandler); 391218822Sdim } 39233965Sjdp } 393130570Sobrien //where 39489861Sobrien protected UnenterScanner unenterScanner = new UnenterScanner(); 395130570Sobrien 39689861Sobrien class UnenterScanner extends TreeScanner { 397130570Sobrien @Override 398130570Sobrien public void visitClassDef(JCClassDecl tree) { 39989861Sobrien ClassSymbol csym = tree.sym; 400130570Sobrien //if something went wrong during method applicability check 401130570Sobrien //it is possible that nested expressions inside argument expression 40289861Sobrien //are left unchecked - in such cases there's nothing to clean up. 403130570Sobrien if (csym == null) return; 404130570Sobrien typeEnvs.remove(csym); 40589861Sobrien chk.compiled.remove(csym.flatname); 406130570Sobrien syms.classes.remove(csym.flatname); 407130570Sobrien super.visitClassDef(tree); 408218822Sdim } 40989861Sobrien } 410130570Sobrien 411130570Sobrien static class DeferredAttrDiagHandler extends Log.DeferredDiagnosticHandler { 412130570Sobrien 413130570Sobrien static class PosScanner extends TreeScanner { 414130570Sobrien DiagnosticPosition pos; 415130570Sobrien boolean found = false; 41689861Sobrien 417130570Sobrien PosScanner(DiagnosticPosition pos) { 418130570Sobrien this.pos = pos; 419130570Sobrien } 420130570Sobrien 421130570Sobrien @Override 422130570Sobrien public void scan(JCTree tree) { 423130570Sobrien if (tree != null && 424130570Sobrien tree.pos() == pos) { 425130570Sobrien found = true; 426218822Sdim } 427130570Sobrien super.scan(tree); 428130570Sobrien } 429130570Sobrien } 430130570Sobrien 431130570Sobrien DeferredAttrDiagHandler(Log log, JCTree newTree) { 43289861Sobrien super(log, new Filter<JCDiagnostic>() { 43389861Sobrien public boolean accepts(JCDiagnostic d) { 434218822Sdim PosScanner posScanner = new PosScanner(d.getDiagnosticPosition()); 43589861Sobrien posScanner.scan(newTree); 43689861Sobrien return posScanner.found; 437130570Sobrien } 438130570Sobrien }); 43989861Sobrien } 440130570Sobrien } 44189861Sobrien 442130570Sobrien /** 44389861Sobrien * A deferred context is created on each method check. A deferred context is 444130570Sobrien * used to keep track of information associated with the method check, such as 445130570Sobrien * the symbol of the method being checked, the overload resolution phase, 446130570Sobrien * the kind of attribution mode to be applied to deferred types and so forth. 447130570Sobrien * As deferred types are processed (by the method check routine) stuck AST nodes 448130570Sobrien * are added (as new deferred attribution nodes) to this context. The complete() 449130570Sobrien * routine makes sure that all pending nodes are properly processed, by 450130570Sobrien * progressively instantiating all inference variables on which one or more 45189861Sobrien * deferred attribution node is stuck. 452130570Sobrien */ 453130570Sobrien class DeferredAttrContext { 454130570Sobrien 455130570Sobrien /** attribution mode */ 456130570Sobrien final AttrMode mode; 457130570Sobrien 45889861Sobrien /** symbol of the method being checked */ 459130570Sobrien final Symbol msym; 460130570Sobrien 461130570Sobrien /** method resolution step */ 462130570Sobrien final Resolve.MethodResolutionPhase phase; 463130570Sobrien 464130570Sobrien /** inference context */ 465130570Sobrien final InferenceContext inferenceContext; 466130570Sobrien 46789861Sobrien /** parent deferred context */ 46889861Sobrien final DeferredAttrContext parent; 46989861Sobrien 47089861Sobrien /** Warner object to report warnings */ 47189861Sobrien final Warner warn; 47289861Sobrien 47389861Sobrien /** list of deferred attribution nodes to be processed */ 47489861Sobrien ArrayList<DeferredAttrNode> deferredAttrNodes = new ArrayList<>(); 47589861Sobrien 47689861Sobrien DeferredAttrContext(AttrMode mode, Symbol msym, MethodResolutionPhase phase, 47789861Sobrien InferenceContext inferenceContext, DeferredAttrContext parent, Warner warn) { 478130570Sobrien this.mode = mode; 47989861Sobrien this.msym = msym; 48089861Sobrien this.phase = phase; 48189861Sobrien this.parent = parent; 48289861Sobrien this.warn = warn; 48389861Sobrien this.inferenceContext = inferenceContext; 48489861Sobrien } 48589861Sobrien 48689861Sobrien /** 48789861Sobrien * Adds a node to the list of deferred attribution nodes - used by Resolve.rawCheckArgumentsApplicable 48889861Sobrien * Nodes added this way act as 'roots' for the out-of-order method checking process. 48989861Sobrien */ 49089861Sobrien void addDeferredAttrNode(final DeferredType dt, ResultInfo resultInfo, 49189861Sobrien DeferredStuckPolicy deferredStuckPolicy) { 49289861Sobrien deferredAttrNodes.add(new DeferredAttrNode(dt, resultInfo, deferredStuckPolicy)); 49389861Sobrien } 49489861Sobrien 49533965Sjdp /** 49633965Sjdp * Incrementally process all nodes, by skipping 'stuck' nodes and attributing 49733965Sjdp * 'unstuck' ones. If at any point no progress can be made (no 'unstuck' nodes) 49868769Sobrien * some inference variable might get eagerly instantiated so that all nodes 49933965Sjdp * can be type-checked. 500130570Sobrien */ 501130570Sobrien void complete() { 502130570Sobrien while (!deferredAttrNodes.isEmpty()) { 503130570Sobrien Map<Type, Set<Type>> depVarsMap = new LinkedHashMap<>(); 504130570Sobrien List<Type> stuckVars = List.nil(); 505130570Sobrien boolean progress = false; 50633965Sjdp //scan a defensive copy of the node list - this is because a deferred 50733965Sjdp //attribution round can add new nodes to the list 50833965Sjdp for (DeferredAttrNode deferredAttrNode : List.from(deferredAttrNodes)) { 50933965Sjdp if (!deferredAttrNode.process(this)) { 51033965Sjdp List<Type> restStuckVars = 511218822Sdim List.from(deferredAttrNode.deferredStuckPolicy.stuckVars()) 512218822Sdim .intersect(inferenceContext.restvars()); 51333965Sjdp stuckVars = stuckVars.prependList(restStuckVars); 514218822Sdim //update dependency map 51533965Sjdp for (Type t : List.from(deferredAttrNode.deferredStuckPolicy.depVars()) 51633965Sjdp .intersect(inferenceContext.restvars())) { 51733965Sjdp Set<Type> prevDeps = depVarsMap.get(t); 51833965Sjdp if (prevDeps == null) { 519218822Sdim prevDeps = new LinkedHashSet<>(); 52033965Sjdp depVarsMap.put(t, prevDeps); 52133965Sjdp } 52233965Sjdp prevDeps.addAll(restStuckVars); 52333965Sjdp } 52433965Sjdp } else { 52533965Sjdp deferredAttrNodes.remove(deferredAttrNode); 52633965Sjdp progress = true; 52733965Sjdp } 52833965Sjdp } 52933965Sjdp if (!progress) { 53033965Sjdp if (insideOverloadPhase()) { 53133965Sjdp for (DeferredAttrNode deferredNode: deferredAttrNodes) { 53233965Sjdp deferredNode.dt.tree.type = Type.noType; 53333965Sjdp } 53433965Sjdp return; 535218822Sdim } 536218822Sdim //remove all variables that have already been instantiated 53733965Sjdp //from the list of stuck variables 538218822Sdim try { 53933965Sjdp inferenceContext.solveAny(stuckVars, depVarsMap, warn); 54033965Sjdp inferenceContext.notifyChange(); 541218822Sdim } catch (Infer.GraphStrategy.NodeNotFoundException ex) { 54233965Sjdp //this means that we are in speculative mode and the 54333965Sjdp //set of contraints are too tight for progess to be made. 54433965Sjdp //Just leave the remaining expressions as stuck. 54533965Sjdp break; 54633965Sjdp } 54733965Sjdp } 54833965Sjdp } 54933965Sjdp } 55033965Sjdp 55133965Sjdp private boolean insideOverloadPhase() { 55233965Sjdp DeferredAttrContext dac = this; 55333965Sjdp if (dac == emptyDeferredAttrContext) { 55433965Sjdp return false; 55533965Sjdp } 556218822Sdim if (dac.mode == AttrMode.SPECULATIVE) { 557218822Sdim return true; 558218822Sdim } 559218822Sdim return dac.parent.insideOverloadPhase(); 560218822Sdim } 561218822Sdim } 56233965Sjdp 56389861Sobrien /** 56489861Sobrien * Class representing a deferred attribution node. It keeps track of 56589861Sobrien * a deferred type, along with the expected target type information. 56689861Sobrien */ 56733965Sjdp class DeferredAttrNode { 56889861Sobrien 56989861Sobrien /** underlying deferred type */ 57089861Sobrien DeferredType dt; 57133965Sjdp 57289861Sobrien /** underlying target type information */ 57389861Sobrien ResultInfo resultInfo; 57489861Sobrien 57589861Sobrien /** stuck policy associated with this node */ 57633965Sjdp DeferredStuckPolicy deferredStuckPolicy; 57789861Sobrien 57889861Sobrien DeferredAttrNode(DeferredType dt, ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy) { 57989861Sobrien this.dt = dt; 58033965Sjdp this.resultInfo = resultInfo; 58133965Sjdp this.deferredStuckPolicy = deferredStuckPolicy; 58233965Sjdp } 58333965Sjdp 58433965Sjdp /** 58533965Sjdp * Process a deferred attribution node. 58689861Sobrien * Invariant: a stuck node cannot be processed. 58733965Sjdp */ 58889861Sobrien @SuppressWarnings("fallthrough") 58989861Sobrien boolean process(final DeferredAttrContext deferredAttrContext) { 590104840Sobrien switch (deferredAttrContext.mode) { 591104840Sobrien case SPECULATIVE: 592104840Sobrien if (deferredStuckPolicy.isStuck()) { 593104840Sobrien dt.check(resultInfo, dummyStuckPolicy, new StructuralStuckChecker()); 594104840Sobrien return true; 595104840Sobrien } else { 596104840Sobrien Assert.error("Cannot get here"); 597104840Sobrien } 598218822Sdim case CHECK: 599218822Sdim if (deferredStuckPolicy.isStuck()) { 600218822Sdim //stuck expression - see if we can propagate 601218822Sdim if (deferredAttrContext.parent != emptyDeferredAttrContext && 602218822Sdim Type.containsAny(deferredAttrContext.parent.inferenceContext.inferencevars, 603218822Sdim List.from(deferredStuckPolicy.stuckVars()))) { 604218822Sdim deferredAttrContext.parent.addDeferredAttrNode(dt, 605218822Sdim resultInfo.dup(new Check.NestedCheckContext(resultInfo.checkContext) { 606218822Sdim @Override 607104840Sobrien public InferenceContext inferenceContext() { 608218822Sdim return deferredAttrContext.parent.inferenceContext; 609218822Sdim } 610218822Sdim @Override 611218822Sdim public DeferredAttrContext deferredAttrContext() { 61233965Sjdp return deferredAttrContext.parent; 61333965Sjdp } 614104840Sobrien }), deferredStuckPolicy); 615104840Sobrien dt.tree.type = Type.stuckType; 616104840Sobrien return true; 617104840Sobrien } else { 618104840Sobrien return false; 619104840Sobrien } 620104840Sobrien } else { 621104840Sobrien Assert.check(!deferredAttrContext.insideOverloadPhase(), 622218822Sdim "attribution shouldn't be happening here"); 623218822Sdim ResultInfo instResultInfo = 624218822Sdim resultInfo.dup(deferredAttrContext.inferenceContext.asInstType(resultInfo.pt)); 625104840Sobrien dt.check(instResultInfo, dummyStuckPolicy, basicCompleter); 626104840Sobrien return true; 627104840Sobrien } 628104840Sobrien default: 629104840Sobrien throw new AssertionError("Bad mode"); 630104840Sobrien } 631104840Sobrien } 632104840Sobrien 633218822Sdim /** 634218822Sdim * Structural checker for stuck expressions 635218822Sdim */ 636130570Sobrien class StructuralStuckChecker extends TreeScanner implements DeferredTypeCompleter { 637130570Sobrien 638104840Sobrien ResultInfo resultInfo; 639104840Sobrien InferenceContext inferenceContext; 640218822Sdim Env<AttrContext> env; 641218822Sdim 642218822Sdim public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) { 643218822Sdim this.resultInfo = resultInfo; 644218822Sdim this.inferenceContext = deferredAttrContext.inferenceContext; 645218822Sdim this.env = dt.env; 646218822Sdim dt.tree.accept(this); 647104840Sobrien dt.speculativeCache.put(stuckTree, resultInfo); 648104840Sobrien return Type.noType; 64933965Sjdp } 65033965Sjdp 65133965Sjdp @Override 65233965Sjdp public void visitLambda(JCLambda tree) { 65389861Sobrien Check.CheckContext checkContext = resultInfo.checkContext; 65433965Sjdp Type pt = resultInfo.pt; 65589861Sobrien if (!inferenceContext.inferencevars.contains(pt)) { 65689861Sobrien //must be a functional descriptor 65789861Sobrien Type descriptorType = null; 65889861Sobrien try { 65989861Sobrien descriptorType = types.findDescriptorType(pt); 66089861Sobrien } catch (Types.FunctionDescriptorLookupError ex) { 66189861Sobrien checkContext.report(null, ex.getDiagnostic()); 66289861Sobrien } 66333965Sjdp 664218822Sdim if (descriptorType.getParameterTypes().length() != tree.params.length()) { 665218822Sdim checkContext.report(tree, 666218822Sdim diags.fragment("incompatible.arg.types.in.lambda")); 667218822Sdim } 668218822Sdim 669218822Sdim Type currentReturnType = descriptorType.getReturnType(); 670218822Sdim boolean returnTypeIsVoid = currentReturnType.hasTag(VOID); 671218822Sdim if (tree.getBodyKind() == BodyKind.EXPRESSION) { 672218822Sdim boolean isExpressionCompatible = !returnTypeIsVoid || 673218822Sdim TreeInfo.isExpressionStatement((JCExpression)tree.getBody()); 674218822Sdim if (!isExpressionCompatible) { 675218822Sdim resultInfo.checkContext.report(tree.pos(), 676104840Sobrien diags.fragment("incompatible.ret.type.in.lambda", 677104840Sobrien diags.fragment("missing.ret.val", currentReturnType))); 678104840Sobrien } 679104840Sobrien } else { 680104840Sobrien LambdaBodyStructChecker lambdaBodyChecker = 681218822Sdim new LambdaBodyStructChecker(); 682218822Sdim 683218822Sdim tree.body.accept(lambdaBodyChecker); 684218822Sdim boolean isVoidCompatible = lambdaBodyChecker.isVoidCompatible; 68589861Sobrien 68689861Sobrien if (returnTypeIsVoid) { 68789861Sobrien if (!isVoidCompatible) { 68833965Sjdp resultInfo.checkContext.report(tree.pos(), 68933965Sjdp diags.fragment("unexpected.ret.val")); 69033965Sjdp } 69133965Sjdp } else { 69233965Sjdp boolean isValueCompatible = lambdaBodyChecker.isPotentiallyValueCompatible 69333965Sjdp && !canLambdaBodyCompleteNormally(tree); 694218822Sdim if (!isValueCompatible && !isVoidCompatible) { 695218822Sdim log.error(tree.body.pos(), 696218822Sdim "lambda.body.neither.value.nor.void.compatible"); 69733965Sjdp } 69833965Sjdp 69933965Sjdp if (!isValueCompatible) { 700130570Sobrien resultInfo.checkContext.report(tree.pos(), 701130570Sobrien diags.fragment("incompatible.ret.type.in.lambda", 702130570Sobrien diags.fragment("missing.ret.val", currentReturnType))); 70333965Sjdp } 70433965Sjdp } 70533965Sjdp } 70689861Sobrien } 70789861Sobrien } 70889861Sobrien 70989861Sobrien boolean canLambdaBodyCompleteNormally(JCLambda tree) { 71089861Sobrien JCLambda newTree = new TreeCopier<>(make).copy(tree); 71189861Sobrien /* attr.lambdaEnv will create a meaningful env for the 71289861Sobrien * lambda expression. This is specially useful when the 71333965Sjdp * lambda is used as the init of a field. But we need to 71433965Sjdp * remove any added symbol. 71589861Sobrien */ 71689861Sobrien Env<AttrContext> localEnv = attr.lambdaEnv(newTree, env); 71733965Sjdp try { 71889861Sobrien List<JCVariableDecl> tmpParams = newTree.params; 71989861Sobrien while (tmpParams.nonEmpty()) { 72089861Sobrien tmpParams.head.vartype = make.at(tmpParams.head).Type(syms.errType); 72189861Sobrien tmpParams = tmpParams.tail; 722104840Sobrien } 723218822Sdim 72433965Sjdp attr.attribStats(newTree.params, localEnv); 72533965Sjdp 72689861Sobrien /* set pt to Type.noType to avoid generating any bound 72733965Sjdp * which may happen if lambda's return type is an 72833965Sjdp * inference variable 72933965Sjdp */ 73033965Sjdp Attr.ResultInfo bodyResultInfo = attr.new ResultInfo(KindSelector.VAL, Type.noType); 73133965Sjdp localEnv.info.returnResult = bodyResultInfo; 732130570Sobrien 73333965Sjdp // discard any log output 73433965Sjdp Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log); 73589861Sobrien try { 73633965Sjdp JCBlock body = (JCBlock)newTree.body; 737130570Sobrien /* we need to attribute the lambda body before 73889861Sobrien * doing the aliveness analysis. This is because 73933965Sjdp * constant folding occurs during attribution 74033965Sjdp * and the reachability of some statements depends 741218822Sdim * on constant values, for example: 742218822Sdim * 74333965Sjdp * while (true) {...} 744104840Sobrien */ 74533965Sjdp attr.attribStats(body.stats, localEnv); 74633965Sjdp 74733965Sjdp attr.preFlow(newTree); 74889861Sobrien /* make an aliveness / reachability analysis of the lambda 74989861Sobrien * to determine if it can complete normally 75089861Sobrien */ 75189861Sobrien flow.analyzeLambda(localEnv, newTree, make, true); 75289861Sobrien } finally { 75389861Sobrien log.popDiagnosticHandler(diagHandler); 75489861Sobrien } 755104840Sobrien return newTree.canCompleteNormally; 756218822Sdim } finally { 757218822Sdim JCBlock body = (JCBlock)newTree.body; 75889861Sobrien unenterScanner.scan(body.stats); 759218822Sdim localEnv.info.scope.leave(); 760218822Sdim } 761218822Sdim } 76289861Sobrien 76389861Sobrien @Override 76433965Sjdp public void visitNewClass(JCNewClass tree) { 76533965Sjdp //do nothing 76689861Sobrien } 76789861Sobrien 76889861Sobrien @Override 769130570Sobrien public void visitApply(JCMethodInvocation tree) { 770130570Sobrien //do nothing 77189861Sobrien } 77289861Sobrien 77389861Sobrien @Override 77489861Sobrien public void visitReference(JCMemberReference tree) { 775130570Sobrien Check.CheckContext checkContext = resultInfo.checkContext; 77689861Sobrien Type pt = resultInfo.pt; 77789861Sobrien if (!inferenceContext.inferencevars.contains(pt)) { 77889861Sobrien try { 77989861Sobrien types.findDescriptorType(pt); 78089861Sobrien } catch (Types.FunctionDescriptorLookupError ex) { 78189861Sobrien checkContext.report(null, ex.getDiagnostic()); 78289861Sobrien } 783218822Sdim Env<AttrContext> localEnv = env.dup(tree); 784218822Sdim JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv, 785218822Sdim attr.memberReferenceQualifierResult(tree)); 786218822Sdim ListBuffer<Type> argtypes = new ListBuffer<>(); 787218822Sdim for (Type t : types.findDescriptorType(pt).getParameterTypes()) { 788218822Sdim argtypes.append(Type.noType); 78989861Sobrien } 79089861Sobrien JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree); 791130570Sobrien mref2.expr = exprTree; 792130570Sobrien Symbol lookupSym = 79389861Sobrien rs.resolveMemberReference(localEnv, mref2, exprTree.type, 79489861Sobrien tree.name, argtypes.toList(), List.nil(), rs.arityMethodCheck, 79589861Sobrien inferenceContext, rs.structuralReferenceChooser).fst; 79689861Sobrien switch (lookupSym.kind) { 79789861Sobrien case WRONG_MTH: 79889861Sobrien case WRONG_MTHS: 799130570Sobrien //note: as argtypes are erroneous types, type-errors must 800130570Sobrien //have been caused by arity mismatch 80189861Sobrien checkContext.report(tree, diags.fragment(Fragments.IncompatibleArgTypesInMref)); 80289861Sobrien break; 80389861Sobrien case ABSENT_MTH: 80489861Sobrien case STATICERR: 80589861Sobrien //if no method found, or method found with wrong staticness, report better message 806130570Sobrien checkContext.report(tree, ((ResolveError)lookupSym).getDiagnostic(DiagnosticType.FRAGMENT, 80789861Sobrien tree, exprTree.type.tsym, exprTree.type, tree.name, argtypes.toList(), List.nil())); 80889861Sobrien break; 809130570Sobrien } 81089861Sobrien } 81189861Sobrien } 81289861Sobrien } 81389861Sobrien 81489861Sobrien /* This visitor looks for return statements, its analysis will determine if 81589861Sobrien * a lambda body is void or value compatible. We must analyze return 81689861Sobrien * statements contained in the lambda body only, thus any return statement 81789861Sobrien * contained in an inner class or inner lambda body, should be ignored. 81889861Sobrien */ 81989861Sobrien class LambdaBodyStructChecker extends TreeScanner { 82089861Sobrien boolean isVoidCompatible = true; 821218822Sdim boolean isPotentiallyValueCompatible = true; 822218822Sdim 823218822Sdim @Override 824218822Sdim public void visitClassDef(JCClassDecl tree) { 825130570Sobrien // do nothing 82689861Sobrien } 82789861Sobrien 82889861Sobrien @Override 82989861Sobrien public void visitLambda(JCLambda tree) { 83089861Sobrien // do nothing 831218822Sdim } 832130570Sobrien 833130570Sobrien @Override 83489861Sobrien public void visitNewClass(JCNewClass tree) { 83589861Sobrien // do nothing 83689861Sobrien } 83789861Sobrien 83889861Sobrien @Override 83989861Sobrien public void visitReturn(JCReturn tree) { 84089861Sobrien if (tree.expr != null) { 84189861Sobrien isVoidCompatible = false; 84289861Sobrien } else { 84389861Sobrien isPotentiallyValueCompatible = false; 84489861Sobrien } 84589861Sobrien } 84689861Sobrien } 847218822Sdim } 84889861Sobrien 84989861Sobrien /** an empty deferred attribution context - all methods throw exceptions */ 85089861Sobrien final DeferredAttrContext emptyDeferredAttrContext; 85189861Sobrien 85289861Sobrien /** The AttrMode to descriptive name mapping */ 85389861Sobrien private static final EnumMap<AttrMode, String> deferredTypeMapDescriptions; 85489861Sobrien static { 85589861Sobrien deferredTypeMapDescriptions = new EnumMap<>(AttrMode.class); 85689861Sobrien deferredTypeMapDescriptions.put(AttrMode.CHECK, "deferredTypeMap[CHECK]"); 85789861Sobrien deferredTypeMapDescriptions.put(AttrMode.SPECULATIVE, "deferredTypeMap[SPECULATIVE]"); 85889861Sobrien } 85989861Sobrien 86089861Sobrien /** 86189861Sobrien * Map a list of types possibly containing one or more deferred types 86289861Sobrien * into a list of ordinary types. Each deferred type D is mapped into a type T, 86389861Sobrien * where T is computed by retrieving the type that has already been 86489861Sobrien * computed for D during a previous deferred attribution round of the given kind. 86589861Sobrien */ 86689861Sobrien class DeferredTypeMap extends Type.Mapping { 86789861Sobrien DeferredAttrContext deferredAttrContext; 86889861Sobrien 86989861Sobrien protected DeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) { 87089861Sobrien super(deferredTypeMapDescriptions.get(mode)); 871104840Sobrien this.deferredAttrContext = new DeferredAttrContext(mode, msym, phase, 872104840Sobrien infer.emptyContext, emptyDeferredAttrContext, types.noWarnings); 873104840Sobrien } 874104840Sobrien 875104840Sobrien @Override 876104840Sobrien public Type apply(Type t) { 877130570Sobrien if (!t.hasTag(DEFERRED)) { 878130570Sobrien return t.map(this); 879130570Sobrien } else { 880218822Sdim DeferredType dt = (DeferredType)t; 881218822Sdim return typeOf(dt); 882218822Sdim } 883218822Sdim } 884218822Sdim 885218822Sdim protected Type typeOf(DeferredType dt) { 886218822Sdim switch (deferredAttrContext.mode) { 887218822Sdim case CHECK: 888218822Sdim return dt.tree.type == null ? Type.noType : dt.tree.type; 889218822Sdim case SPECULATIVE: 890218822Sdim return dt.speculativeType(deferredAttrContext.msym, deferredAttrContext.phase); 891130570Sobrien } 892218822Sdim Assert.error(); 89389861Sobrien return null; 89489861Sobrien } 895104840Sobrien } 896130570Sobrien 897104840Sobrien /** 898104840Sobrien * Specialized recovery deferred mapping. 899104840Sobrien * Each deferred type D is mapped into a type T, where T is computed either by 900104840Sobrien * (i) retrieving the type that has already been computed for D during a previous 901104840Sobrien * attribution round (as before), or (ii) by synthesizing a new type R for D 902104840Sobrien * (the latter step is useful in a recovery scenario). 903104840Sobrien */ 904218822Sdim public class RecoveryDeferredTypeMap extends DeferredTypeMap { 905218822Sdim 906104840Sobrien public RecoveryDeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) { 907104840Sobrien super(mode, msym, phase != null ? phase : MethodResolutionPhase.BOX); 908104840Sobrien } 909104840Sobrien 910104840Sobrien @Override 911104840Sobrien protected Type typeOf(DeferredType dt) { 912104840Sobrien Type owntype = super.typeOf(dt); 913104840Sobrien return owntype == Type.noType ? 914104840Sobrien recover(dt) : owntype; 915104840Sobrien } 916104840Sobrien 917104840Sobrien /** 918104840Sobrien * Synthesize a type for a deferred type that hasn't been previously 919104840Sobrien * reduced to an ordinary type. Functional deferred types and conditionals 920104840Sobrien * are mapped to themselves, in order to have a richer diagnostic 921104840Sobrien * representation. Remaining deferred types are attributed using 92233965Sjdp * a default expected type (j.l.Object). 92389861Sobrien */ 92489861Sobrien private Type recover(DeferredType dt) { 92533965Sjdp dt.check(attr.new RecoveryInfo(deferredAttrContext) { 926130570Sobrien @Override 927130570Sobrien protected Type check(DiagnosticPosition pos, Type found) { 928130570Sobrien return chk.checkNonVoid(pos, super.check(pos, found)); 929130570Sobrien } 930130570Sobrien }); 93133965Sjdp return super.apply(dt); 93289861Sobrien } 93333965Sjdp } 93433965Sjdp 93533965Sjdp /** 93633965Sjdp * A special tree scanner that would only visit portions of a given tree. 93733965Sjdp * The set of nodes visited by the scanner can be customized at construction-time. 93833965Sjdp */ 939130570Sobrien abstract static class FilterScanner extends TreeScanner { 940130570Sobrien 94133965Sjdp final Filter<JCTree> treeFilter; 94289861Sobrien 94333965Sjdp FilterScanner(final Set<JCTree.Tag> validTags) { 94433965Sjdp this.treeFilter = new Filter<JCTree>() { 94533965Sjdp public boolean accepts(JCTree t) { 94633965Sjdp return validTags.contains(t.getTag()); 94733965Sjdp } 94833965Sjdp }; 94933965Sjdp } 95033965Sjdp 951104840Sobrien @Override 95233965Sjdp public void scan(JCTree tree) { 95333965Sjdp if (tree != null) { 95433965Sjdp if (treeFilter.accepts(tree)) { 95533965Sjdp super.scan(tree); 956104840Sobrien } else { 95733965Sjdp skip(tree); 95878832Sobrien } 95978832Sobrien } 960218822Sdim } 961218822Sdim 96289861Sobrien /** 963130570Sobrien * handler that is executed when a node has been discarded 96478832Sobrien */ 96578832Sobrien void skip(JCTree tree) {} 96633965Sjdp } 96733965Sjdp 96833965Sjdp /** 969218822Sdim * A tree scanner suitable for visiting the target-type dependent nodes of 970218822Sdim * a given argument expression. 971218822Sdim */ 972218822Sdim static class PolyScanner extends FilterScanner { 973218822Sdim 974218822Sdim PolyScanner() { 97533965Sjdp super(EnumSet.of(CONDEXPR, PARENS, LAMBDA, REFERENCE)); 976104840Sobrien } 977104840Sobrien } 978104840Sobrien 97933965Sjdp /** 980104840Sobrien * A tree scanner suitable for visiting the target-type dependent nodes nested 981104840Sobrien * within a lambda expression body. 982104840Sobrien */ 983104840Sobrien static class LambdaReturnScanner extends FilterScanner { 984104840Sobrien 985104840Sobrien LambdaReturnScanner() { 986104840Sobrien super(EnumSet.of(BLOCK, CASE, CATCH, DOLOOP, FOREACHLOOP, 987104840Sobrien FORLOOP, IF, RETURN, SYNCHRONIZED, SWITCH, TRY, WHILELOOP)); 988104840Sobrien } 989104840Sobrien } 990104840Sobrien 991104840Sobrien /** 992104840Sobrien * This visitor is used to check that structural expressions conform 993104840Sobrien * to their target - this step is required as inference could end up 994104840Sobrien * inferring types that make some of the nested expressions incompatible 995104840Sobrien * with their corresponding instantiated target 996104840Sobrien */ 997218822Sdim class CheckStuckPolicy extends PolyScanner implements DeferredStuckPolicy, Infer.FreeTypeListener { 998104840Sobrien 999104840Sobrien Type pt; 1000104840Sobrien Infer.InferenceContext inferenceContext; 1001104840Sobrien Set<Type> stuckVars = new LinkedHashSet<>(); 1002104840Sobrien Set<Type> depVars = new LinkedHashSet<>(); 1003104840Sobrien 1004104840Sobrien @Override 1005104840Sobrien public boolean isStuck() { 1006104840Sobrien return !stuckVars.isEmpty(); 1007104840Sobrien } 100833965Sjdp 1009104840Sobrien @Override 1010218822Sdim public Set<Type> stuckVars() { 1011218822Sdim return stuckVars; 101233965Sjdp } 1013104840Sobrien 1014104840Sobrien @Override 101589861Sobrien public Set<Type> depVars() { 1016104840Sobrien return depVars; 1017104840Sobrien } 1018104840Sobrien 1019104840Sobrien public CheckStuckPolicy(ResultInfo resultInfo, DeferredType dt) { 1020104840Sobrien this.pt = resultInfo.pt; 1021218822Sdim this.inferenceContext = resultInfo.checkContext.inferenceContext(); 1022218822Sdim scan(dt.tree); 1023218822Sdim if (!stuckVars.isEmpty()) { 1024104840Sobrien resultInfo.checkContext.inferenceContext() 1025104840Sobrien .addFreeTypeListener(List.from(stuckVars), this); 1026104840Sobrien } 1027104840Sobrien } 1028104840Sobrien 1029104840Sobrien @Override 1030104840Sobrien public void typesInferred(InferenceContext inferenceContext) { 1031104840Sobrien stuckVars.clear(); 1032104840Sobrien } 1033104840Sobrien 1034104840Sobrien @Override 1035104840Sobrien public void visitLambda(JCLambda tree) { 103633965Sjdp if (inferenceContext.inferenceVars().contains(pt)) { 1037104840Sobrien stuckVars.add(pt); 1038104840Sobrien } 1039104840Sobrien if (!types.isFunctionalInterface(pt)) { 1040104840Sobrien return; 1041104840Sobrien } 1042104840Sobrien Type descType = types.findDescriptorType(pt); 1043104840Sobrien List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes()); 1044104840Sobrien if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT && 1045104840Sobrien freeArgVars.nonEmpty()) { 1046104840Sobrien stuckVars.addAll(freeArgVars); 1047104840Sobrien depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType())); 1048104840Sobrien } 1049104840Sobrien scanLambdaBody(tree, descType.getReturnType()); 1050104840Sobrien } 1051104840Sobrien 1052104840Sobrien @Override 1053218822Sdim public void visitReference(JCMemberReference tree) { 1054218822Sdim scan(tree.expr); 1055130570Sobrien if (inferenceContext.inferenceVars().contains(pt)) { 1056104840Sobrien stuckVars.add(pt); 1057130570Sobrien return; 1058104840Sobrien } 1059218822Sdim if (!types.isFunctionalInterface(pt)) { 1060218822Sdim return; 1061104840Sobrien } 1062218822Sdim 1063104840Sobrien Type descType = types.findDescriptorType(pt); 1064104840Sobrien List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes()); 1065104840Sobrien if (freeArgVars.nonEmpty() && 1066104840Sobrien tree.overloadKind == JCMemberReference.OverloadKind.OVERLOADED) { 1067104840Sobrien stuckVars.addAll(freeArgVars); 1068104840Sobrien depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType())); 1069104840Sobrien } 1070104840Sobrien } 1071104840Sobrien 1072104840Sobrien void scanLambdaBody(JCLambda lambda, final Type pt) { 1073218822Sdim if (lambda.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) { 1074104840Sobrien Type prevPt = this.pt; 1075104840Sobrien try { 1076218822Sdim this.pt = pt; 1077104840Sobrien scan(lambda.body); 1078218822Sdim } finally { 1079218822Sdim this.pt = prevPt; 1080218822Sdim } 1081104840Sobrien } else { 1082104840Sobrien LambdaReturnScanner lambdaScanner = new LambdaReturnScanner() { 1083104840Sobrien @Override 1084218822Sdim public void visitReturn(JCReturn tree) { 1085130570Sobrien if (tree.expr != null) { 1086218822Sdim Type prevPt = CheckStuckPolicy.this.pt; 1087104840Sobrien try { 1088130570Sobrien CheckStuckPolicy.this.pt = pt; 1089104840Sobrien CheckStuckPolicy.this.scan(tree.expr); 1090104840Sobrien } finally { 1091104840Sobrien CheckStuckPolicy.this.pt = prevPt; 1092104840Sobrien } 1093104840Sobrien } 1094104840Sobrien } 1095104840Sobrien }; 1096104840Sobrien lambdaScanner.scan(lambda.body); 1097104840Sobrien } 1098104840Sobrien } 1099104840Sobrien } 110089861Sobrien 110133965Sjdp /** 110289861Sobrien * This visitor is used to check that structural expressions conform 110389861Sobrien * to their target - this step is required as inference could end up 1104104840Sobrien * inferring types that make some of the nested expressions incompatible 110589861Sobrien * with their corresponding instantiated target 110689861Sobrien */ 110789861Sobrien class OverloadStuckPolicy extends CheckStuckPolicy implements DeferredStuckPolicy { 110889861Sobrien 110989861Sobrien boolean stuck; 1110130570Sobrien 111133965Sjdp @Override 1112104840Sobrien public boolean isStuck() { 1113104840Sobrien return super.isStuck() || stuck; 1114104840Sobrien } 111533965Sjdp 1116104840Sobrien public OverloadStuckPolicy(ResultInfo resultInfo, DeferredType dt) { 1117104840Sobrien super(resultInfo, dt); 1118104840Sobrien } 1119104840Sobrien 1120130570Sobrien @Override 1121130570Sobrien public void visitLambda(JCLambda tree) { 112233965Sjdp super.visitLambda(tree); 112333965Sjdp if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT) { 112433965Sjdp stuck = true; 112589861Sobrien } 112689861Sobrien } 112789861Sobrien 112889861Sobrien @Override 112989861Sobrien public void visitReference(JCMemberReference tree) { 113089861Sobrien super.visitReference(tree); 113189861Sobrien if (tree.overloadKind == JCMemberReference.OverloadKind.OVERLOADED) { 113289861Sobrien stuck = true; 1133218822Sdim } 113460509Sobrien } 113589861Sobrien } 113689861Sobrien 113789861Sobrien /** 1138130570Sobrien * Does the argument expression {@code expr} need speculative type-checking? 1139218822Sdim */ 114089861Sobrien boolean isDeferred(Env<AttrContext> env, JCExpression expr) { 114189861Sobrien DeferredChecker dc = new DeferredChecker(env); 114233965Sjdp dc.scan(expr); 114377302Sobrien return dc.result.isPoly(); 114477302Sobrien } 114577302Sobrien 114677302Sobrien /** 114777302Sobrien * The kind of an argument expression. This is used by the analysis that 114877302Sobrien * determines as to whether speculative attribution is necessary. 114977302Sobrien */ 115077302Sobrien enum ArgumentExpressionKind { 115177302Sobrien 115277302Sobrien /** kind that denotes poly argument expression */ 115389861Sobrien POLY, 115477302Sobrien /** kind that denotes a standalone expression */ 115577302Sobrien NO_POLY, 115677302Sobrien /** kind that denotes a primitive/boxed standalone expression */ 115789861Sobrien PRIMITIVE; 115889861Sobrien 115989861Sobrien /** 116089861Sobrien * Does this kind denote a poly argument expression 116189861Sobrien */ 116289861Sobrien public final boolean isPoly() { 116389861Sobrien return this == POLY; 116489861Sobrien } 1165104840Sobrien 116689861Sobrien /** 1167218822Sdim * Does this kind denote a primitive standalone expression 116889861Sobrien */ 1169218822Sdim public final boolean isPrimitive() { 1170130570Sobrien return this == PRIMITIVE; 1171130570Sobrien } 117289861Sobrien 117389861Sobrien /** 117489861Sobrien * Compute the kind of a standalone expression of a given type 1175218822Sdim */ 117633965Sjdp static ArgumentExpressionKind standaloneKind(Type type, Types types) { 117789861Sobrien return types.unboxedTypeOrType(type).isPrimitive() ? 117889861Sobrien ArgumentExpressionKind.PRIMITIVE : 117989861Sobrien ArgumentExpressionKind.NO_POLY; 118089861Sobrien } 118189861Sobrien 118289861Sobrien /** 118333965Sjdp * Compute the kind of a method argument expression given its symbol 118433965Sjdp */ 118533965Sjdp static ArgumentExpressionKind methodKind(Symbol sym, Types types) { 118689861Sobrien Type restype = sym.type.getReturnType(); 118794543Sobrien if (sym.type.hasTag(FORALL) && 118894543Sobrien restype.containsAny(((ForAll)sym.type).tvars)) { 118933965Sjdp return ArgumentExpressionKind.POLY; 119094543Sobrien } else { 119133965Sjdp return ArgumentExpressionKind.standaloneKind(restype, types); 1192130570Sobrien } 119333965Sjdp } 1194218822Sdim } 119577302Sobrien 119677302Sobrien /** 119777302Sobrien * Tree scanner used for checking as to whether an argument expression 119889861Sobrien * requires speculative attribution 1199218822Sdim */ 1200218822Sdim final class DeferredChecker extends FilterScanner { 120178832Sobrien 120233965Sjdp Env<AttrContext> env; 120389861Sobrien ArgumentExpressionKind result; 120489861Sobrien 120589861Sobrien public DeferredChecker(Env<AttrContext> env) { 120689861Sobrien super(deferredCheckerTags); 120733965Sjdp this.env = env; 120833965Sjdp } 120933965Sjdp 121033965Sjdp @Override 121133965Sjdp public void visitLambda(JCLambda tree) { 121233965Sjdp //a lambda is always a poly expression 121333965Sjdp result = ArgumentExpressionKind.POLY; 121433965Sjdp } 121533965Sjdp 1216218822Sdim @Override 1217218822Sdim public void visitReference(JCMemberReference tree) { 1218218822Sdim //perform arity-based check 121933965Sjdp Env<AttrContext> localEnv = env.dup(tree); 122033965Sjdp JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv, 1221130570Sobrien attr.memberReferenceQualifierResult(tree)); 122233965Sjdp JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree); 122389861Sobrien mref2.expr = exprTree; 122433965Sjdp Symbol res = 122533965Sjdp rs.getMemberReference(tree, localEnv, mref2, 122689861Sobrien exprTree.type, tree.name); 122789861Sobrien tree.sym = res; 122889861Sobrien if (res.kind.isOverloadError() || 122933965Sjdp res.type.hasTag(FORALL) || 123089861Sobrien (res.flags() & Flags.VARARGS) != 0 || 123189861Sobrien (TreeInfo.isStaticSelector(exprTree, tree.name.table.names) && 123289861Sobrien exprTree.type.isRaw())) { 123389861Sobrien tree.overloadKind = JCMemberReference.OverloadKind.OVERLOADED; 1234218822Sdim } else { 123589861Sobrien tree.overloadKind = JCMemberReference.OverloadKind.UNOVERLOADED; 123689861Sobrien } 123789861Sobrien //a method reference is always a poly expression 123833965Sjdp result = ArgumentExpressionKind.POLY; 123989861Sobrien } 124089861Sobrien 124189861Sobrien @Override 124289861Sobrien public void visitTypeCast(JCTypeCast tree) { 1243130570Sobrien //a cast is always a standalone expression 124433965Sjdp result = ArgumentExpressionKind.NO_POLY; 1245218822Sdim } 1246218822Sdim 124789861Sobrien @Override 124833965Sjdp public void visitConditional(JCConditional tree) { 124989861Sobrien scan(tree.truepart); 125089861Sobrien if (!result.isPrimitive()) { 125189861Sobrien result = ArgumentExpressionKind.POLY; 125289861Sobrien return; 1253130570Sobrien } 125433965Sjdp scan(tree.falsepart); 1255130570Sobrien result = reduce(ArgumentExpressionKind.PRIMITIVE).isPrimitive() ? 125689861Sobrien ArgumentExpressionKind.PRIMITIVE : 125789861Sobrien ArgumentExpressionKind.POLY; 125889861Sobrien 125989861Sobrien } 126089861Sobrien 126189861Sobrien @Override 126233965Sjdp public void visitNewClass(JCNewClass tree) { 126389861Sobrien result = TreeInfo.isDiamond(tree) ? 1264104840Sobrien ArgumentExpressionKind.POLY : ArgumentExpressionKind.NO_POLY; 126589861Sobrien } 126633965Sjdp 126733965Sjdp @Override 126833965Sjdp public void visitApply(JCMethodInvocation tree) { 126960509Sobrien Name name = TreeInfo.name(tree.meth); 127060509Sobrien 127160509Sobrien //fast path 1272130570Sobrien if (tree.typeargs.nonEmpty() || 1273130570Sobrien name == name.table.names._this || 127460509Sobrien name == name.table.names._super) { 127560509Sobrien result = ArgumentExpressionKind.NO_POLY; 127660509Sobrien return; 127760509Sobrien } 127860509Sobrien 1279130570Sobrien //slow path 1280130570Sobrien Symbol sym = quicklyResolveMethod(env, tree); 128160509Sobrien 128260509Sobrien if (sym == null) { 128333965Sjdp result = ArgumentExpressionKind.POLY; 128433965Sjdp return; 128533965Sjdp } 128633965Sjdp 128733965Sjdp result = analyzeCandidateMethods(sym, ArgumentExpressionKind.PRIMITIVE, 1288130570Sobrien argumentKindAnalyzer); 128933965Sjdp } 129033965Sjdp //where 129160509Sobrien private boolean isSimpleReceiver(JCTree rec) { 129260509Sobrien switch (rec.getTag()) { 129360509Sobrien case IDENT: 129460509Sobrien return true; 1295130570Sobrien case SELECT: 1296218822Sdim return isSimpleReceiver(((JCFieldAccess)rec).selected); 1297130570Sobrien case TYPEAPPLY: 1298130570Sobrien case TYPEARRAY: 1299130570Sobrien return true; 130060509Sobrien case ANNOTATED_TYPE: 130160509Sobrien return isSimpleReceiver(((JCAnnotatedType)rec).underlyingType); 1302218822Sdim case APPLY: 1303218822Sdim return true; 1304218822Sdim default: 1305218822Sdim return false; 1306218822Sdim } 1307218822Sdim } 130860509Sobrien private ArgumentExpressionKind reduce(ArgumentExpressionKind kind) { 1309218822Sdim return argumentKindAnalyzer.reduce(result, kind); 131060509Sobrien } 131160509Sobrien MethodAnalyzer<ArgumentExpressionKind> argumentKindAnalyzer = 131260509Sobrien new MethodAnalyzer<ArgumentExpressionKind>() { 131360509Sobrien @Override 1314130570Sobrien public ArgumentExpressionKind process(MethodSymbol ms) { 1315130570Sobrien return ArgumentExpressionKind.methodKind(ms, types); 1316130570Sobrien } 1317130570Sobrien @Override 1318130570Sobrien public ArgumentExpressionKind reduce(ArgumentExpressionKind kind1, 131960509Sobrien ArgumentExpressionKind kind2) { 132077302Sobrien switch (kind1) { 132177302Sobrien case PRIMITIVE: return kind2; 132277302Sobrien case NO_POLY: return kind2.isPoly() ? kind2 : kind1; 132377302Sobrien case POLY: return kind1; 132460509Sobrien default: 132589861Sobrien Assert.error(); 132689861Sobrien return null; 132777302Sobrien } 132877302Sobrien } 132977302Sobrien @Override 133077302Sobrien public boolean shouldStop(ArgumentExpressionKind result) { 133177302Sobrien return result.isPoly(); 133277302Sobrien } 1333130570Sobrien }; 1334130570Sobrien 1335130570Sobrien @Override 1336130570Sobrien public void visitLiteral(JCLiteral tree) { 1337104840Sobrien Type litType = attr.litType(tree.typetag); 1338130570Sobrien result = ArgumentExpressionKind.standaloneKind(litType, types); 1339130570Sobrien } 1340130570Sobrien 1341130570Sobrien @Override 1342130570Sobrien void skip(JCTree tree) { 1343130570Sobrien result = ArgumentExpressionKind.NO_POLY; 134477302Sobrien } 1345130570Sobrien 1346218822Sdim private Symbol quicklyResolveMethod(Env<AttrContext> env, final JCMethodInvocation tree) { 1347218822Sdim final JCExpression rec = tree.meth.hasTag(SELECT) ? 1348218822Sdim ((JCFieldAccess)tree.meth).selected : 1349130570Sobrien null; 1350104840Sobrien 1351130570Sobrien if (rec != null && !isSimpleReceiver(rec)) { 1352130570Sobrien return null; 1353130570Sobrien } 1354130570Sobrien 1355130570Sobrien Type site; 1356130570Sobrien 1357130570Sobrien if (rec != null) { 1358130570Sobrien if (rec.hasTag(APPLY)) { 135989861Sobrien Symbol recSym = quicklyResolveMethod(env, (JCMethodInvocation) rec); 1360130570Sobrien if (recSym == null) 1361130570Sobrien return null; 1362130570Sobrien Symbol resolvedReturnType = 1363130570Sobrien analyzeCandidateMethods(recSym, syms.errSymbol, returnSymbolAnalyzer); 1364130570Sobrien if (resolvedReturnType == null) 1365130570Sobrien return null; 1366130570Sobrien site = resolvedReturnType.type; 1367130570Sobrien } else { 136889861Sobrien site = attribSpeculative(rec, env, attr.unknownTypeExprInfo).type; 1369130570Sobrien } 1370218822Sdim } else { 1371218822Sdim site = env.enclClass.sym.type; 1372130570Sobrien } 1373130570Sobrien 1374130570Sobrien while (site.hasTag(TYPEVAR)) { 1375130570Sobrien site = site.getUpperBound(); 1376130570Sobrien } 1377130570Sobrien 1378130570Sobrien site = types.capture(site); 1379130570Sobrien 1380130570Sobrien List<Type> args = rs.dummyArgs(tree.args.length()); 1381130570Sobrien Name name = TreeInfo.name(tree.meth); 1382130570Sobrien 1383130570Sobrien Resolve.LookupHelper lh = rs.new LookupHelper(name, site, args, List.<Type>nil(), MethodResolutionPhase.VARARITY) { 1384130570Sobrien @Override 1385130570Sobrien Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) { 1386130570Sobrien return rec == null ? 138789861Sobrien rs.findFun(env, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()) : 1388130570Sobrien rs.findMethod(env, site, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired(), false); 1389130570Sobrien } 1390130570Sobrien @Override 1391130570Sobrien Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) { 1392130570Sobrien return sym; 139389861Sobrien } 1394130570Sobrien }; 1395130570Sobrien 1396130570Sobrien return rs.lookupMethod(env, tree, site.tsym, rs.arityMethodCheck, lh); 1397130570Sobrien } 1398130570Sobrien //where: 1399130570Sobrien MethodAnalyzer<Symbol> returnSymbolAnalyzer = new MethodAnalyzer<Symbol>() { 1400130570Sobrien @Override 140189861Sobrien public Symbol process(MethodSymbol ms) { 1402130570Sobrien ArgumentExpressionKind kind = ArgumentExpressionKind.methodKind(ms, types); 1403130570Sobrien if (kind == ArgumentExpressionKind.POLY || ms.getReturnType().hasTag(TYPEVAR)) 1404130570Sobrien return null; 1405130570Sobrien return ms.getReturnType().tsym; 140677302Sobrien } 1407130570Sobrien @Override 140860509Sobrien public Symbol reduce(Symbol s1, Symbol s2) { 140960509Sobrien return s1 == syms.errSymbol ? s2 : s1 == s2 ? s1 : null; 141033965Sjdp } 141133965Sjdp @Override 141233965Sjdp public boolean shouldStop(Symbol result) { 141333965Sjdp return result == null; 141433965Sjdp } 141533965Sjdp }; 1416130570Sobrien 1417130570Sobrien /** 1418130570Sobrien * Process the result of Resolve.lookupMethod. If sym is a method symbol, the result of 141933965Sjdp * MethodAnalyzer.process is returned. If sym is an ambiguous symbol, all the candidate 142089861Sobrien * methods are inspected one by one, using MethodAnalyzer.process. The outcomes are 142133965Sjdp * reduced using MethodAnalyzer.reduce (using defaultValue as the first value over which 142233965Sjdp * the reduction runs). MethodAnalyzer.shouldStop can be used to stop the inspection early. 142333965Sjdp */ 142433965Sjdp <E> E analyzeCandidateMethods(Symbol sym, E defaultValue, MethodAnalyzer<E> analyzer) { 142533965Sjdp switch (sym.kind) { 142633965Sjdp case MTH: 1427218822Sdim return analyzer.process((MethodSymbol) sym); 142833965Sjdp case AMBIGUOUS: 142989861Sobrien Resolve.AmbiguityError err = (Resolve.AmbiguityError)sym.baseSymbol(); 1430130570Sobrien E res = defaultValue; 1431130570Sobrien for (Symbol s : err.ambiguousSyms) { 1432130570Sobrien if (s.kind == MTH) { 143333965Sjdp res = analyzer.reduce(res, analyzer.process((MethodSymbol) s)); 143433965Sjdp if (analyzer.shouldStop(res)) 143577302Sobrien return res; 143677302Sobrien } 143777302Sobrien } 143877302Sobrien return res; 143977302Sobrien default: 1440218822Sdim return defaultValue; 144133965Sjdp } 144233965Sjdp } 1443130570Sobrien } 144433965Sjdp 144589861Sobrien /** Analyzer for methods - used by analyzeCandidateMethods. */ 144689861Sobrien interface MethodAnalyzer<E> { 144789861Sobrien E process(MethodSymbol ms); 144889861Sobrien E reduce(E e1, E e2); 144989861Sobrien boolean shouldStop(E result); 145089861Sobrien } 145189861Sobrien 145233965Sjdp //where 145333965Sjdp private EnumSet<JCTree.Tag> deferredCheckerTags = 145433965Sjdp EnumSet.of(LAMBDA, REFERENCE, PARENS, TYPECAST, 145533965Sjdp CONDEXPR, NEWCLASS, APPLY, LITERAL); 1456218822Sdim} 145733965Sjdp