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

Mon, 18 Jan 2016 10:58:12 +0000

author
mcimadamore
date
Mon, 18 Jan 2016 10:58:12 +0000
changeset 3075
745c9feb99f2
parent 2811
610ec7dcf431
child 2893
ca5783d9a597
permissions
-rw-r--r--

8130506: javac AssertionError when invoking MethodHandle.invoke with lambda parameter
Reviewed-by: mcimadamore
Contributed-by: srikanth.adayapalam@oracle.com

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

mercurial