Skip to content

Commit 0abe2a0

Browse files
committed
Auto merge of #158643 - adwinwhite:rigid-param-env, r=<try>
Try to mark param env as rigid with the next solver
2 parents 17aa775 + 2d5ce64 commit 0abe2a0

33 files changed

Lines changed: 596 additions & 263 deletions

compiler/rustc_hir_analysis/src/check/compare_impl_item.rs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -239,26 +239,21 @@ fn compare_method_predicate_entailment<'tcx>(
239239
let hybrid_preds = hybrid_preds.into_iter().map(Unnormalized::skip_norm_wip);
240240
let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_def_id);
241241
let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds));
242-
// FIXME(-Zhigher-ranked-assumptions): The `hybrid_preds`
242+
// NOTE(-Zhigher-ranked-assumptions): The `hybrid_preds`
243243
// should be well-formed. However, using them may result in
244244
// region errors as we currently don't track placeholder
245245
// assumptions.
246246
//
247-
// To avoid being backwards incompatible with the old solver,
248-
// we also eagerly normalize the where-bounds in the new solver
249-
// here while ignoring region constraints. This means we can then
250-
// use where-bounds whose normalization results in placeholder
251-
// errors further down without getting any errors.
247+
// We eagerly normalize the where-clauses here while ignoring
248+
// region constraints. This means we can then use where-bounds
249+
// whose normalization results in placeholder errors further
250+
// down without getting any errors.
252251
//
253-
// It should be sound to do so as the only region errors here
252+
// This should be sound to do so as the only region errors here
254253
// should be due to missing implied bounds.
255254
//
256255
// cc trait-system-refactor-initiative/issues/166.
257-
let param_env = if tcx.next_trait_solver_globally() {
258-
traits::deeply_normalize_param_env_ignoring_regions(tcx, param_env, normalize_cause)
259-
} else {
260-
traits::normalize_param_env_or_error(tcx, param_env, normalize_cause)
261-
};
256+
let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
262257
debug!(caller_bounds=?param_env.caller_bounds());
263258

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

compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
298298
self.param_env.caller_bounds().iter().filter_map(|predicate| {
299299
match predicate.kind().skip_binder() {
300300
ty::ClauseKind::Trait(data) if data.self_ty().is_param(index) => {
301-
Some((predicate, span))
301+
Some((ty::set_aliases_to_non_rigid(tcx, predicate).skip_norm_wip(), span))
302302
}
303303
_ => None,
304304
}

compiler/rustc_infer/src/infer/outlives/test_type_match.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ pub(super) fn can_match_erased_ty<'tcx>(
9090
// deal with rigid aliases, making sure we do so correctly
9191
// everywhere is effort, so we're just using `No` everywhere
9292
// for now. This should change soon.
93-
let outlives_ty = ty::set_aliases_to_non_rigid(tcx, outlives_ty).skip_normalization();
93+
let (outlives_ty, erased_ty) =
94+
ty::set_aliases_to_non_rigid(tcx, (outlives_ty, erased_ty)).skip_normalization();
9495
if outlives_ty == erased_ty {
9596
// pointless micro-optimization
9697
true

compiler/rustc_infer/src/infer/outlives/verify.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
258258
let erased_p_ty = self.tcx.erase_and_anonymize_regions(
259259
ty::set_aliases_to_non_rigid(self.tcx, p_ty).skip_norm_wip(),
260260
);
261+
let erased_ty = ty::set_aliases_to_non_rigid(self.tcx, erased_ty).skip_norm_wip();
261262
(erased_p_ty == erased_ty).then_some(ty::Binder::dummy(ty::OutlivesPredicate(p_ty, r)))
262263
}));
263264

compiler/rustc_middle/src/ty/context.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2699,6 +2699,10 @@ impl<'tcx> TyCtxt<'tcx> {
26992699
self.sess.opts.unstable_opts.disable_fast_paths
27002700
}
27012701

2702+
pub fn disable_param_env_hack(self) -> bool {
2703+
self.sess.opts.unstable_opts.disable_param_env_hack
2704+
}
2705+
27022706
pub fn renormalize_rigid_aliases(self) -> bool {
27032707
self.sess.opts.unstable_opts.renormalize_rigid_aliases
27042708
}

compiler/rustc_session/src/options.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2351,6 +2351,8 @@ options! {
23512351
"disable various performance optimizations in trait solving"),
23522352
disable_incr_comp_backend_caching: bool = (false, parse_bool, [TRACKED],
23532353
"disable caching of compiled objects by the codegen backend during incremental compilation"),
2354+
disable_param_env_hack: bool = (false, parse_bool, [TRACKED],
2355+
"do not try to mark param env as rigid for the next solver"),
23542356
dual_proc_macros: bool = (false, parse_bool, [TRACKED],
23552357
"load proc macros for both target and host, but only link to the target (default: no)"),
23562358
dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],

compiler/rustc_trait_selection/src/traits/mod.rs

Lines changed: 100 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ use rustc_errors::ErrorGuaranteed;
3030
pub use rustc_infer::traits::*;
3131
use rustc_macros::TypeVisitable;
3232
use rustc_middle::query::Providers;
33-
use rustc_middle::span_bug;
3433
use rustc_middle::ty::error::{ExpectedFound, TypeError};
3534
use rustc_middle::ty::{
3635
self, Clause, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeFolder,
@@ -250,19 +249,79 @@ fn pred_known_to_hold_modulo_regions<'tcx>(
250249
}
251250
}
252251

252+
fn set_projection_term_to_non_rigid<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
253+
tcx: TyCtxt<'tcx>,
254+
value: T,
255+
) -> T {
256+
value.fold_with(&mut ProjectionTermToNonRigid { tcx })
257+
}
258+
259+
struct ProjectionTermToNonRigid<'tcx> {
260+
tcx: TyCtxt<'tcx>,
261+
}
262+
263+
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ProjectionTermToNonRigid<'tcx> {
264+
fn cx(&self) -> TyCtxt<'tcx> {
265+
self.tcx
266+
}
267+
268+
fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
269+
if let ty::PredicateKind::Clause(clause) = p.kind().skip_binder()
270+
&& let ty::ClauseKind::Projection(projection_pred) = clause
271+
{
272+
p.kind()
273+
.rebind(ty::ProjectionPredicate {
274+
projection_term: projection_pred.projection_term,
275+
term: ty::set_aliases_to_non_rigid(self.tcx, projection_pred.term)
276+
.skip_norm_wip(),
277+
})
278+
.upcast(self.tcx)
279+
} else {
280+
p
281+
}
282+
}
283+
}
284+
285+
struct OpaqueToNonRigid<'tcx> {
286+
tcx: TyCtxt<'tcx>,
287+
}
288+
289+
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for OpaqueToNonRigid<'tcx> {
290+
fn cx(&self) -> TyCtxt<'tcx> {
291+
self.tcx
292+
}
293+
294+
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
295+
if !(t.has_rigid_aliases() && t.has_opaque_types()) {
296+
return t;
297+
}
298+
299+
if let ty::Alias(ty::IsRigid::Yes, alias_ty @ ty::AliasTy { kind: ty::Opaque { .. }, .. }) =
300+
t.kind()
301+
{
302+
let alias_ty = alias_ty.fold_with(self);
303+
Ty::new_alias(self.tcx, ty::IsRigid::No, alias_ty)
304+
} else {
305+
t.super_fold_with(self)
306+
}
307+
}
308+
309+
fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
310+
if c.has_rigid_aliases() && c.has_opaque_types() { c.super_fold_with(self) } else { c }
311+
}
312+
313+
fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
314+
if p.has_rigid_aliases() && p.has_opaque_types() { p.super_fold_with(self) } else { p }
315+
}
316+
}
317+
253318
#[instrument(level = "debug", skip(tcx, elaborated_env))]
254319
fn do_normalize_predicates<'tcx>(
255320
tcx: TyCtxt<'tcx>,
256321
cause: ObligationCause<'tcx>,
257322
elaborated_env: ty::ParamEnv<'tcx>,
258323
predicates: Vec<ty::Clause<'tcx>>,
259324
) -> Result<Vec<ty::Clause<'tcx>>, ErrorGuaranteed> {
260-
// Even if we move back to eager normalization elsewhere,
261-
// param env normalization remains lazy in the next solver.
262-
if tcx.next_trait_solver_globally() {
263-
return Ok(predicates);
264-
}
265-
266325
// FIXME. We should really... do something with these region
267326
// obligations. But this call just continues the older
268327
// behavior (i.e., doesn't cause any new bugs), and it would
@@ -279,10 +338,30 @@ fn do_normalize_predicates<'tcx>(
279338
let span = cause.span;
280339
let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis());
281340
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
341+
// FIXME: The `elaborated_env` is not really rigid. We do this to be
342+
// consistent with the old solver. It fixes several issues with
343+
// lazy norm of param env but unfix others.
344+
let elaborated_env = if tcx.next_trait_solver_globally() && !tcx.disable_param_env_hack() {
345+
// FIXME: combine them into one if the perf is bad.
346+
let elaborated_env = ty::set_aliases_to_rigid(tcx, elaborated_env);
347+
set_projection_term_to_non_rigid(tcx, elaborated_env)
348+
} else {
349+
elaborated_env
350+
};
282351
let predicates = ocx.normalize(&cause, elaborated_env, Unnormalized::new_wip(predicates));
283-
// FIXME: opaque types in param env might be in defining scope but we're
284-
// using non body analysis for here. So the rigidness marker is wrong.
285-
let predicates = ty::set_aliases_to_non_rigid(tcx, predicates).skip_norm_wip();
352+
let predicates = if tcx.next_trait_solver_globally() {
353+
if !tcx.disable_param_env_hack() {
354+
let predicates = set_projection_term_to_non_rigid(tcx, predicates);
355+
// FIXME(type_alias_impl_trait): opaque types in param env might be
356+
// in defining scope but we're using non body analysis here.
357+
// So the rigidness marker is wrong.
358+
predicates.fold_with(&mut OpaqueToNonRigid { tcx })
359+
} else {
360+
ty::set_aliases_to_non_rigid(tcx, predicates).skip_norm_wip()
361+
}
362+
} else {
363+
predicates
364+
};
286365

287366
let errors = ocx.evaluate_obligations_error_on_ambiguity();
288367
if !errors.is_empty() {
@@ -294,17 +373,20 @@ fn do_normalize_predicates<'tcx>(
294373

295374
// We can use the `elaborated_env` here; the region code only
296375
// cares about declarations like `'a: 'b`.
376+
//
297377
// FIXME: It's very weird that we ignore region obligations but apparently
298378
// still need to use `resolve_regions` as we need the resolved regions in
299379
// the normalized predicates.
300-
let errors = infcx.resolve_regions(cause.body_id, elaborated_env, []);
301-
if !errors.is_empty() {
302-
tcx.dcx().span_delayed_bug(
303-
span,
304-
format!("failed region resolution while normalizing {elaborated_env:?}: {errors:?}"),
305-
);
306-
}
307-
380+
//
381+
// FIXME(-Zhigher-ranked-assumptions): We're ignoring region errors for now.
382+
// There're placeholder constraints `leaking` out. This is a hack to work around
383+
// the fact that we don't support placeholder assumptions right now and is necessary
384+
// for `compare_method_predicate_entailment`. We should remove this once we
385+
// have proper support for implied bounds on binders.
386+
//
387+
// This is required by trait-system-refactor-initiative#166. The new solver encounters
388+
// this more frequently as we entirely ignore outlives predicates with the old solver.
389+
let _errors = infcx.resolve_regions(cause.body_id, elaborated_env, []);
308390
match infcx.fully_resolve(predicates) {
309391
Ok(predicates) => Ok(predicates),
310392
Err(fixup_err) => {
@@ -481,69 +563,6 @@ pub fn normalize_param_env_or_error<'tcx>(
481563
ty::ParamEnv::new(tcx.mk_clauses(&predicates))
482564
}
483565

484-
/// Deeply normalize the param env using the next solver ignoring
485-
/// region errors.
486-
///
487-
/// FIXME(-Zhigher-ranked-assumptions): this is a hack to work around
488-
/// the fact that we don't support placeholder assumptions right now
489-
/// and is necessary for `compare_method_predicate_entailment`, see the
490-
/// use of this function for more info. We should remove this once we
491-
/// have proper support for implied bounds on binders.
492-
#[instrument(level = "debug", skip(tcx))]
493-
pub fn deeply_normalize_param_env_ignoring_regions<'tcx>(
494-
tcx: TyCtxt<'tcx>,
495-
unnormalized_env: ty::ParamEnv<'tcx>,
496-
cause: ObligationCause<'tcx>,
497-
) -> ty::ParamEnv<'tcx> {
498-
let predicates: Vec<_> =
499-
util::elaborate(tcx, unnormalized_env.caller_bounds().into_iter()).collect();
500-
501-
debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates);
502-
503-
let elaborated_env = ty::ParamEnv::new(tcx.mk_clauses(&predicates));
504-
if !elaborated_env.has_aliases() {
505-
return elaborated_env;
506-
}
507-
508-
let span = cause.span;
509-
let infcx = tcx
510-
.infer_ctxt()
511-
.with_next_trait_solver(true)
512-
.ignoring_regions()
513-
.build(TypingMode::non_body_analysis());
514-
let predicates = match crate::solve::deeply_normalize::<_, FulfillmentError<'tcx>>(
515-
infcx.at(&cause, elaborated_env),
516-
Unnormalized::new_wip(predicates),
517-
) {
518-
Ok(predicates) => predicates,
519-
Err(errors) => {
520-
infcx.err_ctxt().report_fulfillment_errors(errors);
521-
// An unnormalized env is better than nothing.
522-
debug!("normalize_param_env_or_error: errored resolving predicates");
523-
return elaborated_env;
524-
}
525-
};
526-
527-
debug!("do_normalize_predicates: normalized predicates = {:?}", predicates);
528-
// FIXME(-Zhigher-ranked-assumptions): We're ignoring region errors for now.
529-
// There're placeholder constraints `leaking` out.
530-
// See the fixme in the enclosing function's docs for more.
531-
let _errors = infcx.resolve_regions(cause.body_id, elaborated_env, []);
532-
533-
let predicates = match infcx.fully_resolve(predicates) {
534-
Ok(predicates) => predicates,
535-
Err(fixup_err) => {
536-
span_bug!(
537-
span,
538-
"inference variables in normalized parameter environment: {}",
539-
fixup_err
540-
)
541-
}
542-
};
543-
debug!("normalize_param_env_or_error: final predicates={:?}", predicates);
544-
ty::ParamEnv::new(tcx.mk_clauses(&predicates))
545-
}
546-
547566
#[derive(Debug)]
548567
pub enum EvaluateConstErr {
549568
/// The constant being evaluated was either a generic parameter or inference variable, *or*,

compiler/rustc_type_ir/src/fold.rs

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -563,12 +563,36 @@ where
563563
return ty::Unnormalized::new(value);
564564
}
565565

566-
let mut folder = RigidnessFolder { cx };
566+
let mut folder = RigidnessFolder { cx, target_rigidness: ty::IsRigid::No };
567567
ty::Unnormalized::new(value.fold_with(&mut folder))
568568
}
569569

570+
// FIXME: maybe take Unnormalizedas as input.
571+
pub fn set_aliases_to_rigid<I: Interner, T>(cx: I, value: T) -> T
572+
where
573+
T: TypeFoldable<I>,
574+
{
575+
if !value.has_non_rigid_aliases() {
576+
return value;
577+
}
578+
579+
let mut folder = RigidnessFolder { cx, target_rigidness: ty::IsRigid::Yes };
580+
value.fold_with(&mut folder)
581+
}
582+
583+
// Set all aliases to be rigid or non-rigid.
570584
struct RigidnessFolder<I: Interner> {
571585
cx: I,
586+
target_rigidness: ty::IsRigid,
587+
}
588+
589+
impl<I: Interner> RigidnessFolder<I> {
590+
fn needs_change<T: TypeVisitable<I>>(&self, t: &T) -> bool {
591+
match self.target_rigidness {
592+
ty::IsRigid::Yes => t.has_non_rigid_aliases(),
593+
ty::IsRigid::No => t.has_rigid_aliases(),
594+
}
595+
}
572596
}
573597

574598
impl<I: Interner> TypeFolder<I> for RigidnessFolder<I> {
@@ -578,42 +602,42 @@ impl<I: Interner> TypeFolder<I> for RigidnessFolder<I> {
578602
}
579603

580604
fn fold_binder<T: TypeFoldable<I>>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> {
581-
if t.has_rigid_aliases() { t.super_fold_with(self) } else { t }
605+
if self.needs_change(&t) { t.super_fold_with(self) } else { t }
582606
}
583607

584608
fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
585-
if !t.has_rigid_aliases() {
609+
if !self.needs_change(&t) {
586610
return t;
587611
}
588612

589613
match t.kind() {
590-
ty::Alias(ty::IsRigid::Yes, alias_ty) => {
614+
ty::Alias(is_rigid, alias_ty) if is_rigid != self.target_rigidness => {
591615
let alias_ty = alias_ty.fold_with(self);
592-
I::Ty::new_alias(self.cx(), ty::IsRigid::No, alias_ty)
616+
I::Ty::new_alias(self.cx(), self.target_rigidness, alias_ty)
593617
}
594618
_ => t.super_fold_with(self),
595619
}
596620
}
597621

598622
fn fold_const(&mut self, c: I::Const) -> I::Const {
599-
if !c.has_rigid_aliases() {
623+
if !self.needs_change(&c) {
600624
return c;
601625
}
602626

603627
match c.kind() {
604-
ty::ConstKind::Alias(ty::IsRigid::Yes, alias_const) => {
628+
ty::ConstKind::Alias(is_rigid, alias_const) if is_rigid != self.target_rigidness => {
605629
let alias_const = alias_const.fold_with(self);
606-
I::Const::new_alias(self.cx, ty::IsRigid::No, alias_const)
630+
I::Const::new_alias(self.cx, self.target_rigidness, alias_const)
607631
}
608632
_ => c.super_fold_with(self),
609633
}
610634
}
611635

612636
fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate {
613-
if p.has_rigid_aliases() { p.super_fold_with(self) } else { p }
637+
if self.needs_change(&p) { p.super_fold_with(self) } else { p }
614638
}
615639

616640
fn fold_clauses(&mut self, c: I::Clauses) -> I::Clauses {
617-
if c.has_rigid_aliases() { c.super_fold_with(self) } else { c }
641+
if self.needs_change(&c) { c.super_fold_with(self) } else { c }
618642
}
619643
}

0 commit comments

Comments
 (0)