diff options
author | Florian Diebold <[email protected]> | 2018-12-24 20:00:14 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2018-12-25 14:16:42 +0000 |
commit | 6fcd38cc81bdcc9921da767872dfce65ee7d2d27 (patch) | |
tree | 5d5ae0f57cc25d0bf8b0613a5e05de1f773b42ef /crates/ra_hir/src/ty.rs | |
parent | 4ff161852016c6c15954d6f30bd637834a2b2b68 (diff) |
Infer result of struct literals, and recurse into their child expressions
Diffstat (limited to 'crates/ra_hir/src/ty.rs')
-rw-r--r-- | crates/ra_hir/src/ty.rs | 119 |
1 files changed, 83 insertions, 36 deletions
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 | ||
18 | use crate::{ | 18 | use 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 | ||
127 | impl Ty { | 127 | impl 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 | ||
250 | pub 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 |