Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 7 additions & 12 deletions compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,26 +239,21 @@ fn compare_method_predicate_entailment<'tcx>(
let hybrid_preds = hybrid_preds.into_iter().map(Unnormalized::skip_norm_wip);
let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_def_id);
let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds));
// FIXME(-Zhigher-ranked-assumptions): The `hybrid_preds`
// NOTE(-Zhigher-ranked-assumptions): The `hybrid_preds`
// should be well-formed. However, using them may result in
// region errors as we currently don't track placeholder
// assumptions.
//
// To avoid being backwards incompatible with the old solver,
// we also eagerly normalize the where-bounds in the new solver
// here while ignoring region constraints. This means we can then
// use where-bounds whose normalization results in placeholder
// errors further down without getting any errors.
// We eagerly normalize the where-clauses here while ignoring
// region constraints. This means we can then use where-bounds
// whose normalization results in placeholder errors further
// down without getting any errors.
//
// It should be sound to do so as the only region errors here
// This should be sound to do so as the only region errors here
// should be due to missing implied bounds.
//
// cc trait-system-refactor-initiative/issues/166.
let param_env = if tcx.next_trait_solver_globally() {
traits::deeply_normalize_param_env_ignoring_regions(tcx, param_env, normalize_cause)
} else {
traits::normalize_param_env_or_error(tcx, param_env, normalize_cause)
};
let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
debug!(caller_bounds=?param_env.caller_bounds());

let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
self.param_env.caller_bounds().iter().filter_map(|predicate| {
match predicate.kind().skip_binder() {
ty::ClauseKind::Trait(data) if data.self_ty().is_param(index) => {
Some((predicate, span))
Some((ty::set_aliases_to_non_rigid(tcx, predicate).skip_norm_wip(), span))
}
_ => None,
}
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_infer/src/infer/outlives/test_type_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ pub(super) fn can_match_erased_ty<'tcx>(
// deal with rigid aliases, making sure we do so correctly
// everywhere is effort, so we're just using `No` everywhere
// for now. This should change soon.
let outlives_ty = ty::set_aliases_to_non_rigid(tcx, outlives_ty).skip_normalization();
let (outlives_ty, erased_ty) =
ty::set_aliases_to_non_rigid(tcx, (outlives_ty, erased_ty)).skip_normalization();
if outlives_ty == erased_ty {
// pointless micro-optimization
true
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_infer/src/infer/outlives/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
let erased_p_ty = self.tcx.erase_and_anonymize_regions(
ty::set_aliases_to_non_rigid(self.tcx, p_ty).skip_norm_wip(),
);
let erased_ty = ty::set_aliases_to_non_rigid(self.tcx, erased_ty).skip_norm_wip();
(erased_p_ty == erased_ty).then_some(ty::Binder::dummy(ty::OutlivesPredicate(p_ty, r)))
}));

Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2692,6 +2692,10 @@ impl<'tcx> TyCtxt<'tcx> {
self.sess.opts.unstable_opts.disable_fast_paths
}

pub fn disable_param_env_hack(self) -> bool {
self.sess.opts.unstable_opts.disable_param_env_hack
}

pub fn renormalize_rigid_aliases(self) -> bool {
self.sess.opts.unstable_opts.renormalize_rigid_aliases
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2347,6 +2347,8 @@ options! {
"disable various performance optimizations in trait solving"),
disable_incr_comp_backend_caching: bool = (false, parse_bool, [TRACKED],
"disable caching of compiled objects by the codegen backend during incremental compilation"),
disable_param_env_hack: bool = (false, parse_bool, [TRACKED],
"do not try to mark param env as rigid for the next solver"),
dual_proc_macros: bool = (false, parse_bool, [TRACKED],
"load proc macros for both target and host, but only link to the target (default: no)"),
dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
Expand Down
140 changes: 59 additions & 81 deletions compiler/rustc_trait_selection/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ use rustc_errors::ErrorGuaranteed;
pub use rustc_infer::traits::*;
use rustc_macros::TypeVisitable;
use rustc_middle::query::Providers;
use rustc_middle::span_bug;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::{
self, Clause, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeFolder,
Expand Down Expand Up @@ -250,19 +249,32 @@ fn pred_known_to_hold_modulo_regions<'tcx>(
}
}

fn set_projection_term_to_non_rigid<'tcx>(
tcx: TyCtxt<'tcx>,
predicates: impl IntoIterator<Item = ty::Clause<'tcx>>,
) -> impl Iterator<Item = ty::Clause<'tcx>> {
predicates.into_iter().map(move |clause| {
if let ty::ClauseKind::Projection(projection_pred) = clause.kind().skip_binder() {
clause
.kind()
.rebind(ty::ProjectionPredicate {
projection_term: projection_pred.projection_term,
term: ty::set_aliases_to_non_rigid(tcx, projection_pred.term).skip_norm_wip(),
})
.upcast(tcx)
} else {
clause
}
})
}

#[instrument(level = "debug", skip(tcx, elaborated_env))]
fn do_normalize_predicates<'tcx>(
tcx: TyCtxt<'tcx>,
cause: ObligationCause<'tcx>,
elaborated_env: ty::ParamEnv<'tcx>,
predicates: Vec<ty::Clause<'tcx>>,
) -> Result<Vec<ty::Clause<'tcx>>, ErrorGuaranteed> {
// Even if we move back to eager normalization elsewhere,
// param env normalization remains lazy in the next solver.
if tcx.next_trait_solver_globally() {
return Ok(predicates);
}

// FIXME. We should really... do something with these region
// obligations. But this call just continues the older
// behavior (i.e., doesn't cause any new bugs), and it would
Expand All @@ -279,10 +291,36 @@ fn do_normalize_predicates<'tcx>(
let span = cause.span;
let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis());
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
// FIXME: The `elaborated_env` is not really rigid. We do this to be
// consistent with the old solver. It fixes several issues with
// lazy norm of param env but unfix others.
let elaborated_env = if tcx.next_trait_solver_globally() && !tcx.disable_param_env_hack() {
// FIXME: combine them into one if the perf is bad.
let elaborated_env = ty::set_aliases_to_rigid(tcx, elaborated_env);
let elaborated_env = set_projection_term_to_non_rigid(tcx, elaborated_env.caller_bounds());
ty::ParamEnv::new(tcx.mk_clauses_from_iter(elaborated_env))
} else {
elaborated_env
};
let predicates = ocx.normalize(&cause, elaborated_env, Unnormalized::new_wip(predicates));
// FIXME: opaque types in param env might be in defining scope but we're
// using non body analysis for here. So the rigidness marker is wrong.
let predicates = ty::set_aliases_to_non_rigid(tcx, predicates).skip_norm_wip();
let predicates = if tcx.next_trait_solver_globally() {
if !tcx.disable_param_env_hack() {
let predicates: Vec<_> = set_projection_term_to_non_rigid(tcx, predicates).collect();
// FIXME(type_alias_impl_trait): opaque types in param env might be
// in defining scope but we're using non body analysis here.
// So the rigidness marker is wrong.
ty::set_opaques_to_non_rigid(tcx, predicates).skip_norm_wip()
} else {
// Param env is used in different typing modes but itself
// is normalized in `non_body_analysis`.
// That not only makes the rigidness of opaques types wrong,
// other aliases can be indirectly affected as well.
// So we conservatively set everything to be non-rigid.
ty::set_aliases_to_non_rigid(tcx, predicates).skip_norm_wip()

@lcnr lcnr Jul 2, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keep a comment for why we need to do this if the hack is disabled

(param_env used in different typingmode)

View changes since the review

}
} else {
predicates
};

let errors = ocx.evaluate_obligations_error_on_ambiguity();
if !errors.is_empty() {
Expand All @@ -294,17 +332,20 @@ fn do_normalize_predicates<'tcx>(

// We can use the `elaborated_env` here; the region code only
// cares about declarations like `'a: 'b`.
//
// FIXME: It's very weird that we ignore region obligations but apparently
// still need to use `resolve_regions` as we need the resolved regions in
// the normalized predicates.
let errors = infcx.resolve_regions(cause.body_id, elaborated_env, []);
if !errors.is_empty() {
tcx.dcx().span_delayed_bug(
span,
format!("failed region resolution while normalizing {elaborated_env:?}: {errors:?}"),
);
}

//
// FIXME(-Zhigher-ranked-assumptions): We're ignoring region errors for now.
// There're placeholder constraints `leaking` out. This is a hack to work around
// the fact that we don't support placeholder assumptions right now and is necessary
// for `compare_method_predicate_entailment`. We should remove this once we
// have proper support for implied bounds on binders.
//
// This is required by trait-system-refactor-initiative#166. The new solver encounters
// this more frequently as we entirely ignore outlives predicates with the old solver.
let _errors = infcx.resolve_regions(cause.body_id, elaborated_env, []);
match infcx.fully_resolve(predicates) {
Ok(predicates) => Ok(predicates),
Err(fixup_err) => {
Expand Down Expand Up @@ -481,69 +522,6 @@ pub fn normalize_param_env_or_error<'tcx>(
ty::ParamEnv::new(tcx.mk_clauses(&predicates))
}

/// Deeply normalize the param env using the next solver ignoring
/// region errors.
///
/// FIXME(-Zhigher-ranked-assumptions): this is a hack to work around
/// the fact that we don't support placeholder assumptions right now
/// and is necessary for `compare_method_predicate_entailment`, see the
/// use of this function for more info. We should remove this once we
/// have proper support for implied bounds on binders.
#[instrument(level = "debug", skip(tcx))]
pub fn deeply_normalize_param_env_ignoring_regions<'tcx>(
tcx: TyCtxt<'tcx>,
unnormalized_env: ty::ParamEnv<'tcx>,
cause: ObligationCause<'tcx>,
) -> ty::ParamEnv<'tcx> {
let predicates: Vec<_> =
util::elaborate(tcx, unnormalized_env.caller_bounds().into_iter()).collect();

debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates);

let elaborated_env = ty::ParamEnv::new(tcx.mk_clauses(&predicates));
if !elaborated_env.has_aliases() {
return elaborated_env;
}

let span = cause.span;
let infcx = tcx
.infer_ctxt()
.with_next_trait_solver(true)
.ignoring_regions()
.build(TypingMode::non_body_analysis());
let predicates = match crate::solve::deeply_normalize::<_, FulfillmentError<'tcx>>(
infcx.at(&cause, elaborated_env),
Unnormalized::new_wip(predicates),
) {
Ok(predicates) => predicates,
Err(errors) => {
infcx.err_ctxt().report_fulfillment_errors(errors);
// An unnormalized env is better than nothing.
debug!("normalize_param_env_or_error: errored resolving predicates");
return elaborated_env;
}
};

debug!("do_normalize_predicates: normalized predicates = {:?}", predicates);
// FIXME(-Zhigher-ranked-assumptions): We're ignoring region errors for now.
// There're placeholder constraints `leaking` out.
// See the fixme in the enclosing function's docs for more.
let _errors = infcx.resolve_regions(cause.body_id, elaborated_env, []);

let predicates = match infcx.fully_resolve(predicates) {
Ok(predicates) => predicates,
Err(fixup_err) => {
span_bug!(
span,
"inference variables in normalized parameter environment: {}",
fixup_err
)
}
};
debug!("normalize_param_env_or_error: final predicates={:?}", predicates);
ty::ParamEnv::new(tcx.mk_clauses(&predicates))
}

#[derive(Debug)]
pub enum EvaluateConstErr {
/// The constant being evaluated was either a generic parameter or inference variable, *or*,
Expand Down
Loading
Loading