Skip to content

Make LazyCell<T, F> and LazyLock<T, F> covariant in both T and F #159838

Draft
WaffleLapkin wants to merge 4 commits into
rust-lang:mainfrom
WaffleLapkin:covariant-lazies
Draft

Make LazyCell<T, F> and LazyLock<T, F> covariant in both T and F #159838
WaffleLapkin wants to merge 4 commits into
rust-lang:mainfrom
WaffleLapkin:covariant-lazies

Conversation

@WaffleLapkin

@WaffleLapkin WaffleLapkin commented Jul 24, 2026

Copy link
Copy Markdown
Member

Based on #159738.

See explanation for why it's valid that I wrote as a comment in LazyCell:

// It is non-obvious why `LazyCell` can be covariant in both `T` and `F`
// (and thus use `CovariantUnsafeCell`)...
//
// # `F`
//
// `F` is the easier to explain one; The state only ever transitions *out* of `Uninit(F)`
// (to either `Poisoned` or `Init(T)`), and never into it. In other words `F` is only ever
// read, not written.
//
// One could imagine `LazyCell` implemented as
// ```
// struct {
// state: UnsafeCell<Uninit | Init(T) | Poisoned>,
// f: ManuallyDrop<F>,
// }
// ```
// which would make it "obviously" covariant in `F`.
//
// **NOTE**: the important invariant here is that we never allow writing `F` through
// `&LazyCell`.
//
// # `T`
//
// Why `LazyCell` can be covariant in `T` is even more subtle. We do allow writing `T` through
// a `&LazyCell`, which would normally force us to make `LazyCell` invariant in `T`. However,
// the only value that we allow writing is one returned by `F`... and we don't allow changing
// `F`. So even if a user gets a `&LazyCell<LessrestrictedVersionOfT>`, they cannot write the
// `LessrestrictedVersionOfT` through it.
//
// **NOTE**: the important invariants here are that
// 1. `T` can only be written through `&LazyCell<T, F>` by being returned from `F`
// 2. `F` cannot be overwritten after `LazyCell` creation
//
// # Conclusion
//
// `LazyCell` can be covariant in both `T` and `F`... provided the non-local invariants which
// are listed above.

r? libs-api

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jul 24, 2026
@WaffleLapkin WaffleLapkin changed the title Make LazyCell<T, F> and `LazyLock<T, F> covariant in both T and F Make LazyCell<T, F> and LazyLock<T, F> covariant in both T and F Jul 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants