@@ -32,7 +32,7 @@ use rustc_errors::ErrorGuaranteed;
32
32
use rustc_middle:: query:: Providers ;
33
33
use rustc_middle:: ty:: fold:: TypeFoldable ;
34
34
use 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 } ;
36
36
use rustc_middle:: ty:: { InternalSubsts , SubstsRef } ;
37
37
use rustc_span:: def_id:: DefId ;
38
38
use rustc_span:: Span ;
@@ -272,8 +272,62 @@ pub fn normalize_param_env_or_error<'tcx>(
272
272
// parameter environments once for every fn as it goes,
273
273
// and errors will get reported then; so outside of type inference we
274
274
// 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 ( ) ;
277
331
278
332
debug ! ( "normalize_param_env_or_error: elaborated-predicates={:?}" , predicates) ;
279
333
0 commit comments