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 +- crates/ra_hir/src/lib.rs | 1 + crates/ra_hir/src/module.rs | 4 +- crates/ra_hir/src/module/nameres.rs | 2 +- crates/ra_hir/src/path.rs | 4 +- crates/ra_hir/src/ty.rs | 139 ++++++++++++++++-------------------- crates/ra_hir/src/type_ref.rs | 110 ++++++++++++++++++++++++++++ 7 files changed, 180 insertions(+), 84 deletions(-) create mode 100644 crates/ra_hir/src/type_ref.rs (limited to 'crates/ra_hir') 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::>()?; diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 68fdbb7ea..f1cc0ccd0 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -26,6 +26,7 @@ mod krate; mod module; mod function; mod adt; +mod type_ref; mod ty; use std::ops::Index; diff --git a/crates/ra_hir/src/module.rs b/crates/ra_hir/src/module.rs index e1a0e4b59..b9d36f01f 100644 --- a/crates/ra_hir/src/module.rs +++ b/crates/ra_hir/src/module.rs @@ -115,7 +115,7 @@ impl Module { Ok(res) } - pub fn resolve_path(&self, db: &impl HirDatabase, path: Path) -> Cancelable> { + pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> Cancelable> { let mut curr_per_ns = PerNs::types( match path.kind { PathKind::Crate => self.crate_root(), @@ -131,7 +131,7 @@ impl Module { .def_id(db), ); - let segments = path.segments; + let segments = &path.segments; for name in segments.iter() { let curr = if let Some(r) = curr_per_ns.as_ref().take(Namespace::Types) { r diff --git a/crates/ra_hir/src/module/nameres.rs b/crates/ra_hir/src/module/nameres.rs index 33c9d93c2..98cd225dd 100644 --- a/crates/ra_hir/src/module/nameres.rs +++ b/crates/ra_hir/src/module/nameres.rs @@ -451,7 +451,7 @@ where segments: import.path.segments[i + 1..].iter().cloned().collect(), 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() { self.update(module_id, |items| { let res = Resolution { diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index e04d00900..0b260072c 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs @@ -1,12 +1,12 @@ use ra_syntax::{SmolStr, ast, AstNode, TextRange}; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Path { pub kind: PathKind, pub segments: Vec, } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum PathKind { Plain, Self_, diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 54aa6715c..11b4caa23 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -19,38 +19,9 @@ use crate::{ Def, DefId, FnScopes, Module, Function, Struct, Enum, Path, db::HirDatabase, 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)] pub enum Ty { /// The primitive boolean type. Written as `bool`. @@ -156,16 +127,58 @@ pub struct FnSig { } impl Ty { - pub(crate) fn new_from_ast_path( + pub(crate) fn from_hir( db: &impl HirDatabase, module: &Module, - path: ast::Path, + type_ref: &TypeRef, + ) -> Cancelable { + 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::>()?; + 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::>>()?; + 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 { - let path = if let Some(p) = Path::from_ast(path) { - p - } else { - return Ok(Ty::Unknown); - }; if path.is_ident() { let name = &path.segments[0]; if let Some(int_ty) = primitive::IntTy::from_string(&name) { @@ -187,50 +200,22 @@ impl 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, module: &Module, node: Option, ) -> Cancelable { - node.map(|n| Ty::new(db, module, n)) + node.map(|n| Ty::from_ast(db, module, n)) .unwrap_or(Ok(Ty::Unknown)) } - pub(crate) fn new( + pub(crate) fn from_ast( db: &impl HirDatabase, module: &Module, node: ast::TypeRef, ) -> Cancelable { - use ra_syntax::ast::TypeRef::*; - 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 - }) + Ty::from_hir(db, module, &TypeRef::from_ast(node)) } pub fn unit() -> Self { @@ -280,11 +265,11 @@ pub fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable { .param_list() .map(|pl| { pl.params() - .map(|p| Ty::new_opt(db, &module, p.type_ref())) + .map(|p| Ty::from_ast_opt(db, &module, p.type_ref())) .collect() }) .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 }; Ok(Ty::FnPtr(Arc::new(sig))) } @@ -390,7 +375,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { }; // 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)?; // TODO we will need to add type variables for type parameters etc. here Ok(Some(ty)) @@ -405,7 +390,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } else { 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 } else { return Ok((Ty::Unknown, None)); @@ -575,7 +560,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } ast::Expr::CastExpr(e) => { 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... cast_ty } @@ -620,7 +605,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { for stmt in node.statements() { match 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() { // TODO pass expectation let expr_ty = self.infer_expr(expr)?; @@ -665,7 +650,7 @@ pub fn infer(db: &impl HirDatabase, function: Function) -> Cancelable 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), + Path(Path), + RawPtr(Box, Mutability), + Reference(Box, Mutability), + Array(Box /*, Expr*/), + Slice(Box), + /// A fn pointer. Last element of the vector is the return type. + Fn(Vec), + // 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) -> Self { + if let Some(node) = node { + TypeRef::from_ast(node) + } else { + TypeRef::Error + } + } +} -- cgit v1.2.3