MIR desugaring
Recently
I (Oli) have proposed to add a magic generic parameter on all const fn foo
,
impl const Foo for Bar
and const trait Foo
declarations. This generic
parameter (called constness
henceforth) is forwarded automatically to all
items used within the body of a const fn. The following code blocks demonstrates
the way I envision this magic generic parameter to be created (TLDR: similar to
desugarings).
Examples
Trait declarations
#![allow(unused)] fn main() { const trait Foo {} }
becomes
#![allow(unused)] fn main() { trait Foo<constness C> {} }
Generic parameters
#![allow(unused)] fn main() { const fn foo<T: Bar + ~const Foo>() {} }
becomes
#![allow(unused)] fn main() { fn foo<constness C, T: Bar + Foo<C>>() {} }
Function bodies
#![allow(unused)] fn main() { const fn foo() { bar() } }
becomes
#![allow(unused)] fn main() { fn foo<constness C>() { bar::<C>() } }
Call sites outside of const contexts
fn main() { some_const_fn(); }
becomes
fn main() { some_const_fn::<constness::NotConst>(); }
Call sites in const contexts
#![allow(unused)] fn main() { const MOO: () = { some_const_fn(); } }
becomes
#![allow(unused)] fn main() { const MOO: () = { some_const_fn::<constness::ConstRequired>(); } }
Implementation side:
We add a fourth kind of generic parameter: constness
. All const trait Foo
implicitly get that parameter. In rustc we remove the constness
field from
TraitPredicate
and instead rely on generic parameter substitutions to replace
constness parameters. For now such a generic parameter can either be
Constness::Required
, Constness::Not
or Constness::Param
, where only the
latter is replaced during substitutions, the other two variants are fixed.
Making this work as generic parameter substitution should allow us to re-use all
the existing logic for such substitutions instead of rolling them again. I am
aware of a significant amount of hand-waving happening here, most notably around
where the substitutions are coming from, but I'm hoping we can hash that out in
an explorative implementation