Skip to content

Commit e4510ea

Browse files
authored
Merge pull request swiftlang#63487 from kavon/no-conditional-cast-of-moveonly
prevent move-only types from being cast incorrectly
2 parents 1703b93 + 9a18422 commit e4510ea

File tree

5 files changed

+81
-7
lines changed

5 files changed

+81
-7
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6681,6 +6681,8 @@ ERROR(noimplicitcopy_attr_not_allowed_on_moveonlytype,none,
66816681
"'@_noImplicitCopy' has no effect when applied to a move only type", ())
66826682
ERROR(moveonly_enums_do_not_support_indirect,none,
66836683
"move-only enum %0 cannot be marked indirect or have indirect cases yet", (Identifier))
6684+
ERROR(moveonly_cast,none,
6685+
"move-only types cannot be conditionally cast", ())
66846686

66856687
//------------------------------------------------------------------------------
66866688
// MARK: Type inference from default expressions

lib/Sema/MiscDiagnostics.cpp

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
336336
tupleExpr->getElementNames());
337337
}
338338

339-
// Diagnose checked casts that involve marker protocols.
339+
// Specially diagnose some checked casts that are illegal.
340340
if (auto cast = dyn_cast<CheckedCastExpr>(E)) {
341341
checkCheckedCastExpr(cast);
342342
}
@@ -384,16 +384,39 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
384384
}
385385

386386
void checkCheckedCastExpr(CheckedCastExpr *cast) {
387+
Type castType = cast->getCastType();
388+
if (!castType)
389+
return;
390+
391+
if (castType->isPureMoveOnly()) {
392+
// can't cast anything to move-only; there should be no valid ones.
393+
Ctx.Diags.diagnose(cast->getLoc(), diag::moveonly_cast);
394+
return;
395+
}
396+
397+
// no support for runtime casts from move-only types.
398+
// as of now there is no type it could be cast to except itself, so
399+
// there's no reason for it to happen at runtime.
400+
if (auto fromType = cast->getSubExpr()->getType()) {
401+
if (fromType->isPureMoveOnly()) {
402+
// can't cast move-only to anything.
403+
Ctx.Diags.diagnose(cast->getLoc(), diag::moveonly_cast);
404+
return;
405+
}
406+
}
407+
408+
// now, look for conditional casts to marker protocols.
409+
387410
if (!isa<ConditionalCheckedCastExpr>(cast) && !isa<IsExpr>(cast))
388411
return;
389412

390-
Type castType = cast->getCastType();
391-
if (!castType || !castType->isExistentialType())
413+
if(!castType->isExistentialType())
392414
return;
393415

394416
auto layout = castType->getExistentialLayout();
395417
for (auto proto : layout.getProtocols()) {
396418
if (proto->isMarkerProtocol()) {
419+
// can't conditionally cast to a marker protocol
397420
Ctx.Diags.diagnose(cast->getLoc(), diag::marker_protocol_cast,
398421
proto->getName());
399422
}

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1678,7 +1678,7 @@ TypeChecker::typeCheckCheckedCast(Type fromType, Type toType,
16781678
//
16791679
//
16801680
// Thus, right now, a move-only type is only a subtype of itself.
1681-
if (fromType->isPureMoveOnly())
1681+
if (fromType->isPureMoveOnly() || toType->isPureMoveOnly())
16821682
return CheckedCastKind::Unresolved;
16831683

16841684
// Check for a bridging conversion.

test/Constraints/moveonly_constraints.swift

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ func checkMethodCalls() {
139139
takeMaybe(true ? .none : .just(MO())) // expected-error 3{{move-only type 'MO' cannot be used with generics yet}}
140140
}
141141

142-
func checkCasting(_ b: any Box, _ mo: MO) {
142+
func checkCasting(_ b: any Box, _ mo: MO, _ a: Any) {
143143
// casting dynamically is allowed, but should always fail since you can't
144144
// construct such a type.
145145
let box = b as! ValBox<MO> // expected-error {{move-only type 'MO' cannot be used with generics yet}}
@@ -159,26 +159,65 @@ func checkCasting(_ b: any Box, _ mo: MO) {
159159
_ = MO() as Any // expected-error {{move-only type 'MO' cannot be used with generics yet}}
160160
_ = MO() as MO
161161
_ = MO() as AnyObject // expected-error {{move-only type 'MO' cannot be used with generics yet}}
162+
_ = 5 as MO // expected-error {{cannot convert value of type 'Int' to type 'MO' in coercion}}
163+
_ = a as MO // expected-error {{cannot convert value of type 'Any' to type 'MO' in coercion}}
164+
_ = b as MO // expected-error {{cannot convert value of type 'any Box' to type 'MO' in coercion}}
162165

163166
// FIXME(kavon): make sure at runtime these casts actually fail, or just make them errors? (rdar://104900293)
164167

165168
_ = MO() is AnyHashable // expected-warning {{cast from 'MO' to unrelated type 'AnyHashable' always fails}}
169+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
166170
_ = MO() is AnyObject // expected-warning {{cast from 'MO' to unrelated type 'AnyObject' always fails}}
171+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
167172
_ = MO() is Any // expected-warning {{cast from 'MO' to unrelated type 'Any' always fails}}
173+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
168174
_ = MO() is P // expected-warning {{cast from 'MO' to unrelated type 'any P' always fails}}
175+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
169176
_ = MO() is MO // expected-warning {{'is' test is always true}}
177+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
178+
179+
_ = 5 is MO // expected-warning {{cast from 'Int' to unrelated type 'MO' always fails}}
180+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
181+
_ = a is MO // expected-warning {{cast from 'Any' to unrelated type 'MO' always fails}}
182+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
183+
_ = b is MO // expected-warning {{cast from 'any Box' to unrelated type 'MO' always fails}}
184+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
170185

171186
_ = MO() as! AnyHashable // expected-warning {{cast from 'MO' to unrelated type 'AnyHashable' always fails}}
187+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
172188
_ = MO() as! AnyObject // expected-warning {{cast from 'MO' to unrelated type 'AnyObject' always fails}}
189+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
173190
_ = MO() as! Any // expected-warning {{cast from 'MO' to unrelated type 'Any' always fails}}
191+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
174192
_ = MO() as! P // expected-warning {{cast from 'MO' to unrelated type 'any P' always fails}}
193+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
175194
_ = MO() as! MO // expected-warning {{forced cast of 'MO' to same type has no effect}}
195+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
196+
197+
_ = 5 as! MO // expected-warning {{cast from 'Int' to unrelated type 'MO' always fails}}
198+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
199+
_ = a as! MO // expected-warning {{cast from 'Any' to unrelated type 'MO' always fails}}
200+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
201+
_ = b as! MO // expected-warning {{cast from 'any Box' to unrelated type 'MO' always fails}}
202+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
176203

177204
_ = MO() as? AnyHashable // expected-warning {{cast from 'MO' to unrelated type 'AnyHashable' always fails}}
205+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
178206
_ = MO() as? AnyObject // expected-warning {{cast from 'MO' to unrelated type 'AnyObject' always fails}}
207+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
179208
_ = MO() as? Any // expected-warning {{cast from 'MO' to unrelated type 'Any' always fails}}
209+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
180210
_ = MO() as? P // expected-warning {{cast from 'MO' to unrelated type 'any P' always fails}}
211+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
181212
_ = MO() as? MO // expected-warning {{conditional cast from 'MO' to 'MO' always succeeds}}
213+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
214+
215+
_ = 5 as? MO // expected-warning {{cast from 'Int' to unrelated type 'MO' always fails}}
216+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
217+
_ = a as? MO // expected-warning {{cast from 'Any' to unrelated type 'MO' always fails}}
218+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
219+
_ = b as? MO // expected-warning {{cast from 'any Box' to unrelated type 'MO' always fails}}
220+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
182221

183222
}
184223

test/Sema/moveonly_sendable.swift

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,22 @@ func tryToCastIt(_ fd: FileDescriptor) {
106106
let _ = fd as Sendable // expected-error {{move-only type 'FileDescriptor' cannot be used with generics yet}}
107107

108108
let _ = fd as? Sendable // expected-warning {{cast from 'FileDescriptor' to unrelated type 'any Sendable' always fails}}
109-
// expected-error@-1 {{marker protocol 'Sendable' cannot be used in a conditional cast}}
109+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
110110

111111
let _ = fd as! Sendable // expected-warning {{cast from 'FileDescriptor' to unrelated type 'any Sendable' always fails}}
112+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
112113

113114
let _ = fd is Sendable // expected-warning {{cast from 'FileDescriptor' to unrelated type 'any Sendable' always fails}}
114-
// expected-error@-1 {{marker protocol 'Sendable' cannot be used in a conditional cast}}
115+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
116+
117+
let sendy = mkSendable()
118+
let _ = sendy as FileDescriptor // expected-error {{cannot convert value of type 'any Sendable' to type 'FileDescriptor' in coercion}}
119+
let _ = sendy is FileDescriptor // expected-warning {{cast from 'any Sendable' to unrelated type 'FileDescriptor' always fails}}
120+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
121+
let _ = sendy as! FileDescriptor // expected-warning {{cast from 'any Sendable' to unrelated type 'FileDescriptor' always fails}}
122+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
123+
let _ = sendy as? FileDescriptor// expected-warning {{cast from 'any Sendable' to unrelated type 'FileDescriptor' always fails}}
124+
// expected-error@-1 {{move-only types cannot be conditionally cast}}
115125
}
116126

117127
protocol GiveSendable<T> {

0 commit comments

Comments
 (0)