Skip to content

Commit 4606485

Browse files
committed
typeck: fix ? operator suggestion span
1 parent a809ec9 commit 4606485

File tree

2 files changed

+42
-12
lines changed

2 files changed

+42
-12
lines changed

compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

+3-12
Original file line numberDiff line numberDiff line change
@@ -1291,12 +1291,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12911291
ty::TraitRef::new(self.tcx, into_def_id, [expr_ty, expected_ty]),
12921292
))
12931293
{
1294-
let mut span = expr.span;
1295-
while expr.span.eq_ctxt(span)
1296-
&& let Some(parent_callsite) = span.parent_callsite()
1297-
{
1298-
span = parent_callsite;
1299-
}
1294+
let span = expr.span.find_oldest_ancestor_in_same_ctxt();
13001295

13011296
let mut sugg = if expr.precedence().order() >= PREC_POSTFIX {
13021297
vec![(span.shrink_to_hi(), ".into()".to_owned())]
@@ -1901,12 +1896,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
19011896
None => sugg.to_string(),
19021897
};
19031898

1904-
err.span_suggestion_verbose(
1905-
expr.span.shrink_to_hi(),
1906-
msg,
1907-
sugg,
1908-
Applicability::HasPlaceholders,
1909-
);
1899+
let span = expr.span.find_oldest_ancestor_in_same_ctxt();
1900+
err.span_suggestion_verbose(span.shrink_to_hi(), msg, sugg, Applicability::HasPlaceholders);
19101901
return true;
19111902
}
19121903

compiler/rustc_span/src/lib.rs

+39
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,45 @@ impl Span {
743743
Some(self)
744744
}
745745

746+
/// Recursively walk down the expansion ancestors to find the oldest ancestor span with the same
747+
/// [`SyntaxContext`] the initial span.
748+
///
749+
/// This method is suitable for peeling through *local* macro expansions to find the "innermost"
750+
/// span that is still local and shares the same [`SyntaxContext`]. For example, given
751+
///
752+
/// ```ignore (illustrative example, contains type error)
753+
/// macro_rules! outer {
754+
/// ($x: expr) => {
755+
/// inner!($x)
756+
/// }
757+
/// }
758+
///
759+
/// macro_rules! inner {
760+
/// ($x: expr) => {
761+
/// format!("error: {}", $x)
762+
/// //~^ ERROR mismatched types
763+
/// }
764+
/// }
765+
///
766+
/// fn bar(x: &str) -> Result<(), Box<dyn std::error::Error>> {
767+
/// Err(outer!(x))
768+
/// }
769+
/// ```
770+
///
771+
/// if provided the initial span of `outer!(x)` inside `bar`, this method will recurse
772+
/// the parent callsites until we reach `format!("error: {}", $x)`, at which point it is the
773+
/// oldest ancestor span that is both still local and shares the same [`SyntaxContext`] as the
774+
/// initial span.
775+
pub fn find_oldest_ancestor_in_same_ctxt(self) -> Span {
776+
let mut cur = self;
777+
while cur.eq_ctxt(self)
778+
&& let Some(parent_callsite) = cur.parent_callsite()
779+
{
780+
cur = parent_callsite;
781+
}
782+
cur
783+
}
784+
746785
/// Edition of the crate from which this span came.
747786
pub fn edition(self) -> edition::Edition {
748787
self.ctxt().edition()

0 commit comments

Comments
 (0)