aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-09-07 16:47:56 +0100
committerGitHub <[email protected]>2019-09-07 16:47:56 +0100
commit4a89a7c9026dc3df4466f7b10c666186830d38f6 (patch)
treefdf832ba772141368f27d733cd718ee9a599a346 /crates/ra_hir
parenta73b424e3bcf3e211f87d5a9b175a89231848c6d (diff)
parent8fb3cab76c60fbff5ae6f5984ac07b09b42b742c (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')
-rw-r--r--crates/ra_hir/src/code_model.rs57
-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/path.rs44
-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/method_resolution.rs8
-rw-r--r--crates/ra_hir/src/ty/tests.rs225
-rw-r--r--crates/ra_hir/src/ty/traits.rs15
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs5
-rw-r--r--crates/ra_hir/src/type_ref.rs7
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,
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/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 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_syntax::{ 3use ra_syntax::{
4 ast::{self, NameOwner}, 4 ast::{self, NameOwner, TypeAscriptionOwner},
5 AstNode, 5 AstNode,
6}; 6};
7 7
8use crate::{type_ref::TypeRef, AsName, Name}; 8use crate::{name, type_ref::TypeRef, AsName, Name};
9 9
10#[derive(Debug, Clone, PartialEq, Eq, Hash)] 10#[derive(Debug, Clone, PartialEq, Eq, Hash)]
11pub struct Path { 11pub 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;
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/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]
3648fn where_clause_trait_in_scope_for_method_resolution() {
3649 let t = type_at(
3650 r#"
3651//- /main.rs
3652mod foo {
3653 trait Trait {
3654 fn foo(&self) -> u32 {}
3655 }
3656}
3657
3658fn test<T: foo::Trait>(x: T) {
3659 x.foo()<|>;
3660}
3661"#,
3662 );
3663 assert_eq!(t, "u32");
3664}
3665
3666#[test]
3667fn super_trait_method_resolution() {
3668 assert_snapshot!(
3669 infer(r#"
3670mod foo {
3671 trait SuperTrait {
3672 fn foo(&self) -> u32 {}
3673 }
3674}
3675trait Trait1: foo::SuperTrait {}
3676trait Trait2 where Self: foo::SuperTrait {}
3677
3678fn 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]
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]
3719fn super_trait_assoc_type_bounds() {
3720 assert_snapshot!(
3721 infer(r#"
3722trait SuperTrait { type Type; }
3723trait Trait where Self: SuperTrait {}
3724
3725fn get2<U, T: Trait<Type = U>>(t: T) -> U {}
3726fn set<T: Trait<Type = u64>>(t: T) -> T {t}
3727
3728struct S<T>;
3729impl<T> SuperTrait for S<T> { type Type = T; }
3730impl<T> Trait for S<T> {}
3731
3732fn 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]
3753fn fn_trait() {
3754 assert_snapshot!(
3755 infer(r#"
3756trait FnOnce<Args> {
3757 type Output;
3758
3759 fn call_once(self, args: Args) -> <Self as FnOnce<Args>>::Output;
3760}
3761
3762fn 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]
3781fn closure_1() {
3782 assert_snapshot!(
3783 infer(r#"
3784trait FnOnce<Args> {
3785 type Output;
3786}
3787
3788enum Option<T> { Some(T), None }
3789impl<T> Option<T> {
3790 fn map<U, F: FnOnce(T) -> U>(self, f: F) -> U {}
3791}
3792
3793fn 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]
3832fn closure_2() {
3833 assert_snapshot!(
3834 infer(r#"
3835trait FnOnce<Args> {
3836 type Output;
3837}
3838
3839fn 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
3646fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { 3871fn 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
99impl 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)]
101pub struct InEnvironment<T> { 116pub 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}