Improved support for diagnostic during lambda conversion.
authormcimadamore
Tue Jun 22 17:19:34 2010 +0100 (2 years ago)
changeset 5821cbf9ca0c589
parent 58102b8de982628
child 583dda155f6d75d
Improved support for diagnostic during lambda conversion.
Now the compiler emits more specific info about why a function type cannot be assigned to a SAM type (does not cover method resolution diagnostics).

Examples:

TestX.java:16: incompatible types; target method pippo in class I is not suitable for lambda conversion
I f = #(Integer i) { return new Integer(i); };
^
required: I
found: #Integer(Integer)
1 error

Test.java:16: incompatible types; target method pippo in class I is not suitable for lambda conversion
I f = #(Integer i) { return new Integer(i); };
^
required: I
found: #Integer(Integer)

Test.java:16: incompatible types; the target type of a lambda conversion must be an abstract class/interface
I f = #(Integer i) { return new Integer(i); };
^
required: I
found: #Integer(Integer)

Test.java:16: incompatible types; no target method for lambda conversion found in class I
I f = #(Integer i) { return new Integer(i); };
^
required: I
found: #Integer(Integer)

Test.java:16: incompatible types; the target type of a lambda conversion must define a default constructor
I f = #(Integer i) { return new Integer(i); };
^
required: I
found: #Integer(Integer)
src/share/classes/com/sun/tools/javac/code/Types.java
src/share/classes/com/sun/tools/javac/comp/Check.java
src/share/classes/com/sun/tools/javac/resources/compiler.properties
test/tools/javac/lambda/BadConv01.out
test/tools/javac/lambda/BadConv02.out
--- a/src/share/classes/com/sun/tools/javac/code/Types.java Mon Jun 21 13:43:37 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/code/Types.java Tue Jun 22 17:19:34 2010 +0100
@@ -357,8 +357,8 @@ public class Types {
}
return false;
}
- //where
- private boolean hasDefaultConstructor(ClassSymbol csym) {
+
+ public boolean hasDefaultConstructor(ClassSymbol csym) {
for (Scope.Entry e = csym.members().lookup(names.init) ; e.scope != null ; e = e.next()) {
if (e.sym.kind == Kinds.MTH &&
e.sym.type.getParameterTypes().isEmpty()) {
--- a/src/share/classes/com/sun/tools/javac/comp/Check.java Mon Jun 21 13:43:37 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Check.java Tue Jun 22 17:19:34 2010 +0100
@@ -273,6 +273,46 @@ public class Check {
}
}
+ Type incompatibleTypesError(DiagnosticPosition pos, Type found, Type req) {
+ JCDiagnostic details = null;
+ if (types.isFunctionType(found) &&
+ !types.isFunctionType(req) &&
+ req.tag == CLASS) {
+ //generate better SAM conversion diagnostic
+ ListBuffer<Symbol> samMethods = ListBuffer.lb();
+ types.findSAM(req, samMethods);
+ Name methName = samMethods.nonEmpty() ?
+ samMethods.first().name :
+ null;
+ final String subkey;
+ if ((req.tsym.flags() & ABSTRACT) == 0) {
+ //req must be an abstract class or an interface
+ subkey = "target.for.lambda.conv.must.be.abstract";
+ } else if (!req.isInterface() &&
+ !types.hasDefaultConstructor((ClassSymbol)req.tsym)) {
+ //if req is an abstract class, then it should have a default constructor
+ subkey = "target.for.lambda.conv.must.have.default.constr";
+ } else {
+ //req must define a suitable non-generic method
+ switch (samMethods.size()) {
+ case 0: subkey = "no.target.method.for.lambda.conv"; break;
+ case 1: {
+ subkey = samMethods.first().type.tag == FORALL ?
+ "invalid.generic.target.for.lambda.conv" :
+ "incompatible.target.in.lambda.conv";
+ break;
+ }
+ default: subkey = "incompatible.targets.in.lambda.conv"; break;
+ }
+ }
+ details = diags.fragment(subkey, methName, kindName(req.tsym), req.tsym);
+ }
+ JCDiagnostic subDiag = details != null ?
+ diags.fragment("incompatible.types.1", details) :
+ diags.fragment("incompatible.types");
+ return typeError(pos, subDiag, found, req);
+ }
+
/* ************************************************************************
* duplicate declaration checking
*************************************************************************/
@@ -391,7 +431,7 @@ public class Check {
log.error(pos, "assignment.to.extends-bound", req);
return types.createErrorType(found);
}
- return typeError(pos, diags.fragment("incompatible.types"), found, req);
+ return incompatibleTypesError(pos, found, req);
}
/** Instantiate polymorphic type to some prototype, unless
--- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties Mon Jun 21 13:43:37 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties Tue Jun 22 17:19:34 2010 +0100
@@ -93,6 +93,18 @@ compiler.err.cant.apply.lambda=\
lambda expression cannot be applied to given types\n\
required: {0}\n\
found: {1}
+compiler.misc.no.target.method.for.lambda.conv=\
+ no target method for lambda conversion found in {1} {2}
+compiler.misc.incompatible.target.in.lambda.conv=\
+ target method {0} in {1} {2} is not suitable for lambda conversion
+compiler.misc.incompatible.targets.in.lambda.conv=\
+ no suitable target method for lambda conversion found in {1} {2}
+compiler.misc.invalid.generic.target.for.lambda.conv=\
+ invalid target for lambda conversion: method {0} in {1} {2} is generic
+compiler.misc.target.for.lambda.conv.must.be.abstract=\
+ the target type of a lambda conversion must be an abstract class/interface
+compiler.misc.target.for.lambda.conv.must.have.default.constr=\
+ the target type of a lambda conversion must define a default constructor
compiler.err.cant.assign.val.to.final.var=\
cannot assign a value to final variable {0}
compiler.err.cant.deref=\
--- a/test/tools/javac/lambda/BadConv01.out Mon Jun 21 13:43:37 2010 +0100
+++ b/test/tools/javac/lambda/BadConv01.out Tue Jun 22 17:19:34 2010 +0100
@@ -1,2 +1,2 @@ BadConv01.java:35:13: compiler.err.prob.
-BadConv01.java:35:13: compiler.err.prob.found.req: (compiler.misc.incompatible.types), #int(T), BadConv01.Bar
+BadConv01.java:35:13: compiler.err.prob.found.req: (compiler.misc.incompatible.types.1: (compiler.misc.invalid.generic.target.for.lambda.conv: m, kindname.interface, BadConv01.Bar)), #int(T), BadConv01.Bar
1 error
--- a/test/tools/javac/lambda/BadConv02.out Mon Jun 21 13:43:37 2010 +0100
+++ b/test/tools/javac/lambda/BadConv02.out Tue Jun 22 17:19:34 2010 +0100
@@ -1,3 +1,3 @@ BadConv02.java:44:15: compiler.err.cant.
BadConv02.java:44:15: compiler.err.cant.apply.symbol: kindname.constructor, FooImpl, int, compiler.misc.no.args, kindname.class, BadConv02.FooImpl, null
-BadConv02.java:45:15: compiler.err.prob.found.req: (compiler.misc.incompatible.types), #int(), BadConv02.Foo
+BadConv02.java:45:15: compiler.err.prob.found.req: (compiler.misc.incompatible.types.1: (compiler.misc.target.for.lambda.conv.must.have.default.constr: null, kindname.class, BadConv02.Foo)), #int(), BadConv02.Foo
2 errors