From 568eb255f5a7ee86277ca55af9b83f70f9955004 Mon Sep 17 00:00:00 2001 From: Ivan Kochurkin Date: Fri, 25 Jun 2021 18:58:08 +0300 Subject: [PATCH] [FIR] Split UpperBoundViolated checkers on two files (expression and declaration), add FirUpperBoundViolatedHelpers --- .../checkers/CommonDeclarationCheckers.kt | 3 +- ...ker.kt => FirUpperBoundViolatedHelpers.kt} | 90 ++----------------- ...FirUpperBoundViolatedDeclarationChecker.kt | 39 ++++++++ .../FirUpperBoundViolatedExpressionChecker.kt | 64 +++++++++++++ 4 files changed, 109 insertions(+), 87 deletions(-) rename compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/{expression/FirUpperBoundViolatedChecker.kt => FirUpperBoundViolatedHelpers.kt} (62%) create mode 100644 compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirUpperBoundViolatedDeclarationChecker.kt create mode 100644 compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUpperBoundViolatedExpressionChecker.kt diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt index 1a305b22090..f33f1e76ea7 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt @@ -15,7 +15,6 @@ import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirDelegationInInterfac import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirFunctionTypeParametersSyntaxChecker import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirTypeParameterSyntaxChecker import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirReservedUnderscoreDeclarationChecker -import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirUpperBoundViolatedClassChecker object CommonDeclarationCheckers : DeclarationCheckers() { override val basicDeclarationCheckers: Set @@ -25,7 +24,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() { FirProjectionRelationChecker, FirTypeConstraintsChecker, FirReservedUnderscoreDeclarationChecker, - FirUpperBoundViolatedClassChecker + FirUpperBoundViolatedDeclarationChecker ) override val memberDeclarationCheckers: Set diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUpperBoundViolatedChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirUpperBoundViolatedHelpers.kt similarity index 62% rename from compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUpperBoundViolatedChecker.kt rename to compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirUpperBoundViolatedHelpers.kt index 7f92ee6e889..cb0aca41786 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUpperBoundViolatedChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirUpperBoundViolatedHelpers.kt @@ -1,109 +1,29 @@ /* - * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.expression +package org.jetbrains.kotlin.fir.analysis.checkers -import org.jetbrains.kotlin.fir.FirFakeSourceElementKind import org.jetbrains.kotlin.fir.FirSourceElement -import org.jetbrains.kotlin.fir.analysis.checkers.FirTypeRefSource import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext -import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker -import org.jetbrains.kotlin.fir.analysis.checkers.extractArgumentTypeRefAndSource 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.* -import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression -import org.jetbrains.kotlin.fir.references.FirErrorNamedReference -import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference -import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeInapplicableCandidateError +import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol import org.jetbrains.kotlin.fir.typeContext import org.jetbrains.kotlin.fir.types.* -import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability import org.jetbrains.kotlin.types.AbstractTypeChecker -import org.jetbrains.kotlin.utils.addToStdlib.safeAs - -object FirUpperBoundViolatedClassChecker : FirBasicDeclarationChecker() { - override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { - if (declaration is FirClass<*>) { - for (typeParameter in declaration.typeParameters) { - if (typeParameter is FirTypeParameter) { - for (bound in typeParameter.bounds) { - checkUpperBoundViolated(bound, context, reporter) - } - } - } - - for (superTypeRef in declaration.superTypeRefs) { - checkUpperBoundViolated(superTypeRef, context, reporter) - } - } else if (declaration is FirTypeAlias) { - checkUpperBoundViolated(declaration.expandedTypeRef, context, reporter, isIgnoreTypeParameters = true) - } else if (declaration is FirCallableDeclaration<*>) { - if (declaration.returnTypeRef.source?.kind !is FirFakeSourceElementKind) { - checkUpperBoundViolated( - declaration.returnTypeRef, context, reporter, - isIgnoreTypeParameters = context.containingDeclarations.lastOrNull() is FirTypeAlias - ) - } - } - } -} - -object FirUpperBoundViolatedExpressionChecker : FirQualifiedAccessExpressionChecker() { - override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) { - // something that contains the type parameters - // declarations with their declared bounds. - // it may be the called function declaration - // or the class declaration - val calleReference = expression.calleeReference - var calleeFir: FirTypeParameterRefsOwner? = null - if (calleReference is FirResolvedNamedReference) { - calleeFir = calleReference.safeAs()?.resolvedSymbol?.fir.safeAs() - } else if (calleReference is FirErrorNamedReference) { - val diagnostic = calleReference.diagnostic - if (diagnostic is ConeInapplicableCandidateError && - diagnostic.applicability == CandidateApplicability.INAPPLICABLE_WRONG_RECEIVER - ) { - return - } - calleeFir = calleReference.candidateSymbol?.fir.safeAs() - } - - var typeArguments: List? = null - var typeArgumentRefsAndSources: List? = null - val typeParameters = if (calleeFir is FirConstructor) { - typeArgumentRefsAndSources = - expression.typeArguments.map { FirTypeRefSource((it as? FirTypeProjectionWithVariance)?.typeRef, it.source) } - val prototypeClass = calleeFir.dispatchReceiverType?.toSymbol(context.session)?.fir.safeAs() - prototypeClass?.typeParameters?.map { it.symbol } - } else { - typeArguments = expression.typeArguments - calleeFir?.typeParameters?.map { it.symbol } - } - - checkUpperBoundViolated( - expression.typeRef, - context, - reporter, - typeParameters, - typeArguments, - typeArgumentRefsAndSources - ) - } -} /** * Recursively analyzes type parameters and reports the diagnostic on the given source calculated using typeRef * Returns true if an error occurred */ -private fun checkUpperBoundViolated( +fun checkUpperBoundViolated( typeRef: FirTypeRef?, context: CheckerContext, reporter: DiagnosticReporter, @@ -128,7 +48,7 @@ private fun checkUpperBoundViolated( ?: if (type is ConeClassLikeType) { val fullyExpandedType = type.fullyExpandedType(context.session) val prototypeClass = fullyExpandedType.lookupTag.toSymbol(context.session) - ?.fir.safeAs() + ?.fir as? FirRegularClass ?: return if (type != fullyExpandedType) { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirUpperBoundViolatedDeclarationChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirUpperBoundViolatedDeclarationChecker.kt new file mode 100644 index 00000000000..e9d9add0185 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirUpperBoundViolatedDeclarationChecker.kt @@ -0,0 +1,39 @@ +/* + * 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.FirFakeSourceElementKind +import org.jetbrains.kotlin.fir.analysis.checkers.checkUpperBoundViolated +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.fir.declarations.* + +object FirUpperBoundViolatedDeclarationChecker : FirBasicDeclarationChecker() { + override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { + if (declaration is FirClass<*>) { + for (typeParameter in declaration.typeParameters) { + if (typeParameter is FirTypeParameter) { + for (bound in typeParameter.bounds) { + checkUpperBoundViolated(bound, context, reporter) + } + } + } + + for (superTypeRef in declaration.superTypeRefs) { + checkUpperBoundViolated(superTypeRef, context, reporter) + } + } else if (declaration is FirTypeAlias) { + checkUpperBoundViolated(declaration.expandedTypeRef, context, reporter, isIgnoreTypeParameters = true) + } else if (declaration is FirCallableDeclaration<*>) { + if (declaration.returnTypeRef.source?.kind !is FirFakeSourceElementKind) { + checkUpperBoundViolated( + declaration.returnTypeRef, context, reporter, + isIgnoreTypeParameters = context.containingDeclarations.lastOrNull() is FirTypeAlias + ) + } + } + } +} \ No newline at end of file diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUpperBoundViolatedExpressionChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUpperBoundViolatedExpressionChecker.kt new file mode 100644 index 00000000000..a46b6be897e --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUpperBoundViolatedExpressionChecker.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2010-2020 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.fir.analysis.checkers.FirTypeRefSource +import org.jetbrains.kotlin.fir.analysis.checkers.checkUpperBoundViolated +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.fir.declarations.FirConstructor +import org.jetbrains.kotlin.fir.declarations.FirRegularClass +import org.jetbrains.kotlin.fir.declarations.FirTypeParameterRefsOwner +import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression +import org.jetbrains.kotlin.fir.references.FirErrorNamedReference +import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference +import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeInapplicableCandidateError +import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability +import org.jetbrains.kotlin.utils.addToStdlib.safeAs + +object FirUpperBoundViolatedExpressionChecker : FirQualifiedAccessExpressionChecker() { + override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) { + // something that contains the type parameters + // declarations with their declared bounds. + // it may be the called function declaration + // or the class declaration + val calleReference = expression.calleeReference + var calleeFir: FirTypeParameterRefsOwner? = null + if (calleReference is FirResolvedNamedReference) { + calleeFir = calleReference.safeAs()?.resolvedSymbol?.fir.safeAs() + } else if (calleReference is FirErrorNamedReference) { + val diagnostic = calleReference.diagnostic + if (diagnostic is ConeInapplicableCandidateError && + diagnostic.applicability == CandidateApplicability.INAPPLICABLE_WRONG_RECEIVER + ) { + return + } + calleeFir = calleReference.candidateSymbol?.fir.safeAs() + } + + var typeArguments: List? = null + var typeArgumentRefsAndSources: List? = null + val typeParameters = if (calleeFir is FirConstructor) { + typeArgumentRefsAndSources = + expression.typeArguments.map { FirTypeRefSource((it as? FirTypeProjectionWithVariance)?.typeRef, it.source) } + val prototypeClass = calleeFir.dispatchReceiverType?.toSymbol(context.session)?.fir.safeAs() + prototypeClass?.typeParameters?.map { it.symbol } + } else { + typeArguments = expression.typeArguments + calleeFir?.typeParameters?.map { it.symbol } + } + + checkUpperBoundViolated( + expression.typeRef, + context, + reporter, + typeParameters, + typeArguments, + typeArgumentRefsAndSources + ) + } +} \ No newline at end of file