From b5b68f2094d49cacde6d7f0c49f521a0b25f34bd Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Mon, 24 Dec 2018 19:07:48 +0100 Subject: Add basic HIR and types for structs/enums --- crates/ra_hir/src/adt.rs | 114 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 crates/ra_hir/src/adt.rs (limited to 'crates/ra_hir/src/adt.rs') diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs new file mode 100644 index 000000000..a2d228593 --- /dev/null +++ b/crates/ra_hir/src/adt.rs @@ -0,0 +1,114 @@ +use ra_syntax::{SmolStr, ast::{self, NameOwner}}; + +use crate::{ + DefId, Cancelable, + db::{HirDatabase}, + ty::{Ty}, +}; + +pub struct Struct { + def_id: DefId, +} + +impl Struct { + pub(crate) fn new(def_id: DefId) -> Self { + Struct { def_id } + } + + pub fn name(&self, db: &impl HirDatabase) -> Cancelable { + Ok(db.struct_data(self.def_id)?.name.clone()) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct StructData { + name: SmolStr, + variant_data: VariantData, +} + +impl StructData { + pub(crate) fn new(struct_def: ast::StructDef) -> StructData { + let name = struct_def + .name() + .map(|n| n.text()) + .unwrap_or(SmolStr::new("[error]")); + let variant_data = VariantData::Unit; // TODO implement this + StructData { name, variant_data } + } +} + +pub struct Enum { + def_id: DefId, +} + +impl Enum { + pub(crate) fn new(def_id: DefId) -> Self { + Enum { def_id } + } + + pub fn name(&self, db: &impl HirDatabase) -> Cancelable { + Ok(db.enum_data(self.def_id)?.name.clone()) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct EnumData { + name: SmolStr, + variants: Vec<(SmolStr, VariantData)>, +} + +impl EnumData { + pub(crate) fn new(enum_def: ast::EnumDef) -> Self { + let name = enum_def + .name() + .map(|n| n.text()) + .unwrap_or(SmolStr::new("[error]")); + let variants = Vec::new(); // TODO implement this + EnumData { name, variants } + } +} + +/// A single field of an enum variant or struct +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct StructField { + name: SmolStr, + ty: Ty, +} + +/// Fields of an enum variant or struct +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum VariantData { + Struct(Vec), + Tuple(Vec), + Unit, +} + +impl VariantData { + pub fn fields(&self) -> &[StructField] { + match *self { + VariantData::Struct(ref fields) | VariantData::Tuple(ref fields) => fields, + _ => &[], + } + } + pub fn is_struct(&self) -> bool { + if let VariantData::Struct(..) = *self { + true + } else { + false + } + } + pub fn is_tuple(&self) -> bool { + if let VariantData::Tuple(..) = *self { + true + } else { + false + } + } + pub fn is_unit(&self) -> bool { + if let VariantData::Unit = *self { + true + } else { + false + } + } +} -- cgit v1.2.3 From 6fcd38cc81bdcc9921da767872dfce65ee7d2d27 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Mon, 24 Dec 2018 21:00:14 +0100 Subject: Infer result of struct literals, and recurse into their child expressions --- crates/ra_hir/src/adt.rs | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'crates/ra_hir/src/adt.rs') 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 @@ +use std::sync::Arc; + use ra_syntax::{SmolStr, ast::{self, NameOwner}}; use crate::{ @@ -15,6 +17,14 @@ impl Struct { Struct { def_id } } + pub fn def_id(&self) -> DefId { + self.def_id + } + + pub fn struct_data(&self, db: &impl HirDatabase) -> Cancelable> { + Ok(db.struct_data(self.def_id)?) + } + pub fn name(&self, db: &impl HirDatabase) -> Cancelable { Ok(db.struct_data(self.def_id)?.name.clone()) } @@ -23,7 +33,7 @@ impl Struct { #[derive(Debug, Clone, PartialEq, Eq)] pub struct StructData { name: SmolStr, - variant_data: VariantData, + variant_data: Arc, } impl StructData { @@ -33,8 +43,17 @@ impl StructData { .map(|n| n.text()) .unwrap_or(SmolStr::new("[error]")); let variant_data = VariantData::Unit; // TODO implement this + let variant_data = Arc::new(variant_data); StructData { name, variant_data } } + + pub fn name(&self) -> &SmolStr { + &self.name + } + + pub fn variant_data(&self) -> &Arc { + &self.variant_data + } } pub struct Enum { @@ -46,6 +65,10 @@ impl Enum { Enum { def_id } } + pub fn def_id(&self) -> DefId { + self.def_id + } + pub fn name(&self, db: &impl HirDatabase) -> Cancelable { Ok(db.enum_data(self.def_id)?.name.clone()) } @@ -54,7 +77,7 @@ impl Enum { #[derive(Debug, Clone, PartialEq, Eq)] pub struct EnumData { name: SmolStr, - variants: Vec<(SmolStr, VariantData)>, + variants: Vec<(SmolStr, Arc)>, } impl EnumData { -- cgit v1.2.3 From 07a72859650254d8ba326e2c9683ae52164cb3b5 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 25 Dec 2018 13:31:30 +0100 Subject: Collect field data for structs/enum variants --- crates/ra_hir/src/adt.rs | 69 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 62 insertions(+), 7 deletions(-) (limited to 'crates/ra_hir/src/adt.rs') diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs index ee270ac45..b44f59f0b 100644 --- a/crates/ra_hir/src/adt.rs +++ b/crates/ra_hir/src/adt.rs @@ -1,10 +1,11 @@ use std::sync::Arc; -use ra_syntax::{SmolStr, ast::{self, NameOwner}}; +use ra_syntax::{SmolStr, ast::{self, NameOwner, StructFlavor}}; use crate::{ DefId, Cancelable, db::{HirDatabase}, + module::Module, ty::{Ty}, }; @@ -37,14 +38,18 @@ pub struct StructData { } impl StructData { - pub(crate) fn new(struct_def: ast::StructDef) -> StructData { + pub(crate) fn new( + db: &impl HirDatabase, + module: &Module, + struct_def: ast::StructDef, + ) -> Cancelable { let name = struct_def .name() .map(|n| n.text()) .unwrap_or(SmolStr::new("[error]")); - let variant_data = VariantData::Unit; // TODO implement this + let variant_data = VariantData::new(db, module, struct_def.flavor())?; let variant_data = Arc::new(variant_data); - StructData { name, variant_data } + Ok(StructData { name, variant_data }) } pub fn name(&self) -> &SmolStr { @@ -81,13 +86,30 @@ pub struct EnumData { } impl EnumData { - pub(crate) fn new(enum_def: ast::EnumDef) -> Self { + pub(crate) fn new( + db: &impl HirDatabase, + module: &Module, + enum_def: ast::EnumDef, + ) -> Cancelable { let name = enum_def .name() .map(|n| n.text()) .unwrap_or(SmolStr::new("[error]")); - let variants = Vec::new(); // TODO implement this - EnumData { name, variants } + let variants = if let Some(evl) = enum_def.variant_list() { + evl.variants() + .map(|v| { + Ok(( + v.name() + .map(|n| n.text()) + .unwrap_or_else(|| SmolStr::new("[error]")), + Arc::new(VariantData::new(db, module, v.flavor())?), + )) + }) + .collect::>()? + } else { + Vec::new() + }; + Ok(EnumData { name, variants }) } } @@ -107,6 +129,39 @@ pub enum VariantData { } impl VariantData { + pub fn new(db: &impl HirDatabase, module: &Module, flavor: StructFlavor) -> Cancelable { + Ok(match flavor { + StructFlavor::Tuple(fl) => { + let fields = fl + .fields() + .enumerate() + .map(|(i, fd)| { + Ok(StructField { + name: SmolStr::new(i.to_string()), + ty: Ty::new_opt(db, &module, fd.type_ref())?, + }) + }) + .collect::>()?; + VariantData::Tuple(fields) + } + StructFlavor::Named(fl) => { + let fields = fl + .fields() + .map(|fd| { + Ok(StructField { + name: fd + .name() + .map(|n| n.text()) + .unwrap_or_else(|| SmolStr::new("[error]")), + ty: Ty::new_opt(db, &module, fd.type_ref())?, + }) + }) + .collect::>()?; + VariantData::Struct(fields) + } + StructFlavor::Unit => VariantData::Unit, + }) + } pub fn fields(&self) -> &[StructField] { match *self { VariantData::Struct(ref fields) | VariantData::Tuple(ref fields) => fields, -- cgit v1.2.3 From 55c941cd9fb90c9340f01981e113aabd058b185b Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 25 Dec 2018 13:54:38 +0100 Subject: Type field accesses --- crates/ra_hir/src/adt.rs | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'crates/ra_hir/src/adt.rs') diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs index b44f59f0b..03770ed7d 100644 --- a/crates/ra_hir/src/adt.rs +++ b/crates/ra_hir/src/adt.rs @@ -22,6 +22,10 @@ impl Struct { self.def_id } + pub fn variant_data(&self, db: &impl HirDatabase) -> Cancelable> { + Ok(db.struct_data(self.def_id)?.variant_data.clone()) + } + pub fn struct_data(&self, db: &impl HirDatabase) -> Cancelable> { 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 { + 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, -- cgit v1.2.3 From ab0b63992be0cec4999810096a53b40f63f90349 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 25 Dec 2018 15:15:40 +0100 Subject: Implement basic completion for fields --- crates/ra_hir/src/adt.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'crates/ra_hir/src/adt.rs') diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs index 03770ed7d..e65f8deb8 100644 --- a/crates/ra_hir/src/adt.rs +++ b/crates/ra_hir/src/adt.rs @@ -124,6 +124,15 @@ pub struct StructField { ty: Ty, } +impl StructField { + pub fn name(&self) -> SmolStr { + self.name.clone() + } + pub fn ty(&self) -> Ty { + self.ty.clone() + } +} + /// Fields of an enum variant or struct #[derive(Debug, Clone, PartialEq, Eq)] pub enum VariantData { @@ -168,7 +177,10 @@ impl VariantData { } pub(crate) fn get_field_ty(&self, field_name: &str) -> Option { - self.fields().iter().find(|f| f.name == field_name).map(|f| f.ty.clone()) + self.fields() + .iter() + .find(|f| f.name == field_name) + .map(|f| f.ty.clone()) } pub fn fields(&self) -> &[StructField] { -- cgit v1.2.3 From b96d3612390e070936a176571c946ad0cafa69a9 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 25 Dec 2018 17:55:50 +0100 Subject: Handle structs/enums with missing names a bit better --- crates/ra_hir/src/adt.rs | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) (limited to 'crates/ra_hir/src/adt.rs') diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs index e65f8deb8..40a45b831 100644 --- a/crates/ra_hir/src/adt.rs +++ b/crates/ra_hir/src/adt.rs @@ -30,14 +30,14 @@ impl Struct { Ok(db.struct_data(self.def_id)?) } - pub fn name(&self, db: &impl HirDatabase) -> Cancelable { + pub fn name(&self, db: &impl HirDatabase) -> Cancelable> { Ok(db.struct_data(self.def_id)?.name.clone()) } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct StructData { - name: SmolStr, + name: Option, variant_data: Arc, } @@ -47,17 +47,14 @@ impl StructData { module: &Module, struct_def: ast::StructDef, ) -> Cancelable { - let name = struct_def - .name() - .map(|n| n.text()) - .unwrap_or(SmolStr::new("[error]")); + let name = struct_def.name().map(|n| n.text()); let variant_data = VariantData::new(db, module, struct_def.flavor())?; let variant_data = Arc::new(variant_data); Ok(StructData { name, variant_data }) } - pub fn name(&self) -> &SmolStr { - &self.name + pub fn name(&self) -> Option<&SmolStr> { + self.name.as_ref() } pub fn variant_data(&self) -> &Arc { @@ -78,14 +75,14 @@ impl Enum { self.def_id } - pub fn name(&self, db: &impl HirDatabase) -> Cancelable { + pub fn name(&self, db: &impl HirDatabase) -> Cancelable> { Ok(db.enum_data(self.def_id)?.name.clone()) } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct EnumData { - name: SmolStr, + name: Option, variants: Vec<(SmolStr, Arc)>, } @@ -95,10 +92,7 @@ impl EnumData { module: &Module, enum_def: ast::EnumDef, ) -> Cancelable { - let name = enum_def - .name() - .map(|n| n.text()) - .unwrap_or(SmolStr::new("[error]")); + let name = enum_def.name().map(|n| n.text()); let variants = if let Some(evl) = enum_def.variant_list() { evl.variants() .map(|v| { -- cgit v1.2.3 From cdca39706121b2d1734a94938a2372da881e10c6 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 25 Dec 2018 21:14:13 +0100 Subject: Add a hir::TypeRef as an intermediate between ast::TypeRef and ty::Ty --- crates/ra_hir/src/adt.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'crates/ra_hir/src/adt.rs') diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs index 40a45b831..dae04d258 100644 --- a/crates/ra_hir/src/adt.rs +++ b/crates/ra_hir/src/adt.rs @@ -145,7 +145,7 @@ impl VariantData { .map(|(i, fd)| { Ok(StructField { name: SmolStr::new(i.to_string()), - ty: Ty::new_opt(db, &module, fd.type_ref())?, + ty: Ty::from_ast_opt(db, &module, fd.type_ref())?, }) }) .collect::>()?; @@ -160,7 +160,7 @@ impl VariantData { .name() .map(|n| n.text()) .unwrap_or_else(|| SmolStr::new("[error]")), - ty: Ty::new_opt(db, &module, fd.type_ref())?, + ty: Ty::from_ast_opt(db, &module, fd.type_ref())?, }) }) .collect::>()?; -- cgit v1.2.3 From bc745a139674f289386f3081458793f756cab5b9 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 25 Dec 2018 21:40:33 +0100 Subject: Resolve field types lazily I.e. not already when getting the HIR for the struct. --- crates/ra_hir/src/adt.rs | 71 ++++++++++++++++++++---------------------------- 1 file changed, 29 insertions(+), 42 deletions(-) (limited to 'crates/ra_hir/src/adt.rs') diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs index dae04d258..65c461148 100644 --- a/crates/ra_hir/src/adt.rs +++ b/crates/ra_hir/src/adt.rs @@ -5,8 +5,7 @@ use ra_syntax::{SmolStr, ast::{self, NameOwner, StructFlavor}}; use crate::{ DefId, Cancelable, db::{HirDatabase}, - module::Module, - ty::{Ty}, + type_ref::TypeRef, }; pub struct Struct { @@ -42,15 +41,11 @@ pub struct StructData { } impl StructData { - pub(crate) fn new( - db: &impl HirDatabase, - module: &Module, - struct_def: ast::StructDef, - ) -> Cancelable { + pub(crate) fn new(struct_def: ast::StructDef) -> StructData { let name = struct_def.name().map(|n| n.text()); - let variant_data = VariantData::new(db, module, struct_def.flavor())?; + let variant_data = VariantData::new(struct_def.flavor()); let variant_data = Arc::new(variant_data); - Ok(StructData { name, variant_data }) + StructData { name, variant_data } } pub fn name(&self) -> Option<&SmolStr> { @@ -87,27 +82,23 @@ pub struct EnumData { } impl EnumData { - pub(crate) fn new( - db: &impl HirDatabase, - module: &Module, - enum_def: ast::EnumDef, - ) -> Cancelable { + pub(crate) fn new(enum_def: ast::EnumDef) -> Self { let name = enum_def.name().map(|n| n.text()); let variants = if let Some(evl) = enum_def.variant_list() { evl.variants() .map(|v| { - Ok(( + ( v.name() .map(|n| n.text()) .unwrap_or_else(|| SmolStr::new("[error]")), - Arc::new(VariantData::new(db, module, v.flavor())?), - )) + Arc::new(VariantData::new(v.flavor())), + ) }) - .collect::>()? + .collect() } else { Vec::new() }; - Ok(EnumData { name, variants }) + EnumData { name, variants } } } @@ -115,15 +106,15 @@ impl EnumData { #[derive(Debug, Clone, PartialEq, Eq)] pub struct StructField { name: SmolStr, - ty: Ty, + type_ref: TypeRef, } impl StructField { pub fn name(&self) -> SmolStr { self.name.clone() } - pub fn ty(&self) -> Ty { - self.ty.clone() + pub fn type_ref(&self) -> &TypeRef { + &self.type_ref } } @@ -136,45 +127,41 @@ pub enum VariantData { } impl VariantData { - pub fn new(db: &impl HirDatabase, module: &Module, flavor: StructFlavor) -> Cancelable { - Ok(match flavor { + pub fn new(flavor: StructFlavor) -> Self { + match flavor { StructFlavor::Tuple(fl) => { let fields = fl .fields() .enumerate() - .map(|(i, fd)| { - Ok(StructField { - name: SmolStr::new(i.to_string()), - ty: Ty::from_ast_opt(db, &module, fd.type_ref())?, - }) + .map(|(i, fd)| StructField { + name: SmolStr::new(i.to_string()), + type_ref: TypeRef::from_ast_opt(fd.type_ref()), }) - .collect::>()?; + .collect(); VariantData::Tuple(fields) } StructFlavor::Named(fl) => { let fields = fl .fields() - .map(|fd| { - Ok(StructField { - name: fd - .name() - .map(|n| n.text()) - .unwrap_or_else(|| SmolStr::new("[error]")), - ty: Ty::from_ast_opt(db, &module, fd.type_ref())?, - }) + .map(|fd| StructField { + name: fd + .name() + .map(|n| n.text()) + .unwrap_or_else(|| SmolStr::new("[error]")), + type_ref: TypeRef::from_ast_opt(fd.type_ref()), }) - .collect::>()?; + .collect(); VariantData::Struct(fields) } StructFlavor::Unit => VariantData::Unit, - }) + } } - pub(crate) fn get_field_ty(&self, field_name: &str) -> Option { + pub(crate) fn get_field_type_ref(&self, field_name: &str) -> Option<&TypeRef> { self.fields() .iter() .find(|f| f.name == field_name) - .map(|f| f.ty.clone()) + .map(|f| &f.type_ref) } pub fn fields(&self) -> &[StructField] { -- cgit v1.2.3