Skip to content

Commit a6ab3b6

Browse files
[Sema] Refactor TypeChecker::typeCheckCheckedCast in order to remove all diagnostic emiting logic from it
1 parent 99f1704 commit a6ab3b6

File tree

5 files changed

+77
-151
lines changed

5 files changed

+77
-151
lines changed

lib/Sema/CSApply.cpp

Lines changed: 11 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -3712,12 +3712,8 @@ namespace {
37123712
expr->setCastType(toType);
37133713
cs.setType(castTypeRepr, toType);
37143714

3715-
auto castContextKind =
3716-
SuppressDiagnostics ? CheckedCastContextKind::None
3717-
: CheckedCastContextKind::IsExpr;
37183715
auto castKind = TypeChecker::typeCheckCheckedCast(
3719-
fromType, toType, castContextKind, dc, expr->getLoc(), sub,
3720-
castTypeRepr->getSourceRange());
3716+
fromType, toType, CheckedCastContextKind::IsExpr, dc);
37213717

37223718
switch (castKind) {
37233719
case CheckedCastKind::Unresolved:
@@ -3726,19 +3722,7 @@ namespace {
37263722

37273723
case CheckedCastKind::Coercion:
37283724
case CheckedCastKind::BridgingCoercion:
3729-
expr->setCastKind(castKind);
3730-
break;
37313725
case CheckedCastKind::ValueCast:
3732-
// Check the cast target is a non-foreign type
3733-
if (auto cls = toType->getAs<ClassType>()) {
3734-
if (cls->getDecl()->getForeignClassKind() ==
3735-
ClassDecl::ForeignKind::CFType) {
3736-
ctx.Diags.diagnose(expr->getLoc(), diag::isa_is_foreign_check,
3737-
toType);
3738-
}
3739-
}
3740-
expr->setCastKind(castKind);
3741-
break;
37423726
case CheckedCastKind::ArrayDowncast:
37433727
case CheckedCastKind::DictionaryDowncast:
37443728
case CheckedCastKind::SetDowncast:
@@ -4169,17 +4153,16 @@ namespace {
41694153
if (hasForcedOptionalResult(expr))
41704154
toType = toType->getOptionalObjectType();
41714155

4172-
auto castContextKind = SuppressDiagnostics || expr->isImplicit()
4173-
? CheckedCastContextKind::None
4174-
: CheckedCastContextKind::ForcedCast;
4175-
41764156
const auto castKind = TypeChecker::typeCheckCheckedCast(
4177-
fromType, toType, castContextKind, dc, expr->getLoc(), sub,
4178-
castTypeRange);
4157+
fromType, toType, CheckedCastContextKind::ForcedCast, dc);
41794158
switch (castKind) {
41804159
/// Invalid cast.
41814160
case CheckedCastKind::Unresolved:
4182-
return nullptr;
4161+
if (expr->isImplicit())
4162+
return nullptr;
4163+
4164+
expr->setCastKind(CheckedCastKind::ValueCast);
4165+
break;
41834166
case CheckedCastKind::Coercion:
41844167
case CheckedCastKind::BridgingCoercion: {
41854168
expr->setCastKind(castKind);
@@ -4240,47 +4223,18 @@ namespace {
42404223
"cast requires TypeRepr; implicit casts are superfluous");
42414224

42424225
// The subexpression is always an rvalue.
4243-
auto &ctx = cs.getASTContext();
42444226
auto sub = cs.coerceToRValue(expr->getSubExpr());
42454227
expr->setSubExpr(sub);
42464228

42474229
// Simplify and update the type we're casting to.
42484230
const auto fromType = cs.getType(sub);
42494231
const auto toType = expr->getCastType();
42504232

4251-
bool isSubExprLiteral = isa<LiteralExpr>(sub);
4252-
auto castContextKind =
4253-
(SuppressDiagnostics || expr->isImplicit() || isSubExprLiteral)
4254-
? CheckedCastContextKind::None
4255-
: CheckedCastContextKind::ConditionalCast;
4256-
42574233
auto castKind = TypeChecker::typeCheckCheckedCast(
4258-
fromType, toType, castContextKind, dc, expr->getLoc(), sub,
4259-
castTypeRepr->getSourceRange());
4234+
fromType, toType, CheckedCastContextKind::ConditionalCast, dc);
42604235
switch (castKind) {
42614236
// Invalid cast.
42624237
case CheckedCastKind::Unresolved:
4263-
// FIXME: This literal diagnostics needs to be revisited by a proposal
4264-
// to unify casting semantics for literals.
4265-
// https://bugs.swift.org/browse/SR-12093
4266-
if (isSubExprLiteral) {
4267-
auto protocol = TypeChecker::getLiteralProtocol(ctx, sub);
4268-
// Special handle for literals conditional checked cast when they can
4269-
// be statically coerced to the cast type.
4270-
if (protocol && TypeChecker::conformsToProtocol(
4271-
toType, protocol, dc->getParentModule())) {
4272-
ctx.Diags
4273-
.diagnose(expr->getLoc(),
4274-
diag::literal_conditional_downcast_to_coercion,
4275-
toType);
4276-
} else {
4277-
ctx.Diags
4278-
.diagnose(expr->getLoc(), diag::downcast_to_unrelated, fromType,
4279-
toType)
4280-
.highlight(sub->getSourceRange())
4281-
.highlight(castTypeRepr->getSourceRange());
4282-
}
4283-
}
42844238
expr->setCastKind(CheckedCastKind::ValueCast);
42854239
break;
42864240

@@ -6148,12 +6102,9 @@ static Expr *buildElementConversion(ExprRewriter &rewriter,
61486102
Type destType, bool bridged,
61496103
ConstraintLocatorBuilder locator,
61506104
Expr *element) {
6151-
if (bridged &&
6152-
TypeChecker::typeCheckCheckedCast(srcType, destType,
6153-
CheckedCastContextKind::None,
6154-
rewriter.dc,
6155-
SourceLoc(), nullptr, SourceRange())
6156-
!= CheckedCastKind::Coercion) {
6105+
if (bridged && TypeChecker::typeCheckCheckedCast(
6106+
srcType, destType, CheckedCastContextKind::None,
6107+
rewriter.dc) != CheckedCastKind::Coercion) {
61576108
if (auto conversion =
61586109
rewriter.buildObjCBridgeExpr(element, destType, locator))
61596110
return conversion;

lib/Sema/CSSimplify.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7563,8 +7563,21 @@ static ConstraintFix *maybeWarnAboutExtraneousCast(
75637563
}
75647564

75657565
auto castKind = TypeChecker::typeCheckCheckedCast(
7566-
fromType, toType, CheckedCastContextKind::None, cs.DC, SourceLoc(),
7567-
nullptr, SourceRange());
7566+
fromType, toType, CheckedCastContextKind::None, cs.DC);
7567+
7568+
if (castKind == CheckedCastKind::Unresolved) {
7569+
return AllowCheckedCastToUnrelated::attempt(
7570+
cs, origFromType, origToType, castKind,
7571+
cs.getConstraintLocator(locator));
7572+
}
7573+
7574+
if (castKind == CheckedCastKind::ValueCast) {
7575+
// SR-1612: Special 'is' case diagnostics for CFTypes.
7576+
return AllowNoopExistentialToCFTypeCheckedCast::attempt(
7577+
cs, origFromType, origToType, castKind,
7578+
cs.getConstraintLocator(locator));
7579+
}
7580+
75687581
if (!(castKind == CheckedCastKind::Coercion ||
75697582
castKind == CheckedCastKind::BridgingCoercion))
75707583
return nullptr;
@@ -12813,7 +12826,9 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1281312826
case FixKind::SpecifyBaseTypeForOptionalUnresolvedMember:
1281412827
case FixKind::AllowCheckedCastCoercibleOptionalType:
1281512828
case FixKind::AllowNoopCheckedCast:
12829+
case FixKind::AllowNoopExistentialToCFTypeCheckedCast:
1281612830
case FixKind::AllowUnsupportedRuntimeCheckedCast:
12831+
case FixKind::AllowCheckedCastToUnrelated:
1281712832
case FixKind::AllowInvalidStaticMemberRefOnProtocolMetatype:
1281812833
case FixKind::AllowWrappedValueMismatch:
1281912834
case FixKind::RemoveExtraneousArguments:

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 25 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,9 +1058,8 @@ bool TypeChecker::isObjCBridgedTo(Type type1, Type type2, DeclContext *dc,
10581058
}
10591059

10601060
bool TypeChecker::checkedCastMaySucceed(Type t1, Type t2, DeclContext *dc) {
1061-
auto kind = TypeChecker::typeCheckCheckedCast(t1, t2,
1062-
CheckedCastContextKind::None, dc,
1063-
SourceLoc(), nullptr, SourceRange());
1061+
auto kind = TypeChecker::typeCheckCheckedCast(
1062+
t1, t2, CheckedCastContextKind::None, dc);
10641063
return (kind != CheckedCastKind::Unresolved);
10651064
}
10661065

@@ -1559,24 +1558,10 @@ void ConstraintSystem::print(raw_ostream &out) const {
15591558
}
15601559

15611560
/// Determine the semantics of a checked cast operation.
1562-
CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
1563-
Type toType,
1564-
CheckedCastContextKind contextKind,
1565-
DeclContext *dc,
1566-
SourceLoc diagLoc,
1567-
Expr *fromExpr,
1568-
SourceRange diagToRange) {
1569-
// Determine whether we should suppress diagnostics.
1570-
const bool suppressDiagnostics =
1571-
contextKind == CheckedCastContextKind::None ||
1572-
contextKind == CheckedCastContextKind::Coercion;
1573-
assert((suppressDiagnostics || diagLoc.isValid()) &&
1574-
"diagnostics require a valid source location");
1575-
1576-
SourceRange diagFromRange;
1577-
if (fromExpr)
1578-
diagFromRange = fromExpr->getSourceRange();
1579-
1561+
CheckedCastKind
1562+
TypeChecker::typeCheckCheckedCast(Type fromType, Type toType,
1563+
CheckedCastContextKind contextKind,
1564+
DeclContext *dc) {
15801565
// If the from/to types are equivalent or convertible, this is a coercion.
15811566
bool unwrappedIUO = false;
15821567
if (fromType->isEqual(toType) ||
@@ -1594,31 +1579,20 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
15941579
return CheckedCastKind::BridgingCoercion;
15951580
}
15961581

1597-
Type origFromType = fromType;
1598-
Type origToType = toType;
1599-
16001582
auto *module = dc->getParentModule();
1601-
1602-
auto &diags = dc->getASTContext().Diags;
16031583
bool optionalToOptionalCast = false;
16041584

16051585
// Local function to indicate failure.
16061586
auto failed = [&] {
1607-
if (suppressDiagnostics) {
1587+
if (contextKind == CheckedCastContextKind::Coercion)
16081588
return CheckedCastKind::Unresolved;
1609-
}
16101589

16111590
// Explicit optional-to-optional casts always succeed because a nil
16121591
// value of any optional type can be cast to any other optional type.
16131592
if (optionalToOptionalCast)
16141593
return CheckedCastKind::ValueCast;
16151594

1616-
diags.diagnose(diagLoc, diag::downcast_to_unrelated, origFromType,
1617-
origToType)
1618-
.highlight(diagFromRange)
1619-
.highlight(diagToRange);
1620-
1621-
return CheckedCastKind::ValueCast;
1595+
return CheckedCastKind::Unresolved;
16221596
};
16231597

16241598
// TODO: Explore optionals using the same strategy used by the
@@ -1647,9 +1621,8 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
16471621
// downcast. Complain.
16481622
auto &Context = dc->getASTContext();
16491623
if (extraFromOptionals > 0) {
1650-
switch (typeCheckCheckedCast(fromType, toType,
1651-
CheckedCastContextKind::None, dc,
1652-
SourceLoc(), nullptr, SourceRange())) {
1624+
switch (typeCheckCheckedCast(fromType, toType, CheckedCastContextKind::None,
1625+
dc)) {
16531626
case CheckedCastKind::Coercion:
16541627
case CheckedCastKind::BridgingCoercion: {
16551628
// Treat this as a value cast so we preserve the semantics.
@@ -1670,7 +1643,7 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
16701643
auto checkElementCast = [&](Type fromElt, Type toElt,
16711644
CheckedCastKind castKind) -> CheckedCastKind {
16721645
switch (typeCheckCheckedCast(fromElt, toElt, CheckedCastContextKind::None,
1673-
dc, SourceLoc(), nullptr, SourceRange())) {
1646+
dc)) {
16741647
case CheckedCastKind::Coercion:
16751648
return CheckedCastKind::Coercion;
16761649

@@ -1685,13 +1658,13 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
16851658

16861659
case CheckedCastKind::Unresolved:
16871660
// Even though we know the elements cannot be downcast, we cannot return
1688-
// failed() here as it's possible for an empty Array, Set or Dictionary to
1689-
// be cast to any element type at runtime (SR-6192). The one exception to
1690-
// this is when we're checking whether we can treat a coercion as a checked
1691-
// cast because we don't want to tell the user to use as!, as it's probably
1692-
// the wrong suggestion.
1661+
// Unresolved here as it's possible for an empty Array, Set or Dictionary
1662+
// to be cast to any element type at runtime (SR-6192). The one exception
1663+
// to this is when we're checking whether we can treat a coercion as a
1664+
// checked cast because we don't want to tell the user to use as!, as it's
1665+
// probably the wrong suggestion.
16931666
if (contextKind == CheckedCastContextKind::Coercion)
1694-
return failed();
1667+
return CheckedCastKind::Unresolved;
16951668
return castKind;
16961669
}
16971670
llvm_unreachable("invalid cast type");
@@ -1712,8 +1685,7 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
17121685
hasBridgingConversion = NoBridging;
17131686
bool hasCast = false;
17141687
switch (typeCheckCheckedCast(fromKeyValue->first, toKeyValue->first,
1715-
CheckedCastContextKind::None, dc,
1716-
SourceLoc(), nullptr, SourceRange())) {
1688+
CheckedCastContextKind::None, dc)) {
17171689
case CheckedCastKind::Coercion:
17181690
hasCoercion = true;
17191691
break;
@@ -1727,7 +1699,7 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
17271699
// Handled the same as in checkElementCast; see comment there for
17281700
// rationale.
17291701
if (contextKind == CheckedCastContextKind::Coercion)
1730-
return failed();
1702+
return CheckedCastKind::Unresolved;
17311703
LLVM_FALLTHROUGH;
17321704

17331705
case CheckedCastKind::ArrayDowncast:
@@ -1739,8 +1711,7 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
17391711
}
17401712

17411713
switch (typeCheckCheckedCast(fromKeyValue->second, toKeyValue->second,
1742-
CheckedCastContextKind::None, dc,
1743-
SourceLoc(), nullptr, SourceRange())) {
1714+
CheckedCastContextKind::None, dc)) {
17441715
case CheckedCastKind::Coercion:
17451716
hasCoercion = true;
17461717
break;
@@ -1754,7 +1725,7 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
17541725
// Handled the same as in checkElementCast; see comment there for
17551726
// rationale.
17561727
if (contextKind == CheckedCastContextKind::Coercion)
1757-
return failed();
1728+
return CheckedCastKind::Unresolved;
17581729
LLVM_FALLTHROUGH;
17591730

17601731
case CheckedCastKind::ArrayDowncast:
@@ -1836,31 +1807,14 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
18361807
if (fromFunctionType &&
18371808
(toExistentialType || (toArchetypeType && toConstrainedArchetype))) {
18381809
switch (contextKind) {
1810+
case CheckedCastContextKind::None:
18391811
case CheckedCastContextKind::ConditionalCast:
18401812
case CheckedCastContextKind::ForcedCast:
1841-
diags.diagnose(diagLoc, diag::downcast_to_unrelated, origFromType,
1842-
origToType)
1843-
.highlight(diagFromRange)
1844-
.highlight(diagToRange);
1845-
1846-
// If we're referring to a function with a return value (not Void) then
1847-
// emit a fix-it suggesting to add `()` to call the function
1848-
if (auto DRE = dyn_cast<DeclRefExpr>(fromExpr)) {
1849-
if (auto FD = dyn_cast<FuncDecl>(DRE->getDecl())) {
1850-
if (!FD->getResultInterfaceType()->isVoid()) {
1851-
diags.diagnose(diagLoc, diag::downcast_to_unrelated_fixit,
1852-
FD->getBaseIdentifier())
1853-
.fixItInsertAfter(fromExpr->getEndLoc(), "()");
1854-
}
1855-
}
1856-
}
1857-
1858-
return CheckedCastKind::ValueCast;
1813+
return CheckedCastKind::Unresolved;
18591814

18601815
case CheckedCastContextKind::IsPattern:
18611816
case CheckedCastContextKind::EnumElementPattern:
18621817
case CheckedCastContextKind::IsExpr:
1863-
case CheckedCastContextKind::None:
18641818
case CheckedCastContextKind::Coercion:
18651819
break;
18661820
}
@@ -1870,8 +1824,7 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
18701824
if (Type bridgedToClass = getDynamicBridgedThroughObjCClass(dc, fromType,
18711825
toType)) {
18721826
switch (typeCheckCheckedCast(bridgedToClass, fromType,
1873-
CheckedCastContextKind::None, dc, SourceLoc(),
1874-
nullptr, SourceRange())) {
1827+
CheckedCastContextKind::None, dc)) {
18751828
case CheckedCastKind::ArrayDowncast:
18761829
case CheckedCastKind::BridgingCoercion:
18771830
case CheckedCastKind::Coercion:
@@ -1889,8 +1842,7 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
18891842
if (Type bridgedFromClass = getDynamicBridgedThroughObjCClass(dc, toType,
18901843
fromType)) {
18911844
switch (typeCheckCheckedCast(toType, bridgedFromClass,
1892-
CheckedCastContextKind::None, dc, SourceLoc(),
1893-
nullptr, SourceRange())) {
1845+
CheckedCastContextKind::None, dc)) {
18941846
case CheckedCastKind::ArrayDowncast:
18951847
case CheckedCastKind::BridgingCoercion:
18961848
case CheckedCastKind::Coercion:

0 commit comments

Comments
 (0)