[Diagnostics] Improve diagnostics related to pointer initialization

- Increase impact of a generic pointer-to-pointer mismatch fix to
  match that of a contextual type failure. This allows more specific
  fixes to take precedence.

- De-prioritize generic argument mismatch fix when both types are
  pointers. This allows pointer-to-pointer conversion produce a
  more specific fix.

- De-prioritize fixes that involve `Builtin.RawPointer` or `OpaquePointer`
  in parameter positions. This helps to produce better diagnostics
  for argument mismatches during pointer initialization e.g.
  `UnsafeRawPointer(<pointer>)`.
This commit is contained in:
Pavel Yaskevich
2021-08-20 15:40:45 -07:00
parent 5f268cceab
commit beb23718f8
3 changed files with 48 additions and 23 deletions

View File

@@ -2714,14 +2714,25 @@ ConstraintSystem::matchDeepEqualityTypes(Type type1, Type type2,
}
}
unsigned impact = 1;
if (type1->getAnyPointerElementType() &&
type2->getAnyPointerElementType()) {
// If this is a pointer <-> pointer conversion of different kind,
// there is a dedicated restriction/fix for that in some cases.
// To accommodate that, let's increase the impact of this fix.
impact += 2;
} else {
// Increase the solution's score for each mismtach this fixes.
impact += mismatches.size() - 1;
}
auto *fix = GenericArgumentsMismatch::create(
*this, type1, type2, mismatches, getConstraintLocator(locator));
if (!recordFix(fix)) {
// Increase the solution's score for each mismtach this fixes.
increaseScore(SK_Fix, mismatches.size() - 1);
if (!recordFix(fix, impact))
return getTypeMatchSuccess();
}
return result;
}
return matchDeepTypeArguments(*this, subflags, args1, args2, locator);
@@ -10744,12 +10755,13 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
auto *fix = GenericArgumentsMismatch::create(*this, ptr1, ptr2, {0},
getConstraintLocator(locator));
// Treat this as a contextual type mismatch.
unsigned baseImpact = 2;
// It's possible to implicitly promote pointer into an optional
// before matching base types if other side is an optional, so
// score needs to account for number of such promotions.
int optionalWraps = baseType2.getInt() - baseType1.getInt();
return recordFix(fix,
/*impact=*/1 + abs(optionalWraps))
return recordFix(fix, baseImpact + abs(optionalWraps))
? SolutionKind::Error
: SolutionKind::Solved;
};
@@ -11553,6 +11565,23 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
}
}
// De-prioritize `Builtin.RawPointer` and `OpaquePointer` parameters
// because they usually clash with generic parameter mismatches e.g.
//
// let ptr: UnsafePointer<String> = ...
// _ = UnsafePointer<Int>(ups)
//
// Here initializer overloads have both `Builtin.RawPointer` and
// `OpaquePointer` variants, but the actual issue is that generic argument
// `String` doesn't match `Int`.
{
if (type2->is<BuiltinRawPointerType>())
impact += 1;
if (type2->getAnyNominal() == getASTContext().getOpaquePointerDecl())
impact += 1;
}
return recordFix(fix, impact) ? SolutionKind::Error : SolutionKind::Solved;
}