diff options
author | Florian Diebold <[email protected]> | 2019-10-29 10:04:42 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-11-01 18:57:08 +0000 |
commit | b634ba41e0439cbbb89b12a3d340c8463b35b93e (patch) | |
tree | 4e4b08e6ca6a89714d372d37bdc578393219d8b6 /crates/ra_hir/src/ty | |
parent | ed5212e1ac71e959d802a9a7ad28d06c8b18e022 (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.rs | 106 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 153 |
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}; | |||
6 | use crate::{ | 6 | use 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 | }; |
13 | use std::sync::Arc; | ||
12 | 14 | ||
13 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 15 | impl<'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. | ||
319 | fn 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] |
2796 | fn infer_trait_assoc_method_generics_1() { | ||
2797 | assert_snapshot!( | ||
2798 | infer(r#" | ||
2799 | trait Trait<T> { | ||
2800 | fn make() -> T; | ||
2801 | } | ||
2802 | struct S; | ||
2803 | impl Trait<u32> for S {} | ||
2804 | struct G<T>; | ||
2805 | impl<T> Trait<T> for G<T> {} | ||
2806 | fn 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] | ||
2828 | fn infer_trait_assoc_method_generics_2() { | ||
2829 | assert_snapshot!( | ||
2830 | infer(r#" | ||
2831 | trait Trait<T> { | ||
2832 | fn make<U>() -> (T, U); | ||
2833 | } | ||
2834 | struct S; | ||
2835 | impl Trait<u32> for S {} | ||
2836 | struct G<T>; | ||
2837 | impl<T> Trait<T> for G<T> {} | ||
2838 | fn 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] | ||
2868 | fn infer_trait_assoc_method_generics_3() { | ||
2869 | assert_snapshot!( | ||
2870 | infer(r#" | ||
2871 | trait Trait<T> { | ||
2872 | fn make() -> (Self, T); | ||
2873 | } | ||
2874 | struct S<T>; | ||
2875 | impl Trait<i64> for S<i32> {} | ||
2876 | fn 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] | ||
2890 | fn infer_trait_assoc_method_generics_4() { | ||
2891 | assert_snapshot!( | ||
2892 | infer(r#" | ||
2893 | trait Trait<T> { | ||
2894 | fn make() -> (Self, T); | ||
2895 | } | ||
2896 | struct S<T>; | ||
2897 | impl Trait<i64> for S<u64> {} | ||
2898 | impl Trait<i32> for S<u32> {} | ||
2899 | fn 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] | ||
2917 | fn infer_trait_assoc_method_generics_5() { | ||
2918 | assert_snapshot!( | ||
2919 | infer(r#" | ||
2920 | trait Trait<T> { | ||
2921 | fn make<U>() -> (Self, T, U); | ||
2922 | } | ||
2923 | struct S<T>; | ||
2924 | impl Trait<i64> for S<u64> {} | ||
2925 | fn 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] | ||
2796 | fn infer_from_bound_1() { | 2943 | fn infer_from_bound_1() { |
2797 | assert_snapshot!( | 2944 | assert_snapshot!( |
2798 | infer(r#" | 2945 | infer(r#" |