Reserve box/unbox/equals/hashCode methods inside inline classes
#KT-26573 Fixed
This commit is contained in:
@@ -330,6 +330,7 @@ public interface Errors {
|
||||
DiagnosticFactory0<PsiElement> INLINE_CLASS_CANNOT_IMPLEMENT_INTERFACE_BY_DELEGATION = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtTypeReference> INLINE_CLASS_CANNOT_EXTEND_CLASSES = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtTypeReference> INLINE_CLASS_CANNOT_BE_RECURSIVE = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, String> RESERVED_MEMBER_INSIDE_INLINE_CLASS = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
// Secondary constructors
|
||||
|
||||
|
||||
+1
@@ -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");
|
||||
|
||||
@@ -119,7 +119,8 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf(
|
||||
SuspendOperatorsCheckers,
|
||||
InlineClassDeclarationChecker,
|
||||
PropertiesWithBackingFieldsInsideInlineClass(),
|
||||
AnnotationClassTargetAndRetentionChecker()
|
||||
AnnotationClassTargetAndRetentionChecker(),
|
||||
ReservedMembersAndConstructsForInlineClass()
|
||||
)
|
||||
|
||||
private val DEFAULT_CALL_CHECKERS = listOf(
|
||||
|
||||
+20
@@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 &&
|
||||
|
||||
Vendored
+39
@@ -0,0 +1,39 @@
|
||||
// !LANGUAGE: +InlineClasses
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
inline class IC1(val x: Any) {
|
||||
fun <!RESERVED_MEMBER_INSIDE_INLINE_CLASS!>box<!>() {}
|
||||
fun <!RESERVED_MEMBER_INSIDE_INLINE_CLASS!>box<!>(x: Any) {}
|
||||
|
||||
fun <!RESERVED_MEMBER_INSIDE_INLINE_CLASS!>unbox<!>() {}
|
||||
fun <!RESERVED_MEMBER_INSIDE_INLINE_CLASS!>unbox<!>(x: Any) {}
|
||||
|
||||
override fun <!RESERVED_MEMBER_INSIDE_INLINE_CLASS!>equals<!>(other: Any?): Boolean = true
|
||||
override fun <!RESERVED_MEMBER_INSIDE_INLINE_CLASS!>hashCode<!>(): Int = 0
|
||||
}
|
||||
|
||||
inline class IC2(val x: Any) {
|
||||
fun <!RESERVED_MEMBER_INSIDE_INLINE_CLASS!>box<!>(x: Any) {}
|
||||
fun <!RESERVED_MEMBER_INSIDE_INLINE_CLASS!>box<!>(): Any = TODO()
|
||||
|
||||
fun <!RESERVED_MEMBER_INSIDE_INLINE_CLASS!>unbox<!>(x: Any) {}
|
||||
fun <!RESERVED_MEMBER_INSIDE_INLINE_CLASS!>unbox<!>(): Any = TODO()
|
||||
|
||||
fun <!RESERVED_MEMBER_INSIDE_INLINE_CLASS!>equals<!>(my: Any, other: Any): Boolean = true
|
||||
fun <!RESERVED_MEMBER_INSIDE_INLINE_CLASS!>hashCode<!>(a: Any): Int = 0
|
||||
}
|
||||
|
||||
inline class IC3(val x: Any) {
|
||||
fun <!RESERVED_MEMBER_INSIDE_INLINE_CLASS!>box<!>(x: Any): Any = TODO()
|
||||
fun <!RESERVED_MEMBER_INSIDE_INLINE_CLASS!>unbox<!>(x: Any): Any = TODO()
|
||||
|
||||
fun <!RESERVED_MEMBER_INSIDE_INLINE_CLASS!>equals<!>(): Boolean = true
|
||||
}
|
||||
|
||||
interface WithBox {
|
||||
fun box(): String
|
||||
}
|
||||
|
||||
inline class IC4(val s: String) : WithBox {
|
||||
override fun <!RESERVED_MEMBER_INSIDE_INLINE_CLASS!>box<!>(): String = ""
|
||||
}
|
||||
Vendored
+54
@@ -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
|
||||
}
|
||||
@@ -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");
|
||||
|
||||
Generated
+5
@@ -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");
|
||||
|
||||
@@ -57,4 +57,4 @@ fun PropertyDescriptor.isUnderlyingPropertyOfInlineClass(): Boolean {
|
||||
if (!containingDeclaration.isInlineClass()) return false
|
||||
|
||||
return (containingDeclaration as ClassDescriptor).underlyingRepresentation()?.name == this.name
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user