aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir_def/src/data.rs17
-rw-r--r--crates/hir_ty/src/method_resolution.rs16
-rw-r--r--crates/hir_ty/src/tests/method_resolution.rs49
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
148impl TraitData { 152impl 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 @@
5use std::{iter, sync::Arc}; 5use std::{iter, sync::Arc};
6 6
7use arrayvec::ArrayVec; 7use arrayvec::ArrayVec;
8use base_db::CrateId; 8use base_db::{CrateId, Edition};
9use chalk_ir::{cast::Cast, Mutability, UniverseIndex}; 9use chalk_ir::{cast::Cast, Mutability, UniverseIndex};
10use hir_def::{ 10use 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]
1354fn skip_array_during_method_dispatch() {
1355 check_types(
1356 r#"
1357//- /main2018.rs crate:main2018 deps:core
1358use core::IntoIterator;
1359
1360fn 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
1371use core::IntoIterator;
1372
1373fn 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]
1385pub trait IntoIterator {
1386 type Out;
1387 fn into_iter(self) -> Self::Out;
1388}
1389
1390impl<T> IntoIterator for [T; 1] {
1391 type Out = T;
1392 fn into_iter(self) -> Self::Out {}
1393}
1394impl<'a, T> IntoIterator for &'a [T] {
1395 type Out = &'a T;
1396 fn into_iter(self) -> Self::Out {}
1397}
1398 "#,
1399 );
1400}