Auto merge of #17618 - Veykril:rustc_skip_during_method_dispatch, r=Veykril

Support rustc_skip_during_method_dispatch

Fixes https://github.com/rust-lang/rust-analyzer/issues/17256
This commit is contained in:
bors 2024-07-17 09:48:18 +00:00
commit a62ea0a59e
5 changed files with 94 additions and 17 deletions

View file

@ -223,6 +223,7 @@ pub struct TraitData {
pub is_unsafe: bool, pub is_unsafe: bool,
pub rustc_has_incoherent_inherent_impls: bool, pub rustc_has_incoherent_inherent_impls: bool,
pub skip_array_during_method_dispatch: bool, pub skip_array_during_method_dispatch: bool,
pub skip_boxed_slice_during_method_dispatch: bool,
pub fundamental: bool, pub fundamental: bool,
pub visibility: RawVisibility, pub visibility: RawVisibility,
/// Whether the trait has `#[rust_skip_array_during_method_dispatch]`. `hir_ty` will ignore /// Whether the trait has `#[rust_skip_array_during_method_dispatch]`. `hir_ty` will ignore
@ -250,8 +251,17 @@ impl TraitData {
let is_unsafe = tr_def.is_unsafe; let is_unsafe = tr_def.is_unsafe;
let visibility = item_tree[tr_def.visibility].clone(); let visibility = item_tree[tr_def.visibility].clone();
let attrs = item_tree.attrs(db, module_id.krate(), ModItem::from(tree_id.value).into()); let attrs = item_tree.attrs(db, module_id.krate(), ModItem::from(tree_id.value).into());
let skip_array_during_method_dispatch = let mut skip_array_during_method_dispatch =
attrs.by_key(&sym::rustc_skip_array_during_method_dispatch).exists(); attrs.by_key(&sym::rustc_skip_array_during_method_dispatch).exists();
let mut skip_boxed_slice_during_method_dispatch = false;
for tt in attrs.by_key(&sym::rustc_skip_during_method_dispatch).tt_values() {
for tt in tt.token_trees.iter() {
if let crate::tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) = tt {
skip_array_during_method_dispatch |= ident.sym == sym::array;
skip_boxed_slice_during_method_dispatch |= ident.sym == sym::boxed_slice;
}
}
}
let rustc_has_incoherent_inherent_impls = let rustc_has_incoherent_inherent_impls =
attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists(); attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists();
let fundamental = attrs.by_key(&sym::fundamental).exists(); let fundamental = attrs.by_key(&sym::fundamental).exists();
@ -269,6 +279,7 @@ impl TraitData {
is_unsafe, is_unsafe,
visibility, visibility,
skip_array_during_method_dispatch, skip_array_during_method_dispatch,
skip_boxed_slice_during_method_dispatch,
rustc_has_incoherent_inherent_impls, rustc_has_incoherent_inherent_impls,
fundamental, fundamental,
}), }),

View file

@ -5,7 +5,7 @@
use std::ops::ControlFlow; use std::ops::ControlFlow;
use base_db::CrateId; use base_db::CrateId;
use chalk_ir::{cast::Cast, Mutability, TyKind, UniverseIndex, WhereClause}; use chalk_ir::{cast::Cast, UniverseIndex, WithKind};
use hir_def::{ use hir_def::{
data::{adt::StructFlags, ImplData}, data::{adt::StructFlags, ImplData},
nameres::DefMap, nameres::DefMap,
@ -16,7 +16,6 @@ use hir_expand::name::Name;
use intern::sym; use intern::sym;
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
use span::Edition;
use stdx::never; use stdx::never;
use triomphe::Arc; use triomphe::Arc;
@ -25,12 +24,14 @@ use crate::{
db::HirDatabase, db::HirDatabase,
error_lifetime, from_chalk_trait_id, from_foreign_def_id, error_lifetime, from_chalk_trait_id, from_foreign_def_id,
infer::{unify::InferenceTable, Adjust, Adjustment, OverloadedDeref, PointerCast}, infer::{unify::InferenceTable, Adjust, Adjustment, OverloadedDeref, PointerCast},
lang_items::is_box,
primitive::{FloatTy, IntTy, UintTy}, primitive::{FloatTy, IntTy, UintTy},
to_chalk_trait_id, to_chalk_trait_id,
utils::all_super_traits, utils::all_super_traits,
AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, Goal, Guidance, AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, GenericArgData,
InEnvironment, Interner, Scalar, Solution, Substitution, TraitEnvironment, TraitRef, Goal, Guidance, InEnvironment, Interner, Mutability, Scalar, Solution, Substitution,
TraitRefExt, Ty, TyBuilder, TyExt, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, VariableKind,
WhereClause,
}; };
/// This is used as a key for indexing impls. /// This is used as a key for indexing impls.
@ -1146,17 +1147,30 @@ fn iterate_trait_method_candidates(
'traits: for &t in traits_in_scope { 'traits: for &t in traits_in_scope {
let data = db.trait_data(t); let data = db.trait_data(t);
// Traits annotated with `#[rustc_skip_array_during_method_dispatch]` are skipped during // Traits annotated with `#[rustc_skip_during_method_dispatch]` are skipped during
// method resolution, if the receiver is an array, and we're compiling for editions before // method resolution, if the receiver is an array, and we're compiling for editions before
// 2021. // 2021.
// This is to make `[a].into_iter()` not break code with the new `IntoIterator` impl for // This is to make `[a].into_iter()` not break code with the new `IntoIterator` impl for
// arrays. // arrays.
if data.skip_array_during_method_dispatch if data.skip_array_during_method_dispatch
&& matches!(self_ty.kind(Interner), chalk_ir::TyKind::Array(..)) && matches!(self_ty.kind(Interner), TyKind::Array(..))
{ {
// FIXME: this should really be using the edition of the method name's span, in case it // FIXME: this should really be using the edition of the method name's span, in case it
// comes from a macro // comes from a macro
if db.crate_graph()[krate].edition < Edition::Edition2021 { if !db.crate_graph()[krate].edition.at_least_2021() {
continue;
}
}
if data.skip_boxed_slice_during_method_dispatch
&& matches!(
self_ty.kind(Interner), TyKind::Adt(AdtId(def), subst)
if is_box(table.db, *def)
&& matches!(subst.at(Interner, 0).assert_ty_ref(Interner).kind(Interner), TyKind::Slice(..))
)
{
// FIXME: this should really be using the edition of the method name's span, in case it
// comes from a macro
if !db.crate_graph()[krate].edition.at_least_2024() {
continue; continue;
} }
} }
@ -1619,15 +1633,11 @@ fn generic_implements_goal(
let kinds = let kinds =
binders.iter().cloned().chain(trait_ref.substitution.iter(Interner).skip(1).map(|it| { binders.iter().cloned().chain(trait_ref.substitution.iter(Interner).skip(1).map(|it| {
let vk = match it.data(Interner) { let vk = match it.data(Interner) {
chalk_ir::GenericArgData::Ty(_) => { GenericArgData::Ty(_) => VariableKind::Ty(chalk_ir::TyVariableKind::General),
chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General) GenericArgData::Lifetime(_) => VariableKind::Lifetime,
} GenericArgData::Const(c) => VariableKind::Const(c.data(Interner).ty.clone()),
chalk_ir::GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime,
chalk_ir::GenericArgData::Const(c) => {
chalk_ir::VariableKind::Const(c.data(Interner).ty.clone())
}
}; };
chalk_ir::WithKind::new(vk, UniverseIndex::ROOT) WithKind::new(vk, UniverseIndex::ROOT)
})); }));
let binders = CanonicalVarKinds::from_iter(Interner, kinds); let binders = CanonicalVarKinds::from_iter(Interner, kinds);

View file

@ -1640,6 +1640,55 @@ impl<'a, T> IntoIterator for &'a [T] {
); );
} }
#[test]
fn skip_during_method_dispatch() {
check_types(
r#"
//- /main2018.rs crate:main2018 deps:core edition:2018
use core::IntoIterator;
fn f() {
let v = [4].into_iter();
v;
//^ &'? i32
let a = [0, 1].into_iter();
a;
//^ &'? i32
}
//- /main2021.rs crate:main2021 deps:core edition:2021
use core::IntoIterator;
fn f() {
let v = [4].into_iter();
v;
//^ i32
let a = [0, 1].into_iter();
a;
//^ &'? i32
}
//- /core.rs crate:core
#[rustc_skip_during_method_dispatch(array, boxed_slice)]
pub trait IntoIterator {
type Out;
fn into_iter(self) -> Self::Out;
}
impl<T> IntoIterator for [T; 1] {
type Out = T;
fn into_iter(self) -> Self::Out { loop {} }
}
impl<'a, T> IntoIterator for &'a [T] {
type Out = &'a T;
fn into_iter(self) -> Self::Out { loop {} }
}
"#,
);
}
#[test] #[test]
fn sized_blanket_impl() { fn sized_blanket_impl() {
check_infer( check_infer(

View file

@ -400,6 +400,7 @@ define_symbols! {
rustc_reservation_impl, rustc_reservation_impl,
rustc_safe_intrinsic, rustc_safe_intrinsic,
rustc_skip_array_during_method_dispatch, rustc_skip_array_during_method_dispatch,
rustc_skip_during_method_dispatch,
semitransparent, semitransparent,
shl_assign, shl_assign,
shl, shl,
@ -455,4 +456,6 @@ define_symbols! {
vectorcall, vectorcall,
wasm, wasm,
win64, win64,
array,
boxed_slice,
} }

View file

@ -20,6 +20,10 @@ impl Edition {
self >= Edition::Edition2024 self >= Edition::Edition2024
} }
pub fn at_least_2021(self) -> bool {
self >= Edition::Edition2021
}
pub fn at_least_2018(self) -> bool { pub fn at_least_2018(self) -> bool {
self >= Edition::Edition2018 self >= Edition::Edition2018
} }