Implement reference / pointer types

- parse them
 - infer types of & and * expressions
This commit is contained in:
Florian Diebold 2018-12-25 17:17:39 +01:00
parent b96d361239
commit 2870effd5c
7 changed files with 173 additions and 23 deletions

View File

@ -11,7 +11,7 @@ use rustc_hash::{FxHashMap};
use ra_db::{LocalSyntaxPtr, Cancelable};
use ra_syntax::{
SmolStr,
ast::{self, AstNode, LoopBodyOwner, ArgListOwner},
ast::{self, AstNode, LoopBodyOwner, ArgListOwner, PrefixOp},
SyntaxNodeRef
};
@ -21,6 +21,36 @@ use crate::{
adt::VariantData,
};
#[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`.
@ -56,12 +86,13 @@ pub enum Ty {
/// The pointee of an array slice. Written as `[T]`.
Slice(TyRef),
// A raw pointer. Written as `*mut T` or `*const T`
// RawPtr(TypeAndMut<'tcx>),
/// A raw pointer. Written as `*mut T` or `*const T`
RawPtr(TyRef, Mutability),
/// A reference; a pointer with an associated lifetime. Written as
/// `&'a mut T` or `&'a T`.
Ref(TyRef, Mutability),
// A reference; a pointer with an associated lifetime. Written as
// `&'a mut T` or `&'a T`.
// Ref(Ty<'tcx>, hir::Mutability),
/// A pointer to a function. Written as `fn() -> i32`.
///
/// For example the type of `bar` here:
@ -172,7 +203,7 @@ impl Ty {
) -> Cancelable<Self> {
use ra_syntax::ast::TypeRef::*;
Ok(match node {
ParenType(_inner) => Ty::Unknown, // TODO
ParenType(inner) => Ty::new_opt(db, module, inner.type_ref())?,
TupleType(_inner) => Ty::Unknown, // TODO
NeverType(..) => Ty::Never,
PathType(inner) => {
@ -182,10 +213,18 @@ impl Ty {
Ty::Unknown
}
}
PointerType(_inner) => Ty::Unknown, // TODO
ArrayType(_inner) => Ty::Unknown, // TODO
SliceType(_inner) => Ty::Unknown, // TODO
ReferenceType(_inner) => Ty::Unknown, // TODO
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
@ -209,6 +248,8 @@ impl fmt::Display for Ty {
Ty::Float(t) => write!(f, "{}", t.ty_to_string()),
Ty::Str => write!(f, "str"),
Ty::Slice(t) => write!(f, "[{}]", t),
Ty::RawPtr(t, m) => write!(f, "*{}{}", m.as_keyword_for_ptr(), t),
Ty::Ref(t, m) => write!(f, "&{}{}", m.as_keyword_for_ref(), t),
Ty::Never => write!(f, "!"),
Ty::Tuple(ts) => {
write!(f, "(")?;
@ -539,12 +580,25 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
cast_ty
}
ast::Expr::RefExpr(e) => {
let _inner_ty = self.infer_expr_opt(e.expr())?;
Ty::Unknown
let inner_ty = self.infer_expr_opt(e.expr())?;
let m = Mutability::from_mutable(e.is_mut());
// TODO reference coercions etc.
Ty::Ref(Arc::new(inner_ty), m)
}
ast::Expr::PrefixExpr(e) => {
let _inner_ty = self.infer_expr_opt(e.expr())?;
Ty::Unknown
let inner_ty = self.infer_expr_opt(e.expr())?;
match e.op() {
Some(PrefixOp::Deref) => {
match inner_ty {
// builtin deref:
Ty::Ref(ref_inner, _) => (*ref_inner).clone(),
Ty::RawPtr(ptr_inner, _) => (*ptr_inner).clone(),
// TODO Deref::deref
_ => Ty::Unknown,
}
}
_ => Ty::Unknown,
}
}
ast::Expr::RangeExpr(_e) => Ty::Unknown,
ast::Expr::BinExpr(_e) => Ty::Unknown,

View File

@ -91,6 +91,28 @@ fn test() {
);
}
#[test]
fn infer_refs_and_ptrs() {
check_inference(
r#"
fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) {
a;
*a;
&a;
&mut a;
b;
*b;
&b;
c;
*c;
d;
*d;
}
"#,
"0005_refs.txt",
);
}
fn infer(content: &str) -> String {
let (db, _, file_id) = MockDatabase::with_single_file(content);
let source_file = db.source_file(file_id);

View File

@ -1,4 +1,4 @@
[33; 34) 'd': [unknown]
[33; 34) 'd': &[unknown]
[88; 94) '1isize': [unknown]
[48; 49) 'a': u32
[55; 56) 'b': isize
@ -10,4 +10,4 @@
[17; 18) 'b': isize
[100; 106) '"test"': [unknown]
[42; 121) '{ ...f32; }': ()
[69; 70) 'd': [unknown]
[69; 70) 'd': &[unknown]

View File

@ -0,0 +1,23 @@
[115; 117) '&b': &&mut u32
[88; 94) '&mut a': &mut &u32
[146; 147) 'd': *mut u32
[145; 147) '*d': u32
[65; 66) 'a': &u32
[46; 47) 'd': *mut u32
[59; 150) '{ ... *d; }': ()
[116; 117) 'b': &mut u32
[131; 132) 'c': *const u32
[130; 132) '*c': u32
[72; 74) '*a': u32
[107; 109) '*b': u32
[108; 109) 'b': &mut u32
[9; 10) 'a': &u32
[18; 19) 'b': &mut u32
[93; 94) 'a': &u32
[100; 101) 'b': &mut u32
[81; 82) 'a': &u32
[80; 82) '&a': &&u32
[73; 74) 'a': &u32
[123; 124) 'c': *const u32
[31; 32) 'c': *const u32
[138; 139) 'd': *mut u32

View File

@ -394,3 +394,42 @@ impl<'a> EnumVariant<'a> {
StructFlavor::from_node(self)
}
}
impl<'a> PointerType<'a> {
pub fn is_mut(&self) -> bool {
self.syntax().children().any(|n| n.kind() == MUT_KW)
}
}
impl<'a> ReferenceType<'a> {
pub fn is_mut(&self) -> bool {
self.syntax().children().any(|n| n.kind() == MUT_KW)
}
}
impl<'a> RefExpr<'a> {
pub fn is_mut(&self) -> bool {
self.syntax().children().any(|n| n.kind() == MUT_KW)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum PrefixOp {
/// The `*` operator for dereferencing
Deref,
/// The `!` operator for logical inversion
Not,
/// The `-` operator for negation
Neg,
}
impl<'a> PrefixExpr<'a> {
pub fn op(&self) -> Option<PrefixOp> {
match self.syntax().first_child()?.kind() {
STAR => Some(PrefixOp::Deref),
EXCL => Some(PrefixOp::Not),
MINUS => Some(PrefixOp::Neg),
_ => None,
}
}
}

View File

@ -2607,7 +2607,11 @@ impl<R: TreeRoot<RaTypes>> ParenTypeNode<R> {
}
impl<'a> ParenType<'a> {}
impl<'a> ParenType<'a> {
pub fn type_ref(self) -> Option<TypeRef<'a>> {
super::child_opt(self)
}
}
// Pat
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@ -2972,7 +2976,11 @@ impl<R: TreeRoot<RaTypes>> PointerTypeNode<R> {
}
impl<'a> PointerType<'a> {}
impl<'a> PointerType<'a> {
pub fn type_ref(self) -> Option<TypeRef<'a>> {
super::child_opt(self)
}
}
// PosField
#[derive(Debug, Clone, Copy,)]
@ -3285,7 +3293,11 @@ impl<R: TreeRoot<RaTypes>> ReferenceTypeNode<R> {
}
impl<'a> ReferenceType<'a> {}
impl<'a> ReferenceType<'a> {
pub fn type_ref(self) -> Option<TypeRef<'a>> {
super::child_opt(self)
}
}
// RetType
#[derive(Debug, Clone, Copy,)]

View File

@ -303,14 +303,14 @@ Grammar(
] ),
"ImplItem": (),
"ParenType": (),
"ParenType": (options: ["TypeRef"]),
"TupleType": (),
"NeverType": (),
"PathType": (options: ["Path"]),
"PointerType": (),
"PointerType": (options: ["TypeRef"]),
"ArrayType": (),
"SliceType": (),
"ReferenceType": (),
"ReferenceType": (options: ["TypeRef"]),
"PlaceholderType": (),
"FnPointerType": (),
"ForType": (),