36 import com.sun.tools.javac.tree.JCTree.*; |
36 import com.sun.tools.javac.tree.JCTree.*; |
37 |
37 |
38 import javax.tools.JavaFileObject; |
38 import javax.tools.JavaFileObject; |
39 |
39 |
40 import java.util.ArrayList; |
40 import java.util.ArrayList; |
41 import java.util.HashSet; |
41 import java.util.LinkedHashSet; |
42 import java.util.Map; |
42 import java.util.Map; |
43 import java.util.Queue; |
43 import java.util.Queue; |
44 import java.util.Set; |
44 import java.util.Set; |
45 import java.util.WeakHashMap; |
45 import java.util.WeakHashMap; |
46 |
46 |
47 import static com.sun.tools.javac.code.TypeTag.DEFERRED; |
47 import static com.sun.tools.javac.code.TypeTag.*; |
48 import static com.sun.tools.javac.code.TypeTag.NONE; |
|
49 import static com.sun.tools.javac.tree.JCTree.Tag.*; |
48 import static com.sun.tools.javac.tree.JCTree.Tag.*; |
50 |
49 |
51 /** |
50 /** |
52 * This is an helper class that is used to perform deferred type-analysis. |
51 * This is an helper class that is used to perform deferred type-analysis. |
53 * Each time a poly expression occurs in argument position, javac attributes it |
52 * Each time a poly expression occurs in argument position, javac attributes it |
135 return this.phase == phase; |
134 return this.phase == phase; |
136 } |
135 } |
137 } |
136 } |
138 |
137 |
139 /** |
138 /** |
140 * Clone a speculative cache entry as a fresh entry associated |
|
141 * with a new method (this maybe required to fixup speculative cache |
|
142 * misses after Resolve.access()) |
|
143 */ |
|
144 void dupAllTo(Symbol from, Symbol to) { |
|
145 Assert.check(cache.get(to) == null); |
|
146 List<Entry> entries = cache.get(from); |
|
147 if (entries != null) { |
|
148 cache.put(to, entries); |
|
149 } |
|
150 } |
|
151 |
|
152 /** |
|
153 * Retrieve a speculative cache entry corresponding to given symbol |
139 * Retrieve a speculative cache entry corresponding to given symbol |
154 * and resolution phase |
140 * and resolution phase |
155 */ |
141 */ |
156 Entry get(Symbol msym, MethodResolutionPhase phase) { |
142 Entry get(Symbol msym, MethodResolutionPhase phase) { |
157 List<Entry> entries = cache.get(msym); |
143 List<Entry> entries = cache.get(msym); |
192 */ |
178 */ |
193 Type check(ResultInfo resultInfo) { |
179 Type check(ResultInfo resultInfo) { |
194 DeferredAttrContext deferredAttrContext = |
180 DeferredAttrContext deferredAttrContext = |
195 resultInfo.checkContext.deferredAttrContext(); |
181 resultInfo.checkContext.deferredAttrContext(); |
196 Assert.check(deferredAttrContext != emptyDeferredAttrContext); |
182 Assert.check(deferredAttrContext != emptyDeferredAttrContext); |
197 List<Type> stuckVars = stuckVars(tree, resultInfo); |
183 List<Type> stuckVars = stuckVars(tree, env, resultInfo); |
198 if (stuckVars.nonEmpty()) { |
184 if (stuckVars.nonEmpty()) { |
199 deferredAttrContext.addDeferredAttrNode(this, resultInfo, stuckVars); |
185 deferredAttrContext.addDeferredAttrNode(this, resultInfo, stuckVars); |
200 return Type.noType; |
186 return Type.noType; |
201 } else { |
187 } else { |
202 try { |
188 try { |
273 //where |
259 //where |
274 protected TreeScanner unenterScanner = new TreeScanner() { |
260 protected TreeScanner unenterScanner = new TreeScanner() { |
275 @Override |
261 @Override |
276 public void visitClassDef(JCClassDecl tree) { |
262 public void visitClassDef(JCClassDecl tree) { |
277 ClassSymbol csym = tree.sym; |
263 ClassSymbol csym = tree.sym; |
|
264 //if something went wrong during method applicability check |
|
265 //it is possible that nested expressions inside argument expression |
|
266 //are left unchecked - in such cases there's nothing to clean up. |
|
267 if (csym == null) return; |
278 enter.typeEnvs.remove(csym); |
268 enter.typeEnvs.remove(csym); |
279 chk.compiled.remove(csym.flatname); |
269 chk.compiled.remove(csym.flatname); |
280 syms.classes.remove(csym.flatname); |
270 syms.classes.remove(csym.flatname); |
281 super.visitClassDef(tree); |
271 super.visitClassDef(tree); |
282 } |
272 } |
331 * some inference variable might get eagerly instantiated so that all nodes |
321 * some inference variable might get eagerly instantiated so that all nodes |
332 * can be type-checked. |
322 * can be type-checked. |
333 */ |
323 */ |
334 void complete() { |
324 void complete() { |
335 while (!deferredAttrNodes.isEmpty()) { |
325 while (!deferredAttrNodes.isEmpty()) { |
336 Set<Type> stuckVars = new HashSet<Type>(); |
326 Set<Type> stuckVars = new LinkedHashSet<Type>(); |
337 boolean progress = false; |
327 boolean progress = false; |
338 //scan a defensive copy of the node list - this is because a deferred |
328 //scan a defensive copy of the node list - this is because a deferred |
339 //attribution round can add new nodes to the list |
329 //attribution round can add new nodes to the list |
340 for (DeferredAttrNode deferredAttrNode : List.from(deferredAttrNodes)) { |
330 for (DeferredAttrNode deferredAttrNode : List.from(deferredAttrNodes)) { |
341 if (!deferredAttrNode.isStuck()) { |
331 if (!deferredAttrNode.isStuck()) { |
405 } |
395 } |
406 } |
396 } |
407 |
397 |
408 /** an empty deferred attribution context - all methods throw exceptions */ |
398 /** an empty deferred attribution context - all methods throw exceptions */ |
409 final DeferredAttrContext emptyDeferredAttrContext = |
399 final DeferredAttrContext emptyDeferredAttrContext = |
410 new DeferredAttrContext(null, null, null, null) { |
400 new DeferredAttrContext(AttrMode.CHECK, null, MethodResolutionPhase.BOX, null) { |
411 @Override |
401 @Override |
412 void addDeferredAttrNode(DeferredType dt, ResultInfo ri, List<Type> stuckVars) { |
402 void addDeferredAttrNode(DeferredType dt, ResultInfo ri, List<Type> stuckVars) { |
413 Assert.error("Empty deferred context!"); |
403 Assert.error("Empty deferred context!"); |
414 } |
404 } |
415 @Override |
405 @Override |
469 * (the latter step is useful in a recovery scenario). |
459 * (the latter step is useful in a recovery scenario). |
470 */ |
460 */ |
471 public class RecoveryDeferredTypeMap extends DeferredTypeMap { |
461 public class RecoveryDeferredTypeMap extends DeferredTypeMap { |
472 |
462 |
473 public RecoveryDeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) { |
463 public RecoveryDeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) { |
474 super(mode, msym, phase); |
464 super(mode, msym, phase != null ? phase : MethodResolutionPhase.BOX); |
475 } |
465 } |
476 |
466 |
477 @Override |
467 @Override |
478 protected Type typeOf(DeferredType dt) { |
468 protected Type typeOf(DeferredType dt) { |
479 Type owntype = super.typeOf(dt); |
469 Type owntype = super.typeOf(dt); |
480 return owntype.hasTag(NONE) ? |
470 return owntype == Type.noType ? |
481 recover(dt) : owntype; |
471 recover(dt) : owntype; |
482 } |
472 } |
483 |
473 |
484 @Override |
474 @Override |
485 protected boolean validState(DeferredType dt) { |
475 protected boolean validState(DeferredType dt) { |
493 * representation. Remaining deferred types are attributed using |
483 * representation. Remaining deferred types are attributed using |
494 * a default expected type (j.l.Object). |
484 * a default expected type (j.l.Object). |
495 */ |
485 */ |
496 private Type recover(DeferredType dt) { |
486 private Type recover(DeferredType dt) { |
497 dt.check(attr.new RecoveryInfo(deferredAttrContext)); |
487 dt.check(attr.new RecoveryInfo(deferredAttrContext)); |
498 switch (TreeInfo.skipParens(dt.tree).getTag()) { |
488 return super.apply(dt); |
499 case LAMBDA: |
|
500 case REFERENCE: |
|
501 case CONDEXPR: |
|
502 //propagate those deferred types to the |
|
503 //diagnostic formatter |
|
504 return dt; |
|
505 default: |
|
506 return super.apply(dt); |
|
507 } |
|
508 } |
489 } |
509 } |
490 } |
510 |
491 |
511 /** |
492 /** |
512 * Retrieves the list of inference variables that need to be inferred before |
493 * Retrieves the list of inference variables that need to be inferred before |
513 * an AST node can be type-checked |
494 * an AST node can be type-checked |
514 */ |
495 */ |
515 @SuppressWarnings("fallthrough") |
496 @SuppressWarnings("fallthrough") |
516 List<Type> stuckVars(JCTree tree, ResultInfo resultInfo) { |
497 List<Type> stuckVars(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) { |
517 if (resultInfo.pt.hasTag(NONE) || resultInfo.pt.isErroneous()) { |
498 if (resultInfo.pt.hasTag(NONE) || resultInfo.pt.isErroneous()) { |
518 return List.nil(); |
499 return List.nil(); |
519 } else { |
500 } else { |
520 StuckChecker sc = new StuckChecker(resultInfo); |
501 StuckChecker sc = new StuckChecker(resultInfo, env); |
521 sc.scan(tree); |
502 sc.scan(tree); |
522 return List.from(sc.stuckVars); |
503 return List.from(sc.stuckVars); |
523 } |
504 } |
524 } |
505 } |
525 |
506 |
532 class StuckChecker extends TreeScanner { |
513 class StuckChecker extends TreeScanner { |
533 |
514 |
534 Type pt; |
515 Type pt; |
535 Filter<JCTree> treeFilter; |
516 Filter<JCTree> treeFilter; |
536 Infer.InferenceContext inferenceContext; |
517 Infer.InferenceContext inferenceContext; |
537 Set<Type> stuckVars = new HashSet<Type>(); |
518 Set<Type> stuckVars = new LinkedHashSet<Type>(); |
|
519 Env<AttrContext> env; |
538 |
520 |
539 final Filter<JCTree> argsFilter = new Filter<JCTree>() { |
521 final Filter<JCTree> argsFilter = new Filter<JCTree>() { |
540 public boolean accepts(JCTree t) { |
522 public boolean accepts(JCTree t) { |
541 switch (t.getTag()) { |
523 switch (t.getTag()) { |
542 case CONDEXPR: |
524 case CONDEXPR: |
561 return false; |
543 return false; |
562 } |
544 } |
563 } |
545 } |
564 }; |
546 }; |
565 |
547 |
566 StuckChecker(ResultInfo resultInfo) { |
548 StuckChecker(ResultInfo resultInfo, Env<AttrContext> env) { |
567 this.pt = resultInfo.pt; |
549 this.pt = resultInfo.pt; |
568 this.inferenceContext = resultInfo.checkContext.inferenceContext(); |
550 this.inferenceContext = resultInfo.checkContext.inferenceContext(); |
569 this.treeFilter = argsFilter; |
551 this.treeFilter = argsFilter; |
|
552 this.env = env; |
570 } |
553 } |
571 |
554 |
572 @Override |
555 @Override |
573 public void scan(JCTree tree) { |
556 public void scan(JCTree tree) { |
574 if (tree != null && treeFilter.accepts(tree)) { |
557 if (tree != null && treeFilter.accepts(tree)) { |