[FIR] Add TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER check

This commit is contained in:
Andrey Zinovyev
2021-04-12 13:40:27 +03:00
committed by TeamCityServer
parent 470993ac07
commit 03215f4e0a
19 changed files with 75 additions and 95 deletions
@@ -324,6 +324,8 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
val TYPE_PARAMETERS_NOT_ALLOWED by error<FirSourceElement, KtDeclaration>()
val TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER by error<FirSourceElement, KtTypeParameter>()
val RETURN_TYPE_MISMATCH by error<FirSourceElement, KtExpression>(PositioningStrategy.WHOLE_ELEMENT) {
parameter<ConeKotlinType>("expected")
parameter<ConeKotlinType>("actual")
@@ -238,6 +238,7 @@ object FirErrors {
val BOUND_ON_TYPE_ALIAS_PARAMETER_NOT_ALLOWED by error0<FirSourceElement, KtTypeReference>()
val REIFIED_TYPE_PARAMETER_NO_INLINE by error0<FirSourceElement, PsiElement>()
val TYPE_PARAMETERS_NOT_ALLOWED by error0<FirSourceElement, KtDeclaration>()
val TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER by error0<FirSourceElement, KtTypeParameter>()
val RETURN_TYPE_MISMATCH by error2<FirSourceElement, KtExpression, ConeKotlinType, ConeKotlinType>(SourceElementPositioningStrategies.WHOLE_ELEMENT)
// Reflection
@@ -0,0 +1,37 @@
/*
* 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.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.scopes.impl.toConeType
import org.jetbrains.kotlin.fir.types.*
object FirPropertyTypeParametersChecker : FirPropertyChecker() {
override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) {
val boundsByName = declaration.typeParameters.map { it.name to it.bounds }.toMap()
val usedTypes = HashSet<ConeKotlinType>()
fun collectAllTypes(type: ConeKotlinType) {
if (usedTypes.add(type)) {
type.typeArguments.forEach { it.type?.let(::collectAllTypes) }
if (type is ConeTypeParameterType) {
boundsByName[type.lookupTag.name]?.forEach { collectAllTypes(it.coneType) }
}
}
}
declaration.receiverTypeRef?.let { collectAllTypes(it.coneType) }
val usedNames = usedTypes.filterIsInstance<ConeTypeParameterType>().map { it.lookupTag.name }
declaration.typeParameters.filterNot { usedNames.contains(it.name) }.forEach { danglingParam ->
reporter.reportOn(danglingParam.source, FirErrors.TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER, context)
}
}
}
@@ -229,6 +229,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETERS_N
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_AS_REIFIED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_IN_CATCH_CLAUSE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_IS_NOT_AN_EXPRESSION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_ON_LHS_OF_DOT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNEXPECTED_SAFE_CALL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNINITIALIZED_ENUM_COMPANION
@@ -504,6 +505,8 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
map.put(TYPE_PARAMETERS_NOT_ALLOWED, "Type parameters are not allowed here")
map.put(TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER, "Type parameter of a property must be used in its receiver type")
map.put(RETURN_TYPE_MISMATCH, "Return type mismatch: expected {0}, actual {1}", RENDER_TYPE, RENDER_TYPE)
// Reflection
@@ -42,6 +42,8 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
FirDestructuringDeclarationChecker,
FirConstPropertyChecker,
FirPropertyAccessorChecker,
FirPropertyTypeParametersChecker,
FirPropertyAccessorChecker,
FirInitializerTypeMismatchChecker
)
+4 -4
View File
@@ -9,9 +9,9 @@ interface B {
}
interface G<X> {
val <X> boo: Double where X : A, X : B
val <A> bal: Double where A : B
val <Y> bas: Double where Y : B, <!NAME_IN_CONSTRAINT_IS_NOT_A_TYPE_PARAMETER!>X<!> : B
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>X<!>> boo: Double where X : A, X : B
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>A<!>> bal: Double where A : B
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>Y<!>> bas: Double where Y : B, <!NAME_IN_CONSTRAINT_IS_NOT_A_TYPE_PARAMETER!>X<!> : B
}
class C() : A(), B
@@ -66,4 +66,4 @@ val t1 = test2<A>(<!ARGUMENT_TYPE_MISMATCH!>A()<!>)
val t2 = test2<B>(<!ARGUMENT_TYPE_MISMATCH!>C()<!>)
val t3 = test2<C>(C())
val <T, B : T> x : Int = 0
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>T<!>, <!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>B : T<!>> x : Int = 0
@@ -1 +1 @@
<!MUST_BE_INITIALIZED!>val <T : <!UNRESOLVED_REFERENCE!>KClass<T>.something<!>> abc<!>
<!MUST_BE_INITIALIZED!>val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>T : <!UNRESOLVED_REFERENCE!>KClass<T>.something<!><!>> abc<!>
@@ -43,7 +43,7 @@ abstract class MyAbstractClass1 : MyTrait<Int>, MyAbstractClass<String>() {
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class MyIllegalGenericClass1<!><T> : MyTrait<T>, MyAbstractClass<T>() {}
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class MyIllegalGenericClass2<!><T, R>(r : R) : MyTrait<T>, MyAbstractClass<R>() {
override fun foo(r: R) = r
override val <T> pr : R = r
override val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>T<!>> pr : R = r
}
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class MyIllegalClass1<!> : MyTrait<Int>, MyAbstractClass<String>() {}
abstract class MyLegalAbstractClass1 : MyTrait<Int>, MyAbstractClass<String>() {}
@@ -51,10 +51,10 @@ abstract class MyLegalAbstractClass1 : MyTrait<Int>, MyAbstractClass<String>() {
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class MyIllegalClass2<!><T>(t : T) : MyTrait<Int>, MyAbstractClass<Int>() {
fun foo(t: T) = t
fun bar(t: T) = t
val <R> pr : T = t
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>R<!>> pr : T = t
}
abstract class MyLegalAbstractClass2<T>(t : T) : MyTrait<Int>, MyAbstractClass<Int>() {
fun foo(t: T) = t
fun bar(t: T) = t
val <R> pr : T = t
}
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>R<!>> pr : T = t
}
@@ -1,7 +0,0 @@
fun <T: <!UPPER_BOUND_IS_EXTENSION_FUNCTION_TYPE!>Int.() -> String<!>> foo() {}
val <T: <!UPPER_BOUND_IS_EXTENSION_FUNCTION_TYPE!>Int.() -> String<!>> bar = fun (x: Int): String { return x.toString() }
class A<T> where T : <!UPPER_BOUND_IS_EXTENSION_FUNCTION_TYPE!>Double.(Int) -> Unit<!>
interface B<T, U : <!UPPER_BOUND_IS_EXTENSION_FUNCTION_TYPE!>T.() -> Unit<!>>
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
fun <T: <!UPPER_BOUND_IS_EXTENSION_FUNCTION_TYPE!>Int.() -> String<!>> foo() {}
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>T: <!UPPER_BOUND_IS_EXTENSION_FUNCTION_TYPE!>Int.() -> String<!><!>> bar = fun (x: Int): String { return x.toString() }
@@ -1,7 +0,0 @@
fun <T: (Int) -> String> foo() {}
val <T: (kotlin.Int) -> kotlin.String> bar = fun (x: Int): String { return x.toString() }
class A<T, U, V> where T : () -> Unit, U : (Int) -> Double, V : (T, U) -> U
interface B<T, U : (T) -> Unit>
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
fun <T: (Int) -> String> foo() {}
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>T: (kotlin.Int) -> kotlin.String<!>> bar = fun (x: Int): String { return x.toString() }
@@ -1,44 +0,0 @@
// !DIAGNOSTICS: -REDUNDANT_PROJECTION -CONFLICTING_PROJECTION
interface G
val <T> T.a: Int
get() = 3
val <T1, T2> Map<T1, T2>.b: String
get() = "asds"
val <T : G> G.c: Int get() = 5
val <T1, T2, T3> List<Map<T2, T3>>.d: Int get() = 6
val <T: Any> G.e: T?
get() = null
val <T> List<Map<Int, Map<String, T>>>.f: Int get() = 7
val <T> List<Map<Int, Map<String, out T>>>.g: Int get() = 7
val <T> List<Map<Int, Map<String, in T>>>.h: Int get() = 7
val <T> List<Map<T, Map<T, T>>>.i: Int get() = 7
var <T1, T2, T3, T4> p = 1
class C<T1, T2> {
val <E> T1.a: Int get() = 3
val <E> T2.b: Int get() = 3
val <E> E.c: Int get() = 3
val <E> Map<T1, T2>.d: Int get() = 3
val <E> Map<T1, E>.e: Int get() = 3
}
val <T : Enum<T>> T.z1: Int
get() = 4
interface D<T : Enum<T>>
val <X: D<*>> X.z2: Int
get() = 4
val <Y> D<*>.z3: Int
get() = 4
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -REDUNDANT_PROJECTION -CONFLICTING_PROJECTION
interface G
@@ -1,28 +0,0 @@
val <T : K, K> K.a: Int get() = 4
val <T, K> K.b: Int where T : K
get() = 4
val <T, K> K.c: Int where T : List<K>
get() = 4
val <T, K> K.d: Int where K : T
get() = 4
val <T, K> K.e: Int where K : List<T>
get() = 4
interface G
val <T> G.x1: Int where T : G
get() = 4
val <X, Y, Z> Z.x2: Int where X : Y, Z : Y
get() = 4
val <X, Y: Map<Z, X>, Z: List<List<Y>>> Z.x3: Int
get() = 5
val <X, Y: Map<X, List<Z>>, Z> Map<X, List<Y>>.x4: Int
get() = 5
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>T : K<!>, K> K.a: Int get() = 4
@@ -1004,6 +1004,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER) { firDiagnostic ->
TypeParameterOfPropertyNotUsedInReceiverImpl(
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
}
add(FirErrors.RETURN_TYPE_MISMATCH) { firDiagnostic ->
ReturnTypeMismatchImpl(
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
@@ -713,6 +713,10 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = TypeParametersNotAllowed::class
}
abstract class TypeParameterOfPropertyNotUsedInReceiver : KtFirDiagnostic<KtTypeParameter>() {
override val diagnosticClass get() = TypeParameterOfPropertyNotUsedInReceiver::class
}
abstract class ReturnTypeMismatch : KtFirDiagnostic<KtExpression>() {
override val diagnosticClass get() = ReturnTypeMismatch::class
abstract val expected: KtType
@@ -1152,6 +1152,13 @@ internal class TypeParametersNotAllowedImpl(
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class TypeParameterOfPropertyNotUsedInReceiverImpl(
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,
) : KtFirDiagnostic.TypeParameterOfPropertyNotUsedInReceiver(), KtAbstractFirDiagnostic<KtTypeParameter> {
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class ReturnTypeMismatchImpl(
override val expected: KtType,
override val actual: KtType,