aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-09-07 15:39:05 +0100
committerFlorian Diebold <[email protected]>2019-09-07 15:49:57 +0100
commit8fb3cab76c60fbff5ae6f5984ac07b09b42b742c (patch)
treefdf832ba772141368f27d733cd718ee9a599a346 /crates/ra_hir/src
parent9db34eec209c740ed919afb288f75daa755cd268 (diff)
Fix crash for super trait cycles
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r--crates/ra_hir/src/code_model.rs36
-rw-r--r--crates/ra_hir/src/ty/tests.rs21
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 @@
1pub(crate) mod src; 1pub(crate) mod src;
2pub(crate) mod docs; 2pub(crate) mod docs;
3 3
4use std::iter;
5use std::sync::Arc; 4use std::sync::Arc;
6 5
7use itertools::Itertools;
8
9use ra_db::{CrateId, Edition, FileId, SourceRootId}; 6use ra_db::{CrateId, Edition, FileId, SourceRootId};
10use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; 7use 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]
3698fn super_trait_cycle() {
3699 // This just needs to not crash
3700 assert_snapshot!(
3701 infer(r#"
3702trait A: B {}
3703trait B: A {}
3704
3705fn 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]
3698fn super_trait_assoc_type_bounds() { 3719fn super_trait_assoc_type_bounds() {
3699 assert_snapshot!( 3720 assert_snapshot!(
3700 infer(r#" 3721 infer(r#"