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

Tue, 26 Nov 2013 15:27:19 +0100

author
jlahoda
date
Tue, 26 Nov 2013 15:27:19 +0100
changeset 2206
8acb838c9b79
parent 2193
d4cbb671de1c
child 2370
acd64168cf8b
permissions
-rw-r--r--

8026374: javac accepts void as a method parameter
Summary: Changing Check.validate to reject void types.
Reviewed-by: jjg, vromero

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

mercurial