Improve type parameter bound diagnostic location
If there's only one erroneous bound (vast majority of cases), report it on the bound; otherwise (to avoid reporting it several times) report on the type parameter declaration
This commit is contained in:
@@ -265,7 +265,7 @@ public interface Errors {
|
||||
DiagnosticFactory0<KtTypeReference> DYNAMIC_UPPER_BOUND = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtTypeReference> UPPER_BOUND_IS_EXTENSION_FUNCTION_TYPE = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtTypeReference> ONLY_ONE_CLASS_BOUND_ALLOWED = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtTypeParameter> BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtElement> BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtTypeReference> REPEATED_BOUND = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
DiagnosticFactory1<KtNamedDeclaration, TypeParameterDescriptor> CONFLICTING_UPPER_BOUNDS =
|
||||
|
||||
@@ -179,14 +179,38 @@ class DeclarationsChecker(
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkOnlyOneTypeParameterBound(descriptor: TypeParameterDescriptor, declaration: KtTypeParameter) {
|
||||
private fun checkOnlyOneTypeParameterBound(
|
||||
descriptor: TypeParameterDescriptor, declaration: KtTypeParameter, owner: KtTypeParameterListOwner
|
||||
) {
|
||||
val upperBounds = descriptor.upperBounds
|
||||
val (boundsWhichAreTypeParameters, otherBounds) = upperBounds
|
||||
.map { type -> type.constructor }
|
||||
.partition { constructor -> constructor.declarationDescriptor is TypeParameterDescriptor }
|
||||
.let { pair -> pair.first.toSet() to pair.second.toSet() }
|
||||
if (boundsWhichAreTypeParameters.size > 1 || (boundsWhichAreTypeParameters.isNotEmpty() && otherBounds.isNotEmpty())) {
|
||||
trace.report(BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER.on(declaration))
|
||||
if (boundsWhichAreTypeParameters.size > 1 || (boundsWhichAreTypeParameters.size == 1 && otherBounds.isNotEmpty())) {
|
||||
val reportOn = if (boundsWhichAreTypeParameters.size + otherBounds.size == 2) {
|
||||
// If there's only one problematic bound (either 2 type parameter bounds, or 1 type parameter bound + 1 other bound),
|
||||
// report the diagnostic on that bound
|
||||
|
||||
val allBounds: List<Pair<KtTypeReference, KotlinType?>> =
|
||||
owner.typeConstraints
|
||||
.filter { constraint ->
|
||||
constraint.subjectTypeParameterName?.getReferencedNameAsName() == declaration.nameAsName
|
||||
}
|
||||
.mapNotNull { constraint -> constraint.boundTypeReference }
|
||||
.map { typeReference -> typeReference to trace.bindingContext.get(TYPE, typeReference) }
|
||||
|
||||
val problematicBound =
|
||||
allBounds.firstOrNull { bound -> bound.second?.constructor != boundsWhichAreTypeParameters.first() }
|
||||
|
||||
problematicBound?.first ?: declaration
|
||||
}
|
||||
else {
|
||||
// Otherwise report the diagnostic on the type parameter declaration
|
||||
declaration
|
||||
}
|
||||
|
||||
trace.report(BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER.on(reportOn))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,7 +373,7 @@ class DeclarationsChecker(
|
||||
}
|
||||
val typeParameterDescriptor = trace.get(TYPE_PARAMETER, typeParameter) ?: continue
|
||||
checkSupertypesForConsistency(typeParameterDescriptor, typeParameter)
|
||||
checkOnlyOneTypeParameterBound(typeParameterDescriptor, typeParameter)
|
||||
checkOnlyOneTypeParameterBound(typeParameterDescriptor, typeParameter, typeParameterListOwner)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -3,9 +3,10 @@ interface I2
|
||||
open class C
|
||||
|
||||
interface A1<K, V> where V : K, V : <!REPEATED_BOUND!>K<!>
|
||||
interface A2<K, V, <!BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER!>W<!>> where W : K, W : V
|
||||
interface A2<K, V, W> where W : K, W : <!BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER!>V<!>
|
||||
interface A3<K, <!BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER!>V<!>> where V : I1, V : K, V : I2
|
||||
interface A4<<!BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER!>K<!>, V> where K : I1, K : I2, K : C, K : V, V : I2, V : I1
|
||||
|
||||
fun <K, V> f1() where V : K, V : <!REPEATED_BOUND!>K<!> {}
|
||||
fun <K, V, <!BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER!>W<!>> f2() where W : K, W : V {}
|
||||
fun <K, V, W> f2() where W : K, W : <!BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER!>V<!> {}
|
||||
fun <K, V, <!BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER!>W<!>> f3() where W : K, W : V, W : Any {}
|
||||
|
||||
+1
@@ -2,6 +2,7 @@ package
|
||||
|
||||
public fun </*0*/ K, /*1*/ V : K> f1(): kotlin.Unit where V : K
|
||||
public fun </*0*/ K, /*1*/ V, /*2*/ W : K> f2(): kotlin.Unit where W : V
|
||||
public fun </*0*/ K, /*1*/ V, /*2*/ W : K> f3(): kotlin.Unit where W : V, W : kotlin.Any
|
||||
|
||||
public interface A1</*0*/ K, /*1*/ V : K> where V : K {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
|
||||
Reference in New Issue
Block a user