From b03fc42bdc1215d2363bf5cebc51764bde270c37 Mon Sep 17 00:00:00 2001 From: Dimi Racordon Date: Sat, 24 Aug 2024 01:20:41 +0200 Subject: [PATCH 1/2] Fix the synthesization of move-initializer for union types --- Sources/IR/Emitter.swift | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Sources/IR/Emitter.swift b/Sources/IR/Emitter.swift index 6b87ba421..3c6fcf102 100644 --- a/Sources/IR/Emitter.swift +++ b/Sources/IR/Emitter.swift @@ -737,7 +737,7 @@ struct Emitter { let targets = UnionSwitch.Targets( t.elements.map({ (e) in (key: e, value: appendBlock()) }), uniquingKeysWith: { (a, _) in a }) - emitUnionSwitch(on: receiver, toOneOf: targets, at: site) + emitUnionSwitch(on: argument, toOneOf: targets, at: site) let tail = appendBlock() for (u, b) in targets { @@ -757,12 +757,9 @@ struct Emitter { of receiver: Operand, consuming argument: Operand, containing payload: AnyType, at site: SourceRange ) { - // Deinitialize the receiver. + // Move the argument. let x0 = insert( module.makeOpenUnion(receiver, as: payload, forInitialization: true, at: site))! - emitDeinit(x0, at: site) - - // Move the argument. let x1 = insert(module.makeOpenUnion(argument, as: payload, at: site))! emitMove([.set], x1, to: x0, at: site) From a4fe3115248600f0733e9f0889fdfd4ca47199f0 Mon Sep 17 00:00:00 2001 From: Dimi Racordon Date: Sat, 24 Aug 2024 01:22:48 +0200 Subject: [PATCH 2/2] Improve the API of 'Optional' --- StandardLibrary/Sources/Core/Optional.hylo | 35 +++++++++++++++++++ .../LibraryTests/TestCases/OptionalTests.hylo | 15 ++++++++ 2 files changed, 50 insertions(+) diff --git a/StandardLibrary/Sources/Core/Optional.hylo b/StandardLibrary/Sources/Core/Optional.hylo index 3df537677..11a9a9329 100644 --- a/StandardLibrary/Sources/Core/Optional.hylo +++ b/StandardLibrary/Sources/Core/Optional.hylo @@ -18,6 +18,41 @@ public extension Optional { None() as Optional } + /// Returns `true` iff `self` is equal to `.none()`. + public fun is_empty() -> Bool { + if let _: T = self { false } else { true } + } + + /// Returns an optional containing the result of calling `transform` on the value wrapped in + /// `self` or `.none()` is `self` is empty. + public fun map(_ transform: inout [E](T) -> R) -> Optional { + if let w? = self { transform(w) as _ } else { .none() } + } + +} + +public extension Optional where T: Movable { + + /// Returns the value wrapped in `self` or stops execution if `self` is empty. + /// + /// - Requires: `self` is not empty. + public fun postfix!() sink -> T { + if sink let r? = self { + return r + } else { + fatal_error("optional is empty") + } + } + + /// Returns the value wrapped in `self` and assigns it to `.none()`. + /// + /// - Requires: `self` is not empty. + public fun release() inout -> T { + sink let wrapped = self! + &self = .none() + return wrapped + } + } // Note: We can't declare confitional conformance of `Optional` to "umbrella traits" yet without diff --git a/Tests/LibraryTests/TestCases/OptionalTests.hylo b/Tests/LibraryTests/TestCases/OptionalTests.hylo index 2c266c098..3ba195d71 100644 --- a/Tests/LibraryTests/TestCases/OptionalTests.hylo +++ b/Tests/LibraryTests/TestCases/OptionalTests.hylo @@ -12,4 +12,19 @@ public fun main() { &x = .none() let z = if let i: Int = x { i.copy() } else { 0 } precondition(z == 0) + + &x = 42 as _ + precondition(x! == 42) + + &x = 42 as _ + precondition(!x.is_empty()) + + &x = 42 as _ + precondition(x.release() == 42) + precondition(x.is_empty()) + + &x = 42 as _ + &x = x.map(fun(_ n) { n + 1 }) + precondition(x.release() == 43) + precondition((x.map(fun(_ n) { n + 1 })).is_empty()) }