diff options
author | Jonas Schievink <[email protected]> | 2021-06-01 20:33:14 +0100 |
---|---|---|
committer | Jonas Schievink <[email protected]> | 2021-06-01 20:34:08 +0100 |
commit | 955064b6aaa5c24e980328f9d9fbe731cc29636c (patch) | |
tree | 533c9942faa54bb7859c0fb986c5699847c7cea2 /crates/hir_ty | |
parent | dbdfeeeff91b5e42d8687df09dda1d29f99b34f8 (diff) |
Implement `#[rustc_skip_array_during_method_dispatch]`
Diffstat (limited to 'crates/hir_ty')
-rw-r--r-- | crates/hir_ty/src/method_resolution.rs | 16 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/method_resolution.rs | 49 |
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 @@ | |||
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 | } | ||