Implement reference / pointer types
- parse them - infer types of & and * expressions
This commit is contained in:
parent
b96d361239
commit
2870effd5c
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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]
|
||||
|
23
crates/ra_hir/src/ty/tests/data/0005_refs.txt
Normal file
23
crates/ra_hir/src/ty/tests/data/0005_refs.txt
Normal 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
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,)]
|
||||
|
@ -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": (),
|
||||
|
Loading…
x
Reference in New Issue
Block a user