diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index 4b2ac9c4e8c..6687967b286 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -491,6 +491,10 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { parameter("typeParameter") } + val REIFIED_TYPE_FORBIDDEN_SUBSTITUTION by error { + parameter("type") + } + val FINAL_UPPER_BOUND by warning { parameter("type") } diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index c2472535a47..bdfc23ad659 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -321,6 +321,7 @@ object FirErrors { val TYPE_PARAMETER_AS_REIFIED by error1() val TYPE_PARAMETER_AS_REIFIED_ARRAY by error1() val TYPE_PARAMETER_AS_REIFIED_ARRAY_WARNING by warning1() + val REIFIED_TYPE_FORBIDDEN_SUBSTITUTION by error1() val FINAL_UPPER_BOUND by warning1() val UPPER_BOUND_IS_EXTENSION_FUNCTION_TYPE by error0() val BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER by error0() 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 53803b8d2ab..7d20046589a 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 @@ -5,9 +5,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers -import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirAnonymousFunctionChecker import org.jetbrains.kotlin.fir.analysis.checkers.expression.* -import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirAnonymousFunctionSyntaxChecker object CommonExpressionCheckers : ExpressionCheckers() { override val annotationCallCheckers: Set @@ -43,7 +41,7 @@ object CommonExpressionCheckers : ExpressionCheckers() { FirSealedClassConstructorCallChecker, FirUninitializedEnumChecker, FirFunInterfaceConstructorReferenceChecker, - FirTypeParameterAsReifiedChecker + FirReifiedChecker ) override val functionCallCheckers: Set diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirTypeParameterAsReifiedChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirReifiedChecker.kt similarity index 84% rename from compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirTypeParameterAsReifiedChecker.kt rename to compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirReifiedChecker.kt index 3a51a547dc8..34fd1ce9a5e 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirTypeParameterAsReifiedChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirReifiedChecker.kt @@ -20,7 +20,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.name.StandardClassIds -object FirTypeParameterAsReifiedChecker : FirQualifiedAccessExpressionChecker() { +object FirReifiedChecker : FirQualifiedAccessExpressionChecker() { override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) { val calleReference = expression.calleeReference val typeArguments = expression.typeArguments @@ -33,13 +33,13 @@ object FirTypeParameterAsReifiedChecker : FirQualifiedAccessExpressionChecker() val typeArgument = typeArgumentProjection.toConeTypeProjection().type val typeParameter = typeParameters[index] - if (source != null && (typeParameter.isTypeParameterOfKotlinArray())) { + if (source != null && typeParameter.isReifiedTypeParameterOrFromKotlinArray()) { checkArgumentAndReport(typeArgument, source, false, context, reporter) } } } - private fun FirTypeParameterSymbol.isTypeParameterOfKotlinArray(): Boolean { + private fun FirTypeParameterSymbol.isReifiedTypeParameterOrFromKotlinArray(): Boolean { val containingDeclaration = containingDeclarationSymbol return isReified || containingDeclaration is FirRegularClassSymbol && containingDeclaration.classId == StandardClassIds.Array @@ -69,10 +69,17 @@ object FirTypeParameterAsReifiedChecker : FirQualifiedAccessExpressionChecker() FirErrors.TYPE_PARAMETER_AS_REIFIED } symbol = typeArgument.toSymbol(context.session) as FirTypeParameterSymbol + } else if (typeArgument != null && typeArgument.cannotBeReified()) { + reporter.reportOn(source, FirErrors.REIFIED_TYPE_FORBIDDEN_SUBSTITUTION, typeArgument, context) + return } if (factory != null && !symbol.isReified) { reporter.reportOn(source, factory, symbol, context) } } + + private fun ConeKotlinType.cannotBeReified(): Boolean { + return this.isNothing || this.isNullableNothing || this is ConeCapturedType + } } \ No newline at end of file diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt index 14b6bfcfb1c..022ab0e9321 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt @@ -320,6 +320,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_RETURN_ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_SETTER_PARAMETER_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_SINGLE_EXPRESSION_STRING_TEMPLATE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_VISIBILITY_MODIFIER +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REIFIED_TYPE_FORBIDDEN_SUBSTITUTION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REIFIED_TYPE_IN_CATCH_CLAUSE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REIFIED_TYPE_PARAMETER_NO_INLINE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REPEATED_BOUND @@ -794,6 +795,11 @@ class FirDefaultErrorMessages { "Cannot use ''{0}'' as reified type parameter, since the array type parameter is not reified.", SYMBOL ) + map.put( + REIFIED_TYPE_FORBIDDEN_SUBSTITUTION, + "Cannot use ''{0}'' as reified type parameter", + RENDER_TYPE + ) map.put( FINAL_UPPER_BOUND, "''{0}'' is a final type, and thus a value of the type parameter is predetermined", diff --git a/compiler/testData/diagnostics/tests/callableReference/generic/genericFunctionsWithNullableTypes.fir.kt b/compiler/testData/diagnostics/tests/callableReference/generic/genericFunctionsWithNullableTypes.fir.kt index 5ffe2d86cc8..279caae400a 100644 --- a/compiler/testData/diagnostics/tests/callableReference/generic/genericFunctionsWithNullableTypes.fir.kt +++ b/compiler/testData/diagnostics/tests/callableReference/generic/genericFunctionsWithNullableTypes.fir.kt @@ -24,9 +24,9 @@ fun test(x: T) { baz(null, null, ::foo) baz(null, null, ::foo) - baz(null, "", ::foo) - baz(1, null, ::foo) - baz(null, null, ::foo) + baz(null, "", ::foo) + baz(1, null, ::foo) + baz(null, null, ::foo) val s3: Pair = bar(null, null, ::foo) val s4: Pair = bar(null, null, ::foo) diff --git a/compiler/testData/diagnostics/tests/inference/constraints/ignoreConstraintFromImplicitInNothing.fir.kt b/compiler/testData/diagnostics/tests/inference/constraints/ignoreConstraintFromImplicitInNothing.fir.kt index 4f39ac4875b..6a9198dfc84 100644 --- a/compiler/testData/diagnostics/tests/inference/constraints/ignoreConstraintFromImplicitInNothing.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/constraints/ignoreConstraintFromImplicitInNothing.fir.kt @@ -11,5 +11,5 @@ fun test1() { val f2: Foo = foo1 { it checkType { _() } } val f3: Foo = foo2 { it checkType { _() } } - val f4: Foo = foo2 { it checkType { _() } } -} \ No newline at end of file + val f4: Foo = foo2 { it checkType { _() } } +} diff --git a/compiler/testData/diagnostics/tests/inference/nothingType/discriminateNothingForReifiedParameter.fir.kt b/compiler/testData/diagnostics/tests/inference/nothingType/discriminateNothingForReifiedParameter.fir.kt index 31dfc9b6be5..a89d4fac033 100644 --- a/compiler/testData/diagnostics/tests/inference/nothingType/discriminateNothingForReifiedParameter.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/nothingType/discriminateNothingForReifiedParameter.fir.kt @@ -22,7 +22,7 @@ fun test2() { } fun test3() { - takeReifiedUnbound(null) + takeReifiedUnbound(null) } fun test4(): Bound = takeReifiedUnbound(null) @@ -35,7 +35,7 @@ fun test5(): Bound? = select( fun test6() { select( null, - materializeReified() + materializeReified() ) } @@ -48,6 +48,6 @@ fun test7(): Bound? = fun test8() { select( null, - materializeReifiedUnbound() + materializeReifiedUnbound() ) } diff --git a/compiler/testData/diagnostics/tests/inference/nothingType/reifiedParameterWithRecursiveBound.fir.kt b/compiler/testData/diagnostics/tests/inference/nothingType/reifiedParameterWithRecursiveBound.fir.kt index ec2982fe8a1..02289316e2a 100644 --- a/compiler/testData/diagnostics/tests/inference/nothingType/reifiedParameterWithRecursiveBound.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/nothingType/reifiedParameterWithRecursiveBound.fir.kt @@ -28,7 +28,7 @@ inline fun > testIn(): T { // Unexpected behaviour inline fun > testOut(): T { return try { - outBound() + outBound() } catch (ex: Exception) { throw Exception() } diff --git a/compiler/testData/diagnostics/testsWithStdLib/ArrayOfNothing.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/ArrayOfNothing.fir.kt index 00ec2885ce0..d2d5df3003d 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/ArrayOfNothing.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/ArrayOfNothing.fir.kt @@ -39,8 +39,8 @@ fun test4( ) {} fun test5() { - arrayOf() - Array(10) { throw Exception() } + arrayOf<Nothing>() + Array<Nothing>(10) { throw Exception() } } fun foo(): Array = (object {} as Any) as Array diff --git a/compiler/testData/diagnostics/testsWithStdLib/reified/reifiedNothingSubstitution.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/reified/reifiedNothingSubstitution.fir.kt index bad24a72390..4795e4859cc 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/reified/reifiedNothingSubstitution.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/reified/reifiedNothingSubstitution.fir.kt @@ -5,12 +5,12 @@ inline fun foo(block: () -> T): String = block().toString() inline fun javaClass(): Class = T::class.java fun box() { - val a = arrayOf(null!!) - val b = Array(5) { null!! } - val c = foo() { null!! } + 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 e = foo { "1" as Nothing } + val e1 = foo { "1" as Nothing? } - val f = javaClass() + val f = javaClass<Nothing>() } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt index 755c9f42317..e2cba0e4f6d 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -1454,6 +1454,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.REIFIED_TYPE_FORBIDDEN_SUBSTITUTION) { firDiagnostic -> + ReifiedTypeForbiddenSubstitutionImpl( + firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a), + firDiagnostic as FirPsiDiagnostic, + token, + ) + } add(FirErrors.FINAL_UPPER_BOUND) { firDiagnostic -> FinalUpperBoundImpl( firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a), diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt index 8bde3ef90fb..da7494f19bd 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt @@ -1034,6 +1034,11 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { abstract val typeParameter: KtTypeParameterSymbol } + abstract class ReifiedTypeForbiddenSubstitution : KtFirDiagnostic() { + override val diagnosticClass get() = ReifiedTypeForbiddenSubstitution::class + abstract val type: KtType + } + abstract class FinalUpperBound : KtFirDiagnostic() { override val diagnosticClass get() = FinalUpperBound::class abstract val type: KtType diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index 72b82695a45..7ce3f381783 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -1659,6 +1659,14 @@ internal class TypeParameterAsReifiedArrayWarningImpl( override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) } +internal class ReifiedTypeForbiddenSubstitutionImpl( + override val type: KtType, + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.ReifiedTypeForbiddenSubstitution(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + internal class FinalUpperBoundImpl( override val type: KtType, firDiagnostic: FirPsiDiagnostic,