aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-01-10 19:12:40 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-01-10 19:12:40 +0000
commitdc2a8d5acc53054c86ad17260b69d4bf4f14dbc6 (patch)
treeddf2dbe793448d3e913f869c7dab91ce7175b623 /crates/ra_hir
parenta95536301c346e68a109915e6d54136cae875ab0 (diff)
parente78286c8e88d31045d354320a1d29bbd75405027 (diff)
Merge #470
470: Type inference for enum variants r=flodiebold a=marcusklaas Opened a new PR instead of https://github.com/rust-analyzer/rust-analyzer/pull/461. Totally botched that one. I think I resolved all the issues mentioned there. Co-authored-by: Marcus Klaas de Vries <[email protected]>
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/src/adt.rs108
-rw-r--r--crates/ra_hir/src/code_model_api.rs34
-rw-r--r--crates/ra_hir/src/code_model_impl/module.rs28
-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
10 files changed, 195 insertions, 38 deletions
diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs
index d30390f25..bcb705c24 100644
--- a/crates/ra_hir/src/adt.rs
+++ b/crates/ra_hir/src/adt.rs
@@ -1,10 +1,15 @@
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::{
7 DefId, Name, AsName, Struct, Enum, HirDatabase, DefKind, 10 DefId, DefLoc, Name, AsName, Struct, Enum, EnumVariant,
11 HirDatabase, DefKind,
12 SourceItemId,
8 type_ref::TypeRef, 13 type_ref::TypeRef,
9}; 14};
10 15
@@ -45,33 +50,37 @@ impl StructData {
45 } 50 }
46} 51}
47 52
48impl Enum { 53fn get_def_id(
49 pub(crate) fn new(def_id: DefId) -> Self { 54 db: &impl HirDatabase,
50 Enum { def_id } 55 same_file_loc: &DefLoc,
51 } 56 node: &SyntaxNode,
57 expected_kind: DefKind,
58) -> DefId {
59 let file_id = same_file_loc.source_item_id.file_id;
60 let file_items = db.file_items(file_id);
61
62 let item_id = file_items.id_of(file_id, node);
63 let source_item_id = SourceItemId {
64 item_id: Some(item_id),
65 ..same_file_loc.source_item_id
66 };
67 let loc = DefLoc {
68 kind: expected_kind,
69 source_item_id: source_item_id,
70 ..*same_file_loc
71 };
72 loc.id(db)
52} 73}
53 74
54#[derive(Debug, Clone, PartialEq, Eq)] 75#[derive(Debug, Clone, PartialEq, Eq)]
55pub struct EnumData { 76pub struct EnumData {
56 pub(crate) name: Option<Name>, 77 pub(crate) name: Option<Name>,
57 pub(crate) variants: Vec<(Name, Arc<VariantData>)>, 78 pub(crate) variants: Vec<(Name, EnumVariant)>,
58} 79}
59 80
60impl EnumData { 81impl EnumData {
61 fn new(enum_def: &ast::EnumDef) -> Self { 82 fn new(enum_def: &ast::EnumDef, variants: Vec<(Name, EnumVariant)>) -> Self {
62 let name = enum_def.name().map(|n| n.as_name()); 83 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 } 84 EnumData { name, variants }
76 } 85 }
77 86
@@ -83,7 +92,64 @@ impl EnumData {
83 assert!(def_loc.kind == DefKind::Enum); 92 assert!(def_loc.kind == DefKind::Enum);
84 let syntax = db.file_item(def_loc.source_item_id); 93 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"); 94 let enum_def = ast::EnumDef::cast(&syntax).expect("enum def should point to EnumDef node");
86 Ok(Arc::new(EnumData::new(enum_def))) 95 let variants = if let Some(vl) = enum_def.variant_list() {
96 vl.variants()
97 .filter_map(|variant_def| {
98 let name = variant_def.name().map(|n| n.as_name());
99
100 name.map(|n| {
101 let def_id =
102 get_def_id(db, &def_loc, variant_def.syntax(), DefKind::EnumVariant);
103 (n, EnumVariant::new(def_id))
104 })
105 })
106 .collect()
107 } else {
108 Vec::new()
109 };
110 Ok(Arc::new(EnumData::new(enum_def, variants)))
111 }
112}
113
114#[derive(Debug, Clone, PartialEq, Eq)]
115pub struct EnumVariantData {
116 pub(crate) name: Option<Name>,
117 pub(crate) variant_data: Arc<VariantData>,
118 pub(crate) parent_enum: Enum,
119}
120
121impl EnumVariantData {
122 fn new(variant_def: &ast::EnumVariant, parent_enum: Enum) -> EnumVariantData {
123 let name = variant_def.name().map(|n| n.as_name());
124 let variant_data = VariantData::new(variant_def.flavor());
125 let variant_data = Arc::new(variant_data);
126 EnumVariantData {
127 name,
128 variant_data,
129 parent_enum,
130 }
131 }
132
133 pub(crate) fn enum_variant_data_query(
134 db: &impl HirDatabase,
135 def_id: DefId,
136 ) -> Cancelable<Arc<EnumVariantData>> {
137 let def_loc = def_id.loc(db);
138 assert!(def_loc.kind == DefKind::EnumVariant);
139 let syntax = db.file_item(def_loc.source_item_id);
140 let variant_def = ast::EnumVariant::cast(&syntax)
141 .expect("enum variant def should point to EnumVariant node");
142 let enum_node = syntax
143 .parent()
144 .expect("enum variant should have enum variant list ancestor")
145 .parent()
146 .expect("enum variant list should have enum ancestor");
147 let enum_def_id = get_def_id(db, &def_loc, enum_node, DefKind::Enum);
148
149 Ok(Arc::new(EnumVariantData::new(
150 variant_def,
151 Enum::new(enum_def_id),
152 )))
87 } 153 }
88} 154}
89 155
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs
index fa3e4baa7..725bc7d80 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<Vec<(Name, 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..878dc37c8 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,25 @@ 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 =
146 e.variants(db)?.into_iter().find(|(n, _variant)| n == name);
147
148 if let Some((_n, variant)) = matching_variant {
149 return Ok(PerNs::both(variant.def_id(), e.def_id()));
150 } else {
151 return Ok(PerNs::none());
152 }
153 } else if segments.len() == idx {
154 // enum
155 return Ok(PerNs::types(e.def_id()));
156 } else {
157 // malformed enum?
158 return Ok(PerNs::none());
159 }
160 }
138 _ => return Ok(PerNs::none()), 161 _ => return Ok(PerNs::none()),
139 }; 162 };
140 let scope = module.scope(db)?; 163 let scope = module.scope(db)?;
@@ -146,6 +169,7 @@ impl Module {
146 } 169 }
147 Ok(curr_per_ns) 170 Ok(curr_per_ns)
148 } 171 }
172
149 pub fn problems_impl( 173 pub fn problems_impl(
150 &self, 174 &self,
151 db: &impl HirDatabase, 175 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 b8246a7d1..1aca2f067 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -58,6 +58,6 @@ pub use self::code_model_api::{
58 Crate, CrateDependency, 58 Crate, CrateDependency,
59 Def, 59 Def,
60 Module, ModuleSource, Problem, 60 Module, ModuleSource, Problem,
61 Struct, Enum, 61 Struct, Enum, EnumVariant,
62 Function, FnSignature, 62 Function, FnSignature,
63}; 63};
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