diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-24 20:08:10 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-24 20:08:10 +0000 |
commit | 61d961263387f7293f3d0c4d7b8c8c9a07959ced (patch) | |
tree | b22232818d8d8ad8fff5b11b1656e2602115cd55 /crates/ra_hir | |
parent | 5a684099e9aa3482b408002030fafe1dcd0fa9a9 (diff) | |
parent | c3c09795614f31f988edc9cb051ce024d1996d89 (diff) |
Merge #892
892: Type aliases r=matklad a=flodiebold
This implements type aliases (i.e. `type` definitions).
There's just one snag: handling recursion. E.g. `type Foo = Foo` makes type inference panic with a query cycle. I think the best way to handle this would be if Salsa provided the ability to catch cycle errors? It seems that there's some work underway to support this [here](https://github.com/salsa-rs/salsa/issues/6) and [here](https://github.com/salsa-rs/salsa/pull/147). Should we wait for this? I don't see a good way to handle this without help from Salsa.
Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir')
-rw-r--r-- | crates/ra_hir/src/code_model_api.rs | 17 | ||||
-rw-r--r-- | crates/ra_hir/src/db.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 32 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/snapshots/tests__infer_type_alias.snap | 23 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 35 | ||||
-rw-r--r-- | crates/ra_hir/src/type_alias.rs | 10 |
8 files changed, 116 insertions, 11 deletions
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs index 0779a08a9..29c08e34b 100644 --- a/crates/ra_hir/src/code_model_api.rs +++ b/crates/ra_hir/src/code_model_api.rs | |||
@@ -626,6 +626,23 @@ impl Type { | |||
626 | let module_impls = db.impls_in_module(self.module(db)); | 626 | let module_impls = db.impls_in_module(self.module(db)); |
627 | ImplBlock::containing(module_impls, (*self).into()) | 627 | ImplBlock::containing(module_impls, (*self).into()) |
628 | } | 628 | } |
629 | |||
630 | pub fn type_ref(self, db: &impl PersistentHirDatabase) -> Arc<TypeRef> { | ||
631 | db.type_alias_ref(self) | ||
632 | } | ||
633 | |||
634 | /// Builds a resolver for the type references in this type alias. | ||
635 | pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { | ||
636 | // take the outer scope... | ||
637 | let r = self | ||
638 | .impl_block(db) | ||
639 | .map(|ib| ib.resolver(db)) | ||
640 | .unwrap_or_else(|| self.module(db).resolver(db)); | ||
641 | // ...and add generic params, if present | ||
642 | let p = self.generic_params(db); | ||
643 | let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r }; | ||
644 | r | ||
645 | } | ||
629 | } | 646 | } |
630 | 647 | ||
631 | impl Docs for Type { | 648 | impl Docs for Type { |
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index fc0ee068c..b8bd82f0c 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -15,7 +15,7 @@ use crate::{ | |||
15 | adt::{StructData, EnumData}, | 15 | adt::{StructData, EnumData}, |
16 | impl_block::{ModuleImplBlocks, ImplSourceMap}, | 16 | impl_block::{ModuleImplBlocks, ImplSourceMap}, |
17 | generics::{GenericParams, GenericDef}, | 17 | generics::{GenericParams, GenericDef}, |
18 | ids::SourceFileItemId, nameres::Namespace | 18 | ids::SourceFileItemId, nameres::Namespace, type_ref::TypeRef, code_model_api::Type |
19 | }; | 19 | }; |
20 | 20 | ||
21 | #[salsa::query_group(PersistentHirDatabaseStorage)] | 21 | #[salsa::query_group(PersistentHirDatabaseStorage)] |
@@ -77,6 +77,9 @@ pub trait PersistentHirDatabase: SourceDatabase + AsRef<HirInterner> { | |||
77 | 77 | ||
78 | #[salsa::invoke(crate::FnSignature::fn_signature_query)] | 78 | #[salsa::invoke(crate::FnSignature::fn_signature_query)] |
79 | fn fn_signature(&self, func: Function) -> Arc<FnSignature>; | 79 | fn fn_signature(&self, func: Function) -> Arc<FnSignature>; |
80 | |||
81 | #[salsa::invoke(crate::type_alias::type_alias_ref_query)] | ||
82 | fn type_alias_ref(&self, typ: Type) -> Arc<TypeRef>; | ||
80 | } | 83 | } |
81 | 84 | ||
82 | #[salsa::query_group(HirDatabaseStorage)] | 85 | #[salsa::query_group(HirDatabaseStorage)] |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index f2e0aae6c..78fa4952b 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -29,6 +29,7 @@ mod name; | |||
29 | mod module_tree; | 29 | mod module_tree; |
30 | mod nameres; | 30 | mod nameres; |
31 | mod adt; | 31 | mod adt; |
32 | mod type_alias; | ||
32 | mod type_ref; | 33 | mod type_ref; |
33 | mod ty; | 34 | mod ty; |
34 | mod impl_block; | 35 | mod impl_block; |
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 13080b5aa..29331bea5 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -477,7 +477,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
477 | let ty = self.insert_type_vars(ty.apply_substs(substs)); | 477 | let ty = self.insert_type_vars(ty.apply_substs(substs)); |
478 | (ty, Some(var.into())) | 478 | (ty, Some(var.into())) |
479 | } | 479 | } |
480 | TypableDef::Function(_) | TypableDef::Enum(_) => (Ty::Unknown, None), | 480 | TypableDef::Type(_) | TypableDef::Function(_) | TypableDef::Enum(_) => { |
481 | (Ty::Unknown, None) | ||
482 | } | ||
481 | } | 483 | } |
482 | } | 484 | } |
483 | 485 | ||
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 63e13a30e..a11d964c8 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -10,7 +10,7 @@ use std::sync::Arc; | |||
10 | 10 | ||
11 | use crate::{ | 11 | use crate::{ |
12 | Function, Struct, StructField, Enum, EnumVariant, Path, Name, | 12 | Function, Struct, StructField, Enum, EnumVariant, Path, Name, |
13 | ModuleDef, | 13 | ModuleDef, Type, |
14 | HirDatabase, | 14 | HirDatabase, |
15 | type_ref::TypeRef, | 15 | type_ref::TypeRef, |
16 | name::KnownName, | 16 | name::KnownName, |
@@ -109,7 +109,7 @@ impl Ty { | |||
109 | }; | 109 | }; |
110 | let ty = db.type_for_def(typable, Namespace::Types); | 110 | let ty = db.type_for_def(typable, Namespace::Types); |
111 | let substs = Ty::substs_from_path(db, resolver, path, typable); | 111 | let substs = Ty::substs_from_path(db, resolver, path, typable); |
112 | ty.apply_substs(substs) | 112 | ty.subst(&substs) |
113 | } | 113 | } |
114 | 114 | ||
115 | pub(super) fn substs_from_path_segment( | 115 | pub(super) fn substs_from_path_segment( |
@@ -124,6 +124,7 @@ impl Ty { | |||
124 | TypableDef::Struct(s) => s.generic_params(db), | 124 | TypableDef::Struct(s) => s.generic_params(db), |
125 | TypableDef::Enum(e) => e.generic_params(db), | 125 | TypableDef::Enum(e) => e.generic_params(db), |
126 | TypableDef::EnumVariant(var) => var.parent_enum(db).generic_params(db), | 126 | TypableDef::EnumVariant(var) => var.parent_enum(db).generic_params(db), |
127 | TypableDef::Type(t) => t.generic_params(db), | ||
127 | }; | 128 | }; |
128 | let parent_param_count = def_generics.count_parent_params(); | 129 | let parent_param_count = def_generics.count_parent_params(); |
129 | substs.extend((0..parent_param_count).map(|_| Ty::Unknown)); | 130 | substs.extend((0..parent_param_count).map(|_| Ty::Unknown)); |
@@ -159,9 +160,10 @@ impl Ty { | |||
159 | ) -> Substs { | 160 | ) -> Substs { |
160 | let last = path.segments.last().expect("path should have at least one segment"); | 161 | let last = path.segments.last().expect("path should have at least one segment"); |
161 | let segment = match resolved { | 162 | let segment = match resolved { |
162 | TypableDef::Function(_) => last, | 163 | TypableDef::Function(_) |
163 | TypableDef::Struct(_) => last, | 164 | | TypableDef::Struct(_) |
164 | TypableDef::Enum(_) => last, | 165 | | TypableDef::Enum(_) |
166 | | TypableDef::Type(_) => last, | ||
165 | TypableDef::EnumVariant(_) => { | 167 | TypableDef::EnumVariant(_) => { |
166 | // the generic args for an enum variant may be either specified | 168 | // the generic args for an enum variant may be either specified |
167 | // on the segment referring to the enum, or on the segment | 169 | // on the segment referring to the enum, or on the segment |
@@ -194,11 +196,13 @@ pub(crate) fn type_for_def(db: &impl HirDatabase, def: TypableDef, ns: Namespace | |||
194 | (TypableDef::Struct(s), Namespace::Values) => type_for_struct_constructor(db, s), | 196 | (TypableDef::Struct(s), Namespace::Values) => type_for_struct_constructor(db, s), |
195 | (TypableDef::Enum(e), Namespace::Types) => type_for_enum(db, e), | 197 | (TypableDef::Enum(e), Namespace::Types) => type_for_enum(db, e), |
196 | (TypableDef::EnumVariant(v), Namespace::Values) => type_for_enum_variant_constructor(db, v), | 198 | (TypableDef::EnumVariant(v), Namespace::Values) => type_for_enum_variant_constructor(db, v), |
199 | (TypableDef::Type(t), Namespace::Types) => type_for_type_alias(db, t), | ||
197 | 200 | ||
198 | // 'error' cases: | 201 | // 'error' cases: |
199 | (TypableDef::Function(_), Namespace::Types) => Ty::Unknown, | 202 | (TypableDef::Function(_), Namespace::Types) => Ty::Unknown, |
200 | (TypableDef::Enum(_), Namespace::Values) => Ty::Unknown, | 203 | (TypableDef::Enum(_), Namespace::Values) => Ty::Unknown, |
201 | (TypableDef::EnumVariant(_), Namespace::Types) => Ty::Unknown, | 204 | (TypableDef::EnumVariant(_), Namespace::Types) => Ty::Unknown, |
205 | (TypableDef::Type(_), Namespace::Values) => Ty::Unknown, | ||
202 | } | 206 | } |
203 | } | 207 | } |
204 | 208 | ||
@@ -264,7 +268,7 @@ fn type_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariant) -> | |||
264 | .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref)) | 268 | .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref)) |
265 | .collect::<Vec<_>>(); | 269 | .collect::<Vec<_>>(); |
266 | let substs = make_substs(&generics); | 270 | let substs = make_substs(&generics); |
267 | let output = type_for_enum(db, def.parent_enum(db)).apply_substs(substs.clone()); | 271 | let output = type_for_enum(db, def.parent_enum(db)).subst(&substs); |
268 | let sig = Arc::new(FnSig { input, output }); | 272 | let sig = Arc::new(FnSig { input, output }); |
269 | Ty::FnDef { def: def.into(), sig, name, substs } | 273 | Ty::FnDef { def: def.into(), sig, name, substs } |
270 | } | 274 | } |
@@ -298,14 +302,24 @@ fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Ty { | |||
298 | } | 302 | } |
299 | } | 303 | } |
300 | 304 | ||
305 | fn type_for_type_alias(db: &impl HirDatabase, t: Type) -> Ty { | ||
306 | let generics = t.generic_params(db); | ||
307 | let resolver = t.resolver(db); | ||
308 | let type_ref = t.type_ref(db); | ||
309 | let substs = make_substs(&generics); | ||
310 | let inner = Ty::from_hir(db, &resolver, &type_ref); | ||
311 | inner.subst(&substs) | ||
312 | } | ||
313 | |||
301 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | 314 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] |
302 | pub enum TypableDef { | 315 | pub enum TypableDef { |
303 | Function(Function), | 316 | Function(Function), |
304 | Struct(Struct), | 317 | Struct(Struct), |
305 | Enum(Enum), | 318 | Enum(Enum), |
306 | EnumVariant(EnumVariant), | 319 | EnumVariant(EnumVariant), |
320 | Type(Type), | ||
307 | } | 321 | } |
308 | impl_froms!(TypableDef: Function, Struct, Enum, EnumVariant); | 322 | impl_froms!(TypableDef: Function, Struct, Enum, EnumVariant, Type); |
309 | 323 | ||
310 | impl From<ModuleDef> for Option<TypableDef> { | 324 | impl From<ModuleDef> for Option<TypableDef> { |
311 | fn from(def: ModuleDef) -> Option<TypableDef> { | 325 | fn from(def: ModuleDef) -> Option<TypableDef> { |
@@ -314,11 +328,11 @@ impl From<ModuleDef> for Option<TypableDef> { | |||
314 | ModuleDef::Struct(s) => s.into(), | 328 | ModuleDef::Struct(s) => s.into(), |
315 | ModuleDef::Enum(e) => e.into(), | 329 | ModuleDef::Enum(e) => e.into(), |
316 | ModuleDef::EnumVariant(v) => v.into(), | 330 | ModuleDef::EnumVariant(v) => v.into(), |
331 | ModuleDef::Type(t) => t.into(), | ||
317 | ModuleDef::Const(_) | 332 | ModuleDef::Const(_) |
318 | | ModuleDef::Static(_) | 333 | | ModuleDef::Static(_) |
319 | | ModuleDef::Module(_) | 334 | | ModuleDef::Module(_) |
320 | | ModuleDef::Trait(_) | 335 | | ModuleDef::Trait(_) => return None, |
321 | | ModuleDef::Type(_) => return None, | ||
322 | }; | 336 | }; |
323 | Some(res) | 337 | Some(res) |
324 | } | 338 | } |
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_type_alias.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_type_alias.snap new file mode 100644 index 000000000..241c08353 --- /dev/null +++ b/crates/ra_hir/src/ty/snapshots/tests__infer_type_alias.snap | |||
@@ -0,0 +1,23 @@ | |||
1 | --- | ||
2 | created: "2019-02-24T16:13:47.561870283Z" | ||
3 | creator: [email protected] | ||
4 | source: crates/ra_hir/src/ty/tests.rs | ||
5 | expression: "&result" | ||
6 | --- | ||
7 | [117; 118) 'x': A<u32, i128> | ||
8 | [125; 126) 'y': A<&str, u128> | ||
9 | [139; 140) 'z': A<u8, i8> | ||
10 | [155; 212) '{ ...z.y; }': () | ||
11 | [161; 162) 'x': A<u32, i128> | ||
12 | [161; 164) 'x.x': u32 | ||
13 | [170; 171) 'x': A<u32, i128> | ||
14 | [170; 173) 'x.y': i128 | ||
15 | [179; 180) 'y': A<&str, u128> | ||
16 | [179; 182) 'y.x': &str | ||
17 | [188; 189) 'y': A<&str, u128> | ||
18 | [188; 191) 'y.y': u128 | ||
19 | [197; 198) 'z': A<u8, i8> | ||
20 | [197; 200) 'z.x': u8 | ||
21 | [206; 207) 'z': A<u8, i8> | ||
22 | [206; 209) 'z.y': i8 | ||
23 | |||
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index d0da34677..642259225 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -741,6 +741,41 @@ fn test() { | |||
741 | } | 741 | } |
742 | 742 | ||
743 | #[test] | 743 | #[test] |
744 | fn infer_type_alias() { | ||
745 | check_inference( | ||
746 | "infer_type_alias", | ||
747 | r#" | ||
748 | struct A<X, Y> { x: X, y: Y }; | ||
749 | type Foo = A<u32, i128>; | ||
750 | type Bar<T> = A<T, u128>; | ||
751 | type Baz<U, V> = A<V, U>; | ||
752 | fn test(x: Foo, y: Bar<&str>, z: Baz<i8, u8>) { | ||
753 | x.x; | ||
754 | x.y; | ||
755 | y.x; | ||
756 | y.y; | ||
757 | z.x; | ||
758 | z.y; | ||
759 | } | ||
760 | "#, | ||
761 | ) | ||
762 | } | ||
763 | |||
764 | #[test] | ||
765 | #[should_panic] // we currently can't handle this | ||
766 | fn recursive_type_alias() { | ||
767 | check_inference( | ||
768 | "recursive_type_alias", | ||
769 | r#" | ||
770 | struct A<X> {}; | ||
771 | type Foo = Foo; | ||
772 | type Bar = A<Bar>; | ||
773 | fn test(x: Foo) {} | ||
774 | "#, | ||
775 | ) | ||
776 | } | ||
777 | |||
778 | #[test] | ||
744 | fn no_panic_on_field_of_enum() { | 779 | fn no_panic_on_field_of_enum() { |
745 | check_inference( | 780 | check_inference( |
746 | "no_panic_on_field_of_enum", | 781 | "no_panic_on_field_of_enum", |
diff --git a/crates/ra_hir/src/type_alias.rs b/crates/ra_hir/src/type_alias.rs new file mode 100644 index 000000000..ab9481708 --- /dev/null +++ b/crates/ra_hir/src/type_alias.rs | |||
@@ -0,0 +1,10 @@ | |||
1 | //! HIR for type aliases (i.e. the `type` keyword). | ||
2 | |||
3 | use std::sync::Arc; | ||
4 | |||
5 | use crate::{code_model_api::Type, db::PersistentHirDatabase, type_ref::TypeRef}; | ||
6 | |||
7 | pub(crate) fn type_alias_ref_query(db: &impl PersistentHirDatabase, typ: Type) -> Arc<TypeRef> { | ||
8 | let (_, node) = typ.source(db); | ||
9 | Arc::new(TypeRef::from_ast_opt(node.type_ref())) | ||
10 | } | ||