introduce Span::find_ancestor_inside_same_ctxt

and use it for function argument diagnostics
This commit is contained in:
Lukas Markeffsky 2023-06-10 19:13:42 +02:00
parent 10ef96f6a5
commit 3694fd08e6
4 changed files with 57 additions and 24 deletions

View file

@ -519,7 +519,7 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
// suggestions and labels are (more) correct when an arg is a
// macro invocation.
let normalize_span = |span: Span| -> Span {
let normalized_span = span.find_ancestor_inside(error_span).unwrap_or(span);
let normalized_span = span.find_ancestor_inside_same_ctxt(error_span).unwrap_or(span);
// Sometimes macros mess up the spans, so do not normalize the
// arg span to equal the error span, because that's less useful
// than pointing out the arg expr in the wrong context.
@ -1220,22 +1220,23 @@ enum SuggestionText {
};
if let Some(suggestion_text) = suggestion_text {
let source_map = self.sess().source_map();
let (mut suggestion, suggestion_span) =
if let Some(call_span) = full_call_span.find_ancestor_inside(error_span) {
("(".to_string(), call_span.shrink_to_hi().to(error_span.shrink_to_hi()))
} else {
(
format!(
"{}(",
source_map.span_to_snippet(full_call_span).unwrap_or_else(|_| {
fn_def_id.map_or("".to_string(), |fn_def_id| {
tcx.item_name(fn_def_id).to_string()
})
let (mut suggestion, suggestion_span) = if let Some(call_span) =
full_call_span.find_ancestor_inside_same_ctxt(error_span)
{
("(".to_string(), call_span.shrink_to_hi().to(error_span.shrink_to_hi()))
} else {
(
format!(
"{}(",
source_map.span_to_snippet(full_call_span).unwrap_or_else(|_| {
fn_def_id.map_or("".to_string(), |fn_def_id| {
tcx.item_name(fn_def_id).to_string()
})
),
error_span,
)
};
})
),
error_span,
)
};
let mut needs_comma = false;
for (expected_idx, provided_idx) in matched_inputs.iter_enumerated() {
if needs_comma {

View file

@ -685,6 +685,12 @@ pub fn parent_callsite(self) -> Option<Span> {
}
/// Walk down the expansion ancestors to find a span that's contained within `outer`.
///
/// The span returned by this method may have a different [`SyntaxContext`] as `outer`.
/// If you need to extend the span, use [`find_ancestor_inside_same_ctxt`] instead,
/// because joining spans with different syntax contexts can create unexpected results.
///
/// [`find_ancestor_inside_same_ctxt`]: Self::find_ancestor_inside_same_ctxt
pub fn find_ancestor_inside(mut self, outer: Span) -> Option<Span> {
while !outer.contains(self) {
self = self.parent_callsite()?;
@ -692,11 +698,34 @@ pub fn find_ancestor_inside(mut self, outer: Span) -> Option<Span> {
Some(self)
}
/// Like `find_ancestor_inside`, but specifically for when spans might not
/// overlaps. Take care when using this, and prefer `find_ancestor_inside`
/// when you know that the spans are nested (modulo macro expansion).
/// Walk down the expansion ancestors to find a span with the same [`SyntaxContext`] as
/// `other`.
///
/// Like [`find_ancestor_inside_same_ctxt`], but specifically for when spans might not
/// overlap. Take care when using this, and prefer [`find_ancestor_inside`] or
/// [`find_ancestor_inside_same_ctxt`] when you know that the spans are nested (modulo
/// macro expansion).
///
/// [`find_ancestor_inside`]: Self::find_ancestor_inside
/// [`find_ancestor_inside_same_ctxt`]: Self::find_ancestor_inside_same_ctxt
pub fn find_ancestor_in_same_ctxt(mut self, other: Span) -> Option<Span> {
while !Span::eq_ctxt(self, other) {
while !self.eq_ctxt(other) {
self = self.parent_callsite()?;
}
Some(self)
}
/// Walk down the expansion ancestors to find a span that's contained within `outer` and
/// has the same [`SyntaxContext`] as `outer`.
///
/// This method is the combination of [`find_ancestor_inside`] and
/// [`find_ancestor_in_same_ctxt`] and should be preferred when extending the returned span.
/// If you do not need to modify the span, use [`find_ancestor_inside`] instead.
///
/// [`find_ancestor_inside`]: Self::find_ancestor_inside
/// [`find_ancestor_in_same_ctxt`]: Self::find_ancestor_in_same_ctxt
pub fn find_ancestor_inside_same_ctxt(mut self, outer: Span) -> Option<Span> {
while !outer.contains(self) || !self.eq_ctxt(outer) {
self = self.parent_callsite()?;
}
Some(self)

View file

@ -321,7 +321,10 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied
--> $DIR/extra_arguments.rs:53:3
|
LL | one_arg(1, panic!());
| ^^^^^^^ -------- unexpected argument
| ^^^^^^^ ----------
| | |
| | unexpected argument
| help: remove the extra argument
|
note: function defined here
--> $DIR/extra_arguments.rs:2:4
@ -333,8 +336,9 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied
--> $DIR/extra_arguments.rs:54:3
|
LL | one_arg(panic!(), 1);
| ^^^^^^^ - - unexpected argument of type `{integer}`
| |
| ^^^^^^^ ---
| | |
| | unexpected argument of type `{integer}`
| help: remove the extra argument
|
note: function defined here

View file

@ -10,7 +10,6 @@ LL | b"".starts_with(stringify!(foo))
found reference `&'static str`
note: method defined here
--> $SRC_DIR/core/src/slice/mod.rs:LL:COL
= note: this error originates in the macro `stringify` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error