aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcus Klaas de Vries <[email protected]>2019-01-08 15:01:19 +0000
committerMarcus Klaas de Vries <[email protected]>2019-01-10 13:32:56 +0000
commit978de5cf8bfd2ff82696fc8d5369b41e147431c3 (patch)
tree27a25a5f2fb20a4afffed97cbb5b678b251d254b
parentaca14c591fea40b2f803bbf5f02c1571732348fb (diff)
Implement type inference for enum variants
-rw-r--r--crates/ra_hir/src/adt.rs105
-rw-r--r--crates/ra_hir/src/code_model_api.rs34
-rw-r--r--crates/ra_hir/src/code_model_impl/module.rs38
-rw-r--r--crates/ra_hir/src/db.rs7
-rw-r--r--crates/ra_hir/src/ids.rs13
-rw-r--r--crates/ra_hir/src/lib.rs2
-rw-r--r--crates/ra_hir/src/mock.rs1
-rw-r--r--crates/ra_hir/src/ty.rs20
-rw-r--r--crates/ra_hir/src/ty/tests.rs16
-rw-r--r--crates/ra_hir/src/ty/tests/data/enum.txt4
-rw-r--r--crates/ra_ide_api/src/completion/complete_path.rs22
-rw-r--r--crates/ra_ide_api/src/db.rs1
12 files changed, 218 insertions, 45 deletions
diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs
index d30390f25..f1b98cdd7 100644
--- a/crates/ra_hir/src/adt.rs
+++ b/crates/ra_hir/src/adt.rs
@@ -1,10 +1,19 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_db::Cancelable; 3use ra_db::Cancelable;
4use ra_syntax::ast::{self, NameOwner, StructFlavor, AstNode}; 4use ra_syntax::{
5 SyntaxNode,
6 ast::{self, NameOwner, StructFlavor, AstNode}
7};
5 8
6use crate::{ 9use crate::{
10<<<<<<< HEAD
7 DefId, Name, AsName, Struct, Enum, HirDatabase, DefKind, 11 DefId, Name, AsName, Struct, Enum, HirDatabase, DefKind,
12=======
13 DefId, DefLoc, Name, AsName, Struct, Enum, EnumVariant,
14 VariantData, StructField, HirDatabase, DefKind,
15 SourceItemId,
16>>>>>>> 95ac72a3... Implement type inference for enum variants
8 type_ref::TypeRef, 17 type_ref::TypeRef,
9}; 18};
10 19
@@ -45,33 +54,39 @@ impl StructData {
45 } 54 }
46} 55}
47 56
48impl Enum { 57fn get_def_id(
49 pub(crate) fn new(def_id: DefId) -> Self { 58 db: &impl HirDatabase,
50 Enum { def_id } 59 same_file_loc: &DefLoc,
51 } 60 node: &SyntaxNode,
61 expected_kind: DefKind,
62) -> DefId {
63 let file_id = same_file_loc.source_item_id.file_id;
64 let file_items = db.file_items(file_id);
65
66 let item_id = file_items.id_of(file_id, node);
67 let source_item_id = SourceItemId {
68 item_id: Some(item_id),
69 ..same_file_loc.source_item_id
70 };
71 let loc = DefLoc {
72 kind: expected_kind,
73 source_item_id: source_item_id,
74 ..*same_file_loc
75 };
76 loc.id(db)
52} 77}
53 78
54#[derive(Debug, Clone, PartialEq, Eq)] 79#[derive(Debug, Clone, PartialEq, Eq)]
55pub struct EnumData { 80pub struct EnumData {
56 pub(crate) name: Option<Name>, 81 pub(crate) name: Option<Name>,
57 pub(crate) variants: Vec<(Name, Arc<VariantData>)>, 82 // TODO: keep track of names also since we already have them?
83 // then we won't need additional db lookups
84 pub(crate) variants: Option<Vec<EnumVariant>>,
58} 85}
59 86
60impl EnumData { 87impl EnumData {
61 fn new(enum_def: &ast::EnumDef) -> Self { 88 fn new(enum_def: &ast::EnumDef, variants: Option<Vec<EnumVariant>>) -> Self {
62 let name = enum_def.name().map(|n| n.as_name()); 89 let name = enum_def.name().map(|n| n.as_name());
63 let variants = if let Some(evl) = enum_def.variant_list() {
64 evl.variants()
65 .map(|v| {
66 (
67 v.name().map(|n| n.as_name()).unwrap_or_else(Name::missing),
68 Arc::new(VariantData::new(v.flavor())),
69 )
70 })
71 .collect()
72 } else {
73 Vec::new()
74 };
75 EnumData { name, variants } 90 EnumData { name, variants }
76 } 91 }
77 92
@@ -83,7 +98,57 @@ impl EnumData {
83 assert!(def_loc.kind == DefKind::Enum); 98 assert!(def_loc.kind == DefKind::Enum);
84 let syntax = db.file_item(def_loc.source_item_id); 99 let syntax = db.file_item(def_loc.source_item_id);
85 let enum_def = ast::EnumDef::cast(&syntax).expect("enum def should point to EnumDef node"); 100 let enum_def = ast::EnumDef::cast(&syntax).expect("enum def should point to EnumDef node");
86 Ok(Arc::new(EnumData::new(enum_def))) 101 let variants = enum_def.variant_list().map(|vl| {
102 vl.variants()
103 .map(|ev| {
104 let def_id = get_def_id(db, &def_loc, ev.syntax(), DefKind::EnumVariant);
105 EnumVariant::new(def_id)
106 })
107 .collect()
108 });
109 Ok(Arc::new(EnumData::new(enum_def, variants)))
110 }
111}
112
113#[derive(Debug, Clone, PartialEq, Eq)]
114pub struct EnumVariantData {
115 pub(crate) name: Option<Name>,
116 pub(crate) variant_data: Arc<VariantData>,
117 pub(crate) parent_enum: Enum,
118}
119
120impl EnumVariantData {
121 fn new(variant_def: &ast::EnumVariant, parent_enum: Enum) -> EnumVariantData {
122 let name = variant_def.name().map(|n| n.as_name());
123 let variant_data = VariantData::new(variant_def.flavor());
124 let variant_data = Arc::new(variant_data);
125 EnumVariantData {
126 name,
127 variant_data,
128 parent_enum,
129 }
130 }
131
132 pub(crate) fn enum_variant_data_query(
133 db: &impl HirDatabase,
134 def_id: DefId,
135 ) -> Cancelable<Arc<EnumVariantData>> {
136 let def_loc = def_id.loc(db);
137 assert!(def_loc.kind == DefKind::EnumVariant);
138 let syntax = db.file_item(def_loc.source_item_id);
139 let variant_def = ast::EnumVariant::cast(&syntax)
140 .expect("enum variant def should point to EnumVariant node");
141 let enum_node = syntax
142 .parent()
143 .expect("enum variant should have enum variant list ancestor")
144 .parent()
145 .expect("enum variant list should have enum ancestor");
146 let enum_def_id = get_def_id(db, &def_loc, enum_node, DefKind::Enum);
147
148 Ok(Arc::new(EnumVariantData::new(
149 variant_def,
150 Enum::new(enum_def_id),
151 )))
87 } 152 }
88} 153}
89 154
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs
index fa3e4baa7..c7d1bf0a6 100644
--- a/crates/ra_hir/src/code_model_api.rs
+++ b/crates/ra_hir/src/code_model_api.rs
@@ -44,6 +44,7 @@ pub enum Def {
44 Module(Module), 44 Module(Module),
45 Struct(Struct), 45 Struct(Struct),
46 Enum(Enum), 46 Enum(Enum),
47 EnumVariant(EnumVariant),
47 Function(Function), 48 Function(Function),
48 Item, 49 Item,
49} 50}
@@ -188,6 +189,10 @@ pub struct Enum {
188} 189}
189 190
190impl Enum { 191impl Enum {
192 pub(crate) fn new(def_id: DefId) -> Self {
193 Enum { def_id }
194 }
195
191 pub fn def_id(&self) -> DefId { 196 pub fn def_id(&self) -> DefId {
192 self.def_id 197 self.def_id
193 } 198 }
@@ -196,12 +201,39 @@ impl Enum {
196 Ok(db.enum_data(self.def_id)?.name.clone()) 201 Ok(db.enum_data(self.def_id)?.name.clone())
197 } 202 }
198 203
199 pub fn variants(&self, db: &impl HirDatabase) -> Cancelable<Vec<(Name, Arc<VariantData>)>> { 204 pub fn variants(&self, db: &impl HirDatabase) -> Cancelable<Option<Vec<EnumVariant>>> {
200 Ok(db.enum_data(self.def_id)?.variants.clone()) 205 Ok(db.enum_data(self.def_id)?.variants.clone())
201 } 206 }
202} 207}
203 208
204#[derive(Debug, Clone, PartialEq, Eq, Hash)] 209#[derive(Debug, Clone, PartialEq, Eq, Hash)]
210pub struct EnumVariant {
211 pub(crate) def_id: DefId,
212}
213
214impl EnumVariant {
215 pub(crate) fn new(def_id: DefId) -> Self {
216 EnumVariant { def_id }
217 }
218
219 pub fn def_id(&self) -> DefId {
220 self.def_id
221 }
222
223 pub fn parent_enum(&self, db: &impl HirDatabase) -> Cancelable<Enum> {
224 Ok(db.enum_variant_data(self.def_id)?.parent_enum.clone())
225 }
226
227 pub fn name(&self, db: &impl HirDatabase) -> Cancelable<Option<Name>> {
228 Ok(db.enum_variant_data(self.def_id)?.name.clone())
229 }
230
231 pub fn variant_data(&self, db: &impl HirDatabase) -> Cancelable<Arc<VariantData>> {
232 Ok(db.enum_variant_data(self.def_id)?.variant_data.clone())
233 }
234}
235
236#[derive(Debug, Clone, PartialEq, Eq, Hash)]
205pub struct Function { 237pub struct Function {
206 pub(crate) def_id: DefId, 238 pub(crate) def_id: DefId,
207} 239}
diff --git a/crates/ra_hir/src/code_model_impl/module.rs b/crates/ra_hir/src/code_model_impl/module.rs
index 1cb408cff..d7d62e863 100644
--- a/crates/ra_hir/src/code_model_impl/module.rs
+++ b/crates/ra_hir/src/code_model_impl/module.rs
@@ -13,6 +13,7 @@ impl Module {
13 pub(crate) fn new(def_id: DefId) -> Self { 13 pub(crate) fn new(def_id: DefId) -> Self {
14 crate::code_model_api::Module { def_id } 14 crate::code_model_api::Module { def_id }
15 } 15 }
16
16 pub(crate) fn from_module_id( 17 pub(crate) fn from_module_id(
17 db: &impl HirDatabase, 18 db: &impl HirDatabase,
18 source_root_id: SourceRootId, 19 source_root_id: SourceRootId,
@@ -85,6 +86,7 @@ impl Module {
85 let module_id = loc.module_id.crate_root(&module_tree); 86 let module_id = loc.module_id.crate_root(&module_tree);
86 Module::from_module_id(db, loc.source_root_id, module_id) 87 Module::from_module_id(db, loc.source_root_id, module_id)
87 } 88 }
89
88 /// Finds a child module with the specified name. 90 /// Finds a child module with the specified name.
89 pub fn child_impl(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> { 91 pub fn child_impl(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> {
90 let loc = self.def_id.loc(db); 92 let loc = self.def_id.loc(db);
@@ -92,12 +94,14 @@ impl Module {
92 let child_id = ctry!(loc.module_id.child(&module_tree, name)); 94 let child_id = ctry!(loc.module_id.child(&module_tree, name));
93 Module::from_module_id(db, loc.source_root_id, child_id).map(Some) 95 Module::from_module_id(db, loc.source_root_id, child_id).map(Some)
94 } 96 }
97
95 pub fn parent_impl(&self, db: &impl HirDatabase) -> Cancelable<Option<Module>> { 98 pub fn parent_impl(&self, db: &impl HirDatabase) -> Cancelable<Option<Module>> {
96 let loc = self.def_id.loc(db); 99 let loc = self.def_id.loc(db);
97 let module_tree = db.module_tree(loc.source_root_id)?; 100 let module_tree = db.module_tree(loc.source_root_id)?;
98 let parent_id = ctry!(loc.module_id.parent(&module_tree)); 101 let parent_id = ctry!(loc.module_id.parent(&module_tree));
99 Module::from_module_id(db, loc.source_root_id, parent_id).map(Some) 102 Module::from_module_id(db, loc.source_root_id, parent_id).map(Some)
100 } 103 }
104
101 /// Returns a `ModuleScope`: a set of items, visible in this module. 105 /// Returns a `ModuleScope`: a set of items, visible in this module.
102 pub fn scope_impl(&self, db: &impl HirDatabase) -> Cancelable<ModuleScope> { 106 pub fn scope_impl(&self, db: &impl HirDatabase) -> Cancelable<ModuleScope> {
103 let loc = self.def_id.loc(db); 107 let loc = self.def_id.loc(db);
@@ -105,6 +109,7 @@ impl Module {
105 let res = item_map.per_module[&loc.module_id].clone(); 109 let res = item_map.per_module[&loc.module_id].clone();
106 Ok(res) 110 Ok(res)
107 } 111 }
112
108 pub fn resolve_path_impl( 113 pub fn resolve_path_impl(
109 &self, 114 &self,
110 db: &impl HirDatabase, 115 db: &impl HirDatabase,
@@ -126,7 +131,7 @@ impl Module {
126 ); 131 );
127 132
128 let segments = &path.segments; 133 let segments = &path.segments;
129 for name in segments.iter() { 134 for (idx, name) in segments.iter().enumerate() {
130 let curr = if let Some(r) = curr_per_ns.as_ref().take_types() { 135 let curr = if let Some(r) = curr_per_ns.as_ref().take_types() {
131 r 136 r
132 } else { 137 } else {
@@ -134,7 +139,35 @@ impl Module {
134 }; 139 };
135 let module = match curr.resolve(db)? { 140 let module = match curr.resolve(db)? {
136 Def::Module(it) => it, 141 Def::Module(it) => it,
137 // TODO here would be the place to handle enum variants... 142 Def::Enum(e) => {
143 if segments.len() == idx + 1 {
144 // enum variant
145 let matching_variant = e.variants(db)?.map(|variants| {
146 variants
147 .into_iter()
148 // FIXME: replace by match lol
149 .find(|variant| {
150 variant
151 .name(db)
152 .map(|o| o.map(|ref n| n == name))
153 .unwrap_or(Some(false))
154 .unwrap_or(false)
155 })
156 });
157
158 if let Some(Some(variant)) = matching_variant {
159 return Ok(PerNs::both(variant.def_id(), e.def_id()));
160 } else {
161 return Ok(PerNs::none());
162 }
163 } else if segments.len() == idx {
164 // enum
165 return Ok(PerNs::types(e.def_id()));
166 } else {
167 // malformed enum?
168 return Ok(PerNs::none());
169 }
170 }
138 _ => return Ok(PerNs::none()), 171 _ => return Ok(PerNs::none()),
139 }; 172 };
140 let scope = module.scope(db)?; 173 let scope = module.scope(db)?;
@@ -146,6 +179,7 @@ impl Module {
146 } 179 }
147 Ok(curr_per_ns) 180 Ok(curr_per_ns)
148 } 181 }
182
149 pub fn problems_impl( 183 pub fn problems_impl(
150 &self, 184 &self,
151 db: &impl HirDatabase, 185 db: &impl HirDatabase,
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 7dbe93f2b..9a6ef8083 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -12,7 +12,7 @@ use crate::{
12 module_tree::{ModuleId, ModuleTree}, 12 module_tree::{ModuleId, ModuleTree},
13 nameres::{ItemMap, InputModuleItems}, 13 nameres::{ItemMap, InputModuleItems},
14 ty::{InferenceResult, Ty}, 14 ty::{InferenceResult, Ty},
15 adt::{StructData, EnumData}, 15 adt::{StructData, EnumData, EnumVariantData},
16 impl_block::ModuleImplBlocks, 16 impl_block::ModuleImplBlocks,
17}; 17};
18 18
@@ -47,6 +47,11 @@ pub trait HirDatabase: SyntaxDatabase
47 use fn crate::adt::EnumData::enum_data_query; 47 use fn crate::adt::EnumData::enum_data_query;
48 } 48 }
49 49
50 fn enum_variant_data(def_id: DefId) -> Cancelable<Arc<EnumVariantData>> {
51 type EnumVariantDataQuery;
52 use fn crate::adt::EnumVariantData::enum_variant_data_query;
53 }
54
50 fn infer(def_id: DefId) -> Cancelable<Arc<InferenceResult>> { 55 fn infer(def_id: DefId) -> Cancelable<Arc<InferenceResult>> {
51 type InferQuery; 56 type InferQuery;
52 use fn crate::ty::infer; 57 use fn crate::ty::infer;
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index 0aa687a08..db0107e53 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -3,7 +3,7 @@ use ra_syntax::{TreePtr, SyntaxKind, SyntaxNode, SourceFile, AstNode, ast};
3use ra_arena::{Arena, RawId, impl_arena_id}; 3use ra_arena::{Arena, RawId, impl_arena_id};
4 4
5use crate::{ 5use crate::{
6 HirDatabase, PerNs, Def, Function, Struct, Enum, ImplBlock, Crate, 6 HirDatabase, PerNs, Def, Function, Struct, Enum, EnumVariant, ImplBlock, Crate,
7 module_tree::ModuleId, 7 module_tree::ModuleId,
8}; 8};
9 9
@@ -145,6 +145,7 @@ pub(crate) enum DefKind {
145 Function, 145 Function,
146 Struct, 146 Struct,
147 Enum, 147 Enum,
148 EnumVariant,
148 Item, 149 Item,
149 150
150 StructCtor, 151 StructCtor,
@@ -170,10 +171,8 @@ impl DefId {
170 let struct_def = Struct::new(self); 171 let struct_def = Struct::new(self);
171 Def::Struct(struct_def) 172 Def::Struct(struct_def)
172 } 173 }
173 DefKind::Enum => { 174 DefKind::Enum => Def::Enum(Enum::new(self)),
174 let enum_def = Enum::new(self); 175 DefKind::EnumVariant => Def::EnumVariant(EnumVariant::new(self)),
175 Def::Enum(enum_def)
176 }
177 DefKind::StructCtor => Def::Item, 176 DefKind::StructCtor => Def::Item,
178 DefKind::Item => Def::Item, 177 DefKind::Item => Def::Item,
179 }; 178 };
@@ -258,7 +257,9 @@ impl SourceFileItems {
258 // change parent's id. This means that, say, adding a new function to a 257 // change parent's id. This means that, say, adding a new function to a
259 // trait does not chage ids of top-level items, which helps caching. 258 // trait does not chage ids of top-level items, which helps caching.
260 bfs(source_file.syntax(), |it| { 259 bfs(source_file.syntax(), |it| {
261 if let Some(module_item) = ast::ModuleItem::cast(it) { 260 if let Some(enum_variant) = ast::EnumVariant::cast(it) {
261 self.alloc(enum_variant.syntax().to_owned());
262 } else if let Some(module_item) = ast::ModuleItem::cast(it) {
262 self.alloc(module_item.syntax().to_owned()); 263 self.alloc(module_item.syntax().to_owned());
263 } else if let Some(macro_call) = ast::MacroCall::cast(it) { 264 } else if let Some(macro_call) = ast::MacroCall::cast(it) {
264 self.alloc(macro_call.syntax().to_owned()); 265 self.alloc(macro_call.syntax().to_owned());
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 1b6b72c98..74957ffc9 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -56,6 +56,6 @@ pub use self::code_model_api::{
56 Crate, CrateDependency, 56 Crate, CrateDependency,
57 Def, 57 Def,
58 Module, ModuleSource, Problem, 58 Module, ModuleSource, Problem,
59 Struct, Enum, 59 Struct, Enum, EnumVariant,
60 Function, FnSignature, 60 Function, FnSignature,
61}; 61};
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index 7a0301648..6f93bb59d 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -233,6 +233,7 @@ salsa::database_storage! {
233 fn type_for_field() for db::TypeForFieldQuery; 233 fn type_for_field() for db::TypeForFieldQuery;
234 fn struct_data() for db::StructDataQuery; 234 fn struct_data() for db::StructDataQuery;
235 fn enum_data() for db::EnumDataQuery; 235 fn enum_data() for db::EnumDataQuery;
236 fn enum_variant_data() for db::EnumVariantDataQuery;
236 fn impls_in_module() for db::ImplsInModuleQuery; 237 fn impls_in_module() for db::ImplsInModuleQuery;
237 fn body_hir() for db::BodyHirQuery; 238 fn body_hir() for db::BodyHirQuery;
238 fn body_syntax_mapping() for db::BodySyntaxMappingQuery; 239 fn body_syntax_mapping() for db::BodySyntaxMappingQuery;
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index eb7764f65..18c41a015 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -30,7 +30,7 @@ use join_to_string::join;
30use ra_db::Cancelable; 30use ra_db::Cancelable;
31 31
32use crate::{ 32use crate::{
33 Def, DefId, Module, Function, Struct, Enum, Path, Name, ImplBlock, 33 Def, DefId, Module, Function, Struct, Enum, EnumVariant, Path, Name, ImplBlock,
34 FnSignature, FnScopes, 34 FnSignature, FnScopes,
35 db::HirDatabase, 35 db::HirDatabase,
36 type_ref::{TypeRef, Mutability}, 36 type_ref::{TypeRef, Mutability},
@@ -453,6 +453,12 @@ pub fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Cancelable<Ty> {
453 }) 453 })
454} 454}
455 455
456pub fn type_for_enum_variant(db: &impl HirDatabase, ev: EnumVariant) -> Cancelable<Ty> {
457 let enum_parent = ev.parent_enum(db)?;
458
459 type_for_enum(db, enum_parent)
460}
461
456pub(super) fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Ty> { 462pub(super) fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Ty> {
457 let def = def_id.resolve(db)?; 463 let def = def_id.resolve(db)?;
458 match def { 464 match def {
@@ -463,6 +469,7 @@ pub(super) fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<T
463 Def::Function(f) => type_for_fn(db, f), 469 Def::Function(f) => type_for_fn(db, f),
464 Def::Struct(s) => type_for_struct(db, s), 470 Def::Struct(s) => type_for_struct(db, s),
465 Def::Enum(e) => type_for_enum(db, e), 471 Def::Enum(e) => type_for_enum(db, e),
472 Def::EnumVariant(ev) => type_for_enum_variant(db, ev),
466 Def::Item => { 473 Def::Item => {
467 log::debug!("trying to get type for item of unknown type {:?}", def_id); 474 log::debug!("trying to get type for item of unknown type {:?}", def_id);
468 Ok(Ty::Unknown) 475 Ok(Ty::Unknown)
@@ -477,12 +484,9 @@ pub(super) fn type_for_field(
477) -> Cancelable<Option<Ty>> { 484) -> Cancelable<Option<Ty>> {
478 let def = def_id.resolve(db)?; 485 let def = def_id.resolve(db)?;
479 let variant_data = match def { 486 let variant_data = match def {
480 Def::Struct(s) => { 487 Def::Struct(s) => s.variant_data(db)?,
481 let variant_data = s.variant_data(db)?; 488 Def::EnumVariant(ev) => ev.variant_data(db)?,
482 variant_data
483 }
484 // TODO: unions 489 // TODO: unions
485 // TODO: enum variants
486 _ => panic!( 490 _ => panic!(
487 "trying to get type for field in non-struct/variant {:?}", 491 "trying to get type for field in non-struct/variant {:?}",
488 def_id 492 def_id
@@ -788,6 +792,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
788 let ty = type_for_struct(self.db, s)?; 792 let ty = type_for_struct(self.db, s)?;
789 (ty, Some(def_id)) 793 (ty, Some(def_id))
790 } 794 }
795 Def::EnumVariant(ev) => {
796 let ty = type_for_enum_variant(self.db, ev)?;
797 (ty, Some(def_id))
798 }
791 _ => (Ty::Unknown, None), 799 _ => (Ty::Unknown, None),
792 }) 800 })
793 } 801 }
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index ba2a44474..d8c0af326 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -95,6 +95,22 @@ fn test() {
95} 95}
96 96
97#[test] 97#[test]
98fn infer_enum() {
99 check_inference(
100 r#"
101enum E {
102 V1 { field: u32 },
103 V2
104}
105fn test() {
106 E::V1 { field: 1 };
107 E::V2;
108}"#,
109 "enum.txt",
110 );
111}
112
113#[test]
98fn infer_refs() { 114fn infer_refs() {
99 check_inference( 115 check_inference(
100 r#" 116 r#"
diff --git a/crates/ra_hir/src/ty/tests/data/enum.txt b/crates/ra_hir/src/ty/tests/data/enum.txt
new file mode 100644
index 000000000..481eb0bc7
--- /dev/null
+++ b/crates/ra_hir/src/ty/tests/data/enum.txt
@@ -0,0 +1,4 @@
1[48; 82) '{ E:...:V2; }': ()
2[52; 70) 'E::V1 ...d: 1 }': E
3[67; 68) '1': u32
4[74; 79) 'E::V2': E
diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs
index 4723a65a6..6a55670d1 100644
--- a/crates/ra_ide_api/src/completion/complete_path.rs
+++ b/crates/ra_ide_api/src/completion/complete_path.rs
@@ -21,14 +21,20 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) -> C
21 .add_to(acc) 21 .add_to(acc)
22 }); 22 });
23 } 23 }
24 hir::Def::Enum(e) => e 24 hir::Def::Enum(e) => {
25 .variants(ctx.db)? 25 e.variants(ctx.db)?
26 .into_iter() 26 .unwrap_or(vec![])
27 .for_each(|(name, _variant)| { 27 .into_iter()
28 CompletionItem::new(CompletionKind::Reference, name.to_string()) 28 .for_each(|variant| {
29 .kind(CompletionItemKind::EnumVariant) 29 let variant_name = variant.name(ctx.db);
30 .add_to(acc) 30
31 }), 31 if let Ok(Some(name)) = variant_name {
32 CompletionItem::new(CompletionKind::Reference, name.to_string())
33 .kind(CompletionItemKind::EnumVariant)
34 .add_to(acc)
35 }
36 })
37 }
32 _ => return Ok(()), 38 _ => return Ok(()),
33 }; 39 };
34 Ok(()) 40 Ok(())
diff --git a/crates/ra_ide_api/src/db.rs b/crates/ra_ide_api/src/db.rs
index a2e06f5db..efdf261be 100644
--- a/crates/ra_ide_api/src/db.rs
+++ b/crates/ra_ide_api/src/db.rs
@@ -122,6 +122,7 @@ salsa::database_storage! {
122 fn type_for_field() for hir::db::TypeForFieldQuery; 122 fn type_for_field() for hir::db::TypeForFieldQuery;
123 fn struct_data() for hir::db::StructDataQuery; 123 fn struct_data() for hir::db::StructDataQuery;
124 fn enum_data() for hir::db::EnumDataQuery; 124 fn enum_data() for hir::db::EnumDataQuery;
125 fn enum_variant_data() for hir::db::EnumVariantDataQuery;
125 fn impls_in_module() for hir::db::ImplsInModuleQuery; 126 fn impls_in_module() for hir::db::ImplsInModuleQuery;
126 fn body_hir() for hir::db::BodyHirQuery; 127 fn body_hir() for hir::db::BodyHirQuery;
127 fn body_syntax_mapping() for hir::db::BodySyntaxMappingQuery; 128 fn body_syntax_mapping() for hir::db::BodySyntaxMappingQuery;