Skip to content

Minor tweaks to make some normalization (adjacent) code less confusing #140468

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
36 changes: 15 additions & 21 deletions compiler/rustc_hir_typeck/src/writeback.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
// Type resolution: the phase that finds all the types in the AST with
// unresolved type variables and replaces "ty_var" types with their
// generic parameters.
//! During type inference, partially inferred terms are
//! represented using inference variables (ty::Infer). These don't appear in
//! the final [`ty::TypeckResults`] since all of the types should have been
//! inferred once typeck is done.
//!
//! When type inference is running however, having to update the typeck results
//! every time a new type is inferred would be unreasonably slow, so instead all
//! of the replacement happens at the end in [`FnCtxt::resolve_type_vars_in_body`],
//! which creates a new `TypeckResults` which doesn't contain any inference variables.

use std::mem;

Expand All @@ -27,15 +33,6 @@ use crate::FnCtxt;
///////////////////////////////////////////////////////////////////////////
// Entry point

// During type inference, partially inferred types are
// represented using Type variables (ty::Infer). These don't appear in
// the final TypeckResults since all of the types should have been
// inferred once typeck is done.
// When type inference is running however, having to update the typeck
// typeck results every time a new type is inferred would be unreasonably slow,
// so instead all of the replacement happens at the end in
// resolve_type_vars_in_body, which creates a new TypeTables which
// doesn't contain any inference types.
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(crate) fn resolve_type_vars_in_body(
&self,
Expand Down Expand Up @@ -90,14 +87,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}

///////////////////////////////////////////////////////////////////////////
// The Writeback context. This visitor walks the HIR, checking the
// fn-specific typeck results to find references to types or regions. It
// resolves those regions to remove inference variables and writes the
// final result back into the master typeck results in the tcx. Here and
// there, it applies a few ad-hoc checks that were not convenient to
// do elsewhere.

/// The Writeback context. This visitor walks the HIR, checking the
/// fn-specific typeck results to find inference variables. It resolves
/// those inference variables and writes the final result into the
/// `TypeckResults`. It also applies a few ad-hoc checks that were not
/// convenient to do elsewhere.
struct WritebackCx<'cx, 'tcx> {
fcx: &'cx FnCtxt<'cx, 'tcx>,

Expand Down Expand Up @@ -897,7 +891,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
let cause = ObligationCause::misc(self.span.to_span(tcx), body_id);
let at = self.fcx.at(&cause, self.fcx.param_env);
let universes = vec![None; outer_exclusive_binder(value).as_usize()];
match solve::deeply_normalize_with_skipped_universes_and_ambiguous_goals(
match solve::deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals(
at, value, universes,
) {
Ok((value, goals)) => {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/src/solve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ pub use fulfill::{FulfillmentCtxt, NextSolverError};
pub(crate) use normalize::deeply_normalize_for_diagnostics;
pub use normalize::{
deeply_normalize, deeply_normalize_with_skipped_universes,
deeply_normalize_with_skipped_universes_and_ambiguous_goals,
deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals,
};
pub use select::InferCtxtSelectExt;
57 changes: 32 additions & 25 deletions compiler/rustc_trait_selection/src/solve/normalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,11 @@ where
T: TypeFoldable<TyCtxt<'tcx>>,
E: FromSolverError<'tcx, NextSolverError<'tcx>>,
{
let (value, goals) =
deeply_normalize_with_skipped_universes_and_ambiguous_goals(at, value, universes)?;
assert_eq!(goals, vec![]);
let (value, coroutine_goals) =
deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals(
at, value, universes,
)?;
assert_eq!(coroutine_goals, vec![]);

Ok(value)
}
Expand All @@ -59,9 +61,9 @@ where
/// entered before passing `value` to the function. This is currently needed for
/// `normalize_erasing_regions`, which skips binders as it walks through a type.
///
/// This returns a set of stalled obligations if the typing mode of the underlying infcx
/// has any stalled coroutine def ids.
pub fn deeply_normalize_with_skipped_universes_and_ambiguous_goals<'tcx, T, E>(
/// This returns a set of stalled obligations involving coroutines if the typing mode of
/// the underlying infcx has any stalled coroutine def ids.
pub fn deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals<'tcx, T, E>(
at: At<'_, 'tcx>,
value: T,
universes: Vec<Option<UniverseIndex>>,
Expand All @@ -71,19 +73,24 @@ where
E: FromSolverError<'tcx, NextSolverError<'tcx>>,
{
let fulfill_cx = FulfillmentCtxt::new(at.infcx);
let mut folder =
NormalizationFolder { at, fulfill_cx, depth: 0, universes, stalled_goals: vec![] };
let mut folder = NormalizationFolder {
at,
fulfill_cx,
depth: 0,
universes,
stalled_coroutine_goals: vec![],
};
let value = value.try_fold_with(&mut folder)?;
let errors = folder.fulfill_cx.select_all_or_error(at.infcx);
if errors.is_empty() { Ok((value, folder.stalled_goals)) } else { Err(errors) }
if errors.is_empty() { Ok((value, folder.stalled_coroutine_goals)) } else { Err(errors) }
}

struct NormalizationFolder<'me, 'tcx, E> {
at: At<'me, 'tcx>,
fulfill_cx: FulfillmentCtxt<'tcx, E>,
depth: usize,
universes: Vec<Option<UniverseIndex>>,
stalled_goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
stalled_coroutine_goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
}

impl<'tcx, E> NormalizationFolder<'_, 'tcx, E>
Expand Down Expand Up @@ -182,7 +189,7 @@ where
return Err(errors);
}

self.stalled_goals.extend(
self.stalled_coroutine_goals.extend(
self.fulfill_cx
.drain_stalled_obligations_for_coroutines(self.at.infcx)
.into_iter()
Expand Down Expand Up @@ -298,13 +305,13 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for DeeplyNormalizeForDiagnosticsFolder<'_,

fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
let infcx = self.at.infcx;
let result =
infcx.commit_if_ok(|_| {
deeply_normalize_with_skipped_universes_and_ambiguous_goals::<
_,
ScrubbedTraitError<'tcx>,
>(self.at, ty, vec![None; ty.outer_exclusive_binder().as_usize()])
});
let result: Result<_, Vec<ScrubbedTraitError<'tcx>>> = infcx.commit_if_ok(|_| {
deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals(
self.at,
ty,
vec![None; ty.outer_exclusive_binder().as_usize()],
)
});
match result {
Ok((ty, _)) => ty,
Err(_) => ty.super_fold_with(self),
Expand All @@ -313,13 +320,13 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for DeeplyNormalizeForDiagnosticsFolder<'_,

fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
let infcx = self.at.infcx;
let result =
infcx.commit_if_ok(|_| {
deeply_normalize_with_skipped_universes_and_ambiguous_goals::<
_,
ScrubbedTraitError<'tcx>,
>(self.at, ct, vec![None; ct.outer_exclusive_binder().as_usize()])
});
let result: Result<_, Vec<ScrubbedTraitError<'tcx>>> = infcx.commit_if_ok(|_| {
deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals(
self.at,
ct,
vec![None; ct.outer_exclusive_binder().as_usize()],
)
});
match result {
Ok((ct, _)) => ct,
Err(_) => ct.super_fold_with(self),
Expand Down
13 changes: 8 additions & 5 deletions compiler/rustc_trait_selection/src/traits/normalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,11 +260,14 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
}

ty::Projection if !data.has_escaping_bound_vars() => {
// This branch is *mostly* just an optimization: when we don't
// have escaping bound vars, we don't need to replace them with
// placeholders (see branch below). *Also*, we know that we can
// register an obligation to *later* project, since we know
// there won't be bound vars there.
// When we don't have escaping bound vars we can normalize ambig aliases
// to inference variables (done in `normalize_projection_ty`). This would
// be wrong if there were escaping bound vars as even if we instantiated
// the bound vars with placeholders, we wouldn't be able to map them back
// after normalization succeeded.
//
// Also, as an optimization: when we don't have escaping bound vars, we don't
// need to replace them with placeholders (see branch below).
let data = data.fold_with(self);
let normalized_ty = project::normalize_projection_ty(
self.selcx,
Expand Down
Loading