aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-10-29 10:04:42 +0000
committerFlorian Diebold <[email protected]>2019-11-01 18:57:08 +0000
commitb634ba41e0439cbbb89b12a3d340c8463b35b93e (patch)
tree4e4b08e6ca6a89714d372d37bdc578393219d8b6 /crates/ra_hir/src/ty
parented5212e1ac71e959d802a9a7ad28d06c8b18e022 (diff)
Get trait assoc item resolution mostly working
Diffstat (limited to 'crates/ra_hir/src/ty')
-rw-r--r--crates/ra_hir/src/ty/infer/path.rs106
-rw-r--r--crates/ra_hir/src/ty/tests.rs153
2 files changed, 248 insertions, 11 deletions
diff --git a/crates/ra_hir/src/ty/infer/path.rs b/crates/ra_hir/src/ty/infer/path.rs
index 77aa35ce1..885588174 100644
--- a/crates/ra_hir/src/ty/infer/path.rs
+++ b/crates/ra_hir/src/ty/infer/path.rs
@@ -6,9 +6,11 @@ use super::{ExprOrPatId, InferenceContext, TraitRef};
6use crate::{ 6use crate::{
7 db::HirDatabase, 7 db::HirDatabase,
8 resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs}, 8 resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs},
9 ty::{lower, traits::TraitEnvironment, Canonical},
9 ty::{Substs, Ty, TypableDef, TypeWalk}, 10 ty::{Substs, Ty, TypableDef, TypeWalk},
10 AssocItem, HasGenericParams, Namespace, Path, 11 AssocItem, HasGenericParams, Name, Namespace, Path, Trait,
11}; 12};
13use std::sync::Arc;
12 14
13impl<'a, D: HirDatabase> InferenceContext<'a, D> { 15impl<'a, D: HirDatabase> InferenceContext<'a, D> {
14 pub(super) fn infer_path( 16 pub(super) fn infer_path(
@@ -39,7 +41,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
39 let ty = Ty::from_type_relative_path(self.db, resolver, ty, remaining_segments_for_ty); 41 let ty = Ty::from_type_relative_path(self.db, resolver, ty, remaining_segments_for_ty);
40 self.resolve_ty_assoc_item( 42 self.resolve_ty_assoc_item(
41 ty, 43 ty,
42 path.segments.last().expect("path had at least one segment"), 44 &path.segments.last().expect("path had at least one segment").name,
43 id, 45 id,
44 )? 46 )?
45 } else { 47 } else {
@@ -125,7 +127,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
125 let segment = 127 let segment =
126 remaining_segments.last().expect("there should be at least one segment here"); 128 remaining_segments.last().expect("there should be at least one segment here");
127 129
128 self.resolve_ty_assoc_item(ty, segment, id) 130 self.resolve_ty_assoc_item(ty, &segment.name, id)
129 } 131 }
130 } 132 }
131 } 133 }
@@ -162,7 +164,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
162 }; 164 };
163 let substs = Substs::build_for_def(self.db, item) 165 let substs = Substs::build_for_def(self.db, item)
164 .use_parent_substs(&trait_ref.substs) 166 .use_parent_substs(&trait_ref.substs)
165 .fill_with_unknown() 167 .fill_with_params()
166 .build(); 168 .build();
167 169
168 self.write_assoc_resolution(id, item); 170 self.write_assoc_resolution(id, item);
@@ -172,20 +174,29 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
172 fn resolve_ty_assoc_item( 174 fn resolve_ty_assoc_item(
173 &mut self, 175 &mut self,
174 ty: Ty, 176 ty: Ty,
175 segment: &PathSegment, 177 name: &Name,
176 id: ExprOrPatId, 178 id: ExprOrPatId,
177 ) -> Option<(ValueNs, Option<Substs>)> { 179 ) -> Option<(ValueNs, Option<Substs>)> {
178 if let Ty::Unknown = ty { 180 if let Ty::Unknown = ty {
179 return None; 181 return None;
180 } 182 }
181 183
184 self.find_inherent_assoc_candidate(ty.clone(), name, id)
185 .or_else(|| self.find_trait_assoc_candidate(ty.clone(), name, id))
186 }
187
188 fn find_inherent_assoc_candidate(
189 &mut self,
190 ty: Ty,
191 name: &Name,
192 id: ExprOrPatId,
193 ) -> Option<(ValueNs, Option<Substs>)> {
182 let krate = self.resolver.krate()?; 194 let krate = self.resolver.krate()?;
183 195
184 // Find impl 196 // Find impl
185 // FIXME: consider trait candidates
186 let item = ty.clone().iterate_impl_items(self.db, krate, |item| match item { 197 let item = ty.clone().iterate_impl_items(self.db, krate, |item| match item {
187 AssocItem::Function(func) => { 198 AssocItem::Function(func) => {
188 if segment.name == func.name(self.db) { 199 if *name == func.name(self.db) {
189 Some(AssocItem::Function(func)) 200 Some(AssocItem::Function(func))
190 } else { 201 } else {
191 None 202 None
@@ -193,7 +204,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
193 } 204 }
194 205
195 AssocItem::Const(konst) => { 206 AssocItem::Const(konst) => {
196 if konst.name(self.db).map_or(false, |n| n == segment.name) { 207 if konst.name(self.db).map_or(false, |n| n == *name) {
197 Some(AssocItem::Const(konst)) 208 Some(AssocItem::Const(konst))
198 } else { 209 } else {
199 None 210 None
@@ -212,6 +223,65 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
212 Some((def, substs)) 223 Some((def, substs))
213 } 224 }
214 225
226 fn find_trait_assoc_candidate(
227 &mut self,
228 ty: Ty,
229 name: &Name,
230 _id: ExprOrPatId,
231 ) -> Option<(ValueNs, Option<Substs>)> {
232 let krate = self.resolver.krate()?;
233
234 let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone());
235
236 let env = lower::trait_env(self.db, &self.resolver);
237 // if we have `T: Trait` in the param env, the trait doesn't need to be in scope
238 let traits_from_env = env
239 .trait_predicates_for_self_ty(&ty)
240 .map(|tr| tr.trait_)
241 .flat_map(|t| t.all_super_traits(self.db));
242 let traits = traits_from_env.chain(self.resolver.traits_in_scope(self.db));
243
244 'traits: for t in traits {
245 let data = t.trait_data(self.db);
246 let mut known_implemented = false;
247 for item in data.items() {
248 if let AssocItem::Function(f) = *item {
249 if f.name(self.db) == *name {
250 if !known_implemented {
251 let goal = generic_implements_goal(
252 self.db,
253 env.clone(),
254 t,
255 canonical_ty.value.clone(),
256 );
257 if self.db.trait_solve(krate, goal).is_none() {
258 continue 'traits;
259 }
260 }
261 known_implemented = true;
262
263 // we're picking this method
264 let trait_substs = Substs::build_for_def(self.db, t)
265 .push(ty.clone())
266 .fill(std::iter::repeat_with(|| self.new_type_var()))
267 .build();
268 let substs = Substs::build_for_def(self.db, f)
269 .use_parent_substs(&trait_substs)
270 .fill_with_params()
271 .build();
272 self.obligations.push(super::Obligation::Trait(TraitRef {
273 trait_: t,
274 substs: trait_substs,
275 }));
276 return Some((ValueNs::Function(f), Some(substs)));
277 }
278 }
279 }
280 }
281
282 None
283 }
284
215 fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> { 285 fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> {
216 if let ValueNs::Function(func) = def { 286 if let ValueNs::Function(func) = def {
217 // We only do the infer if parent has generic params 287 // We only do the infer if parent has generic params
@@ -242,3 +312,23 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
242 } 312 }
243 } 313 }
244} 314}
315
316// TODO remove duplication
317/// This creates Substs for a trait with the given Self type and type variables
318/// for all other parameters, to query Chalk with it.
319fn generic_implements_goal(
320 db: &impl HirDatabase,
321 env: Arc<TraitEnvironment>,
322 trait_: Trait,
323 self_ty: Canonical<Ty>,
324) -> Canonical<super::InEnvironment<super::Obligation>> {
325 let num_vars = self_ty.num_vars;
326 let substs = super::Substs::build_for_def(db, trait_)
327 .push(self_ty.value)
328 .fill_with_bound_vars(num_vars as u32)
329 .build();
330 let num_vars = substs.len() - 1 + self_ty.num_vars;
331 let trait_ref = TraitRef { trait_, substs };
332 let obligation = super::Obligation::Trait(trait_ref);
333 Canonical { num_vars, value: super::InEnvironment::new(env, obligation) }
334}
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index c12326643..7183b205c 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -2782,9 +2782,9 @@ fn test() {
2782 [97; 99) 's1': S 2782 [97; 99) 's1': S
2783 [105; 121) 'Defaul...efault': fn default<S>() -> Self 2783 [105; 121) 'Defaul...efault': fn default<S>() -> Self
2784 [105; 123) 'Defaul...ault()': S 2784 [105; 123) 'Defaul...ault()': S
2785 [133; 135) 's2': {unknown} 2785 [133; 135) 's2': S
2786 [138; 148) 'S::default': {unknown} 2786 [138; 148) 'S::default': fn default<S>() -> Self
2787 [138; 150) 'S::default()': {unknown} 2787 [138; 150) 'S::default()': S
2788 [160; 162) 's3': S 2788 [160; 162) 's3': S
2789 [165; 188) '<S as ...efault': fn default<S>() -> Self 2789 [165; 188) '<S as ...efault': fn default<S>() -> Self
2790 [165; 190) '<S as ...ault()': S 2790 [165; 190) '<S as ...ault()': S
@@ -2793,6 +2793,153 @@ fn test() {
2793} 2793}
2794 2794
2795#[test] 2795#[test]
2796fn infer_trait_assoc_method_generics_1() {
2797 assert_snapshot!(
2798 infer(r#"
2799trait Trait<T> {
2800 fn make() -> T;
2801}
2802struct S;
2803impl Trait<u32> for S {}
2804struct G<T>;
2805impl<T> Trait<T> for G<T> {}
2806fn test() {
2807 let a = S::make();
2808 let b = G::<u64>::make();
2809 let c: f64 = G::make();
2810}
2811"#),
2812 @r###"
2813 [127; 211) '{ ...e(); }': ()
2814 [137; 138) 'a': u32
2815 [141; 148) 'S::make': fn make<S, u32>() -> T
2816 [141; 150) 'S::make()': u32
2817 [160; 161) 'b': u64
2818 [164; 178) 'G::<u64>::make': fn make<G<u64>, u64>() -> T
2819 [164; 180) 'G::<u6...make()': u64
2820 [190; 191) 'c': f64
2821 [199; 206) 'G::make': fn make<G<f64>, f64>() -> T
2822 [199; 208) 'G::make()': f64
2823 "###
2824 );
2825}
2826
2827#[test]
2828fn infer_trait_assoc_method_generics_2() {
2829 assert_snapshot!(
2830 infer(r#"
2831trait Trait<T> {
2832 fn make<U>() -> (T, U);
2833}
2834struct S;
2835impl Trait<u32> for S {}
2836struct G<T>;
2837impl<T> Trait<T> for G<T> {}
2838fn test() {
2839 let a = S::make::<i64>();
2840 let b: (_, i64) = S::make();
2841 let c = G::<u32>::make::<i64>();
2842 let d: (u32, _) = G::make::<i64>();
2843 let e: (u32, i64) = G::make();
2844}
2845"#),
2846 @r###"
2847 [135; 313) '{ ...e(); }': ()
2848 [145; 146) 'a': (u32, i64)
2849 [149; 163) 'S::make::<i64>': fn make<S, u32, i64>() -> (T, U)
2850 [149; 165) 'S::mak...i64>()': (u32, i64)
2851 [175; 176) 'b': (u32, i64)
2852 [189; 196) 'S::make': fn make<S, u32, i64>() -> (T, U)
2853 [189; 198) 'S::make()': (u32, i64)
2854 [208; 209) 'c': (u32, i64)
2855 [212; 233) 'G::<u3...:<i64>': fn make<G<u32>, u32, i64>() -> (T, U)
2856 [212; 235) 'G::<u3...i64>()': (u32, i64)
2857 [245; 246) 'd': (u32, i64)
2858 [259; 273) 'G::make::<i64>': fn make<G<u32>, u32, i64>() -> (T, U)
2859 [259; 275) 'G::mak...i64>()': (u32, i64)
2860 [285; 286) 'e': (u32, i64)
2861 [301; 308) 'G::make': fn make<G<u32>, u32, i64>() -> (T, U)
2862 [301; 310) 'G::make()': (u32, i64)
2863 "###
2864 );
2865}
2866
2867#[test]
2868fn infer_trait_assoc_method_generics_3() {
2869 assert_snapshot!(
2870 infer(r#"
2871trait Trait<T> {
2872 fn make() -> (Self, T);
2873}
2874struct S<T>;
2875impl Trait<i64> for S<i32> {}
2876fn test() {
2877 let a = S::make();
2878}
2879"#),
2880 @r###"
2881 [101; 127) '{ ...e(); }': ()
2882 [111; 112) 'a': {unknown}
2883 [115; 122) 'S::make': {unknown}
2884 [115; 124) 'S::make()': {unknown}
2885 "###
2886 );
2887}
2888
2889#[test]
2890fn infer_trait_assoc_method_generics_4() {
2891 assert_snapshot!(
2892 infer(r#"
2893trait Trait<T> {
2894 fn make() -> (Self, T);
2895}
2896struct S<T>;
2897impl Trait<i64> for S<u64> {}
2898impl Trait<i32> for S<u32> {}
2899fn test() {
2900 let a: (Self<i64>, _) = S::make();
2901 let b: (_, u32) = S::make();
2902}
2903"#),
2904 @r###"
2905 [131; 206) '{ ...e(); }': ()
2906 [141; 142) 'a': ({unknown}, {unknown})
2907 [161; 168) 'S::make': {unknown}
2908 [161; 170) 'S::make()': ({unknown}, {unknown})
2909 [180; 181) 'b': ({unknown}, u32)
2910 [194; 201) 'S::make': {unknown}
2911 [194; 203) 'S::make()': ({unknown}, u32)
2912 "###
2913 );
2914}
2915
2916#[test]
2917fn infer_trait_assoc_method_generics_5() {
2918 assert_snapshot!(
2919 infer(r#"
2920trait Trait<T> {
2921 fn make<U>() -> (Self, T, U);
2922}
2923struct S<T>;
2924impl Trait<i64> for S<u64> {}
2925fn test() {
2926 let a = <S as Trait<i64>>::make::<u8>();
2927 let b: (S<u64>, _, _) = Trait::<i64>::make::<u8>();
2928}
2929"#),
2930 @r###"
2931 [107; 211) '{ ...>(); }': ()
2932 [117; 118) 'a': (S<u64>, i64, u8)
2933 [121; 150) '<S as ...::<u8>': fn make<S<u64>, i64, u8>() -> (Self, T, U)
2934 [121; 152) '<S as ...<u8>()': (S<u64>, i64, u8)
2935 [162; 163) 'b': (S<u64>, i64, u8)
2936 [182; 206) 'Trait:...::<u8>': fn make<S<u64>, i64, u8>() -> (Self, T, U)
2937 [182; 208) 'Trait:...<u8>()': (S<u64>, i64, u8)
2938 "###
2939 );
2940}
2941
2942#[test]
2796fn infer_from_bound_1() { 2943fn infer_from_bound_1() {
2797 assert_snapshot!( 2944 assert_snapshot!(
2798 infer(r#" 2945 infer(r#"