Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 36 additions & 30 deletions compiler/rustc_type_ir/src/region_kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,26 +34,26 @@ rustc_index::newtype_index! {
/// In general, the region lattice looks like
///
/// ```text
/// static ----------+-----...------+ (greatest)
/// empty(Un) -------- (smallest)
/// | \
/// ... \
/// | \
/// empty(U1) -- \
/// | \ placeholder(Un)
/// | \ |
/// empty(root) placeholder(U1) |
/// | | |
/// param regions | |
/// | | |
/// | | |
/// param regions | |
/// | | |
/// empty(root) placeholder(U1) |
/// | / |
/// | / placeholder(Un)
/// empty(U1) -- /
/// | /
/// ... /
/// | /
/// empty(Un) -------- (smallest)
/// static ----------+-----...------+ (greatest)
/// ```
///
/// Early-bound/free regions are the named lifetimes in scope from the
/// function declaration. They have relationships to one another
/// determined based on the declared relationships from the
/// function.
/// Lifetimes in scope from a function declaration are represented via
/// [`RegionKind::ReEarlyParam`]/[`RegionKind::ReLateParam`]. They
/// have relationships to one another and `'static` based on the
/// declared relationships from the function.
///
/// Note that inference variables and bound regions are not included
/// in this diagram. In the case of inference variables, they should
Expand All @@ -62,29 +62,36 @@ rustc_index::newtype_index! {
/// include -- the diagram indicates the relationship between free
/// regions.
///
/// You can read more about the distinction between early and late bound
/// parameters in the rustc dev guide: [Early vs Late bound parameters].
///
/// A note on subtyping: If we assume that references take their region
/// covariantly, and use that to define the subtyping relationship of regions,
/// it may be somewhat surprising that `'empty` is Top and `'static` is Bottom,
/// and that "`'a` is a subtype of `'b`" is defined as "`'a` is bigger than
/// `'b`" - good to keep in mind.
///
/// ## Inference variables
///
/// During region inference, we sometimes create inference variables,
/// represented as `ReVar`. These will be inferred by the code in
/// `infer::lexical_region_resolve` to some free region from the
/// lattice above (the minimal region that meets the
/// represented as [`RegionKind::ReVar`]. These will be inferred by
/// the code in `infer::lexical_region_resolve` to some free region
/// from the lattice above (the minimal region that meets the
/// constraints).
///
/// During NLL checking, where regions are defined differently, we
/// also use `ReVar` -- in that case, the index is used to index into
/// the NLL region checker's data structures. The variable may in fact
/// represent either a free region or an inference variable, in that
/// case.
/// also use [`RegionKind::ReVar`] -- in that case, the index is used
/// to index into the NLL region checker's data structures. The
/// variable may in fact represent either a free region or an
/// inference variable, in that case.
///
/// ## Bound Regions
///
/// These are regions that are stored behind a binder and must be instantiated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the pre-existing comment here is wrong/wildly misleading. Early bound parameters are not ReBound. This comment implies that a ReBound can correspond to either an early or a late bound parameter but actually it just always corresponds to a lifetime from a for<'a, ...> binder

I would probably drop everything about early/late here and only talk about them in relation to the Binder type

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just pushed an edit, how's this?

/// with some concrete region before being used. There are two kind of
/// bound regions: early-bound, which are bound in an item's `Generics`,
/// and are instantiated by an `GenericArgs`, and late-bound, which are part of
/// higher-ranked types (e.g., `for<'a> fn(&'a ())`), and are instantiated by
/// the likes of `liberate_late_bound_regions`. The distinction exists
/// because higher-ranked lifetimes aren't supported in all places. See [1][2].
/// with some concrete region before being used. A type can be wrapped in a
/// `Binder`, which introduces new type/const/lifetime variables (e.g., `for<'a>
/// fn(&'a ())`). These parameters are referred to via [`RegionKind::ReBound`].
/// You can instantiate them by the likes of `liberate_late_bound_regions`.
///
/// Unlike `Param`s, bound regions are not supposed to exist "in the wild"
/// outside their binder, e.g., in types passed to type inference, and
Expand Down Expand Up @@ -123,8 +130,7 @@ rustc_index::newtype_index! {
/// happen, you can use `leak_check`. This is more clearly explained
/// by the [rustc dev guide].
///
/// [1]: https://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/
/// [2]: https://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/
/// [Early vs Late bound parameters]: https://rustc-dev-guide.rust-lang.org/early-late-parameters.html
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
#[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)]
#[derive(GenericTypeVisitable)]
Expand Down Expand Up @@ -160,7 +166,7 @@ pub enum RegionKind<I: Interner> {
/// more info about early and late bound lifetime parameters.
ReLateParam(I::LateParamRegion),

/// Static data that has an "infinite" lifetime. Top in the region lattice.
/// Static data that has an "infinite" lifetime. Bottom in the region lattice.
ReStatic,

/// A region variable. Should not exist outside of type inference.
Expand Down
6 changes: 6 additions & 0 deletions src/doc/rustc-dev-guide/src/early-late-parameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@

> **NOTE**: This chapter largely talks about early/late bound as being solely relevant when discussing function item types/function definitions. This is potentially not completely true, async blocks and closures should likely be discussed somewhat in this chapter.

See also these blog posts from when the distinction between early and late bound parameters was
introduced: [Intermingled parameter lists] and [Intermingled parameter lists, take 2].

[Intermingled parameter lists]: https://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/
[Intermingled parameter lists, take 2]: https://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/

## What does it mean to be "early" bound or "late" bound

Every function definition has a corresponding ZST that implements the `Fn*` traits known as a [function item type][function_item_type]. This part of the chapter will talk a little bit about the "desugaring" of function item types as it is useful context for explaining the difference between early bound and late bound generic parameters.
Expand Down
Loading