[CS] Better propagate holes from contextual types

Eagerly bind invalid type references to holes and propagate contextual
type holes in `repairFailures`. This avoids some unnecessary diagnostics
in cases where we have an invalid contextual type.
This commit is contained in:
Hamish Knight
2025-08-29 15:04:20 +01:00
parent b4fe5df669
commit 1b0eed22be
4 changed files with 63 additions and 5 deletions

View File

@@ -5569,6 +5569,17 @@ bool ConstraintSystem::repairFailures(
return true;
};
// Propagate a hole from one type to another. This is useful for contextual
// types since type resolution forms a top-level ErrorType for types with
// nested errors, e.g `S<@error_type>` becomes `@error_type`. As such, when
// matching `S<$T0> == $T1` where `$T1` is a hole from a contextual type, we
// want to eagerly turn `$T0` into a hole since it's likely that `$T1` would
// have provided the contextual info for it.
auto tryPropagateHole = [&](Type from, Type to) {
if (from->isPlaceholder() && to->hasTypeVariable())
recordTypeVariablesAsHoles(to);
};
if (path.empty()) {
if (!anchor)
return false;
@@ -6342,6 +6353,13 @@ bool ConstraintSystem::repairFailures(
case ConstraintLocator::ClosureBody:
case ConstraintLocator::ClosureResult: {
// If either type is a placeholder, consider this fixed, eagerly propagating
// a hole from the contextual type.
if (lhs->isPlaceholder() || rhs->isPlaceholder()) {
tryPropagateHole(rhs, lhs);
return true;
}
if (repairByInsertingExplicitCall(lhs, rhs))
break;
@@ -6361,9 +6379,12 @@ bool ConstraintSystem::repairFailures(
}
case ConstraintLocator::ContextualType: {
// If either type is a placeholder, consider this fixed
if (lhs->isPlaceholder() || rhs->isPlaceholder())
// If either type is a placeholder, consider this fixed, eagerly propagating
// a hole from the contextual type.
if (lhs->isPlaceholder() || rhs->isPlaceholder()) {
tryPropagateHole(rhs, lhs);
return true;
}
// If either side is not yet resolved, it's too early for this fix.
if (lhs->isTypeVariableOrMember() || rhs->isTypeVariableOrMember())
@@ -7002,6 +7023,13 @@ bool ConstraintSystem::repairFailures(
}
case ConstraintLocator::CoercionOperand: {
// If either type is a placeholder, consider this fixed, eagerly propagating
// a hole from the contextual type.
if (lhs->isPlaceholder() || rhs->isPlaceholder()) {
tryPropagateHole(rhs, lhs);
return true;
}
auto *coercion = castToExpr<CoerceExpr>(anchor);
// Coercion from T.Type to T.Protocol.