Which ParamEnv
do I use?
When needing a ParamEnv
in the compiler there are a few options for obtaining one:
- The correct env is already in scope simply use it (or pass it down the call stack to where you are).
- The
tcx.param_env(def_id)
query - Use
ParamEnv::new
to construct an env with an arbitrary set of where clauses. Then calltraits::normalize_param_env_or_error
which will handle normalizing and elaborating all the where clauses in the env for you. - Creating an empty environment via
ParamEnv::reveal_all
orParamEnv::empty
In the large majority of cases a ParamEnv
when required already exists somewhere in scope or above in the call stack and should be passed down. A non exhaustive list of places where you might find an existing ParamEnv
:
- During typeck
FnCtxt
has aparam_env
field - When writing late lints the
LateContext
has aparam_env
field - During well formedness checking the
WfCheckingCtxt
has aparam_env
field - The
TypeChecker
used by Mir Typeck has aparam_env
field - In the next-gen trait solver all
Goal
s have aparam_env
field specifying what environment to prove the goal in - When editing an existing
TypeRelation
if it implementsPredicateEmittingRelation
then aparam_env
method will be available.
Using the param_env
query to obtain an env is generally done at the start of some kind of analysis and then passed everywhere that a ParamEnv
is required. For example the type checker will create a ParamEnv
for the item it is type checking and then pass it around everywhere.
Creating an env from an arbitrary set of where clauses is usually unnecessary and should only be done if the environment you need does not correspond to an actual item in the source code (i.e. compare_method_predicate_entailment
as mentioned earlier).
Creating an empty environment via ParamEnv::empty
is almost always wrong. There are very few places where we actually know that the environment should be empty. One of the only places where we do actually know this is after monomorphization, however the ParamEnv
there should be constructed via ParamEnv::reveal_all
instead as at this point we should be able to determine the hidden type of opaque types. Codegen/Post-mono is one of the only places that should be using ParamEnv::reveal_all
.
An additional piece of complexity here is specifying the Reveal
(see linked docs for explanation of what reveal does) used for the ParamEnv
. When constructing a param env using the param_env
query it will have Reveal::UserFacing
, if Reveal::All
is desired then the tcx.param_env_reveal_all_normalized
query can be used instead.
The ParamEnv
type has a method ParamEnv::with_reveal_all_normalized
which converts an existing ParamEnv
into one with Reveal::All
specified. Where possible the previously mentioned query should be preferred as it is more efficient.