Skip to content

Commit

Permalink
More inference-friendly API for lazy
Browse files Browse the repository at this point in the history
The signature for new was

```
fn new<F>(f: F) -> Lazy<T, F>
```

Notably, with `F` unconstrained, `T` can be literally anything, and just
`let _ = Lazy::new(|| 92)` would not typecheck.

This historiacally was a necessity -- `new` is a `const` function, it
couldn't have any bounds. Today though, we can move `new` under the `F:
FnOnce() -> T` bound, which gives the compiler enough data to infer the
type of T from closure.
  • Loading branch information
matklad committed Oct 29, 2022
1 parent 33b55ac commit 3cddc8b
Show file tree
Hide file tree
Showing 4 changed files with 14 additions and 7 deletions.
4 changes: 1 addition & 3 deletions library/core/src/cell/lazy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ pub struct LazyCell<T, F = fn() -> T> {
init: Cell<Option<F>>,
}

impl<T, F> LazyCell<T, F> {
impl<T, F: FnOnce() -> T> LazyCell<T, F> {
/// Creates a new lazy value with the given initializing function.
///
/// # Examples
Expand All @@ -51,9 +51,7 @@ impl<T, F> LazyCell<T, F> {
pub const fn new(init: F) -> LazyCell<T, F> {
LazyCell { cell: OnceCell::new(), init: Cell::new(Some(init)) }
}
}

impl<T, F: FnOnce() -> T> LazyCell<T, F> {
/// Forces the evaluation of this lazy value and returns a reference to
/// the result.
///
Expand Down
6 changes: 6 additions & 0 deletions library/core/tests/lazy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,12 @@ fn lazy_new() {
assert_eq!(called.get(), 1);
}

// Check that we can infer `T` from closure's type.
#[test]
fn lazy_type_inference() {
let _ = LazyCell::new(|| ());
}

#[test]
fn aliasing_in_get() {
let x = OnceCell::new();
Expand Down
5 changes: 1 addition & 4 deletions library/std/src/sync/lazy_lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,14 @@ pub struct LazyLock<T, F = fn() -> T> {
cell: OnceLock<T>,
init: Cell<Option<F>>,
}

impl<T, F> LazyLock<T, F> {
impl<T, F: FnOnce() -> T> LazyLock<T, F> {
/// Creates a new lazy value with the given initializing
/// function.
#[unstable(feature = "once_cell", issue = "74465")]
pub const fn new(f: F) -> LazyLock<T, F> {
LazyLock { cell: OnceLock::new(), init: Cell::new(Some(f)) }
}
}

impl<T, F: FnOnce() -> T> LazyLock<T, F> {
/// Forces the evaluation of this lazy value and
/// returns a reference to result. This is equivalent
/// to the `Deref` impl, but is explicit.
Expand Down
6 changes: 6 additions & 0 deletions library/std/src/sync/lazy_lock/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,12 @@ fn sync_lazy_poisoning() {
}
}

// Check that we can infer `T` from closure's type.
#[test]
fn lazy_type_inference() {
let _ = LazyCell::new(|| ());
}

#[test]
fn is_sync_send() {
fn assert_traits<T: Send + Sync>() {}
Expand Down

0 comments on commit 3cddc8b

Please sign in to comment.