Skip to content

Commit 9b322e3

Browse files
committed
[stdlib] Optional: Allow non-escapable wrapped types
1 parent 9d86a45 commit 9b322e3

File tree

2 files changed

+69
-8
lines changed

2 files changed

+69
-8
lines changed

stdlib/public/core/Optional.swift

+10-7
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@
118118
/// Unconditionally unwrapping a `nil` instance with `!` triggers a runtime
119119
/// error.
120120
@frozen
121-
public enum Optional<Wrapped: ~Copyable>: ~Copyable {
121+
public enum Optional<Wrapped: ~Copyable & ~Escapable>: ~Copyable, ~Escapable {
122122
// The compiler has special knowledge of Optional<Wrapped>, including the fact
123123
// that it is an `enum` with cases named `none` and `some`.
124124

@@ -132,14 +132,17 @@ public enum Optional<Wrapped: ~Copyable>: ~Copyable {
132132
case some(Wrapped)
133133
}
134134

135-
extension Optional: Copyable where Wrapped: Copyable {}
135+
extension Optional: Copyable where Wrapped: Copyable /*& ~Escapable */ {}
136+
extension Optional: Escapable where Wrapped: Escapable /*& ~Copyable */ {}
136137

137-
extension Optional: Sendable where Wrapped: ~Copyable & Sendable { }
138+
extension Optional: BitwiseCopyable where Wrapped: BitwiseCopyable {}
139+
// FIXME: Maybe BitwiseCopyable shouldn't require Escapability
140+
141+
extension Optional: Sendable where Wrapped: ~Copyable & ~Escapable & Sendable {}
138142

139-
extension Optional: BitwiseCopyable where Wrapped: BitwiseCopyable { }
140143

141144
@_preInverseGenerics
142-
extension Optional: ExpressibleByNilLiteral where Wrapped: ~Copyable {
145+
extension Optional: ExpressibleByNilLiteral where Wrapped: ~Copyable & ~Escapable {
143146
/// Creates an instance initialized with `nil`.
144147
///
145148
/// Do not call this initializer directly. It is used by the compiler when you
@@ -151,12 +154,12 @@ extension Optional: ExpressibleByNilLiteral where Wrapped: ~Copyable {
151154
/// initializer behind the scenes.
152155
@_transparent
153156
@_preInverseGenerics
154-
public init(nilLiteral: ()) {
157+
public init(nilLiteral: ()) -> dependsOn(immortal) Self {
155158
self = .none
156159
}
157160
}
158161

159-
extension Optional where Wrapped: ~Copyable {
162+
extension Optional where Wrapped: ~Copyable & Escapable {
160163
/// Creates an instance that stores the given value.
161164
@_transparent
162165
@_preInverseGenerics

test/stdlib/Optional.swift

+59-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-run-simple-swift
1+
// RUN: %target-run-simple-swift(-enable-experimental-feature NonescapableTypes)
22
// REQUIRES: executable_test
33
// REQUIRES: reflection
44

@@ -426,4 +426,62 @@ OptionalTests.test("unsafelyUnwrapped nil")
426426
}
427427
#endif
428428

429+
func isCopyable<T: ~Copyable & ~Escapable>(_: T.Type) -> Bool { false }
430+
func isCopyable<T: ~Escapable>(_: T.Type) -> Bool { true }
431+
432+
func isBitwiseCopyable<T: ~Copyable & ~Escapable>(_: T.Type) -> Bool { false }
433+
func isBitwiseCopyable<T: BitwiseCopyable & ~Escapable>(_: T.Type) -> Bool { true }
434+
435+
#if $NonescapableTypes
436+
func isEscapable<T: ~Escapable & ~Copyable>(_: T.Type) -> Bool { false }
437+
func isEscapable<T: ~Copyable>(_: T.Type) -> Bool { true }
438+
#endif
439+
440+
struct TrivialStruct {}
441+
struct NoncopyableStruct: ~Copyable {}
442+
class RegularClass {}
443+
444+
#if $NonescapableTypes
445+
struct NonescapableStruct: ~Escapable, BitwiseCopyable {}
446+
struct NoncopyableNonescapableStruct: ~Copyable, ~Escapable {}
447+
struct NonescapableNontrivialStruct: ~Escapable {
448+
let foo: RegularClass? = nil
449+
}
450+
#endif
451+
452+
OptionalTests.test("Copyability") {
453+
expectTrue(isCopyable(Optional<TrivialStruct>.self))
454+
expectFalse(isCopyable(Optional<NoncopyableStruct>.self))
455+
expectTrue(isCopyable(Optional<RegularClass>.self))
456+
#if $NonescapableTypes
457+
expectTrue(isCopyable(Optional<NonescapableStruct>.self))
458+
expectFalse(isCopyable(Optional<NoncopyableNonescapableStruct>.self))
459+
expectTrue(isCopyable(Optional<NonescapableNontrivialStruct>.self))
460+
#endif
461+
}
462+
463+
OptionalTests.test("BitwiseCopyability") {
464+
expectTrue(isBitwiseCopyable(Optional<TrivialStruct>.self))
465+
expectFalse(isBitwiseCopyable(Optional<NoncopyableStruct>.self))
466+
expectFalse(isBitwiseCopyable(Optional<RegularClass>.self))
467+
#if $NonescapableTypes
468+
// FIXME: Should this be true?
469+
expectFalse(isBitwiseCopyable(Optional<NonescapableStruct>.self))
470+
471+
expectFalse(isBitwiseCopyable(Optional<NoncopyableNonescapableStruct>.self))
472+
expectFalse(isBitwiseCopyable(Optional<NonescapableNontrivialStruct>.self))
473+
#endif
474+
}
475+
476+
#if $NonescapableTypes
477+
OptionalTests.test("Escapability") {
478+
expectTrue(isEscapable(Optional<TrivialStruct>.self))
479+
expectTrue(isEscapable(Optional<NoncopyableStruct>.self))
480+
expectTrue(isEscapable(Optional<RegularClass>.self))
481+
expectFalse(isEscapable(Optional<NonescapableStruct>.self))
482+
expectFalse(isEscapable(Optional<NoncopyableNonescapableStruct>.self))
483+
expectFalse(isEscapable(Optional<NonescapableNontrivialStruct>.self))
484+
}
485+
#endif
486+
429487
runAllTests()

0 commit comments

Comments
 (0)