Point of macro expansion from call expr if it involves macro var
This commit is contained in:
parent
e16a049adb
commit
ab31129956
4 changed files with 82 additions and 3 deletions
|
@ -158,7 +158,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
self.typeck_results.borrow_mut().used_trait_imports.insert(import_id);
|
self.typeck_results.borrow_mut().used_trait_imports.insert(import_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (span, sugg_span, source, item_name, args) = match self.tcx.hir_node(call_id) {
|
let (span, expr_span, source, item_name, args) = match self.tcx.hir_node(call_id) {
|
||||||
hir::Node::Expr(&hir::Expr {
|
hir::Node::Expr(&hir::Expr {
|
||||||
kind: hir::ExprKind::MethodCall(segment, rcvr, args, _),
|
kind: hir::ExprKind::MethodCall(segment, rcvr, args, _),
|
||||||
span,
|
span,
|
||||||
|
@ -194,6 +194,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
node => unreachable!("{node:?}"),
|
node => unreachable!("{node:?}"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Try to get the span of the identifier within the expression's syntax context (if that's different).
|
||||||
|
let within_macro_span = span.within_macro(expr_span);
|
||||||
|
|
||||||
// Avoid suggestions when we don't know what's going on.
|
// Avoid suggestions when we don't know what's going on.
|
||||||
if let Err(guar) = rcvr_ty.error_reported() {
|
if let Err(guar) = rcvr_ty.error_reported() {
|
||||||
return guar;
|
return guar;
|
||||||
|
@ -207,10 +210,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
call_id,
|
call_id,
|
||||||
source,
|
source,
|
||||||
args,
|
args,
|
||||||
sugg_span,
|
expr_span,
|
||||||
&mut no_match_data,
|
&mut no_match_data,
|
||||||
expected,
|
expected,
|
||||||
trait_missing_method,
|
trait_missing_method,
|
||||||
|
within_macro_span,
|
||||||
),
|
),
|
||||||
|
|
||||||
MethodError::Ambiguity(mut sources) => {
|
MethodError::Ambiguity(mut sources) => {
|
||||||
|
@ -221,6 +225,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
"multiple applicable items in scope"
|
"multiple applicable items in scope"
|
||||||
);
|
);
|
||||||
err.span_label(item_name.span, format!("multiple `{item_name}` found"));
|
err.span_label(item_name.span, format!("multiple `{item_name}` found"));
|
||||||
|
if let Some(within_macro_span) = within_macro_span {
|
||||||
|
err.span_label(within_macro_span, "due to this macro variable");
|
||||||
|
}
|
||||||
|
|
||||||
self.note_candidates_on_method_error(
|
self.note_candidates_on_method_error(
|
||||||
rcvr_ty,
|
rcvr_ty,
|
||||||
|
@ -230,7 +237,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
span,
|
span,
|
||||||
&mut err,
|
&mut err,
|
||||||
&mut sources,
|
&mut sources,
|
||||||
Some(sugg_span),
|
Some(expr_span),
|
||||||
);
|
);
|
||||||
err.emit()
|
err.emit()
|
||||||
}
|
}
|
||||||
|
@ -252,6 +259,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
.span_if_local(def_id)
|
.span_if_local(def_id)
|
||||||
.unwrap_or_else(|| self.tcx.def_span(def_id));
|
.unwrap_or_else(|| self.tcx.def_span(def_id));
|
||||||
err.span_label(sp, format!("private {kind} defined here"));
|
err.span_label(sp, format!("private {kind} defined here"));
|
||||||
|
if let Some(within_macro_span) = within_macro_span {
|
||||||
|
err.span_label(within_macro_span, "due to this macro variable");
|
||||||
|
}
|
||||||
self.suggest_valid_traits(&mut err, item_name, out_of_scope_traits, true);
|
self.suggest_valid_traits(&mut err, item_name, out_of_scope_traits, true);
|
||||||
err.emit()
|
err.emit()
|
||||||
}
|
}
|
||||||
|
@ -268,6 +278,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
if !needs_mut {
|
if !needs_mut {
|
||||||
err.span_label(bound_span, "this has a `Sized` requirement");
|
err.span_label(bound_span, "this has a `Sized` requirement");
|
||||||
}
|
}
|
||||||
|
if let Some(within_macro_span) = within_macro_span {
|
||||||
|
err.span_label(within_macro_span, "due to this macro variable");
|
||||||
|
}
|
||||||
if !candidates.is_empty() {
|
if !candidates.is_empty() {
|
||||||
let help = format!(
|
let help = format!(
|
||||||
"{an}other candidate{s} {were} found in the following trait{s}",
|
"{an}other candidate{s} {were} found in the following trait{s}",
|
||||||
|
@ -581,6 +594,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
no_match_data: &mut NoMatchData<'tcx>,
|
no_match_data: &mut NoMatchData<'tcx>,
|
||||||
expected: Expectation<'tcx>,
|
expected: Expectation<'tcx>,
|
||||||
trait_missing_method: bool,
|
trait_missing_method: bool,
|
||||||
|
within_macro_span: Option<Span>,
|
||||||
) -> ErrorGuaranteed {
|
) -> ErrorGuaranteed {
|
||||||
let mode = no_match_data.mode;
|
let mode = no_match_data.mode;
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
|
@ -721,6 +735,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
if tcx.sess.source_map().is_multiline(sugg_span) {
|
if tcx.sess.source_map().is_multiline(sugg_span) {
|
||||||
err.span_label(sugg_span.with_hi(span.lo()), "");
|
err.span_label(sugg_span.with_hi(span.lo()), "");
|
||||||
}
|
}
|
||||||
|
if let Some(within_macro_span) = within_macro_span {
|
||||||
|
err.span_label(within_macro_span, "due to this macro variable");
|
||||||
|
}
|
||||||
|
|
||||||
if short_ty_str.len() < ty_str.len() && ty_str.len() > 10 {
|
if short_ty_str.len() < ty_str.len() && ty_str.len() > 10 {
|
||||||
ty_str = short_ty_str;
|
ty_str = short_ty_str;
|
||||||
|
|
|
@ -1057,6 +1057,29 @@ impl Span {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the `Span` within the syntax context of "within". This is useful when
|
||||||
|
/// "self" is an expansion from a macro variable, since this can be used for
|
||||||
|
/// providing extra macro expansion context for certain errors.
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// macro_rules! m {
|
||||||
|
/// ($ident:ident) => { ($ident,) }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// m!(outer_ident);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// If "self" is the span of the outer_ident, and "within" is the span of the `($ident,)`
|
||||||
|
/// expr, then this will return the span of the `$ident` macro variable.
|
||||||
|
pub fn within_macro(self, within: Span) -> Option<Span> {
|
||||||
|
match Span::prepare_to_combine(self, within) {
|
||||||
|
Ok((self_, _, parent)) if self_.lo != self.lo() && self.hi() != self_.hi => {
|
||||||
|
Some(Span::new(self_.lo, self_.hi, self_.ctxt, parent))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn from_inner(self, inner: InnerSpan) -> Span {
|
pub fn from_inner(self, inner: InnerSpan) -> Span {
|
||||||
let span = self.data();
|
let span = self.data();
|
||||||
Span::new(
|
Span::new(
|
||||||
|
|
18
tests/ui/methods/ident-from-macro-expansion.rs
Normal file
18
tests/ui/methods/ident-from-macro-expansion.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
macro_rules! dot {
|
||||||
|
($id:ident) => {
|
||||||
|
().$id();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! dispatch {
|
||||||
|
($id:ident) => {
|
||||||
|
<()>::$id();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
dot!(hello);
|
||||||
|
//~^ ERROR no method named `hello` found for unit type `()` in the current scope
|
||||||
|
dispatch!(hello);
|
||||||
|
//~^ ERROR no function or associated item named `hello` found for unit type `()` in the current scope
|
||||||
|
}
|
21
tests/ui/methods/ident-from-macro-expansion.stderr
Normal file
21
tests/ui/methods/ident-from-macro-expansion.stderr
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
error[E0599]: no method named `hello` found for unit type `()` in the current scope
|
||||||
|
--> $DIR/ident-from-macro-expansion.rs:14:10
|
||||||
|
|
|
||||||
|
LL | ().$id();
|
||||||
|
| --- due to this macro variable
|
||||||
|
...
|
||||||
|
LL | dot!(hello);
|
||||||
|
| ^^^^^ method not found in `()`
|
||||||
|
|
||||||
|
error[E0599]: no function or associated item named `hello` found for unit type `()` in the current scope
|
||||||
|
--> $DIR/ident-from-macro-expansion.rs:16:15
|
||||||
|
|
|
||||||
|
LL | <()>::$id();
|
||||||
|
| --- due to this macro variable
|
||||||
|
...
|
||||||
|
LL | dispatch!(hello);
|
||||||
|
| ^^^^^ function or associated item not found in `()`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0599`.
|
Loading…
Add table
Add a link
Reference in a new issue