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 4d4d13f2729..305bb6b1869 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 @@ -921,6 +921,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { val TYPE_ALIAS by object : DiagnosticGroup("Type alias") { val TOPLEVEL_TYPEALIASES_ONLY by error() val RECURSIVE_TYPEALIAS_EXPANSION by error() + val TYPEALIAS_SHOULD_EXPAND_TO_CLASS by error { + parameter("expandedType") + } } val EXTENDED_CHECKERS by object : DiagnosticGroup("Extended checkers") { 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 55a2bdcf822..49e5eb4e84e 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 @@ -500,6 +500,7 @@ object FirErrors { // Type alias val TOPLEVEL_TYPEALIASES_ONLY by error0() val RECURSIVE_TYPEALIAS_EXPANSION by error0() + val TYPEALIAS_SHOULD_EXPAND_TO_CLASS by error1() // Extended checkers val REDUNDANT_VISIBILITY_MODIFIER by warning0(SourceElementPositioningStrategies.VISIBILITY_MODIFIER) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTypeAliasChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTypeAliasChecker.kt index e34baa09a94..881781224ac 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTypeAliasChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTypeAliasChecker.kt @@ -12,12 +12,49 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration import org.jetbrains.kotlin.fir.declarations.FirTypeAlias +import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnsupportedDynamicType +import org.jetbrains.kotlin.fir.resolve.fullyExpandedType +import org.jetbrains.kotlin.fir.resolve.toSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol +import org.jetbrains.kotlin.fir.types.* object FirTypeAliasChecker : FirMemberDeclarationChecker() { override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { if (declaration !is FirTypeAlias) return + if (context.containingDeclarations.lastOrNull() !is FirFile) { reporter.reportOn(declaration.source, FirErrors.TOPLEVEL_TYPEALIASES_ONLY, context) } + + fun containsTypeParameter(type: ConeKotlinType): Boolean { + if (type is ConeTypeParameterType) { + return true + } + + if (type is ConeClassLikeType && type.lookupTag.toSymbol(context.session) is FirTypeAliasSymbol) { + for (typeArgument in type.typeArguments) { + val typeArgumentType = (typeArgument as? ConeKotlinType) ?: (typeArgument as? ConeKotlinTypeProjection)?.type + if (typeArgumentType != null && containsTypeParameter(typeArgumentType)) { + return true + } + } + } + + return false + } + + val expandedTypeRef = declaration.expandedTypeRef + val fullyExpandedType = expandedTypeRef.coneType.fullyExpandedType(context.session) + + if (containsTypeParameter(fullyExpandedType) || + fullyExpandedType is ConeClassErrorType && fullyExpandedType.diagnostic is ConeUnsupportedDynamicType + ) { + reporter.reportOn( + declaration.expandedTypeRef.source, + FirErrors.TYPEALIAS_SHOULD_EXPAND_TO_CLASS, + expandedTypeRef.coneType, + context + ) + } } } \ 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 b12ecadfe31..5b43fec7baf 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 @@ -308,6 +308,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SYNTAX import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.THROWABLE_TYPE_MISMATCH import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TOO_MANY_ARGUMENTS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TOPLEVEL_TYPEALIASES_ONLY +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPEALIAS_SHOULD_EXPAND_TO_CLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_ARGUMENTS_NOT_ALLOWED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_CANT_BE_USED_FOR_CONST_VAL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_MISMATCH @@ -1183,6 +1184,11 @@ class FirDefaultErrorMessages { // Type alias map.put(TOPLEVEL_TYPEALIASES_ONLY, "Nested and local type aliases are not supported") map.put(RECURSIVE_TYPEALIAS_EXPANSION, "Recursive type alias in expansion") + map.put( + TYPEALIAS_SHOULD_EXPAND_TO_CLASS, + "Type alias expands to {0}, which is not a class, an interface, or an object", + RENDER_TYPE + ) // Returns map.put(RETURN_NOT_ALLOWED, "'return' is not allowed here") diff --git a/compiler/testData/diagnostics/tests/classLiteral/typealiases.fir.kt b/compiler/testData/diagnostics/tests/classLiteral/typealiases.fir.kt index f280c2b4f14..65512e40add 100644 --- a/compiler/testData/diagnostics/tests/classLiteral/typealiases.fir.kt +++ b/compiler/testData/diagnostics/tests/classLiteral/typealiases.fir.kt @@ -9,7 +9,7 @@ typealias TTNullableTString = TNullableTString fun f3() = TTNullableTString::class inline fun f4(b: Boolean): Any { - typealias X = T - typealias Y = T? + typealias X = T + typealias Y = T? return if (b) X::class else Y::class } diff --git a/compiler/testData/diagnostics/tests/typealias/typeAliasShouldExpandToClass.fir.kt b/compiler/testData/diagnostics/tests/typealias/typeAliasShouldExpandToClass.fir.kt deleted file mode 100644 index ba72e03fbe7..00000000000 --- a/compiler/testData/diagnostics/tests/typealias/typeAliasShouldExpandToClass.fir.kt +++ /dev/null @@ -1,16 +0,0 @@ -// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER -TOPLEVEL_TYPEALIASES_ONLY - -typealias ToTypeParam1 = T -typealias ToTypeParam2 = ToTypeParam1 -typealias ToTypeParam3 = ToTypeParam2 -typealias ToTypeParam4 = ToTypeParam1 - -typealias ToFun1 = () -> Unit -typealias ToFun2 = (T) -> Unit - -class Outer { - typealias ToTypeParam1 = T - typealias ToTypeParam2 = ToTypeParam1 - typealias ToTypeParam3 = ToTypeParam2 - typealias ToTypeParam4 = ToTypeParam1 -} diff --git a/compiler/testData/diagnostics/tests/typealias/typeAliasShouldExpandToClass.kt b/compiler/testData/diagnostics/tests/typealias/typeAliasShouldExpandToClass.kt index 3dfdc3e6e5f..690b6894732 100644 --- a/compiler/testData/diagnostics/tests/typealias/typeAliasShouldExpandToClass.kt +++ b/compiler/testData/diagnostics/tests/typealias/typeAliasShouldExpandToClass.kt @@ -1,5 +1,8 @@ +// FIR_IDENTICAL // !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER -TOPLEVEL_TYPEALIASES_ONLY +typealias Dyn = dynamic + typealias ToTypeParam1 = T typealias ToTypeParam2 = ToTypeParam1 typealias ToTypeParam3 = ToTypeParam2 diff --git a/compiler/testData/diagnostics/tests/typealias/typeAliasShouldExpandToClass.txt b/compiler/testData/diagnostics/tests/typealias/typeAliasShouldExpandToClass.txt index 9d9b35f6810..2e554ee69f3 100644 --- a/compiler/testData/diagnostics/tests/typealias/typeAliasShouldExpandToClass.txt +++ b/compiler/testData/diagnostics/tests/typealias/typeAliasShouldExpandToClass.txt @@ -10,9 +10,11 @@ public final class Outer { public typealias ToTypeParam3 = Outer.ToTypeParam2 public typealias ToTypeParam4 = Outer.ToTypeParam1 } +public typealias Dyn = [ERROR : dynamic type in wrong context] public typealias ToFun1 = () -> kotlin.Unit public typealias ToFun2 = (T) -> kotlin.Unit public typealias ToTypeParam1 = T public typealias ToTypeParam2 = ToTypeParam1 public typealias ToTypeParam3 = ToTypeParam2 public typealias ToTypeParam4 = ToTypeParam1 + 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 da919c98c06..de135d28c56 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 @@ -2498,6 +2498,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.TYPEALIAS_SHOULD_EXPAND_TO_CLASS) { firDiagnostic -> + TypealiasShouldExpandToClassImpl( + firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a), + firDiagnostic as FirPsiDiagnostic, + token, + ) + } add(FirErrors.REDUNDANT_VISIBILITY_MODIFIER) { firDiagnostic -> RedundantVisibilityModifierImpl( firDiagnostic as FirPsiDiagnostic, 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 4f7a52ef261..2208aadb390 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 @@ -1757,6 +1757,11 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = RecursiveTypealiasExpansion::class } + abstract class TypealiasShouldExpandToClass : KtFirDiagnostic() { + override val diagnosticClass get() = TypealiasShouldExpandToClass::class + abstract val expandedType: KtType + } + abstract class RedundantVisibilityModifier : KtFirDiagnostic() { override val diagnosticClass get() = RedundantVisibilityModifier::class } 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 b4fed17713e..c141f3933d0 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 @@ -2841,6 +2841,14 @@ internal class RecursiveTypealiasExpansionImpl( override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) } +internal class TypealiasShouldExpandToClassImpl( + override val expandedType: KtType, + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.TypealiasShouldExpandToClass(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + internal class RedundantVisibilityModifierImpl( firDiagnostic: FirPsiDiagnostic, override val token: ValidityToken,