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

Mon, 08 Sep 2014 10:48:18 +0200

author
jlahoda
date
Mon, 08 Sep 2014 10:48:18 +0200
changeset 2563
c627efb5fdcd
parent 2429
94ea21ecfe2d
child 2564
ced008063508
permissions
-rw-r--r--

8056014: Type inference may be skipped for a complex receiver generic method in a parameter position
Summary: When checking if deferred attribution is needed for a chain of methods, stop on any method that returns any type variable, as the rest of analysis cannot use the correct type.
Reviewed-by: mcimadamore, vromero

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

mercurial