mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-29 13:25:09 +00:00
Implement #[rustc_skip_array_during_method_dispatch]
This commit is contained in:
parent
dbdfeeeff9
commit
955064b6aa
3 changed files with 77 additions and 2 deletions
|
@ -143,6 +143,7 @@ pub struct TraitData {
|
||||||
pub is_auto: bool,
|
pub is_auto: bool,
|
||||||
pub is_unsafe: bool,
|
pub is_unsafe: bool,
|
||||||
pub visibility: RawVisibility,
|
pub visibility: RawVisibility,
|
||||||
|
pub skip_array_during_method_dispatch: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TraitData {
|
impl TraitData {
|
||||||
|
@ -157,6 +158,10 @@ impl TraitData {
|
||||||
let container = AssocContainerId::TraitId(tr);
|
let container = AssocContainerId::TraitId(tr);
|
||||||
let visibility = item_tree[tr_def.visibility].clone();
|
let visibility = item_tree[tr_def.visibility].clone();
|
||||||
let mut expander = Expander::new(db, tr_loc.id.file_id(), module_id);
|
let mut expander = Expander::new(db, tr_loc.id.file_id(), module_id);
|
||||||
|
let skip_array_during_method_dispatch = item_tree
|
||||||
|
.attrs(db, tr_loc.container.krate(), ModItem::from(tr_loc.id.value).into())
|
||||||
|
.by_key("rustc_skip_array_during_method_dispatch")
|
||||||
|
.exists();
|
||||||
|
|
||||||
let items = collect_items(
|
let items = collect_items(
|
||||||
db,
|
db,
|
||||||
|
@ -168,7 +173,14 @@ impl TraitData {
|
||||||
100,
|
100,
|
||||||
);
|
);
|
||||||
|
|
||||||
Arc::new(TraitData { name, items, is_auto, is_unsafe, visibility })
|
Arc::new(TraitData {
|
||||||
|
name,
|
||||||
|
items,
|
||||||
|
is_auto,
|
||||||
|
is_unsafe,
|
||||||
|
visibility,
|
||||||
|
skip_array_during_method_dispatch,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ {
|
pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ {
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
use std::{iter, sync::Arc};
|
use std::{iter, sync::Arc};
|
||||||
|
|
||||||
use arrayvec::ArrayVec;
|
use arrayvec::ArrayVec;
|
||||||
use base_db::CrateId;
|
use base_db::{CrateId, Edition};
|
||||||
use chalk_ir::{cast::Cast, Mutability, UniverseIndex};
|
use chalk_ir::{cast::Cast, Mutability, UniverseIndex};
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
lang_item::LangItemTarget, nameres::DefMap, AssocContainerId, AssocItemId, FunctionId,
|
lang_item::LangItemTarget, nameres::DefMap, AssocContainerId, AssocItemId, FunctionId,
|
||||||
|
@ -639,6 +639,7 @@ fn iterate_trait_method_candidates(
|
||||||
receiver_ty: Option<&Canonical<Ty>>,
|
receiver_ty: Option<&Canonical<Ty>>,
|
||||||
callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool,
|
callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
let receiver_is_array = matches!(self_ty.value.kind(&Interner), chalk_ir::TyKind::Array(..));
|
||||||
// if ty is `dyn Trait`, the trait doesn't need to be in scope
|
// if ty is `dyn Trait`, the trait doesn't need to be in scope
|
||||||
let inherent_trait =
|
let inherent_trait =
|
||||||
self_ty.value.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t));
|
self_ty.value.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t));
|
||||||
|
@ -655,6 +656,19 @@ fn iterate_trait_method_candidates(
|
||||||
'traits: for t in traits {
|
'traits: for t in traits {
|
||||||
let data = db.trait_data(t);
|
let data = db.trait_data(t);
|
||||||
|
|
||||||
|
// Traits annotated with `#[rustc_skip_array_during_method_dispatch]` are skipped during
|
||||||
|
// method resolution, if the receiver is an array, and we're compiling for editions before
|
||||||
|
// 2021.
|
||||||
|
// This is to make `[a].into_iter()` not break code with the new `IntoIterator` impl for
|
||||||
|
// arrays.
|
||||||
|
if data.skip_array_during_method_dispatch && receiver_is_array {
|
||||||
|
// 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 < Edition::Edition2021 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// we'll be lazy about checking whether the type implements the
|
// we'll be lazy about checking whether the type implements the
|
||||||
// trait, but if we find out it doesn't, we'll skip the rest of the
|
// trait, but if we find out it doesn't, we'll skip the rest of the
|
||||||
// iteration
|
// iteration
|
||||||
|
|
|
@ -1349,3 +1349,52 @@ fn f() {
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn skip_array_during_method_dispatch() {
|
||||||
|
check_types(
|
||||||
|
r#"
|
||||||
|
//- /main2018.rs crate:main2018 deps:core
|
||||||
|
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_array_during_method_dispatch]
|
||||||
|
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 {}
|
||||||
|
}
|
||||||
|
impl<'a, T> IntoIterator for &'a [T] {
|
||||||
|
type Out = &'a T;
|
||||||
|
fn into_iter(self) -> Self::Out {}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue