Merge pull request #64036 from xedin/rdar-106054263

[CSSimplify] Detect and diagnose generic argument mismatches individually
This commit is contained in:
Pavel Yaskevich
2023-03-06 10:18:09 -08:00
committed by GitHub
10 changed files with 163 additions and 20 deletions

View File

@@ -3748,15 +3748,23 @@ ConstraintSystem::matchDeepEqualityTypes(Type type1, Type type2,
// Match up the generic arguments, exactly.
if (shouldAttemptFixes()) {
auto *baseLoc =
getConstraintLocator(locator, {LocatorPathElt::GenericType(bound1),
LocatorPathElt::GenericType(bound2)});
auto argMatchingFlags =
subflags | TMF_ApplyingFix | TMF_MatchingGenericArguments;
// Optionals have a lot of special diagnostics and only one
// generic argument so if we' re dealing with one, don't produce generic
// arguments mismatch fixes.
if (bound1->getDecl()->isOptionalDecl())
return matchDeepTypeArguments(*this, subflags, args1, args2, locator);
return matchDeepTypeArguments(*this, argMatchingFlags, args1, args2,
baseLoc);
SmallVector<unsigned, 4> mismatches;
auto result = matchDeepTypeArguments(
*this, subflags | TMF_ApplyingFix, args1, args2, locator,
*this, argMatchingFlags, args1, args2, baseLoc,
[&mismatches](unsigned position) { mismatches.push_back(position); });
if (mismatches.empty())
@@ -4843,7 +4851,7 @@ static bool repairOutOfOrderArgumentsInBinaryFunction(
/// \return true if at least some of the failures has been repaired
/// successfully, which allows type matcher to continue.
bool ConstraintSystem::repairFailures(
Type lhs, Type rhs, ConstraintKind matchKind,
Type lhs, Type rhs, ConstraintKind matchKind, TypeMatchOptions flags,
SmallVectorImpl<RestrictionOrFix> &conversionsOrFixes,
ConstraintLocatorBuilder locator) {
SmallVector<LocatorPathElt, 4> path;
@@ -5344,7 +5352,7 @@ bool ConstraintSystem::repairFailures(
// let's re-attempt to repair without l-value conversion in the
// locator to fix underlying type mismatch.
if (path.back().is<LocatorPathElt::FunctionResult>()) {
return repairFailures(lhs, rhs, matchKind, conversionsOrFixes,
return repairFailures(lhs, rhs, matchKind, flags, conversionsOrFixes,
getConstraintLocator(anchor, path));
}
@@ -6133,7 +6141,7 @@ bool ConstraintSystem::repairFailures(
if (!path.empty() && path.back().is<LocatorPathElt::PackType>())
path.pop_back();
return repairFailures(lhs, rhs, matchKind, conversionsOrFixes,
return repairFailures(lhs, rhs, matchKind, flags, conversionsOrFixes,
getConstraintLocator(anchor, path));
}
@@ -6369,7 +6377,8 @@ bool ConstraintSystem::repairFailures(
// failure e.g. `String bind T.Element`, so let's drop the generic argument
// path element and recurse in repairFailures to check and potentially
// record the requirement failure fix.
path.pop_back();
auto genericArgElt =
path.pop_back_val().castTo<LocatorPathElt::GenericArgument>();
// If we have something like ... -> type req # -> pack element #, we're
// solving a requirement of the form T : P where T is a type parameter pack
@@ -6377,11 +6386,61 @@ bool ConstraintSystem::repairFailures(
path.pop_back();
if (!path.empty() && path.back().is<LocatorPathElt::AnyRequirement>()) {
return repairFailures(lhs, rhs, matchKind, conversionsOrFixes,
return repairFailures(lhs, rhs, matchKind, flags, conversionsOrFixes,
getConstraintLocator(anchor, path));
}
break;
// When the solver sets `TMF_MatchingGenericArguments` it means
// that it's matching generic argument pairs to identify any mismatches
// as part of larger matching of two generic types. Letting this
// fail results in a single fix that aggregates all mismatch locations.
//
// Types are not always resolved enough to enable that which means
// that the comparison should be delayed, which brings us here - a
// standalone constraint that represents such a match, in such cases
// we create a fix per mismatch location and coalesce them during
// diagnostics.
if (flags.contains(TMF_MatchingGenericArguments))
break;
Type fromType;
Type toType;
if (path.size() >= 2) {
if (path[path.size() - 2].is<LocatorPathElt::GenericType>()) {
fromType = path[path.size() - 2]
.castTo<LocatorPathElt::GenericType>()
.getType();
}
if (path[path.size() - 1].is<LocatorPathElt::GenericType>()) {
toType = path[path.size() - 1]
.castTo<LocatorPathElt::GenericType>()
.getType();
}
}
if (!fromType || !toType)
break;
// Drop both `GenericType` elements.
path.pop_back();
path.pop_back();
ConstraintFix *fix = nullptr;
if (!path.empty() && path.back().is<LocatorPathElt::AnyRequirement>()) {
fix = fixRequirementFailure(*this, fromType, toType, anchor, path);
} else {
fix = GenericArgumentsMismatch::create(
*this, fromType, toType, {genericArgElt.getIndex()},
getConstraintLocator(anchor, path));
}
if (!fix)
break;
conversionsOrFixes.push_back(fix);
return true;
}
case ConstraintLocator::ResultBuilderBodyResult: {
@@ -7478,7 +7537,8 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
// Attempt fixes iff it's allowed, both types are concrete and
// we are not in the middle of attempting one already.
if (shouldAttemptFixes() && !flags.contains(TMF_ApplyingFix)) {
if (repairFailures(type1, type2, kind, conversionsOrFixes, locator)) {
if (repairFailures(type1, type2, kind, flags, conversionsOrFixes,
locator)) {
if (conversionsOrFixes.empty())
return getTypeMatchSuccess();
}
@@ -14038,7 +14098,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
case FixKind::MustBeCopyable:
case FixKind::AllowInvalidPackElement:
case FixKind::MacroMissingPound:
case FixKind::AllowGlobalActorMismatch: {
case FixKind::AllowGlobalActorMismatch:
case FixKind::GenericArgumentsMismatch: {
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
}
case FixKind::IgnoreInvalidASTNode: {
@@ -14258,7 +14319,6 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
case FixKind::TreatKeyPathSubscriptIndexAsHashable:
case FixKind::AllowInvalidRefInKeyPath:
case FixKind::DefaultGenericArgument:
case FixKind::GenericArgumentsMismatch:
case FixKind::AllowMutatingMemberOnRValueBase:
case FixKind::AllowTupleSplatForSingleParameter:
case FixKind::AllowNonClassTypeToConvertToAnyObject: