diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-09-07 16:47:56 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2019-09-07 16:47:56 +0100 |
commit | 4a89a7c9026dc3df4466f7b10c666186830d38f6 (patch) | |
tree | fdf832ba772141368f27d733cd718ee9a599a346 /crates/ra_hir/src | |
parent | a73b424e3bcf3e211f87d5a9b175a89231848c6d (diff) | |
parent | 8fb3cab76c60fbff5ae6f5984ac07b09b42b742c (diff) |
Merge #1786
1786: Various minor trait improvements r=matklad a=flodiebold
- lower bounds on trait definition, i.e. super traits
- use super traits for associated types
- use traits from where clauses and their super traits for method resolution
- lower fn-like paths (i.e. `Fn(X, Y) -> Z`)
- pass the environment to Chalk in the correct way to make elaboration work, i.e. inferring things like `T: Clone` from `T: Copy`. The clauses need to be wrapped in `FromEnv` clauses for that to work, which I didn't do before.
- add some tests for closure inference already
Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 57 | ||||
-rw-r--r-- | crates/ra_hir/src/generics.rs | 22 | ||||
-rw-r--r-- | crates/ra_hir/src/name.rs | 6 | ||||
-rw-r--r-- | crates/ra_hir/src/path.rs | 44 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/autoderef.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 6 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 27 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 8 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 225 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits.rs | 15 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits/chalk.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir/src/type_ref.rs | 7 |
12 files changed, 387 insertions, 39 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index f7efc1b66..1bb2f9f28 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -820,7 +820,52 @@ impl Trait { | |||
820 | self.trait_data(db).items().to_vec() | 820 | self.trait_data(db).items().to_vec() |
821 | } | 821 | } |
822 | 822 | ||
823 | pub fn associated_type_by_name(self, db: &impl DefDatabase, name: Name) -> Option<TypeAlias> { | 823 | fn direct_super_traits(self, db: &impl HirDatabase) -> Vec<Trait> { |
824 | let resolver = self.resolver(db); | ||
825 | // returning the iterator directly doesn't easily work because of | ||
826 | // lifetime problems, but since there usually shouldn't be more than a | ||
827 | // few direct traits this should be fine (we could even use some kind of | ||
828 | // SmallVec if performance is a concern) | ||
829 | self.generic_params(db) | ||
830 | .where_predicates | ||
831 | .iter() | ||
832 | .filter_map(|pred| match &pred.type_ref { | ||
833 | TypeRef::Path(p) if p.as_ident() == Some(&crate::name::SELF_TYPE) => { | ||
834 | pred.bound.as_path() | ||
835 | } | ||
836 | _ => None, | ||
837 | }) | ||
838 | .filter_map(|path| { | ||
839 | match resolver.resolve_path_without_assoc_items(db, path).take_types() { | ||
840 | Some(crate::Resolution::Def(ModuleDef::Trait(t))) => Some(t), | ||
841 | _ => None, | ||
842 | } | ||
843 | }) | ||
844 | .collect() | ||
845 | } | ||
846 | |||
847 | /// Returns an iterator over the whole super trait hierarchy (including the | ||
848 | /// trait itself). | ||
849 | pub fn all_super_traits(self, db: &impl HirDatabase) -> Vec<Trait> { | ||
850 | // we need to take care a bit here to avoid infinite loops in case of cycles | ||
851 | // (i.e. if we have `trait A: B; trait B: A;`) | ||
852 | let mut result = vec![self]; | ||
853 | let mut i = 0; | ||
854 | while i < result.len() { | ||
855 | let t = result[i]; | ||
856 | // yeah this is quadratic, but trait hierarchies should be flat | ||
857 | // enough that this doesn't matter | ||
858 | for tt in t.direct_super_traits(db) { | ||
859 | if !result.contains(&tt) { | ||
860 | result.push(tt); | ||
861 | } | ||
862 | } | ||
863 | i += 1; | ||
864 | } | ||
865 | result | ||
866 | } | ||
867 | |||
868 | pub fn associated_type_by_name(self, db: &impl DefDatabase, name: &Name) -> Option<TypeAlias> { | ||
824 | let trait_data = self.trait_data(db); | 869 | let trait_data = self.trait_data(db); |
825 | trait_data | 870 | trait_data |
826 | .items() | 871 | .items() |
@@ -829,7 +874,15 @@ impl Trait { | |||
829 | TraitItem::TypeAlias(t) => Some(*t), | 874 | TraitItem::TypeAlias(t) => Some(*t), |
830 | _ => None, | 875 | _ => None, |
831 | }) | 876 | }) |
832 | .find(|t| t.name(db) == name) | 877 | .find(|t| &t.name(db) == name) |
878 | } | ||
879 | |||
880 | pub fn associated_type_by_name_including_super_traits( | ||
881 | self, | ||
882 | db: &impl HirDatabase, | ||
883 | name: &Name, | ||
884 | ) -> Option<TypeAlias> { | ||
885 | self.all_super_traits(db).into_iter().find_map(|t| t.associated_type_by_name(db, name)) | ||
833 | } | 886 | } |
834 | 887 | ||
835 | 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/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, | |||
123 | pub(crate) const RESULT_MOD: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"result")); | 118 | pub(crate) const RESULT_MOD: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"result")); |
124 | pub(crate) const RESULT_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Result")); | 119 | pub(crate) const RESULT_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Result")); |
125 | pub(crate) const OUTPUT: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Output")); | 120 | pub(crate) const OUTPUT: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Output")); |
121 | pub(crate) const TARGET: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Target")); | ||
126 | 122 | ||
127 | fn resolve_name(text: &SmolStr) -> SmolStr { | 123 | fn resolve_name(text: &SmolStr) -> SmolStr { |
128 | let raw_start = "r#"; | 124 | let raw_start = "r#"; |
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index 24316fc91..d6c78593b 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs | |||
@@ -1,11 +1,11 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | ast::{self, NameOwner}, | 4 | ast::{self, NameOwner, TypeAscriptionOwner}, |
5 | AstNode, | 5 | AstNode, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | use crate::{type_ref::TypeRef, AsName, Name}; | 8 | use crate::{name, type_ref::TypeRef, AsName, Name}; |
9 | 9 | ||
10 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 10 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
11 | pub struct Path { | 11 | pub struct Path { |
@@ -76,8 +76,16 @@ impl Path { | |||
76 | 76 | ||
77 | match segment.kind()? { | 77 | match segment.kind()? { |
78 | ast::PathSegmentKind::Name(name) => { | 78 | ast::PathSegmentKind::Name(name) => { |
79 | let args = | 79 | let args = segment |
80 | segment.type_arg_list().and_then(GenericArgs::from_ast).map(Arc::new); | 80 | .type_arg_list() |
81 | .and_then(GenericArgs::from_ast) | ||
82 | .or_else(|| { | ||
83 | GenericArgs::from_fn_like_path_ast( | ||
84 | segment.param_list(), | ||
85 | segment.ret_type(), | ||
86 | ) | ||
87 | }) | ||
88 | .map(Arc::new); | ||
81 | let segment = PathSegment { name: name.as_name(), args_and_bindings: args }; | 89 | let segment = PathSegment { name: name.as_name(), args_and_bindings: args }; |
82 | segments.push(segment); | 90 | segments.push(segment); |
83 | } | 91 | } |
@@ -187,6 +195,34 @@ impl GenericArgs { | |||
187 | } | 195 | } |
188 | } | 196 | } |
189 | 197 | ||
198 | /// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y) | ||
199 | /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`). | ||
200 | pub(crate) fn from_fn_like_path_ast( | ||
201 | params: Option<ast::ParamList>, | ||
202 | ret_type: Option<ast::RetType>, | ||
203 | ) -> Option<GenericArgs> { | ||
204 | let mut args = Vec::new(); | ||
205 | let mut bindings = Vec::new(); | ||
206 | if let Some(params) = params { | ||
207 | let mut param_types = Vec::new(); | ||
208 | for param in params.params() { | ||
209 | let type_ref = TypeRef::from_ast_opt(param.ascribed_type()); | ||
210 | param_types.push(type_ref); | ||
211 | } | ||
212 | let arg = GenericArg::Type(TypeRef::Tuple(param_types)); | ||
213 | args.push(arg); | ||
214 | } | ||
215 | if let Some(ret_type) = ret_type { | ||
216 | let type_ref = TypeRef::from_ast_opt(ret_type.type_ref()); | ||
217 | bindings.push((name::OUTPUT, type_ref)) | ||
218 | } | ||
219 | if args.is_empty() && bindings.is_empty() { | ||
220 | None | ||
221 | } else { | ||
222 | Some(GenericArgs { args, has_self_type: false, bindings }) | ||
223 | } | ||
224 | } | ||
225 | |||
190 | pub(crate) fn empty() -> GenericArgs { | 226 | pub(crate) fn empty() -> GenericArgs { |
191 | GenericArgs { args: Vec::new(), has_self_type: false, bindings: Vec::new() } | 227 | GenericArgs { args: Vec::new(), has_self_type: false, bindings: Vec::new() } |
192 | } | 228 | } |
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; | |||
8 | use log::{info, warn}; | 8 | use log::{info, warn}; |
9 | 9 | ||
10 | use super::{traits::Solution, Canonical, Ty, TypeWalk}; | 10 | use super::{traits::Solution, Canonical, Ty, TypeWalk}; |
11 | use crate::{HasGenericParams, HirDatabase, Name, Resolver}; | 11 | use crate::{name, HasGenericParams, HirDatabase, Resolver}; |
12 | 12 | ||
13 | const AUTODEREF_RECURSION_LIMIT: usize = 10; | 13 | const 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/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index 9873a0440..cf787bdaa 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -212,7 +212,13 @@ fn iterate_trait_method_candidates<T>( | |||
212 | // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that) | 212 | // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that) |
213 | let env = lower::trait_env(db, resolver); | 213 | let env = lower::trait_env(db, resolver); |
214 | // if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope | 214 | // if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope |
215 | let traits = ty.value.inherent_trait().into_iter().chain(resolver.traits_in_scope(db)); | 215 | let inherent_trait = ty.value.inherent_trait().into_iter(); |
216 | // if we have `T: Trait` in the param env, the trait doesn't need to be in scope | ||
217 | let traits_from_env = env | ||
218 | .trait_predicates_for_self_ty(&ty.value) | ||
219 | .map(|tr| tr.trait_) | ||
220 | .flat_map(|t| t.all_super_traits(db)); | ||
221 | let traits = inherent_trait.chain(traits_from_env).chain(resolver.traits_in_scope(db)); | ||
216 | 'traits: for t in traits { | 222 | 'traits: for t in traits { |
217 | let data = t.trait_data(db); | 223 | let data = t.trait_data(db); |
218 | 224 | ||
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index d92d4659b..c4bddde85 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -3643,6 +3643,231 @@ fn test<T: Trait1<Type = u32>>(x: T) { | |||
3643 | "### | 3643 | "### |
3644 | ); | 3644 | ); |
3645 | } | 3645 | } |
3646 | |||
3647 | #[test] | ||
3648 | fn where_clause_trait_in_scope_for_method_resolution() { | ||
3649 | let t = type_at( | ||
3650 | r#" | ||
3651 | //- /main.rs | ||
3652 | mod foo { | ||
3653 | trait Trait { | ||
3654 | fn foo(&self) -> u32 {} | ||
3655 | } | ||
3656 | } | ||
3657 | |||
3658 | fn test<T: foo::Trait>(x: T) { | ||
3659 | x.foo()<|>; | ||
3660 | } | ||
3661 | "#, | ||
3662 | ); | ||
3663 | assert_eq!(t, "u32"); | ||
3664 | } | ||
3665 | |||
3666 | #[test] | ||
3667 | fn super_trait_method_resolution() { | ||
3668 | assert_snapshot!( | ||
3669 | infer(r#" | ||
3670 | mod foo { | ||
3671 | trait SuperTrait { | ||
3672 | fn foo(&self) -> u32 {} | ||
3673 | } | ||
3674 | } | ||
3675 | trait Trait1: foo::SuperTrait {} | ||
3676 | trait Trait2 where Self: foo::SuperTrait {} | ||
3677 | |||
3678 | fn test<T: Trait1, U: Trait2>(x: T, y: U) { | ||
3679 | x.foo(); | ||
3680 | y.foo(); | ||
3681 | } | ||
3682 | "#), | ||
3683 | @r###" | ||
3684 | [50; 54) 'self': &Self | ||
3685 | [63; 65) '{}': () | ||
3686 | [182; 183) 'x': T | ||
3687 | [188; 189) 'y': U | ||
3688 | [194; 223) '{ ...o(); }': () | ||
3689 | [200; 201) 'x': T | ||
3690 | [200; 207) 'x.foo()': u32 | ||
3691 | [213; 214) 'y': U | ||
3692 | [213; 220) 'y.foo()': u32 | ||
3693 | "### | ||
3694 | ); | ||
3695 | } | ||
3696 | |||
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] | ||
3719 | fn super_trait_assoc_type_bounds() { | ||
3720 | assert_snapshot!( | ||
3721 | infer(r#" | ||
3722 | trait SuperTrait { type Type; } | ||
3723 | trait Trait where Self: SuperTrait {} | ||
3724 | |||
3725 | fn get2<U, T: Trait<Type = U>>(t: T) -> U {} | ||
3726 | fn set<T: Trait<Type = u64>>(t: T) -> T {t} | ||
3727 | |||
3728 | struct S<T>; | ||
3729 | impl<T> SuperTrait for S<T> { type Type = T; } | ||
3730 | impl<T> Trait for S<T> {} | ||
3731 | |||
3732 | fn test() { | ||
3733 | get2(set(S)); | ||
3734 | } | ||
3735 | "#), | ||
3736 | @r###" | ||
3737 | [103; 104) 't': T | ||
3738 | [114; 116) '{}': () | ||
3739 | [146; 147) 't': T | ||
3740 | [157; 160) '{t}': T | ||
3741 | [158; 159) 't': T | ||
3742 | [259; 280) '{ ...S)); }': () | ||
3743 | [265; 269) 'get2': fn get2<u64, S<u64>>(T) -> U | ||
3744 | [265; 277) 'get2(set(S))': u64 | ||
3745 | [270; 273) 'set': fn set<S<u64>>(T) -> T | ||
3746 | [270; 276) 'set(S)': S<u64> | ||
3747 | [274; 275) 'S': S<u64> | ||
3748 | "### | ||
3749 | ); | ||
3750 | } | ||
3751 | |||
3752 | #[test] | ||
3753 | fn fn_trait() { | ||
3754 | assert_snapshot!( | ||
3755 | infer(r#" | ||
3756 | trait FnOnce<Args> { | ||
3757 | type Output; | ||
3758 | |||
3759 | fn call_once(self, args: Args) -> <Self as FnOnce<Args>>::Output; | ||
3760 | } | ||
3761 | |||
3762 | fn test<F: FnOnce(u32, u64) -> u128>(f: F) { | ||
3763 | f.call_once((1, 2)); | ||
3764 | } | ||
3765 | "#), | ||
3766 | @r###" | ||
3767 | [57; 61) 'self': Self | ||
3768 | [63; 67) 'args': Args | ||
3769 | [150; 151) 'f': F | ||
3770 | [156; 184) '{ ...2)); }': () | ||
3771 | [162; 163) 'f': F | ||
3772 | [162; 181) 'f.call...1, 2))': {unknown} | ||
3773 | [174; 180) '(1, 2)': (u32, u64) | ||
3774 | [175; 176) '1': u32 | ||
3775 | [178; 179) '2': u64 | ||
3776 | "### | ||
3777 | ); | ||
3778 | } | ||
3779 | |||
3780 | #[test] | ||
3781 | fn closure_1() { | ||
3782 | assert_snapshot!( | ||
3783 | infer(r#" | ||
3784 | trait FnOnce<Args> { | ||
3785 | type Output; | ||
3786 | } | ||
3787 | |||
3788 | enum Option<T> { Some(T), None } | ||
3789 | impl<T> Option<T> { | ||
3790 | fn map<U, F: FnOnce(T) -> U>(self, f: F) -> U {} | ||
3791 | } | ||
3792 | |||
3793 | fn test() { | ||
3794 | let x = Option::Some(1i32); | ||
3795 | x.map(|v| v + 1); | ||
3796 | x.map(|_v| 1u64); | ||
3797 | let y: Option<i64> = x.map(|_v| 1); | ||
3798 | } | ||
3799 | "#), | ||
3800 | @r###" | ||
3801 | [128; 132) 'self': Option<T> | ||
3802 | [134; 135) 'f': F | ||
3803 | [145; 147) '{}': () | ||
3804 | [161; 280) '{ ... 1); }': () | ||
3805 | [171; 172) 'x': Option<i32> | ||
3806 | [175; 187) 'Option::Some': Some<i32>(T) -> Option<T> | ||
3807 | [175; 193) 'Option...(1i32)': Option<i32> | ||
3808 | [188; 192) '1i32': i32 | ||
3809 | [199; 200) 'x': Option<i32> | ||
3810 | [199; 215) 'x.map(...v + 1)': {unknown} | ||
3811 | [205; 214) '|v| v + 1': {unknown} | ||
3812 | [206; 207) 'v': {unknown} | ||
3813 | [209; 210) 'v': {unknown} | ||
3814 | [209; 214) 'v + 1': i32 | ||
3815 | [213; 214) '1': i32 | ||
3816 | [221; 222) 'x': Option<i32> | ||
3817 | [221; 237) 'x.map(... 1u64)': {unknown} | ||
3818 | [227; 236) '|_v| 1u64': {unknown} | ||
3819 | [228; 230) '_v': {unknown} | ||
3820 | [232; 236) '1u64': u64 | ||
3821 | [247; 248) 'y': Option<i64> | ||
3822 | [264; 265) 'x': Option<i32> | ||
3823 | [264; 277) 'x.map(|_v| 1)': Option<i64> | ||
3824 | [270; 276) '|_v| 1': {unknown} | ||
3825 | [271; 273) '_v': {unknown} | ||
3826 | [275; 276) '1': i32 | ||
3827 | "### | ||
3828 | ); | ||
3829 | } | ||
3830 | |||
3831 | #[test] | ||
3832 | fn closure_2() { | ||
3833 | assert_snapshot!( | ||
3834 | infer(r#" | ||
3835 | trait FnOnce<Args> { | ||
3836 | type Output; | ||
3837 | } | ||
3838 | |||
3839 | fn test<F: FnOnce(u32) -> u64>(f: F) { | ||
3840 | f(1); | ||
3841 | let g = |v| v + 1; | ||
3842 | g(1u64); | ||
3843 | let h = |v| 1u128 + v; | ||
3844 | } | ||
3845 | "#), | ||
3846 | @r###" | ||
3847 | [73; 74) 'f': F | ||
3848 | [79; 155) '{ ...+ v; }': () | ||
3849 | [85; 86) 'f': F | ||
3850 | [85; 89) 'f(1)': {unknown} | ||
3851 | [87; 88) '1': i32 | ||
3852 | [99; 100) 'g': {unknown} | ||
3853 | [103; 112) '|v| v + 1': {unknown} | ||
3854 | [104; 105) 'v': {unknown} | ||
3855 | [107; 108) 'v': {unknown} | ||
3856 | [107; 112) 'v + 1': i32 | ||
3857 | [111; 112) '1': i32 | ||
3858 | [118; 119) 'g': {unknown} | ||
3859 | [118; 125) 'g(1u64)': {unknown} | ||
3860 | [120; 124) '1u64': u64 | ||
3861 | [135; 136) 'h': {unknown} | ||
3862 | [139; 152) '|v| 1u128 + v': {unknown} | ||
3863 | [140; 141) 'v': u128 | ||
3864 | [143; 148) '1u128': u128 | ||
3865 | [143; 152) '1u128 + v': u128 | ||
3866 | [151; 152) 'v': u128 | ||
3867 | "### | ||
3868 | ); | ||
3869 | } | ||
3870 | |||
3646 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { | 3871 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { |
3647 | let file = db.parse(pos.file_id).ok().unwrap(); | 3872 | let file = db.parse(pos.file_id).ok().unwrap(); |
3648 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); | 3873 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); |
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs index 6e0271a96..c0c132809 100644 --- a/crates/ra_hir/src/ty/traits.rs +++ b/crates/ra_hir/src/ty/traits.rs | |||
@@ -96,6 +96,21 @@ pub struct TraitEnvironment { | |||
96 | pub predicates: Vec<GenericPredicate>, | 96 | pub predicates: Vec<GenericPredicate>, |
97 | } | 97 | } |
98 | 98 | ||
99 | impl TraitEnvironment { | ||
100 | /// Returns trait refs with the given self type which are supposed to hold | ||
101 | /// in this trait env. E.g. if we are in `foo<T: SomeTrait>()`, this will | ||
102 | /// find that `T: SomeTrait` if we call it for `T`. | ||
103 | pub(crate) fn trait_predicates_for_self_ty<'a>( | ||
104 | &'a self, | ||
105 | ty: &'a Ty, | ||
106 | ) -> impl Iterator<Item = &'a TraitRef> + 'a { | ||
107 | self.predicates.iter().filter_map(move |pred| match pred { | ||
108 | GenericPredicate::Implemented(tr) if tr.self_ty() == ty => Some(tr), | ||
109 | _ => None, | ||
110 | }) | ||
111 | } | ||
112 | } | ||
113 | |||
99 | /// Something (usually a goal), along with an environment. | 114 | /// Something (usually a goal), along with an environment. |
100 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] | 115 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] |
101 | pub struct InEnvironment<T> { | 116 | pub struct InEnvironment<T> { |
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index c201c5e50..8a127efa1 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs | |||
@@ -314,7 +314,8 @@ impl ToChalk for Arc<super::TraitEnvironment> { | |||
314 | // for env, we just ignore errors | 314 | // for env, we just ignore errors |
315 | continue; | 315 | continue; |
316 | } | 316 | } |
317 | clauses.push(pred.clone().to_chalk(db).cast()); | 317 | let program_clause: chalk_ir::ProgramClause = pred.clone().to_chalk(db).cast(); |
318 | clauses.push(program_clause.into_from_env_clause()); | ||
318 | } | 319 | } |
319 | chalk_ir::Environment::new().add_clauses(clauses) | 320 | chalk_ir::Environment::new().add_clauses(clauses) |
320 | } | 321 | } |
@@ -636,7 +637,7 @@ pub(crate) fn impl_datum_query( | |||
636 | _ => None, | 637 | _ => None, |
637 | }) | 638 | }) |
638 | .filter_map(|t| { | 639 | .filter_map(|t| { |
639 | let assoc_ty = trait_.associated_type_by_name(db, t.name(db))?; | 640 | 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); | 641 | let ty = db.type_for_def(t.into(), crate::Namespace::Types).subst(&bound_vars); |
641 | Some(chalk_rust_ir::AssociatedTyValue { | 642 | Some(chalk_rust_ir::AssociatedTyValue { |
642 | impl_id, | 643 | 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 | } |