Merge pull request #20980 from ShoyuVanilla/shallow-normalize

fix: Remove some deep normalizations from infer
This commit is contained in:
Shoyu Vanilla (Flint) 2025-11-21 17:04:41 +00:00 committed by GitHub
commit c4b8917db3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 93 additions and 18 deletions

View file

@ -110,8 +110,8 @@ impl<'db> CastCheck<'db> {
&mut self,
ctx: &mut InferenceContext<'_, 'db>,
) -> Result<(), InferenceDiagnostic<'db>> {
self.expr_ty = ctx.table.eagerly_normalize_and_resolve_shallow_in(self.expr_ty);
self.cast_ty = ctx.table.eagerly_normalize_and_resolve_shallow_in(self.cast_ty);
self.expr_ty = ctx.table.try_structurally_resolve_type(self.expr_ty);
self.cast_ty = ctx.table.try_structurally_resolve_type(self.cast_ty);
// This should always come first so that we apply the coercion, which impacts infer vars.
if ctx
@ -159,7 +159,7 @@ impl<'db> CastCheck<'db> {
TyKind::FnDef(..) => {
let sig =
self.expr_ty.callable_sig(ctx.interner()).expect("FnDef had no sig");
let sig = ctx.table.eagerly_normalize_and_resolve_shallow_in(sig);
let sig = ctx.table.normalize_associated_types_in(sig);
let fn_ptr = Ty::new_fn_ptr(ctx.interner(), sig);
if ctx
.coerce(
@ -191,7 +191,7 @@ impl<'db> CastCheck<'db> {
},
// array-ptr-cast
CastTy::Ptr(t, m) => {
let t = ctx.table.eagerly_normalize_and_resolve_shallow_in(t);
let t = ctx.table.try_structurally_resolve_type(t);
if !ctx.table.is_sized(t) {
return Err(CastError::IllegalCast);
}
@ -375,7 +375,7 @@ fn pointer_kind<'db>(
ty: Ty<'db>,
ctx: &mut InferenceContext<'_, 'db>,
) -> Result<Option<PointerKind<'db>>, ()> {
let ty = ctx.table.eagerly_normalize_and_resolve_shallow_in(ty);
let ty = ctx.table.try_structurally_resolve_type(ty);
if ctx.table.is_sized(ty) {
return Ok(Some(PointerKind::Thin));

View file

@ -284,17 +284,6 @@ impl<'db> InferenceTable<'db> {
self.at(&ObligationCause::new()).deeply_normalize(ty.clone()).unwrap_or(ty)
}
/// Works almost same as [`Self::normalize_associated_types_in`], but this also resolves shallow
/// the inference variables
pub(crate) fn eagerly_normalize_and_resolve_shallow_in<T>(&mut self, ty: T) -> T
where
T: TypeFoldable<DbInterner<'db>>,
{
let ty = self.resolve_vars_with_obligations(ty);
let ty = self.normalize_associated_types_in(ty);
self.resolve_vars_with_obligations(ty)
}
pub(crate) fn normalize_alias_ty(&mut self, alias: Ty<'db>) -> Ty<'db> {
self.infer_ctxt
.at(&ObligationCause::new(), self.trait_env.env)
@ -651,7 +640,7 @@ impl<'db> InferenceTable<'db> {
}
let mut ty = ty;
ty = self.eagerly_normalize_and_resolve_shallow_in(ty);
ty = self.try_structurally_resolve_type(ty);
if let Some(sized) = short_circuit_trivial_tys(ty) {
return sized;
}
@ -673,7 +662,7 @@ impl<'db> InferenceTable<'db> {
// Structs can have DST as its last field and such cases are not handled
// as unsized by the chalk, so we do this manually.
ty = last_field_ty;
ty = self.eagerly_normalize_and_resolve_shallow_in(ty);
ty = self.try_structurally_resolve_type(ty);
if let Some(sized) = short_circuit_trivial_tys(ty) {
return sized;
}

View file

@ -605,5 +605,91 @@ impl SimpleModel for ExampleData {
}
}
"#,
)
}
#[test]
fn regression_20975() {
check_infer(
r#"
//- minicore: future, iterators, range
use core::future::Future;
struct Foo<T>(T);
trait X {}
impl X for i32 {}
impl X for i64 {}
impl<T: X> Iterator for Foo<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.next_spec()
}
}
trait Bar {
type Item;
fn next_spec(&mut self) -> Option<Self::Item>;
}
impl<T: X> Bar for Foo<T> {
type Item = T;
fn next_spec(&mut self) -> Option<Self::Item> {
None
}
}
struct JoinAll<F>
where
F: Future,
{
f: F,
}
fn join_all<I>(iter: I) -> JoinAll<<I as IntoIterator>::Item>
where
I: IntoIterator,
<I as IntoIterator>::Item: Future,
{
loop {}
}
fn main() {
let x = Foo(42).filter_map(|_| Some(async {}));
join_all(x);
}
"#,
expect![[r#"
164..168 'self': &'? mut Foo<T>
192..224 '{ ... }': Option<T>
202..206 'self': &'? mut Foo<T>
202..218 'self.n...spec()': Option<T>
278..282 'self': &'? mut Self
380..384 'self': &'? mut Foo<T>
408..428 '{ ... }': Option<T>
418..422 'None': Option<T>
501..505 'iter': I
614..629 '{ loop {} }': JoinAll<impl Future>
620..627 'loop {}': !
625..627 '{}': ()
641..713 '{ ...(x); }': ()
651..652 'x': FilterMap<Foo<i32>, impl FnMut(i32) -> Option<impl Future<Output = ()>>>
655..658 'Foo': fn Foo<i32>(i32) -> Foo<i32>
655..662 'Foo(42)': Foo<i32>
655..693 'Foo(42...c {}))': FilterMap<Foo<i32>, impl FnMut(i32) -> Option<impl Future<Output = ()>>>
659..661 '42': i32
674..692 '|_| So...nc {})': impl FnMut(i32) -> Option<impl Future<Output = ()>>
675..676 '_': i32
678..682 'Some': fn Some<impl Future<Output = ()>>(impl Future<Output = ()>) -> Option<impl Future<Output = ()>>
678..692 'Some(async {})': Option<impl Future<Output = ()>>
683..691 'async {}': impl Future<Output = ()>
699..707 'join_all': fn join_all<FilterMap<Foo<i32>, impl FnMut(i32) -> Option<impl Future<Output = ()>>>>(FilterMap<Foo<i32>, impl FnMut(i32) -> Option<impl Future<Output = ()>>>) -> JoinAll<<FilterMap<Foo<i32>, impl FnMut(i32) -> Option<impl Future<Output = ()>>> as IntoIterator>::Item>
699..710 'join_all(x)': JoinAll<impl Future<Output = ()>>
708..709 'x': FilterMap<Foo<i32>, impl FnMut(i32) -> Option<impl Future<Output = ()>>>
"#]],
);
}