I.e. not already when getting the HIR for the struct.
fn submodules() for hir::db::SubmodulesQuery;
fn infer() for hir::db::InferQuery;
fn type_for_def() for hir::db::TypeForDefQuery;
+ fn type_for_field() for hir::db::TypeForFieldQuery;
fn struct_data() for hir::db::StructDataQuery;
fn enum_data() for hir::db::EnumDataQuery;
}
use crate::{
DefId, Cancelable,
db::{HirDatabase},
- module::Module,
- ty::{Ty},
+ type_ref::TypeRef,
};
pub struct Struct {
}
impl StructData {
- pub(crate) fn new(
- db: &impl HirDatabase,
- module: &Module,
- struct_def: ast::StructDef,
- ) -> Cancelable<StructData> {
+ 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> {
}
impl EnumData {
- pub(crate) fn new(
- db: &impl HirDatabase,
- module: &Module,
- enum_def: ast::EnumDef,
- ) -> Cancelable<Self> {
+ 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::<Cancelable<_>>()?
+ .collect()
} else {
Vec::new()
};
- Ok(EnumData { name, variants })
+ EnumData { name, variants }
}
}
#[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
}
}
}
impl VariantData {
- pub fn new(db: &impl HirDatabase, module: &Module, flavor: StructFlavor) -> Cancelable<Self> {
- 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::<Cancelable<_>>()?;
+ .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::<Cancelable<_>>()?;
+ .collect();
VariantData::Struct(fields)
}
StructFlavor::Unit => VariantData::Unit,
- })
+ }
}
- pub(crate) fn get_field_ty(&self, field_name: &str) -> Option<Ty> {
+ 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] {
use std::sync::Arc;
use ra_syntax::{
+ SmolStr,
SyntaxNode,
ast::FnDefNode,
};
use fn query_definitions::type_for_def;
}
+ fn type_for_field(def_id: DefId, field: SmolStr) -> Cancelable<Ty> {
+ type TypeForFieldQuery;
+ use fn query_definitions::type_for_field;
+ }
+
fn file_items(file_id: FileId) -> Arc<SourceFileItems> {
type SourceFileItemsQuery;
use fn query_definitions::file_items;
fn submodules() for db::SubmodulesQuery;
fn infer() for db::InferQuery;
fn type_for_def() for db::TypeForDefQuery;
+ fn type_for_field() for db::TypeForFieldQuery;
fn struct_data() for db::StructDataQuery;
fn enum_data() for db::EnumDataQuery;
}
ty::type_for_def(db, def_id)
}
+pub(super) fn type_for_field(
+ db: &impl HirDatabase,
+ def_id: DefId,
+ field: SmolStr,
+) -> Cancelable<Ty> {
+ ty::type_for_field(db, def_id, field)
+}
+
pub(super) fn struct_data(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<StructData>> {
let def_loc = def_id.loc(db);
assert!(def_loc.kind == DefKind::Struct);
let syntax = db.file_item(def_loc.source_item_id);
let struct_def =
ast::StructDef::cast(syntax.borrowed()).expect("struct def should point to StructDef node");
- let module = def_id.module(db)?;
- Ok(Arc::new(StructData::new(
- db,
- &module,
- struct_def.borrowed(),
- )?))
+ Ok(Arc::new(StructData::new(struct_def.borrowed())))
}
pub(super) fn enum_data(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<EnumData>> {
let syntax = db.file_item(def_loc.source_item_id);
let enum_def =
ast::EnumDef::cast(syntax.borrowed()).expect("enum def should point to EnumDef node");
- let module = def_id.module(db)?;
- Ok(Arc::new(EnumData::new(db, &module, enum_def.borrowed())?))
+ Ok(Arc::new(EnumData::new(enum_def.borrowed())))
}
pub(super) fn file_items(db: &impl HirDatabase, file_id: FileId) -> Arc<SourceFileItems> {
}
}
+pub(super) fn type_for_field(
+ db: &impl HirDatabase,
+ def_id: DefId,
+ field: SmolStr,
+) -> Cancelable<Ty> {
+ let def = def_id.resolve(db)?;
+ let variant_data = match def {
+ Def::Struct(s) => {
+ let variant_data = s.variant_data(db)?;
+ variant_data
+ }
+ // TODO: unions
+ // TODO: enum variants
+ _ => panic!(
+ "trying to get type for field in non-struct/variant {:?}",
+ def_id
+ ),
+ };
+ let module = def_id.module(db)?;
+ let type_ref = if let Some(tr) = variant_data.get_field_type_ref(&field) {
+ tr
+ } else {
+ return Ok(Ty::Unknown);
+ };
+ Ty::from_hir(db, &module, &type_ref)
+}
+
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct InferenceResult {
type_of: FxHashMap<LocalSyntaxPtr, Ty>,
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::Adt { def_id, .. } => self.db.type_for_field(def_id, text)?,
_ => Ty::Unknown,
}
} else {
}
}
- fn from_ast_opt(node: Option<ast::TypeRef>) -> Self {
+ pub(crate) fn from_ast_opt(node: Option<ast::TypeRef>) -> Self {
if let Some(node) = node {
TypeRef::from_ast(node)
} else {