From 28a6928873a2fe000f0fecd55f7795fc6b3ebad6 Mon Sep 17 00:00:00 2001 From: Ivan Kochurkin Date: Tue, 6 Jul 2021 01:24:53 +0300 Subject: [PATCH] [FIR] Check rest OUTER_CLASS_ARGUMENTS_REQUIRED diagnostics on checkers stage Add FirOuterClassArgumentsRequiredChecker --- .../checkers/CommonDeclarationCheckers.kt | 1 + .../FirOuterClassArgumentsRequiredChecker.kt | 109 ++++++++++++++++++ .../implicitArguments/inStaticScope.fir.kt | 7 -- .../implicitArguments/inStaticScope.kt | 3 + .../implicitArguments/inStaticScope.txt | 8 ++ 5 files changed, 121 insertions(+), 7 deletions(-) create mode 100644 compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirOuterClassArgumentsRequiredChecker.kt delete mode 100644 compiler/testData/diagnostics/tests/generics/innerClasses/implicitArguments/inStaticScope.fir.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 21fa5255e5b..133bfab4f7a 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 @@ -88,6 +88,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() { FirFunInterfaceDeclarationChecker, FirNestedClassChecker, FirInlineClassDeclarationChecker, + FirOuterClassArgumentsRequiredChecker ) override val constructorCheckers: Set diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirOuterClassArgumentsRequiredChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirOuterClassArgumentsRequiredChecker.kt new file mode 100644 index 00000000000..c6475e64af2 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirOuterClassArgumentsRequiredChecker.kt @@ -0,0 +1,109 @@ +/* + * 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.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.context.findClosest +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.FirRegularClass +import org.jetbrains.kotlin.fir.declarations.FirTypeParameterRef +import org.jetbrains.kotlin.fir.declarations.FirTypedDeclaration +import org.jetbrains.kotlin.fir.resolve.getClassThatContainsTypeParameter +import org.jetbrains.kotlin.fir.resolve.isValidTypeParameter +import org.jetbrains.kotlin.fir.resolve.toSymbol +import org.jetbrains.kotlin.fir.resolve.toTypeProjections +import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol +import org.jetbrains.kotlin.fir.types.* + +object FirOuterClassArgumentsRequiredChecker : FirRegularClassChecker() { + override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) { + for (superTypeRef in declaration.superTypeRefs) { + checkOuterClassArgumentsRequired(superTypeRef, declaration, context, reporter) + } + + for (subDecl in declaration.declarations) { + if (subDecl is FirTypedDeclaration) { + checkOuterClassArgumentsRequired(subDecl.returnTypeRef, declaration, context, reporter) + } + } + } +} + +private fun checkOuterClassArgumentsRequired( + typeRef: FirTypeRef, + declaration: FirRegularClass?, + context: CheckerContext, + reporter: DiagnosticReporter +) { + val type: ConeKotlinType + + if (typeRef is FirResolvedTypeRef) { + if (typeRef is FirErrorTypeRef) { + return + } + + type = typeRef.type + val delegatedTypeRef = typeRef.delegatedTypeRef + + if (delegatedTypeRef is FirUserTypeRef) { + + if (type is ConeClassLikeType) { + val symbol = type.lookupTag.toSymbol(context.session) + + if (symbol is FirRegularClassSymbol) { + var problemTypeParameter: FirTypeParameterRef? = null + val typeArguments = delegatedTypeRef.qualifier.toTypeProjections() + val argumentsFromOuterClassesAndParentsCount = symbol.fir.typeParameters.drop(typeArguments.size).sumOf { + val result = if (isValidTypeParameter(it, declaration, context.session)) { + 1 + } else { + if (problemTypeParameter == null) { + problemTypeParameter = it + } + 0 + } + return@sumOf result + } + val finalTypeArgumentsCount = typeArguments.size + argumentsFromOuterClassesAndParentsCount + + if (finalTypeArgumentsCount != symbol.fir.typeParameters.size) { + val source = typeRef.source + if (problemTypeParameter != null) { + var outerClass: FirRegularClass? = null + context.findClosest { + outerClass = getClassThatContainsTypeParameter(it, problemTypeParameter!!) + return@findClosest outerClass != null + } + if (outerClass != null) { + reporter.reportOn(source, FirErrors.OUTER_CLASS_ARGUMENTS_REQUIRED, outerClass!!, context) + } + } else { + reporter.reportOn( + source, + FirErrors.WRONG_NUMBER_OF_TYPE_ARGUMENTS, + symbol.fir.typeParameters.size - argumentsFromOuterClassesAndParentsCount, + symbol, + context + ) + } + } + } + } + } + } else if (typeRef is ConeKotlinType) { + type = typeRef + } else { + return + } + + for (index in type.typeArguments.indices) { + val firTypeRefSource = extractArgumentTypeRefAndSource(typeRef, index) ?: continue + firTypeRefSource.typeRef?.let { checkOuterClassArgumentsRequired(it, declaration, context, reporter) } + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/generics/innerClasses/implicitArguments/inStaticScope.fir.kt b/compiler/testData/diagnostics/tests/generics/innerClasses/implicitArguments/inStaticScope.fir.kt deleted file mode 100644 index 44a567abaa0..00000000000 --- a/compiler/testData/diagnostics/tests/generics/innerClasses/implicitArguments/inStaticScope.fir.kt +++ /dev/null @@ -1,7 +0,0 @@ -interface Inv -class Outer { - inner class Inner - - class Nested : Inv - object Obj : Inv -} diff --git a/compiler/testData/diagnostics/tests/generics/innerClasses/implicitArguments/inStaticScope.kt b/compiler/testData/diagnostics/tests/generics/innerClasses/implicitArguments/inStaticScope.kt index a377312ddb7..f2f0b2fe8e3 100644 --- a/compiler/testData/diagnostics/tests/generics/innerClasses/implicitArguments/inStaticScope.kt +++ b/compiler/testData/diagnostics/tests/generics/innerClasses/implicitArguments/inStaticScope.kt @@ -1,7 +1,10 @@ +// FIR_IDENTICAL interface Inv class Outer { inner class Inner class Nested : Inv<Inner> + inner class Inner2 : Inv // no error object Obj : Inv<Inner> } + diff --git a/compiler/testData/diagnostics/tests/generics/innerClasses/implicitArguments/inStaticScope.txt b/compiler/testData/diagnostics/tests/generics/innerClasses/implicitArguments/inStaticScope.txt index 7c8c334c59f..985bd6e49f7 100644 --- a/compiler/testData/diagnostics/tests/generics/innerClasses/implicitArguments/inStaticScope.txt +++ b/compiler/testData/diagnostics/tests/generics/innerClasses/implicitArguments/inStaticScope.txt @@ -19,6 +19,13 @@ public final class Outer { public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } + public final inner class Inner2 /*captured type parameters: /*0*/ E*/ : Inv.Inner> { + public constructor Inner2() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + public final class Nested : Inv<[ERROR : Inner]> { public constructor Nested() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean @@ -33,3 +40,4 @@ public final class Outer { public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } } +