mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-26 20:09:19 +00:00
Add initial (flawed) implementation of binding annotations
This commit is contained in:
parent
9433a108cf
commit
d48d5b8b6c
7 changed files with 97 additions and 5 deletions
|
@ -88,7 +88,7 @@ impl FnScopes {
|
||||||
|
|
||||||
fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) {
|
fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) {
|
||||||
match &body[pat] {
|
match &body[pat] {
|
||||||
Pat::Bind { name } => self.scopes[scope].entries.push(ScopeEntry {
|
Pat::Bind { name, .. } => self.scopes[scope].entries.push(ScopeEntry {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
pat,
|
pat,
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -329,6 +329,43 @@ impl Expr {
|
||||||
pub struct PatId(RawId);
|
pub struct PatId(RawId);
|
||||||
impl_arena_id!(PatId);
|
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)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub struct FieldPat {
|
pub struct FieldPat {
|
||||||
pub(crate) name: Name,
|
pub(crate) name: Name,
|
||||||
|
@ -359,7 +396,9 @@ pub enum Pat {
|
||||||
Path(Path),
|
Path(Path),
|
||||||
Lit(ExprId),
|
Lit(ExprId),
|
||||||
Bind {
|
Bind {
|
||||||
|
mode: BindingAnnotation,
|
||||||
name: Name,
|
name: Name,
|
||||||
|
sub_pat: Option<PatId>,
|
||||||
},
|
},
|
||||||
TupleStruct {
|
TupleStruct {
|
||||||
path: Option<Path>,
|
path: Option<Path>,
|
||||||
|
@ -793,7 +832,13 @@ impl ExprCollector {
|
||||||
.name()
|
.name()
|
||||||
.map(|nr| nr.as_name())
|
.map(|nr| nr.as_name())
|
||||||
.unwrap_or_else(Name::missing);
|
.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) => {
|
ast::PatKind::TupleStructPat(p) => {
|
||||||
let path = p.path().and_then(Path::from_ast);
|
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(
|
let param = collector.alloc_pat(
|
||||||
Pat::Bind {
|
Pat::Bind {
|
||||||
name: Name::self_param(),
|
name: Name::self_param(),
|
||||||
|
mode: BindingAnnotation::Unannotated,
|
||||||
|
sub_pat: None,
|
||||||
},
|
},
|
||||||
self_param,
|
self_param,
|
||||||
);
|
);
|
||||||
|
|
|
@ -37,7 +37,7 @@ use crate::{
|
||||||
db::HirDatabase,
|
db::HirDatabase,
|
||||||
type_ref::{TypeRef, Mutability},
|
type_ref::{TypeRef, Mutability},
|
||||||
name::KnownName,
|
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.
|
/// The ID of a type variable.
|
||||||
|
@ -985,6 +985,30 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
path: ref p,
|
path: ref p,
|
||||||
args: ref fields,
|
args: ref fields,
|
||||||
} => self.infer_struct(p.as_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,
|
_ => Ty::Unknown,
|
||||||
};
|
};
|
||||||
// use a new type variable if we got Ty::Unknown here
|
// use a new type variable if we got Ty::Unknown here
|
||||||
|
|
|
@ -377,6 +377,10 @@ fn test(x: &i32) {
|
||||||
}
|
}
|
||||||
|
|
||||||
let lambda = |a: u64, b, c: i32| { a + b; c };
|
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",
|
"pattern.txt",
|
||||||
|
|
|
@ -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]
|
#[test]
|
||||||
fn test_doc_comment_of_items() {
|
fn test_doc_comment_of_items() {
|
||||||
let file = SourceFile::parse(
|
let file = SourceFile::parse(
|
||||||
|
|
|
@ -180,7 +180,11 @@ impl AstNode for BindPat {
|
||||||
|
|
||||||
|
|
||||||
impl ast::NameOwner for BindPat {}
|
impl ast::NameOwner for BindPat {}
|
||||||
impl BindPat {}
|
impl BindPat {
|
||||||
|
pub fn pat(&self) -> Option<&Pat> {
|
||||||
|
super::child_opt(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Block
|
// Block
|
||||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||||
|
|
|
@ -488,7 +488,10 @@ Grammar(
|
||||||
),
|
),
|
||||||
|
|
||||||
"RefPat": ( options: [ "Pat" ]),
|
"RefPat": ( options: [ "Pat" ]),
|
||||||
"BindPat": ( traits: ["NameOwner"] ),
|
"BindPat": (
|
||||||
|
options: [ "Pat" ],
|
||||||
|
traits: ["NameOwner"]
|
||||||
|
),
|
||||||
"PlaceholderPat": (),
|
"PlaceholderPat": (),
|
||||||
"PathPat": ( options: [ "Path" ] ),
|
"PathPat": ( options: [ "Path" ] ),
|
||||||
"StructPat": ( options: ["FieldPatList", "Path"] ),
|
"StructPat": ( options: ["FieldPatList", "Path"] ),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue