mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-27 12:29:21 +00:00
Add basic HIR and types for structs/enums
This commit is contained in:
parent
5fb426cb9e
commit
b5b68f2094
9 changed files with 244 additions and 29 deletions
|
@ -95,6 +95,8 @@ salsa::database_storage! {
|
||||||
fn submodules() for hir::db::SubmodulesQuery;
|
fn submodules() for hir::db::SubmodulesQuery;
|
||||||
fn infer() for hir::db::InferQuery;
|
fn infer() for hir::db::InferQuery;
|
||||||
fn type_for_def() for hir::db::TypeForDefQuery;
|
fn type_for_def() for hir::db::TypeForDefQuery;
|
||||||
|
fn struct_data() for db::StructDataQuery;
|
||||||
|
fn enum_data() for db::EnumDataQuery;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
114
crates/ra_hir/src/adt.rs
Normal file
114
crates/ra_hir/src/adt.rs
Normal file
|
@ -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<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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,6 +15,7 @@ use crate::{
|
||||||
module::{ModuleId, ModuleTree, ModuleSource,
|
module::{ModuleId, ModuleTree, ModuleSource,
|
||||||
nameres::{ItemMap, InputModuleItems}},
|
nameres::{ItemMap, InputModuleItems}},
|
||||||
ty::{InferenceResult, Ty},
|
ty::{InferenceResult, Ty},
|
||||||
|
adt::{StructData, EnumData},
|
||||||
};
|
};
|
||||||
|
|
||||||
salsa::query_group! {
|
salsa::query_group! {
|
||||||
|
@ -31,6 +32,16 @@ pub trait HirDatabase: SyntaxDatabase
|
||||||
use fn query_definitions::fn_syntax;
|
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>> {
|
fn infer(fn_id: FnId) -> Cancelable<Arc<InferenceResult>> {
|
||||||
type InferQuery;
|
type InferQuery;
|
||||||
use fn query_definitions::infer;
|
use fn query_definitions::infer;
|
||||||
|
|
|
@ -25,6 +25,7 @@ pub mod source_binder;
|
||||||
mod krate;
|
mod krate;
|
||||||
mod module;
|
mod module;
|
||||||
mod function;
|
mod function;
|
||||||
|
mod adt;
|
||||||
mod ty;
|
mod ty;
|
||||||
|
|
||||||
use std::ops::Index;
|
use std::ops::Index;
|
||||||
|
@ -42,6 +43,7 @@ pub use self::{
|
||||||
krate::Crate,
|
krate::Crate,
|
||||||
module::{Module, ModuleId, Problem, nameres::ItemMap, ModuleScope, Resolution},
|
module::{Module, ModuleId, Problem, nameres::ItemMap, ModuleScope, Resolution},
|
||||||
function::{Function, FnScopes},
|
function::{Function, FnScopes},
|
||||||
|
adt::{Struct, Enum},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use self::function::FnSignatureInfo;
|
pub use self::function::FnSignatureInfo;
|
||||||
|
@ -56,6 +58,8 @@ ra_db::impl_numeric_id!(DefId);
|
||||||
pub(crate) enum DefKind {
|
pub(crate) enum DefKind {
|
||||||
Module,
|
Module,
|
||||||
Function,
|
Function,
|
||||||
|
Struct,
|
||||||
|
Enum,
|
||||||
Item,
|
Item,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,8 +77,8 @@ impl DefKind {
|
||||||
SyntaxKind::FN_DEF => Some(DefKind::Function),
|
SyntaxKind::FN_DEF => Some(DefKind::Function),
|
||||||
SyntaxKind::MODULE => Some(DefKind::Module),
|
SyntaxKind::MODULE => Some(DefKind::Module),
|
||||||
// These define items, but don't have their own DefKinds yet:
|
// These define items, but don't have their own DefKinds yet:
|
||||||
SyntaxKind::STRUCT_DEF => Some(DefKind::Item),
|
SyntaxKind::STRUCT_DEF => Some(DefKind::Struct),
|
||||||
SyntaxKind::ENUM_DEF => Some(DefKind::Item),
|
SyntaxKind::ENUM_DEF => Some(DefKind::Enum),
|
||||||
SyntaxKind::TRAIT_DEF => Some(DefKind::Item),
|
SyntaxKind::TRAIT_DEF => Some(DefKind::Item),
|
||||||
SyntaxKind::TYPE_DEF => Some(DefKind::Item),
|
SyntaxKind::TYPE_DEF => Some(DefKind::Item),
|
||||||
SyntaxKind::CONST_DEF => Some(DefKind::Item),
|
SyntaxKind::CONST_DEF => Some(DefKind::Item),
|
||||||
|
@ -99,6 +103,8 @@ impl DefLoc {
|
||||||
pub enum Def {
|
pub enum Def {
|
||||||
Module(Module),
|
Module(Module),
|
||||||
Function(Function),
|
Function(Function),
|
||||||
|
Struct(Struct),
|
||||||
|
Enum(Enum),
|
||||||
Item,
|
Item,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,6 +120,14 @@ impl DefId {
|
||||||
let function = Function::new(self);
|
let function = Function::new(self);
|
||||||
Def::Function(function)
|
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,
|
DefKind::Item => Def::Item,
|
||||||
};
|
};
|
||||||
Ok(res)
|
Ok(res)
|
||||||
|
|
|
@ -193,6 +193,8 @@ salsa::database_storage! {
|
||||||
fn submodules() for db::SubmodulesQuery;
|
fn submodules() for db::SubmodulesQuery;
|
||||||
fn infer() for db::InferQuery;
|
fn infer() for db::InferQuery;
|
||||||
fn type_for_def() for db::TypeForDefQuery;
|
fn type_for_def() for db::TypeForDefQuery;
|
||||||
|
fn struct_data() for db::StructDataQuery;
|
||||||
|
fn enum_data() for db::EnumDataQuery;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,8 @@ use crate::{
|
||||||
imp::Submodule,
|
imp::Submodule,
|
||||||
nameres::{InputModuleItems, ItemMap, Resolver},
|
nameres::{InputModuleItems, ItemMap, Resolver},
|
||||||
},
|
},
|
||||||
ty::{self, InferenceResult, Ty}
|
ty::{self, InferenceResult, Ty},
|
||||||
|
adt::{StructData, EnumData},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Resolve `FnId` to the corresponding `SyntaxNode`
|
/// Resolve `FnId` to the corresponding `SyntaxNode`
|
||||||
|
@ -45,6 +46,24 @@ pub(super) fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<T
|
||||||
ty::type_for_def(db, def_id)
|
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> {
|
pub(super) fn file_items(db: &impl HirDatabase, file_id: FileId) -> Arc<SourceFileItems> {
|
||||||
let mut res = SourceFileItems::new(file_id);
|
let mut res = SourceFileItems::new(file_id);
|
||||||
let source_file = db.source_file(file_id);
|
let source_file = db.source_file(file_id);
|
||||||
|
|
|
@ -17,7 +17,7 @@ use ra_syntax::{
|
||||||
|
|
||||||
use crate::{Def, DefId, FnScopes, Module, Function, Path, db::HirDatabase};
|
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 {
|
pub enum Ty {
|
||||||
/// The primitive boolean type. Written as `bool`.
|
/// The primitive boolean type. Written as `bool`.
|
||||||
Bool,
|
Bool,
|
||||||
|
@ -35,8 +35,15 @@ pub enum Ty {
|
||||||
/// A primitive floating-point type. For example, `f64`.
|
/// A primitive floating-point type. For example, `f64`.
|
||||||
Float(primitive::FloatTy),
|
Float(primitive::FloatTy),
|
||||||
|
|
||||||
// Structures, enumerations and unions.
|
/// Structures, enumerations and unions.
|
||||||
// Adt(AdtDef, Substs),
|
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`.
|
/// The pointee of a string slice. Written as `str`.
|
||||||
Str,
|
Str,
|
||||||
|
|
||||||
|
@ -107,45 +114,48 @@ pub enum Ty {
|
||||||
|
|
||||||
type TyRef = Arc<Ty>;
|
type TyRef = Arc<Ty>;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||||
pub struct FnSig {
|
pub struct FnSig {
|
||||||
input: Vec<Ty>,
|
input: Vec<Ty>,
|
||||||
output: Ty,
|
output: Ty,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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::*;
|
use ra_syntax::ast::TypeRef::*;
|
||||||
Ok(match node {
|
Ok(match node {
|
||||||
ParenType(_inner) => Ty::Unknown, // TODO
|
ParenType(_inner) => Ty::Unknown, // TODO
|
||||||
TupleType(_inner) => Ty::Unknown, // TODO
|
TupleType(_inner) => Ty::Unknown, // TODO
|
||||||
NeverType(..) => Ty::Never,
|
NeverType(..) => Ty::Never,
|
||||||
PathType(inner) => {
|
PathType(inner) => {
|
||||||
let path = if let Some(p) = inner.path() {
|
let path = if let Some(p) = inner.path().and_then(Path::from_ast) {
|
||||||
p
|
p
|
||||||
} else {
|
} else {
|
||||||
return Ok(Ty::Unknown);
|
return Ok(Ty::Unknown);
|
||||||
};
|
};
|
||||||
if path.qualifier().is_none() {
|
if path.is_ident() {
|
||||||
let name = path
|
let name = &path.segments[0];
|
||||||
.segment()
|
|
||||||
.and_then(|s| s.name_ref())
|
|
||||||
.map(|n| n.text())
|
|
||||||
.unwrap_or(SmolStr::new(""));
|
|
||||||
if let Some(int_ty) = primitive::IntTy::from_string(&name) {
|
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) {
|
} 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) {
|
} else if let Some(float_ty) = primitive::FloatTy::from_string(&name) {
|
||||||
Ty::Float(float_ty)
|
return Ok(Ty::Float(float_ty));
|
||||||
} else {
|
|
||||||
// TODO
|
|
||||||
Ty::Unknown
|
|
||||||
}
|
}
|
||||||
} 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
|
PointerType(_inner) => Ty::Unknown, // TODO
|
||||||
ArrayType(_inner) => Ty::Unknown, // TODO
|
ArrayType(_inner) => Ty::Unknown, // TODO
|
||||||
|
@ -189,6 +199,7 @@ impl fmt::Display for Ty {
|
||||||
}
|
}
|
||||||
write!(f, ") -> {}", sig.output)
|
write!(f, ") -> {}", sig.output)
|
||||||
}
|
}
|
||||||
|
Ty::Adt { name, .. } => write!(f, "{}", name),
|
||||||
Ty::Unknown => write!(f, "[unknown]"),
|
Ty::Unknown => write!(f, "[unknown]"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -196,6 +207,7 @@ impl fmt::Display for Ty {
|
||||||
|
|
||||||
pub fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> {
|
pub fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> {
|
||||||
let syntax = f.syntax(db);
|
let syntax = f.syntax(db);
|
||||||
|
let module = f.module(db)?;
|
||||||
let node = syntax.borrowed();
|
let node = syntax.borrowed();
|
||||||
// TODO we ignore type parameters for now
|
// TODO we ignore type parameters for now
|
||||||
let input = node
|
let input = node
|
||||||
|
@ -204,7 +216,7 @@ pub fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> {
|
||||||
pl.params()
|
pl.params()
|
||||||
.map(|p| {
|
.map(|p| {
|
||||||
p.type_ref()
|
p.type_ref()
|
||||||
.map(|t| Ty::new(db, t))
|
.map(|t| Ty::new(db, &module, t))
|
||||||
.unwrap_or(Ok(Ty::Unknown))
|
.unwrap_or(Ok(Ty::Unknown))
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
@ -213,7 +225,7 @@ pub fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> {
|
||||||
let output = node
|
let output = node
|
||||||
.ret_type()
|
.ret_type()
|
||||||
.and_then(|rt| rt.type_ref())
|
.and_then(|rt| rt.type_ref())
|
||||||
.map(|t| Ty::new(db, t))
|
.map(|t| Ty::new(db, &module, t))
|
||||||
.unwrap_or(Ok(Ty::Unknown))?;
|
.unwrap_or(Ok(Ty::Unknown))?;
|
||||||
let sig = FnSig { input, output };
|
let sig = FnSig { input, output };
|
||||||
Ok(Ty::FnPtr(Arc::new(sig)))
|
Ok(Ty::FnPtr(Arc::new(sig)))
|
||||||
|
@ -232,6 +244,14 @@ pub fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Ty> {
|
||||||
Ok(Ty::Unknown)
|
Ok(Ty::Unknown)
|
||||||
}
|
}
|
||||||
Def::Function(f) => type_for_fn(db, f),
|
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 => {
|
Def::Item => {
|
||||||
log::debug!("trying to get type for item of unknown type {:?}", def_id);
|
log::debug!("trying to get type for item of unknown type {:?}", def_id);
|
||||||
Ok(Ty::Unknown)
|
Ok(Ty::Unknown)
|
||||||
|
@ -492,7 +512,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
};
|
};
|
||||||
let cast_ty = e
|
let cast_ty = e
|
||||||
.type_ref()
|
.type_ref()
|
||||||
.map(|t| Ty::new(self.db, t))
|
.map(|t| Ty::new(self.db, &self.module, t))
|
||||||
.unwrap_or(Ok(Ty::Unknown))?;
|
.unwrap_or(Ok(Ty::Unknown))?;
|
||||||
// TODO do the coercion...
|
// TODO do the coercion...
|
||||||
cast_ty
|
cast_ty
|
||||||
|
@ -526,7 +546,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
match stmt {
|
match stmt {
|
||||||
ast::Stmt::LetStmt(stmt) => {
|
ast::Stmt::LetStmt(stmt) => {
|
||||||
let decl_ty = if let Some(type_ref) = stmt.type_ref() {
|
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 {
|
} else {
|
||||||
Ty::Unknown
|
Ty::Unknown
|
||||||
};
|
};
|
||||||
|
@ -576,7 +596,7 @@ pub fn infer(db: &impl HirDatabase, function: Function) -> Cancelable<InferenceR
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
if let Some(type_ref) = param.type_ref() {
|
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);
|
ctx.type_of.insert(LocalSyntaxPtr::new(pat.syntax()), ty);
|
||||||
} else {
|
} else {
|
||||||
// TODO self param
|
// TODO self param
|
||||||
|
|
|
@ -68,6 +68,29 @@ fn test() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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 {
|
fn infer(content: &str) -> String {
|
||||||
let (db, _, file_id) = MockDatabase::with_single_file(content);
|
let (db, _, file_id) = MockDatabase::with_single_file(content);
|
||||||
let source_file = db.source_file(file_id);
|
let source_file = db.source_file(file_id);
|
||||||
|
|
10
crates/ra_hir/src/ty/tests/data/0004_struct.txt
Normal file
10
crates/ra_hir/src/ty/tests/data/0004_struct.txt
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
[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]
|
Loading…
Add table
Add a link
Reference in a new issue