8015809: More user friendly compile-time errors for uncaught exceptions in lambda expression
Producing individual errors for uncaught undeclared exceptions inside lambda expressions, rather than one error for the whole lambda Reviewed-by: mcimadamore
This commit is contained in:
parent
746be81338
commit
59e0637339
@ -1161,7 +1161,7 @@ public abstract class Type implements TypeMirror {
|
||||
}
|
||||
|
||||
public boolean contains(Type elem) {
|
||||
return elem == this || contains(argtypes, elem) || restype.contains(elem);
|
||||
return elem == this || contains(argtypes, elem) || restype.contains(elem) || contains(thrown, elem);
|
||||
}
|
||||
|
||||
public MethodType asMethodType() { return this; }
|
||||
|
@ -2607,8 +2607,7 @@ public class Attr extends JCTree.Visitor {
|
||||
* are compatible with the expected functional interface descriptor. This means that:
|
||||
* (i) parameter types must be identical to those of the target descriptor; (ii) return
|
||||
* types must be compatible with the return type of the expected descriptor;
|
||||
* (iii) thrown types must be 'included' in the thrown types list of the expected
|
||||
* descriptor.
|
||||
* (iii) finish inference of thrown types if required.
|
||||
*/
|
||||
private void checkLambdaCompatible(JCLambda tree, Type descriptor, CheckContext checkContext, boolean speculativeAttr) {
|
||||
Type returnType = checkContext.inferenceContext().asFree(descriptor.getReturnType());
|
||||
@ -2630,9 +2629,7 @@ public class Attr extends JCTree.Visitor {
|
||||
|
||||
if (!speculativeAttr) {
|
||||
List<Type> thrownTypes = checkContext.inferenceContext().asFree(descriptor.getThrownTypes());
|
||||
if (chk.unhandled(tree.inferredThrownTypes == null ? List.<Type>nil() : tree.inferredThrownTypes, thrownTypes).nonEmpty()) {
|
||||
log.error(tree, "incompatible.thrown.types.in.lambda", tree.inferredThrownTypes);
|
||||
}
|
||||
chk.unhandled(tree.inferredThrownTypes == null ? List.<Type>nil() : tree.inferredThrownTypes, thrownTypes);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -224,7 +224,7 @@ public class Flow {
|
||||
}
|
||||
try {
|
||||
new AliveAnalyzer().analyzeTree(env, that, make);
|
||||
new FlowAnalyzer().analyzeTree(env, that, make);
|
||||
new LambdaFlowAnalyzer().analyzeTree(env, that, make);
|
||||
} finally {
|
||||
if (!speculative) {
|
||||
log.popDiagnosticHandler(diagHandler);
|
||||
@ -1259,12 +1259,24 @@ public class Flow {
|
||||
ListBuffer<FlowPendingExit> prevPending = pendingExits;
|
||||
try {
|
||||
pendingExits = ListBuffer.lb();
|
||||
caught = List.of(syms.throwableType); //inhibit exception checking
|
||||
caught = tree.getDescriptorType(types).getThrownTypes();
|
||||
thrown = List.nil();
|
||||
scan(tree.body);
|
||||
tree.inferredThrownTypes = thrown;
|
||||
}
|
||||
finally {
|
||||
List<FlowPendingExit> exits = pendingExits.toList();
|
||||
pendingExits = new ListBuffer<FlowPendingExit>();
|
||||
while (exits.nonEmpty()) {
|
||||
FlowPendingExit exit = exits.head;
|
||||
exits = exits.tail;
|
||||
if (exit.thrown == null) {
|
||||
Assert.check(exit.tree.hasTag(RETURN));
|
||||
} else {
|
||||
// uncaught throws will be reported later
|
||||
pendingExits.append(exit);
|
||||
}
|
||||
}
|
||||
|
||||
errorUncaught();
|
||||
} finally {
|
||||
pendingExits = prevPending;
|
||||
caught = prevCaught;
|
||||
thrown = prevThrown;
|
||||
@ -1302,6 +1314,33 @@ public class Flow {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized pass that performs inference of thrown types for lambdas.
|
||||
*/
|
||||
class LambdaFlowAnalyzer extends FlowAnalyzer {
|
||||
@Override
|
||||
public void visitLambda(JCLambda tree) {
|
||||
if (tree.type != null &&
|
||||
tree.type.isErroneous()) {
|
||||
return;
|
||||
}
|
||||
List<Type> prevCaught = caught;
|
||||
List<Type> prevThrown = thrown;
|
||||
ListBuffer<FlowPendingExit> prevPending = pendingExits;
|
||||
try {
|
||||
pendingExits = ListBuffer.lb();
|
||||
caught = List.of(syms.throwableType);
|
||||
thrown = List.nil();
|
||||
scan(tree.body);
|
||||
tree.inferredThrownTypes = thrown;
|
||||
} finally {
|
||||
pendingExits = prevPending;
|
||||
caught = prevCaught;
|
||||
thrown = prevThrown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This pass implements (i) definite assignment analysis, which ensures that
|
||||
* each variable is assigned when used and (ii) definite unassignment analysis,
|
||||
|
@ -732,10 +732,6 @@ compiler.misc.incompatible.ret.type.in.mref=\
|
||||
bad return type in method reference\n\
|
||||
{0}
|
||||
|
||||
# 0: list of type
|
||||
compiler.err.incompatible.thrown.types.in.lambda=\
|
||||
incompatible thrown types {0} in lambda expression
|
||||
|
||||
# 0: list of type
|
||||
compiler.err.incompatible.thrown.types.in.mref=\
|
||||
incompatible thrown types {0} in method reference
|
||||
|
@ -645,7 +645,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
public List<Type> targets;
|
||||
|
||||
public Type getDescriptorType(Types types) {
|
||||
return types.findDescriptorType(targets.head);
|
||||
return targets.nonEmpty() ? types.findDescriptorType(targets.head) : types.createErrorType(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -21,12 +21,41 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// key: compiler.err.incompatible.thrown.types.in.lambda
|
||||
/*
|
||||
* @test
|
||||
* @bug 8015809
|
||||
* @summary Producing individual errors for uncaught undeclared exceptions inside lambda expressions, instead of one error for whole lambda
|
||||
* @compile/fail/ref=ExceptionsInLambda.out -XDrawDiagnostics ExceptionsInLambda.java
|
||||
*/
|
||||
|
||||
class IncompatibleThrownTypesInLambda {
|
||||
interface SAM {
|
||||
void m();
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
|
||||
public class ExceptionsInLambda {
|
||||
|
||||
public static void main(Runnable p, File f) {
|
||||
main(() -> {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
Reader in = new FileReader(f);
|
||||
int r;
|
||||
|
||||
while ((r = in.read()) != (-1)) {
|
||||
sb.append((char) r);
|
||||
}
|
||||
}, f);
|
||||
|
||||
doOpen(() -> new FileInputStream(f));
|
||||
}
|
||||
|
||||
SAM s = ()-> { throw new Exception(); };
|
||||
public static InputStream doOpen(Open open) {
|
||||
return open.open();
|
||||
}
|
||||
|
||||
public interface Open {
|
||||
public InputStream open();
|
||||
}
|
||||
}
|
4
langtools/test/tools/javac/lambda/ExceptionsInLambda.out
Normal file
4
langtools/test/tools/javac/lambda/ExceptionsInLambda.out
Normal file
@ -0,0 +1,4 @@
|
||||
ExceptionsInLambda.java:43:25: compiler.err.unreported.exception.need.to.catch.or.throw: java.io.FileNotFoundException
|
||||
ExceptionsInLambda.java:46:32: compiler.err.unreported.exception.need.to.catch.or.throw: java.io.IOException
|
||||
ExceptionsInLambda.java:51:22: compiler.err.unreported.exception.need.to.catch.or.throw: java.io.FileNotFoundException
|
||||
3 errors
|
@ -1,6 +1,5 @@
|
||||
TargetType21.java:28:9: compiler.err.ref.ambiguous: call, kindname.method, call(TargetType21.SAM2), TargetType21, kindname.method, <R,A>call(TargetType21.SAM3<R,A>), TargetType21
|
||||
TargetType21.java:28:14: compiler.err.incompatible.thrown.types.in.lambda: java.lang.Exception
|
||||
TargetType21.java:29:9: compiler.err.ref.ambiguous: call, kindname.method, call(TargetType21.SAM2), TargetType21, kindname.method, <R,A>call(TargetType21.SAM3<R,A>), TargetType21
|
||||
TargetType21.java:30:13: compiler.err.prob.found.req: (compiler.misc.cyclic.inference: A)
|
||||
TargetType21.java:31:9: compiler.err.ref.ambiguous: call, kindname.method, call(TargetType21.SAM1), TargetType21, kindname.method, <R,A>call(TargetType21.SAM3<R,A>), TargetType21
|
||||
5 errors
|
||||
4 errors
|
||||
|
Loading…
Reference in New Issue
Block a user