diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 10b737df428..adba9b77657 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -88,6 +88,7 @@ import static org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage.getR import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.*; import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass; import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.OtherOrigin; +import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.TraitImpl; import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER; import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_PRIVATE; import static org.jetbrains.org.objectweb.asm.Opcodes.GETFIELD; @@ -197,7 +198,7 @@ public class ExpressionCodegen extends JetVisitor implem ); - ClassContext objectContext = context.intoAnonymousClass(classDescriptor, this); + ClassContext objectContext = context.intoAnonymousClass(classDescriptor, this, OwnerKind.IMPLEMENTATION); new ImplementationBodyCodegen(objectDeclaration, objectContext, classBuilder, state, getParentCodegen()).generate(); @@ -285,9 +286,16 @@ public class ExpressionCodegen extends JetVisitor implem Type asmType = asmTypeForAnonymousClass(bindingContext, declaration); ClassBuilder classBuilder = state.getFactory().newVisitor(OtherOrigin(declaration, descriptor), asmType, declaration.getContainingFile()); - ClassContext objectContext = context.intoAnonymousClass(descriptor, this); + ClassContext objectContext = context.intoAnonymousClass(descriptor, this, OwnerKind.IMPLEMENTATION); new ImplementationBodyCodegen(declaration, objectContext, classBuilder, state, getParentCodegen()).generate(); + if (declaration instanceof JetClass && ((JetClass) declaration).isTrait()) { + Type traitImplType = state.getTypeMapper().mapTraitImpl(descriptor); + ClassBuilder traitImplBuilder = state.getFactory().newVisitor(TraitImpl(declaration, descriptor), traitImplType, declaration.getContainingFile()); + ClassContext traitImplContext = context.intoAnonymousClass(descriptor, this, OwnerKind.TRAIT_IMPL); + new TraitImplBodyCodegen(declaration, traitImplContext, traitImplBuilder, state, parentCodegen).generate(); + } + return StackValue.none(); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/context/CodegenContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/context/CodegenContext.java index 13366024a9e..22bb09dfd80 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/context/CodegenContext.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/context/CodegenContext.java @@ -160,8 +160,8 @@ public abstract class CodegenContext { } @NotNull - public ClassContext intoAnonymousClass(@NotNull ClassDescriptor descriptor, @NotNull ExpressionCodegen codegen) { - return new AnonymousClassContext(codegen.getState().getTypeMapper(), descriptor, OwnerKind.IMPLEMENTATION, this, codegen); + public ClassContext intoAnonymousClass(@NotNull ClassDescriptor descriptor, @NotNull ExpressionCodegen codegen, @NotNull OwnerKind ownerKind) { + return new AnonymousClassContext(codegen.getState().getTypeMapper(), descriptor, ownerKind, this, codegen); } @NotNull diff --git a/compiler/testData/codegen/box/traits/kt5495.kt b/compiler/testData/codegen/box/traits/kt5495.kt new file mode 100644 index 00000000000..7a78baa0b9b --- /dev/null +++ b/compiler/testData/codegen/box/traits/kt5495.kt @@ -0,0 +1,9 @@ +fun box(): String { + trait A { + fun foo() = "OK" + } + + class B : A + + return B().foo() +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/codegen/KotlinSyntheticClassAnnotationTest.java b/compiler/tests/org/jetbrains/jet/codegen/KotlinSyntheticClassAnnotationTest.java index dd65996889e..05cbf1b22bc 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/KotlinSyntheticClassAnnotationTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/KotlinSyntheticClassAnnotationTest.java @@ -45,76 +45,88 @@ public class KotlinSyntheticClassAnnotationTest extends CodegenTestCase { public void testPackagePart() { doTest("fun foo() = 42", "$", - PACKAGE_PART); + PACKAGE_PART, false); } public void testTraitImpl() { doTest("trait A { fun foo() = 42 }", JvmAbi.TRAIT_IMPL_SUFFIX, - TRAIT_IMPL); + TRAIT_IMPL, true); } public void testSamWrapper() { doTest("val f = {}\nval foo = Thread(f)", "$sam", - SAM_WRAPPER); + SAM_WRAPPER, false); } public void testSamLambda() { doTest("val foo = Thread { }", "$1", - SAM_LAMBDA); + SAM_LAMBDA, true); } public void testCallableReferenceWrapper() { doTest("val f = String::get", "$1", - CALLABLE_REFERENCE_WRAPPER); + CALLABLE_REFERENCE_WRAPPER, true); } public void testLocalFunction() { doTest("fun foo() { fun bar() {} }", "$1", - LOCAL_FUNCTION); + LOCAL_FUNCTION, true); } public void testAnonymousFunction() { doTest("val f = {}", "$1", - ANONYMOUS_FUNCTION); + ANONYMOUS_FUNCTION, true); } public void testLocalClass() { doTest("fun foo() { class Local }", "Local", - LOCAL_CLASS); + LOCAL_CLASS, true); } public void testLocalTraitImpl() { + doTest("fun foo() { trait Local { fun bar() = 42 } }", + "Local$$TImpl", + LOCAL_CLASS, true); + } + + public void testLocalTraitInterface() { doTest("fun foo() { trait Local { fun bar() = 42 } }", "Local", - LOCAL_CLASS); + LOCAL_CLASS, true); } public void testInnerClassOfLocalClass() { doTest("fun foo() { class Local { inner class Inner } }", "Inner", - LOCAL_CLASS); + LOCAL_CLASS, true); } public void testAnonymousObject() { doTest("val o = object {}", "$1", - ANONYMOUS_OBJECT); + ANONYMOUS_OBJECT, true); } - private void doTest(@NotNull String code, @NotNull final String classNamePart, @NotNull KotlinSyntheticClass.Kind expectedKind) { + private void doTest( + @NotNull String code, + @NotNull final String classNamePart, + @NotNull KotlinSyntheticClass.Kind expectedKind, + final boolean endWithNotContains + ) { loadText("package " + PACKAGE_NAME + "\n\n" + code); List output = generateClassesInFile().asList(); Collection files = Collections2.filter(output, new Predicate() { @Override public boolean apply(OutputFile file) { - return file.getRelativePath().contains(classNamePart); + String path = file.getRelativePath(); + return endWithNotContains ? path.endsWith(classNamePart + ".class") : path.contains(classNamePart); } }); assertFalse("No files with \"" + classNamePart + "\" in the name are found: " + output, files.isEmpty()); diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java index 33ed7968b1c..e21d7116bc1 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -6283,6 +6283,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("kt5495.kt") + public void testKt5495() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/traits/kt5495.kt"); + doTest(fileName); + } + @TestMetadata("multiple.kt") public void testMultiple() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/traits/multiple.kt");