From b4674a172e3cabff44f9b6ed78c6f3d8fa5a2b4f Mon Sep 17 00:00:00 2001 From: Mikhail Zarechenskiy Date: Tue, 4 Sep 2018 14:21:43 +0300 Subject: [PATCH] Reserve secondary constructors with bodies inside inline classes #KT-26575 Fixed --- .../jetbrains/kotlin/diagnostics/Errors.java | 1 + .../rendering/DefaultErrorMessages.java | 1 + .../checkers/InlineClassDeclarationChecker.kt | 24 +++++++++++++++---- .../secondaryConstructorsInsideInlineClass.kt | 2 ++ ...edMembersAndConstructsInsideInlineClass.kt | 6 +++++ ...dMembersAndConstructsInsideInlineClass.txt | 9 +++++++ 6 files changed, 38 insertions(+), 5 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index bc632f8538a..325927f6e62 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -331,6 +331,7 @@ public interface Errors { DiagnosticFactory0 INLINE_CLASS_CANNOT_EXTEND_CLASSES = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 INLINE_CLASS_CANNOT_BE_RECURSIVE = DiagnosticFactory0.create(ERROR); DiagnosticFactory1 RESERVED_MEMBER_INSIDE_INLINE_CLASS = DiagnosticFactory1.create(ERROR); + DiagnosticFactory0 SECONDARY_CONSTRUCTOR_WITH_BODY_INSIDE_INLINE_CLASS = DiagnosticFactory0.create(ERROR); // 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 f48994e3251..08e7dfbccc5 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -662,6 +662,7 @@ public class DefaultErrorMessages { MAP.put(INLINE_CLASS_CANNOT_EXTEND_CLASSES, "Inline class cannot extend classes"); MAP.put(INLINE_CLASS_CANNOT_BE_RECURSIVE, "Inline class cannot be recursive"); MAP.put(RESERVED_MEMBER_INSIDE_INLINE_CLASS, "Member with the name ''{0}'' is reserved for future releases", STRING); + MAP.put(SECONDARY_CONSTRUCTOR_WITH_BODY_INSIDE_INLINE_CLASS, "Secondary constructors with bodies are reserved for for future releases"); 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/checkers/InlineClassDeclarationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/InlineClassDeclarationChecker.kt index 890e6beff7a..1f314ddb23d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/InlineClassDeclarationChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/InlineClassDeclarationChecker.kt @@ -151,11 +151,25 @@ class ReservedMembersAndConstructsForInlineClass : DeclarationChecker { val containingDeclaration = descriptor.containingDeclaration ?: return if (!containingDeclaration.isInlineClass()) return - if (declaration is KtFunction && descriptor is FunctionDescriptor) { - val functionName = descriptor.name.asString() - if (functionName in reservedFunctions) { - val nameIdentifier = declaration.nameIdentifier ?: return - context.trace.report(Errors.RESERVED_MEMBER_INSIDE_INLINE_CLASS.on(nameIdentifier, functionName)) + if (descriptor !is FunctionDescriptor) return + + when (descriptor) { + is SimpleFunctionDescriptor -> { + val ktFunction = declaration as? KtFunction ?: return + val functionName = descriptor.name.asString() + if (functionName in reservedFunctions) { + val nameIdentifier = ktFunction.nameIdentifier ?: return + context.trace.report(Errors.RESERVED_MEMBER_INSIDE_INLINE_CLASS.on(nameIdentifier, functionName)) + } + } + + is ConstructorDescriptor -> { + val secondaryConstructor = declaration as? KtSecondaryConstructor ?: return + val bodyExpression = secondaryConstructor.bodyExpression + if (secondaryConstructor.hasBlockBody() && bodyExpression is KtBlockExpression) { + val lBrace = bodyExpression.lBrace ?: return + context.trace.report(Errors.SECONDARY_CONSTRUCTOR_WITH_BODY_INSIDE_INLINE_CLASS.on(lBrace)) + } } } } diff --git a/compiler/testData/codegen/box/inlineClasses/secondaryConstructorsInsideInlineClass.kt b/compiler/testData/codegen/box/inlineClasses/secondaryConstructorsInsideInlineClass.kt index 8b6e6d3d69e..c1415f2b7cb 100644 --- a/compiler/testData/codegen/box/inlineClasses/secondaryConstructorsInsideInlineClass.kt +++ b/compiler/testData/codegen/box/inlineClasses/secondaryConstructorsInsideInlineClass.kt @@ -1,6 +1,8 @@ // !LANGUAGE: +InlineClasses // IGNORE_BACKEND: JVM_IR +@file:Suppress("SECONDARY_CONSTRUCTOR_WITH_BODY_INSIDE_INLINE_CLASS") + var global = "wrong" inline class Foo(val x: String) { diff --git a/compiler/testData/diagnostics/tests/inlineClasses/reservedMembersAndConstructsInsideInlineClass.kt b/compiler/testData/diagnostics/tests/inlineClasses/reservedMembersAndConstructsInsideInlineClass.kt index f89743f19d5..147141c101d 100644 --- a/compiler/testData/diagnostics/tests/inlineClasses/reservedMembersAndConstructsInsideInlineClass.kt +++ b/compiler/testData/diagnostics/tests/inlineClasses/reservedMembersAndConstructsInsideInlineClass.kt @@ -36,4 +36,10 @@ interface WithBox { inline class IC4(val s: String) : WithBox { override fun box(): String = "" +} + +inline class IC5(val a: String) { + constructor(i: Int) : this(i.toString()) { + TODO("something") + } } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inlineClasses/reservedMembersAndConstructsInsideInlineClass.txt b/compiler/testData/diagnostics/tests/inlineClasses/reservedMembersAndConstructsInsideInlineClass.txt index 898e604caf3..42e8dcd55e8 100644 --- a/compiler/testData/diagnostics/tests/inlineClasses/reservedMembersAndConstructsInsideInlineClass.txt +++ b/compiler/testData/diagnostics/tests/inlineClasses/reservedMembersAndConstructsInsideInlineClass.txt @@ -46,6 +46,15 @@ public final inline class IC4 : WithBox { public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String } +public final inline class IC5 { + public constructor IC5(/*0*/ i: kotlin.Int) + public constructor IC5(/*0*/ a: kotlin.String) + public final val a: kotlin.String + public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String +} + public interface WithBox { public abstract fun box(): kotlin.String public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean