Don't generate bridges for equals(), hashCode(), toString()
Otherwise an assertion is failing in the algorithm which is related to an inconsistency of java.lang.Object inheritance in JDR (KT-4890)
This commit is contained in:
@@ -47,6 +47,7 @@ import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
|||||||
import org.jetbrains.jet.lang.resolve.constants.JavaClassValue;
|
import org.jetbrains.jet.lang.resolve.constants.JavaClassValue;
|
||||||
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
|
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
|
||||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||||
|
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||||
import org.jetbrains.org.objectweb.asm.AnnotationVisitor;
|
import org.jetbrains.org.objectweb.asm.AnnotationVisitor;
|
||||||
import org.jetbrains.org.objectweb.asm.Label;
|
import org.jetbrains.org.objectweb.asm.Label;
|
||||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||||
@@ -427,6 +428,9 @@ public class FunctionCodegen extends ParentCodegenAwareImpl {
|
|||||||
if (owner.getContextKind() == OwnerKind.TRAIT_IMPL) return;
|
if (owner.getContextKind() == OwnerKind.TRAIT_IMPL) return;
|
||||||
if (isTrait(descriptor.getContainingDeclaration())) return;
|
if (isTrait(descriptor.getContainingDeclaration())) return;
|
||||||
|
|
||||||
|
// equals(Any?), hashCode(), toString() never need bridges
|
||||||
|
if (isMethodOfAny(descriptor)) return;
|
||||||
|
|
||||||
// If the function doesn't have a physical declaration among super-functions, it's a SAM adapter or alike and doesn't need bridges
|
// If the function doesn't have a physical declaration among super-functions, it's a SAM adapter or alike and doesn't need bridges
|
||||||
if (CallResolverUtil.isOrOverridesSynthesized(descriptor)) return;
|
if (CallResolverUtil.isOrOverridesSynthesized(descriptor)) return;
|
||||||
|
|
||||||
@@ -448,6 +452,19 @@ public class FunctionCodegen extends ParentCodegenAwareImpl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isMethodOfAny(@NotNull FunctionDescriptor descriptor) {
|
||||||
|
String name = descriptor.getName().asString();
|
||||||
|
List<ValueParameterDescriptor> parameters = descriptor.getValueParameters();
|
||||||
|
if (parameters.isEmpty()) {
|
||||||
|
return name.equals("hashCode") || name.equals("toString");
|
||||||
|
}
|
||||||
|
else if (parameters.size() == 1 && name.equals("equals")) {
|
||||||
|
ValueParameterDescriptor parameter = parameters.get(0);
|
||||||
|
return parameter.getType().equals(KotlinBuiltIns.getInstance().getNullableAnyType());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private static String[] getThrownExceptions(@NotNull FunctionDescriptor function, @NotNull final JetTypeMapper mapper) {
|
private static String[] getThrownExceptions(@NotNull FunctionDescriptor function, @NotNull final JetTypeMapper mapper) {
|
||||||
AnnotationDescriptor annotation = function.getAnnotations().findAnnotation(new FqName("kotlin.throws"));
|
AnnotationDescriptor annotation = function.getAnnotations().findAnnotation(new FqName("kotlin.throws"));
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import java.util.HashSet
|
||||||
|
|
||||||
|
trait A : Set<String>
|
||||||
|
|
||||||
|
class B : A, HashSet<String>() {
|
||||||
|
override fun clone(): B = throw AssertionError()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
return try {
|
||||||
|
B().clone()
|
||||||
|
"Fail 1"
|
||||||
|
} catch (e: AssertionError) {
|
||||||
|
try {
|
||||||
|
(B() : HashSet<String>).clone()
|
||||||
|
"Fail 2"
|
||||||
|
} catch (e: AssertionError) {
|
||||||
|
"OK"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import java.util.HashSet
|
||||||
|
|
||||||
|
trait A : Set<String>
|
||||||
|
|
||||||
|
class B : A, HashSet<String>()
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val b = B()
|
||||||
|
b.add("OK")
|
||||||
|
return b.iterator().next()
|
||||||
|
}
|
||||||
@@ -405,6 +405,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest("compiler/testData/codegen/box/bridges/noBridgeOnMutableCollectionInheritance.kt");
|
doTest("compiler/testData/codegen/box/bridges/noBridgeOnMutableCollectionInheritance.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("objectClone.kt")
|
||||||
|
public void testObjectClone() throws Exception {
|
||||||
|
doTest("compiler/testData/codegen/box/bridges/objectClone.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("overrideAbstractProperty.kt")
|
@TestMetadata("overrideAbstractProperty.kt")
|
||||||
public void testOverrideAbstractProperty() throws Exception {
|
public void testOverrideAbstractProperty() throws Exception {
|
||||||
doTest("compiler/testData/codegen/box/bridges/overrideAbstractProperty.kt");
|
doTest("compiler/testData/codegen/box/bridges/overrideAbstractProperty.kt");
|
||||||
@@ -1086,6 +1091,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest("compiler/testData/codegen/box/classes/funDelegation.kt");
|
doTest("compiler/testData/codegen/box/classes/funDelegation.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inheritSetAndHashSet.kt")
|
||||||
|
public void testInheritSetAndHashSet() throws Exception {
|
||||||
|
doTest("compiler/testData/codegen/box/classes/inheritSetAndHashSet.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("inheritance.kt")
|
@TestMetadata("inheritance.kt")
|
||||||
public void testInheritance() throws Exception {
|
public void testInheritance() throws Exception {
|
||||||
doTest("compiler/testData/codegen/box/classes/inheritance.kt");
|
doTest("compiler/testData/codegen/box/classes/inheritance.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user