src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java

Thu, 31 Aug 2017 15:17:03 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:17:03 +0800
changeset 2525
2eb010b6cb22
parent 2429
94ea21ecfe2d
parent 0
959103a6100f
child 2702
9ca8d8713094
permissions
-rw-r--r--

merge

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

mercurial