Skip to content

Commit eca614b

Browse files
committed
Add migration lint for 2024 prelude additions
This adds the migration lint for the newly ambiguous methods `poll` and `into_future`. When these methods are used on types implementing the respective traits, it will be ambiguous in the future, which can lead to hard errors or behavior changes depending on the exact circumstances.
1 parent 98dcbae commit eca614b

20 files changed

+367
-1
lines changed

Diff for: compiler/rustc_hir/src/lang_items.rs

+1
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ language_item_table! {
250250

251251
Iterator, sym::iterator, iterator_trait, Target::Trait, GenericRequirement::Exact(0);
252252
FusedIterator, sym::fused_iterator, fused_iterator_trait, Target::Trait, GenericRequirement::Exact(0);
253+
IntoFuture, sym::into_future_trait, into_future_trait, Target::Trait, GenericRequirement::None;
253254
Future, sym::future_trait, future_trait, Target::Trait, GenericRequirement::Exact(0);
254255
FutureOutput, sym::future_output, future_output, Target::AssocTy, GenericRequirement::Exact(0);
255256
AsyncIterator, sym::async_iterator, async_iterator_trait, Target::Trait, GenericRequirement::Exact(0);

Diff for: compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_hir as hir;
99
use rustc_lint::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER};
1010
use rustc_middle::span_bug;
1111
use rustc_middle::ty::{self, Ty};
12-
use rustc_session::lint::builtin::RUST_2021_PRELUDE_COLLISIONS;
12+
use rustc_session::lint::builtin::{RUST_2021_PRELUDE_COLLISIONS, RUST_2024_PRELUDE_COLLISIONS};
1313
use rustc_span::symbol::kw::{Empty, Underscore};
1414
use rustc_span::symbol::{sym, Ident};
1515
use rustc_span::Span;
@@ -35,6 +35,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
3535
let (prelude_or_array_lint, edition) = match segment.ident.name {
3636
// `try_into` was added to the prelude in Rust 2021.
3737
sym::try_into if !span.at_least_rust_2021() => (RUST_2021_PRELUDE_COLLISIONS, "2021"),
38+
// `Future::poll` was added to the prelude in Rust 2024.
39+
sym::poll
40+
// We check that the self type is `Pin<&mut _>` to avoid false positives for this common name.
41+
if !span.at_least_rust_2024()
42+
&& let ty::Adt(adt_def, args) = self_ty.kind()
43+
&& self.tcx.is_lang_item(adt_def.did(), hir::LangItem::Pin)
44+
&& let ty::Ref(_, _, ty::Mutability::Mut) =
45+
args[0].as_type().unwrap().kind() =>
46+
{
47+
(RUST_2024_PRELUDE_COLLISIONS, "2024")
48+
}
49+
// `IntoFuture::into_future` was added to the prelude in Rust 2024.
50+
sym::into_future if !span.at_least_rust_2024() => {
51+
(RUST_2024_PRELUDE_COLLISIONS, "2024")
52+
}
3853
// `into_iter` wasn't added to the prelude,
3954
// but `[T; N].into_iter()` doesn't resolve to IntoIterator::into_iter
4055
// before Rust 2021, which results in the same problem.

Diff for: compiler/rustc_lint_defs/src/builtin.rs

+41
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ declare_lint_pass! {
9191
RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
9292
RUST_2021_PRELUDE_COLLISIONS,
9393
RUST_2024_INCOMPATIBLE_PAT,
94+
RUST_2024_PRELUDE_COLLISIONS,
9495
SELF_CONSTRUCTOR_FROM_OUTER_ITEM,
9596
SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
9697
SINGLE_USE_LIFETIMES,
@@ -3750,6 +3751,46 @@ declare_lint! {
37503751
};
37513752
}
37523753

3754+
declare_lint! {
3755+
/// The `rust_2024_prelude_collisions` lint detects the usage of trait methods which are ambiguous
3756+
/// with traits added to the prelude in future editions.
3757+
///
3758+
/// ### Example
3759+
///
3760+
/// ```rust,edition2021,compile_fail
3761+
/// #![deny(rust_2024_prelude_collisions)]
3762+
/// trait Meow {
3763+
/// fn poll(&self) {}
3764+
/// }
3765+
/// impl<T> Meow for T {}
3766+
///
3767+
/// fn main() {
3768+
/// core::pin::pin!(async {}).poll();
3769+
/// // ^^^^^^^^
3770+
/// // This call to try_into matches both Future::poll and Meow::poll as
3771+
/// // `Future` has been added to the Rust prelude in 2024 edition.
3772+
/// }
3773+
/// ```
3774+
///
3775+
/// {{produces}}
3776+
///
3777+
/// ### Explanation
3778+
///
3779+
/// Rust 2024, introduces two new additions to the standard library's prelude,
3780+
/// `Future` and `IntoFuture`. This results in an ambiguity as to which method/function
3781+
/// to call when an existing `poll`/`into_future` method is called via dot-call syntax or
3782+
/// a `poll`/`into_future` associated function is called directly on a type.
3783+
///
3784+
pub RUST_2024_PRELUDE_COLLISIONS,
3785+
Allow,
3786+
"detects the usage of trait methods which are ambiguous with traits added to the \
3787+
prelude in future editions",
3788+
@future_incompatible = FutureIncompatibleInfo {
3789+
reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024),
3790+
reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2024/prelude.html>",
3791+
};
3792+
}
3793+
37533794
declare_lint! {
37543795
/// The `rust_2021_prefixes_incompatible_syntax` lint detects identifiers that will be parsed as a
37553796
/// prefix instead in Rust 2021.

Diff for: compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1042,6 +1042,7 @@ symbols! {
10421042
integral,
10431043
into_async_iter_into_iter,
10441044
into_future,
1045+
into_future_trait,
10451046
into_iter,
10461047
intra_doc_pointers,
10471048
intrinsics,

Diff for: library/core/src/future/into_future.rs

+1
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ use crate::future::Future;
105105
message = "`{Self}` is not a future",
106106
note = "{Self} must be a future or must implement `IntoFuture` to be awaited"
107107
)]
108+
#[cfg_attr(not(bootstrap), lang = "into_future_trait")]
108109
pub trait IntoFuture {
109110
/// The output that the future will produce on completion.
110111
#[stable(feature = "into_future", since = "1.64.0")]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//@ revisions: e2021 e2024
2+
//@[e2021] edition: 2021
3+
//@[e2024] edition: 2024
4+
//@[e2024] compile-flags: -Zunstable-options
5+
//@ check-pass
6+
7+
#![deny(rust_2024_prelude_collisions)]
8+
9+
use std::future::Future;
10+
11+
fn main() {
12+
core::pin::pin!(async {}).poll(&mut context());
13+
}
14+
15+
fn context() -> core::task::Context<'static> {
16+
loop {}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//@ revisions: e2021 e2024
2+
//@[e2021] edition: 2021
3+
//@[e2021] run-rustfix
4+
//@[e2024] edition: 2024
5+
//@[e2024] compile-flags: -Zunstable-options
6+
//@[e2024] check-pass
7+
8+
#![deny(rust_2024_prelude_collisions)]
9+
trait Meow {
10+
fn poll(&self, _ctx: &mut core::task::Context<'_>) {}
11+
}
12+
impl<T> Meow for T {}
13+
fn main() {
14+
Meow::poll(&core::pin::pin!(async {}), &mut context());
15+
//[e2021]~^ ERROR trait method `poll` will become ambiguous in Rust 2024
16+
//[e2021]~| WARN this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
17+
}
18+
19+
fn context() -> core::task::Context<'static> {
20+
loop {}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: trait method `poll` will become ambiguous in Rust 2024
2+
--> $DIR/future-poll-async-block.rs:14:5
3+
|
4+
LL | core::pin::pin!(async {}).poll(&mut context());
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `Meow::poll(&core::pin::pin!(async {}), &mut context())`
6+
|
7+
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
8+
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/prelude.html>
9+
note: the lint level is defined here
10+
--> $DIR/future-poll-async-block.rs:8:9
11+
|
12+
LL | #![deny(rust_2024_prelude_collisions)]
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
14+
15+
error: aborting due to 1 previous error
16+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//@ revisions: e2021 e2024
2+
//@[e2021] edition: 2021
3+
//@[e2021] run-rustfix
4+
//@[e2024] edition: 2024
5+
//@[e2024] compile-flags: -Zunstable-options
6+
//@[e2024] check-pass
7+
8+
#![deny(rust_2024_prelude_collisions)]
9+
trait Meow {
10+
fn poll(&self, _ctx: &mut core::task::Context<'_>) {}
11+
}
12+
impl<T> Meow for T {}
13+
fn main() {
14+
core::pin::pin!(async {}).poll(&mut context());
15+
//[e2021]~^ ERROR trait method `poll` will become ambiguous in Rust 2024
16+
//[e2021]~| WARN this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
17+
}
18+
19+
fn context() -> core::task::Context<'static> {
20+
loop {}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//@ revisions: e2021 e2024
2+
//@[e2021] edition: 2021
3+
//@[e2021] run-rustfix
4+
//@[e2024] edition: 2024
5+
//@[e2024] compile-flags: -Zunstable-options
6+
//@[e2024] check-pass
7+
8+
#![deny(rust_2024_prelude_collisions)]
9+
trait Meow {
10+
fn poll(&self) {}
11+
}
12+
impl<T> Meow for T {}
13+
fn main() {
14+
// This is a deliberate false positive.
15+
// While `()` does not implement `Future` and can therefore not be ambiguous, we
16+
// do not check that in the lint, as that introduces additional complexities.
17+
// Just checking whether the self type is `Pin<&mut _>` is enough.
18+
Meow::poll(&core::pin::pin!(()));
19+
//[e2021]~^ ERROR trait method `poll` will become ambiguous in Rust 2024
20+
//[e2021]~| WARN this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: trait method `poll` will become ambiguous in Rust 2024
2+
--> $DIR/future-poll-not-future-pinned.rs:18:5
3+
|
4+
LL | core::pin::pin!(()).poll();
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `Meow::poll(&core::pin::pin!(()))`
6+
|
7+
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
8+
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/prelude.html>
9+
note: the lint level is defined here
10+
--> $DIR/future-poll-not-future-pinned.rs:8:9
11+
|
12+
LL | #![deny(rust_2024_prelude_collisions)]
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
14+
15+
error: aborting due to 1 previous error
16+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//@ revisions: e2021 e2024
2+
//@[e2021] edition: 2021
3+
//@[e2021] run-rustfix
4+
//@[e2024] edition: 2024
5+
//@[e2024] compile-flags: -Zunstable-options
6+
//@[e2024] check-pass
7+
8+
#![deny(rust_2024_prelude_collisions)]
9+
trait Meow {
10+
fn poll(&self) {}
11+
}
12+
impl<T> Meow for T {}
13+
fn main() {
14+
// This is a deliberate false positive.
15+
// While `()` does not implement `Future` and can therefore not be ambiguous, we
16+
// do not check that in the lint, as that introduces additional complexities.
17+
// Just checking whether the self type is `Pin<&mut _>` is enough.
18+
core::pin::pin!(()).poll();
19+
//[e2021]~^ ERROR trait method `poll` will become ambiguous in Rust 2024
20+
//[e2021]~| WARN this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//@ revisions: e2021 e2024
2+
//@[e2021] edition: 2021
3+
//@[e2024] edition: 2024
4+
//@[e2024] compile-flags: -Zunstable-options
5+
//@ check-pass
6+
7+
#![deny(rust_2024_prelude_collisions)]
8+
trait Meow {
9+
fn poll(&self) {}
10+
}
11+
impl<T> Meow for T {}
12+
fn main() {
13+
// As the self type here is not `Pin<&mut _>`, the lint does not fire.
14+
().poll();
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//@ revisions: e2021 e2024
2+
//@[e2021] edition: 2021
3+
//@[e2021] run-rustfix
4+
//@[e2024] edition: 2024
5+
//@[e2024] compile-flags: -Zunstable-options
6+
//@[e2024] check-pass
7+
8+
#![deny(rust_2024_prelude_collisions)]
9+
trait Meow {
10+
fn into_future(&self) {}
11+
}
12+
impl Meow for Cat {}
13+
14+
struct Cat;
15+
16+
impl core::future::IntoFuture for Cat {
17+
type Output = ();
18+
type IntoFuture = core::future::Ready<()>;
19+
20+
fn into_future(self) -> Self::IntoFuture {
21+
core::future::ready(())
22+
}
23+
}
24+
25+
fn main() {
26+
Meow::into_future(&Cat);
27+
//[e2021]~^ ERROR trait method `into_future` will become ambiguous in Rust 2024
28+
//[e2021]~| WARN this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: trait method `into_future` will become ambiguous in Rust 2024
2+
--> $DIR/into-future-adt.rs:26:5
3+
|
4+
LL | Cat.into_future();
5+
| ^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `Meow::into_future(&Cat)`
6+
|
7+
= warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
8+
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/prelude.html>
9+
note: the lint level is defined here
10+
--> $DIR/into-future-adt.rs:8:9
11+
|
12+
LL | #![deny(rust_2024_prelude_collisions)]
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
14+
15+
error: aborting due to 1 previous error
16+
+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//@ revisions: e2021 e2024
2+
//@[e2021] edition: 2021
3+
//@[e2021] run-rustfix
4+
//@[e2024] edition: 2024
5+
//@[e2024] compile-flags: -Zunstable-options
6+
//@[e2024] check-pass
7+
8+
#![deny(rust_2024_prelude_collisions)]
9+
trait Meow {
10+
fn into_future(&self) {}
11+
}
12+
impl Meow for Cat {}
13+
14+
struct Cat;
15+
16+
impl core::future::IntoFuture for Cat {
17+
type Output = ();
18+
type IntoFuture = core::future::Ready<()>;
19+
20+
fn into_future(self) -> Self::IntoFuture {
21+
core::future::ready(())
22+
}
23+
}
24+
25+
fn main() {
26+
Cat.into_future();
27+
//[e2021]~^ ERROR trait method `into_future` will become ambiguous in Rust 2024
28+
//[e2021]~| WARN this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//@ revisions: e2021 e2024
2+
//@[e2021] edition: 2021
3+
//@[e2024] edition: 2024
4+
//@[e2024] compile-flags: -Zunstable-options
5+
//@ check-pass
6+
7+
#![deny(rust_2024_prelude_collisions)]
8+
9+
use core::future::IntoFuture;
10+
11+
struct Cat;
12+
13+
impl IntoFuture for Cat {
14+
type Output = ();
15+
type IntoFuture = core::future::Ready<()>;
16+
17+
fn into_future(self) -> Self::IntoFuture {
18+
core::future::ready(())
19+
}
20+
}
21+
22+
fn main() {
23+
let _ = Cat.into_future();
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//@ revisions: e2021 e2024
2+
//@[e2021] edition: 2021
3+
//@[e2021] run-rustfix
4+
//@[e2024] edition: 2024
5+
//@[e2024] compile-flags: -Zunstable-options
6+
//@[e2024] check-pass
7+
8+
#![deny(rust_2024_prelude_collisions)]
9+
trait Meow {
10+
fn into_future(&self) {}
11+
}
12+
impl Meow for Cat {}
13+
14+
struct Cat;
15+
16+
fn main() {
17+
// This is a false positive, but it should be rare enough to not matter, and checking whether it implements
18+
// the trait can have other nontrivial consequences, so it was decided to accept this.
19+
Meow::into_future(&Cat);
20+
//[e2021]~^ ERROR trait method `into_future` will become ambiguous in Rust 2024
21+
//[e2021]~| WARN this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
22+
}

0 commit comments

Comments
 (0)