diff options
-rw-r--r-- | crates/hir_def/src/data.rs | 17 | ||||
-rw-r--r-- | crates/hir_ty/src/method_resolution.rs | 16 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/method_resolution.rs | 49 |
3 files changed, 80 insertions, 2 deletions
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs index d2bb381be..52cb7777b 100644 --- a/crates/hir_def/src/data.rs +++ b/crates/hir_def/src/data.rs | |||
@@ -143,6 +143,10 @@ pub struct TraitData { | |||
143 | pub is_auto: bool, | 143 | pub is_auto: bool, |
144 | pub is_unsafe: bool, | 144 | pub is_unsafe: bool, |
145 | pub visibility: RawVisibility, | 145 | pub visibility: RawVisibility, |
146 | /// Whether the trait has `#[rust_skip_array_during_method_dispatch]`. `hir_ty` will ignore | ||
147 | /// method calls to this trait's methods when the receiver is an array and the crate edition is | ||
148 | /// 2015 or 2018. | ||
149 | pub skip_array_during_method_dispatch: bool, | ||
146 | } | 150 | } |
147 | 151 | ||
148 | impl TraitData { | 152 | impl TraitData { |
@@ -157,6 +161,10 @@ impl TraitData { | |||
157 | let container = AssocContainerId::TraitId(tr); | 161 | let container = AssocContainerId::TraitId(tr); |
158 | let visibility = item_tree[tr_def.visibility].clone(); | 162 | let visibility = item_tree[tr_def.visibility].clone(); |
159 | let mut expander = Expander::new(db, tr_loc.id.file_id(), module_id); | 163 | let mut expander = Expander::new(db, tr_loc.id.file_id(), module_id); |
164 | let skip_array_during_method_dispatch = item_tree | ||
165 | .attrs(db, tr_loc.container.krate(), ModItem::from(tr_loc.id.value).into()) | ||
166 | .by_key("rustc_skip_array_during_method_dispatch") | ||
167 | .exists(); | ||
160 | 168 | ||
161 | let items = collect_items( | 169 | let items = collect_items( |
162 | db, | 170 | db, |
@@ -168,7 +176,14 @@ impl TraitData { | |||
168 | 100, | 176 | 100, |
169 | ); | 177 | ); |
170 | 178 | ||
171 | Arc::new(TraitData { name, items, is_auto, is_unsafe, visibility }) | 179 | Arc::new(TraitData { |
180 | name, | ||
181 | items, | ||
182 | is_auto, | ||
183 | is_unsafe, | ||
184 | visibility, | ||
185 | skip_array_during_method_dispatch, | ||
186 | }) | ||
172 | } | 187 | } |
173 | 188 | ||
174 | pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ { | 189 | pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ { |
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs index af6b6cda7..a23527f7d 100644 --- a/crates/hir_ty/src/method_resolution.rs +++ b/crates/hir_ty/src/method_resolution.rs | |||
@@ -5,7 +5,7 @@ | |||
5 | use std::{iter, sync::Arc}; | 5 | use std::{iter, sync::Arc}; |
6 | 6 | ||
7 | use arrayvec::ArrayVec; | 7 | use arrayvec::ArrayVec; |
8 | use base_db::CrateId; | 8 | use base_db::{CrateId, Edition}; |
9 | use chalk_ir::{cast::Cast, Mutability, UniverseIndex}; | 9 | use chalk_ir::{cast::Cast, Mutability, UniverseIndex}; |
10 | use hir_def::{ | 10 | use hir_def::{ |
11 | lang_item::LangItemTarget, nameres::DefMap, AssocContainerId, AssocItemId, FunctionId, | 11 | lang_item::LangItemTarget, nameres::DefMap, AssocContainerId, AssocItemId, FunctionId, |
@@ -639,6 +639,7 @@ fn iterate_trait_method_candidates( | |||
639 | receiver_ty: Option<&Canonical<Ty>>, | 639 | receiver_ty: Option<&Canonical<Ty>>, |
640 | callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, | 640 | callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, |
641 | ) -> bool { | 641 | ) -> bool { |
642 | let receiver_is_array = matches!(self_ty.value.kind(&Interner), chalk_ir::TyKind::Array(..)); | ||
642 | // if ty is `dyn Trait`, the trait doesn't need to be in scope | 643 | // if ty is `dyn Trait`, the trait doesn't need to be in scope |
643 | let inherent_trait = | 644 | let inherent_trait = |
644 | self_ty.value.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t)); | 645 | 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( | |||
655 | 'traits: for t in traits { | 656 | 'traits: for t in traits { |
656 | let data = db.trait_data(t); | 657 | let data = db.trait_data(t); |
657 | 658 | ||
659 | // Traits annotated with `#[rustc_skip_array_during_method_dispatch]` are skipped during | ||
660 | // method resolution, if the receiver is an array, and we're compiling for editions before | ||
661 | // 2021. | ||
662 | // This is to make `[a].into_iter()` not break code with the new `IntoIterator` impl for | ||
663 | // arrays. | ||
664 | if data.skip_array_during_method_dispatch && receiver_is_array { | ||
665 | // FIXME: this should really be using the edition of the method name's span, in case it | ||
666 | // comes from a macro | ||
667 | if db.crate_graph()[krate].edition < Edition::Edition2021 { | ||
668 | continue; | ||
669 | } | ||
670 | } | ||
671 | |||
658 | // we'll be lazy about checking whether the type implements the | 672 | // we'll be lazy about checking whether the type implements the |
659 | // trait, but if we find out it doesn't, we'll skip the rest of the | 673 | // trait, but if we find out it doesn't, we'll skip the rest of the |
660 | // iteration | 674 | // iteration |
diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs index 058eb9129..f26b2c8a7 100644 --- a/crates/hir_ty/src/tests/method_resolution.rs +++ b/crates/hir_ty/src/tests/method_resolution.rs | |||
@@ -1349,3 +1349,52 @@ fn f() { | |||
1349 | "#, | 1349 | "#, |
1350 | ); | 1350 | ); |
1351 | } | 1351 | } |
1352 | |||
1353 | #[test] | ||
1354 | fn skip_array_during_method_dispatch() { | ||
1355 | check_types( | ||
1356 | r#" | ||
1357 | //- /main2018.rs crate:main2018 deps:core | ||
1358 | use core::IntoIterator; | ||
1359 | |||
1360 | fn f() { | ||
1361 | let v = [4].into_iter(); | ||
1362 | v; | ||
1363 | //^ &i32 | ||
1364 | |||
1365 | let a = [0, 1].into_iter(); | ||
1366 | a; | ||
1367 | //^ &i32 | ||
1368 | } | ||
1369 | |||
1370 | //- /main2021.rs crate:main2021 deps:core edition:2021 | ||
1371 | use core::IntoIterator; | ||
1372 | |||
1373 | fn f() { | ||
1374 | let v = [4].into_iter(); | ||
1375 | v; | ||
1376 | //^ i32 | ||
1377 | |||
1378 | let a = [0, 1].into_iter(); | ||
1379 | a; | ||
1380 | //^ &i32 | ||
1381 | } | ||
1382 | |||
1383 | //- /core.rs crate:core | ||
1384 | #[rustc_skip_array_during_method_dispatch] | ||
1385 | pub trait IntoIterator { | ||
1386 | type Out; | ||
1387 | fn into_iter(self) -> Self::Out; | ||
1388 | } | ||
1389 | |||
1390 | impl<T> IntoIterator for [T; 1] { | ||
1391 | type Out = T; | ||
1392 | fn into_iter(self) -> Self::Out {} | ||
1393 | } | ||
1394 | impl<'a, T> IntoIterator for &'a [T] { | ||
1395 | type Out = &'a T; | ||
1396 | fn into_iter(self) -> Self::Out {} | ||
1397 | } | ||
1398 | "#, | ||
1399 | ); | ||
1400 | } | ||