fn submodules() for hir::db::SubmodulesQuery;
fn infer() for hir::db::InferQuery;
fn type_for_def() for hir::db::TypeForDefQuery;
+ fn struct_data() for db::StructDataQuery;
+ fn enum_data() for db::EnumDataQuery;
}
}
}
--- /dev/null
+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<SmolStr> {
+ 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<SmolStr> {
+ 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<StructField>),
+ Tuple(Vec<StructField>),
+ 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
+ }
+ }
+}
module::{ModuleId, ModuleTree, ModuleSource,
nameres::{ItemMap, InputModuleItems}},
ty::{InferenceResult, Ty},
+ adt::{StructData, EnumData},
};
salsa::query_group! {
use fn query_definitions::fn_syntax;
}
+ fn struct_data(def_id: DefId) -> Cancelable<Arc<StructData>> {
+ type StructDataQuery;
+ use fn query_definitions::struct_data;
+ }
+
+ fn enum_data(def_id: DefId) -> Cancelable<Arc<EnumData>> {
+ type EnumDataQuery;
+ use fn query_definitions::enum_data;
+ }
+
fn infer(fn_id: FnId) -> Cancelable<Arc<InferenceResult>> {
type InferQuery;
use fn query_definitions::infer;
mod krate;
mod module;
mod function;
+mod adt;
mod ty;
use std::ops::Index;
krate::Crate,
module::{Module, ModuleId, Problem, nameres::ItemMap, ModuleScope, Resolution},
function::{Function, FnScopes},
+ adt::{Struct, Enum},
};
pub use self::function::FnSignatureInfo;
pub(crate) enum DefKind {
Module,
Function,
+ Struct,
+ Enum,
Item,
}
SyntaxKind::FN_DEF => Some(DefKind::Function),
SyntaxKind::MODULE => Some(DefKind::Module),
// These define items, but don't have their own DefKinds yet:
- SyntaxKind::STRUCT_DEF => Some(DefKind::Item),
- SyntaxKind::ENUM_DEF => Some(DefKind::Item),
+ SyntaxKind::STRUCT_DEF => Some(DefKind::Struct),
+ SyntaxKind::ENUM_DEF => Some(DefKind::Enum),
SyntaxKind::TRAIT_DEF => Some(DefKind::Item),
SyntaxKind::TYPE_DEF => Some(DefKind::Item),
SyntaxKind::CONST_DEF => Some(DefKind::Item),
pub enum Def {
Module(Module),
Function(Function),
+ Struct(Struct),
+ Enum(Enum),
Item,
}
let function = Function::new(self);
Def::Function(function)
}
+ DefKind::Struct => {
+ let struct_def = Struct::new(self);
+ Def::Struct(struct_def)
+ }
+ DefKind::Enum => {
+ let enum_def = Enum::new(self);
+ Def::Enum(enum_def)
+ }
DefKind::Item => Def::Item,
};
Ok(res)
fn submodules() for db::SubmodulesQuery;
fn infer() for db::InferQuery;
fn type_for_def() for db::TypeForDefQuery;
+ fn struct_data() for db::StructDataQuery;
+ fn enum_data() for db::EnumDataQuery;
}
}
}
imp::Submodule,
nameres::{InputModuleItems, ItemMap, Resolver},
},
- ty::{self, InferenceResult, Ty}
+ ty::{self, InferenceResult, Ty},
+ adt::{StructData, EnumData},
};
/// Resolve `FnId` to the corresponding `SyntaxNode`
ty::type_for_def(db, def_id)
}
+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");
+ Ok(Arc::new(StructData::new(struct_def.borrowed())))
+}
+
+pub(super) fn enum_data(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<EnumData>> {
+ let def_loc = def_id.loc(db);
+ assert!(def_loc.kind == DefKind::Enum);
+ 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");
+ Ok(Arc::new(EnumData::new(enum_def.borrowed())))
+}
+
pub(super) fn file_items(db: &impl HirDatabase, file_id: FileId) -> Arc<SourceFileItems> {
let mut res = SourceFileItems::new(file_id);
let source_file = db.source_file(file_id);
use crate::{Def, DefId, FnScopes, Module, Function, Path, db::HirDatabase};
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum Ty {
/// The primitive boolean type. Written as `bool`.
Bool,
/// A primitive floating-point type. For example, `f64`.
Float(primitive::FloatTy),
- // Structures, enumerations and unions.
- // Adt(AdtDef, Substs),
+ /// Structures, enumerations and unions.
+ Adt {
+ /// The DefId of the struct/enum.
+ def_id: DefId,
+ /// The name, for displaying.
+ name: SmolStr,
+ // later we'll need generic substitutions here
+ },
+
/// The pointee of a string slice. Written as `str`.
Str,
type TyRef = Arc<Ty>;
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct FnSig {
input: Vec<Ty>,
output: Ty,
}
impl Ty {
- pub fn new(_db: &impl HirDatabase, node: ast::TypeRef) -> Cancelable<Self> {
+ pub(crate) fn new(
+ db: &impl HirDatabase,
+ module: &Module,
+ node: ast::TypeRef,
+ ) -> Cancelable<Self> {
use ra_syntax::ast::TypeRef::*;
Ok(match node {
ParenType(_inner) => Ty::Unknown, // TODO
TupleType(_inner) => Ty::Unknown, // TODO
NeverType(..) => Ty::Never,
PathType(inner) => {
- let path = if let Some(p) = inner.path() {
+ let path = if let Some(p) = inner.path().and_then(Path::from_ast) {
p
} else {
return Ok(Ty::Unknown);
};
- if path.qualifier().is_none() {
- let name = path
- .segment()
- .and_then(|s| s.name_ref())
- .map(|n| n.text())
- .unwrap_or(SmolStr::new(""));
+ if path.is_ident() {
+ let name = &path.segments[0];
if let Some(int_ty) = primitive::IntTy::from_string(&name) {
- Ty::Int(int_ty)
+ return Ok(Ty::Int(int_ty));
} else if let Some(uint_ty) = primitive::UintTy::from_string(&name) {
- Ty::Uint(uint_ty)
+ return Ok(Ty::Uint(uint_ty));
} else if let Some(float_ty) = primitive::FloatTy::from_string(&name) {
- Ty::Float(float_ty)
- } else {
- // TODO
- Ty::Unknown
+ return Ok(Ty::Float(float_ty));
}
- } else {
- // TODO
- Ty::Unknown
}
+
+ // Resolve in module (in type namespace)
+ let resolved = if let Some(r) = module.resolve_path(db, path)? {
+ r
+ } else {
+ return Ok(Ty::Unknown);
+ };
+ let ty = db.type_for_def(resolved)?;
+ ty
}
PointerType(_inner) => Ty::Unknown, // TODO
ArrayType(_inner) => Ty::Unknown, // TODO
}
write!(f, ") -> {}", sig.output)
}
+ Ty::Adt { name, .. } => write!(f, "{}", name),
Ty::Unknown => write!(f, "[unknown]"),
}
}
pub fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> {
let syntax = f.syntax(db);
+ let module = f.module(db)?;
let node = syntax.borrowed();
// TODO we ignore type parameters for now
let input = node
pl.params()
.map(|p| {
p.type_ref()
- .map(|t| Ty::new(db, t))
+ .map(|t| Ty::new(db, &module, t))
.unwrap_or(Ok(Ty::Unknown))
})
.collect()
let output = node
.ret_type()
.and_then(|rt| rt.type_ref())
- .map(|t| Ty::new(db, t))
+ .map(|t| Ty::new(db, &module, t))
.unwrap_or(Ok(Ty::Unknown))?;
let sig = FnSig { input, output };
Ok(Ty::FnPtr(Arc::new(sig)))
Ok(Ty::Unknown)
}
Def::Function(f) => type_for_fn(db, f),
+ Def::Struct(s) => Ok(Ty::Adt {
+ def_id,
+ name: s.name(db)?,
+ }),
+ Def::Enum(e) => Ok(Ty::Adt {
+ def_id,
+ name: e.name(db)?,
+ }),
Def::Item => {
log::debug!("trying to get type for item of unknown type {:?}", def_id);
Ok(Ty::Unknown)
};
let cast_ty = e
.type_ref()
- .map(|t| Ty::new(self.db, t))
+ .map(|t| Ty::new(self.db, &self.module, t))
.unwrap_or(Ok(Ty::Unknown))?;
// TODO do the coercion...
cast_ty
match stmt {
ast::Stmt::LetStmt(stmt) => {
let decl_ty = if let Some(type_ref) = stmt.type_ref() {
- Ty::new(self.db, type_ref)?
+ Ty::new(self.db, &self.module, type_ref)?
} else {
Ty::Unknown
};
continue;
};
if let Some(type_ref) = param.type_ref() {
- let ty = Ty::new(db, type_ref)?;
+ let ty = Ty::new(db, &ctx.module, type_ref)?;
ctx.type_of.insert(LocalSyntaxPtr::new(pat.syntax()), ty);
} else {
// TODO self param
);
}
+#[test]
+fn infer_struct() {
+ check_inference(
+ r#"
+struct A {
+ b: B,
+ c: C,
+}
+struct B;
+struct C(usize);
+
+fn test() {
+ let c = C(1);
+ B;
+ let a: A = A { b: B, c: C() };
+ a.b;
+ a.c;
+}
+"#,
+ "0004_struct.txt",
+ );
+}
+
fn infer(content: &str) -> String {
let (db, _, file_id) = MockDatabase::with_single_file(content);
let source_file = db.source_file(file_id);
--- /dev/null
+[86; 90) 'C(1)': [unknown]
+[72; 153) '{ ...a.c; }': ()
+[86; 87) 'C': C
+[107; 108) 'a': A
+[114; 132) 'A { b:... C() }': [unknown]
+[138; 141) 'a.b': [unknown]
+[147; 150) 'a.c': [unknown]
+[96; 97) 'B': B
+[88; 89) '1': [unknown]
+[82; 83) 'c': [unknown]