@@ -32,7 +32,7 @@ use rustc_errors::ErrorGuaranteed;
3232use rustc_middle:: query:: Providers ;
3333use rustc_middle:: ty:: fold:: TypeFoldable ;
3434use rustc_middle:: ty:: visit:: { TypeVisitable , TypeVisitableExt } ;
35- use rustc_middle:: ty:: { self , ToPredicate , Ty , TyCtxt , TypeSuperVisitable } ;
35+ use rustc_middle:: ty:: { self , ToPredicate , Ty , TyCtxt , TypeFolder , TypeSuperVisitable } ;
3636use rustc_middle:: ty:: { InternalSubsts , SubstsRef } ;
3737use rustc_span:: def_id:: DefId ;
3838use rustc_span:: Span ;
@@ -272,8 +272,62 @@ pub fn normalize_param_env_or_error<'tcx>(
272272 // parameter environments once for every fn as it goes,
273273 // and errors will get reported then; so outside of type inference we
274274 // can be sure that no errors should occur.
275- let mut predicates: Vec < _ > =
276- util:: elaborate ( tcx, unnormalized_env. caller_bounds ( ) . into_iter ( ) ) . collect ( ) ;
275+ let mut predicates: Vec < _ > = util:: elaborate (
276+ tcx,
277+ unnormalized_env. caller_bounds ( ) . into_iter ( ) . map ( |predicate| {
278+ if tcx. features ( ) . generic_const_exprs {
279+ return predicate;
280+ }
281+
282+ struct ConstNormalizer < ' tcx > ( TyCtxt < ' tcx > ) ;
283+
284+ impl < ' tcx > TypeFolder < TyCtxt < ' tcx > > for ConstNormalizer < ' tcx > {
285+ fn interner ( & self ) -> TyCtxt < ' tcx > {
286+ self . 0
287+ }
288+
289+ fn fold_const ( & mut self , c : ty:: Const < ' tcx > ) -> ty:: Const < ' tcx > {
290+ // While it is pretty sus to be evaluating things with an empty param env, it
291+ // should actually be okay since without `feature(generic_const_exprs)` the only
292+ // const arguments that have a non-empty param env are array repeat counts. These
293+ // do not appear in the type system though.
294+ c. eval ( self . 0 , ty:: ParamEnv :: empty ( ) )
295+ }
296+ }
297+
298+ // This whole normalization step is a hack to work around the fact that
299+ // `normalize_param_env_or_error` is fundamentally broken from using an
300+ // unnormalized param env with a trait solver that expects the param env
301+ // to be normalized.
302+ //
303+ // When normalizing the param env we can end up evaluating obligations
304+ // that have been normalized but can only be proven via a where clause
305+ // which is still in its unnormalized form. example:
306+ //
307+ // Attempting to prove `T: Trait<<u8 as Identity>::Assoc>` in a param env
308+ // with a `T: Trait<<u8 as Identity>::Assoc>` where clause will fail because
309+ // we first normalize obligations before proving them so we end up proving
310+ // `T: Trait<u8>`. Since lazy normalization is not implemented equating `u8`
311+ // with `<u8 as Identity>::Assoc` fails outright so we incorrectly believe that
312+ // we cannot prove `T: Trait<u8>`.
313+ //
314+ // The same thing is true for const generics- attempting to prove
315+ // `T: Trait<ConstKind::Unevaluated(...)>` with the same thing as a where clauses
316+ // will fail. After normalization we may be attempting to prove `T: Trait<4>` with
317+ // the unnormalized where clause `T: Trait<ConstKind::Unevaluated(...)>`. In order
318+ // for the obligation to hold `4` must be equal to `ConstKind::Unevaluated(...)`
319+ // but as we do not have lazy norm implemented, equating the two consts fails outright.
320+ //
321+ // Ideally we would not normalize consts here at all but it is required for backwards
322+ // compatibility. Eventually when lazy norm is implemented this can just be removed.
323+ // We do not normalize types here as there is no backwards compatibility requirement
324+ // for us to do so.
325+ //
326+ // FIXME(-Ztrait-solver=next): remove this hack since we have deferred projection equality
327+ predicate. fold_with ( & mut ConstNormalizer ( tcx) )
328+ } ) ,
329+ )
330+ . collect ( ) ;
277331
278332 debug ! ( "normalize_param_env_or_error: elaborated-predicates={:?}" , predicates) ;
279333
0 commit comments