diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-01-19 18:03:36 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-01-19 18:03:36 +0000 |
commit | 1c296d54e3dcc36c1a778873f26035000a352ba2 (patch) | |
tree | 0a6ce660ee32080287284c93bffaaaada91f3584 /crates/ra_hir/src | |
parent | bade91db081a3465dea3547ab8ab669f78fde9dc (diff) | |
parent | 5f3509e140d19b989db418a00ac6778c622cde5d (diff) |
Merge #576
576: Beginnings of generics r=matklad a=flodiebold
This implements the beginnings of the generics infrastructure; generic parameters for structs work and are correctly substituted in fields. Functions and methods aren't handled at all yet (as the tests show).
The name resolution in `ty` really needs refactoring now, I hope to do that next ;)
Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/adt.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir/src/code_model_api.rs | 21 | ||||
-rw-r--r-- | crates/ra_hir/src/code_model_impl/module.rs | 25 | ||||
-rw-r--r-- | crates/ra_hir/src/db.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/generics.rs | 48 | ||||
-rw-r--r-- | crates/ra_hir/src/ids.rs | 9 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/mock.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 24 | ||||
-rw-r--r-- | crates/ra_hir/src/path.rs | 68 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 370 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 17 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 89 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/data/function_generics.txt | 14 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/data/generic_chain.txt | 29 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/data/generics_in_patterns.txt | 17 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/data/struct_generics.txt | 15 |
17 files changed, 663 insertions, 94 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 7215236f9..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,7 +147,7 @@ impl Module { | |||
147 | .def_id, | 147 | .def_id, |
148 | ); | 148 | ); |
149 | 149 | ||
150 | for name in path.segments.iter() { | 150 | for segment in path.segments.iter() { |
151 | let curr = match curr_per_ns.as_ref().take_types() { | 151 | let curr = match curr_per_ns.as_ref().take_types() { |
152 | Some(r) => r, | 152 | Some(r) => r, |
153 | None => { | 153 | None => { |
@@ -163,15 +163,17 @@ impl Module { | |||
163 | curr_per_ns = match curr.resolve(db) { | 163 | curr_per_ns = match curr.resolve(db) { |
164 | Def::Module(m) => { | 164 | Def::Module(m) => { |
165 | let scope = m.scope(db); | 165 | let scope = m.scope(db); |
166 | match scope.get(&name) { | 166 | match scope.get(&segment.name) { |
167 | Some(r) => r.def_id, | 167 | Some(r) => r.def_id, |
168 | None => PerNs::none(), | 168 | None => PerNs::none(), |
169 | } | 169 | } |
170 | } | 170 | } |
171 | Def::Enum(e) => { | 171 | Def::Enum(e) => { |
172 | // enum variant | 172 | // enum variant |
173 | let matching_variant = | 173 | let matching_variant = e |
174 | e.variants(db).into_iter().find(|(n, _variant)| n == name); | 174 | .variants(db) |
175 | .into_iter() | ||
176 | .find(|(n, _variant)| n == &segment.name); | ||
175 | 177 | ||
176 | match matching_variant { | 178 | match matching_variant { |
177 | Some((_n, variant)) => PerNs::both(variant.def_id(), e.def_id()), | 179 | Some((_n, variant)) => PerNs::both(variant.def_id(), e.def_id()), |
@@ -189,7 +191,10 @@ impl Module { | |||
189 | curr_per_ns | 191 | curr_per_ns |
190 | } | 192 | } |
191 | 193 | ||
192 | 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)> { | ||
193 | let loc = self.def_id.loc(db); | 198 | let loc = self.def_id.loc(db); |
194 | let module_tree = db.module_tree(loc.source_root_id); | 199 | let module_tree = db.module_tree(loc.source_root_id); |
195 | 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..9b7182485 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,9 +684,9 @@ 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 |
502 | _ => panic!( | 691 | _ => panic!( |
503 | "trying to get type for field in non-struct/variant {:?}", | 692 | "trying to get type for field in non-struct/variant {:?}", |
@@ -507,7 +696,13 @@ pub(super) fn type_for_field(db: &impl HirDatabase, def_id: DefId, field: Name) | |||
507 | let module = def_id.module(db); | 696 | let module = def_id.module(db); |
508 | let impl_block = def_id.impl_block(db); | 697 | let impl_block = def_id.impl_block(db); |
509 | let type_ref = variant_data.get_field_type_ref(&field)?; | 698 | let type_ref = variant_data.get_field_type_ref(&field)?; |
510 | Some(Ty::from_hir(db, &module, impl_block.as_ref(), &type_ref)) | 699 | Some(Ty::from_hir( |
700 | db, | ||
701 | &module, | ||
702 | impl_block.as_ref(), | ||
703 | &generics, | ||
704 | &type_ref, | ||
705 | )) | ||
511 | } | 706 | } |
512 | 707 | ||
513 | /// The result of type inference: A mapping from expressions and patterns to types. | 708 | /// The result of type inference: A mapping from expressions and patterns to types. |
@@ -684,8 +879,26 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
684 | self.type_of_pat.insert(pat, ty); | 879 | self.type_of_pat.insert(pat, ty); |
685 | } | 880 | } |
686 | 881 | ||
687 | fn make_ty(&self, type_ref: &TypeRef) -> Ty { | 882 | fn make_ty(&mut self, type_ref: &TypeRef) -> Ty { |
688 | Ty::from_hir(self.db, &self.module, self.impl_block.as_ref(), type_ref) | 883 | // TODO provide generics of function |
884 | let generics = GenericParams::default(); | ||
885 | let ty = Ty::from_hir( | ||
886 | self.db, | ||
887 | &self.module, | ||
888 | self.impl_block.as_ref(), | ||
889 | &generics, | ||
890 | type_ref, | ||
891 | ); | ||
892 | let ty = self.insert_type_vars(ty); | ||
893 | ty | ||
894 | } | ||
895 | |||
896 | fn unify_substs(&mut self, substs1: &Substs, substs2: &Substs) -> bool { | ||
897 | substs1 | ||
898 | .0 | ||
899 | .iter() | ||
900 | .zip(substs2.0.iter()) | ||
901 | .all(|(t1, t2)| self.unify(t1, t2)) | ||
689 | } | 902 | } |
690 | 903 | ||
691 | fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { | 904 | fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { |
@@ -708,12 +921,16 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
708 | (Ty::Bool, _) | (Ty::Str, _) | (Ty::Never, _) | (Ty::Char, _) => ty1 == ty2, | 921 | (Ty::Bool, _) | (Ty::Str, _) | (Ty::Never, _) | (Ty::Char, _) => ty1 == ty2, |
709 | ( | 922 | ( |
710 | Ty::Adt { | 923 | Ty::Adt { |
711 | def_id: def_id1, .. | 924 | def_id: def_id1, |
925 | substs: substs1, | ||
926 | .. | ||
712 | }, | 927 | }, |
713 | Ty::Adt { | 928 | Ty::Adt { |
714 | def_id: def_id2, .. | 929 | def_id: def_id2, |
930 | substs: substs2, | ||
931 | .. | ||
715 | }, | 932 | }, |
716 | ) if def_id1 == def_id2 => true, | 933 | ) if def_id1 == def_id2 => self.unify_substs(substs1, substs2), |
717 | (Ty::Slice(t1), Ty::Slice(t2)) => self.unify(t1, t2), | 934 | (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), | 935 | (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), | 936 | (Ty::Ref(t1, m1), Ty::Ref(t2, m2)) if m1 == m2 => self.unify(t1, t2), |
@@ -848,73 +1065,100 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
848 | Some(ty) | 1065 | Some(ty) |
849 | } | 1066 | } |
850 | 1067 | ||
851 | fn resolve_variant(&self, path: Option<&Path>) -> (Ty, Option<DefId>) { | 1068 | fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option<DefId>) { |
852 | let path = if let Some(path) = path { | 1069 | let path = match path { |
853 | path | 1070 | Some(path) => path, |
854 | } else { | 1071 | None => return (Ty::Unknown, None), |
855 | return (Ty::Unknown, None); | ||
856 | }; | 1072 | }; |
857 | let def_id = if let Some(def_id) = self.module.resolve_path(self.db, &path).take_types() { | 1073 | let def_id = match self.module.resolve_path(self.db, &path).take_types() { |
858 | def_id | 1074 | Some(def_id) => def_id, |
859 | } else { | 1075 | _ => return (Ty::Unknown, None), |
860 | return (Ty::Unknown, None); | ||
861 | }; | 1076 | }; |
1077 | // TODO remove the duplication between here and `Ty::from_path`? | ||
1078 | // TODO provide generics of function | ||
1079 | let generics = GenericParams::default(); | ||
1080 | let substs = Ty::substs_from_path( | ||
1081 | self.db, | ||
1082 | &self.module, | ||
1083 | self.impl_block.as_ref(), | ||
1084 | &generics, | ||
1085 | path, | ||
1086 | def_id, | ||
1087 | ); | ||
862 | match def_id.resolve(self.db) { | 1088 | match def_id.resolve(self.db) { |
863 | Def::Struct(s) => { | 1089 | Def::Struct(s) => { |
864 | let ty = type_for_struct(self.db, s); | 1090 | let ty = type_for_struct(self.db, s); |
1091 | let ty = self.insert_type_vars(ty.apply_substs(substs)); | ||
865 | (ty, Some(def_id)) | 1092 | (ty, Some(def_id)) |
866 | } | 1093 | } |
867 | Def::EnumVariant(ev) => { | 1094 | Def::EnumVariant(ev) => { |
868 | let ty = type_for_enum_variant(self.db, ev); | 1095 | let ty = type_for_enum_variant(self.db, ev); |
1096 | let ty = self.insert_type_vars(ty.apply_substs(substs)); | ||
869 | (ty, Some(def_id)) | 1097 | (ty, Some(def_id)) |
870 | } | 1098 | } |
871 | _ => (Ty::Unknown, None), | 1099 | _ => (Ty::Unknown, None), |
872 | } | 1100 | } |
873 | } | 1101 | } |
874 | 1102 | ||
875 | fn resolve_fields(&self, path: Option<&Path>) -> Option<(Ty, Vec<StructField>)> { | 1103 | 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()?; | 1104 | let (ty, def_id) = self.resolve_variant(path); |
1105 | let def_id = def_id?; | ||
877 | let def = def_id.resolve(self.db); | 1106 | let def = def_id.resolve(self.db); |
878 | 1107 | ||
879 | match def { | 1108 | match def { |
880 | Def::Struct(s) => { | 1109 | Def::Struct(s) => { |
881 | let fields = s.fields(self.db); | 1110 | let fields = s.fields(self.db); |
882 | Some((type_for_struct(self.db, s), fields)) | 1111 | Some((ty, fields)) |
883 | } | 1112 | } |
884 | Def::EnumVariant(ev) => { | 1113 | Def::EnumVariant(ev) => { |
885 | let fields = ev.fields(self.db); | 1114 | let fields = ev.fields(self.db); |
886 | Some((type_for_enum_variant(self.db, ev), fields)) | 1115 | Some((ty, fields)) |
887 | } | 1116 | } |
888 | _ => None, | 1117 | _ => None, |
889 | } | 1118 | } |
890 | } | 1119 | } |
891 | 1120 | ||
892 | fn infer_tuple_struct_pat(&mut self, path: Option<&Path>, subpats: &[PatId]) -> Ty { | 1121 | fn infer_tuple_struct_pat( |
1122 | &mut self, | ||
1123 | path: Option<&Path>, | ||
1124 | subpats: &[PatId], | ||
1125 | expected: &Ty, | ||
1126 | ) -> Ty { | ||
893 | let (ty, fields) = self | 1127 | let (ty, fields) = self |
894 | .resolve_fields(path) | 1128 | .resolve_fields(path) |
895 | .unwrap_or((Ty::Unknown, Vec::new())); | 1129 | .unwrap_or((Ty::Unknown, Vec::new())); |
896 | 1130 | ||
1131 | self.unify(&ty, expected); | ||
1132 | |||
1133 | let substs = ty.substs().expect("adt should have substs"); | ||
1134 | |||
897 | for (i, &subpat) in subpats.iter().enumerate() { | 1135 | for (i, &subpat) in subpats.iter().enumerate() { |
898 | let expected_ty = fields | 1136 | let expected_ty = fields |
899 | .get(i) | 1137 | .get(i) |
900 | .and_then(|field| field.ty(self.db)) | 1138 | .and_then(|field| field.ty(self.db)) |
901 | .unwrap_or(Ty::Unknown); | 1139 | .unwrap_or(Ty::Unknown) |
1140 | .subst(&substs); | ||
902 | self.infer_pat(subpat, &expected_ty); | 1141 | self.infer_pat(subpat, &expected_ty); |
903 | } | 1142 | } |
904 | 1143 | ||
905 | ty | 1144 | ty |
906 | } | 1145 | } |
907 | 1146 | ||
908 | fn infer_struct_pat(&mut self, path: Option<&Path>, subpats: &[FieldPat]) -> Ty { | 1147 | fn infer_struct_pat(&mut self, path: Option<&Path>, subpats: &[FieldPat], expected: &Ty) -> Ty { |
909 | let (ty, fields) = self | 1148 | let (ty, fields) = self |
910 | .resolve_fields(path) | 1149 | .resolve_fields(path) |
911 | .unwrap_or((Ty::Unknown, Vec::new())); | 1150 | .unwrap_or((Ty::Unknown, Vec::new())); |
912 | 1151 | ||
1152 | self.unify(&ty, expected); | ||
1153 | |||
1154 | let substs = ty.substs().expect("adt should have substs"); | ||
1155 | |||
913 | for subpat in subpats { | 1156 | for subpat in subpats { |
914 | let matching_field = fields.iter().find(|field| field.name() == &subpat.name); | 1157 | let matching_field = fields.iter().find(|field| field.name() == &subpat.name); |
915 | let expected_ty = matching_field | 1158 | let expected_ty = matching_field |
916 | .and_then(|field| field.ty(self.db)) | 1159 | .and_then(|field| field.ty(self.db)) |
917 | .unwrap_or(Ty::Unknown); | 1160 | .unwrap_or(Ty::Unknown) |
1161 | .subst(&substs); | ||
918 | self.infer_pat(subpat.pat, &expected_ty); | 1162 | self.infer_pat(subpat.pat, &expected_ty); |
919 | } | 1163 | } |
920 | 1164 | ||
@@ -959,11 +1203,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
959 | Pat::TupleStruct { | 1203 | Pat::TupleStruct { |
960 | path: ref p, | 1204 | path: ref p, |
961 | args: ref subpats, | 1205 | args: ref subpats, |
962 | } => self.infer_tuple_struct_pat(p.as_ref(), subpats), | 1206 | } => self.infer_tuple_struct_pat(p.as_ref(), subpats, expected), |
963 | Pat::Struct { | 1207 | Pat::Struct { |
964 | path: ref p, | 1208 | path: ref p, |
965 | args: ref fields, | 1209 | args: ref fields, |
966 | } => self.infer_struct_pat(p.as_ref(), fields), | 1210 | } => self.infer_struct_pat(p.as_ref(), fields, expected), |
967 | Pat::Path(path) => self | 1211 | Pat::Path(path) => self |
968 | .module | 1212 | .module |
969 | .resolve_path(self.db, &path) | 1213 | .resolve_path(self.db, &path) |
@@ -1155,11 +1399,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1155 | spread, | 1399 | spread, |
1156 | } => { | 1400 | } => { |
1157 | let (ty, def_id) = self.resolve_variant(path.as_ref()); | 1401 | let (ty, def_id) = self.resolve_variant(path.as_ref()); |
1402 | let substs = ty.substs().expect("adt should have substs"); | ||
1158 | for field in fields { | 1403 | for field in fields { |
1159 | let field_ty = if let Some(def_id) = def_id { | 1404 | let field_ty = if let Some(def_id) = def_id { |
1160 | self.db | 1405 | self.db |
1161 | .type_for_field(def_id, field.name.clone()) | 1406 | .type_for_field(def_id, field.name.clone()) |
1162 | .unwrap_or(Ty::Unknown) | 1407 | .unwrap_or(Ty::Unknown) |
1408 | .subst(&substs) | ||
1163 | } else { | 1409 | } else { |
1164 | Ty::Unknown | 1410 | Ty::Unknown |
1165 | }; | 1411 | }; |
@@ -1180,7 +1426,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1180 | let i = name.to_string().parse::<usize>().ok(); | 1426 | let i = name.to_string().parse::<usize>().ok(); |
1181 | i.and_then(|i| fields.get(i).cloned()) | 1427 | i.and_then(|i| fields.get(i).cloned()) |
1182 | } | 1428 | } |
1183 | Ty::Adt { def_id, .. } => self.db.type_for_field(def_id, name.clone()), | 1429 | Ty::Adt { |
1430 | def_id, ref substs, .. | ||
1431 | } => self | ||
1432 | .db | ||
1433 | .type_for_field(def_id, name.clone()) | ||
1434 | .map(|ty| ty.subst(substs)), | ||
1184 | _ => None, | 1435 | _ => None, |
1185 | }) | 1436 | }) |
1186 | .unwrap_or(Ty::Unknown); | 1437 | .unwrap_or(Ty::Unknown); |
@@ -1193,7 +1444,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1193 | Expr::Cast { expr, type_ref } => { | 1444 | Expr::Cast { expr, type_ref } => { |
1194 | let _inner_ty = self.infer_expr(*expr, &Expectation::none()); | 1445 | let _inner_ty = self.infer_expr(*expr, &Expectation::none()); |
1195 | let cast_ty = self.make_ty(type_ref); | 1446 | let cast_ty = self.make_ty(type_ref); |
1196 | let cast_ty = self.insert_type_vars(cast_ty); | ||
1197 | // TODO check the cast... | 1447 | // TODO check the cast... |
1198 | cast_ty | 1448 | cast_ty |
1199 | } | 1449 | } |
@@ -1305,12 +1555,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1305 | type_ref, | 1555 | type_ref, |
1306 | initializer, | 1556 | initializer, |
1307 | } => { | 1557 | } => { |
1308 | let decl_ty = Ty::from_hir_opt( | 1558 | let decl_ty = type_ref |
1309 | self.db, | 1559 | .as_ref() |
1310 | &self.module, | 1560 | .map(|tr| self.make_ty(tr)) |
1311 | self.impl_block.as_ref(), | 1561 | .unwrap_or(Ty::Unknown); |
1312 | type_ref.as_ref(), | ||
1313 | ); | ||
1314 | let decl_ty = self.insert_type_vars(decl_ty); | 1562 | let decl_ty = self.insert_type_vars(decl_ty); |
1315 | let ty = if let Some(expr) = initializer { | 1563 | let ty = if let Some(expr) = initializer { |
1316 | let expr_ty = self.infer_expr(*expr, &Expectation::has_type(decl_ty)); | 1564 | let expr_ty = self.infer_expr(*expr, &Expectation::has_type(decl_ty)); |
@@ -1338,13 +1586,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1338 | let body = Arc::clone(&self.body); // avoid borrow checker problem | 1586 | let body = Arc::clone(&self.body); // avoid borrow checker problem |
1339 | for (type_ref, pat) in signature.params().iter().zip(body.params()) { | 1587 | for (type_ref, pat) in signature.params().iter().zip(body.params()) { |
1340 | let ty = self.make_ty(type_ref); | 1588 | let ty = self.make_ty(type_ref); |
1341 | let ty = self.insert_type_vars(ty); | ||
1342 | 1589 | ||
1343 | self.infer_pat(*pat, &ty); | 1590 | self.infer_pat(*pat, &ty); |
1344 | } | 1591 | } |
1345 | self.return_ty = { | 1592 | self.return_ty = { |
1346 | let ty = self.make_ty(signature.ret_type()); | 1593 | let ty = self.make_ty(signature.ret_type()); |
1347 | let ty = self.insert_type_vars(ty); | ||
1348 | ty | 1594 | ty |
1349 | }; | 1595 | }; |
1350 | } | 1596 | } |
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..06e32df59 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -418,6 +418,95 @@ 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 | |||
421 | fn infer(content: &str) -> String { | 510 | fn infer(content: &str) -> String { |
422 | let (db, _, file_id) = MockDatabase::with_single_file(content); | 511 | let (db, _, file_id) = MockDatabase::with_single_file(content); |
423 | let source_file = db.source_file(file_id); | 512 | 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/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 | ||