Description
What is this?
"Lazy normalization" is a change to how we handle associated types (and constants) so that we wait until we have to equate an associated type (or constant) has to be equated or processed to normalize it (i.e., figure out if there is an impl we can use to find its definition), rather than doing so eagerly. This has a number of advantages, and in particular for const generics it can prevent a large number of cyclic errors.
Subissues
- Tracking issue for Lazy Normalization of Constants #72219 -- Lazy normalization for constants
Further background reading
What is this "lazy normalization"? (see #60471 (comment))
@Aaron1011 Normalization is replacing "projections" (such as
<T as Trait>::AssocType
or unevaluated constant expressions - a better name than "projection" might be "expression" or "call" - something that only says how to get to a final "value", not what it is) with what they resolve/evaluate to.
E.g.&<Rc<str> as Deref>::Target
becomes&str
, and[T; {1+1}]
becomes[T; 2]
.Right now all of this is done "eagerly", i.e. as soon as possible, and always (during typeck, or whenever there is enough information to normalize further), but that causes some issues:
for associated types it's HRTB-related (IIRC)
for type-level constants it's cyclic dependencies between the constant and the parent definition it's found in, which is why we can't fix Array lengths don't support generic parameters. #43408 (it's a one-line change, but then not even libcore compiles anymore)
Lazy normalization would simply defer the work of resolving/evaluating such type-level constructs until the very moment they are needed (such as when requiring that two types are the same, or when computing the low-level layout of a type for miri/codegen).
The associated type problem is more subtle (at least from what I've heard), but for constant expressions in types, it will simply break the cyclic dependencies because definitions will no longer force the evaluation of constant expressions they contain.