change ParamEnv::and to sometimes keep the environment [VIC]

In general, we've been moving towards a semantics where you can have
contradictory where-clauses, and we try to honor them.  There are
already existing run-pass tests where we take that philosophy as
well (e.g., `compile-fail/issue-36839.rs`). The current behavior of
`and`, where it strips the environment, breaks that code.
This commit is contained in:
Niko Matsakis 2018-02-20 10:37:35 -05:00
parent 64d4ed300b
commit 80b4c45ee4

View file

@ -1439,31 +1439,38 @@ impl<'tcx> ParamEnv<'tcx> {
} }
/// Creates a suitable environment in which to perform trait /// Creates a suitable environment in which to perform trait
/// queries on the given value. This will either be `self` *or* /// queries on the given value. When type-checking, this is simply
/// the empty environment, depending on whether `value` references /// the pair of the environment plus value. But when reveal is set to
/// type parameters that are in scope. (If it doesn't, then any /// All, then if `value` does not reference any type parameters, we will
/// judgements should be completely independent of the context, /// pair it with the empty environment. This improves caching and is generally
/// and hence we can safely use the empty environment so as to /// invisible.
/// enable more sharing across functions.)
/// ///
/// NB: This is a mildly dubious thing to do, in that a function /// NB: We preserve the environment when type-checking because it
/// (or other environment) might have wacky where-clauses like /// is possible for the user to have wacky where-clauses like
/// `where Box<u32>: Copy`, which are clearly never /// `where Box<u32>: Copy`, which are clearly never
/// satisfiable. The code will at present ignore these, /// satisfiable. We generally want to behave as if they were true,
/// effectively, when type-checking the body of said /// although the surrounding function is never reachable.
/// function. This preserves existing behavior in any
/// case. --nmatsakis
pub fn and<T: TypeFoldable<'tcx>>(self, value: T) -> ParamEnvAnd<'tcx, T> { pub fn and<T: TypeFoldable<'tcx>>(self, value: T) -> ParamEnvAnd<'tcx, T> {
assert!(!value.needs_infer()); match self.reveal {
if value.has_param_types() || value.has_self_ty() { Reveal::UserFacing => {
ParamEnvAnd { ParamEnvAnd {
param_env: self, param_env: self,
value, value,
}
} }
} else {
ParamEnvAnd { Reveal::All => {
param_env: self.without_caller_bounds(), if value.needs_infer() || value.has_param_types() || value.has_self_ty() {
value, ParamEnvAnd {
param_env: self,
value,
}
} else {
ParamEnvAnd {
param_env: self.without_caller_bounds(),
value,
}
}
} }
} }
} }