Skip to content

Commit

Permalink
Rollup merge of #88496 - m-ou-se:prelude-collision-lifetime-generics,…
Browse files Browse the repository at this point in the history
… r=petrochenkov

Fix prelude collision lint suggestion for generics with lifetimes

Fixes #88470

cc `@nikomatsakis`
  • Loading branch information
m-ou-se committed Aug 31, 2021
2 parents 4adacfd + 78a7d1c commit fdf9c09
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 47 deletions.
65 changes: 38 additions & 27 deletions compiler/rustc_typeck/src/check/method/prelude2021.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,47 +239,58 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let trait_path = self.trait_path_or_bare_name(span, expr_id, pick.item.container.id());
let trait_generics = self.tcx.generics_of(pick.item.container.id());

let parameter_count = trait_generics.count() - (trait_generics.has_self as usize);
let trait_name = if parameter_count == 0 {
trait_path
} else {
format!(
"{}<{}>",
trait_path,
std::iter::repeat("_").take(parameter_count).collect::<Vec<_>>().join(", ")
)
};
let trait_name =
if trait_generics.params.len() <= trait_generics.has_self as usize {
trait_path
} else {
let counts = trait_generics.own_counts();
format!(
"{}<{}>",
trait_path,
std::iter::repeat("'_")
.take(counts.lifetimes)
.chain(std::iter::repeat("_").take(
counts.types + counts.consts - trait_generics.has_self as usize
))
.collect::<Vec<_>>()
.join(", ")
)
};

let mut lint = lint.build(&format!(
"trait-associated function `{}` will become ambiguous in Rust 2021",
method_name.name
));

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

let self_ty_generics_count = match self_ty.kind() {
// 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
// for a "<" in `self_ty_name`.
Adt(def, _) if !self_ty_name.contains('<') => self.tcx.generics_of(def.did).count(),
_ => 0,
};
let self_ty_generics = if self_ty_generics_count > 0 {
format!("<{}>", vec!["_"; self_ty_generics_count].join(", "))
} else {
String::new()
};
// 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
// for a "<" in `self_ty_name`.
if !self_ty_name.contains('<') {
if let Adt(def, _) = self_ty.kind() {
let generics = self.tcx.generics_of(def.did);
if !generics.params.is_empty() {
let counts = generics.own_counts();
self_ty_name += &format!(
"<{}>",
std::iter::repeat("'_")
.take(counts.lifetimes)
.chain(std::iter::repeat("_").take(counts.types + counts.consts))
.collect::<Vec<_>>()
.join(", ")
);
}
}
}
lint.span_suggestion(
span,
"disambiguate the associated function",
format!(
"<{}{} as {}>::{}",
self_ty_name, self_ty_generics, trait_name, method_name.name,
),
format!("<{} as {}>::{}", self_ty_name, trait_name, method_name.name,),
Applicability::MachineApplicable,
);

Expand Down
30 changes: 30 additions & 0 deletions src/test/ui/rust-2021/future-prelude-collision-generic-trait.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// See https://github.com/rust-lang/rust/issues/88470
// run-rustfix
// edition:2018
// check-pass
#![warn(rust_2021_prelude_collisions)]
#![allow(dead_code)]
#![allow(unused_imports)]

pub trait PyTryFrom<'v, T>: Sized {
fn try_from<V>(value: V) -> Result<&'v Self, T>;
}

pub trait PyTryInto<T>: Sized {
fn try_into(&self) -> Result<&T, i32>;
}

struct Foo;

impl<U> PyTryInto<U> for Foo
where
U: for<'v> PyTryFrom<'v, i32>,
{
fn try_into(&self) -> Result<&U, i32> {
<U as PyTryFrom<'_, _>>::try_from(self)
//~^ WARNING trait-associated function `try_from` will become ambiguous in Rust 2021
//~| this is accepted in the current edition (Rust 2018)
}
}

fn main() {}
30 changes: 30 additions & 0 deletions src/test/ui/rust-2021/future-prelude-collision-generic-trait.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// See https://github.com/rust-lang/rust/issues/88470
// run-rustfix
// edition:2018
// check-pass
#![warn(rust_2021_prelude_collisions)]
#![allow(dead_code)]
#![allow(unused_imports)]

pub trait PyTryFrom<'v, T>: Sized {
fn try_from<V>(value: V) -> Result<&'v Self, T>;
}

pub trait PyTryInto<T>: Sized {
fn try_into(&self) -> Result<&T, i32>;
}

struct Foo;

impl<U> PyTryInto<U> for Foo
where
U: for<'v> PyTryFrom<'v, i32>,
{
fn try_into(&self) -> Result<&U, i32> {
U::try_from(self)
//~^ WARNING trait-associated function `try_from` will become ambiguous in Rust 2021
//~| this is accepted in the current edition (Rust 2018)
}
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
warning: trait-associated function `try_from` will become ambiguous in Rust 2021
--> $DIR/future-prelude-collision-generic-trait.rs:24:9
|
LL | U::try_from(self)
| ^^^^^^^^^^^ help: disambiguate the associated function: `<U as PyTryFrom<'_, _>>::try_from`
|
note: the lint level is defined here
--> $DIR/future-prelude-collision-generic-trait.rs:5: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: 1 warning emitted

16 changes: 8 additions & 8 deletions src/test/ui/rust-2021/future-prelude-collision-generic.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,32 @@
#![allow(dead_code)]
#![allow(unused_imports)]

struct Generic<T, U>(T, U);
struct Generic<'a, U>(&'a U);

trait MyFromIter {
fn from_iter(_: i32) -> Self;
}

impl MyFromIter for Generic<i32, i32> {
fn from_iter(x: i32) -> Self {
Self(x, x)
impl MyFromIter for Generic<'static, i32> {
fn from_iter(_: i32) -> Self {
todo!()
}
}

impl std::iter::FromIterator<i32> for Generic<i32, i32> {
impl std::iter::FromIterator<i32> for Generic<'static, i32> {
fn from_iter<T: IntoIterator<Item = i32>>(_: T) -> Self {
todo!()
}
}

fn main() {
<Generic<_, _> as MyFromIter>::from_iter(1);
<Generic<'_, _> as MyFromIter>::from_iter(1);
//~^ WARNING trait-associated function `from_iter` will become ambiguous in Rust 2021
//~| this is accepted in the current edition (Rust 2018)
<Generic::<i32, i32> as MyFromIter>::from_iter(1);
<Generic::<'static, i32> as MyFromIter>::from_iter(1);
//~^ WARNING trait-associated function `from_iter` will become ambiguous in Rust 2021
//~| this is accepted in the current edition (Rust 2018)
<Generic::<_, _> as MyFromIter>::from_iter(1);
<Generic::<'_, _> as MyFromIter>::from_iter(1);
//~^ WARNING trait-associated function `from_iter` will become ambiguous in Rust 2021
//~| this is accepted in the current edition (Rust 2018)
}
14 changes: 7 additions & 7 deletions src/test/ui/rust-2021/future-prelude-collision-generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@
#![allow(dead_code)]
#![allow(unused_imports)]

struct Generic<T, U>(T, U);
struct Generic<'a, U>(&'a U);

trait MyFromIter {
fn from_iter(_: i32) -> Self;
}

impl MyFromIter for Generic<i32, i32> {
fn from_iter(x: i32) -> Self {
Self(x, x)
impl MyFromIter for Generic<'static, i32> {
fn from_iter(_: i32) -> Self {
todo!()
}
}

impl std::iter::FromIterator<i32> for Generic<i32, i32> {
impl std::iter::FromIterator<i32> for Generic<'static, i32> {
fn from_iter<T: IntoIterator<Item = i32>>(_: T) -> Self {
todo!()
}
Expand All @@ -28,10 +28,10 @@ fn main() {
Generic::from_iter(1);
//~^ WARNING trait-associated function `from_iter` will become ambiguous in Rust 2021
//~| this is accepted in the current edition (Rust 2018)
Generic::<i32, i32>::from_iter(1);
Generic::<'static, i32>::from_iter(1);
//~^ WARNING trait-associated function `from_iter` will become ambiguous in Rust 2021
//~| this is accepted in the current edition (Rust 2018)
Generic::<_, _>::from_iter(1);
Generic::<'_, _>::from_iter(1);
//~^ WARNING trait-associated function `from_iter` will become ambiguous in Rust 2021
//~| this is accepted in the current edition (Rust 2018)
}
10 changes: 5 additions & 5 deletions src/test/ui/rust-2021/future-prelude-collision-generic.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ warning: trait-associated function `from_iter` will become ambiguous in Rust 202
--> $DIR/future-prelude-collision-generic.rs:28:5
|
LL | Generic::from_iter(1);
| ^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `<Generic<_, _> as MyFromIter>::from_iter`
| ^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `<Generic<'_, _> as MyFromIter>::from_iter`
|
note: the lint level is defined here
--> $DIR/future-prelude-collision-generic.rs:5:9
Expand All @@ -15,17 +15,17 @@ LL | #![warn(rust_2021_prelude_collisions)]
warning: trait-associated function `from_iter` will become ambiguous in Rust 2021
--> $DIR/future-prelude-collision-generic.rs:31:5
|
LL | Generic::<i32, i32>::from_iter(1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `<Generic::<i32, i32> as MyFromIter>::from_iter`
LL | Generic::<'static, i32>::from_iter(1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `<Generic::<'static, i32> as MyFromIter>::from_iter`
|
= 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 `from_iter` will become ambiguous in Rust 2021
--> $DIR/future-prelude-collision-generic.rs:34:5
|
LL | Generic::<_, _>::from_iter(1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `<Generic::<_, _> as MyFromIter>::from_iter`
LL | Generic::<'_, _>::from_iter(1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `<Generic::<'_, _> as MyFromIter>::from_iter`
|
= 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>
Expand Down

0 comments on commit fdf9c09

Please sign in to comment.