Merge pull request #26577 from xedin/improve-force-downcast-diags

[Diagnostics] Make force downcast fix contextual and move it to `repa…
This commit is contained in:
Pavel Yaskevich
2019-08-09 09:19:10 -07:00
committed by GitHub
9 changed files with 136 additions and 95 deletions

View File

@@ -2186,6 +2186,58 @@ static ConstraintFix *fixPropertyWrapperFailure(
return nullptr;
}
static bool canBridgeThroughCast(ConstraintSystem &cs, Type fromType,
Type toType) {
// If we have a value of type AnyObject that we're trying to convert to
// a class, force a downcast.
// FIXME: Also allow types bridged through Objective-C classes.
if (fromType->isAnyObject() && toType->getClassOrBoundGenericClass())
return true;
auto &TC = cs.getTypeChecker();
auto bridged = TC.getDynamicBridgedThroughObjCClass(cs.DC, fromType, toType);
if (!bridged)
return false;
// Note: don't perform this recovery for NSNumber;
if (auto classType = bridged->getAs<ClassType>()) {
SmallString<16> scratch;
if (classType->getDecl()->isObjC() &&
classType->getDecl()->getObjCRuntimeName(scratch) == "NSNumber")
return false;
}
return true;
}
static bool
repairViaBridgingCast(ConstraintSystem &cs, Type fromType, Type toType,
SmallVectorImpl<RestrictionOrFix> &conversionsOrFixes,
ConstraintLocatorBuilder locator) {
auto objectType1 = fromType->getOptionalObjectType();
auto objectType2 = toType->getOptionalObjectType();
if (objectType1 && !objectType2) {
auto *anchor = locator.trySimplifyToExpr();
if (!anchor)
return false;
if (auto *overload = cs.findSelectedOverloadFor(anchor)) {
auto *decl = overload->Choice.getDeclOrNull();
if (decl &&
decl->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>())
fromType = objectType1;
}
}
if (!canBridgeThroughCast(cs, fromType, toType))
return false;
conversionsOrFixes.push_back(ForceDowncast::create(
cs, fromType, toType, cs.getConstraintLocator(locator)));
return true;
}
/// Attempt to repair typing failures and record fixes if needed.
/// \return true if at least some of the failures has been repaired
/// successfully, which allows type matcher to continue.
@@ -2301,6 +2353,9 @@ bool ConstraintSystem::repairFailures(
if (repairByAnyToAnyObjectCast(lhs, rhs))
return true;
if (repairViaBridgingCast(*this, lhs, rhs, conversionsOrFixes, locator))
return true;
}
return false;
@@ -2321,7 +2376,10 @@ bool ConstraintSystem::repairFailures(
case ConstraintLocator::ApplyArgToParam: {
auto loc = getConstraintLocator(locator);
if (repairByInsertingExplicitCall(lhs, rhs))
return true;
break;
if (repairViaBridgingCast(*this, lhs, rhs, conversionsOrFixes, locator))
break;
if (lhs->getOptionalObjectType() && !rhs->getOptionalObjectType()) {
conversionsOrFixes.push_back(
@@ -2444,10 +2502,13 @@ bool ConstraintSystem::repairFailures(
}
if (repairByInsertingExplicitCall(lhs, rhs))
return true;
break;
if (repairByAnyToAnyObjectCast(lhs, rhs))
return true;
break;
if (repairViaBridgingCast(*this, lhs, rhs, conversionsOrFixes, locator))
break;
// If both types are key path, the only differences
// between them are mutability and/or root, value type mismatch.
@@ -3317,32 +3378,6 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
}
}
// If we have a value of type AnyObject that we're trying to convert to
// a class, force a downcast.
// FIXME: Also allow types bridged through Objective-C classes.
if (objectType1->isAnyObject() &&
type2->getClassOrBoundGenericClass()) {
conversionsOrFixes.push_back(
ForceDowncast::create(*this, type2, getConstraintLocator(locator)));
}
// If we could perform a bridging cast, try it.
if (auto bridged =
TC.getDynamicBridgedThroughObjCClass(DC, objectType1, type2)) {
// Note: don't perform this recovery for NSNumber;
bool useFix = true;
if (auto classType = bridged->getAs<ClassType>()) {
SmallString<16> scratch;
if (classType->getDecl()->isObjC() &&
classType->getDecl()->getObjCRuntimeName(scratch) == "NSNumber")
useFix = false;
}
if (useFix)
conversionsOrFixes.push_back(
ForceDowncast::create(*this, type2, getConstraintLocator(locator)));
}
if (!type1->is<LValueType>() && type2->is<InOutType>()) {
// If we have a concrete type that's an rvalue, "fix" it.
conversionsOrFixes.push_back(