From cb9c18b7ad2e00f4c1e1db3ce75a4e45ee7b8e28 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 30 Jul 2012 16:11:38 +0400 Subject: [PATCH] KT-2498 Bridge method is not generated for method when generic parameters are substituted in superclass #KT-2498 Fixed generateBridgeIfNeeded() now works as follows: for a given method, find which declared methods does this method override via breadth-first search. For each such declared method, generate a bridge if and only if its signature is different. Keep different methods' signatures in a set to avoid duplicated bridge signatures. --- .../jet/codegen/FunctionCodegen.java | 118 +++++++++++------- .../codegen/bridges/delegationToTraitImpl.kt | 15 +++ compiler/testData/codegen/bridges/diamond.kt | 23 ++++ .../codegen/bridges/longChainOneBridge.kt | 28 +++++ ...anyTypeArgumentsSubstitutedSuccessively.kt | 23 ++++ .../codegen/bridges/methodFromTrait.kt | 16 +++ compiler/testData/codegen/bridges/simple.kt | 17 +++ .../testData/codegen/bridges/simpleEnum.kt | 20 +++ .../codegen/bridges/simpleGenericMethod.kt | 17 +++ .../testData/codegen/bridges/simpleObject.kt | 21 ++++ .../codegen/bridges/simpleReturnType.kt | 16 +++ .../codegen/bridges/simpleUpperBound.kt | 17 +++ .../bridges/substitutionInSuperClass.kt | 20 +++ .../substitutionInSuperClassAbstractFun.kt | 20 +++ ...itutionInSuperClassBoundedTypeArguments.kt | 19 +++ .../bridges/substitutionInSuperClassEnum.kt | 24 ++++ .../substitutionInSuperClassGenericMethod.kt | 20 +++ .../bridges/substitutionInSuperClassObject.kt | 25 ++++ .../substitutionInSuperClassUpperBound.kt | 20 +++ ...woParentsWithDifferentMethodsTwoBridges.kt | 22 ++++ .../twoParentsWithTheSameMethodOneBridge.kt | 22 ++++ .../testData/codegen/regressions/kt2498.kt | 19 +++ .../jet/codegen/BridgeMethodGenTest.java | 108 +++++++++++++++- 23 files changed, 602 insertions(+), 48 deletions(-) create mode 100644 compiler/testData/codegen/bridges/delegationToTraitImpl.kt create mode 100644 compiler/testData/codegen/bridges/diamond.kt create mode 100644 compiler/testData/codegen/bridges/longChainOneBridge.kt create mode 100644 compiler/testData/codegen/bridges/manyTypeArgumentsSubstitutedSuccessively.kt create mode 100644 compiler/testData/codegen/bridges/methodFromTrait.kt create mode 100644 compiler/testData/codegen/bridges/simple.kt create mode 100644 compiler/testData/codegen/bridges/simpleEnum.kt create mode 100644 compiler/testData/codegen/bridges/simpleGenericMethod.kt create mode 100644 compiler/testData/codegen/bridges/simpleObject.kt create mode 100644 compiler/testData/codegen/bridges/simpleReturnType.kt create mode 100644 compiler/testData/codegen/bridges/simpleUpperBound.kt create mode 100644 compiler/testData/codegen/bridges/substitutionInSuperClass.kt create mode 100644 compiler/testData/codegen/bridges/substitutionInSuperClassAbstractFun.kt create mode 100644 compiler/testData/codegen/bridges/substitutionInSuperClassBoundedTypeArguments.kt create mode 100644 compiler/testData/codegen/bridges/substitutionInSuperClassEnum.kt create mode 100644 compiler/testData/codegen/bridges/substitutionInSuperClassGenericMethod.kt create mode 100644 compiler/testData/codegen/bridges/substitutionInSuperClassObject.kt create mode 100644 compiler/testData/codegen/bridges/substitutionInSuperClassUpperBound.kt create mode 100644 compiler/testData/codegen/bridges/twoParentsWithDifferentMethodsTwoBridges.kt create mode 100644 compiler/testData/codegen/bridges/twoParentsWithTheSameMethodOneBridge.kt create mode 100644 compiler/testData/codegen/regressions/kt2498.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java index a54f455bc13..ef5a85bc8b8 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -341,13 +341,47 @@ public class FunctionCodegen { } static void generateBridgeIfNeeded(CodegenContext owner, GenerationState state, ClassBuilder v, Method jvmSignature, FunctionDescriptor functionDescriptor, OwnerKind kind) { - Set overriddenFunctions = functionDescriptor.getOverriddenDescriptors(); - if (kind != OwnerKind.TRAIT_IMPL) { - for (FunctionDescriptor overriddenFunction : overriddenFunctions) { - // TODO should we check params here as well? - checkOverride(owner, state, v, jvmSignature, functionDescriptor, overriddenFunction.getOriginal()); + if (kind == OwnerKind.TRAIT_IMPL) { + return; + } + + Method method = state.getInjector().getJetTypeMapper().mapSignature(functionDescriptor.getName(), functionDescriptor).getAsmMethod(); + + Queue bfsQueue = new LinkedList(); + Set visited = new HashSet(); + + bfsQueue.offer(functionDescriptor.getOriginal()); + visited.add(functionDescriptor.getOriginal()); + for (FunctionDescriptor overriddenDescriptor : functionDescriptor.getOverriddenDescriptors()) { + FunctionDescriptor orig = overriddenDescriptor.getOriginal(); + if (!visited.contains(orig)) { + bfsQueue.offer(overriddenDescriptor); + visited.add(overriddenDescriptor); } - checkOverride(owner, state, v, jvmSignature, functionDescriptor, functionDescriptor.getOriginal()); + } + + Set bridgesToGenerate = new HashSet(); + while (!bfsQueue.isEmpty()) { + FunctionDescriptor descriptor = bfsQueue.poll(); + if (descriptor.getKind() == CallableMemberDescriptor.Kind.DECLARATION) { + Method overridden = state.getInjector().getJetTypeMapper().mapSignature(descriptor.getName(), descriptor.getOriginal()).getAsmMethod(); + if (differentMethods(method, overridden)) { + bridgesToGenerate.add(overridden); + } + continue; + } + + for (FunctionDescriptor overriddenDescriptor : descriptor.getOverriddenDescriptors()) { + FunctionDescriptor orig = overriddenDescriptor.getOriginal(); + if (!visited.contains(orig)) { + bfsQueue.offer(orig); + visited.add(orig); + } + } + } + + for (Method overridden : bridgesToGenerate) { + generateBridge(owner, state, v, jvmSignature, functionDescriptor, overridden); } } @@ -516,53 +550,43 @@ public class FunctionCodegen { return false; } - private static void checkOverride(CodegenContext owner, GenerationState state, ClassBuilder v, Method jvmSignature, FunctionDescriptor functionDescriptor, FunctionDescriptor overriddenFunction) { - Method method = state.getInjector().getJetTypeMapper().mapSignature(functionDescriptor.getName(), functionDescriptor).getAsmMethod(); - Method overridden = state.getInjector().getJetTypeMapper().mapSignature(overriddenFunction.getName(), overriddenFunction.getOriginal()).getAsmMethod(); + private static void generateBridge(CodegenContext owner, GenerationState state, ClassBuilder v, Method jvmSignature, FunctionDescriptor functionDescriptor, Method overridden) { + int flags = ACC_PUBLIC | ACC_BRIDGE; // TODO. - if (overriddenFunction.getModality() == Modality.ABSTRACT) { - Set overriddenFunctions = overriddenFunction.getOverriddenDescriptors(); - for (FunctionDescriptor of : overriddenFunctions) { - checkOverride(owner, state, v, jvmSignature, overriddenFunction, of.getOriginal()); - } + final MethodVisitor mv = v.newMethod(null, flags, jvmSignature.getName(), overridden.getDescriptor(), null, null); + if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) { + StubCodegen.generateStubCode(mv); } + else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { + mv.visitCode(); - if (differentMethods(method, overridden)) { - int flags = ACC_PUBLIC | ACC_BRIDGE; // TODO. - - final MethodVisitor mv = v.newMethod(null, flags, jvmSignature.getName(), overridden.getDescriptor(), null, null); - if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) { - StubCodegen.generateStubCode(mv); - } - else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { - mv.visitCode(); - - Type[] argTypes = overridden.getArgumentTypes(); - InstructionAdapter iv = new InstructionAdapter(mv); - iv.load(0, JetTypeMapper.TYPE_OBJECT); - for (int i = 0, reg = 1; i < argTypes.length; i++) { - Type argType = argTypes[i]; - iv.load(reg, argType); - if (argType.getSort() == Type.OBJECT) { - StackValue.onStack(JetTypeMapper.TYPE_OBJECT).put(jvmSignature.getArgumentTypes()[i], iv); - } - else if (argType.getSort() == Type.ARRAY) { - StackValue.onStack(JetTypeMapper.ARRAY_GENERIC_TYPE).put(jvmSignature.getArgumentTypes()[i], iv); - } - - //noinspection AssignmentToForLoopParameter - reg += argType.getSize(); + Type[] argTypes = overridden.getArgumentTypes(); + Type[] originalArgTypes = jvmSignature.getArgumentTypes(); + InstructionAdapter iv = new InstructionAdapter(mv); + iv.load(0, JetTypeMapper.TYPE_OBJECT); + for (int i = 0, reg = 1; i < argTypes.length; i++) { + Type argType = argTypes[i]; + iv.load(reg, argType); + if (argType.getSort() == Type.OBJECT) { + StackValue.onStack(JetTypeMapper.TYPE_OBJECT).put(originalArgTypes[i], iv); + } + else if (argType.getSort() == Type.ARRAY) { + StackValue.onStack(JetTypeMapper.ARRAY_GENERIC_TYPE).put(originalArgTypes[i], iv); } - iv.invokevirtual(state.getInjector().getJetTypeMapper().mapType(((ClassDescriptor) owner.getContextDescriptor()).getDefaultType(), MapTypeMode.VALUE).getInternalName(), - jvmSignature.getName(), jvmSignature.getDescriptor()); - if (JetTypeMapper.isPrimitive(jvmSignature.getReturnType()) && !JetTypeMapper.isPrimitive(overridden.getReturnType())) - StackValue.valueOf(iv, jvmSignature.getReturnType()); - if (jvmSignature.getReturnType() == Type.VOID_TYPE) - iv.aconst(null); - iv.areturn(overridden.getReturnType()); - endVisit(mv, "bridge method", BindingContextUtils.callableDescriptorToDeclaration(state.getBindingContext(), functionDescriptor)); + //noinspection AssignmentToForLoopParameter + reg += argType.getSize(); } + + iv.invokevirtual(state.getInjector().getJetTypeMapper().mapType( + ((ClassDescriptor) owner.getContextDescriptor()).getDefaultType(), MapTypeMode.VALUE).getInternalName(), + jvmSignature.getName(), jvmSignature.getDescriptor()); + if (JetTypeMapper.isPrimitive(jvmSignature.getReturnType()) && !JetTypeMapper.isPrimitive(overridden.getReturnType())) + StackValue.valueOf(iv, jvmSignature.getReturnType()); + if (jvmSignature.getReturnType() == Type.VOID_TYPE) + iv.aconst(null); + iv.areturn(overridden.getReturnType()); + endVisit(mv, "bridge method", BindingContextUtils.callableDescriptorToDeclaration(state.getBindingContext(), functionDescriptor)); } } diff --git a/compiler/testData/codegen/bridges/delegationToTraitImpl.kt b/compiler/testData/codegen/bridges/delegationToTraitImpl.kt new file mode 100644 index 00000000000..9cd6c1d6b5f --- /dev/null +++ b/compiler/testData/codegen/bridges/delegationToTraitImpl.kt @@ -0,0 +1,15 @@ +trait A { + fun foo(t: T) = "A" +} + +class Z : A + + +fun box(): String { + val z = Z() + return when { + z.foo("") != "A" -> "Fail #1" + (z : A).foo("") != "A" -> "Fail #2" + else -> "OK" + } +} diff --git a/compiler/testData/codegen/bridges/diamond.kt b/compiler/testData/codegen/bridges/diamond.kt new file mode 100644 index 00000000000..2e798707253 --- /dev/null +++ b/compiler/testData/codegen/bridges/diamond.kt @@ -0,0 +1,23 @@ +trait A { + fun foo(t: T, u: U) = "A" +} + +trait B : A + +trait C : A + +class Z : B, C { + override fun foo(t: String, u: Int) = "Z" +} + + +fun box(): String { + val z = Z() + return when { + z.foo("", 0) != "Z" -> "Fail #1" + (z : C).foo("", 0) != "Z" -> "Fail #2" + (z : B).foo("", 0) != "Z" -> "Fail #3" + (z : A).foo("", 0) != "Z" -> "Fail #4" + else -> "OK" + } +} diff --git a/compiler/testData/codegen/bridges/longChainOneBridge.kt b/compiler/testData/codegen/bridges/longChainOneBridge.kt new file mode 100644 index 00000000000..4f47fe333e1 --- /dev/null +++ b/compiler/testData/codegen/bridges/longChainOneBridge.kt @@ -0,0 +1,28 @@ +open class A { + open fun foo(t: T) = "A" +} + +open class B : A() + +open class C : B() { + override fun foo(t: String) = "C" +} + +open class D : C() + +class Z : D() { + override fun foo(t: String) = "Z" +} + + +fun box(): String { + val z = Z() + return when { + z.foo("") != "Z" -> "Fail #1" + (z : D).foo("") != "Z" -> "Fail #2" + (z : C).foo("") != "Z" -> "Fail #3" + (z : B).foo("") != "Z" -> "Fail #4" + (z : A).foo("") != "Z" -> "Fail #5" + else -> "OK" + } +} diff --git a/compiler/testData/codegen/bridges/manyTypeArgumentsSubstitutedSuccessively.kt b/compiler/testData/codegen/bridges/manyTypeArgumentsSubstitutedSuccessively.kt new file mode 100644 index 00000000000..c66feefd1d2 --- /dev/null +++ b/compiler/testData/codegen/bridges/manyTypeArgumentsSubstitutedSuccessively.kt @@ -0,0 +1,23 @@ +open class A { + open fun foo(t: T, u: U, v: V) = "A" +} + +open class B : A() + +open class C : B() + +class Z : C() { + override fun foo(t: String, u: Int, v: Double) = "Z" +} + + +fun box(): String { + val z = Z() + return when { + z.foo("", 0, 0.0) != "Z" -> "Fail #1" + (z : C).foo("", 0, 0.0) != "Z" -> "Fail #2" + (z : B).foo("", 0, 0.0) != "Z" -> "Fail #3" + (z : A).foo("", 0, 0.0) != "Z" -> "Fail #4" + else -> "OK" + } +} diff --git a/compiler/testData/codegen/bridges/methodFromTrait.kt b/compiler/testData/codegen/bridges/methodFromTrait.kt new file mode 100644 index 00000000000..95c87724b52 --- /dev/null +++ b/compiler/testData/codegen/bridges/methodFromTrait.kt @@ -0,0 +1,16 @@ +trait A { + fun foo(t: T, u: U) = "A" +} + +class Z : A { + override fun foo(t: T, u: Int) = "Z" +} + +fun box(): String { + val z = Z() + return when { + z.foo(0, 0) != "Z" -> "Fail #1" + (z : A).foo(0, 0) != "Z" -> "Fail #2" + else -> "OK" + } +} diff --git a/compiler/testData/codegen/bridges/simple.kt b/compiler/testData/codegen/bridges/simple.kt new file mode 100644 index 00000000000..80a996ec6d4 --- /dev/null +++ b/compiler/testData/codegen/bridges/simple.kt @@ -0,0 +1,17 @@ +open class A { + open fun foo(t: T) = "A" +} + +class Z : A() { + override fun foo(t: String) = "Z" +} + + +fun box(): String { + val z = Z() + return when { + z.foo("") != "Z" -> "Fail #1" + (z : A).foo("") != "Z" -> "Fail #2" + else -> "OK" + } +} diff --git a/compiler/testData/codegen/bridges/simpleEnum.kt b/compiler/testData/codegen/bridges/simpleEnum.kt new file mode 100644 index 00000000000..e760837b352 --- /dev/null +++ b/compiler/testData/codegen/bridges/simpleEnum.kt @@ -0,0 +1,20 @@ +open enum class A { + open fun foo(t: T) = "A" +} + +enum class Z(val name: String) : A() { + Z1 : Z("Z1") + Z2 : Z("Z2") + override fun foo(t: String) = name +} + + +fun box(): String { + return when { + Z.Z1.foo("") != "Z1" -> "Fail #1" + Z.Z2.foo("") != "Z2" -> "Fail #2" + (Z.Z1 : A).foo("") != "Z1" -> "Fail #3" + (Z.Z2 : A).foo("") != "Z2" -> "Fail #4" + else -> "OK" + } +} diff --git a/compiler/testData/codegen/bridges/simpleGenericMethod.kt b/compiler/testData/codegen/bridges/simpleGenericMethod.kt new file mode 100644 index 00000000000..95ef4de467c --- /dev/null +++ b/compiler/testData/codegen/bridges/simpleGenericMethod.kt @@ -0,0 +1,17 @@ +open class A { + open fun foo(t: T, u: U) = "A" +} + +class Z : A() { + override fun foo(t: String, u: U) = "Z" +} + + +fun box(): String { + val z = Z() + return when { + z.foo("", 0) != "Z" -> "Fail #1" + (z : A).foo("", 0) != "Z" -> "Fail #2" + else -> "OK" + } +} diff --git a/compiler/testData/codegen/bridges/simpleObject.kt b/compiler/testData/codegen/bridges/simpleObject.kt new file mode 100644 index 00000000000..6f378c9deda --- /dev/null +++ b/compiler/testData/codegen/bridges/simpleObject.kt @@ -0,0 +1,21 @@ +open class A { + open fun foo(t: T) = "A" +} + +object Z : A() { + override fun foo(t: String) = "Z" +} + + +fun box(): String { + val z = object : A() { + override fun foo(t: String) = "z" + } + return when { + Z.foo("") != "Z" -> "Fail #1" + z.foo("") != "z" -> "Fail #2" + (Z : A).foo("") != "Z" -> "Fail #3" + (z : A).foo("") != "z" -> "Fail #4" + else -> "OK" + } +} diff --git a/compiler/testData/codegen/bridges/simpleReturnType.kt b/compiler/testData/codegen/bridges/simpleReturnType.kt new file mode 100644 index 00000000000..d00af1d3913 --- /dev/null +++ b/compiler/testData/codegen/bridges/simpleReturnType.kt @@ -0,0 +1,16 @@ +open class A(val t: T) { + open fun foo(): T = t +} + +class Z : A(17) { + override fun foo() = 239 +} + +fun box(): String { + val z = Z() + return when { + z.foo() != 239 -> "Fail #1" + (z : A).foo() != 239 -> "Fail #2" + else -> "OK" + } +} diff --git a/compiler/testData/codegen/bridges/simpleUpperBound.kt b/compiler/testData/codegen/bridges/simpleUpperBound.kt new file mode 100644 index 00000000000..eb57d12065e --- /dev/null +++ b/compiler/testData/codegen/bridges/simpleUpperBound.kt @@ -0,0 +1,17 @@ +open class A { + open fun foo(t: T) = "A" +} + +class Z : A() { + override fun foo(t: Int) = "Z" +} + + +fun box(): String { + val z = Z() + return when { + z.foo(0) != "Z" -> "Fail #1" + (z : A).foo(0) != "Z" -> "Fail #2" + else -> "OK" + } +} diff --git a/compiler/testData/codegen/bridges/substitutionInSuperClass.kt b/compiler/testData/codegen/bridges/substitutionInSuperClass.kt new file mode 100644 index 00000000000..dae5c4c0f33 --- /dev/null +++ b/compiler/testData/codegen/bridges/substitutionInSuperClass.kt @@ -0,0 +1,20 @@ +open class A { + open fun foo(t: T) = "A" +} + +open class B : A() + +class Z : B() { + override fun foo(t: String) = "Z" +} + + +fun box(): String { + val z = Z() + return when { + z.foo("") != "Z" -> "Fail #1" + (z : B).foo("") != "Z" -> "Fail #2" + (z : A).foo("") != "Z" -> "Fail #3" + else -> "OK" + } +} diff --git a/compiler/testData/codegen/bridges/substitutionInSuperClassAbstractFun.kt b/compiler/testData/codegen/bridges/substitutionInSuperClassAbstractFun.kt new file mode 100644 index 00000000000..6c658283d1f --- /dev/null +++ b/compiler/testData/codegen/bridges/substitutionInSuperClassAbstractFun.kt @@ -0,0 +1,20 @@ +abstract class A { + abstract fun foo(t: T): String +} + +abstract class B : A() + +class Z : B() { + override fun foo(t: String) = "Z" +} + + +fun box(): String { + val z = Z() + return when { + z.foo("") != "Z" -> "Fail #1" + (z : B).foo("") != "Z" -> "Fail #2" + (z : A).foo("") != "Z" -> "Fail #3" + else -> "OK" + } +} diff --git a/compiler/testData/codegen/bridges/substitutionInSuperClassBoundedTypeArguments.kt b/compiler/testData/codegen/bridges/substitutionInSuperClassBoundedTypeArguments.kt new file mode 100644 index 00000000000..2b6015812f7 --- /dev/null +++ b/compiler/testData/codegen/bridges/substitutionInSuperClassBoundedTypeArguments.kt @@ -0,0 +1,19 @@ +open class A { + open fun foo(t: T, u: U) = "A" +} + +open class B : A() + +class Z : B() { + override fun foo(t: Int, u: Number) = "Z" +} + +fun box(): String { + val z = Z() + return when { + z.foo(0, 0) != "Z" -> "Fail #1" + (z : B).foo(0, 0) != "Z" -> "Fail #2" + (z : A).foo(0, 0) != "Z" -> "Fail #3" + else -> "OK" + } +} diff --git a/compiler/testData/codegen/bridges/substitutionInSuperClassEnum.kt b/compiler/testData/codegen/bridges/substitutionInSuperClassEnum.kt new file mode 100644 index 00000000000..ce191b04c23 --- /dev/null +++ b/compiler/testData/codegen/bridges/substitutionInSuperClassEnum.kt @@ -0,0 +1,24 @@ +open enum class A { + open fun foo(t: T) = "A" +} + +open enum class B : A() + +enum class Z(val name: String) : B() { + Z1 : Z("Z1") + Z2 : Z("Z2") + override fun foo(t: String) = name +} + + +fun box(): String { + return when { + Z.Z1.foo("") != "Z1" -> "Fail #1" + Z.Z2.foo("") != "Z2" -> "Fail #2" + (Z.Z1 : B).foo("") != "Z1" -> "Fail #3" + (Z.Z2 : B).foo("") != "Z2" -> "Fail #4" + (Z.Z1 : A).foo("") != "Z1" -> "Fail #5" + (Z.Z2 : A).foo("") != "Z2" -> "Fail #6" + else -> "OK" + } +} diff --git a/compiler/testData/codegen/bridges/substitutionInSuperClassGenericMethod.kt b/compiler/testData/codegen/bridges/substitutionInSuperClassGenericMethod.kt new file mode 100644 index 00000000000..ee22fb3ca43 --- /dev/null +++ b/compiler/testData/codegen/bridges/substitutionInSuperClassGenericMethod.kt @@ -0,0 +1,20 @@ +open class A { + open fun foo(t: T, u: U) = "A" +} + +open class B : A() + +class Z : B() { + override fun foo(t: String, u: U) = "Z" +} + + +fun box(): String { + val z = Z() + return when { + z.foo("", 0) != "Z" -> "Fail #1" + (z : B).foo("", 0) != "Z" -> "Fail #2" + (z : A).foo("", 0) != "Z" -> "Fail #3" + else -> "OK" + } +} diff --git a/compiler/testData/codegen/bridges/substitutionInSuperClassObject.kt b/compiler/testData/codegen/bridges/substitutionInSuperClassObject.kt new file mode 100644 index 00000000000..6e436d0c724 --- /dev/null +++ b/compiler/testData/codegen/bridges/substitutionInSuperClassObject.kt @@ -0,0 +1,25 @@ +open class A { + open fun foo(t: T) = "A" +} + +open class B : A() + +object Z : B() { + override fun foo(t: String) = "Z" +} + + +fun box(): String { + val o = object : B() { + override fun foo(t: String) = "o" + } + return when { + Z.foo("") != "Z" -> "Fail #1" + o.foo("") != "o" -> "Fail #2" + (Z : B).foo("") != "Z" -> "Fail #3" + (o : B).foo("") != "o" -> "Fail #4" + (Z : A).foo("") != "Z" -> "Fail #5" + (o : A).foo("") != "o" -> "Fail #6" + else -> "OK" + } +} diff --git a/compiler/testData/codegen/bridges/substitutionInSuperClassUpperBound.kt b/compiler/testData/codegen/bridges/substitutionInSuperClassUpperBound.kt new file mode 100644 index 00000000000..ae908934eba --- /dev/null +++ b/compiler/testData/codegen/bridges/substitutionInSuperClassUpperBound.kt @@ -0,0 +1,20 @@ +open class A { + open fun foo(t: T) = "A" +} + +open class B : A() + +class Z : B() { + override fun foo(t: Int) = "Z" +} + + +fun box(): String { + val z = Z() + return when { + z.foo(0) != "Z" -> "Fail #1" + (z : B).foo(0) != "Z" -> "Fail #2" + (z : A).foo(0) != "Z" -> "Fail #3" + else -> "OK" + } +} diff --git a/compiler/testData/codegen/bridges/twoParentsWithDifferentMethodsTwoBridges.kt b/compiler/testData/codegen/bridges/twoParentsWithDifferentMethodsTwoBridges.kt new file mode 100644 index 00000000000..ea9bf3da18c --- /dev/null +++ b/compiler/testData/codegen/bridges/twoParentsWithDifferentMethodsTwoBridges.kt @@ -0,0 +1,22 @@ +trait A { + fun foo(t: T, u: Int) = "A" +} + +trait B { + fun foo(t: T, u: U) = "B" +} + +class Z : A, B { + override fun foo(t: String, u: Int) = "Z" +} + + +fun box(): String { + val z = Z() + return when { + z.foo("", 0) != "Z" -> "Fail #1" + (z : A).foo("", 0) != "Z" -> "Fail #2" + (z : B).foo("", 0) != "Z" -> "Fail #3" + else -> "OK" + } +} diff --git a/compiler/testData/codegen/bridges/twoParentsWithTheSameMethodOneBridge.kt b/compiler/testData/codegen/bridges/twoParentsWithTheSameMethodOneBridge.kt new file mode 100644 index 00000000000..22163c367ef --- /dev/null +++ b/compiler/testData/codegen/bridges/twoParentsWithTheSameMethodOneBridge.kt @@ -0,0 +1,22 @@ +trait A { + fun foo(t: T) = "A" +} + +trait B { + fun foo(t: T) = "B" +} + +class Z : A, B { + override fun foo(t: Int) = "Z" +} + + +fun box(): String { + val z = Z() + return when { + z.foo(0) != "Z" -> "Fail #1" + (z : A).foo(0) != "Z" -> "Fail #2" + (z : B).foo(0) != "Z" -> "Fail #3" + else -> "OK" + } +} diff --git a/compiler/testData/codegen/regressions/kt2498.kt b/compiler/testData/codegen/regressions/kt2498.kt new file mode 100644 index 00000000000..e52b96a0aa9 --- /dev/null +++ b/compiler/testData/codegen/regressions/kt2498.kt @@ -0,0 +1,19 @@ +import java.util.LinkedList + +open class BaseStringList: LinkedList() { +} + +class StringList: BaseStringList() { + public override fun get(index: Int): String { + return "StringList.get()" + } +} + +fun box(): String { + val myStringList = StringList() + myStringList.add("first element") + if (myStringList.get(0) != "StringList.get()") return "Fail #1" + if ((myStringList: BaseStringList).get(0) != "StringList.get()") return "Fail #2" + if ((myStringList: LinkedList).get(0) != "StringList.get()") return "Fail #3" + return "OK" +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/BridgeMethodGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/BridgeMethodGenTest.java index f4853a521c3..a337f0c97d3 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/BridgeMethodGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/BridgeMethodGenTest.java @@ -19,13 +19,119 @@ package org.jetbrains.jet.codegen; import org.jetbrains.jet.ConfigurationKind; public class BridgeMethodGenTest extends CodegenTestCase { + public void testBridgeMethod () throws Exception { createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); blackBoxFile("bridge.jet"); } - + public void testKt1959() { createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); blackBoxFile("regressions/kt1959.kt"); } + + public void testDelegationToTraitImpl() { + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); + blackBoxFile("bridges/delegationToTraitImpl.kt"); + } + + public void testDiamond() { + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); + blackBoxFile("bridges/diamond.kt"); + } + + public void testLongChainOneBridge() { + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); + blackBoxFile("bridges/longChainOneBridge.kt"); + } + + public void testManyTypeArgumentsSubstitutedSuccessively() { + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); + blackBoxFile("bridges/manyTypeArgumentsSubstitutedSuccessively.kt"); + } + + public void testMethodFromTrait() { + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); + blackBoxFile("bridges/methodFromTrait.kt"); + } + + public void testSimple() { + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); + blackBoxFile("bridges/simple.kt"); + } + + public void testSimpleEnum() { + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); + blackBoxFile("bridges/simpleEnum.kt"); + } + + public void testSimpleGenericMethod() { + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); + blackBoxFile("bridges/simpleGenericMethod.kt"); + } + + public void testSimpleObject() { + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); + blackBoxFile("bridges/simpleObject.kt"); + } + + public void testSimpleReturnType() { + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); + blackBoxFile("bridges/simpleReturnType.kt"); + } + + public void testSimpleUpperBound() { + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); + blackBoxFile("bridges/simpleUpperBound.kt"); + } + + public void testSubstitutionInSuperClass() { + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); + blackBoxFile("bridges/substitutionInSuperClass.kt"); + } + + public void testSubstitutionInSuperClassAbstractFun() { + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); + blackBoxFile("bridges/substitutionInSuperClassAbstractFun.kt"); + } + + public void testSubstitutionInSuperClassBoundedTypeArguments() { + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); + blackBoxFile("bridges/substitutionInSuperClassBoundedTypeArguments.kt"); + } + + public void testSubstitutionInSuperClassEnum() { + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); + blackBoxFile("bridges/substitutionInSuperClassEnum.kt"); + } + + public void testSubstitutionInSuperClassGenericMethod() { + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); + blackBoxFile("bridges/substitutionInSuperClassGenericMethod.kt"); + } + + public void testSubstitutionInSuperClassObject() { + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); + blackBoxFile("bridges/substitutionInSuperClassObject.kt"); + } + + public void testSubstitutionInSuperClassUpperBound() { + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); + blackBoxFile("bridges/substitutionInSuperClassUpperBound.kt"); + } + + public void testTwoParentsWithDifferentMethodsTwoBridges() { + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); + blackBoxFile("bridges/twoParentsWithDifferentMethodsTwoBridges.kt"); + } + + public void testTwoParentsWithTheSameMethodOneBridge() { + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); + blackBoxFile("bridges/twoParentsWithTheSameMethodOneBridge.kt"); + } + + public void testKt2498() { + createEnvironmentWithFullJdk(); + blackBoxFile("regressions/kt2498.kt"); + } }