Type field accesses

This commit is contained in:
Florian Diebold 2018-12-25 13:54:38 +01:00
parent 07a7285965
commit 55c941cd9f
5 changed files with 54 additions and 5 deletions

View File

@ -22,6 +22,10 @@ impl Struct {
self.def_id
}
pub fn variant_data(&self, db: &impl HirDatabase) -> Cancelable<Arc<VariantData>> {
Ok(db.struct_data(self.def_id)?.variant_data.clone())
}
pub fn struct_data(&self, db: &impl HirDatabase) -> Cancelable<Arc<StructData>> {
Ok(db.struct_data(self.def_id)?)
}
@ -162,6 +166,11 @@ impl VariantData {
StructFlavor::Unit => VariantData::Unit,
})
}
pub(crate) fn get_field_ty(&self, field_name: &str) -> Option<Ty> {
self.fields().iter().find(|f| f.name == field_name).map(|f| f.ty.clone())
}
pub fn fields(&self) -> &[StructField] {
match *self {
VariantData::Struct(ref fields) | VariantData::Tuple(ref fields) => fields,

View File

@ -384,6 +384,14 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
})
}
fn infer_expr_opt(&mut self, expr: Option<ast::Expr>) -> Cancelable<Ty> {
if let Some(e) = expr {
self.infer_expr(e)
} else {
Ok(Ty::Unknown)
}
}
fn infer_expr(&mut self, expr: ast::Expr) -> Cancelable<Ty> {
let ty = match expr {
ast::Expr::IfExpr(e) => {
@ -559,7 +567,29 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
Ty::Unknown
}
ast::Expr::IndexExpr(_e) => Ty::Unknown,
ast::Expr::FieldExpr(_e) => Ty::Unknown,
ast::Expr::FieldExpr(e) => {
let receiver_ty = self.infer_expr_opt(e.expr())?;
if let Some(nr) = e.name_ref() {
let text = nr.text();
match receiver_ty {
Ty::Tuple(fields) => {
let i = text.parse::<usize>().ok();
i.and_then(|i| fields.get(i).cloned()).unwrap_or(Ty::Unknown)
}
Ty::Adt { def_id, .. } => {
let field_ty = match def_id.resolve(self.db)? {
Def::Struct(s) => s.variant_data(self.db)?.get_field_ty(&text),
// TODO unions
_ => None,
};
field_ty.unwrap_or(Ty::Unknown)
}
_ => Ty::Unknown,
}
} else {
Ty::Unknown
}
},
ast::Expr::TryExpr(e) => {
let _inner_ty = if let Some(e) = e.expr() {
self.infer_expr(e)?

View File

@ -4,9 +4,11 @@
[129; 130) '1': [unknown]
[107; 108) 'a': A
[127; 128) 'C': [unknown]
[139; 142) 'a.b': [unknown]
[139; 142) 'a.b': B
[114; 133) 'A { b:...C(1) }': A
[148; 151) 'a.c': [unknown]
[148; 151) 'a.c': C
[148; 149) 'a': A
[139; 140) 'a': A
[72; 154) '{ ...a.c; }': ()
[96; 97) 'B': [unknown]
[88; 89) '1': [unknown]

View File

@ -1123,7 +1123,15 @@ impl<R: TreeRoot<RaTypes>> FieldExprNode<R> {
}
impl<'a> FieldExpr<'a> {}
impl<'a> FieldExpr<'a> {
pub fn expr(self) -> Option<Expr<'a>> {
super::child_opt(self)
}
pub fn name_ref(self) -> Option<NameRef<'a>> {
super::child_opt(self)
}
}
// FieldPatList
#[derive(Debug, Clone, Copy,)]

View File

@ -406,7 +406,7 @@ Grammar(
options: [ "Expr" ],
),
"IndexExpr": (),
"FieldExpr": (),
"FieldExpr": (options: ["Expr", "NameRef"]),
"TryExpr": (options: ["Expr"]),
"CastExpr": (options: ["Expr", "TypeRef"]),
"RefExpr": (options: ["Expr"]),