Sat, 07 Nov 2020 10:30:02 +0800
Added tag mips-jdk8u275-b01 for changeset eb6ee6a5f2fe
1 /*
2 * Copyright (c) 2012, 2015, 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 resultInfo.checkContext.deferredAttrContext().insideOverloadPhase()) {
229 deferredStuckPolicy = new OverloadStuckPolicy(resultInfo, this);
230 } else {
231 deferredStuckPolicy = new CheckStuckPolicy(resultInfo, this);
232 }
233 return check(resultInfo, deferredStuckPolicy, basicCompleter);
234 }
236 private Type check(ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy,
237 DeferredTypeCompleter deferredTypeCompleter) {
238 DeferredAttrContext deferredAttrContext =
239 resultInfo.checkContext.deferredAttrContext();
240 Assert.check(deferredAttrContext != emptyDeferredAttrContext);
241 if (deferredStuckPolicy.isStuck()) {
242 deferredAttrContext.addDeferredAttrNode(this, resultInfo, deferredStuckPolicy);
243 return Type.noType;
244 } else {
245 try {
246 return deferredTypeCompleter.complete(this, resultInfo, deferredAttrContext);
247 } finally {
248 mode = deferredAttrContext.mode;
249 }
250 }
251 }
252 }
254 /**
255 * A completer for deferred types. Defines an entry point for type-checking
256 * a deferred type.
257 */
258 interface DeferredTypeCompleter {
259 /**
260 * Entry point for type-checking a deferred type. Depending on the
261 * circumstances, type-checking could amount to full attribution
262 * or partial structural check (aka potential applicability).
263 */
264 Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext);
265 }
268 /**
269 * A basic completer for deferred types. This completer type-checks a deferred type
270 * using attribution; depending on the attribution mode, this could be either standard
271 * or speculative attribution.
272 */
273 DeferredTypeCompleter basicCompleter = new DeferredTypeCompleter() {
274 public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
275 switch (deferredAttrContext.mode) {
276 case SPECULATIVE:
277 //Note: if a symbol is imported twice we might do two identical
278 //speculative rounds...
279 Assert.check(dt.mode == null || dt.mode == AttrMode.SPECULATIVE);
280 JCTree speculativeTree = attribSpeculative(dt.tree, dt.env, resultInfo);
281 dt.speculativeCache.put(speculativeTree, resultInfo);
282 return speculativeTree.type;
283 case CHECK:
284 Assert.check(dt.mode != null);
285 return attr.attribTree(dt.tree, dt.env, resultInfo);
286 }
287 Assert.error();
288 return null;
289 }
290 };
292 DeferredTypeCompleter dummyCompleter = new DeferredTypeCompleter() {
293 public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
294 Assert.check(deferredAttrContext.mode == AttrMode.CHECK);
295 return dt.tree.type = Type.stuckType;
296 }
297 };
299 /**
300 * Policy for detecting stuck expressions. Different criteria might cause
301 * an expression to be judged as stuck, depending on whether the check
302 * is performed during overload resolution or after most specific.
303 */
304 interface DeferredStuckPolicy {
305 /**
306 * Has the policy detected that a given expression should be considered stuck?
307 */
308 boolean isStuck();
309 /**
310 * Get the set of inference variables a given expression depends upon.
311 */
312 Set<Type> stuckVars();
313 /**
314 * Get the set of inference variables which might get new constraints
315 * if a given expression is being type-checked.
316 */
317 Set<Type> depVars();
318 }
320 /**
321 * Basic stuck policy; an expression is never considered to be stuck.
322 */
323 DeferredStuckPolicy dummyStuckPolicy = new DeferredStuckPolicy() {
324 @Override
325 public boolean isStuck() {
326 return false;
327 }
328 @Override
329 public Set<Type> stuckVars() {
330 return Collections.emptySet();
331 }
332 @Override
333 public Set<Type> depVars() {
334 return Collections.emptySet();
335 }
336 };
338 /**
339 * The 'mode' in which the deferred type is to be type-checked
340 */
341 public enum AttrMode {
342 /**
343 * A speculative type-checking round is used during overload resolution
344 * mainly to generate constraints on inference variables. Side-effects
345 * arising from type-checking the expression associated with the deferred
346 * type are reversed after the speculative round finishes. This means the
347 * expression tree will be left in a blank state.
348 */
349 SPECULATIVE,
350 /**
351 * This is the plain type-checking mode. Produces side-effects on the underlying AST node
352 */
353 CHECK;
354 }
356 /**
357 * Routine that performs speculative type-checking; the input AST node is
358 * cloned (to avoid side-effects cause by Attr) and compiler state is
359 * restored after type-checking. All diagnostics (but critical ones) are
360 * disabled during speculative type-checking.
361 */
362 JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
363 final JCTree newTree = new TreeCopier<Object>(make).copy(tree);
364 Env<AttrContext> speculativeEnv = env.dup(newTree, env.info.dup(env.info.scope.dupUnshared()));
365 speculativeEnv.info.scope.owner = env.info.scope.owner;
366 Log.DeferredDiagnosticHandler deferredDiagnosticHandler =
367 new Log.DeferredDiagnosticHandler(log, new Filter<JCDiagnostic>() {
368 public boolean accepts(final JCDiagnostic d) {
369 class PosScanner extends TreeScanner {
370 boolean found = false;
372 @Override
373 public void scan(JCTree tree) {
374 if (tree != null &&
375 tree.pos() == d.getDiagnosticPosition()) {
376 found = true;
377 }
378 super.scan(tree);
379 }
380 };
381 PosScanner posScanner = new PosScanner();
382 posScanner.scan(newTree);
383 return posScanner.found;
384 }
385 });
386 try {
387 attr.attribTree(newTree, speculativeEnv, resultInfo);
388 unenterScanner.scan(newTree);
389 return newTree;
390 } finally {
391 unenterScanner.scan(newTree);
392 log.popDiagnosticHandler(deferredDiagnosticHandler);
393 }
394 }
395 //where
396 protected UnenterScanner unenterScanner = new UnenterScanner();
398 class UnenterScanner extends TreeScanner {
399 @Override
400 public void visitClassDef(JCClassDecl tree) {
401 ClassSymbol csym = tree.sym;
402 //if something went wrong during method applicability check
403 //it is possible that nested expressions inside argument expression
404 //are left unchecked - in such cases there's nothing to clean up.
405 if (csym == null) return;
406 typeEnvs.remove(csym);
407 chk.compiled.remove(csym.flatname);
408 syms.classes.remove(csym.flatname);
409 super.visitClassDef(tree);
410 }
411 }
413 /**
414 * A deferred context is created on each method check. A deferred context is
415 * used to keep track of information associated with the method check, such as
416 * the symbol of the method being checked, the overload resolution phase,
417 * the kind of attribution mode to be applied to deferred types and so forth.
418 * As deferred types are processed (by the method check routine) stuck AST nodes
419 * are added (as new deferred attribution nodes) to this context. The complete()
420 * routine makes sure that all pending nodes are properly processed, by
421 * progressively instantiating all inference variables on which one or more
422 * deferred attribution node is stuck.
423 */
424 class DeferredAttrContext {
426 /** attribution mode */
427 final AttrMode mode;
429 /** symbol of the method being checked */
430 final Symbol msym;
432 /** method resolution step */
433 final Resolve.MethodResolutionPhase phase;
435 /** inference context */
436 final InferenceContext inferenceContext;
438 /** parent deferred context */
439 final DeferredAttrContext parent;
441 /** Warner object to report warnings */
442 final Warner warn;
444 /** list of deferred attribution nodes to be processed */
445 ArrayList<DeferredAttrNode> deferredAttrNodes = new ArrayList<DeferredAttrNode>();
447 DeferredAttrContext(AttrMode mode, Symbol msym, MethodResolutionPhase phase,
448 InferenceContext inferenceContext, DeferredAttrContext parent, Warner warn) {
449 this.mode = mode;
450 this.msym = msym;
451 this.phase = phase;
452 this.parent = parent;
453 this.warn = warn;
454 this.inferenceContext = inferenceContext;
455 }
457 /**
458 * Adds a node to the list of deferred attribution nodes - used by Resolve.rawCheckArgumentsApplicable
459 * Nodes added this way act as 'roots' for the out-of-order method checking process.
460 */
461 void addDeferredAttrNode(final DeferredType dt, ResultInfo resultInfo,
462 DeferredStuckPolicy deferredStuckPolicy) {
463 deferredAttrNodes.add(new DeferredAttrNode(dt, resultInfo, deferredStuckPolicy));
464 }
466 /**
467 * Incrementally process all nodes, by skipping 'stuck' nodes and attributing
468 * 'unstuck' ones. If at any point no progress can be made (no 'unstuck' nodes)
469 * some inference variable might get eagerly instantiated so that all nodes
470 * can be type-checked.
471 */
472 void complete() {
473 while (!deferredAttrNodes.isEmpty()) {
474 Map<Type, Set<Type>> depVarsMap = new LinkedHashMap<Type, Set<Type>>();
475 List<Type> stuckVars = List.nil();
476 boolean progress = false;
477 //scan a defensive copy of the node list - this is because a deferred
478 //attribution round can add new nodes to the list
479 for (DeferredAttrNode deferredAttrNode : List.from(deferredAttrNodes)) {
480 if (!deferredAttrNode.process(this)) {
481 List<Type> restStuckVars =
482 List.from(deferredAttrNode.deferredStuckPolicy.stuckVars())
483 .intersect(inferenceContext.restvars());
484 stuckVars = stuckVars.prependList(restStuckVars);
485 //update dependency map
486 for (Type t : List.from(deferredAttrNode.deferredStuckPolicy.depVars())
487 .intersect(inferenceContext.restvars())) {
488 Set<Type> prevDeps = depVarsMap.get(t);
489 if (prevDeps == null) {
490 prevDeps = new LinkedHashSet<Type>();
491 depVarsMap.put(t, prevDeps);
492 }
493 prevDeps.addAll(restStuckVars);
494 }
495 } else {
496 deferredAttrNodes.remove(deferredAttrNode);
497 progress = true;
498 }
499 }
500 if (!progress) {
501 if (insideOverloadPhase()) {
502 for (DeferredAttrNode deferredNode: deferredAttrNodes) {
503 deferredNode.dt.tree.type = Type.noType;
504 }
505 return;
506 }
507 //remove all variables that have already been instantiated
508 //from the list of stuck variables
509 try {
510 inferenceContext.solveAny(stuckVars, depVarsMap, warn);
511 inferenceContext.notifyChange();
512 } catch (Infer.GraphStrategy.NodeNotFoundException ex) {
513 //this means that we are in speculative mode and the
514 //set of contraints are too tight for progess to be made.
515 //Just leave the remaining expressions as stuck.
516 break;
517 }
518 }
519 }
520 }
522 private boolean insideOverloadPhase() {
523 DeferredAttrContext dac = this;
524 if (dac == emptyDeferredAttrContext) {
525 return false;
526 }
527 if (dac.mode == AttrMode.SPECULATIVE) {
528 return true;
529 }
530 return dac.parent.insideOverloadPhase();
531 }
532 }
534 /**
535 * Class representing a deferred attribution node. It keeps track of
536 * a deferred type, along with the expected target type information.
537 */
538 class DeferredAttrNode {
540 /** underlying deferred type */
541 DeferredType dt;
543 /** underlying target type information */
544 ResultInfo resultInfo;
546 /** stuck policy associated with this node */
547 DeferredStuckPolicy deferredStuckPolicy;
549 DeferredAttrNode(DeferredType dt, ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy) {
550 this.dt = dt;
551 this.resultInfo = resultInfo;
552 this.deferredStuckPolicy = deferredStuckPolicy;
553 }
555 /**
556 * Process a deferred attribution node.
557 * Invariant: a stuck node cannot be processed.
558 */
559 @SuppressWarnings("fallthrough")
560 boolean process(final DeferredAttrContext deferredAttrContext) {
561 switch (deferredAttrContext.mode) {
562 case SPECULATIVE:
563 if (deferredStuckPolicy.isStuck()) {
564 dt.check(resultInfo, dummyStuckPolicy, new StructuralStuckChecker());
565 return true;
566 } else {
567 Assert.error("Cannot get here");
568 }
569 case CHECK:
570 if (deferredStuckPolicy.isStuck()) {
571 //stuck expression - see if we can propagate
572 if (deferredAttrContext.parent != emptyDeferredAttrContext &&
573 Type.containsAny(deferredAttrContext.parent.inferenceContext.inferencevars,
574 List.from(deferredStuckPolicy.stuckVars()))) {
575 deferredAttrContext.parent.addDeferredAttrNode(dt,
576 resultInfo.dup(new Check.NestedCheckContext(resultInfo.checkContext) {
577 @Override
578 public InferenceContext inferenceContext() {
579 return deferredAttrContext.parent.inferenceContext;
580 }
581 @Override
582 public DeferredAttrContext deferredAttrContext() {
583 return deferredAttrContext.parent;
584 }
585 }), deferredStuckPolicy);
586 dt.tree.type = Type.stuckType;
587 return true;
588 } else {
589 return false;
590 }
591 } else {
592 Assert.check(!deferredAttrContext.insideOverloadPhase(),
593 "attribution shouldn't be happening here");
594 ResultInfo instResultInfo =
595 resultInfo.dup(deferredAttrContext.inferenceContext.asInstType(resultInfo.pt));
596 dt.check(instResultInfo, dummyStuckPolicy, basicCompleter);
597 return true;
598 }
599 default:
600 throw new AssertionError("Bad mode");
601 }
602 }
604 /**
605 * Structural checker for stuck expressions
606 */
607 class StructuralStuckChecker extends TreeScanner implements DeferredTypeCompleter {
609 ResultInfo resultInfo;
610 InferenceContext inferenceContext;
611 Env<AttrContext> env;
613 public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
614 this.resultInfo = resultInfo;
615 this.inferenceContext = deferredAttrContext.inferenceContext;
616 this.env = dt.env;
617 dt.tree.accept(this);
618 dt.speculativeCache.put(stuckTree, resultInfo);
619 return Type.noType;
620 }
622 @Override
623 public void visitLambda(JCLambda tree) {
624 Check.CheckContext checkContext = resultInfo.checkContext;
625 Type pt = resultInfo.pt;
626 if (!inferenceContext.inferencevars.contains(pt)) {
627 //must be a functional descriptor
628 Type descriptorType = null;
629 try {
630 descriptorType = types.findDescriptorType(pt);
631 } catch (Types.FunctionDescriptorLookupError ex) {
632 checkContext.report(null, ex.getDiagnostic());
633 }
635 if (descriptorType.getParameterTypes().length() != tree.params.length()) {
636 checkContext.report(tree,
637 diags.fragment("incompatible.arg.types.in.lambda"));
638 }
640 Type currentReturnType = descriptorType.getReturnType();
641 boolean returnTypeIsVoid = currentReturnType.hasTag(VOID);
642 if (tree.getBodyKind() == BodyKind.EXPRESSION) {
643 boolean isExpressionCompatible = !returnTypeIsVoid ||
644 TreeInfo.isExpressionStatement((JCExpression)tree.getBody());
645 if (!isExpressionCompatible) {
646 resultInfo.checkContext.report(tree.pos(),
647 diags.fragment("incompatible.ret.type.in.lambda",
648 diags.fragment("missing.ret.val", currentReturnType)));
649 }
650 } else {
651 LambdaBodyStructChecker lambdaBodyChecker =
652 new LambdaBodyStructChecker();
654 tree.body.accept(lambdaBodyChecker);
655 boolean isVoidCompatible = lambdaBodyChecker.isVoidCompatible;
657 if (returnTypeIsVoid) {
658 if (!isVoidCompatible) {
659 resultInfo.checkContext.report(tree.pos(),
660 diags.fragment("unexpected.ret.val"));
661 }
662 } else {
663 boolean isValueCompatible = lambdaBodyChecker.isPotentiallyValueCompatible
664 && !canLambdaBodyCompleteNormally(tree);
665 if (!isValueCompatible && !isVoidCompatible) {
666 log.error(tree.body.pos(),
667 "lambda.body.neither.value.nor.void.compatible");
668 }
670 if (!isValueCompatible) {
671 resultInfo.checkContext.report(tree.pos(),
672 diags.fragment("incompatible.ret.type.in.lambda",
673 diags.fragment("missing.ret.val", currentReturnType)));
674 }
675 }
676 }
677 }
678 }
680 boolean canLambdaBodyCompleteNormally(JCLambda tree) {
681 JCLambda newTree = new TreeCopier<>(make).copy(tree);
682 /* attr.lambdaEnv will create a meaningful env for the
683 * lambda expression. This is specially useful when the
684 * lambda is used as the init of a field. But we need to
685 * remove any added symbol.
686 */
687 Env<AttrContext> localEnv = attr.lambdaEnv(newTree, env);
688 try {
689 List<JCVariableDecl> tmpParams = newTree.params;
690 while (tmpParams.nonEmpty()) {
691 tmpParams.head.vartype = make.at(tmpParams.head).Type(syms.errType);
692 tmpParams = tmpParams.tail;
693 }
695 attr.attribStats(newTree.params, localEnv);
697 /* set pt to Type.noType to avoid generating any bound
698 * which may happen if lambda's return type is an
699 * inference variable
700 */
701 Attr.ResultInfo bodyResultInfo = attr.new ResultInfo(VAL, Type.noType);
702 localEnv.info.returnResult = bodyResultInfo;
704 // discard any log output
705 Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
706 try {
707 JCBlock body = (JCBlock)newTree.body;
708 /* we need to attribute the lambda body before
709 * doing the aliveness analysis. This is because
710 * constant folding occurs during attribution
711 * and the reachability of some statements depends
712 * on constant values, for example:
713 *
714 * while (true) {...}
715 */
716 attr.attribStats(body.stats, localEnv);
718 attr.preFlow(newTree);
719 /* make an aliveness / reachability analysis of the lambda
720 * to determine if it can complete normally
721 */
722 flow.analyzeLambda(localEnv, newTree, make, true);
723 } finally {
724 log.popDiagnosticHandler(diagHandler);
725 }
726 return newTree.canCompleteNormally;
727 } finally {
728 JCBlock body = (JCBlock)newTree.body;
729 unenterScanner.scan(body.stats);
730 localEnv.info.scope.leave();
731 }
732 }
734 @Override
735 public void visitNewClass(JCNewClass tree) {
736 //do nothing
737 }
739 @Override
740 public void visitApply(JCMethodInvocation tree) {
741 //do nothing
742 }
744 @Override
745 public void visitReference(JCMemberReference tree) {
746 Check.CheckContext checkContext = resultInfo.checkContext;
747 Type pt = resultInfo.pt;
748 if (!inferenceContext.inferencevars.contains(pt)) {
749 try {
750 types.findDescriptorType(pt);
751 } catch (Types.FunctionDescriptorLookupError ex) {
752 checkContext.report(null, ex.getDiagnostic());
753 }
754 Env<AttrContext> localEnv = env.dup(tree);
755 JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv,
756 attr.memberReferenceQualifierResult(tree));
757 ListBuffer<Type> argtypes = new ListBuffer<>();
758 for (Type t : types.findDescriptorType(pt).getParameterTypes()) {
759 argtypes.append(Type.noType);
760 }
761 JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree);
762 mref2.expr = exprTree;
763 Symbol lookupSym =
764 rs.resolveMemberReferenceByArity(localEnv, mref2, exprTree.type,
765 tree.name, argtypes.toList(), inferenceContext);
766 switch (lookupSym.kind) {
767 //note: as argtypes are erroneous types, type-errors must
768 //have been caused by arity mismatch
769 case Kinds.ABSENT_MTH:
770 case Kinds.WRONG_MTH:
771 case Kinds.WRONG_MTHS:
772 case Kinds.WRONG_STATICNESS:
773 checkContext.report(tree, diags.fragment("incompatible.arg.types.in.mref"));
774 }
775 }
776 }
777 }
779 /* This visitor looks for return statements, its analysis will determine if
780 * a lambda body is void or value compatible. We must analyze return
781 * statements contained in the lambda body only, thus any return statement
782 * contained in an inner class or inner lambda body, should be ignored.
783 */
784 class LambdaBodyStructChecker extends TreeScanner {
785 boolean isVoidCompatible = true;
786 boolean isPotentiallyValueCompatible = true;
788 @Override
789 public void visitClassDef(JCClassDecl tree) {
790 // do nothing
791 }
793 @Override
794 public void visitLambda(JCLambda tree) {
795 // do nothing
796 }
798 @Override
799 public void visitNewClass(JCNewClass tree) {
800 // do nothing
801 }
803 @Override
804 public void visitReturn(JCReturn tree) {
805 if (tree.expr != null) {
806 isVoidCompatible = false;
807 } else {
808 isPotentiallyValueCompatible = false;
809 }
810 }
811 }
812 }
814 /** an empty deferred attribution context - all methods throw exceptions */
815 final DeferredAttrContext emptyDeferredAttrContext;
817 /**
818 * Map a list of types possibly containing one or more deferred types
819 * into a list of ordinary types. Each deferred type D is mapped into a type T,
820 * where T is computed by retrieving the type that has already been
821 * computed for D during a previous deferred attribution round of the given kind.
822 */
823 class DeferredTypeMap extends Type.Mapping {
825 DeferredAttrContext deferredAttrContext;
827 protected DeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
828 super(String.format("deferredTypeMap[%s]", mode));
829 this.deferredAttrContext = new DeferredAttrContext(mode, msym, phase,
830 infer.emptyContext, emptyDeferredAttrContext, types.noWarnings);
831 }
833 @Override
834 public Type apply(Type t) {
835 if (!t.hasTag(DEFERRED)) {
836 return t.map(this);
837 } else {
838 DeferredType dt = (DeferredType)t;
839 return typeOf(dt);
840 }
841 }
843 protected Type typeOf(DeferredType dt) {
844 switch (deferredAttrContext.mode) {
845 case CHECK:
846 return dt.tree.type == null ? Type.noType : dt.tree.type;
847 case SPECULATIVE:
848 return dt.speculativeType(deferredAttrContext.msym, deferredAttrContext.phase);
849 }
850 Assert.error();
851 return null;
852 }
853 }
855 /**
856 * Specialized recovery deferred mapping.
857 * Each deferred type D is mapped into a type T, where T is computed either by
858 * (i) retrieving the type that has already been computed for D during a previous
859 * attribution round (as before), or (ii) by synthesizing a new type R for D
860 * (the latter step is useful in a recovery scenario).
861 */
862 public class RecoveryDeferredTypeMap extends DeferredTypeMap {
864 public RecoveryDeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
865 super(mode, msym, phase != null ? phase : MethodResolutionPhase.BOX);
866 }
868 @Override
869 protected Type typeOf(DeferredType dt) {
870 Type owntype = super.typeOf(dt);
871 return owntype == Type.noType ?
872 recover(dt) : owntype;
873 }
875 /**
876 * Synthesize a type for a deferred type that hasn't been previously
877 * reduced to an ordinary type. Functional deferred types and conditionals
878 * are mapped to themselves, in order to have a richer diagnostic
879 * representation. Remaining deferred types are attributed using
880 * a default expected type (j.l.Object).
881 */
882 private Type recover(DeferredType dt) {
883 dt.check(attr.new RecoveryInfo(deferredAttrContext) {
884 @Override
885 protected Type check(DiagnosticPosition pos, Type found) {
886 return chk.checkNonVoid(pos, super.check(pos, found));
887 }
888 });
889 return super.apply(dt);
890 }
891 }
893 /**
894 * A special tree scanner that would only visit portions of a given tree.
895 * The set of nodes visited by the scanner can be customized at construction-time.
896 */
897 abstract static class FilterScanner extends TreeScanner {
899 final Filter<JCTree> treeFilter;
901 FilterScanner(final Set<JCTree.Tag> validTags) {
902 this.treeFilter = new Filter<JCTree>() {
903 public boolean accepts(JCTree t) {
904 return validTags.contains(t.getTag());
905 }
906 };
907 }
909 @Override
910 public void scan(JCTree tree) {
911 if (tree != null) {
912 if (treeFilter.accepts(tree)) {
913 super.scan(tree);
914 } else {
915 skip(tree);
916 }
917 }
918 }
920 /**
921 * handler that is executed when a node has been discarded
922 */
923 void skip(JCTree tree) {}
924 }
926 /**
927 * A tree scanner suitable for visiting the target-type dependent nodes of
928 * a given argument expression.
929 */
930 static class PolyScanner extends FilterScanner {
932 PolyScanner() {
933 super(EnumSet.of(CONDEXPR, PARENS, LAMBDA, REFERENCE));
934 }
935 }
937 /**
938 * A tree scanner suitable for visiting the target-type dependent nodes nested
939 * within a lambda expression body.
940 */
941 static class LambdaReturnScanner extends FilterScanner {
943 LambdaReturnScanner() {
944 super(EnumSet.of(BLOCK, CASE, CATCH, DOLOOP, FOREACHLOOP,
945 FORLOOP, IF, RETURN, SYNCHRONIZED, SWITCH, TRY, WHILELOOP));
946 }
947 }
949 /**
950 * This visitor is used to check that structural expressions conform
951 * to their target - this step is required as inference could end up
952 * inferring types that make some of the nested expressions incompatible
953 * with their corresponding instantiated target
954 */
955 class CheckStuckPolicy extends PolyScanner implements DeferredStuckPolicy, Infer.FreeTypeListener {
957 Type pt;
958 Infer.InferenceContext inferenceContext;
959 Set<Type> stuckVars = new LinkedHashSet<Type>();
960 Set<Type> depVars = new LinkedHashSet<Type>();
962 @Override
963 public boolean isStuck() {
964 return !stuckVars.isEmpty();
965 }
967 @Override
968 public Set<Type> stuckVars() {
969 return stuckVars;
970 }
972 @Override
973 public Set<Type> depVars() {
974 return depVars;
975 }
977 public CheckStuckPolicy(ResultInfo resultInfo, DeferredType dt) {
978 this.pt = resultInfo.pt;
979 this.inferenceContext = resultInfo.checkContext.inferenceContext();
980 scan(dt.tree);
981 if (!stuckVars.isEmpty()) {
982 resultInfo.checkContext.inferenceContext()
983 .addFreeTypeListener(List.from(stuckVars), this);
984 }
985 }
987 @Override
988 public void typesInferred(InferenceContext inferenceContext) {
989 stuckVars.clear();
990 }
992 @Override
993 public void visitLambda(JCLambda tree) {
994 if (inferenceContext.inferenceVars().contains(pt)) {
995 stuckVars.add(pt);
996 }
997 if (!types.isFunctionalInterface(pt)) {
998 return;
999 }
1000 Type descType = types.findDescriptorType(pt);
1001 List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
1002 if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT &&
1003 freeArgVars.nonEmpty()) {
1004 stuckVars.addAll(freeArgVars);
1005 depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType()));
1006 }
1007 scanLambdaBody(tree, descType.getReturnType());
1008 }
1010 @Override
1011 public void visitReference(JCMemberReference tree) {
1012 scan(tree.expr);
1013 if (inferenceContext.inferenceVars().contains(pt)) {
1014 stuckVars.add(pt);
1015 return;
1016 }
1017 if (!types.isFunctionalInterface(pt)) {
1018 return;
1019 }
1021 Type descType = types.findDescriptorType(pt);
1022 List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
1023 if (freeArgVars.nonEmpty() &&
1024 tree.overloadKind == JCMemberReference.OverloadKind.OVERLOADED) {
1025 stuckVars.addAll(freeArgVars);
1026 depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType()));
1027 }
1028 }
1030 void scanLambdaBody(JCLambda lambda, final Type pt) {
1031 if (lambda.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) {
1032 Type prevPt = this.pt;
1033 try {
1034 this.pt = pt;
1035 scan(lambda.body);
1036 } finally {
1037 this.pt = prevPt;
1038 }
1039 } else {
1040 LambdaReturnScanner lambdaScanner = new LambdaReturnScanner() {
1041 @Override
1042 public void visitReturn(JCReturn tree) {
1043 if (tree.expr != null) {
1044 Type prevPt = CheckStuckPolicy.this.pt;
1045 try {
1046 CheckStuckPolicy.this.pt = pt;
1047 CheckStuckPolicy.this.scan(tree.expr);
1048 } finally {
1049 CheckStuckPolicy.this.pt = prevPt;
1050 }
1051 }
1052 }
1053 };
1054 lambdaScanner.scan(lambda.body);
1055 }
1056 }
1057 }
1059 /**
1060 * This visitor is used to check that structural expressions conform
1061 * to their target - this step is required as inference could end up
1062 * inferring types that make some of the nested expressions incompatible
1063 * with their corresponding instantiated target
1064 */
1065 class OverloadStuckPolicy extends CheckStuckPolicy implements DeferredStuckPolicy {
1067 boolean stuck;
1069 @Override
1070 public boolean isStuck() {
1071 return super.isStuck() || stuck;
1072 }
1074 public OverloadStuckPolicy(ResultInfo resultInfo, DeferredType dt) {
1075 super(resultInfo, dt);
1076 }
1078 @Override
1079 public void visitLambda(JCLambda tree) {
1080 super.visitLambda(tree);
1081 if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT) {
1082 stuck = true;
1083 }
1084 }
1086 @Override
1087 public void visitReference(JCMemberReference tree) {
1088 super.visitReference(tree);
1089 if (tree.overloadKind == JCMemberReference.OverloadKind.OVERLOADED) {
1090 stuck = true;
1091 }
1092 }
1093 }
1095 /**
1096 * Does the argument expression {@code expr} need speculative type-checking?
1097 */
1098 boolean isDeferred(Env<AttrContext> env, JCExpression expr) {
1099 DeferredChecker dc = new DeferredChecker(env);
1100 dc.scan(expr);
1101 return dc.result.isPoly();
1102 }
1104 /**
1105 * The kind of an argument expression. This is used by the analysis that
1106 * determines as to whether speculative attribution is necessary.
1107 */
1108 enum ArgumentExpressionKind {
1110 /** kind that denotes poly argument expression */
1111 POLY,
1112 /** kind that denotes a standalone expression */
1113 NO_POLY,
1114 /** kind that denotes a primitive/boxed standalone expression */
1115 PRIMITIVE;
1117 /**
1118 * Does this kind denote a poly argument expression
1119 */
1120 public final boolean isPoly() {
1121 return this == POLY;
1122 }
1124 /**
1125 * Does this kind denote a primitive standalone expression
1126 */
1127 public final boolean isPrimitive() {
1128 return this == PRIMITIVE;
1129 }
1131 /**
1132 * Compute the kind of a standalone expression of a given type
1133 */
1134 static ArgumentExpressionKind standaloneKind(Type type, Types types) {
1135 return types.unboxedTypeOrType(type).isPrimitive() ?
1136 ArgumentExpressionKind.PRIMITIVE :
1137 ArgumentExpressionKind.NO_POLY;
1138 }
1140 /**
1141 * Compute the kind of a method argument expression given its symbol
1142 */
1143 static ArgumentExpressionKind methodKind(Symbol sym, Types types) {
1144 Type restype = sym.type.getReturnType();
1145 if (sym.type.hasTag(FORALL) &&
1146 restype.containsAny(((ForAll)sym.type).tvars)) {
1147 return ArgumentExpressionKind.POLY;
1148 } else {
1149 return ArgumentExpressionKind.standaloneKind(restype, types);
1150 }
1151 }
1152 }
1154 /**
1155 * Tree scanner used for checking as to whether an argument expression
1156 * requires speculative attribution
1157 */
1158 final class DeferredChecker extends FilterScanner {
1160 Env<AttrContext> env;
1161 ArgumentExpressionKind result;
1163 public DeferredChecker(Env<AttrContext> env) {
1164 super(deferredCheckerTags);
1165 this.env = env;
1166 }
1168 @Override
1169 public void visitLambda(JCLambda tree) {
1170 //a lambda is always a poly expression
1171 result = ArgumentExpressionKind.POLY;
1172 }
1174 @Override
1175 public void visitReference(JCMemberReference tree) {
1176 //perform arity-based check
1177 Env<AttrContext> localEnv = env.dup(tree);
1178 JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv,
1179 attr.memberReferenceQualifierResult(tree));
1180 JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree);
1181 mref2.expr = exprTree;
1182 Symbol res =
1183 rs.getMemberReference(tree, localEnv, mref2,
1184 exprTree.type, tree.name);
1185 tree.sym = res;
1186 if (res.kind >= Kinds.ERRONEOUS ||
1187 res.type.hasTag(FORALL) ||
1188 (res.flags() & Flags.VARARGS) != 0 ||
1189 (TreeInfo.isStaticSelector(exprTree, tree.name.table.names) &&
1190 exprTree.type.isRaw())) {
1191 tree.overloadKind = JCMemberReference.OverloadKind.OVERLOADED;
1192 } else {
1193 tree.overloadKind = JCMemberReference.OverloadKind.UNOVERLOADED;
1194 }
1195 //a method reference is always a poly expression
1196 result = ArgumentExpressionKind.POLY;
1197 }
1199 @Override
1200 public void visitTypeCast(JCTypeCast tree) {
1201 //a cast is always a standalone expression
1202 result = ArgumentExpressionKind.NO_POLY;
1203 }
1205 @Override
1206 public void visitConditional(JCConditional tree) {
1207 scan(tree.truepart);
1208 if (!result.isPrimitive()) {
1209 result = ArgumentExpressionKind.POLY;
1210 return;
1211 }
1212 scan(tree.falsepart);
1213 result = reduce(ArgumentExpressionKind.PRIMITIVE);
1214 }
1216 @Override
1217 public void visitNewClass(JCNewClass tree) {
1218 result = (TreeInfo.isDiamond(tree) || attr.findDiamonds) ?
1219 ArgumentExpressionKind.POLY : ArgumentExpressionKind.NO_POLY;
1220 }
1222 @Override
1223 public void visitApply(JCMethodInvocation tree) {
1224 Name name = TreeInfo.name(tree.meth);
1226 //fast path
1227 if (tree.typeargs.nonEmpty() ||
1228 name == name.table.names._this ||
1229 name == name.table.names._super) {
1230 result = ArgumentExpressionKind.NO_POLY;
1231 return;
1232 }
1234 //slow path
1235 Symbol sym = quicklyResolveMethod(env, tree);
1237 if (sym == null) {
1238 result = ArgumentExpressionKind.POLY;
1239 return;
1240 }
1242 result = analyzeCandidateMethods(sym, ArgumentExpressionKind.PRIMITIVE,
1243 argumentKindAnalyzer);
1244 }
1245 //where
1246 private boolean isSimpleReceiver(JCTree rec) {
1247 switch (rec.getTag()) {
1248 case IDENT:
1249 return true;
1250 case SELECT:
1251 return isSimpleReceiver(((JCFieldAccess)rec).selected);
1252 case TYPEAPPLY:
1253 case TYPEARRAY:
1254 return true;
1255 case ANNOTATED_TYPE:
1256 return isSimpleReceiver(((JCAnnotatedType)rec).underlyingType);
1257 case APPLY:
1258 return true;
1259 case NEWCLASS:
1260 JCNewClass nc = (JCNewClass) rec;
1261 return nc.encl == null && nc.def == null && !TreeInfo.isDiamond(nc);
1262 default:
1263 return false;
1264 }
1265 }
1266 private ArgumentExpressionKind reduce(ArgumentExpressionKind kind) {
1267 return argumentKindAnalyzer.reduce(result, kind);
1268 }
1269 MethodAnalyzer<ArgumentExpressionKind> argumentKindAnalyzer =
1270 new MethodAnalyzer<ArgumentExpressionKind>() {
1271 @Override
1272 public ArgumentExpressionKind process(MethodSymbol ms) {
1273 return ArgumentExpressionKind.methodKind(ms, types);
1274 }
1275 @Override
1276 public ArgumentExpressionKind reduce(ArgumentExpressionKind kind1,
1277 ArgumentExpressionKind kind2) {
1278 switch (kind1) {
1279 case PRIMITIVE: return kind2;
1280 case NO_POLY: return kind2.isPoly() ? kind2 : kind1;
1281 case POLY: return kind1;
1282 default:
1283 Assert.error();
1284 return null;
1285 }
1286 }
1287 @Override
1288 public boolean shouldStop(ArgumentExpressionKind result) {
1289 return result.isPoly();
1290 }
1291 };
1293 @Override
1294 public void visitLiteral(JCLiteral tree) {
1295 Type litType = attr.litType(tree.typetag);
1296 result = ArgumentExpressionKind.standaloneKind(litType, types);
1297 }
1299 @Override
1300 void skip(JCTree tree) {
1301 result = ArgumentExpressionKind.NO_POLY;
1302 }
1304 private Symbol quicklyResolveMethod(Env<AttrContext> env, final JCMethodInvocation tree) {
1305 final JCExpression rec = tree.meth.hasTag(SELECT) ?
1306 ((JCFieldAccess)tree.meth).selected :
1307 null;
1309 if (rec != null && !isSimpleReceiver(rec)) {
1310 return null;
1311 }
1313 Type site;
1315 if (rec != null) {
1316 switch (rec.getTag()) {
1317 case APPLY:
1318 Symbol recSym = quicklyResolveMethod(env, (JCMethodInvocation) rec);
1319 if (recSym == null)
1320 return null;
1321 Symbol resolvedReturnType =
1322 analyzeCandidateMethods(recSym, syms.errSymbol, returnSymbolAnalyzer);
1323 if (resolvedReturnType == null)
1324 return null;
1325 site = resolvedReturnType.type;
1326 break;
1327 case NEWCLASS:
1328 JCNewClass nc = (JCNewClass) rec;
1329 site = attribSpeculative(nc.clazz, env, attr.unknownTypeExprInfo).type;
1330 break;
1331 default:
1332 site = attribSpeculative(rec, env, attr.unknownTypeExprInfo).type;
1333 break;
1334 }
1335 } else {
1336 site = env.enclClass.sym.type;
1337 }
1339 while (site.hasTag(TYPEVAR)) {
1340 site = site.getUpperBound();
1341 }
1343 site = types.capture(site);
1345 List<Type> args = rs.dummyArgs(tree.args.length());
1346 Name name = TreeInfo.name(tree.meth);
1348 Resolve.LookupHelper lh = rs.new LookupHelper(name, site, args, List.<Type>nil(), MethodResolutionPhase.VARARITY) {
1349 @Override
1350 Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
1351 return rec == null ?
1352 rs.findFun(env, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()) :
1353 rs.findMethod(env, site, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired(), false);
1354 }
1355 @Override
1356 Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
1357 return sym;
1358 }
1359 };
1361 return rs.lookupMethod(env, tree, site.tsym, rs.arityMethodCheck, lh);
1362 }
1363 //where:
1364 MethodAnalyzer<Symbol> returnSymbolAnalyzer = new MethodAnalyzer<Symbol>() {
1365 @Override
1366 public Symbol process(MethodSymbol ms) {
1367 ArgumentExpressionKind kind = ArgumentExpressionKind.methodKind(ms, types);
1368 if (kind == ArgumentExpressionKind.POLY || ms.getReturnType().hasTag(TYPEVAR))
1369 return null;
1370 return ms.getReturnType().tsym;
1371 }
1372 @Override
1373 public Symbol reduce(Symbol s1, Symbol s2) {
1374 return s1 == syms.errSymbol ? s2 : s1 == s2 ? s1 : null;
1375 }
1376 @Override
1377 public boolean shouldStop(Symbol result) {
1378 return result == null;
1379 }
1380 };
1382 /**
1383 * Process the result of Resolve.lookupMethod. If sym is a method symbol, the result of
1384 * MethodAnalyzer.process is returned. If sym is an ambiguous symbol, all the candidate
1385 * methods are inspected one by one, using MethodAnalyzer.process. The outcomes are
1386 * reduced using MethodAnalyzer.reduce (using defaultValue as the first value over which
1387 * the reduction runs). MethodAnalyzer.shouldStop can be used to stop the inspection early.
1388 */
1389 <E> E analyzeCandidateMethods(Symbol sym, E defaultValue, MethodAnalyzer<E> analyzer) {
1390 switch (sym.kind) {
1391 case Kinds.MTH:
1392 return analyzer.process((MethodSymbol) sym);
1393 case Kinds.AMBIGUOUS:
1394 Resolve.AmbiguityError err = (Resolve.AmbiguityError)sym.baseSymbol();
1395 E res = defaultValue;
1396 for (Symbol s : err.ambiguousSyms) {
1397 if (s.kind == Kinds.MTH) {
1398 res = analyzer.reduce(res, analyzer.process((MethodSymbol) s));
1399 if (analyzer.shouldStop(res))
1400 return res;
1401 }
1402 }
1403 return res;
1404 default:
1405 return defaultValue;
1406 }
1407 }
1408 }
1410 /** Analyzer for methods - used by analyzeCandidateMethods. */
1411 interface MethodAnalyzer<E> {
1412 E process(MethodSymbol ms);
1413 E reduce(E e1, E e2);
1414 boolean shouldStop(E result);
1415 }
1417 //where
1418 private EnumSet<JCTree.Tag> deferredCheckerTags =
1419 EnumSet.of(LAMBDA, REFERENCE, PARENS, TYPECAST,
1420 CONDEXPR, NEWCLASS, APPLY, LITERAL);
1421 }