8182047: javac compile error on type-parameter-exceptions in lambda expressions
Reviewed-by: mcimadamore
This commit is contained in:
parent
c00b47cf6e
commit
b081062f1c
@ -2106,7 +2106,7 @@ public class Types {
|
|||||||
Type out = erasure.visit(t, recurse);
|
Type out = erasure.visit(t, recurse);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// where
|
// where
|
||||||
private TypeMapping<Boolean> erasure = new StructuralTypeMapping<Boolean>() {
|
private TypeMapping<Boolean> erasure = new StructuralTypeMapping<Boolean>() {
|
||||||
private Type combineMetadata(final Type s,
|
private Type combineMetadata(final Type s,
|
||||||
|
@ -2515,14 +2515,9 @@ public class Attr extends JCTree.Visitor {
|
|||||||
//add thrown types as bounds to the thrown types free variables if needed:
|
//add thrown types as bounds to the thrown types free variables if needed:
|
||||||
if (resultInfo.checkContext.inferenceContext().free(lambdaType.getThrownTypes())) {
|
if (resultInfo.checkContext.inferenceContext().free(lambdaType.getThrownTypes())) {
|
||||||
List<Type> inferredThrownTypes = flow.analyzeLambdaThrownTypes(env, that, make);
|
List<Type> inferredThrownTypes = flow.analyzeLambdaThrownTypes(env, that, make);
|
||||||
List<Type> thrownTypes = resultInfo.checkContext.inferenceContext().asUndetVars(lambdaType.getThrownTypes());
|
if(!checkExConstraints(inferredThrownTypes, lambdaType.getThrownTypes(), resultInfo.checkContext.inferenceContext())) {
|
||||||
|
log.error(that, Errors.IncompatibleThrownTypesInMref(lambdaType.getThrownTypes()));
|
||||||
chk.unhandled(inferredThrownTypes, thrownTypes);
|
}
|
||||||
|
|
||||||
//18.2.5: "In addition, for all j (1 <= j <= n), the constraint reduces to the bound throws Ej"
|
|
||||||
thrownTypes.stream()
|
|
||||||
.filter(t -> t.hasTag(UNDETVAR))
|
|
||||||
.forEach(t -> ((UndetVar)t).setThrow());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
checkAccessibleTypes(that, localEnv, resultInfo.checkContext.inferenceContext(), lambdaType, currentTarget);
|
checkAccessibleTypes(that, localEnv, resultInfo.checkContext.inferenceContext(), lambdaType, currentTarget);
|
||||||
@ -3111,17 +3106,72 @@ public class Attr extends JCTree.Visitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!speculativeAttr) {
|
if (!speculativeAttr) {
|
||||||
List<Type> thrownTypes = inferenceContext.asUndetVars(descriptor.getThrownTypes());
|
if (!checkExConstraints(refType.getThrownTypes(), descriptor.getThrownTypes(), inferenceContext)) {
|
||||||
if (chk.unhandled(refType.getThrownTypes(), thrownTypes).nonEmpty()) {
|
|
||||||
log.error(tree, Errors.IncompatibleThrownTypesInMref(refType.getThrownTypes()));
|
log.error(tree, Errors.IncompatibleThrownTypesInMref(refType.getThrownTypes()));
|
||||||
}
|
}
|
||||||
//18.2.5: "In addition, for all j (1 <= j <= n), the constraint reduces to the bound throws Ej"
|
|
||||||
thrownTypes.stream()
|
|
||||||
.filter(t -> t.hasTag(UNDETVAR))
|
|
||||||
.forEach(t -> ((UndetVar)t).setThrow());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean checkExConstraints(
|
||||||
|
List<Type> thrownByFuncExpr,
|
||||||
|
List<Type> thrownAtFuncType,
|
||||||
|
InferenceContext inferenceContext) {
|
||||||
|
/** 18.2.5: Otherwise, let E1, ..., En be the types in the function type's throws clause that
|
||||||
|
* are not proper types
|
||||||
|
*/
|
||||||
|
List<Type> nonProperList = thrownAtFuncType.stream()
|
||||||
|
.filter(e -> inferenceContext.free(e)).collect(List.collector());
|
||||||
|
List<Type> properList = thrownAtFuncType.diff(nonProperList);
|
||||||
|
|
||||||
|
/** Let X1,...,Xm be the checked exception types that the lambda body can throw or
|
||||||
|
* in the throws clause of the invocation type of the method reference's compile-time
|
||||||
|
* declaration
|
||||||
|
*/
|
||||||
|
List<Type> checkedList = thrownByFuncExpr.stream()
|
||||||
|
.filter(e -> chk.isChecked(e)).collect(List.collector());
|
||||||
|
|
||||||
|
/** If n = 0 (the function type's throws clause consists only of proper types), then
|
||||||
|
* if there exists some i (1 <= i <= m) such that Xi is not a subtype of any proper type
|
||||||
|
* in the throws clause, the constraint reduces to false; otherwise, the constraint
|
||||||
|
* reduces to true
|
||||||
|
*/
|
||||||
|
ListBuffer<Type> uncaughtByProperTypes = new ListBuffer<>();
|
||||||
|
for (Type checked : checkedList) {
|
||||||
|
boolean isSubtype = false;
|
||||||
|
for (Type proper : properList) {
|
||||||
|
if (types.isSubtype(checked, proper)) {
|
||||||
|
isSubtype = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isSubtype) {
|
||||||
|
uncaughtByProperTypes.add(checked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nonProperList.isEmpty() && !uncaughtByProperTypes.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** If n > 0, the constraint reduces to a set of subtyping constraints:
|
||||||
|
* for all i (1 <= i <= m), if Xi is not a subtype of any proper type in the
|
||||||
|
* throws clause, then the constraints include, for all j (1 <= j <= n), <Xi <: Ej>
|
||||||
|
*/
|
||||||
|
List<Type> nonProperAsUndet = inferenceContext.asUndetVars(nonProperList);
|
||||||
|
uncaughtByProperTypes.forEach(checkedEx -> {
|
||||||
|
nonProperAsUndet.forEach(nonProper -> {
|
||||||
|
types.isSubtype(checkedEx, nonProper);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/** In addition, for all j (1 <= j <= n), the constraint reduces to the bound throws Ej
|
||||||
|
*/
|
||||||
|
nonProperAsUndet.stream()
|
||||||
|
.filter(t -> t.hasTag(UNDETVAR))
|
||||||
|
.forEach(t -> ((UndetVar)t).setThrow());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set functional type info on the underlying AST. Note: as the target descriptor
|
* Set functional type info on the underlying AST. Note: as the target descriptor
|
||||||
* might contain inference variables, we might need to register an hook in the
|
* might contain inference variables, we might need to register an hook in the
|
||||||
|
@ -1568,6 +1568,10 @@ public class Check {
|
|||||||
exc.hasTag(BOT);
|
exc.hasTag(BOT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isChecked(Type exc) {
|
||||||
|
return !isUnchecked(exc);
|
||||||
|
}
|
||||||
|
|
||||||
/** Same, but handling completion failures.
|
/** Same, but handling completion failures.
|
||||||
*/
|
*/
|
||||||
boolean isUnchecked(DiagnosticPosition pos, Type exc) {
|
boolean isUnchecked(DiagnosticPosition pos, Type exc) {
|
||||||
|
@ -808,7 +808,7 @@ compiler.err.lambda.body.neither.value.nor.void.compatible=\
|
|||||||
|
|
||||||
# 0: list of type
|
# 0: list of type
|
||||||
compiler.err.incompatible.thrown.types.in.mref=\
|
compiler.err.incompatible.thrown.types.in.mref=\
|
||||||
incompatible thrown types {0} in method reference
|
incompatible thrown types {0} in functional expression
|
||||||
|
|
||||||
compiler.misc.incompatible.arg.types.in.lambda=\
|
compiler.misc.incompatible.arg.types.in.lambda=\
|
||||||
incompatible parameter types in lambda expression
|
incompatible parameter types in lambda expression
|
||||||
|
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8182047
|
||||||
|
* @summary javac compile error on type-parameter-exceptions in lambda expressions
|
||||||
|
* @compile CorrectGenerationOfExConstraintsTest.java
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class CorrectGenerationOfExConstraintsTest {
|
||||||
|
public static class MyExBase extends Exception {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MyEx1 extends MyExBase {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MyEx2 extends MyExBase {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface MyLambdaIF1 <E extends Exception> {
|
||||||
|
void lambdaFun() throws E, MyEx2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface MyLambdaIF2 <E extends Exception> {
|
||||||
|
void lambdaFun() throws MyEx2, E;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <E extends Exception> void fun1(MyLambdaIF1<E> myLambda) throws E, MyEx2 {
|
||||||
|
myLambda.lambdaFun();
|
||||||
|
}
|
||||||
|
|
||||||
|
public <E extends Exception> void fun2(MyLambdaIF2<E> myLambda) throws E, MyEx2 {
|
||||||
|
myLambda.lambdaFun();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void useIt1() throws MyEx1, MyEx2 {
|
||||||
|
fun1(this::lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void useIt1a() throws MyExBase {
|
||||||
|
fun1(this::lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void useIt2() throws MyEx1, MyEx2 {
|
||||||
|
fun2(this::lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void lambda() throws MyEx1, MyEx2 {
|
||||||
|
if (Math.random() > 0.5)
|
||||||
|
throw new MyEx2();
|
||||||
|
throw new MyEx1();
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user