DiagnosticReporterByTrackingStrategy: refactor positioning

This commit is contained in:
Mikhail Glukhikh
2023-02-03 17:52:36 +01:00
committed by Space Team
parent 739e7d3a7a
commit 7a58c2e99f
5 changed files with 66 additions and 45 deletions
@@ -30,6 +30,6 @@ class ConeLambdaArgumentConstraintPosition(
class ConeBuilderInferenceSubstitutionConstraintPosition(initialConstraint: InitialConstraint) : class ConeBuilderInferenceSubstitutionConstraintPosition(initialConstraint: InitialConstraint) :
BuilderInferenceSubstitutionConstraintPosition<Nothing?, InitialConstraint>(null, initialConstraint) // TODO BuilderInferenceSubstitutionConstraintPosition<Nothing?>(null, initialConstraint) // TODO
class ConeReceiverConstraintPosition(receiver: FirExpression) : ReceiverConstraintPosition<FirExpression>(receiver) class ConeReceiverConstraintPosition(receiver: FirExpression) : ReceiverConstraintPosition<FirExpression>(receiver)
@@ -451,16 +451,16 @@ class DiagnosticReporterByTrackingStrategy(
val argument = val argument =
when (position) { when (position) {
is ArgumentConstraintPositionImpl -> position.argument is ArgumentConstraintPosition<*> -> position.argument as KotlinCallArgument
is ReceiverConstraintPositionImpl -> position.argument is ReceiverConstraintPosition<*> -> position.argument as KotlinCallArgument
is LambdaArgumentConstraintPositionImpl -> position.lambda.atom is LambdaArgumentConstraintPosition<*> -> (position.lambda as ResolvedLambdaAtom).atom
else -> null else -> null
} }
val isWarning = error is NewConstraintWarning val isWarning = error is NewConstraintWarning
val typeMismatchDiagnostic = if (isWarning) TYPE_MISMATCH_WARNING else TYPE_MISMATCH val typeMismatchDiagnostic = if (isWarning) TYPE_MISMATCH_WARNING else TYPE_MISMATCH
val report = if (isWarning) trace::reportDiagnosticOnce else trace::report val report = if (isWarning) trace::reportDiagnosticOnce else trace::report
argument?.let { if (argument != null) {
(it as? LambdaKotlinCallArgument)?.let lambda@{ lambda -> (argument as? LambdaKotlinCallArgument)?.let lambda@{ lambda ->
val parameterTypes = lambda.parametersTypes?.toList() ?: return@lambda val parameterTypes = lambda.parametersTypes?.toList() ?: return@lambda
val index = parameterTypes.indexOf(error.upperKotlinType.unwrap()) val index = parameterTypes.indexOf(error.upperKotlinType.unwrap())
val lambdaExpression = lambda.psiExpression as? KtLambdaExpression ?: return@lambda val lambdaExpression = lambda.psiExpression as? KtLambdaExpression ?: return@lambda
@@ -471,7 +471,7 @@ class DiagnosticReporterByTrackingStrategy(
return return
} }
val expression = it.psiExpression ?: return val expression = argument.psiExpression ?: return
val deparenthesized = KtPsiUtil.safeDeparenthesize(expression) val deparenthesized = KtPsiUtil.safeDeparenthesize(expression)
if (reportConstantTypeMismatch(error, deparenthesized)) return if (reportConstantTypeMismatch(error, deparenthesized)) return
@@ -485,46 +485,67 @@ class DiagnosticReporterByTrackingStrategy(
} }
} }
report(typeMismatchDiagnostic.on(deparenthesized, error.upperKotlinType, error.lowerKotlinType)) report(typeMismatchDiagnostic.on(deparenthesized, error.upperKotlinType, error.lowerKotlinType))
return
} }
(position as? ExpectedTypeConstraintPositionImpl)?.let { @Suppress("KotlinConstantConditions")
val call = it.topLevelCall.psiKotlinCall.psiCall.callElement as? KtExpression when (position) {
val inferredType = is BuilderInferenceExpectedTypeConstraintPosition -> {
if (!error.lowerKotlinType.isNullableNothing()) error.lowerKotlinType val inferredType =
else error.upperKotlinType.makeNullable() if (!error.lowerKotlinType.isNullableNothing()) error.lowerKotlinType
if (call != null) { else error.upperKotlinType.makeNullable()
report(typeMismatchDiagnostic.on(call, error.upperKotlinType, inferredType)) trace.report(TYPE_MISMATCH.on(position.topLevelCall, error.upperKotlinType, inferredType))
} }
} is ExpectedTypeConstraintPosition<*> -> {
val call = (position.topLevelCall as? KotlinCall)?.psiKotlinCall?.psiCall?.callElement as? KtExpression
(position as? BuilderInferenceExpectedTypeConstraintPosition)?.let { val inferredType =
val inferredType = if (!error.lowerKotlinType.isNullableNothing()) error.lowerKotlinType
if (!error.lowerKotlinType.isNullableNothing()) error.lowerKotlinType else error.upperKotlinType.makeNullable()
else error.upperKotlinType.makeNullable() if (call != null) {
trace.report(TYPE_MISMATCH.on(it.topLevelCall, error.upperKotlinType, inferredType)) report(typeMismatchDiagnostic.on(call, error.upperKotlinType, inferredType))
} }
(position as? BuilderInferenceSubstitutionConstraintPositionImpl)?.let {
reportConstraintErrorByPosition(error, it.initialConstraint.position)
}
(position as? ExplicitTypeParameterConstraintPositionImpl)?.let {
val typeArgumentReference = (it.typeArgument as SimpleTypeArgumentImpl).typeProjection.typeReference ?: return@let
val diagnosticFactory = if (isWarning) UPPER_BOUND_VIOLATED_WARNING else UPPER_BOUND_VIOLATED
report(diagnosticFactory.on(typeArgumentReference, error.upperKotlinType, error.lowerKotlinType))
}
(position as? FixVariableConstraintPositionImpl)?.let {
val morePreciseDiagnosticExists = allDiagnostics.any { other ->
val otherError = other.constraintSystemError ?: return@any false
otherError is NewConstraintError && otherError.position.from !is FixVariableConstraintPositionImpl
} }
if (morePreciseDiagnosticExists) return is BuilderInferenceSubstitutionConstraintPosition<*> -> {
reportConstraintErrorByPosition(error, position.initialConstraint.position)
}
is ExplicitTypeParameterConstraintPosition<*> -> {
val typeArgumentReference = (position.typeArgument as SimpleTypeArgumentImpl).typeProjection.typeReference ?: return
val diagnosticFactory = if (isWarning) UPPER_BOUND_VIOLATED_WARNING else UPPER_BOUND_VIOLATED
report(diagnosticFactory.on(typeArgumentReference, error.upperKotlinType, error.lowerKotlinType))
}
is FixVariableConstraintPosition<*> -> {
val morePreciseDiagnosticExists = allDiagnostics.any { other ->
val otherError = other.constraintSystemError ?: return@any false
otherError is NewConstraintError && otherError.position.from !is FixVariableConstraintPositionImpl
}
if (morePreciseDiagnosticExists) return
val call = (it.resolvedAtom?.atom as? PSIKotlinCall)?.psiCall ?: call val call = ((position.resolvedAtom as? ResolvedAtom)?.atom as? PSIKotlinCall)?.psiCall ?: call
val expression = call.calleeExpression ?: return val expression = call.calleeExpression ?: return
trace.reportDiagnosticOnce(typeMismatchDiagnostic.on(expression, error.upperKotlinType, error.lowerKotlinType)) trace.reportDiagnosticOnce(typeMismatchDiagnostic.on(expression, error.upperKotlinType, error.lowerKotlinType))
}
BuilderInferencePosition -> {
// some error reported later?
}
is CallableReferenceConstraintPosition<*> -> TODO()
is DeclaredUpperBoundConstraintPosition<*> -> TODO()
is DelegatedPropertyConstraintPosition<*> -> {
// DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE, reported later
}
is IncorporationConstraintPosition -> TODO()
is InjectedAnotherStubTypeConstraintPosition<*> -> TODO()
is KnownTypeParameterConstraintPosition<*> -> {
// UPPER_BOUND_VIOLATED, reported later?
}
is LHSArgumentConstraintPosition<*, *> -> TODO()
SimpleConstraintSystemConstraintPosition -> TODO()
// Never reachable
is ArgumentConstraintPosition<*>,
is LambdaArgumentConstraintPosition<*>,
is ReceiverConstraintPosition<*> -> {
throw AssertionError("Should not be here")
}
} }
} }
@@ -24,9 +24,9 @@ abstract class InjectedAnotherStubTypeConstraintPosition<T>(private val builderI
override fun toString(): String = "Injected from $builderInferenceLambdaOfInjectedStubType builder inference call" override fun toString(): String = "Injected from $builderInferenceLambdaOfInjectedStubType builder inference call"
} }
abstract class BuilderInferenceSubstitutionConstraintPosition<L, I>( abstract class BuilderInferenceSubstitutionConstraintPosition<L>(
private val builderInferenceLambda: L, private val builderInferenceLambda: L,
val initialConstraint: I, val initialConstraint: InitialConstraint,
val isFromNotSubstitutedDeclaredUpperBound: Boolean = false val isFromNotSubstitutedDeclaredUpperBound: Boolean = false
) : ConstraintPosition(), OnlyInputTypeConstraintPosition { ) : ConstraintPosition(), OnlyInputTypeConstraintPosition {
override fun toString(): String = "Incorporated builder inference constraint $initialConstraint " + override fun toString(): String = "Incorporated builder inference constraint $initialConstraint " +
@@ -458,7 +458,7 @@ class KotlinConstraintSystemCompleter(
val position = constraint.position.from.let { basicPosition -> val position = constraint.position.from.let { basicPosition ->
if (basicPosition is IncorporationConstraintPosition) basicPosition.from else basicPosition if (basicPosition is IncorporationConstraintPosition) basicPosition.from else basicPosition
} }
if (position is BuilderInferenceSubstitutionConstraintPosition<*, *> && position.isFromNotSubstitutedDeclaredUpperBound) { if (position is BuilderInferenceSubstitutionConstraintPosition<*> && position.isFromNotSubstitutedDeclaredUpperBound) {
upperBoundType = constraint.type upperBoundType = constraint.type
true true
} else { } else {
@@ -21,7 +21,7 @@ class BuilderInferenceSubstitutionConstraintPositionImpl(
builderInferenceLambda: LambdaKotlinCallArgument, builderInferenceLambda: LambdaKotlinCallArgument,
initialConstraint: InitialConstraint, initialConstraint: InitialConstraint,
isFromNotSubstitutedDeclaredUpperBound: Boolean = false isFromNotSubstitutedDeclaredUpperBound: Boolean = false
) : BuilderInferenceSubstitutionConstraintPosition<LambdaKotlinCallArgument, InitialConstraint>( ) : BuilderInferenceSubstitutionConstraintPosition<LambdaKotlinCallArgument>(
builderInferenceLambda, initialConstraint, isFromNotSubstitutedDeclaredUpperBound builderInferenceLambda, initialConstraint, isFromNotSubstitutedDeclaredUpperBound
) )