From bb18203ae6b7e3dabbd10a6a056ee705cb8e0495 Mon Sep 17 00:00:00 2001 From: Nick Date: Tue, 25 Aug 2020 17:34:06 +0300 Subject: [PATCH] [FIR] Various checkers performance fixes --- .../resolve/diagnostics/someOverridesTest.kt | 10 + .../resolve/diagnostics/someOverridesTest.txt | 31 +++ .../fir/FirDiagnosticsTestGenerated.java | 5 + ...DiagnosticsWithLightTreeTestGenerated.java | 5 + .../checkers/FirDeclarationInspector.kt | 218 +++++++++++++----- .../checkers/context/CheckerContext.kt | 2 +- .../declaration/DefaultDeclarationCheckers.kt | 5 +- .../FirConflictingProjectionChecker.kt | 34 +-- .../FirDelegationInInterfaceChecker.kt | 11 +- ...ethodOfAnyImplementedInInterfaceChecker.kt | 25 +- ...rSupertypeInitializedInInterfaceChecker.kt | 11 +- ...ypeInitializedWithoutPrimaryConstructor.kt | 1 + .../FirTypeMismatchOnOverrideChecker.kt | 67 +----- ...rclassNotAccessibleFromInterfaceChecker.kt | 8 +- ...ypeArgumentsNotAllowedExpressionChecker.kt | 3 +- .../FirUpperBoundViolatedChecker.kt | 29 ++- 16 files changed, 300 insertions(+), 165 deletions(-) create mode 100644 compiler/fir/analysis-tests/testData/resolve/diagnostics/someOverridesTest.kt create mode 100644 compiler/fir/analysis-tests/testData/resolve/diagnostics/someOverridesTest.txt diff --git a/compiler/fir/analysis-tests/testData/resolve/diagnostics/someOverridesTest.kt b/compiler/fir/analysis-tests/testData/resolve/diagnostics/someOverridesTest.kt new file mode 100644 index 00000000000..8ab1ba0beca --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/diagnostics/someOverridesTest.kt @@ -0,0 +1,10 @@ +open class A +open class B : A() + +open class First { + open fun test(item: T) {} +} + +open class Second : First() { + override fun test(item: A) {} +} diff --git a/compiler/fir/analysis-tests/testData/resolve/diagnostics/someOverridesTest.txt b/compiler/fir/analysis-tests/testData/resolve/diagnostics/someOverridesTest.txt new file mode 100644 index 00000000000..3c4ec19e34c --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/diagnostics/someOverridesTest.txt @@ -0,0 +1,31 @@ +FILE: someOverridesTest.kt + public open class A : R|kotlin/Any| { + public constructor(): R|A| { + super() + } + + } + public open class B : R|A| { + public constructor(): R|B| { + super() + } + + } + public open class First : R|kotlin/Any| { + public constructor(): R|First| { + super() + } + + public open fun test(item: R|T|): R|kotlin/Unit| { + } + + } + public open class Second : R|First| { + public constructor(): R|Second| { + super|>() + } + + public open override fun test(item: R|A|): R|kotlin/Unit| { + } + + } diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java index 5c664cff5aa..9c134186188 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java @@ -1056,6 +1056,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest { runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/sealedSupertype.kt"); } + @TestMetadata("someOverridesTest.kt") + public void testSomeOverridesTest() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/someOverridesTest.kt"); + } + @TestMetadata("superIsNotAnExpression.kt") public void testSuperIsNotAnExpression() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/superIsNotAnExpression.kt"); diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java index 91f176b51b1..c15d9e0fb55 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java @@ -1056,6 +1056,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/sealedSupertype.kt"); } + @TestMetadata("someOverridesTest.kt") + public void testSomeOverridesTest() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/someOverridesTest.kt"); + } + @TestMetadata("superIsNotAnExpression.kt") public void testSuperIsNotAnExpression() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/superIsNotAnExpression.kt"); diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirDeclarationInspector.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirDeclarationInspector.kt index b6e75187695..b479b4517b4 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirDeclarationInspector.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirDeclarationInspector.kt @@ -9,9 +9,7 @@ import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirFakeSourceElementKind import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.symbols.CallableId -import org.jetbrains.kotlin.fir.types.FirErrorTypeRef -import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef -import org.jetbrains.kotlin.fir.types.FirTypeRef +import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name @@ -19,78 +17,172 @@ import org.jetbrains.kotlin.name.Name * Provides representations for FirElement's. */ interface FirDeclarationPresenter { - open class RepresentationBuilder { - var receiver = "" - var name = "" - - open fun build() = "[$receiver] $name" + fun StringBuilder.appendRepresentation(it: FirElement) { + append("NO_REPRESENTATION") } - fun buildRepresentation(init: RepresentationBuilder.() -> Unit): String { - return RepresentationBuilder().apply(init).build() + fun StringBuilder.appendRepresentation(it: ClassId) { + append(it.packageFqName.asString()) + append('/') + append(it.relativeClassName.asString()) } - class FunctionRepresentationBuilder : RepresentationBuilder() { - var representsOperator = false - var typeArguments = "" - var parameters = "" - - override fun build() = "<$typeArguments> [$receiver] ${if (representsOperator) "operator " else ""}$name ($parameters)" - } - - fun buildFunctionRepresentation(init: FunctionRepresentationBuilder.() -> Unit): String { - return FunctionRepresentationBuilder().apply(init).build() - } - - fun represent(it: FirElement) = "NO_REPRESENTATION" - - fun represent(it: ClassId) = it.packageFqName.asString() + '/' + it.relativeClassName.asString() - - fun represent(it: CallableId) = if (it.className != null) { - it.packageName.asString() + '/' + it.className + '.' + it.callableName - } else { - it.packageName.asString() + '/' + it.callableName - } - - fun represent(it: FirTypeRef) = when (it) { - is FirResolvedTypeRef -> it.type.toString() - is FirErrorTypeRef -> "ERROR" - else -> "?" - } - - fun represent(it: FirTypeParameter) = it.name.asString() + " : " + it.bounds - .map { represent(it) } - .sorted() - .joinToString() - - fun represent(it: FirValueParameter): String { - val prefix = if (it.isVararg) "vararg " else "" - return prefix + " " + represent(it.returnTypeRef) - } - - fun represent(it: FirProperty) = buildRepresentation { - it.receiverTypeRef?.let { - receiver = represent(it) + fun StringBuilder.appendRepresentation(it: CallableId) { + if (it.className != null) { + append(it.packageName.asString()) + append('/') + append(it.className) + append('.') + append(it.callableName) + } else { + append(it.packageName.asString()) + append('/') + append(it.callableName) } - name = represent(it.symbol.callableId) } - fun represent(it: FirSimpleFunction) = buildFunctionRepresentation { - typeArguments = it.typeParameters.joinToString { represent(it) } - it.receiverTypeRef?.let { - receiver = represent(it) + fun StringBuilder.appendRepresentation(it: ConeTypeProjection) { + when (it) { + ConeStarProjection -> { + append('*') + } + is ConeKotlinTypeProjectionIn -> { + append("in ") + appendRepresentation(it.type) + } + is ConeKotlinTypeProjectionOut -> { + append("out ") + appendRepresentation(it.type) + } + is ConeKotlinType -> { + appendRepresentation(it) + } } - representsOperator = it.isOperator - name = represent(it.symbol.callableId) - parameters = it.valueParameters.joinToString { represent(it) } } - fun represent(it: FirTypeAlias) = buildRepresentation { - name = represent(it.symbol.classId) + fun StringBuilder.appendRepresentation(it: ConeKotlinType) { + when (it) { + is ConeDefinitelyNotNullType -> { + appendRepresentation(it.original) + append(it.nullability.suffix) + } + is ConeClassErrorType -> { + append("ERROR(") + append(it.diagnostic.reason) + append(')') + } + is ConeCapturedType -> { + append(it.constructor.projection) + append(it.nullability.suffix) + } + is ConeClassLikeType -> { + appendRepresentation(it.lookupTag.classId) + if (it.typeArguments.isNotEmpty()) { + append('<') + it.typeArguments.forEach { that -> + appendRepresentation(that) + append(',') + } + append('>') + } + append(it.nullability.suffix) + } + is ConeLookupTagBasedType -> { + append(it.lookupTag.name) + append(it.nullability.suffix) + } + is ConeIntegerLiteralType -> { + append(it.value) + append(it.nullability.suffix) + } + is ConeFlexibleType, + is ConeIntersectionType, + is ConeStubType -> { + append("ERROR") + } + } } - fun represent(it: FirRegularClass) = buildRepresentation { - name = represent(it.symbol.classId) + fun StringBuilder.appendRepresentation(it: FirTypeRef) { + when (it) { + is FirResolvedTypeRef -> appendRepresentation(it.type) + is FirErrorTypeRef -> append("ERROR") + else -> append("?") + } + } + + fun StringBuilder.appendRepresentation(it: FirTypeParameter) { + append(it.name.asString()) + append(':') + when (it.bounds.size) { + 0 -> { + } + 1 -> { + appendRepresentation(it.bounds[0]) + } + else -> { + val set = sortedSetOf() + it.bounds.forEach { that -> + set.add(buildString { appendRepresentation(that) }) + } + set.forEach { that -> + append(that) + append(',') + } + } + } + } + + fun StringBuilder.appendRepresentation(it: FirValueParameter) { + if (it.isVararg) { + append("vararg ") + } + appendRepresentation(it.returnTypeRef) + } + + fun represent(it: FirProperty) = buildString { + append('[') + it.receiverTypeRef?.let { + appendRepresentation(it) + } + append(']') + appendRepresentation(it.symbol.callableId) + } + + fun represent(it: FirSimpleFunction) = buildString { + append('<') + it.typeParameters.forEach { + appendRepresentation(it) + append(',') + } + append('>') + append('[') + it.receiverTypeRef?.let { + appendRepresentation(it) + } + append(']') + if (it.isOperator) { + append("operator ") + } + appendRepresentation(it.symbol.callableId) + append('(') + it.valueParameters.forEach { + appendRepresentation(it) + append(',') + } + append(')') + } + + fun represent(it: FirTypeAlias) = buildString { + append('[') + append(']') + appendRepresentation(it.symbol.classId) + } + + fun represent(it: FirRegularClass) = buildString { + append('[') + append(']') + appendRepresentation(it.symbol.classId) } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/context/CheckerContext.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/context/CheckerContext.kt index 2d7301763c7..235bfbe5f9c 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/context/CheckerContext.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/context/CheckerContext.kt @@ -28,7 +28,7 @@ abstract class CheckerContext { * T instance or null if no such item could be found. */ inline fun findClosest(): T? { - for (it in containingDeclarations.reversed()) { + for (it in containingDeclarations.asReversed()) { return it as? T ?: continue } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/DefaultDeclarationCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/DefaultDeclarationCheckers.kt index 372b8604950..6557eb8677b 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/DefaultDeclarationCheckers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/DefaultDeclarationCheckers.kt @@ -27,7 +27,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() { FirConflictingProjectionChecker, ) - override val memberDeclarationCheckers: List = listOf( + override val memberDeclarationCheckers: List =listOf( FirInfixFunctionDeclarationChecker, FirExposedVisibilityDeclarationChecker, FirCommonConstructorDelegationIssuesChecker, @@ -41,11 +41,10 @@ object CommonDeclarationCheckers : DeclarationCheckers() { FirEnumClassSimpleChecker, FirSealedSupertypeChecker, FirInapplicableLateinitChecker, - FirTypeMismatchOnOverrideChecker, ) override val regularClassCheckers: List = listOf( - + FirTypeMismatchOnOverrideChecker, ) override val constructorCheckers: List = listOf( diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConflictingProjectionChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConflictingProjectionChecker.kt index f0c438e2c91..39e73764caf 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConflictingProjectionChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConflictingProjectionChecker.kt @@ -13,25 +13,20 @@ import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.types.Variance +import org.jetbrains.kotlin.utils.addToStdlib.min import org.jetbrains.kotlin.utils.addToStdlib.safeAs object FirConflictingProjectionChecker : FirBasicDeclarationChecker() { override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { - // we can't just check for FirTypedDeclaration - // because it leads to duplicate reports for - // some cases. Maybe we should fix this via not - // visiting the same firs twice instead. + if (declaration is FirPropertyAccessor) { + return + } + + if (declaration is FirTypedDeclaration) { + checkTypeRef(declaration.returnTypeRef, context, reporter) + } + when (declaration) { - is FirPropertyAccessor -> {} - is FirProperty -> { - checkTypeRef(declaration.returnTypeRef, context, reporter) - } - is FirFunction<*> -> { - for (it in declaration.valueParameters) { - checkTypeRef(it.returnTypeRef, context, reporter) - } - checkTypeRef(declaration.returnTypeRef, context, reporter) - } is FirClass<*> -> { for (it in declaration.superTypeRefs) { checkTypeRef(it, context, reporter) @@ -56,14 +51,19 @@ object FirConflictingProjectionChecker : FirBasicDeclarationChecker() { ?.fir.safeAs() ?: return - declaration.typeParameters.zip(typeRef.coneType.typeArguments).forEach { (proto, actual) -> + val size = min(declaration.typeParameters.size, typeRef.coneType.typeArguments.size) + + for (it in 0 until size) { + val proto = declaration.typeParameters[it] + val actual = typeRef.coneType.typeArguments[it] + val protoVariance = proto.safeAs() ?.symbol?.fir ?.variance - ?: return@forEach + ?: continue if (protoVariance == Variance.INVARIANT) { - return@forEach + continue } if ( diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDelegationInInterfaceChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDelegationInInterfaceChecker.kt index 9ce489e0069..a230304c1fe 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDelegationInInterfaceChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDelegationInInterfaceChecker.kt @@ -47,10 +47,13 @@ object FirDelegationInInterfaceChecker : FirMemberDeclarationChecker() { return -1 } - private fun PsiElement.findSuperTypeDelegation() = if (children.isNotEmpty() && children[0] !is PsiErrorElement) { - children[0].children.indexOfFirst { it is KtDelegatedSuperTypeEntry } - } else { - -1 + private fun PsiElement.findSuperTypeDelegation(): Int { + val children = this.children // this is a method call and it collects children + return if (children.isNotEmpty() && children[0] !is PsiErrorElement) { + children[0].children.indexOfFirst { it is KtDelegatedSuperTypeEntry } + } else { + -1 + } } private fun LighterASTNode.findSuperTypeDelegation(tree: FlyweightCapableTreeStructure): Int { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMethodOfAnyImplementedInInterfaceChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMethodOfAnyImplementedInInterfaceChecker.kt index 60204ad570a..e34b23e4aff 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMethodOfAnyImplementedInInterfaceChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMethodOfAnyImplementedInInterfaceChecker.kt @@ -34,13 +34,26 @@ object FirMethodOfAnyImplementedInInterfaceChecker : FirMemberDeclarationChecker inspector = this } - override fun represent(it: FirSimpleFunction) = buildFunctionRepresentation { - typeArguments = it.typeParameters.joinToString { represent(it) } - it.receiverTypeRef?.let { - receiver = represent(it) + @Suppress("DuplicatedCode") + override fun represent(it: FirSimpleFunction) = buildString { + append('<') + it.typeParameters.forEach { + appendRepresentation(it) + append(',') } - name = it.name.asString() - parameters = it.valueParameters.joinToString { represent(it) } + append('>') + append('[') + it.receiverTypeRef?.let { + appendRepresentation(it) + } + append(']') + append(it.name.asString()) + append('(') + it.valueParameters.forEach { + appendRepresentation(it) + append(',') + } + append(')') } override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirSupertypeInitializedInInterfaceChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirSupertypeInitializedInInterfaceChecker.kt index fee00b02153..c8a748f5f6d 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirSupertypeInitializedInInterfaceChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirSupertypeInitializedInInterfaceChecker.kt @@ -47,10 +47,13 @@ object FirSupertypeInitializedInInterfaceChecker : FirMemberDeclarationChecker() return -1 } - private fun PsiElement.findSuperTypeCall() = if (children.isNotEmpty() && children[0] !is PsiErrorElement) { - children[0].children.indexOfFirst { it is KtSuperTypeCallEntry } - } else { - -1 + private fun PsiElement.findSuperTypeCall(): Int { + val children = this.children // this is a method call and it collects children + return if (children.isNotEmpty() && children[0] !is PsiErrorElement) { + children[0].children.indexOfFirst { it is KtSuperTypeCallEntry } + } else { + -1 + } } private fun LighterASTNode.findSuperTypeCall(tree: FlyweightCapableTreeStructure): Int { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirSupertypeInitializedWithoutPrimaryConstructor.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirSupertypeInitializedWithoutPrimaryConstructor.kt index 5dd90601109..cab6c21648c 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirSupertypeInitializedWithoutPrimaryConstructor.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirSupertypeInitializedWithoutPrimaryConstructor.kt @@ -52,6 +52,7 @@ object FirSupertypeInitializedWithoutPrimaryConstructor : FirMemberDeclarationCh } private fun PsiElement.anySupertypeHasConstructorParentheses(): Boolean { + val children = this.children // this is a method call and it collects children return children.isNotEmpty() && children[0] !is PsiErrorElement && children[0].children.any { it is KtSuperTypeCallEntry } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTypeMismatchOnOverrideChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTypeMismatchOnOverrideChecker.kt index fcd07b8b562..2e5dab15750 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTypeMismatchOnOverrideChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTypeMismatchOnOverrideChecker.kt @@ -10,9 +10,7 @@ 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.declarations.* -import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap -import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.scopes.impl.toConeType import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol @@ -23,14 +21,11 @@ import org.jetbrains.kotlin.fir.typeContext import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.types.AbstractTypeChecker import org.jetbrains.kotlin.types.AbstractTypeCheckerContext +import org.jetbrains.kotlin.utils.addToStdlib.min import org.jetbrains.kotlin.utils.addToStdlib.safeAs -object FirTypeMismatchOnOverrideChecker : FirMemberDeclarationChecker() { - override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { - if (declaration !is FirRegularClass) { - return - } - +object FirTypeMismatchOnOverrideChecker : FirRegularClassChecker() { + override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) { val typeCheckerContext = context.session.typeContext.newBaseTypeCheckerContext( errorTypesEqualToAnything = false, stubTypesEqualToAnything = false @@ -43,8 +38,8 @@ object FirTypeMismatchOnOverrideChecker : FirMemberDeclarationChecker() { for (it in declaration.declarations) { when (it) { - is FirSimpleFunction -> checkFunction(declaration, it, context, reporter, typeCheckerContext, firTypeScope) - is FirProperty -> checkProperty(declaration, it, context, reporter, typeCheckerContext, firTypeScope) + is FirSimpleFunction -> checkFunction(it, reporter, typeCheckerContext, firTypeScope) + is FirProperty -> checkProperty(it, reporter, typeCheckerContext, firTypeScope) } } } @@ -73,38 +68,6 @@ object FirTypeMismatchOnOverrideChecker : FirMemberDeclarationChecker() { return overriddenProperties.toList() } - private fun FirRegularClass.substituteAllSupertypeParameters(context: CheckerContext): ConeSubstitutor { - val allSupertypesMapping = mutableMapOf() - val remapper = mutableMapOf() - - fun FirRegularClass.collectSupertypes() { - for (it in superTypeRefs) { - val fir = it.coneType.safeAs()?.lookupTag?.toSymbol(context.session) - ?.fir.safeAs() - ?: continue - - if (it.coneType.typeArguments.size != fir.typeParameters.size) { - continue - } - - for (that in fir.typeParameters.indices) { - val proto = fir.typeParameters[that].symbol - val actual = it.coneType.typeArguments[that].safeAs() - ?.lowerBoundIfFlexible() - ?: continue - val value = remapper.getOrDefault(actual, actual) - remapper[proto.fir.toConeType()] = value - allSupertypesMapping[proto] = value - } - - fir.collectSupertypes() - } - } - - collectSupertypes() - return substitutorByMap(allSupertypesMapping) - } - private fun ConeKotlinType.substituteAllTypeParameters( overrideDeclaration: FirCallableMemberDeclaration<*>, baseDeclarationSymbol: FirCallableSymbol<*>, @@ -117,32 +80,30 @@ object FirTypeMismatchOnOverrideChecker : FirMemberDeclarationChecker() { ?: return this val map = mutableMapOf() + val size = min(overrideDeclaration.typeParameters.size, parametersOwner.typeParameters.size) + + for (it in 0 until size) { + val to = overrideDeclaration.typeParameters[it] + val from = parametersOwner.typeParameters[it] - overrideDeclaration.typeParameters.zip(parametersOwner.typeParameters).forEach { (to, from) -> map[from.symbol] = to.toConeType() } return substitutorByMap(map).substituteOrSelf(this) } - private fun ConeKotlinType.substituteOrSelf(substitutor: ConeSubstitutor) = substitutor.substituteOrSelf(this) - private fun FirCallableMemberDeclaration<*>.checkReturnType( - regularClass: FirRegularClass, overriddenSymbols: List>, - context: CheckerContext, typeCheckerContext: AbstractTypeCheckerContext, ): FirMemberDeclaration? { val returnType = returnTypeRef.safeAs()?.type ?: return null val bounds = overriddenSymbols.map { it.fir.returnTypeRef.coneType.upperBoundIfFlexible() } - val supertypesParameterSubstitutor = regularClass.substituteAllSupertypeParameters(context) for (it in bounds.indices) { val restriction = bounds[it] .substituteAllTypeParameters(this, overriddenSymbols[it]) - .substituteOrSelf(supertypesParameterSubstitutor) if (!AbstractTypeChecker.isSubtypeOf(typeCheckerContext, returnType, restriction)) { return overriddenSymbols[it].fir.safeAs() @@ -153,9 +114,7 @@ object FirTypeMismatchOnOverrideChecker : FirMemberDeclarationChecker() { } private fun checkFunction( - regularClass: FirRegularClass, function: FirSimpleFunction, - context: CheckerContext, reporter: DiagnosticReporter, typeCheckerContext: AbstractTypeCheckerContext, firTypeScope: FirTypeScope @@ -171,9 +130,7 @@ object FirTypeMismatchOnOverrideChecker : FirMemberDeclarationChecker() { } val restriction = function.checkReturnType( - regularClass = regularClass, overriddenSymbols = overriddenFunctionSymbols, - context = context, typeCheckerContext = typeCheckerContext ) @@ -187,9 +144,7 @@ object FirTypeMismatchOnOverrideChecker : FirMemberDeclarationChecker() { } private fun checkProperty( - regularClass: FirRegularClass, property: FirProperty, - context: CheckerContext, reporter: DiagnosticReporter, typeCheckerContext: AbstractTypeCheckerContext, firTypeScope: FirTypeScope @@ -205,9 +160,7 @@ object FirTypeMismatchOnOverrideChecker : FirMemberDeclarationChecker() { } val restriction = property.checkReturnType( - regularClass = regularClass, overriddenSymbols = overriddenPropertySymbols, - context = context, typeCheckerContext = typeCheckerContext ) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirSuperclassNotAccessibleFromInterfaceChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirSuperclassNotAccessibleFromInterfaceChecker.kt index 82419a387ea..19644efb0c1 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirSuperclassNotAccessibleFromInterfaceChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirSuperclassNotAccessibleFromInterfaceChecker.kt @@ -8,13 +8,13 @@ package org.jetbrains.kotlin.fir.analysis.checkers.expression import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.fir.FirSourceElement import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext -import org.jetbrains.kotlin.fir.analysis.checkers.isSuperclassOf import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference +import org.jetbrains.kotlin.fir.references.FirSuperReference import org.jetbrains.kotlin.fir.resolve.firSymbolProvider import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol @@ -22,6 +22,10 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs object FirSuperclassNotAccessibleFromInterfaceChecker : FirQualifiedAccessChecker() { override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) { + expression.explicitReceiver.safeAs() + ?.calleeReference.safeAs() + ?: return + val closestClass = context.findClosest() ?: return if (closestClass.classKind == ClassKind.INTERFACE) { @@ -30,7 +34,7 @@ object FirSuperclassNotAccessibleFromInterfaceChecker : FirQualifiedAccessChecke ?.fir ?: return - if (origin.source != null && origin.isSuperclassOf(closestClass)) { + if (origin.source != null && origin.classKind == ClassKind.CLASS) { reporter.report(expression.explicitReceiver?.source) } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirTypeArgumentsNotAllowedExpressionChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirTypeArgumentsNotAllowedExpressionChecker.kt index 9b30629f65c..7f6a529f7cc 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirTypeArgumentsNotAllowedExpressionChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirTypeArgumentsNotAllowedExpressionChecker.kt @@ -50,7 +50,8 @@ object FirTypeArgumentsNotAllowedExpressionChecker : FirQualifiedAccessChecker() } private fun PsiElement.hasAnyArguments(): Boolean { - return this.children.size > 1 && this.children[1] is KtTypeArgumentList + val children = this.children // this is a method call and it collects children + return children.size > 1 && children[1] is KtTypeArgumentList } private fun LighterASTNode.hasAnyArguments(tree: FlyweightCapableTreeStructure): Boolean { 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/expression/FirUpperBoundViolatedChecker.kt index 525a1897d94..9dec6b1797c 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/expression/FirUpperBoundViolatedChecker.kt @@ -35,13 +35,13 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() { ?.fir.safeAs() ?: return - val typeCheckerContext = context.session.typeContext.newBaseTypeCheckerContext( - errorTypesEqualToAnything = false, - stubTypesEqualToAnything = false - ) + val count = min(calleeFir.typeParameters.size, expression.typeArguments.size) + + if (count == 0) { + return + } val parameterPairs = mutableMapOf() - val count = min(calleeFir.typeParameters.size, expression.typeArguments.size) for (it in 0 until count) { expression.typeArguments[it].safeAs() @@ -61,6 +61,11 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() { parameterPairs.mapValues { it.value.type } ) + val typeCheckerContext = context.session.typeContext.newBaseTypeCheckerContext( + errorTypesEqualToAnything = false, + stubTypesEqualToAnything = false + ) + parameterPairs.forEach { (proto, actual) -> if (actual.source == null) { // inferred types don't report INAPPLICABLE_CANDIDATE for type aliases! @@ -122,9 +127,14 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() { ?.type.safeAs() ?: return - val constructorsParameterPairs = mutableMapOf() val count = min(protoConstructor.typeParameters.size, actualConstructor.typeArguments.size) + if (count == 0) { + return + } + + val constructorsParameterPairs = mutableMapOf() + for (it in 0 until count) { actualConstructor.typeArguments[it].safeAs() ?.let { that -> @@ -182,9 +192,14 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() { ?.fir.safeAs() ?: return false - val parameterPairs = mutableMapOf() val count = min(prototypeClass.typeParameters.size, type.typeArguments.size) + if (count == 0) { + return false + } + + val parameterPairs = mutableMapOf() + for (it in 0 until count) { type.typeArguments[it].safeAs() ?.let { that ->