diff options
25 files changed, 882 insertions, 153 deletions
diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs index d87fe7049..ab1c428db 100644 --- a/crates/ra_hir/src/adt.rs +++ b/crates/ra_hir/src/adt.rs | |||
@@ -1,3 +1,6 @@ | |||
1 | //! This module contains the implementation details of the HIR for ADTs, i.e. | ||
2 | //! structs and enums (and unions). | ||
3 | |||
1 | use std::sync::Arc; | 4 | use std::sync::Arc; |
2 | 5 | ||
3 | use ra_syntax::{ | 6 | use ra_syntax::{ |
@@ -62,7 +65,7 @@ fn get_def_id( | |||
62 | }; | 65 | }; |
63 | let loc = DefLoc { | 66 | let loc = DefLoc { |
64 | kind: expected_kind, | 67 | kind: expected_kind, |
65 | source_item_id: source_item_id, | 68 | source_item_id, |
66 | ..*same_file_loc | 69 | ..*same_file_loc |
67 | }; | 70 | }; |
68 | loc.id(db) | 71 | loc.id(db) |
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs index 11e919c1a..88eda5ed0 100644 --- a/crates/ra_hir/src/code_model_api.rs +++ b/crates/ra_hir/src/code_model_api.rs | |||
@@ -12,6 +12,7 @@ use crate::{ | |||
12 | expr::BodySyntaxMapping, | 12 | expr::BodySyntaxMapping, |
13 | ty::InferenceResult, | 13 | ty::InferenceResult, |
14 | adt::VariantData, | 14 | adt::VariantData, |
15 | generics::GenericParams, | ||
15 | code_model_impl::def_id_to_ast, | 16 | code_model_impl::def_id_to_ast, |
16 | }; | 17 | }; |
17 | 18 | ||
@@ -201,6 +202,10 @@ impl Struct { | |||
201 | pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc<ast::StructDef>) { | 202 | pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc<ast::StructDef>) { |
202 | def_id_to_ast(db, self.def_id) | 203 | def_id_to_ast(db, self.def_id) |
203 | } | 204 | } |
205 | |||
206 | pub fn generic_params(&self, db: &impl HirDatabase) -> Arc<GenericParams> { | ||
207 | db.generic_params(self.def_id) | ||
208 | } | ||
204 | } | 209 | } |
205 | 210 | ||
206 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 211 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
@@ -228,6 +233,10 @@ impl Enum { | |||
228 | pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc<ast::EnumDef>) { | 233 | pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc<ast::EnumDef>) { |
229 | def_id_to_ast(db, self.def_id) | 234 | def_id_to_ast(db, self.def_id) |
230 | } | 235 | } |
236 | |||
237 | pub fn generic_params(&self, db: &impl HirDatabase) -> Arc<GenericParams> { | ||
238 | db.generic_params(self.def_id) | ||
239 | } | ||
231 | } | 240 | } |
232 | 241 | ||
233 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 242 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
@@ -339,6 +348,10 @@ impl Function { | |||
339 | pub fn infer(&self, db: &impl HirDatabase) -> Arc<InferenceResult> { | 348 | pub fn infer(&self, db: &impl HirDatabase) -> Arc<InferenceResult> { |
340 | db.infer(self.def_id) | 349 | db.infer(self.def_id) |
341 | } | 350 | } |
351 | |||
352 | pub fn generic_params(&self, db: &impl HirDatabase) -> Arc<GenericParams> { | ||
353 | db.generic_params(self.def_id) | ||
354 | } | ||
342 | } | 355 | } |
343 | 356 | ||
344 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 357 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
@@ -384,6 +397,10 @@ impl Trait { | |||
384 | pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc<ast::TraitDef>) { | 397 | pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc<ast::TraitDef>) { |
385 | def_id_to_ast(db, self.def_id) | 398 | def_id_to_ast(db, self.def_id) |
386 | } | 399 | } |
400 | |||
401 | pub fn generic_params(&self, db: &impl HirDatabase) -> Arc<GenericParams> { | ||
402 | db.generic_params(self.def_id) | ||
403 | } | ||
387 | } | 404 | } |
388 | 405 | ||
389 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 406 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
@@ -399,4 +416,8 @@ impl Type { | |||
399 | pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc<ast::TypeDef>) { | 416 | pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc<ast::TypeDef>) { |
400 | def_id_to_ast(db, self.def_id) | 417 | def_id_to_ast(db, self.def_id) |
401 | } | 418 | } |
419 | |||
420 | pub fn generic_params(&self, db: &impl HirDatabase) -> Arc<GenericParams> { | ||
421 | db.generic_params(self.def_id) | ||
422 | } | ||
402 | } | 423 | } |
diff --git a/crates/ra_hir/src/code_model_impl/module.rs b/crates/ra_hir/src/code_model_impl/module.rs index e5394d440..73c212de8 100644 --- a/crates/ra_hir/src/code_model_impl/module.rs +++ b/crates/ra_hir/src/code_model_impl/module.rs | |||
@@ -95,7 +95,7 @@ impl Module { | |||
95 | } | 95 | } |
96 | 96 | ||
97 | /// Finds a child module with the specified name. | 97 | /// Finds a child module with the specified name. |
98 | pub fn child_impl(&self, db: &impl HirDatabase, name: &Name) -> Option<Module> { | 98 | pub(crate) fn child_impl(&self, db: &impl HirDatabase, name: &Name) -> Option<Module> { |
99 | let loc = self.def_id.loc(db); | 99 | let loc = self.def_id.loc(db); |
100 | let module_tree = db.module_tree(loc.source_root_id); | 100 | let module_tree = db.module_tree(loc.source_root_id); |
101 | let child_id = loc.module_id.child(&module_tree, name)?; | 101 | let child_id = loc.module_id.child(&module_tree, name)?; |
@@ -103,7 +103,7 @@ impl Module { | |||
103 | } | 103 | } |
104 | 104 | ||
105 | /// Iterates over all child modules. | 105 | /// Iterates over all child modules. |
106 | pub fn children_impl(&self, db: &impl HirDatabase) -> impl Iterator<Item = Module> { | 106 | pub(crate) fn children_impl(&self, db: &impl HirDatabase) -> impl Iterator<Item = Module> { |
107 | // FIXME this should be implementable without collecting into a vec, but | 107 | // FIXME this should be implementable without collecting into a vec, but |
108 | // it's kind of hard since the iterator needs to keep a reference to the | 108 | // it's kind of hard since the iterator needs to keep a reference to the |
109 | // module tree. | 109 | // module tree. |
@@ -117,7 +117,7 @@ impl Module { | |||
117 | children.into_iter() | 117 | children.into_iter() |
118 | } | 118 | } |
119 | 119 | ||
120 | pub fn parent_impl(&self, db: &impl HirDatabase) -> Option<Module> { | 120 | pub(crate) fn parent_impl(&self, db: &impl HirDatabase) -> Option<Module> { |
121 | let loc = self.def_id.loc(db); | 121 | let loc = self.def_id.loc(db); |
122 | let module_tree = db.module_tree(loc.source_root_id); | 122 | let module_tree = db.module_tree(loc.source_root_id); |
123 | let parent_id = loc.module_id.parent(&module_tree)?; | 123 | let parent_id = loc.module_id.parent(&module_tree)?; |
@@ -125,13 +125,13 @@ impl Module { | |||
125 | } | 125 | } |
126 | 126 | ||
127 | /// Returns a `ModuleScope`: a set of items, visible in this module. | 127 | /// Returns a `ModuleScope`: a set of items, visible in this module. |
128 | pub fn scope_impl(&self, db: &impl HirDatabase) -> ModuleScope { | 128 | pub(crate) fn scope_impl(&self, db: &impl HirDatabase) -> ModuleScope { |
129 | let loc = self.def_id.loc(db); | 129 | let loc = self.def_id.loc(db); |
130 | let item_map = db.item_map(loc.source_root_id); | 130 | let item_map = db.item_map(loc.source_root_id); |
131 | item_map.per_module[&loc.module_id].clone() | 131 | item_map.per_module[&loc.module_id].clone() |
132 | } | 132 | } |
133 | 133 | ||
134 | pub fn resolve_path_impl(&self, db: &impl HirDatabase, path: &Path) -> PerNs<DefId> { | 134 | pub(crate) fn resolve_path_impl(&self, db: &impl HirDatabase, path: &Path) -> PerNs<DefId> { |
135 | let mut curr_per_ns = PerNs::types( | 135 | let mut curr_per_ns = PerNs::types( |
136 | match path.kind { | 136 | match path.kind { |
137 | PathKind::Crate => self.crate_root(db), | 137 | PathKind::Crate => self.crate_root(db), |
@@ -147,47 +147,54 @@ impl Module { | |||
147 | .def_id, | 147 | .def_id, |
148 | ); | 148 | ); |
149 | 149 | ||
150 | let segments = &path.segments; | 150 | for segment in path.segments.iter() { |
151 | for (idx, name) in segments.iter().enumerate() { | 151 | let curr = match curr_per_ns.as_ref().take_types() { |
152 | let curr = if let Some(r) = curr_per_ns.as_ref().take_types() { | 152 | Some(r) => r, |
153 | r | 153 | None => { |
154 | } else { | 154 | // we still have path segments left, but the path so far |
155 | return PerNs::none(); | 155 | // didn't resolve in the types namespace => no resolution |
156 | // (don't break here because curr_per_ns might contain | ||
157 | // something in the value namespace, and it would be wrong | ||
158 | // to return that) | ||
159 | return PerNs::none(); | ||
160 | } | ||
156 | }; | 161 | }; |
157 | let module = match curr.resolve(db) { | 162 | // resolve segment in curr |
158 | Def::Module(it) => it, | 163 | curr_per_ns = match curr.resolve(db) { |
164 | Def::Module(m) => { | ||
165 | let scope = m.scope(db); | ||
166 | match scope.get(&segment.name) { | ||
167 | Some(r) => r.def_id, | ||
168 | None => PerNs::none(), | ||
169 | } | ||
170 | } | ||
159 | Def::Enum(e) => { | 171 | Def::Enum(e) => { |
160 | if segments.len() == idx + 1 { | 172 | // enum variant |
161 | // enum variant | 173 | let matching_variant = e |
162 | let matching_variant = | 174 | .variants(db) |
163 | e.variants(db).into_iter().find(|(n, _variant)| n == name); | 175 | .into_iter() |
164 | 176 | .find(|(n, _variant)| n == &segment.name); | |
165 | if let Some((_n, variant)) = matching_variant { | 177 | |
166 | return PerNs::both(variant.def_id(), e.def_id()); | 178 | match matching_variant { |
167 | } else { | 179 | Some((_n, variant)) => PerNs::both(variant.def_id(), e.def_id()), |
168 | return PerNs::none(); | 180 | None => PerNs::none(), |
169 | } | ||
170 | } else if segments.len() == idx { | ||
171 | // enum | ||
172 | return PerNs::types(e.def_id()); | ||
173 | } else { | ||
174 | // malformed enum? | ||
175 | return PerNs::none(); | ||
176 | } | 181 | } |
177 | } | 182 | } |
178 | _ => return PerNs::none(), | 183 | _ => { |
179 | }; | 184 | // could be an inherent method call in UFCS form |
180 | let scope = module.scope(db); | 185 | // (`Struct::method`), or some other kind of associated |
181 | curr_per_ns = if let Some(r) = scope.get(&name) { | 186 | // item... Which we currently don't handle (TODO) |
182 | r.def_id | 187 | PerNs::none() |
183 | } else { | 188 | } |
184 | return PerNs::none(); | ||
185 | }; | 189 | }; |
186 | } | 190 | } |
187 | curr_per_ns | 191 | curr_per_ns |
188 | } | 192 | } |
189 | 193 | ||
190 | pub fn problems_impl(&self, db: &impl HirDatabase) -> Vec<(TreeArc<SyntaxNode>, Problem)> { | 194 | pub(crate) fn problems_impl( |
195 | &self, | ||
196 | db: &impl HirDatabase, | ||
197 | ) -> Vec<(TreeArc<SyntaxNode>, Problem)> { | ||
191 | let loc = self.def_id.loc(db); | 198 | let loc = self.def_id.loc(db); |
192 | let module_tree = db.module_tree(loc.source_root_id); | 199 | let module_tree = db.module_tree(loc.source_root_id); |
193 | loc.module_id.problems(&module_tree, db) | 200 | loc.module_id.problems(&module_tree, db) |
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 60065cf6a..f383701d7 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -14,6 +14,7 @@ use crate::{ | |||
14 | ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks}, | 14 | ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks}, |
15 | adt::{StructData, EnumData, EnumVariantData}, | 15 | adt::{StructData, EnumData, EnumVariantData}, |
16 | impl_block::ModuleImplBlocks, | 16 | impl_block::ModuleImplBlocks, |
17 | generics::GenericParams, | ||
17 | }; | 18 | }; |
18 | 19 | ||
19 | #[salsa::query_group] | 20 | #[salsa::query_group] |
@@ -101,6 +102,9 @@ pub trait HirDatabase: | |||
101 | #[salsa::invoke(crate::expr::body_syntax_mapping)] | 102 | #[salsa::invoke(crate::expr::body_syntax_mapping)] |
102 | fn body_syntax_mapping(&self, def_id: DefId) -> Arc<crate::expr::BodySyntaxMapping>; | 103 | fn body_syntax_mapping(&self, def_id: DefId) -> Arc<crate::expr::BodySyntaxMapping>; |
103 | 104 | ||
105 | #[salsa::invoke(crate::generics::GenericParams::generic_params_query)] | ||
106 | fn generic_params(&self, def_id: DefId) -> Arc<GenericParams>; | ||
107 | |||
104 | #[salsa::invoke(crate::FnSignature::fn_signature_query)] | 108 | #[salsa::invoke(crate::FnSignature::fn_signature_query)] |
105 | fn fn_signature(&self, def_id: DefId) -> Arc<FnSignature>; | 109 | fn fn_signature(&self, def_id: DefId) -> Arc<FnSignature>; |
106 | } | 110 | } |
diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs new file mode 100644 index 000000000..d8248ad49 --- /dev/null +++ b/crates/ra_hir/src/generics.rs | |||
@@ -0,0 +1,48 @@ | |||
1 | //! Many kinds of items or constructs can have generic parameters: functions, | ||
2 | //! structs, impls, traits, etc. This module provides a common HIR for these | ||
3 | //! generic parameters. See also the `Generics` type and the `generics_of` query | ||
4 | //! in rustc. | ||
5 | |||
6 | use std::sync::Arc; | ||
7 | |||
8 | use ra_syntax::ast::{TypeParamList, AstNode, NameOwner}; | ||
9 | |||
10 | use crate::{db::HirDatabase, DefId, Name, AsName}; | ||
11 | |||
12 | /// Data about a generic parameter (to a function, struct, impl, ...). | ||
13 | #[derive(Clone, PartialEq, Eq, Debug)] | ||
14 | pub struct GenericParam { | ||
15 | pub(crate) idx: u32, | ||
16 | pub(crate) name: Name, | ||
17 | } | ||
18 | |||
19 | /// Data about the generic parameters of a function, struct, impl, etc. | ||
20 | #[derive(Clone, PartialEq, Eq, Debug, Default)] | ||
21 | pub struct GenericParams { | ||
22 | pub(crate) params: Vec<GenericParam>, | ||
23 | } | ||
24 | |||
25 | impl GenericParams { | ||
26 | pub(crate) fn generic_params_query(db: &impl HirDatabase, def_id: DefId) -> Arc<GenericParams> { | ||
27 | let (_file_id, node) = def_id.source(db); | ||
28 | let mut generics = GenericParams::default(); | ||
29 | if let Some(type_param_list) = node.children().find_map(TypeParamList::cast) { | ||
30 | for (idx, type_param) in type_param_list.type_params().enumerate() { | ||
31 | let name = type_param | ||
32 | .name() | ||
33 | .map(AsName::as_name) | ||
34 | .unwrap_or_else(Name::missing); | ||
35 | let param = GenericParam { | ||
36 | idx: idx as u32, | ||
37 | name, | ||
38 | }; | ||
39 | generics.params.push(param); | ||
40 | } | ||
41 | } | ||
42 | Arc::new(generics) | ||
43 | } | ||
44 | |||
45 | pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> { | ||
46 | self.params.iter().find(|p| &p.name == name) | ||
47 | } | ||
48 | } | ||
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs index 0d8e67547..c5408e277 100644 --- a/crates/ra_hir/src/ids.rs +++ b/crates/ra_hir/src/ids.rs | |||
@@ -151,6 +151,15 @@ pub(crate) enum DefKind { | |||
151 | Type, | 151 | Type, |
152 | Item, | 152 | Item, |
153 | 153 | ||
154 | /// The constructor of a struct. E.g. if we have `struct Foo(usize)`, the | ||
155 | /// name `Foo` needs to resolve to different types depending on whether we | ||
156 | /// are in the types or values namespace: As a type, `Foo` of course refers | ||
157 | /// to the struct `Foo`; as a value, `Foo` is a callable type with signature | ||
158 | /// `(usize) -> Foo`. The cleanest approach to handle this seems to be to | ||
159 | /// have different defs in the two namespaces. | ||
160 | /// | ||
161 | /// rustc does the same; note that it even creates a struct constructor if | ||
162 | /// the struct isn't a tuple struct (see `CtorKind::Fictive` in rustc). | ||
154 | StructCtor, | 163 | StructCtor, |
155 | } | 164 | } |
156 | 165 | ||
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index f1402a286..361d39f03 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -24,6 +24,7 @@ mod type_ref; | |||
24 | mod ty; | 24 | mod ty; |
25 | mod impl_block; | 25 | mod impl_block; |
26 | mod expr; | 26 | mod expr; |
27 | mod generics; | ||
27 | 28 | ||
28 | mod code_model_api; | 29 | mod code_model_api; |
29 | mod code_model_impl; | 30 | mod code_model_impl; |
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs index 018e5e0d4..6e6f2f04b 100644 --- a/crates/ra_hir/src/mock.rs +++ b/crates/ra_hir/src/mock.rs | |||
@@ -243,6 +243,7 @@ salsa::database_storage! { | |||
243 | fn body_hir() for db::BodyHirQuery; | 243 | fn body_hir() for db::BodyHirQuery; |
244 | fn body_syntax_mapping() for db::BodySyntaxMappingQuery; | 244 | fn body_syntax_mapping() for db::BodySyntaxMappingQuery; |
245 | fn fn_signature() for db::FnSignatureQuery; | 245 | fn fn_signature() for db::FnSignatureQuery; |
246 | fn generic_params() for db::GenericParamsQuery; | ||
246 | } | 247 | } |
247 | } | 248 | } |
248 | } | 249 | } |
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 4efafd409..4874e82f3 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -221,10 +221,10 @@ where | |||
221 | }; | 221 | }; |
222 | } | 222 | } |
223 | for (import_id, import_data) in input.imports.iter() { | 223 | for (import_id, import_data) in input.imports.iter() { |
224 | if let Some(name) = import_data.path.segments.iter().last() { | 224 | if let Some(segment) = import_data.path.segments.iter().last() { |
225 | if !import_data.is_glob { | 225 | if !import_data.is_glob { |
226 | module_items.items.insert( | 226 | module_items.items.insert( |
227 | name.clone(), | 227 | segment.name.clone(), |
228 | Resolution { | 228 | Resolution { |
229 | def_id: PerNs::none(), | 229 | def_id: PerNs::none(), |
230 | import: Some(import_id), | 230 | import: Some(import_id), |
@@ -319,13 +319,13 @@ where | |||
319 | PathKind::Crate => module_id.crate_root(&self.module_tree), | 319 | PathKind::Crate => module_id.crate_root(&self.module_tree), |
320 | }; | 320 | }; |
321 | 321 | ||
322 | for (i, name) in import.path.segments.iter().enumerate() { | 322 | for (i, segment) in import.path.segments.iter().enumerate() { |
323 | let is_last = i == import.path.segments.len() - 1; | 323 | let is_last = i == import.path.segments.len() - 1; |
324 | 324 | ||
325 | let def_id = match self.result.per_module[&curr].items.get(name) { | 325 | let def_id = match self.result.per_module[&curr].items.get(&segment.name) { |
326 | Some(res) if !res.def_id.is_none() => res.def_id, | 326 | Some(res) if !res.def_id.is_none() => res.def_id, |
327 | _ => { | 327 | _ => { |
328 | log::debug!("path segment {:?} not found", name); | 328 | log::debug!("path segment {:?} not found", segment.name); |
329 | return false; | 329 | return false; |
330 | } | 330 | } |
331 | }; | 331 | }; |
@@ -336,7 +336,7 @@ where | |||
336 | } else { | 336 | } else { |
337 | log::debug!( | 337 | log::debug!( |
338 | "path segment {:?} resolved to value only, but is not last", | 338 | "path segment {:?} resolved to value only, but is not last", |
339 | name | 339 | segment.name |
340 | ); | 340 | ); |
341 | return false; | 341 | return false; |
342 | }; | 342 | }; |
@@ -358,17 +358,17 @@ where | |||
358 | log::debug!("resolving {:?} in other source root", path); | 358 | log::debug!("resolving {:?} in other source root", path); |
359 | let def_id = module.resolve_path(self.db, &path); | 359 | let def_id = module.resolve_path(self.db, &path); |
360 | if !def_id.is_none() { | 360 | if !def_id.is_none() { |
361 | let name = path.segments.last().unwrap(); | 361 | let last_segment = path.segments.last().unwrap(); |
362 | self.update(module_id, |items| { | 362 | self.update(module_id, |items| { |
363 | let res = Resolution { | 363 | let res = Resolution { |
364 | def_id, | 364 | def_id, |
365 | import: Some(import_id), | 365 | import: Some(import_id), |
366 | }; | 366 | }; |
367 | items.items.insert(name.clone(), res); | 367 | items.items.insert(last_segment.name.clone(), res); |
368 | }); | 368 | }); |
369 | log::debug!( | 369 | log::debug!( |
370 | "resolved import {:?} ({:?}) cross-source root to {:?}", | 370 | "resolved import {:?} ({:?}) cross-source root to {:?}", |
371 | name, | 371 | last_segment.name, |
372 | import, | 372 | import, |
373 | def_id.map(|did| did.loc(self.db)) | 373 | def_id.map(|did| did.loc(self.db)) |
374 | ); | 374 | ); |
@@ -382,7 +382,7 @@ where | |||
382 | _ => { | 382 | _ => { |
383 | log::debug!( | 383 | log::debug!( |
384 | "path segment {:?} resolved to non-module {:?}, but is not last", | 384 | "path segment {:?} resolved to non-module {:?}, but is not last", |
385 | name, | 385 | segment.name, |
386 | type_def_id.loc(self.db) | 386 | type_def_id.loc(self.db) |
387 | ); | 387 | ); |
388 | return true; // this resolved to a non-module, so the path won't ever resolve | 388 | return true; // this resolved to a non-module, so the path won't ever resolve |
@@ -391,7 +391,7 @@ where | |||
391 | } else { | 391 | } else { |
392 | log::debug!( | 392 | log::debug!( |
393 | "resolved import {:?} ({:?}) within source root to {:?}", | 393 | "resolved import {:?} ({:?}) within source root to {:?}", |
394 | name, | 394 | segment.name, |
395 | import, | 395 | import, |
396 | def_id.map(|did| did.loc(self.db)) | 396 | def_id.map(|did| did.loc(self.db)) |
397 | ); | 397 | ); |
@@ -400,7 +400,7 @@ where | |||
400 | def_id, | 400 | def_id, |
401 | import: Some(import_id), | 401 | import: Some(import_id), |
402 | }; | 402 | }; |
403 | items.items.insert(name.clone(), res); | 403 | items.items.insert(segment.name.clone(), res); |
404 | }) | 404 | }) |
405 | } | 405 | } |
406 | } | 406 | } |
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index 7b0ce3b61..c3d14c689 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs | |||
@@ -1,11 +1,35 @@ | |||
1 | use std::sync::Arc; | ||
2 | |||
1 | use ra_syntax::{ast, AstNode}; | 3 | use ra_syntax::{ast, AstNode}; |
2 | 4 | ||
3 | use crate::{Name, AsName}; | 5 | use crate::{Name, AsName, type_ref::TypeRef}; |
4 | 6 | ||
5 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 7 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
6 | pub struct Path { | 8 | pub struct Path { |
7 | pub kind: PathKind, | 9 | pub kind: PathKind, |
8 | pub segments: Vec<Name>, | 10 | pub segments: Vec<PathSegment>, |
11 | } | ||
12 | |||
13 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
14 | pub struct PathSegment { | ||
15 | pub name: Name, | ||
16 | pub args_and_bindings: Option<Arc<GenericArgs>>, | ||
17 | } | ||
18 | |||
19 | /// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This | ||
20 | /// can (in the future) also include bindings of associated types, like in | ||
21 | /// `Iterator<Item = Foo>`. | ||
22 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
23 | pub struct GenericArgs { | ||
24 | pub args: Vec<GenericArg>, | ||
25 | // someday also bindings | ||
26 | } | ||
27 | |||
28 | /// A single generic argument. | ||
29 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
30 | pub enum GenericArg { | ||
31 | Type(TypeRef), | ||
32 | // or lifetime... | ||
9 | } | 33 | } |
10 | 34 | ||
11 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 35 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
@@ -34,7 +58,17 @@ impl Path { | |||
34 | loop { | 58 | loop { |
35 | let segment = path.segment()?; | 59 | let segment = path.segment()?; |
36 | match segment.kind()? { | 60 | match segment.kind()? { |
37 | ast::PathSegmentKind::Name(name) => segments.push(name.as_name()), | 61 | ast::PathSegmentKind::Name(name) => { |
62 | let args = segment | ||
63 | .type_arg_list() | ||
64 | .and_then(GenericArgs::from_ast) | ||
65 | .map(Arc::new); | ||
66 | let segment = PathSegment { | ||
67 | name: name.as_name(), | ||
68 | args_and_bindings: args, | ||
69 | }; | ||
70 | segments.push(segment); | ||
71 | } | ||
38 | ast::PathSegmentKind::CrateKw => { | 72 | ast::PathSegmentKind::CrateKw => { |
39 | kind = PathKind::Crate; | 73 | kind = PathKind::Crate; |
40 | break; | 74 | break; |
@@ -88,7 +122,23 @@ impl Path { | |||
88 | if self.kind != PathKind::Plain || self.segments.len() > 1 { | 122 | if self.kind != PathKind::Plain || self.segments.len() > 1 { |
89 | return None; | 123 | return None; |
90 | } | 124 | } |
91 | self.segments.first() | 125 | self.segments.first().map(|s| &s.name) |
126 | } | ||
127 | } | ||
128 | |||
129 | impl GenericArgs { | ||
130 | fn from_ast(node: &ast::TypeArgList) -> Option<GenericArgs> { | ||
131 | let mut args = Vec::new(); | ||
132 | for type_arg in node.type_args() { | ||
133 | let type_ref = TypeRef::from_ast_opt(type_arg.type_ref()); | ||
134 | args.push(GenericArg::Type(type_ref)); | ||
135 | } | ||
136 | // lifetimes and assoc type args ignored for now | ||
137 | if args.len() > 0 { | ||
138 | Some(GenericArgs { args }) | ||
139 | } else { | ||
140 | None | ||
141 | } | ||
92 | } | 142 | } |
93 | } | 143 | } |
94 | 144 | ||
@@ -96,7 +146,10 @@ impl From<Name> for Path { | |||
96 | fn from(name: Name) -> Path { | 146 | fn from(name: Name) -> Path { |
97 | Path { | 147 | Path { |
98 | kind: PathKind::Plain, | 148 | kind: PathKind::Plain, |
99 | segments: vec![name], | 149 | segments: vec![PathSegment { |
150 | name, | ||
151 | args_and_bindings: None, | ||
152 | }], | ||
100 | } | 153 | } |
101 | } | 154 | } |
102 | } | 155 | } |
@@ -160,7 +213,10 @@ fn convert_path(prefix: Option<Path>, path: &ast::Path) -> Option<Path> { | |||
160 | kind: PathKind::Plain, | 213 | kind: PathKind::Plain, |
161 | segments: Vec::with_capacity(1), | 214 | segments: Vec::with_capacity(1), |
162 | }); | 215 | }); |
163 | res.segments.push(name.as_name()); | 216 | res.segments.push(PathSegment { |
217 | name: name.as_name(), | ||
218 | args_and_bindings: None, // no type args in use | ||
219 | }); | ||
164 | res | 220 | res |
165 | } | 221 | } |
166 | ast::PathSegmentKind::CrateKw => { | 222 | ast::PathSegmentKind::CrateKw => { |
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 8d6493887..c602450e1 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -37,6 +37,8 @@ use crate::{ | |||
37 | type_ref::{TypeRef, Mutability}, | 37 | type_ref::{TypeRef, Mutability}, |
38 | name::KnownName, | 38 | name::KnownName, |
39 | expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat}, | 39 | expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat}, |
40 | generics::GenericParams, | ||
41 | path::GenericArg, | ||
40 | }; | 42 | }; |
41 | 43 | ||
42 | /// The ID of a type variable. | 44 | /// The ID of a type variable. |
@@ -151,10 +153,20 @@ impl Expectation { | |||
151 | } | 153 | } |
152 | } | 154 | } |
153 | 155 | ||
156 | /// A list of substitutions for generic parameters. | ||
157 | #[derive(Clone, PartialEq, Eq, Debug)] | ||
158 | pub struct Substs(Arc<[Ty]>); | ||
159 | |||
160 | impl Substs { | ||
161 | pub fn empty() -> Substs { | ||
162 | Substs(Arc::new([])) | ||
163 | } | ||
164 | } | ||
165 | |||
154 | /// A type. This is based on the `TyKind` enum in rustc (librustc/ty/sty.rs). | 166 | /// A type. This is based on the `TyKind` enum in rustc (librustc/ty/sty.rs). |
155 | /// | 167 | /// |
156 | /// This should be cheap to clone. | 168 | /// This should be cheap to clone. |
157 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] | 169 | #[derive(Clone, PartialEq, Eq, Debug)] |
158 | pub enum Ty { | 170 | pub enum Ty { |
159 | /// The primitive boolean type. Written as `bool`. | 171 | /// The primitive boolean type. Written as `bool`. |
160 | Bool, | 172 | Bool, |
@@ -175,7 +187,8 @@ pub enum Ty { | |||
175 | def_id: DefId, | 187 | def_id: DefId, |
176 | /// The name, for displaying. | 188 | /// The name, for displaying. |
177 | name: Name, | 189 | name: Name, |
178 | // later we'll need generic substitutions here | 190 | /// Substitutions for the generic parameters of the type. |
191 | substs: Substs, | ||
179 | }, | 192 | }, |
180 | 193 | ||
181 | /// The pointee of a string slice. Written as `str`. | 194 | /// The pointee of a string slice. Written as `str`. |
@@ -234,9 +247,15 @@ pub enum Ty { | |||
234 | 247 | ||
235 | // Opaque (`impl Trait`) type found in a return type. | 248 | // Opaque (`impl Trait`) type found in a return type. |
236 | // Opaque(DefId, Substs), | 249 | // Opaque(DefId, Substs), |
250 | /// A type parameter; for example, `T` in `fn f<T>(x: T) {} | ||
251 | Param { | ||
252 | /// The index of the parameter (starting with parameters from the | ||
253 | /// surrounding impl, then the current function). | ||
254 | idx: u32, | ||
255 | /// The name of the parameter, for displaying. | ||
256 | name: Name, | ||
257 | }, | ||
237 | 258 | ||
238 | // A type parameter; for example, `T` in `fn f<T>(x: T) {} | ||
239 | // Param(ParamTy), | ||
240 | /// A type variable used during type checking. Not to be confused with a | 259 | /// A type variable used during type checking. Not to be confused with a |
241 | /// type parameter. | 260 | /// type parameter. |
242 | Infer(InferTy), | 261 | Infer(InferTy), |
@@ -250,7 +269,7 @@ pub enum Ty { | |||
250 | } | 269 | } |
251 | 270 | ||
252 | /// A function signature. | 271 | /// A function signature. |
253 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] | 272 | #[derive(Clone, PartialEq, Eq, Debug)] |
254 | pub struct FnSig { | 273 | pub struct FnSig { |
255 | input: Vec<Ty>, | 274 | input: Vec<Ty>, |
256 | output: Ty, | 275 | output: Ty, |
@@ -259,8 +278,12 @@ pub struct FnSig { | |||
259 | impl Ty { | 278 | impl Ty { |
260 | pub(crate) fn from_hir( | 279 | pub(crate) fn from_hir( |
261 | db: &impl HirDatabase, | 280 | db: &impl HirDatabase, |
281 | // TODO: the next three parameters basically describe the scope for name | ||
282 | // resolution; this should be refactored into something like a general | ||
283 | // resolver architecture | ||
262 | module: &Module, | 284 | module: &Module, |
263 | impl_block: Option<&ImplBlock>, | 285 | impl_block: Option<&ImplBlock>, |
286 | generics: &GenericParams, | ||
264 | type_ref: &TypeRef, | 287 | type_ref: &TypeRef, |
265 | ) -> Self { | 288 | ) -> Self { |
266 | match type_ref { | 289 | match type_ref { |
@@ -268,32 +291,32 @@ impl Ty { | |||
268 | TypeRef::Tuple(inner) => { | 291 | TypeRef::Tuple(inner) => { |
269 | let inner_tys = inner | 292 | let inner_tys = inner |
270 | .iter() | 293 | .iter() |
271 | .map(|tr| Ty::from_hir(db, module, impl_block, tr)) | 294 | .map(|tr| Ty::from_hir(db, module, impl_block, generics, tr)) |
272 | .collect::<Vec<_>>(); | 295 | .collect::<Vec<_>>(); |
273 | Ty::Tuple(inner_tys.into()) | 296 | Ty::Tuple(inner_tys.into()) |
274 | } | 297 | } |
275 | TypeRef::Path(path) => Ty::from_hir_path(db, module, impl_block, path), | 298 | TypeRef::Path(path) => Ty::from_hir_path(db, module, impl_block, generics, path), |
276 | TypeRef::RawPtr(inner, mutability) => { | 299 | TypeRef::RawPtr(inner, mutability) => { |
277 | let inner_ty = Ty::from_hir(db, module, impl_block, inner); | 300 | let inner_ty = Ty::from_hir(db, module, impl_block, generics, inner); |
278 | Ty::RawPtr(Arc::new(inner_ty), *mutability) | 301 | Ty::RawPtr(Arc::new(inner_ty), *mutability) |
279 | } | 302 | } |
280 | TypeRef::Array(inner) => { | 303 | TypeRef::Array(inner) => { |
281 | let inner_ty = Ty::from_hir(db, module, impl_block, inner); | 304 | let inner_ty = Ty::from_hir(db, module, impl_block, generics, inner); |
282 | Ty::Array(Arc::new(inner_ty)) | 305 | Ty::Array(Arc::new(inner_ty)) |
283 | } | 306 | } |
284 | TypeRef::Slice(inner) => { | 307 | TypeRef::Slice(inner) => { |
285 | let inner_ty = Ty::from_hir(db, module, impl_block, inner); | 308 | let inner_ty = Ty::from_hir(db, module, impl_block, generics, inner); |
286 | Ty::Slice(Arc::new(inner_ty)) | 309 | Ty::Slice(Arc::new(inner_ty)) |
287 | } | 310 | } |
288 | TypeRef::Reference(inner, mutability) => { | 311 | TypeRef::Reference(inner, mutability) => { |
289 | let inner_ty = Ty::from_hir(db, module, impl_block, inner); | 312 | let inner_ty = Ty::from_hir(db, module, impl_block, generics, inner); |
290 | Ty::Ref(Arc::new(inner_ty), *mutability) | 313 | Ty::Ref(Arc::new(inner_ty), *mutability) |
291 | } | 314 | } |
292 | TypeRef::Placeholder => Ty::Unknown, | 315 | TypeRef::Placeholder => Ty::Unknown, |
293 | TypeRef::Fn(params) => { | 316 | TypeRef::Fn(params) => { |
294 | let mut inner_tys = params | 317 | let mut inner_tys = params |
295 | .iter() | 318 | .iter() |
296 | .map(|tr| Ty::from_hir(db, module, impl_block, tr)) | 319 | .map(|tr| Ty::from_hir(db, module, impl_block, generics, tr)) |
297 | .collect::<Vec<_>>(); | 320 | .collect::<Vec<_>>(); |
298 | let return_ty = inner_tys | 321 | let return_ty = inner_tys |
299 | .pop() | 322 | .pop() |
@@ -312,15 +335,19 @@ impl Ty { | |||
312 | db: &impl HirDatabase, | 335 | db: &impl HirDatabase, |
313 | module: &Module, | 336 | module: &Module, |
314 | impl_block: Option<&ImplBlock>, | 337 | impl_block: Option<&ImplBlock>, |
338 | generics: &GenericParams, | ||
315 | type_ref: Option<&TypeRef>, | 339 | type_ref: Option<&TypeRef>, |
316 | ) -> Self { | 340 | ) -> Self { |
317 | type_ref.map_or(Ty::Unknown, |t| Ty::from_hir(db, module, impl_block, t)) | 341 | type_ref.map_or(Ty::Unknown, |t| { |
342 | Ty::from_hir(db, module, impl_block, generics, t) | ||
343 | }) | ||
318 | } | 344 | } |
319 | 345 | ||
320 | pub(crate) fn from_hir_path( | 346 | pub(crate) fn from_hir_path( |
321 | db: &impl HirDatabase, | 347 | db: &impl HirDatabase, |
322 | module: &Module, | 348 | module: &Module, |
323 | impl_block: Option<&ImplBlock>, | 349 | impl_block: Option<&ImplBlock>, |
350 | generics: &GenericParams, | ||
324 | path: &Path, | 351 | path: &Path, |
325 | ) -> Self { | 352 | ) -> Self { |
326 | if let Some(name) = path.as_ident() { | 353 | if let Some(name) = path.as_ident() { |
@@ -329,7 +356,15 @@ impl Ty { | |||
329 | } else if let Some(float_ty) = primitive::UncertainFloatTy::from_name(name) { | 356 | } else if let Some(float_ty) = primitive::UncertainFloatTy::from_name(name) { |
330 | return Ty::Float(float_ty); | 357 | return Ty::Float(float_ty); |
331 | } else if name.as_known_name() == Some(KnownName::SelfType) { | 358 | } else if name.as_known_name() == Some(KnownName::SelfType) { |
332 | return Ty::from_hir_opt(db, module, None, impl_block.map(|i| i.target_type())); | 359 | // TODO pass the impl block's generics? |
360 | let generics = &GenericParams::default(); | ||
361 | return Ty::from_hir_opt( | ||
362 | db, | ||
363 | module, | ||
364 | None, | ||
365 | generics, | ||
366 | impl_block.map(|i| i.target_type()), | ||
367 | ); | ||
333 | } else if let Some(known) = name.as_known_name() { | 368 | } else if let Some(known) = name.as_known_name() { |
334 | match known { | 369 | match known { |
335 | KnownName::Bool => return Ty::Bool, | 370 | KnownName::Bool => return Ty::Bool, |
@@ -337,16 +372,89 @@ impl Ty { | |||
337 | KnownName::Str => return Ty::Str, | 372 | KnownName::Str => return Ty::Str, |
338 | _ => {} | 373 | _ => {} |
339 | } | 374 | } |
375 | } else if let Some(generic_param) = generics.find_by_name(&name) { | ||
376 | return Ty::Param { | ||
377 | idx: generic_param.idx, | ||
378 | name: generic_param.name.clone(), | ||
379 | }; | ||
340 | } | 380 | } |
341 | } | 381 | } |
342 | 382 | ||
343 | // Resolve in module (in type namespace) | 383 | // Resolve in module (in type namespace) |
344 | let resolved = if let Some(r) = module.resolve_path(db, path).take_types() { | 384 | let resolved = match module.resolve_path(db, path).take_types() { |
345 | r | 385 | Some(r) => r, |
346 | } else { | 386 | None => return Ty::Unknown, |
347 | return Ty::Unknown; | ||
348 | }; | 387 | }; |
349 | db.type_for_def(resolved) | 388 | let ty = db.type_for_def(resolved); |
389 | let substs = Ty::substs_from_path(db, module, impl_block, generics, path, resolved); | ||
390 | ty.apply_substs(substs) | ||
391 | } | ||
392 | |||
393 | /// Collect generic arguments from a path into a `Substs`. See also | ||
394 | /// `create_substs_for_ast_path` and `def_to_ty` in rustc. | ||
395 | fn substs_from_path( | ||
396 | db: &impl HirDatabase, | ||
397 | // the scope of the segment... | ||
398 | module: &Module, | ||
399 | impl_block: Option<&ImplBlock>, | ||
400 | outer_generics: &GenericParams, | ||
401 | path: &Path, | ||
402 | resolved: DefId, | ||
403 | ) -> Substs { | ||
404 | let mut substs = Vec::new(); | ||
405 | let def = resolved.resolve(db); | ||
406 | let last = path | ||
407 | .segments | ||
408 | .last() | ||
409 | .expect("path should have at least one segment"); | ||
410 | let (def_generics, segment) = match def { | ||
411 | Def::Struct(s) => (s.generic_params(db), last), | ||
412 | Def::Enum(e) => (e.generic_params(db), last), | ||
413 | Def::Function(f) => (f.generic_params(db), last), | ||
414 | Def::Trait(t) => (t.generic_params(db), last), | ||
415 | Def::EnumVariant(ev) => { | ||
416 | // the generic args for an enum variant may be either specified | ||
417 | // on the segment referring to the enum, or on the segment | ||
418 | // referring to the variant. So `Option::<T>::None` and | ||
419 | // `Option::None::<T>` are both allowed (though the former is | ||
420 | // preferred). See also `def_ids_for_path_segments` in rustc. | ||
421 | let len = path.segments.len(); | ||
422 | let segment = if len >= 2 && path.segments[len - 2].args_and_bindings.is_some() { | ||
423 | // Option::<T>::None | ||
424 | &path.segments[len - 2] | ||
425 | } else { | ||
426 | // Option::None::<T> | ||
427 | last | ||
428 | }; | ||
429 | (ev.parent_enum(db).generic_params(db), segment) | ||
430 | } | ||
431 | _ => return Substs::empty(), | ||
432 | }; | ||
433 | // substs_from_path | ||
434 | if let Some(generic_args) = &segment.args_and_bindings { | ||
435 | // if args are provided, it should be all of them, but we can't rely on that | ||
436 | let param_count = def_generics.params.len(); | ||
437 | for arg in generic_args.args.iter().take(param_count) { | ||
438 | match arg { | ||
439 | GenericArg::Type(type_ref) => { | ||
440 | let ty = Ty::from_hir(db, module, impl_block, outer_generics, type_ref); | ||
441 | substs.push(ty); | ||
442 | } | ||
443 | } | ||
444 | } | ||
445 | } | ||
446 | // add placeholders for args that were not provided | ||
447 | // TODO: handle defaults | ||
448 | for _ in segment | ||
449 | .args_and_bindings | ||
450 | .as_ref() | ||
451 | .map(|ga| ga.args.len()) | ||
452 | .unwrap_or(0)..def_generics.params.len() | ||
453 | { | ||
454 | substs.push(Ty::Unknown); | ||
455 | } | ||
456 | assert_eq!(substs.len(), def_generics.params.len()); | ||
457 | Substs(substs.into()) | ||
350 | } | 458 | } |
351 | 459 | ||
352 | pub fn unit() -> Self { | 460 | pub fn unit() -> Self { |
@@ -374,7 +482,14 @@ impl Ty { | |||
374 | } | 482 | } |
375 | sig_mut.output.walk_mut(f); | 483 | sig_mut.output.walk_mut(f); |
376 | } | 484 | } |
377 | Ty::Adt { .. } => {} // need to walk type parameters later | 485 | Ty::Adt { substs, .. } => { |
486 | // Without an Arc::make_mut_slice, we can't avoid the clone here: | ||
487 | let mut v: Vec<_> = substs.0.iter().cloned().collect(); | ||
488 | for t in &mut v { | ||
489 | t.walk_mut(f); | ||
490 | } | ||
491 | substs.0 = v.into(); | ||
492 | } | ||
378 | _ => {} | 493 | _ => {} |
379 | } | 494 | } |
380 | } | 495 | } |
@@ -394,6 +509,49 @@ impl Ty { | |||
394 | _ => None, | 509 | _ => None, |
395 | } | 510 | } |
396 | } | 511 | } |
512 | |||
513 | /// If this is a type with type parameters (an ADT or function), replaces | ||
514 | /// the `Substs` for these type parameters with the given ones. (So e.g. if | ||
515 | /// `self` is `Option<_>` and the substs contain `u32`, we'll have | ||
516 | /// `Option<u32>` afterwards.) | ||
517 | pub fn apply_substs(self, substs: Substs) -> Ty { | ||
518 | match self { | ||
519 | Ty::Adt { def_id, name, .. } => Ty::Adt { | ||
520 | def_id, | ||
521 | name, | ||
522 | substs, | ||
523 | }, | ||
524 | _ => self, | ||
525 | } | ||
526 | } | ||
527 | |||
528 | /// Replaces type parameters in this type using the given `Substs`. (So e.g. | ||
529 | /// if `self` is `&[T]`, where type parameter T has index 0, and the | ||
530 | /// `Substs` contain `u32` at index 0, we'll have `&[u32]` afterwards.) | ||
531 | pub fn subst(self, substs: &Substs) -> Ty { | ||
532 | self.fold(&mut |ty| match ty { | ||
533 | Ty::Param { idx, name } => { | ||
534 | if (idx as usize) < substs.0.len() { | ||
535 | substs.0[idx as usize].clone() | ||
536 | } else { | ||
537 | // TODO: does this indicate a bug? i.e. should we always | ||
538 | // have substs for all type params? (they might contain the | ||
539 | // params themselves again...) | ||
540 | Ty::Param { idx, name } | ||
541 | } | ||
542 | } | ||
543 | ty => ty, | ||
544 | }) | ||
545 | } | ||
546 | |||
547 | /// Returns the type parameters of this type if it has some (i.e. is an ADT | ||
548 | /// or function); so if `self` is `Option<u32>`, this returns the `u32`. | ||
549 | fn substs(&self) -> Option<Substs> { | ||
550 | match self { | ||
551 | Ty::Adt { substs, .. } => Some(substs.clone()), | ||
552 | _ => None, | ||
553 | } | ||
554 | } | ||
397 | } | 555 | } |
398 | 556 | ||
399 | impl fmt::Display for Ty { | 557 | impl fmt::Display for Ty { |
@@ -425,7 +583,17 @@ impl fmt::Display for Ty { | |||
425 | .to_fmt(f)?; | 583 | .to_fmt(f)?; |
426 | write!(f, " -> {}", sig.output) | 584 | write!(f, " -> {}", sig.output) |
427 | } | 585 | } |
428 | Ty::Adt { name, .. } => write!(f, "{}", name), | 586 | Ty::Adt { name, substs, .. } => { |
587 | write!(f, "{}", name)?; | ||
588 | if substs.0.len() > 0 { | ||
589 | join(substs.0.iter()) | ||
590 | .surround_with("<", ">") | ||
591 | .separator(", ") | ||
592 | .to_fmt(f)?; | ||
593 | } | ||
594 | Ok(()) | ||
595 | } | ||
596 | Ty::Param { name, .. } => write!(f, "{}", name), | ||
429 | Ty::Unknown => write!(f, "[unknown]"), | 597 | Ty::Unknown => write!(f, "[unknown]"), |
430 | Ty::Infer(..) => write!(f, "_"), | 598 | Ty::Infer(..) => write!(f, "_"), |
431 | } | 599 | } |
@@ -440,28 +608,49 @@ fn type_for_fn(db: &impl HirDatabase, f: Function) -> Ty { | |||
440 | let signature = f.signature(db); | 608 | let signature = f.signature(db); |
441 | let module = f.module(db); | 609 | let module = f.module(db); |
442 | let impl_block = f.impl_block(db); | 610 | let impl_block = f.impl_block(db); |
443 | // TODO we ignore type parameters for now | 611 | let generics = f.generic_params(db); |
444 | let input = signature | 612 | let input = signature |
445 | .params() | 613 | .params() |
446 | .iter() | 614 | .iter() |
447 | .map(|tr| Ty::from_hir(db, &module, impl_block.as_ref(), tr)) | 615 | .map(|tr| Ty::from_hir(db, &module, impl_block.as_ref(), &generics, tr)) |
448 | .collect::<Vec<_>>(); | 616 | .collect::<Vec<_>>(); |
449 | let output = Ty::from_hir(db, &module, impl_block.as_ref(), signature.ret_type()); | 617 | let output = Ty::from_hir( |
618 | db, | ||
619 | &module, | ||
620 | impl_block.as_ref(), | ||
621 | &generics, | ||
622 | signature.ret_type(), | ||
623 | ); | ||
450 | let sig = FnSig { input, output }; | 624 | let sig = FnSig { input, output }; |
451 | Ty::FnPtr(Arc::new(sig)) | 625 | Ty::FnPtr(Arc::new(sig)) |
452 | } | 626 | } |
453 | 627 | ||
628 | fn make_substs(generics: &GenericParams) -> Substs { | ||
629 | Substs( | ||
630 | generics | ||
631 | .params | ||
632 | .iter() | ||
633 | .map(|_p| Ty::Unknown) | ||
634 | .collect::<Vec<_>>() | ||
635 | .into(), | ||
636 | ) | ||
637 | } | ||
638 | |||
454 | fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Ty { | 639 | fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Ty { |
640 | let generics = s.generic_params(db); | ||
455 | Ty::Adt { | 641 | Ty::Adt { |
456 | def_id: s.def_id(), | 642 | def_id: s.def_id(), |
457 | name: s.name(db).unwrap_or_else(Name::missing), | 643 | name: s.name(db).unwrap_or_else(Name::missing), |
644 | substs: make_substs(&generics), | ||
458 | } | 645 | } |
459 | } | 646 | } |
460 | 647 | ||
461 | pub(crate) fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Ty { | 648 | pub(crate) fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Ty { |
649 | let generics = s.generic_params(db); | ||
462 | Ty::Adt { | 650 | Ty::Adt { |
463 | def_id: s.def_id(), | 651 | def_id: s.def_id(), |
464 | name: s.name(db).unwrap_or_else(Name::missing), | 652 | name: s.name(db).unwrap_or_else(Name::missing), |
653 | substs: make_substs(&generics), | ||
465 | } | 654 | } |
466 | } | 655 | } |
467 | 656 | ||
@@ -495,19 +684,29 @@ pub(super) fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Ty { | |||
495 | 684 | ||
496 | pub(super) fn type_for_field(db: &impl HirDatabase, def_id: DefId, field: Name) -> Option<Ty> { | 685 | pub(super) fn type_for_field(db: &impl HirDatabase, def_id: DefId, field: Name) -> Option<Ty> { |
497 | let def = def_id.resolve(db); | 686 | let def = def_id.resolve(db); |
498 | let variant_data = match def { | 687 | let (variant_data, generics) = match def { |
499 | Def::Struct(s) => s.variant_data(db), | 688 | Def::Struct(s) => (s.variant_data(db), s.generic_params(db)), |
500 | Def::EnumVariant(ev) => ev.variant_data(db), | 689 | Def::EnumVariant(ev) => (ev.variant_data(db), ev.parent_enum(db).generic_params(db)), |
501 | // TODO: unions | 690 | // TODO: unions |
691 | Def::Enum(_) => { | ||
692 | // this can happen in (invalid) code, but enums don't have fields themselves | ||
693 | return None; | ||
694 | } | ||
502 | _ => panic!( | 695 | _ => panic!( |
503 | "trying to get type for field in non-struct/variant {:?}", | 696 | "trying to get type for field {:?} in non-struct/variant {:?}", |
504 | def_id | 697 | field, def_id |
505 | ), | 698 | ), |
506 | }; | 699 | }; |
507 | let module = def_id.module(db); | 700 | let module = def_id.module(db); |
508 | let impl_block = def_id.impl_block(db); | 701 | let impl_block = def_id.impl_block(db); |
509 | let type_ref = variant_data.get_field_type_ref(&field)?; | 702 | let type_ref = variant_data.get_field_type_ref(&field)?; |
510 | Some(Ty::from_hir(db, &module, impl_block.as_ref(), &type_ref)) | 703 | Some(Ty::from_hir( |
704 | db, | ||
705 | &module, | ||
706 | impl_block.as_ref(), | ||
707 | &generics, | ||
708 | &type_ref, | ||
709 | )) | ||
511 | } | 710 | } |
512 | 711 | ||
513 | /// The result of type inference: A mapping from expressions and patterns to types. | 712 | /// The result of type inference: A mapping from expressions and patterns to types. |
@@ -684,8 +883,26 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
684 | self.type_of_pat.insert(pat, ty); | 883 | self.type_of_pat.insert(pat, ty); |
685 | } | 884 | } |
686 | 885 | ||
687 | fn make_ty(&self, type_ref: &TypeRef) -> Ty { | 886 | fn make_ty(&mut self, type_ref: &TypeRef) -> Ty { |
688 | Ty::from_hir(self.db, &self.module, self.impl_block.as_ref(), type_ref) | 887 | // TODO provide generics of function |
888 | let generics = GenericParams::default(); | ||
889 | let ty = Ty::from_hir( | ||
890 | self.db, | ||
891 | &self.module, | ||
892 | self.impl_block.as_ref(), | ||
893 | &generics, | ||
894 | type_ref, | ||
895 | ); | ||
896 | let ty = self.insert_type_vars(ty); | ||
897 | ty | ||
898 | } | ||
899 | |||
900 | fn unify_substs(&mut self, substs1: &Substs, substs2: &Substs) -> bool { | ||
901 | substs1 | ||
902 | .0 | ||
903 | .iter() | ||
904 | .zip(substs2.0.iter()) | ||
905 | .all(|(t1, t2)| self.unify(t1, t2)) | ||
689 | } | 906 | } |
690 | 907 | ||
691 | fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { | 908 | fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { |
@@ -708,12 +925,16 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
708 | (Ty::Bool, _) | (Ty::Str, _) | (Ty::Never, _) | (Ty::Char, _) => ty1 == ty2, | 925 | (Ty::Bool, _) | (Ty::Str, _) | (Ty::Never, _) | (Ty::Char, _) => ty1 == ty2, |
709 | ( | 926 | ( |
710 | Ty::Adt { | 927 | Ty::Adt { |
711 | def_id: def_id1, .. | 928 | def_id: def_id1, |
929 | substs: substs1, | ||
930 | .. | ||
712 | }, | 931 | }, |
713 | Ty::Adt { | 932 | Ty::Adt { |
714 | def_id: def_id2, .. | 933 | def_id: def_id2, |
934 | substs: substs2, | ||
935 | .. | ||
715 | }, | 936 | }, |
716 | ) if def_id1 == def_id2 => true, | 937 | ) if def_id1 == def_id2 => self.unify_substs(substs1, substs2), |
717 | (Ty::Slice(t1), Ty::Slice(t2)) => self.unify(t1, t2), | 938 | (Ty::Slice(t1), Ty::Slice(t2)) => self.unify(t1, t2), |
718 | (Ty::RawPtr(t1, m1), Ty::RawPtr(t2, m2)) if m1 == m2 => self.unify(t1, t2), | 939 | (Ty::RawPtr(t1, m1), Ty::RawPtr(t2, m2)) if m1 == m2 => self.unify(t1, t2), |
719 | (Ty::Ref(t1, m1), Ty::Ref(t2, m2)) if m1 == m2 => self.unify(t1, t2), | 940 | (Ty::Ref(t1, m1), Ty::Ref(t2, m2)) if m1 == m2 => self.unify(t1, t2), |
@@ -848,73 +1069,100 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
848 | Some(ty) | 1069 | Some(ty) |
849 | } | 1070 | } |
850 | 1071 | ||
851 | fn resolve_variant(&self, path: Option<&Path>) -> (Ty, Option<DefId>) { | 1072 | fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option<DefId>) { |
852 | let path = if let Some(path) = path { | 1073 | let path = match path { |
853 | path | 1074 | Some(path) => path, |
854 | } else { | 1075 | None => return (Ty::Unknown, None), |
855 | return (Ty::Unknown, None); | ||
856 | }; | 1076 | }; |
857 | let def_id = if let Some(def_id) = self.module.resolve_path(self.db, &path).take_types() { | 1077 | let def_id = match self.module.resolve_path(self.db, &path).take_types() { |
858 | def_id | 1078 | Some(def_id) => def_id, |
859 | } else { | 1079 | _ => return (Ty::Unknown, None), |
860 | return (Ty::Unknown, None); | ||
861 | }; | 1080 | }; |
1081 | // TODO remove the duplication between here and `Ty::from_path`? | ||
1082 | // TODO provide generics of function | ||
1083 | let generics = GenericParams::default(); | ||
1084 | let substs = Ty::substs_from_path( | ||
1085 | self.db, | ||
1086 | &self.module, | ||
1087 | self.impl_block.as_ref(), | ||
1088 | &generics, | ||
1089 | path, | ||
1090 | def_id, | ||
1091 | ); | ||
862 | match def_id.resolve(self.db) { | 1092 | match def_id.resolve(self.db) { |
863 | Def::Struct(s) => { | 1093 | Def::Struct(s) => { |
864 | let ty = type_for_struct(self.db, s); | 1094 | let ty = type_for_struct(self.db, s); |
1095 | let ty = self.insert_type_vars(ty.apply_substs(substs)); | ||
865 | (ty, Some(def_id)) | 1096 | (ty, Some(def_id)) |
866 | } | 1097 | } |
867 | Def::EnumVariant(ev) => { | 1098 | Def::EnumVariant(ev) => { |
868 | let ty = type_for_enum_variant(self.db, ev); | 1099 | let ty = type_for_enum_variant(self.db, ev); |
1100 | let ty = self.insert_type_vars(ty.apply_substs(substs)); | ||
869 | (ty, Some(def_id)) | 1101 | (ty, Some(def_id)) |
870 | } | 1102 | } |
871 | _ => (Ty::Unknown, None), | 1103 | _ => (Ty::Unknown, None), |
872 | } | 1104 | } |
873 | } | 1105 | } |
874 | 1106 | ||
875 | fn resolve_fields(&self, path: Option<&Path>) -> Option<(Ty, Vec<StructField>)> { | 1107 | fn resolve_fields(&mut self, path: Option<&Path>) -> Option<(Ty, Vec<StructField>)> { |
876 | let def_id = self.module.resolve_path(self.db, path?).take_types()?; | 1108 | let (ty, def_id) = self.resolve_variant(path); |
1109 | let def_id = def_id?; | ||
877 | let def = def_id.resolve(self.db); | 1110 | let def = def_id.resolve(self.db); |
878 | 1111 | ||
879 | match def { | 1112 | match def { |
880 | Def::Struct(s) => { | 1113 | Def::Struct(s) => { |
881 | let fields = s.fields(self.db); | 1114 | let fields = s.fields(self.db); |
882 | Some((type_for_struct(self.db, s), fields)) | 1115 | Some((ty, fields)) |
883 | } | 1116 | } |
884 | Def::EnumVariant(ev) => { | 1117 | Def::EnumVariant(ev) => { |
885 | let fields = ev.fields(self.db); | 1118 | let fields = ev.fields(self.db); |
886 | Some((type_for_enum_variant(self.db, ev), fields)) | 1119 | Some((ty, fields)) |
887 | } | 1120 | } |
888 | _ => None, | 1121 | _ => None, |
889 | } | 1122 | } |
890 | } | 1123 | } |
891 | 1124 | ||
892 | fn infer_tuple_struct_pat(&mut self, path: Option<&Path>, subpats: &[PatId]) -> Ty { | 1125 | fn infer_tuple_struct_pat( |
1126 | &mut self, | ||
1127 | path: Option<&Path>, | ||
1128 | subpats: &[PatId], | ||
1129 | expected: &Ty, | ||
1130 | ) -> Ty { | ||
893 | let (ty, fields) = self | 1131 | let (ty, fields) = self |
894 | .resolve_fields(path) | 1132 | .resolve_fields(path) |
895 | .unwrap_or((Ty::Unknown, Vec::new())); | 1133 | .unwrap_or((Ty::Unknown, Vec::new())); |
896 | 1134 | ||
1135 | self.unify(&ty, expected); | ||
1136 | |||
1137 | let substs = ty.substs().expect("adt should have substs"); | ||
1138 | |||
897 | for (i, &subpat) in subpats.iter().enumerate() { | 1139 | for (i, &subpat) in subpats.iter().enumerate() { |
898 | let expected_ty = fields | 1140 | let expected_ty = fields |
899 | .get(i) | 1141 | .get(i) |
900 | .and_then(|field| field.ty(self.db)) | 1142 | .and_then(|field| field.ty(self.db)) |
901 | .unwrap_or(Ty::Unknown); | 1143 | .unwrap_or(Ty::Unknown) |
1144 | .subst(&substs); | ||
902 | self.infer_pat(subpat, &expected_ty); | 1145 | self.infer_pat(subpat, &expected_ty); |
903 | } | 1146 | } |
904 | 1147 | ||
905 | ty | 1148 | ty |
906 | } | 1149 | } |
907 | 1150 | ||
908 | fn infer_struct_pat(&mut self, path: Option<&Path>, subpats: &[FieldPat]) -> Ty { | 1151 | fn infer_struct_pat(&mut self, path: Option<&Path>, subpats: &[FieldPat], expected: &Ty) -> Ty { |
909 | let (ty, fields) = self | 1152 | let (ty, fields) = self |
910 | .resolve_fields(path) | 1153 | .resolve_fields(path) |
911 | .unwrap_or((Ty::Unknown, Vec::new())); | 1154 | .unwrap_or((Ty::Unknown, Vec::new())); |
912 | 1155 | ||
1156 | self.unify(&ty, expected); | ||
1157 | |||
1158 | let substs = ty.substs().expect("adt should have substs"); | ||
1159 | |||
913 | for subpat in subpats { | 1160 | for subpat in subpats { |
914 | let matching_field = fields.iter().find(|field| field.name() == &subpat.name); | 1161 | let matching_field = fields.iter().find(|field| field.name() == &subpat.name); |
915 | let expected_ty = matching_field | 1162 | let expected_ty = matching_field |
916 | .and_then(|field| field.ty(self.db)) | 1163 | .and_then(|field| field.ty(self.db)) |
917 | .unwrap_or(Ty::Unknown); | 1164 | .unwrap_or(Ty::Unknown) |
1165 | .subst(&substs); | ||
918 | self.infer_pat(subpat.pat, &expected_ty); | 1166 | self.infer_pat(subpat.pat, &expected_ty); |
919 | } | 1167 | } |
920 | 1168 | ||
@@ -959,11 +1207,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
959 | Pat::TupleStruct { | 1207 | Pat::TupleStruct { |
960 | path: ref p, | 1208 | path: ref p, |
961 | args: ref subpats, | 1209 | args: ref subpats, |
962 | } => self.infer_tuple_struct_pat(p.as_ref(), subpats), | 1210 | } => self.infer_tuple_struct_pat(p.as_ref(), subpats, expected), |
963 | Pat::Struct { | 1211 | Pat::Struct { |
964 | path: ref p, | 1212 | path: ref p, |
965 | args: ref fields, | 1213 | args: ref fields, |
966 | } => self.infer_struct_pat(p.as_ref(), fields), | 1214 | } => self.infer_struct_pat(p.as_ref(), fields, expected), |
967 | Pat::Path(path) => self | 1215 | Pat::Path(path) => self |
968 | .module | 1216 | .module |
969 | .resolve_path(self.db, &path) | 1217 | .resolve_path(self.db, &path) |
@@ -1155,11 +1403,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1155 | spread, | 1403 | spread, |
1156 | } => { | 1404 | } => { |
1157 | let (ty, def_id) = self.resolve_variant(path.as_ref()); | 1405 | let (ty, def_id) = self.resolve_variant(path.as_ref()); |
1406 | let substs = ty.substs().expect("adt should have substs"); | ||
1158 | for field in fields { | 1407 | for field in fields { |
1159 | let field_ty = if let Some(def_id) = def_id { | 1408 | let field_ty = if let Some(def_id) = def_id { |
1160 | self.db | 1409 | self.db |
1161 | .type_for_field(def_id, field.name.clone()) | 1410 | .type_for_field(def_id, field.name.clone()) |
1162 | .unwrap_or(Ty::Unknown) | 1411 | .unwrap_or(Ty::Unknown) |
1412 | .subst(&substs) | ||
1163 | } else { | 1413 | } else { |
1164 | Ty::Unknown | 1414 | Ty::Unknown |
1165 | }; | 1415 | }; |
@@ -1180,7 +1430,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1180 | let i = name.to_string().parse::<usize>().ok(); | 1430 | let i = name.to_string().parse::<usize>().ok(); |
1181 | i.and_then(|i| fields.get(i).cloned()) | 1431 | i.and_then(|i| fields.get(i).cloned()) |
1182 | } | 1432 | } |
1183 | Ty::Adt { def_id, .. } => self.db.type_for_field(def_id, name.clone()), | 1433 | Ty::Adt { |
1434 | def_id, ref substs, .. | ||
1435 | } => self | ||
1436 | .db | ||
1437 | .type_for_field(def_id, name.clone()) | ||
1438 | .map(|ty| ty.subst(substs)), | ||
1184 | _ => None, | 1439 | _ => None, |
1185 | }) | 1440 | }) |
1186 | .unwrap_or(Ty::Unknown); | 1441 | .unwrap_or(Ty::Unknown); |
@@ -1193,7 +1448,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1193 | Expr::Cast { expr, type_ref } => { | 1448 | Expr::Cast { expr, type_ref } => { |
1194 | let _inner_ty = self.infer_expr(*expr, &Expectation::none()); | 1449 | let _inner_ty = self.infer_expr(*expr, &Expectation::none()); |
1195 | let cast_ty = self.make_ty(type_ref); | 1450 | let cast_ty = self.make_ty(type_ref); |
1196 | let cast_ty = self.insert_type_vars(cast_ty); | ||
1197 | // TODO check the cast... | 1451 | // TODO check the cast... |
1198 | cast_ty | 1452 | cast_ty |
1199 | } | 1453 | } |
@@ -1305,12 +1559,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1305 | type_ref, | 1559 | type_ref, |
1306 | initializer, | 1560 | initializer, |
1307 | } => { | 1561 | } => { |
1308 | let decl_ty = Ty::from_hir_opt( | 1562 | let decl_ty = type_ref |
1309 | self.db, | 1563 | .as_ref() |
1310 | &self.module, | 1564 | .map(|tr| self.make_ty(tr)) |
1311 | self.impl_block.as_ref(), | 1565 | .unwrap_or(Ty::Unknown); |
1312 | type_ref.as_ref(), | ||
1313 | ); | ||
1314 | let decl_ty = self.insert_type_vars(decl_ty); | 1566 | let decl_ty = self.insert_type_vars(decl_ty); |
1315 | let ty = if let Some(expr) = initializer { | 1567 | let ty = if let Some(expr) = initializer { |
1316 | let expr_ty = self.infer_expr(*expr, &Expectation::has_type(decl_ty)); | 1568 | let expr_ty = self.infer_expr(*expr, &Expectation::has_type(decl_ty)); |
@@ -1338,13 +1590,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1338 | let body = Arc::clone(&self.body); // avoid borrow checker problem | 1590 | let body = Arc::clone(&self.body); // avoid borrow checker problem |
1339 | for (type_ref, pat) in signature.params().iter().zip(body.params()) { | 1591 | for (type_ref, pat) in signature.params().iter().zip(body.params()) { |
1340 | let ty = self.make_ty(type_ref); | 1592 | let ty = self.make_ty(type_ref); |
1341 | let ty = self.insert_type_vars(ty); | ||
1342 | 1593 | ||
1343 | self.infer_pat(*pat, &ty); | 1594 | self.infer_pat(*pat, &ty); |
1344 | } | 1595 | } |
1345 | self.return_ty = { | 1596 | self.return_ty = { |
1346 | let ty = self.make_ty(signature.ret_type()); | 1597 | let ty = self.make_ty(signature.ret_type()); |
1347 | let ty = self.insert_type_vars(ty); | ||
1348 | ty | 1598 | ty |
1349 | }; | 1599 | }; |
1350 | } | 1600 | } |
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index b221bd142..9f65c5fe1 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -8,7 +8,11 @@ use rustc_hash::FxHashMap; | |||
8 | 8 | ||
9 | use ra_db::SourceRootId; | 9 | use ra_db::SourceRootId; |
10 | 10 | ||
11 | use crate::{HirDatabase, DefId, module_tree::ModuleId, Module, Crate, Name, Function, impl_block::{ImplId, ImplBlock, ImplItem}}; | 11 | use crate::{ |
12 | HirDatabase, DefId, module_tree::ModuleId, Module, Crate, Name, Function, | ||
13 | impl_block::{ImplId, ImplBlock, ImplItem}, | ||
14 | generics::GenericParams | ||
15 | }; | ||
12 | use super::Ty; | 16 | use super::Ty; |
13 | 17 | ||
14 | /// This is used as a key for indexing impls. | 18 | /// This is used as a key for indexing impls. |
@@ -64,8 +68,15 @@ impl CrateImplBlocks { | |||
64 | if let Some(_target_trait) = impl_data.target_trait() { | 68 | if let Some(_target_trait) = impl_data.target_trait() { |
65 | // ignore for now | 69 | // ignore for now |
66 | } else { | 70 | } else { |
67 | let target_ty = | 71 | // TODO provide generics of impl |
68 | Ty::from_hir(db, &module, Some(&impl_block), impl_data.target_type()); | 72 | let generics = GenericParams::default(); |
73 | let target_ty = Ty::from_hir( | ||
74 | db, | ||
75 | &module, | ||
76 | Some(&impl_block), | ||
77 | &generics, | ||
78 | impl_data.target_type(), | ||
79 | ); | ||
69 | if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) { | 80 | if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) { |
70 | self.impls | 81 | self.impls |
71 | .entry(target_ty_fp) | 82 | .entry(target_ty_fp) |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index fc4054159..5aa24a29b 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -418,6 +418,109 @@ fn test() { | |||
418 | ); | 418 | ); |
419 | } | 419 | } |
420 | 420 | ||
421 | #[test] | ||
422 | fn infer_struct_generics() { | ||
423 | check_inference( | ||
424 | r#" | ||
425 | struct A<T> { | ||
426 | x: T, | ||
427 | } | ||
428 | |||
429 | fn test(a1: A<u32>, i: i32) { | ||
430 | a1.x; | ||
431 | let a2 = A { x: i }; | ||
432 | a2.x; | ||
433 | let a3 = A::<i128> { x: 1 }; | ||
434 | a3.x; | ||
435 | } | ||
436 | "#, | ||
437 | "struct_generics.txt", | ||
438 | ); | ||
439 | } | ||
440 | |||
441 | #[test] | ||
442 | fn infer_generics_in_patterns() { | ||
443 | check_inference( | ||
444 | r#" | ||
445 | struct A<T> { | ||
446 | x: T, | ||
447 | } | ||
448 | |||
449 | enum Option<T> { | ||
450 | Some(T), | ||
451 | None, | ||
452 | } | ||
453 | |||
454 | fn test(a1: A<u32>, o: Option<u64>) { | ||
455 | let A { x: x2 } = a1; | ||
456 | let A::<i64> { x: x3 } = A { x: 1 }; | ||
457 | match o { | ||
458 | Option::Some(t) => t, | ||
459 | _ => 1, | ||
460 | }; | ||
461 | } | ||
462 | "#, | ||
463 | "generics_in_patterns.txt", | ||
464 | ); | ||
465 | } | ||
466 | |||
467 | #[test] | ||
468 | fn infer_function_generics() { | ||
469 | check_inference( | ||
470 | r#" | ||
471 | fn id<T>(t: T) -> T { t } | ||
472 | |||
473 | fn test() { | ||
474 | id(1u32); | ||
475 | id::<i128>(1); | ||
476 | let x: u64 = id(1); | ||
477 | } | ||
478 | "#, | ||
479 | "function_generics.txt", | ||
480 | ); | ||
481 | } | ||
482 | |||
483 | #[test] | ||
484 | fn infer_generic_chain() { | ||
485 | check_inference( | ||
486 | r#" | ||
487 | struct A<T> { | ||
488 | x: T, | ||
489 | } | ||
490 | impl<T2> A<T2> { | ||
491 | fn x(self) -> T2 { | ||
492 | self.x | ||
493 | } | ||
494 | } | ||
495 | fn id<T>(t: T) -> T { t } | ||
496 | |||
497 | fn test() -> i128 { | ||
498 | let x = 1; | ||
499 | let y = id(x); | ||
500 | let a = A { x: id(y) }; | ||
501 | let z = id(a.x); | ||
502 | let b = A { x: z }; | ||
503 | b.x() | ||
504 | } | ||
505 | "#, | ||
506 | "generic_chain.txt", | ||
507 | ); | ||
508 | } | ||
509 | |||
510 | #[test] | ||
511 | fn no_panic_on_field_of_enum() { | ||
512 | check_inference( | ||
513 | r#" | ||
514 | enum X {} | ||
515 | |||
516 | fn test(x: X) { | ||
517 | x.some_field; | ||
518 | } | ||
519 | "#, | ||
520 | "no_panic_on_field_of_enum.txt", | ||
521 | ); | ||
522 | } | ||
523 | |||
421 | fn infer(content: &str) -> String { | 524 | fn infer(content: &str) -> String { |
422 | let (db, _, file_id) = MockDatabase::with_single_file(content); | 525 | let (db, _, file_id) = MockDatabase::with_single_file(content); |
423 | let source_file = db.source_file(file_id); | 526 | let source_file = db.source_file(file_id); |
diff --git a/crates/ra_hir/src/ty/tests/data/function_generics.txt b/crates/ra_hir/src/ty/tests/data/function_generics.txt new file mode 100644 index 000000000..e44d26cfd --- /dev/null +++ b/crates/ra_hir/src/ty/tests/data/function_generics.txt | |||
@@ -0,0 +1,14 @@ | |||
1 | [10; 11) 't': [unknown] | ||
2 | [21; 26) '{ t }': [unknown] | ||
3 | [23; 24) 't': [unknown] | ||
4 | [38; 98) '{ ...(1); }': () | ||
5 | [44; 46) 'id': fn(T) -> T | ||
6 | [44; 52) 'id(1u32)': T | ||
7 | [47; 51) '1u32': u32 | ||
8 | [58; 68) 'id::<i128>': fn(T) -> T | ||
9 | [58; 71) 'id::<i128>(1)': T | ||
10 | [69; 70) '1': T | ||
11 | [81; 82) 'x': T | ||
12 | [90; 92) 'id': fn(T) -> T | ||
13 | [90; 95) 'id(1)': T | ||
14 | [93; 94) '1': T | ||
diff --git a/crates/ra_hir/src/ty/tests/data/generic_chain.txt b/crates/ra_hir/src/ty/tests/data/generic_chain.txt new file mode 100644 index 000000000..568e00846 --- /dev/null +++ b/crates/ra_hir/src/ty/tests/data/generic_chain.txt | |||
@@ -0,0 +1,29 @@ | |||
1 | [53; 57) 'self': A<[unknown]> | ||
2 | [65; 87) '{ ... }': [unknown] | ||
3 | [75; 79) 'self': A<[unknown]> | ||
4 | [75; 81) 'self.x': [unknown] | ||
5 | [99; 100) 't': [unknown] | ||
6 | [110; 115) '{ t }': [unknown] | ||
7 | [112; 113) 't': [unknown] | ||
8 | [135; 261) '{ ....x() }': i128 | ||
9 | [146; 147) 'x': T | ||
10 | [150; 151) '1': T | ||
11 | [162; 163) 'y': T | ||
12 | [166; 168) 'id': fn(T) -> T | ||
13 | [166; 171) 'id(x)': T | ||
14 | [169; 170) 'x': T | ||
15 | [182; 183) 'a': A<T> | ||
16 | [186; 200) 'A { x: id(y) }': A<T> | ||
17 | [193; 195) 'id': fn(T) -> T | ||
18 | [193; 198) 'id(y)': T | ||
19 | [196; 197) 'y': T | ||
20 | [211; 212) 'z': T | ||
21 | [215; 217) 'id': fn(T) -> T | ||
22 | [215; 222) 'id(a.x)': T | ||
23 | [218; 219) 'a': A<T> | ||
24 | [218; 221) 'a.x': T | ||
25 | [233; 234) 'b': A<T> | ||
26 | [237; 247) 'A { x: z }': A<T> | ||
27 | [244; 245) 'z': T | ||
28 | [254; 255) 'b': A<T> | ||
29 | [254; 259) 'b.x()': i128 | ||
diff --git a/crates/ra_hir/src/ty/tests/data/generics_in_patterns.txt b/crates/ra_hir/src/ty/tests/data/generics_in_patterns.txt new file mode 100644 index 000000000..1b01ef19e --- /dev/null +++ b/crates/ra_hir/src/ty/tests/data/generics_in_patterns.txt | |||
@@ -0,0 +1,17 @@ | |||
1 | [79; 81) 'a1': A<u32> | ||
2 | [91; 92) 'o': Option<u64> | ||
3 | [107; 244) '{ ... }; }': () | ||
4 | [117; 128) 'A { x: x2 }': A<u32> | ||
5 | [124; 126) 'x2': u32 | ||
6 | [131; 133) 'a1': A<u32> | ||
7 | [143; 161) 'A::<i6...: x3 }': A<i64> | ||
8 | [157; 159) 'x3': i64 | ||
9 | [164; 174) 'A { x: 1 }': A<i64> | ||
10 | [171; 172) '1': i64 | ||
11 | [180; 241) 'match ... }': u64 | ||
12 | [186; 187) 'o': Option<u64> | ||
13 | [198; 213) 'Option::Some(t)': Option<u64> | ||
14 | [211; 212) 't': u64 | ||
15 | [217; 218) 't': u64 | ||
16 | [228; 229) '_': Option<u64> | ||
17 | [233; 234) '1': u64 | ||
diff --git a/crates/ra_hir/src/ty/tests/data/no_panic_on_field_of_enum.txt b/crates/ra_hir/src/ty/tests/data/no_panic_on_field_of_enum.txt new file mode 100644 index 000000000..4dca0b7f4 --- /dev/null +++ b/crates/ra_hir/src/ty/tests/data/no_panic_on_field_of_enum.txt | |||
@@ -0,0 +1,4 @@ | |||
1 | [20; 21) 'x': X | ||
2 | [26; 47) '{ ...eld; }': () | ||
3 | [32; 33) 'x': X | ||
4 | [32; 44) 'x.some_field': [unknown] | ||
diff --git a/crates/ra_hir/src/ty/tests/data/struct_generics.txt b/crates/ra_hir/src/ty/tests/data/struct_generics.txt new file mode 100644 index 000000000..1024a39a9 --- /dev/null +++ b/crates/ra_hir/src/ty/tests/data/struct_generics.txt | |||
@@ -0,0 +1,15 @@ | |||
1 | [36; 38) 'a1': A<u32> | ||
2 | [48; 49) 'i': i32 | ||
3 | [56; 147) '{ ...3.x; }': () | ||
4 | [62; 64) 'a1': A<u32> | ||
5 | [62; 66) 'a1.x': u32 | ||
6 | [76; 78) 'a2': A<i32> | ||
7 | [81; 91) 'A { x: i }': A<i32> | ||
8 | [88; 89) 'i': i32 | ||
9 | [97; 99) 'a2': A<i32> | ||
10 | [97; 101) 'a2.x': i32 | ||
11 | [111; 113) 'a3': A<i128> | ||
12 | [116; 134) 'A::<i1...x: 1 }': A<i128> | ||
13 | [131; 132) '1': i128 | ||
14 | [140; 142) 'a3': A<i128> | ||
15 | [140; 144) 'a3.x': i128 | ||
diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs index fb8b2fc88..32fd497be 100644 --- a/crates/ra_ide_api/src/completion/complete_dot.rs +++ b/crates/ra_ide_api/src/completion/complete_dot.rs | |||
@@ -25,7 +25,9 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { | |||
25 | fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) { | 25 | fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) { |
26 | for receiver in receiver.autoderef(ctx.db) { | 26 | for receiver in receiver.autoderef(ctx.db) { |
27 | match receiver { | 27 | match receiver { |
28 | Ty::Adt { def_id, .. } => { | 28 | Ty::Adt { |
29 | def_id, ref substs, .. | ||
30 | } => { | ||
29 | match def_id.resolve(ctx.db) { | 31 | match def_id.resolve(ctx.db) { |
30 | Def::Struct(s) => { | 32 | Def::Struct(s) => { |
31 | for field in s.fields(ctx.db) { | 33 | for field in s.fields(ctx.db) { |
@@ -35,7 +37,7 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) | |||
35 | field.name().to_string(), | 37 | field.name().to_string(), |
36 | ) | 38 | ) |
37 | .kind(CompletionItemKind::Field) | 39 | .kind(CompletionItemKind::Field) |
38 | .set_detail(field.ty(ctx.db).map(|ty| ty.to_string())) | 40 | .set_detail(field.ty(ctx.db).map(|ty| ty.subst(substs).to_string())) |
39 | .add_to(acc); | 41 | .add_to(acc); |
40 | } | 42 | } |
41 | } | 43 | } |
diff --git a/crates/ra_ide_api/src/db.rs b/crates/ra_ide_api/src/db.rs index c2978f909..a1b666899 100644 --- a/crates/ra_ide_api/src/db.rs +++ b/crates/ra_ide_api/src/db.rs | |||
@@ -129,6 +129,7 @@ salsa::database_storage! { | |||
129 | fn body_hir() for hir::db::BodyHirQuery; | 129 | fn body_hir() for hir::db::BodyHirQuery; |
130 | fn body_syntax_mapping() for hir::db::BodySyntaxMappingQuery; | 130 | fn body_syntax_mapping() for hir::db::BodySyntaxMappingQuery; |
131 | fn fn_signature() for hir::db::FnSignatureQuery; | 131 | fn fn_signature() for hir::db::FnSignatureQuery; |
132 | fn generic_params() for hir::db::GenericParamsQuery; | ||
132 | } | 133 | } |
133 | } | 134 | } |
134 | } | 135 | } |
diff --git a/crates/ra_ide_api/src/extend_selection.rs b/crates/ra_ide_api/src/extend_selection.rs index 9f0ab2f1c..718b4def5 100644 --- a/crates/ra_ide_api/src/extend_selection.rs +++ b/crates/ra_ide_api/src/extend_selection.rs | |||
@@ -51,7 +51,7 @@ mod tests { | |||
51 | } | 51 | } |
52 | ", | 52 | ", |
53 | ); | 53 | ); |
54 | let r = analysis.extend_selection(frange); | 54 | let r = analysis.extend_selection(frange).unwrap(); |
55 | assert_eq!(r, TextRange::from_to(51.into(), 56.into())); | 55 | assert_eq!(r, TextRange::from_to(51.into(), 56.into())); |
56 | } | 56 | } |
57 | } | 57 | } |
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index fb0821ff6..a09a8f926 100644 --- a/crates/ra_ide_api/src/lib.rs +++ b/crates/ra_ide_api/src/lib.rs | |||
@@ -299,7 +299,7 @@ impl Analysis { | |||
299 | } | 299 | } |
300 | 300 | ||
301 | /// Gets the syntax tree of the file. | 301 | /// Gets the syntax tree of the file. |
302 | pub fn file_syntax(&self, file_id: FileId) -> TreeArc<SourceFile> { | 302 | pub fn parse(&self, file_id: FileId) -> TreeArc<SourceFile> { |
303 | self.db.source_file(file_id).clone() | 303 | self.db.source_file(file_id).clone() |
304 | } | 304 | } |
305 | 305 | ||
@@ -310,14 +310,15 @@ impl Analysis { | |||
310 | } | 310 | } |
311 | 311 | ||
312 | /// Selects the next syntactic nodes encopasing the range. | 312 | /// Selects the next syntactic nodes encopasing the range. |
313 | pub fn extend_selection(&self, frange: FileRange) -> TextRange { | 313 | pub fn extend_selection(&self, frange: FileRange) -> Cancelable<TextRange> { |
314 | extend_selection::extend_selection(&self.db, frange) | 314 | self.with_db(|db| extend_selection::extend_selection(db, frange)) |
315 | } | 315 | } |
316 | 316 | ||
317 | /// Returns position of the mathcing brace (all types of braces are | 317 | /// Returns position of the mathcing brace (all types of braces are |
318 | /// supported). | 318 | /// supported). |
319 | pub fn matching_brace(&self, file: &SourceFile, offset: TextUnit) -> Option<TextUnit> { | 319 | pub fn matching_brace(&self, position: FilePosition) -> Option<TextUnit> { |
320 | ra_ide_api_light::matching_brace(file, offset) | 320 | let file = self.db.source_file(position.file_id); |
321 | ra_ide_api_light::matching_brace(&file, position.offset) | ||
321 | } | 322 | } |
322 | 323 | ||
323 | /// Returns a syntax tree represented as `String`, for debug purposes. | 324 | /// Returns a syntax tree represented as `String`, for debug purposes. |
@@ -388,8 +389,7 @@ impl Analysis { | |||
388 | &self, | 389 | &self, |
389 | position: FilePosition, | 390 | position: FilePosition, |
390 | ) -> Cancelable<Option<RangeInfo<Vec<NavigationTarget>>>> { | 391 | ) -> Cancelable<Option<RangeInfo<Vec<NavigationTarget>>>> { |
391 | self.db | 392 | self.with_db(|db| goto_definition::goto_definition(db, position)) |
392 | .catch_canceled(|db| goto_definition::goto_definition(db, position)) | ||
393 | } | 393 | } |
394 | 394 | ||
395 | /// Finds all usages of the reference at point. | 395 | /// Finds all usages of the reference at point. |
@@ -404,8 +404,7 @@ impl Analysis { | |||
404 | 404 | ||
405 | /// Computes parameter information for the given call expression. | 405 | /// Computes parameter information for the given call expression. |
406 | pub fn call_info(&self, position: FilePosition) -> Cancelable<Option<CallInfo>> { | 406 | pub fn call_info(&self, position: FilePosition) -> Cancelable<Option<CallInfo>> { |
407 | self.db | 407 | self.with_db(|db| call_info::call_info(db, position)) |
408 | .catch_canceled(|db| call_info::call_info(db, position)) | ||
409 | } | 408 | } |
410 | 409 | ||
411 | /// Returns a `mod name;` declaration which created the current module. | 410 | /// Returns a `mod name;` declaration which created the current module. |
@@ -420,33 +419,28 @@ impl Analysis { | |||
420 | 419 | ||
421 | /// Returns the root file of the given crate. | 420 | /// Returns the root file of the given crate. |
422 | pub fn crate_root(&self, crate_id: CrateId) -> Cancelable<FileId> { | 421 | pub fn crate_root(&self, crate_id: CrateId) -> Cancelable<FileId> { |
423 | Ok(self.db.crate_graph().crate_root(crate_id)) | 422 | self.with_db(|db| db.crate_graph().crate_root(crate_id)) |
424 | } | 423 | } |
425 | 424 | ||
426 | /// Returns the set of possible targets to run for the current file. | 425 | /// Returns the set of possible targets to run for the current file. |
427 | pub fn runnables(&self, file_id: FileId) -> Cancelable<Vec<Runnable>> { | 426 | pub fn runnables(&self, file_id: FileId) -> Cancelable<Vec<Runnable>> { |
428 | self.db | 427 | self.with_db(|db| runnables::runnables(db, file_id)) |
429 | .catch_canceled(|db| runnables::runnables(db, file_id)) | ||
430 | } | 428 | } |
431 | 429 | ||
432 | /// Computes syntax highlighting for the given file. | 430 | /// Computes syntax highlighting for the given file. |
433 | pub fn highlight(&self, file_id: FileId) -> Cancelable<Vec<HighlightedRange>> { | 431 | pub fn highlight(&self, file_id: FileId) -> Cancelable<Vec<HighlightedRange>> { |
434 | self.db | 432 | self.with_db(|db| syntax_highlighting::highlight(db, file_id)) |
435 | .catch_canceled(|db| syntax_highlighting::highlight(db, file_id)) | ||
436 | } | 433 | } |
437 | 434 | ||
438 | /// Computes completions at the given position. | 435 | /// Computes completions at the given position. |
439 | pub fn completions(&self, position: FilePosition) -> Cancelable<Option<Vec<CompletionItem>>> { | 436 | pub fn completions(&self, position: FilePosition) -> Cancelable<Option<Vec<CompletionItem>>> { |
440 | let completions = self | 437 | self.with_db(|db| completion::completions(db, position).map(Into::into)) |
441 | .db | ||
442 | .catch_canceled(|db| completion::completions(db, position))?; | ||
443 | Ok(completions.map(|it| it.into())) | ||
444 | } | 438 | } |
445 | 439 | ||
446 | /// Computes assists (aks code actons aka intentions) for the given | 440 | /// Computes assists (aks code actons aka intentions) for the given |
447 | /// position. | 441 | /// position. |
448 | pub fn assists(&self, frange: FileRange) -> Cancelable<Vec<SourceChange>> { | 442 | pub fn assists(&self, frange: FileRange) -> Cancelable<Vec<SourceChange>> { |
449 | Ok(self.db.assists(frange)) | 443 | self.with_db(|db| db.assists(frange)) |
450 | } | 444 | } |
451 | 445 | ||
452 | /// Computes the set of diagnostics for the given file. | 446 | /// Computes the set of diagnostics for the given file. |
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index d1e8c5774..497f819be 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs | |||
@@ -8,7 +8,7 @@ use lsp_types::{ | |||
8 | WorkspaceEdit | 8 | WorkspaceEdit |
9 | }; | 9 | }; |
10 | use ra_ide_api::{ | 10 | use ra_ide_api::{ |
11 | FileId, FilePosition, FileRange, FoldKind, Query, RangeInfo, RunnableKind, Severity, | 11 | FileId, FilePosition, FileRange, FoldKind, Query, RangeInfo, RunnableKind, Severity, Cancelable, |
12 | }; | 12 | }; |
13 | use ra_syntax::{AstNode, TextUnit}; | 13 | use ra_syntax::{AstNode, TextUnit}; |
14 | use rustc_hash::FxHashMap; | 14 | use rustc_hash::FxHashMap; |
@@ -40,9 +40,13 @@ pub fn handle_extend_selection( | |||
40 | .into_iter() | 40 | .into_iter() |
41 | .map_conv_with(&line_index) | 41 | .map_conv_with(&line_index) |
42 | .map(|range| FileRange { file_id, range }) | 42 | .map(|range| FileRange { file_id, range }) |
43 | .map(|frange| world.analysis().extend_selection(frange)) | 43 | .map(|frange| { |
44 | .map_conv_with(&line_index) | 44 | world |
45 | .collect(); | 45 | .analysis() |
46 | .extend_selection(frange) | ||
47 | .map(|it| it.conv_with(&line_index)) | ||
48 | }) | ||
49 | .collect::<Cancelable<Vec<_>>>()?; | ||
46 | Ok(req::ExtendSelectionResult { selections }) | 50 | Ok(req::ExtendSelectionResult { selections }) |
47 | } | 51 | } |
48 | 52 | ||
@@ -51,7 +55,6 @@ pub fn handle_find_matching_brace( | |||
51 | params: req::FindMatchingBraceParams, | 55 | params: req::FindMatchingBraceParams, |
52 | ) -> Result<Vec<Position>> { | 56 | ) -> Result<Vec<Position>> { |
53 | let file_id = params.text_document.try_conv_with(&world)?; | 57 | let file_id = params.text_document.try_conv_with(&world)?; |
54 | let file = world.analysis().file_syntax(file_id); | ||
55 | let line_index = world.analysis().file_line_index(file_id); | 58 | let line_index = world.analysis().file_line_index(file_id); |
56 | let res = params | 59 | let res = params |
57 | .offsets | 60 | .offsets |
@@ -60,7 +63,7 @@ pub fn handle_find_matching_brace( | |||
60 | .map(|offset| { | 63 | .map(|offset| { |
61 | world | 64 | world |
62 | .analysis() | 65 | .analysis() |
63 | .matching_brace(&file, offset) | 66 | .matching_brace(FilePosition { file_id, offset }) |
64 | .unwrap_or(offset) | 67 | .unwrap_or(offset) |
65 | }) | 68 | }) |
66 | .map_conv_with(&line_index) | 69 | .map_conv_with(&line_index) |
@@ -315,7 +318,7 @@ pub fn handle_completion( | |||
315 | let mut res = false; | 318 | let mut res = false; |
316 | if let Some(ctx) = params.context { | 319 | if let Some(ctx) = params.context { |
317 | if ctx.trigger_character.unwrap_or_default() == ":" { | 320 | if ctx.trigger_character.unwrap_or_default() == ":" { |
318 | let source_file = world.analysis().file_syntax(position.file_id); | 321 | let source_file = world.analysis().parse(position.file_id); |
319 | let syntax = source_file.syntax(); | 322 | let syntax = source_file.syntax(); |
320 | let text = syntax.text(); | 323 | let text = syntax.text(); |
321 | if let Some(next_char) = text.char_at(position.offset) { | 324 | if let Some(next_char) = text.char_at(position.offset) { |
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index 271040bf4..9fe946172 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs | |||
@@ -105,6 +105,38 @@ impl ArrayType { | |||
105 | } | 105 | } |
106 | } | 106 | } |
107 | 107 | ||
108 | // AssocTypeArg | ||
109 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
110 | #[repr(transparent)] | ||
111 | pub struct AssocTypeArg { | ||
112 | pub(crate) syntax: SyntaxNode, | ||
113 | } | ||
114 | unsafe impl TransparentNewType for AssocTypeArg { | ||
115 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
116 | } | ||
117 | |||
118 | impl AstNode for AssocTypeArg { | ||
119 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
120 | match syntax.kind() { | ||
121 | ASSOC_TYPE_ARG => Some(AssocTypeArg::from_repr(syntax.into_repr())), | ||
122 | _ => None, | ||
123 | } | ||
124 | } | ||
125 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
126 | fn to_owned(&self) -> TreeArc<AssocTypeArg> { TreeArc::cast(self.syntax.to_owned()) } | ||
127 | } | ||
128 | |||
129 | |||
130 | impl AssocTypeArg { | ||
131 | pub fn name_ref(&self) -> Option<&NameRef> { | ||
132 | super::child_opt(self) | ||
133 | } | ||
134 | |||
135 | pub fn type_ref(&self) -> Option<&TypeRef> { | ||
136 | super::child_opt(self) | ||
137 | } | ||
138 | } | ||
139 | |||
108 | // Attr | 140 | // Attr |
109 | #[derive(Debug, PartialEq, Eq, Hash)] | 141 | #[derive(Debug, PartialEq, Eq, Hash)] |
110 | #[repr(transparent)] | 142 | #[repr(transparent)] |
@@ -1397,6 +1429,34 @@ impl AstNode for Lifetime { | |||
1397 | impl ast::AstToken for Lifetime {} | 1429 | impl ast::AstToken for Lifetime {} |
1398 | impl Lifetime {} | 1430 | impl Lifetime {} |
1399 | 1431 | ||
1432 | // LifetimeArg | ||
1433 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
1434 | #[repr(transparent)] | ||
1435 | pub struct LifetimeArg { | ||
1436 | pub(crate) syntax: SyntaxNode, | ||
1437 | } | ||
1438 | unsafe impl TransparentNewType for LifetimeArg { | ||
1439 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
1440 | } | ||
1441 | |||
1442 | impl AstNode for LifetimeArg { | ||
1443 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
1444 | match syntax.kind() { | ||
1445 | LIFETIME_ARG => Some(LifetimeArg::from_repr(syntax.into_repr())), | ||
1446 | _ => None, | ||
1447 | } | ||
1448 | } | ||
1449 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
1450 | fn to_owned(&self) -> TreeArc<LifetimeArg> { TreeArc::cast(self.syntax.to_owned()) } | ||
1451 | } | ||
1452 | |||
1453 | |||
1454 | impl LifetimeArg { | ||
1455 | pub fn lifetime(&self) -> Option<&Lifetime> { | ||
1456 | super::child_opt(self) | ||
1457 | } | ||
1458 | } | ||
1459 | |||
1400 | // LifetimeParam | 1460 | // LifetimeParam |
1401 | #[derive(Debug, PartialEq, Eq, Hash)] | 1461 | #[derive(Debug, PartialEq, Eq, Hash)] |
1402 | #[repr(transparent)] | 1462 | #[repr(transparent)] |
@@ -2355,6 +2415,10 @@ impl PathSegment { | |||
2355 | pub fn name_ref(&self) -> Option<&NameRef> { | 2415 | pub fn name_ref(&self) -> Option<&NameRef> { |
2356 | super::child_opt(self) | 2416 | super::child_opt(self) |
2357 | } | 2417 | } |
2418 | |||
2419 | pub fn type_arg_list(&self) -> Option<&TypeArgList> { | ||
2420 | super::child_opt(self) | ||
2421 | } | ||
2358 | } | 2422 | } |
2359 | 2423 | ||
2360 | // PathType | 2424 | // PathType |
@@ -3335,6 +3399,70 @@ impl TupleType { | |||
3335 | } | 3399 | } |
3336 | } | 3400 | } |
3337 | 3401 | ||
3402 | // TypeArg | ||
3403 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
3404 | #[repr(transparent)] | ||
3405 | pub struct TypeArg { | ||
3406 | pub(crate) syntax: SyntaxNode, | ||
3407 | } | ||
3408 | unsafe impl TransparentNewType for TypeArg { | ||
3409 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
3410 | } | ||
3411 | |||
3412 | impl AstNode for TypeArg { | ||
3413 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
3414 | match syntax.kind() { | ||
3415 | TYPE_ARG => Some(TypeArg::from_repr(syntax.into_repr())), | ||
3416 | _ => None, | ||
3417 | } | ||
3418 | } | ||
3419 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
3420 | fn to_owned(&self) -> TreeArc<TypeArg> { TreeArc::cast(self.syntax.to_owned()) } | ||
3421 | } | ||
3422 | |||
3423 | |||
3424 | impl TypeArg { | ||
3425 | pub fn type_ref(&self) -> Option<&TypeRef> { | ||
3426 | super::child_opt(self) | ||
3427 | } | ||
3428 | } | ||
3429 | |||
3430 | // TypeArgList | ||
3431 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
3432 | #[repr(transparent)] | ||
3433 | pub struct TypeArgList { | ||
3434 | pub(crate) syntax: SyntaxNode, | ||
3435 | } | ||
3436 | unsafe impl TransparentNewType for TypeArgList { | ||
3437 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
3438 | } | ||
3439 | |||
3440 | impl AstNode for TypeArgList { | ||
3441 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
3442 | match syntax.kind() { | ||
3443 | TYPE_ARG_LIST => Some(TypeArgList::from_repr(syntax.into_repr())), | ||
3444 | _ => None, | ||
3445 | } | ||
3446 | } | ||
3447 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
3448 | fn to_owned(&self) -> TreeArc<TypeArgList> { TreeArc::cast(self.syntax.to_owned()) } | ||
3449 | } | ||
3450 | |||
3451 | |||
3452 | impl TypeArgList { | ||
3453 | pub fn type_args(&self) -> impl Iterator<Item = &TypeArg> { | ||
3454 | super::children(self) | ||
3455 | } | ||
3456 | |||
3457 | pub fn lifetime_args(&self) -> impl Iterator<Item = &LifetimeArg> { | ||
3458 | super::children(self) | ||
3459 | } | ||
3460 | |||
3461 | pub fn assoc_type_args(&self) -> impl Iterator<Item = &AssocTypeArg> { | ||
3462 | super::children(self) | ||
3463 | } | ||
3464 | } | ||
3465 | |||
3338 | // TypeDef | 3466 | // TypeDef |
3339 | #[derive(Debug, PartialEq, Eq, Hash)] | 3467 | #[derive(Debug, PartialEq, Eq, Hash)] |
3340 | #[repr(transparent)] | 3468 | #[repr(transparent)] |
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index fc47c36d3..0385183fd 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron | |||
@@ -597,8 +597,16 @@ Grammar( | |||
597 | ] | 597 | ] |
598 | ), | 598 | ), |
599 | "PathSegment": ( | 599 | "PathSegment": ( |
600 | options: [ "NameRef" ] | 600 | options: [ "NameRef", "TypeArgList" ] |
601 | ), | 601 | ), |
602 | "TypeArgList": (collections: [ | ||
603 | ["type_args", "TypeArg"], | ||
604 | ["lifetime_args", "LifetimeArg"], | ||
605 | ["assoc_type_args", "AssocTypeArg"], | ||
606 | ]), | ||
607 | "TypeArg": (options: ["TypeRef"]), | ||
608 | "AssocTypeArg": (options: ["NameRef", "TypeRef"]), | ||
609 | "LifetimeArg": (options: ["Lifetime"]), | ||
602 | "Comment": ( traits: ["AstToken"] ), | 610 | "Comment": ( traits: ["AstToken"] ), |
603 | "Whitespace": ( traits: ["AstToken"] ), | 611 | "Whitespace": ( traits: ["AstToken"] ), |
604 | }, | 612 | }, |