default binding modes: add pat_binding_modes
This PR kicks off the implementation of the [default binding modes RFC][1] by introducing the `pat_binding_modes` typeck table mentioned in the [mentoring instructions][2]. `pat_binding_modes` is populated in `librustc_typeck/check/_match.rs` and used wherever the HIR would be scraped prior to this PR. Unfortunately, one blemish, namely a two callers to `contains_explicit_ref_binding`, remains. This will likely have to be removed when the second part of [1], the `pat_adjustments` table, is tackled. Appropriate comments have been added. See #42640. [1]: https://github.com/rust-lang/rfcs/pull/2005 [2]: https://github.com/rust-lang/rust/issues/42640#issuecomment-313535089
This commit is contained in:
parent
5c71e4ef90
commit
851c77088d
@ -2191,7 +2191,7 @@ impl<'a> LoweringContext<'a> {
|
||||
let next_ident = self.str_to_ident("__next");
|
||||
let next_pat = self.pat_ident_binding_mode(e.span,
|
||||
next_ident,
|
||||
hir::BindByValue(hir::MutMutable));
|
||||
hir::BindingAnnotation::Mutable);
|
||||
|
||||
// `::std::option::Option::Some(val) => next = val`
|
||||
let pat_arm = {
|
||||
@ -2215,8 +2215,9 @@ impl<'a> LoweringContext<'a> {
|
||||
};
|
||||
|
||||
// `mut iter`
|
||||
let iter_pat = self.pat_ident_binding_mode(e.span, iter,
|
||||
hir::BindByValue(hir::MutMutable));
|
||||
let iter_pat = self.pat_ident_binding_mode(e.span,
|
||||
iter,
|
||||
hir::BindingAnnotation::Mutable);
|
||||
|
||||
// `match ::std::iter::Iterator::next(&mut iter) { ... }`
|
||||
let match_expr = {
|
||||
@ -2503,10 +2504,13 @@ impl<'a> LoweringContext<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_binding_mode(&mut self, b: &BindingMode) -> hir::BindingMode {
|
||||
fn lower_binding_mode(&mut self, b: &BindingMode) -> hir::BindingAnnotation {
|
||||
match *b {
|
||||
BindingMode::ByRef(m) => hir::BindByRef(self.lower_mutability(m)),
|
||||
BindingMode::ByValue(m) => hir::BindByValue(self.lower_mutability(m)),
|
||||
BindingMode::ByValue(Mutability::Immutable) =>
|
||||
hir::BindingAnnotation::Unannotated,
|
||||
BindingMode::ByRef(Mutability::Immutable) => hir::BindingAnnotation::Ref,
|
||||
BindingMode::ByValue(Mutability::Mutable) => hir::BindingAnnotation::Mutable,
|
||||
BindingMode::ByRef(Mutability::Mutable) => hir::BindingAnnotation::RefMut,
|
||||
}
|
||||
}
|
||||
|
||||
@ -2647,7 +2651,7 @@ impl<'a> LoweringContext<'a> {
|
||||
fn stmt_let(&mut self, sp: Span, mutbl: bool, ident: Name, ex: P<hir::Expr>)
|
||||
-> (hir::Stmt, NodeId) {
|
||||
let pat = if mutbl {
|
||||
self.pat_ident_binding_mode(sp, ident, hir::BindByValue(hir::MutMutable))
|
||||
self.pat_ident_binding_mode(sp, ident, hir::BindingAnnotation::Mutable)
|
||||
} else {
|
||||
self.pat_ident(sp, ident)
|
||||
};
|
||||
@ -2703,10 +2707,10 @@ impl<'a> LoweringContext<'a> {
|
||||
}
|
||||
|
||||
fn pat_ident(&mut self, span: Span, name: Name) -> P<hir::Pat> {
|
||||
self.pat_ident_binding_mode(span, name, hir::BindByValue(hir::MutImmutable))
|
||||
self.pat_ident_binding_mode(span, name, hir::BindingAnnotation::Unannotated)
|
||||
}
|
||||
|
||||
fn pat_ident_binding_mode(&mut self, span: Span, name: Name, bm: hir::BindingMode)
|
||||
fn pat_ident_binding_mode(&mut self, span: Span, name: Name, bm: hir::BindingAnnotation)
|
||||
-> P<hir::Pat> {
|
||||
let id = self.next_id();
|
||||
let parent_def = self.parent_def.unwrap();
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
// The Rust HIR.
|
||||
|
||||
pub use self::BindingMode::*;
|
||||
pub use self::BinOp_::*;
|
||||
pub use self::BlockCheckMode::*;
|
||||
pub use self::CaptureClause::*;
|
||||
@ -628,10 +627,28 @@ pub struct FieldPat {
|
||||
pub is_shorthand: bool,
|
||||
}
|
||||
|
||||
/// 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, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
|
||||
pub enum BindingMode {
|
||||
BindByRef(Mutability),
|
||||
BindByValue(Mutability),
|
||||
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,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||
@ -647,7 +664,7 @@ pub enum PatKind {
|
||||
|
||||
/// A fresh binding `ref mut binding @ OPT_SUBPATTERN`.
|
||||
/// The `DefId` is for the definition of the variable being bound.
|
||||
Binding(BindingMode, DefId, Spanned<Name>, Option<P<Pat>>),
|
||||
Binding(BindingAnnotation, DefId, Spanned<Name>, Option<P<Pat>>),
|
||||
|
||||
/// A struct or struct variant pattern, e.g. `Variant {x, y, ..}`.
|
||||
/// The `bool` is `true` in the presence of a `..`.
|
||||
|
@ -87,7 +87,7 @@ impl hir::Pat {
|
||||
/// Call `f` on every "binding" in a pattern, e.g., on `a` in
|
||||
/// `match foo() { Some(a) => (), None => () }`
|
||||
pub fn each_binding<F>(&self, mut f: F)
|
||||
where F: FnMut(hir::BindingMode, ast::NodeId, Span, &Spanned<ast::Name>),
|
||||
where F: FnMut(hir::BindingAnnotation, ast::NodeId, Span, &Spanned<ast::Name>),
|
||||
{
|
||||
self.walk(|p| {
|
||||
if let PatKind::Binding(binding_mode, _, ref pth, _) = p.node {
|
||||
@ -130,12 +130,10 @@ impl hir::Pat {
|
||||
|
||||
pub fn simple_name(&self) -> Option<ast::Name> {
|
||||
match self.node {
|
||||
PatKind::Binding(hir::BindByValue(..), _, ref path1, None) => {
|
||||
Some(path1.node)
|
||||
}
|
||||
_ => {
|
||||
None
|
||||
}
|
||||
PatKind::Binding(hir::BindingAnnotation::Unannotated, _, ref path1, None) |
|
||||
PatKind::Binding(hir::BindingAnnotation::Mutable, _, ref path1, None) =>
|
||||
Some(path1.node),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,16 +161,22 @@ impl hir::Pat {
|
||||
}
|
||||
|
||||
/// Checks if the pattern contains any `ref` or `ref mut` bindings,
|
||||
/// and if yes whether its containing mutable ones or just immutables ones.
|
||||
pub fn contains_ref_binding(&self) -> Option<hir::Mutability> {
|
||||
/// and if yes whether it contains mutable or just immutables ones.
|
||||
///
|
||||
/// FIXME(tschottdorf): this is problematic as the HIR is being scraped,
|
||||
/// but ref bindings may be implicit after #42640.
|
||||
pub fn contains_explicit_ref_binding(&self) -> Option<hir::Mutability> {
|
||||
let mut result = None;
|
||||
self.each_binding(|mode, _, _, _| {
|
||||
if let hir::BindingMode::BindByRef(m) = mode {
|
||||
// Pick Mutable as maximum
|
||||
match result {
|
||||
None | Some(hir::MutImmutable) => result = Some(m),
|
||||
_ => (),
|
||||
self.each_binding(|annotation, _, _, _| {
|
||||
match annotation {
|
||||
hir::BindingAnnotation::Ref => {
|
||||
match result {
|
||||
None | Some(hir::MutImmutable) => result = Some(hir::MutImmutable),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
hir::BindingAnnotation::RefMut => result = Some(hir::MutMutable),
|
||||
_ => (),
|
||||
}
|
||||
});
|
||||
result
|
||||
@ -182,9 +186,11 @@ impl hir::Pat {
|
||||
impl hir::Arm {
|
||||
/// Checks if the patterns for this arm contain any `ref` or `ref mut`
|
||||
/// bindings, and if yes whether its containing mutable ones or just immutables ones.
|
||||
pub fn contains_ref_binding(&self) -> Option<hir::Mutability> {
|
||||
pub fn contains_explicit_ref_binding(&self) -> Option<hir::Mutability> {
|
||||
// FIXME(tschottdorf): contains_explicit_ref_binding() must be removed
|
||||
// for #42640.
|
||||
self.pats.iter()
|
||||
.filter_map(|pat| pat.contains_ref_binding())
|
||||
.filter_map(|pat| pat.contains_explicit_ref_binding())
|
||||
.max_by_key(|m| match *m {
|
||||
hir::MutMutable => 1,
|
||||
hir::MutImmutable => 0,
|
||||
|
@ -1651,12 +1651,16 @@ impl<'a> State<'a> {
|
||||
PatKind::Wild => self.s.word("_")?,
|
||||
PatKind::Binding(binding_mode, _, ref path1, ref sub) => {
|
||||
match binding_mode {
|
||||
hir::BindByRef(mutbl) => {
|
||||
hir::BindingAnnotation::Ref => {
|
||||
self.word_nbsp("ref")?;
|
||||
self.print_mutability(mutbl)?;
|
||||
self.print_mutability(hir::MutImmutable)?;
|
||||
}
|
||||
hir::BindByValue(hir::MutImmutable) => {}
|
||||
hir::BindByValue(hir::MutMutable) => {
|
||||
hir::BindingAnnotation::RefMut => {
|
||||
self.word_nbsp("ref")?;
|
||||
self.print_mutability(hir::MutMutable)?;
|
||||
}
|
||||
hir::BindingAnnotation::Unannotated => {}
|
||||
hir::BindingAnnotation::Mutable => {
|
||||
self.word_nbsp("mut")?;
|
||||
}
|
||||
}
|
||||
|
@ -442,9 +442,11 @@ impl_stable_hash_for!(struct hir::FieldPat {
|
||||
is_shorthand
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(enum hir::BindingMode {
|
||||
BindByRef(mutability),
|
||||
BindByValue(mutability)
|
||||
impl_stable_hash_for!(enum hir::BindingAnnotation {
|
||||
Unannotated,
|
||||
Mutable,
|
||||
Ref,
|
||||
RefMut
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(enum hir::RangeEnd {
|
||||
|
@ -617,6 +617,7 @@ for ty::TypeckTables<'tcx> {
|
||||
ref node_types,
|
||||
ref node_substs,
|
||||
ref adjustments,
|
||||
ref pat_binding_modes,
|
||||
ref upvar_capture_map,
|
||||
ref closure_tys,
|
||||
ref closure_kinds,
|
||||
@ -637,6 +638,7 @@ for ty::TypeckTables<'tcx> {
|
||||
ich::hash_stable_nodemap(hcx, hasher, node_types);
|
||||
ich::hash_stable_nodemap(hcx, hasher, node_substs);
|
||||
ich::hash_stable_nodemap(hcx, hasher, adjustments);
|
||||
ich::hash_stable_nodemap(hcx, hasher, pat_binding_modes);
|
||||
ich::hash_stable_hashmap(hcx, hasher, upvar_capture_map, |hcx, up_var_id| {
|
||||
let ty::UpvarId {
|
||||
var_id,
|
||||
|
@ -796,16 +796,19 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||
debug!("determine_pat_move_mode cmt_discr={:?} pat={:?}", cmt_discr,
|
||||
pat);
|
||||
return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |cmt_pat, pat| {
|
||||
match pat.node {
|
||||
PatKind::Binding(hir::BindByRef(..), ..) =>
|
||||
mode.lub(BorrowingMatch),
|
||||
PatKind::Binding(hir::BindByValue(..), ..) => {
|
||||
match copy_or_move(&self.mc, self.param_env, &cmt_pat, PatBindingMove) {
|
||||
Copy => mode.lub(CopyingMatch),
|
||||
Move(..) => mode.lub(MovingMatch),
|
||||
if let PatKind::Binding(..) = pat.node {
|
||||
let bm = *self.mc.tables.pat_binding_modes.get(&pat.id)
|
||||
.expect("missing binding mode");
|
||||
match bm {
|
||||
ty::BindByReference(..) =>
|
||||
mode.lub(BorrowingMatch),
|
||||
ty::BindByValue(..) => {
|
||||
match copy_or_move(&self.mc, self.param_env, &cmt_pat, PatBindingMove) {
|
||||
Copy => mode.lub(CopyingMatch),
|
||||
Move(..) => mode.lub(MovingMatch),
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}));
|
||||
}
|
||||
@ -818,8 +821,9 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||
|
||||
let ExprUseVisitor { ref mc, ref mut delegate, param_env } = *self;
|
||||
return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |cmt_pat, pat| {
|
||||
if let PatKind::Binding(bmode, def_id, ..) = pat.node {
|
||||
if let PatKind::Binding(_, def_id, ..) = pat.node {
|
||||
debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}", cmt_pat, pat, match_mode);
|
||||
let bm = *mc.tables.pat_binding_modes.get(&pat.id).expect("missing binding mode");
|
||||
|
||||
// pat_ty: the type of the binding being produced.
|
||||
let pat_ty = return_if_err!(mc.node_ty(pat.id));
|
||||
@ -832,14 +836,14 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
// It is also a borrow or copy/move of the value being matched.
|
||||
match bmode {
|
||||
hir::BindByRef(m) => {
|
||||
match bm {
|
||||
ty::BindByReference(m) => {
|
||||
if let ty::TyRef(r, _) = pat_ty.sty {
|
||||
let bk = ty::BorrowKind::from_mutbl(m);
|
||||
delegate.borrow(pat.id, pat.span, cmt_pat, r, bk, RefBinding);
|
||||
}
|
||||
}
|
||||
hir::BindByValue(..) => {
|
||||
ty::BindByValue(..) => {
|
||||
let mode = copy_or_move(mc, param_env, &cmt_pat, PatBindingMove);
|
||||
debug!("walk_pat binding consuming pat");
|
||||
delegate.consume_pat(pat, cmt_pat, mode);
|
||||
|
@ -330,11 +330,12 @@ impl MutabilityCategory {
|
||||
ret
|
||||
}
|
||||
|
||||
fn from_local(tcx: TyCtxt, id: ast::NodeId) -> MutabilityCategory {
|
||||
fn from_local(tcx: TyCtxt, tables: &ty::TypeckTables, id: ast::NodeId) -> MutabilityCategory {
|
||||
let ret = match tcx.hir.get(id) {
|
||||
hir_map::NodeLocal(p) => match p.node {
|
||||
PatKind::Binding(bind_mode, ..) => {
|
||||
if bind_mode == hir::BindByValue(hir::MutMutable) {
|
||||
PatKind::Binding(..) => {
|
||||
let bm = *tables.pat_binding_modes.get(&p.id).expect("missing binding mode");
|
||||
if bm == ty::BindByValue(hir::MutMutable) {
|
||||
McDeclared
|
||||
} else {
|
||||
McImmutable
|
||||
@ -475,16 +476,21 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||
// *being borrowed* is. But ideally we would put in a more
|
||||
// fundamental fix to this conflated use of the node id.
|
||||
let ret_ty = match pat.node {
|
||||
PatKind::Binding(hir::BindByRef(_), ..) => {
|
||||
// a bind-by-ref means that the base_ty will be the type of the ident itself,
|
||||
// but what we want here is the type of the underlying value being borrowed.
|
||||
// So peel off one-level, turning the &T into T.
|
||||
match base_ty.builtin_deref(false, ty::NoPreference) {
|
||||
Some(t) => t.ty,
|
||||
None => {
|
||||
debug!("By-ref binding of non-derefable type {:?}", base_ty);
|
||||
return Err(());
|
||||
PatKind::Binding(..) => {
|
||||
let bm = *self.tables.pat_binding_modes.get(&pat.id).expect("missing binding mode");
|
||||
if let ty::BindByReference(_) = bm {
|
||||
// a bind-by-ref means that the base_ty will be the type of the ident itself,
|
||||
// but what we want here is the type of the underlying value being borrowed.
|
||||
// So peel off one-level, turning the &T into T.
|
||||
match base_ty.builtin_deref(false, ty::NoPreference) {
|
||||
Some(t) => t.ty,
|
||||
None => {
|
||||
debug!("By-ref binding of non-derefable type {:?}", base_ty);
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
base_ty
|
||||
}
|
||||
}
|
||||
_ => base_ty,
|
||||
@ -659,7 +665,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||
id,
|
||||
span,
|
||||
cat: Categorization::Local(vid),
|
||||
mutbl: MutabilityCategory::from_local(self.tcx, vid),
|
||||
mutbl: MutabilityCategory::from_local(self.tcx, self.tables, vid),
|
||||
ty: expr_ty,
|
||||
note: NoteNone
|
||||
}))
|
||||
@ -711,7 +717,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||
let var_ty = self.node_ty(var_id)?;
|
||||
|
||||
// Mutability of original variable itself
|
||||
let var_mutbl = MutabilityCategory::from_local(self.tcx, var_id);
|
||||
let var_mutbl = MutabilityCategory::from_local(self.tcx, self.tables, var_id);
|
||||
|
||||
// Construct the upvar. This represents access to the field
|
||||
// from the environment (perhaps we should eventually desugar
|
||||
|
@ -889,8 +889,32 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
|
||||
/// | ( ..., P&, ... )
|
||||
/// | box P&
|
||||
fn is_binding_pat(pat: &hir::Pat) -> bool {
|
||||
// Note that the code below looks for *explicit* refs only, that is, it won't
|
||||
// know about *implicit* refs as introduced in #42640.
|
||||
//
|
||||
// This is not a problem. For example, consider
|
||||
//
|
||||
// let (ref x, ref y) = (Foo { .. }, Bar { .. });
|
||||
//
|
||||
// Due to the explicit refs on the left hand side, the below code would signal
|
||||
// that the temporary value on the right hand side should live until the end of
|
||||
// the enclosing block (as opposed to being dropped after the let is complete).
|
||||
//
|
||||
// To create an implicit ref, however, you must have a borrowed value on the RHS
|
||||
// already, as in this example (which won't compile before #42640):
|
||||
//
|
||||
// let Foo { x, .. } = &Foo { x: ..., ... };
|
||||
//
|
||||
// in place of
|
||||
//
|
||||
// let Foo { ref x, .. } = Foo { ... };
|
||||
//
|
||||
// In the former case (the implicit ref version), the temporary is created by the
|
||||
// & expression, and its lifetime would be extended to the end of the block (due
|
||||
// to a different rule, not the below code).
|
||||
match pat.node {
|
||||
PatKind::Binding(hir::BindByRef(_), ..) => true,
|
||||
PatKind::Binding(hir::BindingAnnotation::Ref, ..) |
|
||||
PatKind::Binding(hir::BindingAnnotation::RefMut, ..) => true,
|
||||
|
||||
PatKind::Struct(_, ref field_pats, _) => {
|
||||
field_pats.iter().any(|fp| is_binding_pat(&fp.node.pat))
|
||||
|
35
src/librustc/ty/binding.rs
Normal file
35
src/librustc/ty/binding.rs
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use hir::BindingAnnotation::*;
|
||||
use hir::BindingAnnotation;
|
||||
use hir::Mutability;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
|
||||
pub enum BindingMode {
|
||||
BindByReference(Mutability),
|
||||
BindByValue(Mutability),
|
||||
}
|
||||
|
||||
impl BindingMode {
|
||||
pub fn convert(ba: BindingAnnotation) -> BindingMode {
|
||||
match ba {
|
||||
Unannotated => BindingMode::BindByValue(Mutability::MutImmutable),
|
||||
Mutable => BindingMode::BindByValue(Mutability::MutMutable),
|
||||
Ref => BindingMode::BindByReference(Mutability::MutImmutable),
|
||||
RefMut => BindingMode::BindByReference(Mutability::MutMutable),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_stable_hash_for!(enum self::BindingMode {
|
||||
BindByReference(mutability),
|
||||
BindByValue(mutability)
|
||||
});
|
@ -40,6 +40,7 @@ use ty::layout::{Layout, TargetDataLayout};
|
||||
use ty::inhabitedness::DefIdForest;
|
||||
use ty::maps;
|
||||
use ty::steal::Steal;
|
||||
use ty::BindingMode;
|
||||
use util::nodemap::{NodeMap, NodeSet, DefIdSet};
|
||||
use util::nodemap::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::accumulate_vec::AccumulateVec;
|
||||
@ -223,6 +224,9 @@ pub struct TypeckTables<'tcx> {
|
||||
|
||||
pub adjustments: NodeMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
|
||||
|
||||
// Stores the actual binding mode for all instances of hir::BindingAnnotation.
|
||||
pub pat_binding_modes: NodeMap<BindingMode>,
|
||||
|
||||
/// Borrows
|
||||
pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>,
|
||||
|
||||
@ -274,6 +278,7 @@ impl<'tcx> TypeckTables<'tcx> {
|
||||
node_types: FxHashMap(),
|
||||
node_substs: NodeMap(),
|
||||
adjustments: NodeMap(),
|
||||
pat_binding_modes: NodeMap(),
|
||||
upvar_capture_map: FxHashMap(),
|
||||
closure_tys: NodeMap(),
|
||||
closure_kinds: NodeMap(),
|
||||
|
@ -74,6 +74,9 @@ pub use self::sty::InferTy::*;
|
||||
pub use self::sty::RegionKind::*;
|
||||
pub use self::sty::TypeVariants::*;
|
||||
|
||||
pub use self::binding::BindingMode;
|
||||
pub use self::binding::BindingMode::*;
|
||||
|
||||
pub use self::context::{TyCtxt, GlobalArenas, tls};
|
||||
pub use self::context::{Lift, TypeckTables};
|
||||
|
||||
@ -84,6 +87,7 @@ pub use self::trait_def::TraitDef;
|
||||
pub use self::maps::queries;
|
||||
|
||||
pub mod adjustment;
|
||||
pub mod binding;
|
||||
pub mod cast;
|
||||
pub mod error;
|
||||
pub mod fast_reject;
|
||||
|
@ -871,14 +871,15 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn local_binding_mode(&self, node_id: ast::NodeId) -> hir::BindingMode {
|
||||
fn local_binding_mode(&self, node_id: ast::NodeId) -> ty::BindingMode {
|
||||
let pat = match self.tcx.hir.get(node_id) {
|
||||
hir_map::Node::NodeLocal(pat) => pat,
|
||||
node => bug!("bad node for local: {:?}", node)
|
||||
};
|
||||
|
||||
match pat.node {
|
||||
hir::PatKind::Binding(mode, ..) => mode,
|
||||
hir::PatKind::Binding(..) =>
|
||||
*self.tables.pat_binding_modes.get(&pat.id).expect("missing binding mode"),
|
||||
_ => bug!("local is not a binding: {:?}", pat)
|
||||
}
|
||||
}
|
||||
@ -913,7 +914,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
Some(ImmutabilityBlame::ClosureEnv(_)) => {}
|
||||
Some(ImmutabilityBlame::ImmLocal(node_id)) => {
|
||||
let let_span = self.tcx.hir.span(node_id);
|
||||
if let hir::BindingMode::BindByValue(..) = self.local_binding_mode(node_id) {
|
||||
if let ty::BindByValue(..) = self.local_binding_mode(node_id) {
|
||||
if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) {
|
||||
let (_, is_implicit_self) = self.local_ty(node_id);
|
||||
if is_implicit_self && snippet != "self" {
|
||||
@ -930,7 +931,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
Some(ImmutabilityBlame::LocalDeref(node_id)) => {
|
||||
let let_span = self.tcx.hir.span(node_id);
|
||||
match self.local_binding_mode(node_id) {
|
||||
hir::BindingMode::BindByRef(..) => {
|
||||
ty::BindByReference(..) => {
|
||||
let snippet = self.tcx.sess.codemap().span_to_snippet(let_span);
|
||||
if let Ok(snippet) = snippet {
|
||||
db.span_label(
|
||||
@ -940,7 +941,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
);
|
||||
}
|
||||
}
|
||||
hir::BindingMode::BindByValue(..) => {
|
||||
ty::BindByValue(..) => {
|
||||
if let (Some(local_ty), is_implicit_self) = self.local_ty(node_id) {
|
||||
if let Some(msg) =
|
||||
self.suggest_mut_for_immutable(local_ty, is_implicit_self) {
|
||||
|
@ -268,7 +268,12 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
|
||||
|
||||
fn check_for_bindings_named_the_same_as_variants(cx: &MatchVisitor, pat: &Pat) {
|
||||
pat.walk(|p| {
|
||||
if let PatKind::Binding(hir::BindByValue(hir::MutImmutable), _, name, None) = p.node {
|
||||
if let PatKind::Binding(_, _, name, None) = p.node {
|
||||
let bm = *cx.tables.pat_binding_modes.get(&p.id).expect("missing binding mode");
|
||||
if bm != ty::BindByValue(hir::MutImmutable) {
|
||||
// Nothing to check.
|
||||
return true;
|
||||
}
|
||||
let pat_ty = cx.tables.pat_ty(p);
|
||||
if let ty::TyAdt(edef, _) = pat_ty.sty {
|
||||
if edef.is_enum() && edef.variants.iter().any(|variant| {
|
||||
@ -452,8 +457,9 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
|
||||
pats: &[P<Pat>]) {
|
||||
let mut by_ref_span = None;
|
||||
for pat in pats {
|
||||
pat.each_binding(|bm, _, span, _path| {
|
||||
if let hir::BindByRef(..) = bm {
|
||||
pat.each_binding(|_, id, span, _path| {
|
||||
let bm = *cx.tables.pat_binding_modes.get(&id).expect("missing binding mode");
|
||||
if let ty::BindByReference(..) = bm {
|
||||
by_ref_span = Some(span);
|
||||
}
|
||||
})
|
||||
@ -484,10 +490,16 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
|
||||
|
||||
for pat in pats {
|
||||
pat.walk(|p| {
|
||||
if let PatKind::Binding(hir::BindByValue(..), _, _, ref sub) = p.node {
|
||||
let pat_ty = cx.tables.node_id_to_type(p.id);
|
||||
if pat_ty.moves_by_default(cx.tcx, cx.param_env, pat.span) {
|
||||
check_move(p, sub.as_ref().map(|p| &**p));
|
||||
if let PatKind::Binding(_, _, _, ref sub) = p.node {
|
||||
let bm = *cx.tables.pat_binding_modes.get(&p.id).expect("missing binding mode");
|
||||
match bm {
|
||||
ty::BindByValue(..) => {
|
||||
let pat_ty = cx.tables.node_id_to_type(p.id);
|
||||
if pat_ty.moves_by_default(cx.tcx, cx.param_env, pat.span) {
|
||||
check_move(p, sub.as_ref().map(|p| &**p));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
true
|
||||
|
@ -374,27 +374,31 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
PatKind::Binding(bm, def_id, ref ident, ref sub) => {
|
||||
PatKind::Binding(_, def_id, ref ident, ref sub) => {
|
||||
let id = self.tcx.hir.as_local_node_id(def_id).unwrap();
|
||||
let var_ty = self.tables.node_id_to_type(pat.id);
|
||||
let region = match var_ty.sty {
|
||||
ty::TyRef(r, _) => Some(r),
|
||||
_ => None,
|
||||
};
|
||||
let bm = *self.tables.pat_binding_modes.get(&pat.id)
|
||||
.expect("missing binding mode");
|
||||
let (mutability, mode) = match bm {
|
||||
hir::BindByValue(hir::MutMutable) =>
|
||||
ty::BindByValue(hir::MutMutable) =>
|
||||
(Mutability::Mut, BindingMode::ByValue),
|
||||
hir::BindByValue(hir::MutImmutable) =>
|
||||
ty::BindByValue(hir::MutImmutable) =>
|
||||
(Mutability::Not, BindingMode::ByValue),
|
||||
hir::BindByRef(hir::MutMutable) =>
|
||||
(Mutability::Not, BindingMode::ByRef(region.unwrap(), BorrowKind::Mut)),
|
||||
hir::BindByRef(hir::MutImmutable) =>
|
||||
(Mutability::Not, BindingMode::ByRef(region.unwrap(), BorrowKind::Shared)),
|
||||
ty::BindByReference(hir::MutMutable) =>
|
||||
(Mutability::Not, BindingMode::ByRef(
|
||||
region.unwrap(), BorrowKind::Mut)),
|
||||
ty::BindByReference(hir::MutImmutable) =>
|
||||
(Mutability::Not, BindingMode::ByRef(
|
||||
region.unwrap(), BorrowKind::Shared)),
|
||||
};
|
||||
|
||||
// A ref x pattern is the same node used for x, and as such it has
|
||||
// x's type, which is &T, where we want T (the type being matched).
|
||||
if let hir::BindByRef(_) = bm {
|
||||
if let ty::BindByReference(_) = bm {
|
||||
if let ty::TyRef(_, mt) = ty.sty {
|
||||
ty = mt.ty;
|
||||
} else {
|
||||
|
@ -44,9 +44,13 @@ impl UnusedMut {
|
||||
|
||||
let mut mutables = FxHashMap();
|
||||
for p in pats {
|
||||
p.each_binding(|mode, id, _, path1| {
|
||||
p.each_binding(|_, id, span, path1| {
|
||||
let bm = match cx.tables.pat_binding_modes.get(&id) {
|
||||
Some(&bm) => bm,
|
||||
None => span_bug!(span, "missing binding mode"),
|
||||
};
|
||||
let name = path1.node;
|
||||
if let hir::BindByValue(hir::MutMutable) = mode {
|
||||
if let ty::BindByValue(hir::MutMutable) = bm {
|
||||
if !name.as_str().starts_with("_") {
|
||||
match mutables.entry(name) {
|
||||
Vacant(entry) => {
|
||||
|
@ -2277,8 +2277,9 @@ impl<'a> Resolver<'a> {
|
||||
false, pat.span)
|
||||
.and_then(LexicalScopeBinding::item);
|
||||
let resolution = binding.map(NameBinding::def).and_then(|def| {
|
||||
let ivmode = BindingMode::ByValue(Mutability::Immutable);
|
||||
let always_binding = !pat_src.is_refutable() || opt_pat.is_some() ||
|
||||
bmode != BindingMode::ByValue(Mutability::Immutable);
|
||||
bmode != ivmode;
|
||||
match def {
|
||||
Def::StructCtor(_, CtorKind::Const) |
|
||||
Def::VariantCtor(_, CtorKind::Const) |
|
||||
|
@ -113,10 +113,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
self.demand_eqtype(pat.span, expected, rhs_ty);
|
||||
common_type
|
||||
}
|
||||
PatKind::Binding(bm, def_id, _, ref sub) => {
|
||||
PatKind::Binding(ba, def_id, _, ref sub) => {
|
||||
// Note the binding mode in the typeck tables. For now, what we store is always
|
||||
// identical to what could be scraped from the HIR, but this will change with
|
||||
// default binding modes (#42640).
|
||||
let bm = ty::BindingMode::convert(ba);
|
||||
self.inh.tables.borrow_mut().pat_binding_modes.insert(pat.id, bm);
|
||||
|
||||
let typ = self.local_ty(pat.span, pat.id);
|
||||
match bm {
|
||||
hir::BindByRef(mutbl) => {
|
||||
ty::BindByReference(mutbl) => {
|
||||
// if the binding is like
|
||||
// ref x | ref const x | ref mut x
|
||||
// then `x` is assigned a value of type `&M T` where M is the mutability
|
||||
@ -131,7 +137,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
self.demand_eqtype(pat.span, region_ty, typ);
|
||||
}
|
||||
// otherwise the type of x is the expected type T
|
||||
hir::BindByValue(_) => {
|
||||
ty::BindByValue(_) => {
|
||||
// As above, `T <: typeof(x)` is required but we
|
||||
// use equality, see (*) below.
|
||||
self.demand_eqtype(pat.span, expected, typ);
|
||||
@ -396,11 +402,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
match_src: hir::MatchSource) -> Ty<'tcx> {
|
||||
let tcx = self.tcx;
|
||||
|
||||
// Not entirely obvious: if matches may create ref bindings, we
|
||||
// want to use the *precise* type of the discriminant, *not* some
|
||||
// supertype, as the "discriminant type" (issue #23116).
|
||||
// Not entirely obvious: if matches may create ref bindings, we want to
|
||||
// use the *precise* type of the discriminant, *not* some supertype, as
|
||||
// the "discriminant type" (issue #23116).
|
||||
//
|
||||
// FIXME(tschottdorf): don't call contains_explicit_ref_binding, which
|
||||
// is problematic as the HIR is being scraped, but ref bindings may be
|
||||
// implicit after #42640. We need to make sure that pat_adjustments
|
||||
// (once introduced) is populated by the time we get here.
|
||||
let contains_ref_bindings = arms.iter()
|
||||
.filter_map(|a| a.contains_ref_binding())
|
||||
.filter_map(|a| a.contains_explicit_ref_binding())
|
||||
.max_by_key(|m| match *m {
|
||||
hir::MutMutable => 1,
|
||||
hir::MutImmutable => 0,
|
||||
|
@ -3999,7 +3999,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
local: &'gcx hir::Local,
|
||||
init: &'gcx hir::Expr) -> Ty<'tcx>
|
||||
{
|
||||
let ref_bindings = local.pat.contains_ref_binding();
|
||||
// FIXME(tschottdorf): contains_explicit_ref_binding() must be removed
|
||||
// for #42640.
|
||||
let ref_bindings = local.pat.contains_explicit_ref_binding();
|
||||
|
||||
let local_ty = self.local_ty(init.span, local.id);
|
||||
if let Some(m) = ref_bindings {
|
||||
|
@ -1196,9 +1196,13 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
||||
mc.cat_pattern(discr_cmt, root_pat, |sub_cmt, sub_pat| {
|
||||
match sub_pat.node {
|
||||
// `ref x` pattern
|
||||
PatKind::Binding(hir::BindByRef(mutbl), ..) => {
|
||||
self.link_region_from_node_type(sub_pat.span, sub_pat.id,
|
||||
mutbl, sub_cmt);
|
||||
PatKind::Binding(..) => {
|
||||
let bm = *mc.tables.pat_binding_modes.get(&sub_pat.id)
|
||||
.expect("missing binding mode");
|
||||
if let ty::BindByReference(mutbl) = bm {
|
||||
self.link_region_from_node_type(sub_pat.span, sub_pat.id,
|
||||
mutbl, sub_cmt);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -178,6 +178,15 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
fn visit_pat(&mut self, p: &'gcx hir::Pat) {
|
||||
match p.node {
|
||||
hir::PatKind::Binding(..) => {
|
||||
let bm = *self.fcx.tables.borrow().pat_binding_modes.get(&p.id)
|
||||
.expect("missing binding mode");
|
||||
self.tables.pat_binding_modes.insert(p.id, bm);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
self.visit_node_id(p.span, p.id);
|
||||
intravisit::walk_pat(self, p);
|
||||
}
|
||||
|
@ -867,13 +867,14 @@ mod tests {
|
||||
pat: P(ast::Pat {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
node: PatKind::Ident(
|
||||
ast::BindingMode::ByValue(ast::Mutability::Immutable),
|
||||
Spanned{
|
||||
span: sp(6,7),
|
||||
node: Ident::from_str("b")},
|
||||
None
|
||||
),
|
||||
span: sp(6,7)
|
||||
ast::BindingMode::ByValue(
|
||||
ast::Mutability::Immutable),
|
||||
Spanned{
|
||||
span: sp(6,7),
|
||||
node: Ident::from_str("b")},
|
||||
None
|
||||
),
|
||||
span: sp(6,7)
|
||||
}),
|
||||
id: ast::DUMMY_NODE_ID
|
||||
}],
|
||||
|
Loading…
x
Reference in New Issue
Block a user