Skip to content

Commit ed48994

Browse files
committed
deeply normalize param env in compare_impl_item
1 parent fb505a7 commit ed48994

File tree

7 files changed

+173
-2
lines changed

7 files changed

+173
-2
lines changed

compiler/rustc_hir_analysis/src/check/compare_impl_item.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,14 @@ fn compare_method_predicate_entailment<'tcx>(
236236

237237
let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_def_id);
238238
let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds));
239-
let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
239+
// FIXME(-Zhigher-ranked-assumptions): lazy normalization may postpone region constraints to
240+
// an infcx that checks regions. Deeply normalize the param env in the next solver as well.
241+
// cc trait-system-refactor-initiative/issues/166.
242+
let param_env = if tcx.next_trait_solver_globally() {
243+
traits::deeply_normalize_param_env_or_error(tcx, param_env, normalize_cause)
244+
} else {
245+
traits::normalize_param_env_or_error(tcx, param_env, normalize_cause)
246+
};
240247
debug!(caller_bounds=?param_env.caller_bounds());
241248

242249
let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());

compiler/rustc_trait_selection/src/solve/normalize.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,8 @@ where
198198
if ty.has_escaping_bound_vars() {
199199
let (ty, mapped_regions, mapped_types, mapped_consts) =
200200
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, ty);
201+
// FIXME: Temporary placeholders may get added to infcx's region constraints/obligations,
202+
// which can cause problem for `resolve_regions`.
201203
let result =
202204
ensure_sufficient_stack(|| self.normalize_alias_term(ty.into()))?.expect_type();
203205
Ok(PlaceholderReplacer::replace_placeholders(

compiler/rustc_trait_selection/src/traits/mod.rs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,58 @@ fn do_normalize_predicates<'tcx>(
317317
}
318318
}
319319

320+
// A temporay hack. Don't use this.
321+
// See `deeply_normalize_param_env_or_error`.
322+
#[instrument(level = "debug", skip(tcx, elaborated_env))]
323+
fn do_deeply_normalize_predicates<'tcx>(
324+
tcx: TyCtxt<'tcx>,
325+
cause: ObligationCause<'tcx>,
326+
elaborated_env: ty::ParamEnv<'tcx>,
327+
predicates: Vec<ty::Clause<'tcx>>,
328+
) -> Result<Vec<ty::Clause<'tcx>>, ErrorGuaranteed> {
329+
let span = cause.span;
330+
let infcx = tcx
331+
.infer_ctxt()
332+
.with_next_trait_solver(true)
333+
.ignoring_regions()
334+
.build(TypingMode::non_body_analysis());
335+
let predicates = match crate::solve::deeply_normalize::<_, FulfillmentError<'tcx>>(
336+
infcx.at(&cause, elaborated_env),
337+
predicates,
338+
) {
339+
Ok(predicates) => predicates,
340+
Err(errors) => {
341+
let reported = infcx.err_ctxt().report_fulfillment_errors(errors);
342+
return Err(reported);
343+
}
344+
};
345+
346+
debug!("do_normalize_predicates: normalized predicates = {:?}", predicates);
347+
348+
// The next solver doesn't ignore region constraints so we do it manually.
349+
drop(infcx.take_registered_region_obligations());
350+
drop(infcx.take_registered_region_assumptions());
351+
drop(infcx.take_and_reset_region_constraints());
352+
let errors = infcx.resolve_regions(cause.body_id, elaborated_env, []);
353+
if !errors.is_empty() {
354+
tcx.dcx().span_delayed_bug(
355+
span,
356+
format!("failed region resolution while normalizing {elaborated_env:?}: {errors:?}"),
357+
);
358+
}
359+
360+
match infcx.fully_resolve(predicates) {
361+
Ok(predicates) => Ok(predicates),
362+
Err(fixup_err) => {
363+
span_bug!(
364+
span,
365+
"inference variables in normalized parameter environment: {}",
366+
fixup_err
367+
)
368+
}
369+
}
370+
}
371+
320372
// FIXME: this is gonna need to be removed ...
321373
/// Normalizes the parameter environment, reporting errors if they occur.
322374
#[instrument(level = "debug", skip(tcx))]
@@ -477,6 +529,66 @@ pub fn normalize_param_env_or_error<'tcx>(
477529
ty::ParamEnv::new(tcx.mk_clauses(&predicates))
478530
}
479531

532+
// FIXME(-Zhigher-ranked-assumptions): this is a hack to walk around the fact that we don't support
533+
// placeholder assumptions right now.
534+
// We should remove this once we have proper support for implied bounds on binders.
535+
/// Deeply normalize the param env using the next solver.
536+
#[instrument(level = "debug", skip(tcx))]
537+
pub fn deeply_normalize_param_env_or_error<'tcx>(
538+
tcx: TyCtxt<'tcx>,
539+
unnormalized_env: ty::ParamEnv<'tcx>,
540+
cause: ObligationCause<'tcx>,
541+
) -> ty::ParamEnv<'tcx> {
542+
let mut predicates: Vec<_> =
543+
util::elaborate(tcx, unnormalized_env.caller_bounds().into_iter()).collect();
544+
545+
debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates);
546+
547+
let elaborated_env = ty::ParamEnv::new(tcx.mk_clauses(&predicates));
548+
if !elaborated_env.has_aliases() {
549+
return elaborated_env;
550+
}
551+
552+
let outlives_predicates: Vec<_> = predicates
553+
.extract_if(.., |predicate| {
554+
matches!(predicate.kind().skip_binder(), ty::ClauseKind::TypeOutlives(..))
555+
})
556+
.collect();
557+
558+
debug!(
559+
"normalize_param_env_or_error: predicates=(non-outlives={:?}, outlives={:?})",
560+
predicates, outlives_predicates
561+
);
562+
let Ok(non_outlives_predicates) =
563+
do_deeply_normalize_predicates(tcx, cause.clone(), elaborated_env, predicates)
564+
else {
565+
// An unnormalized env is better than nothing.
566+
debug!("normalize_param_env_or_error: errored resolving non-outlives predicates");
567+
return elaborated_env;
568+
};
569+
570+
debug!("normalize_param_env_or_error: non-outlives predicates={:?}", non_outlives_predicates);
571+
572+
// Not sure whether it is better to include the unnormalized TypeOutlives predicates
573+
// here. I believe they should not matter, because we are ignoring TypeOutlives param-env
574+
// predicates here anyway. Keeping them here anyway because it seems safer.
575+
let outlives_env = non_outlives_predicates.iter().chain(&outlives_predicates).cloned();
576+
let outlives_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(outlives_env));
577+
let Ok(outlives_predicates) =
578+
do_deeply_normalize_predicates(tcx, cause, outlives_env, outlives_predicates)
579+
else {
580+
// An unnormalized env is better than nothing.
581+
debug!("normalize_param_env_or_error: errored resolving outlives predicates");
582+
return elaborated_env;
583+
};
584+
debug!("normalize_param_env_or_error: outlives predicates={:?}", outlives_predicates);
585+
586+
let mut predicates = non_outlives_predicates;
587+
predicates.extend(outlives_predicates);
588+
debug!("normalize_param_env_or_error: final predicates={:?}", predicates);
589+
ty::ParamEnv::new(tcx.mk_clauses(&predicates))
590+
}
591+
480592
#[derive(Debug)]
481593
pub enum EvaluateConstErr {
482594
/// The constant being evaluated was either a generic parameter or inference variable, *or*,

tests/ui/higher-ranked/trait-bounds/issue-100689.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
//@ check-pass
2+
//@ revisions: old next
3+
//@[next] compile-flags: -Znext-solver
24

35
struct Foo<'a> {
46
foo: &'a mut usize,

tests/ui/higher-ranked/trait-bounds/issue-102899.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
//@ check-pass
2+
//@ revisions: old next
3+
//@[next] compile-flags: -Znext-solver
24

35
pub trait BufferTrait<'buffer> {
46
type Subset<'channel>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//@ check-pass
2+
//@ compile-flags: -Znext-solver
3+
4+
// See trait-system-refactor-initiative/issues/166.
5+
// The old solver doesn't check normalization constraints in `compare_impl_item`.
6+
// The new solver performs lazy normalization so those region constraints may get postponed to
7+
// an infcx that considers regions.
8+
trait Trait {
9+
type Assoc<'a>
10+
where
11+
Self: 'a;
12+
}
13+
impl<'b> Trait for &'b u32 {
14+
type Assoc<'a> = &'a u32
15+
where
16+
Self: 'a;
17+
}
18+
19+
trait Bound<T> {}
20+
trait Entailment<T: Trait> {
21+
fn method()
22+
where
23+
Self: for<'a> Bound<<T as Trait>::Assoc<'a>>;
24+
}
25+
26+
impl<'b, T> Entailment<&'b u32> for T {
27+
// Instantiates trait where-clauses with `&'b u32` and then normalizes
28+
// `T: for<'a> Bound<<&'b u32 as Trait>::Assoc<'a>>` in a separate infcx
29+
// without checking region constraints.
30+
//
31+
// It normalizes to `T: Bound<&'a u32>`, dropping the `&'b u32: 'a` constraint.
32+
fn method()
33+
where
34+
Self: for<'a> Bound<&'a u32>
35+
{}
36+
}
37+
38+
fn main() {}

tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
error[E0275]: overflow evaluating the requirement `<() as A<T>>::Assoc == _`
2+
--> $DIR/normalize-param-env-2.rs:22:5
3+
|
4+
LL | / fn f()
5+
LL | | where
6+
LL | | Self::Assoc: A<T>,
7+
| |__________________________^
8+
19
error[E0275]: overflow evaluating the requirement `<() as A<T>>::Assoc: A<T>`
210
--> $DIR/normalize-param-env-2.rs:24:22
311
|
@@ -46,6 +54,6 @@ LL | where
4654
LL | Self::Assoc: A<T>,
4755
| ^^^^ required by this bound in `A::f`
4856

49-
error: aborting due to 5 previous errors
57+
error: aborting due to 6 previous errors
5058

5159
For more information about this error, try `rustc --explain E0275`.

0 commit comments

Comments
 (0)