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

Thu, 22 Aug 2013 13:12:43 +0100

author
vromero
date
Thu, 22 Aug 2013 13:12:43 +0100
changeset 1974
25aaff78d754
parent 1899
c60a5099863a
child 2000
4a6acc42c3a1
permissions
-rw-r--r--

8023112: javac should not use lazy constant evaluation approach for method references
Reviewed-by: jjg, mcimadamore

mcimadamore@1347 1 /*
mcimadamore@1674 2 * Copyright (c) 2012, 2013, 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
mcimadamore@1347 28 import com.sun.tools.javac.code.*;
mcimadamore@1347 29 import com.sun.tools.javac.tree.*;
mcimadamore@1347 30 import com.sun.tools.javac.util.*;
mcimadamore@1674 31 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
mcimadamore@1347 32 import com.sun.tools.javac.code.Symbol.*;
mcimadamore@1347 33 import com.sun.tools.javac.code.Type.*;
mcimadamore@1347 34 import com.sun.tools.javac.comp.Attr.ResultInfo;
mcimadamore@1347 35 import com.sun.tools.javac.comp.Infer.InferenceContext;
mcimadamore@1347 36 import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
mcimadamore@1897 37 import com.sun.tools.javac.comp.Resolve.ReferenceLookupHelper;
mcimadamore@1347 38 import com.sun.tools.javac.tree.JCTree.*;
mcimadamore@1347 39
mcimadamore@1347 40
mcimadamore@1347 41 import java.util.ArrayList;
mcimadamore@1481 42 import java.util.EnumSet;
mcimadamore@1415 43 import java.util.LinkedHashSet;
mcimadamore@1347 44 import java.util.Map;
mcimadamore@1347 45 import java.util.Set;
mcimadamore@1347 46 import java.util.WeakHashMap;
mcimadamore@1347 47
mcimadamore@1415 48 import static com.sun.tools.javac.code.TypeTag.*;
mcimadamore@1347 49 import static com.sun.tools.javac.tree.JCTree.Tag.*;
mcimadamore@1347 50
mcimadamore@1347 51 /**
mcimadamore@1347 52 * This is an helper class that is used to perform deferred type-analysis.
mcimadamore@1347 53 * Each time a poly expression occurs in argument position, javac attributes it
mcimadamore@1347 54 * with a temporary 'deferred type' that is checked (possibly multiple times)
mcimadamore@1347 55 * against an expected formal type.
mcimadamore@1347 56 *
mcimadamore@1347 57 * <p><b>This is NOT part of any supported API.
mcimadamore@1347 58 * If you write code that depends on this, you do so at your own risk.
mcimadamore@1347 59 * This code and its internal interfaces are subject to change or
mcimadamore@1347 60 * deletion without notice.</b>
mcimadamore@1347 61 */
mcimadamore@1347 62 public class DeferredAttr extends JCTree.Visitor {
mcimadamore@1347 63 protected static final Context.Key<DeferredAttr> deferredAttrKey =
mcimadamore@1347 64 new Context.Key<DeferredAttr>();
mcimadamore@1347 65
mcimadamore@1347 66 final Attr attr;
mcimadamore@1347 67 final Check chk;
mcimadamore@1510 68 final JCDiagnostic.Factory diags;
mcimadamore@1347 69 final Enter enter;
mcimadamore@1347 70 final Infer infer;
mcimadamore@1581 71 final Resolve rs;
mcimadamore@1347 72 final Log log;
mcimadamore@1347 73 final Symtab syms;
mcimadamore@1347 74 final TreeMaker make;
mcimadamore@1347 75 final Types types;
mcimadamore@1347 76
mcimadamore@1347 77 public static DeferredAttr instance(Context context) {
mcimadamore@1347 78 DeferredAttr instance = context.get(deferredAttrKey);
mcimadamore@1347 79 if (instance == null)
mcimadamore@1347 80 instance = new DeferredAttr(context);
mcimadamore@1347 81 return instance;
mcimadamore@1347 82 }
mcimadamore@1347 83
mcimadamore@1347 84 protected DeferredAttr(Context context) {
mcimadamore@1347 85 context.put(deferredAttrKey, this);
mcimadamore@1347 86 attr = Attr.instance(context);
mcimadamore@1347 87 chk = Check.instance(context);
mcimadamore@1510 88 diags = JCDiagnostic.Factory.instance(context);
mcimadamore@1347 89 enter = Enter.instance(context);
mcimadamore@1347 90 infer = Infer.instance(context);
mcimadamore@1581 91 rs = Resolve.instance(context);
mcimadamore@1347 92 log = Log.instance(context);
mcimadamore@1347 93 syms = Symtab.instance(context);
mcimadamore@1347 94 make = TreeMaker.instance(context);
mcimadamore@1347 95 types = Types.instance(context);
mcimadamore@1510 96 Names names = Names.instance(context);
mcimadamore@1889 97 stuckTree = make.Ident(names.empty).setType(Type.stuckType);
mcimadamore@1897 98 emptyDeferredAttrContext =
mcimadamore@1897 99 new DeferredAttrContext(AttrMode.CHECK, null, MethodResolutionPhase.BOX, infer.emptyContext, null, null) {
mcimadamore@1897 100 @Override
mcimadamore@1897 101 void addDeferredAttrNode(DeferredType dt, ResultInfo ri, List<Type> stuckVars) {
mcimadamore@1897 102 Assert.error("Empty deferred context!");
mcimadamore@1897 103 }
mcimadamore@1897 104 @Override
mcimadamore@1897 105 void complete() {
mcimadamore@1897 106 Assert.error("Empty deferred context!");
mcimadamore@1897 107 }
mcimadamore@1897 108 };
mcimadamore@1347 109 }
mcimadamore@1347 110
mcimadamore@1510 111 /** shared tree for stuck expressions */
mcimadamore@1510 112 final JCTree stuckTree;
mcimadamore@1510 113
mcimadamore@1347 114 /**
mcimadamore@1347 115 * This type represents a deferred type. A deferred type starts off with
mcimadamore@1347 116 * no information on the underlying expression type. Such info needs to be
mcimadamore@1347 117 * discovered through type-checking the deferred type against a target-type.
mcimadamore@1347 118 * Every deferred type keeps a pointer to the AST node from which it originated.
mcimadamore@1347 119 */
mcimadamore@1347 120 public class DeferredType extends Type {
mcimadamore@1347 121
mcimadamore@1347 122 public JCExpression tree;
mcimadamore@1347 123 Env<AttrContext> env;
mcimadamore@1347 124 AttrMode mode;
mcimadamore@1347 125 SpeculativeCache speculativeCache;
mcimadamore@1347 126
mcimadamore@1347 127 DeferredType(JCExpression tree, Env<AttrContext> env) {
vromero@1853 128 super(null);
mcimadamore@1347 129 this.tree = tree;
mcimadamore@1899 130 this.env = attr.copyEnv(env);
mcimadamore@1347 131 this.speculativeCache = new SpeculativeCache();
mcimadamore@1347 132 }
mcimadamore@1347 133
vromero@1853 134 @Override
vromero@1853 135 public TypeTag getTag() {
vromero@1853 136 return DEFERRED;
vromero@1853 137 }
vromero@1853 138
mcimadamore@1347 139 /**
mcimadamore@1347 140 * A speculative cache is used to keep track of all overload resolution rounds
mcimadamore@1347 141 * that triggered speculative attribution on a given deferred type. Each entry
mcimadamore@1347 142 * stores a pointer to the speculative tree and the resolution phase in which the entry
mcimadamore@1347 143 * has been added.
mcimadamore@1347 144 */
mcimadamore@1347 145 class SpeculativeCache {
mcimadamore@1347 146
mcimadamore@1347 147 private Map<Symbol, List<Entry>> cache =
mcimadamore@1347 148 new WeakHashMap<Symbol, List<Entry>>();
mcimadamore@1347 149
mcimadamore@1347 150 class Entry {
mcimadamore@1347 151 JCTree speculativeTree;
mcimadamore@1347 152 Resolve.MethodResolutionPhase phase;
mcimadamore@1347 153
mcimadamore@1347 154 public Entry(JCTree speculativeTree, MethodResolutionPhase phase) {
mcimadamore@1347 155 this.speculativeTree = speculativeTree;
mcimadamore@1347 156 this.phase = phase;
mcimadamore@1347 157 }
mcimadamore@1347 158
mcimadamore@1347 159 boolean matches(Resolve.MethodResolutionPhase phase) {
mcimadamore@1347 160 return this.phase == phase;
mcimadamore@1347 161 }
mcimadamore@1347 162 }
mcimadamore@1347 163
mcimadamore@1347 164 /**
mcimadamore@1347 165 * Retrieve a speculative cache entry corresponding to given symbol
mcimadamore@1347 166 * and resolution phase
mcimadamore@1347 167 */
mcimadamore@1347 168 Entry get(Symbol msym, MethodResolutionPhase phase) {
mcimadamore@1347 169 List<Entry> entries = cache.get(msym);
mcimadamore@1347 170 if (entries == null) return null;
mcimadamore@1347 171 for (Entry e : entries) {
mcimadamore@1347 172 if (e.matches(phase)) return e;
mcimadamore@1347 173 }
mcimadamore@1347 174 return null;
mcimadamore@1347 175 }
mcimadamore@1347 176
mcimadamore@1347 177 /**
mcimadamore@1347 178 * Stores a speculative cache entry corresponding to given symbol
mcimadamore@1347 179 * and resolution phase
mcimadamore@1347 180 */
mcimadamore@1347 181 void put(Symbol msym, JCTree speculativeTree, MethodResolutionPhase phase) {
mcimadamore@1347 182 List<Entry> entries = cache.get(msym);
mcimadamore@1347 183 if (entries == null) {
mcimadamore@1347 184 entries = List.nil();
mcimadamore@1347 185 }
mcimadamore@1347 186 cache.put(msym, entries.prepend(new Entry(speculativeTree, phase)));
mcimadamore@1347 187 }
mcimadamore@1347 188 }
mcimadamore@1347 189
mcimadamore@1347 190 /**
mcimadamore@1347 191 * Get the type that has been computed during a speculative attribution round
mcimadamore@1347 192 */
mcimadamore@1347 193 Type speculativeType(Symbol msym, MethodResolutionPhase phase) {
mcimadamore@1347 194 SpeculativeCache.Entry e = speculativeCache.get(msym, phase);
mcimadamore@1347 195 return e != null ? e.speculativeTree.type : Type.noType;
mcimadamore@1347 196 }
mcimadamore@1347 197
mcimadamore@1347 198 /**
mcimadamore@1347 199 * Check a deferred type against a potential target-type. Depending on
mcimadamore@1347 200 * the current attribution mode, a normal vs. speculative attribution
mcimadamore@1347 201 * round is performed on the underlying AST node. There can be only one
mcimadamore@1347 202 * speculative round for a given target method symbol; moreover, a normal
mcimadamore@1347 203 * attribution round must follow one or more speculative rounds.
mcimadamore@1347 204 */
mcimadamore@1347 205 Type check(ResultInfo resultInfo) {
mcimadamore@1481 206 return check(resultInfo, stuckVars(tree, env, resultInfo), basicCompleter);
mcimadamore@1481 207 }
mcimadamore@1481 208
mcimadamore@1481 209 Type check(ResultInfo resultInfo, List<Type> stuckVars, DeferredTypeCompleter deferredTypeCompleter) {
mcimadamore@1347 210 DeferredAttrContext deferredAttrContext =
mcimadamore@1347 211 resultInfo.checkContext.deferredAttrContext();
mcimadamore@1347 212 Assert.check(deferredAttrContext != emptyDeferredAttrContext);
mcimadamore@1347 213 if (stuckVars.nonEmpty()) {
mcimadamore@1347 214 deferredAttrContext.addDeferredAttrNode(this, resultInfo, stuckVars);
mcimadamore@1347 215 return Type.noType;
mcimadamore@1347 216 } else {
mcimadamore@1347 217 try {
mcimadamore@1481 218 return deferredTypeCompleter.complete(this, resultInfo, deferredAttrContext);
mcimadamore@1347 219 } finally {
mcimadamore@1347 220 mode = deferredAttrContext.mode;
mcimadamore@1347 221 }
mcimadamore@1347 222 }
mcimadamore@1347 223 }
mcimadamore@1347 224 }
mcimadamore@1347 225
mcimadamore@1347 226 /**
mcimadamore@1481 227 * A completer for deferred types. Defines an entry point for type-checking
mcimadamore@1481 228 * a deferred type.
mcimadamore@1481 229 */
mcimadamore@1481 230 interface DeferredTypeCompleter {
mcimadamore@1481 231 /**
mcimadamore@1481 232 * Entry point for type-checking a deferred type. Depending on the
mcimadamore@1481 233 * circumstances, type-checking could amount to full attribution
mcimadamore@1481 234 * or partial structural check (aka potential applicability).
mcimadamore@1481 235 */
mcimadamore@1481 236 Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext);
mcimadamore@1481 237 }
mcimadamore@1481 238
mcimadamore@1481 239 /**
mcimadamore@1481 240 * A basic completer for deferred types. This completer type-checks a deferred type
mcimadamore@1481 241 * using attribution; depending on the attribution mode, this could be either standard
mcimadamore@1481 242 * or speculative attribution.
mcimadamore@1481 243 */
mcimadamore@1481 244 DeferredTypeCompleter basicCompleter = new DeferredTypeCompleter() {
mcimadamore@1481 245 public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
mcimadamore@1481 246 switch (deferredAttrContext.mode) {
mcimadamore@1481 247 case SPECULATIVE:
mcimadamore@1654 248 //Note: if a symbol is imported twice we might do two identical
mcimadamore@1654 249 //speculative rounds...
mcimadamore@1654 250 Assert.check(dt.mode == null || dt.mode == AttrMode.SPECULATIVE);
mcimadamore@1481 251 JCTree speculativeTree = attribSpeculative(dt.tree, dt.env, resultInfo);
mcimadamore@1481 252 dt.speculativeCache.put(deferredAttrContext.msym, speculativeTree, deferredAttrContext.phase);
mcimadamore@1481 253 return speculativeTree.type;
mcimadamore@1481 254 case CHECK:
mcimadamore@1562 255 Assert.check(dt.mode != null);
mcimadamore@1481 256 return attr.attribTree(dt.tree, dt.env, resultInfo);
mcimadamore@1481 257 }
mcimadamore@1481 258 Assert.error();
mcimadamore@1481 259 return null;
mcimadamore@1481 260 }
mcimadamore@1481 261 };
mcimadamore@1481 262
mcimadamore@1562 263 DeferredTypeCompleter dummyCompleter = new DeferredTypeCompleter() {
mcimadamore@1562 264 public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
mcimadamore@1562 265 Assert.check(deferredAttrContext.mode == AttrMode.CHECK);
mcimadamore@1899 266 return dt.tree.type = Type.stuckType;
mcimadamore@1562 267 }
mcimadamore@1562 268 };
mcimadamore@1562 269
mcimadamore@1481 270 /**
mcimadamore@1347 271 * The 'mode' in which the deferred type is to be type-checked
mcimadamore@1347 272 */
mcimadamore@1347 273 public enum AttrMode {
mcimadamore@1347 274 /**
mcimadamore@1347 275 * A speculative type-checking round is used during overload resolution
mcimadamore@1347 276 * mainly to generate constraints on inference variables. Side-effects
mcimadamore@1347 277 * arising from type-checking the expression associated with the deferred
mcimadamore@1347 278 * type are reversed after the speculative round finishes. This means the
mcimadamore@1347 279 * expression tree will be left in a blank state.
mcimadamore@1347 280 */
mcimadamore@1347 281 SPECULATIVE,
mcimadamore@1347 282 /**
mcimadamore@1347 283 * This is the plain type-checking mode. Produces side-effects on the underlying AST node
mcimadamore@1347 284 */
mcimadamore@1347 285 CHECK;
mcimadamore@1347 286 }
mcimadamore@1347 287
mcimadamore@1347 288 /**
mcimadamore@1347 289 * Routine that performs speculative type-checking; the input AST node is
mcimadamore@1347 290 * cloned (to avoid side-effects cause by Attr) and compiler state is
mcimadamore@1347 291 * restored after type-checking. All diagnostics (but critical ones) are
mcimadamore@1347 292 * disabled during speculative type-checking.
mcimadamore@1347 293 */
mcimadamore@1347 294 JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
mcimadamore@1596 295 final JCTree newTree = new TreeCopier<Object>(make).copy(tree);
mcimadamore@1347 296 Env<AttrContext> speculativeEnv = env.dup(newTree, env.info.dup(env.info.scope.dupUnshared()));
mcimadamore@1347 297 speculativeEnv.info.scope.owner = env.info.scope.owner;
jjg@1406 298 Log.DeferredDiagnosticHandler deferredDiagnosticHandler =
jjg@1406 299 new Log.DeferredDiagnosticHandler(log, new Filter<JCDiagnostic>() {
mcimadamore@1596 300 public boolean accepts(final JCDiagnostic d) {
mcimadamore@1596 301 class PosScanner extends TreeScanner {
mcimadamore@1596 302 boolean found = false;
mcimadamore@1596 303
mcimadamore@1596 304 @Override
mcimadamore@1596 305 public void scan(JCTree tree) {
mcimadamore@1596 306 if (tree != null &&
mcimadamore@1596 307 tree.pos() == d.getDiagnosticPosition()) {
mcimadamore@1596 308 found = true;
mcimadamore@1596 309 }
mcimadamore@1596 310 super.scan(tree);
mcimadamore@1596 311 }
mcimadamore@1596 312 };
mcimadamore@1596 313 PosScanner posScanner = new PosScanner();
mcimadamore@1596 314 posScanner.scan(newTree);
mcimadamore@1596 315 return posScanner.found;
jjg@1406 316 }
jjg@1406 317 });
mcimadamore@1347 318 try {
mcimadamore@1347 319 attr.attribTree(newTree, speculativeEnv, resultInfo);
mcimadamore@1347 320 unenterScanner.scan(newTree);
mcimadamore@1347 321 return newTree;
mcimadamore@1347 322 } finally {
mcimadamore@1347 323 unenterScanner.scan(newTree);
jjg@1406 324 log.popDiagnosticHandler(deferredDiagnosticHandler);
mcimadamore@1347 325 }
mcimadamore@1347 326 }
mcimadamore@1347 327 //where
mcimadamore@1347 328 protected TreeScanner unenterScanner = new TreeScanner() {
mcimadamore@1347 329 @Override
mcimadamore@1347 330 public void visitClassDef(JCClassDecl tree) {
mcimadamore@1347 331 ClassSymbol csym = tree.sym;
mcimadamore@1415 332 //if something went wrong during method applicability check
mcimadamore@1415 333 //it is possible that nested expressions inside argument expression
mcimadamore@1415 334 //are left unchecked - in such cases there's nothing to clean up.
mcimadamore@1415 335 if (csym == null) return;
mcimadamore@1347 336 enter.typeEnvs.remove(csym);
mcimadamore@1347 337 chk.compiled.remove(csym.flatname);
mcimadamore@1347 338 syms.classes.remove(csym.flatname);
mcimadamore@1347 339 super.visitClassDef(tree);
mcimadamore@1347 340 }
mcimadamore@1347 341 };
mcimadamore@1347 342
mcimadamore@1347 343 /**
mcimadamore@1347 344 * A deferred context is created on each method check. A deferred context is
mcimadamore@1347 345 * used to keep track of information associated with the method check, such as
mcimadamore@1347 346 * the symbol of the method being checked, the overload resolution phase,
mcimadamore@1347 347 * the kind of attribution mode to be applied to deferred types and so forth.
mcimadamore@1347 348 * As deferred types are processed (by the method check routine) stuck AST nodes
mcimadamore@1347 349 * are added (as new deferred attribution nodes) to this context. The complete()
mcimadamore@1347 350 * routine makes sure that all pending nodes are properly processed, by
mcimadamore@1347 351 * progressively instantiating all inference variables on which one or more
mcimadamore@1347 352 * deferred attribution node is stuck.
mcimadamore@1347 353 */
mcimadamore@1347 354 class DeferredAttrContext {
mcimadamore@1347 355
mcimadamore@1347 356 /** attribution mode */
mcimadamore@1347 357 final AttrMode mode;
mcimadamore@1347 358
mcimadamore@1347 359 /** symbol of the method being checked */
mcimadamore@1347 360 final Symbol msym;
mcimadamore@1347 361
mcimadamore@1347 362 /** method resolution step */
mcimadamore@1347 363 final Resolve.MethodResolutionPhase phase;
mcimadamore@1347 364
mcimadamore@1347 365 /** inference context */
mcimadamore@1347 366 final InferenceContext inferenceContext;
mcimadamore@1347 367
mcimadamore@1551 368 /** parent deferred context */
mcimadamore@1551 369 final DeferredAttrContext parent;
mcimadamore@1551 370
mcimadamore@1551 371 /** Warner object to report warnings */
mcimadamore@1551 372 final Warner warn;
mcimadamore@1551 373
mcimadamore@1347 374 /** list of deferred attribution nodes to be processed */
mcimadamore@1347 375 ArrayList<DeferredAttrNode> deferredAttrNodes = new ArrayList<DeferredAttrNode>();
mcimadamore@1347 376
mcimadamore@1551 377 DeferredAttrContext(AttrMode mode, Symbol msym, MethodResolutionPhase phase,
mcimadamore@1551 378 InferenceContext inferenceContext, DeferredAttrContext parent, Warner warn) {
mcimadamore@1347 379 this.mode = mode;
mcimadamore@1347 380 this.msym = msym;
mcimadamore@1347 381 this.phase = phase;
mcimadamore@1551 382 this.parent = parent;
mcimadamore@1551 383 this.warn = warn;
mcimadamore@1347 384 this.inferenceContext = inferenceContext;
mcimadamore@1347 385 }
mcimadamore@1347 386
mcimadamore@1347 387 /**
mcimadamore@1347 388 * Adds a node to the list of deferred attribution nodes - used by Resolve.rawCheckArgumentsApplicable
mcimadamore@1347 389 * Nodes added this way act as 'roots' for the out-of-order method checking process.
mcimadamore@1347 390 */
mcimadamore@1347 391 void addDeferredAttrNode(final DeferredType dt, ResultInfo resultInfo, List<Type> stuckVars) {
mcimadamore@1347 392 deferredAttrNodes.add(new DeferredAttrNode(dt, resultInfo, stuckVars));
mcimadamore@1347 393 }
mcimadamore@1347 394
mcimadamore@1347 395 /**
mcimadamore@1347 396 * Incrementally process all nodes, by skipping 'stuck' nodes and attributing
mcimadamore@1347 397 * 'unstuck' ones. If at any point no progress can be made (no 'unstuck' nodes)
mcimadamore@1347 398 * some inference variable might get eagerly instantiated so that all nodes
mcimadamore@1347 399 * can be type-checked.
mcimadamore@1347 400 */
mcimadamore@1347 401 void complete() {
mcimadamore@1347 402 while (!deferredAttrNodes.isEmpty()) {
mcimadamore@1415 403 Set<Type> stuckVars = new LinkedHashSet<Type>();
mcimadamore@1347 404 boolean progress = false;
mcimadamore@1347 405 //scan a defensive copy of the node list - this is because a deferred
mcimadamore@1347 406 //attribution round can add new nodes to the list
mcimadamore@1347 407 for (DeferredAttrNode deferredAttrNode : List.from(deferredAttrNodes)) {
mcimadamore@1551 408 if (!deferredAttrNode.process(this)) {
mcimadamore@1510 409 stuckVars.addAll(deferredAttrNode.stuckVars);
mcimadamore@1510 410 } else {
mcimadamore@1347 411 deferredAttrNodes.remove(deferredAttrNode);
mcimadamore@1347 412 progress = true;
mcimadamore@1347 413 }
mcimadamore@1347 414 }
mcimadamore@1347 415 if (!progress) {
mcimadamore@1347 416 //remove all variables that have already been instantiated
mcimadamore@1347 417 //from the list of stuck variables
mcimadamore@1562 418 inferenceContext.solveAny(List.from(stuckVars), warn);
mcimadamore@1550 419 inferenceContext.notifyChange();
mcimadamore@1347 420 }
mcimadamore@1347 421 }
mcimadamore@1347 422 }
mcimadamore@1551 423 }
mcimadamore@1551 424
mcimadamore@1551 425 /**
mcimadamore@1551 426 * Class representing a deferred attribution node. It keeps track of
mcimadamore@1551 427 * a deferred type, along with the expected target type information.
mcimadamore@1551 428 */
mcimadamore@1551 429 class DeferredAttrNode implements Infer.FreeTypeListener {
mcimadamore@1551 430
mcimadamore@1551 431 /** underlying deferred type */
mcimadamore@1551 432 DeferredType dt;
mcimadamore@1551 433
mcimadamore@1551 434 /** underlying target type information */
mcimadamore@1551 435 ResultInfo resultInfo;
mcimadamore@1551 436
mcimadamore@1551 437 /** list of uninferred inference variables causing this node to be stuck */
mcimadamore@1551 438 List<Type> stuckVars;
mcimadamore@1551 439
mcimadamore@1551 440 DeferredAttrNode(DeferredType dt, ResultInfo resultInfo, List<Type> stuckVars) {
mcimadamore@1551 441 this.dt = dt;
mcimadamore@1551 442 this.resultInfo = resultInfo;
mcimadamore@1551 443 this.stuckVars = stuckVars;
mcimadamore@1551 444 if (!stuckVars.isEmpty()) {
mcimadamore@1551 445 resultInfo.checkContext.inferenceContext().addFreeTypeListener(stuckVars, this);
mcimadamore@1551 446 }
mcimadamore@1551 447 }
mcimadamore@1551 448
mcimadamore@1551 449 @Override
mcimadamore@1551 450 public void typesInferred(InferenceContext inferenceContext) {
mcimadamore@1551 451 stuckVars = List.nil();
mcimadamore@1551 452 resultInfo = resultInfo.dup(inferenceContext.asInstType(resultInfo.pt));
mcimadamore@1551 453 }
mcimadamore@1347 454
mcimadamore@1347 455 /**
mcimadamore@1551 456 * Process a deferred attribution node.
mcimadamore@1551 457 * Invariant: a stuck node cannot be processed.
mcimadamore@1347 458 */
mcimadamore@1551 459 @SuppressWarnings("fallthrough")
mcimadamore@1551 460 boolean process(DeferredAttrContext deferredAttrContext) {
mcimadamore@1551 461 switch (deferredAttrContext.mode) {
mcimadamore@1551 462 case SPECULATIVE:
mcimadamore@1551 463 dt.check(resultInfo, List.<Type>nil(), new StructuralStuckChecker());
mcimadamore@1551 464 return true;
mcimadamore@1551 465 case CHECK:
mcimadamore@1551 466 if (stuckVars.nonEmpty()) {
mcimadamore@1562 467 //stuck expression - see if we can propagate
mcimadamore@1562 468 if (deferredAttrContext.parent != emptyDeferredAttrContext &&
mcimadamore@1562 469 Type.containsAny(deferredAttrContext.parent.inferenceContext.inferencevars, List.from(stuckVars))) {
mcimadamore@1562 470 deferredAttrContext.parent.deferredAttrNodes.add(this);
mcimadamore@1562 471 dt.check(resultInfo, List.<Type>nil(), dummyCompleter);
mcimadamore@1562 472 return true;
mcimadamore@1562 473 } else {
mcimadamore@1562 474 return false;
mcimadamore@1562 475 }
mcimadamore@1551 476 } else {
mcimadamore@1551 477 dt.check(resultInfo, stuckVars, basicCompleter);
mcimadamore@1551 478 return true;
mcimadamore@1551 479 }
mcimadamore@1551 480 default:
mcimadamore@1551 481 throw new AssertionError("Bad mode");
mcimadamore@1551 482 }
mcimadamore@1551 483 }
mcimadamore@1347 484
mcimadamore@1551 485 /**
mcimadamore@1551 486 * Structural checker for stuck expressions
mcimadamore@1551 487 */
mcimadamore@1551 488 class StructuralStuckChecker extends TreeScanner implements DeferredTypeCompleter {
mcimadamore@1347 489
mcimadamore@1347 490 ResultInfo resultInfo;
mcimadamore@1551 491 InferenceContext inferenceContext;
mcimadamore@1347 492
mcimadamore@1551 493 public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
mcimadamore@1551 494 this.resultInfo = resultInfo;
mcimadamore@1551 495 this.inferenceContext = deferredAttrContext.inferenceContext;
mcimadamore@1551 496 dt.tree.accept(this);
mcimadamore@1551 497 dt.speculativeCache.put(deferredAttrContext.msym, stuckTree, deferredAttrContext.phase);
mcimadamore@1551 498 return Type.noType;
mcimadamore@1551 499 }
mcimadamore@1347 500
mcimadamore@1551 501 @Override
mcimadamore@1551 502 public void visitLambda(JCLambda tree) {
mcimadamore@1551 503 Check.CheckContext checkContext = resultInfo.checkContext;
mcimadamore@1551 504 Type pt = resultInfo.pt;
mcimadamore@1551 505 if (inferenceContext.inferencevars.contains(pt)) {
mcimadamore@1551 506 //ok
mcimadamore@1551 507 return;
mcimadamore@1551 508 } else {
mcimadamore@1551 509 //must be a functional descriptor
mcimadamore@1551 510 try {
mcimadamore@1551 511 Type desc = types.findDescriptorType(pt);
mcimadamore@1551 512 if (desc.getParameterTypes().length() != tree.params.length()) {
mcimadamore@1551 513 checkContext.report(tree, diags.fragment("incompatible.arg.types.in.lambda"));
mcimadamore@1551 514 }
mcimadamore@1551 515 } catch (Types.FunctionDescriptorLookupError ex) {
mcimadamore@1551 516 checkContext.report(null, ex.getDiagnostic());
mcimadamore@1551 517 }
mcimadamore@1347 518 }
mcimadamore@1347 519 }
mcimadamore@1347 520
mcimadamore@1347 521 @Override
mcimadamore@1551 522 public void visitNewClass(JCNewClass tree) {
mcimadamore@1551 523 //do nothing
mcimadamore@1347 524 }
mcimadamore@1347 525
mcimadamore@1551 526 @Override
mcimadamore@1551 527 public void visitApply(JCMethodInvocation tree) {
mcimadamore@1551 528 //do nothing
mcimadamore@1347 529 }
mcimadamore@1347 530
mcimadamore@1551 531 @Override
mcimadamore@1551 532 public void visitReference(JCMemberReference tree) {
mcimadamore@1551 533 Check.CheckContext checkContext = resultInfo.checkContext;
mcimadamore@1551 534 Type pt = resultInfo.pt;
mcimadamore@1551 535 if (inferenceContext.inferencevars.contains(pt)) {
mcimadamore@1551 536 //ok
mcimadamore@1551 537 return;
mcimadamore@1551 538 } else {
mcimadamore@1551 539 try {
mcimadamore@1551 540 types.findDescriptorType(pt);
mcimadamore@1551 541 } catch (Types.FunctionDescriptorLookupError ex) {
mcimadamore@1551 542 checkContext.report(null, ex.getDiagnostic());
mcimadamore@1510 543 }
mcimadamore@1897 544 switch (tree.sym.kind) {
mcimadamore@1581 545 //note: as argtypes are erroneous types, type-errors must
mcimadamore@1581 546 //have been caused by arity mismatch
mcimadamore@1581 547 case Kinds.ABSENT_MTH:
mcimadamore@1581 548 case Kinds.WRONG_MTH:
mcimadamore@1581 549 case Kinds.WRONG_MTHS:
mcimadamore@1581 550 case Kinds.STATICERR:
mcimadamore@1581 551 case Kinds.MISSING_ENCL:
mcimadamore@1581 552 checkContext.report(null, diags.fragment("incompatible.arg.types.in.mref"));
mcimadamore@1581 553 }
mcimadamore@1510 554 }
mcimadamore@1347 555 }
mcimadamore@1347 556 }
mcimadamore@1347 557 }
mcimadamore@1347 558
mcimadamore@1347 559 /** an empty deferred attribution context - all methods throw exceptions */
mcimadamore@1897 560 final DeferredAttrContext emptyDeferredAttrContext;
mcimadamore@1347 561
mcimadamore@1347 562 /**
mcimadamore@1347 563 * Map a list of types possibly containing one or more deferred types
mcimadamore@1347 564 * into a list of ordinary types. Each deferred type D is mapped into a type T,
mcimadamore@1347 565 * where T is computed by retrieving the type that has already been
mcimadamore@1347 566 * computed for D during a previous deferred attribution round of the given kind.
mcimadamore@1347 567 */
mcimadamore@1347 568 class DeferredTypeMap extends Type.Mapping {
mcimadamore@1347 569
mcimadamore@1347 570 DeferredAttrContext deferredAttrContext;
mcimadamore@1347 571
mcimadamore@1347 572 protected DeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
mcimadamore@1347 573 super(String.format("deferredTypeMap[%s]", mode));
mcimadamore@1551 574 this.deferredAttrContext = new DeferredAttrContext(mode, msym, phase,
mcimadamore@1551 575 infer.emptyContext, emptyDeferredAttrContext, types.noWarnings);
mcimadamore@1347 576 }
mcimadamore@1347 577
mcimadamore@1347 578 protected boolean validState(DeferredType dt) {
mcimadamore@1347 579 return dt.mode != null &&
mcimadamore@1347 580 deferredAttrContext.mode.ordinal() <= dt.mode.ordinal();
mcimadamore@1347 581 }
mcimadamore@1347 582
mcimadamore@1347 583 @Override
mcimadamore@1347 584 public Type apply(Type t) {
jjg@1374 585 if (!t.hasTag(DEFERRED)) {
mcimadamore@1347 586 return t.map(this);
mcimadamore@1347 587 } else {
mcimadamore@1347 588 DeferredType dt = (DeferredType)t;
mcimadamore@1347 589 Assert.check(validState(dt));
mcimadamore@1347 590 return typeOf(dt);
mcimadamore@1347 591 }
mcimadamore@1347 592 }
mcimadamore@1347 593
mcimadamore@1347 594 protected Type typeOf(DeferredType dt) {
mcimadamore@1347 595 switch (deferredAttrContext.mode) {
mcimadamore@1347 596 case CHECK:
mcimadamore@1347 597 return dt.tree.type == null ? Type.noType : dt.tree.type;
mcimadamore@1347 598 case SPECULATIVE:
mcimadamore@1347 599 return dt.speculativeType(deferredAttrContext.msym, deferredAttrContext.phase);
mcimadamore@1347 600 }
mcimadamore@1347 601 Assert.error();
mcimadamore@1347 602 return null;
mcimadamore@1347 603 }
mcimadamore@1347 604 }
mcimadamore@1347 605
mcimadamore@1347 606 /**
mcimadamore@1347 607 * Specialized recovery deferred mapping.
mcimadamore@1347 608 * Each deferred type D is mapped into a type T, where T is computed either by
mcimadamore@1347 609 * (i) retrieving the type that has already been computed for D during a previous
mcimadamore@1347 610 * attribution round (as before), or (ii) by synthesizing a new type R for D
mcimadamore@1347 611 * (the latter step is useful in a recovery scenario).
mcimadamore@1347 612 */
mcimadamore@1347 613 public class RecoveryDeferredTypeMap extends DeferredTypeMap {
mcimadamore@1347 614
mcimadamore@1347 615 public RecoveryDeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
mcimadamore@1415 616 super(mode, msym, phase != null ? phase : MethodResolutionPhase.BOX);
mcimadamore@1347 617 }
mcimadamore@1347 618
mcimadamore@1347 619 @Override
mcimadamore@1347 620 protected Type typeOf(DeferredType dt) {
mcimadamore@1347 621 Type owntype = super.typeOf(dt);
mcimadamore@1415 622 return owntype == Type.noType ?
mcimadamore@1347 623 recover(dt) : owntype;
mcimadamore@1347 624 }
mcimadamore@1347 625
mcimadamore@1347 626 @Override
mcimadamore@1347 627 protected boolean validState(DeferredType dt) {
mcimadamore@1347 628 return true;
mcimadamore@1347 629 }
mcimadamore@1347 630
mcimadamore@1347 631 /**
mcimadamore@1347 632 * Synthesize a type for a deferred type that hasn't been previously
mcimadamore@1347 633 * reduced to an ordinary type. Functional deferred types and conditionals
mcimadamore@1347 634 * are mapped to themselves, in order to have a richer diagnostic
mcimadamore@1347 635 * representation. Remaining deferred types are attributed using
mcimadamore@1347 636 * a default expected type (j.l.Object).
mcimadamore@1347 637 */
mcimadamore@1347 638 private Type recover(DeferredType dt) {
mcimadamore@1889 639 dt.check(attr.new RecoveryInfo(deferredAttrContext) {
mcimadamore@1889 640 @Override
mcimadamore@1889 641 protected Type check(DiagnosticPosition pos, Type found) {
mcimadamore@1889 642 return chk.checkNonVoid(pos, super.check(pos, found));
mcimadamore@1889 643 }
mcimadamore@1889 644 });
mcimadamore@1415 645 return super.apply(dt);
mcimadamore@1347 646 }
mcimadamore@1347 647 }
mcimadamore@1347 648
mcimadamore@1347 649 /**
mcimadamore@1347 650 * Retrieves the list of inference variables that need to be inferred before
mcimadamore@1347 651 * an AST node can be type-checked
mcimadamore@1347 652 */
mcimadamore@1347 653 @SuppressWarnings("fallthrough")
mcimadamore@1415 654 List<Type> stuckVars(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
mcimadamore@1415 655 if (resultInfo.pt.hasTag(NONE) || resultInfo.pt.isErroneous()) {
mcimadamore@1348 656 return List.nil();
mcimadamore@1348 657 } else {
mcimadamore@1897 658 return stuckVarsInternal(tree, resultInfo.pt, env, resultInfo.checkContext.inferenceContext());
mcimadamore@1481 659 }
mcimadamore@1481 660 }
mcimadamore@1481 661 //where
mcimadamore@1897 662 private List<Type> stuckVarsInternal(JCTree tree, Type pt, Env<AttrContext> env, Infer.InferenceContext inferenceContext) {
mcimadamore@1897 663 StuckChecker sc = new StuckChecker(pt, env, inferenceContext);
mcimadamore@1348 664 sc.scan(tree);
mcimadamore@1348 665 return List.from(sc.stuckVars);
mcimadamore@1348 666 }
mcimadamore@1481 667
mcimadamore@1481 668 /**
mcimadamore@1481 669 * A special tree scanner that would only visit portions of a given tree.
mcimadamore@1481 670 * The set of nodes visited by the scanner can be customized at construction-time.
mcimadamore@1481 671 */
mcimadamore@1481 672 abstract static class FilterScanner extends TreeScanner {
mcimadamore@1481 673
mcimadamore@1481 674 final Filter<JCTree> treeFilter;
mcimadamore@1481 675
mcimadamore@1481 676 FilterScanner(final Set<JCTree.Tag> validTags) {
mcimadamore@1481 677 this.treeFilter = new Filter<JCTree>() {
mcimadamore@1481 678 public boolean accepts(JCTree t) {
mcimadamore@1481 679 return validTags.contains(t.getTag());
mcimadamore@1481 680 }
mcimadamore@1481 681 };
mcimadamore@1481 682 }
mcimadamore@1481 683
mcimadamore@1481 684 @Override
mcimadamore@1481 685 public void scan(JCTree tree) {
mcimadamore@1481 686 if (tree != null) {
mcimadamore@1481 687 if (treeFilter.accepts(tree)) {
mcimadamore@1481 688 super.scan(tree);
mcimadamore@1481 689 } else {
mcimadamore@1481 690 skip(tree);
mcimadamore@1481 691 }
mcimadamore@1481 692 }
mcimadamore@1481 693 }
mcimadamore@1481 694
mcimadamore@1481 695 /**
mcimadamore@1481 696 * handler that is executed when a node has been discarded
mcimadamore@1481 697 */
mcimadamore@1481 698 abstract void skip(JCTree tree);
mcimadamore@1481 699 }
mcimadamore@1481 700
mcimadamore@1481 701 /**
mcimadamore@1481 702 * A tree scanner suitable for visiting the target-type dependent nodes of
mcimadamore@1481 703 * a given argument expression.
mcimadamore@1481 704 */
mcimadamore@1481 705 static class PolyScanner extends FilterScanner {
mcimadamore@1481 706
mcimadamore@1481 707 PolyScanner() {
mcimadamore@1481 708 super(EnumSet.of(CONDEXPR, PARENS, LAMBDA, REFERENCE));
mcimadamore@1481 709 }
mcimadamore@1481 710
mcimadamore@1481 711 @Override
mcimadamore@1481 712 void skip(JCTree tree) {
mcimadamore@1481 713 //do nothing
mcimadamore@1481 714 }
mcimadamore@1481 715 }
mcimadamore@1481 716
mcimadamore@1481 717 /**
mcimadamore@1481 718 * A tree scanner suitable for visiting the target-type dependent nodes nested
mcimadamore@1481 719 * within a lambda expression body.
mcimadamore@1481 720 */
mcimadamore@1481 721 static class LambdaReturnScanner extends FilterScanner {
mcimadamore@1481 722
mcimadamore@1481 723 LambdaReturnScanner() {
mcimadamore@1481 724 super(EnumSet.of(BLOCK, CASE, CATCH, DOLOOP, FOREACHLOOP,
mcimadamore@1481 725 FORLOOP, RETURN, SYNCHRONIZED, SWITCH, TRY, WHILELOOP));
mcimadamore@1481 726 }
mcimadamore@1481 727
mcimadamore@1481 728 @Override
mcimadamore@1481 729 void skip(JCTree tree) {
mcimadamore@1481 730 //do nothing
mcimadamore@1481 731 }
mcimadamore@1348 732 }
mcimadamore@1348 733
mcimadamore@1348 734 /**
mcimadamore@1348 735 * This visitor is used to check that structural expressions conform
mcimadamore@1348 736 * to their target - this step is required as inference could end up
mcimadamore@1348 737 * inferring types that make some of the nested expressions incompatible
mcimadamore@1348 738 * with their corresponding instantiated target
mcimadamore@1348 739 */
mcimadamore@1481 740 class StuckChecker extends PolyScanner {
mcimadamore@1348 741
mcimadamore@1348 742 Type pt;
mcimadamore@1897 743 Env<AttrContext> env;
mcimadamore@1348 744 Infer.InferenceContext inferenceContext;
mcimadamore@1415 745 Set<Type> stuckVars = new LinkedHashSet<Type>();
mcimadamore@1348 746
mcimadamore@1897 747 StuckChecker(Type pt, Env<AttrContext> env, Infer.InferenceContext inferenceContext) {
mcimadamore@1481 748 this.pt = pt;
mcimadamore@1897 749 this.env = env;
mcimadamore@1481 750 this.inferenceContext = inferenceContext;
mcimadamore@1348 751 }
mcimadamore@1348 752
mcimadamore@1348 753 @Override
mcimadamore@1348 754 public void visitLambda(JCLambda tree) {
mcimadamore@1481 755 if (inferenceContext.inferenceVars().contains(pt)) {
mcimadamore@1481 756 stuckVars.add(pt);
mcimadamore@1348 757 }
mcimadamore@1510 758 if (!types.isFunctionalInterface(pt)) {
mcimadamore@1481 759 return;
mcimadamore@1481 760 }
mcimadamore@1481 761 Type descType = types.findDescriptorType(pt);
mcimadamore@1481 762 List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
mcimadamore@1510 763 if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT &&
mcimadamore@1481 764 freeArgVars.nonEmpty()) {
mcimadamore@1481 765 stuckVars.addAll(freeArgVars);
mcimadamore@1481 766 }
mcimadamore@1481 767 scanLambdaBody(tree, descType.getReturnType());
mcimadamore@1348 768 }
mcimadamore@1348 769
mcimadamore@1348 770 @Override
mcimadamore@1348 771 public void visitReference(JCMemberReference tree) {
mcimadamore@1348 772 scan(tree.expr);
mcimadamore@1348 773 if (inferenceContext.inferenceVars().contains(pt)) {
mcimadamore@1348 774 stuckVars.add(pt);
mcimadamore@1348 775 return;
mcimadamore@1348 776 }
mcimadamore@1510 777 if (!types.isFunctionalInterface(pt)) {
mcimadamore@1348 778 return;
mcimadamore@1348 779 }
mcimadamore@1415 780
mcimadamore@1348 781 Type descType = types.findDescriptorType(pt);
mcimadamore@1348 782 List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
mcimadamore@1897 783 Env<AttrContext> localEnv = env.dup(tree, env.info.dup());
mcimadamore@1897 784 if (freeArgVars.nonEmpty()) {
mcimadamore@1897 785 //perform arity-based check
mcimadamore@1897 786 JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv,
mcimadamore@1897 787 attr.memberReferenceQualifierResult(tree));
mcimadamore@1897 788 ListBuffer<Type> argtypes = ListBuffer.lb();
mcimadamore@1897 789 for (Type t : descType.getParameterTypes()) {
mcimadamore@1897 790 argtypes.append(Type.noType);
mcimadamore@1897 791 }
mcimadamore@1897 792 JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree);
mcimadamore@1897 793 mref2.expr = exprTree;
mcimadamore@1897 794 Pair<Symbol, ReferenceLookupHelper> lookupRes =
mcimadamore@1897 795 rs.resolveMemberReference(tree, localEnv, mref2, exprTree.type,
mcimadamore@1897 796 tree.name, argtypes.toList(), null, true, rs.arityMethodCheck,
mcimadamore@1897 797 inferenceContext);
mcimadamore@1897 798 Symbol res = tree.sym = lookupRes.fst;
mcimadamore@1897 799 if (res.kind >= Kinds.ERRONEOUS ||
mcimadamore@1897 800 res.type.hasTag(FORALL) ||
mcimadamore@1897 801 (res.flags() & Flags.VARARGS) != 0 ||
mcimadamore@1897 802 (TreeInfo.isStaticSelector(exprTree, tree.name.table.names) &&
mcimadamore@1897 803 exprTree.type.isRaw())) {
mcimadamore@1897 804 stuckVars.addAll(freeArgVars);
mcimadamore@1897 805 }
mcimadamore@1897 806 }
mcimadamore@1348 807 }
mcimadamore@1348 808
mcimadamore@1481 809 void scanLambdaBody(JCLambda lambda, final Type pt) {
mcimadamore@1481 810 if (lambda.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) {
mcimadamore@1897 811 stuckVars.addAll(stuckVarsInternal(lambda.body, pt, env, inferenceContext));
mcimadamore@1481 812 } else {
mcimadamore@1481 813 LambdaReturnScanner lambdaScanner = new LambdaReturnScanner() {
mcimadamore@1481 814 @Override
mcimadamore@1481 815 public void visitReturn(JCReturn tree) {
mcimadamore@1481 816 if (tree.expr != null) {
mcimadamore@1897 817 stuckVars.addAll(stuckVarsInternal(tree.expr, pt, env, inferenceContext));
mcimadamore@1481 818 }
mcimadamore@1481 819 }
mcimadamore@1481 820 };
mcimadamore@1481 821 lambdaScanner.scan(lambda.body);
mcimadamore@1348 822 }
mcimadamore@1347 823 }
mcimadamore@1347 824 }
mcimadamore@1697 825
mcimadamore@1697 826 /**
mcimadamore@1697 827 * Does the argument expression {@code expr} need speculative type-checking?
mcimadamore@1697 828 */
mcimadamore@1697 829 boolean isDeferred(Env<AttrContext> env, JCExpression expr) {
mcimadamore@1697 830 DeferredChecker dc = new DeferredChecker(env);
mcimadamore@1697 831 dc.scan(expr);
mcimadamore@1697 832 return dc.result.isPoly();
mcimadamore@1697 833 }
mcimadamore@1697 834
mcimadamore@1697 835 /**
mcimadamore@1697 836 * The kind of an argument expression. This is used by the analysis that
mcimadamore@1697 837 * determines as to whether speculative attribution is necessary.
mcimadamore@1697 838 */
mcimadamore@1697 839 enum ArgumentExpressionKind {
mcimadamore@1697 840
mcimadamore@1697 841 /** kind that denotes poly argument expression */
mcimadamore@1697 842 POLY,
mcimadamore@1697 843 /** kind that denotes a standalone expression */
mcimadamore@1697 844 NO_POLY,
mcimadamore@1697 845 /** kind that denotes a primitive/boxed standalone expression */
mcimadamore@1697 846 PRIMITIVE;
mcimadamore@1697 847
mcimadamore@1697 848 /**
mcimadamore@1697 849 * Does this kind denote a poly argument expression
mcimadamore@1697 850 */
mcimadamore@1697 851 public final boolean isPoly() {
mcimadamore@1697 852 return this == POLY;
mcimadamore@1697 853 }
mcimadamore@1697 854
mcimadamore@1697 855 /**
mcimadamore@1697 856 * Does this kind denote a primitive standalone expression
mcimadamore@1697 857 */
mcimadamore@1697 858 public final boolean isPrimitive() {
mcimadamore@1697 859 return this == PRIMITIVE;
mcimadamore@1697 860 }
mcimadamore@1697 861
mcimadamore@1697 862 /**
mcimadamore@1697 863 * Compute the kind of a standalone expression of a given type
mcimadamore@1697 864 */
mcimadamore@1697 865 static ArgumentExpressionKind standaloneKind(Type type, Types types) {
mcimadamore@1697 866 return types.unboxedTypeOrType(type).isPrimitive() ?
mcimadamore@1697 867 ArgumentExpressionKind.PRIMITIVE :
mcimadamore@1697 868 ArgumentExpressionKind.NO_POLY;
mcimadamore@1697 869 }
mcimadamore@1697 870
mcimadamore@1697 871 /**
mcimadamore@1697 872 * Compute the kind of a method argument expression given its symbol
mcimadamore@1697 873 */
mcimadamore@1697 874 static ArgumentExpressionKind methodKind(Symbol sym, Types types) {
mcimadamore@1697 875 Type restype = sym.type.getReturnType();
mcimadamore@1697 876 if (sym.type.hasTag(FORALL) &&
mcimadamore@1697 877 restype.containsAny(((ForAll)sym.type).tvars)) {
mcimadamore@1697 878 return ArgumentExpressionKind.POLY;
mcimadamore@1697 879 } else {
mcimadamore@1697 880 return ArgumentExpressionKind.standaloneKind(restype, types);
mcimadamore@1697 881 }
mcimadamore@1697 882 }
mcimadamore@1697 883 }
mcimadamore@1697 884
mcimadamore@1697 885 /**
mcimadamore@1697 886 * Tree scanner used for checking as to whether an argument expression
mcimadamore@1697 887 * requires speculative attribution
mcimadamore@1697 888 */
mcimadamore@1697 889 final class DeferredChecker extends FilterScanner {
mcimadamore@1697 890
mcimadamore@1697 891 Env<AttrContext> env;
mcimadamore@1697 892 ArgumentExpressionKind result;
mcimadamore@1697 893
mcimadamore@1697 894 public DeferredChecker(Env<AttrContext> env) {
mcimadamore@1697 895 super(deferredCheckerTags);
mcimadamore@1697 896 this.env = env;
mcimadamore@1697 897 }
mcimadamore@1697 898
mcimadamore@1697 899 @Override
mcimadamore@1697 900 public void visitLambda(JCLambda tree) {
mcimadamore@1697 901 //a lambda is always a poly expression
mcimadamore@1697 902 result = ArgumentExpressionKind.POLY;
mcimadamore@1697 903 }
mcimadamore@1697 904
mcimadamore@1697 905 @Override
mcimadamore@1697 906 public void visitReference(JCMemberReference tree) {
mcimadamore@1697 907 //a method reference is always a poly expression
mcimadamore@1697 908 result = ArgumentExpressionKind.POLY;
mcimadamore@1697 909 }
mcimadamore@1697 910
mcimadamore@1697 911 @Override
mcimadamore@1697 912 public void visitTypeCast(JCTypeCast tree) {
mcimadamore@1697 913 //a cast is always a standalone expression
mcimadamore@1697 914 result = ArgumentExpressionKind.NO_POLY;
mcimadamore@1697 915 }
mcimadamore@1697 916
mcimadamore@1697 917 @Override
mcimadamore@1697 918 public void visitConditional(JCConditional tree) {
mcimadamore@1697 919 scan(tree.truepart);
mcimadamore@1697 920 if (!result.isPrimitive()) {
mcimadamore@1697 921 result = ArgumentExpressionKind.POLY;
mcimadamore@1697 922 return;
mcimadamore@1697 923 }
mcimadamore@1697 924 scan(tree.falsepart);
mcimadamore@1697 925 result = reduce(ArgumentExpressionKind.PRIMITIVE);
mcimadamore@1697 926 }
mcimadamore@1697 927
mcimadamore@1697 928 @Override
mcimadamore@1697 929 public void visitNewClass(JCNewClass tree) {
mcimadamore@1697 930 result = (TreeInfo.isDiamond(tree) || attr.findDiamonds) ?
mcimadamore@1697 931 ArgumentExpressionKind.POLY : ArgumentExpressionKind.NO_POLY;
mcimadamore@1697 932 }
mcimadamore@1697 933
mcimadamore@1697 934 @Override
mcimadamore@1697 935 public void visitApply(JCMethodInvocation tree) {
mcimadamore@1697 936 Name name = TreeInfo.name(tree.meth);
mcimadamore@1697 937
mcimadamore@1697 938 //fast path
mcimadamore@1697 939 if (tree.typeargs.nonEmpty() ||
mcimadamore@1697 940 name == name.table.names._this ||
mcimadamore@1697 941 name == name.table.names._super) {
mcimadamore@1697 942 result = ArgumentExpressionKind.NO_POLY;
mcimadamore@1697 943 return;
mcimadamore@1697 944 }
mcimadamore@1697 945
mcimadamore@1697 946 //slow path
mcimadamore@1697 947 final JCExpression rec = tree.meth.hasTag(SELECT) ?
mcimadamore@1697 948 ((JCFieldAccess)tree.meth).selected :
mcimadamore@1697 949 null;
mcimadamore@1697 950
mcimadamore@1697 951 if (rec != null && !isSimpleReceiver(rec)) {
mcimadamore@1697 952 //give up if receiver is too complex (to cut down analysis time)
mcimadamore@1697 953 result = ArgumentExpressionKind.POLY;
mcimadamore@1697 954 return;
mcimadamore@1697 955 }
mcimadamore@1697 956
mcimadamore@1697 957 Type site = rec != null ?
mcimadamore@1697 958 attribSpeculative(rec, env, attr.unknownTypeExprInfo).type :
mcimadamore@1697 959 env.enclClass.sym.type;
mcimadamore@1697 960
mcimadamore@1888 961 while (site.hasTag(TYPEVAR)) {
mcimadamore@1888 962 site = site.getUpperBound();
mcimadamore@1888 963 }
mcimadamore@1888 964
mcimadamore@1897 965 List<Type> args = rs.dummyArgs(tree.args.length());
mcimadamore@1697 966
mcimadamore@1897 967 Resolve.LookupHelper lh = rs.new LookupHelper(name, site, args, List.<Type>nil(), MethodResolutionPhase.VARARITY) {
mcimadamore@1697 968 @Override
mcimadamore@1697 969 Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
mcimadamore@1697 970 return rec == null ?
mcimadamore@1697 971 rs.findFun(env, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()) :
mcimadamore@1697 972 rs.findMethod(env, site, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired(), false);
mcimadamore@1697 973 }
mcimadamore@1697 974 @Override
mcimadamore@1697 975 Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
mcimadamore@1697 976 return sym;
mcimadamore@1697 977 }
mcimadamore@1697 978 };
mcimadamore@1697 979
mcimadamore@1697 980 Symbol sym = rs.lookupMethod(env, tree, site.tsym, rs.arityMethodCheck, lh);
mcimadamore@1697 981
mcimadamore@1697 982 if (sym.kind == Kinds.AMBIGUOUS) {
mcimadamore@1697 983 Resolve.AmbiguityError err = (Resolve.AmbiguityError)sym.baseSymbol();
mcimadamore@1697 984 result = ArgumentExpressionKind.PRIMITIVE;
vromero@1850 985 for (Symbol s : err.ambiguousSyms) {
vromero@1850 986 if (result.isPoly()) break;
mcimadamore@1697 987 if (s.kind == Kinds.MTH) {
mcimadamore@1697 988 result = reduce(ArgumentExpressionKind.methodKind(s, types));
mcimadamore@1697 989 }
mcimadamore@1697 990 }
mcimadamore@1697 991 } else {
mcimadamore@1697 992 result = (sym.kind == Kinds.MTH) ?
mcimadamore@1697 993 ArgumentExpressionKind.methodKind(sym, types) :
mcimadamore@1697 994 ArgumentExpressionKind.NO_POLY;
mcimadamore@1697 995 }
mcimadamore@1697 996 }
mcimadamore@1697 997 //where
mcimadamore@1697 998 private boolean isSimpleReceiver(JCTree rec) {
mcimadamore@1697 999 switch (rec.getTag()) {
mcimadamore@1697 1000 case IDENT:
mcimadamore@1697 1001 return true;
mcimadamore@1697 1002 case SELECT:
mcimadamore@1697 1003 return isSimpleReceiver(((JCFieldAccess)rec).selected);
mcimadamore@1697 1004 case TYPEAPPLY:
mcimadamore@1697 1005 case TYPEARRAY:
mcimadamore@1697 1006 return true;
mcimadamore@1697 1007 case ANNOTATED_TYPE:
mcimadamore@1697 1008 return isSimpleReceiver(((JCAnnotatedType)rec).underlyingType);
mcimadamore@1697 1009 default:
mcimadamore@1697 1010 return false;
mcimadamore@1697 1011 }
mcimadamore@1697 1012 }
mcimadamore@1697 1013 private ArgumentExpressionKind reduce(ArgumentExpressionKind kind) {
mcimadamore@1697 1014 switch (result) {
mcimadamore@1697 1015 case PRIMITIVE: return kind;
mcimadamore@1697 1016 case NO_POLY: return kind.isPoly() ? kind : result;
mcimadamore@1697 1017 case POLY: return result;
mcimadamore@1697 1018 default:
mcimadamore@1697 1019 Assert.error();
mcimadamore@1697 1020 return null;
mcimadamore@1697 1021 }
mcimadamore@1697 1022 }
mcimadamore@1697 1023
mcimadamore@1697 1024 @Override
mcimadamore@1697 1025 public void visitLiteral(JCLiteral tree) {
mcimadamore@1697 1026 Type litType = attr.litType(tree.typetag);
mcimadamore@1697 1027 result = ArgumentExpressionKind.standaloneKind(litType, types);
mcimadamore@1697 1028 }
mcimadamore@1697 1029
mcimadamore@1697 1030 @Override
mcimadamore@1697 1031 void skip(JCTree tree) {
mcimadamore@1697 1032 result = ArgumentExpressionKind.NO_POLY;
mcimadamore@1697 1033 }
mcimadamore@1697 1034 }
mcimadamore@1697 1035 //where
mcimadamore@1697 1036 private EnumSet<JCTree.Tag> deferredCheckerTags =
mcimadamore@1697 1037 EnumSet.of(LAMBDA, REFERENCE, PARENS, TYPECAST,
mcimadamore@1697 1038 CONDEXPR, NEWCLASS, APPLY, LITERAL);
mcimadamore@1347 1039 }

mercurial