Skip to content

Commit 277d771

Browse files
authored
Merge pull request #29019 from xedin/rdar-56436235-5.2
[5.2][TypeChecker] Treat tuples specially while validating checked casts
2 parents 61ca401 + b2099b1 commit 277d771

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
@@ -4075,27 +4075,32 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
40754075
}
40764076
}
40774077

4078-
// Check for casts between specific concrete types that cannot succeed.
4079-
if (auto toElementType = ConstraintSystem::isArrayType(toType)) {
4080-
if (auto fromElementType = ConstraintSystem::isArrayType(fromType)) {
4081-
switch (typeCheckCheckedCast(*fromElementType, *toElementType,
4082-
CheckedCastContextKind::None, dc,
4083-
SourceLoc(), nullptr, SourceRange())) {
4084-
case CheckedCastKind::Coercion:
4085-
return CheckedCastKind::Coercion;
4078+
auto checkElementCast = [&](Type fromElt, Type toElt,
4079+
CheckedCastKind castKind) -> CheckedCastKind {
4080+
switch (typeCheckCheckedCast(fromElt, toElt, CheckedCastContextKind::None,
4081+
dc, SourceLoc(), nullptr, SourceRange())) {
4082+
case CheckedCastKind::Coercion:
4083+
return CheckedCastKind::Coercion;
40864084

4087-
case CheckedCastKind::BridgingCoercion:
4088-
return CheckedCastKind::BridgingCoercion;
4085+
case CheckedCastKind::BridgingCoercion:
4086+
return CheckedCastKind::BridgingCoercion;
40894087

4090-
case CheckedCastKind::ArrayDowncast:
4091-
case CheckedCastKind::DictionaryDowncast:
4092-
case CheckedCastKind::SetDowncast:
4093-
case CheckedCastKind::ValueCast:
4094-
return CheckedCastKind::ArrayDowncast;
4088+
case CheckedCastKind::ArrayDowncast:
4089+
case CheckedCastKind::DictionaryDowncast:
4090+
case CheckedCastKind::SetDowncast:
4091+
case CheckedCastKind::ValueCast:
4092+
return castKind;
40954093

4096-
case CheckedCastKind::Unresolved:
4097-
return failed();
4098-
}
4094+
case CheckedCastKind::Unresolved:
4095+
return failed();
4096+
}
4097+
};
4098+
4099+
// Check for casts between specific concrete types that cannot succeed.
4100+
if (auto toElementType = ConstraintSystem::isArrayType(toType)) {
4101+
if (auto fromElementType = ConstraintSystem::isArrayType(fromType)) {
4102+
return checkElementCast(*fromElementType, *toElementType,
4103+
CheckedCastKind::ArrayDowncast);
40994104
}
41004105
}
41014106

@@ -4165,24 +4170,31 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
41654170

41664171
if (auto toElementType = ConstraintSystem::isSetType(toType)) {
41674172
if (auto fromElementType = ConstraintSystem::isSetType(fromType)) {
4168-
switch (typeCheckCheckedCast(*fromElementType, *toElementType,
4169-
CheckedCastContextKind::None, dc,
4170-
SourceLoc(), nullptr, SourceRange())) {
4171-
case CheckedCastKind::Coercion:
4172-
return CheckedCastKind::Coercion;
4173-
4174-
case CheckedCastKind::BridgingCoercion:
4175-
return CheckedCastKind::BridgingCoercion;
4176-
4177-
case CheckedCastKind::ArrayDowncast:
4178-
case CheckedCastKind::DictionaryDowncast:
4179-
case CheckedCastKind::SetDowncast:
4180-
case CheckedCastKind::ValueCast:
4181-
return CheckedCastKind::SetDowncast;
4173+
return checkElementCast(*fromElementType, *toElementType,
4174+
CheckedCastKind::SetDowncast);
4175+
}
4176+
}
41824177

4183-
case CheckedCastKind::Unresolved:
4178+
if (auto toTuple = toType->getAs<TupleType>()) {
4179+
if (auto fromTuple = fromType->getAs<TupleType>()) {
4180+
if (fromTuple->getNumElements() != toTuple->getNumElements())
41844181
return failed();
4182+
4183+
for (unsigned i = 0, n = toTuple->getNumElements(); i != n; ++i) {
4184+
const auto &fromElt = fromTuple->getElement(i);
4185+
const auto &toElt = toTuple->getElement(i);
4186+
4187+
if (fromElt.getName() != toElt.getName())
4188+
return failed();
4189+
4190+
auto result = checkElementCast(fromElt.getType(), toElt.getType(),
4191+
CheckedCastKind::ValueCast);
4192+
4193+
if (result == CheckedCastKind::Unresolved)
4194+
return result;
41854195
}
4196+
4197+
return CheckedCastKind::ValueCast;
41864198
}
41874199
}
41884200

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)