about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2022-12-27 12:33:33 -0800
committerGitHub <noreply@github.com>2022-12-27 12:33:33 -0800
commit4b668a1feed45b3061fbf0d1d42fb1a695c0d4b3 (patch)
tree68ccf98bcfa2d79d78ae0fbe27a4a505a056b1c2
parentdb7962532610cfbfb9be17e8d6c1b48acf5ed184 (diff)
parent3cddc8bff6d5357fc68a87c802a7f4fa3e1642a7 (diff)
downloadrust-4b668a1feed45b3061fbf0d1d42fb1a695c0d4b3.tar.gz
rust-4b668a1feed45b3061fbf0d1d42fb1a695c0d4b3.zip
Rollup merge of #103718 - matklad:infer-lazy, r=dtolnay
More inference-friendly API for lazy

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.
-rw-r--r--library/core/src/cell/lazy.rs4
-rw-r--r--library/core/tests/lazy.rs6
-rw-r--r--library/std/src/sync/lazy_lock.rs5
-rw-r--r--library/std/src/sync/lazy_lock/tests.rs6
4 files changed, 14 insertions, 7 deletions
diff --git a/library/core/src/cell/lazy.rs b/library/core/src/cell/lazy.rs
index b355d94ce49..19f80daef1d 100644
--- a/library/core/src/cell/lazy.rs
+++ b/library/core/src/cell/lazy.rs
@@ -35,7 +35,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
@@ -55,9 +55,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.
     ///
diff --git a/library/core/tests/lazy.rs b/library/core/tests/lazy.rs
index 70fcc6d2d4b..c7c3c479b71 100644
--- a/library/core/tests/lazy.rs
+++ b/library/core/tests/lazy.rs
@@ -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();
diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs
index c8d3289ca4a..bf5a716fa03 100644
--- a/library/std/src/sync/lazy_lock.rs
+++ b/library/std/src/sync/lazy_lock.rs
@@ -46,17 +46,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.
diff --git a/library/std/src/sync/lazy_lock/tests.rs b/library/std/src/sync/lazy_lock/tests.rs
index f11b66bfca5..a5d4e25c596 100644
--- a/library/std/src/sync/lazy_lock/tests.rs
+++ b/library/std/src/sync/lazy_lock/tests.rs
@@ -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>() {}