typeck: fix ?
operator suggestion span
This commit is contained in:
parent
a809ec96f3
commit
4606485d0c
2 changed files with 42 additions and 12 deletions
|
@ -1291,12 +1291,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
ty::TraitRef::new(self.tcx, into_def_id, [expr_ty, expected_ty]),
|
ty::TraitRef::new(self.tcx, into_def_id, [expr_ty, expected_ty]),
|
||||||
))
|
))
|
||||||
{
|
{
|
||||||
let mut span = expr.span;
|
let span = expr.span.find_oldest_ancestor_in_same_ctxt();
|
||||||
while expr.span.eq_ctxt(span)
|
|
||||||
&& let Some(parent_callsite) = span.parent_callsite()
|
|
||||||
{
|
|
||||||
span = parent_callsite;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut sugg = if expr.precedence().order() >= PREC_POSTFIX {
|
let mut sugg = if expr.precedence().order() >= PREC_POSTFIX {
|
||||||
vec![(span.shrink_to_hi(), ".into()".to_owned())]
|
vec![(span.shrink_to_hi(), ".into()".to_owned())]
|
||||||
|
@ -1901,12 +1896,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
None => sugg.to_string(),
|
None => sugg.to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
err.span_suggestion_verbose(
|
let span = expr.span.find_oldest_ancestor_in_same_ctxt();
|
||||||
expr.span.shrink_to_hi(),
|
err.span_suggestion_verbose(span.shrink_to_hi(), msg, sugg, Applicability::HasPlaceholders);
|
||||||
msg,
|
|
||||||
sugg,
|
|
||||||
Applicability::HasPlaceholders,
|
|
||||||
);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -743,6 +743,45 @@ impl Span {
|
||||||
Some(self)
|
Some(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Recursively walk down the expansion ancestors to find the oldest ancestor span with the same
|
||||||
|
/// [`SyntaxContext`] the initial span.
|
||||||
|
///
|
||||||
|
/// This method is suitable for peeling through *local* macro expansions to find the "innermost"
|
||||||
|
/// span that is still local and shares the same [`SyntaxContext`]. For example, given
|
||||||
|
///
|
||||||
|
/// ```ignore (illustrative example, contains type error)
|
||||||
|
/// macro_rules! outer {
|
||||||
|
/// ($x: expr) => {
|
||||||
|
/// inner!($x)
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// macro_rules! inner {
|
||||||
|
/// ($x: expr) => {
|
||||||
|
/// format!("error: {}", $x)
|
||||||
|
/// //~^ ERROR mismatched types
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn bar(x: &str) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
/// Err(outer!(x))
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// if provided the initial span of `outer!(x)` inside `bar`, this method will recurse
|
||||||
|
/// the parent callsites until we reach `format!("error: {}", $x)`, at which point it is the
|
||||||
|
/// oldest ancestor span that is both still local and shares the same [`SyntaxContext`] as the
|
||||||
|
/// initial span.
|
||||||
|
pub fn find_oldest_ancestor_in_same_ctxt(self) -> Span {
|
||||||
|
let mut cur = self;
|
||||||
|
while cur.eq_ctxt(self)
|
||||||
|
&& let Some(parent_callsite) = cur.parent_callsite()
|
||||||
|
{
|
||||||
|
cur = parent_callsite;
|
||||||
|
}
|
||||||
|
cur
|
||||||
|
}
|
||||||
|
|
||||||
/// Edition of the crate from which this span came.
|
/// Edition of the crate from which this span came.
|
||||||
pub fn edition(self) -> edition::Edition {
|
pub fn edition(self) -> edition::Edition {
|
||||||
self.ctxt().edition()
|
self.ctxt().edition()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue