Skip to content

Commit

Permalink
refactor: move helper to be method on Span
Browse files Browse the repository at this point in the history
  • Loading branch information
jieyouxu committed Apr 9, 2024
1 parent d8f63a6 commit 98e9201
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 18 deletions.
20 changes: 2 additions & 18 deletions compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1291,7 +1291,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty::TraitRef::new(self.tcx, into_def_id, [expr_ty, expected_ty]),
))
{
let span = find_local_most_ancestor_suggestable_span(expr.span);
let span = expr.span.find_local_most_ancestor_suggestable_span();

let mut sugg = if expr.precedence().order() >= PREC_POSTFIX {
vec![(span.shrink_to_hi(), ".into()".to_owned())]
Expand Down Expand Up @@ -1896,7 +1896,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
None => sugg.to_string(),
};

let span = find_local_most_ancestor_suggestable_span(expr.span);
let span = expr.span.find_local_most_ancestor_suggestable_span();
err.span_suggestion_verbose(span.shrink_to_hi(), msg, sugg, Applicability::HasPlaceholders);
return true;
}
Expand Down Expand Up @@ -3171,19 +3171,3 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
}

/// For suggestion span, recursively try to look for the ancestor span which shares the same syntax
/// context as the initially provided `span`. This will recursively look into local macros until the
/// span inside the most ancestor local macro is found. It will stop recursing as soon as the
/// syntax context of a potential parent callsite changes, such as if the potential parent callsite
/// is in a foreign macro. This helps to prevent leaking implementation details from upstream
/// crates and stdlib crates that the user likely have no control over.
fn find_local_most_ancestor_suggestable_span(initial_span: Span) -> Span {
let mut span = initial_span;
while initial_span.eq_ctxt(span)
&& let Some(parent_callsite) = span.parent_callsite()
{
span = parent_callsite;
}
span
}
39 changes: 39 additions & 0 deletions compiler/rustc_span/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,45 @@ impl Span {
Some(self)
}

/// Recursively walk down the expansion ancestors to find the most ancestor span with the same
/// [`SyntaxContext`] as `initial`.
///
/// 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
///
/// ```
/// 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))

Check failure on line 767 in compiler/rustc_span/src/lib.rs

View workflow job for this annotation

GitHub Actions / PR - x86_64-gnu-llvm-17

mismatched types
/// }
/// ```
///
/// 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
/// most ancestor span that is both still local and shares the same [`SyntaxContext`] as the
/// `initial` span.
pub fn find_local_most_ancestor_suggestable_span(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.
pub fn edition(self) -> edition::Edition {
self.ctxt().edition()
Expand Down

0 comments on commit 98e9201

Please sign in to comment.