Compare commits

...

2 Commits

Author SHA1 Message Date
Ilmir Usmanov
d8c0a81da7 IC: Forbid inner classes inside inline classes
#KT-43067 Fixed
2020-12-03 18:41:11 +01:00
Ilmir Usmanov
481a3878bd Value classes: Allow nested inline classes 2020-12-03 18:41:01 +01:00
26 changed files with 191 additions and 8 deletions

View File

@@ -12917,6 +12917,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
runTest("compiler/testData/diagnostics/tests/inlineClasses/inlineClassesInsideAnnotations.kt");
}
@TestMetadata("innerClassInsideInlineClass.kt")
public void testInnerClassInsideInlineClass() throws Exception {
runTest("compiler/testData/diagnostics/tests/inlineClasses/innerClassInsideInlineClass.kt");
}
@TestMetadata("lateinitInlineClasses.kt")
public void testLateinitInlineClasses() throws Exception {
runTest("compiler/testData/diagnostics/tests/inlineClasses/lateinitInlineClasses.kt");

View File

@@ -14157,6 +14157,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/inlineClasses/multifileClass.kt");
}
@TestMetadata("nestedInlineClass.kt")
public void testNestedInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/nestedInlineClass.kt");
}
@TestMetadata("noAssertionsOnInlineClassBasedOnNullableType.kt")
public void testNoAssertionsOnInlineClassBasedOnNullableType() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/noAssertionsOnInlineClassBasedOnNullableType.kt");

View File

@@ -362,6 +362,7 @@ public interface Errors {
DiagnosticFactory0<KtTypeReference> INLINE_CLASS_CANNOT_BE_RECURSIVE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<PsiElement, String> RESERVED_MEMBER_INSIDE_INLINE_CLASS = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<PsiElement> SECONDARY_CONSTRUCTOR_WITH_BODY_INSIDE_INLINE_CLASS = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> INNER_CLASS_INSIDE_INLINE_CLASS = DiagnosticFactory0.create(ERROR);
// Result class

View File

@@ -704,7 +704,7 @@ public class DefaultErrorMessages {
MAP.put(NON_PRIVATE_CONSTRUCTOR_IN_ENUM, "Constructor must be private in enum class");
MAP.put(NON_PRIVATE_CONSTRUCTOR_IN_SEALED, "Constructor must be private in sealed class");
MAP.put(INLINE_CLASS_NOT_TOP_LEVEL, "Inline classes are only allowed on top level");
MAP.put(INLINE_CLASS_NOT_TOP_LEVEL, "Inline classes cannot be local or inner");
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(INLINE_CLASS_CONSTRUCTOR_WRONG_PARAMETERS_SIZE, "Inline class must have exactly one primary constructor parameter");
@@ -717,6 +717,7 @@ public class DefaultErrorMessages {
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(INNER_CLASS_INSIDE_INLINE_CLASS, "Inline class cannot have inner classes");
MAP.put(RESULT_CLASS_IN_RETURN_TYPE, "'kotlin.Result' cannot be used as a return type");
MAP.put(RESULT_CLASS_WITH_NULLABLE_OPERATOR, "Expression of type 'kotlin.Result' cannot be used as a left operand of ''{0}''", STRING);

View File

@@ -28,6 +28,7 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf(
SuspendLimitationsChecker,
InlineClassDeclarationChecker,
PropertiesWithBackingFieldsInsideInlineClass(),
InnerClassInsideInlineClass(),
AnnotationClassTargetAndRetentionChecker(),
ReservedMembersAndConstructsForInlineClass(),
ResultClassInReturnTypeChecker(),

View File

@@ -29,7 +29,7 @@ object InlineClassDeclarationChecker : DeclarationChecker {
require(inlineOrValueKeyword != null) { "Declaration of inline class must have 'inline' keyword" }
val trace = context.trace
if (!DescriptorUtils.isTopLevelDeclaration(descriptor)) {
if (descriptor.isInner || DescriptorUtils.isLocal(descriptor)) {
trace.report(Errors.INLINE_CLASS_NOT_TOP_LEVEL.on(inlineOrValueKeyword))
return
}
@@ -124,6 +124,18 @@ class PropertiesWithBackingFieldsInsideInlineClass : DeclarationChecker {
}
}
class InnerClassInsideInlineClass : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
if (declaration !is KtClass) return
if (descriptor !is ClassDescriptor) return
if (!descriptor.isInner) return
if (!descriptor.containingDeclaration.isInlineClass()) return
context.trace.report(Errors.INNER_CLASS_INSIDE_INLINE_CLASS.on(declaration.modifierList!!.getModifier(KtTokens.INNER_KEYWORD)!!))
}
}
class ReservedMembersAndConstructsForInlineClass : DeclarationChecker {
companion object {

View File

@@ -2,6 +2,7 @@
// WITH_RUNTIME
inline class Z(val x: Int) {
@Suppress("INNER_CLASS_INSIDE_INLINE_CLASS")
inner class Inner(val y: Int) {
val xx = x
}

View File

@@ -2,6 +2,7 @@
// WITH_RUNTIME
inline class Z(val x: Int) {
@Suppress("INNER_CLASS_INSIDE_INLINE_CLASS")
inner class Inner(val z: Z) {
val xx = x
}

View File

@@ -0,0 +1,25 @@
// !LANGUAGE: +InlineClasses
class C {
inline class IC1(val s: String)
companion object {
inline class IC2(val s: String)
}
}
object O {
inline class IC3(val s: String)
}
interface I {
inline class IC4(val s: String)
}
fun box(): String {
if (C.IC1("OK").s != "OK") return "FAIL 1"
if (C.Companion.IC2("OK").s != "OK") return "FAIL 2"
if (O.IC3("OK").s != "OK") return "FAIL 3"
if (I.IC4("OK").s != "OK") return "FAIL 4"
return "OK"
}

View File

@@ -12,6 +12,7 @@ class Outer(val z1: Z) {
}
inline class InlineOuter(val z1: Z) {
@Suppress("INNER_CLASS_INSIDE_INLINE_CLASS")
inner class Inner(val z2: Z) {
val test = "$z1 $z2"
}

View File

@@ -16,13 +16,20 @@ inline class A9(final val x: Int)
class B1 {
companion object {
inline class C1(val x: Int)
inner inline class C11(val x: Int)
}
inline class C2(val x: Int)
inner inline class C21(val x: Int)
}
object B2 {
inline class C3(val x: Int)
inner inline class C31(val x: Int)
}
fun foo() {
inline class C4(val x: Int)
}
final inline class D0(val x: Int)

View File

@@ -15,14 +15,21 @@ inline class A9(final val x: Int)
class B1 {
companion object {
<!INLINE_CLASS_NOT_TOP_LEVEL!>inline<!> class C1(val x: Int)
inline class C1(val x: Int)
<!WRONG_MODIFIER_CONTAINING_DECLARATION!>inner<!> inline class C11(val x: Int)
}
<!INLINE_CLASS_NOT_TOP_LEVEL!>inline<!> class C2(val x: Int)
inline class C2(val x: Int)
inner <!INLINE_CLASS_NOT_TOP_LEVEL!>inline<!> class C21(val x: Int)
}
object B2 {
<!INLINE_CLASS_NOT_TOP_LEVEL!>inline<!> class C3(val x: Int)
inline class C3(val x: Int)
<!WRONG_MODIFIER_CONTAINING_DECLARATION!>inner<!> inline class C31(val x: Int)
}
fun foo() {
<!INLINE_CLASS_NOT_TOP_LEVEL, WRONG_MODIFIER_TARGET!>inline<!> class C4(val x: Int)
}
final inline class D0(val x: Int)

View File

@@ -1,5 +1,7 @@
package
public fun foo(): kotlin.Unit
public final inline class A0 {
public constructor A0(/*0*/ x: kotlin.Int)
public final val x: kotlin.Int
@@ -92,6 +94,14 @@ public final class B1 {
public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
}
public final inner inline class C21 {
public constructor C21(/*0*/ x: kotlin.Int)
public final val x: kotlin.Int
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 companion object Companion {
private constructor Companion()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@@ -105,6 +115,14 @@ public final class B1 {
public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
}
public final inline class C11 {
public constructor C11(/*0*/ x: kotlin.Int)
public final val x: kotlin.Int
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
}
}
}
@@ -121,6 +139,14 @@ public object B2 {
public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
}
public final inline class C31 {
public constructor C31(/*0*/ x: kotlin.Int)
public final val x: kotlin.Int
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 D0 {

View File

@@ -0,0 +1,8 @@
// !LANGUAGE: +InlineClasses
// !DIAGNOSTICS: -UNUSED_VARIABLE
inline class Foo(val x: Int) {
inner class InnerC
inner object InnerO
inner interface InnerI
}

View File

@@ -0,0 +1,8 @@
// !LANGUAGE: +InlineClasses
// !DIAGNOSTICS: -UNUSED_VARIABLE
inline class Foo(val x: Int) {
<!INNER_CLASS_INSIDE_INLINE_CLASS!>inner<!> class InnerC
<!WRONG_MODIFIER_TARGET!>inner<!> object InnerO
<!WRONG_MODIFIER_TARGET!>inner<!> interface InnerI
}

View File

@@ -0,0 +1,29 @@
package
public final inline class Foo {
public constructor Foo(/*0*/ x: kotlin.Int)
public final val x: kotlin.Int
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 inner class InnerC {
public constructor InnerC()
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 interface InnerI {
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 object InnerO {
private constructor InnerO()
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
}
}

View File

@@ -30,16 +30,16 @@ value class A9(final val x: Int)
class B1 {
companion object {
@JvmInline
<!INLINE_CLASS_NOT_TOP_LEVEL!>value<!> class C1(val x: Int)
value class C1(val x: Int)
}
@JvmInline
<!INLINE_CLASS_NOT_TOP_LEVEL!>value<!> class C2(val x: Int)
value class C2(val x: Int)
}
object B2 {
@JvmInline
<!INLINE_CLASS_NOT_TOP_LEVEL!>value<!> class C3(val x: Int)
value class C3(val x: Int)
}
@JvmInline

View File

@@ -12924,6 +12924,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali
runTest("compiler/testData/diagnostics/tests/inlineClasses/inlineClassesInsideAnnotations.kt");
}
@TestMetadata("innerClassInsideInlineClass.kt")
public void testInnerClassInsideInlineClass() throws Exception {
runTest("compiler/testData/diagnostics/tests/inlineClasses/innerClassInsideInlineClass.kt");
}
@TestMetadata("lateinitInlineClasses.kt")
public void testLateinitInlineClasses() throws Exception {
runTest("compiler/testData/diagnostics/tests/inlineClasses/lateinitInlineClasses.kt");

View File

@@ -12919,6 +12919,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
runTest("compiler/testData/diagnostics/tests/inlineClasses/inlineClassesInsideAnnotations.kt");
}
@TestMetadata("innerClassInsideInlineClass.kt")
public void testInnerClassInsideInlineClass() throws Exception {
runTest("compiler/testData/diagnostics/tests/inlineClasses/innerClassInsideInlineClass.kt");
}
@TestMetadata("lateinitInlineClasses.kt")
public void testLateinitInlineClasses() throws Exception {
runTest("compiler/testData/diagnostics/tests/inlineClasses/lateinitInlineClasses.kt");

View File

@@ -15557,6 +15557,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/inlineClasses/multifileClass.kt");
}
@TestMetadata("nestedInlineClass.kt")
public void testNestedInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/nestedInlineClass.kt");
}
@TestMetadata("noAssertionsOnInlineClassBasedOnNullableType.kt")
public void testNoAssertionsOnInlineClassBasedOnNullableType() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/noAssertionsOnInlineClassBasedOnNullableType.kt");

View File

@@ -15567,6 +15567,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/inlineClasses/mappingOfBoxedFlexibleInlineClassType.kt");
}
@TestMetadata("nestedInlineClass.kt")
public void testNestedInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/nestedInlineClass.kt");
}
@TestMetadata("noAssertionsOnInlineClassBasedOnNullableType.kt")
public void testNoAssertionsOnInlineClassBasedOnNullableType() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/noAssertionsOnInlineClassBasedOnNullableType.kt");

View File

@@ -14157,6 +14157,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/inlineClasses/multifileClass.kt");
}
@TestMetadata("nestedInlineClass.kt")
public void testNestedInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/nestedInlineClass.kt");
}
@TestMetadata("noAssertionsOnInlineClassBasedOnNullableType.kt")
public void testNoAssertionsOnInlineClassBasedOnNullableType() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/noAssertionsOnInlineClassBasedOnNullableType.kt");

View File

@@ -12152,6 +12152,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
runTest("compiler/testData/codegen/box/inlineClasses/multifileClass.kt");
}
@TestMetadata("nestedInlineClass.kt")
public void testNestedInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/nestedInlineClass.kt");
}
@TestMetadata("noAssertionsOnInlineClassBasedOnNullableType.kt")
public void testNoAssertionsOnInlineClassBasedOnNullableType() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/noAssertionsOnInlineClassBasedOnNullableType.kt");

View File

@@ -12152,6 +12152,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/inlineClasses/multifileClass.kt");
}
@TestMetadata("nestedInlineClass.kt")
public void testNestedInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/nestedInlineClass.kt");
}
@TestMetadata("noAssertionsOnInlineClassBasedOnNullableType.kt")
public void testNoAssertionsOnInlineClassBasedOnNullableType() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/noAssertionsOnInlineClassBasedOnNullableType.kt");

View File

@@ -12217,6 +12217,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/inlineClasses/multifileClass.kt");
}
@TestMetadata("nestedInlineClass.kt")
public void testNestedInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/nestedInlineClass.kt");
}
@TestMetadata("noAssertionsOnInlineClassBasedOnNullableType.kt")
public void testNoAssertionsOnInlineClassBasedOnNullableType() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/noAssertionsOnInlineClassBasedOnNullableType.kt");

View File

@@ -6627,6 +6627,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
runTest("compiler/testData/codegen/box/inlineClasses/mangledSuperCalls.kt");
}
@TestMetadata("nestedInlineClass.kt")
public void testNestedInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/nestedInlineClass.kt");
}
@TestMetadata("noAssertionsOnInlineClassBasedOnNullableType.kt")
public void testNoAssertionsOnInlineClassBasedOnNullableType() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/noAssertionsOnInlineClassBasedOnNullableType.kt");