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