35 import com.sun.tools.javac.comp.DeferredAttr.DeferredAttrContext; |
35 import com.sun.tools.javac.comp.DeferredAttr.DeferredAttrContext; |
36 import com.sun.tools.javac.comp.DeferredAttr.DeferredType; |
36 import com.sun.tools.javac.comp.DeferredAttr.DeferredType; |
37 import com.sun.tools.javac.comp.Infer.InferenceContext; |
37 import com.sun.tools.javac.comp.Infer.InferenceContext; |
38 import com.sun.tools.javac.comp.Infer.FreeTypeListener; |
38 import com.sun.tools.javac.comp.Infer.FreeTypeListener; |
39 import com.sun.tools.javac.comp.Resolve.MethodResolutionContext.Candidate; |
39 import com.sun.tools.javac.comp.Resolve.MethodResolutionContext.Candidate; |
|
40 import com.sun.tools.javac.comp.Resolve.MethodResolutionDiagHelper.DiagnosticRewriter; |
|
41 import com.sun.tools.javac.comp.Resolve.MethodResolutionDiagHelper.Template; |
40 import com.sun.tools.javac.jvm.*; |
42 import com.sun.tools.javac.jvm.*; |
|
43 import com.sun.tools.javac.main.Option; |
41 import com.sun.tools.javac.tree.*; |
44 import com.sun.tools.javac.tree.*; |
42 import com.sun.tools.javac.tree.JCTree.*; |
45 import com.sun.tools.javac.tree.JCTree.*; |
43 import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind; |
46 import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind; |
44 import com.sun.tools.javac.tree.JCTree.JCPolyExpression.*; |
47 import com.sun.tools.javac.tree.JCTree.JCPolyExpression.*; |
45 import com.sun.tools.javac.util.*; |
48 import com.sun.tools.javac.util.*; |
122 Source source = Source.instance(context); |
126 Source source = Source.instance(context); |
123 boxingEnabled = source.allowBoxing(); |
127 boxingEnabled = source.allowBoxing(); |
124 varargsEnabled = source.allowVarargs(); |
128 varargsEnabled = source.allowVarargs(); |
125 Options options = Options.instance(context); |
129 Options options = Options.instance(context); |
126 debugResolve = options.isSet("debugresolve"); |
130 debugResolve = options.isSet("debugresolve"); |
|
131 compactMethodDiags = options.isSet(Option.XDIAGS, "compact") || |
|
132 options.isUnset(Option.XDIAGS) && options.isUnset("rawDiagnostics"); |
127 verboseResolutionMode = VerboseResolutionMode.getVerboseResolutionMode(options); |
133 verboseResolutionMode = VerboseResolutionMode.getVerboseResolutionMode(options); |
128 Target target = Target.instance(context); |
134 Target target = Target.instance(context); |
129 allowMethodHandles = target.hasMethodHandles(); |
135 allowMethodHandles = target.hasMethodHandles(); |
130 allowDefaultMethods = source.allowDefaultMethods(); |
136 allowDefaultMethods = source.allowDefaultMethods(); |
131 allowStructuralMostSpecific = source.allowStructuralMostSpecific(); |
137 allowStructuralMostSpecific = source.allowStructuralMostSpecific(); |
689 List<Type> argtypes, |
699 List<Type> argtypes, |
690 List<Type> formals, |
700 List<Type> formals, |
691 Warner warn) { |
701 Warner warn) { |
692 //should we expand formals? |
702 //should we expand formals? |
693 boolean useVarargs = deferredAttrContext.phase.isVarargsRequired(); |
703 boolean useVarargs = deferredAttrContext.phase.isVarargsRequired(); |
|
704 List<JCExpression> trees = TreeInfo.args(env.tree); |
694 |
705 |
695 //inference context used during this method check |
706 //inference context used during this method check |
696 InferenceContext inferenceContext = deferredAttrContext.inferenceContext; |
707 InferenceContext inferenceContext = deferredAttrContext.inferenceContext; |
697 |
708 |
698 Type varargsFormal = useVarargs ? formals.last() : null; |
709 Type varargsFormal = useVarargs ? formals.last() : null; |
699 |
710 |
700 if (varargsFormal == null && |
711 if (varargsFormal == null && |
701 argtypes.size() != formals.size()) { |
712 argtypes.size() != formals.size()) { |
702 reportMC(MethodCheckDiag.ARITY_MISMATCH, inferenceContext); // not enough args |
713 reportMC(env.tree, MethodCheckDiag.ARITY_MISMATCH, inferenceContext); // not enough args |
703 } |
714 } |
704 |
715 |
705 while (argtypes.nonEmpty() && formals.head != varargsFormal) { |
716 while (argtypes.nonEmpty() && formals.head != varargsFormal) { |
706 checkArg(false, argtypes.head, formals.head, deferredAttrContext, warn); |
717 DiagnosticPosition pos = trees != null ? trees.head : null; |
|
718 checkArg(pos, false, argtypes.head, formals.head, deferredAttrContext, warn); |
707 argtypes = argtypes.tail; |
719 argtypes = argtypes.tail; |
708 formals = formals.tail; |
720 formals = formals.tail; |
|
721 trees = trees != null ? trees.tail : trees; |
709 } |
722 } |
710 |
723 |
711 if (formals.head != varargsFormal) { |
724 if (formals.head != varargsFormal) { |
712 reportMC(MethodCheckDiag.ARITY_MISMATCH, inferenceContext); // not enough args |
725 reportMC(env.tree, MethodCheckDiag.ARITY_MISMATCH, inferenceContext); // not enough args |
713 } |
726 } |
714 |
727 |
715 if (useVarargs) { |
728 if (useVarargs) { |
716 //note: if applicability check is triggered by most specific test, |
729 //note: if applicability check is triggered by most specific test, |
717 //the last argument of a varargs is _not_ an array type (see JLS 15.12.2.5) |
730 //the last argument of a varargs is _not_ an array type (see JLS 15.12.2.5) |
718 final Type elt = types.elemtype(varargsFormal); |
731 final Type elt = types.elemtype(varargsFormal); |
719 while (argtypes.nonEmpty()) { |
732 while (argtypes.nonEmpty()) { |
720 checkArg(true, argtypes.head, elt, deferredAttrContext, warn); |
733 DiagnosticPosition pos = trees != null ? trees.head : null; |
|
734 checkArg(pos, true, argtypes.head, elt, deferredAttrContext, warn); |
721 argtypes = argtypes.tail; |
735 argtypes = argtypes.tail; |
|
736 trees = trees != null ? trees.tail : trees; |
722 } |
737 } |
723 } |
738 } |
724 } |
739 } |
725 |
740 |
726 /** |
741 /** |
727 * Does the actual argument conforms to the corresponding formal? |
742 * Does the actual argument conforms to the corresponding formal? |
728 */ |
743 */ |
729 abstract void checkArg(boolean varargs, Type actual, Type formal, DeferredAttrContext deferredAttrContext, Warner warn); |
744 abstract void checkArg(DiagnosticPosition pos, boolean varargs, Type actual, Type formal, DeferredAttrContext deferredAttrContext, Warner warn); |
730 |
745 |
731 protected void reportMC(MethodCheckDiag diag, InferenceContext inferenceContext, Object... args) { |
746 protected void reportMC(DiagnosticPosition pos, MethodCheckDiag diag, InferenceContext inferenceContext, Object... args) { |
732 boolean inferDiag = inferenceContext != infer.emptyContext; |
747 boolean inferDiag = inferenceContext != infer.emptyContext; |
733 InapplicableMethodException ex = inferDiag ? |
748 InapplicableMethodException ex = inferDiag ? |
734 infer.inferenceException : inapplicableMethodException; |
749 infer.inferenceException : inapplicableMethodException; |
735 if (inferDiag && (!diag.inferKey.equals(diag.basicKey))) { |
750 if (inferDiag && (!diag.inferKey.equals(diag.basicKey))) { |
736 Object[] args2 = new Object[args.length + 1]; |
751 Object[] args2 = new Object[args.length + 1]; |
737 System.arraycopy(args, 0, args2, 1, args.length); |
752 System.arraycopy(args, 0, args2, 1, args.length); |
738 args2[0] = inferenceContext.inferenceVars(); |
753 args2[0] = inferenceContext.inferenceVars(); |
739 args = args2; |
754 args = args2; |
740 } |
755 } |
741 throw ex.setMessage(inferDiag ? diag.inferKey : diag.basicKey, args); |
756 String key = inferDiag ? diag.inferKey : diag.basicKey; |
|
757 throw ex.setMessage(diags.create(DiagnosticType.FRAGMENT, log.currentSource(), pos, key, args)); |
742 } |
758 } |
743 |
759 |
744 public MethodCheck mostSpecificCheck(List<Type> actuals, boolean strict) { |
760 public MethodCheck mostSpecificCheck(List<Type> actuals, boolean strict) { |
745 return nilMethodCheck; |
761 return nilMethodCheck; |
746 } |
762 } |
776 * A method check handler (see above) is used in order to report errors. |
792 * A method check handler (see above) is used in order to report errors. |
777 */ |
793 */ |
778 MethodCheck resolveMethodCheck = new AbstractMethodCheck() { |
794 MethodCheck resolveMethodCheck = new AbstractMethodCheck() { |
779 |
795 |
780 @Override |
796 @Override |
781 void checkArg(boolean varargs, Type actual, Type formal, DeferredAttrContext deferredAttrContext, Warner warn) { |
797 void checkArg(DiagnosticPosition pos, boolean varargs, Type actual, Type formal, DeferredAttrContext deferredAttrContext, Warner warn) { |
782 ResultInfo mresult = methodCheckResult(varargs, formal, deferredAttrContext, warn); |
798 ResultInfo mresult = methodCheckResult(varargs, formal, deferredAttrContext, warn); |
783 mresult.check(null, actual); |
799 mresult.check(pos, actual); |
784 } |
800 } |
785 |
801 |
786 @Override |
802 @Override |
787 public void argumentsAcceptable(final Env<AttrContext> env, |
803 public void argumentsAcceptable(final Env<AttrContext> env, |
788 DeferredAttrContext deferredAttrContext, |
804 DeferredAttrContext deferredAttrContext, |
3325 return diags.create(dkind, log.currentSource(), pos, |
3341 return diags.create(dkind, log.currentSource(), pos, |
3326 key, name, first, second); |
3342 key, name, first, second); |
3327 } |
3343 } |
3328 else { |
3344 else { |
3329 Candidate c = errCandidate(); |
3345 Candidate c = errCandidate(); |
|
3346 if (compactMethodDiags) { |
|
3347 for (Map.Entry<Template, DiagnosticRewriter> _entry : |
|
3348 MethodResolutionDiagHelper.rewriters.entrySet()) { |
|
3349 if (_entry.getKey().matches(c.details)) { |
|
3350 JCDiagnostic simpleDiag = |
|
3351 _entry.getValue().rewriteDiagnostic(diags, pos, |
|
3352 log.currentSource(), dkind, c.details); |
|
3353 simpleDiag.setFlag(DiagnosticFlag.COMPRESSED); |
|
3354 return simpleDiag; |
|
3355 } |
|
3356 } |
|
3357 } |
3330 Symbol ws = c.sym.asMemberOf(site, types); |
3358 Symbol ws = c.sym.asMemberOf(site, types); |
3331 return diags.create(dkind, log.currentSource(), pos, |
3359 return diags.create(dkind, log.currentSource(), pos, |
3332 "cant.apply.symbol", |
3360 "cant.apply.symbol", |
3333 kindName(ws), |
3361 kindName(ws), |
3334 ws.name == names.init ? ws.owner.name : ws.name, |
3362 ws.name == names.init ? ws.owner.name : ws.name, |
3373 Symbol location, |
3401 Symbol location, |
3374 Type site, |
3402 Type site, |
3375 Name name, |
3403 Name name, |
3376 List<Type> argtypes, |
3404 List<Type> argtypes, |
3377 List<Type> typeargtypes) { |
3405 List<Type> typeargtypes) { |
3378 if (!resolveContext.candidates.isEmpty()) { |
3406 Map<Symbol, JCDiagnostic> candidatesMap = mapCandidates(); |
|
3407 Map<Symbol, JCDiagnostic> filteredCandidates = filterCandidates(candidatesMap); |
|
3408 if (filteredCandidates.isEmpty()) { |
|
3409 filteredCandidates = candidatesMap; |
|
3410 } |
|
3411 boolean truncatedDiag = candidatesMap.size() != filteredCandidates.size(); |
|
3412 if (filteredCandidates.size() > 1) { |
3379 JCDiagnostic err = diags.create(dkind, |
3413 JCDiagnostic err = diags.create(dkind, |
|
3414 null, |
|
3415 truncatedDiag ? |
|
3416 EnumSet.of(DiagnosticFlag.COMPRESSED) : |
|
3417 EnumSet.noneOf(DiagnosticFlag.class), |
3380 log.currentSource(), |
3418 log.currentSource(), |
3381 pos, |
3419 pos, |
3382 "cant.apply.symbols", |
3420 "cant.apply.symbols", |
3383 name == names.init ? KindName.CONSTRUCTOR : absentKind(kind), |
3421 name == names.init ? KindName.CONSTRUCTOR : absentKind(kind), |
3384 name == names.init ? site.tsym.name : name, |
3422 name == names.init ? site.tsym.name : name, |
3385 methodArguments(argtypes)); |
3423 methodArguments(argtypes)); |
3386 return new JCDiagnostic.MultilineDiagnostic(err, candidateDetails(site)); |
3424 return new JCDiagnostic.MultilineDiagnostic(err, candidateDetails(filteredCandidates, site)); |
|
3425 } else if (filteredCandidates.size() == 1) { |
|
3426 JCDiagnostic d = new InapplicableSymbolError(resolveContext).getDiagnostic(dkind, pos, |
|
3427 location, site, name, argtypes, typeargtypes); |
|
3428 if (truncatedDiag) { |
|
3429 d.setFlag(DiagnosticFlag.COMPRESSED); |
|
3430 } |
|
3431 return d; |
3387 } else { |
3432 } else { |
3388 return new SymbolNotFoundError(ABSENT_MTH).getDiagnostic(dkind, pos, |
3433 return new SymbolNotFoundError(ABSENT_MTH).getDiagnostic(dkind, pos, |
3389 location, site, name, argtypes, typeargtypes); |
3434 location, site, name, argtypes, typeargtypes); |
3390 } |
3435 } |
3391 } |
3436 } |
3392 |
|
3393 //where |
3437 //where |
3394 List<JCDiagnostic> candidateDetails(Type site) { |
3438 private Map<Symbol, JCDiagnostic> mapCandidates() { |
3395 Map<Symbol, JCDiagnostic> details = new LinkedHashMap<Symbol, JCDiagnostic>(); |
3439 Map<Symbol, JCDiagnostic> candidates = new LinkedHashMap<Symbol, JCDiagnostic>(); |
3396 for (Candidate c : resolveContext.candidates) { |
3440 for (Candidate c : resolveContext.candidates) { |
3397 if (c.isApplicable()) continue; |
3441 if (c.isApplicable()) continue; |
3398 JCDiagnostic detailDiag = diags.fragment("inapplicable.method", |
3442 candidates.put(c.sym, c.details); |
3399 Kinds.kindName(c.sym), |
3443 } |
3400 c.sym.location(site, types), |
3444 return candidates; |
3401 c.sym.asMemberOf(site, types), |
3445 } |
3402 c.details); |
3446 |
3403 details.put(c.sym, detailDiag); |
3447 Map<Symbol, JCDiagnostic> filterCandidates(Map<Symbol, JCDiagnostic> candidatesMap) { |
3404 } |
3448 Map<Symbol, JCDiagnostic> candidates = new LinkedHashMap<Symbol, JCDiagnostic>(); |
3405 return List.from(details.values()); |
3449 for (Map.Entry<Symbol, JCDiagnostic> _entry : candidatesMap.entrySet()) { |
3406 } |
3450 JCDiagnostic d = _entry.getValue(); |
|
3451 if (!compactMethodDiags || |
|
3452 !new Template(MethodCheckDiag.ARITY_MISMATCH.regex()).matches(d)) { |
|
3453 candidates.put(_entry.getKey(), d); |
|
3454 } |
|
3455 } |
|
3456 return candidates; |
|
3457 } |
|
3458 |
|
3459 private List<JCDiagnostic> candidateDetails(Map<Symbol, JCDiagnostic> candidatesMap, Type site) { |
|
3460 List<JCDiagnostic> details = List.nil(); |
|
3461 for (Map.Entry<Symbol, JCDiagnostic> _entry : candidatesMap.entrySet()) { |
|
3462 Symbol sym = _entry.getKey(); |
|
3463 JCDiagnostic detailDiag = diags.fragment("inapplicable.method", |
|
3464 Kinds.kindName(sym), |
|
3465 sym.location(site, types), |
|
3466 sym.asMemberOf(site, types), |
|
3467 _entry.getValue()); |
|
3468 details = details.prepend(detailDiag); |
|
3469 } |
|
3470 //typically members are visited in reverse order (see Scope) |
|
3471 //so we need to reverse the candidate list so that candidates |
|
3472 //conform to source order |
|
3473 return details; |
|
3474 } |
3407 } |
3475 } |
3408 |
3476 |
3409 /** |
3477 /** |
3410 * An InvalidSymbolError error class indicating that a symbol is not |
3478 * An InvalidSymbolError error class indicating that a symbol is not |
3411 * accessible from a given site |
3479 * accessible from a given site |
3622 JCDiagnostic getDiagnostic(DiagnosticType dkind, DiagnosticPosition pos, Symbol location, Type site, Name name, List<Type> argtypes, List<Type> typeargtypes) { |
3690 JCDiagnostic getDiagnostic(DiagnosticType dkind, DiagnosticPosition pos, Symbol location, Type site, Name name, List<Type> argtypes, List<Type> typeargtypes) { |
3623 return delegatedError.getDiagnostic(dkind, pos, location, site, name, argtypes, typeargtypes); |
3691 return delegatedError.getDiagnostic(dkind, pos, location, site, name, argtypes, typeargtypes); |
3624 } |
3692 } |
3625 } |
3693 } |
3626 |
3694 |
|
3695 /** |
|
3696 * Helper class for method resolution diagnostic simplification. |
|
3697 * Certain resolution diagnostic are rewritten as simpler diagnostic |
|
3698 * where the enclosing resolution diagnostic (i.e. 'inapplicable method') |
|
3699 * is stripped away, as it doesn't carry additional info. The logic |
|
3700 * for matching a given diagnostic is given in terms of a template |
|
3701 * hierarchy: a diagnostic template can be specified programmatically, |
|
3702 * so that only certain diagnostics are matched. Each templete is then |
|
3703 * associated with a rewriter object that carries out the task of rewtiting |
|
3704 * the diagnostic to a simpler one. |
|
3705 */ |
|
3706 static class MethodResolutionDiagHelper { |
|
3707 |
|
3708 /** |
|
3709 * A diagnostic rewriter transforms a method resolution diagnostic |
|
3710 * into a simpler one |
|
3711 */ |
|
3712 interface DiagnosticRewriter { |
|
3713 JCDiagnostic rewriteDiagnostic(JCDiagnostic.Factory diags, |
|
3714 DiagnosticPosition preferedPos, DiagnosticSource preferredSource, |
|
3715 DiagnosticType preferredKind, JCDiagnostic d); |
|
3716 } |
|
3717 |
|
3718 /** |
|
3719 * A diagnostic template is made up of two ingredients: (i) a regular |
|
3720 * expression for matching a diagnostic key and (ii) a list of sub-templates |
|
3721 * for matching diagnostic arguments. |
|
3722 */ |
|
3723 static class Template { |
|
3724 |
|
3725 /** regex used to match diag key */ |
|
3726 String regex; |
|
3727 |
|
3728 /** templates used to match diagnostic args */ |
|
3729 Template[] subTemplates; |
|
3730 |
|
3731 Template(String key, Template... subTemplates) { |
|
3732 this.regex = key; |
|
3733 this.subTemplates = subTemplates; |
|
3734 } |
|
3735 |
|
3736 /** |
|
3737 * Returns true if the regex matches the diagnostic key and if |
|
3738 * all diagnostic arguments are matches by corresponding sub-templates. |
|
3739 */ |
|
3740 boolean matches(Object o) { |
|
3741 JCDiagnostic d = (JCDiagnostic)o; |
|
3742 Object[] args = d.getArgs(); |
|
3743 if (!d.getCode().matches(regex) || |
|
3744 subTemplates.length != d.getArgs().length) { |
|
3745 return false; |
|
3746 } |
|
3747 for (int i = 0; i < args.length ; i++) { |
|
3748 if (!subTemplates[i].matches(args[i])) { |
|
3749 return false; |
|
3750 } |
|
3751 } |
|
3752 return true; |
|
3753 } |
|
3754 } |
|
3755 |
|
3756 /** a dummy template that match any diagnostic argument */ |
|
3757 static final Template skip = new Template("") { |
|
3758 @Override |
|
3759 boolean matches(Object d) { |
|
3760 return true; |
|
3761 } |
|
3762 }; |
|
3763 |
|
3764 /** rewriter map used for method resolution simplification */ |
|
3765 static final Map<Template, DiagnosticRewriter> rewriters = |
|
3766 new LinkedHashMap<Template, DiagnosticRewriter>(); |
|
3767 |
|
3768 static { |
|
3769 String argMismatchRegex = MethodCheckDiag.ARG_MISMATCH.regex(); |
|
3770 rewriters.put(new Template(argMismatchRegex, new Template("(.*)(bad.arg.types.in.lambda)", skip, skip)), |
|
3771 new DiagnosticRewriter() { |
|
3772 @Override |
|
3773 public JCDiagnostic rewriteDiagnostic(JCDiagnostic.Factory diags, |
|
3774 DiagnosticPosition preferedPos, DiagnosticSource preferredSource, |
|
3775 DiagnosticType preferredKind, JCDiagnostic d) { |
|
3776 return (JCDiagnostic)((JCDiagnostic)d.getArgs()[0]).getArgs()[1]; |
|
3777 } |
|
3778 }); |
|
3779 |
|
3780 rewriters.put(new Template(argMismatchRegex, skip), |
|
3781 new DiagnosticRewriter() { |
|
3782 @Override |
|
3783 public JCDiagnostic rewriteDiagnostic(JCDiagnostic.Factory diags, |
|
3784 DiagnosticPosition preferedPos, DiagnosticSource preferredSource, |
|
3785 DiagnosticType preferredKind, JCDiagnostic d) { |
|
3786 JCDiagnostic cause = (JCDiagnostic)d.getArgs()[0]; |
|
3787 return diags.create(preferredKind, preferredSource, d.getDiagnosticPosition(), |
|
3788 "prob.found.req", cause); |
|
3789 } |
|
3790 }); |
|
3791 } |
|
3792 } |
|
3793 |
3627 enum MethodResolutionPhase { |
3794 enum MethodResolutionPhase { |
3628 BASIC(false, false), |
3795 BASIC(false, false), |
3629 BOX(true, false), |
3796 BOX(true, false), |
3630 VARARITY(true, true) { |
3797 VARARITY(true, true) { |
3631 @Override |
3798 @Override |