aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--crates/ra_hir/Cargo.toml1
-rw-r--r--crates/ra_hir/src/code_model.rs54
-rw-r--r--crates/ra_hir/src/generics.rs22
-rw-r--r--crates/ra_hir/src/name.rs6
-rw-r--r--crates/ra_hir/src/ty/autoderef.rs4
-rw-r--r--crates/ra_hir/src/ty/infer.rs6
-rw-r--r--crates/ra_hir/src/ty/lower.rs27
-rw-r--r--crates/ra_hir/src/ty/tests.rs10
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs2
-rw-r--r--crates/ra_hir/src/type_ref.rs7
11 files changed, 102 insertions, 38 deletions
diff --git a/Cargo.lock b/Cargo.lock
index f93f11a82..7f7de3bf4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1007,6 +1007,7 @@ dependencies = [
1007 "chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git)", 1007 "chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git)",
1008 "ena 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", 1008 "ena 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
1009 "insta 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 1009 "insta 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
1010 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
1010 "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", 1011 "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
1011 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 1012 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
1012 "once_cell 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 1013 "once_cell 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml
index d9bed4dda..e89b97daf 100644
--- a/crates/ra_hir/Cargo.toml
+++ b/crates/ra_hir/Cargo.toml
@@ -12,6 +12,7 @@ rustc-hash = "1.0"
12parking_lot = "0.9.0" 12parking_lot = "0.9.0"
13ena = "0.13" 13ena = "0.13"
14once_cell = "1.0.1" 14once_cell = "1.0.1"
15itertools = "0.8.0"
15 16
16ra_syntax = { path = "../ra_syntax" } 17ra_syntax = { path = "../ra_syntax" }
17ra_arena = { path = "../ra_arena" } 18ra_arena = { path = "../ra_arena" }
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index f7efc1b66..4739246cb 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -1,8 +1,11 @@
1pub(crate) mod src; 1pub(crate) mod src;
2pub(crate) mod docs; 2pub(crate) mod docs;
3 3
4use std::iter;
4use std::sync::Arc; 5use std::sync::Arc;
5 6
7use itertools::Itertools;
8
6use ra_db::{CrateId, Edition, FileId, SourceRootId}; 9use ra_db::{CrateId, Edition, FileId, SourceRootId};
7use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; 10use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
8 11
@@ -820,7 +823,43 @@ impl Trait {
820 self.trait_data(db).items().to_vec() 823 self.trait_data(db).items().to_vec()
821 } 824 }
822 825
823 pub fn associated_type_by_name(self, db: &impl DefDatabase, name: Name) -> Option<TypeAlias> { 826 fn direct_super_traits(self, db: &impl HirDatabase) -> Vec<Trait> {
827 let resolver = self.resolver(db);
828 // returning the iterator directly doesn't easily work because of
829 // lifetime problems, but since there usually shouldn't be more than a
830 // few direct traits this should be fine (we could even use some kind of
831 // SmallVec if performance is a concern)
832 self.generic_params(db)
833 .where_predicates
834 .iter()
835 .filter_map(|pred| match &pred.type_ref {
836 TypeRef::Path(p) if p.as_ident() == Some(&crate::name::SELF_TYPE) => {
837 pred.bound.as_path()
838 }
839 _ => None,
840 })
841 .filter_map(|path| {
842 match resolver.resolve_path_without_assoc_items(db, path).take_types() {
843 Some(crate::Resolution::Def(ModuleDef::Trait(t))) => Some(t),
844 _ => None,
845 }
846 })
847 .collect()
848 }
849
850 /// Returns an iterator over the whole super trait hierarchy (not including
851 /// the trait itself). (This iterator may be infinite in case of circular
852 /// super trait dependencies, which are possible in malformed code.)
853 pub fn all_super_traits<'a>(
854 self,
855 db: &'a impl HirDatabase,
856 ) -> impl Iterator<Item = Trait> + 'a {
857 self.direct_super_traits(db).into_iter().flat_map(move |t| {
858 iter::once(t).chain(Box::new(t.all_super_traits(db)) as Box<dyn Iterator<Item = Trait>>)
859 })
860 }
861
862 pub fn associated_type_by_name(self, db: &impl DefDatabase, name: &Name) -> Option<TypeAlias> {
824 let trait_data = self.trait_data(db); 863 let trait_data = self.trait_data(db);
825 trait_data 864 trait_data
826 .items() 865 .items()
@@ -829,7 +868,18 @@ impl Trait {
829 TraitItem::TypeAlias(t) => Some(*t), 868 TraitItem::TypeAlias(t) => Some(*t),
830 _ => None, 869 _ => None,
831 }) 870 })
832 .find(|t| t.name(db) == name) 871 .find(|t| &t.name(db) == name)
872 }
873
874 pub fn associated_type_by_name_including_super_traits(
875 self,
876 db: &impl HirDatabase,
877 name: &Name,
878 ) -> Option<TypeAlias> {
879 iter::once(self)
880 .chain(self.all_super_traits(db))
881 .unique()
882 .find_map(|t| t.associated_type_by_name(db, name))
833 } 883 }
834 884
835 pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc<TraitData> { 885 pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc<TraitData> {
diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs
index d6728cc9f..c76df0698 100644
--- a/crates/ra_hir/src/generics.rs
+++ b/crates/ra_hir/src/generics.rs
@@ -87,11 +87,15 @@ impl GenericParams {
87 // traits get the Self type as an implicit first type parameter 87 // traits get the Self type as an implicit first type parameter
88 generics.params.push(GenericParam { idx: start, name: SELF_TYPE, default: None }); 88 generics.params.push(GenericParam { idx: start, name: SELF_TYPE, default: None });
89 generics.fill(&it.source(db).ast, start + 1); 89 generics.fill(&it.source(db).ast, start + 1);
90 // add super traits as bounds on Self
91 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
92 let self_param = TypeRef::Path(SELF_TYPE.into());
93 generics.fill_bounds(&it.source(db).ast, self_param);
90 } 94 }
91 GenericDef::TypeAlias(it) => generics.fill(&it.source(db).ast, start), 95 GenericDef::TypeAlias(it) => generics.fill(&it.source(db).ast, start),
92 // Note that we don't add `Self` here: in `impl`s, `Self` is not a 96 // Note that we don't add `Self` here: in `impl`s, `Self` is not a
93 // type-parameter, but rather is a type-alias for impl's target 97 // type-parameter, but rather is a type-alias for impl's target
94 // type, so this is handled by the resovler. 98 // type, so this is handled by the resolver.
95 GenericDef::ImplBlock(it) => generics.fill(&it.source(db).ast, start), 99 GenericDef::ImplBlock(it) => generics.fill(&it.source(db).ast, start),
96 GenericDef::EnumVariant(_) => {} 100 GenericDef::EnumVariant(_) => {}
97 } 101 }
@@ -108,6 +112,14 @@ impl GenericParams {
108 } 112 }
109 } 113 }
110 114
115 fn fill_bounds(&mut self, node: &impl ast::TypeBoundsOwner, type_ref: TypeRef) {
116 for bound in
117 node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds())
118 {
119 self.add_where_predicate_from_bound(bound, type_ref.clone());
120 }
121 }
122
111 fn fill_params(&mut self, params: ast::TypeParamList, start: u32) { 123 fn fill_params(&mut self, params: ast::TypeParamList, start: u32) {
112 for (idx, type_param) in params.type_params().enumerate() { 124 for (idx, type_param) in params.type_params().enumerate() {
113 let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); 125 let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
@@ -117,13 +129,7 @@ impl GenericParams {
117 self.params.push(param); 129 self.params.push(param);
118 130
119 let type_ref = TypeRef::Path(name.into()); 131 let type_ref = TypeRef::Path(name.into());
120 for bound in type_param 132 self.fill_bounds(&type_param, type_ref);
121 .type_bound_list()
122 .iter()
123 .flat_map(|type_bound_list| type_bound_list.bounds())
124 {
125 self.add_where_predicate_from_bound(bound, type_ref.clone());
126 }
127 } 133 }
128 } 134 }
129 135
diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs
index 9c4822d91..13bc901bc 100644
--- a/crates/ra_hir/src/name.rs
+++ b/crates/ra_hir/src/name.rs
@@ -38,11 +38,6 @@ impl Name {
38 Name::new(idx.to_string().into()) 38 Name::new(idx.to_string().into())
39 } 39 }
40 40
41 // Needed for Deref
42 pub(crate) fn target() -> Name {
43 Name::new("Target".into())
44 }
45
46 // There's should be no way to extract a string out of `Name`: `Name` in the 41 // There's should be no way to extract a string out of `Name`: `Name` in the
47 // future, `Name` will include hygiene information, and you can't encode 42 // future, `Name` will include hygiene information, and you can't encode
48 // hygiene into a String. 43 // hygiene into a String.
@@ -123,6 +118,7 @@ pub(crate) const FUTURE_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6,
123pub(crate) const RESULT_MOD: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"result")); 118pub(crate) const RESULT_MOD: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"result"));
124pub(crate) const RESULT_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Result")); 119pub(crate) const RESULT_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Result"));
125pub(crate) const OUTPUT: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Output")); 120pub(crate) const OUTPUT: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Output"));
121pub(crate) const TARGET: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Target"));
126 122
127fn resolve_name(text: &SmolStr) -> SmolStr { 123fn resolve_name(text: &SmolStr) -> SmolStr {
128 let raw_start = "r#"; 124 let raw_start = "r#";
diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs
index 08f52a53b..caa17f64e 100644
--- a/crates/ra_hir/src/ty/autoderef.rs
+++ b/crates/ra_hir/src/ty/autoderef.rs
@@ -8,7 +8,7 @@ use std::iter::successors;
8use log::{info, warn}; 8use log::{info, warn};
9 9
10use super::{traits::Solution, Canonical, Ty, TypeWalk}; 10use super::{traits::Solution, Canonical, Ty, TypeWalk};
11use crate::{HasGenericParams, HirDatabase, Name, Resolver}; 11use crate::{name, HasGenericParams, HirDatabase, Resolver};
12 12
13const AUTODEREF_RECURSION_LIMIT: usize = 10; 13const AUTODEREF_RECURSION_LIMIT: usize = 10;
14 14
@@ -42,7 +42,7 @@ fn deref_by_trait(
42 crate::lang_item::LangItemTarget::Trait(t) => t, 42 crate::lang_item::LangItemTarget::Trait(t) => t,
43 _ => return None, 43 _ => return None,
44 }; 44 };
45 let target = deref_trait.associated_type_by_name(db, Name::target())?; 45 let target = deref_trait.associated_type_by_name(db, &name::TARGET)?;
46 46
47 if target.generic_params(db).count_params_including_parent() != 1 { 47 if target.generic_params(db).count_params_including_parent() != 1 {
48 // the Target type + Deref trait should only have one generic parameter, 48 // the Target type + Deref trait should only have one generic parameter,
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index ec3b7ffef..0e6ebd365 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -1453,7 +1453,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1453 1453
1454 match self.resolver.resolve_path_segments(self.db, &into_iter_path).into_fully_resolved() { 1454 match self.resolver.resolve_path_segments(self.db, &into_iter_path).into_fully_resolved() {
1455 PerNs { types: Some(Def(Trait(trait_))), .. } => { 1455 PerNs { types: Some(Def(Trait(trait_))), .. } => {
1456 Some(trait_.associated_type_by_name(self.db, name::ITEM)?) 1456 Some(trait_.associated_type_by_name(self.db, &name::ITEM)?)
1457 } 1457 }
1458 _ => None, 1458 _ => None,
1459 } 1459 }
@@ -1471,7 +1471,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1471 1471
1472 match self.resolver.resolve_path_segments(self.db, &ops_try_path).into_fully_resolved() { 1472 match self.resolver.resolve_path_segments(self.db, &ops_try_path).into_fully_resolved() {
1473 PerNs { types: Some(Def(Trait(trait_))), .. } => { 1473 PerNs { types: Some(Def(Trait(trait_))), .. } => {
1474 Some(trait_.associated_type_by_name(self.db, name::OK)?) 1474 Some(trait_.associated_type_by_name(self.db, &name::OK)?)
1475 } 1475 }
1476 _ => None, 1476 _ => None,
1477 } 1477 }
@@ -1493,7 +1493,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1493 .into_fully_resolved() 1493 .into_fully_resolved()
1494 { 1494 {
1495 PerNs { types: Some(Def(Trait(trait_))), .. } => { 1495 PerNs { types: Some(Def(Trait(trait_))), .. } => {
1496 Some(trait_.associated_type_by_name(self.db, name::OUTPUT)?) 1496 Some(trait_.associated_type_by_name(self.db, &name::OUTPUT)?)
1497 } 1497 }
1498 _ => None, 1498 _ => None,
1499 } 1499 }
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index f6f0137cf..480bae740 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -132,14 +132,16 @@ impl Ty {
132 if let Some(remaining_index) = remaining_index { 132 if let Some(remaining_index) = remaining_index {
133 if remaining_index == path.segments.len() - 1 { 133 if remaining_index == path.segments.len() - 1 {
134 let segment = &path.segments[remaining_index]; 134 let segment = &path.segments[remaining_index];
135 let associated_ty = 135 let associated_ty = match trait_ref
136 match trait_ref.trait_.associated_type_by_name(db, segment.name.clone()) { 136 .trait_
137 Some(t) => t, 137 .associated_type_by_name_including_super_traits(db, &segment.name)
138 None => { 138 {
139 // associated type not found 139 Some(t) => t,
140 return Ty::Unknown; 140 None => {
141 } 141 // associated type not found
142 }; 142 return Ty::Unknown;
143 }
144 };
143 // FIXME handle type parameters on the segment 145 // FIXME handle type parameters on the segment
144 Ty::Projection(ProjectionTy { associated_ty, parameters: trait_ref.substs }) 146 Ty::Projection(ProjectionTy { associated_ty, parameters: trait_ref.substs })
145 } else { 147 } else {
@@ -387,10 +389,11 @@ fn assoc_type_bindings_from_type_bound<'a>(
387 .flat_map(|segment| segment.args_and_bindings.iter()) 389 .flat_map(|segment| segment.args_and_bindings.iter())
388 .flat_map(|args_and_bindings| args_and_bindings.bindings.iter()) 390 .flat_map(|args_and_bindings| args_and_bindings.bindings.iter())
389 .map(move |(name, type_ref)| { 391 .map(move |(name, type_ref)| {
390 let associated_ty = match trait_ref.trait_.associated_type_by_name(db, name.clone()) { 392 let associated_ty =
391 None => return GenericPredicate::Error, 393 match trait_ref.trait_.associated_type_by_name_including_super_traits(db, &name) {
392 Some(t) => t, 394 None => return GenericPredicate::Error,
393 }; 395 Some(t) => t,
396 };
394 let projection_ty = 397 let projection_ty =
395 ProjectionTy { associated_ty, parameters: trait_ref.substs.clone() }; 398 ProjectionTy { associated_ty, parameters: trait_ref.substs.clone() };
396 let ty = Ty::from_hir(db, resolver, type_ref); 399 let ty = Ty::from_hir(db, resolver, type_ref);
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index cb5540cb6..17c4e3556 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -3720,11 +3720,11 @@ fn test() {
3720 [157; 160) '{t}': T 3720 [157; 160) '{t}': T
3721 [158; 159) 't': T 3721 [158; 159) 't': T
3722 [259; 280) '{ ...S)); }': () 3722 [259; 280) '{ ...S)); }': ()
3723 [265; 269) 'get2': fn get2<{unknown}, S<{unknown}>>(T) -> U 3723 [265; 269) 'get2': fn get2<u64, S<u64>>(T) -> U
3724 [265; 277) 'get2(set(S))': {unknown} 3724 [265; 277) 'get2(set(S))': u64
3725 [270; 273) 'set': fn set<S<{unknown}>>(T) -> T 3725 [270; 273) 'set': fn set<S<u64>>(T) -> T
3726 [270; 276) 'set(S)': S<{unknown}> 3726 [270; 276) 'set(S)': S<u64>
3727 [274; 275) 'S': S<{unknown}> 3727 [274; 275) 'S': S<u64>
3728 "### 3728 "###
3729 ); 3729 );
3730} 3730}
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index c201c5e50..cfe0cab16 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -636,7 +636,7 @@ pub(crate) fn impl_datum_query(
636 _ => None, 636 _ => None,
637 }) 637 })
638 .filter_map(|t| { 638 .filter_map(|t| {
639 let assoc_ty = trait_.associated_type_by_name(db, t.name(db))?; 639 let assoc_ty = trait_.associated_type_by_name(db, &t.name(db))?;
640 let ty = db.type_for_def(t.into(), crate::Namespace::Types).subst(&bound_vars); 640 let ty = db.type_for_def(t.into(), crate::Namespace::Types).subst(&bound_vars);
641 Some(chalk_rust_ir::AssociatedTyValue { 641 Some(chalk_rust_ir::AssociatedTyValue {
642 impl_id, 642 impl_id,
diff --git a/crates/ra_hir/src/type_ref.rs b/crates/ra_hir/src/type_ref.rs
index fa91bfb22..bc8acc7ee 100644
--- a/crates/ra_hir/src/type_ref.rs
+++ b/crates/ra_hir/src/type_ref.rs
@@ -150,4 +150,11 @@ impl TypeBound {
150 ast::TypeBoundKind::ForType(_) | ast::TypeBoundKind::Lifetime(_) => TypeBound::Error, 150 ast::TypeBoundKind::ForType(_) | ast::TypeBoundKind::Lifetime(_) => TypeBound::Error,
151 } 151 }
152 } 152 }
153
154 pub fn as_path(&self) -> Option<&Path> {
155 match self {
156 TypeBound::Path(p) => Some(p),
157 _ => None,
158 }
159 }
153} 160}