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

Tue, 12 Mar 2013 16:02:13 +0000

author
mcimadamore
date
Tue, 12 Mar 2013 16:02:13 +0000
changeset 1627
6db9a3b1a93f
parent 1613
d2a98dde7ecc
child 1654
b6cf07c54c29
permissions
-rw-r--r--

8008540: Constructor reference to non-reifiable array should be rejected
8008539: Spurious error when constructor reference mention an interface type
8008538: Constructor reference accepts wildcard parameterized types
Summary: Overhaul of Check.checkConstructorRefType
Reviewed-by: jjg

mcimadamore@1347 1 /*
mcimadamore@1347 2 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
mcimadamore@1347 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
mcimadamore@1347 4 *
mcimadamore@1347 5 * This code is free software; you can redistribute it and/or modify it
mcimadamore@1347 6 * under the terms of the GNU General Public License version 2 only, as
mcimadamore@1347 7 * published by the Free Software Foundation. Oracle designates this
mcimadamore@1347 8 * particular file as subject to the "Classpath" exception as provided
mcimadamore@1347 9 * by Oracle in the LICENSE file that accompanied this code.
mcimadamore@1347 10 *
mcimadamore@1347 11 * This code is distributed in the hope that it will be useful, but WITHOUT
mcimadamore@1347 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
mcimadamore@1347 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
mcimadamore@1347 14 * version 2 for more details (a copy is included in the LICENSE file that
mcimadamore@1347 15 * accompanied this code).
mcimadamore@1347 16 *
mcimadamore@1347 17 * You should have received a copy of the GNU General Public License version
mcimadamore@1347 18 * 2 along with this work; if not, write to the Free Software Foundation,
mcimadamore@1347 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
mcimadamore@1347 20 *
mcimadamore@1347 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
mcimadamore@1347 22 * or visit www.oracle.com if you need additional information or have any
mcimadamore@1347 23 * questions.
mcimadamore@1347 24 */
mcimadamore@1347 25
mcimadamore@1347 26 package com.sun.tools.javac.comp;
mcimadamore@1347 27
mcimadamore@1347 28 import com.sun.tools.javac.code.*;
mcimadamore@1347 29 import com.sun.tools.javac.tree.*;
mcimadamore@1347 30 import com.sun.tools.javac.util.*;
mcimadamore@1347 31 import com.sun.tools.javac.code.Symbol.*;
mcimadamore@1347 32 import com.sun.tools.javac.code.Type.*;
mcimadamore@1347 33 import com.sun.tools.javac.comp.Attr.ResultInfo;
mcimadamore@1347 34 import com.sun.tools.javac.comp.Infer.InferenceContext;
mcimadamore@1347 35 import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
mcimadamore@1347 36 import com.sun.tools.javac.tree.JCTree.*;
mcimadamore@1347 37
mcimadamore@1347 38 import javax.tools.JavaFileObject;
mcimadamore@1347 39
mcimadamore@1347 40 import java.util.ArrayList;
mcimadamore@1481 41 import java.util.EnumSet;
mcimadamore@1415 42 import java.util.LinkedHashSet;
mcimadamore@1347 43 import java.util.Map;
mcimadamore@1347 44 import java.util.Queue;
mcimadamore@1347 45 import java.util.Set;
mcimadamore@1347 46 import java.util.WeakHashMap;
mcimadamore@1347 47
mcimadamore@1415 48 import static com.sun.tools.javac.code.TypeTag.*;
mcimadamore@1347 49 import static com.sun.tools.javac.tree.JCTree.Tag.*;
mcimadamore@1347 50
mcimadamore@1347 51 /**
mcimadamore@1347 52 * This is an helper class that is used to perform deferred type-analysis.
mcimadamore@1347 53 * Each time a poly expression occurs in argument position, javac attributes it
mcimadamore@1347 54 * with a temporary 'deferred type' that is checked (possibly multiple times)
mcimadamore@1347 55 * against an expected formal type.
mcimadamore@1347 56 *
mcimadamore@1347 57 * <p><b>This is NOT part of any supported API.
mcimadamore@1347 58 * If you write code that depends on this, you do so at your own risk.
mcimadamore@1347 59 * This code and its internal interfaces are subject to change or
mcimadamore@1347 60 * deletion without notice.</b>
mcimadamore@1347 61 */
mcimadamore@1347 62 public class DeferredAttr extends JCTree.Visitor {
mcimadamore@1347 63 protected static final Context.Key<DeferredAttr> deferredAttrKey =
mcimadamore@1347 64 new Context.Key<DeferredAttr>();
mcimadamore@1347 65
mcimadamore@1347 66 final Attr attr;
mcimadamore@1347 67 final Check chk;
mcimadamore@1510 68 final JCDiagnostic.Factory diags;
mcimadamore@1347 69 final Enter enter;
mcimadamore@1347 70 final Infer infer;
mcimadamore@1581 71 final Resolve rs;
mcimadamore@1347 72 final Log log;
mcimadamore@1347 73 final Symtab syms;
mcimadamore@1347 74 final TreeMaker make;
mcimadamore@1347 75 final Types types;
mcimadamore@1347 76
mcimadamore@1347 77 public static DeferredAttr instance(Context context) {
mcimadamore@1347 78 DeferredAttr instance = context.get(deferredAttrKey);
mcimadamore@1347 79 if (instance == null)
mcimadamore@1347 80 instance = new DeferredAttr(context);
mcimadamore@1347 81 return instance;
mcimadamore@1347 82 }
mcimadamore@1347 83
mcimadamore@1347 84 protected DeferredAttr(Context context) {
mcimadamore@1347 85 context.put(deferredAttrKey, this);
mcimadamore@1347 86 attr = Attr.instance(context);
mcimadamore@1347 87 chk = Check.instance(context);
mcimadamore@1510 88 diags = JCDiagnostic.Factory.instance(context);
mcimadamore@1347 89 enter = Enter.instance(context);
mcimadamore@1347 90 infer = Infer.instance(context);
mcimadamore@1581 91 rs = Resolve.instance(context);
mcimadamore@1347 92 log = Log.instance(context);
mcimadamore@1347 93 syms = Symtab.instance(context);
mcimadamore@1347 94 make = TreeMaker.instance(context);
mcimadamore@1347 95 types = Types.instance(context);
mcimadamore@1510 96 Names names = Names.instance(context);
mcimadamore@1510 97 stuckTree = make.Ident(names.empty).setType(Type.noType);
mcimadamore@1347 98 }
mcimadamore@1347 99
mcimadamore@1510 100 /** shared tree for stuck expressions */
mcimadamore@1510 101 final JCTree stuckTree;
mcimadamore@1510 102
mcimadamore@1347 103 /**
mcimadamore@1347 104 * This type represents a deferred type. A deferred type starts off with
mcimadamore@1347 105 * no information on the underlying expression type. Such info needs to be
mcimadamore@1347 106 * discovered through type-checking the deferred type against a target-type.
mcimadamore@1347 107 * Every deferred type keeps a pointer to the AST node from which it originated.
mcimadamore@1347 108 */
mcimadamore@1347 109 public class DeferredType extends Type {
mcimadamore@1347 110
mcimadamore@1347 111 public JCExpression tree;
mcimadamore@1347 112 Env<AttrContext> env;
mcimadamore@1347 113 AttrMode mode;
mcimadamore@1347 114 SpeculativeCache speculativeCache;
mcimadamore@1347 115
mcimadamore@1347 116 DeferredType(JCExpression tree, Env<AttrContext> env) {
mcimadamore@1347 117 super(DEFERRED, null);
mcimadamore@1347 118 this.tree = tree;
mcimadamore@1347 119 this.env = env.dup(tree, env.info.dup());
mcimadamore@1347 120 this.speculativeCache = new SpeculativeCache();
mcimadamore@1347 121 }
mcimadamore@1347 122
mcimadamore@1347 123 /**
mcimadamore@1347 124 * A speculative cache is used to keep track of all overload resolution rounds
mcimadamore@1347 125 * that triggered speculative attribution on a given deferred type. Each entry
mcimadamore@1347 126 * stores a pointer to the speculative tree and the resolution phase in which the entry
mcimadamore@1347 127 * has been added.
mcimadamore@1347 128 */
mcimadamore@1347 129 class SpeculativeCache {
mcimadamore@1347 130
mcimadamore@1347 131 private Map<Symbol, List<Entry>> cache =
mcimadamore@1347 132 new WeakHashMap<Symbol, List<Entry>>();
mcimadamore@1347 133
mcimadamore@1347 134 class Entry {
mcimadamore@1347 135 JCTree speculativeTree;
mcimadamore@1347 136 Resolve.MethodResolutionPhase phase;
mcimadamore@1347 137
mcimadamore@1347 138 public Entry(JCTree speculativeTree, MethodResolutionPhase phase) {
mcimadamore@1347 139 this.speculativeTree = speculativeTree;
mcimadamore@1347 140 this.phase = phase;
mcimadamore@1347 141 }
mcimadamore@1347 142
mcimadamore@1347 143 boolean matches(Resolve.MethodResolutionPhase phase) {
mcimadamore@1347 144 return this.phase == phase;
mcimadamore@1347 145 }
mcimadamore@1347 146 }
mcimadamore@1347 147
mcimadamore@1347 148 /**
mcimadamore@1347 149 * Retrieve a speculative cache entry corresponding to given symbol
mcimadamore@1347 150 * and resolution phase
mcimadamore@1347 151 */
mcimadamore@1347 152 Entry get(Symbol msym, MethodResolutionPhase phase) {
mcimadamore@1347 153 List<Entry> entries = cache.get(msym);
mcimadamore@1347 154 if (entries == null) return null;
mcimadamore@1347 155 for (Entry e : entries) {
mcimadamore@1347 156 if (e.matches(phase)) return e;
mcimadamore@1347 157 }
mcimadamore@1347 158 return null;
mcimadamore@1347 159 }
mcimadamore@1347 160
mcimadamore@1347 161 /**
mcimadamore@1347 162 * Stores a speculative cache entry corresponding to given symbol
mcimadamore@1347 163 * and resolution phase
mcimadamore@1347 164 */
mcimadamore@1347 165 void put(Symbol msym, JCTree speculativeTree, MethodResolutionPhase phase) {
mcimadamore@1347 166 List<Entry> entries = cache.get(msym);
mcimadamore@1347 167 if (entries == null) {
mcimadamore@1347 168 entries = List.nil();
mcimadamore@1347 169 }
mcimadamore@1347 170 cache.put(msym, entries.prepend(new Entry(speculativeTree, phase)));
mcimadamore@1347 171 }
mcimadamore@1347 172 }
mcimadamore@1347 173
mcimadamore@1347 174 /**
mcimadamore@1347 175 * Get the type that has been computed during a speculative attribution round
mcimadamore@1347 176 */
mcimadamore@1347 177 Type speculativeType(Symbol msym, MethodResolutionPhase phase) {
mcimadamore@1347 178 SpeculativeCache.Entry e = speculativeCache.get(msym, phase);
mcimadamore@1347 179 return e != null ? e.speculativeTree.type : Type.noType;
mcimadamore@1347 180 }
mcimadamore@1347 181
mcimadamore@1347 182 /**
mcimadamore@1347 183 * Check a deferred type against a potential target-type. Depending on
mcimadamore@1347 184 * the current attribution mode, a normal vs. speculative attribution
mcimadamore@1347 185 * round is performed on the underlying AST node. There can be only one
mcimadamore@1347 186 * speculative round for a given target method symbol; moreover, a normal
mcimadamore@1347 187 * attribution round must follow one or more speculative rounds.
mcimadamore@1347 188 */
mcimadamore@1347 189 Type check(ResultInfo resultInfo) {
mcimadamore@1481 190 return check(resultInfo, stuckVars(tree, env, resultInfo), basicCompleter);
mcimadamore@1481 191 }
mcimadamore@1481 192
mcimadamore@1481 193 Type check(ResultInfo resultInfo, List<Type> stuckVars, DeferredTypeCompleter deferredTypeCompleter) {
mcimadamore@1347 194 DeferredAttrContext deferredAttrContext =
mcimadamore@1347 195 resultInfo.checkContext.deferredAttrContext();
mcimadamore@1347 196 Assert.check(deferredAttrContext != emptyDeferredAttrContext);
mcimadamore@1347 197 if (stuckVars.nonEmpty()) {
mcimadamore@1347 198 deferredAttrContext.addDeferredAttrNode(this, resultInfo, stuckVars);
mcimadamore@1347 199 return Type.noType;
mcimadamore@1347 200 } else {
mcimadamore@1347 201 try {
mcimadamore@1481 202 return deferredTypeCompleter.complete(this, resultInfo, deferredAttrContext);
mcimadamore@1347 203 } finally {
mcimadamore@1347 204 mode = deferredAttrContext.mode;
mcimadamore@1347 205 }
mcimadamore@1347 206 }
mcimadamore@1347 207 }
mcimadamore@1347 208 }
mcimadamore@1347 209
mcimadamore@1347 210 /**
mcimadamore@1481 211 * A completer for deferred types. Defines an entry point for type-checking
mcimadamore@1481 212 * a deferred type.
mcimadamore@1481 213 */
mcimadamore@1481 214 interface DeferredTypeCompleter {
mcimadamore@1481 215 /**
mcimadamore@1481 216 * Entry point for type-checking a deferred type. Depending on the
mcimadamore@1481 217 * circumstances, type-checking could amount to full attribution
mcimadamore@1481 218 * or partial structural check (aka potential applicability).
mcimadamore@1481 219 */
mcimadamore@1481 220 Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext);
mcimadamore@1481 221 }
mcimadamore@1481 222
mcimadamore@1481 223 /**
mcimadamore@1481 224 * A basic completer for deferred types. This completer type-checks a deferred type
mcimadamore@1481 225 * using attribution; depending on the attribution mode, this could be either standard
mcimadamore@1481 226 * or speculative attribution.
mcimadamore@1481 227 */
mcimadamore@1481 228 DeferredTypeCompleter basicCompleter = new DeferredTypeCompleter() {
mcimadamore@1481 229 public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
mcimadamore@1481 230 switch (deferredAttrContext.mode) {
mcimadamore@1481 231 case SPECULATIVE:
mcimadamore@1481 232 Assert.check(dt.mode == null ||
mcimadamore@1481 233 (dt.mode == AttrMode.SPECULATIVE &&
mcimadamore@1481 234 dt.speculativeType(deferredAttrContext.msym, deferredAttrContext.phase).hasTag(NONE)));
mcimadamore@1481 235 JCTree speculativeTree = attribSpeculative(dt.tree, dt.env, resultInfo);
mcimadamore@1481 236 dt.speculativeCache.put(deferredAttrContext.msym, speculativeTree, deferredAttrContext.phase);
mcimadamore@1481 237 return speculativeTree.type;
mcimadamore@1481 238 case CHECK:
mcimadamore@1562 239 Assert.check(dt.mode != null);
mcimadamore@1481 240 return attr.attribTree(dt.tree, dt.env, resultInfo);
mcimadamore@1481 241 }
mcimadamore@1481 242 Assert.error();
mcimadamore@1481 243 return null;
mcimadamore@1481 244 }
mcimadamore@1481 245 };
mcimadamore@1481 246
mcimadamore@1562 247 DeferredTypeCompleter dummyCompleter = new DeferredTypeCompleter() {
mcimadamore@1562 248 public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
mcimadamore@1562 249 Assert.check(deferredAttrContext.mode == AttrMode.CHECK);
mcimadamore@1562 250 return dt.tree.type = Type.noType;
mcimadamore@1562 251 }
mcimadamore@1562 252 };
mcimadamore@1562 253
mcimadamore@1481 254 /**
mcimadamore@1347 255 * The 'mode' in which the deferred type is to be type-checked
mcimadamore@1347 256 */
mcimadamore@1347 257 public enum AttrMode {
mcimadamore@1347 258 /**
mcimadamore@1347 259 * A speculative type-checking round is used during overload resolution
mcimadamore@1347 260 * mainly to generate constraints on inference variables. Side-effects
mcimadamore@1347 261 * arising from type-checking the expression associated with the deferred
mcimadamore@1347 262 * type are reversed after the speculative round finishes. This means the
mcimadamore@1347 263 * expression tree will be left in a blank state.
mcimadamore@1347 264 */
mcimadamore@1347 265 SPECULATIVE,
mcimadamore@1347 266 /**
mcimadamore@1347 267 * This is the plain type-checking mode. Produces side-effects on the underlying AST node
mcimadamore@1347 268 */
mcimadamore@1347 269 CHECK;
mcimadamore@1347 270 }
mcimadamore@1347 271
mcimadamore@1347 272 /**
mcimadamore@1347 273 * Routine that performs speculative type-checking; the input AST node is
mcimadamore@1347 274 * cloned (to avoid side-effects cause by Attr) and compiler state is
mcimadamore@1347 275 * restored after type-checking. All diagnostics (but critical ones) are
mcimadamore@1347 276 * disabled during speculative type-checking.
mcimadamore@1347 277 */
mcimadamore@1347 278 JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
mcimadamore@1596 279 final JCTree newTree = new TreeCopier<Object>(make).copy(tree);
mcimadamore@1347 280 Env<AttrContext> speculativeEnv = env.dup(newTree, env.info.dup(env.info.scope.dupUnshared()));
mcimadamore@1347 281 speculativeEnv.info.scope.owner = env.info.scope.owner;
jjg@1406 282 Log.DeferredDiagnosticHandler deferredDiagnosticHandler =
jjg@1406 283 new Log.DeferredDiagnosticHandler(log, new Filter<JCDiagnostic>() {
mcimadamore@1596 284 public boolean accepts(final JCDiagnostic d) {
mcimadamore@1596 285 class PosScanner extends TreeScanner {
mcimadamore@1596 286 boolean found = false;
mcimadamore@1596 287
mcimadamore@1596 288 @Override
mcimadamore@1596 289 public void scan(JCTree tree) {
mcimadamore@1596 290 if (tree != null &&
mcimadamore@1596 291 tree.pos() == d.getDiagnosticPosition()) {
mcimadamore@1596 292 found = true;
mcimadamore@1596 293 }
mcimadamore@1596 294 super.scan(tree);
mcimadamore@1596 295 }
mcimadamore@1596 296 };
mcimadamore@1596 297 PosScanner posScanner = new PosScanner();
mcimadamore@1596 298 posScanner.scan(newTree);
mcimadamore@1596 299 return posScanner.found;
jjg@1406 300 }
jjg@1406 301 });
mcimadamore@1347 302 try {
mcimadamore@1347 303 attr.attribTree(newTree, speculativeEnv, resultInfo);
mcimadamore@1347 304 unenterScanner.scan(newTree);
mcimadamore@1347 305 return newTree;
mcimadamore@1347 306 } finally {
mcimadamore@1347 307 unenterScanner.scan(newTree);
jjg@1406 308 log.popDiagnosticHandler(deferredDiagnosticHandler);
mcimadamore@1347 309 }
mcimadamore@1347 310 }
mcimadamore@1347 311 //where
mcimadamore@1347 312 protected TreeScanner unenterScanner = new TreeScanner() {
mcimadamore@1347 313 @Override
mcimadamore@1347 314 public void visitClassDef(JCClassDecl tree) {
mcimadamore@1347 315 ClassSymbol csym = tree.sym;
mcimadamore@1415 316 //if something went wrong during method applicability check
mcimadamore@1415 317 //it is possible that nested expressions inside argument expression
mcimadamore@1415 318 //are left unchecked - in such cases there's nothing to clean up.
mcimadamore@1415 319 if (csym == null) return;
mcimadamore@1347 320 enter.typeEnvs.remove(csym);
mcimadamore@1347 321 chk.compiled.remove(csym.flatname);
mcimadamore@1347 322 syms.classes.remove(csym.flatname);
mcimadamore@1347 323 super.visitClassDef(tree);
mcimadamore@1347 324 }
mcimadamore@1347 325 };
mcimadamore@1347 326
mcimadamore@1347 327 /**
mcimadamore@1347 328 * A deferred context is created on each method check. A deferred context is
mcimadamore@1347 329 * used to keep track of information associated with the method check, such as
mcimadamore@1347 330 * the symbol of the method being checked, the overload resolution phase,
mcimadamore@1347 331 * the kind of attribution mode to be applied to deferred types and so forth.
mcimadamore@1347 332 * As deferred types are processed (by the method check routine) stuck AST nodes
mcimadamore@1347 333 * are added (as new deferred attribution nodes) to this context. The complete()
mcimadamore@1347 334 * routine makes sure that all pending nodes are properly processed, by
mcimadamore@1347 335 * progressively instantiating all inference variables on which one or more
mcimadamore@1347 336 * deferred attribution node is stuck.
mcimadamore@1347 337 */
mcimadamore@1347 338 class DeferredAttrContext {
mcimadamore@1347 339
mcimadamore@1347 340 /** attribution mode */
mcimadamore@1347 341 final AttrMode mode;
mcimadamore@1347 342
mcimadamore@1347 343 /** symbol of the method being checked */
mcimadamore@1347 344 final Symbol msym;
mcimadamore@1347 345
mcimadamore@1347 346 /** method resolution step */
mcimadamore@1347 347 final Resolve.MethodResolutionPhase phase;
mcimadamore@1347 348
mcimadamore@1347 349 /** inference context */
mcimadamore@1347 350 final InferenceContext inferenceContext;
mcimadamore@1347 351
mcimadamore@1551 352 /** parent deferred context */
mcimadamore@1551 353 final DeferredAttrContext parent;
mcimadamore@1551 354
mcimadamore@1551 355 /** Warner object to report warnings */
mcimadamore@1551 356 final Warner warn;
mcimadamore@1551 357
mcimadamore@1347 358 /** list of deferred attribution nodes to be processed */
mcimadamore@1347 359 ArrayList<DeferredAttrNode> deferredAttrNodes = new ArrayList<DeferredAttrNode>();
mcimadamore@1347 360
mcimadamore@1551 361 DeferredAttrContext(AttrMode mode, Symbol msym, MethodResolutionPhase phase,
mcimadamore@1551 362 InferenceContext inferenceContext, DeferredAttrContext parent, Warner warn) {
mcimadamore@1347 363 this.mode = mode;
mcimadamore@1347 364 this.msym = msym;
mcimadamore@1347 365 this.phase = phase;
mcimadamore@1551 366 this.parent = parent;
mcimadamore@1551 367 this.warn = warn;
mcimadamore@1347 368 this.inferenceContext = inferenceContext;
mcimadamore@1347 369 }
mcimadamore@1347 370
mcimadamore@1347 371 /**
mcimadamore@1347 372 * Adds a node to the list of deferred attribution nodes - used by Resolve.rawCheckArgumentsApplicable
mcimadamore@1347 373 * Nodes added this way act as 'roots' for the out-of-order method checking process.
mcimadamore@1347 374 */
mcimadamore@1347 375 void addDeferredAttrNode(final DeferredType dt, ResultInfo resultInfo, List<Type> stuckVars) {
mcimadamore@1347 376 deferredAttrNodes.add(new DeferredAttrNode(dt, resultInfo, stuckVars));
mcimadamore@1347 377 }
mcimadamore@1347 378
mcimadamore@1347 379 /**
mcimadamore@1347 380 * Incrementally process all nodes, by skipping 'stuck' nodes and attributing
mcimadamore@1347 381 * 'unstuck' ones. If at any point no progress can be made (no 'unstuck' nodes)
mcimadamore@1347 382 * some inference variable might get eagerly instantiated so that all nodes
mcimadamore@1347 383 * can be type-checked.
mcimadamore@1347 384 */
mcimadamore@1347 385 void complete() {
mcimadamore@1347 386 while (!deferredAttrNodes.isEmpty()) {
mcimadamore@1415 387 Set<Type> stuckVars = new LinkedHashSet<Type>();
mcimadamore@1347 388 boolean progress = false;
mcimadamore@1347 389 //scan a defensive copy of the node list - this is because a deferred
mcimadamore@1347 390 //attribution round can add new nodes to the list
mcimadamore@1347 391 for (DeferredAttrNode deferredAttrNode : List.from(deferredAttrNodes)) {
mcimadamore@1551 392 if (!deferredAttrNode.process(this)) {
mcimadamore@1510 393 stuckVars.addAll(deferredAttrNode.stuckVars);
mcimadamore@1510 394 } else {
mcimadamore@1347 395 deferredAttrNodes.remove(deferredAttrNode);
mcimadamore@1347 396 progress = true;
mcimadamore@1347 397 }
mcimadamore@1347 398 }
mcimadamore@1347 399 if (!progress) {
mcimadamore@1347 400 //remove all variables that have already been instantiated
mcimadamore@1347 401 //from the list of stuck variables
mcimadamore@1562 402 inferenceContext.solveAny(List.from(stuckVars), warn);
mcimadamore@1550 403 inferenceContext.notifyChange();
mcimadamore@1347 404 }
mcimadamore@1347 405 }
mcimadamore@1347 406 }
mcimadamore@1551 407 }
mcimadamore@1551 408
mcimadamore@1551 409 /**
mcimadamore@1551 410 * Class representing a deferred attribution node. It keeps track of
mcimadamore@1551 411 * a deferred type, along with the expected target type information.
mcimadamore@1551 412 */
mcimadamore@1551 413 class DeferredAttrNode implements Infer.FreeTypeListener {
mcimadamore@1551 414
mcimadamore@1551 415 /** underlying deferred type */
mcimadamore@1551 416 DeferredType dt;
mcimadamore@1551 417
mcimadamore@1551 418 /** underlying target type information */
mcimadamore@1551 419 ResultInfo resultInfo;
mcimadamore@1551 420
mcimadamore@1551 421 /** list of uninferred inference variables causing this node to be stuck */
mcimadamore@1551 422 List<Type> stuckVars;
mcimadamore@1551 423
mcimadamore@1551 424 DeferredAttrNode(DeferredType dt, ResultInfo resultInfo, List<Type> stuckVars) {
mcimadamore@1551 425 this.dt = dt;
mcimadamore@1551 426 this.resultInfo = resultInfo;
mcimadamore@1551 427 this.stuckVars = stuckVars;
mcimadamore@1551 428 if (!stuckVars.isEmpty()) {
mcimadamore@1551 429 resultInfo.checkContext.inferenceContext().addFreeTypeListener(stuckVars, this);
mcimadamore@1551 430 }
mcimadamore@1551 431 }
mcimadamore@1551 432
mcimadamore@1551 433 @Override
mcimadamore@1551 434 public void typesInferred(InferenceContext inferenceContext) {
mcimadamore@1551 435 stuckVars = List.nil();
mcimadamore@1551 436 resultInfo = resultInfo.dup(inferenceContext.asInstType(resultInfo.pt));
mcimadamore@1551 437 }
mcimadamore@1347 438
mcimadamore@1347 439 /**
mcimadamore@1551 440 * Process a deferred attribution node.
mcimadamore@1551 441 * Invariant: a stuck node cannot be processed.
mcimadamore@1347 442 */
mcimadamore@1551 443 @SuppressWarnings("fallthrough")
mcimadamore@1551 444 boolean process(DeferredAttrContext deferredAttrContext) {
mcimadamore@1551 445 switch (deferredAttrContext.mode) {
mcimadamore@1551 446 case SPECULATIVE:
mcimadamore@1551 447 dt.check(resultInfo, List.<Type>nil(), new StructuralStuckChecker());
mcimadamore@1551 448 return true;
mcimadamore@1551 449 case CHECK:
mcimadamore@1551 450 if (stuckVars.nonEmpty()) {
mcimadamore@1562 451 //stuck expression - see if we can propagate
mcimadamore@1562 452 if (deferredAttrContext.parent != emptyDeferredAttrContext &&
mcimadamore@1562 453 Type.containsAny(deferredAttrContext.parent.inferenceContext.inferencevars, List.from(stuckVars))) {
mcimadamore@1562 454 deferredAttrContext.parent.deferredAttrNodes.add(this);
mcimadamore@1562 455 dt.check(resultInfo, List.<Type>nil(), dummyCompleter);
mcimadamore@1562 456 return true;
mcimadamore@1562 457 } else {
mcimadamore@1562 458 return false;
mcimadamore@1562 459 }
mcimadamore@1551 460 } else {
mcimadamore@1551 461 dt.check(resultInfo, stuckVars, basicCompleter);
mcimadamore@1551 462 return true;
mcimadamore@1551 463 }
mcimadamore@1551 464 default:
mcimadamore@1551 465 throw new AssertionError("Bad mode");
mcimadamore@1551 466 }
mcimadamore@1551 467 }
mcimadamore@1347 468
mcimadamore@1551 469 /**
mcimadamore@1551 470 * Structural checker for stuck expressions
mcimadamore@1551 471 */
mcimadamore@1551 472 class StructuralStuckChecker extends TreeScanner implements DeferredTypeCompleter {
mcimadamore@1347 473
mcimadamore@1347 474 ResultInfo resultInfo;
mcimadamore@1551 475 InferenceContext inferenceContext;
mcimadamore@1581 476 Env<AttrContext> env;
mcimadamore@1347 477
mcimadamore@1551 478 public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
mcimadamore@1551 479 this.resultInfo = resultInfo;
mcimadamore@1551 480 this.inferenceContext = deferredAttrContext.inferenceContext;
mcimadamore@1581 481 this.env = dt.env.dup(dt.tree, dt.env.info.dup());
mcimadamore@1551 482 dt.tree.accept(this);
mcimadamore@1551 483 dt.speculativeCache.put(deferredAttrContext.msym, stuckTree, deferredAttrContext.phase);
mcimadamore@1551 484 return Type.noType;
mcimadamore@1551 485 }
mcimadamore@1347 486
mcimadamore@1551 487 @Override
mcimadamore@1551 488 public void visitLambda(JCLambda tree) {
mcimadamore@1551 489 Check.CheckContext checkContext = resultInfo.checkContext;
mcimadamore@1551 490 Type pt = resultInfo.pt;
mcimadamore@1551 491 if (inferenceContext.inferencevars.contains(pt)) {
mcimadamore@1551 492 //ok
mcimadamore@1551 493 return;
mcimadamore@1551 494 } else {
mcimadamore@1551 495 //must be a functional descriptor
mcimadamore@1551 496 try {
mcimadamore@1551 497 Type desc = types.findDescriptorType(pt);
mcimadamore@1551 498 if (desc.getParameterTypes().length() != tree.params.length()) {
mcimadamore@1551 499 checkContext.report(tree, diags.fragment("incompatible.arg.types.in.lambda"));
mcimadamore@1551 500 }
mcimadamore@1551 501 } catch (Types.FunctionDescriptorLookupError ex) {
mcimadamore@1551 502 checkContext.report(null, ex.getDiagnostic());
mcimadamore@1551 503 }
mcimadamore@1347 504 }
mcimadamore@1347 505 }
mcimadamore@1347 506
mcimadamore@1347 507 @Override
mcimadamore@1551 508 public void visitNewClass(JCNewClass tree) {
mcimadamore@1551 509 //do nothing
mcimadamore@1347 510 }
mcimadamore@1347 511
mcimadamore@1551 512 @Override
mcimadamore@1551 513 public void visitApply(JCMethodInvocation tree) {
mcimadamore@1551 514 //do nothing
mcimadamore@1347 515 }
mcimadamore@1347 516
mcimadamore@1551 517 @Override
mcimadamore@1551 518 public void visitReference(JCMemberReference tree) {
mcimadamore@1551 519 Check.CheckContext checkContext = resultInfo.checkContext;
mcimadamore@1551 520 Type pt = resultInfo.pt;
mcimadamore@1551 521 if (inferenceContext.inferencevars.contains(pt)) {
mcimadamore@1551 522 //ok
mcimadamore@1551 523 return;
mcimadamore@1551 524 } else {
mcimadamore@1551 525 try {
mcimadamore@1551 526 types.findDescriptorType(pt);
mcimadamore@1551 527 } catch (Types.FunctionDescriptorLookupError ex) {
mcimadamore@1551 528 checkContext.report(null, ex.getDiagnostic());
mcimadamore@1510 529 }
mcimadamore@1581 530 JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), env,
mcimadamore@1581 531 attr.memberReferenceQualifierResult(tree));
mcimadamore@1581 532 ListBuffer<Type> argtypes = ListBuffer.lb();
mcimadamore@1581 533 for (Type t : types.findDescriptorType(pt).getParameterTypes()) {
mcimadamore@1581 534 argtypes.append(syms.errType);
mcimadamore@1581 535 }
mcimadamore@1581 536 JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree);
mcimadamore@1581 537 mref2.expr = exprTree;
mcimadamore@1581 538 Pair<Symbol, ?> lookupRes =
mcimadamore@1581 539 rs.resolveMemberReference(tree, env, mref2, exprTree.type, tree.name, argtypes.toList(), null, true);
mcimadamore@1581 540 switch (lookupRes.fst.kind) {
mcimadamore@1581 541 //note: as argtypes are erroneous types, type-errors must
mcimadamore@1581 542 //have been caused by arity mismatch
mcimadamore@1581 543 case Kinds.ABSENT_MTH:
mcimadamore@1581 544 case Kinds.WRONG_MTH:
mcimadamore@1581 545 case Kinds.WRONG_MTHS:
mcimadamore@1581 546 case Kinds.STATICERR:
mcimadamore@1581 547 case Kinds.MISSING_ENCL:
mcimadamore@1581 548 checkContext.report(null, diags.fragment("incompatible.arg.types.in.mref"));
mcimadamore@1581 549 }
mcimadamore@1510 550 }
mcimadamore@1347 551 }
mcimadamore@1347 552 }
mcimadamore@1347 553 }
mcimadamore@1347 554
mcimadamore@1347 555 /** an empty deferred attribution context - all methods throw exceptions */
mcimadamore@1347 556 final DeferredAttrContext emptyDeferredAttrContext =
mcimadamore@1551 557 new DeferredAttrContext(AttrMode.CHECK, null, MethodResolutionPhase.BOX, null, null, null) {
mcimadamore@1347 558 @Override
mcimadamore@1347 559 void addDeferredAttrNode(DeferredType dt, ResultInfo ri, List<Type> stuckVars) {
mcimadamore@1347 560 Assert.error("Empty deferred context!");
mcimadamore@1347 561 }
mcimadamore@1347 562 @Override
mcimadamore@1347 563 void complete() {
mcimadamore@1347 564 Assert.error("Empty deferred context!");
mcimadamore@1347 565 }
mcimadamore@1347 566 };
mcimadamore@1347 567
mcimadamore@1347 568 /**
mcimadamore@1347 569 * Map a list of types possibly containing one or more deferred types
mcimadamore@1347 570 * into a list of ordinary types. Each deferred type D is mapped into a type T,
mcimadamore@1347 571 * where T is computed by retrieving the type that has already been
mcimadamore@1347 572 * computed for D during a previous deferred attribution round of the given kind.
mcimadamore@1347 573 */
mcimadamore@1347 574 class DeferredTypeMap extends Type.Mapping {
mcimadamore@1347 575
mcimadamore@1347 576 DeferredAttrContext deferredAttrContext;
mcimadamore@1347 577
mcimadamore@1347 578 protected DeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
mcimadamore@1347 579 super(String.format("deferredTypeMap[%s]", mode));
mcimadamore@1551 580 this.deferredAttrContext = new DeferredAttrContext(mode, msym, phase,
mcimadamore@1551 581 infer.emptyContext, emptyDeferredAttrContext, types.noWarnings);
mcimadamore@1347 582 }
mcimadamore@1347 583
mcimadamore@1347 584 protected boolean validState(DeferredType dt) {
mcimadamore@1347 585 return dt.mode != null &&
mcimadamore@1347 586 deferredAttrContext.mode.ordinal() <= dt.mode.ordinal();
mcimadamore@1347 587 }
mcimadamore@1347 588
mcimadamore@1347 589 @Override
mcimadamore@1347 590 public Type apply(Type t) {
jjg@1374 591 if (!t.hasTag(DEFERRED)) {
mcimadamore@1347 592 return t.map(this);
mcimadamore@1347 593 } else {
mcimadamore@1347 594 DeferredType dt = (DeferredType)t;
mcimadamore@1347 595 Assert.check(validState(dt));
mcimadamore@1347 596 return typeOf(dt);
mcimadamore@1347 597 }
mcimadamore@1347 598 }
mcimadamore@1347 599
mcimadamore@1347 600 protected Type typeOf(DeferredType dt) {
mcimadamore@1347 601 switch (deferredAttrContext.mode) {
mcimadamore@1347 602 case CHECK:
mcimadamore@1347 603 return dt.tree.type == null ? Type.noType : dt.tree.type;
mcimadamore@1347 604 case SPECULATIVE:
mcimadamore@1347 605 return dt.speculativeType(deferredAttrContext.msym, deferredAttrContext.phase);
mcimadamore@1347 606 }
mcimadamore@1347 607 Assert.error();
mcimadamore@1347 608 return null;
mcimadamore@1347 609 }
mcimadamore@1347 610 }
mcimadamore@1347 611
mcimadamore@1347 612 /**
mcimadamore@1347 613 * Specialized recovery deferred mapping.
mcimadamore@1347 614 * Each deferred type D is mapped into a type T, where T is computed either by
mcimadamore@1347 615 * (i) retrieving the type that has already been computed for D during a previous
mcimadamore@1347 616 * attribution round (as before), or (ii) by synthesizing a new type R for D
mcimadamore@1347 617 * (the latter step is useful in a recovery scenario).
mcimadamore@1347 618 */
mcimadamore@1347 619 public class RecoveryDeferredTypeMap extends DeferredTypeMap {
mcimadamore@1347 620
mcimadamore@1347 621 public RecoveryDeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
mcimadamore@1415 622 super(mode, msym, phase != null ? phase : MethodResolutionPhase.BOX);
mcimadamore@1347 623 }
mcimadamore@1347 624
mcimadamore@1347 625 @Override
mcimadamore@1347 626 protected Type typeOf(DeferredType dt) {
mcimadamore@1347 627 Type owntype = super.typeOf(dt);
mcimadamore@1415 628 return owntype == Type.noType ?
mcimadamore@1347 629 recover(dt) : owntype;
mcimadamore@1347 630 }
mcimadamore@1347 631
mcimadamore@1347 632 @Override
mcimadamore@1347 633 protected boolean validState(DeferredType dt) {
mcimadamore@1347 634 return true;
mcimadamore@1347 635 }
mcimadamore@1347 636
mcimadamore@1347 637 /**
mcimadamore@1347 638 * Synthesize a type for a deferred type that hasn't been previously
mcimadamore@1347 639 * reduced to an ordinary type. Functional deferred types and conditionals
mcimadamore@1347 640 * are mapped to themselves, in order to have a richer diagnostic
mcimadamore@1347 641 * representation. Remaining deferred types are attributed using
mcimadamore@1347 642 * a default expected type (j.l.Object).
mcimadamore@1347 643 */
mcimadamore@1347 644 private Type recover(DeferredType dt) {
mcimadamore@1348 645 dt.check(attr.new RecoveryInfo(deferredAttrContext));
mcimadamore@1415 646 return super.apply(dt);
mcimadamore@1347 647 }
mcimadamore@1347 648 }
mcimadamore@1347 649
mcimadamore@1347 650 /**
mcimadamore@1347 651 * Retrieves the list of inference variables that need to be inferred before
mcimadamore@1347 652 * an AST node can be type-checked
mcimadamore@1347 653 */
mcimadamore@1347 654 @SuppressWarnings("fallthrough")
mcimadamore@1415 655 List<Type> stuckVars(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
mcimadamore@1415 656 if (resultInfo.pt.hasTag(NONE) || resultInfo.pt.isErroneous()) {
mcimadamore@1348 657 return List.nil();
mcimadamore@1348 658 } else {
mcimadamore@1481 659 return stuckVarsInternal(tree, resultInfo.pt, resultInfo.checkContext.inferenceContext());
mcimadamore@1481 660 }
mcimadamore@1481 661 }
mcimadamore@1481 662 //where
mcimadamore@1481 663 private List<Type> stuckVarsInternal(JCTree tree, Type pt, Infer.InferenceContext inferenceContext) {
mcimadamore@1481 664 StuckChecker sc = new StuckChecker(pt, inferenceContext);
mcimadamore@1348 665 sc.scan(tree);
mcimadamore@1348 666 return List.from(sc.stuckVars);
mcimadamore@1348 667 }
mcimadamore@1481 668
mcimadamore@1481 669 /**
mcimadamore@1481 670 * A special tree scanner that would only visit portions of a given tree.
mcimadamore@1481 671 * The set of nodes visited by the scanner can be customized at construction-time.
mcimadamore@1481 672 */
mcimadamore@1481 673 abstract static class FilterScanner extends TreeScanner {
mcimadamore@1481 674
mcimadamore@1481 675 final Filter<JCTree> treeFilter;
mcimadamore@1481 676
mcimadamore@1481 677 FilterScanner(final Set<JCTree.Tag> validTags) {
mcimadamore@1481 678 this.treeFilter = new Filter<JCTree>() {
mcimadamore@1481 679 public boolean accepts(JCTree t) {
mcimadamore@1481 680 return validTags.contains(t.getTag());
mcimadamore@1481 681 }
mcimadamore@1481 682 };
mcimadamore@1481 683 }
mcimadamore@1481 684
mcimadamore@1481 685 @Override
mcimadamore@1481 686 public void scan(JCTree tree) {
mcimadamore@1481 687 if (tree != null) {
mcimadamore@1481 688 if (treeFilter.accepts(tree)) {
mcimadamore@1481 689 super.scan(tree);
mcimadamore@1481 690 } else {
mcimadamore@1481 691 skip(tree);
mcimadamore@1481 692 }
mcimadamore@1481 693 }
mcimadamore@1481 694 }
mcimadamore@1481 695
mcimadamore@1481 696 /**
mcimadamore@1481 697 * handler that is executed when a node has been discarded
mcimadamore@1481 698 */
mcimadamore@1481 699 abstract void skip(JCTree tree);
mcimadamore@1481 700 }
mcimadamore@1481 701
mcimadamore@1481 702 /**
mcimadamore@1481 703 * A tree scanner suitable for visiting the target-type dependent nodes of
mcimadamore@1481 704 * a given argument expression.
mcimadamore@1481 705 */
mcimadamore@1481 706 static class PolyScanner extends FilterScanner {
mcimadamore@1481 707
mcimadamore@1481 708 PolyScanner() {
mcimadamore@1481 709 super(EnumSet.of(CONDEXPR, PARENS, LAMBDA, REFERENCE));
mcimadamore@1481 710 }
mcimadamore@1481 711
mcimadamore@1481 712 @Override
mcimadamore@1481 713 void skip(JCTree tree) {
mcimadamore@1481 714 //do nothing
mcimadamore@1481 715 }
mcimadamore@1481 716 }
mcimadamore@1481 717
mcimadamore@1481 718 /**
mcimadamore@1481 719 * A tree scanner suitable for visiting the target-type dependent nodes nested
mcimadamore@1481 720 * within a lambda expression body.
mcimadamore@1481 721 */
mcimadamore@1481 722 static class LambdaReturnScanner extends FilterScanner {
mcimadamore@1481 723
mcimadamore@1481 724 LambdaReturnScanner() {
mcimadamore@1481 725 super(EnumSet.of(BLOCK, CASE, CATCH, DOLOOP, FOREACHLOOP,
mcimadamore@1481 726 FORLOOP, RETURN, SYNCHRONIZED, SWITCH, TRY, WHILELOOP));
mcimadamore@1481 727 }
mcimadamore@1481 728
mcimadamore@1481 729 @Override
mcimadamore@1481 730 void skip(JCTree tree) {
mcimadamore@1481 731 //do nothing
mcimadamore@1481 732 }
mcimadamore@1348 733 }
mcimadamore@1348 734
mcimadamore@1348 735 /**
mcimadamore@1348 736 * This visitor is used to check that structural expressions conform
mcimadamore@1348 737 * to their target - this step is required as inference could end up
mcimadamore@1348 738 * inferring types that make some of the nested expressions incompatible
mcimadamore@1348 739 * with their corresponding instantiated target
mcimadamore@1348 740 */
mcimadamore@1481 741 class StuckChecker extends PolyScanner {
mcimadamore@1348 742
mcimadamore@1348 743 Type pt;
mcimadamore@1348 744 Infer.InferenceContext inferenceContext;
mcimadamore@1415 745 Set<Type> stuckVars = new LinkedHashSet<Type>();
mcimadamore@1348 746
mcimadamore@1481 747 StuckChecker(Type pt, Infer.InferenceContext inferenceContext) {
mcimadamore@1481 748 this.pt = pt;
mcimadamore@1481 749 this.inferenceContext = inferenceContext;
mcimadamore@1348 750 }
mcimadamore@1348 751
mcimadamore@1348 752 @Override
mcimadamore@1348 753 public void visitLambda(JCLambda tree) {
mcimadamore@1481 754 if (inferenceContext.inferenceVars().contains(pt)) {
mcimadamore@1481 755 stuckVars.add(pt);
mcimadamore@1348 756 }
mcimadamore@1510 757 if (!types.isFunctionalInterface(pt)) {
mcimadamore@1481 758 return;
mcimadamore@1481 759 }
mcimadamore@1481 760 Type descType = types.findDescriptorType(pt);
mcimadamore@1481 761 List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
mcimadamore@1510 762 if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT &&
mcimadamore@1481 763 freeArgVars.nonEmpty()) {
mcimadamore@1481 764 stuckVars.addAll(freeArgVars);
mcimadamore@1481 765 }
mcimadamore@1481 766 scanLambdaBody(tree, descType.getReturnType());
mcimadamore@1348 767 }
mcimadamore@1348 768
mcimadamore@1348 769 @Override
mcimadamore@1348 770 public void visitReference(JCMemberReference tree) {
mcimadamore@1348 771 scan(tree.expr);
mcimadamore@1348 772 if (inferenceContext.inferenceVars().contains(pt)) {
mcimadamore@1348 773 stuckVars.add(pt);
mcimadamore@1348 774 return;
mcimadamore@1348 775 }
mcimadamore@1510 776 if (!types.isFunctionalInterface(pt)) {
mcimadamore@1348 777 return;
mcimadamore@1348 778 }
mcimadamore@1415 779
mcimadamore@1348 780 Type descType = types.findDescriptorType(pt);
mcimadamore@1348 781 List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
mcimadamore@1348 782 stuckVars.addAll(freeArgVars);
mcimadamore@1348 783 }
mcimadamore@1348 784
mcimadamore@1481 785 void scanLambdaBody(JCLambda lambda, final Type pt) {
mcimadamore@1481 786 if (lambda.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) {
mcimadamore@1481 787 stuckVars.addAll(stuckVarsInternal(lambda.body, pt, inferenceContext));
mcimadamore@1481 788 } else {
mcimadamore@1481 789 LambdaReturnScanner lambdaScanner = new LambdaReturnScanner() {
mcimadamore@1481 790 @Override
mcimadamore@1481 791 public void visitReturn(JCReturn tree) {
mcimadamore@1481 792 if (tree.expr != null) {
mcimadamore@1481 793 stuckVars.addAll(stuckVarsInternal(tree.expr, pt, inferenceContext));
mcimadamore@1481 794 }
mcimadamore@1481 795 }
mcimadamore@1481 796 };
mcimadamore@1481 797 lambdaScanner.scan(lambda.body);
mcimadamore@1348 798 }
mcimadamore@1347 799 }
mcimadamore@1347 800 }
mcimadamore@1347 801 }

mercurial