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