diff options
-rw-r--r-- | crates/ra_hir/src/ty.rs | 84 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 22 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/data/0001_basics.txt | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/data/0005_refs.txt | 23 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast.rs | 39 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/generated.rs | 18 | ||||
-rw-r--r-- | crates/ra_syntax/src/grammar.ron | 6 |
7 files changed, 173 insertions, 23 deletions
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 3674688ef..54aa6715c 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -11,7 +11,7 @@ use rustc_hash::{FxHashMap}; | |||
11 | use ra_db::{LocalSyntaxPtr, Cancelable}; | 11 | use ra_db::{LocalSyntaxPtr, Cancelable}; |
12 | use ra_syntax::{ | 12 | use ra_syntax::{ |
13 | SmolStr, | 13 | SmolStr, |
14 | ast::{self, AstNode, LoopBodyOwner, ArgListOwner}, | 14 | ast::{self, AstNode, LoopBodyOwner, ArgListOwner, PrefixOp}, |
15 | SyntaxNodeRef | 15 | SyntaxNodeRef |
16 | }; | 16 | }; |
17 | 17 | ||
@@ -21,6 +21,36 @@ use crate::{ | |||
21 | adt::VariantData, | 21 | adt::VariantData, |
22 | }; | 22 | }; |
23 | 23 | ||
24 | #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] | ||
25 | pub enum Mutability { | ||
26 | Shared, | ||
27 | Mut, | ||
28 | } | ||
29 | |||
30 | impl Mutability { | ||
31 | pub fn from_mutable(mutable: bool) -> Mutability { | ||
32 | if mutable { | ||
33 | Mutability::Mut | ||
34 | } else { | ||
35 | Mutability::Shared | ||
36 | } | ||
37 | } | ||
38 | |||
39 | pub fn as_keyword_for_ref(self) -> &'static str { | ||
40 | match self { | ||
41 | Mutability::Shared => "", | ||
42 | Mutability::Mut => "mut ", | ||
43 | } | ||
44 | } | ||
45 | |||
46 | pub fn as_keyword_for_ptr(self) -> &'static str { | ||
47 | match self { | ||
48 | Mutability::Shared => "const ", | ||
49 | Mutability::Mut => "mut ", | ||
50 | } | ||
51 | } | ||
52 | } | ||
53 | |||
24 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] | 54 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] |
25 | pub enum Ty { | 55 | pub enum Ty { |
26 | /// The primitive boolean type. Written as `bool`. | 56 | /// The primitive boolean type. Written as `bool`. |
@@ -56,12 +86,13 @@ pub enum Ty { | |||
56 | /// The pointee of an array slice. Written as `[T]`. | 86 | /// The pointee of an array slice. Written as `[T]`. |
57 | Slice(TyRef), | 87 | Slice(TyRef), |
58 | 88 | ||
59 | // A raw pointer. Written as `*mut T` or `*const T` | 89 | /// A raw pointer. Written as `*mut T` or `*const T` |
60 | // RawPtr(TypeAndMut<'tcx>), | 90 | RawPtr(TyRef, Mutability), |
91 | |||
92 | /// A reference; a pointer with an associated lifetime. Written as | ||
93 | /// `&'a mut T` or `&'a T`. | ||
94 | Ref(TyRef, Mutability), | ||
61 | 95 | ||
62 | // A reference; a pointer with an associated lifetime. Written as | ||
63 | // `&'a mut T` or `&'a T`. | ||
64 | // Ref(Ty<'tcx>, hir::Mutability), | ||
65 | /// A pointer to a function. Written as `fn() -> i32`. | 96 | /// A pointer to a function. Written as `fn() -> i32`. |
66 | /// | 97 | /// |
67 | /// For example the type of `bar` here: | 98 | /// For example the type of `bar` here: |
@@ -172,7 +203,7 @@ impl Ty { | |||
172 | ) -> Cancelable<Self> { | 203 | ) -> Cancelable<Self> { |
173 | use ra_syntax::ast::TypeRef::*; | 204 | use ra_syntax::ast::TypeRef::*; |
174 | Ok(match node { | 205 | Ok(match node { |
175 | ParenType(_inner) => Ty::Unknown, // TODO | 206 | ParenType(inner) => Ty::new_opt(db, module, inner.type_ref())?, |
176 | TupleType(_inner) => Ty::Unknown, // TODO | 207 | TupleType(_inner) => Ty::Unknown, // TODO |
177 | NeverType(..) => Ty::Never, | 208 | NeverType(..) => Ty::Never, |
178 | PathType(inner) => { | 209 | PathType(inner) => { |
@@ -182,10 +213,18 @@ impl Ty { | |||
182 | Ty::Unknown | 213 | Ty::Unknown |
183 | } | 214 | } |
184 | } | 215 | } |
185 | PointerType(_inner) => Ty::Unknown, // TODO | 216 | PointerType(inner) => { |
186 | ArrayType(_inner) => Ty::Unknown, // TODO | 217 | let inner_ty = Ty::new_opt(db, module, inner.type_ref())?; |
187 | SliceType(_inner) => Ty::Unknown, // TODO | 218 | let mutability = Mutability::from_mutable(inner.is_mut()); |
188 | ReferenceType(_inner) => Ty::Unknown, // TODO | 219 | Ty::RawPtr(Arc::new(inner_ty), mutability) |
220 | } | ||
221 | ArrayType(_inner) => Ty::Unknown, // TODO | ||
222 | SliceType(_inner) => Ty::Unknown, // TODO | ||
223 | ReferenceType(inner) => { | ||
224 | let inner_ty = Ty::new_opt(db, module, inner.type_ref())?; | ||
225 | let mutability = Mutability::from_mutable(inner.is_mut()); | ||
226 | Ty::Ref(Arc::new(inner_ty), mutability) | ||
227 | } | ||
189 | PlaceholderType(_inner) => Ty::Unknown, // TODO | 228 | PlaceholderType(_inner) => Ty::Unknown, // TODO |
190 | FnPointerType(_inner) => Ty::Unknown, // TODO | 229 | FnPointerType(_inner) => Ty::Unknown, // TODO |
191 | ForType(_inner) => Ty::Unknown, // TODO | 230 | ForType(_inner) => Ty::Unknown, // TODO |
@@ -209,6 +248,8 @@ impl fmt::Display for Ty { | |||
209 | Ty::Float(t) => write!(f, "{}", t.ty_to_string()), | 248 | Ty::Float(t) => write!(f, "{}", t.ty_to_string()), |
210 | Ty::Str => write!(f, "str"), | 249 | Ty::Str => write!(f, "str"), |
211 | Ty::Slice(t) => write!(f, "[{}]", t), | 250 | Ty::Slice(t) => write!(f, "[{}]", t), |
251 | Ty::RawPtr(t, m) => write!(f, "*{}{}", m.as_keyword_for_ptr(), t), | ||
252 | Ty::Ref(t, m) => write!(f, "&{}{}", m.as_keyword_for_ref(), t), | ||
212 | Ty::Never => write!(f, "!"), | 253 | Ty::Never => write!(f, "!"), |
213 | Ty::Tuple(ts) => { | 254 | Ty::Tuple(ts) => { |
214 | write!(f, "(")?; | 255 | write!(f, "(")?; |
@@ -539,12 +580,25 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
539 | cast_ty | 580 | cast_ty |
540 | } | 581 | } |
541 | ast::Expr::RefExpr(e) => { | 582 | ast::Expr::RefExpr(e) => { |
542 | let _inner_ty = self.infer_expr_opt(e.expr())?; | 583 | let inner_ty = self.infer_expr_opt(e.expr())?; |
543 | Ty::Unknown | 584 | let m = Mutability::from_mutable(e.is_mut()); |
585 | // TODO reference coercions etc. | ||
586 | Ty::Ref(Arc::new(inner_ty), m) | ||
544 | } | 587 | } |
545 | ast::Expr::PrefixExpr(e) => { | 588 | ast::Expr::PrefixExpr(e) => { |
546 | let _inner_ty = self.infer_expr_opt(e.expr())?; | 589 | let inner_ty = self.infer_expr_opt(e.expr())?; |
547 | Ty::Unknown | 590 | match e.op() { |
591 | Some(PrefixOp::Deref) => { | ||
592 | match inner_ty { | ||
593 | // builtin deref: | ||
594 | Ty::Ref(ref_inner, _) => (*ref_inner).clone(), | ||
595 | Ty::RawPtr(ptr_inner, _) => (*ptr_inner).clone(), | ||
596 | // TODO Deref::deref | ||
597 | _ => Ty::Unknown, | ||
598 | } | ||
599 | } | ||
600 | _ => Ty::Unknown, | ||
601 | } | ||
548 | } | 602 | } |
549 | ast::Expr::RangeExpr(_e) => Ty::Unknown, | 603 | ast::Expr::RangeExpr(_e) => Ty::Unknown, |
550 | ast::Expr::BinExpr(_e) => Ty::Unknown, | 604 | ast::Expr::BinExpr(_e) => Ty::Unknown, |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 9bb58ec85..a76925b58 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -91,6 +91,28 @@ fn test() { | |||
91 | ); | 91 | ); |
92 | } | 92 | } |
93 | 93 | ||
94 | #[test] | ||
95 | fn infer_refs_and_ptrs() { | ||
96 | check_inference( | ||
97 | r#" | ||
98 | fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) { | ||
99 | a; | ||
100 | *a; | ||
101 | &a; | ||
102 | &mut a; | ||
103 | b; | ||
104 | *b; | ||
105 | &b; | ||
106 | c; | ||
107 | *c; | ||
108 | d; | ||
109 | *d; | ||
110 | } | ||
111 | "#, | ||
112 | "0005_refs.txt", | ||
113 | ); | ||
114 | } | ||
115 | |||
94 | fn infer(content: &str) -> String { | 116 | fn infer(content: &str) -> String { |
95 | let (db, _, file_id) = MockDatabase::with_single_file(content); | 117 | let (db, _, file_id) = MockDatabase::with_single_file(content); |
96 | let source_file = db.source_file(file_id); | 118 | let source_file = db.source_file(file_id); |
diff --git a/crates/ra_hir/src/ty/tests/data/0001_basics.txt b/crates/ra_hir/src/ty/tests/data/0001_basics.txt index 0c46f243a..212e92e00 100644 --- a/crates/ra_hir/src/ty/tests/data/0001_basics.txt +++ b/crates/ra_hir/src/ty/tests/data/0001_basics.txt | |||
@@ -1,4 +1,4 @@ | |||
1 | [33; 34) 'd': [unknown] | 1 | [33; 34) 'd': &[unknown] |
2 | [88; 94) '1isize': [unknown] | 2 | [88; 94) '1isize': [unknown] |
3 | [48; 49) 'a': u32 | 3 | [48; 49) 'a': u32 |
4 | [55; 56) 'b': isize | 4 | [55; 56) 'b': isize |
@@ -10,4 +10,4 @@ | |||
10 | [17; 18) 'b': isize | 10 | [17; 18) 'b': isize |
11 | [100; 106) '"test"': [unknown] | 11 | [100; 106) '"test"': [unknown] |
12 | [42; 121) '{ ...f32; }': () | 12 | [42; 121) '{ ...f32; }': () |
13 | [69; 70) 'd': [unknown] | 13 | [69; 70) 'd': &[unknown] |
diff --git a/crates/ra_hir/src/ty/tests/data/0005_refs.txt b/crates/ra_hir/src/ty/tests/data/0005_refs.txt new file mode 100644 index 000000000..296e955c1 --- /dev/null +++ b/crates/ra_hir/src/ty/tests/data/0005_refs.txt | |||
@@ -0,0 +1,23 @@ | |||
1 | [115; 117) '&b': &&mut u32 | ||
2 | [88; 94) '&mut a': &mut &u32 | ||
3 | [146; 147) 'd': *mut u32 | ||
4 | [145; 147) '*d': u32 | ||
5 | [65; 66) 'a': &u32 | ||
6 | [46; 47) 'd': *mut u32 | ||
7 | [59; 150) '{ ... *d; }': () | ||
8 | [116; 117) 'b': &mut u32 | ||
9 | [131; 132) 'c': *const u32 | ||
10 | [130; 132) '*c': u32 | ||
11 | [72; 74) '*a': u32 | ||
12 | [107; 109) '*b': u32 | ||
13 | [108; 109) 'b': &mut u32 | ||
14 | [9; 10) 'a': &u32 | ||
15 | [18; 19) 'b': &mut u32 | ||
16 | [93; 94) 'a': &u32 | ||
17 | [100; 101) 'b': &mut u32 | ||
18 | [81; 82) 'a': &u32 | ||
19 | [80; 82) '&a': &&u32 | ||
20 | [73; 74) 'a': &u32 | ||
21 | [123; 124) 'c': *const u32 | ||
22 | [31; 32) 'c': *const u32 | ||
23 | [138; 139) 'd': *mut u32 | ||
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs index 5dbf9b221..8fb6b6408 100644 --- a/crates/ra_syntax/src/ast.rs +++ b/crates/ra_syntax/src/ast.rs | |||
@@ -394,3 +394,42 @@ impl<'a> EnumVariant<'a> { | |||
394 | StructFlavor::from_node(self) | 394 | StructFlavor::from_node(self) |
395 | } | 395 | } |
396 | } | 396 | } |
397 | |||
398 | impl<'a> PointerType<'a> { | ||
399 | pub fn is_mut(&self) -> bool { | ||
400 | self.syntax().children().any(|n| n.kind() == MUT_KW) | ||
401 | } | ||
402 | } | ||
403 | |||
404 | impl<'a> ReferenceType<'a> { | ||
405 | pub fn is_mut(&self) -> bool { | ||
406 | self.syntax().children().any(|n| n.kind() == MUT_KW) | ||
407 | } | ||
408 | } | ||
409 | |||
410 | impl<'a> RefExpr<'a> { | ||
411 | pub fn is_mut(&self) -> bool { | ||
412 | self.syntax().children().any(|n| n.kind() == MUT_KW) | ||
413 | } | ||
414 | } | ||
415 | |||
416 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
417 | pub enum PrefixOp { | ||
418 | /// The `*` operator for dereferencing | ||
419 | Deref, | ||
420 | /// The `!` operator for logical inversion | ||
421 | Not, | ||
422 | /// The `-` operator for negation | ||
423 | Neg, | ||
424 | } | ||
425 | |||
426 | impl<'a> PrefixExpr<'a> { | ||
427 | pub fn op(&self) -> Option<PrefixOp> { | ||
428 | match self.syntax().first_child()?.kind() { | ||
429 | STAR => Some(PrefixOp::Deref), | ||
430 | EXCL => Some(PrefixOp::Not), | ||
431 | MINUS => Some(PrefixOp::Neg), | ||
432 | _ => None, | ||
433 | } | ||
434 | } | ||
435 | } | ||
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index 6b2800a0e..535dcc975 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs | |||
@@ -2607,7 +2607,11 @@ impl<R: TreeRoot<RaTypes>> ParenTypeNode<R> { | |||
2607 | } | 2607 | } |
2608 | 2608 | ||
2609 | 2609 | ||
2610 | impl<'a> ParenType<'a> {} | 2610 | impl<'a> ParenType<'a> { |
2611 | pub fn type_ref(self) -> Option<TypeRef<'a>> { | ||
2612 | super::child_opt(self) | ||
2613 | } | ||
2614 | } | ||
2611 | 2615 | ||
2612 | // Pat | 2616 | // Pat |
2613 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 2617 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
@@ -2972,7 +2976,11 @@ impl<R: TreeRoot<RaTypes>> PointerTypeNode<R> { | |||
2972 | } | 2976 | } |
2973 | 2977 | ||
2974 | 2978 | ||
2975 | impl<'a> PointerType<'a> {} | 2979 | impl<'a> PointerType<'a> { |
2980 | pub fn type_ref(self) -> Option<TypeRef<'a>> { | ||
2981 | super::child_opt(self) | ||
2982 | } | ||
2983 | } | ||
2976 | 2984 | ||
2977 | // PosField | 2985 | // PosField |
2978 | #[derive(Debug, Clone, Copy,)] | 2986 | #[derive(Debug, Clone, Copy,)] |
@@ -3285,7 +3293,11 @@ impl<R: TreeRoot<RaTypes>> ReferenceTypeNode<R> { | |||
3285 | } | 3293 | } |
3286 | 3294 | ||
3287 | 3295 | ||
3288 | impl<'a> ReferenceType<'a> {} | 3296 | impl<'a> ReferenceType<'a> { |
3297 | pub fn type_ref(self) -> Option<TypeRef<'a>> { | ||
3298 | super::child_opt(self) | ||
3299 | } | ||
3300 | } | ||
3289 | 3301 | ||
3290 | // RetType | 3302 | // RetType |
3291 | #[derive(Debug, Clone, Copy,)] | 3303 | #[derive(Debug, Clone, Copy,)] |
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index dcde32923..8b1bd6d1c 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron | |||
@@ -303,14 +303,14 @@ Grammar( | |||
303 | ] ), | 303 | ] ), |
304 | "ImplItem": (), | 304 | "ImplItem": (), |
305 | 305 | ||
306 | "ParenType": (), | 306 | "ParenType": (options: ["TypeRef"]), |
307 | "TupleType": (), | 307 | "TupleType": (), |
308 | "NeverType": (), | 308 | "NeverType": (), |
309 | "PathType": (options: ["Path"]), | 309 | "PathType": (options: ["Path"]), |
310 | "PointerType": (), | 310 | "PointerType": (options: ["TypeRef"]), |
311 | "ArrayType": (), | 311 | "ArrayType": (), |
312 | "SliceType": (), | 312 | "SliceType": (), |
313 | "ReferenceType": (), | 313 | "ReferenceType": (options: ["TypeRef"]), |
314 | "PlaceholderType": (), | 314 | "PlaceholderType": (), |
315 | "FnPointerType": (), | 315 | "FnPointerType": (), |
316 | "ForType": (), | 316 | "ForType": (), |