From 23798ce260cc7535221f59cab1b180905fe693e8 Mon Sep 17 00:00:00 2001 From: Rohan Singla Date: Wed, 8 Jul 2026 05:09:45 +0530 Subject: [PATCH] diagnostics: fix `let x: vec![]` suggestion pointing into stdlib When a macro call like `vec![]` appears in type position, the compiler's "use `=` if you meant to assign" suggestion was pointing into the macro definition in stdlib instead of the user's own code. Use `hir_ty.span.source_callsite()` to get the original macro call site in user code when computing the suggestion span. --- .../src/hir_ty_lowering/mod.rs | 54 ++++++++++++------- .../let-binding-init-expr-as-ty.rs | 11 ++++ .../let-binding-init-expr-as-ty.stderr | 35 +++++++++--- 3 files changed, 76 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 2b0219f356c3c..5ca511778e5cf 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -3290,18 +3290,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .next() { // `let x: S::new(valid_in_ty_ctxt);` -> `let x = S::new(valid_in_ty_ctxt);` - let err = tcx - .dcx() - .struct_span_err( - hir_ty.span, - "expected type, found associated function call", - ) - .with_span_suggestion_verbose( - stmt.pat.span.between(hir_ty.span), + let mut err = tcx.dcx().struct_span_err( + hir_ty.span, + "expected type, found associated function call", + ); + if let Some(between) = eq_ctxt_suggestion_span(stmt.pat.span, hir_ty.span) { + err.span_suggestion_verbose( + between, "use `=` if you meant to assign", - " = ".to_string(), + " = ", Applicability::MaybeIncorrect, ); + } self.dcx().try_steal_replace_and_emit_err( hir_ty.span, StashKey::ReturnTypeNotation, @@ -3316,18 +3316,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { { // `let x: i32::something(valid_in_ty_ctxt);` -> `let x = i32::something(valid_in_ty_ctxt);` // FIXME: Check that `something` is a valid function in `i32`. - let err = tcx - .dcx() - .struct_span_err( - hir_ty.span, - "expected type, found associated function call", - ) - .with_span_suggestion_verbose( - stmt.pat.span.between(hir_ty.span), + let mut err = tcx.dcx().struct_span_err( + hir_ty.span, + "expected type, found associated function call", + ); + if let Some(between) = eq_ctxt_suggestion_span(stmt.pat.span, hir_ty.span) { + err.span_suggestion_verbose( + between, "use `=` if you meant to assign", - " = ".to_string(), + " = ", Applicability::MaybeIncorrect, ); + } self.dcx().try_steal_replace_and_emit_err( hir_ty.span, StashKey::ReturnTypeNotation, @@ -3813,3 +3813,21 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::Const::new_value(tcx, valtree, adt_ty) } } + +/// Computes the `pat.between(ty)` span for the "use `=`" suggestion on `let pat: ty`. +/// Returns `None` if `pat` and `ty` are in incompatible macro contexts (e.g. `pat` is a +/// metavariable from the call site while `ty` lives in the macro body), in which case no +/// suggestion is emitted. +fn eq_ctxt_suggestion_span(pat: Span, ty: Span) -> Option { + if let Some(ty2) = ty.find_ancestor_in_same_ctxt(pat) + && pat.hi() <= ty2.lo() + { + return Some(pat.between(ty2)); + } + if let Some(pat2) = pat.find_ancestor_in_same_ctxt(ty) + && pat2.hi() <= ty.lo() + { + return Some(pat2.between(ty)); + } + None +} diff --git a/tests/ui/suggestions/let-binding-init-expr-as-ty.rs b/tests/ui/suggestions/let-binding-init-expr-as-ty.rs index c108b567b18b5..fbf197c84e138 100644 --- a/tests/ui/suggestions/let-binding-init-expr-as-ty.rs +++ b/tests/ui/suggestions/let-binding-init-expr-as-ty.rs @@ -28,6 +28,17 @@ fn main() { //~^ ERROR return type notation is experimental let x: S::new(()); //~ ERROR expected type, found associated function call + // Macros — suggestion must point at user code, not the macro definition (#158834) + let x: vec![]; //~ ERROR expected type, found associated function call + + // When the `let` is inside a macro, no suggestion should be emitted at the call site + macro_rules! make { + ($pat:pat) => { + let $pat: Vec::new(); //~ ERROR expected type, found associated function call + }; + } + make!(_); + // Literals let x: 42; //~ ERROR expected type, found `42` let x: ""; //~ ERROR expected type, found `""` diff --git a/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr b/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr index 354d119769119..4fd2b357a648b 100644 --- a/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr +++ b/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr @@ -1,5 +1,5 @@ error: expected type, found `42` - --> $DIR/let-binding-init-expr-as-ty.rs:32:12 + --> $DIR/let-binding-init-expr-as-ty.rs:43:12 | LL | let x: 42; | - ^^ expected type @@ -13,7 +13,7 @@ LL + let x = 42; | error: expected type, found `""` - --> $DIR/let-binding-init-expr-as-ty.rs:33:12 + --> $DIR/let-binding-init-expr-as-ty.rs:44:12 | LL | let x: ""; | - ^^ expected type @@ -39,7 +39,7 @@ LL + let foo = i32::from_be(num); | error[E0573]: expected type, found function `bar` - --> $DIR/let-binding-init-expr-as-ty.rs:36:12 + --> $DIR/let-binding-init-expr-as-ty.rs:47:12 | LL | let x: bar(); | ^^^^^ not a type @@ -51,13 +51,13 @@ LL + let x = bar(); | error[E0573]: expected type, found function `bar` - --> $DIR/let-binding-init-expr-as-ty.rs:37:12 + --> $DIR/let-binding-init-expr-as-ty.rs:48:12 | LL | let x: bar; | ^^^ not a type error[E0573]: expected type, found local variable `x` - --> $DIR/let-binding-init-expr-as-ty.rs:40:12 + --> $DIR/let-binding-init-expr-as-ty.rs:51:12 | LL | struct K(S::new(())); | --------------------- similarly named struct `K` defined here @@ -153,7 +153,30 @@ LL - let x: S::new(()); LL + let x = S::new(()); | -error: aborting due to 13 previous errors +error: expected type, found associated function call + --> $DIR/let-binding-init-expr-as-ty.rs:32:12 + | +LL | let x: vec![]; + | ^^^^^^ + | +help: use `=` if you meant to assign + | +LL - let x: vec![]; +LL + let x = vec![]; + | + +error: expected type, found associated function call + --> $DIR/let-binding-init-expr-as-ty.rs:37:23 + | +LL | let $pat: Vec::new(); + | ^^^^^^^^^^ +... +LL | make!(_); + | -------- in this macro invocation + | + = note: this error originates in the macro `make` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 15 previous errors Some errors have detailed explanations: E0573, E0658. For more information about an error, try `rustc --explain E0573`.