diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBodyCodegen.java index d2e461b2621..b55a356d278 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBodyCodegen.java @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.DescriptorUtils; +import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -51,11 +52,19 @@ public abstract class ClassBodyCodegen extends MemberCodegen { @Override protected void generateBody() { + List companions = new ArrayList(); if (kind != OwnerKind.DEFAULT_IMPLS) { //generate nested classes first and only then generate class body. It necessary to access to nested CodegenContexts for (KtDeclaration declaration : myClass.getDeclarations()) { if (shouldProcessFirst(declaration)) { - generateDeclaration(declaration); + //Generate companions after class body generation (need to record all synthetic accessors) + if (declaration instanceof KtObjectDeclaration && ((KtObjectDeclaration) declaration).isCompanion()) { + companions.add((KtObjectDeclaration) declaration); + CodegenUtilKt.populateCompanionBackingFieldNamesToOuterContextIfNeeded((KtObjectDeclaration) declaration, context, state); + } + else { + generateDeclaration(declaration); + } } } } @@ -66,6 +75,12 @@ public abstract class ClassBodyCodegen extends MemberCodegen { } } + generatePrimaryConstructorProperties(); + generateConstructors(); + for (KtObjectDeclaration companion : companions) { + generateDeclaration(companion); + } + if (!DescriptorUtils.isInterface(descriptor)) { for (DeclarationDescriptor memberDescriptor : DescriptorUtils.getAllDescriptors(descriptor.getDefaultType().getMemberScope())) { if (memberDescriptor instanceof CallableMemberDescriptor) { @@ -88,8 +103,10 @@ public abstract class ClassBodyCodegen extends MemberCodegen { } } } + } + + protected void generateConstructors() { - generatePrimaryConstructorProperties(); } private static boolean shouldProcessFirst(KtDeclaration declaration) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java index 141d6d57b0c..a27c29bbbd0 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java @@ -98,6 +98,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { private List companionObjectPropertiesToCopy; + private final DelegationFieldsInfo delegationFieldsInfo; + private final List> additionalTasks = new ArrayList>(); @@ -112,6 +114,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { super(aClass, context, v, state, parentCodegen); this.classAsmType = typeMapper.mapClass(descriptor); this.isLocal = isLocal; + delegationFieldsInfo = getDelegationFieldsInfo(myClass.getSuperTypeListEntries()); } @Override @@ -228,7 +231,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { @Override protected void generateBody() { - super.generateBody(); if (isInterface(descriptor) && !isLocal) { Type defaultImplsType = state.getTypeMapper().mapDefaultImpls(descriptor); ClassBuilder defaultImplsBuilder = @@ -237,9 +239,10 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { CodegenContext parentContext = context.getParentContext(); assert parentContext != null : "Parent context of interface declaration should not be null"; - ClassContext defaultImplsContext = parentContext.intoClass(descriptor, OwnerKind.DEFAULT_IMPLS, state); + ClassContext defaultImplsContext = parentContext.intoDefaultImplsClass(descriptor, (ClassContext) context, state); new InterfaceImplBodyCodegen(myClass, defaultImplsContext, defaultImplsBuilder, state, this).generate(); } + super.generateBody(); } @Override @@ -371,24 +374,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { generateCompanionObjectBackingFieldCopies(); - DelegationFieldsInfo delegationFieldsInfo = getDelegationFieldsInfo(myClass.getSuperTypeListEntries()); - try { - lookupConstructorExpressionsInClosureIfPresent(); - generatePrimaryConstructor(delegationFieldsInfo); - for (ConstructorDescriptor secondaryConstructor : DescriptorUtilsKt.getSecondaryConstructors(descriptor)) { - generateSecondaryConstructor(secondaryConstructor); - } - } - catch (CompilationException e) { - throw e; - } - catch (ProcessCanceledException e) { - throw e; - } - catch (RuntimeException e) { - throw new RuntimeException("Error generating constructors of class " + myClass.getName() + " with kind " + kind, e); - } - generateTraitMethods(); generateDelegates(delegationFieldsInfo); @@ -410,6 +395,26 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } } + @Override + protected void generateConstructors() { + try { + lookupConstructorExpressionsInClosureIfPresent(); + generatePrimaryConstructor(delegationFieldsInfo); + for (ConstructorDescriptor secondaryConstructor : DescriptorUtilsKt.getSecondaryConstructors(descriptor)) { + generateSecondaryConstructor(secondaryConstructor); + } + } + catch (CompilationException e) { + throw e; + } + catch (ProcessCanceledException e) { + throw e; + } + catch (RuntimeException e) { + throw new RuntimeException("Error generating constructors of class " + myClass.getName() + " with kind " + kind, e); + } + } + private boolean isGenericToArrayPresent() { Collection functions = descriptor.getDefaultType().getMemberScope().getContributedFunctions(Name.identifier("toArray"), NoLookupLocation.FROM_BACKEND); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt index 33ba8d3565b..3152679ddf1 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt @@ -17,8 +17,15 @@ package org.jetbrains.kotlin.codegen +import org.jetbrains.kotlin.codegen.context.FieldOwnerContext +import org.jetbrains.kotlin.codegen.state.GenerationState +import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature.SpecialSignatureInfo +import org.jetbrains.kotlin.psi.KtObjectDeclaration +import org.jetbrains.kotlin.psi.KtProperty import org.jetbrains.kotlin.renderer.DescriptorRenderer +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter @@ -68,3 +75,23 @@ fun generateNullCheckForNonSafeAs( public fun SpecialSignatureInfo.replaceValueParametersIn(sourceSignature: String?): String? = valueParametersSignature?.let { sourceSignature?.replace("^\\(.*\\)".toRegex(), "($it)") } +fun populateCompanionBackingFieldNamesToOuterContextIfNeeded(companion: KtObjectDeclaration, outerContext: FieldOwnerContext<*>, state: GenerationState) { + val descriptor = state.bindingContext.get(BindingContext.CLASS, companion) + + if (descriptor == null || ErrorUtils.isError(descriptor)) { + return + } + + if (!AsmUtil.isCompanionObjectWithBackingFieldsInOuter(descriptor)) { + return + } + val properties = companion.declarations.filterIsInstance() + + properties.forEach { + val variableDescriptor = state.bindingContext.get(BindingContext.VARIABLE, it) + if (variableDescriptor is PropertyDescriptor) { + outerContext.getFieldName(variableDescriptor, it.hasDelegate()) + } + } + +} \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/CodegenContext.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/CodegenContext.java index 92e912eeff1..c9ed6ad752f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/CodegenContext.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/CodegenContext.java @@ -266,6 +266,10 @@ public abstract class CodegenContext { return new MultifileClassFacadeContext(descriptor, this, multifileClassType, filePartType); } + public ClassContext intoDefaultImplsClass(ClassDescriptor descriptor, ClassContext interfaceContext, GenerationState state) { + return new DefaultImplsClassContext(state.getTypeMapper(), descriptor, OwnerKind.DEFAULT_IMPLS, this, null, interfaceContext); + } + @NotNull public ClassContext intoClass(ClassDescriptor descriptor, OwnerKind kind, GenerationState state) { if (descriptor.isCompanionObject()) { @@ -624,7 +628,7 @@ public abstract class CodegenContext { } @Nullable - public CodegenContext findChildContext(@NotNull DeclarationDescriptor child) { + protected CodegenContext findChildContext(@NotNull DeclarationDescriptor child) { return childContexts == null ? null : childContexts.get(child); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/DefaultImplsClassContext.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/DefaultImplsClassContext.kt new file mode 100644 index 00000000000..707a8f35346 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/DefaultImplsClassContext.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.codegen.context + +import org.jetbrains.kotlin.codegen.OwnerKind +import org.jetbrains.kotlin.codegen.state.JetTypeMapper +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor + +class DefaultImplsClassContext( + typeMapper: JetTypeMapper, + contextDescriptor: ClassDescriptor, + contextKind: OwnerKind, + parentContext: CodegenContext<*>?, + localLookup: ((DeclarationDescriptor) -> Boolean)?, + val interfaceContext: ClassContext +) : ClassContext(typeMapper, contextDescriptor, contextKind, parentContext, localLookup) { + + override fun getCompanionObjectContext(): CodegenContext<*>? { + return interfaceContext.companionObjectContext + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxMultiFile/kt9958/a.kt b/compiler/testData/codegen/boxMultiFile/kt9958/a.kt new file mode 100644 index 00000000000..916e2477330 --- /dev/null +++ b/compiler/testData/codegen/boxMultiFile/kt9958/a.kt @@ -0,0 +1,16 @@ +package a + +import b.* + +class B { + companion object : A() {} + + init { + foo() + } +} + +fun box(): String { + B() + return result +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxMultiFile/kt9958/b.kt b/compiler/testData/codegen/boxMultiFile/kt9958/b.kt new file mode 100644 index 00000000000..36d890bfe7b --- /dev/null +++ b/compiler/testData/codegen/boxMultiFile/kt9958/b.kt @@ -0,0 +1,9 @@ +package b + +var result = "fail" + +abstract class A { + protected fun foo() { + result = "OK" + } +} diff --git a/compiler/testData/codegen/boxMultiFile/kt9958Interface/a.kt b/compiler/testData/codegen/boxMultiFile/kt9958Interface/a.kt new file mode 100644 index 00000000000..ed6935687cf --- /dev/null +++ b/compiler/testData/codegen/boxMultiFile/kt9958Interface/a.kt @@ -0,0 +1,18 @@ +package a + +import b.* + +interface B { + companion object : A() {} + + fun test() { + foo() + } +} + +class C : B + +fun box(): String { + C().test() + return result +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxMultiFile/kt9958Interface/b.kt b/compiler/testData/codegen/boxMultiFile/kt9958Interface/b.kt new file mode 100644 index 00000000000..36d890bfe7b --- /dev/null +++ b/compiler/testData/codegen/boxMultiFile/kt9958Interface/b.kt @@ -0,0 +1,9 @@ +package b + +var result = "fail" + +abstract class A { + protected fun foo() { + result = "OK" + } +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxMultiFileCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxMultiFileCodegenTestGenerated.java index aa574feaf84..9e07479f9ff 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxMultiFileCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxMultiFileCodegenTestGenerated.java @@ -107,6 +107,18 @@ public class BlackBoxMultiFileCodegenTestGenerated extends AbstractBlackBoxCodeg doTestMultiFile(fileName); } + @TestMetadata("kt9958") + public void testKt9958() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxMultiFile/kt9958/"); + doTestMultiFile(fileName); + } + + @TestMetadata("kt9958Interface") + public void testKt9958Interface() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxMultiFile/kt9958Interface/"); + doTestMultiFile(fileName); + } + @TestMetadata("mainInFiles") public void testMainInFiles() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxMultiFile/mainInFiles/"); diff --git a/plugins/annotation-collector/testData/collectToFile/nestedClasses/annotations.txt b/plugins/annotation-collector/testData/collectToFile/nestedClasses/annotations.txt index 036ab4d5eb6..209096dc952 100644 --- a/plugins/annotation-collector/testData/collectToFile/nestedClasses/annotations.txt +++ b/plugins/annotation-collector/testData/collectToFile/nestedClasses/annotations.txt @@ -1,7 +1,7 @@ a java.lang.Deprecated 0 p org.test 0 -c 0 0/SomeClass$Companion c 0 0/SomeClass$SomeInnerObject c 0 0/SomeClass$InnerClass c 0 0/SomeClass$InnerClass$InnerClassInInnerClass c 0 0/SomeClass$NestedClass +c 0 0/SomeClass$Companion