From 57b161b08af1319e0b7a5babf057cb0e56c8417b Mon Sep 17 00:00:00 2001 From: Mikhael Bogdanov Date: Tue, 16 Apr 2013 18:32:24 +0400 Subject: [PATCH] KT-3500: ClassFormatError: Duplicate method name&signature in class file && KT-3429: Traits override bug --- .../codegen/ImplementationBodyCodegen.java | 45 +++++++++++++------ .../jet/lang/resolve/java/JvmAbi.java | 2 +- .../jet/lang/diagnostics/Errors.java | 1 + .../rendering/DefaultErrorMessages.java | 1 + .../jet/lang/resolve/DescriptorUtils.java | 24 ++++++---- .../BasicExpressionTypingVisitor.java | 5 +++ compiler/testData/cli/wrongAbiVersion.out | 4 +- .../codegen/box/traits/genericMethod.kt | 21 +++++++++ .../testData/codegen/box/traits/kt3429.kt | 17 +++++++ .../testData/codegen/box/traits/kt3500.kt | 15 +++++++ .../codegen/box/traits/withRequiredSuper.kt | 12 ++--- .../box/traits/withRequiredSuperViaBridge.kt | 4 +- .../thisAndSuper/notAccessibleSuperInTrait.kt | 10 +++++ .../checkers/JetDiagnosticsTestGenerated.java | 5 +++ .../BlackBoxCodegenTestGenerated.java | 30 +++++++++++++ 15 files changed, 166 insertions(+), 30 deletions(-) create mode 100644 compiler/testData/codegen/box/traits/genericMethod.kt create mode 100644 compiler/testData/codegen/box/traits/kt3429.kt create mode 100644 compiler/testData/codegen/box/traits/kt3500.kt create mode 100644 compiler/testData/diagnostics/tests/thisAndSuper/notAccessibleSuperInTrait.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 2dbb0e29143..16a0bc3cd19 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -17,6 +17,7 @@ package org.jetbrains.jet.codegen; import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.util.Pair; import org.jetbrains.annotations.NotNull; @@ -55,6 +56,7 @@ import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames; import org.jetbrains.jet.lang.resolve.java.kt.DescriptorKindUtils; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.TypeUtils; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.lexer.JetTokens; @@ -1298,8 +1300,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } private void generateTraitMethods() { - if (myClass instanceof JetClass && - (((JetClass) myClass).isTrait() || myClass.hasModifier(JetTokens.ABSTRACT_KEYWORD))) { + if (myClass instanceof JetClass && ((JetClass) myClass).isTrait()) { return; } @@ -1699,7 +1700,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { * Return pairs of descriptors. First is member of this that should be implemented by delegating to trait, * second is member of trait that contain implementation. */ - private static List> getTraitImplementations(@NotNull ClassDescriptor classDescriptor) { + private List> getTraitImplementations(@NotNull ClassDescriptor classDescriptor) { List> r = Lists.newArrayList(); root: @@ -1715,21 +1716,39 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { Collection overriddenDeclarations = OverridingUtil.getOverriddenDeclarations(callableMemberDescriptor); - for (CallableMemberDescriptor overriddenDeclaration : overriddenDeclarations) { - if (overriddenDeclaration.getModality() != Modality.ABSTRACT) { - if (!isInterface(overriddenDeclaration.getContainingDeclaration())) { - continue root; - } + + Collection filteredOverriddenDeclarations = + OverridingUtil.filterOverrides(Sets.newLinkedHashSet(overriddenDeclarations)); + + int count = 0; + CallableMemberDescriptor candidate = null; + + for (CallableMemberDescriptor overriddenDeclaration : filteredOverriddenDeclarations) { + if (isKindOf(overriddenDeclaration.getContainingDeclaration(), ClassKind.TRAIT) && + overriddenDeclaration.getModality() != Modality.ABSTRACT) { + candidate = overriddenDeclaration; + count++; } } + if (candidate == null) { + continue; + } - for (CallableMemberDescriptor overriddenDeclaration : overriddenDeclarations) { - if (overriddenDeclaration.getModality() != Modality.ABSTRACT) { - r.add(Pair.create(callableMemberDescriptor, overriddenDeclaration)); - } + assert count == 1 : "Ambiguous overriden declaration: " + callableMemberDescriptor.getName(); + + + Collection superTypesOfSuperClass = + superClassType != null ? TypeUtils.getAllSupertypes(superClassType) : Collections.emptySet(); + ReceiverParameterDescriptor expectedThisObject = candidate.getExpectedThisObject(); + assert expectedThisObject != null; + JetType candidateType = expectedThisObject.getType(); + boolean implementedInSuperClass = superTypesOfSuperClass.contains(candidateType); + + if (!implementedInSuperClass) { + r.add(Pair.create(callableMemberDescriptor, candidate)); } } - return r; } + } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JvmAbi.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JvmAbi.java index 45cc7f668cf..50a9c1fa422 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JvmAbi.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JvmAbi.java @@ -27,7 +27,7 @@ public class JvmAbi { * This constant is used to identify binary format (class file) versions * If you change class file metadata format and/or naming conventions, please increase this number */ - public static final int VERSION = 4; + public static final int VERSION = 5; public static final String TRAIT_IMPL_CLASS_NAME = "$TImpl"; public static final String TRAIT_IMPL_SUFFIX = "$" + TRAIT_IMPL_CLASS_NAME; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index 688675d6ab7..c30f66c426a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -356,6 +356,7 @@ public interface Errors { DiagnosticFactory1 SUPER_IS_NOT_AN_EXPRESSION = DiagnosticFactory1.create(ERROR); DiagnosticFactory0 SUPER_NOT_AVAILABLE = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 SUPERCLASS_NOT_ACCESSIBLE_FROM_TRAIT = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 AMBIGUOUS_SUPER = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 ABSTRACT_SUPER_CALL = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 NOT_A_SUPERTYPE = DiagnosticFactory0.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java index 069a3a7c83f..6a79a12417d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java @@ -213,6 +213,7 @@ public class DefaultErrorMessages { MAP.put(SETTER_PARAMETER_WITH_DEFAULT_VALUE, "Setter parameters cannot have default values"); MAP.put(NO_THIS, "'this' is not defined in this context"); MAP.put(SUPER_NOT_AVAILABLE, "No supertypes are accessible in this context"); + MAP.put(SUPERCLASS_NOT_ACCESSIBLE_FROM_TRAIT, "Superclass is not accessible from trait"); MAP.put(AMBIGUOUS_SUPER, "Many supertypes available, please specify the one you mean in angle brackets, e.g. 'super'"); MAP.put(ABSTRACT_SUPER_CALL, "Abstract member cannot be accessed directly"); MAP.put(NOT_A_SUPERTYPE, "Not a supertype"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java index a11e891545d..597e10eb3f2 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java @@ -273,23 +273,31 @@ public class DescriptorUtils { } public static boolean isClassObject(@NotNull DeclarationDescriptor descriptor) { - return descriptor instanceof ClassDescriptor - && ((ClassDescriptor) descriptor).getKind() == ClassKind.CLASS_OBJECT; + return isKindOf(descriptor, ClassKind.CLASS_OBJECT); } public static boolean isAnonymous(@Nullable ClassifierDescriptor descriptor) { - return descriptor instanceof ClassDescriptor - && descriptor.getName().isSpecial() && ((ClassDescriptor)descriptor).getKind() == ClassKind.OBJECT; + return isKindOf(descriptor, ClassKind.OBJECT) && descriptor.getName().isSpecial(); } public static boolean isEnumEntry(@NotNull DeclarationDescriptor descriptor) { - return descriptor instanceof ClassDescriptor - && ((ClassDescriptor) descriptor).getKind() == ClassKind.ENUM_ENTRY; + return isKindOf(descriptor, ClassKind.ENUM_ENTRY); } public static boolean isEnumClass(@NotNull DeclarationDescriptor descriptor) { - return descriptor instanceof ClassDescriptor - && ((ClassDescriptor) descriptor).getKind() == ClassKind.ENUM_CLASS; + return isKindOf(descriptor, ClassKind.ENUM_CLASS); + } + + public static boolean isKindOf(@NotNull JetType jetType, @NotNull ClassKind classKind) { + ClassifierDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor(); + return isKindOf(descriptor, classKind); + } + + public static boolean isKindOf(@Nullable DeclarationDescriptor descriptor, @NotNull ClassKind classKind) { + if (descriptor instanceof ClassDescriptor) { + return ((ClassDescriptor) descriptor).getKind() == classKind; + } + return false; } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index 989cf46bd22..07ec68bf6dd 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -494,6 +494,11 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { } } if (result != null) { + if (DescriptorUtils.isKindOf(thisType, ClassKind.TRAIT)) { + if (DescriptorUtils.isKindOf(result, ClassKind.CLASS)) { + context.trace.report(SUPERCLASS_NOT_ACCESSIBLE_FROM_TRAIT.on(expression)); + } + } context.trace.record(BindingContext.EXPRESSION_TYPE, expression.getInstanceReference(), result); context.trace.record(BindingContext.REFERENCE_TARGET, expression.getInstanceReference(), result.getConstructor().getDeclarationDescriptor()); if (superTypeQualifier != null) { diff --git a/compiler/testData/cli/wrongAbiVersion.out b/compiler/testData/cli/wrongAbiVersion.out index 1393afbcf3f..6f4f9b41fb7 100644 --- a/compiler/testData/cli/wrongAbiVersion.out +++ b/compiler/testData/cli/wrongAbiVersion.out @@ -1,4 +1,4 @@ WARNING: $TESTDATA_DIR$/wrongAbiVersion.kt: (3, 9) Parameter 'x' is never used -ERROR: $TESTDATA_DIR$/wrongAbiVersionLib/wrong/WrongPackage.java: (3, 1) Class 'wrong.WrongPackage' was compiled with an incompatible version of Kotlin. Its ABI version is -1, expected ABI version is 4 -ERROR: $TESTDATA_DIR$/wrongAbiVersionLib/ClassWithWrongAbiVersion.java: (3, 1) Class 'ClassWithWrongAbiVersion' was compiled with an incompatible version of Kotlin. Its ABI version is -1, expected ABI version is 4 +ERROR: $TESTDATA_DIR$/wrongAbiVersionLib/wrong/WrongPackage.java: (3, 1) Class 'wrong.WrongPackage' was compiled with an incompatible version of Kotlin. Its ABI version is -1, expected ABI version is 5 +ERROR: $TESTDATA_DIR$/wrongAbiVersionLib/ClassWithWrongAbiVersion.java: (3, 1) Class 'ClassWithWrongAbiVersion' was compiled with an incompatible version of Kotlin. Its ABI version is -1, expected ABI version is 5 COMPILATION_ERROR diff --git a/compiler/testData/codegen/box/traits/genericMethod.kt b/compiler/testData/codegen/box/traits/genericMethod.kt new file mode 100644 index 00000000000..06fa2f35a31 --- /dev/null +++ b/compiler/testData/codegen/box/traits/genericMethod.kt @@ -0,0 +1,21 @@ +trait A { + val property : T + + open fun a() : T { + return property + } +} + +open class B : A { + + override val property: Any = "fail" +} + +open class C : B(), A { + + override val property: Any = "OK" +} + +fun box() : String { + return C().a() as String +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/traits/kt3429.kt b/compiler/testData/codegen/box/traits/kt3429.kt new file mode 100644 index 00000000000..f865200c56c --- /dev/null +++ b/compiler/testData/codegen/box/traits/kt3429.kt @@ -0,0 +1,17 @@ +open class Base { + open fun sayHello(): String{ + return "fail" + } +} + +trait Trait: Base { + override fun sayHello(): String { + return "OK" + } +} + +class Derived(): Base(), Trait + +fun box() : String { + return Derived().sayHello() +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/traits/kt3500.kt b/compiler/testData/codegen/box/traits/kt3500.kt new file mode 100644 index 00000000000..ba3e63ce5ca --- /dev/null +++ b/compiler/testData/codegen/box/traits/kt3500.kt @@ -0,0 +1,15 @@ +trait BK { + fun foo(): String = 10.toString() +} + +trait KTrait: BK { + override fun foo() = 30.toString() +} + +class A : BK, KTrait { + +} + +fun box(): String { + return if (A().foo() == "30") "OK" else "fail" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/traits/withRequiredSuper.kt b/compiler/testData/codegen/box/traits/withRequiredSuper.kt index b4a3231ecaa..ac4d1f89cc3 100644 --- a/compiler/testData/codegen/box/traits/withRequiredSuper.kt +++ b/compiler/testData/codegen/box/traits/withRequiredSuper.kt @@ -1,16 +1,18 @@ open class Base { - open fun foo() { } + open fun foo() : String { + return "fail" + } } trait Derived : Base { - override fun foo() { - super.foo() + override fun foo() : String { + //super.foo() + return "OK" } } class DerivedImpl : Derived, Base() fun box(): String { - DerivedImpl().foo() - return "OK" + return DerivedImpl().foo() } diff --git a/compiler/testData/codegen/box/traits/withRequiredSuperViaBridge.kt b/compiler/testData/codegen/box/traits/withRequiredSuperViaBridge.kt index ddf9a8cae58..a00ac37c3d1 100644 --- a/compiler/testData/codegen/box/traits/withRequiredSuperViaBridge.kt +++ b/compiler/testData/codegen/box/traits/withRequiredSuperViaBridge.kt @@ -1,12 +1,14 @@ open class Base { open fun foo() { } + open fun foo2() { } } trait Derived : Base { override fun foo() { object { fun bar() { - super@Derived.foo() + //super@Derived.foo2() + this@Derived.foo2() } }.bar() } diff --git a/compiler/testData/diagnostics/tests/thisAndSuper/notAccessibleSuperInTrait.kt b/compiler/testData/diagnostics/tests/thisAndSuper/notAccessibleSuperInTrait.kt new file mode 100644 index 00000000000..7a4996bf3dc --- /dev/null +++ b/compiler/testData/diagnostics/tests/thisAndSuper/notAccessibleSuperInTrait.kt @@ -0,0 +1,10 @@ +open class A { + open fun foo() {} +} + +trait ATrait : A { + + override fun foo() { + super.foo() + } +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 2a7c31abccb..0563bbe2250 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -4352,6 +4352,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage doTest("compiler/testData/diagnostics/tests/thisAndSuper/ambigousLabelOnThis.kt"); } + @TestMetadata("notAccessibleSuperInTrait.kt") + public void testNotAccessibleSuperInTrait() throws Exception { + doTest("compiler/testData/diagnostics/tests/thisAndSuper/notAccessibleSuperInTrait.kt"); + } + @TestMetadata("QualifiedThis.kt") public void testQualifiedThis() throws Exception { doTest("compiler/testData/diagnostics/tests/thisAndSuper/QualifiedThis.kt"); diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java index f2d1cfac7eb..0cb760e0543 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -3295,11 +3295,26 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest("compiler/testData/codegen/box/super/innerClassLabeledSuper.kt"); } + @TestMetadata("innerClassLabeledSuper2.kt") + public void testInnerClassLabeledSuper2() throws Exception { + doTest("compiler/testData/codegen/box/super/innerClassLabeledSuper2.kt"); + } + @TestMetadata("innerClassLabeledSuperProperty.kt") public void testInnerClassLabeledSuperProperty() throws Exception { doTest("compiler/testData/codegen/box/super/innerClassLabeledSuperProperty.kt"); } + @TestMetadata("innerClassLabeledSuperProperty2.kt") + public void testInnerClassLabeledSuperProperty2() throws Exception { + doTest("compiler/testData/codegen/box/super/innerClassLabeledSuperProperty2.kt"); + } + + @TestMetadata("kt3492ClassFun.kt") + public void testKt3492ClassFun() throws Exception { + doTest("compiler/testData/codegen/box/super/kt3492ClassFun.kt"); + } + @TestMetadata("kt3492ClassProperty.kt") public void testKt3492ClassProperty() throws Exception { doTest("compiler/testData/codegen/box/super/kt3492ClassProperty.kt"); @@ -3338,6 +3353,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest("compiler/testData/codegen/box/traits/finalMethod.kt"); } + @TestMetadata("genericMethod.kt") + public void testGenericMethod() throws Exception { + doTest("compiler/testData/codegen/box/traits/genericMethod.kt"); + } + @TestMetadata("inheritedFun.kt") public void testInheritedFun() throws Exception { doTest("compiler/testData/codegen/box/traits/inheritedFun.kt"); @@ -3383,6 +3403,16 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest("compiler/testData/codegen/box/traits/kt3413.kt"); } + @TestMetadata("kt3429.kt") + public void testKt3429() throws Exception { + doTest("compiler/testData/codegen/box/traits/kt3429.kt"); + } + + @TestMetadata("kt3500.kt") + public void testKt3500() throws Exception { + doTest("compiler/testData/codegen/box/traits/kt3500.kt"); + } + @TestMetadata("multiple.kt") public void testMultiple() throws Exception { doTest("compiler/testData/codegen/box/traits/multiple.kt");