Wed, 27 Apr 2016 01:34:52 +0800
Initial load
http://hg.openjdk.java.net/jdk8u/jdk8u/langtools/
changeset: 2573:53ca196be1ae
tag: jdk8u25-b17
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;
80 final TypeEnvs typeEnvs;
82 public static DeferredAttr instance(Context context) {
83 DeferredAttr instance = context.get(deferredAttrKey);
84 if (instance == null)
85 instance = new DeferredAttr(context);
86 return instance;
87 }
89 protected DeferredAttr(Context context) {
90 context.put(deferredAttrKey, this);
91 attr = Attr.instance(context);
92 chk = Check.instance(context);
93 diags = JCDiagnostic.Factory.instance(context);
94 enter = Enter.instance(context);
95 infer = Infer.instance(context);
96 rs = Resolve.instance(context);
97 log = Log.instance(context);
98 syms = Symtab.instance(context);
99 make = TreeMaker.instance(context);
100 types = Types.instance(context);
101 flow = Flow.instance(context);
102 names = Names.instance(context);
103 stuckTree = make.Ident(names.empty).setType(Type.stuckType);
104 typeEnvs = TypeEnvs.instance(context);
105 emptyDeferredAttrContext =
106 new DeferredAttrContext(AttrMode.CHECK, null, MethodResolutionPhase.BOX, infer.emptyContext, null, null) {
107 @Override
108 void addDeferredAttrNode(DeferredType dt, ResultInfo ri, DeferredStuckPolicy deferredStuckPolicy) {
109 Assert.error("Empty deferred context!");
110 }
111 @Override
112 void complete() {
113 Assert.error("Empty deferred context!");
114 }
116 @Override
117 public String toString() {
118 return "Empty deferred context!";
119 }
120 };
121 }
123 /** shared tree for stuck expressions */
124 final JCTree stuckTree;
126 /**
127 * This type represents a deferred type. A deferred type starts off with
128 * no information on the underlying expression type. Such info needs to be
129 * discovered through type-checking the deferred type against a target-type.
130 * Every deferred type keeps a pointer to the AST node from which it originated.
131 */
132 public class DeferredType extends Type {
134 public JCExpression tree;
135 Env<AttrContext> env;
136 AttrMode mode;
137 SpeculativeCache speculativeCache;
139 DeferredType(JCExpression tree, Env<AttrContext> env) {
140 super(null);
141 this.tree = tree;
142 this.env = attr.copyEnv(env);
143 this.speculativeCache = new SpeculativeCache();
144 }
146 @Override
147 public TypeTag getTag() {
148 return DEFERRED;
149 }
151 @Override
152 public String toString() {
153 return "DeferredType";
154 }
156 /**
157 * A speculative cache is used to keep track of all overload resolution rounds
158 * that triggered speculative attribution on a given deferred type. Each entry
159 * stores a pointer to the speculative tree and the resolution phase in which the entry
160 * has been added.
161 */
162 class SpeculativeCache {
164 private Map<Symbol, List<Entry>> cache =
165 new WeakHashMap<Symbol, List<Entry>>();
167 class Entry {
168 JCTree speculativeTree;
169 ResultInfo resultInfo;
171 public Entry(JCTree speculativeTree, ResultInfo resultInfo) {
172 this.speculativeTree = speculativeTree;
173 this.resultInfo = resultInfo;
174 }
176 boolean matches(MethodResolutionPhase phase) {
177 return resultInfo.checkContext.deferredAttrContext().phase == phase;
178 }
179 }
181 /**
182 * Retrieve a speculative cache entry corresponding to given symbol
183 * and resolution phase
184 */
185 Entry get(Symbol msym, MethodResolutionPhase phase) {
186 List<Entry> entries = cache.get(msym);
187 if (entries == null) return null;
188 for (Entry e : entries) {
189 if (e.matches(phase)) return e;
190 }
191 return null;
192 }
194 /**
195 * Stores a speculative cache entry corresponding to given symbol
196 * and resolution phase
197 */
198 void put(JCTree speculativeTree, ResultInfo resultInfo) {
199 Symbol msym = resultInfo.checkContext.deferredAttrContext().msym;
200 List<Entry> entries = cache.get(msym);
201 if (entries == null) {
202 entries = List.nil();
203 }
204 cache.put(msym, entries.prepend(new Entry(speculativeTree, resultInfo)));
205 }
206 }
208 /**
209 * Get the type that has been computed during a speculative attribution round
210 */
211 Type speculativeType(Symbol msym, MethodResolutionPhase phase) {
212 SpeculativeCache.Entry e = speculativeCache.get(msym, phase);
213 return e != null ? e.speculativeTree.type : Type.noType;
214 }
216 /**
217 * Check a deferred type against a potential target-type. Depending on
218 * the current attribution mode, a normal vs. speculative attribution
219 * round is performed on the underlying AST node. There can be only one
220 * speculative round for a given target method symbol; moreover, a normal
221 * attribution round must follow one or more speculative rounds.
222 */
223 Type check(ResultInfo resultInfo) {
224 DeferredStuckPolicy deferredStuckPolicy;
225 if (resultInfo.pt.hasTag(NONE) || resultInfo.pt.isErroneous()) {
226 deferredStuckPolicy = dummyStuckPolicy;
227 } else if (resultInfo.checkContext.deferredAttrContext().mode == AttrMode.SPECULATIVE) {
228 deferredStuckPolicy = new OverloadStuckPolicy(resultInfo, this);
229 } else {
230 deferredStuckPolicy = new CheckStuckPolicy(resultInfo, this);
231 }
232 return check(resultInfo, deferredStuckPolicy, basicCompleter);
233 }
235 private Type check(ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy,
236 DeferredTypeCompleter deferredTypeCompleter) {
237 DeferredAttrContext deferredAttrContext =
238 resultInfo.checkContext.deferredAttrContext();
239 Assert.check(deferredAttrContext != emptyDeferredAttrContext);
240 if (deferredStuckPolicy.isStuck()) {
241 deferredAttrContext.addDeferredAttrNode(this, resultInfo, deferredStuckPolicy);
242 return Type.noType;
243 } else {
244 try {
245 return deferredTypeCompleter.complete(this, resultInfo, deferredAttrContext);
246 } finally {
247 mode = deferredAttrContext.mode;
248 }
249 }
250 }
251 }
253 /**
254 * A completer for deferred types. Defines an entry point for type-checking
255 * a deferred type.
256 */
257 interface DeferredTypeCompleter {
258 /**
259 * Entry point for type-checking a deferred type. Depending on the
260 * circumstances, type-checking could amount to full attribution
261 * or partial structural check (aka potential applicability).
262 */
263 Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext);
264 }
267 /**
268 * A basic completer for deferred types. This completer type-checks a deferred type
269 * using attribution; depending on the attribution mode, this could be either standard
270 * or speculative attribution.
271 */
272 DeferredTypeCompleter basicCompleter = new DeferredTypeCompleter() {
273 public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
274 switch (deferredAttrContext.mode) {
275 case SPECULATIVE:
276 //Note: if a symbol is imported twice we might do two identical
277 //speculative rounds...
278 Assert.check(dt.mode == null || dt.mode == AttrMode.SPECULATIVE);
279 JCTree speculativeTree = attribSpeculative(dt.tree, dt.env, resultInfo);
280 dt.speculativeCache.put(speculativeTree, resultInfo);
281 return speculativeTree.type;
282 case CHECK:
283 Assert.check(dt.mode != null);
284 return attr.attribTree(dt.tree, dt.env, resultInfo);
285 }
286 Assert.error();
287 return null;
288 }
289 };
291 DeferredTypeCompleter dummyCompleter = new DeferredTypeCompleter() {
292 public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
293 Assert.check(deferredAttrContext.mode == AttrMode.CHECK);
294 return dt.tree.type = Type.stuckType;
295 }
296 };
298 /**
299 * Policy for detecting stuck expressions. Different criteria might cause
300 * an expression to be judged as stuck, depending on whether the check
301 * is performed during overload resolution or after most specific.
302 */
303 interface DeferredStuckPolicy {
304 /**
305 * Has the policy detected that a given expression should be considered stuck?
306 */
307 boolean isStuck();
308 /**
309 * Get the set of inference variables a given expression depends upon.
310 */
311 Set<Type> stuckVars();
312 /**
313 * Get the set of inference variables which might get new constraints
314 * if a given expression is being type-checked.
315 */
316 Set<Type> depVars();
317 }
319 /**
320 * Basic stuck policy; an expression is never considered to be stuck.
321 */
322 DeferredStuckPolicy dummyStuckPolicy = new DeferredStuckPolicy() {
323 @Override
324 public boolean isStuck() {
325 return false;
326 }
327 @Override
328 public Set<Type> stuckVars() {
329 return Collections.emptySet();
330 }
331 @Override
332 public Set<Type> depVars() {
333 return Collections.emptySet();
334 }
335 };
337 /**
338 * The 'mode' in which the deferred type is to be type-checked
339 */
340 public enum AttrMode {
341 /**
342 * A speculative type-checking round is used during overload resolution
343 * mainly to generate constraints on inference variables. Side-effects
344 * arising from type-checking the expression associated with the deferred
345 * type are reversed after the speculative round finishes. This means the
346 * expression tree will be left in a blank state.
347 */
348 SPECULATIVE,
349 /**
350 * This is the plain type-checking mode. Produces side-effects on the underlying AST node
351 */
352 CHECK;
353 }
355 /**
356 * Routine that performs speculative type-checking; the input AST node is
357 * cloned (to avoid side-effects cause by Attr) and compiler state is
358 * restored after type-checking. All diagnostics (but critical ones) are
359 * disabled during speculative type-checking.
360 */
361 JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
362 final JCTree newTree = new TreeCopier<Object>(make).copy(tree);
363 Env<AttrContext> speculativeEnv = env.dup(newTree, env.info.dup(env.info.scope.dupUnshared()));
364 speculativeEnv.info.scope.owner = env.info.scope.owner;
365 Log.DeferredDiagnosticHandler deferredDiagnosticHandler =
366 new Log.DeferredDiagnosticHandler(log, new Filter<JCDiagnostic>() {
367 public boolean accepts(final JCDiagnostic d) {
368 class PosScanner extends TreeScanner {
369 boolean found = false;
371 @Override
372 public void scan(JCTree tree) {
373 if (tree != null &&
374 tree.pos() == d.getDiagnosticPosition()) {
375 found = true;
376 }
377 super.scan(tree);
378 }
379 };
380 PosScanner posScanner = new PosScanner();
381 posScanner.scan(newTree);
382 return posScanner.found;
383 }
384 });
385 try {
386 attr.attribTree(newTree, speculativeEnv, resultInfo);
387 unenterScanner.scan(newTree);
388 return newTree;
389 } finally {
390 unenterScanner.scan(newTree);
391 log.popDiagnosticHandler(deferredDiagnosticHandler);
392 }
393 }
394 //where
395 protected UnenterScanner unenterScanner = new UnenterScanner();
397 class UnenterScanner extends TreeScanner {
398 @Override
399 public void visitClassDef(JCClassDecl tree) {
400 ClassSymbol csym = tree.sym;
401 //if something went wrong during method applicability check
402 //it is possible that nested expressions inside argument expression
403 //are left unchecked - in such cases there's nothing to clean up.
404 if (csym == null) return;
405 typeEnvs.remove(csym);
406 chk.compiled.remove(csym.flatname);
407 syms.classes.remove(csym.flatname);
408 super.visitClassDef(tree);
409 }
410 }
412 /**
413 * A deferred context is created on each method check. A deferred context is
414 * used to keep track of information associated with the method check, such as
415 * the symbol of the method being checked, the overload resolution phase,
416 * the kind of attribution mode to be applied to deferred types and so forth.
417 * As deferred types are processed (by the method check routine) stuck AST nodes
418 * are added (as new deferred attribution nodes) to this context. The complete()
419 * routine makes sure that all pending nodes are properly processed, by
420 * progressively instantiating all inference variables on which one or more
421 * deferred attribution node is stuck.
422 */
423 class DeferredAttrContext {
425 /** attribution mode */
426 final AttrMode mode;
428 /** symbol of the method being checked */
429 final Symbol msym;
431 /** method resolution step */
432 final Resolve.MethodResolutionPhase phase;
434 /** inference context */
435 final InferenceContext inferenceContext;
437 /** parent deferred context */
438 final DeferredAttrContext parent;
440 /** Warner object to report warnings */
441 final Warner warn;
443 /** list of deferred attribution nodes to be processed */
444 ArrayList<DeferredAttrNode> deferredAttrNodes = new ArrayList<DeferredAttrNode>();
446 DeferredAttrContext(AttrMode mode, Symbol msym, MethodResolutionPhase phase,
447 InferenceContext inferenceContext, DeferredAttrContext parent, Warner warn) {
448 this.mode = mode;
449 this.msym = msym;
450 this.phase = phase;
451 this.parent = parent;
452 this.warn = warn;
453 this.inferenceContext = inferenceContext;
454 }
456 /**
457 * Adds a node to the list of deferred attribution nodes - used by Resolve.rawCheckArgumentsApplicable
458 * Nodes added this way act as 'roots' for the out-of-order method checking process.
459 */
460 void addDeferredAttrNode(final DeferredType dt, ResultInfo resultInfo,
461 DeferredStuckPolicy deferredStuckPolicy) {
462 deferredAttrNodes.add(new DeferredAttrNode(dt, resultInfo, deferredStuckPolicy));
463 }
465 /**
466 * Incrementally process all nodes, by skipping 'stuck' nodes and attributing
467 * 'unstuck' ones. If at any point no progress can be made (no 'unstuck' nodes)
468 * some inference variable might get eagerly instantiated so that all nodes
469 * can be type-checked.
470 */
471 void complete() {
472 while (!deferredAttrNodes.isEmpty()) {
473 Map<Type, Set<Type>> depVarsMap = new LinkedHashMap<Type, Set<Type>>();
474 List<Type> stuckVars = List.nil();
475 boolean progress = false;
476 //scan a defensive copy of the node list - this is because a deferred
477 //attribution round can add new nodes to the list
478 for (DeferredAttrNode deferredAttrNode : List.from(deferredAttrNodes)) {
479 if (!deferredAttrNode.process(this)) {
480 List<Type> restStuckVars =
481 List.from(deferredAttrNode.deferredStuckPolicy.stuckVars())
482 .intersect(inferenceContext.restvars());
483 stuckVars = stuckVars.prependList(restStuckVars);
484 //update dependency map
485 for (Type t : List.from(deferredAttrNode.deferredStuckPolicy.depVars())
486 .intersect(inferenceContext.restvars())) {
487 Set<Type> prevDeps = depVarsMap.get(t);
488 if (prevDeps == null) {
489 prevDeps = new LinkedHashSet<Type>();
490 depVarsMap.put(t, prevDeps);
491 }
492 prevDeps.addAll(restStuckVars);
493 }
494 } else {
495 deferredAttrNodes.remove(deferredAttrNode);
496 progress = true;
497 }
498 }
499 if (!progress) {
500 DeferredAttrContext dac = this;
501 while (dac != emptyDeferredAttrContext) {
502 if (dac.mode == AttrMode.SPECULATIVE) {
503 //unsticking does not take place during overload
504 break;
505 }
506 dac = dac.parent;
507 }
508 //remove all variables that have already been instantiated
509 //from the list of stuck variables
510 try {
511 inferenceContext.solveAny(stuckVars, depVarsMap, warn);
512 inferenceContext.notifyChange();
513 } catch (Infer.GraphStrategy.NodeNotFoundException ex) {
514 //this means that we are in speculative mode and the
515 //set of contraints are too tight for progess to be made.
516 //Just leave the remaining expressions as stuck.
517 break;
518 }
519 }
520 }
521 }
522 }
524 /**
525 * Class representing a deferred attribution node. It keeps track of
526 * a deferred type, along with the expected target type information.
527 */
528 class DeferredAttrNode {
530 /** underlying deferred type */
531 DeferredType dt;
533 /** underlying target type information */
534 ResultInfo resultInfo;
536 /** stuck policy associated with this node */
537 DeferredStuckPolicy deferredStuckPolicy;
539 DeferredAttrNode(DeferredType dt, ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy) {
540 this.dt = dt;
541 this.resultInfo = resultInfo;
542 this.deferredStuckPolicy = deferredStuckPolicy;
543 }
545 /**
546 * Process a deferred attribution node.
547 * Invariant: a stuck node cannot be processed.
548 */
549 @SuppressWarnings("fallthrough")
550 boolean process(final DeferredAttrContext deferredAttrContext) {
551 switch (deferredAttrContext.mode) {
552 case SPECULATIVE:
553 if (deferredStuckPolicy.isStuck()) {
554 dt.check(resultInfo, dummyStuckPolicy, new StructuralStuckChecker());
555 return true;
556 } else {
557 Assert.error("Cannot get here");
558 }
559 case CHECK:
560 if (deferredStuckPolicy.isStuck()) {
561 //stuck expression - see if we can propagate
562 if (deferredAttrContext.parent != emptyDeferredAttrContext &&
563 Type.containsAny(deferredAttrContext.parent.inferenceContext.inferencevars,
564 List.from(deferredStuckPolicy.stuckVars()))) {
565 deferredAttrContext.parent.addDeferredAttrNode(dt,
566 resultInfo.dup(new Check.NestedCheckContext(resultInfo.checkContext) {
567 @Override
568 public InferenceContext inferenceContext() {
569 return deferredAttrContext.parent.inferenceContext;
570 }
571 @Override
572 public DeferredAttrContext deferredAttrContext() {
573 return deferredAttrContext.parent;
574 }
575 }), deferredStuckPolicy);
576 dt.tree.type = Type.stuckType;
577 return true;
578 } else {
579 return false;
580 }
581 } else {
582 ResultInfo instResultInfo =
583 resultInfo.dup(deferredAttrContext.inferenceContext.asInstType(resultInfo.pt));
584 dt.check(instResultInfo, dummyStuckPolicy, basicCompleter);
585 return true;
586 }
587 default:
588 throw new AssertionError("Bad mode");
589 }
590 }
592 /**
593 * Structural checker for stuck expressions
594 */
595 class StructuralStuckChecker extends TreeScanner implements DeferredTypeCompleter {
597 ResultInfo resultInfo;
598 InferenceContext inferenceContext;
599 Env<AttrContext> env;
601 public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
602 this.resultInfo = resultInfo;
603 this.inferenceContext = deferredAttrContext.inferenceContext;
604 this.env = dt.env;
605 dt.tree.accept(this);
606 dt.speculativeCache.put(stuckTree, resultInfo);
607 return Type.noType;
608 }
610 @Override
611 public void visitLambda(JCLambda tree) {
612 Check.CheckContext checkContext = resultInfo.checkContext;
613 Type pt = resultInfo.pt;
614 if (!inferenceContext.inferencevars.contains(pt)) {
615 //must be a functional descriptor
616 Type descriptorType = null;
617 try {
618 descriptorType = types.findDescriptorType(pt);
619 } catch (Types.FunctionDescriptorLookupError ex) {
620 checkContext.report(null, ex.getDiagnostic());
621 }
623 if (descriptorType.getParameterTypes().length() != tree.params.length()) {
624 checkContext.report(tree,
625 diags.fragment("incompatible.arg.types.in.lambda"));
626 }
628 Type currentReturnType = descriptorType.getReturnType();
629 boolean returnTypeIsVoid = currentReturnType.hasTag(VOID);
630 if (tree.getBodyKind() == BodyKind.EXPRESSION) {
631 boolean isExpressionCompatible = !returnTypeIsVoid ||
632 TreeInfo.isExpressionStatement((JCExpression)tree.getBody());
633 if (!isExpressionCompatible) {
634 resultInfo.checkContext.report(tree.pos(),
635 diags.fragment("incompatible.ret.type.in.lambda",
636 diags.fragment("missing.ret.val", currentReturnType)));
637 }
638 } else {
639 LambdaBodyStructChecker lambdaBodyChecker =
640 new LambdaBodyStructChecker();
642 tree.body.accept(lambdaBodyChecker);
643 boolean isVoidCompatible = lambdaBodyChecker.isVoidCompatible;
645 if (returnTypeIsVoid) {
646 if (!isVoidCompatible) {
647 resultInfo.checkContext.report(tree.pos(),
648 diags.fragment("unexpected.ret.val"));
649 }
650 } else {
651 boolean isValueCompatible = lambdaBodyChecker.isPotentiallyValueCompatible
652 && !canLambdaBodyCompleteNormally(tree);
653 if (!isValueCompatible && !isVoidCompatible) {
654 log.error(tree.body.pos(),
655 "lambda.body.neither.value.nor.void.compatible");
656 }
658 if (!isValueCompatible) {
659 resultInfo.checkContext.report(tree.pos(),
660 diags.fragment("incompatible.ret.type.in.lambda",
661 diags.fragment("missing.ret.val", currentReturnType)));
662 }
663 }
664 }
665 }
666 }
668 boolean canLambdaBodyCompleteNormally(JCLambda tree) {
669 JCLambda newTree = new TreeCopier<>(make).copy(tree);
670 /* attr.lambdaEnv will create a meaningful env for the
671 * lambda expression. This is specially useful when the
672 * lambda is used as the init of a field. But we need to
673 * remove any added symbol.
674 */
675 Env<AttrContext> localEnv = attr.lambdaEnv(newTree, env);
676 try {
677 List<JCVariableDecl> tmpParams = newTree.params;
678 while (tmpParams.nonEmpty()) {
679 tmpParams.head.vartype = make.at(tmpParams.head).Type(syms.errType);
680 tmpParams = tmpParams.tail;
681 }
683 attr.attribStats(newTree.params, localEnv);
685 /* set pt to Type.noType to avoid generating any bound
686 * which may happen if lambda's return type is an
687 * inference variable
688 */
689 Attr.ResultInfo bodyResultInfo = attr.new ResultInfo(VAL, Type.noType);
690 localEnv.info.returnResult = bodyResultInfo;
692 // discard any log output
693 Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
694 try {
695 JCBlock body = (JCBlock)newTree.body;
696 /* we need to attribute the lambda body before
697 * doing the aliveness analysis. This is because
698 * constant folding occurs during attribution
699 * and the reachability of some statements depends
700 * on constant values, for example:
701 *
702 * while (true) {...}
703 */
704 attr.attribStats(body.stats, localEnv);
706 attr.preFlow(newTree);
707 /* make an aliveness / reachability analysis of the lambda
708 * to determine if it can complete normally
709 */
710 flow.analyzeLambda(localEnv, newTree, make, true);
711 } finally {
712 log.popDiagnosticHandler(diagHandler);
713 }
714 return newTree.canCompleteNormally;
715 } finally {
716 JCBlock body = (JCBlock)newTree.body;
717 unenterScanner.scan(body.stats);
718 localEnv.info.scope.leave();
719 }
720 }
722 @Override
723 public void visitNewClass(JCNewClass tree) {
724 //do nothing
725 }
727 @Override
728 public void visitApply(JCMethodInvocation tree) {
729 //do nothing
730 }
732 @Override
733 public void visitReference(JCMemberReference tree) {
734 Check.CheckContext checkContext = resultInfo.checkContext;
735 Type pt = resultInfo.pt;
736 if (!inferenceContext.inferencevars.contains(pt)) {
737 try {
738 types.findDescriptorType(pt);
739 } catch (Types.FunctionDescriptorLookupError ex) {
740 checkContext.report(null, ex.getDiagnostic());
741 }
742 Env<AttrContext> localEnv = env.dup(tree);
743 JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv,
744 attr.memberReferenceQualifierResult(tree));
745 ListBuffer<Type> argtypes = new ListBuffer<>();
746 for (Type t : types.findDescriptorType(pt).getParameterTypes()) {
747 argtypes.append(Type.noType);
748 }
749 JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree);
750 mref2.expr = exprTree;
751 Symbol lookupSym =
752 rs.resolveMemberReferenceByArity(localEnv, mref2, exprTree.type,
753 tree.name, argtypes.toList(), inferenceContext);
754 switch (lookupSym.kind) {
755 //note: as argtypes are erroneous types, type-errors must
756 //have been caused by arity mismatch
757 case Kinds.ABSENT_MTH:
758 case Kinds.WRONG_MTH:
759 case Kinds.WRONG_MTHS:
760 case Kinds.WRONG_STATICNESS:
761 checkContext.report(tree, diags.fragment("incompatible.arg.types.in.mref"));
762 }
763 }
764 }
765 }
767 /* This visitor looks for return statements, its analysis will determine if
768 * a lambda body is void or value compatible. We must analyze return
769 * statements contained in the lambda body only, thus any return statement
770 * contained in an inner class or inner lambda body, should be ignored.
771 */
772 class LambdaBodyStructChecker extends TreeScanner {
773 boolean isVoidCompatible = true;
774 boolean isPotentiallyValueCompatible = true;
776 @Override
777 public void visitClassDef(JCClassDecl tree) {
778 // do nothing
779 }
781 @Override
782 public void visitLambda(JCLambda tree) {
783 // do nothing
784 }
786 @Override
787 public void visitNewClass(JCNewClass tree) {
788 // do nothing
789 }
791 @Override
792 public void visitReturn(JCReturn tree) {
793 if (tree.expr != null) {
794 isVoidCompatible = false;
795 } else {
796 isPotentiallyValueCompatible = false;
797 }
798 }
799 }
800 }
802 /** an empty deferred attribution context - all methods throw exceptions */
803 final DeferredAttrContext emptyDeferredAttrContext;
805 /**
806 * Map a list of types possibly containing one or more deferred types
807 * into a list of ordinary types. Each deferred type D is mapped into a type T,
808 * where T is computed by retrieving the type that has already been
809 * computed for D during a previous deferred attribution round of the given kind.
810 */
811 class DeferredTypeMap extends Type.Mapping {
813 DeferredAttrContext deferredAttrContext;
815 protected DeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
816 super(String.format("deferredTypeMap[%s]", mode));
817 this.deferredAttrContext = new DeferredAttrContext(mode, msym, phase,
818 infer.emptyContext, emptyDeferredAttrContext, types.noWarnings);
819 }
821 @Override
822 public Type apply(Type t) {
823 if (!t.hasTag(DEFERRED)) {
824 return t.map(this);
825 } else {
826 DeferredType dt = (DeferredType)t;
827 return typeOf(dt);
828 }
829 }
831 protected Type typeOf(DeferredType dt) {
832 switch (deferredAttrContext.mode) {
833 case CHECK:
834 return dt.tree.type == null ? Type.noType : dt.tree.type;
835 case SPECULATIVE:
836 return dt.speculativeType(deferredAttrContext.msym, deferredAttrContext.phase);
837 }
838 Assert.error();
839 return null;
840 }
841 }
843 /**
844 * Specialized recovery deferred mapping.
845 * Each deferred type D is mapped into a type T, where T is computed either by
846 * (i) retrieving the type that has already been computed for D during a previous
847 * attribution round (as before), or (ii) by synthesizing a new type R for D
848 * (the latter step is useful in a recovery scenario).
849 */
850 public class RecoveryDeferredTypeMap extends DeferredTypeMap {
852 public RecoveryDeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
853 super(mode, msym, phase != null ? phase : MethodResolutionPhase.BOX);
854 }
856 @Override
857 protected Type typeOf(DeferredType dt) {
858 Type owntype = super.typeOf(dt);
859 return owntype == Type.noType ?
860 recover(dt) : owntype;
861 }
863 /**
864 * Synthesize a type for a deferred type that hasn't been previously
865 * reduced to an ordinary type. Functional deferred types and conditionals
866 * are mapped to themselves, in order to have a richer diagnostic
867 * representation. Remaining deferred types are attributed using
868 * a default expected type (j.l.Object).
869 */
870 private Type recover(DeferredType dt) {
871 dt.check(attr.new RecoveryInfo(deferredAttrContext) {
872 @Override
873 protected Type check(DiagnosticPosition pos, Type found) {
874 return chk.checkNonVoid(pos, super.check(pos, found));
875 }
876 });
877 return super.apply(dt);
878 }
879 }
881 /**
882 * A special tree scanner that would only visit portions of a given tree.
883 * The set of nodes visited by the scanner can be customized at construction-time.
884 */
885 abstract static class FilterScanner extends TreeScanner {
887 final Filter<JCTree> treeFilter;
889 FilterScanner(final Set<JCTree.Tag> validTags) {
890 this.treeFilter = new Filter<JCTree>() {
891 public boolean accepts(JCTree t) {
892 return validTags.contains(t.getTag());
893 }
894 };
895 }
897 @Override
898 public void scan(JCTree tree) {
899 if (tree != null) {
900 if (treeFilter.accepts(tree)) {
901 super.scan(tree);
902 } else {
903 skip(tree);
904 }
905 }
906 }
908 /**
909 * handler that is executed when a node has been discarded
910 */
911 void skip(JCTree tree) {}
912 }
914 /**
915 * A tree scanner suitable for visiting the target-type dependent nodes of
916 * a given argument expression.
917 */
918 static class PolyScanner extends FilterScanner {
920 PolyScanner() {
921 super(EnumSet.of(CONDEXPR, PARENS, LAMBDA, REFERENCE));
922 }
923 }
925 /**
926 * A tree scanner suitable for visiting the target-type dependent nodes nested
927 * within a lambda expression body.
928 */
929 static class LambdaReturnScanner extends FilterScanner {
931 LambdaReturnScanner() {
932 super(EnumSet.of(BLOCK, CASE, CATCH, DOLOOP, FOREACHLOOP,
933 FORLOOP, IF, RETURN, SYNCHRONIZED, SWITCH, TRY, WHILELOOP));
934 }
935 }
937 /**
938 * This visitor is used to check that structural expressions conform
939 * to their target - this step is required as inference could end up
940 * inferring types that make some of the nested expressions incompatible
941 * with their corresponding instantiated target
942 */
943 class CheckStuckPolicy extends PolyScanner implements DeferredStuckPolicy, Infer.FreeTypeListener {
945 Type pt;
946 Infer.InferenceContext inferenceContext;
947 Set<Type> stuckVars = new LinkedHashSet<Type>();
948 Set<Type> depVars = new LinkedHashSet<Type>();
950 @Override
951 public boolean isStuck() {
952 return !stuckVars.isEmpty();
953 }
955 @Override
956 public Set<Type> stuckVars() {
957 return stuckVars;
958 }
960 @Override
961 public Set<Type> depVars() {
962 return depVars;
963 }
965 public CheckStuckPolicy(ResultInfo resultInfo, DeferredType dt) {
966 this.pt = resultInfo.pt;
967 this.inferenceContext = resultInfo.checkContext.inferenceContext();
968 scan(dt.tree);
969 if (!stuckVars.isEmpty()) {
970 resultInfo.checkContext.inferenceContext()
971 .addFreeTypeListener(List.from(stuckVars), this);
972 }
973 }
975 @Override
976 public void typesInferred(InferenceContext inferenceContext) {
977 stuckVars.clear();
978 }
980 @Override
981 public void visitLambda(JCLambda tree) {
982 if (inferenceContext.inferenceVars().contains(pt)) {
983 stuckVars.add(pt);
984 }
985 if (!types.isFunctionalInterface(pt)) {
986 return;
987 }
988 Type descType = types.findDescriptorType(pt);
989 List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
990 if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT &&
991 freeArgVars.nonEmpty()) {
992 stuckVars.addAll(freeArgVars);
993 depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType()));
994 }
995 scanLambdaBody(tree, descType.getReturnType());
996 }
998 @Override
999 public void visitReference(JCMemberReference tree) {
1000 scan(tree.expr);
1001 if (inferenceContext.inferenceVars().contains(pt)) {
1002 stuckVars.add(pt);
1003 return;
1004 }
1005 if (!types.isFunctionalInterface(pt)) {
1006 return;
1007 }
1009 Type descType = types.findDescriptorType(pt);
1010 List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
1011 if (freeArgVars.nonEmpty() &&
1012 tree.overloadKind == JCMemberReference.OverloadKind.OVERLOADED) {
1013 stuckVars.addAll(freeArgVars);
1014 depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType()));
1015 }
1016 }
1018 void scanLambdaBody(JCLambda lambda, final Type pt) {
1019 if (lambda.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) {
1020 Type prevPt = this.pt;
1021 try {
1022 this.pt = pt;
1023 scan(lambda.body);
1024 } finally {
1025 this.pt = prevPt;
1026 }
1027 } else {
1028 LambdaReturnScanner lambdaScanner = new LambdaReturnScanner() {
1029 @Override
1030 public void visitReturn(JCReturn tree) {
1031 if (tree.expr != null) {
1032 Type prevPt = CheckStuckPolicy.this.pt;
1033 try {
1034 CheckStuckPolicy.this.pt = pt;
1035 CheckStuckPolicy.this.scan(tree.expr);
1036 } finally {
1037 CheckStuckPolicy.this.pt = prevPt;
1038 }
1039 }
1040 }
1041 };
1042 lambdaScanner.scan(lambda.body);
1043 }
1044 }
1045 }
1047 /**
1048 * This visitor is used to check that structural expressions conform
1049 * to their target - this step is required as inference could end up
1050 * inferring types that make some of the nested expressions incompatible
1051 * with their corresponding instantiated target
1052 */
1053 class OverloadStuckPolicy extends CheckStuckPolicy implements DeferredStuckPolicy {
1055 boolean stuck;
1057 @Override
1058 public boolean isStuck() {
1059 return super.isStuck() || stuck;
1060 }
1062 public OverloadStuckPolicy(ResultInfo resultInfo, DeferredType dt) {
1063 super(resultInfo, dt);
1064 }
1066 @Override
1067 public void visitLambda(JCLambda tree) {
1068 super.visitLambda(tree);
1069 if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT) {
1070 stuck = true;
1071 }
1072 }
1074 @Override
1075 public void visitReference(JCMemberReference tree) {
1076 super.visitReference(tree);
1077 if (tree.overloadKind == JCMemberReference.OverloadKind.OVERLOADED) {
1078 stuck = true;
1079 }
1080 }
1081 }
1083 /**
1084 * Does the argument expression {@code expr} need speculative type-checking?
1085 */
1086 boolean isDeferred(Env<AttrContext> env, JCExpression expr) {
1087 DeferredChecker dc = new DeferredChecker(env);
1088 dc.scan(expr);
1089 return dc.result.isPoly();
1090 }
1092 /**
1093 * The kind of an argument expression. This is used by the analysis that
1094 * determines as to whether speculative attribution is necessary.
1095 */
1096 enum ArgumentExpressionKind {
1098 /** kind that denotes poly argument expression */
1099 POLY,
1100 /** kind that denotes a standalone expression */
1101 NO_POLY,
1102 /** kind that denotes a primitive/boxed standalone expression */
1103 PRIMITIVE;
1105 /**
1106 * Does this kind denote a poly argument expression
1107 */
1108 public final boolean isPoly() {
1109 return this == POLY;
1110 }
1112 /**
1113 * Does this kind denote a primitive standalone expression
1114 */
1115 public final boolean isPrimitive() {
1116 return this == PRIMITIVE;
1117 }
1119 /**
1120 * Compute the kind of a standalone expression of a given type
1121 */
1122 static ArgumentExpressionKind standaloneKind(Type type, Types types) {
1123 return types.unboxedTypeOrType(type).isPrimitive() ?
1124 ArgumentExpressionKind.PRIMITIVE :
1125 ArgumentExpressionKind.NO_POLY;
1126 }
1128 /**
1129 * Compute the kind of a method argument expression given its symbol
1130 */
1131 static ArgumentExpressionKind methodKind(Symbol sym, Types types) {
1132 Type restype = sym.type.getReturnType();
1133 if (sym.type.hasTag(FORALL) &&
1134 restype.containsAny(((ForAll)sym.type).tvars)) {
1135 return ArgumentExpressionKind.POLY;
1136 } else {
1137 return ArgumentExpressionKind.standaloneKind(restype, types);
1138 }
1139 }
1140 }
1142 /**
1143 * Tree scanner used for checking as to whether an argument expression
1144 * requires speculative attribution
1145 */
1146 final class DeferredChecker extends FilterScanner {
1148 Env<AttrContext> env;
1149 ArgumentExpressionKind result;
1151 public DeferredChecker(Env<AttrContext> env) {
1152 super(deferredCheckerTags);
1153 this.env = env;
1154 }
1156 @Override
1157 public void visitLambda(JCLambda tree) {
1158 //a lambda is always a poly expression
1159 result = ArgumentExpressionKind.POLY;
1160 }
1162 @Override
1163 public void visitReference(JCMemberReference tree) {
1164 //perform arity-based check
1165 Env<AttrContext> localEnv = env.dup(tree);
1166 JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv,
1167 attr.memberReferenceQualifierResult(tree));
1168 JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree);
1169 mref2.expr = exprTree;
1170 Symbol res =
1171 rs.getMemberReference(tree, localEnv, mref2,
1172 exprTree.type, tree.name);
1173 tree.sym = res;
1174 if (res.kind >= Kinds.ERRONEOUS ||
1175 res.type.hasTag(FORALL) ||
1176 (res.flags() & Flags.VARARGS) != 0 ||
1177 (TreeInfo.isStaticSelector(exprTree, tree.name.table.names) &&
1178 exprTree.type.isRaw())) {
1179 tree.overloadKind = JCMemberReference.OverloadKind.OVERLOADED;
1180 } else {
1181 tree.overloadKind = JCMemberReference.OverloadKind.UNOVERLOADED;
1182 }
1183 //a method reference is always a poly expression
1184 result = ArgumentExpressionKind.POLY;
1185 }
1187 @Override
1188 public void visitTypeCast(JCTypeCast tree) {
1189 //a cast is always a standalone expression
1190 result = ArgumentExpressionKind.NO_POLY;
1191 }
1193 @Override
1194 public void visitConditional(JCConditional tree) {
1195 scan(tree.truepart);
1196 if (!result.isPrimitive()) {
1197 result = ArgumentExpressionKind.POLY;
1198 return;
1199 }
1200 scan(tree.falsepart);
1201 result = reduce(ArgumentExpressionKind.PRIMITIVE);
1202 }
1204 @Override
1205 public void visitNewClass(JCNewClass tree) {
1206 result = (TreeInfo.isDiamond(tree) || attr.findDiamonds) ?
1207 ArgumentExpressionKind.POLY : ArgumentExpressionKind.NO_POLY;
1208 }
1210 @Override
1211 public void visitApply(JCMethodInvocation tree) {
1212 Name name = TreeInfo.name(tree.meth);
1214 //fast path
1215 if (tree.typeargs.nonEmpty() ||
1216 name == name.table.names._this ||
1217 name == name.table.names._super) {
1218 result = ArgumentExpressionKind.NO_POLY;
1219 return;
1220 }
1222 //slow path
1223 Symbol sym = quicklyResolveMethod(env, tree);
1225 if (sym == null) {
1226 result = ArgumentExpressionKind.POLY;
1227 return;
1228 }
1230 result = analyzeCandidateMethods(sym, ArgumentExpressionKind.PRIMITIVE,
1231 argumentKindAnalyzer);
1232 }
1233 //where
1234 private boolean isSimpleReceiver(JCTree rec) {
1235 switch (rec.getTag()) {
1236 case IDENT:
1237 return true;
1238 case SELECT:
1239 return isSimpleReceiver(((JCFieldAccess)rec).selected);
1240 case TYPEAPPLY:
1241 case TYPEARRAY:
1242 return true;
1243 case ANNOTATED_TYPE:
1244 return isSimpleReceiver(((JCAnnotatedType)rec).underlyingType);
1245 case APPLY:
1246 return true;
1247 default:
1248 return false;
1249 }
1250 }
1251 private ArgumentExpressionKind reduce(ArgumentExpressionKind kind) {
1252 return argumentKindAnalyzer.reduce(result, kind);
1253 }
1254 MethodAnalyzer<ArgumentExpressionKind> argumentKindAnalyzer =
1255 new MethodAnalyzer<ArgumentExpressionKind>() {
1256 @Override
1257 public ArgumentExpressionKind process(MethodSymbol ms) {
1258 return ArgumentExpressionKind.methodKind(ms, types);
1259 }
1260 @Override
1261 public ArgumentExpressionKind reduce(ArgumentExpressionKind kind1,
1262 ArgumentExpressionKind kind2) {
1263 switch (kind1) {
1264 case PRIMITIVE: return kind2;
1265 case NO_POLY: return kind2.isPoly() ? kind2 : kind1;
1266 case POLY: return kind1;
1267 default:
1268 Assert.error();
1269 return null;
1270 }
1271 }
1272 @Override
1273 public boolean shouldStop(ArgumentExpressionKind result) {
1274 return result.isPoly();
1275 }
1276 };
1278 @Override
1279 public void visitLiteral(JCLiteral tree) {
1280 Type litType = attr.litType(tree.typetag);
1281 result = ArgumentExpressionKind.standaloneKind(litType, types);
1282 }
1284 @Override
1285 void skip(JCTree tree) {
1286 result = ArgumentExpressionKind.NO_POLY;
1287 }
1289 private Symbol quicklyResolveMethod(Env<AttrContext> env, final JCMethodInvocation tree) {
1290 final JCExpression rec = tree.meth.hasTag(SELECT) ?
1291 ((JCFieldAccess)tree.meth).selected :
1292 null;
1294 if (rec != null && !isSimpleReceiver(rec)) {
1295 return null;
1296 }
1298 Type site;
1300 if (rec != null) {
1301 if (rec.hasTag(APPLY)) {
1302 Symbol recSym = quicklyResolveMethod(env, (JCMethodInvocation) rec);
1303 if (recSym == null)
1304 return null;
1305 Symbol resolvedReturnType =
1306 analyzeCandidateMethods(recSym, syms.errSymbol, returnSymbolAnalyzer);
1307 if (resolvedReturnType == null)
1308 return null;
1309 site = resolvedReturnType.type;
1310 } else {
1311 site = attribSpeculative(rec, env, attr.unknownTypeExprInfo).type;
1312 }
1313 } else {
1314 site = env.enclClass.sym.type;
1315 }
1317 List<Type> args = rs.dummyArgs(tree.args.length());
1318 Name name = TreeInfo.name(tree.meth);
1320 Resolve.LookupHelper lh = rs.new LookupHelper(name, site, args, List.<Type>nil(), MethodResolutionPhase.VARARITY) {
1321 @Override
1322 Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
1323 return rec == null ?
1324 rs.findFun(env, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()) :
1325 rs.findMethod(env, site, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired(), false);
1326 }
1327 @Override
1328 Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
1329 return sym;
1330 }
1331 };
1333 return rs.lookupMethod(env, tree, site.tsym, rs.arityMethodCheck, lh);
1334 }
1335 //where:
1336 MethodAnalyzer<Symbol> returnSymbolAnalyzer = new MethodAnalyzer<Symbol>() {
1337 @Override
1338 public Symbol process(MethodSymbol ms) {
1339 ArgumentExpressionKind kind = ArgumentExpressionKind.methodKind(ms, types);
1340 return kind != ArgumentExpressionKind.POLY ? ms.getReturnType().tsym : null;
1341 }
1342 @Override
1343 public Symbol reduce(Symbol s1, Symbol s2) {
1344 return s1 == syms.errSymbol ? s2 : s1 == s2 ? s1 : null;
1345 }
1346 @Override
1347 public boolean shouldStop(Symbol result) {
1348 return result == null;
1349 }
1350 };
1352 /**
1353 * Process the result of Resolve.lookupMethod. If sym is a method symbol, the result of
1354 * MethodAnalyzer.process is returned. If sym is an ambiguous symbol, all the candidate
1355 * methods are inspected one by one, using MethodAnalyzer.process. The outcomes are
1356 * reduced using MethodAnalyzer.reduce (using defaultValue as the first value over which
1357 * the reduction runs). MethodAnalyzer.shouldStop can be used to stop the inspection early.
1358 */
1359 <E> E analyzeCandidateMethods(Symbol sym, E defaultValue, MethodAnalyzer<E> analyzer) {
1360 switch (sym.kind) {
1361 case Kinds.MTH:
1362 return analyzer.process((MethodSymbol) sym);
1363 case Kinds.AMBIGUOUS:
1364 Resolve.AmbiguityError err = (Resolve.AmbiguityError)sym.baseSymbol();
1365 E res = defaultValue;
1366 for (Symbol s : err.ambiguousSyms) {
1367 if (s.kind == Kinds.MTH) {
1368 res = analyzer.reduce(res, analyzer.process((MethodSymbol) s));
1369 if (analyzer.shouldStop(res))
1370 return res;
1371 }
1372 }
1373 return res;
1374 default:
1375 return defaultValue;
1376 }
1377 }
1378 }
1380 /** Analyzer for methods - used by analyzeCandidateMethods. */
1381 interface MethodAnalyzer<E> {
1382 E process(MethodSymbol ms);
1383 E reduce(E e1, E e2);
1384 boolean shouldStop(E result);
1385 }
1387 //where
1388 private EnumSet<JCTree.Tag> deferredCheckerTags =
1389 EnumSet.of(LAMBDA, REFERENCE, PARENS, TYPECAST,
1390 CONDEXPR, NEWCLASS, APPLY, LITERAL);
1391 }