diff options
author | Marcus Klaas de Vries <[email protected]> | 2019-01-17 12:08:18 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2019-01-19 12:37:26 +0000 |
commit | d48d5b8b6ca59b462b3a84dad9868daff2eddb6d (patch) | |
tree | 20f1936ccf07abea463ae81b36132efd76ad4f71 /crates/ra_hir/src | |
parent | 9433a108cfcf3a9c7de9299d6641a5abf9031a17 (diff) |
Add initial (flawed) implementation of binding annotations
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/code_model_impl/function/scope.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/expr.rs | 49 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 26 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 4 |
4 files changed, 78 insertions, 3 deletions
diff --git a/crates/ra_hir/src/code_model_impl/function/scope.rs b/crates/ra_hir/src/code_model_impl/function/scope.rs index c551e445a..7e8eb7704 100644 --- a/crates/ra_hir/src/code_model_impl/function/scope.rs +++ b/crates/ra_hir/src/code_model_impl/function/scope.rs | |||
@@ -88,7 +88,7 @@ impl FnScopes { | |||
88 | 88 | ||
89 | fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) { | 89 | fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) { |
90 | match &body[pat] { | 90 | match &body[pat] { |
91 | Pat::Bind { name } => self.scopes[scope].entries.push(ScopeEntry { | 91 | Pat::Bind { name, .. } => self.scopes[scope].entries.push(ScopeEntry { |
92 | name: name.clone(), | 92 | name: name.clone(), |
93 | pat, | 93 | pat, |
94 | }), | 94 | }), |
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index e7235c1a1..4d372c97b 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs | |||
@@ -329,6 +329,43 @@ impl Expr { | |||
329 | pub struct PatId(RawId); | 329 | pub struct PatId(RawId); |
330 | impl_arena_id!(PatId); | 330 | impl_arena_id!(PatId); |
331 | 331 | ||
332 | // copied verbatim from librustc::hir | ||
333 | |||
334 | /// Explicit binding annotations given in the HIR for a binding. Note | ||
335 | /// that this is not the final binding *mode* that we infer after type | ||
336 | /// inference. | ||
337 | #[derive(Clone, PartialEq, Eq, Debug, Copy)] | ||
338 | pub enum BindingAnnotation { | ||
339 | /// No binding annotation given: this means that the final binding mode | ||
340 | /// will depend on whether we have skipped through a `&` reference | ||
341 | /// when matching. For example, the `x` in `Some(x)` will have binding | ||
342 | /// mode `None`; if you do `let Some(x) = &Some(22)`, it will | ||
343 | /// ultimately be inferred to be by-reference. | ||
344 | /// | ||
345 | /// Note that implicit reference skipping is not implemented yet (#42640). | ||
346 | Unannotated, | ||
347 | |||
348 | /// Annotated with `mut x` -- could be either ref or not, similar to `None`. | ||
349 | Mutable, | ||
350 | |||
351 | /// Annotated as `ref`, like `ref x` | ||
352 | Ref, | ||
353 | |||
354 | /// Annotated as `ref mut x`. | ||
355 | RefMut, | ||
356 | } | ||
357 | |||
358 | impl BindingAnnotation { | ||
359 | fn new(is_mutable: bool, is_ref: bool) -> Self { | ||
360 | match (is_mutable, is_ref) { | ||
361 | (true, true) => BindingAnnotation::RefMut, | ||
362 | (false, true) => BindingAnnotation::Ref, | ||
363 | (true, false) => BindingAnnotation::Mutable, | ||
364 | (false, false) => BindingAnnotation::Unannotated, | ||
365 | } | ||
366 | } | ||
367 | } | ||
368 | |||
332 | #[derive(Debug, Clone, Eq, PartialEq)] | 369 | #[derive(Debug, Clone, Eq, PartialEq)] |
333 | pub struct FieldPat { | 370 | pub struct FieldPat { |
334 | pub(crate) name: Name, | 371 | pub(crate) name: Name, |
@@ -359,7 +396,9 @@ pub enum Pat { | |||
359 | Path(Path), | 396 | Path(Path), |
360 | Lit(ExprId), | 397 | Lit(ExprId), |
361 | Bind { | 398 | Bind { |
399 | mode: BindingAnnotation, | ||
362 | name: Name, | 400 | name: Name, |
401 | sub_pat: Option<PatId>, | ||
363 | }, | 402 | }, |
364 | TupleStruct { | 403 | TupleStruct { |
365 | path: Option<Path>, | 404 | path: Option<Path>, |
@@ -793,7 +832,13 @@ impl ExprCollector { | |||
793 | .name() | 832 | .name() |
794 | .map(|nr| nr.as_name()) | 833 | .map(|nr| nr.as_name()) |
795 | .unwrap_or_else(Name::missing); | 834 | .unwrap_or_else(Name::missing); |
796 | Pat::Bind { name } | 835 | let annotation = BindingAnnotation::new(bp.is_mutable(), bp.is_ref()); |
836 | let sub_pat = bp.pat().map(|subpat| self.collect_pat(subpat)); | ||
837 | Pat::Bind { | ||
838 | name, | ||
839 | mode: annotation, | ||
840 | sub_pat, | ||
841 | } | ||
797 | } | 842 | } |
798 | ast::PatKind::TupleStructPat(p) => { | 843 | ast::PatKind::TupleStructPat(p) => { |
799 | let path = p.path().and_then(Path::from_ast); | 844 | let path = p.path().and_then(Path::from_ast); |
@@ -882,6 +927,8 @@ pub(crate) fn collect_fn_body_syntax(node: &ast::FnDef) -> BodySyntaxMapping { | |||
882 | let param = collector.alloc_pat( | 927 | let param = collector.alloc_pat( |
883 | Pat::Bind { | 928 | Pat::Bind { |
884 | name: Name::self_param(), | 929 | name: Name::self_param(), |
930 | mode: BindingAnnotation::Unannotated, | ||
931 | sub_pat: None, | ||
885 | }, | 932 | }, |
886 | self_param, | 933 | self_param, |
887 | ); | 934 | ); |
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 8ad80990e..bc842dd26 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -37,7 +37,7 @@ use crate::{ | |||
37 | db::HirDatabase, | 37 | db::HirDatabase, |
38 | type_ref::{TypeRef, Mutability}, | 38 | type_ref::{TypeRef, Mutability}, |
39 | name::KnownName, | 39 | name::KnownName, |
40 | expr::{Body, Expr, MatchArm, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat}, | 40 | expr::{Body, Expr, BindingAnnotation, MatchArm, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat}, |
41 | }; | 41 | }; |
42 | 42 | ||
43 | /// The ID of a type variable. | 43 | /// The ID of a type variable. |
@@ -985,6 +985,30 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
985 | path: ref p, | 985 | path: ref p, |
986 | args: ref fields, | 986 | args: ref fields, |
987 | } => self.infer_struct(p.as_ref(), fields), | 987 | } => self.infer_struct(p.as_ref(), fields), |
988 | Pat::Path(path) => { | ||
989 | // is this right? | ||
990 | self.module | ||
991 | .resolve_path(self.db, &path) | ||
992 | .take_values() | ||
993 | .map_or(Ty::Unknown, |resolved| self.db.type_for_def(resolved)) | ||
994 | } | ||
995 | Pat::Bind { | ||
996 | mode, | ||
997 | name: _name, | ||
998 | sub_pat, | ||
999 | } => { | ||
1000 | let subty = if let Some(subpat) = sub_pat { | ||
1001 | self.infer_pat(*subpat, expected) | ||
1002 | } else { | ||
1003 | Ty::Unknown | ||
1004 | }; | ||
1005 | |||
1006 | match mode { | ||
1007 | BindingAnnotation::Ref => Ty::Ref(subty.into(), Mutability::Shared), | ||
1008 | BindingAnnotation::RefMut => Ty::Ref(subty.into(), Mutability::Mut), | ||
1009 | BindingAnnotation::Mutable | BindingAnnotation::Unannotated => subty, | ||
1010 | } | ||
1011 | } | ||
988 | _ => Ty::Unknown, | 1012 | _ => Ty::Unknown, |
989 | }; | 1013 | }; |
990 | // use a new type variable if we got Ty::Unknown here | 1014 | // use a new type variable if we got Ty::Unknown here |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index dfc83bb17..e817a8da9 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -377,6 +377,10 @@ fn test(x: &i32) { | |||
377 | } | 377 | } |
378 | 378 | ||
379 | let lambda = |a: u64, b, c: i32| { a + b; c }; | 379 | let lambda = |a: u64, b, c: i32| { a + b; c }; |
380 | |||
381 | let ref ref_to_x = x; | ||
382 | let mut mut_x = x; | ||
383 | let ref mut mut_ref_to_x = x; | ||
380 | } | 384 | } |
381 | "#, | 385 | "#, |
382 | "pattern.txt", | 386 | "pattern.txt", |