Skip to content

Commit b133b7e

Browse files
authored
Merge pull request #28910 from xedin/rdar-56436235
[TypeChecker] Treat tuples specially while validating checked casts
2 parents 246d52d + d7b12a6 commit b133b7e

File tree

2 files changed

+61
-33
lines changed

2 files changed

+61
-33
lines changed

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 45 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4150,27 +4150,32 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
41504150
}
41514151
}
41524152

4153-
// Check for casts between specific concrete types that cannot succeed.
4154-
if (auto toElementType = ConstraintSystem::isArrayType(toType)) {
4155-
if (auto fromElementType = ConstraintSystem::isArrayType(fromType)) {
4156-
switch (typeCheckCheckedCast(*fromElementType, *toElementType,
4157-
CheckedCastContextKind::None, dc,
4158-
SourceLoc(), nullptr, SourceRange())) {
4159-
case CheckedCastKind::Coercion:
4160-
return CheckedCastKind::Coercion;
4153+
auto checkElementCast = [&](Type fromElt, Type toElt,
4154+
CheckedCastKind castKind) -> CheckedCastKind {
4155+
switch (typeCheckCheckedCast(fromElt, toElt, CheckedCastContextKind::None,
4156+
dc, SourceLoc(), nullptr, SourceRange())) {
4157+
case CheckedCastKind::Coercion:
4158+
return CheckedCastKind::Coercion;
41614159

4162-
case CheckedCastKind::BridgingCoercion:
4163-
return CheckedCastKind::BridgingCoercion;
4160+
case CheckedCastKind::BridgingCoercion:
4161+
return CheckedCastKind::BridgingCoercion;
41644162

4165-
case CheckedCastKind::ArrayDowncast:
4166-
case CheckedCastKind::DictionaryDowncast:
4167-
case CheckedCastKind::SetDowncast:
4168-
case CheckedCastKind::ValueCast:
4169-
return CheckedCastKind::ArrayDowncast;
4163+
case CheckedCastKind::ArrayDowncast:
4164+
case CheckedCastKind::DictionaryDowncast:
4165+
case CheckedCastKind::SetDowncast:
4166+
case CheckedCastKind::ValueCast:
4167+
return castKind;
41704168

4171-
case CheckedCastKind::Unresolved:
4172-
return failed();
4173-
}
4169+
case CheckedCastKind::Unresolved:
4170+
return failed();
4171+
}
4172+
};
4173+
4174+
// Check for casts between specific concrete types that cannot succeed.
4175+
if (auto toElementType = ConstraintSystem::isArrayType(toType)) {
4176+
if (auto fromElementType = ConstraintSystem::isArrayType(fromType)) {
4177+
return checkElementCast(*fromElementType, *toElementType,
4178+
CheckedCastKind::ArrayDowncast);
41744179
}
41754180
}
41764181

@@ -4240,24 +4245,31 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
42404245

42414246
if (auto toElementType = ConstraintSystem::isSetType(toType)) {
42424247
if (auto fromElementType = ConstraintSystem::isSetType(fromType)) {
4243-
switch (typeCheckCheckedCast(*fromElementType, *toElementType,
4244-
CheckedCastContextKind::None, dc,
4245-
SourceLoc(), nullptr, SourceRange())) {
4246-
case CheckedCastKind::Coercion:
4247-
return CheckedCastKind::Coercion;
4248-
4249-
case CheckedCastKind::BridgingCoercion:
4250-
return CheckedCastKind::BridgingCoercion;
4251-
4252-
case CheckedCastKind::ArrayDowncast:
4253-
case CheckedCastKind::DictionaryDowncast:
4254-
case CheckedCastKind::SetDowncast:
4255-
case CheckedCastKind::ValueCast:
4256-
return CheckedCastKind::SetDowncast;
4248+
return checkElementCast(*fromElementType, *toElementType,
4249+
CheckedCastKind::SetDowncast);
4250+
}
4251+
}
42574252

4258-
case CheckedCastKind::Unresolved:
4253+
if (auto toTuple = toType->getAs<TupleType>()) {
4254+
if (auto fromTuple = fromType->getAs<TupleType>()) {
4255+
if (fromTuple->getNumElements() != toTuple->getNumElements())
42594256
return failed();
4257+
4258+
for (unsigned i = 0, n = toTuple->getNumElements(); i != n; ++i) {
4259+
const auto &fromElt = fromTuple->getElement(i);
4260+
const auto &toElt = toTuple->getElement(i);
4261+
4262+
if (fromElt.getName() != toElt.getName())
4263+
return failed();
4264+
4265+
auto result = checkElementCast(fromElt.getType(), toElt.getType(),
4266+
CheckedCastKind::ValueCast);
4267+
4268+
if (result == CheckedCastKind::Unresolved)
4269+
return result;
42604270
}
4271+
4272+
return CheckedCastKind::ValueCast;
42614273
}
42624274
}
42634275

test/Constraints/casts.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,3 +222,19 @@ func compare<T>(_: T, _: T) {} // expected-note {{'compare' declared here}}
222222
func compare<T>(_: T?, _: T?) {}
223223

224224
_ = nil? as? Int?? // expected-error {{nil literal cannot be the source of a conditional cast}}
225+
226+
func test_tuple_casts_no_warn() {
227+
struct Foo {}
228+
229+
let arr: [(Any, Any)] = [(Foo(), Foo())]
230+
let tup: (Any, Any) = (Foo(), Foo())
231+
232+
_ = arr as! [(Foo, Foo)] // Ok
233+
_ = tup as! (Foo, Foo) // Ok
234+
235+
_ = arr as! [(Foo, Foo, Foo)] // expected-warning {{cast from '[(Any, Any)]' to unrelated type '[(Foo, Foo, Foo)]' always fails}}
236+
_ = tup as! (Foo, Foo, Foo) // expected-warning {{cast from '(Any, Any)' to unrelated type '(Foo, Foo, Foo)' always fails}}
237+
238+
_ = arr as! [(a: Foo, Foo)] // expected-warning {{cast from '[(Any, Any)]' to unrelated type '[(a: Foo, Foo)]' always fails}}
239+
_ = tup as! (a: Foo, Foo) // expected-warning {{cast from '(Any, Any)' to unrelated type '(a: Foo, Foo)' always fails}}
240+
}

0 commit comments

Comments
 (0)