Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use right span in prelude collision suggestions with macros. #88501

Merged
merged 4 commits into from
Aug 31, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions compiler/rustc_span/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,14 @@ impl Span {
if !expn_data.is_root() { Some(expn_data.call_site) } else { None }
}

/// Walk down the expansion ancestors to find a span that's contained within `outer`.
pub fn find_ancestor_inside(mut self, outer: Span) -> Option<Span> {
while !outer.contains(self) {
self = self.parent()?;
}
Some(self)
}

/// Edition of the crate from which this span came.
pub fn edition(self) -> edition::Edition {
self.ctxt().edition()
Expand Down
36 changes: 22 additions & 14 deletions compiler/rustc_typeck/src/check/method/prelude2021.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,15 +156,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
segment.ident.name
));

let (self_adjusted, precise) = self.adjust_expr(pick, self_expr);
let (self_adjusted, precise) = self.adjust_expr(pick, self_expr, sp);
if precise {
let args = args
.iter()
.skip(1)
.map(|arg| {
let span = arg.span.find_ancestor_inside(sp).unwrap_or_default();
format!(
", {}",
self.sess().source_map().span_to_snippet(arg.span).unwrap()
self.sess().source_map().span_to_snippet(span).unwrap()
)
})
.collect::<String>();
Expand Down Expand Up @@ -272,11 +273,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
method_name.name
));

let mut self_ty_name = self
.sess()
.source_map()
.span_to_snippet(self_ty_span)
.unwrap_or_else(|_| self_ty.to_string());
let mut self_ty_name = self_ty_span
.find_ancestor_inside(span)
.and_then(|span| self.sess().source_map().span_to_snippet(span).ok())
.unwrap_or_else(|| self_ty.to_string());

// Get the number of generics the self type has (if an Adt) unless we can determine that
// the user has written the self type with generics already which we (naively) do by looking
Expand Down Expand Up @@ -370,7 +370,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Creates a string version of the `expr` that includes explicit adjustments.
/// Returns the string and also a bool indicating whther this is a *precise*
/// suggestion.
fn adjust_expr(&self, pick: &Pick<'tcx>, expr: &hir::Expr<'tcx>) -> (String, bool) {
fn adjust_expr(
&self,
pick: &Pick<'tcx>,
expr: &hir::Expr<'tcx>,
outer: Span,
) -> (String, bool) {
let derefs = "*".repeat(pick.autoderefs);

let autoref = match pick.autoref_or_ptr_adjustment {
Expand All @@ -379,12 +384,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
};

let (expr_text, precise) =
if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) {
(expr_text, true)
} else {
("(..)".to_string(), false)
};
let (expr_text, precise) = if let Some(expr_text) = expr
.span
.find_ancestor_inside(outer)
.and_then(|span| self.sess().source_map().span_to_snippet(span).ok())
{
(expr_text, true)
} else {
("(..)".to_string(), false)
};

let adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
pick.autoref_or_ptr_adjustment
Expand Down
8 changes: 3 additions & 5 deletions compiler/rustc_typeck/src/check/upvar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -680,15 +680,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
migrated_variables_concat
);

let mut closure_body_span = self.tcx.hir().span(body_id.hir_id);

// If the body was entirely expanded from a macro
// invocation, i.e. the body is not contained inside the
// closure span, then we walk up the expansion until we
// find the span before the expansion.
while !closure_body_span.is_dummy() && !closure_span.contains(closure_body_span) {
closure_body_span = closure_body_span.parent().unwrap_or(DUMMY_SP);
}
let closure_body_span = self.tcx.hir().span(body_id.hir_id)
.find_ancestor_inside(closure_span)
.unwrap_or(DUMMY_SP);

if let Ok(s) = self.tcx.sess.source_map().span_to_snippet(closure_body_span) {
let mut lines = s.lines();
Expand Down
45 changes: 45 additions & 0 deletions src/test/ui/rust-2021/future-prelude-collision-macros.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// run-rustfix
// edition:2018
// check-pass
#![warn(rust_2021_prelude_collisions)]
#![allow(unreachable_code)]

macro_rules! foo {
() => {{
123;
S
}};
}

trait MyTry<T> {
fn try_into(self, _: u8);
}

struct S;

impl MyTry<i32> for S {
fn try_into(self, _: u8) {}
}

trait TryFromU8: Sized {
fn try_from(_: u8);
}

impl TryFromU8 for u32 {
fn try_from(_: u8) {}
}

macro_rules! bar {
() => {
u32
};
}

fn main() {
MyTry::try_into(foo!(), todo!());
//~^ WARNING trait method `try_into` will become ambiguous in Rust 2021
//~| WARNING this is accepted in the current edition
<bar!() as TryFromU8>::try_from(0);
//~^ WARNING trait-associated function `try_from` will become ambiguous in Rust 2021
//~| WARNING this is accepted in the current edition
}
45 changes: 45 additions & 0 deletions src/test/ui/rust-2021/future-prelude-collision-macros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// run-rustfix
// edition:2018
// check-pass
#![warn(rust_2021_prelude_collisions)]
#![allow(unreachable_code)]

macro_rules! foo {
() => {{
123;
S
}};
}

trait MyTry<T> {
fn try_into(self, _: u8);
}

struct S;

impl MyTry<i32> for S {
fn try_into(self, _: u8) {}
}

trait TryFromU8: Sized {
fn try_from(_: u8);
}

impl TryFromU8 for u32 {
fn try_from(_: u8) {}
}

macro_rules! bar {
() => {
u32
};
}

fn main() {
foo!().try_into(todo!());
//~^ WARNING trait method `try_into` will become ambiguous in Rust 2021
//~| WARNING this is accepted in the current edition
<bar!()>::try_from(0);
//~^ WARNING trait-associated function `try_from` will become ambiguous in Rust 2021
//~| WARNING this is accepted in the current edition
}
25 changes: 25 additions & 0 deletions src/test/ui/rust-2021/future-prelude-collision-macros.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
warning: trait method `try_into` will become ambiguous in Rust 2021
--> $DIR/future-prelude-collision-macros.rs:39:5
|
LL | foo!().try_into(todo!());
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `MyTry::try_into(foo!(), todo!())`
|
note: the lint level is defined here
--> $DIR/future-prelude-collision-macros.rs:4:9
|
LL | #![warn(rust_2021_prelude_collisions)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>

warning: trait-associated function `try_from` will become ambiguous in Rust 2021
--> $DIR/future-prelude-collision-macros.rs:42:5
|
LL | <bar!()>::try_from(0);
| ^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `<bar!() as TryFromU8>::try_from`
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>

warning: 2 warnings emitted