diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AbstractAccessorForFunctionDescriptor.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/AbstractAccessorForFunctionDescriptor.kt new file mode 100644 index 00000000000..3026db4b904 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AbstractAccessorForFunctionDescriptor.kt @@ -0,0 +1,47 @@ +/* + * 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 + +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl +import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.DescriptorUtils +import java.util.* + +open public class AbstractAccessorForFunctionDescriptor( + containingDeclaration: DeclarationDescriptor, + name: Name +) : SimpleFunctionDescriptorImpl(containingDeclaration, null, Annotations.EMPTY, + name, CallableMemberDescriptor.Kind.DECLARATION, SourceElement.NO_SOURCE) { + + protected fun copyTypeParameters(descriptor: FunctionDescriptor): List = descriptor.getTypeParameters().map { + val copy = TypeParameterDescriptorImpl.createForFurtherModification( + this, it.getAnnotations(), it.isReified(), + it.getVariance(), it.getName(), + it.getIndex(), SourceElement.NO_SOURCE) + for (upperBound in it.getUpperBounds()) { + copy.addUpperBound(upperBound) + } + copy.setInitialized() + copy + } + + protected fun copyValueParameters(descriptor: FunctionDescriptor): List = + descriptor.getValueParameters().map { it.copy(this, it.getName()) } +} diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AccessorForConstructorDescriptor.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/AccessorForConstructorDescriptor.kt new file mode 100644 index 00000000000..dc66125a88a --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AccessorForConstructorDescriptor.kt @@ -0,0 +1,52 @@ +/* + * 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 + +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl +import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.jvm.AsmTypes +import java.util.* + +public class AccessorForConstructorDescriptor( + private val calleeDescriptor: ConstructorDescriptor, + containingDeclaration: DeclarationDescriptor +) : AbstractAccessorForFunctionDescriptor(containingDeclaration, Name.special("")) + , ConstructorDescriptor + , AccessorForCallableDescriptor { + + override fun getCalleeDescriptor(): ConstructorDescriptor = calleeDescriptor + + override fun getContainingDeclaration(): ClassDescriptor = calleeDescriptor.getContainingDeclaration() + + override fun isPrimary(): Boolean = false + + init { + initialize( + DescriptorUtils.getReceiverParameterType(getExtensionReceiverParameter()), + calleeDescriptor.getDispatchReceiverParameter(), + copyTypeParameters(calleeDescriptor), + copyValueParameters(calleeDescriptor), + calleeDescriptor.getReturnType(), + Modality.FINAL, + Visibilities.INTERNAL + ) + } +} diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AccessorForFunctionDescriptor.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/AccessorForFunctionDescriptor.java index 1b65ba54d33..988989d6fed 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/AccessorForFunctionDescriptor.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AccessorForFunctionDescriptor.java @@ -18,20 +18,13 @@ package org.jetbrains.kotlin.codegen; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.descriptors.*; -import org.jetbrains.kotlin.descriptors.annotations.Annotations; -import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl; -import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.annotations.AnnotationsPackage; -import org.jetbrains.kotlin.types.JetType; - -import java.util.ArrayList; -import java.util.List; import static org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER; -public class AccessorForFunctionDescriptor extends SimpleFunctionDescriptorImpl implements AccessorForCallableDescriptor { +public class AccessorForFunctionDescriptor extends AbstractAccessorForFunctionDescriptor implements AccessorForCallableDescriptor { private final FunctionDescriptor calleeDescriptor; @@ -40,9 +33,8 @@ public class AccessorForFunctionDescriptor extends SimpleFunctionDescriptorImpl @NotNull DeclarationDescriptor containingDeclaration, int index ) { - super(containingDeclaration, null, Annotations.EMPTY, - Name.identifier("access$" + (descriptor instanceof ConstructorDescriptor ? "init" : descriptor.getName()) + "$" + index), - Kind.DECLARATION, SourceElement.NO_SOURCE); + super(containingDeclaration, + Name.identifier("access$" + (descriptor instanceof ConstructorDescriptor ? "init" : descriptor.getName()) + "$" + index)); this.calleeDescriptor = descriptor; initialize(DescriptorUtils.getReceiverParameterType(descriptor.getExtensionReceiverParameter()), @@ -56,34 +48,6 @@ public class AccessorForFunctionDescriptor extends SimpleFunctionDescriptorImpl Visibilities.INTERNAL); } - @NotNull - private List copyTypeParameters(@NotNull FunctionDescriptor descriptor) { - List typeParameters = descriptor.getTypeParameters(); - List result = new ArrayList(typeParameters.size()); - for (TypeParameterDescriptor typeParameter : typeParameters) { - TypeParameterDescriptorImpl copy = TypeParameterDescriptorImpl.createForFurtherModification( - this, typeParameter.getAnnotations(), typeParameter.isReified(), - typeParameter.getVariance(), typeParameter.getName(), typeParameter.getIndex(), SourceElement.NO_SOURCE - ); - for (JetType upperBound : typeParameter.getUpperBounds()) { - copy.addUpperBound(upperBound); - } - copy.setInitialized(); - result.add(copy); - } - return result; - } - - @NotNull - private List copyValueParameters(@NotNull FunctionDescriptor descriptor) { - List valueParameters = descriptor.getValueParameters(); - List result = new ArrayList(valueParameters.size()); - for (ValueParameterDescriptor valueParameter : valueParameters) { - result.add(valueParameter.copy(this, valueParameter.getName())); - } - return result; - } - @NotNull @Override public FunctionDescriptor getCalleeDescriptor() { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java index 35424ad274e..42b4e4ff79d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java @@ -170,7 +170,7 @@ public class AsmUtil { public static boolean isStaticMethod(OwnerKind kind, CallableMemberDescriptor functionDescriptor) { return isStaticKind(kind) || - JetTypeMapper.isAccessor(functionDescriptor) || + JetTypeMapper.isStaticAccessor(functionDescriptor) || AnnotationsPackage.isPlatformStaticInObjectOrClass(functionDescriptor); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 3c93fff0063..f2e254eb64f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -70,6 +70,8 @@ import org.jetbrains.kotlin.resolve.constants.evaluate.EvaluatePackage; import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage; import org.jetbrains.kotlin.resolve.inline.InlineUtil; import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm; +import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind; +import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature; import org.jetbrains.kotlin.resolve.scopes.receivers.*; import org.jetbrains.kotlin.types.Approximation; @@ -2410,6 +2412,16 @@ public class ExpressionCodegen extends JetVisitor implem callGenerator.putValueIfNeeded(null, Type.INT_TYPE, StackValue.constant(mask, Type.INT_TYPE)); } + // Extra constructor marker argument + if (callableMethod instanceof CallableMethod) { + List callableParameters = ((CallableMethod) callableMethod).getValueParameters(); + for (JvmMethodParameterSignature parameter: callableParameters) { + if (parameter.getKind() == JvmMethodParameterKind.CONSTRUCTOR_MARKER) { + callGenerator.putValueIfNeeded(null, parameter.getAsmType(), StackValue.constant(null, parameter.getAsmType())); + } + } + } + callGenerator.genCall(callableMethod, resolvedCall, !masks.isEmpty(), this); } @@ -3385,6 +3397,14 @@ public class ExpressionCodegen extends JetVisitor implem return generateConstructorCall(resolvedCall, type); } + @NotNull + public ConstructorDescriptor getConstructorDescriptor(@NotNull ResolvedCall resolvedCall) { + FunctionDescriptor accessibleDescriptor = accessibleFunctionDescriptor(resolvedCall); + assert accessibleDescriptor instanceof ConstructorDescriptor : + "getConstructorDescriptor must be called only for constructors: " + accessibleDescriptor; + return (ConstructorDescriptor) accessibleDescriptor; + } + @NotNull public StackValue generateConstructorCall(@NotNull final ResolvedCall resolvedCall, @NotNull final Type objectType) { return StackValue.functionCall(objectType, new Function1() { @@ -3393,7 +3413,7 @@ public class ExpressionCodegen extends JetVisitor implem v.anew(objectType); v.dup(); - ConstructorDescriptor constructor = (ConstructorDescriptor) resolvedCall.getResultingDescriptor(); + ConstructorDescriptor constructor = getConstructorDescriptor(resolvedCall); ReceiverParameterDescriptor dispatchReceiver = constructor.getDispatchReceiverParameter(); if (dispatchReceiver != null) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java index 67d28ed0ede..dc5df70fd9d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java @@ -57,6 +57,7 @@ import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.VarargValueArgument; import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage; +import org.jetbrains.kotlin.resolve.jvm.AsmTypes; import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmClassSignature; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind; @@ -831,7 +832,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { private void generateSyntheticAccessor(Map.Entry entry) { if (entry.getValue() instanceof FunctionDescriptor) { - FunctionDescriptor bridge = (FunctionDescriptor) entry.getValue(); + final FunctionDescriptor bridge = (FunctionDescriptor) entry.getValue(); final FunctionDescriptor original = (FunctionDescriptor) entry.getKey(); functionCodegen.generateMethod( Synthetic(null, original), bridge, @@ -840,7 +841,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) { markLineNumberForSyntheticFunction(descriptor, codegen.v); - generateMethodCallTo(original, codegen.v); + generateMethodCallTo(original, bridge, codegen.v); codegen.v.areturn(signature.getReturnType()); } } @@ -921,15 +922,21 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } } - private void generateMethodCallTo(FunctionDescriptor functionDescriptor, InstructionAdapter iv) { + private void generateMethodCallTo( + @NotNull FunctionDescriptor functionDescriptor, + @Nullable FunctionDescriptor bridgeDescriptor, + @NotNull InstructionAdapter iv + ) { boolean isConstructor = functionDescriptor instanceof ConstructorDescriptor; - boolean callFromAccessor = !JetTypeMapper.isAccessor(functionDescriptor); + boolean bridgeIsAccessorConstructor = bridgeDescriptor instanceof AccessorForConstructorDescriptor; + boolean callFromAccessor = bridgeIsAccessorConstructor + || (bridgeDescriptor != null && JetTypeMapper.isAccessor(bridgeDescriptor)); CallableMethod callableMethod = isConstructor ? typeMapper.mapToCallableMethod((ConstructorDescriptor) functionDescriptor) : typeMapper.mapToCallableMethod(functionDescriptor, callFromAccessor, context); int reg = 1; - if (isConstructor) { + if (isConstructor && !bridgeIsAccessorConstructor) { iv.anew(callableMethod.getOwner()); iv.dup(); reg = 0; @@ -941,8 +948,13 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } for (Type argType : callableMethod.getParameterTypes()) { - iv.load(reg, argType); - reg += argType.getSize(); + if (AsmTypes.DEFAULT_CONSTRUCTOR_MARKER.equals(argType)) { + iv.aconst(null); + } + else { + iv.load(reg, argType); + reg += argType.getSize(); + } } callableMethod.genInvokeInstruction(iv); } @@ -1036,7 +1048,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { private void generateCompanionObjectInitializer(@NotNull ClassDescriptor companionObject) { ExpressionCodegen codegen = createOrGetClInitCodegen(); FunctionDescriptor constructor = context.accessibleFunctionDescriptor(KotlinPackage.single(companionObject.getConstructors())); - generateMethodCallTo(constructor, codegen.v); + generateMethodCallTo(constructor, null, codegen.v); codegen.v.dup(); StackValue instance = StackValue.onStack(typeMapper.mapClass(companionObject)); StackValue.singleton(companionObject, typeMapper).store(instance, codegen.v, true); @@ -1475,7 +1487,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { return; } iv.load(0, OBJECT_TYPE); - ConstructorDescriptor delegateConstructor = SamCodegenUtil.resolveSamAdapter(delegationConstructorCall.getResultingDescriptor()); + ConstructorDescriptor delegateConstructor = SamCodegenUtil.resolveSamAdapter(codegen.getConstructorDescriptor(delegationConstructorCall)); CallableMethod delegateConstructorCallable = typeMapper.mapToCallableMethod(delegateConstructor); CallableMethod callable = typeMapper.mapToCallableMethod(constructorDescriptor); 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 e462f0e64a9..976a6cd225b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/CodegenContext.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/CodegenContext.java @@ -241,9 +241,12 @@ public abstract class CodegenContext { } int accessorIndex = accessors.size(); - if (descriptor instanceof SimpleFunctionDescriptor || descriptor instanceof ConstructorDescriptor) { + if (descriptor instanceof SimpleFunctionDescriptor) { accessor = new AccessorForFunctionDescriptor((FunctionDescriptor) descriptor, contextDescriptor, accessorIndex); } + else if (descriptor instanceof ConstructorDescriptor) { + accessor = new AccessorForConstructorDescriptor((ConstructorDescriptor) descriptor, contextDescriptor); + } else if (descriptor instanceof PropertyDescriptor) { if (isForBackingFieldInOuterClass) { accessor = new AccessorForPropertyBackingFieldInOuterClass((PropertyDescriptor) descriptor, contextDescriptor, diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java index c475d39bdb7..832e249f77c 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java @@ -584,7 +584,7 @@ public class JetTypeMapper { } else { if (isStaticDeclaration(functionDescriptor) || - isAccessor(functionDescriptor) || + isStaticAccessor(functionDescriptor) || AnnotationsPackage.isPlatformStaticInObjectOrClass(functionDescriptor)) { invokeOpcode = INVOKESTATIC; } @@ -643,6 +643,11 @@ public class JetTypeMapper { return descriptor instanceof AccessorForCallableDescriptor; } + public static boolean isStaticAccessor(@NotNull CallableMemberDescriptor descriptor) { + if (descriptor instanceof AccessorForConstructorDescriptor) return false; + return isAccessor(descriptor); + } + @NotNull private static FunctionDescriptor findAnyDeclaration(@NotNull FunctionDescriptor function) { if (function.getKind() == CallableMemberDescriptor.Kind.DECLARATION) { @@ -748,6 +753,10 @@ public class JetTypeMapper { writeParameter(sw, parameter.getType()); } + if (f instanceof AccessorForConstructorDescriptor) { + writeParameter(sw, JvmMethodParameterKind.CONSTRUCTOR_MARKER, DEFAULT_CONSTRUCTOR_MARKER); + } + writeVoidReturn(sw); } else { diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/jvmSignature/JvmMethodParameterKind.java b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/jvmSignature/JvmMethodParameterKind.java index e0874b33468..6971e764436 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/jvmSignature/JvmMethodParameterKind.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/jvmSignature/JvmMethodParameterKind.java @@ -23,7 +23,8 @@ public enum JvmMethodParameterKind { RECEIVER, CAPTURED_LOCAL_VARIABLE, ENUM_NAME_OR_ORDINAL, - SUPER_CALL_PARAM; + SUPER_CALL_PARAM, + CONSTRUCTOR_MARKER; public boolean isSkippedInGenericSignature() { return this == OUTER || this == ENUM_NAME_OR_ORDINAL; diff --git a/compiler/testData/codegen/box/privateConstructors/base.kt b/compiler/testData/codegen/box/privateConstructors/base.kt new file mode 100644 index 00000000000..f856a95217b --- /dev/null +++ b/compiler/testData/codegen/box/privateConstructors/base.kt @@ -0,0 +1,9 @@ +// See also KT-6299 +public open class Outer private constructor() { + class Inner: Outer() +} + +fun box(): String { + val outer = Outer.Inner() + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/privateConstructors/companion.kt b/compiler/testData/codegen/box/privateConstructors/companion.kt new file mode 100644 index 00000000000..482c81233a4 --- /dev/null +++ b/compiler/testData/codegen/box/privateConstructors/companion.kt @@ -0,0 +1,11 @@ +// See also KT-6299 +public open class Outer private constructor() { + companion object { + fun foo() = Outer() + } +} + +fun box(): String { + val outer = Outer.foo() + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/privateConstructors/inline.kt b/compiler/testData/codegen/box/privateConstructors/inline.kt new file mode 100644 index 00000000000..2816df3f16a --- /dev/null +++ b/compiler/testData/codegen/box/privateConstructors/inline.kt @@ -0,0 +1,11 @@ +// See also KT-6299 +public open class Outer private constructor() { + companion object { + inline fun foo() = Outer() + } +} + +fun box(): String { + val outer = Outer.foo() + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/privateConstructors/inner.kt b/compiler/testData/codegen/box/privateConstructors/inner.kt new file mode 100644 index 00000000000..16c1734f08f --- /dev/null +++ b/compiler/testData/codegen/box/privateConstructors/inner.kt @@ -0,0 +1,15 @@ +// See also KT-6299 +public open class Outer private constructor(val s: String) { + inner class Inner: Outer("O") { + fun foo(): String { + return this.s + this@Outer.s + } + } + class Nested: Outer("K") + fun bar() = Inner() +} + +fun box(): String { + val inner = Outer.Nested().bar() + return inner.foo() +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/privateConstructors/secondary.kt b/compiler/testData/codegen/box/privateConstructors/secondary.kt new file mode 100644 index 00000000000..6f59e0474b1 --- /dev/null +++ b/compiler/testData/codegen/box/privateConstructors/secondary.kt @@ -0,0 +1,9 @@ +// See also KT-6299 +public open class Outer private constructor(val x: Int) { + constructor(): this(42) +} + +fun box(): String { + val outer = Outer() + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/privateConstructors/withArguments.kt b/compiler/testData/codegen/box/privateConstructors/withArguments.kt new file mode 100644 index 00000000000..a53517a81dd --- /dev/null +++ b/compiler/testData/codegen/box/privateConstructors/withArguments.kt @@ -0,0 +1,13 @@ +// See also KT-6299 +public open class Outer private constructor(val s: String, val f: Boolean = true) { + class Inner: Outer("xyz") + class Other: Outer("abc", true) + class Another: Outer("", false) +} + +fun box(): String { + val outer = Outer.Inner() + val other = Outer.Other() + val another = Outer.Another() + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/privateConstructors/withDefault.kt b/compiler/testData/codegen/box/privateConstructors/withDefault.kt new file mode 100644 index 00000000000..cb96e8dcb4b --- /dev/null +++ b/compiler/testData/codegen/box/privateConstructors/withDefault.kt @@ -0,0 +1,11 @@ +// See also KT-6299 +public open class Outer private constructor(val x: Int = 0) { + class Inner: Outer() + class Other: Outer(42) +} + +fun box(): String { + val outer = Outer.Inner() + val other = Outer.Other() + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/privateConstructors/withLinkedClasses.kt b/compiler/testData/codegen/box/privateConstructors/withLinkedClasses.kt new file mode 100644 index 00000000000..ff7f86f847a --- /dev/null +++ b/compiler/testData/codegen/box/privateConstructors/withLinkedClasses.kt @@ -0,0 +1,12 @@ +// See also KT-6299 +public open class Outer private constructor(val p: Outer?) { + object First: Outer(null) + class Other(p: Outer = First): Outer(p) +} + +fun box(): String { + val second = Outer.Other() + val third = Outer.Other(second) + val fourth = Outer.Other(third) + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/privateConstructors/withLinkedObjects.kt b/compiler/testData/codegen/box/privateConstructors/withLinkedObjects.kt new file mode 100644 index 00000000000..549e13912ef --- /dev/null +++ b/compiler/testData/codegen/box/privateConstructors/withLinkedObjects.kt @@ -0,0 +1,13 @@ +// See also KT-6299 +public open class Outer private constructor(val p: Outer?) { + object Inner: Outer(null) + object Other: Outer(Inner) + object Another: Outer(Other) +} + +fun box(): String { + val outer = Outer.Inner + val other = Outer.Other + val another = Outer.Another + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/privateConstructors/withVarargs.kt b/compiler/testData/codegen/box/privateConstructors/withVarargs.kt new file mode 100644 index 00000000000..f7791f1968c --- /dev/null +++ b/compiler/testData/codegen/box/privateConstructors/withVarargs.kt @@ -0,0 +1,13 @@ +// See also KT-6299 +public open class Outer private constructor(val s: String, vararg i: Int) { + class Inner: Outer("xyz") + class Other: Outer("abc", 1, 2, 3) + class Another: Outer("", 42) +} + +fun box(): String { + val outer = Outer.Inner() + val other = Outer.Other() + val another = Outer.Another() + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithStdlib/privateConstructor/synthetic.kt b/compiler/testData/codegen/boxWithStdlib/privateConstructor/synthetic.kt new file mode 100644 index 00000000000..e3fc6cd92d5 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/privateConstructor/synthetic.kt @@ -0,0 +1,26 @@ +// private constructors are transformed into synthetic +class PrivateConstructor private constructor() { + class Nested { val a = PrivateConstructor() } +} + +fun check(klass: Class<*>) { + var hasSynthetic = false + var hasSimple = false + for (method in klass.getDeclaredConstructors()) { + if (method.isSynthetic()) { + hasSynthetic = true + } + else { + hasSimple = true + } + } + if (hasSynthetic && hasSimple) return + throw AssertionError("Class should have both synthetic and non-synthetic constructor: ($hasSynthetic, $hasSimple)") +} + +fun box(): String { + check(javaClass()) + // Also check that synthetic accessors really work + PrivateConstructor.Nested() + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/synthetic/syntheticAccessorNames.kt b/compiler/testData/codegen/boxWithStdlib/synthetic/syntheticAccessorNames.kt index cee187def83..d63e4ffc397 100644 --- a/compiler/testData/codegen/boxWithStdlib/synthetic/syntheticAccessorNames.kt +++ b/compiler/testData/codegen/boxWithStdlib/synthetic/syntheticAccessorNames.kt @@ -2,10 +2,6 @@ // This is crucial for some JVM frameworks like Quasar which rely on the bytecode being similar to the one generated by javac // See https://youtrack.jetbrains.com/issue/KT-6870 -class PrivateConstructor private constructor() { - class Nested { val a = PrivateConstructor() } -} - class PrivatePropertyGet { private val x = 42 @@ -33,13 +29,11 @@ fun check(klass: Class<*>) { } fun box(): String { - check(javaClass()) check(javaClass()) check(javaClass()) check(javaClass()) // Also check that synthetic accessors really work - PrivateConstructor.Nested() PrivatePropertyGet().Inner() PrivatePropertySet().Inner() PrivateMethod().Inner() diff --git a/compiler/testData/codegen/bytecodeText/staticFields/classObject.kt b/compiler/testData/codegen/bytecodeText/staticFields/classObject.kt index 34977448c45..069eefa79f0 100644 --- a/compiler/testData/codegen/bytecodeText/staticFields/classObject.kt +++ b/compiler/testData/codegen/bytecodeText/staticFields/classObject.kt @@ -4,4 +4,4 @@ class A { } } // A and companion object constructor call -// 2 ALOAD 0 \ No newline at end of file +// 3 ALOAD 0 \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/staticFields/classObjectSyntheticAccessor.kt b/compiler/testData/codegen/bytecodeText/staticFields/classObjectSyntheticAccessor.kt index 7496744e3b2..8ef75cec9be 100644 --- a/compiler/testData/codegen/bytecodeText/staticFields/classObjectSyntheticAccessor.kt +++ b/compiler/testData/codegen/bytecodeText/staticFields/classObjectSyntheticAccessor.kt @@ -4,5 +4,5 @@ class A { } } // A and companion object constructor call -// 2 ALOAD 0 +// 3 ALOAD 0 // 1 synthetic access\$getR diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/flags/AbstractWriteFlagsTest.java b/compiler/tests/org/jetbrains/kotlin/codegen/flags/AbstractWriteFlagsTest.java index 666ee699415..5f0e35bc590 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/flags/AbstractWriteFlagsTest.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/flags/AbstractWriteFlagsTest.java @@ -234,7 +234,7 @@ public abstract class AbstractWriteFlagsTest extends UsefulTestCase { @Override public MethodVisitor visitMethod(int access, @NotNull String name, @NotNull String desc, String signature, String[] exceptions) { - if (name.equals(funName)) { + if (name.equals(funName) && (access & Opcodes.ACC_SYNTHETIC) == 0) { this.access = access; isExists = true; } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java index f03db1151b4..d99e42a4664 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -5984,6 +5984,75 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { } } + @TestMetadata("compiler/testData/codegen/box/privateConstructors") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class PrivateConstructors extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInPrivateConstructors() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/privateConstructors"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("base.kt") + public void testBase() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/privateConstructors/base.kt"); + doTest(fileName); + } + + @TestMetadata("companion.kt") + public void testCompanion() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/privateConstructors/companion.kt"); + doTest(fileName); + } + + @TestMetadata("inline.kt") + public void testInline() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/privateConstructors/inline.kt"); + doTest(fileName); + } + + @TestMetadata("inner.kt") + public void testInner() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/privateConstructors/inner.kt"); + doTest(fileName); + } + + @TestMetadata("secondary.kt") + public void testSecondary() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/privateConstructors/secondary.kt"); + doTest(fileName); + } + + @TestMetadata("withArguments.kt") + public void testWithArguments() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/privateConstructors/withArguments.kt"); + doTest(fileName); + } + + @TestMetadata("withDefault.kt") + public void testWithDefault() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/privateConstructors/withDefault.kt"); + doTest(fileName); + } + + @TestMetadata("withLinkedClasses.kt") + public void testWithLinkedClasses() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/privateConstructors/withLinkedClasses.kt"); + doTest(fileName); + } + + @TestMetadata("withLinkedObjects.kt") + public void testWithLinkedObjects() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/privateConstructors/withLinkedObjects.kt"); + doTest(fileName); + } + + @TestMetadata("withVarargs.kt") + public void testWithVarargs() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/privateConstructors/withVarargs.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/codegen/box/properties") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index f8b759ec6ca..abaf55f04e1 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -2312,6 +2312,21 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode } } + @TestMetadata("compiler/testData/codegen/boxWithStdlib/privateConstructor") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class PrivateConstructor extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInPrivateConstructor() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/privateConstructor"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("synthetic.kt") + public void testSynthetic() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/privateConstructor/synthetic.kt"); + doTestWithStdlib(fileName); + } + } + @TestMetadata("compiler/testData/codegen/boxWithStdlib/ranges") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/plugins/annotation-collector/testData/collectToFile/nestedClasses/annotations.txt b/plugins/annotation-collector/testData/collectToFile/nestedClasses/annotations.txt index 746edbfad6a..4183ec87fa3 100644 --- a/plugins/annotation-collector/testData/collectToFile/nestedClasses/annotations.txt +++ b/plugins/annotation-collector/testData/collectToFile/nestedClasses/annotations.txt @@ -1,8 +1,6 @@ a java.lang.Deprecated 0 p org.test 0 c 0 0/SomeClass$Companion -a org.jetbrains.annotations.NotNull 1 -m 1 0/SomeClass$Companion access$init$0 c 0 0/SomeClass$SomeInnerObject c 0 0/SomeClass$InnerClass c 0 0/SomeClass$InnerClass$InnerClassInInnerClass diff --git a/plugins/annotation-collector/testData/collectToFile/platformStatic/annotations.txt b/plugins/annotation-collector/testData/collectToFile/platformStatic/annotations.txt index 4d9c66f1134..b8d64a800d4 100644 --- a/plugins/annotation-collector/testData/collectToFile/platformStatic/annotations.txt +++ b/plugins/annotation-collector/testData/collectToFile/platformStatic/annotations.txt @@ -3,9 +3,7 @@ p org.test 0 m 0 0/SomeClass$Companion a a kotlin.inline 1 m 1 0/SomeClass$Companion a -a org.jetbrains.annotations.NotNull 2 -m 2 0/SomeClass$Companion access$init$0 -a java.lang.Deprecated 3 -f 3 0/SomeClass OBJECT$ +a java.lang.Deprecated 2 +f 2 0/SomeClass OBJECT$ m 0 0/SomeClass a m 1 0/SomeClass a