[FIR] Add MISPLACED_TYPE_PARAMETER_CONSTRAINTS check

This commit is contained in:
Andrey Zinovyev
2021-04-12 19:59:26 +03:00
committed by TeamCityServer
parent 412b941486
commit 0d525bbe85
13 changed files with 45 additions and 43 deletions
@@ -334,6 +334,8 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
val CYCLIC_GENERIC_UPPER_BOUND by error<FirSourceElement, PsiElement>()
val DEPRECATED_TYPE_PARAMETER_SYNTAX by error<FirSourceElement, KtTypeParameterList>()
val MISPLACED_TYPE_PARAMETER_CONSTRAINTS by warning<FirSourceElement, KtTypeParameter>()
}
val REFLECTION by object : DiagnosticGroup("Reflection") {
@@ -242,6 +242,7 @@ object FirErrors {
val RETURN_TYPE_MISMATCH by error2<FirSourceElement, KtExpression, ConeKotlinType, ConeKotlinType>(SourceElementPositioningStrategies.WHOLE_ELEMENT)
val CYCLIC_GENERIC_UPPER_BOUND by error0<FirSourceElement, PsiElement>()
val DEPRECATED_TYPE_PARAMETER_SYNTAX by error0<FirSourceElement, KtTypeParameterList>()
val MISPLACED_TYPE_PARAMETER_CONSTRAINTS by warning0<FirSourceElement, KtTypeParameter>()
// Reflection
val EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED by error1<FirSourceElement, KtExpression, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
@@ -42,6 +42,7 @@ object FirTypeParameterBoundsChecker : FirTypeParameterChecker() {
checkBoundUniqueness(declaration, context, reporter)
checkConflictingBounds(declaration, context, reporter)
checkTypeAliasBound(declaration, containingDeclaration, context, reporter)
checkBoundsPlacement(declaration, context, reporter)
}
private fun checkFinalUpperBounds(
@@ -147,6 +148,15 @@ object FirTypeParameterBoundsChecker : FirTypeParameterChecker() {
}
}
private fun checkBoundsPlacement(declaration: FirTypeParameter, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.bounds.size < 2) return
val (constraint, params) = declaration.bounds.partition { it.isInTypeConstraint() }
if (params.isNotEmpty() && constraint.isNotEmpty()) {
reporter.reportOn(declaration.source, FirErrors.MISPLACED_TYPE_PARAMETER_CONSTRAINTS, context)
}
}
private fun KotlinTypeMarker.isRelated(context: TypeCheckerProviderContext, type: KotlinTypeMarker?): Boolean =
isSubtypeOf(context, type) || isSupertypeOf(context, type)
@@ -140,6 +140,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MANY_COMPANION_OB
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MISPLACED_TYPE_PARAMETER_CONSTRAINTS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MISSING_VAL_ON_ANNOTATION_PARAMETER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MULTIPLE_VARARG_PARAMETERS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MUST_BE_INITIALIZED
@@ -515,6 +516,11 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
map.put(DEPRECATED_TYPE_PARAMETER_SYNTAX, "Type parameters must be placed before the name of the function")
map.put(
MISPLACED_TYPE_PARAMETER_CONSTRAINTS,
"If a type parameter has multiple constraints, they all need to be placed in the 'where' clause"
)
// Reflection
map.put(
EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED,
@@ -1,23 +0,0 @@
// See KT-9438: Enforce the Single Instantiation Inheritance Rule for type parameters
interface A
interface B
interface D<T>
interface IncorrectF<T : D<A>> where T : <!REPEATED_BOUND!>D<B><!>
interface CorrectF<T> where T : D<A>, T : <!REPEATED_BOUND!>D<B><!>
interface G<T>
interface IncorrectH<T : G<D<A>>> where T : <!REPEATED_BOUND!>G<D<T>><!>
interface CorrectH<T> where T : G<D<A>>, T : <!REPEATED_BOUND!>G<D<B>><!>
interface incorrectJ<T: G<D<T>>> where T : <!REPEATED_BOUND!>G<D<T?>><!>
interface correctJ<T> where T : G<D<T>>, T : <!REPEATED_BOUND!>G<D<T?>><!>
fun <T> bar() where T : D<A>, T : <!REPEATED_BOUND!>D<B><!> {}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// See KT-9438: Enforce the Single Instantiation Inheritance Rule for type parameters
interface A
@@ -1,19 +1,19 @@
class A
interface I0<T : <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>A<Int><!>>
interface I1<T> where T : <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>A<Int><!>
interface I2<T : <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>A<Int><!>> where T : <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>A<Int><!>
interface I2<<!MISPLACED_TYPE_PARAMETER_CONSTRAINTS!>T : <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>A<Int><!><!>> where T : <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>A<Int><!>
fun <E : <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>A<Int><!>> foo0() {}
fun <E> foo1() where E : <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>A<Int><!> {}
fun <E : <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>A<Int><!>> foo2() where E : <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>A<Int><!> {}
fun <<!MISPLACED_TYPE_PARAMETER_CONSTRAINTS!>E : <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>A<Int><!><!>> foo2() where E : <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>A<Int><!> {}
val <E : <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>A<Int><!>> E.p1: Int
get() = 1
val <E> E.p2: Int where E : <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>A<Int><!>
get() = 1
val <E : <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>A<Int><!>> E.p3: Int where E : <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>A<Int><!>
val <<!MISPLACED_TYPE_PARAMETER_CONSTRAINTS!>E : <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>A<Int><!><!>> E.p3: Int where E : <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>A<Int><!>
get() = 1
// See KT-8200
interface X
public class EnumAttribute<T : <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>X<T><!>>(val klass: Class<T>) where T : Enum<T>
public class EnumAttribute<<!MISPLACED_TYPE_PARAMETER_CONSTRAINTS!>T : <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>X<T><!><!>>(val klass: Class<T>) where T : Enum<T>
@@ -1,14 +1,14 @@
interface I0<T : <!UNRESOLVED_REFERENCE!>Unresolved0<String><!>>
interface I1<T> where T : <!UNRESOLVED_REFERENCE!>Unresolved1<String><!>
interface I2<T : <!UNRESOLVED_REFERENCE!>Unresolved2<String><!>> where T : <!UNRESOLVED_REFERENCE!>Unresolved3<String><!>
interface I2<<!MISPLACED_TYPE_PARAMETER_CONSTRAINTS!>T : <!UNRESOLVED_REFERENCE!>Unresolved2<String><!><!>> where T : <!UNRESOLVED_REFERENCE!>Unresolved3<String><!>
fun <E : <!UNRESOLVED_REFERENCE!>Unresolved4<String><!>> foo0() {}
fun <E> foo1() where E : <!UNRESOLVED_REFERENCE!>Unresolved5<String><!> {}
fun <E : <!UNRESOLVED_REFERENCE!>Unresolved6<String><!>> foo2() where E : <!UNRESOLVED_REFERENCE!>Unresolved7<String><!> {}
fun <<!MISPLACED_TYPE_PARAMETER_CONSTRAINTS!>E : <!UNRESOLVED_REFERENCE!>Unresolved6<String><!><!>> foo2() where E : <!UNRESOLVED_REFERENCE!>Unresolved7<String><!> {}
val <E : <!UNRESOLVED_REFERENCE!>Unresolved7<!>> E.p1: Int
get() = 1
val <E> E.p2: Int where E : <!UNRESOLVED_REFERENCE!>Unresolved8<!>
get() = 1
val <E : <!UNRESOLVED_REFERENCE!>Unresolved9<!>> E.p3: Int where E : <!UNRESOLVED_REFERENCE!>Unresolved10<!>
val <<!MISPLACED_TYPE_PARAMETER_CONSTRAINTS!>E : <!UNRESOLVED_REFERENCE!>Unresolved9<!><!>> E.p3: Int where E : <!UNRESOLVED_REFERENCE!>Unresolved10<!>
get() = 1
@@ -1,13 +0,0 @@
class Foo<T : Cloneable> where T : Comparable<T> {
fun <U : Cloneable> foo(u: U): U where U: Comparable<U> {
fun <<!BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER!>T: Any<!>> bar() where T: U {}
return u
}
val <U : Cloneable> U.foo: U? where U: Comparable<U>
get() { return null }
}
class Bar<T : Cloneable, U> where U: Comparable<T> {
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
class Foo<<!MISPLACED_TYPE_PARAMETER_CONSTRAINTS!>T : Cloneable<!>> where T : Comparable<T> {
fun <<!MISPLACED_TYPE_PARAMETER_CONSTRAINTS!>U : Cloneable<!>> foo(u: U): U where U: Comparable<U> {
fun <<!BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER, MISPLACED_TYPE_PARAMETER_CONSTRAINTS!>T: Any<!>> bar() where T: U {}
@@ -1030,6 +1030,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.MISPLACED_TYPE_PARAMETER_CONSTRAINTS) { firDiagnostic ->
MisplacedTypeParameterConstraintsImpl(
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
}
add(FirErrors.EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED) { firDiagnostic ->
ExtensionInClassReferenceNotAllowedImpl(
firSymbolBuilder.callableBuilder.buildCallableSymbol(firDiagnostic.a as FirCallableDeclaration),
@@ -731,6 +731,10 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = DeprecatedTypeParameterSyntax::class
}
abstract class MisplacedTypeParameterConstraints : KtFirDiagnostic<KtTypeParameter>() {
override val diagnosticClass get() = MisplacedTypeParameterConstraints::class
}
abstract class ExtensionInClassReferenceNotAllowed : KtFirDiagnostic<KtExpression>() {
override val diagnosticClass get() = ExtensionInClassReferenceNotAllowed::class
abstract val referencedDeclaration: KtCallableSymbol
@@ -1182,6 +1182,13 @@ internal class DeprecatedTypeParameterSyntaxImpl(
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class MisplacedTypeParameterConstraintsImpl(
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,
) : KtFirDiagnostic.MisplacedTypeParameterConstraints(), KtAbstractFirDiagnostic<KtTypeParameter> {
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class ExtensionInClassReferenceNotAllowedImpl(
override val referencedDeclaration: KtCallableSymbol,
firDiagnostic: FirPsiDiagnostic<*>,