From d48d5b8b6ca59b462b3a84dad9868daff2eddb6d Mon Sep 17 00:00:00 2001 From: Marcus Klaas de Vries Date: Thu, 17 Jan 2019 13:08:18 +0100 Subject: Add initial (flawed) implementation of binding annotations --- .../ra_hir/src/code_model_impl/function/scope.rs | 2 +- crates/ra_hir/src/expr.rs | 49 +++++++++++++++++++++- crates/ra_hir/src/ty.rs | 26 +++++++++++- crates/ra_hir/src/ty/tests.rs | 4 ++ crates/ra_syntax/src/ast.rs | 10 +++++ crates/ra_syntax/src/ast/generated.rs | 6 ++- crates/ra_syntax/src/grammar.ron | 5 ++- 7 files changed, 97 insertions(+), 5 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 { fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) { match &body[pat] { - Pat::Bind { name } => self.scopes[scope].entries.push(ScopeEntry { + Pat::Bind { name, .. } => self.scopes[scope].entries.push(ScopeEntry { name: name.clone(), pat, }), 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 { pub struct PatId(RawId); impl_arena_id!(PatId); +// copied verbatim from librustc::hir + +/// Explicit binding annotations given in the HIR for a binding. Note +/// that this is not the final binding *mode* that we infer after type +/// inference. +#[derive(Clone, PartialEq, Eq, Debug, Copy)] +pub enum BindingAnnotation { + /// No binding annotation given: this means that the final binding mode + /// will depend on whether we have skipped through a `&` reference + /// when matching. For example, the `x` in `Some(x)` will have binding + /// mode `None`; if you do `let Some(x) = &Some(22)`, it will + /// ultimately be inferred to be by-reference. + /// + /// Note that implicit reference skipping is not implemented yet (#42640). + Unannotated, + + /// Annotated with `mut x` -- could be either ref or not, similar to `None`. + Mutable, + + /// Annotated as `ref`, like `ref x` + Ref, + + /// Annotated as `ref mut x`. + RefMut, +} + +impl BindingAnnotation { + fn new(is_mutable: bool, is_ref: bool) -> Self { + match (is_mutable, is_ref) { + (true, true) => BindingAnnotation::RefMut, + (false, true) => BindingAnnotation::Ref, + (true, false) => BindingAnnotation::Mutable, + (false, false) => BindingAnnotation::Unannotated, + } + } +} + #[derive(Debug, Clone, Eq, PartialEq)] pub struct FieldPat { pub(crate) name: Name, @@ -359,7 +396,9 @@ pub enum Pat { Path(Path), Lit(ExprId), Bind { + mode: BindingAnnotation, name: Name, + sub_pat: Option, }, TupleStruct { path: Option, @@ -793,7 +832,13 @@ impl ExprCollector { .name() .map(|nr| nr.as_name()) .unwrap_or_else(Name::missing); - Pat::Bind { name } + let annotation = BindingAnnotation::new(bp.is_mutable(), bp.is_ref()); + let sub_pat = bp.pat().map(|subpat| self.collect_pat(subpat)); + Pat::Bind { + name, + mode: annotation, + sub_pat, + } } ast::PatKind::TupleStructPat(p) => { let path = p.path().and_then(Path::from_ast); @@ -882,6 +927,8 @@ pub(crate) fn collect_fn_body_syntax(node: &ast::FnDef) -> BodySyntaxMapping { let param = collector.alloc_pat( Pat::Bind { name: Name::self_param(), + mode: BindingAnnotation::Unannotated, + sub_pat: None, }, self_param, ); 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::{ db::HirDatabase, type_ref::{TypeRef, Mutability}, name::KnownName, - expr::{Body, Expr, MatchArm, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat}, + expr::{Body, Expr, BindingAnnotation, MatchArm, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat}, }; /// The ID of a type variable. @@ -985,6 +985,30 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { path: ref p, args: ref fields, } => self.infer_struct(p.as_ref(), fields), + Pat::Path(path) => { + // is this right? + self.module + .resolve_path(self.db, &path) + .take_values() + .map_or(Ty::Unknown, |resolved| self.db.type_for_def(resolved)) + } + Pat::Bind { + mode, + name: _name, + sub_pat, + } => { + let subty = if let Some(subpat) = sub_pat { + self.infer_pat(*subpat, expected) + } else { + Ty::Unknown + }; + + match mode { + BindingAnnotation::Ref => Ty::Ref(subty.into(), Mutability::Shared), + BindingAnnotation::RefMut => Ty::Ref(subty.into(), Mutability::Mut), + BindingAnnotation::Mutable | BindingAnnotation::Unannotated => subty, + } + } _ => Ty::Unknown, }; // 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) { } let lambda = |a: u64, b, c: i32| { a + b; c }; + + let ref ref_to_x = x; + let mut mut_x = x; + let ref mut mut_ref_to_x = x; } "#, "pattern.txt", diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs index 4b7edbbe7..0ee9ef199 100644 --- a/crates/ra_syntax/src/ast.rs +++ b/crates/ra_syntax/src/ast.rs @@ -713,6 +713,16 @@ impl FieldPatList { } } +impl BindPat { + pub fn is_mutable(&self) -> bool { + self.syntax().children().any(|n| n.kind() == MUT_KW) + } + + pub fn is_ref(&self) -> bool { + self.syntax().children().any(|n| n.kind() == REF_KW) + } +} + #[test] fn test_doc_comment_of_items() { let file = SourceFile::parse( diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index 251d53bdf..ead0f1293 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs @@ -180,7 +180,11 @@ impl AstNode for BindPat { impl ast::NameOwner for BindPat {} -impl BindPat {} +impl BindPat { + pub fn pat(&self) -> Option<&Pat> { + super::child_opt(self) + } +} // Block #[derive(Debug, PartialEq, Eq, Hash)] diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index 33080f664..d58e0dd35 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron @@ -488,7 +488,10 @@ Grammar( ), "RefPat": ( options: [ "Pat" ]), - "BindPat": ( traits: ["NameOwner"] ), + "BindPat": ( + options: [ "Pat" ], + traits: ["NameOwner"] + ), "PlaceholderPat": (), "PathPat": ( options: [ "Path" ] ), "StructPat": ( options: ["FieldPatList", "Path"] ), -- cgit v1.2.3