From 6a120d2f85159341ff746285053f5a7c7efc6805 Mon Sep 17 00:00:00 2001 From: Mikhail Zarechenskiy Date: Sun, 6 May 2018 03:31:16 +0300 Subject: [PATCH] Require presence of public primary constructor for inline class --- .../jetbrains/kotlin/diagnostics/Errors.java | 1 + .../rendering/DefaultErrorMessages.java | 1 + .../checkers/InlineClassDeclarationChecker.kt | 8 ++++ ...hapeOfInlineClassWithPrivateConstructor.kt | 3 -- ...apeOfInlineClassWithPrivateConstructor.txt | 12 ------ ...fPublicPrimaryConstructorForInlineClass.kt | 7 ++++ ...PublicPrimaryConstructorForInlineClass.txt | 41 +++++++++++++++++++ .../checkers/DiagnosticsTestGenerated.java | 5 +++ .../DiagnosticsUsingJavacTestGenerated.java | 5 +++ .../codegen/BytecodeListingTestGenerated.java | 5 --- 10 files changed, 68 insertions(+), 20 deletions(-) delete mode 100644 compiler/testData/codegen/bytecodeListing/inlineClasses/shapeOfInlineClassWithPrivateConstructor.kt delete mode 100644 compiler/testData/codegen/bytecodeListing/inlineClasses/shapeOfInlineClassWithPrivateConstructor.txt create mode 100644 compiler/testData/diagnostics/tests/inlineClasses/presenceOfPublicPrimaryConstructorForInlineClass.kt create mode 100644 compiler/testData/diagnostics/tests/inlineClasses/presenceOfPublicPrimaryConstructorForInlineClass.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 5f7d32cd114..e831aac11ba 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -313,6 +313,7 @@ public interface Errors { DiagnosticFactory0 INLINE_CLASS_NOT_TOP_LEVEL = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 INLINE_CLASS_NOT_FINAL = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 ABSENCE_OF_PRIMARY_CONSTRUCTOR_FOR_INLINE_CLASS = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 NON_PUBLIC_PRIMARY_CONSTRUCTOR_OF_INLINE_CLASS = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 INLINE_CLASS_CONSTRUCTOR_WRONG_PARAMETERS_SIZE = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 INLINE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER = DiagnosticFactory0.create(ERROR); 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 4cc37ef2bdb..f5e1ce0d7fb 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -627,6 +627,7 @@ public class DefaultErrorMessages { MAP.put(INLINE_CLASS_NOT_TOP_LEVEL, "Inline classes are only allowed on top level"); MAP.put(INLINE_CLASS_NOT_FINAL, "Inline classes can be only final"); MAP.put(ABSENCE_OF_PRIMARY_CONSTRUCTOR_FOR_INLINE_CLASS, "Primary constructor is required for inline class"); + MAP.put(NON_PUBLIC_PRIMARY_CONSTRUCTOR_OF_INLINE_CLASS, "Primary constructor of inline class must be public"); 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"); 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 f0d9b0bd52c..efa8e055cfe 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/InlineClassDeclarationChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/InlineClassDeclarationChecker.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.KtClass import org.jetbrains.kotlin.psi.KtDeclaration @@ -17,6 +18,7 @@ import org.jetbrains.kotlin.psi.KtParameter import org.jetbrains.kotlin.psi.getModificationStamp import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier import org.jetbrains.kotlin.psi.psiUtil.modalityModifier +import org.jetbrains.kotlin.psi.psiUtil.visibilityModifier import org.jetbrains.kotlin.resolve.DescriptorUtils object InlineClassDeclarationChecker : DeclarationChecker { @@ -46,6 +48,12 @@ object InlineClassDeclarationChecker : DeclarationChecker { return } + val primaryConstructorVisibility = descriptor.unsubstitutedPrimaryConstructor?.visibility + if (primaryConstructorVisibility != null && primaryConstructorVisibility != Visibilities.PUBLIC) { + trace.report(Errors.NON_PUBLIC_PRIMARY_CONSTRUCTOR_OF_INLINE_CLASS.on(primaryConstructor.visibilityModifier() ?: inlineKeyword)) + return + } + val baseParameter = primaryConstructor.valueParameters.singleOrNull() if (baseParameter == null) { (primaryConstructor.valueParameterList ?: declaration).let { diff --git a/compiler/testData/codegen/bytecodeListing/inlineClasses/shapeOfInlineClassWithPrivateConstructor.kt b/compiler/testData/codegen/bytecodeListing/inlineClasses/shapeOfInlineClassWithPrivateConstructor.kt deleted file mode 100644 index 0c901e42ab3..00000000000 --- a/compiler/testData/codegen/bytecodeListing/inlineClasses/shapeOfInlineClassWithPrivateConstructor.kt +++ /dev/null @@ -1,3 +0,0 @@ -// !LANGUAGE: +InlineClasses - -inline class UInt private constructor(val value: Int) \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeListing/inlineClasses/shapeOfInlineClassWithPrivateConstructor.txt b/compiler/testData/codegen/bytecodeListing/inlineClasses/shapeOfInlineClassWithPrivateConstructor.txt deleted file mode 100644 index 3ea2e039690..00000000000 --- a/compiler/testData/codegen/bytecodeListing/inlineClasses/shapeOfInlineClassWithPrivateConstructor.txt +++ /dev/null @@ -1,12 +0,0 @@ -@kotlin.Metadata -public final static class UInt$Erased { - public final static @org.jetbrains.annotations.NotNull method box(p0: int): UInt -} - -@kotlin.Metadata -public final class UInt { - private final field value: int - private method (p0: int): void - public final method getValue(): int - public final method unbox(): int -} diff --git a/compiler/testData/diagnostics/tests/inlineClasses/presenceOfPublicPrimaryConstructorForInlineClass.kt b/compiler/testData/diagnostics/tests/inlineClasses/presenceOfPublicPrimaryConstructorForInlineClass.kt new file mode 100644 index 00000000000..3b33f655c0c --- /dev/null +++ b/compiler/testData/diagnostics/tests/inlineClasses/presenceOfPublicPrimaryConstructorForInlineClass.kt @@ -0,0 +1,7 @@ +// !LANGUAGE: +InlineClasses + +inline class ConstructorWithDefaultVisibility(val x: Int) +inline class PublicConstructor public constructor(val x: Int) +inline class InternalConstructor internal constructor(val x: Int) +inline class ProtectedConstructor protected constructor(val x: Int) +inline class PrivateConstructor private constructor(val x: Int) diff --git a/compiler/testData/diagnostics/tests/inlineClasses/presenceOfPublicPrimaryConstructorForInlineClass.txt b/compiler/testData/diagnostics/tests/inlineClasses/presenceOfPublicPrimaryConstructorForInlineClass.txt new file mode 100644 index 00000000000..15f1332fc72 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inlineClasses/presenceOfPublicPrimaryConstructorForInlineClass.txt @@ -0,0 +1,41 @@ +package + +public final inline class ConstructorWithDefaultVisibility { + public constructor ConstructorWithDefaultVisibility(/*0*/ x: kotlin.Int) + public final val x: 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 InternalConstructor { + internal constructor InternalConstructor(/*0*/ x: kotlin.Int) + public final val x: 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 PrivateConstructor { + private constructor PrivateConstructor(/*0*/ x: kotlin.Int) + public final val x: 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 ProtectedConstructor { + protected constructor ProtectedConstructor(/*0*/ x: kotlin.Int) + public final val x: 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 PublicConstructor { + public constructor PublicConstructor(/*0*/ x: kotlin.Int) + public final val x: 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 +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 3154655831a..3b36589b70d 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -10682,6 +10682,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { public void testInlineClassDeclarationCheck() throws Exception { runTest("compiler/testData/diagnostics/tests/inlineClasses/inlineClassDeclarationCheck.kt"); } + + @TestMetadata("presenceOfPublicPrimaryConstructorForInlineClass.kt") + public void testPresenceOfPublicPrimaryConstructorForInlineClass() throws Exception { + runTest("compiler/testData/diagnostics/tests/inlineClasses/presenceOfPublicPrimaryConstructorForInlineClass.kt"); + } } @TestMetadata("compiler/testData/diagnostics/tests/inner") diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 91c0e03a785..d77e4b87b79 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -10682,6 +10682,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing public void testInlineClassDeclarationCheck() throws Exception { runTest("compiler/testData/diagnostics/tests/inlineClasses/inlineClassDeclarationCheck.kt"); } + + @TestMetadata("presenceOfPublicPrimaryConstructorForInlineClass.kt") + public void testPresenceOfPublicPrimaryConstructorForInlineClass() throws Exception { + runTest("compiler/testData/diagnostics/tests/inlineClasses/presenceOfPublicPrimaryConstructorForInlineClass.kt"); + } } @TestMetadata("compiler/testData/diagnostics/tests/inner") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java index a5b28a401d0..20a85d0dce3 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java @@ -284,11 +284,6 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest { public void testShapeOfInlineClassWithPrimitive() throws Exception { runTest("compiler/testData/codegen/bytecodeListing/inlineClasses/shapeOfInlineClassWithPrimitive.kt"); } - - @TestMetadata("shapeOfInlineClassWithPrivateConstructor.kt") - public void testShapeOfInlineClassWithPrivateConstructor() throws Exception { - runTest("compiler/testData/codegen/bytecodeListing/inlineClasses/shapeOfInlineClassWithPrivateConstructor.kt"); - } } @TestMetadata("compiler/testData/codegen/bytecodeListing/specialBridges")