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
72 changes: 12 additions & 60 deletions compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ use rustc_infer::infer::{
};
use rustc_infer::traits::ObligationCause;
use rustc_infer::traits::query::{
CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpDeeplyNormalizeGoal,
CanonicalTypeOpNormalizeGoal, CanonicalTypeOpProvePredicateGoal,
CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpNormalizeGoal,
CanonicalTypeOpProvePredicateGoal,
};
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::{
self, RePlaceholder, Region, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex, Unnormalized,
self, RePlaceholder, Region, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex,
};
use rustc_span::Span;
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
Expand Down Expand Up @@ -109,14 +109,6 @@ impl<'tcx, T: Copy + fmt::Display + TypeFoldable<TyCtxt<'tcx>> + 'tcx> ToUnivers
}
}

impl<'tcx, T: Copy + fmt::Display + TypeFoldable<TyCtxt<'tcx>> + 'tcx> ToUniverseInfo<'tcx>
for CanonicalTypeOpDeeplyNormalizeGoal<'tcx, T>
{
fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
UniverseInfo::TypeOp(Rc::new(DeeplyNormalizeQuery { canonical_query: self, base_universe }))
}
}

impl<'tcx> ToUniverseInfo<'tcx> for CanonicalTypeOpAscribeUserTypeGoal<'tcx> {
fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
UniverseInfo::TypeOp(Rc::new(AscribeUserTypeQuery { canonical_query: self, base_universe }))
Expand Down Expand Up @@ -247,7 +239,14 @@ where
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> Diag<'tcx> {
tcx.dcx().create_err(HigherRankedLifetimeError {
cause: Some(HigherRankedErrorCause::CouldNotNormalize {
value: self.canonical_query.canonical.value.value.value.to_string(),
value: self
.canonical_query
.canonical
.value
.value
.value
.skip_normalization()
.to_string(),
}),
span,
})
Expand Down Expand Up @@ -275,54 +274,7 @@ where
// the former fails to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs`
// test. Check after #85499 lands to see if its fixes have erased this difference.
let ty::ParamEnvAnd { param_env, value } = key;
let _ = ocx.normalize(&cause, param_env, Unnormalized::new_wip(value.value));

let diag = try_extract_error_from_fulfill_cx(
&ocx,
mbcx.mir_def_id(),
placeholder_region,
error_region,
)?
.with_dcx(mbcx.dcx());
Some(diag)
}
}

struct DeeplyNormalizeQuery<'tcx, T> {
canonical_query: CanonicalTypeOpDeeplyNormalizeGoal<'tcx, T>,
base_universe: ty::UniverseIndex,
}

impl<'tcx, T> TypeOpInfo<'tcx> for DeeplyNormalizeQuery<'tcx, T>
where
T: Copy + fmt::Display + TypeFoldable<TyCtxt<'tcx>> + 'tcx,
{
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> Diag<'tcx> {
tcx.dcx().create_err(HigherRankedLifetimeError {
cause: Some(HigherRankedErrorCause::CouldNotNormalize {
value: self.canonical_query.canonical.value.value.value.to_string(),
}),
span,
})
}

fn base_universe(&self) -> ty::UniverseIndex {
self.base_universe
}

fn nice_error<'infcx>(
&self,
mbcx: &mut MirBorrowckCtxt<'_, 'infcx, 'tcx>,
cause: ObligationCause<'tcx>,
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
) -> Option<Diag<'infcx>> {
let (infcx, key, _) =
mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
let ocx = ObligationCtxt::new(&infcx);

let ty::ParamEnvAnd { param_env, value } = key;
let _ = ocx.deeply_normalize(&cause, param_env, Unnormalized::new_wip(value.value));
let _ = ocx.normalize(&cause, param_env, value.value);

let diag = try_extract_error_from_fulfill_cx(
&ocx,
Expand Down
16 changes: 9 additions & 7 deletions compiler/rustc_borrowck/src/type_check/canonical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,16 +194,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
self.normalize_with_category(value, location, ConstraintCategory::Boring)
}

pub(super) fn deeply_normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T
pub(super) fn deeply_normalize<T>(
&mut self,
value: Unnormalized<'tcx, T>,
location: impl NormalizeLocation,
) -> Result<T, ErrorGuaranteed>
where
T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
{
let result: Result<_, ErrorGuaranteed> = self.fully_perform_op(
self.fully_perform_op(
location.to_locations(),
ConstraintCategory::Boring,
self.infcx.param_env.and(type_op::normalize::DeeplyNormalize { value }),
);
result.unwrap_or(value)

@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.

can you instead change the signature of this function to propagate the ErrorGuaranteed and handle it in its one call site?

View changes since the review

self.infcx.param_env.and(type_op::normalize::Normalize { value }),
)
}

#[instrument(skip(self), level = "debug")]
Expand All @@ -216,14 +219,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
where
T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
{
let value = value.skip_normalization();
let param_env = self.infcx.param_env;
let result: Result<_, ErrorGuaranteed> = self.fully_perform_op(
location.to_locations(),
category,
param_env.and(type_op::normalize::Normalize { value }),
);
result.unwrap_or(value)
result.unwrap_or(value.skip_norm_wip())
}

#[instrument(skip(self), level = "debug")]
Expand Down
12 changes: 7 additions & 5 deletions compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use rustc_infer::infer::canonical::{QueryRegionConstraint, QueryRegionConstraint
use rustc_infer::infer::outlives::env::RegionBoundPairs;
use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
use rustc_infer::traits::query::type_op::DeeplyNormalize;
use rustc_infer::traits::query::type_op::Normalize;
use rustc_middle::bug;
use rustc_middle::ty::{
self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, elaborate, fold_regions,
Expand Down Expand Up @@ -183,7 +183,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
// in the new trait solver.
if infcx.next_trait_solver() {
t1 = self.normalize_and_add_type_outlives_constraints(
t1,
ty::Unnormalized::new_wip(t1),
&mut next_outlives_predicates,
);
}
Expand Down Expand Up @@ -279,15 +279,17 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
self.constraints.type_tests.push(type_test);
}

// FIXME(trait-refactor-initiative#260): This function needs to
// be removed.
fn normalize_and_add_type_outlives_constraints(
&self,
ty: Ty<'tcx>,
ty: ty::Unnormalized<'tcx, Ty<'tcx>>,
next_outlives_predicates: &mut Vec<(
ty::ArgOutlivesPredicate<'tcx>,
ConstraintCategory<'tcx>,
)>,
) -> Ty<'tcx> {
match self.infcx.fully_perform(DeeplyNormalize { value: ty }, self.span) {
match self.infcx.fully_perform(Normalize { value: ty }, self.span) {
Ok(TypeOpOutput { output: ty, constraints, .. }) => {
// FIXME(higher_ranked_auto): What should we do with the assumptions here?
if let Some(QueryRegionConstraints { constraints, assumptions: _ }) = constraints {
Expand All @@ -299,7 +301,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
}
ty
}
Err(_) => ty,
Err(_) => ty.skip_norm_wip(),
}
}
}
Expand Down
39 changes: 23 additions & 16 deletions compiler/rustc_borrowck/src/type_check/free_region_relations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use rustc_infer::infer::canonical::QueryRegionConstraints;
use rustc_infer::infer::outlives;
use rustc_infer::infer::outlives::env::RegionBoundPairs;
use rustc_infer::infer::region_constraints::GenericKind;
use rustc_infer::traits::query::type_op::DeeplyNormalize;
use rustc_infer::traits::query::type_op::Normalize;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::traits::query::OutlivesBound;
use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt};
Expand Down Expand Up @@ -244,7 +244,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
}
let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } = self
.infcx
.fully_perform(DeeplyNormalize { value: ty }, span)
.fully_perform(Normalize { value: ty::Unnormalized::new_wip(ty) }, span)
.unwrap_or_else(|guar| TypeOpOutput {
output: Ty::new_error(self.infcx.tcx, guar),
constraints: None,
Expand Down Expand Up @@ -298,8 +298,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
if matches!(tcx.def_kind(defining_ty_def_id), DefKind::AssocFn | DefKind::AssocConst { .. })
{
for &(ty, _) in tcx.assumed_wf_types(tcx.local_parent(defining_ty_def_id)) {
let result: Result<_, ErrorGuaranteed> =
self.infcx.fully_perform(DeeplyNormalize { value: ty }, span);
let result: Result<_, ErrorGuaranteed> = self
.infcx
.fully_perform(Normalize { value: ty::Unnormalized::new_wip(ty) }, span);
let Ok(TypeOpOutput { output: norm_ty, constraints: c, .. }) = result else {
continue;
};
Expand Down Expand Up @@ -348,18 +349,24 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
) {
// In the new solver, normalize the type-outlives obligation assumptions.
if self.infcx.next_trait_solver() {
let Ok(TypeOpOutput {
output: normalized_outlives,
constraints: constraints_normalize,
error_info: _,
}) = self.infcx.fully_perform(DeeplyNormalize { value: outlives }, span)
else {
self.infcx.dcx().delayed_bug(format!("could not normalize {outlives:?}"));
return;
};
outlives = normalized_outlives;
if let Some(c) = constraints_normalize {
constraints.push(c);
match self
.infcx
.fully_perform(Normalize { value: ty::Unnormalized::new_wip(outlives) }, span)
{
Ok(TypeOpOutput {
output: normalized_outlives,
constraints: constraints_normalize,
error_info: _,
}) => {
outlives = normalized_outlives;
if let Some(c) = constraints_normalize {
constraints.push(c);
}
}
Err(guar) => {
let _: ErrorGuaranteed = guar;
return;
}
}
}

Expand Down
10 changes: 9 additions & 1 deletion compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -829,7 +829,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
ConstraintCategory::Boring,
);

let sig = self.deeply_normalize(unnormalized_sig, term_location);
let sig = match self
.deeply_normalize(ty::Unnormalized::new_wip(unnormalized_sig), term_location)
{
Ok(sig) => sig,
Err(guar) => {
let _: ErrorGuaranteed = guar;
return;
}
};
// HACK(#114936): `WF(sig)` does not imply `WF(normalized(sig))`
// with built-in `Fn` implementations, since the impl may not be
// well-formed itself.
Expand Down
34 changes: 23 additions & 11 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1394,24 +1394,17 @@ impl<'tcx> InferCtxt<'tcx> {
}
}

// Instantiates the bound variables in a given binder with fresh inference
// variables in the current universe.
//
// Use this method if you'd like to find some generic parameters of the binder's
// variables (e.g. during a method call). If there isn't a [`BoundRegionConversionTime`]
// that corresponds to your use case, consider whether or not you should
// use [`InferCtxt::enter_forall`] instead.
pub fn instantiate_binder_with_fresh_vars<T>(
pub fn instantiate_binder_with_fresh_vars_unnormalized<T>(
&self,
span: Span,
lbrct: BoundRegionConversionTime,
value: ty::Binder<'tcx, T>,
) -> T
) -> ty::Unnormalized<'tcx, T>
where
T: TypeFoldable<TyCtxt<'tcx>> + Copy,
{
if let Some(inner) = value.no_bound_vars() {
return inner;
return ty::Unnormalized::new(inner);
}

let bound_vars = value.bound_vars();
Expand Down Expand Up @@ -1444,7 +1437,26 @@ impl<'tcx> InferCtxt<'tcx> {
}
}
let delegate = ToFreshVars { args };
self.tcx.replace_bound_vars_uncached(value, delegate)
ty::Unnormalized::new(self.tcx.replace_bound_vars_uncached(value, delegate))
}

// Instantiates the bound variables in a given binder with fresh inference
// variables in the current universe.
//
// Use this method if you'd like to find some generic parameters of the binder's
// variables (e.g. during a method call). If there isn't a [`BoundRegionConversionTime`]
// that corresponds to your use case, consider whether or not you should
// use [`InferCtxt::enter_forall`] instead.
pub fn instantiate_binder_with_fresh_vars<T>(
&self,
span: Span,
lbrct: BoundRegionConversionTime,
value: ty::Binder<'tcx, T>,
) -> T
where
T: TypeFoldable<TyCtxt<'tcx>> + Copy,
{
self.instantiate_binder_with_fresh_vars_unnormalized(span, lbrct, value).skip_norm_wip()
}

/// See the [`region_constraints::RegionConstraintCollector::verify_generic_bound`] method.
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_middle/src/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2510,7 +2510,7 @@ rustc_queries! {
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Ty<'tcx>>>,
NoSolution,
> {
desc { "normalizing `{}`", goal.canonical.value.value.value }
desc { "normalizing `{}`", goal.canonical.value.value.value.skip_normalization() }
}

/// Do not call this query directly: part of the `Normalize` type-op
Expand All @@ -2520,7 +2520,7 @@ rustc_queries! {
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::Clause<'tcx>>>,
NoSolution,
> {
desc { "normalizing `{:?}`", goal.canonical.value.value.value }
desc { "normalizing `{:?}`", goal.canonical.value.value.value.skip_normalization() }
}

/// Do not call this query directly: part of the `Normalize` type-op
Expand All @@ -2530,7 +2530,7 @@ rustc_queries! {
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::PolyFnSig<'tcx>>>,
NoSolution,
> {
desc { "normalizing `{:?}`", goal.canonical.value.value.value }
desc { "normalizing `{:?}`", goal.canonical.value.value.value.skip_normalization() }
}

/// Do not call this query directly: part of the `Normalize` type-op
Expand All @@ -2540,7 +2540,7 @@ rustc_queries! {
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::FnSig<'tcx>>>,
NoSolution,
> {
desc { "normalizing `{:?}`", goal.canonical.value.value.value }
desc { "normalizing `{:?}`", goal.canonical.value.value.value.skip_normalization() }
}

query instantiate_and_check_impossible_predicates(key: (DefId, GenericArgsRef<'tcx>)) -> bool {
Expand Down
Loading
Loading