[FIR] Various checkers performance fixes

This commit is contained in:
Nick
2020-08-25 17:34:06 +03:00
parent 5c88eb722d
commit bb18203ae6
16 changed files with 300 additions and 165 deletions
@@ -0,0 +1,10 @@
open class A
open class B : A()
open class First<T> {
open fun test(item: T) {}
}
open class Second : First<A>() {
override fun test(item: A) {}
}
@@ -0,0 +1,31 @@
FILE: someOverridesTest.kt
public open class A : R|kotlin/Any| {
public constructor(): R|A| {
super<R|kotlin/Any|>()
}
}
public open class B : R|A| {
public constructor(): R|B| {
super<R|A|>()
}
}
public open class First<T> : R|kotlin/Any| {
public constructor<T>(): R|First<T>| {
super<R|kotlin/Any|>()
}
public open fun test(item: R|T|): R|kotlin/Unit| {
}
}
public open class Second : R|First<A>| {
public constructor(): R|Second| {
super<R|First<A>|>()
}
public open override fun test(item: R|A|): R|kotlin/Unit| {
}
}
@@ -1056,6 +1056,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/sealedSupertype.kt"); 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") @TestMetadata("superIsNotAnExpression.kt")
public void testSuperIsNotAnExpression() throws Exception { public void testSuperIsNotAnExpression() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/superIsNotAnExpression.kt"); runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/superIsNotAnExpression.kt");
@@ -1056,6 +1056,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/sealedSupertype.kt"); 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") @TestMetadata("superIsNotAnExpression.kt")
public void testSuperIsNotAnExpression() throws Exception { public void testSuperIsNotAnExpression() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/superIsNotAnExpression.kt"); runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/superIsNotAnExpression.kt");
@@ -9,9 +9,7 @@ import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.symbols.CallableId import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.types.FirErrorTypeRef import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -19,78 +17,172 @@ import org.jetbrains.kotlin.name.Name
* Provides representations for FirElement's. * Provides representations for FirElement's.
*/ */
interface FirDeclarationPresenter { interface FirDeclarationPresenter {
open class RepresentationBuilder { fun StringBuilder.appendRepresentation(it: FirElement) {
var receiver = "" append("NO_REPRESENTATION")
var name = ""
open fun build() = "[$receiver] $name"
} }
fun buildRepresentation(init: RepresentationBuilder.() -> Unit): String { fun StringBuilder.appendRepresentation(it: ClassId) {
return RepresentationBuilder().apply(init).build() append(it.packageFqName.asString())
append('/')
append(it.relativeClassName.asString())
} }
class FunctionRepresentationBuilder : RepresentationBuilder() { fun StringBuilder.appendRepresentation(it: CallableId) {
var representsOperator = false if (it.className != null) {
var typeArguments = "" append(it.packageName.asString())
var parameters = "" append('/')
append(it.className)
override fun build() = "<$typeArguments> [$receiver] ${if (representsOperator) "operator " else ""}$name ($parameters)" append('.')
} append(it.callableName)
} else {
fun buildFunctionRepresentation(init: FunctionRepresentationBuilder.() -> Unit): String { append(it.packageName.asString())
return FunctionRepresentationBuilder().apply(init).build() append('/')
} append(it.callableName)
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)
} }
name = represent(it.symbol.callableId)
} }
fun represent(it: FirSimpleFunction) = buildFunctionRepresentation { fun StringBuilder.appendRepresentation(it: ConeTypeProjection) {
typeArguments = it.typeParameters.joinToString { represent(it) } when (it) {
it.receiverTypeRef?.let { ConeStarProjection -> {
receiver = represent(it) 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 { fun StringBuilder.appendRepresentation(it: ConeKotlinType) {
name = represent(it.symbol.classId) 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 { fun StringBuilder.appendRepresentation(it: FirTypeRef) {
name = represent(it.symbol.classId) 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<String>()
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)
} }
} }
@@ -28,7 +28,7 @@ abstract class CheckerContext {
* T instance or null if no such item could be found. * T instance or null if no such item could be found.
*/ */
inline fun <reified T : FirDeclaration> findClosest(): T? { inline fun <reified T : FirDeclaration> findClosest(): T? {
for (it in containingDeclarations.reversed()) { for (it in containingDeclarations.asReversed()) {
return it as? T ?: continue return it as? T ?: continue
} }
@@ -27,7 +27,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
FirConflictingProjectionChecker, FirConflictingProjectionChecker,
) )
override val memberDeclarationCheckers: List<FirMemberDeclarationChecker> = listOf( override val memberDeclarationCheckers: List<FirMemberDeclarationChecker> =listOf(
FirInfixFunctionDeclarationChecker, FirInfixFunctionDeclarationChecker,
FirExposedVisibilityDeclarationChecker, FirExposedVisibilityDeclarationChecker,
FirCommonConstructorDelegationIssuesChecker, FirCommonConstructorDelegationIssuesChecker,
@@ -41,11 +41,10 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
FirEnumClassSimpleChecker, FirEnumClassSimpleChecker,
FirSealedSupertypeChecker, FirSealedSupertypeChecker,
FirInapplicableLateinitChecker, FirInapplicableLateinitChecker,
FirTypeMismatchOnOverrideChecker,
) )
override val regularClassCheckers: List<FirRegularClassChecker> = listOf( override val regularClassCheckers: List<FirRegularClassChecker> = listOf(
FirTypeMismatchOnOverrideChecker,
) )
override val constructorCheckers: List<FirConstructorChecker> = listOf( override val constructorCheckers: List<FirConstructorChecker> = listOf(
@@ -13,25 +13,20 @@ import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.addToStdlib.min
import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.addToStdlib.safeAs
object FirConflictingProjectionChecker : FirBasicDeclarationChecker() { object FirConflictingProjectionChecker : FirBasicDeclarationChecker() {
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
// we can't just check for FirTypedDeclaration if (declaration is FirPropertyAccessor) {
// because it leads to duplicate reports for return
// some cases. Maybe we should fix this via not }
// visiting the same firs twice instead.
if (declaration is FirTypedDeclaration) {
checkTypeRef(declaration.returnTypeRef, context, reporter)
}
when (declaration) { 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<*> -> { is FirClass<*> -> {
for (it in declaration.superTypeRefs) { for (it in declaration.superTypeRefs) {
checkTypeRef(it, context, reporter) checkTypeRef(it, context, reporter)
@@ -56,14 +51,19 @@ object FirConflictingProjectionChecker : FirBasicDeclarationChecker() {
?.fir.safeAs<FirRegularClass>() ?.fir.safeAs<FirRegularClass>()
?: return ?: 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<FirTypeParameterRef>() val protoVariance = proto.safeAs<FirTypeParameterRef>()
?.symbol?.fir ?.symbol?.fir
?.variance ?.variance
?: return@forEach ?: continue
if (protoVariance == Variance.INVARIANT) { if (protoVariance == Variance.INVARIANT) {
return@forEach continue
} }
if ( if (
@@ -47,10 +47,13 @@ object FirDelegationInInterfaceChecker : FirMemberDeclarationChecker() {
return -1 return -1
} }
private fun PsiElement.findSuperTypeDelegation() = if (children.isNotEmpty() && children[0] !is PsiErrorElement) { private fun PsiElement.findSuperTypeDelegation(): Int {
children[0].children.indexOfFirst { it is KtDelegatedSuperTypeEntry } val children = this.children // this is a method call and it collects children
} else { return if (children.isNotEmpty() && children[0] !is PsiErrorElement) {
-1 children[0].children.indexOfFirst { it is KtDelegatedSuperTypeEntry }
} else {
-1
}
} }
private fun LighterASTNode.findSuperTypeDelegation(tree: FlyweightCapableTreeStructure<LighterASTNode>): Int { private fun LighterASTNode.findSuperTypeDelegation(tree: FlyweightCapableTreeStructure<LighterASTNode>): Int {
@@ -34,13 +34,26 @@ object FirMethodOfAnyImplementedInInterfaceChecker : FirMemberDeclarationChecker
inspector = this inspector = this
} }
override fun represent(it: FirSimpleFunction) = buildFunctionRepresentation { @Suppress("DuplicatedCode")
typeArguments = it.typeParameters.joinToString { represent(it) } override fun represent(it: FirSimpleFunction) = buildString {
it.receiverTypeRef?.let { append('<')
receiver = represent(it) it.typeParameters.forEach {
appendRepresentation(it)
append(',')
} }
name = it.name.asString() append('>')
parameters = it.valueParameters.joinToString { represent(it) } 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) { override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
@@ -47,10 +47,13 @@ object FirSupertypeInitializedInInterfaceChecker : FirMemberDeclarationChecker()
return -1 return -1
} }
private fun PsiElement.findSuperTypeCall() = if (children.isNotEmpty() && children[0] !is PsiErrorElement) { private fun PsiElement.findSuperTypeCall(): Int {
children[0].children.indexOfFirst { it is KtSuperTypeCallEntry } val children = this.children // this is a method call and it collects children
} else { return if (children.isNotEmpty() && children[0] !is PsiErrorElement) {
-1 children[0].children.indexOfFirst { it is KtSuperTypeCallEntry }
} else {
-1
}
} }
private fun LighterASTNode.findSuperTypeCall(tree: FlyweightCapableTreeStructure<LighterASTNode>): Int { private fun LighterASTNode.findSuperTypeCall(tree: FlyweightCapableTreeStructure<LighterASTNode>): Int {
@@ -52,6 +52,7 @@ object FirSupertypeInitializedWithoutPrimaryConstructor : FirMemberDeclarationCh
} }
private fun PsiElement.anySupertypeHasConstructorParentheses(): Boolean { 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 } return children.isNotEmpty() && children[0] !is PsiErrorElement && children[0].children.any { it is KtSuperTypeCallEntry }
} }
@@ -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.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.* 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.substitution.substitutorByMap
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.scopes.*
import org.jetbrains.kotlin.fir.scopes.impl.toConeType import org.jetbrains.kotlin.fir.scopes.impl.toConeType
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol 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.fir.types.*
import org.jetbrains.kotlin.types.AbstractTypeChecker import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext import org.jetbrains.kotlin.types.AbstractTypeCheckerContext
import org.jetbrains.kotlin.utils.addToStdlib.min
import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.addToStdlib.safeAs
object FirTypeMismatchOnOverrideChecker : FirMemberDeclarationChecker() { object FirTypeMismatchOnOverrideChecker : FirRegularClassChecker() {
override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration !is FirRegularClass) {
return
}
val typeCheckerContext = context.session.typeContext.newBaseTypeCheckerContext( val typeCheckerContext = context.session.typeContext.newBaseTypeCheckerContext(
errorTypesEqualToAnything = false, errorTypesEqualToAnything = false,
stubTypesEqualToAnything = false stubTypesEqualToAnything = false
@@ -43,8 +38,8 @@ object FirTypeMismatchOnOverrideChecker : FirMemberDeclarationChecker() {
for (it in declaration.declarations) { for (it in declaration.declarations) {
when (it) { when (it) {
is FirSimpleFunction -> checkFunction(declaration, it, context, reporter, typeCheckerContext, firTypeScope) is FirSimpleFunction -> checkFunction(it, reporter, typeCheckerContext, firTypeScope)
is FirProperty -> checkProperty(declaration, it, context, reporter, typeCheckerContext, firTypeScope) is FirProperty -> checkProperty(it, reporter, typeCheckerContext, firTypeScope)
} }
} }
} }
@@ -73,38 +68,6 @@ object FirTypeMismatchOnOverrideChecker : FirMemberDeclarationChecker() {
return overriddenProperties.toList() return overriddenProperties.toList()
} }
private fun FirRegularClass.substituteAllSupertypeParameters(context: CheckerContext): ConeSubstitutor {
val allSupertypesMapping = mutableMapOf<FirTypeParameterSymbol, ConeKotlinType>()
val remapper = mutableMapOf<ConeKotlinType, ConeKotlinType>()
fun FirRegularClass.collectSupertypes() {
for (it in superTypeRefs) {
val fir = it.coneType.safeAs<ConeClassLikeType>()?.lookupTag?.toSymbol(context.session)
?.fir.safeAs<FirRegularClass>()
?: 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<ConeKotlinType>()
?.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( private fun ConeKotlinType.substituteAllTypeParameters(
overrideDeclaration: FirCallableMemberDeclaration<*>, overrideDeclaration: FirCallableMemberDeclaration<*>,
baseDeclarationSymbol: FirCallableSymbol<*>, baseDeclarationSymbol: FirCallableSymbol<*>,
@@ -117,32 +80,30 @@ object FirTypeMismatchOnOverrideChecker : FirMemberDeclarationChecker() {
?: return this ?: return this
val map = mutableMapOf<FirTypeParameterSymbol, ConeKotlinType>() val map = mutableMapOf<FirTypeParameterSymbol, ConeKotlinType>()
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() map[from.symbol] = to.toConeType()
} }
return substitutorByMap(map).substituteOrSelf(this) return substitutorByMap(map).substituteOrSelf(this)
} }
private fun ConeKotlinType.substituteOrSelf(substitutor: ConeSubstitutor) = substitutor.substituteOrSelf(this)
private fun FirCallableMemberDeclaration<*>.checkReturnType( private fun FirCallableMemberDeclaration<*>.checkReturnType(
regularClass: FirRegularClass,
overriddenSymbols: List<FirCallableSymbol<*>>, overriddenSymbols: List<FirCallableSymbol<*>>,
context: CheckerContext,
typeCheckerContext: AbstractTypeCheckerContext, typeCheckerContext: AbstractTypeCheckerContext,
): FirMemberDeclaration? { ): FirMemberDeclaration? {
val returnType = returnTypeRef.safeAs<FirResolvedTypeRef>()?.type val returnType = returnTypeRef.safeAs<FirResolvedTypeRef>()?.type
?: return null ?: return null
val bounds = overriddenSymbols.map { it.fir.returnTypeRef.coneType.upperBoundIfFlexible() } val bounds = overriddenSymbols.map { it.fir.returnTypeRef.coneType.upperBoundIfFlexible() }
val supertypesParameterSubstitutor = regularClass.substituteAllSupertypeParameters(context)
for (it in bounds.indices) { for (it in bounds.indices) {
val restriction = bounds[it] val restriction = bounds[it]
.substituteAllTypeParameters(this, overriddenSymbols[it]) .substituteAllTypeParameters(this, overriddenSymbols[it])
.substituteOrSelf(supertypesParameterSubstitutor)
if (!AbstractTypeChecker.isSubtypeOf(typeCheckerContext, returnType, restriction)) { if (!AbstractTypeChecker.isSubtypeOf(typeCheckerContext, returnType, restriction)) {
return overriddenSymbols[it].fir.safeAs() return overriddenSymbols[it].fir.safeAs()
@@ -153,9 +114,7 @@ object FirTypeMismatchOnOverrideChecker : FirMemberDeclarationChecker() {
} }
private fun checkFunction( private fun checkFunction(
regularClass: FirRegularClass,
function: FirSimpleFunction, function: FirSimpleFunction,
context: CheckerContext,
reporter: DiagnosticReporter, reporter: DiagnosticReporter,
typeCheckerContext: AbstractTypeCheckerContext, typeCheckerContext: AbstractTypeCheckerContext,
firTypeScope: FirTypeScope firTypeScope: FirTypeScope
@@ -171,9 +130,7 @@ object FirTypeMismatchOnOverrideChecker : FirMemberDeclarationChecker() {
} }
val restriction = function.checkReturnType( val restriction = function.checkReturnType(
regularClass = regularClass,
overriddenSymbols = overriddenFunctionSymbols, overriddenSymbols = overriddenFunctionSymbols,
context = context,
typeCheckerContext = typeCheckerContext typeCheckerContext = typeCheckerContext
) )
@@ -187,9 +144,7 @@ object FirTypeMismatchOnOverrideChecker : FirMemberDeclarationChecker() {
} }
private fun checkProperty( private fun checkProperty(
regularClass: FirRegularClass,
property: FirProperty, property: FirProperty,
context: CheckerContext,
reporter: DiagnosticReporter, reporter: DiagnosticReporter,
typeCheckerContext: AbstractTypeCheckerContext, typeCheckerContext: AbstractTypeCheckerContext,
firTypeScope: FirTypeScope firTypeScope: FirTypeScope
@@ -205,9 +160,7 @@ object FirTypeMismatchOnOverrideChecker : FirMemberDeclarationChecker() {
} }
val restriction = property.checkReturnType( val restriction = property.checkReturnType(
regularClass = regularClass,
overriddenSymbols = overriddenPropertySymbols, overriddenSymbols = overriddenPropertySymbols,
context = context,
typeCheckerContext = typeCheckerContext typeCheckerContext = typeCheckerContext
) )
@@ -8,13 +8,13 @@ package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirSourceElement import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext 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.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration
import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference 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.resolve.firSymbolProvider
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
@@ -22,6 +22,10 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
object FirSuperclassNotAccessibleFromInterfaceChecker : FirQualifiedAccessChecker() { object FirSuperclassNotAccessibleFromInterfaceChecker : FirQualifiedAccessChecker() {
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
expression.explicitReceiver.safeAs<FirQualifiedAccessExpression>()
?.calleeReference.safeAs<FirSuperReference>()
?: return
val closestClass = context.findClosest<FirRegularClass>() ?: return val closestClass = context.findClosest<FirRegularClass>() ?: return
if (closestClass.classKind == ClassKind.INTERFACE) { if (closestClass.classKind == ClassKind.INTERFACE) {
@@ -30,7 +34,7 @@ object FirSuperclassNotAccessibleFromInterfaceChecker : FirQualifiedAccessChecke
?.fir ?.fir
?: return ?: return
if (origin.source != null && origin.isSuperclassOf(closestClass)) { if (origin.source != null && origin.classKind == ClassKind.CLASS) {
reporter.report(expression.explicitReceiver?.source) reporter.report(expression.explicitReceiver?.source)
} }
} }
@@ -50,7 +50,8 @@ object FirTypeArgumentsNotAllowedExpressionChecker : FirQualifiedAccessChecker()
} }
private fun PsiElement.hasAnyArguments(): Boolean { 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<LighterASTNode>): Boolean { private fun LighterASTNode.hasAnyArguments(tree: FlyweightCapableTreeStructure<LighterASTNode>): Boolean {
@@ -35,13 +35,13 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
?.fir.safeAs<FirTypeParameterRefsOwner>() ?.fir.safeAs<FirTypeParameterRefsOwner>()
?: return ?: return
val typeCheckerContext = context.session.typeContext.newBaseTypeCheckerContext( val count = min(calleeFir.typeParameters.size, expression.typeArguments.size)
errorTypesEqualToAnything = false,
stubTypesEqualToAnything = false if (count == 0) {
) return
}
val parameterPairs = mutableMapOf<FirTypeParameterSymbol, FirResolvedTypeRef>() val parameterPairs = mutableMapOf<FirTypeParameterSymbol, FirResolvedTypeRef>()
val count = min(calleeFir.typeParameters.size, expression.typeArguments.size)
for (it in 0 until count) { for (it in 0 until count) {
expression.typeArguments[it].safeAs<FirTypeProjectionWithVariance>() expression.typeArguments[it].safeAs<FirTypeProjectionWithVariance>()
@@ -61,6 +61,11 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
parameterPairs.mapValues { it.value.type } parameterPairs.mapValues { it.value.type }
) )
val typeCheckerContext = context.session.typeContext.newBaseTypeCheckerContext(
errorTypesEqualToAnything = false,
stubTypesEqualToAnything = false
)
parameterPairs.forEach { (proto, actual) -> parameterPairs.forEach { (proto, actual) ->
if (actual.source == null) { if (actual.source == null) {
// inferred types don't report INAPPLICABLE_CANDIDATE for type aliases! // inferred types don't report INAPPLICABLE_CANDIDATE for type aliases!
@@ -122,9 +127,14 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
?.type.safeAs<ConeClassLikeType>() ?.type.safeAs<ConeClassLikeType>()
?: return ?: return
val constructorsParameterPairs = mutableMapOf<FirTypeParameterSymbol, ConeSimpleKotlinType>()
val count = min(protoConstructor.typeParameters.size, actualConstructor.typeArguments.size) val count = min(protoConstructor.typeParameters.size, actualConstructor.typeArguments.size)
if (count == 0) {
return
}
val constructorsParameterPairs = mutableMapOf<FirTypeParameterSymbol, ConeSimpleKotlinType>()
for (it in 0 until count) { for (it in 0 until count) {
actualConstructor.typeArguments[it].safeAs<ConeSimpleKotlinType>() actualConstructor.typeArguments[it].safeAs<ConeSimpleKotlinType>()
?.let { that -> ?.let { that ->
@@ -182,9 +192,14 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
?.fir.safeAs<FirRegularClass>() ?.fir.safeAs<FirRegularClass>()
?: return false ?: return false
val parameterPairs = mutableMapOf<FirTypeParameterSymbol, ConeClassLikeType>()
val count = min(prototypeClass.typeParameters.size, type.typeArguments.size) val count = min(prototypeClass.typeParameters.size, type.typeArguments.size)
if (count == 0) {
return false
}
val parameterPairs = mutableMapOf<FirTypeParameterSymbol, ConeClassLikeType>()
for (it in 0 until count) { for (it in 0 until count) {
type.typeArguments[it].safeAs<ConeClassLikeType>() type.typeArguments[it].safeAs<ConeClassLikeType>()
?.let { that -> ?.let { that ->