Skip to content
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

[stdlib] Generalize some constructs for non-escapable types #73258

Draft
wants to merge 14 commits into
base: main
Choose a base branch
from
Draft
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: 8 additions & 8 deletions lib/Sema/TypeCheckInvertible.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,14 +187,14 @@ static void checkInvertibleConformanceCommon(DeclContext *dc,

static_assert((unsigned)RequirementKind::LAST_KIND == 4,
"update %select in diagnostic!");
if (illegalSecondType) {
auto t = ctx.Diags.diagnose(conformanceLoc,
diag::inverse_cannot_be_conditional_on_requirement,
thisProto,
req.getFirstType(),
static_cast<unsigned>(req.getKind()),
illegalSecondType);
}
// if (illegalSecondType) {
// auto t = ctx.Diags.diagnose(conformanceLoc,
// diag::inverse_cannot_be_conditional_on_requirement,
// thisProto,
// req.getFirstType(),
// static_cast<unsigned>(req.getKind()),
// illegalSecondType);
// }
}
}
}
Expand Down
10 changes: 7 additions & 3 deletions stdlib/public/core/Builtin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,11 @@ func _canBeClass<T>(_: T.Type) -> Int8 {
/// Returns: A new instance of type `U`, cast from `x`.
@inlinable // unsafe-performance
@_transparent
@_preInverseGenerics
@unsafe
public func unsafeBitCast<T, U>(_ x: T, to type: U.Type) -> U {
public func unsafeBitCast<T: ~Escapable, U>(
_ x: T, to type: U.Type
) -> U {
_precondition(MemoryLayout<T>.size == MemoryLayout<U>.size,
"Can't unsafeBitCast between types of different sizes")
return Builtin.reinterpretCast(x)
Expand Down Expand Up @@ -754,9 +757,10 @@ func _COWBufferForReading<T: AnyObject>(_ object: T) -> T {
/// Returns `true` if type is a POD type. A POD type is a type that does not
/// require any special handling on copying or destruction.
@_transparent
@_preInverseGenerics
public // @testable
func _isPOD<T>(_ type: T.Type) -> Bool {
return Bool(Builtin.ispod(type))
func _isPOD<T: ~Copyable & ~Escapable>(_ type: T.Type) -> Bool {
Bool(Builtin.ispod(type))
}

/// Returns `true` if `type` is known to refer to a concrete type once all
Expand Down
4 changes: 4 additions & 0 deletions stdlib/public/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,10 @@ list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "Macros")
list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "FreestandingMacros")
list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "Extern")
list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "BitwiseCopyable")
list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "NonescapableTypes")

# FIXME: Module verification appears borken.
list(APPEND swift_stdlib_compile_flags "-no-verify-emitted-module-interface")

if("${SWIFT_NATIVE_SWIFT_TOOLS_PATH}" STREQUAL "")
set(swift_bin_dir "${CMAKE_BINARY_DIR}/bin")
Expand Down
4 changes: 2 additions & 2 deletions stdlib/public/core/CompilerProtocols.swift
Original file line number Diff line number Diff line change
Expand Up @@ -266,9 +266,9 @@ public protocol CaseIterable {
/// `Optional` type conforms to `ExpressibleByNilLiteral`.
/// `ExpressibleByNilLiteral` conformance for types that use `nil` for other
/// purposes is discouraged.
public protocol ExpressibleByNilLiteral: ~Copyable {
public protocol ExpressibleByNilLiteral: ~Copyable, ~Escapable {
/// Creates an instance initialized with `nil`.
init(nilLiteral: ())
init(nilLiteral: ()) -> dependsOn(immortal) Self
}

public protocol _ExpressibleByBuiltinIntegerLiteral {
Expand Down
28 changes: 24 additions & 4 deletions stdlib/public/core/LifetimeManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,17 @@
//
//===----------------------------------------------------------------------===//

/// Extends the lifetime of the given instance.
///
/// - Parameters:
/// - x: An instance to preserve until this function returns.
@_alwaysEmitIntoClient
public func extendLifetime<T: ~Copyable & ~Escapable>(
_ x: borrowing T
) {
Builtin.fixLifetime(x)
}

/// Evaluates a closure while ensuring that the given instance is not destroyed
/// before the closure returns.
///
Expand All @@ -20,7 +31,11 @@
/// return value for the `withExtendedLifetime(_:_:)` method.
/// - Returns: The return value, if any, of the `body` closure parameter.
@_alwaysEmitIntoClient
public func withExtendedLifetime<T: ~Copyable, E: Error, Result: ~Copyable>(
public func withExtendedLifetime<
T: ~Copyable & ~Escapable,
E: Error,
Result: ~Copyable
>(
_ x: borrowing T,
_ body: () throws(E) -> Result
) throws(E) -> Result {
Expand All @@ -32,7 +47,8 @@ public func withExtendedLifetime<T: ~Copyable, E: Error, Result: ~Copyable>(
@_silgen_name("$ss20withExtendedLifetimeyq_x_q_yKXEtKr0_lF")
@usableFromInline
internal func __abi_withExtendedLifetime<T, Result>(
_ x: T, _ body: () throws -> Result
_ x: T,
_ body: () throws -> Result
) rethrows -> Result {
defer { _fixLifetime(x) }
return try body()
Expand All @@ -48,7 +64,11 @@ internal func __abi_withExtendedLifetime<T, Result>(
/// return value for the `withExtendedLifetime(_:_:)` method.
/// - Returns: The return value, if any, of the `body` closure parameter.
@_alwaysEmitIntoClient
public func withExtendedLifetime<T: ~Copyable, E: Error, Result: ~Copyable>(
public func withExtendedLifetime<
T: ~Copyable & ~Escapable,
E: Error,
Result: ~Copyable
>(
_ x: borrowing T,
_ body: (borrowing T) throws(E) -> Result
) throws(E) -> Result {
Expand All @@ -70,7 +90,7 @@ internal func __abi_withExtendedLifetime<T, Result>(
// shorten the lifetime of x to be before this point.
@_transparent
@_preInverseGenerics
public func _fixLifetime<T: ~Copyable>(_ x: borrowing T) {
public func _fixLifetime<T: ~Copyable & ~Escapable>(_ x: borrowing T) {
Builtin.fixLifetime(x)
}

Expand Down
4 changes: 3 additions & 1 deletion stdlib/public/core/ManagedBuffer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,9 @@ extension ManagedBufferPointer where Element: ~Copyable {
}
}

extension ManagedBufferPointer: Equatable {
@_preInverseGenerics
extension ManagedBufferPointer: Equatable where Element: ~Copyable {
@_preInverseGenerics
@inlinable
public static func == (
lhs: ManagedBufferPointer,
Expand Down
7 changes: 4 additions & 3 deletions stdlib/public/core/MemoryLayout.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,10 @@
/// byteCount: count * MemoryLayout<Point>.stride,
/// alignment: MemoryLayout<Point>.alignment)
@frozen // namespace
public enum MemoryLayout<T: ~Copyable>: ~BitwiseCopyable, Copyable {}
public enum MemoryLayout<T: ~Copyable & ~Escapable>
: ~BitwiseCopyable, Copyable, Escapable {}

extension MemoryLayout where T: ~Copyable {
extension MemoryLayout where T: ~Copyable & ~Escapable {
/// The contiguous memory footprint of `T`, in bytes.
///
/// A type's size does not include any dynamically allocated or out of line
Expand Down Expand Up @@ -81,7 +82,7 @@ extension MemoryLayout where T: ~Copyable {
}
}

extension MemoryLayout where T: ~Copyable {
extension MemoryLayout where T: ~Copyable & ~Escapable {
/// Returns the contiguous memory footprint of the given instance.
///
/// The result does not include any dynamically allocated or out of line
Expand Down
17 changes: 2 additions & 15 deletions stdlib/public/core/Misc.swift
Original file line number Diff line number Diff line change
Expand Up @@ -228,25 +228,12 @@ func _rethrowsViaClosure(_ fn: () throws -> ()) rethrows {
/// protocol NoRequirements: ~Copyable { }
///
/// Extensions to the `Copyable` protocol are not allowed.
@_marker public protocol Copyable {}
@_marker public protocol Copyable/*: ~Escapable*/ {}

@_documentation(visibility: internal)
@_marker public protocol Escapable {}
@_marker public protocol Escapable/*: ~Copyable*/ {}

#if $BitwiseCopyable2
#if $NonescapableTypes
@_marker public protocol BitwiseCopyable: ~Escapable { }
#else
@_marker public protocol BitwiseCopyable { }
#endif

@available(*, deprecated, message: "Use BitwiseCopyable")
public typealias _BitwiseCopyable = BitwiseCopyable
#else
#if $NonescapableTypes
@_marker public protocol _BitwiseCopyable: ~Escapable { }
#else
@_marker public protocol _BitwiseCopyable { }
#endif
public typealias BitwiseCopyable = _BitwiseCopyable
#endif
9 changes: 7 additions & 2 deletions stdlib/public/core/ObjectIdentifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ public struct ObjectIdentifier: Sendable {
public init(_ x: Any.Type) {
self._value = unsafeBitCast(x, to: Builtin.RawPointer.self)
}

@_alwaysEmitIntoClient
public init(_ x: any (~Copyable & ~Escapable).Type) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could just convert the old Any.Type initializer and mark it @_preInverseGenerics.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh! I thought Any.Type wouldn't ever include noncopyable/nonescapable stuff. I'll put it on the to do list! 👍

self._value = unsafeBitCast(x, to: Builtin.RawPointer.self)
}
}

#else
Expand All @@ -79,8 +84,8 @@ public struct ObjectIdentifier: Sendable {
self._value = Builtin.bridgeToRawPointer(x)
}

@inlinable // trivial-implementation
public init<Object>(_ x: Object.Type) {
@inlinable
public init<T: ~Copyable & ~Escapable>(_ x: T.Type) {
self._value = unsafeBitCast(x, to: Builtin.RawPointer.self)
}
}
Expand Down
18 changes: 11 additions & 7 deletions stdlib/public/core/Optional.swift
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@
/// Unconditionally unwrapping a `nil` instance with `!` triggers a runtime
/// error.
@frozen
public enum Optional<Wrapped: ~Copyable>: ~Copyable {
public enum Optional<Wrapped: ~Copyable & ~Escapable>: ~Copyable, ~Escapable {
// The compiler has special knowledge of Optional<Wrapped>, including the fact
// that it is an `enum` with cases named `none` and `some`.

Expand All @@ -132,14 +132,18 @@ public enum Optional<Wrapped: ~Copyable>: ~Copyable {
case some(Wrapped)
}

extension Optional: Copyable where Wrapped: Copyable {}
extension Optional: Copyable where Wrapped: Copyable /*& ~Escapable */ {}

extension Optional: Sendable where Wrapped: ~Copyable & Sendable { }
extension Optional: Escapable where Wrapped: Escapable /*& ~Copyable */ {}

extension Optional: BitwiseCopyable
where Wrapped: BitwiseCopyable & ~Escapable {}

extension Optional: Sendable where Wrapped: ~Copyable & ~Escapable & Sendable {}

extension Optional: BitwiseCopyable where Wrapped: BitwiseCopyable { }

@_preInverseGenerics
extension Optional: ExpressibleByNilLiteral where Wrapped: ~Copyable {
extension Optional: ExpressibleByNilLiteral where Wrapped: ~Copyable & ~Escapable {
/// Creates an instance initialized with `nil`.
///
/// Do not call this initializer directly. It is used by the compiler when you
Expand All @@ -151,12 +155,12 @@ extension Optional: ExpressibleByNilLiteral where Wrapped: ~Copyable {
/// initializer behind the scenes.
@_transparent
@_preInverseGenerics
public init(nilLiteral: ()) {
public init(nilLiteral: ()) -> dependsOn(immortal) Self {
self = .none
}
}

extension Optional where Wrapped: ~Copyable {
extension Optional where Wrapped: ~Copyable & Escapable {
/// Creates an instance that stores the given value.
@_transparent
@_preInverseGenerics
Expand Down
49 changes: 28 additions & 21 deletions stdlib/public/core/Result.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,19 @@
/// A value that represents either a success or a failure, including an
/// associated value in each case.
@frozen
public enum Result<Success: ~Copyable, Failure: Error> {
public enum Result<Success: ~Copyable & ~Escapable, Failure: Error> {
/// A success, storing a `Success` value.
case success(Success)

/// A failure, storing a `Failure` value.
case failure(Failure)
}

extension Result: Copyable where Success: Copyable {}
extension Result: Copyable where Success: Copyable /*& ~Escapable*/ {}

extension Result: Sendable where Success: Sendable & ~Copyable {}
extension Result: Escapable where Success: Escapable /*& ~Copyable*/ {}

extension Result: Sendable where Success: Sendable & ~Copyable & ~Escapable {}

extension Result: Equatable where Success: Equatable, Failure: Equatable {}

Expand Down Expand Up @@ -62,7 +64,9 @@ extension Result {
return .failure(failure)
}
}
}

extension Result {
@_spi(SwiftStdlibLegacyABI) @available(swift, obsoleted: 1)
@_silgen_name("$ss6ResultO3mapyAByqd__q_Gqd__xXElF")
@usableFromInline
Expand Down Expand Up @@ -107,7 +111,7 @@ extension Result where Success: ~Copyable {
}
}

extension Result where Success: ~Copyable {
extension Result where Success: ~Copyable & ~Escapable {
/// Returns a new result, mapping any failure value using the given
/// transformation.
///
Expand Down Expand Up @@ -204,7 +208,9 @@ extension Result {
return .failure(failure)
}
}
}

extension Result {
@_spi(SwiftStdlibLegacyABI) @available(swift, obsoleted: 1)
@_silgen_name("$ss6ResultO7flatMapyAByqd__q_GADxXElF")
@usableFromInline
Expand Down Expand Up @@ -249,7 +255,7 @@ extension Result where Success: ~Copyable {
}
}

extension Result where Success: ~Copyable {
extension Result where Success: ~Copyable & ~Escapable {
/// Returns a new result, mapping any failure value using the given
/// transformation and unwrapping the produced result.
///
Expand Down Expand Up @@ -286,7 +292,7 @@ extension Result {
}
}

extension Result where Success: ~Copyable {
extension Result where Success: ~Copyable & ~Escapable {
/// Returns the success value as a throwing expression.
///
/// Use this method to retrieve the value of this result if it represents a
Expand Down Expand Up @@ -314,21 +320,6 @@ extension Result where Success: ~Copyable {
}
}

extension Result where Success: ~Copyable {
/// Creates a new result by evaluating a throwing closure, capturing the
/// returned value as a success, or any thrown error as a failure.
///
/// - Parameter body: A potentially throwing closure to evaluate.
@_alwaysEmitIntoClient
public init(catching body: () throws(Failure) -> Success) {
do {
self = .success(try body())
} catch {
self = .failure(error)
}
}
}

extension Result {
/// ABI: Historical get() throws
@_spi(SwiftStdlibLegacyABI) @available(swift, obsoleted: 1)
Expand All @@ -345,6 +336,22 @@ extension Result {

}

extension Result where Success: ~Copyable {
/// Creates a new result by evaluating a throwing closure, capturing the
/// returned value as a success, or any thrown error as a failure.
///
/// - Parameter body: A potentially throwing closure to evaluate.
@_alwaysEmitIntoClient
public init(catching body: () throws(Failure) -> Success) {
// FIXME: This should allow a non-escapable `Success` -- but what's `self`'s lifetime dependence in that case?
do {
self = .success(try body())
} catch {
self = .failure(error)
}
}
}

extension Result where Failure == Swift.Error {
/// ABI: Historical init(catching:)
@_spi(SwiftStdlibLegacyABI) @available(swift, obsoleted: 1)
Expand Down
Loading