mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-27 04:19:13 +00:00
Add a hir::TypeRef as an intermediate between ast::TypeRef and ty::Ty
This commit is contained in:
parent
2870effd5c
commit
cdca397061
10 changed files with 219 additions and 95 deletions
|
@ -8,7 +8,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) -> C
|
|||
(Some(path), Some(module)) => (path.clone(), module),
|
||||
_ => 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,
|
||||
None => return Ok(()),
|
||||
};
|
||||
|
|
|
@ -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::<Cancelable<_>>()?;
|
||||
|
@ -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::<Cancelable<_>>()?;
|
||||
|
|
|
@ -26,6 +26,7 @@ mod krate;
|
|||
mod module;
|
||||
mod function;
|
||||
mod adt;
|
||||
mod type_ref;
|
||||
mod ty;
|
||||
|
||||
use std::ops::Index;
|
||||
|
|
|
@ -115,7 +115,7 @@ impl Module {
|
|||
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(
|
||||
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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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<SmolStr>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum PathKind {
|
||||
Plain,
|
||||
Self_,
|
||||
|
|
|
@ -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<Self> {
|
||||
let path = if let Some(p) = Path::from_ast(path) {
|
||||
p
|
||||
} else {
|
||||
return Ok(Ty::Unknown);
|
||||
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> {
|
||||
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<ast::TypeRef>,
|
||||
) -> Cancelable<Self> {
|
||||
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<Self> {
|
||||
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<Ty> {
|
|||
.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<InferenceR
|
|||
continue;
|
||||
};
|
||||
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);
|
||||
} else {
|
||||
// TODO self param
|
||||
|
|
110
crates/ra_hir/src/type_ref.rs
Normal file
110
crates/ra_hir/src/type_ref.rs
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
#[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
|
||||
#[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
|
||||
#[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
|
||||
#[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
|
||||
#[derive(Debug, Clone, Copy,)]
|
||||
|
|
|
@ -304,16 +304,16 @@ Grammar(
|
|||
"ImplItem": (),
|
||||
|
||||
"ParenType": (options: ["TypeRef"]),
|
||||
"TupleType": (),
|
||||
"TupleType": ( collections: [["fields", "TypeRef"]] ),
|
||||
"NeverType": (),
|
||||
"PathType": (options: ["Path"]),
|
||||
"PointerType": (options: ["TypeRef"]),
|
||||
"ArrayType": (),
|
||||
"SliceType": (),
|
||||
"ArrayType": ( options: ["TypeRef", "Expr"] ),
|
||||
"SliceType": ( options: ["TypeRef"] ),
|
||||
"ReferenceType": (options: ["TypeRef"]),
|
||||
"PlaceholderType": (),
|
||||
"FnPointerType": (),
|
||||
"ForType": (),
|
||||
"FnPointerType": (options: ["ParamList", "RetType"]),
|
||||
"ForType": (options: ["TypeRef"]),
|
||||
"ImplTraitType": (),
|
||||
"DynTraitType": (),
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue