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

Tue, 22 Apr 2014 17:55:22 +0100

author
vromero
date
Tue, 22 Apr 2014 17:55:22 +0100
changeset 2370
acd64168cf8b
parent 2193
d4cbb671de1c
child 2382
14979dd5e034
permissions
-rw-r--r--

8029718: Should always use lambda body structure to disambiguate overload resolution
Reviewed-by: dlsmith, jjg, jlahoda

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

mercurial