mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-29 18:23:49 +00:00
Add initial (flawed) implementation of binding annotations
This commit is contained in:
parent
9433a108cf
commit
d48d5b8b6c
@ -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,
|
||||
}),
|
||||
|
@ -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<PatId>,
|
||||
},
|
||||
TupleStruct {
|
||||
path: Option<Path>,
|
||||
@ -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,
|
||||
);
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
|
@ -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(
|
||||
|
@ -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)]
|
||||
|
@ -488,7 +488,10 @@ Grammar(
|
||||
),
|
||||
|
||||
"RefPat": ( options: [ "Pat" ]),
|
||||
"BindPat": ( traits: ["NameOwner"] ),
|
||||
"BindPat": (
|
||||
options: [ "Pat" ],
|
||||
traits: ["NameOwner"]
|
||||
),
|
||||
"PlaceholderPat": (),
|
||||
"PathPat": ( options: [ "Path" ] ),
|
||||
"StructPat": ( options: ["FieldPatList", "Path"] ),
|
||||
|
Loading…
Reference in New Issue
Block a user