refactor: make Promise implementation opaque (#3273)

This follows the standard `Ref` recipe and moves the `unsafeCast` into
C++
This commit is contained in:
Sebastian Ullrich 2024-02-09 11:43:41 +01:00 committed by GitHub
parent a7364499d2
commit b548b4faae
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 19 additions and 11 deletions

View file

@ -6,11 +6,15 @@ Authors: Gabriel Ebner
prelude
import Init.System.IO
set_option linter.missingDocs true
namespace IO
/-- Internally, a `Promise` is just a `Task` that is in the "Promised" or "Finished" state. -/
private opaque PromiseImpl (α : Type) : { P : Type // Nonempty α ↔ Nonempty P } :=
⟨Task α, fun ⟨_⟩ => ⟨⟨_⟩⟩, fun ⟨⟨_⟩⟩ => ⟨_⟩⟩
private opaque PromisePointed : NonemptyType.{0}
private structure PromiseImpl (α : Type) : Type where
prom : PromisePointed.type
h : Nonempty α
/--
`Promise α` allows you to create a `Task α` whose value is provided later by calling `resolve`.
@ -26,10 +30,10 @@ Every promise must eventually be resolved.
Otherwise the memory used for the promise will be leaked,
and any tasks depending on the promise's result will wait forever.
-/
def Promise (α : Type) : Type := (PromiseImpl α).1
def Promise (α : Type) : Type := PromiseImpl α
instance [Nonempty α] : Nonempty (Promise α) :=
(PromiseImpl α).2.1 inferInstance
instance [s : Nonempty α] : Nonempty (Promise α) :=
Nonempty.intro { prom := Classical.choice PromisePointed.property, h := s }
/-- Creates a new `Promise`. -/
@[extern "lean_io_promise_new"]
@ -43,15 +47,12 @@ Only the first call to this function has an effect.
@[extern "lean_io_promise_resolve"]
opaque Promise.resolve (value : α) (promise : @& Promise α) : BaseIO Unit
private unsafe def Promise.resultImpl (promise : Promise α) : Task α :=
unsafeCast promise
/--
The result task of a `Promise`.
The task blocks until `Promise.resolve` is called.
-/
@[implemented_by Promise.resultImpl]
@[extern "lean_io_promise_result"]
opaque Promise.result (promise : Promise α) : Task α :=
have : Nonempty α := (PromiseImpl α).2.2 ⟨promise⟩
have : Nonempty α := promise.h
Classical.choice inferInstance

View file

@ -1033,6 +1033,8 @@ extern "C" LEAN_EXPORT b_obj_res lean_io_wait_any_core(b_obj_arg task_list) {
return g_task_manager->wait_any(task_list);
}
// Internally, a `Promise` is just a `Task` that is in the "Promised" or "Finished" state
extern "C" LEAN_EXPORT obj_res lean_io_promise_new(obj_arg) {
lean_always_assert(g_task_manager);
bool keep_alive = false;
@ -1050,6 +1052,11 @@ extern "C" LEAN_EXPORT obj_res lean_io_promise_resolve(obj_arg value, b_obj_arg
return io_result_mk_ok(box(0));
}
extern "C" LEAN_EXPORT obj_res lean_io_promise_result(obj_arg promise) {
// the task is the promise itself
return promise;
}
// =======================================
// Natural numbers