aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-02-25 12:03:57 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-02-25 12:03:57 +0000
commit7c9acf2f834c582d9cad4f7d0679a0697c591432 (patch)
tree5829e5a0e4567c532a5d430ed9406a8cd072f5ca /crates/ra_hir/src
parent4f67df904252c5fbbf3b892bb2e8405778bc904a (diff)
parentcff9a7dfadc6069bbc7b49c3ceb8497c78d426ab (diff)
Merge #897
897: Add basic const/static type inference r=flodiebold a=vipentti This adds basic const/static type inference discussed in #887. Currently the inference does not work for const/static declared inside a block. In addition the inference does not work inside the bodies of const/static. Co-authored-by: Ville Penttinen <[email protected]>
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r--crates/ra_hir/src/code_model_api.rs42
-rw-r--r--crates/ra_hir/src/code_model_impl.rs1
-rw-r--r--crates/ra_hir/src/code_model_impl/konst.rs37
-rw-r--r--crates/ra_hir/src/db.rs7
-rw-r--r--crates/ra_hir/src/lib.rs2
-rw-r--r--crates/ra_hir/src/ty/infer.rs21
-rw-r--r--crates/ra_hir/src/ty/lower.rs35
-rw-r--r--crates/ra_hir/src/ty/snapshots/tests__infer_associated_const.snap14
-rw-r--r--crates/ra_hir/src/ty/snapshots/tests__infer_const.snap14
-rw-r--r--crates/ra_hir/src/ty/snapshots/tests__infer_static.snap16
-rw-r--r--crates/ra_hir/src/ty/tests.rs37
11 files changed, 206 insertions, 20 deletions
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs
index 9a44aaa43..da0f1ec94 100644
--- a/crates/ra_hir/src/code_model_api.rs
+++ b/crates/ra_hir/src/code_model_api.rs
@@ -554,11 +554,26 @@ impl Const {
554 self.id.module(db) 554 self.id.module(db)
555 } 555 }
556 556
557 pub fn signature(&self, db: &impl HirDatabase) -> Arc<ConstSignature> {
558 db.const_signature(*self)
559 }
560
557 /// The containing impl block, if this is a method. 561 /// The containing impl block, if this is a method.
558 pub fn impl_block(&self, db: &impl PersistentHirDatabase) -> Option<ImplBlock> { 562 pub fn impl_block(&self, db: &impl PersistentHirDatabase) -> Option<ImplBlock> {
559 let module_impls = db.impls_in_module(self.module(db)); 563 let module_impls = db.impls_in_module(self.module(db));
560 ImplBlock::containing(module_impls, (*self).into()) 564 ImplBlock::containing(module_impls, (*self).into())
561 } 565 }
566
567 // TODO: move to a more general type for 'body-having' items
568 /// Builds a resolver for code inside this item.
569 pub fn resolver(&self, db: &impl HirDatabase) -> Resolver {
570 // take the outer scope...
571 let r = self
572 .impl_block(db)
573 .map(|ib| ib.resolver(db))
574 .unwrap_or_else(|| self.module(db).resolver(db));
575 r
576 }
562} 577}
563 578
564impl Docs for Const { 579impl Docs for Const {
@@ -567,6 +582,23 @@ impl Docs for Const {
567 } 582 }
568} 583}
569 584
585/// The declared signature of a const.
586#[derive(Debug, Clone, PartialEq, Eq)]
587pub struct ConstSignature {
588 pub(crate) name: Name,
589 pub(crate) type_ref: TypeRef,
590}
591
592impl ConstSignature {
593 pub fn name(&self) -> &Name {
594 &self.name
595 }
596
597 pub fn type_ref(&self) -> &TypeRef {
598 &self.type_ref
599 }
600}
601
570#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 602#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
571pub struct Static { 603pub struct Static {
572 pub(crate) id: StaticId, 604 pub(crate) id: StaticId,
@@ -580,6 +612,16 @@ impl Static {
580 pub fn module(&self, db: &impl PersistentHirDatabase) -> Module { 612 pub fn module(&self, db: &impl PersistentHirDatabase) -> Module {
581 self.id.module(db) 613 self.id.module(db)
582 } 614 }
615
616 pub fn signature(&self, db: &impl HirDatabase) -> Arc<ConstSignature> {
617 db.static_signature(*self)
618 }
619
620 /// Builds a resolver for code inside this item.
621 pub fn resolver(&self, db: &impl HirDatabase) -> Resolver {
622 // take the outer scope...
623 self.module(db).resolver(db)
624 }
583} 625}
584 626
585impl Docs for Static { 627impl Docs for Static {
diff --git a/crates/ra_hir/src/code_model_impl.rs b/crates/ra_hir/src/code_model_impl.rs
index 1f28fab74..24df9a113 100644
--- a/crates/ra_hir/src/code_model_impl.rs
+++ b/crates/ra_hir/src/code_model_impl.rs
@@ -1,3 +1,4 @@
1mod krate; // `crate` is invalid ident :( 1mod krate; // `crate` is invalid ident :(
2mod konst; // `const` is invalid ident :(
2mod module; 3mod module;
3pub(crate) mod function; 4pub(crate) mod function;
diff --git a/crates/ra_hir/src/code_model_impl/konst.rs b/crates/ra_hir/src/code_model_impl/konst.rs
new file mode 100644
index 000000000..ecf4c8122
--- /dev/null
+++ b/crates/ra_hir/src/code_model_impl/konst.rs
@@ -0,0 +1,37 @@
1use std::sync::Arc;
2
3use ra_syntax::ast::{self, NameOwner};
4
5use crate::{
6 Name, AsName, Const, ConstSignature, Static,
7 type_ref::{TypeRef},
8 PersistentHirDatabase,
9};
10
11fn const_signature_for<N: NameOwner>(
12 node: &N,
13 type_ref: Option<&ast::TypeRef>,
14) -> Arc<ConstSignature> {
15 let name = node.name().map(|n| n.as_name()).unwrap_or_else(Name::missing);
16 let type_ref = TypeRef::from_ast_opt(type_ref);
17 let sig = ConstSignature { name, type_ref };
18 Arc::new(sig)
19}
20
21impl ConstSignature {
22 pub(crate) fn const_signature_query(
23 db: &impl PersistentHirDatabase,
24 konst: Const,
25 ) -> Arc<ConstSignature> {
26 let (_, node) = konst.source(db);
27 const_signature_for(&*node, node.type_ref())
28 }
29
30 pub(crate) fn static_signature_query(
31 db: &impl PersistentHirDatabase,
32 konst: Static,
33 ) -> Arc<ConstSignature> {
34 let (_, node) = konst.source(db);
35 const_signature_for(&*node, node.type_ref())
36 }
37}
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index b8715abab..ec848f1b2 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -8,6 +8,7 @@ use crate::{
8 SourceFileItems, SourceItemId, Crate, Module, HirInterner, 8 SourceFileItems, SourceItemId, Crate, Module, HirInterner,
9 Function, FnSignature, ExprScopes, TypeAlias, 9 Function, FnSignature, ExprScopes, TypeAlias,
10 Struct, Enum, StructField, 10 Struct, Enum, StructField,
11 Const, ConstSignature, Static,
11 macros::MacroExpansion, 12 macros::MacroExpansion,
12 module_tree::ModuleTree, 13 module_tree::ModuleTree,
13 nameres::{ItemMap, lower::{LoweredModule, ImportSourceMap}}, 14 nameres::{ItemMap, lower::{LoweredModule, ImportSourceMap}},
@@ -82,6 +83,12 @@ pub trait PersistentHirDatabase: SourceDatabase + AsRef<HirInterner> {
82 83
83 #[salsa::invoke(crate::type_alias::type_alias_ref_query)] 84 #[salsa::invoke(crate::type_alias::type_alias_ref_query)]
84 fn type_alias_ref(&self, typ: TypeAlias) -> Arc<TypeRef>; 85 fn type_alias_ref(&self, typ: TypeAlias) -> Arc<TypeRef>;
86
87 #[salsa::invoke(crate::ConstSignature::const_signature_query)]
88 fn const_signature(&self, konst: Const) -> Arc<ConstSignature>;
89
90 #[salsa::invoke(crate::ConstSignature::static_signature_query)]
91 fn static_signature(&self, konst: Static) -> Arc<ConstSignature>;
85} 92}
86 93
87#[salsa::query_group(HirDatabaseStorage)] 94#[salsa::query_group(HirDatabaseStorage)]
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index aa5fc5607..edc1b4f57 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -71,6 +71,6 @@ pub use self::code_model_api::{
71 Struct, Enum, EnumVariant, 71 Struct, Enum, EnumVariant,
72 Function, FnSignature, 72 Function, FnSignature,
73 StructField, FieldSource, 73 StructField, FieldSource,
74 Static, Const, 74 Static, Const, ConstSignature,
75 Trait, TypeAlias, 75 Trait, TypeAlias,
76}; 76};
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 921130b71..5e4d49ffb 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -393,17 +393,22 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
393 // Attempt to find an impl_item for the type which has a name matching 393 // Attempt to find an impl_item for the type which has a name matching
394 // the current segment 394 // the current segment
395 log::debug!("looking for path segment: {:?}", segment); 395 log::debug!("looking for path segment: {:?}", segment);
396 let item = ty.iterate_impl_items(self.db, |item| match item { 396 let item: crate::ModuleDef = ty.iterate_impl_items(self.db, |item| match item {
397 crate::ImplItem::Method(func) => { 397 crate::ImplItem::Method(func) => {
398 let sig = func.signature(self.db); 398 let sig = func.signature(self.db);
399 if segment.name == *sig.name() { 399 if segment.name == *sig.name() {
400 return Some(func); 400 return Some(func.into());
401 } 401 }
402 None 402 None
403 } 403 }
404 404
405 // TODO: Resolve associated const 405 crate::ImplItem::Const(konst) => {
406 crate::ImplItem::Const(_) => None, 406 let sig = konst.signature(self.db);
407 if segment.name == *sig.name() {
408 return Some(konst.into());
409 }
410 None
411 }
407 412
408 // TODO: Resolve associated types 413 // TODO: Resolve associated types
409 crate::ImplItem::TypeAlias(_) => None, 414 crate::ImplItem::TypeAlias(_) => None,
@@ -477,9 +482,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
477 let ty = self.insert_type_vars(ty.apply_substs(substs)); 482 let ty = self.insert_type_vars(ty.apply_substs(substs));
478 (ty, Some(var.into())) 483 (ty, Some(var.into()))
479 } 484 }
480 TypableDef::TypeAlias(_) | TypableDef::Function(_) | TypableDef::Enum(_) => { 485 TypableDef::TypeAlias(_)
481 (Ty::Unknown, None) 486 | TypableDef::Function(_)
482 } 487 | TypableDef::Enum(_)
488 | TypableDef::Const(_)
489 | TypableDef::Static(_) => (Ty::Unknown, None),
483 } 490 }
484 } 491 }
485 492
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index b66b8e4a5..f4e055feb 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -11,6 +11,7 @@ use std::sync::Arc;
11use crate::{ 11use crate::{
12 Function, Struct, StructField, Enum, EnumVariant, Path, Name, 12 Function, Struct, StructField, Enum, EnumVariant, Path, Name,
13 ModuleDef, TypeAlias, 13 ModuleDef, TypeAlias,
14 Const, Static,
14 HirDatabase, 15 HirDatabase,
15 type_ref::TypeRef, 16 type_ref::TypeRef,
16 name::KnownName, 17 name::KnownName,
@@ -125,6 +126,7 @@ impl Ty {
125 TypableDef::Enum(e) => e.generic_params(db), 126 TypableDef::Enum(e) => e.generic_params(db),
126 TypableDef::EnumVariant(var) => var.parent_enum(db).generic_params(db), 127 TypableDef::EnumVariant(var) => var.parent_enum(db).generic_params(db),
127 TypableDef::TypeAlias(t) => t.generic_params(db), 128 TypableDef::TypeAlias(t) => t.generic_params(db),
129 TypableDef::Const(_) | TypableDef::Static(_) => GenericParams::default().into(),
128 }; 130 };
129 let parent_param_count = def_generics.count_parent_params(); 131 let parent_param_count = def_generics.count_parent_params();
130 substs.extend((0..parent_param_count).map(|_| Ty::Unknown)); 132 substs.extend((0..parent_param_count).map(|_| Ty::Unknown));
@@ -163,6 +165,8 @@ impl Ty {
163 TypableDef::Function(_) 165 TypableDef::Function(_)
164 | TypableDef::Struct(_) 166 | TypableDef::Struct(_)
165 | TypableDef::Enum(_) 167 | TypableDef::Enum(_)
168 | TypableDef::Const(_)
169 | TypableDef::Static(_)
166 | TypableDef::TypeAlias(_) => last, 170 | TypableDef::TypeAlias(_) => last,
167 TypableDef::EnumVariant(_) => { 171 TypableDef::EnumVariant(_) => {
168 // the generic args for an enum variant may be either specified 172 // the generic args for an enum variant may be either specified
@@ -197,12 +201,16 @@ pub(crate) fn type_for_def(db: &impl HirDatabase, def: TypableDef, ns: Namespace
197 (TypableDef::Enum(e), Namespace::Types) => type_for_enum(db, e), 201 (TypableDef::Enum(e), Namespace::Types) => type_for_enum(db, e),
198 (TypableDef::EnumVariant(v), Namespace::Values) => type_for_enum_variant_constructor(db, v), 202 (TypableDef::EnumVariant(v), Namespace::Values) => type_for_enum_variant_constructor(db, v),
199 (TypableDef::TypeAlias(t), Namespace::Types) => type_for_type_alias(db, t), 203 (TypableDef::TypeAlias(t), Namespace::Types) => type_for_type_alias(db, t),
204 (TypableDef::Const(c), Namespace::Values) => type_for_const(db, c),
205 (TypableDef::Static(c), Namespace::Values) => type_for_static(db, c),
200 206
201 // 'error' cases: 207 // 'error' cases:
202 (TypableDef::Function(_), Namespace::Types) => Ty::Unknown, 208 (TypableDef::Function(_), Namespace::Types) => Ty::Unknown,
203 (TypableDef::Enum(_), Namespace::Values) => Ty::Unknown, 209 (TypableDef::Enum(_), Namespace::Values) => Ty::Unknown,
204 (TypableDef::EnumVariant(_), Namespace::Types) => Ty::Unknown, 210 (TypableDef::EnumVariant(_), Namespace::Types) => Ty::Unknown,
205 (TypableDef::TypeAlias(_), Namespace::Values) => Ty::Unknown, 211 (TypableDef::TypeAlias(_), Namespace::Values) => Ty::Unknown,
212 (TypableDef::Const(_), Namespace::Types) => Ty::Unknown,
213 (TypableDef::Static(_), Namespace::Types) => Ty::Unknown,
206 } 214 }
207} 215}
208 216
@@ -233,6 +241,22 @@ fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty {
233 Ty::FnDef { def: def.into(), sig, name, substs } 241 Ty::FnDef { def: def.into(), sig, name, substs }
234} 242}
235 243
244/// Build the declared type of a const.
245fn type_for_const(db: &impl HirDatabase, def: Const) -> Ty {
246 let signature = def.signature(db);
247 let resolver = def.resolver(db);
248
249 Ty::from_hir(db, &resolver, signature.type_ref())
250}
251
252/// Build the declared type of a static.
253fn type_for_static(db: &impl HirDatabase, def: Static) -> Ty {
254 let signature = def.signature(db);
255 let resolver = def.resolver(db);
256
257 Ty::from_hir(db, &resolver, signature.type_ref())
258}
259
236/// Build the type of a tuple struct constructor. 260/// Build the type of a tuple struct constructor.
237fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty { 261fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty {
238 let var_data = def.variant_data(db); 262 let var_data = def.variant_data(db);
@@ -318,8 +342,10 @@ pub enum TypableDef {
318 Enum(Enum), 342 Enum(Enum),
319 EnumVariant(EnumVariant), 343 EnumVariant(EnumVariant),
320 TypeAlias(TypeAlias), 344 TypeAlias(TypeAlias),
345 Const(Const),
346 Static(Static),
321} 347}
322impl_froms!(TypableDef: Function, Struct, Enum, EnumVariant, TypeAlias); 348impl_froms!(TypableDef: Function, Struct, Enum, EnumVariant, TypeAlias, Const, Static);
323 349
324impl From<ModuleDef> for Option<TypableDef> { 350impl From<ModuleDef> for Option<TypableDef> {
325 fn from(def: ModuleDef) -> Option<TypableDef> { 351 fn from(def: ModuleDef) -> Option<TypableDef> {
@@ -329,10 +355,9 @@ impl From<ModuleDef> for Option<TypableDef> {
329 ModuleDef::Enum(e) => e.into(), 355 ModuleDef::Enum(e) => e.into(),
330 ModuleDef::EnumVariant(v) => v.into(), 356 ModuleDef::EnumVariant(v) => v.into(),
331 ModuleDef::TypeAlias(t) => t.into(), 357 ModuleDef::TypeAlias(t) => t.into(),
332 ModuleDef::Const(_) 358 ModuleDef::Const(v) => v.into(),
333 | ModuleDef::Static(_) 359 ModuleDef::Static(v) => v.into(),
334 | ModuleDef::Module(_) 360 ModuleDef::Module(_) | ModuleDef::Trait(_) => return None,
335 | ModuleDef::Trait(_) => return None,
336 }; 361 };
337 Some(res) 362 Some(res)
338 } 363 }
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_associated_const.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_associated_const.snap
index 131d1fa16..51f3fd4c0 100644
--- a/crates/ra_hir/src/ty/snapshots/tests__infer_associated_const.snap
+++ b/crates/ra_hir/src/ty/snapshots/tests__infer_associated_const.snap
@@ -1,14 +1,14 @@
1--- 1---
2created: "2019-02-21T21:51:46.497925200Z" 2created: "2019-02-25T08:36:33.885804400Z"
3creator: [email protected] 3creator: [email protected]
4source: crates/ra_hir/src/ty/tests.rs 4source: crates/ra_hir/src/ty/tests.rs
5expression: "&result" 5expression: "&result"
6--- 6---
7[227; 305) '{ ...:ID; }': () 7[227; 305) '{ ...:ID; }': ()
8[237; 238) 'x': [unknown] 8[237; 238) 'x': u32
9[241; 252) 'Struct::FOO': [unknown] 9[241; 252) 'Struct::FOO': u32
10[262; 263) 'y': [unknown] 10[262; 263) 'y': u32
11[266; 275) 'Enum::BAR': [unknown] 11[266; 275) 'Enum::BAR': u32
12[285; 286) 'z': [unknown] 12[285; 286) 'z': u32
13[289; 302) 'TraitTest::ID': [unknown] 13[289; 302) 'TraitTest::ID': u32
14 14
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_const.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_const.snap
new file mode 100644
index 000000000..a5eba3980
--- /dev/null
+++ b/crates/ra_hir/src/ty/snapshots/tests__infer_const.snap
@@ -0,0 +1,14 @@
1---
2created: "2019-02-25T07:26:34.115351100Z"
3creator: [email protected]
4source: crates/ra_hir/src/ty/tests.rs
5expression: "&result"
6---
7[95; 213) '{ ...NST; }': ()
8[138; 139) 'x': [unknown]
9[142; 153) 'LOCAL_CONST': [unknown]
10[163; 164) 'z': u32
11[167; 179) 'GLOBAL_CONST': u32
12[189; 191) 'id': u32
13[194; 210) 'Foo::A..._CONST': u32
14
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_static.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_static.snap
new file mode 100644
index 000000000..5d90f56ed
--- /dev/null
+++ b/crates/ra_hir/src/ty/snapshots/tests__infer_static.snap
@@ -0,0 +1,16 @@
1---
2created: "2019-02-25T08:20:17.807316Z"
3creator: [email protected]
4source: crates/ra_hir/src/ty/tests.rs
5expression: "&result"
6---
7[85; 280) '{ ...MUT; }': ()
8[173; 174) 'x': [unknown]
9[177; 189) 'LOCAL_STATIC': [unknown]
10[199; 200) 'y': [unknown]
11[203; 219) 'LOCAL_...IC_MUT': [unknown]
12[229; 230) 'z': u32
13[233; 246) 'GLOBAL_STATIC': u32
14[256; 257) 'w': u32
15[260; 277) 'GLOBAL...IC_MUT': u32
16
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 642259225..8de46a29e 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -1006,6 +1006,43 @@ mod foo {
1006 assert_eq!("i128", type_at_pos(&db, pos)); 1006 assert_eq!("i128", type_at_pos(&db, pos));
1007} 1007}
1008 1008
1009#[test]
1010fn infer_const() {
1011 check_inference(
1012 "infer_const",
1013 r#"
1014struct Foo;
1015impl Foo { const ASSOC_CONST: u32 = 0; }
1016const GLOBAL_CONST: u32 = 101;
1017fn test() {
1018 const LOCAL_CONST: u32 = 99;
1019 let x = LOCAL_CONST;
1020 let z = GLOBAL_CONST;
1021 let id = Foo::ASSOC_CONST;
1022}
1023"#,
1024 );
1025}
1026
1027#[test]
1028fn infer_static() {
1029 check_inference(
1030 "infer_static",
1031 r#"
1032static GLOBAL_STATIC: u32 = 101;
1033static mut GLOBAL_STATIC_MUT: u32 = 101;
1034fn test() {
1035 static LOCAL_STATIC: u32 = 99;
1036 static mut LOCAL_STATIC_MUT: u32 = 99;
1037 let x = LOCAL_STATIC;
1038 let y = LOCAL_STATIC_MUT;
1039 let z = GLOBAL_STATIC;
1040 let w = GLOBAL_STATIC_MUT;
1041}
1042"#,
1043 );
1044}
1045
1009fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { 1046fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
1010 let func = source_binder::function_from_position(db, pos).unwrap(); 1047 let func = source_binder::function_from_position(db, pos).unwrap();
1011 let body_syntax_mapping = func.body_syntax_mapping(db); 1048 let body_syntax_mapping = func.body_syntax_mapping(db);