]>
Commit | Line | Data |
---|---|---|
a1dfa0c6 XL |
1 | # Parameter Environment |
2 | ||
6a06907d | 3 | When working with associated and/or generic items (types, constants, |
a1dfa0c6 XL |
4 | functions/methods) it is often relevant to have more information about the |
5 | `Self` or generic parameters. Trait bounds and similar information is encoded in | |
ba9703b0 | 6 | the [`ParamEnv`][pe]. Often this is not enough information to obtain things like the |
a1dfa0c6 XL |
7 | type's `Layout`, but you can do all kinds of other checks on it (e.g. whether a |
8 | type implements `Copy`) or you can evaluate an associated constant whose value | |
9 | does not depend on anything from the parameter environment. | |
10 | ||
ba9703b0 XL |
11 | [pe]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html |
12 | ||
a1dfa0c6 XL |
13 | For example if you have a function |
14 | ||
15 | ```rust | |
ba9703b0 | 16 | fn foo<T: Copy>(t: T) { ... } |
a1dfa0c6 XL |
17 | ``` |
18 | ||
19 | the parameter environment for that function is `[T: Copy]`. This means any | |
20 | evaluation within this function will, when accessing the type `T`, know about | |
21 | its `Copy` bound via the parameter environment. | |
22 | ||
ba9703b0 XL |
23 | You can get the parameter environment for a `def_id` using the |
24 | [`param_env`][query] query. However, this `ParamEnv` can be too generic for | |
25 | your use case. Using the `ParamEnv` from the surrounding context can allow you | |
26 | to evaluate more things. For example, suppose we had something the following: | |
27 | ||
6a06907d | 28 | [query]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ty_utils/ty/fn.param_env.html |
ba9703b0 XL |
29 | |
30 | ```rust | |
31 | trait Foo { | |
32 | type Assoc; | |
33 | } | |
34 | ||
35 | trait Bar { } | |
36 | ||
37 | trait Baz { | |
38 | fn stuff() -> bool; | |
39 | } | |
40 | ||
41 | fn foo<T>(t: T) | |
42 | where | |
43 | T: Foo, | |
44 | <T as Foo>::Assoc: Bar | |
45 | { | |
46 | bar::<T::Assoc>() | |
47 | } | |
48 | ||
49 | fn bar<T: Baz>() { | |
50 | if T::stuff() { mep() } else { mop() } | |
51 | } | |
52 | ``` | |
53 | ||
54 | We may know some things inside `bar` that we wouldn't know if we just fetched | |
55 | `bar`'s param env because of the `<T as Foo>::Assoc: Bar` bound in `foo`. This | |
56 | is a contrived example that makes no sense in our existing analyses, but we may | |
57 | run into similar cases when doing analyses with associated constants on generic | |
58 | traits or traits with assoc types. | |
59 | ||
60 | ## Bundling | |
a1dfa0c6 XL |
61 | |
62 | Another great thing about `ParamEnv` is that you can use it to bundle the thing | |
ba9703b0 XL |
63 | depending on generic parameters (e.g. a `Ty`) by calling the [`and`][and] |
64 | method. This will produce a [`ParamEnvAnd<Ty>`][pea], making clear that you | |
65 | should probably not be using the inner value without taking care to also use | |
66 | the [`ParamEnv`][pe]. | |
67 | ||
68 | [and]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html#method.and | |
69 | [pea]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnvAnd.html |