Skip to content

Commit ab31129

Browse files
Point of macro expansion from call expr if it involves macro var
1 parent e16a049 commit ab31129

File tree

4 files changed

+82
-3
lines changed

4 files changed

+82
-3
lines changed

compiler/rustc_hir_typeck/src/method/suggest.rs

+20-3
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
158158
self.typeck_results.borrow_mut().used_trait_imports.insert(import_id);
159159
}
160160

161-
let (span, sugg_span, source, item_name, args) = match self.tcx.hir_node(call_id) {
161+
let (span, expr_span, source, item_name, args) = match self.tcx.hir_node(call_id) {
162162
hir::Node::Expr(&hir::Expr {
163163
kind: hir::ExprKind::MethodCall(segment, rcvr, args, _),
164164
span,
@@ -194,6 +194,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
194194
node => unreachable!("{node:?}"),
195195
};
196196

197+
// Try to get the span of the identifier within the expression's syntax context (if that's different).
198+
let within_macro_span = span.within_macro(expr_span);
199+
197200
// Avoid suggestions when we don't know what's going on.
198201
if let Err(guar) = rcvr_ty.error_reported() {
199202
return guar;
@@ -207,10 +210,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
207210
call_id,
208211
source,
209212
args,
210-
sugg_span,
213+
expr_span,
211214
&mut no_match_data,
212215
expected,
213216
trait_missing_method,
217+
within_macro_span,
214218
),
215219

216220
MethodError::Ambiguity(mut sources) => {
@@ -221,6 +225,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
221225
"multiple applicable items in scope"
222226
);
223227
err.span_label(item_name.span, format!("multiple `{item_name}` found"));
228+
if let Some(within_macro_span) = within_macro_span {
229+
err.span_label(within_macro_span, "due to this macro variable");
230+
}
224231

225232
self.note_candidates_on_method_error(
226233
rcvr_ty,
@@ -230,7 +237,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
230237
span,
231238
&mut err,
232239
&mut sources,
233-
Some(sugg_span),
240+
Some(expr_span),
234241
);
235242
err.emit()
236243
}
@@ -252,6 +259,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
252259
.span_if_local(def_id)
253260
.unwrap_or_else(|| self.tcx.def_span(def_id));
254261
err.span_label(sp, format!("private {kind} defined here"));
262+
if let Some(within_macro_span) = within_macro_span {
263+
err.span_label(within_macro_span, "due to this macro variable");
264+
}
255265
self.suggest_valid_traits(&mut err, item_name, out_of_scope_traits, true);
256266
err.emit()
257267
}
@@ -268,6 +278,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
268278
if !needs_mut {
269279
err.span_label(bound_span, "this has a `Sized` requirement");
270280
}
281+
if let Some(within_macro_span) = within_macro_span {
282+
err.span_label(within_macro_span, "due to this macro variable");
283+
}
271284
if !candidates.is_empty() {
272285
let help = format!(
273286
"{an}other candidate{s} {were} found in the following trait{s}",
@@ -581,6 +594,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
581594
no_match_data: &mut NoMatchData<'tcx>,
582595
expected: Expectation<'tcx>,
583596
trait_missing_method: bool,
597+
within_macro_span: Option<Span>,
584598
) -> ErrorGuaranteed {
585599
let mode = no_match_data.mode;
586600
let tcx = self.tcx;
@@ -721,6 +735,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
721735
if tcx.sess.source_map().is_multiline(sugg_span) {
722736
err.span_label(sugg_span.with_hi(span.lo()), "");
723737
}
738+
if let Some(within_macro_span) = within_macro_span {
739+
err.span_label(within_macro_span, "due to this macro variable");
740+
}
724741

725742
if short_ty_str.len() < ty_str.len() && ty_str.len() > 10 {
726743
ty_str = short_ty_str;

compiler/rustc_span/src/lib.rs

+23
Original file line numberDiff line numberDiff line change
@@ -1057,6 +1057,29 @@ impl Span {
10571057
}
10581058
}
10591059

1060+
/// Returns the `Span` within the syntax context of "within". This is useful when
1061+
/// "self" is an expansion from a macro variable, since this can be used for
1062+
/// providing extra macro expansion context for certain errors.
1063+
///
1064+
/// ```text
1065+
/// macro_rules! m {
1066+
/// ($ident:ident) => { ($ident,) }
1067+
/// }
1068+
///
1069+
/// m!(outer_ident);
1070+
/// ```
1071+
///
1072+
/// If "self" is the span of the outer_ident, and "within" is the span of the `($ident,)`
1073+
/// expr, then this will return the span of the `$ident` macro variable.
1074+
pub fn within_macro(self, within: Span) -> Option<Span> {
1075+
match Span::prepare_to_combine(self, within) {
1076+
Ok((self_, _, parent)) if self_.lo != self.lo() && self.hi() != self_.hi => {
1077+
Some(Span::new(self_.lo, self_.hi, self_.ctxt, parent))
1078+
}
1079+
_ => None,
1080+
}
1081+
}
1082+
10601083
pub fn from_inner(self, inner: InnerSpan) -> Span {
10611084
let span = self.data();
10621085
Span::new(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
macro_rules! dot {
2+
($id:ident) => {
3+
().$id();
4+
}
5+
}
6+
7+
macro_rules! dispatch {
8+
($id:ident) => {
9+
<()>::$id();
10+
}
11+
}
12+
13+
fn main() {
14+
dot!(hello);
15+
//~^ ERROR no method named `hello` found for unit type `()` in the current scope
16+
dispatch!(hello);
17+
//~^ ERROR no function or associated item named `hello` found for unit type `()` in the current scope
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0599]: no method named `hello` found for unit type `()` in the current scope
2+
--> $DIR/ident-from-macro-expansion.rs:14:10
3+
|
4+
LL | ().$id();
5+
| --- due to this macro variable
6+
...
7+
LL | dot!(hello);
8+
| ^^^^^ method not found in `()`
9+
10+
error[E0599]: no function or associated item named `hello` found for unit type `()` in the current scope
11+
--> $DIR/ident-from-macro-expansion.rs:16:15
12+
|
13+
LL | <()>::$id();
14+
| --- due to this macro variable
15+
...
16+
LL | dispatch!(hello);
17+
| ^^^^^ function or associated item not found in `()`
18+
19+
error: aborting due to 2 previous errors
20+
21+
For more information about this error, try `rustc --explain E0599`.

0 commit comments

Comments
 (0)