Rollup merge of #59473 - estebank:borrow-sugg-inside-macro, r=davidtwco
Do not emit incorrect borrow suggestion involving macros and fix overlapping multiline spans Fix #58298.
This commit is contained in:
commit
c105f34fcb
@ -243,6 +243,7 @@ impl EmitterWriter {
|
|||||||
end_col: hi.col_display,
|
end_col: hi.col_display,
|
||||||
is_primary: span_label.is_primary,
|
is_primary: span_label.is_primary,
|
||||||
label: span_label.label.clone(),
|
label: span_label.label.clone(),
|
||||||
|
overlaps_exactly: false,
|
||||||
};
|
};
|
||||||
multiline_annotations.push((lo.file.clone(), ml.clone()));
|
multiline_annotations.push((lo.file.clone(), ml.clone()));
|
||||||
AnnotationType::Multiline(ml)
|
AnnotationType::Multiline(ml)
|
||||||
@ -258,10 +259,7 @@ impl EmitterWriter {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if !ann.is_multiline() {
|
if !ann.is_multiline() {
|
||||||
add_annotation_to_file(&mut output,
|
add_annotation_to_file(&mut output, lo.file, lo.line, ann);
|
||||||
lo.file,
|
|
||||||
lo.line,
|
|
||||||
ann);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -274,10 +272,12 @@ impl EmitterWriter {
|
|||||||
let ref mut a = item.1;
|
let ref mut a = item.1;
|
||||||
// Move all other multiline annotations overlapping with this one
|
// Move all other multiline annotations overlapping with this one
|
||||||
// one level to the right.
|
// one level to the right.
|
||||||
if &ann != a &&
|
if !(ann.same_span(a)) &&
|
||||||
num_overlap(ann.line_start, ann.line_end, a.line_start, a.line_end, true)
|
num_overlap(ann.line_start, ann.line_end, a.line_start, a.line_end, true)
|
||||||
{
|
{
|
||||||
a.increase_depth();
|
a.increase_depth();
|
||||||
|
} else if ann.same_span(a) && &ann != a {
|
||||||
|
a.overlaps_exactly = true;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -289,9 +289,38 @@ impl EmitterWriter {
|
|||||||
if ann.depth > max_depth {
|
if ann.depth > max_depth {
|
||||||
max_depth = ann.depth;
|
max_depth = ann.depth;
|
||||||
}
|
}
|
||||||
|
let mut end_ann = ann.as_end();
|
||||||
|
if !ann.overlaps_exactly {
|
||||||
|
// avoid output like
|
||||||
|
//
|
||||||
|
// | foo(
|
||||||
|
// | _____^
|
||||||
|
// | |_____|
|
||||||
|
// | || bar,
|
||||||
|
// | || );
|
||||||
|
// | || ^
|
||||||
|
// | ||______|
|
||||||
|
// | |______foo
|
||||||
|
// | baz
|
||||||
|
//
|
||||||
|
// and instead get
|
||||||
|
//
|
||||||
|
// | foo(
|
||||||
|
// | _____^
|
||||||
|
// | | bar,
|
||||||
|
// | | );
|
||||||
|
// | | ^
|
||||||
|
// | | |
|
||||||
|
// | |______foo
|
||||||
|
// | baz
|
||||||
add_annotation_to_file(&mut output, file.clone(), ann.line_start, ann.as_start());
|
add_annotation_to_file(&mut output, file.clone(), ann.line_start, ann.as_start());
|
||||||
|
// 4 is the minimum vertical length of a multiline span when presented: two lines
|
||||||
|
// of code and two lines of underline. This is not true for the special case where
|
||||||
|
// the beginning doesn't have an underline, but the current logic seems to be
|
||||||
|
// working correctly.
|
||||||
let middle = min(ann.line_start + 4, ann.line_end);
|
let middle = min(ann.line_start + 4, ann.line_end);
|
||||||
for line in ann.line_start + 1..middle {
|
for line in ann.line_start + 1..middle {
|
||||||
|
// Every `|` that joins the beginning of the span (`___^`) to the end (`|__^`).
|
||||||
add_annotation_to_file(&mut output, file.clone(), line, ann.as_line());
|
add_annotation_to_file(&mut output, file.clone(), line, ann.as_line());
|
||||||
}
|
}
|
||||||
if middle < ann.line_end - 1 {
|
if middle < ann.line_end - 1 {
|
||||||
@ -299,7 +328,10 @@ impl EmitterWriter {
|
|||||||
add_annotation_to_file(&mut output, file.clone(), line, ann.as_line());
|
add_annotation_to_file(&mut output, file.clone(), line, ann.as_line());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
add_annotation_to_file(&mut output, file, ann.line_end, ann.as_end());
|
} else {
|
||||||
|
end_ann.annotation_type = AnnotationType::Singleline;
|
||||||
|
}
|
||||||
|
add_annotation_to_file(&mut output, file, ann.line_end, end_ann);
|
||||||
}
|
}
|
||||||
for file_vec in output.iter_mut() {
|
for file_vec in output.iter_mut() {
|
||||||
file_vec.multiline_depth = max_depth;
|
file_vec.multiline_depth = max_depth;
|
||||||
|
@ -18,6 +18,7 @@ pub struct MultilineAnnotation {
|
|||||||
pub end_col: usize,
|
pub end_col: usize,
|
||||||
pub is_primary: bool,
|
pub is_primary: bool,
|
||||||
pub label: Option<String>,
|
pub label: Option<String>,
|
||||||
|
pub overlaps_exactly: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MultilineAnnotation {
|
impl MultilineAnnotation {
|
||||||
@ -25,6 +26,12 @@ impl MultilineAnnotation {
|
|||||||
self.depth += 1;
|
self.depth += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Compare two `MultilineAnnotation`s considering only the `Span` they cover.
|
||||||
|
pub fn same_span(&self, other: &MultilineAnnotation) -> bool {
|
||||||
|
self.line_start == other.line_start && self.line_end == other.line_end
|
||||||
|
&& self.start_col == other.start_col && self.end_col == other.end_col
|
||||||
|
}
|
||||||
|
|
||||||
pub fn as_start(&self) -> Annotation {
|
pub fn as_start(&self) -> Annotation {
|
||||||
Annotation {
|
Annotation {
|
||||||
start_col: self.start_col,
|
start_col: self.start_col,
|
||||||
|
@ -10,7 +10,7 @@ use rustc::hir::Node;
|
|||||||
use rustc::hir::{Item, ItemKind, print};
|
use rustc::hir::{Item, ItemKind, print};
|
||||||
use rustc::ty::{self, Ty, AssociatedItem};
|
use rustc::ty::{self, Ty, AssociatedItem};
|
||||||
use rustc::ty::adjustment::AllowTwoPhase;
|
use rustc::ty::adjustment::AllowTwoPhase;
|
||||||
use errors::{Applicability, DiagnosticBuilder, SourceMapper};
|
use errors::{Applicability, DiagnosticBuilder};
|
||||||
|
|
||||||
use super::method::probe;
|
use super::method::probe;
|
||||||
|
|
||||||
@ -292,9 +292,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||||||
expected: Ty<'tcx>)
|
expected: Ty<'tcx>)
|
||||||
-> Option<(Span, &'static str, String)> {
|
-> Option<(Span, &'static str, String)> {
|
||||||
let cm = self.sess().source_map();
|
let cm = self.sess().source_map();
|
||||||
// Use the callsite's span if this is a macro call. #41858
|
let sp = expr.span;
|
||||||
let sp = cm.call_span_if_macro(expr.span);
|
|
||||||
if !cm.span_to_filename(sp).is_real() {
|
if !cm.span_to_filename(sp).is_real() {
|
||||||
|
// Ignore if span is from within a macro #41858, #58298. We previously used the macro
|
||||||
|
// call span, but that breaks down when the type error comes from multiple calls down.
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,6 +374,66 @@ error: foo
|
|||||||
"#);
|
"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn triple_exact_overlap() {
|
||||||
|
test_harness(r#"
|
||||||
|
fn foo() {
|
||||||
|
X0 Y0 Z0
|
||||||
|
X1 Y1 Z1
|
||||||
|
X2 Y2 Z2
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
vec![
|
||||||
|
SpanLabel {
|
||||||
|
start: Position {
|
||||||
|
string: "X0",
|
||||||
|
count: 1,
|
||||||
|
},
|
||||||
|
end: Position {
|
||||||
|
string: "X2",
|
||||||
|
count: 1,
|
||||||
|
},
|
||||||
|
label: "`X` is a good letter",
|
||||||
|
},
|
||||||
|
SpanLabel {
|
||||||
|
start: Position {
|
||||||
|
string: "X0",
|
||||||
|
count: 1,
|
||||||
|
},
|
||||||
|
end: Position {
|
||||||
|
string: "X2",
|
||||||
|
count: 1,
|
||||||
|
},
|
||||||
|
label: "`Y` is a good letter too",
|
||||||
|
},
|
||||||
|
SpanLabel {
|
||||||
|
start: Position {
|
||||||
|
string: "X0",
|
||||||
|
count: 1,
|
||||||
|
},
|
||||||
|
end: Position {
|
||||||
|
string: "X2",
|
||||||
|
count: 1,
|
||||||
|
},
|
||||||
|
label: "`Z` label",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
r#"
|
||||||
|
error: foo
|
||||||
|
--> test.rs:3:3
|
||||||
|
|
|
||||||
|
3 | / X0 Y0 Z0
|
||||||
|
4 | | X1 Y1 Z1
|
||||||
|
5 | | X2 Y2 Z2
|
||||||
|
| | ^
|
||||||
|
| | |
|
||||||
|
| | `X` is a good letter
|
||||||
|
| |____`Y` is a good letter too
|
||||||
|
| `Z` label
|
||||||
|
|
||||||
|
"#);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn minimum_depth() {
|
fn minimum_depth() {
|
||||||
test_harness(r#"
|
test_harness(r#"
|
||||||
|
@ -50,10 +50,7 @@ error[E0308]: mismatched types
|
|||||||
--> $DIR/coerce-suggestions.rs:21:9
|
--> $DIR/coerce-suggestions.rs:21:9
|
||||||
|
|
|
|
||||||
LL | s = format!("foo");
|
LL | s = format!("foo");
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^ expected mutable reference, found struct `std::string::String`
|
||||||
| |
|
|
||||||
| expected mutable reference, found struct `std::string::String`
|
|
||||||
| help: consider mutably borrowing here: `&mut format!("foo")`
|
|
||||||
|
|
|
|
||||||
= note: expected type `&mut std::string::String`
|
= note: expected type `&mut std::string::String`
|
||||||
found type `std::string::String`
|
found type `std::string::String`
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
fn warn(_: &str) {}
|
||||||
|
|
||||||
|
macro_rules! intrinsic_match {
|
||||||
|
($intrinsic:expr) => {
|
||||||
|
warn(format!("unsupported intrinsic {}", $intrinsic));
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
intrinsic_match! {
|
||||||
|
"abc"
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/dont-suggest-deref-inside-macro-issue-58298.rs:11:5
|
||||||
|
|
|
||||||
|
LL | / intrinsic_match! {
|
||||||
|
LL | | "abc"
|
||||||
|
LL | | };
|
||||||
|
| | ^
|
||||||
|
| | |
|
||||||
|
| |______expected &str, found struct `std::string::String`
|
||||||
|
| in this macro invocation
|
||||||
|
|
|
||||||
|
= note: expected type `&str`
|
||||||
|
found type `std::string::String`
|
||||||
|
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
Loading…
Reference in New Issue
Block a user