aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2018-12-24 20:00:14 +0000
committerFlorian Diebold <[email protected]>2018-12-25 14:16:42 +0000
commit6fcd38cc81bdcc9921da767872dfce65ee7d2d27 (patch)
tree5d5ae0f57cc25d0bf8b0613a5e05de1f773b42ef /crates/ra_hir
parent4ff161852016c6c15954d6f30bd637834a2b2b68 (diff)
Infer result of struct literals, and recurse into their child expressions
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/src/adt.rs27
-rw-r--r--crates/ra_hir/src/ty.rs119
-rw-r--r--crates/ra_hir/src/ty/tests.rs2
-rw-r--r--crates/ra_hir/src/ty/tests/data/0004_struct.txt12
4 files changed, 117 insertions, 43 deletions
diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs
index a2d228593..ee270ac45 100644
--- a/crates/ra_hir/src/adt.rs
+++ b/crates/ra_hir/src/adt.rs
@@ -1,3 +1,5 @@
1use std::sync::Arc;
2
1use ra_syntax::{SmolStr, ast::{self, NameOwner}}; 3use ra_syntax::{SmolStr, ast::{self, NameOwner}};
2 4
3use crate::{ 5use crate::{
@@ -15,6 +17,14 @@ impl Struct {
15 Struct { def_id } 17 Struct { def_id }
16 } 18 }
17 19
20 pub fn def_id(&self) -> DefId {
21 self.def_id
22 }
23
24 pub fn struct_data(&self, db: &impl HirDatabase) -> Cancelable<Arc<StructData>> {
25 Ok(db.struct_data(self.def_id)?)
26 }
27
18 pub fn name(&self, db: &impl HirDatabase) -> Cancelable<SmolStr> { 28 pub fn name(&self, db: &impl HirDatabase) -> Cancelable<SmolStr> {
19 Ok(db.struct_data(self.def_id)?.name.clone()) 29 Ok(db.struct_data(self.def_id)?.name.clone())
20 } 30 }
@@ -23,7 +33,7 @@ impl Struct {
23#[derive(Debug, Clone, PartialEq, Eq)] 33#[derive(Debug, Clone, PartialEq, Eq)]
24pub struct StructData { 34pub struct StructData {
25 name: SmolStr, 35 name: SmolStr,
26 variant_data: VariantData, 36 variant_data: Arc<VariantData>,
27} 37}
28 38
29impl StructData { 39impl StructData {
@@ -33,8 +43,17 @@ impl StructData {
33 .map(|n| n.text()) 43 .map(|n| n.text())
34 .unwrap_or(SmolStr::new("[error]")); 44 .unwrap_or(SmolStr::new("[error]"));
35 let variant_data = VariantData::Unit; // TODO implement this 45 let variant_data = VariantData::Unit; // TODO implement this
46 let variant_data = Arc::new(variant_data);
36 StructData { name, variant_data } 47 StructData { name, variant_data }
37 } 48 }
49
50 pub fn name(&self) -> &SmolStr {
51 &self.name
52 }
53
54 pub fn variant_data(&self) -> &Arc<VariantData> {
55 &self.variant_data
56 }
38} 57}
39 58
40pub struct Enum { 59pub struct Enum {
@@ -46,6 +65,10 @@ impl Enum {
46 Enum { def_id } 65 Enum { def_id }
47 } 66 }
48 67
68 pub fn def_id(&self) -> DefId {
69 self.def_id
70 }
71
49 pub fn name(&self, db: &impl HirDatabase) -> Cancelable<SmolStr> { 72 pub fn name(&self, db: &impl HirDatabase) -> Cancelable<SmolStr> {
50 Ok(db.enum_data(self.def_id)?.name.clone()) 73 Ok(db.enum_data(self.def_id)?.name.clone())
51 } 74 }
@@ -54,7 +77,7 @@ impl Enum {
54#[derive(Debug, Clone, PartialEq, Eq)] 77#[derive(Debug, Clone, PartialEq, Eq)]
55pub struct EnumData { 78pub struct EnumData {
56 name: SmolStr, 79 name: SmolStr,
57 variants: Vec<(SmolStr, VariantData)>, 80 variants: Vec<(SmolStr, Arc<VariantData>)>,
58} 81}
59 82
60impl EnumData { 83impl EnumData {
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 429292cfc..386af8120 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -16,9 +16,9 @@ use ra_syntax::{
16}; 16};
17 17
18use crate::{ 18use crate::{
19 Def, DefId, FnScopes, Module, Function, 19 Def, DefId, FnScopes, Module, Function, Struct, Path,
20 Path, db::HirDatabase, 20 db::HirDatabase,
21 module::nameres::Namespace 21 adt::VariantData,
22}; 22};
23 23
24#[derive(Clone, PartialEq, Eq, Hash, Debug)] 24#[derive(Clone, PartialEq, Eq, Hash, Debug)]
@@ -125,6 +125,37 @@ pub struct FnSig {
125} 125}
126 126
127impl Ty { 127impl Ty {
128 pub(crate) fn new_from_ast_path(
129 db: &impl HirDatabase,
130 module: &Module,
131 path: ast::Path,
132 ) -> Cancelable<Self> {
133 let path = if let Some(p) = Path::from_ast(path) {
134 p
135 } else {
136 return Ok(Ty::Unknown);
137 };
138 if path.is_ident() {
139 let name = &path.segments[0];
140 if let Some(int_ty) = primitive::IntTy::from_string(&name) {
141 return Ok(Ty::Int(int_ty));
142 } else if let Some(uint_ty) = primitive::UintTy::from_string(&name) {
143 return Ok(Ty::Uint(uint_ty));
144 } else if let Some(float_ty) = primitive::FloatTy::from_string(&name) {
145 return Ok(Ty::Float(float_ty));
146 }
147 }
148
149 // Resolve in module (in type namespace)
150 let resolved = if let Some(r) = module.resolve_path(db, path)?.take_types() {
151 r
152 } else {
153 return Ok(Ty::Unknown);
154 };
155 let ty = db.type_for_def(resolved)?;
156 Ok(ty)
157 }
158
128 pub(crate) fn new( 159 pub(crate) fn new(
129 db: &impl HirDatabase, 160 db: &impl HirDatabase,
130 module: &Module, 161 module: &Module,
@@ -136,31 +167,11 @@ impl Ty {
136 TupleType(_inner) => Ty::Unknown, // TODO 167 TupleType(_inner) => Ty::Unknown, // TODO
137 NeverType(..) => Ty::Never, 168 NeverType(..) => Ty::Never,
138 PathType(inner) => { 169 PathType(inner) => {
139 let path = if let Some(p) = inner.path().and_then(Path::from_ast) { 170 if let Some(path) = inner.path() {
140 p 171 Ty::new_from_ast_path(db, module, path)?
141 } else { 172 } else {
142 return Ok(Ty::Unknown); 173 Ty::Unknown
143 };
144 if path.is_ident() {
145 let name = &path.segments[0];
146 if let Some(int_ty) = primitive::IntTy::from_string(&name) {
147 return Ok(Ty::Int(int_ty));
148 } else if let Some(uint_ty) = primitive::UintTy::from_string(&name) {
149 return Ok(Ty::Uint(uint_ty));
150 } else if let Some(float_ty) = primitive::FloatTy::from_string(&name) {
151 return Ok(Ty::Float(float_ty));
152 }
153 } 174 }
154
155 // Resolve in module (in type namespace)
156 let resolved =
157 if let Some(r) = module.resolve_path(db, path)?.take(Namespace::Types) {
158 r
159 } else {
160 return Ok(Ty::Unknown);
161 };
162 let ty = db.type_for_def(resolved)?;
163 ty
164 } 175 }
165 PointerType(_inner) => Ty::Unknown, // TODO 176 PointerType(_inner) => Ty::Unknown, // TODO
166 ArrayType(_inner) => Ty::Unknown, // TODO 177 ArrayType(_inner) => Ty::Unknown, // TODO
@@ -236,6 +247,13 @@ pub fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> {
236 Ok(Ty::FnPtr(Arc::new(sig))) 247 Ok(Ty::FnPtr(Arc::new(sig)))
237} 248}
238 249
250pub fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Cancelable<Ty> {
251 Ok(Ty::Adt {
252 def_id: s.def_id(),
253 name: s.name(db)?,
254 })
255}
256
239// TODO this should probably be per namespace (i.e. types vs. values), since for 257// TODO this should probably be per namespace (i.e. types vs. values), since for
240// a tuple struct `struct Foo(Bar)`, Foo has function type as a value, but 258// a tuple struct `struct Foo(Bar)`, Foo has function type as a value, but
241// defines the struct type Foo when used in the type namespace. rustc has a 259// defines the struct type Foo when used in the type namespace. rustc has a
@@ -249,10 +267,7 @@ pub fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Ty> {
249 Ok(Ty::Unknown) 267 Ok(Ty::Unknown)
250 } 268 }
251 Def::Function(f) => type_for_fn(db, f), 269 Def::Function(f) => type_for_fn(db, f),
252 Def::Struct(s) => Ok(Ty::Adt { 270 Def::Struct(s) => type_for_struct(db, s),
253 def_id,
254 name: s.name(db)?,
255 }),
256 Def::Enum(e) => Ok(Ty::Adt { 271 Def::Enum(e) => Ok(Ty::Adt {
257 def_id, 272 def_id,
258 name: e.name(db)?, 273 name: e.name(db)?,
@@ -330,15 +345,36 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
330 }; 345 };
331 346
332 // resolve in module 347 // resolve in module
333 let resolved = ctry!(self 348 let resolved = ctry!(self.module.resolve_path(self.db, path)?.take_values());
334 .module
335 .resolve_path(self.db, path)?
336 .take(Namespace::Values));
337 let ty = self.db.type_for_def(resolved)?; 349 let ty = self.db.type_for_def(resolved)?;
338 // TODO we will need to add type variables for type parameters etc. here 350 // TODO we will need to add type variables for type parameters etc. here
339 Ok(Some(ty)) 351 Ok(Some(ty))
340 } 352 }
341 353
354 fn resolve_variant(
355 &self,
356 path: Option<ast::Path>,
357 ) -> Cancelable<(Ty, Option<Arc<VariantData>>)> {
358 let path = if let Some(path) = path.and_then(Path::from_ast) {
359 path
360 } else {
361 return Ok((Ty::Unknown, None));
362 };
363 let def_id = if let Some(def_id) = self.module.resolve_path(self.db, path)?.take_types() {
364 def_id
365 } else {
366 return Ok((Ty::Unknown, None));
367 };
368 Ok(match def_id.resolve(self.db)? {
369 Def::Struct(s) => {
370 let struct_data = self.db.struct_data(def_id)?;
371 let ty = type_for_struct(self.db, s)?;
372 (ty, Some(struct_data.variant_data().clone()))
373 }
374 _ => (Ty::Unknown, None),
375 })
376 }
377
342 fn infer_expr(&mut self, expr: ast::Expr) -> Cancelable<Ty> { 378 fn infer_expr(&mut self, expr: ast::Expr) -> Cancelable<Ty> {
343 let ty = match expr { 379 let ty = match expr {
344 ast::Expr::IfExpr(e) => { 380 ast::Expr::IfExpr(e) => {
@@ -488,7 +524,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
488 ast::Expr::Label(_e) => Ty::Unknown, 524 ast::Expr::Label(_e) => Ty::Unknown,
489 ast::Expr::ReturnExpr(e) => { 525 ast::Expr::ReturnExpr(e) => {
490 if let Some(e) = e.expr() { 526 if let Some(e) = e.expr() {
491 // TODO unify with return type 527 // TODO unify with / expect return type
492 self.infer_expr(e)?; 528 self.infer_expr(e)?;
493 }; 529 };
494 Ty::Never 530 Ty::Never
@@ -497,7 +533,18 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
497 // Can this even occur outside of a match expression? 533 // Can this even occur outside of a match expression?
498 Ty::Unknown 534 Ty::Unknown
499 } 535 }
500 ast::Expr::StructLit(_e) => Ty::Unknown, 536 ast::Expr::StructLit(e) => {
537 let (ty, variant_data) = self.resolve_variant(e.path())?;
538 if let Some(nfl) = e.named_field_list() {
539 for field in nfl.fields() {
540 if let Some(e) = field.expr() {
541 // TODO unify with / expect field type
542 self.infer_expr(e)?;
543 }
544 }
545 }
546 ty
547 }
501 ast::Expr::NamedFieldList(_) | ast::Expr::NamedField(_) => { 548 ast::Expr::NamedFieldList(_) | ast::Expr::NamedField(_) => {
502 // Can this even occur outside of a struct literal? 549 // Can this even occur outside of a struct literal?
503 Ty::Unknown 550 Ty::Unknown
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 170eef147..9bb58ec85 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -82,7 +82,7 @@ struct C(usize);
82fn test() { 82fn test() {
83 let c = C(1); 83 let c = C(1);
84 B; 84 B;
85 let a: A = A { b: B, c: C() }; 85 let a: A = A { b: B, c: C(1) };
86 a.b; 86 a.b;
87 a.c; 87 a.c;
88} 88}
diff --git a/crates/ra_hir/src/ty/tests/data/0004_struct.txt b/crates/ra_hir/src/ty/tests/data/0004_struct.txt
index a4371c5a5..41357749f 100644
--- a/crates/ra_hir/src/ty/tests/data/0004_struct.txt
+++ b/crates/ra_hir/src/ty/tests/data/0004_struct.txt
@@ -1,10 +1,14 @@
1[86; 90) 'C(1)': [unknown] 1[86; 90) 'C(1)': [unknown]
2[72; 153) '{ ...a.c; }': () 2[121; 122) 'B': [unknown]
3[86; 87) 'C': [unknown] 3[86; 87) 'C': [unknown]
4[129; 130) '1': [unknown]
4[107; 108) 'a': A 5[107; 108) 'a': A
5[114; 132) 'A { b:... C() }': [unknown] 6[127; 128) 'C': [unknown]
6[138; 141) 'a.b': [unknown] 7[139; 142) 'a.b': [unknown]
7[147; 150) 'a.c': [unknown] 8[114; 133) 'A { b:...C(1) }': A
9[148; 151) 'a.c': [unknown]
10[72; 154) '{ ...a.c; }': ()
8[96; 97) 'B': [unknown] 11[96; 97) 'B': [unknown]
9[88; 89) '1': [unknown] 12[88; 89) '1': [unknown]
10[82; 83) 'c': [unknown] 13[82; 83) 'c': [unknown]
14[127; 131) 'C(1)': [unknown]