From 3f462659d20b3fbb0567427fac95f95e0d159d5c Mon Sep 17 00:00:00 2001 From: Mikhail Zarechenskiy Date: Thu, 14 Jun 2018 17:49:33 +0300 Subject: [PATCH] Determine underlying property of inline class by its name Previous way to distinguish "primary constructor properties" from other properties wasn't correct for deserialized properties, because currently we don't have special information about this in metadata --- .../kotlin/codegen/ExpressionCodegen.java | 6 +----- .../kotlin/codegen/FunctionCodegen.java | 4 +--- .../ExpectedActualDeclarationChecker.kt | 12 +++++------- ...allDeserializedPropertyOnInlineClassType.kt | 18 ++++++++++++++++++ ...ompileKotlinAgainstKotlinTestGenerated.java | 5 +++++ .../kotlin/resolve/inlineClassesUtils.kt | 8 ++++++++ 6 files changed, 38 insertions(+), 15 deletions(-) create mode 100644 compiler/testData/compileKotlinAgainstKotlin/callDeserializedPropertyOnInlineClassType.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 9db30476638..082a82c6ff4 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -1707,11 +1707,7 @@ public class ExpressionCodegen extends KtVisitor impleme if (descriptor instanceof PropertyDescriptor) { PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; - boolean isUnderlyingPropertyOfInlineClass = - InlineClassesUtilsKt.isInlineClass(propertyDescriptor.getContainingDeclaration()) && - JvmCodegenUtil.hasBackingField(propertyDescriptor, contextKind(), bindingContext); - - if (isUnderlyingPropertyOfInlineClass) { + if (InlineClassesUtilsKt.isUnderlyingPropertyOfInlineClass(propertyDescriptor)) { KotlinType propertyType = propertyDescriptor.getType(); return StackValue.underlyingValueOfInlineClass(typeMapper.mapType(propertyType), propertyType, receiver); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index 5b6d2e61df7..57db28dd992 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -23,7 +23,6 @@ import org.jetbrains.kotlin.codegen.coroutines.SuspendFunctionGenerationStrategy import org.jetbrains.kotlin.codegen.coroutines.SuspendInlineFunctionGenerationStrategy; import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; -import org.jetbrains.kotlin.codegen.state.TypeMapperUtilsKt; import org.jetbrains.kotlin.config.JvmDefaultMode; import org.jetbrains.kotlin.config.JvmTarget; import org.jetbrains.kotlin.config.LanguageFeature; @@ -295,8 +294,7 @@ public class FunctionCodegen { // descriptor corresponds to the underlying value if (functionDescriptor instanceof PropertyAccessorDescriptor) { PropertyDescriptor property = ((PropertyAccessorDescriptor) functionDescriptor).getCorrespondingProperty(); - // property for the underlying value - if (JvmCodegenUtil.hasBackingField(property, contextKind, bindingContext)) { + if (InlineClassesUtilsKt.isUnderlyingPropertyOfInlineClass(property)) { return false; } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExpectedActualDeclarationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExpectedActualDeclarationChecker.kt index 82004b657c7..47b999be5af 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExpectedActualDeclarationChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExpectedActualDeclarationChecker.kt @@ -135,7 +135,7 @@ object ExpectedActualDeclarationChecker : DeclarationChecker { if (compatibility.allStrongIncompatibilities()) return if (Compatible in compatibility) { - if (checkActual && requireActualModifier(descriptor, trace)) { + if (checkActual && requireActualModifier(descriptor)) { trace.report(Errors.ACTUAL_MISSING.on(reportOn)) } @@ -204,16 +204,14 @@ object ExpectedActualDeclarationChecker : DeclarationChecker { // - annotation constructors, because annotation classes can only have one constructor // - inline class primary constructors, because inline class must have primary constructor // - value parameter inside primary constructor of inline class, because inline class must have one value parameter - private fun requireActualModifier(descriptor: MemberDescriptor, trace: BindingTrace): Boolean { + private fun requireActualModifier(descriptor: MemberDescriptor): Boolean { return !descriptor.isAnnotationConstructor() && !descriptor.isPrimaryConstructorOfInlineClass() && - !isMainPropertyOfInlineClass(descriptor, trace) + !isUnderlyingPropertyOfInlineClass(descriptor) } - private fun isMainPropertyOfInlineClass(descriptor: MemberDescriptor, trace: BindingTrace): Boolean { - if (descriptor !is PropertyDescriptor) return false - if (!descriptor.containingDeclaration.isInlineClass()) return false - return trace.bindingContext[BindingContext.BACKING_FIELD_REQUIRED, descriptor] == true + private fun isUnderlyingPropertyOfInlineClass(descriptor: MemberDescriptor): Boolean { + return descriptor is PropertyDescriptor && descriptor.isUnderlyingPropertyOfInlineClass() } // This should ideally be handled by CallableMemberDescriptor.Kind, but default constructors have kind DECLARATION and non-empty source. diff --git a/compiler/testData/compileKotlinAgainstKotlin/callDeserializedPropertyOnInlineClassType.kt b/compiler/testData/compileKotlinAgainstKotlin/callDeserializedPropertyOnInlineClassType.kt new file mode 100644 index 00000000000..b3978712ea0 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstKotlin/callDeserializedPropertyOnInlineClassType.kt @@ -0,0 +1,18 @@ +// FILE: A.kt + +package a + +@Suppress("UNSUPPORTED_FEATURE") +inline class Foo(val x: IntArray) { + val size: Int get() = x.size +} + +// FILE: B.kt + +import a.* + +fun box(): String { + val a = Foo(intArrayOf(3, 4)) + if (a.size != 2) return "Fail" + return "OK" +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstKotlinTestGenerated.java index 365b1675691..f8d92f6e4ff 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstKotlinTestGenerated.java @@ -39,6 +39,11 @@ public class CompileKotlinAgainstKotlinTestGenerated extends AbstractCompileKotl runTest("compiler/testData/compileKotlinAgainstKotlin/annotationsOnTypeAliases.kt"); } + @TestMetadata("callDeserializedPropertyOnInlineClassType.kt") + public void testCallDeserializedPropertyOnInlineClassType() throws Exception { + runTest("compiler/testData/compileKotlinAgainstKotlin/callDeserializedPropertyOnInlineClassType.kt"); + } + @TestMetadata("callsToMultifileClassFromOtherPackage.kt") public void testCallsToMultifileClassFromOtherPackage() throws Exception { runTest("compiler/testData/compileKotlinAgainstKotlin/callsToMultifileClassFromOtherPackage.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/inlineClassesUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/inlineClassesUtils.kt index 2768bb95590..ff930abb2db 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/inlineClassesUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/inlineClassesUtils.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.resolve import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.types.KotlinType @@ -39,3 +40,10 @@ fun KotlinType.isNullableUnderlyingType(): Boolean { return TypeUtils.isNullableType(underlyingType) } + +fun PropertyDescriptor.isUnderlyingPropertyOfInlineClass(): Boolean { + val containingDeclaration = this.containingDeclaration + if (!containingDeclaration.isInlineClass()) return false + + return (containingDeclaration as ClassDescriptor).underlyingRepresentation()?.name == this.name +} \ No newline at end of file