Prohibit inline classes with special underlying types
#KT-25328 Fixed #KT-23819 Fixed
This commit is contained in:
@@ -324,6 +324,7 @@ public interface Errors {
|
|||||||
DiagnosticFactory0<KtParameter> INLINE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER = DiagnosticFactory0.create(ERROR);
|
DiagnosticFactory0<KtParameter> INLINE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER = DiagnosticFactory0.create(ERROR);
|
||||||
DiagnosticFactory0<PsiElement> INLINE_CLASS_WITH_INITIALIZER = DiagnosticFactory0.create(ERROR);
|
DiagnosticFactory0<PsiElement> INLINE_CLASS_WITH_INITIALIZER = DiagnosticFactory0.create(ERROR);
|
||||||
DiagnosticFactory0<KtProperty> PROPERTY_WITH_BACKING_FIELD_INSIDE_INLINE_CLASS = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
|
DiagnosticFactory0<KtProperty> PROPERTY_WITH_BACKING_FIELD_INSIDE_INLINE_CLASS = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
|
||||||
|
DiagnosticFactory1<KtTypeReference, KotlinType> INLINE_CLASS_HAS_INAPPLICABLE_PARAMETER_TYPE = DiagnosticFactory1.create(ERROR);
|
||||||
|
|
||||||
// Secondary constructors
|
// Secondary constructors
|
||||||
|
|
||||||
|
|||||||
+1
@@ -650,6 +650,7 @@ public class DefaultErrorMessages {
|
|||||||
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_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(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(PROPERTY_WITH_BACKING_FIELD_INSIDE_INLINE_CLASS, "Inline class cannot have properties with backing fields");
|
||||||
|
MAP.put(INLINE_CLASS_HAS_INAPPLICABLE_PARAMETER_TYPE, "Inline class cannot have value parameter of type ''{0}''", RENDER_TYPE);
|
||||||
|
|
||||||
MAP.put(VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED, "Variance annotations are only allowed for type parameters of classes and interfaces");
|
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");
|
MAP.put(BOUND_ON_TYPE_ALIAS_PARAMETER_NOT_ALLOWED, "Bounds are not allowed on type alias parameters");
|
||||||
|
|||||||
+16
@@ -14,6 +14,11 @@ import org.jetbrains.kotlin.psi.psiUtil.visibilityModifier
|
|||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.isInlineClass
|
import org.jetbrains.kotlin.resolve.isInlineClass
|
||||||
|
import org.jetbrains.kotlin.resolve.substitutedUnderlyingType
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.isNothing
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
object InlineClassDeclarationChecker : DeclarationChecker {
|
object InlineClassDeclarationChecker : DeclarationChecker {
|
||||||
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
||||||
@@ -71,6 +76,17 @@ object InlineClassDeclarationChecker : DeclarationChecker {
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val baseParameterType = descriptor.safeAs<ClassDescriptor>()?.defaultType?.substitutedUnderlyingType()
|
||||||
|
if (baseParameterType != null &&
|
||||||
|
(baseParameterType.isUnit() || baseParameterType.isNothing() || baseParameterType.isTypeParameter())
|
||||||
|
) {
|
||||||
|
val typeReference = baseParameter.typeReference
|
||||||
|
if (typeReference != null) {
|
||||||
|
trace.report(Errors.INLINE_CLASS_HAS_INAPPLICABLE_PARAMETER_TYPE.on(typeReference, baseParameterType))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isParameterAcceptableForInlineClass(parameter: KtParameter): Boolean {
|
private fun isParameterAcceptableForInlineClass(parameter: KtParameter): Boolean {
|
||||||
|
|||||||
Vendored
+10
@@ -0,0 +1,10 @@
|
|||||||
|
// !LANGUAGE: +InlineClasses
|
||||||
|
|
||||||
|
inline class Foo<T>(val x: <!INLINE_CLASS_HAS_INAPPLICABLE_PARAMETER_TYPE!>T<!>)
|
||||||
|
inline class FooNullable<T>(val x: <!INLINE_CLASS_HAS_INAPPLICABLE_PARAMETER_TYPE!>T?<!>)
|
||||||
|
|
||||||
|
inline class Bar(val u: <!INLINE_CLASS_HAS_INAPPLICABLE_PARAMETER_TYPE!>Unit<!>)
|
||||||
|
inline class BarNullable(val u: Unit?)
|
||||||
|
|
||||||
|
inline class Baz(val u: <!INLINE_CLASS_HAS_INAPPLICABLE_PARAMETER_TYPE!>Nothing<!>)
|
||||||
|
inline class BazNullable(val u: Nothing?)
|
||||||
Vendored
+49
@@ -0,0 +1,49 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public final inline class Bar {
|
||||||
|
public constructor Bar(/*0*/ u: kotlin.Unit)
|
||||||
|
public final val u: kotlin.Unit
|
||||||
|
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 inline class BarNullable {
|
||||||
|
public constructor BarNullable(/*0*/ u: kotlin.Unit?)
|
||||||
|
public final val u: kotlin.Unit?
|
||||||
|
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 inline class Baz {
|
||||||
|
public constructor Baz(/*0*/ u: kotlin.Nothing)
|
||||||
|
public final val u: kotlin.Nothing
|
||||||
|
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 inline class BazNullable {
|
||||||
|
public constructor BazNullable(/*0*/ u: kotlin.Nothing?)
|
||||||
|
public final val u: kotlin.Nothing?
|
||||||
|
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 inline class Foo</*0*/ T> {
|
||||||
|
public constructor Foo</*0*/ T>(/*0*/ x: T)
|
||||||
|
public final val x: T
|
||||||
|
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 inline class FooNullable</*0*/ T> {
|
||||||
|
public constructor FooNullable</*0*/ T>(/*0*/ x: T?)
|
||||||
|
public final val x: T?
|
||||||
|
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
|
||||||
|
}
|
||||||
Vendored
+1
@@ -1,5 +1,6 @@
|
|||||||
// !LANGUAGE: +InlineClasses
|
// !LANGUAGE: +InlineClasses
|
||||||
|
|
||||||
|
@Suppress("INLINE_CLASS_HAS_INAPPLICABLE_PARAMETER_TYPE")
|
||||||
inline class Default<T>(val x: T)
|
inline class Default<T>(val x: T)
|
||||||
|
|
||||||
class Inv<T>
|
class Inv<T>
|
||||||
|
|||||||
Vendored
+3
@@ -1,6 +1,9 @@
|
|||||||
// !LANGUAGE: +InlineClasses
|
// !LANGUAGE: +InlineClasses
|
||||||
|
|
||||||
|
@Suppress("INLINE_CLASS_HAS_INAPPLICABLE_PARAMETER_TYPE")
|
||||||
inline class NonNull<T : Any>(val x: T)
|
inline class NonNull<T : Any>(val x: T)
|
||||||
|
|
||||||
|
@Suppress("INLINE_CLASS_HAS_INAPPLICABLE_PARAMETER_TYPE")
|
||||||
inline class NullableValue<T : Any>(val x: T?)
|
inline class NullableValue<T : Any>(val x: T?)
|
||||||
|
|
||||||
object Test {
|
object Test {
|
||||||
|
|||||||
@@ -10872,6 +10872,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
runTest("compiler/testData/diagnostics/tests/inlineClasses/inlineClassImplementsCollection.kt");
|
runTest("compiler/testData/diagnostics/tests/inlineClasses/inlineClassImplementsCollection.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inlineClassWithForbiddenUnderlyingType.kt")
|
||||||
|
public void testInlineClassWithForbiddenUnderlyingType() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/inlineClasses/inlineClassWithForbiddenUnderlyingType.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("inlineClassesInsideAnnotations.kt")
|
@TestMetadata("inlineClassesInsideAnnotations.kt")
|
||||||
public void testInlineClassesInsideAnnotations() throws Exception {
|
public void testInlineClassesInsideAnnotations() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/inlineClasses/inlineClassesInsideAnnotations.kt");
|
runTest("compiler/testData/diagnostics/tests/inlineClasses/inlineClassesInsideAnnotations.kt");
|
||||||
|
|||||||
Generated
+5
@@ -10872,6 +10872,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
|||||||
runTest("compiler/testData/diagnostics/tests/inlineClasses/inlineClassImplementsCollection.kt");
|
runTest("compiler/testData/diagnostics/tests/inlineClasses/inlineClassImplementsCollection.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inlineClassWithForbiddenUnderlyingType.kt")
|
||||||
|
public void testInlineClassWithForbiddenUnderlyingType() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/inlineClasses/inlineClassWithForbiddenUnderlyingType.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("inlineClassesInsideAnnotations.kt")
|
@TestMetadata("inlineClassesInsideAnnotations.kt")
|
||||||
public void testInlineClassesInsideAnnotations() throws Exception {
|
public void testInlineClassesInsideAnnotations() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/inlineClasses/inlineClassesInsideAnnotations.kt");
|
runTest("compiler/testData/diagnostics/tests/inlineClasses/inlineClassesInsideAnnotations.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user