mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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:
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user