diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-24 06:45:08 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-24 06:45:08 +0000 |
commit | c5e74cebdcbade069c0e1e81e298ab7d729e4cd5 (patch) | |
tree | 574d01f1f7532574ed22610341b3ac79da59d93f /crates/ra_hir/src/ty/lower.rs | |
parent | 1eef9fbefe44e919f6ddc7ce1c44625ffde6be1c (diff) | |
parent | 82fe7b77a3b4f49540ae1fc319bdd38afd73c877 (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]>
Diffstat (limited to 'crates/ra_hir/src/ty/lower.rs')
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 67 |
1 files changed, 41 insertions, 26 deletions
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 |