Add ClassDescriptor.getInlineClassRepresentation

This will be used at least in the JVM backend instead of the current
approach where we're loading the primary constructor's first parameter,
which isn't good enough since primary constructor can be private, and
we can't rely on private declarations in case they're declared in
another module.
This commit is contained in:
Alexander Udalov
2021-03-23 12:58:53 +01:00
parent 6aaff9dfb7
commit 7fb3f48c67
22 changed files with 214 additions and 11 deletions
@@ -6731,6 +6731,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/compileKotlinAgainstKotlin/inlineClasses/defaultWithInlineClassAndReceivers.kt");
}
@Test
@TestMetadata("extensionPropertyWithSameName.kt")
public void testExtensionPropertyWithSameName() throws Exception {
runTest("compiler/testData/codegen/box/compileKotlinAgainstKotlin/inlineClasses/extensionPropertyWithSameName.kt");
}
@Test
@TestMetadata("funInterface.kt")
public void testFunInterface() throws Exception {
@@ -6824,6 +6830,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/compileKotlinAgainstKotlin/inlineClasses/oldMangling/defaultWithInlineClassAndReceivers.kt");
}
@Test
@TestMetadata("extensionPropertyWithSameName.kt")
public void testExtensionPropertyWithSameName() throws Exception {
runTest("compiler/testData/codegen/box/compileKotlinAgainstKotlin/inlineClasses/oldMangling/extensionPropertyWithSameName.kt");
}
@Test
@TestMetadata("inlineClassFakeOverrideMangling.kt")
public void testInlineClassFakeOverrideMangling() throws Exception {
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.types.AbstractClassTypeConstructor
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.SimpleType
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner
@@ -93,6 +94,7 @@ class SyntheticClassOrObjectDescriptor(
override fun getStaticScope() = MemberScope.Empty
override fun getUnsubstitutedMemberScope(kotlinTypeRefiner: KotlinTypeRefiner) = unsubstitutedMemberScope
override fun getSealedSubclasses() = emptyList<ClassDescriptor>()
override fun getInlineClassRepresentation(): InlineClassRepresentation<SimpleType>? = null
init {
assert(modality != Modality.SEALED) { "Implement getSealedSubclasses() for this class: ${this::class.java}" }
@@ -22,14 +22,12 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0;
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.name.SpecialNames;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.psi.psiUtil.KtPsiUtilKt;
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
import org.jetbrains.kotlin.psi.synthetics.SyntheticClassOrObjectDescriptor;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.*;
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil;
import org.jetbrains.kotlin.resolve.lazy.LazyClassContext;
import org.jetbrains.kotlin.resolve.lazy.LazyEntity;
@@ -581,6 +579,25 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
return sealedSubclasses.invoke();
}
@Nullable
@Override
public InlineClassRepresentation<SimpleType> getInlineClassRepresentation() {
if (!InlineClassesUtilsKt.isInlineClass(this)) return null;
ClassConstructorDescriptor constructor = getUnsubstitutedPrimaryConstructor();
if (constructor != null) {
ValueParameterDescriptor parameter = firstOrNull(constructor.getValueParameters());
if (parameter != null) {
return new InlineClassRepresentation<>(parameter.getName(), (SimpleType) parameter.getType());
}
}
// Don't crash on invalid code.
return new InlineClassRepresentation<>(
SpecialNames.SAFE_IDENTIFIER_FOR_NO_NAME, c.getModuleDescriptor().getBuiltIns().getAnyType()
);
}
@Override
public String toString() {
// not using DescriptorRenderer to preserve laziness
@@ -615,6 +615,8 @@ open class IrBasedClassDescriptor(owner: IrClass) : ClassDescriptor, IrBasedDecl
TODO("not implemented")
}
override fun getInlineClassRepresentation(): InlineClassRepresentation<SimpleType>? = TODO("not implemented")
override fun getOriginal() = this
override fun isExpect() = false
@@ -739,6 +741,8 @@ open class IrBasedEnumEntryDescriptor(owner: IrEnumEntry) : ClassDescriptor, IrB
TODO("not implemented")
}
override fun getInlineClassRepresentation(): InlineClassRepresentation<SimpleType>? = TODO("not implemented")
override fun getOriginal() = this
override fun isExpect() = false
@@ -1157,4 +1161,4 @@ private fun IrSimpleFunctionSymbol.toIrBasedDescriptorIfPossible(): FunctionDesc
@OptIn(ObsoleteDescriptorBasedAPI::class)
private fun IrPropertySymbol.toIrBasedDescriptorIfPossible(): PropertyDescriptor =
if (isBound) owner.toIrBasedDescriptor() else descriptor
if (isBound) owner.toIrBasedDescriptor() else descriptor
@@ -0,0 +1,14 @@
// WITH_RUNTIME
// MODULE: lib
// FILE: A.kt
inline class A(val value: String) {
val Char.value: String get() = this + nonExtensionValue()
fun nonExtensionValue(): String = value
}
// MODULE: main(lib)
// FILE: B.kt
fun box(): String = with(A("K")) { 'O'.value }
@@ -0,0 +1,16 @@
// TARGET_BACKEND: JVM
// WITH_RUNTIME
// MODULE: lib
// USE_OLD_INLINE_CLASSES_MANGLING_SCHEME
// FILE: A.kt
inline class A(val value: String) {
val Char.value: String get() = this + nonExtensionValue()
fun nonExtensionValue(): String = value
}
// MODULE: main(lib)
// FILE: B.kt
fun box(): String = with(A("K")) { 'O'.value }
@@ -6731,6 +6731,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/compileKotlinAgainstKotlin/inlineClasses/defaultWithInlineClassAndReceivers.kt");
}
@Test
@TestMetadata("extensionPropertyWithSameName.kt")
public void testExtensionPropertyWithSameName() throws Exception {
runTest("compiler/testData/codegen/box/compileKotlinAgainstKotlin/inlineClasses/extensionPropertyWithSameName.kt");
}
@Test
@TestMetadata("funInterface.kt")
public void testFunInterface() throws Exception {
@@ -6824,6 +6830,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/compileKotlinAgainstKotlin/inlineClasses/oldMangling/defaultWithInlineClassAndReceivers.kt");
}
@Test
@TestMetadata("extensionPropertyWithSameName.kt")
public void testExtensionPropertyWithSameName() throws Exception {
runTest("compiler/testData/codegen/box/compileKotlinAgainstKotlin/inlineClasses/oldMangling/extensionPropertyWithSameName.kt");
}
@Test
@TestMetadata("inlineClassFakeOverrideMangling.kt")
public void testInlineClassFakeOverrideMangling() throws Exception {
@@ -6731,6 +6731,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/compileKotlinAgainstKotlin/inlineClasses/defaultWithInlineClassAndReceivers.kt");
}
@Test
@TestMetadata("extensionPropertyWithSameName.kt")
public void testExtensionPropertyWithSameName() throws Exception {
runTest("compiler/testData/codegen/box/compileKotlinAgainstKotlin/inlineClasses/extensionPropertyWithSameName.kt");
}
@Test
@TestMetadata("funInterface.kt")
public void testFunInterface() throws Exception {
@@ -6824,6 +6830,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/compileKotlinAgainstKotlin/inlineClasses/oldMangling/defaultWithInlineClassAndReceivers.kt");
}
@Test
@TestMetadata("extensionPropertyWithSameName.kt")
public void testExtensionPropertyWithSameName() throws Exception {
runTest("compiler/testData/codegen/box/compileKotlinAgainstKotlin/inlineClasses/oldMangling/extensionPropertyWithSameName.kt");
}
@Test
@TestMetadata("inlineClassFakeOverrideMangling.kt")
public void testInlineClassFakeOverrideMangling() throws Exception {
@@ -518,6 +518,12 @@ public class JvmIrAgainstOldBoxTestGenerated extends AbstractJvmIrAgainstOldBoxT
runTest("compiler/testData/codegen/box/compileKotlinAgainstKotlin/inlineClasses/defaultWithInlineClassAndReceivers.kt");
}
@Test
@TestMetadata("extensionPropertyWithSameName.kt")
public void testExtensionPropertyWithSameName() throws Exception {
runTest("compiler/testData/codegen/box/compileKotlinAgainstKotlin/inlineClasses/extensionPropertyWithSameName.kt");
}
@Test
@TestMetadata("funInterface.kt")
public void testFunInterface() throws Exception {
@@ -611,6 +617,12 @@ public class JvmIrAgainstOldBoxTestGenerated extends AbstractJvmIrAgainstOldBoxT
runTest("compiler/testData/codegen/box/compileKotlinAgainstKotlin/inlineClasses/oldMangling/defaultWithInlineClassAndReceivers.kt");
}
@Test
@TestMetadata("extensionPropertyWithSameName.kt")
public void testExtensionPropertyWithSameName() throws Exception {
runTest("compiler/testData/codegen/box/compileKotlinAgainstKotlin/inlineClasses/oldMangling/extensionPropertyWithSameName.kt");
}
@Test
@TestMetadata("inlineClassFakeOverrideMangling.kt")
public void testInlineClassFakeOverrideMangling() throws Exception {
@@ -518,6 +518,12 @@ public class JvmOldAgainstIrBoxTestGenerated extends AbstractJvmOldAgainstIrBoxT
runTest("compiler/testData/codegen/box/compileKotlinAgainstKotlin/inlineClasses/defaultWithInlineClassAndReceivers.kt");
}
@Test
@TestMetadata("extensionPropertyWithSameName.kt")
public void testExtensionPropertyWithSameName() throws Exception {
runTest("compiler/testData/codegen/box/compileKotlinAgainstKotlin/inlineClasses/extensionPropertyWithSameName.kt");
}
@Test
@TestMetadata("funInterface.kt")
public void testFunInterface() throws Exception {
@@ -611,6 +617,12 @@ public class JvmOldAgainstIrBoxTestGenerated extends AbstractJvmOldAgainstIrBoxT
runTest("compiler/testData/codegen/box/compileKotlinAgainstKotlin/inlineClasses/oldMangling/defaultWithInlineClassAndReceivers.kt");
}
@Test
@TestMetadata("extensionPropertyWithSameName.kt")
public void testExtensionPropertyWithSameName() throws Exception {
runTest("compiler/testData/codegen/box/compileKotlinAgainstKotlin/inlineClasses/oldMangling/extensionPropertyWithSameName.kt");
}
@Test
@TestMetadata("inlineClassFakeOverrideMangling.kt")
public void testInlineClassFakeOverrideMangling() throws Exception {
@@ -0,0 +1,14 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.descriptors
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.model.SimpleTypeMarker
class InlineClassRepresentation<Type : SimpleTypeMarker>(
val underlyingPropertyName: Name,
val underlyingType: Type,
)
@@ -195,6 +195,8 @@ class LazyJavaClassDescriptor(
emptyList()
}
override fun getInlineClassRepresentation(): InlineClassRepresentation<SimpleType>? = null
override fun toString() = "Lazy Java class ${this.fqNameUnsafe}"
private inner class LazyJavaClassTypeConstructor : AbstractClassTypeConstructor(c.storageManager) {
@@ -18,7 +18,6 @@ import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner
import java.util.*
/**
* A [ClassDescriptor] representing the fictitious class for a function type, such as kotlin.Function1 or kotlin.reflect.KFunction2.
@@ -88,6 +87,7 @@ class FunctionClassDescriptor(
override val annotations: Annotations get() = Annotations.EMPTY
override fun getSource(): SourceElement = SourceElement.NO_SOURCE
override fun getSealedSubclasses() = emptyList<ClassDescriptor>()
override fun getInlineClassRepresentation(): InlineClassRepresentation<SimpleType>? = null
override fun getDeclaredTypeParameters() = parameters
@@ -97,6 +97,9 @@ public interface ClassDescriptor extends ClassifierDescriptorWithTypeParameters,
@NotNull
Collection<ClassDescriptor> getSealedSubclasses();
@Nullable
InlineClassRepresentation<SimpleType> getInlineClassRepresentation();
@NotNull
@Override
ClassDescriptor getOriginal();
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.types.ClassTypeConstructorImpl
import org.jetbrains.kotlin.types.SimpleType
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner
@@ -83,6 +84,7 @@ class NotFoundClasses(private val storageManager: StorageManager, private val mo
override fun getUnsubstitutedPrimaryConstructor(): ClassConstructorDescriptor? = null
override fun getCompanionObjectDescriptor(): ClassDescriptor? = null
override fun getSealedSubclasses(): Collection<ClassDescriptor> = emptyList()
override fun getInlineClassRepresentation(): InlineClassRepresentation<SimpleType>? = null
override fun toString() = "class $name (not found)"
}
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.resolve.scopes.MemberScope;
import org.jetbrains.kotlin.storage.StorageManager;
import org.jetbrains.kotlin.types.ClassTypeConstructorImpl;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.SimpleType;
import org.jetbrains.kotlin.types.TypeConstructor;
import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner;
@@ -174,4 +175,10 @@ public class ClassDescriptorImpl extends ClassDescriptorBase {
public Collection<ClassDescriptor> getSealedSubclasses() {
return Collections.emptyList();
}
@Nullable
@Override
public InlineClassRepresentation<SimpleType> getInlineClassRepresentation() {
return null;
}
}
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.storage.NotNullLazyValue;
import org.jetbrains.kotlin.storage.StorageManager;
import org.jetbrains.kotlin.types.ClassTypeConstructorImpl;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.SimpleType;
import org.jetbrains.kotlin.types.TypeConstructor;
import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner;
import org.jetbrains.kotlin.utils.Printer;
@@ -192,6 +193,12 @@ public class EnumEntrySyntheticClassDescriptor extends ClassDescriptorBase {
return Collections.emptyList();
}
@Nullable
@Override
public InlineClassRepresentation<SimpleType> getInlineClassRepresentation() {
return null;
}
private class EnumEntryScope extends MemberScopeImpl {
private final MemoizedFunctionToNotNull<Name, Collection<? extends SimpleFunctionDescriptor>> functions;
private final MemoizedFunctionToNotNull<Name, Collection<? extends PropertyDescriptor>> properties;
@@ -314,10 +314,25 @@ public class LazySubstitutingClassDescriptor extends ModuleAwareClassDescriptor
return original.getSealedSubclasses();
}
@Nullable
@Override
public InlineClassRepresentation<SimpleType> getInlineClassRepresentation() {
InlineClassRepresentation<SimpleType> representation = original.getInlineClassRepresentation();
//noinspection ConstantConditions
return representation == null ? null : new InlineClassRepresentation<SimpleType>(
representation.getUnderlyingPropertyName(),
substituteSimpleType(getInlineClassRepresentation().getUnderlyingType())
);
}
@Nullable
@Override
public SimpleType getDefaultFunctionTypeForSamInterface() {
SimpleType type = original.getDefaultFunctionTypeForSamInterface();
return substituteSimpleType(original.getDefaultFunctionTypeForSamInterface());
}
@Nullable
private SimpleType substituteSimpleType(@Nullable SimpleType type) {
if (type == null || originalSubstitutor.isEmpty()) return type;
TypeSubstitutor substitutor = getSubstitutor();
@@ -189,6 +189,12 @@ public class MutableClassDescriptor extends ClassDescriptorBase {
return Collections.emptyList();
}
@Nullable
@Override
public InlineClassRepresentation<SimpleType> getInlineClassRepresentation() {
return null;
}
@Override
public String toString() {
return DeclarationDescriptorImpl.toString(this);
@@ -15,10 +15,7 @@ import org.jetbrains.kotlin.incremental.record
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorFactory
import org.jetbrains.kotlin.resolve.NonReportingOverrideStrategy
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.CliSealedClassInheritorsProvider
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.MemberScope
@@ -68,6 +65,7 @@ class DeserializedClassDescriptor(
private val constructors = c.storageManager.createLazyValue { computeConstructors() }
private val companionObjectDescriptor = c.storageManager.createNullableLazyValue { computeCompanionObjectDescriptor() }
private val sealedSubclasses = c.storageManager.createLazyValue { computeSubclassesForSealedClass() }
private val inlineClassRepresentation = c.storageManager.createNullableLazyValue { computeInlineClassRepresentation() }
internal val thisAsProtoContainer: ProtoContainer.Class = ProtoContainer.Class(
classProto, c.nameResolver, c.typeTable, sourceElement,
@@ -170,6 +168,35 @@ class DeserializedClassDescriptor(
override fun getSealedSubclasses() = sealedSubclasses()
override fun getInlineClassRepresentation(): InlineClassRepresentation<SimpleType>? = inlineClassRepresentation()
private fun computeInlineClassRepresentation(): InlineClassRepresentation<SimpleType>? {
if (!isInlineClass()) return null
val propertyName = when {
classProto.hasInlineClassUnderlyingPropertyName() ->
c.nameResolver.getName(classProto.inlineClassUnderlyingPropertyName)
!metadataVersion.isAtLeast(1, 5, 1) -> {
// Before 1.5, inline classes did not have underlying property name & type in the metadata.
// However, they were experimental, so supposedly this logic can be removed at some point in the future.
val constructor = unsubstitutedPrimaryConstructor ?: error("Inline class has no primary constructor: $this")
constructor.valueParameters.first().name
}
else -> error("Inline class has no underlying property name in metadata: $this")
}
val type = classProto.inlineClassUnderlyingType(c.typeTable)?.let(c.typeDeserializer::simpleType)
?: run {
val underlyingProperty =
memberScope.getContributedVariables(propertyName, NoLookupLocation.FROM_DESERIALIZATION)
.singleOrNull { it.extensionReceiverParameter == null }
?: error("Inline class has no underlying property: $this")
underlyingProperty.type as SimpleType
}
return InlineClassRepresentation(propertyName, type)
}
override fun toString() =
"deserialized ${if (isExpect) "expect " else ""}class $name" // not using descriptor renderer to preserve laziness
@@ -222,6 +222,8 @@ class KtSymbolBasedClassDescriptor(override val ktSymbol: KtNamedClassOrObjectSy
override fun getSealedSubclasses(): Collection<ClassDescriptor> = implementationPostponed()
override fun getInlineClassRepresentation(): InlineClassRepresentation<SimpleType> = TODO("Not yet implemented")
override fun getMemberScope(typeArguments: MutableList<out TypeProjection>): MemberScope = noImplementation()
override fun getMemberScope(typeSubstitution: TypeSubstitution): MemberScope = noImplementation()
override fun getUnsubstitutedMemberScope(): MemberScope = noImplementation()
@@ -4470,6 +4470,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
runTest("compiler/testData/codegen/box/compileKotlinAgainstKotlin/inlineClasses/defaultWithInlineClassAndReceivers.kt");
}
@TestMetadata("extensionPropertyWithSameName.kt")
public void testExtensionPropertyWithSameName() throws Exception {
runTest("compiler/testData/codegen/box/compileKotlinAgainstKotlin/inlineClasses/extensionPropertyWithSameName.kt");
}
@TestMetadata("funInterface.kt")
public void testFunInterface() throws Exception {
runTest("compiler/testData/codegen/box/compileKotlinAgainstKotlin/inlineClasses/funInterface.kt");