Parameter Environment

When working with associated and/or or generic items (types, constants, functions/methods) it is often relevant to have more information about the Self or generic parameters. Trait bounds and similar information is encoded in the ParamEnv. Often this is not enough information to obtain things like the type's Layout, but you can do all kinds of other checks on it (e.g. whether a type implements Copy) or you can evaluate an associated constant whose value does not depend on anything from the parameter environment.

For example if you have a function


#![allow(unused)]
fn main() {
fn foo<T: Copy>(t: T) { ... }
}

the parameter environment for that function is [T: Copy]. This means any evaluation within this function will, when accessing the type T, know about its Copy bound via the parameter environment.

You can get the parameter environment for a def_id using the param_env query. However, this ParamEnv can be too generic for your use case. Using the ParamEnv from the surrounding context can allow you to evaluate more things. For example, suppose we had something the following:


#![allow(unused)]
fn main() {
trait Foo {
    type Assoc;
}

trait Bar { }

trait Baz {
    fn stuff() -> bool;
}

fn foo<T>(t: T)
where
    T: Foo,
    <T as Foo>::Assoc: Bar
{
   bar::<T::Assoc>()
}

fn bar<T: Baz>() {
    if T::stuff() { mep() } else { mop() }
}
}

We may know some things inside bar that we wouldn't know if we just fetched bar's param env because of the <T as Foo>::Assoc: Bar bound in foo. This is a contrived example that makes no sense in our existing analyses, but we may run into similar cases when doing analyses with associated constants on generic traits or traits with assoc types.

Bundling

Another great thing about ParamEnv is that you can use it to bundle the thing depending on generic parameters (e.g. a Ty) by calling the and method. This will produce a ParamEnvAnd<Ty>, making clear that you should probably not be using the inner value without taking care to also use the ParamEnv.