aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty/infer/path.rs
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/infer/path.rs
parented5212e1ac71e959d802a9a7ad28d06c8b18e022 (diff)
Get trait assoc item resolution mostly working
Diffstat (limited to 'crates/ra_hir/src/ty/infer/path.rs')
-rw-r--r--crates/ra_hir/src/ty/infer/path.rs106
1 files changed, 98 insertions, 8 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}