Skip to content

Prevent noncopyable metatypes from being converted to Any #65606

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions lib/AST/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1768,10 +1768,18 @@ static ProtocolConformanceRef getBuiltinFunctionTypeConformance(
/// appropriate.
static ProtocolConformanceRef getBuiltinMetaTypeTypeConformance(
Type type, const AnyMetatypeType *metatypeType, ProtocolDecl *protocol) {
// All metatypes are Sendable and Copyable
if (protocol->isSpecificProtocol(KnownProtocolKind::Sendable) ||
protocol->isSpecificProtocol(KnownProtocolKind::Copyable)) {
ASTContext &ctx = protocol->getASTContext();
ASTContext &ctx = protocol->getASTContext();

// Only metatypes of Copyable types are Copyable.
if (protocol->isSpecificProtocol(KnownProtocolKind::Copyable) &&
!metatypeType->getInstanceType()->isPureMoveOnly()) {
return ProtocolConformanceRef(
ctx.getBuiltinConformance(type, protocol, GenericSignature(), { },
BuiltinConformanceKind::Synthesized));
}

// All metatypes are Sendable
if (protocol->isSpecificProtocol(KnownProtocolKind::Sendable)) {
return ProtocolConformanceRef(
ctx.getBuiltinConformance(type, protocol, GenericSignature(), { },
BuiltinConformanceKind::Synthesized));
Expand Down
4 changes: 2 additions & 2 deletions lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3806,8 +3806,8 @@ ConstraintSystem::matchExistentialTypes(Type type1, Type type2,
return getTypeMatchAmbiguous();
}

// move-only types cannot match with any existential types.
if (type1->isPureMoveOnly()) {
// move-only types (and their metatypes) cannot match with existential types.
if (type1->getMetatypeInstanceType()->isPureMoveOnly()) {
// tailor error message
if (shouldAttemptFixes()) {
auto *fix = MustBeCopyable::create(*this, type1,
Expand Down
14 changes: 8 additions & 6 deletions lib/Sema/TypeCheckConstraints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1629,12 +1629,12 @@ TypeChecker::typeCheckCheckedCast(Type fromType, Type toType,
}

// Since move-only types currently cannot conform to protocols, nor be a class
// type, the subtyping hierarchy is a bit bizarre as of now:
// type, the subtyping hierarchy looks a bit like this:
//
// noncopyable
// structs and enums
// |
// +--------- Any
// ~Copyable
// / \
// / \
// +--------- Any noncopyable structs/enums
// | |
// AnyObject protocol
// | existentials
Expand All @@ -1646,7 +1646,9 @@ TypeChecker::typeCheckCheckedCast(Type fromType, Type toType,
//
//
// Thus, right now, a move-only type is only a subtype of itself.
if (fromType->isPureMoveOnly() || toType->isPureMoveOnly())
// We also want to prevent conversions of a move-only type's metatype.
if (fromType->getMetatypeInstanceType()->isPureMoveOnly()
|| toType->getMetatypeInstanceType()->isPureMoveOnly())
return CheckedCastKind::Unresolved;

// Check for a bridging conversion.
Expand Down
4 changes: 2 additions & 2 deletions stdlib/public/Concurrency/PartialAsyncTask.swift
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,9 @@ public struct ExecutorJob: Sendable {
/// and it appearing as 0 for _different_ jobs may lead to misunderstanding it as
/// being "the same 0 id job", we specifically print 0 (id not set) as nil.
if (id > 0) {
return "\(Self.self)(id: \(id))"
return "ExecutorJob(id: \(id))"
} else {
return "\(Self.self)(id: nil)"
return "ExecutorJob(id: nil)"
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ internal final class DistributedRemoteActorReferenceExecutor: SerialExecutor {
@inlinable
public func enqueue(_ job: __owned ExecutorJob) {
let jobDescription = job.description
fatalError("Attempted to enqueue \(ExecutorJob.self) (\(jobDescription)) on executor of remote distributed actor reference!")
fatalError("Attempted to enqueue ExecutorJob (\(jobDescription)) on executor of remote distributed actor reference!")
}

public func asUnownedSerialExecutor() -> UnownedSerialExecutor {
Expand Down
16 changes: 16 additions & 0 deletions test/Constraints/moveonly_constraints.swift
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,11 @@ func checkCasting(_ b: any Box, _ mo: borrowing MO, _ a: Any) {
let _: MO = dup.get()
let _: MO = dup.val

let _: Any = MO.self // expected-error {{move-only type 'MO.Type' cannot be used with generics yet}}
let _: AnyObject = MO.self // expected-error {{move-only type 'MO.Type' cannot be used with generics yet}}
let _ = MO.self as Any // expected-error {{move-only type 'MO.Type' cannot be used with generics yet}}
let _ = MO.self is Any // expected-warning {{cast from 'MO.Type' to unrelated type 'Any' always fails}}

let _: Sendable = (MO(), MO()) // expected-error {{move-only type '(MO, MO)' cannot be used with generics yet}}
let _: Sendable = MO() // expected-error {{move-only type 'MO' cannot be used with generics yet}}
let _: _Copyable = mo // expected-error {{'_Copyable' is unavailable}}
Expand Down Expand Up @@ -266,3 +271,14 @@ struct GenerousGuy: Gives { // expected-error {{type 'GenerousGuy' does not conf
typealias Ty = MO // expected-note {{possibly intended match 'GenerousGuy.Ty' (aka 'MO') does not conform to '_Copyable'}}
func give() -> Ty {}
}

func doBadMetatypeStuff<T>(_ t: T) {
let y = t as! Any.Type
if let MO_MetaType = y as? MO.Type { // expected-warning {{cast from 'any Any.Type' to unrelated type 'MO.Type' always fails}}
let x = MO_MetaType.init()
let _ = x
}
}
func tryToDoBadMetatypeStuff() {
doBadMetatypeStuff(MO.self) // expected-error {{move-only type 'MO.Type' cannot be used with generics yet}}
}