diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index ea46e84e1aa..c46a3aa61f6 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -317,6 +317,7 @@ public interface Errors { DiagnosticFactory0 INLINE_CLASS_CONSTRUCTOR_WRONG_PARAMETERS_SIZE = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 INLINE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 INLINE_CLASS_WITH_INITIALIZER = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 PROPERTY_WITH_BACKING_FIELD_INSIDE_INLINE_CLASS = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE); // Secondary constructors diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index f38a920aa38..aca76bff47e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -631,6 +631,7 @@ public class DefaultErrorMessages { MAP.put(INLINE_CLASS_CONSTRUCTOR_WRONG_PARAMETERS_SIZE, "Inline class must have exactly one primary constructor parameter"); MAP.put(INLINE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER, "Inline class primary constructor must have only final read-only (val) property parameter"); MAP.put(INLINE_CLASS_WITH_INITIALIZER, "Inline class cannot have an initializer block"); + MAP.put(PROPERTY_WITH_BACKING_FIELD_INSIDE_INLINE_CLASS, "Inline class cannot have properties with backing fields"); MAP.put(VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED, "Variance annotations are only allowed for type parameters of classes and interfaces"); MAP.put(BOUND_ON_TYPE_ALIAS_PARAMETER_NOT_ALLOWED, "Bounds are not allowed on type alias parameters"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt index c5b1168e5c0..a9d7e0e2c7b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt @@ -84,7 +84,8 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf( DelegationChecker(), KClassWithIncorrectTypeArgumentChecker, SuspendOperatorsCheckers, - InlineClassDeclarationChecker + InlineClassDeclarationChecker, + PropertiesWithBackingFieldsInsideInlineClass() ) private val DEFAULT_CALL_CHECKERS = listOf( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/InlineClassDeclarationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/InlineClassDeclarationChecker.kt index 18c86dd382d..1291ca7aff2 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/InlineClassDeclarationChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/InlineClassDeclarationChecker.kt @@ -5,19 +5,15 @@ package org.jetbrains.kotlin.resolve.checkers -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.ClassKind -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.lexer.KtTokens -import org.jetbrains.kotlin.psi.KtClass -import org.jetbrains.kotlin.psi.KtClassInitializer -import org.jetbrains.kotlin.psi.KtDeclaration -import org.jetbrains.kotlin.psi.KtParameter +import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.modalityModifier import org.jetbrains.kotlin.psi.psiUtil.visibilityModifier +import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.isInlineClass object InlineClassDeclarationChecker : DeclarationChecker { override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) { @@ -81,4 +77,17 @@ object InlineClassDeclarationChecker : DeclarationChecker { val isOpen = parameter.modalityModifier()?.node?.elementType == KtTokens.OPEN_KEYWORD return parameter.hasValOrVar() && !parameter.isMutable && !parameter.isVarArg && !parameter.hasDefaultValue() && !isOpen } +} + +class PropertiesWithBackingFieldsInsideInlineClass : DeclarationChecker { + override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) { + if (declaration !is KtProperty) return + if (descriptor !is PropertyDescriptor) return + + if (!descriptor.containingDeclaration.isInlineClass()) return + + if (context.trace.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor) == true) { + context.trace.report(Errors.PROPERTY_WITH_BACKING_FIELD_INSIDE_INLINE_CLASS.on(declaration)) + } + } } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inlineClasses/propertiesWithBackingFieldsInsideInlineClass.kt b/compiler/testData/diagnostics/tests/inlineClasses/propertiesWithBackingFieldsInsideInlineClass.kt new file mode 100644 index 00000000000..f5774f75596 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inlineClasses/propertiesWithBackingFieldsInsideInlineClass.kt @@ -0,0 +1,34 @@ +// !LANGUAGE: +InlineClasses +// !DIAGNOSTICS: -UNUSED_PARAMETER + +interface A { + val goodSize: Int +} + +interface B { + val badSize: Int +} + +inline class Foo(val x: Int) : A, B { + val a0 + get() = 0 + + val a1 = 0 + + var a2: Int + get() = 1 + set(value) {} + + var a3: Int = 0 + get() = 1 + set(value) { + field = value + } + + override val goodSize: Int + get() = 0 + + override val badSize: Int = 0 + + lateinit var lateinitProperty: String +} diff --git a/compiler/testData/diagnostics/tests/inlineClasses/propertiesWithBackingFieldsInsideInlineClass.txt b/compiler/testData/diagnostics/tests/inlineClasses/propertiesWithBackingFieldsInsideInlineClass.txt new file mode 100644 index 00000000000..80e6b55192f --- /dev/null +++ b/compiler/testData/diagnostics/tests/inlineClasses/propertiesWithBackingFieldsInsideInlineClass.txt @@ -0,0 +1,30 @@ +package + +public interface A { + public abstract val goodSize: kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface B { + public abstract val badSize: kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final inline class Foo : A, B { + public constructor Foo(/*0*/ x: kotlin.Int) + public final val a0: kotlin.Int + public final val a1: kotlin.Int = 0 + public final var a2: kotlin.Int + public final var a3: kotlin.Int + public open override /*1*/ val badSize: kotlin.Int = 0 + public open override /*1*/ val goodSize: kotlin.Int + public final lateinit var lateinitProperty: kotlin.String + public final val x: kotlin.Int + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index fe1644af792..c9de2409ff4 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -10693,6 +10693,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { runTest("compiler/testData/diagnostics/tests/inlineClasses/presenceOfPublicPrimaryConstructorForInlineClass.kt"); } + @TestMetadata("propertiesWithBackingFieldsInsideInlineClass.kt") + public void testPropertiesWithBackingFieldsInsideInlineClass() throws Exception { + runTest("compiler/testData/diagnostics/tests/inlineClasses/propertiesWithBackingFieldsInsideInlineClass.kt"); + } + @TestMetadata("varargsOnParametersOfInlineClassType.kt") public void testVarargsOnParametersOfInlineClassType() throws Exception { runTest("compiler/testData/diagnostics/tests/inlineClasses/varargsOnParametersOfInlineClassType.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 6bd433edede..600b0308863 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -10693,6 +10693,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/inlineClasses/presenceOfPublicPrimaryConstructorForInlineClass.kt"); } + @TestMetadata("propertiesWithBackingFieldsInsideInlineClass.kt") + public void testPropertiesWithBackingFieldsInsideInlineClass() throws Exception { + runTest("compiler/testData/diagnostics/tests/inlineClasses/propertiesWithBackingFieldsInsideInlineClass.kt"); + } + @TestMetadata("varargsOnParametersOfInlineClassType.kt") public void testVarargsOnParametersOfInlineClassType() throws Exception { runTest("compiler/testData/diagnostics/tests/inlineClasses/varargsOnParametersOfInlineClassType.kt");