Skip to content

Commit ae9660c

Browse files
committed
Prevent noncopyable metatypes from being converted to Any
These metatypes are a gateway to more incorrect uses of these noncopyable values because we don't yet have the corresponding runtime support yet. The other use cases of using metatypes of noncopyable types in generics is not high enough to warrant people using them yet. resolves rdar://106452518
1 parent aff5b20 commit ae9660c

File tree

5 files changed

+40
-14
lines changed

5 files changed

+40
-14
lines changed

lib/AST/Module.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1768,10 +1768,18 @@ static ProtocolConformanceRef getBuiltinFunctionTypeConformance(
17681768
/// appropriate.
17691769
static ProtocolConformanceRef getBuiltinMetaTypeTypeConformance(
17701770
Type type, const AnyMetatypeType *metatypeType, ProtocolDecl *protocol) {
1771-
// All metatypes are Sendable and Copyable
1772-
if (protocol->isSpecificProtocol(KnownProtocolKind::Sendable) ||
1773-
protocol->isSpecificProtocol(KnownProtocolKind::Copyable)) {
1774-
ASTContext &ctx = protocol->getASTContext();
1771+
ASTContext &ctx = protocol->getASTContext();
1772+
1773+
// Only metatypes of Copyable types are Copyable.
1774+
if (protocol->isSpecificProtocol(KnownProtocolKind::Copyable) &&
1775+
!metatypeType->getInstanceType()->isPureMoveOnly()) {
1776+
return ProtocolConformanceRef(
1777+
ctx.getBuiltinConformance(type, protocol, GenericSignature(), { },
1778+
BuiltinConformanceKind::Synthesized));
1779+
}
1780+
1781+
// All metatypes are Sendable
1782+
if (protocol->isSpecificProtocol(KnownProtocolKind::Sendable)) {
17751783
return ProtocolConformanceRef(
17761784
ctx.getBuiltinConformance(type, protocol, GenericSignature(), { },
17771785
BuiltinConformanceKind::Synthesized));

lib/Sema/CSSimplify.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3806,8 +3806,8 @@ ConstraintSystem::matchExistentialTypes(Type type1, Type type2,
38063806
return getTypeMatchAmbiguous();
38073807
}
38083808

3809-
// move-only types cannot match with any existential types.
3810-
if (type1->isPureMoveOnly()) {
3809+
// move-only types (and their metatypes) cannot match with existential types.
3810+
if (type1->getMetatypeInstanceType()->isPureMoveOnly()) {
38113811
// tailor error message
38123812
if (shouldAttemptFixes()) {
38133813
auto *fix = MustBeCopyable::create(*this, type1,

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1629,12 +1629,12 @@ TypeChecker::typeCheckCheckedCast(Type fromType, Type toType,
16291629
}
16301630

16311631
// Since move-only types currently cannot conform to protocols, nor be a class
1632-
// type, the subtyping hierarchy is a bit bizarre as of now:
1632+
// type, the subtyping hierarchy looks a bit like this:
16331633
//
1634-
// noncopyable
1635-
// structs and enums
1636-
// |
1637-
// +--------- Any
1634+
// ~Copyable
1635+
// / \
1636+
// / \
1637+
// +--------- Any noncopyable structs/enums
16381638
// | |
16391639
// AnyObject protocol
16401640
// | existentials
@@ -1646,7 +1646,9 @@ TypeChecker::typeCheckCheckedCast(Type fromType, Type toType,
16461646
//
16471647
//
16481648
// Thus, right now, a move-only type is only a subtype of itself.
1649-
if (fromType->isPureMoveOnly() || toType->isPureMoveOnly())
1649+
// We also want to prevent conversions of a move-only type's metatype.
1650+
if (fromType->getMetatypeInstanceType()->isPureMoveOnly()
1651+
|| toType->getMetatypeInstanceType()->isPureMoveOnly())
16501652
return CheckedCastKind::Unresolved;
16511653

16521654
// Check for a bridging conversion.

stdlib/public/Concurrency/PartialAsyncTask.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,9 @@ public struct ExecutorJob: Sendable {
142142
/// and it appearing as 0 for _different_ jobs may lead to misunderstanding it as
143143
/// being "the same 0 id job", we specifically print 0 (id not set) as nil.
144144
if (id > 0) {
145-
return "\(Self.self)(id: \(id))"
145+
return "ExecutorJob(id: \(id))"
146146
} else {
147-
return "\(Self.self)(id: nil)"
147+
return "ExecutorJob(id: nil)"
148148
}
149149
}
150150
}

test/Constraints/moveonly_constraints.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,11 @@ func checkCasting(_ b: any Box, _ mo: borrowing MO, _ a: Any) {
148148
let _: MO = dup.get()
149149
let _: MO = dup.val
150150

151+
let _: Any = MO.self // expected-error {{move-only type 'MO.Type' cannot be used with generics yet}}
152+
let _: AnyObject = MO.self // expected-error {{move-only type 'MO.Type' cannot be used with generics yet}}
153+
let _ = MO.self as Any // expected-error {{move-only type 'MO.Type' cannot be used with generics yet}}
154+
let _ = MO.self is Any // expected-warning {{cast from 'MO.Type' to unrelated type 'Any' always fails}}
155+
151156
let _: Sendable = (MO(), MO()) // expected-error {{move-only type '(MO, MO)' cannot be used with generics yet}}
152157
let _: Sendable = MO() // expected-error {{move-only type 'MO' cannot be used with generics yet}}
153158
let _: _Copyable = mo // expected-error {{'_Copyable' is unavailable}}
@@ -266,3 +271,14 @@ struct GenerousGuy: Gives { // expected-error {{type 'GenerousGuy' does not conf
266271
typealias Ty = MO // expected-note {{possibly intended match 'GenerousGuy.Ty' (aka 'MO') does not conform to '_Copyable'}}
267272
func give() -> Ty {}
268273
}
274+
275+
func doBadMetatypeStuff<T>(_ t: T) {
276+
let y = t as! Any.Type
277+
if let MO_MetaType = y as? MO.Type { // expected-warning {{cast from 'any Any.Type' to unrelated type 'MO.Type' always fails}}
278+
let x = MO_MetaType.init()
279+
let _ = x
280+
}
281+
}
282+
func tryToDoBadMetatypeStuff() {
283+
doBadMetatypeStuff(MO.self) // expected-error {{move-only type 'MO.Type' cannot be used with generics yet}}
284+
}

0 commit comments

Comments
 (0)