Skip to content

Commit e8fbd99

Browse files
committed
Auto merge of rust-lang#124097 - compiler-errors:box-into-iter, r=WaffleLapkin
Add `IntoIterator` for `Box<[T]>` + edition 2024-specific lints * Adds a similar method probe opt-out mechanism to the `[T;N]: IntoIterator` implementation for edition 2021. * Adjusts the relevant lints (shadowed `.into_iter()` calls, new source of method ambiguity). * Adds some tests. * Took the liberty to rework the logic in the `ARRAY_INTO_ITER` lint, since it was kind of confusing. Based mostly off of rust-lang#116607. ACP: rust-lang/libs-team#263 References rust-lang#59878 Tracking for Rust 2024: rust-lang#123759 Crater run was done here: rust-lang#116607 (comment) Consensus afaict was that there is too much breakage, so let's do this in an edition-dependent way much like `[T; N]: IntoIterator`.
2 parents e875391 + 917bb83 commit e8fbd99

37 files changed

+688
-247
lines changed

compiler/rustc_ast/src/ptr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ impl<'a, T> IntoIterator for &'a P<[T]> {
184184
type Item = &'a T;
185185
type IntoIter = slice::Iter<'a, T>;
186186
fn into_iter(self) -> Self::IntoIter {
187-
self.ptr.into_iter()
187+
self.ptr.iter()
188188
}
189189
}
190190

compiler/rustc_feature/src/builtin_attrs.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -899,10 +899,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
899899
"the `#[rustc_main]` attribute is used internally to specify test entry point function",
900900
),
901901
rustc_attr!(
902-
rustc_skip_array_during_method_dispatch, Normal, template!(Word),
903-
WarnFollowing, EncodeCrossCrate::No,
904-
"the `#[rustc_skip_array_during_method_dispatch]` attribute is used to exclude a trait \
905-
from method dispatch when the receiver is an array, for compatibility in editions < 2021."
902+
rustc_skip_during_method_dispatch, Normal, template!(List: "array, boxed_slice"), WarnFollowing,
903+
EncodeCrossCrate::No,
904+
"the `#[rustc_skip_during_method_dispatch]` attribute is used to exclude a trait \
905+
from method dispatch when the receiver is of the following type, for compatibility in \
906+
editions < 2021 (array) or editions < 2024 (boxed_slice)."
906907
),
907908
rustc_attr!(
908909
rustc_must_implement_one_of, Normal, template!(List: "function1, function2, ..."),

compiler/rustc_hir_analysis/src/collect.rs

+19-2
Original file line numberDiff line numberDiff line change
@@ -1117,8 +1117,24 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
11171117

11181118
let is_marker = tcx.has_attr(def_id, sym::marker);
11191119
let rustc_coinductive = tcx.has_attr(def_id, sym::rustc_coinductive);
1120-
let skip_array_during_method_dispatch =
1121-
tcx.has_attr(def_id, sym::rustc_skip_array_during_method_dispatch);
1120+
1121+
// FIXME: We could probably do way better attribute validation here.
1122+
let mut skip_array_during_method_dispatch = false;
1123+
let mut skip_boxed_slice_during_method_dispatch = false;
1124+
for attr in tcx.get_attrs(def_id, sym::rustc_skip_during_method_dispatch) {
1125+
if let Some(lst) = attr.meta_item_list() {
1126+
for item in lst {
1127+
if let Some(ident) = item.ident() {
1128+
match ident.as_str() {
1129+
"array" => skip_array_during_method_dispatch = true,
1130+
"boxed_slice" => skip_boxed_slice_during_method_dispatch = true,
1131+
_ => (),
1132+
}
1133+
}
1134+
}
1135+
}
1136+
}
1137+
11221138
let specialization_kind = if tcx.has_attr(def_id, sym::rustc_unsafe_specialization_marker) {
11231139
ty::trait_def::TraitSpecializationKind::Marker
11241140
} else if tcx.has_attr(def_id, sym::rustc_specialization_trait) {
@@ -1253,6 +1269,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
12531269
is_marker,
12541270
is_coinductive: rustc_coinductive || is_auto,
12551271
skip_array_during_method_dispatch,
1272+
skip_boxed_slice_during_method_dispatch,
12561273
specialization_kind,
12571274
must_implement_one_of,
12581275
implement_via_object,

compiler/rustc_hir_typeck/src/method/mod.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/method-lookup.html
44
55
mod confirm;
6-
mod prelude2021;
6+
mod prelude_edition_lints;
77
pub mod probe;
88
mod suggest;
99

@@ -186,7 +186,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
186186
let pick =
187187
self.lookup_probe(segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?;
188188

189-
self.lint_dot_call_from_2018(self_ty, segment, span, call_expr, self_expr, &pick, args);
189+
self.lint_edition_dependent_dot_call(
190+
self_ty, segment, span, call_expr, self_expr, &pick, args,
191+
);
190192

191193
for &import_id in &pick.import_ids {
192194
debug!("used_trait_import: {:?}", import_id);

compiler/rustc_hir_typeck/src/method/prelude2021.rs compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs

+34-18
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
use crate::{
2-
method::probe::{self, Pick},
3-
FnCtxt,
4-
};
1+
use crate::method::probe::{self, Pick};
2+
use crate::FnCtxt;
3+
54
use hir::def_id::DefId;
65
use hir::HirId;
76
use hir::ItemKind;
87
use rustc_errors::Applicability;
98
use rustc_hir as hir;
9+
use rustc_lint::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER};
1010
use rustc_middle::span_bug;
1111
use rustc_middle::ty::{self, Ty};
1212
use rustc_session::lint::builtin::RUST_2021_PRELUDE_COLLISIONS;
@@ -17,7 +17,7 @@ use rustc_trait_selection::infer::InferCtxtExt;
1717
use std::fmt::Write;
1818

1919
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
20-
pub(super) fn lint_dot_call_from_2018(
20+
pub(super) fn lint_edition_dependent_dot_call(
2121
&self,
2222
self_ty: Ty<'tcx>,
2323
segment: &hir::PathSegment<'_>,
@@ -32,22 +32,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
3232
segment.ident, self_ty, call_expr, self_expr
3333
);
3434

35-
// Rust 2021 and later is already using the new prelude
36-
if span.at_least_rust_2021() {
37-
return;
38-
}
39-
40-
let prelude_or_array_lint = match segment.ident.name {
35+
let (prelude_or_array_lint, edition) = match segment.ident.name {
4136
// `try_into` was added to the prelude in Rust 2021.
42-
sym::try_into => RUST_2021_PRELUDE_COLLISIONS,
37+
sym::try_into if !span.at_least_rust_2021() => (RUST_2021_PRELUDE_COLLISIONS, "2021"),
4338
// `into_iter` wasn't added to the prelude,
4439
// but `[T; N].into_iter()` doesn't resolve to IntoIterator::into_iter
4540
// before Rust 2021, which results in the same problem.
4641
// It is only a problem for arrays.
47-
sym::into_iter if let ty::Array(..) = self_ty.kind() => {
48-
// In this case, it wasn't really a prelude addition that was the problem.
49-
// Instead, the problem is that the array-into_iter hack will no longer apply in Rust 2021.
50-
rustc_lint::ARRAY_INTO_ITER
42+
sym::into_iter => {
43+
if let ty::Array(..) = self_ty.kind()
44+
&& !span.at_least_rust_2021()
45+
{
46+
// In this case, it wasn't really a prelude addition that was the problem.
47+
// Instead, the problem is that the array-into_iter hack will no longer
48+
// apply in Rust 2021.
49+
(ARRAY_INTO_ITER, "2021")
50+
} else if self_ty.is_box()
51+
&& self_ty.boxed_ty().is_slice()
52+
&& !span.at_least_rust_2024()
53+
{
54+
// In this case, it wasn't really a prelude addition that was the problem.
55+
// Instead, the problem is that the boxed-slice-into_iter hack will no
56+
// longer apply in Rust 2024.
57+
(BOXED_SLICE_INTO_ITER, "2024")
58+
} else {
59+
return;
60+
}
5161
}
5262
_ => return,
5363
};
@@ -81,7 +91,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
8191
prelude_or_array_lint,
8292
self_expr.hir_id,
8393
self_expr.span,
84-
format!("trait method `{}` will become ambiguous in Rust 2021", segment.ident.name),
94+
format!(
95+
"trait method `{}` will become ambiguous in Rust {edition}",
96+
segment.ident.name
97+
),
8598
|lint| {
8699
let sp = self_expr.span;
87100

@@ -131,7 +144,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
131144
prelude_or_array_lint,
132145
call_expr.hir_id,
133146
call_expr.span,
134-
format!("trait method `{}` will become ambiguous in Rust 2021", segment.ident.name),
147+
format!(
148+
"trait method `{}` will become ambiguous in Rust {edition}",
149+
segment.ident.name
150+
),
135151
|lint| {
136152
let sp = call_expr.span;
137153
let trait_name = self.trait_path_or_bare_name(

compiler/rustc_hir_typeck/src/method/probe.rs

+12
Original file line numberDiff line numberDiff line change
@@ -1444,6 +1444,18 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
14441444
return ProbeResult::NoMatch;
14451445
}
14461446
}
1447+
1448+
// Some trait methods are excluded for boxed slices before 2024.
1449+
// (`boxed_slice.into_iter()` wants a slice iterator for compatibility.)
1450+
if self_ty.is_box()
1451+
&& self_ty.boxed_ty().is_slice()
1452+
&& !method_name.span.at_least_rust_2024()
1453+
{
1454+
let trait_def = self.tcx.trait_def(poly_trait_ref.def_id());
1455+
if trait_def.skip_boxed_slice_during_method_dispatch {
1456+
return ProbeResult::NoMatch;
1457+
}
1458+
}
14471459
}
14481460

14491461
let trait_ref = self.instantiate_binder_with_fresh_vars(

compiler/rustc_lint/messages.ftl

+7-7
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,6 @@ lint_ambiguous_wide_pointer_comparisons = ambiguous wide pointer comparison, the
22
.addr_metadata_suggestion = use explicit `std::ptr::eq` method to compare metadata and addresses
33
.addr_suggestion = use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
44
5-
lint_array_into_iter =
6-
this method call resolves to `<&{$target} as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <{$target} as IntoIterator>::into_iter in Rust 2021
7-
.use_iter_suggestion = use `.iter()` instead of `.into_iter()` to avoid ambiguity
8-
.remove_into_iter_suggestion = or remove `.into_iter()` to iterate by value
9-
.use_explicit_into_iter_suggestion =
10-
or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
11-
125
lint_async_fn_in_trait = use of `async fn` in public traits is discouraged as auto trait bounds cannot be specified
136
.note = you can suppress this lint if you plan to use the trait only in your own code, or do not care about auto traits like `Send` on the `Future`
147
.suggestion = you can alternatively desugar to a normal `fn` that returns `impl Future` and add any desired bounds such as `Send`, but these cannot be relaxed without a breaking API change
@@ -565,6 +558,13 @@ lint_renamed_lint = lint `{$name}` has been renamed to `{$replace}`
565558
566559
lint_requested_level = requested on the command line with `{$level} {$lint_name}`
567560
561+
lint_shadowed_into_iter =
562+
this method call resolves to `<&{$target} as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<{$target} as IntoIterator>::into_iter` in Rust {$edition}
563+
.use_iter_suggestion = use `.iter()` instead of `.into_iter()` to avoid ambiguity
564+
.remove_into_iter_suggestion = or remove `.into_iter()` to iterate by value
565+
.use_explicit_into_iter_suggestion =
566+
or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
567+
568568
lint_span_use_eq_ctxt = use `.eq_ctxt()` instead of `.ctxt() == .ctxt()`
569569
570570
lint_supertrait_as_deref_target = this `Deref` implementation is covered by an implicit supertrait coercion

compiler/rustc_lint/src/array_into_iter.rs

-144
This file was deleted.

0 commit comments

Comments
 (0)