mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 11:04:34 +02:00
8012003: Method diagnostics resolution need to be simplified in some cases
Unfold method resolution diagnostics when they mention errors in poly expressions Reviewed-by: jjg, vromero
This commit is contained in:
parent
892414e73c
commit
ec458693f7
20 changed files with 419 additions and 36 deletions
|
@ -2391,7 +2391,8 @@ public class Attr extends JCTree.Visitor {
|
||||||
for (JCDiagnostic deferredDiag : lambdaDeferredHandler.getDiagnostics()) {
|
for (JCDiagnostic deferredDiag : lambdaDeferredHandler.getDiagnostics()) {
|
||||||
if (deferredDiag.getKind() == JCDiagnostic.Kind.ERROR) {
|
if (deferredDiag.getKind() == JCDiagnostic.Kind.ERROR) {
|
||||||
resultInfo.checkContext
|
resultInfo.checkContext
|
||||||
.report(that, diags.fragment("bad.arg.types.in.lambda", TreeInfo.types(that.params)));
|
.report(that, diags.fragment("bad.arg.types.in.lambda", TreeInfo.types(that.params),
|
||||||
|
deferredDiag)); //hidden diag parameter
|
||||||
//we mark the lambda as erroneous - this is crucial in the recovery step
|
//we mark the lambda as erroneous - this is crucial in the recovery step
|
||||||
//as parameter-dependent type error won't be reported in that stage,
|
//as parameter-dependent type error won't be reported in that stage,
|
||||||
//meaning that a lambda will be deemed erroeneous only if there is
|
//meaning that a lambda will be deemed erroeneous only if there is
|
||||||
|
|
|
@ -37,7 +37,10 @@ import com.sun.tools.javac.comp.DeferredAttr.DeferredType;
|
||||||
import com.sun.tools.javac.comp.Infer.InferenceContext;
|
import com.sun.tools.javac.comp.Infer.InferenceContext;
|
||||||
import com.sun.tools.javac.comp.Infer.FreeTypeListener;
|
import com.sun.tools.javac.comp.Infer.FreeTypeListener;
|
||||||
import com.sun.tools.javac.comp.Resolve.MethodResolutionContext.Candidate;
|
import com.sun.tools.javac.comp.Resolve.MethodResolutionContext.Candidate;
|
||||||
|
import com.sun.tools.javac.comp.Resolve.MethodResolutionDiagHelper.DiagnosticRewriter;
|
||||||
|
import com.sun.tools.javac.comp.Resolve.MethodResolutionDiagHelper.Template;
|
||||||
import com.sun.tools.javac.jvm.*;
|
import com.sun.tools.javac.jvm.*;
|
||||||
|
import com.sun.tools.javac.main.Option;
|
||||||
import com.sun.tools.javac.tree.*;
|
import com.sun.tools.javac.tree.*;
|
||||||
import com.sun.tools.javac.tree.JCTree.*;
|
import com.sun.tools.javac.tree.JCTree.*;
|
||||||
import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind;
|
import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind;
|
||||||
|
@ -94,6 +97,7 @@ public class Resolve {
|
||||||
public final boolean allowDefaultMethods;
|
public final boolean allowDefaultMethods;
|
||||||
public final boolean allowStructuralMostSpecific;
|
public final boolean allowStructuralMostSpecific;
|
||||||
private final boolean debugResolve;
|
private final boolean debugResolve;
|
||||||
|
private final boolean compactMethodDiags;
|
||||||
final EnumSet<VerboseResolutionMode> verboseResolutionMode;
|
final EnumSet<VerboseResolutionMode> verboseResolutionMode;
|
||||||
|
|
||||||
Scope polymorphicSignatureScope;
|
Scope polymorphicSignatureScope;
|
||||||
|
@ -124,6 +128,8 @@ public class Resolve {
|
||||||
varargsEnabled = source.allowVarargs();
|
varargsEnabled = source.allowVarargs();
|
||||||
Options options = Options.instance(context);
|
Options options = Options.instance(context);
|
||||||
debugResolve = options.isSet("debugresolve");
|
debugResolve = options.isSet("debugresolve");
|
||||||
|
compactMethodDiags = options.isSet(Option.XDIAGS, "compact") ||
|
||||||
|
options.isUnset(Option.XDIAGS) && options.isUnset("rawDiagnostics");
|
||||||
verboseResolutionMode = VerboseResolutionMode.getVerboseResolutionMode(options);
|
verboseResolutionMode = VerboseResolutionMode.getVerboseResolutionMode(options);
|
||||||
Target target = Target.instance(context);
|
Target target = Target.instance(context);
|
||||||
allowMethodHandles = target.hasMethodHandles();
|
allowMethodHandles = target.hasMethodHandles();
|
||||||
|
@ -661,6 +667,10 @@ public class Resolve {
|
||||||
this.basicKey = basicKey;
|
this.basicKey = basicKey;
|
||||||
this.inferKey = inferKey;
|
this.inferKey = inferKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String regex() {
|
||||||
|
return String.format("([a-z]*\\.)*(%s|%s)", basicKey, inferKey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -691,6 +701,7 @@ public class Resolve {
|
||||||
Warner warn) {
|
Warner warn) {
|
||||||
//should we expand formals?
|
//should we expand formals?
|
||||||
boolean useVarargs = deferredAttrContext.phase.isVarargsRequired();
|
boolean useVarargs = deferredAttrContext.phase.isVarargsRequired();
|
||||||
|
List<JCExpression> trees = TreeInfo.args(env.tree);
|
||||||
|
|
||||||
//inference context used during this method check
|
//inference context used during this method check
|
||||||
InferenceContext inferenceContext = deferredAttrContext.inferenceContext;
|
InferenceContext inferenceContext = deferredAttrContext.inferenceContext;
|
||||||
|
@ -699,17 +710,19 @@ public class Resolve {
|
||||||
|
|
||||||
if (varargsFormal == null &&
|
if (varargsFormal == null &&
|
||||||
argtypes.size() != formals.size()) {
|
argtypes.size() != formals.size()) {
|
||||||
reportMC(MethodCheckDiag.ARITY_MISMATCH, inferenceContext); // not enough args
|
reportMC(env.tree, MethodCheckDiag.ARITY_MISMATCH, inferenceContext); // not enough args
|
||||||
}
|
}
|
||||||
|
|
||||||
while (argtypes.nonEmpty() && formals.head != varargsFormal) {
|
while (argtypes.nonEmpty() && formals.head != varargsFormal) {
|
||||||
checkArg(false, argtypes.head, formals.head, deferredAttrContext, warn);
|
DiagnosticPosition pos = trees != null ? trees.head : null;
|
||||||
|
checkArg(pos, false, argtypes.head, formals.head, deferredAttrContext, warn);
|
||||||
argtypes = argtypes.tail;
|
argtypes = argtypes.tail;
|
||||||
formals = formals.tail;
|
formals = formals.tail;
|
||||||
|
trees = trees != null ? trees.tail : trees;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (formals.head != varargsFormal) {
|
if (formals.head != varargsFormal) {
|
||||||
reportMC(MethodCheckDiag.ARITY_MISMATCH, inferenceContext); // not enough args
|
reportMC(env.tree, MethodCheckDiag.ARITY_MISMATCH, inferenceContext); // not enough args
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useVarargs) {
|
if (useVarargs) {
|
||||||
|
@ -717,8 +730,10 @@ public class Resolve {
|
||||||
//the last argument of a varargs is _not_ an array type (see JLS 15.12.2.5)
|
//the last argument of a varargs is _not_ an array type (see JLS 15.12.2.5)
|
||||||
final Type elt = types.elemtype(varargsFormal);
|
final Type elt = types.elemtype(varargsFormal);
|
||||||
while (argtypes.nonEmpty()) {
|
while (argtypes.nonEmpty()) {
|
||||||
checkArg(true, argtypes.head, elt, deferredAttrContext, warn);
|
DiagnosticPosition pos = trees != null ? trees.head : null;
|
||||||
|
checkArg(pos, true, argtypes.head, elt, deferredAttrContext, warn);
|
||||||
argtypes = argtypes.tail;
|
argtypes = argtypes.tail;
|
||||||
|
trees = trees != null ? trees.tail : trees;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -726,9 +741,9 @@ public class Resolve {
|
||||||
/**
|
/**
|
||||||
* Does the actual argument conforms to the corresponding formal?
|
* Does the actual argument conforms to the corresponding formal?
|
||||||
*/
|
*/
|
||||||
abstract void checkArg(boolean varargs, Type actual, Type formal, DeferredAttrContext deferredAttrContext, Warner warn);
|
abstract void checkArg(DiagnosticPosition pos, boolean varargs, Type actual, Type formal, DeferredAttrContext deferredAttrContext, Warner warn);
|
||||||
|
|
||||||
protected void reportMC(MethodCheckDiag diag, InferenceContext inferenceContext, Object... args) {
|
protected void reportMC(DiagnosticPosition pos, MethodCheckDiag diag, InferenceContext inferenceContext, Object... args) {
|
||||||
boolean inferDiag = inferenceContext != infer.emptyContext;
|
boolean inferDiag = inferenceContext != infer.emptyContext;
|
||||||
InapplicableMethodException ex = inferDiag ?
|
InapplicableMethodException ex = inferDiag ?
|
||||||
infer.inferenceException : inapplicableMethodException;
|
infer.inferenceException : inapplicableMethodException;
|
||||||
|
@ -738,7 +753,8 @@ public class Resolve {
|
||||||
args2[0] = inferenceContext.inferenceVars();
|
args2[0] = inferenceContext.inferenceVars();
|
||||||
args = args2;
|
args = args2;
|
||||||
}
|
}
|
||||||
throw ex.setMessage(inferDiag ? diag.inferKey : diag.basicKey, args);
|
String key = inferDiag ? diag.inferKey : diag.basicKey;
|
||||||
|
throw ex.setMessage(diags.create(DiagnosticType.FRAGMENT, log.currentSource(), pos, key, args));
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodCheck mostSpecificCheck(List<Type> actuals, boolean strict) {
|
public MethodCheck mostSpecificCheck(List<Type> actuals, boolean strict) {
|
||||||
|
@ -752,7 +768,7 @@ public class Resolve {
|
||||||
*/
|
*/
|
||||||
MethodCheck arityMethodCheck = new AbstractMethodCheck() {
|
MethodCheck arityMethodCheck = new AbstractMethodCheck() {
|
||||||
@Override
|
@Override
|
||||||
void checkArg(boolean varargs, Type actual, Type formal, DeferredAttrContext deferredAttrContext, Warner warn) {
|
void checkArg(DiagnosticPosition pos, boolean varargs, Type actual, Type formal, DeferredAttrContext deferredAttrContext, Warner warn) {
|
||||||
//do nothing - actual always compatible to formals
|
//do nothing - actual always compatible to formals
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -778,9 +794,9 @@ public class Resolve {
|
||||||
MethodCheck resolveMethodCheck = new AbstractMethodCheck() {
|
MethodCheck resolveMethodCheck = new AbstractMethodCheck() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void checkArg(boolean varargs, Type actual, Type formal, DeferredAttrContext deferredAttrContext, Warner warn) {
|
void checkArg(DiagnosticPosition pos, boolean varargs, Type actual, Type formal, DeferredAttrContext deferredAttrContext, Warner warn) {
|
||||||
ResultInfo mresult = methodCheckResult(varargs, formal, deferredAttrContext, warn);
|
ResultInfo mresult = methodCheckResult(varargs, formal, deferredAttrContext, warn);
|
||||||
mresult.check(null, actual);
|
mresult.check(pos, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -809,7 +825,7 @@ public class Resolve {
|
||||||
} else {
|
} else {
|
||||||
if (!isAccessible(env, t)) {
|
if (!isAccessible(env, t)) {
|
||||||
Symbol location = env.enclClass.sym;
|
Symbol location = env.enclClass.sym;
|
||||||
reportMC(MethodCheckDiag.INACCESSIBLE_VARARGS, inferenceContext, t, Kinds.kindName(location), location);
|
reportMC(env.tree, MethodCheckDiag.INACCESSIBLE_VARARGS, inferenceContext, t, Kinds.kindName(location), location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -822,7 +838,7 @@ public class Resolve {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void report(DiagnosticPosition pos, JCDiagnostic details) {
|
public void report(DiagnosticPosition pos, JCDiagnostic details) {
|
||||||
reportMC(methodDiag, deferredAttrContext.inferenceContext, details);
|
reportMC(pos, methodDiag, deferredAttrContext.inferenceContext, details);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return new MethodResultInfo(to, checkContext);
|
return new MethodResultInfo(to, checkContext);
|
||||||
|
@ -3327,6 +3343,18 @@ public class Resolve {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Candidate c = errCandidate();
|
Candidate c = errCandidate();
|
||||||
|
if (compactMethodDiags) {
|
||||||
|
for (Map.Entry<Template, DiagnosticRewriter> _entry :
|
||||||
|
MethodResolutionDiagHelper.rewriters.entrySet()) {
|
||||||
|
if (_entry.getKey().matches(c.details)) {
|
||||||
|
JCDiagnostic simpleDiag =
|
||||||
|
_entry.getValue().rewriteDiagnostic(diags, pos,
|
||||||
|
log.currentSource(), dkind, c.details);
|
||||||
|
simpleDiag.setFlag(DiagnosticFlag.COMPRESSED);
|
||||||
|
return simpleDiag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Symbol ws = c.sym.asMemberOf(site, types);
|
Symbol ws = c.sym.asMemberOf(site, types);
|
||||||
return diags.create(dkind, log.currentSource(), pos,
|
return diags.create(dkind, log.currentSource(), pos,
|
||||||
"cant.apply.symbol",
|
"cant.apply.symbol",
|
||||||
|
@ -3375,34 +3403,74 @@ public class Resolve {
|
||||||
Name name,
|
Name name,
|
||||||
List<Type> argtypes,
|
List<Type> argtypes,
|
||||||
List<Type> typeargtypes) {
|
List<Type> typeargtypes) {
|
||||||
if (!resolveContext.candidates.isEmpty()) {
|
Map<Symbol, JCDiagnostic> candidatesMap = mapCandidates();
|
||||||
|
Map<Symbol, JCDiagnostic> filteredCandidates = filterCandidates(candidatesMap);
|
||||||
|
if (filteredCandidates.isEmpty()) {
|
||||||
|
filteredCandidates = candidatesMap;
|
||||||
|
}
|
||||||
|
boolean truncatedDiag = candidatesMap.size() != filteredCandidates.size();
|
||||||
|
if (filteredCandidates.size() > 1) {
|
||||||
JCDiagnostic err = diags.create(dkind,
|
JCDiagnostic err = diags.create(dkind,
|
||||||
|
null,
|
||||||
|
truncatedDiag ?
|
||||||
|
EnumSet.of(DiagnosticFlag.COMPRESSED) :
|
||||||
|
EnumSet.noneOf(DiagnosticFlag.class),
|
||||||
log.currentSource(),
|
log.currentSource(),
|
||||||
pos,
|
pos,
|
||||||
"cant.apply.symbols",
|
"cant.apply.symbols",
|
||||||
name == names.init ? KindName.CONSTRUCTOR : absentKind(kind),
|
name == names.init ? KindName.CONSTRUCTOR : absentKind(kind),
|
||||||
name == names.init ? site.tsym.name : name,
|
name == names.init ? site.tsym.name : name,
|
||||||
methodArguments(argtypes));
|
methodArguments(argtypes));
|
||||||
return new JCDiagnostic.MultilineDiagnostic(err, candidateDetails(site));
|
return new JCDiagnostic.MultilineDiagnostic(err, candidateDetails(filteredCandidates, site));
|
||||||
|
} else if (filteredCandidates.size() == 1) {
|
||||||
|
JCDiagnostic d = new InapplicableSymbolError(resolveContext).getDiagnostic(dkind, pos,
|
||||||
|
location, site, name, argtypes, typeargtypes);
|
||||||
|
if (truncatedDiag) {
|
||||||
|
d.setFlag(DiagnosticFlag.COMPRESSED);
|
||||||
|
}
|
||||||
|
return d;
|
||||||
} else {
|
} else {
|
||||||
return new SymbolNotFoundError(ABSENT_MTH).getDiagnostic(dkind, pos,
|
return new SymbolNotFoundError(ABSENT_MTH).getDiagnostic(dkind, pos,
|
||||||
location, site, name, argtypes, typeargtypes);
|
location, site, name, argtypes, typeargtypes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//where
|
//where
|
||||||
List<JCDiagnostic> candidateDetails(Type site) {
|
private Map<Symbol, JCDiagnostic> mapCandidates() {
|
||||||
Map<Symbol, JCDiagnostic> details = new LinkedHashMap<Symbol, JCDiagnostic>();
|
Map<Symbol, JCDiagnostic> candidates = new LinkedHashMap<Symbol, JCDiagnostic>();
|
||||||
for (Candidate c : resolveContext.candidates) {
|
for (Candidate c : resolveContext.candidates) {
|
||||||
if (c.isApplicable()) continue;
|
if (c.isApplicable()) continue;
|
||||||
JCDiagnostic detailDiag = diags.fragment("inapplicable.method",
|
candidates.put(c.sym, c.details);
|
||||||
Kinds.kindName(c.sym),
|
|
||||||
c.sym.location(site, types),
|
|
||||||
c.sym.asMemberOf(site, types),
|
|
||||||
c.details);
|
|
||||||
details.put(c.sym, detailDiag);
|
|
||||||
}
|
}
|
||||||
return List.from(details.values());
|
return candidates;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Symbol, JCDiagnostic> filterCandidates(Map<Symbol, JCDiagnostic> candidatesMap) {
|
||||||
|
Map<Symbol, JCDiagnostic> candidates = new LinkedHashMap<Symbol, JCDiagnostic>();
|
||||||
|
for (Map.Entry<Symbol, JCDiagnostic> _entry : candidatesMap.entrySet()) {
|
||||||
|
JCDiagnostic d = _entry.getValue();
|
||||||
|
if (!compactMethodDiags ||
|
||||||
|
!new Template(MethodCheckDiag.ARITY_MISMATCH.regex()).matches(d)) {
|
||||||
|
candidates.put(_entry.getKey(), d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return candidates;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<JCDiagnostic> candidateDetails(Map<Symbol, JCDiagnostic> candidatesMap, Type site) {
|
||||||
|
List<JCDiagnostic> details = List.nil();
|
||||||
|
for (Map.Entry<Symbol, JCDiagnostic> _entry : candidatesMap.entrySet()) {
|
||||||
|
Symbol sym = _entry.getKey();
|
||||||
|
JCDiagnostic detailDiag = diags.fragment("inapplicable.method",
|
||||||
|
Kinds.kindName(sym),
|
||||||
|
sym.location(site, types),
|
||||||
|
sym.asMemberOf(site, types),
|
||||||
|
_entry.getValue());
|
||||||
|
details = details.prepend(detailDiag);
|
||||||
|
}
|
||||||
|
//typically members are visited in reverse order (see Scope)
|
||||||
|
//so we need to reverse the candidate list so that candidates
|
||||||
|
//conform to source order
|
||||||
|
return details;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3624,6 +3692,105 @@ public class Resolve {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class for method resolution diagnostic simplification.
|
||||||
|
* Certain resolution diagnostic are rewritten as simpler diagnostic
|
||||||
|
* where the enclosing resolution diagnostic (i.e. 'inapplicable method')
|
||||||
|
* is stripped away, as it doesn't carry additional info. The logic
|
||||||
|
* for matching a given diagnostic is given in terms of a template
|
||||||
|
* hierarchy: a diagnostic template can be specified programmatically,
|
||||||
|
* so that only certain diagnostics are matched. Each templete is then
|
||||||
|
* associated with a rewriter object that carries out the task of rewtiting
|
||||||
|
* the diagnostic to a simpler one.
|
||||||
|
*/
|
||||||
|
static class MethodResolutionDiagHelper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A diagnostic rewriter transforms a method resolution diagnostic
|
||||||
|
* into a simpler one
|
||||||
|
*/
|
||||||
|
interface DiagnosticRewriter {
|
||||||
|
JCDiagnostic rewriteDiagnostic(JCDiagnostic.Factory diags,
|
||||||
|
DiagnosticPosition preferedPos, DiagnosticSource preferredSource,
|
||||||
|
DiagnosticType preferredKind, JCDiagnostic d);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A diagnostic template is made up of two ingredients: (i) a regular
|
||||||
|
* expression for matching a diagnostic key and (ii) a list of sub-templates
|
||||||
|
* for matching diagnostic arguments.
|
||||||
|
*/
|
||||||
|
static class Template {
|
||||||
|
|
||||||
|
/** regex used to match diag key */
|
||||||
|
String regex;
|
||||||
|
|
||||||
|
/** templates used to match diagnostic args */
|
||||||
|
Template[] subTemplates;
|
||||||
|
|
||||||
|
Template(String key, Template... subTemplates) {
|
||||||
|
this.regex = key;
|
||||||
|
this.subTemplates = subTemplates;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the regex matches the diagnostic key and if
|
||||||
|
* all diagnostic arguments are matches by corresponding sub-templates.
|
||||||
|
*/
|
||||||
|
boolean matches(Object o) {
|
||||||
|
JCDiagnostic d = (JCDiagnostic)o;
|
||||||
|
Object[] args = d.getArgs();
|
||||||
|
if (!d.getCode().matches(regex) ||
|
||||||
|
subTemplates.length != d.getArgs().length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < args.length ; i++) {
|
||||||
|
if (!subTemplates[i].matches(args[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** a dummy template that match any diagnostic argument */
|
||||||
|
static final Template skip = new Template("") {
|
||||||
|
@Override
|
||||||
|
boolean matches(Object d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** rewriter map used for method resolution simplification */
|
||||||
|
static final Map<Template, DiagnosticRewriter> rewriters =
|
||||||
|
new LinkedHashMap<Template, DiagnosticRewriter>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
String argMismatchRegex = MethodCheckDiag.ARG_MISMATCH.regex();
|
||||||
|
rewriters.put(new Template(argMismatchRegex, new Template("(.*)(bad.arg.types.in.lambda)", skip, skip)),
|
||||||
|
new DiagnosticRewriter() {
|
||||||
|
@Override
|
||||||
|
public JCDiagnostic rewriteDiagnostic(JCDiagnostic.Factory diags,
|
||||||
|
DiagnosticPosition preferedPos, DiagnosticSource preferredSource,
|
||||||
|
DiagnosticType preferredKind, JCDiagnostic d) {
|
||||||
|
return (JCDiagnostic)((JCDiagnostic)d.getArgs()[0]).getArgs()[1];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
rewriters.put(new Template(argMismatchRegex, skip),
|
||||||
|
new DiagnosticRewriter() {
|
||||||
|
@Override
|
||||||
|
public JCDiagnostic rewriteDiagnostic(JCDiagnostic.Factory diags,
|
||||||
|
DiagnosticPosition preferedPos, DiagnosticSource preferredSource,
|
||||||
|
DiagnosticType preferredKind, JCDiagnostic d) {
|
||||||
|
JCDiagnostic cause = (JCDiagnostic)d.getArgs()[0];
|
||||||
|
return diags.create(preferredKind, preferredSource, d.getDiagnosticPosition(),
|
||||||
|
"prob.found.req", cause);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum MethodResolutionPhase {
|
enum MethodResolutionPhase {
|
||||||
BASIC(false, false),
|
BASIC(false, false),
|
||||||
BOX(true, false),
|
BOX(true, false),
|
||||||
|
|
|
@ -1614,6 +1614,9 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
|
||||||
log.warning("proc.use.proc.or.implicit");
|
log.warning("proc.use.proc.or.implicit");
|
||||||
}
|
}
|
||||||
chk.reportDeferredDiagnostics();
|
chk.reportDeferredDiagnostics();
|
||||||
|
if (log.compressedOutput) {
|
||||||
|
log.mandatoryNote(null, "compressed.diags");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Close the compiler, flushing the logs
|
/** Close the compiler, flushing the logs
|
||||||
|
|
|
@ -407,6 +407,8 @@ public enum Option {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
XDIAGS("-Xdiags:", "opt.diags", EXTENDED, BASIC, ONEOF, "compact", "verbose"),
|
||||||
|
|
||||||
/* This is a back door to the compiler's option table.
|
/* This is a back door to the compiler's option table.
|
||||||
* -XDx=y sets the option x to the value y.
|
* -XDx=y sets the option x to the value y.
|
||||||
* -XDx sets the option x to the value x.
|
* -XDx sets the option x to the value x.
|
||||||
|
|
|
@ -227,11 +227,13 @@ compiler.misc.not.an.intf.component=\
|
||||||
|
|
||||||
# 0: symbol kind, 1: message segment
|
# 0: symbol kind, 1: message segment
|
||||||
compiler.err.invalid.mref=\
|
compiler.err.invalid.mref=\
|
||||||
invalid {0} reference; {1}
|
invalid {0} reference\n\
|
||||||
|
{1}
|
||||||
|
|
||||||
# 0: symbol kind, 1: message segment
|
# 0: symbol kind, 1: message segment
|
||||||
compiler.misc.invalid.mref=\
|
compiler.misc.invalid.mref=\
|
||||||
invalid {0} reference; {1}
|
invalid {0} reference\n\
|
||||||
|
{1}
|
||||||
|
|
||||||
compiler.misc.static.mref.with.targs=\
|
compiler.misc.static.mref.with.targs=\
|
||||||
parameterized qualifier on static method reference
|
parameterized qualifier on static method reference
|
||||||
|
@ -714,7 +716,8 @@ compiler.err.neither.conditional.subtype=\
|
||||||
|
|
||||||
# 0: message segment
|
# 0: message segment
|
||||||
compiler.misc.incompatible.type.in.conditional=\
|
compiler.misc.incompatible.type.in.conditional=\
|
||||||
bad type in conditional expression; {0}
|
bad type in conditional expression\n\
|
||||||
|
{0}
|
||||||
|
|
||||||
compiler.misc.conditional.target.cant.be.void=\
|
compiler.misc.conditional.target.cant.be.void=\
|
||||||
target-type for conditional expression cannot be void
|
target-type for conditional expression cannot be void
|
||||||
|
@ -743,7 +746,7 @@ compiler.misc.incompatible.arg.types.in.lambda=\
|
||||||
compiler.misc.incompatible.arg.types.in.mref=\
|
compiler.misc.incompatible.arg.types.in.mref=\
|
||||||
incompatible parameter types in method reference
|
incompatible parameter types in method reference
|
||||||
|
|
||||||
# 0: list of type
|
# 0: list of type, 1: message segment
|
||||||
compiler.misc.bad.arg.types.in.lambda=\
|
compiler.misc.bad.arg.types.in.lambda=\
|
||||||
cannot type-check lambda expression with inferred parameter types\n\
|
cannot type-check lambda expression with inferred parameter types\n\
|
||||||
inferred types: {0}
|
inferred types: {0}
|
||||||
|
@ -1154,6 +1157,9 @@ compiler.misc.x.print.rounds=\
|
||||||
## The following string will appear before all messages keyed as:
|
## The following string will appear before all messages keyed as:
|
||||||
## "compiler.note".
|
## "compiler.note".
|
||||||
|
|
||||||
|
compiler.note.compressed.diags=\
|
||||||
|
Some messages have been simplified; recompile with -Xdiags:verbose to get full output
|
||||||
|
|
||||||
compiler.note.potential.lambda.found=\
|
compiler.note.potential.lambda.found=\
|
||||||
This anonymous inner class creation can be turned into a lambda expression.
|
This anonymous inner class creation can be turned into a lambda expression.
|
||||||
|
|
||||||
|
@ -1742,6 +1748,10 @@ compiler.err.not.within.bounds=\
|
||||||
compiler.err.prob.found.req=\
|
compiler.err.prob.found.req=\
|
||||||
incompatible types: {0}
|
incompatible types: {0}
|
||||||
|
|
||||||
|
# 0: message segment
|
||||||
|
compiler.misc.prob.found.req=\
|
||||||
|
incompatible types: {0}
|
||||||
|
|
||||||
# 0: message segment, 1: type, 2: type
|
# 0: message segment, 1: type, 2: type
|
||||||
compiler.warn.prob.found.req=\
|
compiler.warn.prob.found.req=\
|
||||||
{0}\n\
|
{0}\n\
|
||||||
|
|
|
@ -168,6 +168,8 @@ javac.opt.prefer=\
|
||||||
Specify which file to read when both a source file and class file are found for an implicitly compiled class
|
Specify which file to read when both a source file and class file are found for an implicitly compiled class
|
||||||
javac.opt.AT=\
|
javac.opt.AT=\
|
||||||
Read options and filenames from file
|
Read options and filenames from file
|
||||||
|
javac.opt.diags=\
|
||||||
|
Select a diagnostic mode
|
||||||
|
|
||||||
## errors
|
## errors
|
||||||
|
|
||||||
|
|
|
@ -349,6 +349,7 @@ public class JCDiagnostic implements Diagnostic<JavaFileObject> {
|
||||||
SYNTAX,
|
SYNTAX,
|
||||||
RECOVERABLE,
|
RECOVERABLE,
|
||||||
NON_DEFERRABLE,
|
NON_DEFERRABLE,
|
||||||
|
COMPRESSED
|
||||||
}
|
}
|
||||||
|
|
||||||
private final DiagnosticType type;
|
private final DiagnosticType type;
|
||||||
|
|
|
@ -154,11 +154,11 @@ public class List<A> extends AbstractCollection<A> implements java.util.List<A>
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <A> List<A> from(Iterable<? extends A> coll) {
|
public static <A> List<A> from(Iterable<? extends A> coll) {
|
||||||
List<A> xs = nil();
|
ListBuffer<A> xs = ListBuffer.lb();
|
||||||
for (A a : coll) {
|
for (A a : coll) {
|
||||||
xs = new List<A>(a, xs);
|
xs.append(a);
|
||||||
}
|
}
|
||||||
return xs;
|
return xs.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Construct a list consisting of a given number of identical elements.
|
/** Construct a list consisting of a given number of identical elements.
|
||||||
|
|
|
@ -213,6 +213,11 @@ public class Log extends AbstractLog {
|
||||||
*/
|
*/
|
||||||
public Set<String> expectDiagKeys;
|
public Set<String> expectDiagKeys;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set to true if a compressed diagnostic is reported
|
||||||
|
*/
|
||||||
|
public boolean compressedOutput;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JavacMessages object used for localization.
|
* JavacMessages object used for localization.
|
||||||
*/
|
*/
|
||||||
|
@ -597,6 +602,9 @@ public class Log extends AbstractLog {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (diagnostic.isFlagSet(JCDiagnostic.DiagnosticFlag.COMPRESSED)) {
|
||||||
|
compressedOutput = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
/**
|
||||||
|
* @test /nodynamiccopyright/
|
||||||
|
* @bug 8012003
|
||||||
|
* @summary Method diagnostics resolution need to be simplified in some cases
|
||||||
|
* test general overload resolution simplifications
|
||||||
|
* @compile/fail/ref=T8012003a.out -XDrawDiagnostics -Xdiags:compact T8012003a.java
|
||||||
|
*/
|
||||||
|
|
||||||
|
class T8012003a {
|
||||||
|
void m1(Integer i) { }
|
||||||
|
|
||||||
|
void m2(Integer i) { }
|
||||||
|
void m2(Integer i, Object o) { }
|
||||||
|
|
||||||
|
void m3(Integer i) { }
|
||||||
|
void m3(String s) { }
|
||||||
|
|
||||||
|
void test() {
|
||||||
|
m1("");
|
||||||
|
m1(false ? "" : "");
|
||||||
|
m2("");
|
||||||
|
m3('x');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
T8012003a.java:19:12: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, java.lang.Integer)
|
||||||
|
T8012003a.java:20:20: compiler.err.prob.found.req: (compiler.misc.incompatible.type.in.conditional: (compiler.misc.inconvertible.types: java.lang.String, java.lang.Integer))
|
||||||
|
T8012003a.java:21:12: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, java.lang.Integer)
|
||||||
|
T8012003a.java:22:9: compiler.err.cant.apply.symbols: kindname.method, m3, char,{(compiler.misc.inapplicable.method: kindname.method, T8012003a, m3(java.lang.Integer), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: char, java.lang.Integer))),(compiler.misc.inapplicable.method: kindname.method, T8012003a, m3(java.lang.String), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: char, java.lang.String)))}
|
||||||
|
- compiler.note.compressed.diags
|
||||||
|
4 errors
|
|
@ -0,0 +1,37 @@
|
||||||
|
/**
|
||||||
|
* @test /nodynamiccopyright/
|
||||||
|
* @bug 8012003
|
||||||
|
* @summary Method diagnostics resolution need to be simplified in some cases
|
||||||
|
* test lambda-related overload resolution simplifications
|
||||||
|
* @compile/fail/ref=T8012003b.out -XDrawDiagnostics -Xdiags:compact T8012003b.java
|
||||||
|
*/
|
||||||
|
|
||||||
|
class T8012003b {
|
||||||
|
|
||||||
|
interface Consumer_V<X> {
|
||||||
|
void m(X x);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Consumer_NV<X> {
|
||||||
|
Integer m(X x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void m1(Runnable r) { }
|
||||||
|
void m1(Runnable r, String s) { }
|
||||||
|
|
||||||
|
void m2(Consumer_V<Integer> ci) { }
|
||||||
|
|
||||||
|
void m3(Consumer_NV<String> ci) { }
|
||||||
|
|
||||||
|
void g(String arg) { }
|
||||||
|
String g2(String arg) { return arg; }
|
||||||
|
|
||||||
|
void test() {
|
||||||
|
m1(this::g);
|
||||||
|
m1(()->1);
|
||||||
|
m1(()->false ? "" : "");
|
||||||
|
m2(this::g);
|
||||||
|
m3(this::g2);
|
||||||
|
m3(this::k);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
T8012003b.java:30:12: compiler.err.prob.found.req: (compiler.misc.invalid.mref: kindname.method, (compiler.misc.cant.apply.symbol: kindname.method, g, java.lang.String, compiler.misc.no.args, kindname.class, T8012003b, (compiler.misc.arg.length.mismatch)))
|
||||||
|
T8012003b.java:31:16: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.inconvertible.types: int, void))
|
||||||
|
T8012003b.java:32:22: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.conditional.target.cant.be.void))
|
||||||
|
T8012003b.java:33:12: compiler.err.prob.found.req: (compiler.misc.invalid.mref: kindname.method, (compiler.misc.prob.found.req: (compiler.misc.inconvertible.types: java.lang.Integer, java.lang.String)))
|
||||||
|
T8012003b.java:34:12: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.mref: (compiler.misc.inconvertible.types: java.lang.String, java.lang.Integer))
|
||||||
|
T8012003b.java:35:12: compiler.err.invalid.mref: kindname.method, (compiler.misc.cant.resolve.location.args: kindname.method, k, , , (compiler.misc.location: kindname.class, T8012003b, null))
|
||||||
|
- compiler.note.compressed.diags
|
||||||
|
6 errors
|
|
@ -0,0 +1,24 @@
|
||||||
|
/**
|
||||||
|
* @test /nodynamiccopyright/
|
||||||
|
* @bug 8012003
|
||||||
|
* @summary Method diagnostics resolution need to be simplified in some cases
|
||||||
|
* test simplification of lambda type-checking error leading to resolution failure
|
||||||
|
* @compile/fail/ref=T8012003c.out -XDrawDiagnostics -Xdiags:compact T8012003c.java
|
||||||
|
*/
|
||||||
|
|
||||||
|
class T8012003c {
|
||||||
|
|
||||||
|
interface I {
|
||||||
|
void m(P p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void m(I i) { }
|
||||||
|
|
||||||
|
void test() {
|
||||||
|
m(p->p.m());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class P {
|
||||||
|
private void m() { }
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
T8012003c.java:18:15: compiler.err.report.access: m(), private, P
|
||||||
|
- compiler.note.compressed.diags
|
||||||
|
1 error
|
|
@ -24,6 +24,9 @@
|
||||||
// key: compiler.err.cant.apply.symbol
|
// key: compiler.err.cant.apply.symbol
|
||||||
// key: compiler.misc.no.conforming.assignment.exists
|
// key: compiler.misc.no.conforming.assignment.exists
|
||||||
// key: compiler.misc.bad.arg.types.in.lambda
|
// key: compiler.misc.bad.arg.types.in.lambda
|
||||||
|
// key: compiler.err.prob.found.req
|
||||||
|
// key: compiler.misc.inconvertible.types
|
||||||
|
// options: -Xdiags:verbose
|
||||||
|
|
||||||
class BadArgTypesInLambda {
|
class BadArgTypesInLambda {
|
||||||
interface SAM {
|
interface SAM {
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// key: compiler.err.prob.found.req
|
||||||
|
// key: compiler.misc.inconvertible.types
|
||||||
|
// key: compiler.note.compressed.diags
|
||||||
|
// key: compiler.note.note
|
||||||
|
// key: compiler.misc.count.error
|
||||||
|
// key: compiler.err.error
|
||||||
|
// run: backdoor
|
||||||
|
|
||||||
|
class CompressedDiags {
|
||||||
|
|
||||||
|
void m(String s) { }
|
||||||
|
|
||||||
|
void test() {
|
||||||
|
m(1);
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,6 +28,7 @@
|
||||||
// key: compiler.misc.inconvertible.types
|
// key: compiler.misc.inconvertible.types
|
||||||
// key: compiler.misc.count.error
|
// key: compiler.misc.count.error
|
||||||
// key: compiler.err.error
|
// key: compiler.err.error
|
||||||
|
// options: -Xdiags:verbose
|
||||||
// run: backdoor
|
// run: backdoor
|
||||||
|
|
||||||
class KindnameConstructor {
|
class KindnameConstructor {
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// key: compiler.err.prob.found.req
|
||||||
|
// key: compiler.misc.prob.found.req
|
||||||
|
// key: compiler.misc.inconvertible.types
|
||||||
|
// key: compiler.misc.invalid.mref
|
||||||
|
// key: compiler.misc.kindname.method
|
||||||
|
// key: compiler.misc.count.error
|
||||||
|
// key: compiler.err.error
|
||||||
|
// run: backdoor
|
||||||
|
|
||||||
|
class ProbFoundReqFragment {
|
||||||
|
|
||||||
|
interface I {
|
||||||
|
void g(int i);
|
||||||
|
}
|
||||||
|
|
||||||
|
void m(String s) { }
|
||||||
|
|
||||||
|
void test() {
|
||||||
|
I i = this::m;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
TargetType66.java:22:9: compiler.err.ref.ambiguous: g, kindname.method, g(TargetType66.SAM1), TargetType66, kindname.method, g(TargetType66.SAM2), TargetType66
|
TargetType66.java:22:9: compiler.err.ref.ambiguous: g, kindname.method, g(TargetType66.SAM1), TargetType66, kindname.method, g(TargetType66.SAM2), TargetType66
|
||||||
TargetType66.java:23:9: compiler.err.cant.apply.symbols: kindname.method, g, @578,{(compiler.misc.inapplicable.method: kindname.method, TargetType66, g(TargetType66.SAM1), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.bad.arg.types.in.lambda: java.lang.String))),(compiler.misc.inapplicable.method: kindname.method, TargetType66, g(TargetType66.SAM2), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.bad.arg.types.in.lambda: java.lang.Integer)))}
|
TargetType66.java:23:9: compiler.err.cant.apply.symbols: kindname.method, g, @578,{(compiler.misc.inapplicable.method: kindname.method, TargetType66, g(TargetType66.SAM1), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.bad.arg.types.in.lambda: java.lang.String, (compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, java.lang.Character))))),(compiler.misc.inapplicable.method: kindname.method, TargetType66, g(TargetType66.SAM2), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.bad.arg.types.in.lambda: java.lang.Integer, (compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.Integer, java.lang.Character)))))}
|
||||||
TargetType66.java:24:30: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, java.lang.Character)
|
TargetType66.java:24:30: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, java.lang.Character)
|
||||||
3 errors
|
3 errors
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue