diff options
author | Florian Diebold <[email protected]> | 2019-09-07 15:39:05 +0100 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-09-07 15:49:57 +0100 |
commit | 8fb3cab76c60fbff5ae6f5984ac07b09b42b742c (patch) | |
tree | fdf832ba772141368f27d733cd718ee9a599a346 /crates/ra_hir/src | |
parent | 9db34eec209c740ed919afb288f75daa755cd268 (diff) |
Fix crash for super trait cycles
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 36 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 21 |
2 files changed, 39 insertions, 18 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 52ee1834f..1bb2f9f28 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -1,11 +1,8 @@ | |||
1 | pub(crate) mod src; | 1 | pub(crate) mod src; |
2 | pub(crate) mod docs; | 2 | pub(crate) mod docs; |
3 | 3 | ||
4 | use std::iter; | ||
5 | use std::sync::Arc; | 4 | use std::sync::Arc; |
6 | 5 | ||
7 | use itertools::Itertools; | ||
8 | |||
9 | use ra_db::{CrateId, Edition, FileId, SourceRootId}; | 6 | use ra_db::{CrateId, Edition, FileId, SourceRootId}; |
10 | use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; | 7 | use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; |
11 | 8 | ||
@@ -849,20 +846,23 @@ impl Trait { | |||
849 | 846 | ||
850 | /// Returns an iterator over the whole super trait hierarchy (including the | 847 | /// Returns an iterator over the whole super trait hierarchy (including the |
851 | /// trait itself). | 848 | /// trait itself). |
852 | pub fn all_super_traits<'a>( | 849 | pub fn all_super_traits(self, db: &impl HirDatabase) -> Vec<Trait> { |
853 | self, | 850 | // we need to take care a bit here to avoid infinite loops in case of cycles |
854 | db: &'a impl HirDatabase, | 851 | // (i.e. if we have `trait A: B; trait B: A;`) |
855 | ) -> impl Iterator<Item = Trait> + 'a { | 852 | let mut result = vec![self]; |
856 | self.all_super_traits_inner(db).unique() | 853 | let mut i = 0; |
857 | } | 854 | while i < result.len() { |
858 | 855 | let t = result[i]; | |
859 | fn all_super_traits_inner<'a>( | 856 | // yeah this is quadratic, but trait hierarchies should be flat |
860 | self, | 857 | // enough that this doesn't matter |
861 | db: &'a impl HirDatabase, | 858 | for tt in t.direct_super_traits(db) { |
862 | ) -> impl Iterator<Item = Trait> + 'a { | 859 | if !result.contains(&tt) { |
863 | iter::once(self).chain(self.direct_super_traits(db).into_iter().flat_map(move |t| { | 860 | result.push(tt); |
864 | iter::once(t).chain(Box::new(t.all_super_traits(db)) as Box<dyn Iterator<Item = Trait>>) | 861 | } |
865 | })) | 862 | } |
863 | i += 1; | ||
864 | } | ||
865 | result | ||
866 | } | 866 | } |
867 | 867 | ||
868 | pub fn associated_type_by_name(self, db: &impl DefDatabase, name: &Name) -> Option<TypeAlias> { | 868 | pub fn associated_type_by_name(self, db: &impl DefDatabase, name: &Name) -> Option<TypeAlias> { |
@@ -882,7 +882,7 @@ impl Trait { | |||
882 | db: &impl HirDatabase, | 882 | db: &impl HirDatabase, |
883 | name: &Name, | 883 | name: &Name, |
884 | ) -> Option<TypeAlias> { | 884 | ) -> Option<TypeAlias> { |
885 | self.all_super_traits(db).find_map(|t| t.associated_type_by_name(db, name)) | 885 | self.all_super_traits(db).into_iter().find_map(|t| t.associated_type_by_name(db, name)) |
886 | } | 886 | } |
887 | 887 | ||
888 | pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc<TraitData> { | 888 | pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc<TraitData> { |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 3f86a5c80..c4bddde85 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -3695,6 +3695,27 @@ fn test<T: Trait1, U: Trait2>(x: T, y: U) { | |||
3695 | } | 3695 | } |
3696 | 3696 | ||
3697 | #[test] | 3697 | #[test] |
3698 | fn super_trait_cycle() { | ||
3699 | // This just needs to not crash | ||
3700 | assert_snapshot!( | ||
3701 | infer(r#" | ||
3702 | trait A: B {} | ||
3703 | trait B: A {} | ||
3704 | |||
3705 | fn test<T: A>(x: T) { | ||
3706 | x.foo(); | ||
3707 | } | ||
3708 | "#), | ||
3709 | @r###" | ||
3710 | [44; 45) 'x': T | ||
3711 | [50; 66) '{ ...o(); }': () | ||
3712 | [56; 57) 'x': T | ||
3713 | [56; 63) 'x.foo()': {unknown} | ||
3714 | "### | ||
3715 | ); | ||
3716 | } | ||
3717 | |||
3718 | #[test] | ||
3698 | fn super_trait_assoc_type_bounds() { | 3719 | fn super_trait_assoc_type_bounds() { |
3699 | assert_snapshot!( | 3720 | assert_snapshot!( |
3700 | infer(r#" | 3721 | infer(r#" |