diff options
Diffstat (limited to 'crates/ra_hir/src/ty/lower.rs')
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 95 |
1 files changed, 70 insertions, 25 deletions
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 003a89f0d..4523b3954 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -17,9 +17,9 @@ use crate::{ | |||
17 | resolve::{Resolver, Resolution}, | 17 | resolve::{Resolver, Resolution}, |
18 | path::{ PathSegment, GenericArg}, | 18 | path::{ PathSegment, GenericArg}, |
19 | generics::GenericParams, | 19 | generics::GenericParams, |
20 | adt::VariantDef, | 20 | adt::VariantDef, Trait |
21 | }; | 21 | }; |
22 | use super::{Ty, primitive, FnSig, Substs, TypeCtor}; | 22 | use super::{Ty, primitive, FnSig, Substs, TypeCtor, TraitRef}; |
23 | 23 | ||
24 | impl Ty { | 24 | impl Ty { |
25 | pub(crate) fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self { | 25 | pub(crate) fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self { |
@@ -115,7 +115,6 @@ impl Ty { | |||
115 | segment: &PathSegment, | 115 | segment: &PathSegment, |
116 | resolved: TypableDef, | 116 | resolved: TypableDef, |
117 | ) -> Substs { | 117 | ) -> Substs { |
118 | let mut substs = Vec::new(); | ||
119 | let def_generics = match resolved { | 118 | let def_generics = match resolved { |
120 | TypableDef::Function(func) => func.generic_params(db), | 119 | TypableDef::Function(func) => func.generic_params(db), |
121 | TypableDef::Struct(s) => s.generic_params(db), | 120 | TypableDef::Struct(s) => s.generic_params(db), |
@@ -124,28 +123,7 @@ impl Ty { | |||
124 | TypableDef::TypeAlias(t) => t.generic_params(db), | 123 | TypableDef::TypeAlias(t) => t.generic_params(db), |
125 | TypableDef::Const(_) | TypableDef::Static(_) => GenericParams::default().into(), | 124 | TypableDef::Const(_) | TypableDef::Static(_) => GenericParams::default().into(), |
126 | }; | 125 | }; |
127 | let parent_param_count = def_generics.count_parent_params(); | 126 | substs_from_path_segment(db, resolver, segment, &def_generics, false) |
128 | substs.extend((0..parent_param_count).map(|_| Ty::Unknown)); | ||
129 | if let Some(generic_args) = &segment.args_and_bindings { | ||
130 | // if args are provided, it should be all of them, but we can't rely on that | ||
131 | let param_count = def_generics.params.len(); | ||
132 | for arg in generic_args.args.iter().take(param_count) { | ||
133 | match arg { | ||
134 | GenericArg::Type(type_ref) => { | ||
135 | let ty = Ty::from_hir(db, resolver, type_ref); | ||
136 | substs.push(ty); | ||
137 | } | ||
138 | } | ||
139 | } | ||
140 | } | ||
141 | // add placeholders for args that were not provided | ||
142 | // FIXME: handle defaults | ||
143 | let supplied_params = substs.len(); | ||
144 | for _ in supplied_params..def_generics.count_params_including_parent() { | ||
145 | substs.push(Ty::Unknown); | ||
146 | } | ||
147 | assert_eq!(substs.len(), def_generics.count_params_including_parent()); | ||
148 | Substs(substs.into()) | ||
149 | } | 127 | } |
150 | 128 | ||
151 | /// Collect generic arguments from a path into a `Substs`. See also | 129 | /// Collect generic arguments from a path into a `Substs`. See also |
@@ -185,6 +163,73 @@ impl Ty { | |||
185 | } | 163 | } |
186 | } | 164 | } |
187 | 165 | ||
166 | pub(super) fn substs_from_path_segment( | ||
167 | db: &impl HirDatabase, | ||
168 | resolver: &Resolver, | ||
169 | segment: &PathSegment, | ||
170 | def_generics: &GenericParams, | ||
171 | add_self_param: bool, | ||
172 | ) -> Substs { | ||
173 | let mut substs = Vec::new(); | ||
174 | let parent_param_count = def_generics.count_parent_params(); | ||
175 | substs.extend((0..parent_param_count).map(|_| Ty::Unknown)); | ||
176 | if add_self_param { | ||
177 | // FIXME this add_self_param argument is kind of a hack: Traits have the | ||
178 | // Self type as an implicit first type parameter, but it can't be | ||
179 | // actually provided in the type arguments | ||
180 | substs.push(Ty::Unknown); | ||
181 | } | ||
182 | if let Some(generic_args) = &segment.args_and_bindings { | ||
183 | // if args are provided, it should be all of them, but we can't rely on that | ||
184 | let param_count = def_generics.params.len(); | ||
185 | for arg in generic_args.args.iter().take(param_count) { | ||
186 | match arg { | ||
187 | GenericArg::Type(type_ref) => { | ||
188 | let ty = Ty::from_hir(db, resolver, type_ref); | ||
189 | substs.push(ty); | ||
190 | } | ||
191 | } | ||
192 | } | ||
193 | } | ||
194 | // add placeholders for args that were not provided | ||
195 | // FIXME: handle defaults | ||
196 | let supplied_params = substs.len(); | ||
197 | for _ in supplied_params..def_generics.count_params_including_parent() { | ||
198 | substs.push(Ty::Unknown); | ||
199 | } | ||
200 | assert_eq!(substs.len(), def_generics.count_params_including_parent()); | ||
201 | Substs(substs.into()) | ||
202 | } | ||
203 | |||
204 | impl TraitRef { | ||
205 | pub(crate) fn from_hir( | ||
206 | db: &impl HirDatabase, | ||
207 | resolver: &Resolver, | ||
208 | type_ref: &TypeRef, | ||
209 | ) -> Option<Self> { | ||
210 | let path = match type_ref { | ||
211 | TypeRef::Path(path) => path, | ||
212 | _ => return None, | ||
213 | }; | ||
214 | let resolved = match resolver.resolve_path(db, &path).take_types()? { | ||
215 | Resolution::Def(ModuleDef::Trait(tr)) => tr, | ||
216 | _ => return None, | ||
217 | }; | ||
218 | let substs = Self::substs_from_path(db, resolver, path, resolved); | ||
219 | Some(TraitRef { trait_: resolved, substs }) | ||
220 | } | ||
221 | |||
222 | fn substs_from_path( | ||
223 | db: &impl HirDatabase, | ||
224 | resolver: &Resolver, | ||
225 | path: &Path, | ||
226 | resolved: Trait, | ||
227 | ) -> Substs { | ||
228 | let segment = path.segments.last().expect("path should have at least one segment"); | ||
229 | substs_from_path_segment(db, resolver, segment, &resolved.generic_params(db), true) | ||
230 | } | ||
231 | } | ||
232 | |||
188 | /// Build the declared type of an item. This depends on the namespace; e.g. for | 233 | /// Build the declared type of an item. This depends on the namespace; e.g. for |
189 | /// `struct Foo(usize)`, we have two types: The type of the struct itself, and | 234 | /// `struct Foo(usize)`, we have two types: The type of the struct itself, and |
190 | /// the constructor function `(usize) -> Foo` which lives in the values | 235 | /// the constructor function `(usize) -> Foo` which lives in the values |