Which ParamEnv do I use?

When needing a ParamEnv in the compiler there are a few options for obtaining one:

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:

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.