Skip to content

Commit f6bbf33

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 (cherry picked from commit 4710fc6)
1 parent 76e21ad commit f6bbf33

File tree

6 files changed

+41
-15
lines changed

6 files changed

+41
-15
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
@@ -3831,8 +3831,8 @@ ConstraintSystem::matchExistentialTypes(Type type1, Type type2,
38313831
return getTypeMatchAmbiguous();
38323832
}
38333833

3834-
// move-only types cannot match with any existential types.
3835-
if (type1->isPureMoveOnly()) {
3834+
// move-only types (and their metatypes) cannot match with existential types.
3835+
if (type1->getMetatypeInstanceType()->isPureMoveOnly()) {
38363836
// tailor error message
38373837
if (shouldAttemptFixes()) {
38383838
auto *fix = MustBeCopyable::create(*this, type1,

lib/Sema/TypeCheckConstraints.cpp

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

16541654
// Since move-only types currently cannot conform to protocols, nor be a class
1655-
// type, the subtyping hierarchy is a bit bizarre as of now:
1655+
// type, the subtyping hierarchy looks a bit like this:
16561656
//
1657-
// noncopyable
1658-
// structs and enums
1659-
// |
1660-
// +--------- Any
1657+
// ~Copyable
1658+
// / \
1659+
// / \
1660+
// +--------- Any noncopyable structs/enums
16611661
// | |
16621662
// AnyObject protocol
16631663
// | existentials
@@ -1669,7 +1669,9 @@ TypeChecker::typeCheckCheckedCast(Type fromType, Type toType,
16691669
//
16701670
//
16711671
// Thus, right now, a move-only type is only a subtype of itself.
1672-
if (fromType->isPureMoveOnly() || toType->isPureMoveOnly())
1672+
// We also want to prevent conversions of a move-only type's metatype.
1673+
if (fromType->getMetatypeInstanceType()->isPureMoveOnly()
1674+
|| toType->getMetatypeInstanceType()->isPureMoveOnly())
16731675
return CheckedCastKind::Unresolved;
16741676

16751677
// 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
}

stdlib/public/Distributed/DistributedDefaultExecutor.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ internal final class DistributedRemoteActorReferenceExecutor: SerialExecutor {
2626
@inlinable
2727
public func enqueue(_ job: __owned ExecutorJob) {
2828
let jobDescription = job.description
29-
fatalError("Attempted to enqueue \(Job.self) (\(jobDescription)) on executor of remote distributed actor reference!")
29+
fatalError("Attempted to enqueue ExecutorJob (\(jobDescription)) on executor of remote distributed actor reference!")
3030
}
3131

3232
public func asUnownedSerialExecutor() -> UnownedSerialExecutor {

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)