aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty/src
diff options
context:
space:
mode:
authorJonas Schievink <[email protected]>2021-06-01 20:33:14 +0100
committerJonas Schievink <[email protected]>2021-06-01 20:34:08 +0100
commit955064b6aaa5c24e980328f9d9fbe731cc29636c (patch)
tree533c9942faa54bb7859c0fb986c5699847c7cea2 /crates/hir_ty/src
parentdbdfeeeff91b5e42d8687df09dda1d29f99b34f8 (diff)
Implement `#[rustc_skip_array_during_method_dispatch]`
Diffstat (limited to 'crates/hir_ty/src')
-rw-r--r--crates/hir_ty/src/method_resolution.rs16
-rw-r--r--crates/hir_ty/src/tests/method_resolution.rs49
2 files changed, 64 insertions, 1 deletions
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}