Skip to content

Commit 079420f

Browse files
authored
Merge pull request #65643 from kavon/5.9-noncopyable-metatypes
[5.9🍒] Prevent noncopyable metatypes from being converted to `Any`
2 parents 03ff4a3 + f6bbf33 commit 079420f

File tree

4 files changed

+38
-12
lines changed

4 files changed

+38
-12
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.

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)