Skip to content

Commit d7b12a6

Browse files
committed
[TypeChecker] Treat tuples specially while validating checked casts
Based on the checked cast behavior don't warn about unrelated casts between tuples unless their sizes or labels differ. Resolves: rdar://problem/56436235
1 parent 3994a1d commit d7b12a6

File tree

2 files changed

+39
-0
lines changed

2 files changed

+39
-0
lines changed

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4175,6 +4175,29 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
41754175
}
41764176
}
41774177

4178+
if (auto toTuple = toType->getAs<TupleType>()) {
4179+
if (auto fromTuple = fromType->getAs<TupleType>()) {
4180+
if (fromTuple->getNumElements() != toTuple->getNumElements())
4181+
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;
4195+
}
4196+
4197+
return CheckedCastKind::ValueCast;
4198+
}
4199+
}
4200+
41784201
assert(!toType->isAny() && "casts to 'Any' should've been handled above");
41794202
assert(!toType->isAnyObject() &&
41804203
"casts to 'AnyObject' should've been handled above");

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)