Skip to content

Commit b18704d

Browse files
committed
Fix future_prelude_collision for object calls and use as _
1 parent 9bee7f0 commit b18704d

7 files changed

+313
-59
lines changed

compiler/rustc_typeck/src/check/method/prelude2021.rs

Lines changed: 138 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use hir::ItemKind;
44
use rustc_ast::Mutability;
55
use rustc_errors::Applicability;
66
use rustc_hir as hir;
7-
use rustc_middle::ty::Ty;
7+
use rustc_middle::ty::{Ref, Ty};
88
use rustc_session::lint::builtin::FUTURE_PRELUDE_COLLISION;
99
use rustc_span::symbol::kw::Underscore;
1010
use rustc_span::symbol::{sym, Ident};
@@ -46,21 +46,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
4646
return;
4747
}
4848

49-
self.tcx.struct_span_lint_hir(
50-
FUTURE_PRELUDE_COLLISION,
51-
call_expr.hir_id,
52-
call_expr.span,
53-
|lint| {
54-
let sp = call_expr.span;
55-
let trait_name =
56-
self.trait_path_or_bare_name(span, call_expr.hir_id, pick.item.container.id());
57-
58-
let mut lint = lint.build(&format!(
59-
"trait method `{}` will become ambiguous in Rust 2021",
60-
segment.ident.name
61-
));
62-
63-
if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span) {
49+
if matches!(pick.kind, probe::PickKind::InherentImplPick | probe::PickKind::ObjectPick) {
50+
// avoid repeatedly adding unneeded `&*`s
51+
if pick.autoderefs == 1
52+
&& matches!(
53+
pick.autoref_or_ptr_adjustment,
54+
Some(probe::AutorefOrPtrAdjustment::Autoref { .. })
55+
)
56+
&& matches!(self_ty.kind(), Ref(..))
57+
{
58+
return;
59+
}
60+
// Inherent impls only require not relying on autoref and autoderef in order to
61+
// ensure that the trait implementation won't be used
62+
self.tcx.struct_span_lint_hir(
63+
FUTURE_PRELUDE_COLLISION,
64+
self_expr.hir_id,
65+
self_expr.span,
66+
|lint| {
67+
let sp = self_expr.span;
68+
69+
let mut lint = lint.build(&format!(
70+
"trait method `{}` will become ambiguous in Rust 2021",
71+
segment.ident.name
72+
));
73+
6474
let derefs = "*".repeat(pick.autoderefs);
6575

6676
let autoref = match pick.autoref_or_ptr_adjustment {
@@ -74,46 +84,115 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
7484
}) => "&",
7585
Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
7686
};
77-
let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
78-
pick.autoref_or_ptr_adjustment
87+
if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span)
7988
{
80-
format!("{}{} as *const _", derefs, self_expr)
89+
let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
90+
pick.autoref_or_ptr_adjustment
91+
{
92+
format!("{}{} as *const _", derefs, self_expr)
93+
} else {
94+
format!("{}{}{}", autoref, derefs, self_expr)
95+
};
96+
97+
lint.span_suggestion(
98+
sp,
99+
"disambiguate the method call",
100+
format!("({})", self_adjusted),
101+
Applicability::MachineApplicable,
102+
);
81103
} else {
82-
format!("{}{}{}", autoref, derefs, self_expr)
83-
};
84-
let args = args
85-
.iter()
86-
.skip(1)
87-
.map(|arg| {
88-
format!(
89-
", {}",
90-
self.sess().source_map().span_to_snippet(arg.span).unwrap()
91-
)
92-
})
93-
.collect::<String>();
94-
95-
lint.span_suggestion(
96-
sp,
97-
"disambiguate the associated function",
98-
format!(
99-
"{}::{}({}{})",
100-
trait_name, segment.ident.name, self_adjusted, args
101-
),
102-
Applicability::MachineApplicable,
103-
);
104-
} else {
105-
lint.span_help(
106-
sp,
107-
&format!(
108-
"disambiguate the associated function with `{}::{}(...)`",
109-
trait_name, segment.ident,
110-
),
104+
let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
105+
pick.autoref_or_ptr_adjustment
106+
{
107+
format!("{}(...) as *const _", derefs)
108+
} else {
109+
format!("{}{}...", autoref, derefs)
110+
};
111+
lint.span_help(
112+
sp,
113+
&format!("disambiguate the method call with `({})`", self_adjusted,),
114+
);
115+
}
116+
117+
lint.emit();
118+
},
119+
);
120+
} else {
121+
// trait implementations require full disambiguation to not clash with the new prelude
122+
// additions (i.e. convert from dot-call to fully-qualified call)
123+
self.tcx.struct_span_lint_hir(
124+
FUTURE_PRELUDE_COLLISION,
125+
call_expr.hir_id,
126+
call_expr.span,
127+
|lint| {
128+
let sp = call_expr.span;
129+
let trait_name = self.trait_path_or_bare_name(
130+
span,
131+
call_expr.hir_id,
132+
pick.item.container.id(),
111133
);
112-
}
113134

114-
lint.emit();
115-
},
116-
);
135+
let mut lint = lint.build(&format!(
136+
"trait method `{}` will become ambiguous in Rust 2021",
137+
segment.ident.name
138+
));
139+
140+
if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span)
141+
{
142+
let derefs = "*".repeat(pick.autoderefs);
143+
144+
let autoref = match pick.autoref_or_ptr_adjustment {
145+
Some(probe::AutorefOrPtrAdjustment::Autoref {
146+
mutbl: Mutability::Mut,
147+
..
148+
}) => "&mut ",
149+
Some(probe::AutorefOrPtrAdjustment::Autoref {
150+
mutbl: Mutability::Not,
151+
..
152+
}) => "&",
153+
Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
154+
};
155+
let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
156+
pick.autoref_or_ptr_adjustment
157+
{
158+
format!("{}{} as *const _", derefs, self_expr)
159+
} else {
160+
format!("{}{}{}", autoref, derefs, self_expr)
161+
};
162+
let args = args
163+
.iter()
164+
.skip(1)
165+
.map(|arg| {
166+
format!(
167+
", {}",
168+
self.sess().source_map().span_to_snippet(arg.span).unwrap()
169+
)
170+
})
171+
.collect::<String>();
172+
173+
lint.span_suggestion(
174+
sp,
175+
"disambiguate the associated function",
176+
format!(
177+
"{}::{}({}{})",
178+
trait_name, segment.ident.name, self_adjusted, args
179+
),
180+
Applicability::MachineApplicable,
181+
);
182+
} else {
183+
lint.span_help(
184+
sp,
185+
&format!(
186+
"disambiguate the associated function with `{}::{}(...)`",
187+
trait_name, segment.ident,
188+
),
189+
);
190+
}
191+
192+
lint.emit();
193+
},
194+
);
195+
}
117196
}
118197

119198
pub(super) fn lint_fully_qualified_call_from_2018(
@@ -226,11 +305,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
226305
// All that is left is `_`! We need to use the full path. It doesn't matter which one we pick,
227306
// so just take the first one.
228307
match import_items[0].kind {
229-
ItemKind::Use(path, _) => {
230-
// FIXME: serialize path into something readable like a::b, there must be a fn for this
231-
debug!("no name for trait, found import of path: {:?}", path);
232-
return None;
233-
}
308+
ItemKind::Use(path, _) => Some(
309+
path.segments
310+
.iter()
311+
.map(|segment| segment.ident.to_string())
312+
.collect::<Vec<_>>()
313+
.join("::"),
314+
),
234315
_ => {
235316
span_bug!(span, "unexpected item kind, expected a use: {:?}", import_items[0].kind);
236317
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// run-rustfix
2+
// edition:2018
3+
// check-pass
4+
#![warn(future_prelude_collision)]
5+
#![allow(dead_code)]
6+
#![allow(unused_imports)]
7+
8+
mod m {
9+
pub trait TryIntoU32 {
10+
fn try_into(self) -> Result<u32, ()>;
11+
}
12+
13+
impl TryIntoU32 for u8 {
14+
fn try_into(self) -> Result<u32, ()> {
15+
Ok(self as u32)
16+
}
17+
}
18+
19+
pub trait AnotherTrick {}
20+
}
21+
22+
mod a {
23+
use crate::m::TryIntoU32;
24+
25+
fn main() {
26+
// In this case, we can just use `TryIntoU32`
27+
let _: u32 = TryIntoU32::try_into(3u8).unwrap();
28+
//~^ WARNING trait method `try_into` will become ambiguous in Rust 2021
29+
//~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
30+
}
31+
}
32+
33+
mod b {
34+
use crate::m::AnotherTrick as TryIntoU32;
35+
use crate::m::TryIntoU32 as _;
36+
37+
fn main() {
38+
// In this case, a `TryIntoU32::try_into` rewrite will not work, and we need to use
39+
// the path `crate::m::TryIntoU32` (with which it was imported).
40+
let _: u32 = crate::m::TryIntoU32::try_into(3u8).unwrap();
41+
//~^ WARNING trait method `try_into` will become ambiguous in Rust 2021
42+
//~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
43+
}
44+
}
45+
46+
mod c {
47+
use super::m::TryIntoU32 as _;
48+
use crate::m::AnotherTrick as TryIntoU32;
49+
50+
fn main() {
51+
// In this case, a `TryIntoU32::try_into` rewrite will not work, and we need to use
52+
// the path `super::m::TryIntoU32` (with which it was imported).
53+
let _: u32 = super::m::TryIntoU32::try_into(3u8).unwrap();
54+
//~^ WARNING trait method `try_into` will become ambiguous in Rust 2021
55+
//~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
56+
}
57+
}
58+
59+
fn main() {}

src/test/ui/rust-2021/future-prelude-collision-imported.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// check-pass
44
#![warn(future_prelude_collision)]
55
#![allow(dead_code)]
6+
#![allow(unused_imports)]
67

78
mod m {
89
pub trait TryIntoU32 {
@@ -24,6 +25,8 @@ mod a {
2425
fn main() {
2526
// In this case, we can just use `TryIntoU32`
2627
let _: u32 = 3u8.try_into().unwrap();
28+
//~^ WARNING trait method `try_into` will become ambiguous in Rust 2021
29+
//~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
2730
}
2831
}
2932

@@ -35,6 +38,8 @@ mod b {
3538
// In this case, a `TryIntoU32::try_into` rewrite will not work, and we need to use
3639
// the path `crate::m::TryIntoU32` (with which it was imported).
3740
let _: u32 = 3u8.try_into().unwrap();
41+
//~^ WARNING trait method `try_into` will become ambiguous in Rust 2021
42+
//~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
3843
}
3944
}
4045

@@ -46,6 +51,8 @@ mod c {
4651
// In this case, a `TryIntoU32::try_into` rewrite will not work, and we need to use
4752
// the path `super::m::TryIntoU32` (with which it was imported).
4853
let _: u32 = 3u8.try_into().unwrap();
54+
//~^ WARNING trait method `try_into` will become ambiguous in Rust 2021
55+
//~^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
4956
}
5057
}
5158

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
warning: trait method `try_into` will become ambiguous in Rust 2021
2+
--> $DIR/future-prelude-collision-imported.rs:27:22
3+
|
4+
LL | let _: u32 = 3u8.try_into().unwrap();
5+
| ^^^^^^^^^^^^^^ help: disambiguate the associated function: `TryIntoU32::try_into(3u8)`
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/future-prelude-collision-imported.rs:4:9
9+
|
10+
LL | #![warn(future_prelude_collision)]
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^
12+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
13+
= note: for more information, see issue #85684 <https://github.com/rust-lang/rust/issues/85684>
14+
15+
warning: trait method `try_into` will become ambiguous in Rust 2021
16+
--> $DIR/future-prelude-collision-imported.rs:40:22
17+
|
18+
LL | let _: u32 = 3u8.try_into().unwrap();
19+
| ^^^^^^^^^^^^^^ help: disambiguate the associated function: `crate::m::TryIntoU32::try_into(3u8)`
20+
|
21+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
22+
= note: for more information, see issue #85684 <https://github.com/rust-lang/rust/issues/85684>
23+
24+
warning: trait method `try_into` will become ambiguous in Rust 2021
25+
--> $DIR/future-prelude-collision-imported.rs:53:22
26+
|
27+
LL | let _: u32 = 3u8.try_into().unwrap();
28+
| ^^^^^^^^^^^^^^ help: disambiguate the associated function: `super::m::TryIntoU32::try_into(3u8)`
29+
|
30+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
31+
= note: for more information, see issue #85684 <https://github.com/rust-lang/rust/issues/85684>
32+
33+
warning: 3 warnings emitted
34+
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// run-rustfix
2+
// edition:2018
3+
#![warn(future_prelude_collision)]
4+
#![allow(dead_code)]
5+
#![allow(unused_imports)]
6+
7+
mod m {
8+
pub trait TryIntoU32 {
9+
fn try_into(self) -> Result<u32, ()>;
10+
}
11+
12+
impl TryIntoU32 for u8 {
13+
fn try_into(self) -> Result<u32, ()> {
14+
Ok(self as u32)
15+
}
16+
}
17+
18+
pub trait AnotherTrick {}
19+
}
20+
21+
mod d {
22+
use crate::m::AnotherTrick as TryIntoU32;
23+
use crate::m::*;
24+
25+
fn main() {
26+
// Here, `TryIntoU32` is imported but shadowed, but in that case we don't permit its methods
27+
// to be available.
28+
let _: u32 = 3u8.try_into().unwrap();
29+
//~^ ERROR no method named `try_into` found for type `u8` in the current scope
30+
}
31+
}
32+
33+
fn main() {}

0 commit comments

Comments
 (0)