Skip to content

Commit

Permalink
Merge pull request #1570 from hylo-lang/optional-api
Browse files Browse the repository at this point in the history
Improve the API of `Optional`
  • Loading branch information
kyouko-taiga authored Aug 24, 2024
2 parents 02a4f3c + a4fe311 commit 4c84fbc
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 5 deletions.
7 changes: 2 additions & 5 deletions Sources/IR/Emitter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)

Expand Down
35 changes: 35 additions & 0 deletions StandardLibrary/Sources/Core/Optional.hylo
Original file line number Diff line number Diff line change
Expand Up @@ -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<E, R>(_ transform: inout [E](T) -> R) -> Optional<R> {
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
Expand Down
15 changes: 15 additions & 0 deletions Tests/LibraryTests/TestCases/OptionalTests.hylo
Original file line number Diff line number Diff line change
Expand Up @@ -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())
}

0 comments on commit 4c84fbc

Please sign in to comment.