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

Thu, 04 Oct 2012 13:04:53 +0100

author
mcimadamore
date
Thu, 04 Oct 2012 13:04:53 +0100
changeset 1347
1408af4cd8b0
child 1348
573ceb23beeb
permissions
-rw-r--r--

7177387: Add target-typing support in method context
Summary: Add support for deferred types and speculative attribution
Reviewed-by: jjg, dlsmith

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@1347 41 import java.util.HashSet;
mcimadamore@1347 42 import java.util.Map;
mcimadamore@1347 43 import java.util.Queue;
mcimadamore@1347 44 import java.util.Set;
mcimadamore@1347 45 import java.util.WeakHashMap;
mcimadamore@1347 46
mcimadamore@1347 47 import static com.sun.tools.javac.code.TypeTags.*;
mcimadamore@1347 48 import static com.sun.tools.javac.tree.JCTree.Tag.*;
mcimadamore@1347 49 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
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@1347 68 final Enter enter;
mcimadamore@1347 69 final Infer infer;
mcimadamore@1347 70 final Log log;
mcimadamore@1347 71 final Symtab syms;
mcimadamore@1347 72 final TreeMaker make;
mcimadamore@1347 73 final Types types;
mcimadamore@1347 74
mcimadamore@1347 75 public static DeferredAttr instance(Context context) {
mcimadamore@1347 76 DeferredAttr instance = context.get(deferredAttrKey);
mcimadamore@1347 77 if (instance == null)
mcimadamore@1347 78 instance = new DeferredAttr(context);
mcimadamore@1347 79 return instance;
mcimadamore@1347 80 }
mcimadamore@1347 81
mcimadamore@1347 82 protected DeferredAttr(Context context) {
mcimadamore@1347 83 context.put(deferredAttrKey, this);
mcimadamore@1347 84 attr = Attr.instance(context);
mcimadamore@1347 85 chk = Check.instance(context);
mcimadamore@1347 86 enter = Enter.instance(context);
mcimadamore@1347 87 infer = Infer.instance(context);
mcimadamore@1347 88 log = Log.instance(context);
mcimadamore@1347 89 syms = Symtab.instance(context);
mcimadamore@1347 90 make = TreeMaker.instance(context);
mcimadamore@1347 91 types = Types.instance(context);
mcimadamore@1347 92 }
mcimadamore@1347 93
mcimadamore@1347 94 /**
mcimadamore@1347 95 * This type represents a deferred type. A deferred type starts off with
mcimadamore@1347 96 * no information on the underlying expression type. Such info needs to be
mcimadamore@1347 97 * discovered through type-checking the deferred type against a target-type.
mcimadamore@1347 98 * Every deferred type keeps a pointer to the AST node from which it originated.
mcimadamore@1347 99 */
mcimadamore@1347 100 public class DeferredType extends Type {
mcimadamore@1347 101
mcimadamore@1347 102 public JCExpression tree;
mcimadamore@1347 103 Env<AttrContext> env;
mcimadamore@1347 104 AttrMode mode;
mcimadamore@1347 105 SpeculativeCache speculativeCache;
mcimadamore@1347 106
mcimadamore@1347 107 DeferredType(JCExpression tree, Env<AttrContext> env) {
mcimadamore@1347 108 super(DEFERRED, null);
mcimadamore@1347 109 this.tree = tree;
mcimadamore@1347 110 this.env = env.dup(tree, env.info.dup());
mcimadamore@1347 111 this.speculativeCache = new SpeculativeCache();
mcimadamore@1347 112 }
mcimadamore@1347 113
mcimadamore@1347 114 /**
mcimadamore@1347 115 * A speculative cache is used to keep track of all overload resolution rounds
mcimadamore@1347 116 * that triggered speculative attribution on a given deferred type. Each entry
mcimadamore@1347 117 * stores a pointer to the speculative tree and the resolution phase in which the entry
mcimadamore@1347 118 * has been added.
mcimadamore@1347 119 */
mcimadamore@1347 120 class SpeculativeCache {
mcimadamore@1347 121
mcimadamore@1347 122 private Map<Symbol, List<Entry>> cache =
mcimadamore@1347 123 new WeakHashMap<Symbol, List<Entry>>();
mcimadamore@1347 124
mcimadamore@1347 125 class Entry {
mcimadamore@1347 126 JCTree speculativeTree;
mcimadamore@1347 127 Resolve.MethodResolutionPhase phase;
mcimadamore@1347 128
mcimadamore@1347 129 public Entry(JCTree speculativeTree, MethodResolutionPhase phase) {
mcimadamore@1347 130 this.speculativeTree = speculativeTree;
mcimadamore@1347 131 this.phase = phase;
mcimadamore@1347 132 }
mcimadamore@1347 133
mcimadamore@1347 134 boolean matches(Resolve.MethodResolutionPhase phase) {
mcimadamore@1347 135 return this.phase == phase;
mcimadamore@1347 136 }
mcimadamore@1347 137 }
mcimadamore@1347 138
mcimadamore@1347 139 /**
mcimadamore@1347 140 * Clone a speculative cache entry as a fresh entry associated
mcimadamore@1347 141 * with a new method (this maybe required to fixup speculative cache
mcimadamore@1347 142 * misses after Resolve.access())
mcimadamore@1347 143 */
mcimadamore@1347 144 void dupAllTo(Symbol from, Symbol to) {
mcimadamore@1347 145 Assert.check(cache.get(to) == null);
mcimadamore@1347 146 List<Entry> entries = cache.get(from);
mcimadamore@1347 147 if (entries != null) {
mcimadamore@1347 148 cache.put(to, entries);
mcimadamore@1347 149 }
mcimadamore@1347 150 }
mcimadamore@1347 151
mcimadamore@1347 152 /**
mcimadamore@1347 153 * Retrieve a speculative cache entry corresponding to given symbol
mcimadamore@1347 154 * and resolution phase
mcimadamore@1347 155 */
mcimadamore@1347 156 Entry get(Symbol msym, MethodResolutionPhase phase) {
mcimadamore@1347 157 List<Entry> entries = cache.get(msym);
mcimadamore@1347 158 if (entries == null) return null;
mcimadamore@1347 159 for (Entry e : entries) {
mcimadamore@1347 160 if (e.matches(phase)) return e;
mcimadamore@1347 161 }
mcimadamore@1347 162 return null;
mcimadamore@1347 163 }
mcimadamore@1347 164
mcimadamore@1347 165 /**
mcimadamore@1347 166 * Stores a speculative cache entry corresponding to given symbol
mcimadamore@1347 167 * and resolution phase
mcimadamore@1347 168 */
mcimadamore@1347 169 void put(Symbol msym, JCTree speculativeTree, MethodResolutionPhase phase) {
mcimadamore@1347 170 List<Entry> entries = cache.get(msym);
mcimadamore@1347 171 if (entries == null) {
mcimadamore@1347 172 entries = List.nil();
mcimadamore@1347 173 }
mcimadamore@1347 174 cache.put(msym, entries.prepend(new Entry(speculativeTree, phase)));
mcimadamore@1347 175 }
mcimadamore@1347 176 }
mcimadamore@1347 177
mcimadamore@1347 178 /**
mcimadamore@1347 179 * Get the type that has been computed during a speculative attribution round
mcimadamore@1347 180 */
mcimadamore@1347 181 Type speculativeType(Symbol msym, MethodResolutionPhase phase) {
mcimadamore@1347 182 SpeculativeCache.Entry e = speculativeCache.get(msym, phase);
mcimadamore@1347 183 return e != null ? e.speculativeTree.type : Type.noType;
mcimadamore@1347 184 }
mcimadamore@1347 185
mcimadamore@1347 186 /**
mcimadamore@1347 187 * Check a deferred type against a potential target-type. Depending on
mcimadamore@1347 188 * the current attribution mode, a normal vs. speculative attribution
mcimadamore@1347 189 * round is performed on the underlying AST node. There can be only one
mcimadamore@1347 190 * speculative round for a given target method symbol; moreover, a normal
mcimadamore@1347 191 * attribution round must follow one or more speculative rounds.
mcimadamore@1347 192 */
mcimadamore@1347 193 Type check(ResultInfo resultInfo) {
mcimadamore@1347 194 DeferredAttrContext deferredAttrContext =
mcimadamore@1347 195 resultInfo.checkContext.deferredAttrContext();
mcimadamore@1347 196 Assert.check(deferredAttrContext != emptyDeferredAttrContext);
mcimadamore@1347 197 List<Type> stuckVars = stuckVars(tree, resultInfo);
mcimadamore@1347 198 if (stuckVars.nonEmpty()) {
mcimadamore@1347 199 deferredAttrContext.addDeferredAttrNode(this, resultInfo, stuckVars);
mcimadamore@1347 200 return Type.noType;
mcimadamore@1347 201 } else {
mcimadamore@1347 202 try {
mcimadamore@1347 203 switch (deferredAttrContext.mode) {
mcimadamore@1347 204 case SPECULATIVE:
mcimadamore@1347 205 Assert.check(mode == null ||
mcimadamore@1347 206 (mode == AttrMode.SPECULATIVE &&
mcimadamore@1347 207 speculativeType(deferredAttrContext.msym, deferredAttrContext.phase).tag == NONE));
mcimadamore@1347 208 JCTree speculativeTree = attribSpeculative(tree, env, resultInfo);
mcimadamore@1347 209 speculativeCache.put(deferredAttrContext.msym, speculativeTree, deferredAttrContext.phase);
mcimadamore@1347 210 return speculativeTree.type;
mcimadamore@1347 211 case CHECK:
mcimadamore@1347 212 Assert.check(mode == AttrMode.SPECULATIVE);
mcimadamore@1347 213 return attr.attribTree(tree, env, resultInfo);
mcimadamore@1347 214 }
mcimadamore@1347 215 Assert.error();
mcimadamore@1347 216 return null;
mcimadamore@1347 217 } finally {
mcimadamore@1347 218 mode = deferredAttrContext.mode;
mcimadamore@1347 219 }
mcimadamore@1347 220 }
mcimadamore@1347 221 }
mcimadamore@1347 222 }
mcimadamore@1347 223
mcimadamore@1347 224 /**
mcimadamore@1347 225 * The 'mode' in which the deferred type is to be type-checked
mcimadamore@1347 226 */
mcimadamore@1347 227 public enum AttrMode {
mcimadamore@1347 228 /**
mcimadamore@1347 229 * A speculative type-checking round is used during overload resolution
mcimadamore@1347 230 * mainly to generate constraints on inference variables. Side-effects
mcimadamore@1347 231 * arising from type-checking the expression associated with the deferred
mcimadamore@1347 232 * type are reversed after the speculative round finishes. This means the
mcimadamore@1347 233 * expression tree will be left in a blank state.
mcimadamore@1347 234 */
mcimadamore@1347 235 SPECULATIVE,
mcimadamore@1347 236 /**
mcimadamore@1347 237 * This is the plain type-checking mode. Produces side-effects on the underlying AST node
mcimadamore@1347 238 */
mcimadamore@1347 239 CHECK;
mcimadamore@1347 240 }
mcimadamore@1347 241
mcimadamore@1347 242 /**
mcimadamore@1347 243 * Routine that performs speculative type-checking; the input AST node is
mcimadamore@1347 244 * cloned (to avoid side-effects cause by Attr) and compiler state is
mcimadamore@1347 245 * restored after type-checking. All diagnostics (but critical ones) are
mcimadamore@1347 246 * disabled during speculative type-checking.
mcimadamore@1347 247 */
mcimadamore@1347 248 JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
mcimadamore@1347 249 JCTree newTree = new TreeCopier<Object>(make).copy(tree);
mcimadamore@1347 250 Env<AttrContext> speculativeEnv = env.dup(newTree, env.info.dup(env.info.scope.dupUnshared()));
mcimadamore@1347 251 speculativeEnv.info.scope.owner = env.info.scope.owner;
mcimadamore@1347 252 Filter<JCDiagnostic> prevDeferDiagsFilter = log.deferredDiagFilter;
mcimadamore@1347 253 Queue<JCDiagnostic> prevDeferredDiags = log.deferredDiagnostics;
mcimadamore@1347 254 final JavaFileObject currentSource = log.currentSourceFile();
mcimadamore@1347 255 try {
mcimadamore@1347 256 log.deferredDiagnostics = new ListBuffer<JCDiagnostic>();
mcimadamore@1347 257 log.deferredDiagFilter = new Filter<JCDiagnostic>() {
mcimadamore@1347 258 public boolean accepts(JCDiagnostic t) {
mcimadamore@1347 259 return t.getDiagnosticSource().getFile().equals(currentSource);
mcimadamore@1347 260 }
mcimadamore@1347 261 };
mcimadamore@1347 262 attr.attribTree(newTree, speculativeEnv, resultInfo);
mcimadamore@1347 263 unenterScanner.scan(newTree);
mcimadamore@1347 264 return newTree;
mcimadamore@1347 265 } catch (Abort ex) {
mcimadamore@1347 266 //if some very bad condition occurred during deferred attribution
mcimadamore@1347 267 //we should dump all errors before killing javac
mcimadamore@1347 268 log.reportDeferredDiagnostics();
mcimadamore@1347 269 throw ex;
mcimadamore@1347 270 } finally {
mcimadamore@1347 271 unenterScanner.scan(newTree);
mcimadamore@1347 272 log.deferredDiagFilter = prevDeferDiagsFilter;
mcimadamore@1347 273 log.deferredDiagnostics = prevDeferredDiags;
mcimadamore@1347 274 }
mcimadamore@1347 275 }
mcimadamore@1347 276 //where
mcimadamore@1347 277 protected TreeScanner unenterScanner = new TreeScanner() {
mcimadamore@1347 278 @Override
mcimadamore@1347 279 public void visitClassDef(JCClassDecl tree) {
mcimadamore@1347 280 ClassSymbol csym = tree.sym;
mcimadamore@1347 281 enter.typeEnvs.remove(csym);
mcimadamore@1347 282 chk.compiled.remove(csym.flatname);
mcimadamore@1347 283 syms.classes.remove(csym.flatname);
mcimadamore@1347 284 super.visitClassDef(tree);
mcimadamore@1347 285 }
mcimadamore@1347 286 };
mcimadamore@1347 287
mcimadamore@1347 288 /**
mcimadamore@1347 289 * A deferred context is created on each method check. A deferred context is
mcimadamore@1347 290 * used to keep track of information associated with the method check, such as
mcimadamore@1347 291 * the symbol of the method being checked, the overload resolution phase,
mcimadamore@1347 292 * the kind of attribution mode to be applied to deferred types and so forth.
mcimadamore@1347 293 * As deferred types are processed (by the method check routine) stuck AST nodes
mcimadamore@1347 294 * are added (as new deferred attribution nodes) to this context. The complete()
mcimadamore@1347 295 * routine makes sure that all pending nodes are properly processed, by
mcimadamore@1347 296 * progressively instantiating all inference variables on which one or more
mcimadamore@1347 297 * deferred attribution node is stuck.
mcimadamore@1347 298 */
mcimadamore@1347 299 class DeferredAttrContext {
mcimadamore@1347 300
mcimadamore@1347 301 /** attribution mode */
mcimadamore@1347 302 final AttrMode mode;
mcimadamore@1347 303
mcimadamore@1347 304 /** symbol of the method being checked */
mcimadamore@1347 305 final Symbol msym;
mcimadamore@1347 306
mcimadamore@1347 307 /** method resolution step */
mcimadamore@1347 308 final Resolve.MethodResolutionPhase phase;
mcimadamore@1347 309
mcimadamore@1347 310 /** inference context */
mcimadamore@1347 311 final InferenceContext inferenceContext;
mcimadamore@1347 312
mcimadamore@1347 313 /** list of deferred attribution nodes to be processed */
mcimadamore@1347 314 ArrayList<DeferredAttrNode> deferredAttrNodes = new ArrayList<DeferredAttrNode>();
mcimadamore@1347 315
mcimadamore@1347 316 DeferredAttrContext(AttrMode mode, Symbol msym, MethodResolutionPhase phase, InferenceContext inferenceContext) {
mcimadamore@1347 317 this.mode = mode;
mcimadamore@1347 318 this.msym = msym;
mcimadamore@1347 319 this.phase = phase;
mcimadamore@1347 320 this.inferenceContext = inferenceContext;
mcimadamore@1347 321 }
mcimadamore@1347 322
mcimadamore@1347 323 /**
mcimadamore@1347 324 * Adds a node to the list of deferred attribution nodes - used by Resolve.rawCheckArgumentsApplicable
mcimadamore@1347 325 * Nodes added this way act as 'roots' for the out-of-order method checking process.
mcimadamore@1347 326 */
mcimadamore@1347 327 void addDeferredAttrNode(final DeferredType dt, ResultInfo resultInfo, List<Type> stuckVars) {
mcimadamore@1347 328 deferredAttrNodes.add(new DeferredAttrNode(dt, resultInfo, stuckVars));
mcimadamore@1347 329 }
mcimadamore@1347 330
mcimadamore@1347 331 /**
mcimadamore@1347 332 * Incrementally process all nodes, by skipping 'stuck' nodes and attributing
mcimadamore@1347 333 * 'unstuck' ones. If at any point no progress can be made (no 'unstuck' nodes)
mcimadamore@1347 334 * some inference variable might get eagerly instantiated so that all nodes
mcimadamore@1347 335 * can be type-checked.
mcimadamore@1347 336 */
mcimadamore@1347 337 void complete() {
mcimadamore@1347 338 while (!deferredAttrNodes.isEmpty()) {
mcimadamore@1347 339 Set<Type> stuckVars = new HashSet<Type>();
mcimadamore@1347 340 boolean progress = false;
mcimadamore@1347 341 //scan a defensive copy of the node list - this is because a deferred
mcimadamore@1347 342 //attribution round can add new nodes to the list
mcimadamore@1347 343 for (DeferredAttrNode deferredAttrNode : List.from(deferredAttrNodes)) {
mcimadamore@1347 344 if (!deferredAttrNode.isStuck()) {
mcimadamore@1347 345 deferredAttrNode.process();
mcimadamore@1347 346 deferredAttrNodes.remove(deferredAttrNode);
mcimadamore@1347 347 progress = true;
mcimadamore@1347 348 } else {
mcimadamore@1347 349 stuckVars.addAll(deferredAttrNode.stuckVars);
mcimadamore@1347 350 }
mcimadamore@1347 351 }
mcimadamore@1347 352 if (!progress) {
mcimadamore@1347 353 //remove all variables that have already been instantiated
mcimadamore@1347 354 //from the list of stuck variables
mcimadamore@1347 355 inferenceContext.solveAny(inferenceContext.freeVarsIn(List.from(stuckVars)), types, infer);
mcimadamore@1347 356 inferenceContext.notifyChange(types);
mcimadamore@1347 357 }
mcimadamore@1347 358 }
mcimadamore@1347 359 }
mcimadamore@1347 360
mcimadamore@1347 361 /**
mcimadamore@1347 362 * Class representing a deferred attribution node. It keeps track of
mcimadamore@1347 363 * a deferred type, along with the expected target type information.
mcimadamore@1347 364 */
mcimadamore@1347 365 class DeferredAttrNode implements Infer.InferenceContext.FreeTypeListener {
mcimadamore@1347 366
mcimadamore@1347 367 /** underlying deferred type */
mcimadamore@1347 368 DeferredType dt;
mcimadamore@1347 369
mcimadamore@1347 370 /** underlying target type information */
mcimadamore@1347 371 ResultInfo resultInfo;
mcimadamore@1347 372
mcimadamore@1347 373 /** list of uninferred inference variables causing this node to be stuck */
mcimadamore@1347 374 List<Type> stuckVars;
mcimadamore@1347 375
mcimadamore@1347 376 DeferredAttrNode(DeferredType dt, ResultInfo resultInfo, List<Type> stuckVars) {
mcimadamore@1347 377 this.dt = dt;
mcimadamore@1347 378 this.resultInfo = resultInfo;
mcimadamore@1347 379 this.stuckVars = stuckVars;
mcimadamore@1347 380 if (!stuckVars.isEmpty()) {
mcimadamore@1347 381 resultInfo.checkContext.inferenceContext().addFreeTypeListener(stuckVars, this);
mcimadamore@1347 382 }
mcimadamore@1347 383 }
mcimadamore@1347 384
mcimadamore@1347 385 @Override
mcimadamore@1347 386 public void typesInferred(InferenceContext inferenceContext) {
mcimadamore@1347 387 stuckVars = List.nil();
mcimadamore@1347 388 resultInfo = resultInfo.dup(inferenceContext.asInstType(resultInfo.pt, types));
mcimadamore@1347 389 }
mcimadamore@1347 390
mcimadamore@1347 391 /**
mcimadamore@1347 392 * is this node stuck?
mcimadamore@1347 393 */
mcimadamore@1347 394 boolean isStuck() {
mcimadamore@1347 395 return stuckVars.nonEmpty();
mcimadamore@1347 396 }
mcimadamore@1347 397
mcimadamore@1347 398 /**
mcimadamore@1347 399 * Process a deferred attribution node.
mcimadamore@1347 400 * Invariant: a stuck node cannot be processed.
mcimadamore@1347 401 */
mcimadamore@1347 402 void process() {
mcimadamore@1347 403 if (isStuck()) {
mcimadamore@1347 404 throw new IllegalStateException("Cannot process a stuck deferred node");
mcimadamore@1347 405 }
mcimadamore@1347 406 dt.check(resultInfo);
mcimadamore@1347 407 }
mcimadamore@1347 408 }
mcimadamore@1347 409 }
mcimadamore@1347 410
mcimadamore@1347 411 /** an empty deferred attribution context - all methods throw exceptions */
mcimadamore@1347 412 final DeferredAttrContext emptyDeferredAttrContext =
mcimadamore@1347 413 new DeferredAttrContext(null, null, null, null) {
mcimadamore@1347 414 @Override
mcimadamore@1347 415 void addDeferredAttrNode(DeferredType dt, ResultInfo ri, List<Type> stuckVars) {
mcimadamore@1347 416 Assert.error("Empty deferred context!");
mcimadamore@1347 417 }
mcimadamore@1347 418 @Override
mcimadamore@1347 419 void complete() {
mcimadamore@1347 420 Assert.error("Empty deferred context!");
mcimadamore@1347 421 }
mcimadamore@1347 422 };
mcimadamore@1347 423
mcimadamore@1347 424 /**
mcimadamore@1347 425 * Map a list of types possibly containing one or more deferred types
mcimadamore@1347 426 * into a list of ordinary types. Each deferred type D is mapped into a type T,
mcimadamore@1347 427 * where T is computed by retrieving the type that has already been
mcimadamore@1347 428 * computed for D during a previous deferred attribution round of the given kind.
mcimadamore@1347 429 */
mcimadamore@1347 430 class DeferredTypeMap extends Type.Mapping {
mcimadamore@1347 431
mcimadamore@1347 432 DeferredAttrContext deferredAttrContext;
mcimadamore@1347 433
mcimadamore@1347 434 protected DeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
mcimadamore@1347 435 super(String.format("deferredTypeMap[%s]", mode));
mcimadamore@1347 436 this.deferredAttrContext = new DeferredAttrContext(mode, msym, phase, infer.emptyContext);
mcimadamore@1347 437 }
mcimadamore@1347 438
mcimadamore@1347 439 protected boolean validState(DeferredType dt) {
mcimadamore@1347 440 return dt.mode != null &&
mcimadamore@1347 441 deferredAttrContext.mode.ordinal() <= dt.mode.ordinal();
mcimadamore@1347 442 }
mcimadamore@1347 443
mcimadamore@1347 444 @Override
mcimadamore@1347 445 public Type apply(Type t) {
mcimadamore@1347 446 if (t.tag != DEFERRED) {
mcimadamore@1347 447 return t.map(this);
mcimadamore@1347 448 } else {
mcimadamore@1347 449 DeferredType dt = (DeferredType)t;
mcimadamore@1347 450 Assert.check(validState(dt));
mcimadamore@1347 451 return typeOf(dt);
mcimadamore@1347 452 }
mcimadamore@1347 453 }
mcimadamore@1347 454
mcimadamore@1347 455 protected Type typeOf(DeferredType dt) {
mcimadamore@1347 456 switch (deferredAttrContext.mode) {
mcimadamore@1347 457 case CHECK:
mcimadamore@1347 458 return dt.tree.type == null ? Type.noType : dt.tree.type;
mcimadamore@1347 459 case SPECULATIVE:
mcimadamore@1347 460 return dt.speculativeType(deferredAttrContext.msym, deferredAttrContext.phase);
mcimadamore@1347 461 }
mcimadamore@1347 462 Assert.error();
mcimadamore@1347 463 return null;
mcimadamore@1347 464 }
mcimadamore@1347 465 }
mcimadamore@1347 466
mcimadamore@1347 467 /**
mcimadamore@1347 468 * Specialized recovery deferred mapping.
mcimadamore@1347 469 * Each deferred type D is mapped into a type T, where T is computed either by
mcimadamore@1347 470 * (i) retrieving the type that has already been computed for D during a previous
mcimadamore@1347 471 * attribution round (as before), or (ii) by synthesizing a new type R for D
mcimadamore@1347 472 * (the latter step is useful in a recovery scenario).
mcimadamore@1347 473 */
mcimadamore@1347 474 public class RecoveryDeferredTypeMap extends DeferredTypeMap {
mcimadamore@1347 475
mcimadamore@1347 476 public RecoveryDeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
mcimadamore@1347 477 super(mode, msym, phase);
mcimadamore@1347 478 }
mcimadamore@1347 479
mcimadamore@1347 480 @Override
mcimadamore@1347 481 protected Type typeOf(DeferredType dt) {
mcimadamore@1347 482 Type owntype = super.typeOf(dt);
mcimadamore@1347 483 return owntype.tag == NONE ?
mcimadamore@1347 484 recover(dt) : owntype;
mcimadamore@1347 485 }
mcimadamore@1347 486
mcimadamore@1347 487 @Override
mcimadamore@1347 488 protected boolean validState(DeferredType dt) {
mcimadamore@1347 489 return true;
mcimadamore@1347 490 }
mcimadamore@1347 491
mcimadamore@1347 492 /**
mcimadamore@1347 493 * Synthesize a type for a deferred type that hasn't been previously
mcimadamore@1347 494 * reduced to an ordinary type. Functional deferred types and conditionals
mcimadamore@1347 495 * are mapped to themselves, in order to have a richer diagnostic
mcimadamore@1347 496 * representation. Remaining deferred types are attributed using
mcimadamore@1347 497 * a default expected type (j.l.Object).
mcimadamore@1347 498 */
mcimadamore@1347 499 private Type recover(DeferredType dt) {
mcimadamore@1347 500 dt.check(new RecoveryInfo());
mcimadamore@1347 501 switch (TreeInfo.skipParens(dt.tree).getTag()) {
mcimadamore@1347 502 case LAMBDA:
mcimadamore@1347 503 case REFERENCE:
mcimadamore@1347 504 case CONDEXPR:
mcimadamore@1347 505 //propagate those deferred types to the
mcimadamore@1347 506 //diagnostic formatter
mcimadamore@1347 507 return dt;
mcimadamore@1347 508 default:
mcimadamore@1347 509 return super.apply(dt);
mcimadamore@1347 510 }
mcimadamore@1347 511 }
mcimadamore@1347 512
mcimadamore@1347 513 class RecoveryInfo extends ResultInfo {
mcimadamore@1347 514
mcimadamore@1347 515 public RecoveryInfo() {
mcimadamore@1347 516 attr.super(Kinds.VAL, Type.recoveryType, new Check.NestedCheckContext(chk.basicHandler) {
mcimadamore@1347 517 @Override
mcimadamore@1347 518 public DeferredAttrContext deferredAttrContext() {
mcimadamore@1347 519 return deferredAttrContext;
mcimadamore@1347 520 }
mcimadamore@1347 521 @Override
mcimadamore@1347 522 public boolean compatible(Type found, Type req, Warner warn) {
mcimadamore@1347 523 return true;
mcimadamore@1347 524 }
mcimadamore@1347 525 @Override
mcimadamore@1347 526 public void report(DiagnosticPosition pos, JCDiagnostic details) {
mcimadamore@1347 527 //do nothing
mcimadamore@1347 528 }
mcimadamore@1347 529 });
mcimadamore@1347 530 }
mcimadamore@1347 531
mcimadamore@1347 532 @Override
mcimadamore@1347 533 protected Type check(DiagnosticPosition pos, Type found) {
mcimadamore@1347 534 return chk.checkNonVoid(pos, super.check(pos, found));
mcimadamore@1347 535 }
mcimadamore@1347 536 }
mcimadamore@1347 537 }
mcimadamore@1347 538
mcimadamore@1347 539 /**
mcimadamore@1347 540 * Retrieves the list of inference variables that need to be inferred before
mcimadamore@1347 541 * an AST node can be type-checked
mcimadamore@1347 542 */
mcimadamore@1347 543 @SuppressWarnings("fallthrough")
mcimadamore@1347 544 List<Type> stuckVars(JCExpression tree, ResultInfo resultInfo) {
mcimadamore@1347 545 switch (tree.getTag()) {
mcimadamore@1347 546 case LAMBDA:
mcimadamore@1347 547 case REFERENCE:
mcimadamore@1347 548 Assert.error("not supported yet");
mcimadamore@1347 549 default:
mcimadamore@1347 550 return List.nil();
mcimadamore@1347 551 }
mcimadamore@1347 552 }
mcimadamore@1347 553 }

mercurial