From 85cff98a384a024bf6c34519a3e5e76d625aa71e Mon Sep 17 00:00:00 2001 From: "Anastasia.Nekrasova" Date: Fri, 1 Dec 2023 12:05:12 +0000 Subject: [PATCH] [K2] Disappeared UNSUPPORTED Prohibit Array ^KT-59881 --- .../checkers/CommonExpressionCheckers.kt | 1 + .../analysis/checkers/CommonTypeCheckers.kt | 1 + .../FirArrayOfNothingQualifierChecker.kt | 43 +++++++++++++++ .../type/FirArrayOfNothingTypeChecker.kt | 32 +++++++++++ .../kotlin/fir/types/ConeBuiltinTypeUtils.kt | 15 +++--- .../testsWithStdLib/ArrayOfNothing.fir.kt | 53 ++++++++++--------- .../testsWithStdLib/ArrayOfNothing.kt | 11 ++-- .../testsWithStdLib/ArrayOfNothing.txt | 17 +++++- .../reified/reifiedNothingSubstitution.fir.kt | 16 ------ .../reified/reifiedNothingSubstitution.kt | 1 + 10 files changed, 140 insertions(+), 50 deletions(-) create mode 100644 compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirArrayOfNothingQualifierChecker.kt create mode 100644 compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirArrayOfNothingTypeChecker.kt delete mode 100644 compiler/testData/diagnostics/testsWithStdLib/reified/reifiedNothingSubstitution.fir.kt diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonExpressionCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonExpressionCheckers.kt index 36289aad286..8d33811f85a 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonExpressionCheckers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonExpressionCheckers.kt @@ -57,6 +57,7 @@ object CommonExpressionCheckers : ExpressionCheckers() { FirIncompatibleClassExpressionChecker, FirMissingDependencyClassChecker, FirMissingDependencySupertypeChecker.ForQualifiedAccessExpressions, + FirArrayOfNothingQualifierChecker, ) override val callCheckers: Set diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonTypeCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonTypeCheckers.kt index febd3514269..a9a6683b15e 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonTypeCheckers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonTypeCheckers.kt @@ -22,5 +22,6 @@ object CommonTypeCheckers : TypeCheckers() { FirOptionalExpectationTypeChecker, FirIncompatibleClassTypeChecker, FirContextReceiversTypeChecker, + FirArrayOfNothingTypeChecker, ) } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirArrayOfNothingQualifierChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirArrayOfNothingQualifierChecker.kt new file mode 100644 index 00000000000..0cf52521aaa --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirArrayOfNothingQualifierChecker.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.analysis.checkers.expression + +import org.jetbrains.kotlin.KtSourceElement +import org.jetbrains.kotlin.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.diagnostics.reportOn +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression +import org.jetbrains.kotlin.fir.types.* + +object FirArrayOfNothingQualifierChecker : FirQualifiedAccessExpressionChecker() { + override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) { + val resolvedType = expression.resolvedType + checkTypeAndTypeArguments(resolvedType, expression.calleeReference.source, context, reporter) + } + + fun ConeKotlinType.isArrayOfNothing(): Boolean { + if (!this.isArrayTypeOrNullableArrayType) return false + val typeParameterType = type.typeArguments.firstOrNull()?.type ?: return false + return typeParameterType.isNothingOrNullableNothing + } + + private fun checkTypeAndTypeArguments( + type: ConeKotlinType, + source: KtSourceElement?, + context: CheckerContext, + reporter: DiagnosticReporter, + ) { + if (type.isArrayOfNothing()) { + reporter.reportOn(source, FirErrors.UNSUPPORTED, "Array is illegal", context) + } else { + for (typeArg in type.typeArguments) { + val typeArgType = typeArg.type ?: continue + checkTypeAndTypeArguments(typeArgType, source, context, reporter) + } + } + } +} diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirArrayOfNothingTypeChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirArrayOfNothingTypeChecker.kt new file mode 100644 index 00000000000..e3f5f387912 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirArrayOfNothingTypeChecker.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.analysis.checkers.type + +import org.jetbrains.kotlin.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.diagnostics.reportOn +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirArrayOfNothingQualifierChecker.isArrayOfNothing +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPEALIAS_EXPANDS_TO_ARRAY_OF_NOTHINGS +import org.jetbrains.kotlin.fir.declarations.FirTypeAlias +import org.jetbrains.kotlin.fir.declarations.FirValueParameter +import org.jetbrains.kotlin.fir.resolve.fullyExpandedType +import org.jetbrains.kotlin.fir.types.* + +object FirArrayOfNothingTypeChecker : FirTypeRefChecker() { + override fun check(typeRef: FirTypeRef, context: CheckerContext, reporter: DiagnosticReporter) { + /** Ignore typealias, see [TYPEALIAS_EXPANDS_TO_ARRAY_OF_NOTHINGS] */ + if (context.containingDeclarations.lastOrNull() is FirTypeAlias) return + val coneType = typeRef.coneTypeOrNull ?: return + val fullyExpandedType = coneType.fullyExpandedType(context.session) + + /** Ignore vararg, see varargOfNothing.kt test */ + val isVararg = (context.containingDeclarations.lastOrNull() as? FirValueParameter)?.isVararg ?: false + if (!isVararg && fullyExpandedType.isArrayOfNothing()) { + reporter.reportOn(typeRef.source, FirErrors.UNSUPPORTED, "Array is illegal", context) + } + } +} diff --git a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeBuiltinTypeUtils.kt b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeBuiltinTypeUtils.kt index f05e6a2334b..a0de51c95c5 100644 --- a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeBuiltinTypeUtils.kt +++ b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeBuiltinTypeUtils.kt @@ -43,12 +43,9 @@ val ConeKotlinType.isPrimitiveOrNullablePrimitive: Boolean get() = isAnyOfBuilti val ConeKotlinType.isPrimitive: Boolean get() = isPrimitiveOrNullablePrimitive && nullability == ConeNullability.NOT_NULL val ConeKotlinType.isPrimitiveNumberOrNullableType: Boolean get() = isPrimitiveOrNullablePrimitive && !isBooleanOrNullableBoolean && !isCharOrNullableChar -val ConeKotlinType.isArrayType: Boolean - get() { - return isBuiltinType(StandardClassIds.Array, false) || - StandardClassIds.primitiveArrayTypeByElementType.values.any { isBuiltinType(it, false) } || - StandardClassIds.unsignedArrayTypeByElementType.values.any { isBuiltinType(it, false) } - } + +val ConeKotlinType.isArrayType: Boolean get() = isArrayType(isNullable = false) +val ConeKotlinType.isArrayTypeOrNullableArrayType: Boolean get() = isArrayType(isNullable = null) // Same as [KotlinBuiltIns#isNonPrimitiveArray] val ConeKotlinType.isNonPrimitiveArray: Boolean @@ -75,3 +72,9 @@ private fun ConeKotlinType.isAnyOfBuiltinType(classIds: Set): Boolean { if (this !is ConeClassLikeType) return false return lookupTag.classId in classIds } + +private fun ConeKotlinType.isArrayType(isNullable: Boolean?): Boolean { + return isBuiltinType(StandardClassIds.Array, isNullable) || + StandardClassIds.primitiveArrayTypeByElementType.values.any { isBuiltinType(it, isNullable) } || + StandardClassIds.unsignedArrayTypeByElementType.values.any { isBuiltinType(it, isNullable) } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/ArrayOfNothing.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/ArrayOfNothing.fir.kt index c87767bcdce..ca3a25be896 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/ArrayOfNothing.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/ArrayOfNothing.fir.kt @@ -1,32 +1,38 @@ // !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE -UNCHECKED_CAST -USELESS_CAST // !LANGUAGE: +ProhibitNonReifiedArraysAsReifiedTypeArguments class A +class C +class D fun test1( - a: Array, - b: Array, - c: Array, - d: Array, - e: Array, - f: Array -) {} + a: Array, + b: Array, + c: Array, + d: Array, + e: Array, + f: Array, + g: CArray>, + h: AArray>> +) { + AArray>>() +} fun test2( - a: Array?, - b: Array?, - c: Array?, - d: Array?, - e: Array?, - f: Array? + a: Array?, + b: Array?, + c: Array?, + d: Array?, + e: Array?, + f: Array? ) {} fun test3( - a: A>, - b: A>, - c: A>, - d: A>, - e: A>, - f: A> + a: A<Array>, + b: A<Array>, + c: A<Array>, + d: A<Array>, + e: A<Array>, + f: A<Array> ) {} fun test4( @@ -39,17 +45,16 @@ fun test4( ) {} fun test5() { - arrayOf<Nothing>() - Array<Nothing>(10) { throw Exception() } + arrayOf<Nothing>() + Array<Nothing>(10) { throw Exception() } } fun foo(): Array = (object {} as Any) as Array -fun test6() = foo() - +fun test6() = foo() class B(val array: Array) fun bar() = B>(arrayOf()) -fun test7() = bar() +fun test7() = bar() diff --git a/compiler/testData/diagnostics/testsWithStdLib/ArrayOfNothing.kt b/compiler/testData/diagnostics/testsWithStdLib/ArrayOfNothing.kt index bc409b922e7..79bc2c9ce18 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/ArrayOfNothing.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/ArrayOfNothing.kt @@ -1,6 +1,8 @@ // !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE -UNCHECKED_CAST -USELESS_CAST // !LANGUAGE: +ProhibitNonReifiedArraysAsReifiedTypeArguments class A +class C +class D fun test1( a: Array, @@ -8,8 +10,12 @@ fun test1( c: Array, d: Array, e: Array, - f: Array -) {} + f: Array, + g: CArray>, + h: AArray>> +) { + AArray>>() +} fun test2( a: Array?, @@ -47,7 +53,6 @@ fun foo(): Array = (object {} as Any) as Array fun test6() = foo() - class B(val array: Array) fun bar() = B>(arrayOf()) diff --git a/compiler/testData/diagnostics/testsWithStdLib/ArrayOfNothing.txt b/compiler/testData/diagnostics/testsWithStdLib/ArrayOfNothing.txt index b905373803d..039c7e5ada8 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/ArrayOfNothing.txt +++ b/compiler/testData/diagnostics/testsWithStdLib/ArrayOfNothing.txt @@ -2,7 +2,7 @@ package public fun bar(): B> public fun foo(): kotlin.Array -public fun test1(/*0*/ a: kotlin.Array, /*1*/ b: kotlin.Array, /*2*/ c: kotlin.Array, /*3*/ d: kotlin.Array, /*4*/ e: kotlin.Array, /*5*/ f: kotlin.Array): kotlin.Unit +public fun test1(/*0*/ a: kotlin.Array, /*1*/ b: kotlin.Array, /*2*/ c: kotlin.Array, /*3*/ d: kotlin.Array, /*4*/ e: kotlin.Array, /*5*/ f: kotlin.Array, /*6*/ g: C>, /*7*/ h: A>>): kotlin.Unit public fun test2(/*0*/ a: kotlin.Array?, /*1*/ b: kotlin.Array?, /*2*/ c: kotlin.Array?, /*3*/ d: kotlin.Array?, /*4*/ e: kotlin.Array?, /*5*/ f: kotlin.Array?): kotlin.Unit public fun test3(/*0*/ a: A>, /*1*/ b: A>, /*2*/ c: A>, /*3*/ d: A>, /*4*/ e: A>, /*5*/ f: A>): kotlin.Unit public fun test4(/*0*/ a: kotlin.Array>, /*1*/ b: kotlin.Array>, /*2*/ c: kotlin.Array>, /*3*/ d: kotlin.Array>, /*4*/ e: kotlin.Array>, /*5*/ f: kotlin.Array>): kotlin.Unit @@ -24,3 +24,18 @@ public final class B { public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } + +public final class C { + public constructor C() + 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 class D { + public constructor D() + 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/testData/diagnostics/testsWithStdLib/reified/reifiedNothingSubstitution.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/reified/reifiedNothingSubstitution.fir.kt deleted file mode 100644 index 815d312ba2a..00000000000 --- a/compiler/testData/diagnostics/testsWithStdLib/reified/reifiedNothingSubstitution.fir.kt +++ /dev/null @@ -1,16 +0,0 @@ -// !DIAGNOSTICS: -UNUSED_PARAMETER -UNREACHABLE_CODE -UNUSED_VARIABLE -DEPRECATION - -inline fun foo(block: () -> T): String = block().toString() - -inline fun javaClass(): Class = T::class.java - -fun box() { - val a = arrayOf(null!!) - val b = Array<Nothing?>(5) { null!! } - val c = foo() { null!! } - val d = foo { null!! } - val e = foo { "1" as Nothing } - val e1 = foo { "1" as Nothing? } - - val f = javaClass<Nothing>() -} diff --git a/compiler/testData/diagnostics/testsWithStdLib/reified/reifiedNothingSubstitution.kt b/compiler/testData/diagnostics/testsWithStdLib/reified/reifiedNothingSubstitution.kt index 1ef08806039..40f3f00002d 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/reified/reifiedNothingSubstitution.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/reified/reifiedNothingSubstitution.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !DIAGNOSTICS: -UNUSED_PARAMETER -UNREACHABLE_CODE -UNUSED_VARIABLE -DEPRECATION inline fun foo(block: () -> T): String = block().toString()