aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-02-24 20:08:10 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-02-24 20:08:10 +0000
commit61d961263387f7293f3d0c4d7b8c8c9a07959ced (patch)
treeb22232818d8d8ad8fff5b11b1656e2602115cd55 /crates
parent5a684099e9aa3482b408002030fafe1dcd0fa9a9 (diff)
parentc3c09795614f31f988edc9cb051ce024d1996d89 (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')
-rw-r--r--crates/ra_hir/src/code_model_api.rs17
-rw-r--r--crates/ra_hir/src/db.rs5
-rw-r--r--crates/ra_hir/src/lib.rs1
-rw-r--r--crates/ra_hir/src/ty/infer.rs4
-rw-r--r--crates/ra_hir/src/ty/lower.rs32
-rw-r--r--crates/ra_hir/src/ty/snapshots/tests__infer_type_alias.snap23
-rw-r--r--crates/ra_hir/src/ty/tests.rs35
-rw-r--r--crates/ra_hir/src/type_alias.rs10
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
631impl Docs for Type { 648impl 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;
29mod module_tree; 29mod module_tree;
30mod nameres; 30mod nameres;
31mod adt; 31mod adt;
32mod type_alias;
32mod type_ref; 33mod type_ref;
33mod ty; 34mod ty;
34mod impl_block; 35mod 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
11use crate::{ 11use 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
305fn 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)]
302pub enum TypableDef { 315pub 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}
308impl_froms!(TypableDef: Function, Struct, Enum, EnumVariant); 322impl_froms!(TypableDef: Function, Struct, Enum, EnumVariant, Type);
309 323
310impl From<ModuleDef> for Option<TypableDef> { 324impl 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---
2created: "2019-02-24T16:13:47.561870283Z"
3creator: [email protected]
4source: crates/ra_hir/src/ty/tests.rs
5expression: "&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]
744fn infer_type_alias() {
745 check_inference(
746 "infer_type_alias",
747 r#"
748struct A<X, Y> { x: X, y: Y };
749type Foo = A<u32, i128>;
750type Bar<T> = A<T, u128>;
751type Baz<U, V> = A<V, U>;
752fn 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
766fn recursive_type_alias() {
767 check_inference(
768 "recursive_type_alias",
769 r#"
770struct A<X> {};
771type Foo = Foo;
772type Bar = A<Bar>;
773fn test(x: Foo) {}
774"#,
775 )
776}
777
778#[test]
744fn no_panic_on_field_of_enum() { 779fn 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
3use std::sync::Arc;
4
5use crate::{code_model_api::Type, db::PersistentHirDatabase, type_ref::TypeRef};
6
7pub(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}