From 56b741627c6d8ecbc5ca5773fcc8d1aa18d27dd4 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Fri, 8 May 2026 05:18:48 +0300 Subject: [PATCH] Do not replace closure capture place types with errors if they fail to normalize This prevents panics, and we need to get rid of this normalization anyway, see https://github.com/rust-lang/rust/pull/155767. --- crates/hir-ty/src/infer/closure/analysis.rs | 13 +++++-------- .../infer/closure/analysis/expr_use_visitor.rs | 1 - crates/hir-ty/src/infer/unify.rs | 2 +- crates/hir-ty/src/tests/closure_captures.rs | 17 +++++++++++++++++ 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/crates/hir-ty/src/infer/closure/analysis.rs b/crates/hir-ty/src/infer/closure/analysis.rs index 82ace17ac0a7..5ea43bc03ca8 100644 --- a/crates/hir-ty/src/infer/closure/analysis.rs +++ b/crates/hir-ty/src/infer/closure/analysis.rs @@ -920,8 +920,8 @@ impl<'a, 'db> InferenceContext<'a, 'db> { self.result.closures_data.insert(closure_def_id, closure_data); } - fn normalize_capture_place(&self, span: Span, place: Place) -> Place { - let mut place = self.infcx().resolve_vars_if_possible(place); + fn normalize_capture_place(&mut self, span: Span, place: Place) -> Place { + let place = self.infcx().resolve_vars_if_possible(place); // In the new solver, types in HIR `Place`s can contain unnormalized aliases, // which can ICE later (e.g. when projecting fields for diagnostics). @@ -945,11 +945,8 @@ impl<'a, 'db> InferenceContext<'a, 'db> { } normalized } - Err(_errors) => { - place.base_ty = self.types.types.error.store(); - for proj in &mut place.projections { - proj.ty = self.types.types.error.store(); - } + Err(errors) => { + self.table.trait_errors.extend(errors); place } } @@ -1002,7 +999,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { } } - fn place_for_root_variable(&self, closure_def_id: ExprId, var_hir_id: BindingId) -> Place { + fn place_for_root_variable(&mut self, closure_def_id: ExprId, var_hir_id: BindingId) -> Place { let place = Place { base_ty: self.result.binding_ty(var_hir_id).store(), base: PlaceBase::Upvar { closure: closure_def_id, var_id: var_hir_id }, diff --git a/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs b/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs index f76e99aa7831..deafff6b43e0 100644 --- a/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs +++ b/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs @@ -475,7 +475,6 @@ impl<'a, 'b, 'db, D: Delegate<'db>> ExprUseVisitor<'a, 'b, 'db, D> { Ok(()) } - // FIXME: It's suspicious that this is public; clippy should probably use `walk_expr`. #[instrument(skip(self), level = "debug")] pub(crate) fn consume_expr(&mut self, expr: ExprId) -> Result { let place_with_id = self.cat_expr(expr)?; diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs index 33311412bf25..8527b42d785c 100644 --- a/crates/hir-ty/src/infer/unify.rs +++ b/crates/hir-ty/src/infer/unify.rs @@ -134,7 +134,7 @@ pub(crate) struct InferenceTable<'db> { pub(crate) infer_ctxt: InferCtxt<'db>, pub(super) fulfillment_cx: FulfillmentCtxt<'db>, pub(super) diverging_type_vars: FxHashSet>, - trait_errors: Vec>, + pub(super) trait_errors: Vec>, } impl<'db> InferenceTable<'db> { diff --git a/crates/hir-ty/src/tests/closure_captures.rs b/crates/hir-ty/src/tests/closure_captures.rs index b01f44acbc55..d60cf839099f 100644 --- a/crates/hir-ty/src/tests/closure_captures.rs +++ b/crates/hir-ty/src/tests/closure_captures.rs @@ -600,3 +600,20 @@ fn f() { expect!["77..110;46..47;96..97 ByRef(Immutable) b &' i32"], ); } + +#[test] +fn fail_to_normalize_place() { + check_closure_captures( + r#" +//- minicore: index, slice +const FAIL_CONST: usize = loop {}; +struct Foo { + arr: [i32; FAIL_CONST], +} +fn foo(foo: &Foo) { + || { return foo.arr[0] }; +} + "#, + expect!["102..126;85..88;114..117 ByRef(Immutable) *foo &' Foo"], + ); +}