Skip to content

Deeply normalize in the new solver in WF #140672

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

Merged
merged 1 commit into from
May 6, 2025
Merged
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
47 changes: 39 additions & 8 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,36 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
)
}

/// Convenience function to *deeply* normalize during wfcheck. In the old solver,
/// this just dispatches to [`WfCheckingCtxt::normalize`], but in the new solver
/// this calls `deeply_normalize` and reports errors if they are encountered.
///
/// This function should be called in favor of `normalize` in cases where we will
/// then check the well-formedness of the type, since we only use the normalized
/// signature types for implied bounds when checking regions.
// FIXME(-Znext-solver): This should be removed when we compute implied outlives
// bounds using the unnormalized signature of the function we're checking.
fn deeply_normalize<T>(&self, span: Span, loc: Option<WellFormedLoc>, value: T) -> T
where
T: TypeFoldable<TyCtxt<'tcx>>,
{
if self.infcx.next_trait_solver() {
match self.ocx.deeply_normalize(
&ObligationCause::new(span, self.body_def_id, ObligationCauseCode::WellFormed(loc)),
self.param_env,
value.clone(),
) {
Ok(value) => value,
Err(errors) => {
self.infcx.err_ctxt().report_fulfillment_errors(errors);
value
}
}
} else {
self.normalize(span, loc, value)
}
}

fn register_wf_obligation(&self, span: Span, loc: Option<WellFormedLoc>, term: ty::Term<'tcx>) {
let cause = traits::ObligationCause::new(
span,
Expand Down Expand Up @@ -297,7 +327,8 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<()
{
let res = enter_wf_checking_ctxt(tcx, item.span, def_id, |wfcx| {
let ty = tcx.type_of(def_id).instantiate_identity();
let item_ty = wfcx.normalize(hir_ty.span, Some(WellFormedLoc::Ty(def_id)), ty);
let item_ty =
wfcx.deeply_normalize(hir_ty.span, Some(WellFormedLoc::Ty(def_id)), ty);
wfcx.register_wf_obligation(
hir_ty.span,
Some(WellFormedLoc::Ty(def_id)),
Expand Down Expand Up @@ -1073,7 +1104,7 @@ fn check_associated_item(
match item.kind {
ty::AssocKind::Const { .. } => {
let ty = tcx.type_of(item.def_id).instantiate_identity();
let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
let ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
wfcx.register_wf_obligation(span, loc, ty.into());
check_sized_if_body(
wfcx,
Expand Down Expand Up @@ -1102,7 +1133,7 @@ fn check_associated_item(
}
if item.defaultness(tcx).has_value() {
let ty = tcx.type_of(item.def_id).instantiate_identity();
let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
let ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
wfcx.register_wf_obligation(span, loc, ty.into());
}
Ok(())
Expand Down Expand Up @@ -1149,7 +1180,7 @@ fn check_type_defn<'tcx>(
let field_id = field.did.expect_local();
let hir::FieldDef { ty: hir_ty, .. } =
tcx.hir_node_by_def_id(field_id).expect_field();
let ty = wfcx.normalize(
let ty = wfcx.deeply_normalize(
hir_ty.span,
None,
tcx.type_of(field.did).instantiate_identity(),
Expand Down Expand Up @@ -1310,7 +1341,7 @@ fn check_item_type(

enter_wf_checking_ctxt(tcx, ty_span, item_id, |wfcx| {
let ty = tcx.type_of(item_id).instantiate_identity();
let item_ty = wfcx.normalize(ty_span, Some(WellFormedLoc::Ty(item_id)), ty);
let item_ty = wfcx.deeply_normalize(ty_span, Some(WellFormedLoc::Ty(item_id)), ty);

let forbid_unsized = match unsized_handling {
UnsizedHandling::Forbid => true,
Expand Down Expand Up @@ -1375,7 +1406,7 @@ fn check_impl<'tcx>(
// other `Foo` impls are incoherent.
tcx.ensure_ok().coherent_trait(trait_ref.def_id)?;
let trait_span = hir_trait_ref.path.span;
let trait_ref = wfcx.normalize(
let trait_ref = wfcx.deeply_normalize(
trait_span,
Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
trait_ref,
Expand Down Expand Up @@ -1435,7 +1466,7 @@ fn check_impl<'tcx>(
}
None => {
let self_ty = tcx.type_of(item.owner_id).instantiate_identity();
let self_ty = wfcx.normalize(
let self_ty = wfcx.deeply_normalize(
item.span,
Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
self_ty,
Expand Down Expand Up @@ -1640,7 +1671,7 @@ fn check_fn_or_method<'tcx>(

sig.inputs_and_output =
tcx.mk_type_list_from_iter(sig.inputs_and_output.iter().enumerate().map(|(idx, ty)| {
wfcx.normalize(
wfcx.deeply_normalize(
arg_span(idx),
Some(WellFormedLoc::Param {
function: def_id,
Expand Down

This file was deleted.

5 changes: 2 additions & 3 deletions tests/ui/associated-inherent-types/bugs/wf-check-skipped.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[current] known-bug: #100041
//@[current] check-pass
//@ known-bug: #100041
//@ check-pass
// FIXME(inherent_associated_types): This should fail.

#![feature(inherent_associated_types)]
Expand All @@ -15,4 +15,3 @@ impl Foo {
}

fn main() -> Foo::Bar::<Vec<[u32]>> {}
//[next]~^ ERROR the size for values of type `[u32]` cannot be known at compilation time
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,31 @@ LL | type Loop = Loop;
= note: in case this is a recursive type alias, consider using a struct, enum, or union instead

error[E0275]: overflow normalizing the type alias `Loop`
--> $DIR/inherent-impls-overflow.rs:10:1
--> $DIR/inherent-impls-overflow.rs:12:1
|
LL | impl Loop {}
| ^^^^^^^^^^^^
|
= note: in case this is a recursive type alias, consider using a struct, enum, or union instead

error[E0275]: overflow normalizing the type alias `Poly0<(((((((...,),),),),),),)>`
--> $DIR/inherent-impls-overflow.rs:14:17
--> $DIR/inherent-impls-overflow.rs:17:17
|
LL | type Poly0<T> = Poly1<(T,)>;
| ^^^^^^^^^^^
|
= note: in case this is a recursive type alias, consider using a struct, enum, or union instead

error[E0275]: overflow normalizing the type alias `Poly1<(((((((...,),),),),),),)>`
--> $DIR/inherent-impls-overflow.rs:17:17
--> $DIR/inherent-impls-overflow.rs:21:17
|
LL | type Poly1<T> = Poly0<(T,)>;
| ^^^^^^^^^^^
|
= note: in case this is a recursive type alias, consider using a struct, enum, or union instead

error[E0275]: overflow normalizing the type alias `Poly1<(((((((...,),),),),),),)>`
--> $DIR/inherent-impls-overflow.rs:21:1
--> $DIR/inherent-impls-overflow.rs:26:1
|
LL | impl Poly0<()> {}
| ^^^^^^^^^^^^^^^^^
Expand Down
46 changes: 41 additions & 5 deletions tests/ui/lazy-type-alias/inherent-impls-overflow.next.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,31 @@
error[E0271]: type mismatch resolving `Loop normalizes-to _`
--> $DIR/inherent-impls-overflow.rs:10:6
--> $DIR/inherent-impls-overflow.rs:8:13
|
LL | type Loop = Loop;
| ^^^^ types differ

error[E0271]: type mismatch resolving `Loop normalizes-to _`
--> $DIR/inherent-impls-overflow.rs:12:1
|
LL | impl Loop {}
| ^^^^^^^^^^^^ types differ

error[E0271]: type mismatch resolving `Loop normalizes-to _`
--> $DIR/inherent-impls-overflow.rs:12:6
|
LL | impl Loop {}
| ^^^^ types differ

error[E0275]: overflow evaluating the requirement `Poly1<(T,)> == _`
--> $DIR/inherent-impls-overflow.rs:17:17
|
LL | type Poly0<T> = Poly1<(T,)>;
| ^^^^^^^^^^^
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inherent_impls_overflow`)

error: type parameter `T` is only used recursively
--> $DIR/inherent-impls-overflow.rs:14:24
--> $DIR/inherent-impls-overflow.rs:17:24
|
LL | type Poly0<T> = Poly1<(T,)>;
| - ^
Expand All @@ -15,8 +35,16 @@ LL | type Poly0<T> = Poly1<(T,)>;
= help: consider removing `T` or referring to it in the body of the type alias
= note: all type parameters must be used in a non-recursive way in order to constrain their variance

error[E0275]: overflow evaluating the requirement `Poly0<(T,)> == _`
--> $DIR/inherent-impls-overflow.rs:21:17
|
LL | type Poly1<T> = Poly0<(T,)>;
| ^^^^^^^^^^^
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inherent_impls_overflow`)

error: type parameter `T` is only used recursively
--> $DIR/inherent-impls-overflow.rs:17:24
--> $DIR/inherent-impls-overflow.rs:21:24
|
LL | type Poly1<T> = Poly0<(T,)>;
| - ^
Expand All @@ -27,14 +55,22 @@ LL | type Poly1<T> = Poly0<(T,)>;
= note: all type parameters must be used in a non-recursive way in order to constrain their variance

error[E0275]: overflow evaluating the requirement `Poly0<()> == _`
--> $DIR/inherent-impls-overflow.rs:21:6
--> $DIR/inherent-impls-overflow.rs:26:1
|
LL | impl Poly0<()> {}
| ^^^^^^^^^^^^^^^^^
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inherent_impls_overflow`)

error[E0275]: overflow evaluating the requirement `Poly0<()> == _`
--> $DIR/inherent-impls-overflow.rs:26:6
|
LL | impl Poly0<()> {}
| ^^^^^^^^^
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inherent_impls_overflow`)

error: aborting due to 4 previous errors
error: aborting due to 9 previous errors

Some errors have detailed explanations: E0271, E0275.
For more information about an error, try `rustc --explain E0271`.
8 changes: 7 additions & 1 deletion tests/ui/lazy-type-alias/inherent-impls-overflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,27 @@
#![feature(lazy_type_alias)]
#![allow(incomplete_features)]

type Loop = Loop; //[current]~ ERROR overflow normalizing the type alias `Loop`
type Loop = Loop;
//[current]~^ ERROR overflow normalizing the type alias `Loop`
//[next]~^^ ERROR type mismatch resolving `Loop normalizes-to _`

impl Loop {}
//[current]~^ ERROR overflow normalizing the type alias `Loop`
//[next]~^^ ERROR type mismatch resolving `Loop normalizes-to _`
//[next]~| ERROR type mismatch resolving `Loop normalizes-to _`

type Poly0<T> = Poly1<(T,)>;
//[current]~^ ERROR overflow normalizing the type alias `Poly0<(((((((...,),),),),),),)>`
//[next]~^^ ERROR type parameter `T` is only used recursively
//[next]~| ERROR overflow evaluating the requirement
type Poly1<T> = Poly0<(T,)>;
//[current]~^ ERROR overflow normalizing the type alias `Poly1<(((((((...,),),),),),),)>`
//[next]~^^ ERROR type parameter `T` is only used recursively
//[next]~| ERROR overflow evaluating the requirement

impl Poly0<()> {}
//[current]~^ ERROR overflow normalizing the type alias `Poly1<(((((((...,),),),),),),)>`
//[next]~^^ ERROR overflow evaluating the requirement `Poly0<()> == _`
//[next]~| ERROR overflow evaluating the requirement

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0277]: the trait bound `for<'a> (): Trait<'a>` is not satisfied
--> $DIR/dont-ice-on-bad-transmute-in-typeck.rs:7:11
--> $DIR/dont-ice-on-bad-transmute-in-typeck.rs:7:22
|
LL | fn foo(x: for<'a> fn(<() as Trait<'a>>::Assoc)) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Trait<'a>` is not implemented for `()`
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Trait<'a>` is not implemented for `()`
|
help: this trait has no implementations, consider adding one
--> $DIR/dont-ice-on-bad-transmute-in-typeck.rs:3:1
Expand Down
1 change: 1 addition & 0 deletions tests/ui/traits/next-solver/issue-118950-root-region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ impl<T> Overlap<T> for T {}
impl<T> Overlap<for<'a> fn(Assoc<'a, T>)> for T where Missing: Overlap<T> {}
//~^ ERROR cannot find type `Missing` in this scope
//~| ERROR the trait bound `T: Overlap<for<'a> fn(Assoc<'a, T>)>` is not satisfied
//~| ERROR the trait bound `for<'a> *const T: ToUnit<'a>` is not satisfied

fn main() {}
14 changes: 13 additions & 1 deletion tests/ui/traits/next-solver/issue-118950-root-region.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,18 @@ LL | trait ToUnit<'a> {
| ^^^^^^^^^^^^^^^^

WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), .. }
error[E0277]: the trait bound `for<'a> *const T: ToUnit<'a>` is not satisfied
--> $DIR/issue-118950-root-region.rs:19:9
|
LL | impl<T> Overlap<for<'a> fn(Assoc<'a, T>)> for T where Missing: Overlap<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `*const T`
|
help: this trait has no implementations, consider adding one
--> $DIR/issue-118950-root-region.rs:8:1
|
LL | trait ToUnit<'a> {
| ^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `T: Overlap<for<'a> fn(Assoc<'a, T>)>` is not satisfied
--> $DIR/issue-118950-root-region.rs:19:47
|
Expand All @@ -37,7 +49,7 @@ help: consider further restricting type parameter `T` with trait `Overlap`
LL | impl<T> Overlap<for<'a> fn(Assoc<'a, T>)> for T where Missing: Overlap<T>, T: Overlap<for<'a> fn(Assoc<'a, T>)> {}
| ++++++++++++++++++++++++++++++++++++++

error: aborting due to 3 previous errors; 1 warning emitted
error: aborting due to 4 previous errors; 1 warning emitted

Some errors have detailed explanations: E0277, E0412.
For more information about an error, try `rustc --explain E0277`.
4 changes: 2 additions & 2 deletions tests/ui/traits/next-solver/non-wf-in-coerce-pointers.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0277]: the trait bound `(): Wf` is not satisfied
--> $DIR/non-wf-in-coerce-pointers.rs:8:17
--> $DIR/non-wf-in-coerce-pointers.rs:8:8
|
LL | f: &'static <() as Wf>::Assoc,
| ^^^^^^^^^^^^^^^^^ the trait `Wf` is not implemented for `()`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Wf` is not implemented for `()`
|
help: this trait has no implementations, consider adding one
--> $DIR/non-wf-in-coerce-pointers.rs:3:1
Expand Down
24 changes: 24 additions & 0 deletions tests/ui/wf/check-wf-of-normalized-signature.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
//@ ignore-compare-mode-next-solver (explicit revisions)
//@ check-pass

// Regression test for <https://github.com/rust-lang/trait-system-refactor-initiative/issues/194>.
// Ensure that we check the well-formedness of `<Check as Mode>::Output<T>` after normalizing
// the type to `()`, since we only imply outlives bounds from the normalized signature, so we
// don't know (e.g.) that `&mut T` is WF.


trait Mode {
type Output<T>;
fn from_mut<T>(_r: &mut Self::Output<T>) -> Self::Output<&mut T>;
}

struct Check;

impl Mode for Check {
type Output<T> = ();
fn from_mut<T>(_r: &mut Self::Output<T>) -> Self::Output<&mut T> {}
}

fn main() {}
Loading
Loading