Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add IntoIterator for Box<[T]> + edition 2024-specific lints #124097

Merged
merged 6 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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()
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very funny to see somewhere in the compiler where we were relying on this behavior.

}
}

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
);
compiler-errors marked this conversation as resolved.
Show resolved Hide resolved

// 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
Loading