Skip to content

Commit

Permalink
Auto merge of #124097 - compiler-errors:box-into-iter, r=WaffleLapkin
Browse files Browse the repository at this point in the history
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 #116607.

ACP: rust-lang/libs-team#263
References #59878
Tracking for Rust 2024: #123759

Crater run was done here: #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`.
  • Loading branch information
bors committed May 21, 2024
2 parents e875391 + 917bb83 commit e8fbd99
Show file tree
Hide file tree
Showing 37 changed files with 688 additions and 247 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_ast/src/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ impl<'a, T> IntoIterator for &'a P<[T]> {
type Item = &'a T;
type IntoIter = slice::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.ptr.into_iter()
self.ptr.iter()
}
}

Expand Down
9 changes: 5 additions & 4 deletions compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -899,10 +899,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
"the `#[rustc_main]` attribute is used internally to specify test entry point function",
),
rustc_attr!(
rustc_skip_array_during_method_dispatch, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::No,
"the `#[rustc_skip_array_during_method_dispatch]` attribute is used to exclude a trait \
from method dispatch when the receiver is an array, for compatibility in editions < 2021."
rustc_skip_during_method_dispatch, Normal, template!(List: "array, boxed_slice"), WarnFollowing,
EncodeCrossCrate::No,
"the `#[rustc_skip_during_method_dispatch]` attribute is used to exclude a trait \
from method dispatch when the receiver is of the following type, for compatibility in \
editions < 2021 (array) or editions < 2024 (boxed_slice)."
),
rustc_attr!(
rustc_must_implement_one_of, Normal, template!(List: "function1, function2, ..."),
Expand Down
21 changes: 19 additions & 2 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1117,8 +1117,24 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {

let is_marker = tcx.has_attr(def_id, sym::marker);
let rustc_coinductive = tcx.has_attr(def_id, sym::rustc_coinductive);
let skip_array_during_method_dispatch =
tcx.has_attr(def_id, sym::rustc_skip_array_during_method_dispatch);

// FIXME: We could probably do way better attribute validation here.
let mut skip_array_during_method_dispatch = false;
let mut skip_boxed_slice_during_method_dispatch = false;
for attr in tcx.get_attrs(def_id, sym::rustc_skip_during_method_dispatch) {
if let Some(lst) = attr.meta_item_list() {
for item in lst {
if let Some(ident) = item.ident() {
match ident.as_str() {
"array" => skip_array_during_method_dispatch = true,
"boxed_slice" => skip_boxed_slice_during_method_dispatch = true,
_ => (),
}
}
}
}
}

let specialization_kind = if tcx.has_attr(def_id, sym::rustc_unsafe_specialization_marker) {
ty::trait_def::TraitSpecializationKind::Marker
} else if tcx.has_attr(def_id, sym::rustc_specialization_trait) {
Expand Down Expand Up @@ -1253,6 +1269,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
is_marker,
is_coinductive: rustc_coinductive || is_auto,
skip_array_during_method_dispatch,
skip_boxed_slice_during_method_dispatch,
specialization_kind,
must_implement_one_of,
implement_via_object,
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_hir_typeck/src/method/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/method-lookup.html

mod confirm;
mod prelude2021;
mod prelude_edition_lints;
pub mod probe;
mod suggest;

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

self.lint_dot_call_from_2018(self_ty, segment, span, call_expr, self_expr, &pick, args);
self.lint_edition_dependent_dot_call(
self_ty, segment, span, call_expr, self_expr, &pick, args,
);

for &import_id in &pick.import_ids {
debug!("used_trait_import: {:?}", import_id);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use crate::{
method::probe::{self, Pick},
FnCtxt,
};
use crate::method::probe::{self, Pick};
use crate::FnCtxt;

use hir::def_id::DefId;
use hir::HirId;
use hir::ItemKind;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER};
use rustc_middle::span_bug;
use rustc_middle::ty::{self, Ty};
use rustc_session::lint::builtin::RUST_2021_PRELUDE_COLLISIONS;
Expand All @@ -17,7 +17,7 @@ use rustc_trait_selection::infer::InferCtxtExt;
use std::fmt::Write;

impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(super) fn lint_dot_call_from_2018(
pub(super) fn lint_edition_dependent_dot_call(
&self,
self_ty: Ty<'tcx>,
segment: &hir::PathSegment<'_>,
Expand All @@ -32,22 +32,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
segment.ident, self_ty, call_expr, self_expr
);

// Rust 2021 and later is already using the new prelude
if span.at_least_rust_2021() {
return;
}

let prelude_or_array_lint = match segment.ident.name {
let (prelude_or_array_lint, edition) = match segment.ident.name {
// `try_into` was added to the prelude in Rust 2021.
sym::try_into => RUST_2021_PRELUDE_COLLISIONS,
sym::try_into if !span.at_least_rust_2021() => (RUST_2021_PRELUDE_COLLISIONS, "2021"),
// `into_iter` wasn't added to the prelude,
// but `[T; N].into_iter()` doesn't resolve to IntoIterator::into_iter
// before Rust 2021, which results in the same problem.
// It is only a problem for arrays.
sym::into_iter if let ty::Array(..) = self_ty.kind() => {
// In this case, it wasn't really a prelude addition that was the problem.
// Instead, the problem is that the array-into_iter hack will no longer apply in Rust 2021.
rustc_lint::ARRAY_INTO_ITER
sym::into_iter => {
if let ty::Array(..) = self_ty.kind()
&& !span.at_least_rust_2021()
{
// In this case, it wasn't really a prelude addition that was the problem.
// Instead, the problem is that the array-into_iter hack will no longer
// apply in Rust 2021.
(ARRAY_INTO_ITER, "2021")
} else if self_ty.is_box()
&& self_ty.boxed_ty().is_slice()
&& !span.at_least_rust_2024()
{
// In this case, it wasn't really a prelude addition that was the problem.
// Instead, the problem is that the boxed-slice-into_iter hack will no
// longer apply in Rust 2024.
(BOXED_SLICE_INTO_ITER, "2024")
} else {
return;
}
}
_ => return,
};
Expand Down Expand Up @@ -81,7 +91,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
prelude_or_array_lint,
self_expr.hir_id,
self_expr.span,
format!("trait method `{}` will become ambiguous in Rust 2021", segment.ident.name),
format!(
"trait method `{}` will become ambiguous in Rust {edition}",
segment.ident.name
),
|lint| {
let sp = self_expr.span;

Expand Down Expand Up @@ -131,7 +144,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
prelude_or_array_lint,
call_expr.hir_id,
call_expr.span,
format!("trait method `{}` will become ambiguous in Rust 2021", segment.ident.name),
format!(
"trait method `{}` will become ambiguous in Rust {edition}",
segment.ident.name
),
|lint| {
let sp = call_expr.span;
let trait_name = self.trait_path_or_bare_name(
Expand Down
12 changes: 12 additions & 0 deletions compiler/rustc_hir_typeck/src/method/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1444,6 +1444,18 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
return ProbeResult::NoMatch;
}
}

// Some trait methods are excluded for boxed slices before 2024.
// (`boxed_slice.into_iter()` wants a slice iterator for compatibility.)
if self_ty.is_box()
&& self_ty.boxed_ty().is_slice()
&& !method_name.span.at_least_rust_2024()
{
let trait_def = self.tcx.trait_def(poly_trait_ref.def_id());
if trait_def.skip_boxed_slice_during_method_dispatch {
return ProbeResult::NoMatch;
}
}
}

let trait_ref = self.instantiate_binder_with_fresh_vars(
Expand Down
14 changes: 7 additions & 7 deletions compiler/rustc_lint/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,6 @@ lint_ambiguous_wide_pointer_comparisons = ambiguous wide pointer comparison, the
.addr_metadata_suggestion = use explicit `std::ptr::eq` method to compare metadata and addresses
.addr_suggestion = use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
lint_array_into_iter =
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
.use_iter_suggestion = use `.iter()` instead of `.into_iter()` to avoid ambiguity
.remove_into_iter_suggestion = or remove `.into_iter()` to iterate by value
.use_explicit_into_iter_suggestion =
or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
lint_async_fn_in_trait = use of `async fn` in public traits is discouraged as auto trait bounds cannot be specified
.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`
.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
Expand Down Expand Up @@ -565,6 +558,13 @@ lint_renamed_lint = lint `{$name}` has been renamed to `{$replace}`
lint_requested_level = requested on the command line with `{$level} {$lint_name}`
lint_shadowed_into_iter =
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}
.use_iter_suggestion = use `.iter()` instead of `.into_iter()` to avoid ambiguity
.remove_into_iter_suggestion = or remove `.into_iter()` to iterate by value
.use_explicit_into_iter_suggestion =
or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
lint_span_use_eq_ctxt = use `.eq_ctxt()` instead of `.ctxt() == .ctxt()`
lint_supertrait_as_deref_target = this `Deref` implementation is covered by an implicit supertrait coercion
Expand Down
144 changes: 0 additions & 144 deletions compiler/rustc_lint/src/array_into_iter.rs

This file was deleted.

Loading

0 comments on commit e8fbd99

Please sign in to comment.