aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty.rs
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-01-06 18:51:42 +0000
committerFlorian Diebold <[email protected]>2019-01-07 13:54:23 +0000
commit7bb279b365e54ee0051e09ead5aa157ff6be917b (patch)
tree7a495d68453ea1e3c7a726e97bbbe19f9bc90532 /crates/ra_hir/src/ty.rs
parenta6071c9f4c8441b4b8f2e970bc055d66cc9be5f0 (diff)
Implement autoderef for field accesses
Diffstat (limited to 'crates/ra_hir/src/ty.rs')
-rw-r--r--crates/ra_hir/src/ty.rs72
1 files changed, 50 insertions, 22 deletions
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index d57990cd2..bba8527b7 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -13,6 +13,7 @@
13//! the union-find implementation from the `ena` crate, which is extracted from 13//! the union-find implementation from the `ena` crate, which is extracted from
14//! rustc. 14//! rustc.
15 15
16mod autoderef;
16mod primitive; 17mod primitive;
17#[cfg(test)] 18#[cfg(test)]
18mod tests; 19mod tests;
@@ -36,6 +37,14 @@ use crate::{
36 expr::{Body, Expr, ExprId, PatId, UnaryOp, BinaryOp, Statement}, 37 expr::{Body, Expr, ExprId, PatId, UnaryOp, BinaryOp, Statement},
37}; 38};
38 39
40fn transpose<T>(x: Cancelable<Option<T>>) -> Option<Cancelable<T>> {
41 match x {
42 Ok(Some(t)) => Some(Ok(t)),
43 Ok(None) => None,
44 Err(e) => Some(Err(e)),
45 }
46}
47
39/// The ID of a type variable. 48/// The ID of a type variable.
40#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] 49#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
41pub struct TypeVarId(u32); 50pub struct TypeVarId(u32);
@@ -357,6 +366,14 @@ impl Ty {
357 }); 366 });
358 self 367 self
359 } 368 }
369
370 fn builtin_deref(&self) -> Option<Ty> {
371 match self {
372 Ty::Ref(t, _) => Some(Ty::clone(t)),
373 Ty::RawPtr(t, _) => Some(Ty::clone(t)),
374 _ => None,
375 }
376 }
360} 377}
361 378
362impl fmt::Display for Ty { 379impl fmt::Display for Ty {
@@ -443,7 +460,11 @@ pub(super) fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<T
443 } 460 }
444} 461}
445 462
446pub(super) fn type_for_field(db: &impl HirDatabase, def_id: DefId, field: Name) -> Cancelable<Ty> { 463pub(super) fn type_for_field(
464 db: &impl HirDatabase,
465 def_id: DefId,
466 field: Name,
467) -> Cancelable<Option<Ty>> {
447 let def = def_id.resolve(db)?; 468 let def = def_id.resolve(db)?;
448 let variant_data = match def { 469 let variant_data = match def {
449 Def::Struct(s) => { 470 Def::Struct(s) => {
@@ -459,12 +480,13 @@ pub(super) fn type_for_field(db: &impl HirDatabase, def_id: DefId, field: Name)
459 }; 480 };
460 let module = def_id.module(db)?; 481 let module = def_id.module(db)?;
461 let impl_block = def_id.impl_block(db)?; 482 let impl_block = def_id.impl_block(db)?;
462 let type_ref = if let Some(tr) = variant_data.get_field_type_ref(&field) { 483 let type_ref = ctry!(variant_data.get_field_type_ref(&field));
463 tr 484 Ok(Some(Ty::from_hir(
464 } else { 485 db,
465 return Ok(Ty::Unknown); 486 &module,
466 }; 487 impl_block.as_ref(),
467 Ty::from_hir(db, &module, impl_block.as_ref(), &type_ref) 488 &type_ref,
489 )?))
468} 490}
469 491
470/// The result of type inference: A mapping from expressions and patterns to types. 492/// The result of type inference: A mapping from expressions and patterns to types.
@@ -802,7 +824,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
802 let (ty, def_id) = self.resolve_variant(path.as_ref())?; 824 let (ty, def_id) = self.resolve_variant(path.as_ref())?;
803 for field in fields { 825 for field in fields {
804 let field_ty = if let Some(def_id) = def_id { 826 let field_ty = if let Some(def_id) = def_id {
805 self.db.type_for_field(def_id, field.name.clone())? 827 self.db
828 .type_for_field(def_id, field.name.clone())?
829 .unwrap_or(Ty::Unknown)
806 } else { 830 } else {
807 Ty::Unknown 831 Ty::Unknown
808 }; 832 };
@@ -815,15 +839,20 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
815 } 839 }
816 Expr::Field { expr, name } => { 840 Expr::Field { expr, name } => {
817 let receiver_ty = self.infer_expr(*expr, &Expectation::none())?; 841 let receiver_ty = self.infer_expr(*expr, &Expectation::none())?;
818 let ty = match receiver_ty { 842 let ty = receiver_ty
819 Ty::Tuple(fields) => { 843 .autoderef(self.db)
820 let i = name.to_string().parse::<usize>().ok(); 844 .find_map(|derefed_ty| match derefed_ty {
821 i.and_then(|i| fields.get(i).cloned()) 845 // this is more complicated than necessary because type_for_field is cancelable
822 .unwrap_or(Ty::Unknown) 846 Ty::Tuple(fields) => {
823 } 847 let i = name.to_string().parse::<usize>().ok();
824 Ty::Adt { def_id, .. } => self.db.type_for_field(def_id, name.clone())?, 848 i.and_then(|i| fields.get(i).cloned()).map(Ok)
825 _ => Ty::Unknown, 849 }
826 }; 850 Ty::Adt { def_id, .. } => {
851 transpose(self.db.type_for_field(def_id, name.clone()))
852 }
853 _ => None,
854 })
855 .unwrap_or(Ok(Ty::Unknown))?;
827 self.insert_type_vars(ty) 856 self.insert_type_vars(ty)
828 } 857 }
829 Expr::Try { expr } => { 858 Expr::Try { expr } => {
@@ -848,12 +877,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
848 let inner_ty = self.infer_expr(*expr, &Expectation::none())?; 877 let inner_ty = self.infer_expr(*expr, &Expectation::none())?;
849 match op { 878 match op {
850 Some(UnaryOp::Deref) => { 879 Some(UnaryOp::Deref) => {
851 match inner_ty { 880 if let Some(derefed_ty) = inner_ty.builtin_deref() {
852 // builtin deref: 881 derefed_ty
853 Ty::Ref(ref_inner, _) => (*ref_inner).clone(), 882 } else {
854 Ty::RawPtr(ptr_inner, _) => (*ptr_inner).clone(),
855 // TODO Deref::deref 883 // TODO Deref::deref
856 _ => Ty::Unknown, 884 Ty::Unknown
857 } 885 }
858 } 886 }
859 _ => Ty::Unknown, 887 _ => Ty::Unknown,