Skip to content

Commit eff1272

Browse files
committed
Auto merge of rust-lang#17618 - Veykril:rustc_skip_during_method_dispatch, r=Veykril
Support rustc_skip_during_method_dispatch Fixes rust-lang/rust-analyzer#17256
2 parents 923e8c7 + 835734e commit eff1272

File tree

5 files changed

+94
-17
lines changed

5 files changed

+94
-17
lines changed

src/tools/rust-analyzer/crates/hir-def/src/data.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ pub struct TraitData {
223223
pub is_unsafe: bool,
224224
pub rustc_has_incoherent_inherent_impls: bool,
225225
pub skip_array_during_method_dispatch: bool,
226+
pub skip_boxed_slice_during_method_dispatch: bool,
226227
pub fundamental: bool,
227228
pub visibility: RawVisibility,
228229
/// Whether the trait has `#[rust_skip_array_during_method_dispatch]`. `hir_ty` will ignore
@@ -250,8 +251,17 @@ impl TraitData {
250251
let is_unsafe = tr_def.is_unsafe;
251252
let visibility = item_tree[tr_def.visibility].clone();
252253
let attrs = item_tree.attrs(db, module_id.krate(), ModItem::from(tree_id.value).into());
253-
let skip_array_during_method_dispatch =
254+
let mut skip_array_during_method_dispatch =
254255
attrs.by_key(&sym::rustc_skip_array_during_method_dispatch).exists();
256+
let mut skip_boxed_slice_during_method_dispatch = false;
257+
for tt in attrs.by_key(&sym::rustc_skip_during_method_dispatch).tt_values() {
258+
for tt in tt.token_trees.iter() {
259+
if let crate::tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) = tt {
260+
skip_array_during_method_dispatch |= ident.sym == sym::array;
261+
skip_boxed_slice_during_method_dispatch |= ident.sym == sym::boxed_slice;
262+
}
263+
}
264+
}
255265
let rustc_has_incoherent_inherent_impls =
256266
attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists();
257267
let fundamental = attrs.by_key(&sym::fundamental).exists();
@@ -269,6 +279,7 @@ impl TraitData {
269279
is_unsafe,
270280
visibility,
271281
skip_array_during_method_dispatch,
282+
skip_boxed_slice_during_method_dispatch,
272283
rustc_has_incoherent_inherent_impls,
273284
fundamental,
274285
}),

src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs

+26-16
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use std::ops::ControlFlow;
66

77
use base_db::CrateId;
8-
use chalk_ir::{cast::Cast, Mutability, TyKind, UniverseIndex, WhereClause};
8+
use chalk_ir::{cast::Cast, UniverseIndex, WithKind};
99
use hir_def::{
1010
data::{adt::StructFlags, ImplData},
1111
nameres::DefMap,
@@ -16,7 +16,6 @@ use hir_expand::name::Name;
1616
use intern::sym;
1717
use rustc_hash::{FxHashMap, FxHashSet};
1818
use smallvec::{smallvec, SmallVec};
19-
use span::Edition;
2019
use stdx::never;
2120
use triomphe::Arc;
2221

@@ -25,12 +24,14 @@ use crate::{
2524
db::HirDatabase,
2625
error_lifetime, from_chalk_trait_id, from_foreign_def_id,
2726
infer::{unify::InferenceTable, Adjust, Adjustment, OverloadedDeref, PointerCast},
27+
lang_items::is_box,
2828
primitive::{FloatTy, IntTy, UintTy},
2929
to_chalk_trait_id,
3030
utils::all_super_traits,
31-
AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, Goal, Guidance,
32-
InEnvironment, Interner, Scalar, Solution, Substitution, TraitEnvironment, TraitRef,
33-
TraitRefExt, Ty, TyBuilder, TyExt,
31+
AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, GenericArgData,
32+
Goal, Guidance, InEnvironment, Interner, Mutability, Scalar, Solution, Substitution,
33+
TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, VariableKind,
34+
WhereClause,
3435
};
3536

3637
/// This is used as a key for indexing impls.
@@ -1146,17 +1147,30 @@ fn iterate_trait_method_candidates(
11461147
'traits: for &t in traits_in_scope {
11471148
let data = db.trait_data(t);
11481149

1149-
// Traits annotated with `#[rustc_skip_array_during_method_dispatch]` are skipped during
1150+
// Traits annotated with `#[rustc_skip_during_method_dispatch]` are skipped during
11501151
// method resolution, if the receiver is an array, and we're compiling for editions before
11511152
// 2021.
11521153
// This is to make `[a].into_iter()` not break code with the new `IntoIterator` impl for
11531154
// arrays.
11541155
if data.skip_array_during_method_dispatch
1155-
&& matches!(self_ty.kind(Interner), chalk_ir::TyKind::Array(..))
1156+
&& matches!(self_ty.kind(Interner), TyKind::Array(..))
11561157
{
11571158
// FIXME: this should really be using the edition of the method name's span, in case it
11581159
// comes from a macro
1159-
if db.crate_graph()[krate].edition < Edition::Edition2021 {
1160+
if !db.crate_graph()[krate].edition.at_least_2021() {
1161+
continue;
1162+
}
1163+
}
1164+
if data.skip_boxed_slice_during_method_dispatch
1165+
&& matches!(
1166+
self_ty.kind(Interner), TyKind::Adt(AdtId(def), subst)
1167+
if is_box(table.db, *def)
1168+
&& matches!(subst.at(Interner, 0).assert_ty_ref(Interner).kind(Interner), TyKind::Slice(..))
1169+
)
1170+
{
1171+
// FIXME: this should really be using the edition of the method name's span, in case it
1172+
// comes from a macro
1173+
if !db.crate_graph()[krate].edition.at_least_2024() {
11601174
continue;
11611175
}
11621176
}
@@ -1619,15 +1633,11 @@ fn generic_implements_goal(
16191633
let kinds =
16201634
binders.iter().cloned().chain(trait_ref.substitution.iter(Interner).skip(1).map(|it| {
16211635
let vk = match it.data(Interner) {
1622-
chalk_ir::GenericArgData::Ty(_) => {
1623-
chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
1624-
}
1625-
chalk_ir::GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime,
1626-
chalk_ir::GenericArgData::Const(c) => {
1627-
chalk_ir::VariableKind::Const(c.data(Interner).ty.clone())
1628-
}
1636+
GenericArgData::Ty(_) => VariableKind::Ty(chalk_ir::TyVariableKind::General),
1637+
GenericArgData::Lifetime(_) => VariableKind::Lifetime,
1638+
GenericArgData::Const(c) => VariableKind::Const(c.data(Interner).ty.clone()),
16291639
};
1630-
chalk_ir::WithKind::new(vk, UniverseIndex::ROOT)
1640+
WithKind::new(vk, UniverseIndex::ROOT)
16311641
}));
16321642
let binders = CanonicalVarKinds::from_iter(Interner, kinds);
16331643

src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs

+49
Original file line numberDiff line numberDiff line change
@@ -1640,6 +1640,55 @@ impl<'a, T> IntoIterator for &'a [T] {
16401640
);
16411641
}
16421642

1643+
#[test]
1644+
fn skip_during_method_dispatch() {
1645+
check_types(
1646+
r#"
1647+
//- /main2018.rs crate:main2018 deps:core edition:2018
1648+
use core::IntoIterator;
1649+
1650+
fn f() {
1651+
let v = [4].into_iter();
1652+
v;
1653+
//^ &'? i32
1654+
1655+
let a = [0, 1].into_iter();
1656+
a;
1657+
//^ &'? i32
1658+
}
1659+
1660+
//- /main2021.rs crate:main2021 deps:core edition:2021
1661+
use core::IntoIterator;
1662+
1663+
fn f() {
1664+
let v = [4].into_iter();
1665+
v;
1666+
//^ i32
1667+
1668+
let a = [0, 1].into_iter();
1669+
a;
1670+
//^ &'? i32
1671+
}
1672+
1673+
//- /core.rs crate:core
1674+
#[rustc_skip_during_method_dispatch(array, boxed_slice)]
1675+
pub trait IntoIterator {
1676+
type Out;
1677+
fn into_iter(self) -> Self::Out;
1678+
}
1679+
1680+
impl<T> IntoIterator for [T; 1] {
1681+
type Out = T;
1682+
fn into_iter(self) -> Self::Out { loop {} }
1683+
}
1684+
impl<'a, T> IntoIterator for &'a [T] {
1685+
type Out = &'a T;
1686+
fn into_iter(self) -> Self::Out { loop {} }
1687+
}
1688+
"#,
1689+
);
1690+
}
1691+
16431692
#[test]
16441693
fn sized_blanket_impl() {
16451694
check_infer(

src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs

+3
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,7 @@ define_symbols! {
400400
rustc_reservation_impl,
401401
rustc_safe_intrinsic,
402402
rustc_skip_array_during_method_dispatch,
403+
rustc_skip_during_method_dispatch,
403404
semitransparent,
404405
shl_assign,
405406
shl,
@@ -455,4 +456,6 @@ define_symbols! {
455456
vectorcall,
456457
wasm,
457458
win64,
459+
array,
460+
boxed_slice,
458461
}

src/tools/rust-analyzer/crates/parser/src/edition.rs

+4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ impl Edition {
2020
self >= Edition::Edition2024
2121
}
2222

23+
pub fn at_least_2021(self) -> bool {
24+
self >= Edition::Edition2021
25+
}
26+
2327
pub fn at_least_2018(self) -> bool {
2428
self >= Edition::Edition2018
2529
}

0 commit comments

Comments
 (0)