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

Mon, 16 Oct 2017 16:07:48 +0800

author
aoqi
date
Mon, 16 Oct 2017 16:07:48 +0800
changeset 2893
ca5783d9a597
parent 2811
610ec7dcf431
parent 2702
9ca8d8713094
permissions
-rw-r--r--

merge

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

mercurial