diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs index 8b657dcb88de..00a1dfff6d95 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs @@ -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>, ()> { - 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)); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index fb195d45685f..5bb71bc50310 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -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(&mut self, ty: T) -> T - where - T: TypeFoldable>, - { - 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; } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs index 18509c52847f..5c1f85cb2a95 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs @@ -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); + +trait X {} + +impl X for i32 {} +impl X for i64 {} + +impl Iterator for Foo { + type Item = T; + fn next(&mut self) -> Option { + self.next_spec() + } +} + +trait Bar { + type Item; + + fn next_spec(&mut self) -> Option; +} + +impl Bar for Foo { + type Item = T; + + fn next_spec(&mut self) -> Option { + None + } +} + +struct JoinAll +where + F: Future, +{ + f: F, +} + +fn join_all(iter: I) -> JoinAll<::Item> +where + I: IntoIterator, + ::Item: Future, +{ + loop {} +} + +fn main() { + let x = Foo(42).filter_map(|_| Some(async {})); + join_all(x); +} +"#, + expect![[r#" + 164..168 'self': &'? mut Foo + 192..224 '{ ... }': Option + 202..206 'self': &'? mut Foo + 202..218 'self.n...spec()': Option + 278..282 'self': &'? mut Self + 380..384 'self': &'? mut Foo + 408..428 '{ ... }': Option + 418..422 'None': Option + 501..505 'iter': I + 614..629 '{ loop {} }': JoinAll + 620..627 'loop {}': ! + 625..627 '{}': () + 641..713 '{ ...(x); }': () + 651..652 'x': FilterMap, impl FnMut(i32) -> Option>> + 655..658 'Foo': fn Foo(i32) -> Foo + 655..662 'Foo(42)': Foo + 655..693 'Foo(42...c {}))': FilterMap, impl FnMut(i32) -> Option>> + 659..661 '42': i32 + 674..692 '|_| So...nc {})': impl FnMut(i32) -> Option> + 675..676 '_': i32 + 678..682 'Some': fn Some>(impl Future) -> Option> + 678..692 'Some(async {})': Option> + 683..691 'async {}': impl Future + 699..707 'join_all': fn join_all, impl FnMut(i32) -> Option>>>(FilterMap, impl FnMut(i32) -> Option>>) -> JoinAll<, impl FnMut(i32) -> Option>> as IntoIterator>::Item> + 699..710 'join_all(x)': JoinAll> + 708..709 'x': FilterMap, impl FnMut(i32) -> Option>> + "#]], ); }