diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java index 0045f7abc34..6dde314b579 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java @@ -29,6 +29,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.backend.common.CodegenUtil; import org.jetbrains.kotlin.backend.common.DataClassMethodGenerator; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; +import org.jetbrains.kotlin.codegen.binding.CodegenBinding; import org.jetbrains.kotlin.codegen.binding.MutableClosure; import org.jetbrains.kotlin.codegen.context.*; import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension; @@ -1593,6 +1594,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { iv.iconst(ordinal); List delegationSpecifiers = enumEntry.getSuperTypeListEntries(); + ResolvedCall defaultArgumentsConstructorCall = CallUtilKt.getResolvedCall(enumEntry, bindingContext); + boolean enumEntryHasSubclass = CodegenBinding.enumEntryNeedSubclass(bindingContext, classDescriptor); if (delegationSpecifiers.size() == 1 && !enumEntryNeedSubclass(bindingContext, enumEntry)) { ResolvedCall resolvedCall = CallUtilKt.getResolvedCallWithAssert(delegationSpecifiers.get(0), bindingContext); @@ -1600,6 +1603,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { codegen.invokeMethodWithArguments(method, resolvedCall, StackValue.none()); } + else if (defaultArgumentsConstructorCall != null && !enumEntryHasSubclass) { + codegen.invokeFunction(defaultArgumentsConstructorCall, StackValue.none()).put(Type.VOID_TYPE, iv); + } else { iv.invokespecial(implClass.getInternalName(), "", "(Ljava/lang/String;I)V", false); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodyResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodyResolver.java index f26edc4c1c8..8c64429b8cc 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodyResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodyResolver.java @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.resolve; import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.util.containers.Queue; import kotlin.Unit; @@ -39,6 +40,7 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; import org.jetbrains.kotlin.resolve.calls.util.CallMaker; +import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil; import org.jetbrains.kotlin.resolve.scopes.*; import org.jetbrains.kotlin.types.*; @@ -58,6 +60,7 @@ import static org.jetbrains.kotlin.resolve.BindingContext.*; import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE; public class BodyResolver { + @NotNull private final Project project; @NotNull private final AnnotationChecker annotationChecker; @NotNull private final ExpressionTypingServices expressionTypingServices; @NotNull private final CallResolver callResolver; @@ -74,6 +77,7 @@ public class BodyResolver { @NotNull private final LanguageVersionSettings languageVersionSettings; public BodyResolver( + @NotNull Project project, @NotNull AnnotationResolver annotationResolver, @NotNull BodyResolveCache bodyResolveCache, @NotNull CallResolver callResolver, @@ -89,6 +93,7 @@ public class BodyResolver { @NotNull OverloadChecker overloadChecker, @NotNull LanguageVersionSettings languageVersionSettings ) { + this.project = project; this.annotationResolver = annotationResolver; this.bodyResolveCache = bodyResolveCache; this.callResolver = callResolver; @@ -262,7 +267,7 @@ public class BodyResolver { public void resolveSuperTypeEntryList( @NotNull final DataFlowInfo outerDataFlowInfo, - @NotNull KtClassOrObject jetClass, + @NotNull KtClassOrObject ktClass, @NotNull final ClassDescriptor descriptor, @Nullable final ConstructorDescriptor primaryConstructor, @NotNull LexicalScope scopeForConstructorResolution, @@ -380,19 +385,49 @@ public class BodyResolver { } }; - for (KtSuperTypeListEntry delegationSpecifier : jetClass.getSuperTypeListEntries()) { + if (ktClass instanceof KtEnumEntry && DescriptorUtils.isEnumEntry(descriptor) && ktClass.getSuperTypeListEntries().isEmpty()) { + assert scopeForConstructor != null : "Scope for enum class constructor should be non-null: " + descriptor; + resolveConstructorCallForEnumEntryWithoutInitializer((KtEnumEntry) ktClass, descriptor, scopeForConstructor, outerDataFlowInfo); + } + + for (KtSuperTypeListEntry delegationSpecifier : ktClass.getSuperTypeListEntries()) { delegationSpecifier.accept(visitor); } - if (DescriptorUtils.isAnnotationClass(descriptor) && jetClass.getSuperTypeList() != null) { - trace.report(SUPERTYPES_FOR_ANNOTATION_CLASS.on(jetClass.getSuperTypeList())); + if (DescriptorUtils.isAnnotationClass(descriptor) && ktClass.getSuperTypeList() != null) { + trace.report(SUPERTYPES_FOR_ANNOTATION_CLASS.on(ktClass.getSuperTypeList())); } if (primaryConstructorDelegationCall[0] != null && primaryConstructor != null) { recordConstructorDelegationCall(trace, primaryConstructor, primaryConstructorDelegationCall[0]); } - checkSupertypeList(descriptor, supertypes, jetClass); + checkSupertypeList(descriptor, supertypes, ktClass); + } + + private void resolveConstructorCallForEnumEntryWithoutInitializer( + @NotNull KtEnumEntry ktEnumEntry, + @NotNull ClassDescriptor enumEntryDescriptor, + @NotNull LexicalScope scopeForConstructor, + @NotNull DataFlowInfo outerDataFlowInfo + ) { + assert enumEntryDescriptor.getKind() == ClassKind.ENUM_ENTRY : "Enum entry expected: " + enumEntryDescriptor; + ClassDescriptor enumClassDescriptor = (ClassDescriptor) enumEntryDescriptor.getContainingDeclaration(); + if (enumClassDescriptor.getKind() != ClassKind.ENUM_CLASS) return; + if (enumClassDescriptor.isHeader()) return; + + List applicableConstructors = DescriptorUtilsKt.getConstructorForEmptyArgumentsList(enumClassDescriptor); + if (applicableConstructors.size() != 1) { + trace.report(ENUM_ENTRY_SHOULD_BE_INITIALIZED.on(ktEnumEntry)); + return; + } + + KtInitializerList ktInitializerList = new KtPsiFactory(project).createEnumEntryInitializerList(); + KtSuperTypeCallEntry ktCallEntry = (KtSuperTypeCallEntry) ktInitializerList.getInitializers().get(0); + Call call = CallMaker.makeConstructorCallWithoutTypeArguments(ktCallEntry); + trace.record(BindingContext.TYPE, ktCallEntry.getTypeReference(), enumClassDescriptor.getDefaultType()); + trace.record(BindingContext.CALL, ktEnumEntry, call); + callResolver.resolveFunctionCall(trace, scopeForConstructor, call, NO_EXPECTED_TYPE, outerDataFlowInfo, false); } // Returns a set of enum or sealed types of which supertypeOwner is an entry or a member diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt index 848e065f7d9..3fc14e13de7 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt @@ -34,6 +34,7 @@ import org.jetbrains.kotlin.resolve.BindingContext.* import org.jetbrains.kotlin.resolve.DescriptorUtils.classCanHaveAbstractMembers import org.jetbrains.kotlin.resolve.DescriptorUtils.classCanHaveOpenMembers import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator +import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.source.KotlinSourceElement import org.jetbrains.kotlin.types.* @@ -882,9 +883,6 @@ class DeclarationsChecker( trace.report(HEADER_ENUM_ENTRY_WITH_BODY.on(enumEntry)) } } - else if (!enumEntry.hasInitializer() && !hasDefaultConstructor(enumClass)) { - trace.report(ENUM_ENTRY_SHOULD_BE_INITIALIZED.on(enumEntry)) - } } else { assert(DescriptorUtils.isInterface(enumClass)) { "Enum entry should be declared in enum class: " + enumEntryClass } @@ -969,9 +967,6 @@ class DeclarationsChecker( return !modifierList.hasModifier(KtTokens.OVERRIDE_KEYWORD) } - private fun hasDefaultConstructor(classDescriptor: ClassDescriptor) = - classDescriptor.constructors.any { it.valueParameters.isEmpty() } - private fun PropertyDescriptor.hasAccessorImplementation(): Boolean { getter?.let { if (it.hasBody()) return true } setter?.let { if (it.hasBody()) return true } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/CallMaker.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/CallMaker.java index 54811533434..c214f979be1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/CallMaker.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/CallMaker.java @@ -282,6 +282,77 @@ public class CallMaker { }; } + @NotNull + public static Call makeConstructorCallForEnumEntryWithoutInitializer(@NotNull final KtSuperTypeCallEntry callElement) { + return new Call() { + @Nullable + @Override + public ASTNode getCallOperationNode() { + return null; + } + + @Nullable + @Override + public Receiver getExplicitReceiver() { + return null; + } + + @Nullable + @Override + public ReceiverValue getDispatchReceiver() { + return null; + } + + @Nullable + @Override + public KtExpression getCalleeExpression() { + return callElement.getCalleeExpression(); + } + + @Nullable + @Override + public KtValueArgumentList getValueArgumentList() { + return callElement.getValueArgumentList(); + } + + @NotNull + @Override + public List getValueArguments() { + return callElement.getValueArguments(); + } + + @NotNull + @Override + public List getFunctionLiteralArguments() { + return Collections.emptyList(); + } + + @NotNull + @Override + public List getTypeArguments() { + return Collections.emptyList(); + } + + @Nullable + @Override + public KtTypeArgumentList getTypeArgumentList() { + return null; + } + + @NotNull + @Override + public KtElement getCallElement() { + return callElement; + } + + @NotNull + @Override + public CallType getCallType() { + return CallType.DEFAULT; + } + }; + } + @NotNull public static Call makeCall(@Nullable final Receiver explicitReceiver, @Nullable final ASTNode callOperationNode, @NotNull final KtCallElement callElement) { return new Call() { diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BodyGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BodyGenerator.kt index 4da8e3e7f3e..3f463c912e9 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BodyGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BodyGenerator.kt @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny import java.lang.AssertionError import java.util.* @@ -267,18 +268,25 @@ class BodyGenerator(val scopeOwner: DeclarationDescriptor, override val context: val statementGenerator = createStatementGenerator() // Entry constructor with argument(s) - ktEnumEntry.getSuperTypeListEntries().firstOrNull()?.let { ktSuperCallElement -> - val enumConstructorCall = statementGenerator.pregenerateCall(getResolvedCall(ktSuperCallElement)!!) - return CallGenerator(statementGenerator).generateEnumConstructorSuperCall( - ktEnumEntry.startOffset, ktEnumEntry.endOffset, - enumConstructorCall) + val ktSuperCallElement = ktEnumEntry.superTypeListEntries.firstOrNull() + if (ktSuperCallElement != null) { + return statementGenerator.generateEnumConstructorCall(getResolvedCall(ktSuperCallElement)!!, ktEnumEntry) } + val enumDefaultConstructorCall = getResolvedCall(ktEnumEntry) + if (enumDefaultConstructorCall != null) { + return statementGenerator.generateEnumConstructorCall(enumDefaultConstructorCall, ktEnumEntry) + } + // No-argument enum entry constructor val enumClassConstructor = enumClassDescriptor.constructors.find { it.valueParameters.isEmpty() }!! return IrEnumConstructorCallImpl(ktEnumEntry.startOffset, ktEnumEntry.endOffset, enumClassConstructor) } + private fun StatementGenerator.generateEnumConstructorCall(constructorCall: ResolvedCall, ktEnumEntry: KtEnumEntry) = + CallGenerator(this).generateEnumConstructorSuperCall(ktEnumEntry.startOffset, ktEnumEntry.endOffset, + pregenerateCall(constructorCall)) + } diff --git a/compiler/testData/codegen/box/enum/defaultCtor/constructorWithDefaultArguments.kt b/compiler/testData/codegen/box/enum/defaultCtor/constructorWithDefaultArguments.kt new file mode 100644 index 00000000000..fcdaf5b62ae --- /dev/null +++ b/compiler/testData/codegen/box/enum/defaultCtor/constructorWithDefaultArguments.kt @@ -0,0 +1,6 @@ +enum class Test(val str: String = "OK") { + OK +} + +fun box(): String = + Test.OK.str \ No newline at end of file diff --git a/compiler/testData/codegen/box/enum/defaultCtor/constructorWithVararg.kt b/compiler/testData/codegen/box/enum/defaultCtor/constructorWithVararg.kt new file mode 100644 index 00000000000..be8f86f66a4 --- /dev/null +++ b/compiler/testData/codegen/box/enum/defaultCtor/constructorWithVararg.kt @@ -0,0 +1,9 @@ +// IGNORE_BACKEND: JS + +enum class Test(vararg xs: Int) { + OK; + val values = xs +} + +fun box(): String = + if (Test.OK.values.size == 0) "OK" else "Fail" \ No newline at end of file diff --git a/compiler/testData/codegen/box/enum/defaultCtor/secondaryConstructorWithDefaultArguments.kt b/compiler/testData/codegen/box/enum/defaultCtor/secondaryConstructorWithDefaultArguments.kt new file mode 100644 index 00000000000..58b0be6c9f0 --- /dev/null +++ b/compiler/testData/codegen/box/enum/defaultCtor/secondaryConstructorWithDefaultArguments.kt @@ -0,0 +1,10 @@ +// IGNORE_BACKEND: JS +// see KT-14097 + +enum class Test(val x: Int, val str: String) { + OK; + constructor(x: Int = 0) : this(x, "OK") +} + +fun box(): String = + Test.OK.str \ No newline at end of file diff --git a/compiler/testData/codegen/box/enum/defaultCtor/secondaryConstructorWithVararg.kt b/compiler/testData/codegen/box/enum/defaultCtor/secondaryConstructorWithVararg.kt new file mode 100644 index 00000000000..9bee8603d4a --- /dev/null +++ b/compiler/testData/codegen/box/enum/defaultCtor/secondaryConstructorWithVararg.kt @@ -0,0 +1,13 @@ +// IGNORE_BACKEND: JS +// see KT-14097 + +enum class Test(val x: Int, val str: String) { + OK; + constructor(vararg xs: Int) : this(xs.size + 42, "OK") +} + +fun box(): String = + if (Test.OK.x == 42) + Test.OK.str + else + "Fail" \ No newline at end of file diff --git a/compiler/testData/codegen/light-analysis/enum/defaultCtor/constructorWithDefaultArguments.txt b/compiler/testData/codegen/light-analysis/enum/defaultCtor/constructorWithDefaultArguments.txt new file mode 100644 index 00000000000..5a114b5eef7 --- /dev/null +++ b/compiler/testData/codegen/light-analysis/enum/defaultCtor/constructorWithDefaultArguments.txt @@ -0,0 +1,15 @@ +@kotlin.Metadata +public final class ConstructorWithDefaultArgumentsKt { + public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String +} + +@kotlin.Metadata +public enum class Test { + public final static field OK: Test + private final @org.jetbrains.annotations.NotNull field str: java.lang.String + protected method (@java.lang.Synthetic p0: java.lang.String, @java.lang.Synthetic p1: int, @org.jetbrains.annotations.NotNull p2: java.lang.String): void + synthetic method (p0: java.lang.String, p1: int, p2: java.lang.String, p3: int, p4: kotlin.jvm.internal.DefaultConstructorMarker): void + public final @org.jetbrains.annotations.NotNull method getStr(): java.lang.String + public static method valueOf(p0: java.lang.String): Test + public static method values(): Test[] +} diff --git a/compiler/testData/codegen/light-analysis/enum/defaultCtor/constructorWithVararg.txt b/compiler/testData/codegen/light-analysis/enum/defaultCtor/constructorWithVararg.txt new file mode 100644 index 00000000000..72f6cca9d74 --- /dev/null +++ b/compiler/testData/codegen/light-analysis/enum/defaultCtor/constructorWithVararg.txt @@ -0,0 +1,14 @@ +@kotlin.Metadata +public final class ConstructorWithVarargKt { + public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String +} + +@kotlin.Metadata +public enum class Test { + public final static field OK: Test + private final @org.jetbrains.annotations.NotNull field values: int[] + protected method (@java.lang.Synthetic p0: java.lang.String, @java.lang.Synthetic p1: int, @org.jetbrains.annotations.NotNull p2: int[]): void + public final @org.jetbrains.annotations.NotNull method getValues(): int[] + public static method valueOf(p0: java.lang.String): Test + public static method values(): Test[] +} diff --git a/compiler/testData/codegen/light-analysis/enum/defaultCtor/secondaryConstructorWithDefaultArguments.txt b/compiler/testData/codegen/light-analysis/enum/defaultCtor/secondaryConstructorWithDefaultArguments.txt new file mode 100644 index 00000000000..b89ecebfafd --- /dev/null +++ b/compiler/testData/codegen/light-analysis/enum/defaultCtor/secondaryConstructorWithDefaultArguments.txt @@ -0,0 +1,18 @@ +@kotlin.Metadata +public final class SecondaryConstructorWithDefaultArgumentsKt { + public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String +} + +@kotlin.Metadata +public enum class Test { + public final static field OK: Test + private final @org.jetbrains.annotations.NotNull field str: java.lang.String + private final field x: int + protected method (@java.lang.Synthetic p0: java.lang.String, @java.lang.Synthetic p1: int, p2: int, @org.jetbrains.annotations.NotNull p3: java.lang.String): void + protected method (p0: java.lang.String, p1: int, p2: int): void + synthetic method (p0: java.lang.String, p1: int, p2: int, p3: int, p4: kotlin.jvm.internal.DefaultConstructorMarker): void + public final @org.jetbrains.annotations.NotNull method getStr(): java.lang.String + public final method getX(): int + public static method valueOf(p0: java.lang.String): Test + public static method values(): Test[] +} diff --git a/compiler/testData/codegen/light-analysis/enum/defaultCtor/secondaryConstructorWithVararg.txt b/compiler/testData/codegen/light-analysis/enum/defaultCtor/secondaryConstructorWithVararg.txt new file mode 100644 index 00000000000..e30b7f28fc7 --- /dev/null +++ b/compiler/testData/codegen/light-analysis/enum/defaultCtor/secondaryConstructorWithVararg.txt @@ -0,0 +1,17 @@ +@kotlin.Metadata +public final class SecondaryConstructorWithVarargKt { + public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String +} + +@kotlin.Metadata +public enum class Test { + public final static field OK: Test + private final @org.jetbrains.annotations.NotNull field str: java.lang.String + private final field x: int + protected method (@java.lang.Synthetic p0: java.lang.String, @java.lang.Synthetic p1: int, @org.jetbrains.annotations.NotNull p2: int[]): void + protected method (@java.lang.Synthetic p0: java.lang.String, @java.lang.Synthetic p1: int, p2: int, @org.jetbrains.annotations.NotNull p3: java.lang.String): void + public final @org.jetbrains.annotations.NotNull method getStr(): java.lang.String + public final method getX(): int + public static method valueOf(p0: java.lang.String): Test + public static method values(): Test[] +} diff --git a/compiler/testData/diagnostics/tests/enum/constructorWithDefaultParametersOnly.kt b/compiler/testData/diagnostics/tests/enum/constructorWithDefaultParametersOnly.kt new file mode 100644 index 00000000000..3c5286d1bba --- /dev/null +++ b/compiler/testData/diagnostics/tests/enum/constructorWithDefaultParametersOnly.kt @@ -0,0 +1,21 @@ +enum class TestOk(val x: String = "OK") { + TEST1, + TEST2(), + TEST3("Hello") +} + +enum class TestErrors(val x: String) { + TEST1, + TEST2(), + TEST3("Hello") +} + +enum class TestMultipleConstructors(val x: String = "", val y: Int = 0) { + TEST; + constructor(x: String = "") : this(x, 0) +} + +enum class TestVarargs(val x: Int) { + TEST; + constructor(vararg xs: Any) : this(xs.size) +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/enum/constructorWithDefaultParametersOnly.txt b/compiler/testData/diagnostics/tests/enum/constructorWithDefaultParametersOnly.txt new file mode 100644 index 00000000000..0e7b5efbe97 --- /dev/null +++ b/compiler/testData/diagnostics/tests/enum/constructorWithDefaultParametersOnly.txt @@ -0,0 +1,92 @@ +package + +public final enum class TestErrors : kotlin.Enum { + enum entry TEST1 + + enum entry TEST2 + + enum entry TEST3 + + private constructor TestErrors(/*0*/ x: kotlin.String) + public final override /*1*/ /*fake_override*/ val name: kotlin.String + public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int + public final val x: kotlin.String + protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any + public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: TestErrors): kotlin.Int + public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit + public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class! + public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): TestErrors + public final /*synthesized*/ fun values(): kotlin.Array +} + +public final enum class TestMultipleConstructors : kotlin.Enum { + enum entry TEST + + private constructor TestMultipleConstructors(/*0*/ x: kotlin.String = ...) + private constructor TestMultipleConstructors(/*0*/ x: kotlin.String = ..., /*1*/ y: kotlin.Int = ...) + public final override /*1*/ /*fake_override*/ val name: kotlin.String + public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int + public final val x: kotlin.String + public final val y: kotlin.Int + protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any + public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: TestMultipleConstructors): kotlin.Int + public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit + public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class! + public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): TestMultipleConstructors + public final /*synthesized*/ fun values(): kotlin.Array +} + +public final enum class TestOk : kotlin.Enum { + enum entry TEST1 + + enum entry TEST2 + + enum entry TEST3 + + private constructor TestOk(/*0*/ x: kotlin.String = ...) + public final override /*1*/ /*fake_override*/ val name: kotlin.String + public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int + public final val x: kotlin.String + protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any + public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: TestOk): kotlin.Int + public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit + public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class! + public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): TestOk + public final /*synthesized*/ fun values(): kotlin.Array +} + +public final enum class TestVarargs : kotlin.Enum { + enum entry TEST + + private constructor TestVarargs(/*0*/ vararg xs: kotlin.Any /*kotlin.Array*/) + private constructor TestVarargs(/*0*/ x: kotlin.Int) + public final override /*1*/ /*fake_override*/ val name: kotlin.String + public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int + public final val x: kotlin.Int + protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any + public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: TestVarargs): kotlin.Int + public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit + public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class! + public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): TestVarargs + public final /*synthesized*/ fun values(): kotlin.Array +} diff --git a/compiler/testData/ir/irText/classes/enum.kt b/compiler/testData/ir/irText/classes/enum.kt index d0e2b8962f7..72cd8431719 100644 --- a/compiler/testData/ir/irText/classes/enum.kt +++ b/compiler/testData/ir/irText/classes/enum.kt @@ -37,4 +37,8 @@ enum class TestEnum4(val x: Int) { } ; abstract fun foo() +} + +enum class TestEnum5(val x: Int = 0) { + TEST1, TEST2(), TEST3(0) } \ No newline at end of file diff --git a/compiler/testData/ir/irText/classes/enum.txt b/compiler/testData/ir/irText/classes/enum.txt index b773c985e1b..652b889c98d 100644 --- a/compiler/testData/ir/irText/classes/enum.txt +++ b/compiler/testData/ir/irText/classes/enum.txt @@ -116,3 +116,30 @@ FILE /enum.kt SYNTHETIC_BODY kind=ENUM_VALUES FUN ENUM_CLASS_SPECIAL_MEMBER public final fun valueOf(value: kotlin.String): TestEnum4 SYNTHETIC_BODY kind=ENUM_VALUEOF + CLASS ENUM_CLASS TestEnum5 + CONSTRUCTOR private constructor TestEnum5(x: kotlin.Int = ...) + x: EXPRESSION_BODY + CONST Int type=kotlin.Int value='0' + BLOCK_BODY + ENUM_CONSTRUCTOR_CALL 'constructor Enum(String, Int)' + INSTANCE_INITIALIZER_CALL classDescriptor='TestEnum5' + PROPERTY public final val x: kotlin.Int + FIELD PROPERTY_BACKING_FIELD public final val x: kotlin.Int + EXPRESSION_BODY + GET_VAR 'value-parameter x: Int = ...' type=kotlin.Int origin=INITIALIZE_PROPERTY_FROM_PARAMETER + FUN DEFAULT_PROPERTY_ACCESSOR public final fun (): kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): Int' + GET_FIELD 'x: Int' type=kotlin.Int origin=null + receiver: GET_VAR '' type=TestEnum5 origin=null + ENUM_ENTRY enum entry TEST1 + init: ENUM_CONSTRUCTOR_CALL 'constructor TestEnum5(Int = ...)' + ENUM_ENTRY enum entry TEST2 + init: ENUM_CONSTRUCTOR_CALL 'constructor TestEnum5(Int = ...)' + ENUM_ENTRY enum entry TEST3 + init: ENUM_CONSTRUCTOR_CALL 'constructor TestEnum5(Int = ...)' + x: CONST Int type=kotlin.Int value='0' + FUN ENUM_CLASS_SPECIAL_MEMBER public final fun values(): kotlin.Array + SYNTHETIC_BODY kind=ENUM_VALUES + FUN ENUM_CLASS_SPECIAL_MEMBER public final fun valueOf(value: kotlin.String): TestEnum5 + SYNTHETIC_BODY kind=ENUM_VALUEOF diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 6cd2342b0d8..274f20405be 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -7018,6 +7018,39 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/enum/valueof.kt"); doTest(fileName); } + + @TestMetadata("compiler/testData/codegen/box/enum/defaultCtor") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class DefaultCtor extends AbstractIrBlackBoxCodegenTest { + public void testAllFilesPresentInDefaultCtor() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/enum/defaultCtor"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + + @TestMetadata("constructorWithDefaultArguments.kt") + public void testConstructorWithDefaultArguments() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/enum/defaultCtor/constructorWithDefaultArguments.kt"); + doTest(fileName); + } + + @TestMetadata("constructorWithVararg.kt") + public void testConstructorWithVararg() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/enum/defaultCtor/constructorWithVararg.kt"); + doTest(fileName); + } + + @TestMetadata("secondaryConstructorWithDefaultArguments.kt") + public void testSecondaryConstructorWithDefaultArguments() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/enum/defaultCtor/secondaryConstructorWithDefaultArguments.kt"); + doTest(fileName); + } + + @TestMetadata("secondaryConstructorWithVararg.kt") + public void testSecondaryConstructorWithVararg() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/enum/defaultCtor/secondaryConstructorWithVararg.kt"); + doTest(fileName); + } + } } @TestMetadata("compiler/testData/codegen/box/evaluate") diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 25f6c8268aa..d34de29b303 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -7327,6 +7327,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("constructorWithDefaultParametersOnly.kt") + public void testConstructorWithDefaultParametersOnly() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/enum/constructorWithDefaultParametersOnly.kt"); + doTest(fileName); + } + @TestMetadata("dontCreatePackageTypeForEnumEntry.kt") public void testDontCreatePackageTypeForEnumEntry() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/enum/dontCreatePackageTypeForEnumEntry.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index ab09a310f85..5ea47d3c4ad 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -7018,6 +7018,39 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/enum/valueof.kt"); doTest(fileName); } + + @TestMetadata("compiler/testData/codegen/box/enum/defaultCtor") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class DefaultCtor extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInDefaultCtor() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/enum/defaultCtor"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + + @TestMetadata("constructorWithDefaultArguments.kt") + public void testConstructorWithDefaultArguments() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/enum/defaultCtor/constructorWithDefaultArguments.kt"); + doTest(fileName); + } + + @TestMetadata("constructorWithVararg.kt") + public void testConstructorWithVararg() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/enum/defaultCtor/constructorWithVararg.kt"); + doTest(fileName); + } + + @TestMetadata("secondaryConstructorWithDefaultArguments.kt") + public void testSecondaryConstructorWithDefaultArguments() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/enum/defaultCtor/secondaryConstructorWithDefaultArguments.kt"); + doTest(fileName); + } + + @TestMetadata("secondaryConstructorWithVararg.kt") + public void testSecondaryConstructorWithVararg() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/enum/defaultCtor/secondaryConstructorWithVararg.kt"); + doTest(fileName); + } + } } @TestMetadata("compiler/testData/codegen/box/evaluate") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeCodegenTestGenerated.java index 820e5f664c3..42a7e8ca6cd 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeCodegenTestGenerated.java @@ -7018,6 +7018,39 @@ public class LightAnalysisModeCodegenTestGenerated extends AbstractLightAnalysis String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/enum/valueof.kt"); doTest(fileName); } + + @TestMetadata("compiler/testData/codegen/box/enum/defaultCtor") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class DefaultCtor extends AbstractLightAnalysisModeCodegenTest { + public void testAllFilesPresentInDefaultCtor() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/enum/defaultCtor"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + + @TestMetadata("constructorWithDefaultArguments.kt") + public void testConstructorWithDefaultArguments() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/enum/defaultCtor/constructorWithDefaultArguments.kt"); + doTest(fileName); + } + + @TestMetadata("constructorWithVararg.kt") + public void testConstructorWithVararg() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/enum/defaultCtor/constructorWithVararg.kt"); + doTest(fileName); + } + + @TestMetadata("secondaryConstructorWithDefaultArguments.kt") + public void testSecondaryConstructorWithDefaultArguments() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/enum/defaultCtor/secondaryConstructorWithDefaultArguments.kt"); + doTest(fileName); + } + + @TestMetadata("secondaryConstructorWithVararg.kt") + public void testSecondaryConstructorWithVararg() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/enum/defaultCtor/secondaryConstructorWithVararg.kt"); + doTest(fileName); + } + } } @TestMetadata("compiler/testData/codegen/box/evaluate") diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt index 51ce93e09f8..f8d000b3322 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt @@ -391,3 +391,9 @@ fun computeSealedSubclasses(sealedClass: ClassDescriptor): Collection = + constructors.filter { it.valueParameters.all { it.hasDefaultValue() || it.varargElementType != null } } diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 37314141e1e..f975e85ae53 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -7937,6 +7937,57 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/enum/valueof.kt"); doTest(fileName); } + + @TestMetadata("compiler/testData/codegen/box/enum/defaultCtor") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class DefaultCtor extends AbstractJsCodegenBoxTest { + public void testAllFilesPresentInDefaultCtor() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/enum/defaultCtor"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true); + } + + @TestMetadata("constructorWithDefaultArguments.kt") + public void testConstructorWithDefaultArguments() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/enum/defaultCtor/constructorWithDefaultArguments.kt"); + doTest(fileName); + } + + @TestMetadata("constructorWithVararg.kt") + public void testConstructorWithVararg() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/enum/defaultCtor/constructorWithVararg.kt"); + try { + doTest(fileName); + } + catch (Throwable ignore) { + return; + } + throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + } + + @TestMetadata("secondaryConstructorWithDefaultArguments.kt") + public void testSecondaryConstructorWithDefaultArguments() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/enum/defaultCtor/secondaryConstructorWithDefaultArguments.kt"); + try { + doTest(fileName); + } + catch (Throwable ignore) { + return; + } + throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + } + + @TestMetadata("secondaryConstructorWithVararg.kt") + public void testSecondaryConstructorWithVararg() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/enum/defaultCtor/secondaryConstructorWithVararg.kt"); + try { + doTest(fileName); + } + catch (Throwable ignore) { + return; + } + throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + } + } } @TestMetadata("compiler/testData/codegen/box/evaluate")