diff --git a/CHANGES b/CHANGES index a7411b6dd..a2fde8986 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,18 @@ * Lwt_result.catch now takes a function (unit -> 'a t) rather than a promise ('a t) (#965) + * Remove the deprecated Lwt.result type (use Stdlib.result instead) (#968) + + * Remove the deprecated Lwt.make_value and Lwt.make_result functions (use Ok and Error instead) (#968) + + * Remove the deprecated and unsafe waiter_of_wakener (keep the waiter around when you create the wakener instead) (#968) + + * Remove the deprecated Lwt_stream.on_termination and Lwt_stream.on_terminate (bind to Lwt_stream.closed instead) (#968) + + * Remove the deprecated Lwt_stream.result type (use Stdlib.result instead) (#968) + + * Remove the deprecated Lwt_stream.map_exn function (use wrap_exn instead) (#968) + ====== Additions ====== * Lwt.reraise an exception raising function which preserves backtraces, recommended for use in Lwt.catch (#963) diff --git a/src/core/lwt.ml b/src/core/lwt.ml index 295a37af5..cfab66246 100644 --- a/src/core/lwt.ml +++ b/src/core/lwt.ml @@ -537,11 +537,6 @@ module Public_types = struct type +'a t type -'a u - (* The contravariance of resolvers is, technically, unsound due to the - existence of [Lwt.waiter_of_wakener]. That is why that function is - deprecated. See - - https://github.com/ocsigen/lwt/issues/458 *) let to_public_promise : ('a, _, _) promise -> 'a t = Obj.magic let to_public_resolver : ('a, _, _) promise -> 'a u = Obj.magic @@ -570,18 +565,10 @@ struct be optimized away even on older versions of OCaml that don't have Flambda and don't support [[@@ocaml.unboxed]]. *) - - - (* Internal name of the public [+'a Lwt.result]. The public name is defined - later in the module. This is to avoid potential confusion with - [Stdlib.result]/[Result.result], as the public name would not be - prefixed with [Lwt.] inside this file. *) - type +'a lwt_result = ('a, exn) Result.t - (* This could probably save an allocation by using [Obj.magic]. *) let state_of_result = function - | Result.Ok x -> Fulfilled x - | Result.Error exn -> Rejected exn + | Ok x -> Fulfilled x + | Error exn -> Rejected exn end include Public_types @@ -1341,11 +1328,11 @@ include Resolution_loop module Resolving : sig - val wakeup_later_result : 'a u -> 'a lwt_result -> unit + val wakeup_later_result : 'a u -> ('a, exn) result -> unit val wakeup_later : 'a u -> 'a -> unit val wakeup_later_exn : _ u -> exn -> unit - val wakeup_result : 'a u -> 'a lwt_result -> unit + val wakeup_result : 'a u -> ('a, exn) result -> unit val wakeup : 'a u -> 'a -> unit val wakeup_exn : _ u -> exn -> unit @@ -1373,8 +1360,8 @@ struct ignore p let wakeup_result r result = wakeup_general "wakeup_result" r result - let wakeup r v = wakeup_general "wakeup" r (Result.Ok v) - let wakeup_exn r exn = wakeup_general "wakeup_exn" r (Result.Error exn) + let wakeup r v = wakeup_general "wakeup" r (Ok v) + let wakeup_exn r exn = wakeup_general "wakeup_exn" r (Error exn) let wakeup_later_general api_function_name r result = let Internal p = to_internal_resolver r in @@ -1397,9 +1384,9 @@ struct let wakeup_later_result r result = wakeup_later_general "wakeup_later_result" r result let wakeup_later r v = - wakeup_later_general "wakeup_later" r (Result.Ok v) + wakeup_later_general "wakeup_later" r (Ok v) let wakeup_later_exn r exn = - wakeup_later_general "wakeup_later_exn" r (Result.Error exn) + wakeup_later_general "wakeup_later_exn" r (Error exn) @@ -1471,15 +1458,15 @@ module Trivial_promises : sig val return : 'a -> 'a t val fail : exn -> _ t - val of_result : 'a lwt_result -> 'a t + val of_result : ('a, exn) result -> 'a t val return_unit : unit t val return_true : bool t val return_false : bool t val return_none : _ option t val return_some : 'a -> 'a option t - val return_ok : 'a -> ('a, _) Result.t t - val return_error : 'e -> (_, 'e) Result.t t + val return_ok : 'a -> ('a, _) result t + val return_error : 'e -> (_, 'e) result t val return_nil : _ list t val fail_with : string -> _ t @@ -1501,8 +1488,8 @@ struct let return_nil = return [] let return_true = return true let return_false = return false - let return_ok x = return (Result.Ok x) - let return_error x = return (Result.Error x) + let return_ok x = return (Ok x) + let return_error x = return (Error x) let fail_with msg = to_public_promise {state = Rejected (Failure msg)} @@ -1525,8 +1512,6 @@ sig val wait : unit -> 'a t * 'a u val task : unit -> 'a t * 'a u - val waiter_of_wakener : 'a u -> 'a t - val add_task_r : 'a u Lwt_sequence.t -> 'a t val add_task_l : 'a u Lwt_sequence.t -> 'a t @@ -1565,12 +1550,6 @@ struct - let waiter_of_wakener r = - let Internal r = to_internal_resolver r in - let p = r in - to_public_promise p - - let cast_sequence_node (node : 'a u Lwt_sequence.node) @@ -2637,7 +2616,7 @@ struct let count_resolved_promises_in (ps : 'a t list) = let rec count_and_gather_rejected total rejected ps = match ps with - | [] -> Result.Error (total, rejected) + | [] -> Error (total, rejected) | p :: ps -> let Internal q = to_internal_promise p in match (underlying q).state with @@ -2647,7 +2626,7 @@ struct in let rec count_fulfilled total ps = match ps with - | [] -> Result.Ok total + | [] -> Ok total | p :: ps -> let Internal q = to_internal_promise p in match (underlying q).state with @@ -2709,7 +2688,7 @@ struct invalid_arg "Lwt.choose [] would return a promise that is pending forever"; match count_resolved_promises_in ps with - | Result.Ok 0 -> + | Ok 0 -> let p = new_pending ~how_to_cancel:(propagate_cancel_to_several ps) in let callback result = @@ -2723,13 +2702,13 @@ struct to_public_promise p - | Result.Ok 1 -> + | Ok 1 -> nth_resolved ps 0 - | Result.Ok n -> + | Ok n -> nth_resolved ps (Random.State.int (Lazy.force prng) n) - | Result.Error (n, ps) -> + | Error (n, ps) -> nth_resolved ps (Random.State.int (Lazy.force prng) n) let pick ps = @@ -3184,14 +3163,3 @@ struct let (let+) x f = map f x let (and+) = both end - - -module Lwt_result_type = -struct - type +'a result = 'a lwt_result - - (* Deprecated. *) - let make_value v = Result.Ok v - let make_error exn = Result.Error exn -end -include Lwt_result_type diff --git a/src/core/lwt.mli b/src/core/lwt.mli index 1a8144baf..4d8ad6dd6 100644 --- a/src/core/lwt.mli +++ b/src/core/lwt.mli @@ -1600,18 +1600,7 @@ Lwt.fail (Stdlib.Invalid_argument s) (** {3 Result type} *) -type nonrec +'a result = ('a, exn) result -(** Representation of the content of a resolved promise of type - ['a ]{!Lwt.t}. - - This type is effectively - -{[ -type +'a Lwt.result = - | Ok of 'a - | Error of exn -]} - +(** A resolved promise of type ['a ]{!Lwt.t} is either fulfilled with a value of type ['a], or rejected with an exception. @@ -1619,18 +1608,10 @@ type +'a Lwt.result = fulfilled corresponds to [Ok of 'a], and rejected corresponds to [Error of exn]. - It's important to note that this type constructor, [Lwt.result], is - different from [Stdlib.result]. It is a specialization of [Stdlib.result] so - that the [Error] constructor always carries [exn]. - For Lwt programming with [result] where the [Error] constructor can carry - arbitrary error types, see module {!Lwt_result}. - - The naming conflict between [Lwt.result] and [Stdlib.result] is an - unfortunate historical accident. [Stdlib.result] did not exist when - [Lwt.result] was created. *) + arbitrary error types, see module {!Lwt_result}. *) -val of_result : 'a result -> 'a t +val of_result : ('a, exn) result -> 'a t (** [Lwt.of_result r] converts an r to a resolved promise. - If [r] is [Ok v], [Lwt.of_result r] is [Lwt.return v], i.e. a promise @@ -1638,7 +1619,7 @@ val of_result : 'a result -> 'a t - If [r] is [Error exn], [Lwt.of_result r] is [Lwt.fail exn], i.e. a promise rejected with [exn]. *) -val wakeup_later_result : 'a u -> 'a result -> unit +val wakeup_later_result : 'a u -> ('a, exn) result -> unit (** [Lwt.wakeup_later_result r result] resolves the pending promise [p] associated to resolver [r], according to [result]: @@ -1802,43 +1783,12 @@ val wakeup_exn : _ u -> exn -> unit (** [Lwt.wakeup_exn r exn] is like {!Lwt.wakeup_later_exn}[ r exn], but has the same problems as {!Lwt.wakeup}. *) -val wakeup_result : 'a u -> 'a result -> unit +val wakeup_result : 'a u -> ('a, exn) result -> unit (** [Lwt.wakeup_result r result] is like {!Lwt.wakeup_later_result}[ r result], but has the same problems as {!Lwt.wakeup}. *) -(** {3 Helpers for resolving} *) - -val make_value : 'a -> 'a result - [@@ocaml.deprecated - " Use Ok (from Stdlib) instead."] -(** [Lwt.make_value v] is equivalent to - {{: https://ocaml.org/api/Stdlib.html#TYPEresult} - [Ok v]}. - - @deprecated Use [Ok] instead *) - -val make_error : exn -> _ result - [@@ocaml.deprecated - " Use Error (from Stdlib) instead."] -(** [Lwt.make_error exn] is equivalent to - {{: https://ocaml.org/api/Stdlib.html#TYPEresult} - [Error exn]}. - - @deprecated Use [Error] (from Stdlib) instead. *) - -val waiter_of_wakener : 'a u -> 'a t - [@@ocaml.deprecated -" This function should be avoided, because it makes subtyping of resolvers - unsound. See - https://github.com/ocsigen/lwt/issues/458"] -(** [Lwt.waiter_of_wakener r] evaluates to the promise associated with resolver - [r]. - - @deprecated Keep the reference to the promise instead. *) - - (** {3 Linked lists of promises} *) diff --git a/src/core/lwt_stream.ml b/src/core/lwt_stream.ml index 8fc5fff34..88e83f449 100644 --- a/src/core/lwt_stream.ml +++ b/src/core/lwt_stream.ml @@ -79,6 +79,8 @@ type 'a t = { source : 'a source; (* The source of the stream. *) close : unit Lwt.u; + (* A wakener for a thread that sleeps until the stream is closed. *) + closed : unit Lwt.t; (* A waiter for a thread that sleeps until the stream is closed. *) mutable node : 'a node; (* Pointer to first pending element, or to [last] if there is no @@ -107,18 +109,15 @@ let clone s = { source = s.source; close = s.close; + closed = s.closed; node = s.node; last = s.last; } let from_source source = - let last = new_node () in - let _, close = Lwt.wait () in - { source = source - ; close = close - ; node = last - ; last = ref last - } + let node = new_node () in + let closed, close = Lwt.wait () in + { source ; close ; closed ; node ; last = ref node } let from f = from_source (From { from_create = f; from_thread = Lwt.return_unit }) @@ -126,17 +125,11 @@ let from f = let from_direct f = from_source (From_direct f) -let closed s = - (Lwt.waiter_of_wakener [@ocaml.warning "-3"]) s.close +let closed s = s.closed let is_closed s = not (Lwt.is_sleeping (closed s)) -let on_termination s f = - Lwt.async (fun () -> closed s >|= f) - -let on_terminate = on_termination - let enqueue' e last = let node = !last and new_last = new_node () in @@ -160,11 +153,10 @@ let create_with_reference () = (* [push] should not close over [t] so that it can be garbage collected even * there are still references to [push]. Unpack all the components of [t] * that [push] needs and reference those identifiers instead. *) - let close = t.close and last = t.last in + let close = t.close and closed = t.closed and last = t.last in (* The push function. It does not keep a reference to the stream. *) let push x = - let waiter_of_wakener = Lwt.waiter_of_wakener [@ocaml.warning "-3"] in - if not (Lwt.is_sleeping (waiter_of_wakener close)) then raise Closed; + if not (Lwt.is_sleeping closed) then raise Closed; (* Push the element at the end of the queue. *) enqueue' x last; (* Send a signal if at least one thread is waiting for a new @@ -448,37 +440,11 @@ let rec get_rec s node = let get s = get_rec s s.node -type 'a result = - | Value of 'a - | Error of exn - let rec get_exn_rec s node = if node == !(s.last) then Lwt.try_bind (fun () -> feed s) (fun () -> get_exn_rec s node) - (fun exn -> Lwt.return (Some (Error exn : _ result))) - (* Note: the [Error] constructor above is from [Lwt_stream.result], not - [Stdlib.result], nor its alias [Lwt.result]. [Lwt_stream.result] is - a deprecated type, defined right above this function. - - The type constraint is necessary to avoid a warning about an ambiguous - constructor. *) - else - match node.data with - | Some value -> - consume s node; - Lwt.return (Some (Value value)) - | None -> - Lwt.return_none - -let map_exn s = from (fun () -> get_exn_rec s s.node) - -let rec get_exn_rec' s node = - if node == !(s.last) then - Lwt.try_bind - (fun () -> feed s) - (fun () -> get_exn_rec' s node) (fun exn -> Lwt.return (Some (Result.Error exn))) else match node.data with @@ -488,7 +454,7 @@ let rec get_exn_rec' s node = | None -> Lwt.return_none -let wrap_exn s = from (fun () -> get_exn_rec' s s.node) +let wrap_exn s = from (fun () -> get_exn_rec s s.node) let rec nget_rec node acc n s = if n <= 0 then diff --git a/src/core/lwt_stream.mli b/src/core/lwt_stream.mli index 80ee6c470..11e9a8472 100644 --- a/src/core/lwt_stream.mli +++ b/src/core/lwt_stream.mli @@ -263,20 +263,6 @@ val closed : 'a t -> unit Lwt.t @since 2.6.0 *) -val on_termination : 'a t -> (unit -> unit) -> unit -[@@ocaml.deprecated " Bind on Lwt_stream.closed."] -(** [on_termination st f] executes [f] when the end of the stream [st] - is reached. Note that the stream may still contain elements if - {!peek} or similar was used. - - @deprecated Use {!closed}. *) - -val on_terminate : 'a t -> (unit -> unit) -> unit -[@@ocaml.deprecated " Bind on Lwt_stream.closed."] -(** Same as {!on_termination}. - - @deprecated Use {!closed}. *) - (** {2 Stream transversal} *) (** Note: all the following functions are destructive. @@ -360,7 +346,7 @@ val concat : 'a t t -> 'a t val flatten : 'a list t -> 'a t (** [flatten st = map_list (fun l -> l) st] *) -val wrap_exn : 'a t -> 'a Lwt.result t +val wrap_exn : 'a t -> ('a, exn) result t (** [wrap_exn s] is a stream [s'] such that each time [s] yields a value [v], [s'] yields [Result.Ok v], and when the source of [s] raises an exception [e], [s'] yields [Result.Error e]. @@ -398,32 +384,3 @@ val hexdump : char t -> string t end ]} *) - -(** {2 Deprecated} *) - -type 'a result = - | Value of 'a - | Error of exn -[@@ocaml.deprecated - " This type is being replaced by Lwt.result and the corresponding function - Lwt_stream.wrap_exn."] -(** A value or an error. - - @deprecated Replaced by {!wrap_exn}, which uses {!Lwt.result}. *) - -[@@@ocaml.warning "-3"] -val map_exn : 'a t -> 'a result t -[@@ocaml.deprecated " Use Lwt_stream.wrap_exn"] -(** [map_exn s] returns a stream that captures all exceptions raised - by the source of the stream (the function passed to {!from}). - - Note that for push-streams (as returned by {!create}) all - elements of the mapped streams are values. - - If the stream source keeps raising the same exception [e] each time the - stream is read, the stream produced by [map_exn] is unbounded. Reading it - will produce [Lwt_stream.Error e] indefinitely. - - @deprecated Use {!wrap_exn}. *) - -[@@@ocaml.warning "+3"] diff --git a/test/core/test_lwt.ml b/test/core/test_lwt.ml index 803b02364..54fc816e4 100644 --- a/test/core/test_lwt.ml +++ b/test/core/test_lwt.ml @@ -163,11 +163,6 @@ let initial_promise_tests = suite "initial promises" [ Lwt.wakeup_result r (Result.Ok "foo"); state_is (Lwt.Return "foo") p end; - - test "waiter_of_wakener" begin fun () -> - let p, r = Lwt.wait () in - Lwt.return ((Lwt.waiter_of_wakener [@ocaml.warning "-3"]) r == p) - end; ] let suites = suites @ [initial_promise_tests] @@ -4360,23 +4355,6 @@ let suites = suites @ [lift_tests] -(* [Lwt.make_value] and [Lwt.make_error] are deprecated, but test them anyway, - for good measure. *) -let make_value_and_error_tests = suite "make_value and make_error" [ - test "make_value" begin fun () -> - Lwt.return ((Lwt.make_value [@ocaml.warning "-3"]) 42 = Result.Ok 42) - end; - - test "make_error" begin fun () -> - Lwt.return - ((Lwt.make_error [@ocaml.warning "-3"]) Exception = - Result.Error Exception) - end; -] -let suites = suites @ [make_value_and_error_tests] - - - (* These tests exercise the callback cleanup mechanism of the Lwt core, which is an implementation detail. When a promise [p] is repeatedly used in functions such as [Lwt.choose], but remains pending, while other promises passed to diff --git a/test/core/test_lwt_stream.ml b/test/core/test_lwt_stream.ml index 31af36df8..a19f0b3df 100644 --- a/test/core/test_lwt_stream.ml +++ b/test/core/test_lwt_stream.ml @@ -371,7 +371,7 @@ let suite = suite "lwt_stream" [ let b9 = Lwt_stream.is_closed st in return (b1 && b2 && b3 && b4 && b5 && b6 && not b7 && not b8 && b9)); - test "closed" + test "closed(bind)" (fun () -> let st = Lwt_stream.from_direct ( let value = ref (Some 1) in @@ -387,15 +387,14 @@ let suite = suite "lwt_stream" [ let b2 = !b = true in return (b1 && b2)); - test "on_termination" + test "closed(on_termination)" (fun () -> let st = Lwt_stream.from_direct ( let value = ref (Some 1) in fun () -> let r = !value in value := None; r) in let b = ref false in - (Lwt_stream.on_termination [@ocaml.warning "-3"]) - st (fun () -> b := true); + (Lwt.on_termination (Lwt_stream.closed st) (fun () -> b := true)); ignore (Lwt_stream.peek st); let b1 = !b = false in ignore (Lwt_stream.junk st); @@ -404,13 +403,12 @@ let suite = suite "lwt_stream" [ let b3 = Lwt_stream.is_closed st in Lwt.return (b1 && b2 && b3)); - test "on_termination when closed" + test "closed when closed" (fun () -> let st = Lwt_stream.of_list [] in let b = ref false in let b1 = Lwt_stream.is_closed st in - (Lwt_stream.on_termination [@ocaml.warning "-3"]) - st (fun () -> b := true); + (Lwt.on_termination (Lwt_stream.closed st) (fun () -> b := true)); Lwt.return (b1 && !b)); test "choose_exhausted"