aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-02-24 06:45:08 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-02-24 06:45:08 +0000
commitc5e74cebdcbade069c0e1e81e298ab7d729e4cd5 (patch)
tree574d01f1f7532574ed22610341b3ac79da59d93f
parent1eef9fbefe44e919f6ddc7ce1c44625ffde6be1c (diff)
parent82fe7b77a3b4f49540ae1fc319bdd38afd73c877 (diff)
Merge #886
886: Associated method generics r=matklad a=flodiebold Refactor associated method resolution a bit and make it work with generics. Co-authored-by: Florian Diebold <[email protected]>
-rw-r--r--crates/ra_hir/src/ty/infer.rs86
-rw-r--r--crates/ra_hir/src/ty/lower.rs67
-rw-r--r--crates/ra_hir/src/ty/snapshots/tests__infer_associated_method_generics.snap8
-rw-r--r--crates/ra_hir/src/ty/tests.rs1
4 files changed, 98 insertions, 64 deletions
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 6ee9080d3..13080b5aa 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -360,46 +360,66 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
360 // we might have resolved into a type for which 360 // we might have resolved into a type for which
361 // we may find some associated item starting at the 361 // we may find some associated item starting at the
362 // path.segment pointed to by `remaining_index´ 362 // path.segment pointed to by `remaining_index´
363 let resolved = 363 let mut resolved =
364 if remaining_index.is_none() { def.take_values()? } else { def.take_types()? }; 364 if remaining_index.is_none() { def.take_values()? } else { def.take_types()? };
365 365
366 let remaining_index = remaining_index.unwrap_or(path.segments.len());
367
368 // resolve intermediate segments
369 for segment in &path.segments[remaining_index..] {
370 let ty = match resolved {
371 Resolution::Def(def) => {
372 let typable: Option<TypableDef> = def.into();
373 let typable = typable?;
374
375 let substs =
376 Ty::substs_from_path_segment(self.db, &self.resolver, segment, typable);
377 self.db.type_for_def(typable, Namespace::Types).apply_substs(substs)
378 }
379 Resolution::LocalBinding(_) => {
380 // can't have a local binding in an associated item path
381 return None;
382 }
383 Resolution::GenericParam(..) => {
384 // TODO associated item of generic param
385 return None;
386 }
387 Resolution::SelfType(_) => {
388 // TODO associated item of self type
389 return None;
390 }
391 };
392
393 // Attempt to find an impl_item for the type which has a name matching
394 // the current segment
395 log::debug!("looking for path segment: {:?}", segment);
396 let item = ty.iterate_impl_items(self.db, |item| match item {
397 crate::ImplItem::Method(func) => {
398 let sig = func.signature(self.db);
399 if segment.name == *sig.name() {
400 return Some(func);
401 }
402 None
403 }
404
405 // TODO: Resolve associated const
406 crate::ImplItem::Const(_) => None,
407
408 // TODO: Resolve associated types
409 crate::ImplItem::Type(_) => None,
410 })?;
411 resolved = Resolution::Def(item.into());
412 }
413
366 match resolved { 414 match resolved {
367 Resolution::Def(def) => { 415 Resolution::Def(def) => {
368 let typable: Option<TypableDef> = def.into(); 416 let typable: Option<TypableDef> = def.into();
369 let typable = typable?; 417 let typable = typable?;
370 418
371 if let Some(remaining_index) = remaining_index { 419 let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable);
372 let ty = self.db.type_for_def(typable, Namespace::Types); 420 let ty = self.db.type_for_def(typable, Namespace::Values).apply_substs(substs);
373 // TODO: Keep resolving the segments 421 let ty = self.insert_type_vars(ty);
374 // if we have more segments to process 422 Some(ty)
375 let segment = &path.segments[remaining_index];
376
377 log::debug!("looking for path segment: {:?}", segment);
378
379 // Attempt to find an impl_item for the type which has a name matching
380 // the current segment
381 let ty = ty.iterate_impl_items(self.db, |item| match item {
382 crate::ImplItem::Method(func) => {
383 let sig = func.signature(self.db);
384 if segment.name == *sig.name() {
385 return Some(func.ty(self.db));
386 }
387 None
388 }
389
390 // TODO: Resolve associated const
391 crate::ImplItem::Const(_) => None,
392
393 // TODO: Resolve associated types
394 crate::ImplItem::Type(_) => None,
395 });
396 ty
397 } else {
398 let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable);
399 let ty = self.db.type_for_def(typable, Namespace::Values).apply_substs(substs);
400 let ty = self.insert_type_vars(ty);
401 Some(ty)
402 }
403 } 423 }
404 Resolution::LocalBinding(pat) => { 424 Resolution::LocalBinding(pat) => {
405 let ty = self.type_of_pat.get(pat)?; 425 let ty = self.type_of_pat.get(pat)?;
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index cc9e0fd40..63e13a30e 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -16,7 +16,7 @@ use crate::{
16 name::KnownName, 16 name::KnownName,
17 nameres::Namespace, 17 nameres::Namespace,
18 resolve::{Resolver, Resolution}, 18 resolve::{Resolver, Resolution},
19 path::GenericArg, 19 path::{ PathSegment, GenericArg},
20 generics::GenericParams, 20 generics::GenericParams,
21 adt::VariantDef, 21 adt::VariantDef,
22}; 22};
@@ -112,36 +112,18 @@ impl Ty {
112 ty.apply_substs(substs) 112 ty.apply_substs(substs)
113 } 113 }
114 114
115 /// Collect generic arguments from a path into a `Substs`. See also 115 pub(super) fn substs_from_path_segment(
116 /// `create_substs_for_ast_path` and `def_to_ty` in rustc.
117 pub(super) fn substs_from_path(
118 db: &impl HirDatabase, 116 db: &impl HirDatabase,
119 resolver: &Resolver, 117 resolver: &Resolver,
120 path: &Path, 118 segment: &PathSegment,
121 resolved: TypableDef, 119 resolved: TypableDef,
122 ) -> Substs { 120 ) -> Substs {
123 let mut substs = Vec::new(); 121 let mut substs = Vec::new();
124 let last = path.segments.last().expect("path should have at least one segment"); 122 let def_generics = match resolved {
125 let (def_generics, segment) = match resolved { 123 TypableDef::Function(func) => func.generic_params(db),
126 TypableDef::Function(func) => (func.generic_params(db), last), 124 TypableDef::Struct(s) => s.generic_params(db),
127 TypableDef::Struct(s) => (s.generic_params(db), last), 125 TypableDef::Enum(e) => e.generic_params(db),
128 TypableDef::Enum(e) => (e.generic_params(db), last), 126 TypableDef::EnumVariant(var) => var.parent_enum(db).generic_params(db),
129 TypableDef::EnumVariant(var) => {
130 // the generic args for an enum variant may be either specified
131 // on the segment referring to the enum, or on the segment
132 // referring to the variant. So `Option::<T>::None` and
133 // `Option::None::<T>` are both allowed (though the former is
134 // preferred). See also `def_ids_for_path_segments` in rustc.
135 let len = path.segments.len();
136 let segment = if len >= 2 && path.segments[len - 2].args_and_bindings.is_some() {
137 // Option::<T>::None
138 &path.segments[len - 2]
139 } else {
140 // Option::None::<T>
141 last
142 };
143 (var.parent_enum(db).generic_params(db), segment)
144 }
145 }; 127 };
146 let parent_param_count = def_generics.count_parent_params(); 128 let parent_param_count = def_generics.count_parent_params();
147 substs.extend((0..parent_param_count).map(|_| Ty::Unknown)); 129 substs.extend((0..parent_param_count).map(|_| Ty::Unknown));
@@ -166,6 +148,39 @@ impl Ty {
166 assert_eq!(substs.len(), def_generics.count_params_including_parent()); 148 assert_eq!(substs.len(), def_generics.count_params_including_parent());
167 Substs(substs.into()) 149 Substs(substs.into())
168 } 150 }
151
152 /// Collect generic arguments from a path into a `Substs`. See also
153 /// `create_substs_for_ast_path` and `def_to_ty` in rustc.
154 pub(super) fn substs_from_path(
155 db: &impl HirDatabase,
156 resolver: &Resolver,
157 path: &Path,
158 resolved: TypableDef,
159 ) -> Substs {
160 let last = path.segments.last().expect("path should have at least one segment");
161 let segment = match resolved {
162 TypableDef::Function(_) => last,
163 TypableDef::Struct(_) => last,
164 TypableDef::Enum(_) => last,
165 TypableDef::EnumVariant(_) => {
166 // the generic args for an enum variant may be either specified
167 // on the segment referring to the enum, or on the segment
168 // referring to the variant. So `Option::<T>::None` and
169 // `Option::None::<T>` are both allowed (though the former is
170 // preferred). See also `def_ids_for_path_segments` in rustc.
171 let len = path.segments.len();
172 let segment = if len >= 2 && path.segments[len - 2].args_and_bindings.is_some() {
173 // Option::<T>::None
174 &path.segments[len - 2]
175 } else {
176 // Option::None::<T>
177 last
178 };
179 segment
180 }
181 };
182 Ty::substs_from_path_segment(db, resolver, segment, resolved)
183 }
169} 184}
170 185
171/// Build the declared type of an item. This depends on the namespace; e.g. for 186/// Build the declared type of an item. This depends on the namespace; e.g. for
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_associated_method_generics.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_associated_method_generics.snap
index fe5d6590e..44694dfdb 100644
--- a/crates/ra_hir/src/ty/snapshots/tests__infer_associated_method_generics.snap
+++ b/crates/ra_hir/src/ty/snapshots/tests__infer_associated_method_generics.snap
@@ -1,5 +1,5 @@
1--- 1---
2created: "2019-02-21T10:25:18.568887300Z" 2created: "2019-02-23T21:58:35.844769207Z"
3creator: [email protected] 3creator: [email protected]
4source: crates/ra_hir/src/ty/tests.rs 4source: crates/ra_hir/src/ty/tests.rs
5expression: "&result" 5expression: "&result"
@@ -9,8 +9,8 @@ expression: "&result"
9[92; 103) 'Gen { val }': Gen<T> 9[92; 103) 'Gen { val }': Gen<T>
10[98; 101) 'val': T 10[98; 101) 'val': T
11[123; 155) '{ ...32); }': () 11[123; 155) '{ ...32); }': ()
12[133; 134) 'a': Gen<[unknown]> 12[133; 134) 'a': Gen<u32>
13[137; 146) 'Gen::make': fn make<[unknown]>(T) -> Gen<T> 13[137; 146) 'Gen::make': fn make<u32>(T) -> Gen<T>
14[137; 152) 'Gen::make(0u32)': Gen<[unknown]> 14[137; 152) 'Gen::make(0u32)': Gen<u32>
15[147; 151) '0u32': u32 15[147; 151) '0u32': u32
16 16
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 77aeca669..d0da34677 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -719,7 +719,6 @@ fn test() {
719} 719}
720 720
721#[test] 721#[test]
722#[ignore] // FIXME: After https://github.com/rust-analyzer/rust-analyzer/pull/866 is merged
723fn infer_associated_method_generics() { 722fn infer_associated_method_generics() {
724 check_inference( 723 check_inference(
725 "infer_associated_method_generics", 724 "infer_associated_method_generics",