diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/Main.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/Main.kt index 2ce00c20859..b28746bf47f 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/Main.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/Main.kt @@ -9,11 +9,17 @@ import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.DIAGNOSTICS_LIST import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.generateDiagnostics import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.expressions.* +import org.jetbrains.kotlin.fir.types.FirTypeRef import java.io.File fun main(args: Array) { val generationPath = args.firstOrNull()?.let { File(it) } ?: File("compiler/fir/checkers/gen").absoluteFile + val typePackage = "org.jetbrains.kotlin.fir.analysis.checkers.type" + generateCheckersComponents(generationPath, typePackage, "FirTypeChecker") { + alias("TypeRefChecker") + } + val expressionPackage = "org.jetbrains.kotlin.fir.analysis.checkers.expression" generateCheckersComponents(generationPath, expressionPackage, "FirExpressionChecker") { alias("BasicExpressionChecker") diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/type/ComposedTypeCheckers.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/type/ComposedTypeCheckers.kt new file mode 100644 index 00000000000..1d91d5de3e1 --- /dev/null +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/type/ComposedTypeCheckers.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2010-2021 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.fir.analysis.CheckersComponentInternal + +/* + * This file was generated automatically + * DO NOT MODIFY IT MANUALLY + */ + +internal class ComposedTypeCheckers : TypeCheckers() { + override val typeRefCheckers: Set + get() = _typeRefCheckers + + private val _typeRefCheckers: MutableSet = mutableSetOf() + + @CheckersComponentInternal + internal fun register(checkers: TypeCheckers) { + _typeRefCheckers += checkers.typeRefCheckers + } +} diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/type/FirTypeCheckerAliases.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/type/FirTypeCheckerAliases.kt new file mode 100644 index 00000000000..c46fe80ee50 --- /dev/null +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/type/FirTypeCheckerAliases.kt @@ -0,0 +1,15 @@ +/* + * Copyright 2010-2021 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 + +/* + * This file was generated automatically + * DO NOT MODIFY IT MANUALLY + */ + +import org.jetbrains.kotlin.fir.types.FirTypeRef + +typealias FirTypeRefChecker = FirTypeChecker diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/type/TypeCheckers.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/type/TypeCheckers.kt new file mode 100644 index 00000000000..a6e44801be5 --- /dev/null +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/type/TypeCheckers.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2010-2021 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.fir.analysis.CheckersComponentInternal + +/* + * This file was generated automatically + * DO NOT MODIFY IT MANUALLY + */ + +abstract class TypeCheckers { + companion object { + val EMPTY: TypeCheckers = object : TypeCheckers() {} + } + + open val typeRefCheckers: Set = emptySet() + + @CheckersComponentInternal internal val allTypeRefCheckers: Set get() = typeRefCheckers +} diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/CheckersComponent.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/CheckersComponent.kt index 207fd136788..eb41314eb0f 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/CheckersComponent.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/CheckersComponent.kt @@ -13,6 +13,8 @@ import org.jetbrains.kotlin.fir.analysis.checkers.declaration.ComposedDeclaratio import org.jetbrains.kotlin.fir.analysis.checkers.declaration.DeclarationCheckers import org.jetbrains.kotlin.fir.analysis.checkers.expression.ComposedExpressionCheckers import org.jetbrains.kotlin.fir.analysis.checkers.expression.ExpressionCheckers +import org.jetbrains.kotlin.fir.analysis.checkers.type.ComposedTypeCheckers +import org.jetbrains.kotlin.fir.analysis.checkers.type.TypeCheckers import org.jetbrains.kotlin.fir.analysis.extensions.FirAdditionalCheckersExtension @RequiresOptIn @@ -26,6 +28,9 @@ class CheckersComponent : FirSessionComponent { val expressionCheckers: ExpressionCheckers get() = _expressionCheckers private val _expressionCheckers = ComposedExpressionCheckers() + val typeCheckers: TypeCheckers get() = _typeCheckers + private val _typeCheckers = ComposedTypeCheckers() + @SessionConfiguration @OptIn(CheckersComponentInternal::class) fun register(checkers: DeclarationCheckers) { @@ -38,10 +43,17 @@ class CheckersComponent : FirSessionComponent { _expressionCheckers.register(checkers) } + @SessionConfiguration + @OptIn(CheckersComponentInternal::class) + fun register(checkers: TypeCheckers) { + _typeCheckers.register(checkers) + } + @SessionConfiguration fun register(checkers: FirAdditionalCheckersExtension) { register(checkers.declarationCheckers) register(checkers.expressionCheckers) + register(checkers.typeCheckers) } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirSuspendOnInvalidTypeChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirSuspendOnInvalidTypeChecker.kt deleted file mode 100644 index c537f2d2335..00000000000 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirSuspendOnInvalidTypeChecker.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2010-2021 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.declaration - -import org.jetbrains.kotlin.fir.FirElement -import org.jetbrains.kotlin.fir.FirFakeSourceElementKind -import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext -import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter -import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors -import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn -import org.jetbrains.kotlin.fir.declarations.FirFile -import org.jetbrains.kotlin.fir.types.FirFunctionTypeRef -import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef -import org.jetbrains.kotlin.fir.types.FirTypeRefWithNullability -import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitorVoid -import org.jetbrains.kotlin.lexer.KtTokens - -object FirSuspendOnInvalidTypeChecker : FirFileChecker() { - override fun check(declaration: FirFile, context: CheckerContext, reporter: DiagnosticReporter) { - // Traverse the entire file to look for source type refs (i.e., Fir(Dynamic|User|Function)TypeRef). - declaration.accept(object : FirDefaultVisitorVoid() { - override fun visitElement(element: FirElement) { - if (element.source?.kind is FirFakeSourceElementKind) return - element.acceptChildren(this) - } - - override fun visitResolvedTypeRef(resolvedTypeRef: FirResolvedTypeRef) { - // We will only get to the source type refs by visiting delegatedTypeRef. - super.visitResolvedTypeRef(resolvedTypeRef) - resolvedTypeRef.delegatedTypeRef?.accept(this) - } - - override fun visitTypeRefWithNullability(typeRefWithNullability: FirTypeRefWithNullability) { - // `suspend` is invalid for non-function types (i.e., FirDynamicTypeRef or FirUserTypeRef). - // - // It is also invalid for nullable function types, e.g., `suspend (() -> Int)?`. - // The correct way to denote a nullable suspend function type is `(suspend () -> Int)?`. - // In both cases, the source for the FirFunctionTypeRef is the TYPE_REFERENCE element. - // In the invalid case, the modifier list is in the source TYPE_REFERENCE element. - // But in the correct case, the modifier list is in the child NULLABLE_TYPE element. - // Therefore, if the FirFunctionTypeRef is marked nullable, it is invalid to HAVE the `suspend` modifier - // on the source element, even though it seems counter-intuitive. - val suspendModifier = typeRefWithNullability.getModifier(KtTokens.SUSPEND_KEYWORD) ?: return - if (typeRefWithNullability !is FirFunctionTypeRef || typeRefWithNullability.isMarkedNullable) { - reporter.reportOn( - suspendModifier.source, - FirErrors.WRONG_MODIFIER_TARGET, - suspendModifier.token, - "non-functional type", - context - ) - } - } - }) - } -} \ No newline at end of file diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirSuspendModifierChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirSuspendModifierChecker.kt new file mode 100644 index 00000000000..7e87dca2416 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirSuspendModifierChecker.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2010-2021 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.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.getModifier +import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn +import org.jetbrains.kotlin.fir.types.FirFunctionTypeRef +import org.jetbrains.kotlin.fir.types.FirTypeRef +import org.jetbrains.kotlin.fir.types.FirTypeRefWithNullability +import org.jetbrains.kotlin.lexer.KtTokens + +object FirSuspendModifierChecker : FirTypeRefChecker() { + override fun check(typeRef: FirTypeRef, context: CheckerContext, reporter: DiagnosticReporter) { + // We are only interested in source type refs (i.e., Fir(Dynamic|User|Function)TypeRef). + if (typeRef !is FirTypeRefWithNullability) return + + val suspendModifier = typeRef.getModifier(KtTokens.SUSPEND_KEYWORD) ?: return + + // `suspend` is invalid for non-function types (i.e., FirDynamicTypeRef or FirUserTypeRef). + // + // It is also invalid for nullable function types, e.g., `suspend (() -> Int)?`. + // The correct way to denote a nullable suspend function type is `(suspend () -> Int)?`. + // (To clarify: You can "mark nullable" a suspend function type, but you cannot "mark suspend" a nullable function type.) + // + // In both invalid and correct cases, the source for the FirFunctionTypeRef is the TYPE_REFERENCE element. + // In the invalid case, the `suspend` modifier is in the source TYPE_REFERENCE element. + // But in the correct case, the `suspend` modifier is in the child NULLABLE_TYPE element, i.e., the source TYPE_REFERENCE element + // will not have the `suspend` modifier. + // + // In both cases, the FirFunctionTypeRef is marked nullable. But it is invalid to have the `suspend` modifier on the source element. + if (typeRef !is FirFunctionTypeRef || typeRef.isMarkedNullable) { + reporter.reportOn( + suspendModifier.source, + FirErrors.WRONG_MODIFIER_TARGET, + suspendModifier.token, + "non-functional type", + context + ) + } + } +} diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirTypeChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirTypeChecker.kt new file mode 100644 index 00000000000..034f2a2fa8e --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirTypeChecker.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2010-2021 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.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.fir.types.FirTypeRef + +abstract class FirTypeChecker { + /** + * [FirTypeChecker] should only be used when the check can be performed independent of the context of the type refs. That is, + * you should NOT be examining containing declarations, qualified accesses, etc. when writing a FirTypeChecker. + * + * If the check is dependent on context, or if it is specific to type refs in a certain kind of declaration or expression, + * please write a [org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirDeclarationChecker] or + * [org.jetbrains.kotlin.fir.analysis.checkers.expression.FirExpressionChecker] instead. + */ + abstract fun check(typeRef: T, context: CheckerContext, reporter: DiagnosticReporter) +} diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/AbstractDiagnosticCollector.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/AbstractDiagnosticCollector.kt index e507e5e6e40..76d5f4831d3 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/AbstractDiagnosticCollector.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/AbstractDiagnosticCollector.kt @@ -72,6 +72,7 @@ fun AbstractDiagnosticCollector.registerAllComponents() { initializeComponents( DeclarationCheckersDiagnosticComponent(this), ExpressionCheckersDiagnosticComponent(this), + TypeCheckersDiagnosticComponent(this), ErrorNodeDiagnosticCollectorComponent(this), ControlFlowAnalysisDiagnosticComponent(this), ) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/TypeCheckersDiagnosticComponent.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/TypeCheckersDiagnosticComponent.kt new file mode 100644 index 00000000000..bf0fb65cdc4 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/TypeCheckersDiagnosticComponent.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2010-2021 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.collectors.components + +import org.jetbrains.kotlin.fir.analysis.CheckersComponentInternal +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.type.FirTypeChecker +import org.jetbrains.kotlin.fir.analysis.checkers.type.TypeCheckers +import org.jetbrains.kotlin.fir.analysis.checkersComponent +import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector +import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.fir.types.* + +@OptIn(CheckersComponentInternal::class) +class TypeCheckersDiagnosticComponent( + collector: AbstractDiagnosticCollector, + private val checkers: TypeCheckers = collector.session.checkersComponent.typeCheckers, +) : AbstractDiagnosticCollectorComponent(collector) { + + override fun visitDynamicTypeRef(dynamicTypeRef: FirDynamicTypeRef, data: CheckerContext) { + checkers.allTypeRefCheckers.check(dynamicTypeRef, data, reporter) + } + + override fun visitFunctionTypeRef(functionTypeRef: FirFunctionTypeRef, data: CheckerContext) { + checkers.allTypeRefCheckers.check(functionTypeRef, data, reporter) + } + + override fun visitUserTypeRef(userTypeRef: FirUserTypeRef, data: CheckerContext) { + checkers.allTypeRefCheckers.check(userTypeRef, data, reporter) + } + + override fun visitResolvedTypeRef(resolvedTypeRef: FirResolvedTypeRef, data: CheckerContext) { + checkers.allTypeRefCheckers.check(resolvedTypeRef, data, reporter) + } + + override fun visitErrorTypeRef(errorTypeRef: FirErrorTypeRef, data: CheckerContext) { + checkers.allTypeRefCheckers.check(errorTypeRef, data, reporter) + } + + override fun visitTypeRefWithNullability(typeRefWithNullability: FirTypeRefWithNullability, data: CheckerContext) { + checkers.allTypeRefCheckers.check(typeRefWithNullability, data, reporter) + } + + override fun visitImplicitTypeRef(implicitTypeRef: FirImplicitTypeRef, data: CheckerContext) { + checkers.allTypeRefCheckers.check(implicitTypeRef, data, reporter) + } + + override fun visitTypeRef(typeRef: FirTypeRef, data: CheckerContext) { + checkers.allTypeRefCheckers.check(typeRef, data, reporter) + } + + private fun Collection>.check( + typeRef: T, + context: CheckerContext, + reporter: DiagnosticReporter + ) { + for (checker in this) { + checker.check(typeRef, context, reporter) + } + } +} diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/extensions/FirAdditionalCheckersExtension.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/extensions/FirAdditionalCheckersExtension.kt index 7089be5cd1a..32eb31fb60d 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/extensions/FirAdditionalCheckersExtension.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/extensions/FirAdditionalCheckersExtension.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.analysis.extensions import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.analysis.checkers.declaration.DeclarationCheckers import org.jetbrains.kotlin.fir.analysis.checkers.expression.ExpressionCheckers +import org.jetbrains.kotlin.fir.analysis.checkers.type.TypeCheckers import org.jetbrains.kotlin.fir.extensions.AbstractFirAdditionalCheckersExtension import org.jetbrains.kotlin.fir.extensions.FirExtensionPointName import org.jetbrains.kotlin.fir.extensions.FirExtensionService @@ -19,6 +20,7 @@ abstract class FirAdditionalCheckersExtension(session: FirSession) : AbstractFir open val declarationCheckers: DeclarationCheckers = DeclarationCheckers.EMPTY open val expressionCheckers: ExpressionCheckers = ExpressionCheckers.EMPTY + open val typeCheckers: TypeCheckers = TypeCheckers.EMPTY final override val name: FirExtensionPointName get() = NAME diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CheckersContainers.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CheckersContainers.kt index 5e0a24291ae..c7dccccb6ee 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CheckersContainers.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CheckersContainers.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.session.FirSessionFactory fun FirSessionFactory.FirSessionConfigurator.registerCommonCheckers() { useCheckers(CommonDeclarationCheckers) useCheckers(CommonExpressionCheckers) + useCheckers(CommonTypeCheckers) } fun FirSessionFactory.FirSessionConfigurator.registerExtendedCommonCheckers() { diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonDeclarationCheckers.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonDeclarationCheckers.kt index fb2ab5655ca..c546ed99cfe 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonDeclarationCheckers.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonDeclarationCheckers.kt @@ -95,7 +95,6 @@ object CommonDeclarationCheckers : DeclarationCheckers() { FirKClassWithIncorrectTypeArgumentChecker, FirTopLevelFunctionsChecker, FirTopLevelPropertiesChecker, - FirSuspendOnInvalidTypeChecker, ) override val controlFlowAnalyserCheckers: Set diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonTypeCheckers.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonTypeCheckers.kt new file mode 100644 index 00000000000..a5ca03979b4 --- /dev/null +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonTypeCheckers.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2010-2021 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.checkers + +import org.jetbrains.kotlin.fir.analysis.cfa.AbstractFirPropertyInitializationChecker +import org.jetbrains.kotlin.fir.analysis.cfa.FirCallsEffectAnalyzer +import org.jetbrains.kotlin.fir.analysis.cfa.FirPropertyInitializationAnalyzer +import org.jetbrains.kotlin.fir.analysis.cfa.FirReturnsImpliesAnalyzer +import org.jetbrains.kotlin.fir.analysis.checkers.cfa.FirControlFlowChecker +import org.jetbrains.kotlin.fir.analysis.checkers.declaration.* +import org.jetbrains.kotlin.fir.analysis.checkers.type.FirSuspendModifierChecker +import org.jetbrains.kotlin.fir.analysis.checkers.type.FirTypeRefChecker +import org.jetbrains.kotlin.fir.analysis.checkers.type.TypeCheckers + +object CommonTypeCheckers : TypeCheckers() { + override val typeRefCheckers: Set = setOf( + FirSuspendModifierChecker + ) +} diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirSessionFactory.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirSessionFactory.kt index 7758e58b1e7..9268481f73a 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirSessionFactory.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirSessionFactory.kt @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.fir.PrivateSessionConstructor import org.jetbrains.kotlin.fir.SessionConfiguration import org.jetbrains.kotlin.fir.analysis.checkers.declaration.DeclarationCheckers import org.jetbrains.kotlin.fir.analysis.checkers.expression.ExpressionCheckers +import org.jetbrains.kotlin.fir.analysis.checkers.type.TypeCheckers import org.jetbrains.kotlin.fir.analysis.checkersComponent import org.jetbrains.kotlin.fir.analysis.extensions.additionalCheckers import org.jetbrains.kotlin.fir.checkers.registerCommonCheckers @@ -53,6 +54,10 @@ object FirSessionFactory { session.checkersComponent.register(checkers) } + fun useCheckers(checkers: TypeCheckers) { + session.checkersComponent.register(checkers) + } + @SessionConfiguration fun configure() { session.extensionService.registerExtensions(registeredExtensions.reduce(BunchOfRegisteredExtensions::plus)) diff --git a/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/modifierApplicability.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/modifierApplicability.fir.kt index f0ea930bea2..e39f7d145d3 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/modifierApplicability.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/modifierApplicability.fir.kt @@ -22,7 +22,8 @@ typealias Test15 = (@A() suspend () -> Unit)? typealias Test16 = (@A suspend () -> Unit)? typealias Test17 = @A suspend RS.() -> Unit typealias Test18 = (suspend () -> Unit)? -typealias Test19 = (@A({ val x: suspend String? = null; "" }()) suspend () -> Unit)? +typealias Test19 = (@A({ val x: suspend String? = null; "" }()) suspend () -> Unit)? +typealias Test20 = (@A("".let { val x: suspend String? = null; it }) suspend () -> Unit)? interface Supertype1 : suspend () -> Unit { diff --git a/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/modifierApplicability.kt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/modifierApplicability.kt index a53d7511a3b..7cd102c794c 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/modifierApplicability.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/modifierApplicability.kt @@ -23,6 +23,7 @@ typealias Test16 = (@A suspend () -> Unit)? typealias Test17 = @A suspend RS.() -> Unit typealias Test18 = (suspend () -> Unit)? typealias Test19 = (@A({ val x: suspend String? = null; "" }()) suspend () -> Unit)? +typealias Test20 = (@A("".let { val x: suspend String? = null; it }) suspend () -> Unit)? interface Supertype1 : suspend () -> Unit { diff --git a/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/modifierApplicability.txt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/modifierApplicability.txt index 8303b04304c..828d09c3324 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/modifierApplicability.txt +++ b/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendFunctionType/modifierApplicability.txt @@ -47,6 +47,7 @@ public typealias Test17 = (@A suspend RS.() -> kotlin.Unit) public typealias Test18 = (suspend () -> kotlin.Unit)? public typealias Test19 = (@A suspend () -> kotlin.Unit)? public typealias Test2 = suspend kotlin.Int.() -> kotlin.Unit +public typealias Test20 = (@A suspend () -> kotlin.Unit)? public typealias Test3 = () -> kotlin.Unit public typealias Test4 = Action public typealias Test5 = kotlin.collections.List kotlin.Unit> diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/AbstractFirIdeDiagnosticsCollector.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/AbstractFirIdeDiagnosticsCollector.kt index 8453a98f216..75f57806a63 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/AbstractFirIdeDiagnosticsCollector.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostics/AbstractFirIdeDiagnosticsCollector.kt @@ -6,13 +6,13 @@ package org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.fir.FirPsiSourceElement import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.SessionConfiguration import org.jetbrains.kotlin.fir.analysis.CheckersComponent import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.declaration.DeclarationCheckers import org.jetbrains.kotlin.fir.analysis.checkers.expression.ExpressionCheckers +import org.jetbrains.kotlin.fir.analysis.checkers.type.TypeCheckers import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector import org.jetbrains.kotlin.fir.analysis.collectors.components.* import org.jetbrains.kotlin.fir.analysis.diagnostics.* @@ -27,11 +27,13 @@ internal abstract class AbstractFirIdeDiagnosticsCollector( init { val declarationCheckers = CheckersFactory.createDeclarationCheckers(useExtendedCheckers) val expressionCheckers = CheckersFactory.createExpressionCheckers(useExtendedCheckers) + val typeCheckers = CheckersFactory.createTypeCheckers(useExtendedCheckers) @Suppress("LeakingThis") initializeComponents( DeclarationCheckersDiagnosticComponent(this, declarationCheckers), ExpressionCheckersDiagnosticComponent(this, expressionCheckers), + TypeCheckersDiagnosticComponent(this, typeCheckers), ErrorNodeDiagnosticCollectorComponent(this), ControlFlowAnalysisDiagnosticComponent(this, declarationCheckers), ) @@ -113,6 +115,8 @@ private object CheckersFactory { fun createExpressionCheckers(useExtendedCheckers: Boolean): ExpressionCheckers = if (useExtendedCheckers) ExtendedExpressionCheckers else CommonExpressionCheckers + fun createTypeCheckers(useExtendedCheckers: Boolean): TypeCheckers = CommonTypeCheckers + // TODO hack to have all checkers present in DeclarationCheckers.memberDeclarationCheckers and similar // If use ExtendedDeclarationCheckers directly when DeclarationCheckers.memberDeclarationCheckers will not contain basicDeclarationCheckers @OptIn(SessionConfiguration::class)