Add a hir::TypeRef as an intermediate between ast::TypeRef and ty::Ty

This commit is contained in:
Florian Diebold 2018-12-25 21:14:13 +01:00
parent 2870effd5c
commit cdca397061
10 changed files with 219 additions and 95 deletions

View file

@ -8,7 +8,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) -> C
(Some(path), Some(module)) => (path.clone(), module), (Some(path), Some(module)) => (path.clone(), module),
_ => return Ok(()), _ => return Ok(()),
}; };
let def_id = match module.resolve_path(ctx.db, path)?.take_types() { let def_id = match module.resolve_path(ctx.db, &path)?.take_types() {
Some(it) => it, Some(it) => it,
None => return Ok(()), None => return Ok(()),
}; };

View file

@ -145,7 +145,7 @@ impl VariantData {
.map(|(i, fd)| { .map(|(i, fd)| {
Ok(StructField { Ok(StructField {
name: SmolStr::new(i.to_string()), 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::<Cancelable<_>>()?; .collect::<Cancelable<_>>()?;
@ -160,7 +160,7 @@ impl VariantData {
.name() .name()
.map(|n| n.text()) .map(|n| n.text())
.unwrap_or_else(|| SmolStr::new("[error]")), .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::<Cancelable<_>>()?; .collect::<Cancelable<_>>()?;

View file

@ -26,6 +26,7 @@ mod krate;
mod module; mod module;
mod function; mod function;
mod adt; mod adt;
mod type_ref;
mod ty; mod ty;
use std::ops::Index; use std::ops::Index;

View file

@ -115,7 +115,7 @@ impl Module {
Ok(res) Ok(res)
} }
pub fn resolve_path(&self, db: &impl HirDatabase, path: Path) -> Cancelable<PerNs<DefId>> { pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> Cancelable<PerNs<DefId>> {
let mut curr_per_ns = PerNs::types( let mut curr_per_ns = PerNs::types(
match path.kind { match path.kind {
PathKind::Crate => self.crate_root(), PathKind::Crate => self.crate_root(),
@ -131,7 +131,7 @@ impl Module {
.def_id(db), .def_id(db),
); );
let segments = path.segments; let segments = &path.segments;
for name in segments.iter() { for name in segments.iter() {
let curr = if let Some(r) = curr_per_ns.as_ref().take(Namespace::Types) { let curr = if let Some(r) = curr_per_ns.as_ref().take(Namespace::Types) {
r r

View file

@ -451,7 +451,7 @@ where
segments: import.path.segments[i + 1..].iter().cloned().collect(), segments: import.path.segments[i + 1..].iter().cloned().collect(),
kind: PathKind::Crate, kind: PathKind::Crate,
}; };
let def_id = module.resolve_path(self.db, path)?; let def_id = module.resolve_path(self.db, &path)?;
if !def_id.is_none() { if !def_id.is_none() {
self.update(module_id, |items| { self.update(module_id, |items| {
let res = Resolution { let res = Resolution {

View file

@ -1,12 +1,12 @@
use ra_syntax::{SmolStr, ast, AstNode, TextRange}; use ra_syntax::{SmolStr, ast, AstNode, TextRange};
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Path { pub struct Path {
pub kind: PathKind, pub kind: PathKind,
pub segments: Vec<SmolStr>, pub segments: Vec<SmolStr>,
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum PathKind { pub enum PathKind {
Plain, Plain,
Self_, Self_,

View file

@ -19,38 +19,9 @@ use crate::{
Def, DefId, FnScopes, Module, Function, Struct, Enum, Path, Def, DefId, FnScopes, Module, Function, Struct, Enum, Path,
db::HirDatabase, db::HirDatabase,
adt::VariantData, adt::VariantData,
type_ref::{TypeRef, Mutability},
}; };
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum Mutability {
Shared,
Mut,
}
impl Mutability {
pub fn from_mutable(mutable: bool) -> Mutability {
if mutable {
Mutability::Mut
} else {
Mutability::Shared
}
}
pub fn as_keyword_for_ref(self) -> &'static str {
match self {
Mutability::Shared => "",
Mutability::Mut => "mut ",
}
}
pub fn as_keyword_for_ptr(self) -> &'static str {
match self {
Mutability::Shared => "const ",
Mutability::Mut => "mut ",
}
}
}
#[derive(Clone, PartialEq, Eq, 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`.
@ -156,16 +127,58 @@ pub struct FnSig {
} }
impl Ty { impl Ty {
pub(crate) fn new_from_ast_path( pub(crate) fn from_hir(
db: &impl HirDatabase, db: &impl HirDatabase,
module: &Module, module: &Module,
path: ast::Path, type_ref: &TypeRef,
) -> Cancelable<Self> {
Ok(match type_ref {
TypeRef::Never => Ty::Never,
TypeRef::Tuple(inner) => {
let inner_tys = inner
.iter()
.map(|tr| Ty::from_hir(db, module, tr))
.collect::<Cancelable<_>>()?;
Ty::Tuple(inner_tys)
}
TypeRef::Path(path) => Ty::from_hir_path(db, module, path)?,
TypeRef::RawPtr(inner, mutability) => {
let inner_ty = Ty::from_hir(db, module, inner)?;
Ty::RawPtr(Arc::new(inner_ty), *mutability)
}
TypeRef::Array(_inner) => Ty::Unknown, // TODO
TypeRef::Slice(inner) => {
let inner_ty = Ty::from_hir(db, module, inner)?;
Ty::Slice(Arc::new(inner_ty))
}
TypeRef::Reference(inner, mutability) => {
let inner_ty = Ty::from_hir(db, module, inner)?;
Ty::Ref(Arc::new(inner_ty), *mutability)
}
TypeRef::Placeholder => Ty::Unknown, // TODO
TypeRef::Fn(params) => {
let mut inner_tys = params
.iter()
.map(|tr| Ty::from_hir(db, module, tr))
.collect::<Cancelable<Vec<_>>>()?;
let return_ty = inner_tys
.pop()
.expect("TypeRef::Fn should always have at least return type");
let sig = FnSig {
input: inner_tys,
output: return_ty,
};
Ty::FnPtr(Arc::new(sig))
}
TypeRef::Error => Ty::Unknown,
})
}
pub(crate) fn from_hir_path(
db: &impl HirDatabase,
module: &Module,
path: &Path,
) -> Cancelable<Self> { ) -> Cancelable<Self> {
let path = if let Some(p) = Path::from_ast(path) {
p
} else {
return Ok(Ty::Unknown);
};
if path.is_ident() { if path.is_ident() {
let name = &path.segments[0]; let name = &path.segments[0];
if let Some(int_ty) = primitive::IntTy::from_string(&name) { if let Some(int_ty) = primitive::IntTy::from_string(&name) {
@ -187,50 +200,22 @@ impl Ty {
Ok(ty) Ok(ty)
} }
pub(crate) fn new_opt( // TODO: These should not be necessary long-term, since everything will work on HIR
pub(crate) fn from_ast_opt(
db: &impl HirDatabase, db: &impl HirDatabase,
module: &Module, module: &Module,
node: Option<ast::TypeRef>, node: Option<ast::TypeRef>,
) -> Cancelable<Self> { ) -> Cancelable<Self> {
node.map(|n| Ty::new(db, module, n)) node.map(|n| Ty::from_ast(db, module, n))
.unwrap_or(Ok(Ty::Unknown)) .unwrap_or(Ok(Ty::Unknown))
} }
pub(crate) fn new( pub(crate) fn from_ast(
db: &impl HirDatabase, db: &impl HirDatabase,
module: &Module, module: &Module,
node: ast::TypeRef, node: ast::TypeRef,
) -> Cancelable<Self> { ) -> Cancelable<Self> {
use ra_syntax::ast::TypeRef::*; Ty::from_hir(db, module, &TypeRef::from_ast(node))
Ok(match node {
ParenType(inner) => Ty::new_opt(db, module, inner.type_ref())?,
TupleType(_inner) => Ty::Unknown, // TODO
NeverType(..) => Ty::Never,
PathType(inner) => {
if let Some(path) = inner.path() {
Ty::new_from_ast_path(db, module, path)?
} else {
Ty::Unknown
}
}
PointerType(inner) => {
let inner_ty = Ty::new_opt(db, module, inner.type_ref())?;
let mutability = Mutability::from_mutable(inner.is_mut());
Ty::RawPtr(Arc::new(inner_ty), mutability)
}
ArrayType(_inner) => Ty::Unknown, // TODO
SliceType(_inner) => Ty::Unknown, // TODO
ReferenceType(inner) => {
let inner_ty = Ty::new_opt(db, module, inner.type_ref())?;
let mutability = Mutability::from_mutable(inner.is_mut());
Ty::Ref(Arc::new(inner_ty), mutability)
}
PlaceholderType(_inner) => Ty::Unknown, // TODO
FnPointerType(_inner) => Ty::Unknown, // TODO
ForType(_inner) => Ty::Unknown, // TODO
ImplTraitType(_inner) => Ty::Unknown, // TODO
DynTraitType(_inner) => Ty::Unknown, // TODO
})
} }
pub fn unit() -> Self { pub fn unit() -> Self {
@ -280,11 +265,11 @@ pub fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> {
.param_list() .param_list()
.map(|pl| { .map(|pl| {
pl.params() pl.params()
.map(|p| Ty::new_opt(db, &module, p.type_ref())) .map(|p| Ty::from_ast_opt(db, &module, p.type_ref()))
.collect() .collect()
}) })
.unwrap_or_else(|| Ok(Vec::new()))?; .unwrap_or_else(|| Ok(Vec::new()))?;
let output = Ty::new_opt(db, &module, node.ret_type().and_then(|rt| rt.type_ref()))?; let output = Ty::from_ast_opt(db, &module, node.ret_type().and_then(|rt| rt.type_ref()))?;
let sig = FnSig { input, output }; let sig = FnSig { input, output };
Ok(Ty::FnPtr(Arc::new(sig))) Ok(Ty::FnPtr(Arc::new(sig)))
} }
@ -390,7 +375,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
}; };
// resolve in module // resolve in module
let resolved = ctry!(self.module.resolve_path(self.db, path)?.take_values()); let resolved = ctry!(self.module.resolve_path(self.db, &path)?.take_values());
let ty = self.db.type_for_def(resolved)?; let ty = self.db.type_for_def(resolved)?;
// TODO we will need to add type variables for type parameters etc. here // TODO we will need to add type variables for type parameters etc. here
Ok(Some(ty)) Ok(Some(ty))
@ -405,7 +390,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
} else { } else {
return Ok((Ty::Unknown, None)); return Ok((Ty::Unknown, None));
}; };
let def_id = if let Some(def_id) = self.module.resolve_path(self.db, path)?.take_types() { let def_id = if let Some(def_id) = self.module.resolve_path(self.db, &path)?.take_types() {
def_id def_id
} else { } else {
return Ok((Ty::Unknown, None)); return Ok((Ty::Unknown, None));
@ -575,7 +560,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
} }
ast::Expr::CastExpr(e) => { ast::Expr::CastExpr(e) => {
let _inner_ty = self.infer_expr_opt(e.expr())?; let _inner_ty = self.infer_expr_opt(e.expr())?;
let cast_ty = Ty::new_opt(self.db, &self.module, e.type_ref())?; let cast_ty = Ty::from_ast_opt(self.db, &self.module, e.type_ref())?;
// TODO do the coercion... // TODO do the coercion...
cast_ty cast_ty
} }
@ -620,7 +605,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
for stmt in node.statements() { for stmt in node.statements() {
match stmt { match stmt {
ast::Stmt::LetStmt(stmt) => { ast::Stmt::LetStmt(stmt) => {
let decl_ty = Ty::new_opt(self.db, &self.module, stmt.type_ref())?; let decl_ty = Ty::from_ast_opt(self.db, &self.module, stmt.type_ref())?;
let ty = if let Some(expr) = stmt.initializer() { let ty = if let Some(expr) = stmt.initializer() {
// TODO pass expectation // TODO pass expectation
let expr_ty = self.infer_expr(expr)?; let expr_ty = self.infer_expr(expr)?;
@ -665,7 +650,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, &ctx.module, type_ref)?; let ty = Ty::from_ast(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

View file

@ -0,0 +1,110 @@
//! HIR for references to types. Paths in these are not yet resolved. They can
//! be directly created from an ast::TypeRef, without further queries.
use ra_syntax::ast;
use crate::Path;
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum Mutability {
Shared,
Mut,
}
impl Mutability {
pub fn from_mutable(mutable: bool) -> Mutability {
if mutable {
Mutability::Mut
} else {
Mutability::Shared
}
}
pub fn as_keyword_for_ref(self) -> &'static str {
match self {
Mutability::Shared => "",
Mutability::Mut => "mut ",
}
}
pub fn as_keyword_for_ptr(self) -> &'static str {
match self {
Mutability::Shared => "const ",
Mutability::Mut => "mut ",
}
}
}
/// Compare ty::Ty
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum TypeRef {
Never,
Placeholder,
Tuple(Vec<TypeRef>),
Path(Path),
RawPtr(Box<TypeRef>, Mutability),
Reference(Box<TypeRef>, Mutability),
Array(Box<TypeRef> /*, Expr*/),
Slice(Box<TypeRef>),
/// A fn pointer. Last element of the vector is the return type.
Fn(Vec<TypeRef>),
// For
// ImplTrait,
// DynTrait,
Error,
}
impl TypeRef {
/// Converts an `ast::TypeRef` to a `hir::TypeRef`.
pub(crate) fn from_ast(node: ast::TypeRef) -> Self {
use ra_syntax::ast::TypeRef::*;
match node {
ParenType(inner) => TypeRef::from_ast_opt(inner.type_ref()),
TupleType(inner) => TypeRef::Tuple(inner.fields().map(TypeRef::from_ast).collect()),
NeverType(..) => TypeRef::Never,
PathType(inner) => inner
.path()
.and_then(Path::from_ast)
.map(TypeRef::Path)
.unwrap_or(TypeRef::Error),
PointerType(inner) => {
let inner_ty = TypeRef::from_ast_opt(inner.type_ref());
let mutability = Mutability::from_mutable(inner.is_mut());
TypeRef::RawPtr(Box::new(inner_ty), mutability)
}
ArrayType(inner) => TypeRef::Array(Box::new(TypeRef::from_ast_opt(inner.type_ref()))),
SliceType(inner) => TypeRef::Slice(Box::new(TypeRef::from_ast_opt(inner.type_ref()))),
ReferenceType(inner) => {
let inner_ty = TypeRef::from_ast_opt(inner.type_ref());
let mutability = Mutability::from_mutable(inner.is_mut());
TypeRef::Reference(Box::new(inner_ty), mutability)
}
PlaceholderType(_inner) => TypeRef::Placeholder,
FnPointerType(inner) => {
let ret_ty = TypeRef::from_ast_opt(inner.ret_type().and_then(|rt| rt.type_ref()));
let mut params = if let Some(pl) = inner.param_list() {
pl.params()
.map(|p| p.type_ref())
.map(TypeRef::from_ast_opt)
.collect()
} else {
Vec::new()
};
params.push(ret_ty);
TypeRef::Fn(params)
}
// for types are close enough for our purposes to the inner type for now...
ForType(inner) => TypeRef::from_ast_opt(inner.type_ref()),
ImplTraitType(_inner) => TypeRef::Error,
DynTraitType(_inner) => TypeRef::Error,
}
}
fn from_ast_opt(node: Option<ast::TypeRef>) -> Self {
if let Some(node) = node {
TypeRef::from_ast(node)
} else {
TypeRef::Error
}
}
}

View file

@ -131,7 +131,15 @@ impl<R: TreeRoot<RaTypes>> ArrayTypeNode<R> {
} }
impl<'a> ArrayType<'a> {} impl<'a> ArrayType<'a> {
pub fn type_ref(self) -> Option<TypeRef<'a>> {
super::child_opt(self)
}
pub fn expr(self) -> Option<Expr<'a>> {
super::child_opt(self)
}
}
// Attr // Attr
#[derive(Debug, Clone, Copy,)] #[derive(Debug, Clone, Copy,)]
@ -1258,7 +1266,15 @@ impl<R: TreeRoot<RaTypes>> FnPointerTypeNode<R> {
} }
impl<'a> FnPointerType<'a> {} impl<'a> FnPointerType<'a> {
pub fn param_list(self) -> Option<ParamList<'a>> {
super::child_opt(self)
}
pub fn ret_type(self) -> Option<RetType<'a>> {
super::child_opt(self)
}
}
// ForExpr // ForExpr
#[derive(Debug, Clone, Copy,)] #[derive(Debug, Clone, Copy,)]
@ -1341,7 +1357,11 @@ impl<R: TreeRoot<RaTypes>> ForTypeNode<R> {
} }
impl<'a> ForType<'a> {} impl<'a> ForType<'a> {
pub fn type_ref(self) -> Option<TypeRef<'a>> {
super::child_opt(self)
}
}
// IfExpr // IfExpr
#[derive(Debug, Clone, Copy,)] #[derive(Debug, Clone, Copy,)]
@ -3490,7 +3510,11 @@ impl<R: TreeRoot<RaTypes>> SliceTypeNode<R> {
} }
impl<'a> SliceType<'a> {} impl<'a> SliceType<'a> {
pub fn type_ref(self) -> Option<TypeRef<'a>> {
super::child_opt(self)
}
}
// SourceFile // SourceFile
#[derive(Debug, Clone, Copy,)] #[derive(Debug, Clone, Copy,)]
@ -4025,7 +4049,11 @@ impl<R: TreeRoot<RaTypes>> TupleTypeNode<R> {
} }
impl<'a> TupleType<'a> {} impl<'a> TupleType<'a> {
pub fn fields(self) -> impl Iterator<Item = TypeRef<'a>> + 'a {
super::children(self)
}
}
// TypeDef // TypeDef
#[derive(Debug, Clone, Copy,)] #[derive(Debug, Clone, Copy,)]

View file

@ -304,16 +304,16 @@ Grammar(
"ImplItem": (), "ImplItem": (),
"ParenType": (options: ["TypeRef"]), "ParenType": (options: ["TypeRef"]),
"TupleType": (), "TupleType": ( collections: [["fields", "TypeRef"]] ),
"NeverType": (), "NeverType": (),
"PathType": (options: ["Path"]), "PathType": (options: ["Path"]),
"PointerType": (options: ["TypeRef"]), "PointerType": (options: ["TypeRef"]),
"ArrayType": (), "ArrayType": ( options: ["TypeRef", "Expr"] ),
"SliceType": (), "SliceType": ( options: ["TypeRef"] ),
"ReferenceType": (options: ["TypeRef"]), "ReferenceType": (options: ["TypeRef"]),
"PlaceholderType": (), "PlaceholderType": (),
"FnPointerType": (), "FnPointerType": (options: ["ParamList", "RetType"]),
"ForType": (), "ForType": (options: ["TypeRef"]),
"ImplTraitType": (), "ImplTraitType": (),
"DynTraitType": (), "DynTraitType": (),