From 12e8b1d844c85cf4b9aef59d4f2d5f07f79d9e59 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Mon, 25 Jul 2022 11:40:32 +0200 Subject: [PATCH] K1: add support for Enum.entries synthetic property (see KT-48872) #KT-53270 Fixed --- .../CompilerDeserializationConfiguration.kt | 2 + .../lazy/descriptors/LazyClassDescriptor.java | 5 +- .../generators/EnumClassMembersGenerator.kt | 35 ++++++- .../codegen/bytecodeListing/enumEntries.kt | 6 +- .../ir/irText/classes/enumEntries.fir.ir.txt | 73 ++++++++++++++ .../ir/irText/classes/enumEntries.fir.kt.txt | 24 +++++ .../ir/irText/classes/enumEntries.ir.txt | 94 ++++++++++--------- .../testData/ir/irText/classes/enumEntries.kt | 1 - .../kotlin/resolve/DescriptorFactory.java | 38 +++++++- .../kotlin/resolve/scopes/MemberScope.kt | 3 + .../scopes/StaticScopeForKotlinEnum.kt | 18 +++- .../DeserializationConfiguration.kt | 3 + .../DeserializedClassDescriptor.kt | 7 +- 13 files changed, 247 insertions(+), 62 deletions(-) create mode 100644 compiler/testData/ir/irText/classes/enumEntries.fir.ir.txt create mode 100644 compiler/testData/ir/irText/classes/enumEntries.fir.kt.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/CompilerDeserializationConfiguration.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/CompilerDeserializationConfiguration.kt index 08ed503963a..0d0c6258145 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/CompilerDeserializationConfiguration.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/CompilerDeserializationConfiguration.kt @@ -25,4 +25,6 @@ class CompilerDeserializationConfiguration(languageVersionSettings: LanguageVers override val isJvmPackageNameSupported = languageVersionSettings.supportsFeature(LanguageFeature.JvmPackageName) override val readDeserializedContracts: Boolean = languageVersionSettings.supportsFeature(LanguageFeature.ReadDeserializedContracts) + + override val supportEnumEntries: Boolean = languageVersionSettings.supportsFeature(LanguageFeature.EnumEntries) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassDescriptor.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassDescriptor.java index 0395618eb50..c1d368ed976 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassDescriptor.java @@ -132,7 +132,10 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes this.scopesHolderForClass = createScopesHolderForClass(c, this.declarationProvider); this.kind = classLikeInfo.getClassKind(); - this.staticScope = kind == ClassKind.ENUM_CLASS ? new StaticScopeForKotlinEnum(storageManager, this) : MemberScope.Empty.INSTANCE; + this.staticScope = kind == ClassKind.ENUM_CLASS ? + new StaticScopeForKotlinEnum( + storageManager, this, c.getLanguageVersionSettings().supportsFeature(LanguageFeature.EnumEntries) + ) : MemberScope.Empty.INSTANCE; this.typeConstructor = new LazyClassTypeConstructor(); diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/EnumClassMembersGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/EnumClassMembersGenerator.kt index f33101d7e92..96623b5801f 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/EnumClassMembersGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/EnumClassMembersGenerator.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.psi2ir.generators +import org.jetbrains.kotlin.builtins.StandardNames.ENUM_ENTRIES import org.jetbrains.kotlin.builtins.StandardNames.ENUM_VALUES import org.jetbrains.kotlin.builtins.StandardNames.ENUM_VALUE_OF import org.jetbrains.kotlin.ir.declarations.IrClass @@ -26,11 +27,13 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrSyntheticBodyImpl import org.jetbrains.kotlin.ir.util.SYNTHETIC_OFFSET import org.jetbrains.kotlin.ir.util.declareSimpleFunctionWithOverrides import org.jetbrains.kotlin.resolve.scopes.findFirstFunction +import org.jetbrains.kotlin.resolve.scopes.findFirstVariable class EnumClassMembersGenerator(declarationGenerator: DeclarationGenerator) : DeclarationGeneratorExtension(declarationGenerator) { fun generateSpecialMembers(irClass: IrClass) { generateValues(irClass) generateValueOf(irClass) + generateEntries(irClass) } private fun generateValues(irClass: IrClass) { @@ -46,7 +49,9 @@ class EnumClassMembersGenerator(declarationGenerator: DeclarationGenerator) : De IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER, valuesFunction ).also { irFunction -> - FunctionGenerator(declarationGenerator).generateFunctionParameterDeclarationsAndReturnType(irFunction, null, null, emptyList()) + FunctionGenerator(declarationGenerator).generateFunctionParameterDeclarationsAndReturnType( + irFunction, null, null, emptyList() + ) irFunction.body = IrSyntheticBodyImpl(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, IrSyntheticBodyKind.ENUM_VALUES) } ) @@ -65,9 +70,35 @@ class EnumClassMembersGenerator(declarationGenerator: DeclarationGenerator) : De IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER, valueOfFunction ).also { irFunction -> - FunctionGenerator(declarationGenerator).generateFunctionParameterDeclarationsAndReturnType(irFunction, null, null, emptyList()) + FunctionGenerator(declarationGenerator).generateFunctionParameterDeclarationsAndReturnType( + irFunction, null, null, emptyList() + ) irFunction.body = IrSyntheticBodyImpl(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, IrSyntheticBodyKind.ENUM_VALUEOF) } ) } + + private fun generateEntries(irClass: IrClass) { + val entriesProperty = irClass.descriptor.staticScope.findFirstVariable(ENUM_ENTRIES.identifier) { + it.dispatchReceiverParameter == null && it.extensionReceiverParameter == null + } ?: return + + irClass.addMember( + context.symbolTable.declareProperty( + SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, + IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER, + entriesProperty + ).also { irProperty -> + irProperty.getter = context.symbolTable.declareSimpleFunctionWithOverrides( + SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, + IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR, + entriesProperty.getter!! + ).also { getter -> + getter.correspondingPropertySymbol = irProperty.symbol + getter.returnType = entriesProperty.returnType!!.toIrType() + getter.body = IrSyntheticBodyImpl(irProperty.startOffset, irProperty.endOffset, IrSyntheticBodyKind.ENUM_ENTRIES) + } + } + ) + } } diff --git a/compiler/testData/codegen/bytecodeListing/enumEntries.kt b/compiler/testData/codegen/bytecodeListing/enumEntries.kt index e200e79d8fd..a1f7de90484 100644 --- a/compiler/testData/codegen/bytecodeListing/enumEntries.kt +++ b/compiler/testData/codegen/bytecodeListing/enumEntries.kt @@ -1,7 +1,7 @@ -// TARGET_BACKEND: JVM_IR - -// WITH_RUNTIME // !LANGUAGE: +EnumEntries +// TARGET_BACKEND: JVM_IR +// FULL_JDK +// WITH_STDLIB enum class SimpleEnum { A, B, C diff --git a/compiler/testData/ir/irText/classes/enumEntries.fir.ir.txt b/compiler/testData/ir/irText/classes/enumEntries.fir.ir.txt new file mode 100644 index 00000000000..d4d800e7f6b --- /dev/null +++ b/compiler/testData/ir/irText/classes/enumEntries.fir.ir.txt @@ -0,0 +1,73 @@ +FILE fqName: fileName:/enumEntries.kt + CLASS ENUM_CLASS name:MyEnum modality:FINAL visibility:public superTypes:[kotlin.Enum<.MyEnum>] + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.MyEnum + CONSTRUCTOR visibility:private <> () returnType:.MyEnum [primary] + BLOCK_BODY + ENUM_CONSTRUCTOR_CALL 'public constructor (name: kotlin.String, ordinal: kotlin.Int) [primary] declared in kotlin.Enum' + : .MyEnum + INSTANCE_INITIALIZER_CALL classDescriptor='CLASS ENUM_CLASS name:MyEnum modality:FINAL visibility:public superTypes:[kotlin.Enum<.MyEnum>]' + ENUM_ENTRY name:Ok + init: EXPRESSION_BODY + ENUM_CONSTRUCTOR_CALL 'private constructor () [primary] declared in .MyEnum' + ENUM_ENTRY name:Nope + init: EXPRESSION_BODY + ENUM_CONSTRUCTOR_CALL 'private constructor () [primary] declared in .MyEnum' + FUN ENUM_CLASS_SPECIAL_MEMBER name:values visibility:public modality:FINAL <> () returnType:kotlin.Array<.MyEnum> + SYNTHETIC_BODY kind=ENUM_VALUES + FUN ENUM_CLASS_SPECIAL_MEMBER name:valueOf visibility:public modality:FINAL <> (value:kotlin.String) returnType:.MyEnum + VALUE_PARAMETER name:value index:0 type:kotlin.String + SYNTHETIC_BODY kind=ENUM_VALUEOF + PROPERTY ENUM_CLASS_SPECIAL_MEMBER name:entries visibility:public modality:FINAL [val] + FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:public modality:FINAL <> () returnType:kotlin.enums.EnumEntries<.MyEnum> + correspondingProperty: PROPERTY ENUM_CLASS_SPECIAL_MEMBER name:entries visibility:public modality:FINAL [val] + SYNTHETIC_BODY kind=ENUM_ENTRIES + FUN FAKE_OVERRIDE name:clone visibility:protected modality:FINAL <> ($this:kotlin.Enum) returnType:kotlin.Any [fake_override] + overridden: + protected final fun clone (): kotlin.Any declared in kotlin.Enum + $this: VALUE_PARAMETER name: type:kotlin.Enum + FUN FAKE_OVERRIDE name:compareTo visibility:public modality:FINAL <> ($this:kotlin.Enum, other:.MyEnum) returnType:kotlin.Int [fake_override,operator] + overridden: + public final fun compareTo (other: E of kotlin.Enum): kotlin.Int [operator] declared in kotlin.Enum + $this: VALUE_PARAMETER name: type:kotlin.Enum + VALUE_PARAMETER name:other index:0 type:.MyEnum + FUN FAKE_OVERRIDE name:equals visibility:public modality:FINAL <> ($this:kotlin.Enum, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator] + overridden: + public final fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Enum + $this: VALUE_PARAMETER name: type:kotlin.Enum + VALUE_PARAMETER name:other index:0 type:kotlin.Any? + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:FINAL <> ($this:kotlin.Enum) returnType:kotlin.Int [fake_override] + overridden: + public final fun hashCode (): kotlin.Int declared in kotlin.Enum + $this: VALUE_PARAMETER name: type:kotlin.Enum + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Enum) returnType:kotlin.String [fake_override] + overridden: + public open fun toString (): kotlin.String declared in kotlin.Enum + $this: VALUE_PARAMETER name: type:kotlin.Enum + PROPERTY FAKE_OVERRIDE name:name visibility:public modality:FINAL [fake_override,val] + annotations: + IntrinsicConstEvaluation + overridden: + public final name: kotlin.String [val] + FUN FAKE_OVERRIDE name: visibility:public modality:FINAL <> ($this:kotlin.Enum) returnType:kotlin.String [fake_override] + correspondingProperty: PROPERTY FAKE_OVERRIDE name:name visibility:public modality:FINAL [fake_override,val] + overridden: + public final fun (): kotlin.String declared in kotlin.Enum + $this: VALUE_PARAMETER name: type:kotlin.Enum + PROPERTY FAKE_OVERRIDE name:ordinal visibility:public modality:FINAL [fake_override,val] + overridden: + public final ordinal: kotlin.Int [val] + FUN FAKE_OVERRIDE name: visibility:public modality:FINAL <> ($this:kotlin.Enum) returnType:kotlin.Int [fake_override] + correspondingProperty: PROPERTY FAKE_OVERRIDE name:ordinal visibility:public modality:FINAL [fake_override,val] + overridden: + public final fun (): kotlin.Int declared in kotlin.Enum + $this: VALUE_PARAMETER name: type:kotlin.Enum + FUN FAKE_OVERRIDE name:getDeclaringClass visibility:public modality:FINAL <> ($this:kotlin.Enum) returnType:@[FlexibleNullability] java.lang.Class<@[FlexibleNullability] .MyEnum?>? [fake_override] + overridden: + public final fun getDeclaringClass (): @[FlexibleNullability] java.lang.Class<@[FlexibleNullability] E of kotlin.Enum?>? declared in kotlin.Enum + $this: VALUE_PARAMETER name: type:kotlin.Enum + FUN name:box visibility:public modality:FINAL <> () returnType:kotlin.enums.EnumEntries<.MyEnum> + annotations: + OptIn(markerClass = [CLASS_REFERENCE 'CLASS IR_EXTERNAL_DECLARATION_STUB ANNOTATION_CLASS name:ExperimentalStdlibApi modality:FINAL visibility:public superTypes:[kotlin.Annotation]' type=kotlin.reflect.KClass]) + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun box (): kotlin.enums.EnumEntries<.MyEnum> declared in ' + CALL 'public final fun (): kotlin.enums.EnumEntries<.MyEnum> declared in .MyEnum' type=kotlin.enums.EnumEntries<.MyEnum> origin=GET_PROPERTY diff --git a/compiler/testData/ir/irText/classes/enumEntries.fir.kt.txt b/compiler/testData/ir/irText/classes/enumEntries.fir.kt.txt new file mode 100644 index 00000000000..54d4577e0c6 --- /dev/null +++ b/compiler/testData/ir/irText/classes/enumEntries.fir.kt.txt @@ -0,0 +1,24 @@ +enum class MyEnum : Enum { + private constructor() /* primary */ { + super/*Enum*/() + /* () */ + + } + + Ok = MyEnum() + + Nope = MyEnum() + + fun values(): Array /* Synthetic body for ENUM_VALUES */ + + fun valueOf(value: String): MyEnum /* Synthetic body for ENUM_VALUEOF */ + + val entries: EnumEntries + get + +} + +@OptIn(markerClass = [ExperimentalStdlibApi::class]) +fun box(): EnumEntries { + return () +} diff --git a/compiler/testData/ir/irText/classes/enumEntries.ir.txt b/compiler/testData/ir/irText/classes/enumEntries.ir.txt index d4d800e7f6b..2d6ae19d9b5 100644 --- a/compiler/testData/ir/irText/classes/enumEntries.ir.txt +++ b/compiler/testData/ir/irText/classes/enumEntries.ir.txt @@ -12,6 +12,54 @@ FILE fqName: fileName:/enumEntries.kt ENUM_ENTRY name:Nope init: EXPRESSION_BODY ENUM_CONSTRUCTOR_CALL 'private constructor () [primary] declared in .MyEnum' + PROPERTY FAKE_OVERRIDE name:name visibility:public modality:FINAL [fake_override,val] + annotations: + IntrinsicConstEvaluation + overridden: + public final name: kotlin.String [val] + FUN FAKE_OVERRIDE name: visibility:public modality:FINAL <> ($this:kotlin.Enum<.MyEnum>) returnType:kotlin.String [fake_override] + correspondingProperty: PROPERTY FAKE_OVERRIDE name:name visibility:public modality:FINAL [fake_override,val] + overridden: + public final fun (): kotlin.String declared in kotlin.Enum + $this: VALUE_PARAMETER name: type:kotlin.Enum<.MyEnum> + PROPERTY FAKE_OVERRIDE name:ordinal visibility:public modality:FINAL [fake_override,val] + overridden: + public final ordinal: kotlin.Int [val] + FUN FAKE_OVERRIDE name: visibility:public modality:FINAL <> ($this:kotlin.Enum<.MyEnum>) returnType:kotlin.Int [fake_override] + correspondingProperty: PROPERTY FAKE_OVERRIDE name:ordinal visibility:public modality:FINAL [fake_override,val] + overridden: + public final fun (): kotlin.Int declared in kotlin.Enum + $this: VALUE_PARAMETER name: type:kotlin.Enum<.MyEnum> + FUN FAKE_OVERRIDE name:clone visibility:protected modality:FINAL <> ($this:kotlin.Enum<.MyEnum>) returnType:kotlin.Any [fake_override] + overridden: + protected final fun clone (): kotlin.Any declared in kotlin.Enum + $this: VALUE_PARAMETER name: type:kotlin.Enum<.MyEnum> + FUN FAKE_OVERRIDE name:compareTo visibility:public modality:FINAL <> ($this:kotlin.Enum<.MyEnum>, other:.MyEnum) returnType:kotlin.Int [fake_override,operator] + overridden: + public final fun compareTo (other: E of kotlin.Enum): kotlin.Int [operator] declared in kotlin.Enum + $this: VALUE_PARAMETER name: type:kotlin.Enum<.MyEnum> + VALUE_PARAMETER name:other index:0 type:.MyEnum + FUN FAKE_OVERRIDE name:equals visibility:public modality:FINAL <> ($this:kotlin.Enum<.MyEnum>, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator] + overridden: + public final fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Enum + $this: VALUE_PARAMETER name: type:kotlin.Enum<.MyEnum> + VALUE_PARAMETER name:other index:0 type:kotlin.Any? + FUN FAKE_OVERRIDE name:finalize visibility:protected/*protected and package*/ modality:FINAL <> ($this:kotlin.Enum<.MyEnum>) returnType:kotlin.Unit [fake_override] + overridden: + protected/*protected and package*/ final fun finalize (): kotlin.Unit declared in kotlin.Enum + $this: VALUE_PARAMETER name: type:kotlin.Enum<.MyEnum> + FUN FAKE_OVERRIDE name:getDeclaringClass visibility:public modality:FINAL <> ($this:kotlin.Enum<.MyEnum>) returnType:@[FlexibleNullability] java.lang.Class<@[FlexibleNullability] .MyEnum?>? [fake_override] + overridden: + public final fun getDeclaringClass (): @[FlexibleNullability] java.lang.Class<@[FlexibleNullability] E of kotlin.Enum?>? declared in kotlin.Enum + $this: VALUE_PARAMETER name: type:kotlin.Enum<.MyEnum> + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:FINAL <> ($this:kotlin.Enum<.MyEnum>) returnType:kotlin.Int [fake_override] + overridden: + public final fun hashCode (): kotlin.Int declared in kotlin.Enum + $this: VALUE_PARAMETER name: type:kotlin.Enum<.MyEnum> + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Enum<.MyEnum>) returnType:kotlin.String [fake_override] + overridden: + public open fun toString (): kotlin.String declared in kotlin.Enum + $this: VALUE_PARAMETER name: type:kotlin.Enum<.MyEnum> FUN ENUM_CLASS_SPECIAL_MEMBER name:values visibility:public modality:FINAL <> () returnType:kotlin.Array<.MyEnum> SYNTHETIC_BODY kind=ENUM_VALUES FUN ENUM_CLASS_SPECIAL_MEMBER name:valueOf visibility:public modality:FINAL <> (value:kotlin.String) returnType:.MyEnum @@ -21,53 +69,9 @@ FILE fqName: fileName:/enumEntries.kt FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:public modality:FINAL <> () returnType:kotlin.enums.EnumEntries<.MyEnum> correspondingProperty: PROPERTY ENUM_CLASS_SPECIAL_MEMBER name:entries visibility:public modality:FINAL [val] SYNTHETIC_BODY kind=ENUM_ENTRIES - FUN FAKE_OVERRIDE name:clone visibility:protected modality:FINAL <> ($this:kotlin.Enum) returnType:kotlin.Any [fake_override] - overridden: - protected final fun clone (): kotlin.Any declared in kotlin.Enum - $this: VALUE_PARAMETER name: type:kotlin.Enum - FUN FAKE_OVERRIDE name:compareTo visibility:public modality:FINAL <> ($this:kotlin.Enum, other:.MyEnum) returnType:kotlin.Int [fake_override,operator] - overridden: - public final fun compareTo (other: E of kotlin.Enum): kotlin.Int [operator] declared in kotlin.Enum - $this: VALUE_PARAMETER name: type:kotlin.Enum - VALUE_PARAMETER name:other index:0 type:.MyEnum - FUN FAKE_OVERRIDE name:equals visibility:public modality:FINAL <> ($this:kotlin.Enum, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator] - overridden: - public final fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Enum - $this: VALUE_PARAMETER name: type:kotlin.Enum - VALUE_PARAMETER name:other index:0 type:kotlin.Any? - FUN FAKE_OVERRIDE name:hashCode visibility:public modality:FINAL <> ($this:kotlin.Enum) returnType:kotlin.Int [fake_override] - overridden: - public final fun hashCode (): kotlin.Int declared in kotlin.Enum - $this: VALUE_PARAMETER name: type:kotlin.Enum - FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Enum) returnType:kotlin.String [fake_override] - overridden: - public open fun toString (): kotlin.String declared in kotlin.Enum - $this: VALUE_PARAMETER name: type:kotlin.Enum - PROPERTY FAKE_OVERRIDE name:name visibility:public modality:FINAL [fake_override,val] - annotations: - IntrinsicConstEvaluation - overridden: - public final name: kotlin.String [val] - FUN FAKE_OVERRIDE name: visibility:public modality:FINAL <> ($this:kotlin.Enum) returnType:kotlin.String [fake_override] - correspondingProperty: PROPERTY FAKE_OVERRIDE name:name visibility:public modality:FINAL [fake_override,val] - overridden: - public final fun (): kotlin.String declared in kotlin.Enum - $this: VALUE_PARAMETER name: type:kotlin.Enum - PROPERTY FAKE_OVERRIDE name:ordinal visibility:public modality:FINAL [fake_override,val] - overridden: - public final ordinal: kotlin.Int [val] - FUN FAKE_OVERRIDE name: visibility:public modality:FINAL <> ($this:kotlin.Enum) returnType:kotlin.Int [fake_override] - correspondingProperty: PROPERTY FAKE_OVERRIDE name:ordinal visibility:public modality:FINAL [fake_override,val] - overridden: - public final fun (): kotlin.Int declared in kotlin.Enum - $this: VALUE_PARAMETER name: type:kotlin.Enum - FUN FAKE_OVERRIDE name:getDeclaringClass visibility:public modality:FINAL <> ($this:kotlin.Enum) returnType:@[FlexibleNullability] java.lang.Class<@[FlexibleNullability] .MyEnum?>? [fake_override] - overridden: - public final fun getDeclaringClass (): @[FlexibleNullability] java.lang.Class<@[FlexibleNullability] E of kotlin.Enum?>? declared in kotlin.Enum - $this: VALUE_PARAMETER name: type:kotlin.Enum FUN name:box visibility:public modality:FINAL <> () returnType:kotlin.enums.EnumEntries<.MyEnum> annotations: - OptIn(markerClass = [CLASS_REFERENCE 'CLASS IR_EXTERNAL_DECLARATION_STUB ANNOTATION_CLASS name:ExperimentalStdlibApi modality:FINAL visibility:public superTypes:[kotlin.Annotation]' type=kotlin.reflect.KClass]) + OptIn(markerClass = [CLASS_REFERENCE 'CLASS IR_EXTERNAL_DECLARATION_STUB ANNOTATION_CLASS name:ExperimentalStdlibApi modality:OPEN visibility:public superTypes:[kotlin.Annotation]' type=kotlin.reflect.KClass]) BLOCK_BODY RETURN type=kotlin.Nothing from='public final fun box (): kotlin.enums.EnumEntries<.MyEnum> declared in ' CALL 'public final fun (): kotlin.enums.EnumEntries<.MyEnum> declared in .MyEnum' type=kotlin.enums.EnumEntries<.MyEnum> origin=GET_PROPERTY diff --git a/compiler/testData/ir/irText/classes/enumEntries.kt b/compiler/testData/ir/irText/classes/enumEntries.kt index fd03b389ae8..211eef071b1 100644 --- a/compiler/testData/ir/irText/classes/enumEntries.kt +++ b/compiler/testData/ir/irText/classes/enumEntries.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL // !LANGUAGE: +EnumEntries // TARGET_BACKEND: JVM_IR // FULL_JDK diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorFactory.java b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorFactory.java index aad3aff2d31..04783bd293f 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorFactory.java +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorFactory.java @@ -22,16 +22,16 @@ import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.annotations.Annotations; import org.jetbrains.kotlin.descriptors.impl.*; import org.jetbrains.kotlin.name.Name; +import org.jetbrains.kotlin.name.StandardClassIds; import org.jetbrains.kotlin.resolve.scopes.receivers.ContextClassReceiver; import org.jetbrains.kotlin.resolve.scopes.receivers.ContextReceiver; import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver; -import org.jetbrains.kotlin.types.KotlinType; -import org.jetbrains.kotlin.types.Variance; +import org.jetbrains.kotlin.types.*; import java.util.Collections; -import static org.jetbrains.kotlin.builtins.StandardNames.ENUM_VALUES; -import static org.jetbrains.kotlin.builtins.StandardNames.ENUM_VALUE_OF; +import static org.jetbrains.kotlin.builtins.StandardNames.*; +import static org.jetbrains.kotlin.resolve.DescriptorUtils.getContainingModule; import static org.jetbrains.kotlin.resolve.DescriptorUtils.getDefaultConstructorVisibility; import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt.getBuiltIns; @@ -172,6 +172,36 @@ public class DescriptorFactory { Modality.FINAL, DescriptorVisibilities.PUBLIC); } + @Nullable + public static PropertyDescriptor createEnumEntriesProperty(@NotNull ClassDescriptor enumClass) { + ClassDescriptor enumEntriesClass = FindClassInModuleKt.findClassAcrossModuleDependencies(getContainingModule(enumClass), + StandardClassIds.INSTANCE.getEnumEntries()); + if (enumEntriesClass == null) { + return null; + } + PropertyDescriptorImpl entries = + PropertyDescriptorImpl.create(enumClass, Annotations.Companion.getEMPTY(), Modality.FINAL, DescriptorVisibilities.PUBLIC, + /* isVar = */ false, ENUM_ENTRIES, CallableMemberDescriptor.Kind.SYNTHESIZED, + enumClass.getSource(), /* lateinit = */ false, /* isConst = */ false, /* isExpect = */ false, + /* isActual = */ false, /* isExternal = */ false, /* isDelegated = */ false); + PropertyGetterDescriptorImpl getter = new PropertyGetterDescriptorImpl( + entries, Annotations.Companion.getEMPTY(), Modality.FINAL, DescriptorVisibilities.PUBLIC, /* isDefault = */ false, + /* isExternal = */ false, /* isInline = */ false, CallableMemberDescriptor.Kind.SYNTHESIZED, + /* original = */ null, enumClass.getSource() + ); + entries.initialize(getter, /* setter = */ null); + entries.setType( + KotlinTypeFactory.simpleType(TypeAttributes.Companion.getEmpty(), + enumEntriesClass.getTypeConstructor(), + Collections.singletonList(new TypeProjectionImpl(enumClass.getDefaultType())), + /* isNullable = */ false), + Collections.emptyList(), null, null, + Collections.emptyList()) + ; + getter.initialize(entries.getReturnType()); + return entries; + } + public static boolean isEnumValuesMethod(@NotNull FunctionDescriptor descriptor) { return descriptor.getName().equals(ENUM_VALUES) && isEnumSpecialMethod(descriptor); } diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/MemberScope.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/MemberScope.kt index 3dd4368533d..15ac34e2855 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/MemberScope.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/MemberScope.kt @@ -70,6 +70,9 @@ fun MemberScope.computeAllNames() = getClassifierNames()?.let { classifierNames inline fun MemberScope.findFirstFunction(name: String, predicate: (CallableMemberDescriptor) -> Boolean) = getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND).first(predicate) +inline fun MemberScope.findFirstVariable(name: String, predicate: (CallableMemberDescriptor) -> Boolean) = + getContributedVariables(Name.identifier(name), NoLookupLocation.FROM_BACKEND).firstOrNull(predicate) + fun Iterable.flatMapClassifierNamesOrNull(): MutableSet? = flatMapToNullable(hashSetOf(), MemberScope::getClassifierNames) diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/StaticScopeForKotlinEnum.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/StaticScopeForKotlinEnum.kt index 532a53c8a18..3a11d9140cf 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/StaticScopeForKotlinEnum.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/StaticScopeForKotlinEnum.kt @@ -18,11 +18,11 @@ package org.jetbrains.kotlin.resolve.scopes import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.incremental.components.LookupLocation import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.resolve.DescriptorFactory.createEnumValueOfMethod -import org.jetbrains.kotlin.resolve.DescriptorFactory.createEnumValuesMethod +import org.jetbrains.kotlin.resolve.DescriptorFactory.* import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.getValue import org.jetbrains.kotlin.utils.Printer @@ -30,8 +30,9 @@ import org.jetbrains.kotlin.utils.SmartList // We don't need to track lookups here since this scope used only for introduce special Enum class members class StaticScopeForKotlinEnum( - storageManager: StorageManager, - private val containingClass: ClassDescriptor + storageManager: StorageManager, + private val containingClass: ClassDescriptor, + private val supportEnumEntries: Boolean ) : MemberScopeImpl() { init { assert(containingClass.kind == ClassKind.ENUM_CLASS) { "Class should be an enum: $containingClass" } @@ -43,11 +44,18 @@ class StaticScopeForKotlinEnum( listOf(createEnumValueOfMethod(containingClass), createEnumValuesMethod(containingClass)) } - override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean) = functions + private val properties: List by storageManager.createLazyValue { + if (supportEnumEntries) listOfNotNull(createEnumEntriesProperty(containingClass)) else emptyList() + } + + override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean) = functions + properties override fun getContributedFunctions(name: Name, location: LookupLocation) = functions.filterTo(SmartList()) { it.name == name } + override fun getContributedVariables(name: Name, location: LookupLocation): Collection = + properties.filterTo(SmartList()) { it.name == name } + override fun printScopeStructure(p: Printer) { p.println("Static scope for $containingClass") } diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/DeserializationConfiguration.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/DeserializationConfiguration.kt index 173ef221115..afb341a2e7f 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/DeserializationConfiguration.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/DeserializationConfiguration.kt @@ -36,5 +36,8 @@ interface DeserializationConfiguration { val preserveDeclarationsOrdering: Boolean get() = false + val supportEnumEntries: Boolean + get() = false + object Default : DeserializationConfiguration } diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedClassDescriptor.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedClassDescriptor.kt index 628c6daf873..7a2bbf7d23b 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedClassDescriptor.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedClassDescriptor.kt @@ -52,7 +52,12 @@ class DeserializedClassDescriptor( VersionRequirementTable.create(classProto.versionRequirementTable), metadataVersion ) - private val staticScope = if (kind == ClassKind.ENUM_CLASS) StaticScopeForKotlinEnum(c.storageManager, this) else MemberScope.Empty + private val staticScope = + if (kind == ClassKind.ENUM_CLASS) + StaticScopeForKotlinEnum(c.storageManager, this, c.components.configuration.supportEnumEntries) + else + MemberScope.Empty + private val typeConstructor = DeserializedClassTypeConstructor() private val memberScopeHolder =