mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-18 01:54:47 +02:00
8058112: Invalid BootstrapMethod for constructor/method reference
Bridge method references with functional interface method parameters of intersection type Reviewed-by: vromero, dlsmith
This commit is contained in:
parent
26298f1124
commit
634c33938c
4 changed files with 306 additions and 41 deletions
|
@ -40,6 +40,7 @@ import com.sun.tools.javac.code.Symbol.VarSymbol;
|
||||||
import com.sun.tools.javac.code.Symtab;
|
import com.sun.tools.javac.code.Symtab;
|
||||||
import com.sun.tools.javac.code.Type;
|
import com.sun.tools.javac.code.Type;
|
||||||
import com.sun.tools.javac.code.Type.MethodType;
|
import com.sun.tools.javac.code.Type.MethodType;
|
||||||
|
import com.sun.tools.javac.code.Type.TypeVar;
|
||||||
import com.sun.tools.javac.code.Types;
|
import com.sun.tools.javac.code.Types;
|
||||||
import com.sun.tools.javac.comp.LambdaToMethod.LambdaAnalyzerPreprocessor.*;
|
import com.sun.tools.javac.comp.LambdaToMethod.LambdaAnalyzerPreprocessor.*;
|
||||||
import com.sun.tools.javac.comp.Lower.BasicFreeVarCollector;
|
import com.sun.tools.javac.comp.Lower.BasicFreeVarCollector;
|
||||||
|
@ -60,6 +61,7 @@ import static com.sun.tools.javac.code.Flags.*;
|
||||||
import static com.sun.tools.javac.code.Kinds.Kind.*;
|
import static com.sun.tools.javac.code.Kinds.Kind.*;
|
||||||
import static com.sun.tools.javac.code.TypeTag.*;
|
import static com.sun.tools.javac.code.TypeTag.*;
|
||||||
import static com.sun.tools.javac.tree.JCTree.Tag.*;
|
import static com.sun.tools.javac.tree.JCTree.Tag.*;
|
||||||
|
import javax.lang.model.type.TypeKind;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This pass desugars lambda expressions into static methods
|
* This pass desugars lambda expressions into static methods
|
||||||
|
@ -759,49 +761,10 @@ public class LambdaToMethod extends TreeTranslator {
|
||||||
int prevPos = make.pos;
|
int prevPos = make.pos;
|
||||||
try {
|
try {
|
||||||
make.at(tree);
|
make.at(tree);
|
||||||
Type samDesc = localContext.bridgedRefSig();
|
|
||||||
List<Type> samPTypes = samDesc.getParameterTypes();
|
|
||||||
|
|
||||||
// an extra argument is prepended in the case where the member
|
|
||||||
// reference is an unbound instance method reference (in which
|
|
||||||
// case the receiver expression in passed.
|
|
||||||
VarSymbol rcvr;
|
|
||||||
switch (tree.kind) {
|
|
||||||
case BOUND:
|
|
||||||
rcvr = addParameter("rec$", tree.getQualifierExpression().type, false);
|
|
||||||
receiverExpression = attr.makeNullCheck(tree.getQualifierExpression());
|
|
||||||
break;
|
|
||||||
case UNBOUND:
|
|
||||||
rcvr = addParameter("rec$", samPTypes.head, false);
|
|
||||||
samPTypes = samPTypes.tail;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
rcvr = null;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// generate the parameter list for the coverted member reference.
|
|
||||||
// the signature will match the signature of the target sam descriptor
|
|
||||||
|
|
||||||
List<Type> refPTypes = tree.sym.type.getParameterTypes();
|
|
||||||
int refSize = refPTypes.size();
|
|
||||||
int samSize = samPTypes.size();
|
|
||||||
// Last parameter to copy from referenced method
|
|
||||||
int last = localContext.needsVarArgsConversion() ? refSize - 1 : refSize;
|
|
||||||
|
|
||||||
List<Type> l = refPTypes;
|
|
||||||
// Use parameter types of the referenced method, excluding final var args
|
|
||||||
for (int i = 0; l.nonEmpty() && i < last; ++i) {
|
|
||||||
addParameter("x$" + i, l.head, true);
|
|
||||||
l = l.tail;
|
|
||||||
}
|
|
||||||
// Flatten out the var args
|
|
||||||
for (int i = last; i < samSize; ++i) {
|
|
||||||
addParameter("xva$" + i, tree.varargsElement, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
//body generation - this can be either a method call or a
|
//body generation - this can be either a method call or a
|
||||||
//new instance creation expression, depending on the member reference kind
|
//new instance creation expression, depending on the member reference kind
|
||||||
|
VarSymbol rcvr = addParametersReturnReceiver();
|
||||||
JCExpression expr = (tree.getMode() == ReferenceMode.INVOKE)
|
JCExpression expr = (tree.getMode() == ReferenceMode.INVOKE)
|
||||||
? expressionInvoke(rcvr)
|
? expressionInvoke(rcvr)
|
||||||
: expressionNew();
|
: expressionNew();
|
||||||
|
@ -816,6 +779,78 @@ public class LambdaToMethod extends TreeTranslator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the parameter list for the converted member reference.
|
||||||
|
*
|
||||||
|
* @return The receiver variable symbol, if any
|
||||||
|
*/
|
||||||
|
VarSymbol addParametersReturnReceiver() {
|
||||||
|
Type samDesc = localContext.bridgedRefSig();
|
||||||
|
List<Type> samPTypes = samDesc.getParameterTypes();
|
||||||
|
List<Type> descPTypes = tree.getDescriptorType(types).getParameterTypes();
|
||||||
|
|
||||||
|
// Determine the receiver, if any
|
||||||
|
VarSymbol rcvr;
|
||||||
|
switch (tree.kind) {
|
||||||
|
case BOUND:
|
||||||
|
// The receiver is explicit in the method reference
|
||||||
|
rcvr = addParameter("rec$", tree.getQualifierExpression().type, false);
|
||||||
|
receiverExpression = attr.makeNullCheck(tree.getQualifierExpression());
|
||||||
|
break;
|
||||||
|
case UNBOUND:
|
||||||
|
// The receiver is the first parameter, extract it and
|
||||||
|
// adjust the SAM and unerased type lists accordingly
|
||||||
|
rcvr = addParameter("rec$", samDesc.getParameterTypes().head, false);
|
||||||
|
samPTypes = samPTypes.tail;
|
||||||
|
descPTypes = descPTypes.tail;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rcvr = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
List<Type> implPTypes = tree.sym.type.getParameterTypes();
|
||||||
|
int implSize = implPTypes.size();
|
||||||
|
int samSize = samPTypes.size();
|
||||||
|
// Last parameter to copy from referenced method, exclude final var args
|
||||||
|
int last = localContext.needsVarArgsConversion() ? implSize - 1 : implSize;
|
||||||
|
|
||||||
|
// Failsafe -- assure match-up
|
||||||
|
boolean checkForIntersection = tree.varargsElement != null || implSize == descPTypes.size();
|
||||||
|
|
||||||
|
// Use parameter types of the implementation method unless the unerased
|
||||||
|
// SAM parameter type is an intersection type, in that case use the
|
||||||
|
// erased SAM parameter type so that the supertype relationship
|
||||||
|
// the implementation method parameters is not obscured.
|
||||||
|
// Note: in this loop, the lists implPTypes, samPTypes, and descPTypes
|
||||||
|
// are used as pointers to the current parameter type information
|
||||||
|
// and are thus not usable afterwards.
|
||||||
|
for (int i = 0; implPTypes.nonEmpty() && i < last; ++i) {
|
||||||
|
// By default use the implementation method parmeter type
|
||||||
|
Type parmType = implPTypes.head;
|
||||||
|
// If the unerased parameter type is a type variable whose
|
||||||
|
// bound is an intersection (eg. <T extends A & B>) then
|
||||||
|
// use the SAM parameter type
|
||||||
|
if (checkForIntersection && descPTypes.head.getKind() == TypeKind.TYPEVAR) {
|
||||||
|
TypeVar tv = (TypeVar) descPTypes.head;
|
||||||
|
if (tv.bound.getKind() == TypeKind.INTERSECTION) {
|
||||||
|
parmType = samPTypes.head;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addParameter("x$" + i, parmType, true);
|
||||||
|
|
||||||
|
// Advance to the next parameter
|
||||||
|
implPTypes = implPTypes.tail;
|
||||||
|
samPTypes = samPTypes.tail;
|
||||||
|
descPTypes = descPTypes.tail;
|
||||||
|
}
|
||||||
|
// Flatten out the var args
|
||||||
|
for (int i = last; i < samSize; ++i) {
|
||||||
|
addParameter("xva$" + i, tree.varargsElement, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rcvr;
|
||||||
|
}
|
||||||
|
|
||||||
JCExpression getReceiverExpression() {
|
JCExpression getReceiverExpression() {
|
||||||
return receiverExpression;
|
return receiverExpression;
|
||||||
}
|
}
|
||||||
|
@ -2063,12 +2098,36 @@ public class LambdaToMethod extends TreeTranslator {
|
||||||
types.isSignaturePolymorphic((MethodSymbol)tree.sym);
|
types.isSignaturePolymorphic((MethodSymbol)tree.sym);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erasure destroys the implementation parameter subtype
|
||||||
|
* relationship for intersection types
|
||||||
|
*/
|
||||||
|
boolean interfaceParameterIsIntersectionType() {
|
||||||
|
List<Type> tl = tree.getDescriptorType(types).getParameterTypes();
|
||||||
|
if (tree.kind == ReferenceKind.UNBOUND) {
|
||||||
|
tl = tl.tail;
|
||||||
|
}
|
||||||
|
for (; tl.nonEmpty(); tl = tl.tail) {
|
||||||
|
Type pt = tl.head;
|
||||||
|
if (pt.getKind() == TypeKind.TYPEVAR) {
|
||||||
|
TypeVar tv = (TypeVar) pt;
|
||||||
|
if (tv.bound.getKind() == TypeKind.INTERSECTION) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does this reference need to be converted to a lambda
|
* Does this reference need to be converted to a lambda
|
||||||
* (i.e. var args need to be expanded or "super" is used)
|
* (i.e. var args need to be expanded or "super" is used)
|
||||||
*/
|
*/
|
||||||
final boolean needsConversionToLambda() {
|
final boolean needsConversionToLambda() {
|
||||||
return isSuper || needsVarArgsConversion() || isArrayOp() ||
|
return interfaceParameterIsIntersectionType() ||
|
||||||
|
isSuper ||
|
||||||
|
needsVarArgsConversion() ||
|
||||||
|
isArrayOp() ||
|
||||||
isPrivateInOtherClass() ||
|
isPrivateInOtherClass() ||
|
||||||
!receiverAccessible() ||
|
!receiverAccessible() ||
|
||||||
(tree.getMode() == ReferenceMode.NEW &&
|
(tree.getMode() == ReferenceMode.NEW &&
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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 8058112
|
||||||
|
* @summary Invalid BootstrapMethod for constructor/method reference
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static java.util.stream.Collectors.toList;
|
||||||
|
|
||||||
|
public class MethodReferenceIntersection1 {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
MethodReferenceIntersection1 main = new MethodReferenceIntersection1();
|
||||||
|
List<Info_MRI1> list = main.toInfoListError(Arrays.asList(new Base_MRI1()));
|
||||||
|
System.out.printf("result %d\n", list.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
public <H extends B_MRI1 & A_MRI1> List<Info_MRI1> toInfoListError(List<H> list) {
|
||||||
|
Comparator<B_MRI1> byNameComparator =
|
||||||
|
(B_MRI1 b1, B_MRI1 b2) -> b1.getB().compareToIgnoreCase(b2.getB());
|
||||||
|
return list.stream().sorted(byNameComparator).map(Info_MRI1::new).collect(toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public <H extends B_MRI1 & A_MRI1> List<Info_MRI1> toInfoListWorks(List<H> list) {
|
||||||
|
Comparator<B_MRI1> byNameComparator =
|
||||||
|
(B_MRI1 b1, B_MRI1 b2) -> b1.getB().compareToIgnoreCase(b2.getB());
|
||||||
|
return list.stream().sorted(byNameComparator).map(s -> new Info_MRI1(s)).collect(toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface B_MRI1 {
|
||||||
|
public String getB();
|
||||||
|
}
|
||||||
|
|
||||||
|
interface A_MRI1 {
|
||||||
|
public long getA();
|
||||||
|
}
|
||||||
|
|
||||||
|
class Info_MRI1 {
|
||||||
|
private final long a;
|
||||||
|
private final String b;
|
||||||
|
|
||||||
|
<H extends A_MRI1 & B_MRI1> Info_MRI1(H h) {
|
||||||
|
a = h.getA();
|
||||||
|
b = h.getB();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Base_MRI1 implements A_MRI1, B_MRI1 {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getA() {
|
||||||
|
return 7L;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getB() {
|
||||||
|
return "hello";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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 8058112
|
||||||
|
* @summary Invalid BootstrapMethod for constructor/method reference
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class MethodReferenceIntersection2 {
|
||||||
|
|
||||||
|
interface B { }
|
||||||
|
|
||||||
|
interface A { }
|
||||||
|
|
||||||
|
static class C implements A, B { }
|
||||||
|
|
||||||
|
static class Info {
|
||||||
|
<H extends A & B> Info(H h) { }
|
||||||
|
|
||||||
|
static <H extends A & B> Info info(H h) {
|
||||||
|
return new Info(h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
test();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note the switch in order compared to that on Info
|
||||||
|
static <H extends B & A> void test() {
|
||||||
|
Function<H, Info> f1L = _h -> new Info(_h);
|
||||||
|
Function<H, Info> f1 = Info::new;
|
||||||
|
Function<H, Info> f2L = _h -> Info.info(_h);
|
||||||
|
Function<H, Info> f2 = Info::info;
|
||||||
|
H c = (H) new C();
|
||||||
|
if(f1.apply(c) instanceof Info &&
|
||||||
|
f2.apply(c) instanceof Info) {
|
||||||
|
System.out.println("Passes.");
|
||||||
|
} else {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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 8058112
|
||||||
|
* @summary Invalid BootstrapMethod for constructor/method reference
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Remi Forax
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class MethodReferenceIntersection3 {
|
||||||
|
interface A {}
|
||||||
|
|
||||||
|
interface Foo {
|
||||||
|
<T extends Object & A> void foo(T t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static <T extends A> void bar(T t) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Foo foo = MethodReferenceIntersection3::bar;
|
||||||
|
foo.foo(new A(){});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue