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

Fri, 02 May 2014 01:25:26 +0100

author
vromero
date
Fri, 02 May 2014 01:25:26 +0100
changeset 2382
14979dd5e034
parent 2370
acd64168cf8b
child 2410
e64bb2f5f0cf
permissions
-rw-r--r--

8030741: Inference: implement eager resolution of return types, consistent with JDK-8028800
Reviewed-by: dlsmith, jjg

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

mercurial