diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 7ef13f37302..bc632f8538a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -330,6 +330,7 @@ public interface Errors { DiagnosticFactory0 INLINE_CLASS_CANNOT_IMPLEMENT_INTERFACE_BY_DELEGATION = DiagnosticFactory0.create(ERROR); 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); // 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 ba193cbc06a..f48994e3251 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -661,6 +661,7 @@ public class DefaultErrorMessages { MAP.put(INLINE_CLASS_CANNOT_IMPLEMENT_INTERFACE_BY_DELEGATION, "Inline class cannot implement an interface by delegation"); 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(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 18fe50aa4c0..95ca34e46f3 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt @@ -119,7 +119,8 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf( SuspendOperatorsCheckers, InlineClassDeclarationChecker, PropertiesWithBackingFieldsInsideInlineClass(), - AnnotationClassTargetAndRetentionChecker() + AnnotationClassTargetAndRetentionChecker(), + ReservedMembersAndConstructsForInlineClass() ) 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 a345a7af584..890e6beff7a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/InlineClassDeclarationChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/InlineClassDeclarationChecker.kt @@ -139,4 +139,24 @@ class PropertiesWithBackingFieldsInsideInlineClass : DeclarationChecker { context.trace.report(Errors.DELEGATED_PROPERTY_INSIDE_INLINE_CLASS.on(it)) } } +} + +class ReservedMembersAndConstructsForInlineClass : DeclarationChecker { + + companion object { + private val reservedFunctions = setOf("box", "unbox", "equals", "hashCode") + } + + override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) { + 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)) + } + } + } } \ No newline at end of file diff --git a/compiler/testData/codegen/box/inlineClasses/inlineClassWithCustomEquals.kt b/compiler/testData/codegen/box/inlineClasses/inlineClassWithCustomEquals.kt index 1b62d0dba87..416d31306d7 100644 --- a/compiler/testData/codegen/box/inlineClasses/inlineClassWithCustomEquals.kt +++ b/compiler/testData/codegen/box/inlineClasses/inlineClassWithCustomEquals.kt @@ -1,6 +1,8 @@ // !LANGUAGE: +InlineClasses // IGNORE_BACKEND: JVM_IR +@file:Suppress("RESERVED_MEMBER_INSIDE_INLINE_CLASS") + inline class Z(val data: Int) { override fun equals(other: Any?): Boolean = other is Z && diff --git a/compiler/testData/diagnostics/tests/inlineClasses/reservedMembersAndConstructsInsideInlineClass.kt b/compiler/testData/diagnostics/tests/inlineClasses/reservedMembersAndConstructsInsideInlineClass.kt new file mode 100644 index 00000000000..f89743f19d5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inlineClasses/reservedMembersAndConstructsInsideInlineClass.kt @@ -0,0 +1,39 @@ +// !LANGUAGE: +InlineClasses +// !DIAGNOSTICS: -UNUSED_PARAMETER + +inline class IC1(val x: Any) { + fun box() {} + fun box(x: Any) {} + + fun unbox() {} + fun unbox(x: Any) {} + + override fun equals(other: Any?): Boolean = true + override fun hashCode(): Int = 0 +} + +inline class IC2(val x: Any) { + fun box(x: Any) {} + fun box(): Any = TODO() + + fun unbox(x: Any) {} + fun unbox(): Any = TODO() + + fun equals(my: Any, other: Any): Boolean = true + fun hashCode(a: Any): Int = 0 +} + +inline class IC3(val x: Any) { + fun box(x: Any): Any = TODO() + fun unbox(x: Any): Any = TODO() + + fun equals(): Boolean = true +} + +interface WithBox { + fun box(): String +} + +inline class IC4(val s: String) : WithBox { + override fun box(): String = "" +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inlineClasses/reservedMembersAndConstructsInsideInlineClass.txt b/compiler/testData/diagnostics/tests/inlineClasses/reservedMembersAndConstructsInsideInlineClass.txt new file mode 100644 index 00000000000..898e604caf3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inlineClasses/reservedMembersAndConstructsInsideInlineClass.txt @@ -0,0 +1,54 @@ +package + +public final inline class IC1 { + public constructor IC1(/*0*/ x: kotlin.Any) + public final val x: kotlin.Any + public final fun box(): kotlin.Unit + public final fun box(/*0*/ x: kotlin.Any): kotlin.Unit + public open override /*1*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String + public final fun unbox(): kotlin.Unit + public final fun unbox(/*0*/ x: kotlin.Any): kotlin.Unit +} + +public final inline class IC2 { + public constructor IC2(/*0*/ x: kotlin.Any) + public final val x: kotlin.Any + public final fun box(): kotlin.Any + public final fun box(/*0*/ x: kotlin.Any): kotlin.Unit + public final fun equals(/*0*/ my: kotlin.Any, /*1*/ other: kotlin.Any): kotlin.Boolean + public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int + public final fun hashCode(/*0*/ a: kotlin.Any): kotlin.Int + public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String + public final fun unbox(): kotlin.Any + public final fun unbox(/*0*/ x: kotlin.Any): kotlin.Unit +} + +public final inline class IC3 { + public constructor IC3(/*0*/ x: kotlin.Any) + public final val x: kotlin.Any + public final fun box(/*0*/ x: kotlin.Any): kotlin.Any + public final fun equals(): kotlin.Boolean + 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 final fun unbox(/*0*/ x: kotlin.Any): kotlin.Any +} + +public final inline class IC4 : WithBox { + public constructor IC4(/*0*/ s: kotlin.String) + public final val s: kotlin.String + public open override /*1*/ fun box(): 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 + 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 2054650a71f..dc786b94988 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -10947,6 +10947,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { runTest("compiler/testData/diagnostics/tests/inlineClasses/recursiveInlineClasses.kt"); } + @TestMetadata("reservedMembersAndConstructsInsideInlineClass.kt") + public void testReservedMembersAndConstructsInsideInlineClass() throws Exception { + runTest("compiler/testData/diagnostics/tests/inlineClasses/reservedMembersAndConstructsInsideInlineClass.kt"); + } + @TestMetadata("unsignedLiteralsWithoutArtifactOnClasspath.kt") public void testUnsignedLiteralsWithoutArtifactOnClasspath() throws Exception { runTest("compiler/testData/diagnostics/tests/inlineClasses/unsignedLiteralsWithoutArtifactOnClasspath.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 35f17cd7fc3..a95c9690631 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -10947,6 +10947,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/inlineClasses/recursiveInlineClasses.kt"); } + @TestMetadata("reservedMembersAndConstructsInsideInlineClass.kt") + public void testReservedMembersAndConstructsInsideInlineClass() throws Exception { + runTest("compiler/testData/diagnostics/tests/inlineClasses/reservedMembersAndConstructsInsideInlineClass.kt"); + } + @TestMetadata("unsignedLiteralsWithoutArtifactOnClasspath.kt") public void testUnsignedLiteralsWithoutArtifactOnClasspath() throws Exception { runTest("compiler/testData/diagnostics/tests/inlineClasses/unsignedLiteralsWithoutArtifactOnClasspath.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/inlineClassesUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/inlineClassesUtils.kt index 384a30e2dbb..49b0422440e 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/inlineClassesUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/inlineClassesUtils.kt @@ -57,4 +57,4 @@ fun PropertyDescriptor.isUnderlyingPropertyOfInlineClass(): Boolean { if (!containingDeclaration.isInlineClass()) return false return (containingDeclaration as ClassDescriptor).underlyingRepresentation()?.name == this.name -} \ No newline at end of file +}