From 18b0bd9bffeeeaf664f4a21894d5bfff51e82b32 Mon Sep 17 00:00:00 2001 From: Ville Penttinen Date: Mon, 25 Feb 2019 09:27:47 +0200 Subject: Add const type inference --- crates/ra_hir/src/ty/infer.rs | 20 ++++++++---- crates/ra_hir/src/ty/lower.rs | 22 ++++++++++--- .../snapshots/tests__infer_associated_const.snap | 14 ++++---- .../src/ty/snapshots/tests__infer_const.snap | 14 ++++++++ .../src/ty/snapshots/tests__infer_static.snap | 16 ++++++++++ crates/ra_hir/src/ty/tests.rs | 37 ++++++++++++++++++++++ 6 files changed, 104 insertions(+), 19 deletions(-) create mode 100644 crates/ra_hir/src/ty/snapshots/tests__infer_const.snap create mode 100644 crates/ra_hir/src/ty/snapshots/tests__infer_static.snap (limited to 'crates/ra_hir/src/ty') diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 921130b71..f5f85308c 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> { // Attempt to find an impl_item for the type which has a name matching // the current segment log::debug!("looking for path segment: {:?}", segment); - let item = ty.iterate_impl_items(self.db, |item| match item { + let item: crate::ModuleDef = ty.iterate_impl_items(self.db, |item| match item { crate::ImplItem::Method(func) => { let sig = func.signature(self.db); if segment.name == *sig.name() { - return Some(func); + return Some(func.into()); } None } - // TODO: Resolve associated const - crate::ImplItem::Const(_) => None, + crate::ImplItem::Const(konst) => { + let sig = konst.signature(self.db); + if segment.name == *sig.name() { + return Some(konst.into()); + } + None + } // TODO: Resolve associated types crate::ImplItem::TypeAlias(_) => None, @@ -477,9 +482,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let ty = self.insert_type_vars(ty.apply_substs(substs)); (ty, Some(var.into())) } - TypableDef::TypeAlias(_) | TypableDef::Function(_) | TypableDef::Enum(_) => { - (Ty::Unknown, None) - } + TypableDef::TypeAlias(_) + | TypableDef::Function(_) + | TypableDef::Enum(_) + | TypableDef::Const(_) => (Ty::Unknown, None), } } diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index b66b8e4a5..4a9b725d1 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; use crate::{ Function, Struct, StructField, Enum, EnumVariant, Path, Name, ModuleDef, TypeAlias, + Const, HirDatabase, type_ref::TypeRef, name::KnownName, @@ -125,6 +126,7 @@ impl Ty { TypableDef::Enum(e) => e.generic_params(db), TypableDef::EnumVariant(var) => var.parent_enum(db).generic_params(db), TypableDef::TypeAlias(t) => t.generic_params(db), + TypableDef::Const(_) => GenericParams::default().into(), }; let parent_param_count = def_generics.count_parent_params(); substs.extend((0..parent_param_count).map(|_| Ty::Unknown)); @@ -163,6 +165,7 @@ impl Ty { TypableDef::Function(_) | TypableDef::Struct(_) | TypableDef::Enum(_) + | TypableDef::Const(_) | TypableDef::TypeAlias(_) => last, TypableDef::EnumVariant(_) => { // the generic args for an enum variant may be either specified @@ -197,12 +200,14 @@ pub(crate) fn type_for_def(db: &impl HirDatabase, def: TypableDef, ns: Namespace (TypableDef::Enum(e), Namespace::Types) => type_for_enum(db, e), (TypableDef::EnumVariant(v), Namespace::Values) => type_for_enum_variant_constructor(db, v), (TypableDef::TypeAlias(t), Namespace::Types) => type_for_type_alias(db, t), + (TypableDef::Const(c), Namespace::Values) => type_for_const(db, c), // 'error' cases: (TypableDef::Function(_), Namespace::Types) => Ty::Unknown, (TypableDef::Enum(_), Namespace::Values) => Ty::Unknown, (TypableDef::EnumVariant(_), Namespace::Types) => Ty::Unknown, (TypableDef::TypeAlias(_), Namespace::Values) => Ty::Unknown, + (TypableDef::Const(_), Namespace::Types) => Ty::Unknown, } } @@ -233,6 +238,14 @@ fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty { Ty::FnDef { def: def.into(), sig, name, substs } } +/// Build the declared type of a const. +fn type_for_const(db: &impl HirDatabase, def: Const) -> Ty { + let signature = def.signature(db); + let resolver = def.resolver(db); + + Ty::from_hir(db, &resolver, signature.type_ref()) +} + /// Build the type of a tuple struct constructor. fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty { let var_data = def.variant_data(db); @@ -318,8 +331,9 @@ pub enum TypableDef { Enum(Enum), EnumVariant(EnumVariant), TypeAlias(TypeAlias), + Const(Const), } -impl_froms!(TypableDef: Function, Struct, Enum, EnumVariant, TypeAlias); +impl_froms!(TypableDef: Function, Struct, Enum, EnumVariant, TypeAlias, Const); impl From for Option { fn from(def: ModuleDef) -> Option { @@ -329,10 +343,8 @@ impl From for Option { ModuleDef::Enum(e) => e.into(), ModuleDef::EnumVariant(v) => v.into(), ModuleDef::TypeAlias(t) => t.into(), - ModuleDef::Const(_) - | ModuleDef::Static(_) - | ModuleDef::Module(_) - | ModuleDef::Trait(_) => return None, + ModuleDef::Const(v) => v.into(), + ModuleDef::Static(_) | ModuleDef::Module(_) | ModuleDef::Trait(_) => return None, }; Some(res) } 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 @@ --- -created: "2019-02-21T21:51:46.497925200Z" +created: "2019-02-25T08:36:33.885804400Z" creator: insta@0.6.3 source: crates/ra_hir/src/ty/tests.rs expression: "&result" --- [227; 305) '{ ...:ID; }': () -[237; 238) 'x': [unknown] -[241; 252) 'Struct::FOO': [unknown] -[262; 263) 'y': [unknown] -[266; 275) 'Enum::BAR': [unknown] -[285; 286) 'z': [unknown] -[289; 302) 'TraitTest::ID': [unknown] +[237; 238) 'x': u32 +[241; 252) 'Struct::FOO': u32 +[262; 263) 'y': u32 +[266; 275) 'Enum::BAR': u32 +[285; 286) 'z': u32 +[289; 302) 'TraitTest::ID': u32 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 @@ +--- +created: "2019-02-25T07:26:34.115351100Z" +creator: insta@0.6.3 +source: crates/ra_hir/src/ty/tests.rs +expression: "&result" +--- +[95; 213) '{ ...NST; }': () +[138; 139) 'x': [unknown] +[142; 153) 'LOCAL_CONST': [unknown] +[163; 164) 'z': u32 +[167; 179) 'GLOBAL_CONST': u32 +[189; 191) 'id': u32 +[194; 210) 'Foo::A..._CONST': u32 + 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..ffe9ca66d --- /dev/null +++ b/crates/ra_hir/src/ty/snapshots/tests__infer_static.snap @@ -0,0 +1,16 @@ +--- +created: "2019-02-25T07:26:41.480764900Z" +creator: insta@0.6.3 +source: crates/ra_hir/src/ty/tests.rs +expression: "&result" +--- +[85; 280) '{ ...MUT; }': () +[173; 174) 'x': [unknown] +[177; 189) 'LOCAL_STATIC': [unknown] +[199; 200) 'y': [unknown] +[203; 219) 'LOCAL_...IC_MUT': [unknown] +[229; 230) 'z': [unknown] +[233; 246) 'GLOBAL_STATIC': [unknown] +[256; 257) 'w': [unknown] +[260; 277) 'GLOBAL...IC_MUT': [unknown] + 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 { assert_eq!("i128", type_at_pos(&db, pos)); } +#[test] +fn infer_const() { + check_inference( + "infer_const", + r#" +struct Foo; +impl Foo { const ASSOC_CONST: u32 = 0; } +const GLOBAL_CONST: u32 = 101; +fn test() { + const LOCAL_CONST: u32 = 99; + let x = LOCAL_CONST; + let z = GLOBAL_CONST; + let id = Foo::ASSOC_CONST; +} +"#, + ); +} + +#[test] +fn infer_static() { + check_inference( + "infer_static", + r#" +static GLOBAL_STATIC: u32 = 101; +static mut GLOBAL_STATIC_MUT: u32 = 101; +fn test() { + static LOCAL_STATIC: u32 = 99; + static mut LOCAL_STATIC_MUT: u32 = 99; + let x = LOCAL_STATIC; + let y = LOCAL_STATIC_MUT; + let z = GLOBAL_STATIC; + let w = GLOBAL_STATIC_MUT; +} +"#, + ); +} + fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { let func = source_binder::function_from_position(db, pos).unwrap(); let body_syntax_mapping = func.body_syntax_mapping(db); -- cgit v1.2.3