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
22 changed files with 268 additions and 106 deletions
|
@ -2191,7 +2191,7 @@ impl<'a> LoweringContext<'a> {
|
||||||
let next_ident = self.str_to_ident("__next");
|
let next_ident = self.str_to_ident("__next");
|
||||||
let next_pat = self.pat_ident_binding_mode(e.span,
|
let next_pat = self.pat_ident_binding_mode(e.span,
|
||||||
next_ident,
|
next_ident,
|
||||||
hir::BindByValue(hir::MutMutable));
|
hir::BindingAnnotation::Mutable);
|
||||||
|
|
||||||
// `::std::option::Option::Some(val) => next = val`
|
// `::std::option::Option::Some(val) => next = val`
|
||||||
let pat_arm = {
|
let pat_arm = {
|
||||||
|
@ -2215,8 +2215,9 @@ impl<'a> LoweringContext<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// `mut iter`
|
// `mut iter`
|
||||||
let iter_pat = self.pat_ident_binding_mode(e.span, iter,
|
let iter_pat = self.pat_ident_binding_mode(e.span,
|
||||||
hir::BindByValue(hir::MutMutable));
|
iter,
|
||||||
|
hir::BindingAnnotation::Mutable);
|
||||||
|
|
||||||
// `match ::std::iter::Iterator::next(&mut iter) { ... }`
|
// `match ::std::iter::Iterator::next(&mut iter) { ... }`
|
||||||
let match_expr = {
|
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 {
|
match *b {
|
||||||
BindingMode::ByRef(m) => hir::BindByRef(self.lower_mutability(m)),
|
BindingMode::ByValue(Mutability::Immutable) =>
|
||||||
BindingMode::ByValue(m) => hir::BindByValue(self.lower_mutability(m)),
|
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>)
|
fn stmt_let(&mut self, sp: Span, mutbl: bool, ident: Name, ex: P<hir::Expr>)
|
||||||
-> (hir::Stmt, NodeId) {
|
-> (hir::Stmt, NodeId) {
|
||||||
let pat = if mutbl {
|
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 {
|
} else {
|
||||||
self.pat_ident(sp, ident)
|
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> {
|
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> {
|
-> P<hir::Pat> {
|
||||||
let id = self.next_id();
|
let id = self.next_id();
|
||||||
let parent_def = self.parent_def.unwrap();
|
let parent_def = self.parent_def.unwrap();
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
|
|
||||||
// The Rust HIR.
|
// The Rust HIR.
|
||||||
|
|
||||||
pub use self::BindingMode::*;
|
|
||||||
pub use self::BinOp_::*;
|
pub use self::BinOp_::*;
|
||||||
pub use self::BlockCheckMode::*;
|
pub use self::BlockCheckMode::*;
|
||||||
pub use self::CaptureClause::*;
|
pub use self::CaptureClause::*;
|
||||||
|
@ -628,10 +627,28 @@ pub struct FieldPat {
|
||||||
pub is_shorthand: bool,
|
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)]
|
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
|
||||||
pub enum BindingMode {
|
pub enum BindingAnnotation {
|
||||||
BindByRef(Mutability),
|
/// No binding annotation given: this means that the final binding mode
|
||||||
BindByValue(Mutability),
|
/// 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)]
|
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||||
|
@ -647,7 +664,7 @@ pub enum PatKind {
|
||||||
|
|
||||||
/// A fresh binding `ref mut binding @ OPT_SUBPATTERN`.
|
/// A fresh binding `ref mut binding @ OPT_SUBPATTERN`.
|
||||||
/// The `DefId` is for the definition of the variable being bound.
|
/// 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, ..}`.
|
/// A struct or struct variant pattern, e.g. `Variant {x, y, ..}`.
|
||||||
/// The `bool` is `true` in the presence of a `..`.
|
/// 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
|
/// Call `f` on every "binding" in a pattern, e.g., on `a` in
|
||||||
/// `match foo() { Some(a) => (), None => () }`
|
/// `match foo() { Some(a) => (), None => () }`
|
||||||
pub fn each_binding<F>(&self, mut f: F)
|
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| {
|
self.walk(|p| {
|
||||||
if let PatKind::Binding(binding_mode, _, ref pth, _) = p.node {
|
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> {
|
pub fn simple_name(&self) -> Option<ast::Name> {
|
||||||
match self.node {
|
match self.node {
|
||||||
PatKind::Binding(hir::BindByValue(..), _, ref path1, None) => {
|
PatKind::Binding(hir::BindingAnnotation::Unannotated, _, ref path1, None) |
|
||||||
Some(path1.node)
|
PatKind::Binding(hir::BindingAnnotation::Mutable, _, ref path1, None) =>
|
||||||
}
|
Some(path1.node),
|
||||||
_ => {
|
_ => None,
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,17 +161,23 @@ impl hir::Pat {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if the pattern contains any `ref` or `ref mut` bindings,
|
/// Checks if the pattern contains any `ref` or `ref mut` bindings,
|
||||||
/// and if yes whether its containing mutable ones or just immutables ones.
|
/// and if yes whether it contains mutable or just immutables ones.
|
||||||
pub fn contains_ref_binding(&self) -> Option<hir::Mutability> {
|
///
|
||||||
|
/// 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;
|
let mut result = None;
|
||||||
self.each_binding(|mode, _, _, _| {
|
self.each_binding(|annotation, _, _, _| {
|
||||||
if let hir::BindingMode::BindByRef(m) = mode {
|
match annotation {
|
||||||
// Pick Mutable as maximum
|
hir::BindingAnnotation::Ref => {
|
||||||
match result {
|
match result {
|
||||||
None | Some(hir::MutImmutable) => result = Some(m),
|
None | Some(hir::MutImmutable) => result = Some(hir::MutImmutable),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
hir::BindingAnnotation::RefMut => result = Some(hir::MutMutable),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
});
|
});
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
@ -182,9 +186,11 @@ impl hir::Pat {
|
||||||
impl hir::Arm {
|
impl hir::Arm {
|
||||||
/// Checks if the patterns for this arm contain any `ref` or `ref mut`
|
/// 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.
|
/// 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()
|
self.pats.iter()
|
||||||
.filter_map(|pat| pat.contains_ref_binding())
|
.filter_map(|pat| pat.contains_explicit_ref_binding())
|
||||||
.max_by_key(|m| match *m {
|
.max_by_key(|m| match *m {
|
||||||
hir::MutMutable => 1,
|
hir::MutMutable => 1,
|
||||||
hir::MutImmutable => 0,
|
hir::MutImmutable => 0,
|
||||||
|
|
|
@ -1651,12 +1651,16 @@ impl<'a> State<'a> {
|
||||||
PatKind::Wild => self.s.word("_")?,
|
PatKind::Wild => self.s.word("_")?,
|
||||||
PatKind::Binding(binding_mode, _, ref path1, ref sub) => {
|
PatKind::Binding(binding_mode, _, ref path1, ref sub) => {
|
||||||
match binding_mode {
|
match binding_mode {
|
||||||
hir::BindByRef(mutbl) => {
|
hir::BindingAnnotation::Ref => {
|
||||||
self.word_nbsp("ref")?;
|
self.word_nbsp("ref")?;
|
||||||
self.print_mutability(mutbl)?;
|
self.print_mutability(hir::MutImmutable)?;
|
||||||
}
|
}
|
||||||
hir::BindByValue(hir::MutImmutable) => {}
|
hir::BindingAnnotation::RefMut => {
|
||||||
hir::BindByValue(hir::MutMutable) => {
|
self.word_nbsp("ref")?;
|
||||||
|
self.print_mutability(hir::MutMutable)?;
|
||||||
|
}
|
||||||
|
hir::BindingAnnotation::Unannotated => {}
|
||||||
|
hir::BindingAnnotation::Mutable => {
|
||||||
self.word_nbsp("mut")?;
|
self.word_nbsp("mut")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -442,9 +442,11 @@ impl_stable_hash_for!(struct hir::FieldPat {
|
||||||
is_shorthand
|
is_shorthand
|
||||||
});
|
});
|
||||||
|
|
||||||
impl_stable_hash_for!(enum hir::BindingMode {
|
impl_stable_hash_for!(enum hir::BindingAnnotation {
|
||||||
BindByRef(mutability),
|
Unannotated,
|
||||||
BindByValue(mutability)
|
Mutable,
|
||||||
|
Ref,
|
||||||
|
RefMut
|
||||||
});
|
});
|
||||||
|
|
||||||
impl_stable_hash_for!(enum hir::RangeEnd {
|
impl_stable_hash_for!(enum hir::RangeEnd {
|
||||||
|
|
|
@ -617,6 +617,7 @@ for ty::TypeckTables<'tcx> {
|
||||||
ref node_types,
|
ref node_types,
|
||||||
ref node_substs,
|
ref node_substs,
|
||||||
ref adjustments,
|
ref adjustments,
|
||||||
|
ref pat_binding_modes,
|
||||||
ref upvar_capture_map,
|
ref upvar_capture_map,
|
||||||
ref closure_tys,
|
ref closure_tys,
|
||||||
ref closure_kinds,
|
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_types);
|
||||||
ich::hash_stable_nodemap(hcx, hasher, node_substs);
|
ich::hash_stable_nodemap(hcx, hasher, node_substs);
|
||||||
ich::hash_stable_nodemap(hcx, hasher, adjustments);
|
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| {
|
ich::hash_stable_hashmap(hcx, hasher, upvar_capture_map, |hcx, up_var_id| {
|
||||||
let ty::UpvarId {
|
let ty::UpvarId {
|
||||||
var_id,
|
var_id,
|
||||||
|
|
|
@ -796,16 +796,19 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||||
debug!("determine_pat_move_mode cmt_discr={:?} pat={:?}", cmt_discr,
|
debug!("determine_pat_move_mode cmt_discr={:?} pat={:?}", cmt_discr,
|
||||||
pat);
|
pat);
|
||||||
return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |cmt_pat, pat| {
|
return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |cmt_pat, pat| {
|
||||||
match pat.node {
|
if let PatKind::Binding(..) = pat.node {
|
||||||
PatKind::Binding(hir::BindByRef(..), ..) =>
|
let bm = *self.mc.tables.pat_binding_modes.get(&pat.id)
|
||||||
|
.expect("missing binding mode");
|
||||||
|
match bm {
|
||||||
|
ty::BindByReference(..) =>
|
||||||
mode.lub(BorrowingMatch),
|
mode.lub(BorrowingMatch),
|
||||||
PatKind::Binding(hir::BindByValue(..), ..) => {
|
ty::BindByValue(..) => {
|
||||||
match copy_or_move(&self.mc, self.param_env, &cmt_pat, PatBindingMove) {
|
match copy_or_move(&self.mc, self.param_env, &cmt_pat, PatBindingMove) {
|
||||||
Copy => mode.lub(CopyingMatch),
|
Copy => mode.lub(CopyingMatch),
|
||||||
Move(..) => mode.lub(MovingMatch),
|
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;
|
let ExprUseVisitor { ref mc, ref mut delegate, param_env } = *self;
|
||||||
return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |cmt_pat, pat| {
|
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);
|
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.
|
// pat_ty: the type of the binding being produced.
|
||||||
let pat_ty = return_if_err!(mc.node_ty(pat.id));
|
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.
|
// It is also a borrow or copy/move of the value being matched.
|
||||||
match bmode {
|
match bm {
|
||||||
hir::BindByRef(m) => {
|
ty::BindByReference(m) => {
|
||||||
if let ty::TyRef(r, _) = pat_ty.sty {
|
if let ty::TyRef(r, _) = pat_ty.sty {
|
||||||
let bk = ty::BorrowKind::from_mutbl(m);
|
let bk = ty::BorrowKind::from_mutbl(m);
|
||||||
delegate.borrow(pat.id, pat.span, cmt_pat, r, bk, RefBinding);
|
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);
|
let mode = copy_or_move(mc, param_env, &cmt_pat, PatBindingMove);
|
||||||
debug!("walk_pat binding consuming pat");
|
debug!("walk_pat binding consuming pat");
|
||||||
delegate.consume_pat(pat, cmt_pat, mode);
|
delegate.consume_pat(pat, cmt_pat, mode);
|
||||||
|
|
|
@ -330,11 +330,12 @@ impl MutabilityCategory {
|
||||||
ret
|
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) {
|
let ret = match tcx.hir.get(id) {
|
||||||
hir_map::NodeLocal(p) => match p.node {
|
hir_map::NodeLocal(p) => match p.node {
|
||||||
PatKind::Binding(bind_mode, ..) => {
|
PatKind::Binding(..) => {
|
||||||
if bind_mode == hir::BindByValue(hir::MutMutable) {
|
let bm = *tables.pat_binding_modes.get(&p.id).expect("missing binding mode");
|
||||||
|
if bm == ty::BindByValue(hir::MutMutable) {
|
||||||
McDeclared
|
McDeclared
|
||||||
} else {
|
} else {
|
||||||
McImmutable
|
McImmutable
|
||||||
|
@ -475,7 +476,9 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
// *being borrowed* is. But ideally we would put in a more
|
// *being borrowed* is. But ideally we would put in a more
|
||||||
// fundamental fix to this conflated use of the node id.
|
// fundamental fix to this conflated use of the node id.
|
||||||
let ret_ty = match pat.node {
|
let ret_ty = match pat.node {
|
||||||
PatKind::Binding(hir::BindByRef(_), ..) => {
|
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,
|
// 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.
|
// but what we want here is the type of the underlying value being borrowed.
|
||||||
// So peel off one-level, turning the &T into T.
|
// So peel off one-level, turning the &T into T.
|
||||||
|
@ -486,6 +489,9 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
base_ty
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => base_ty,
|
_ => base_ty,
|
||||||
};
|
};
|
||||||
|
@ -659,7 +665,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
id,
|
id,
|
||||||
span,
|
span,
|
||||||
cat: Categorization::Local(vid),
|
cat: Categorization::Local(vid),
|
||||||
mutbl: MutabilityCategory::from_local(self.tcx, vid),
|
mutbl: MutabilityCategory::from_local(self.tcx, self.tables, vid),
|
||||||
ty: expr_ty,
|
ty: expr_ty,
|
||||||
note: NoteNone
|
note: NoteNone
|
||||||
}))
|
}))
|
||||||
|
@ -711,7 +717,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
let var_ty = self.node_ty(var_id)?;
|
let var_ty = self.node_ty(var_id)?;
|
||||||
|
|
||||||
// Mutability of original variable itself
|
// 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
|
// Construct the upvar. This represents access to the field
|
||||||
// from the environment (perhaps we should eventually desugar
|
// from the environment (perhaps we should eventually desugar
|
||||||
|
|
|
@ -889,8 +889,32 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
|
||||||
/// | ( ..., P&, ... )
|
/// | ( ..., P&, ... )
|
||||||
/// | box P&
|
/// | box P&
|
||||||
fn is_binding_pat(pat: &hir::Pat) -> bool {
|
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 {
|
match pat.node {
|
||||||
PatKind::Binding(hir::BindByRef(_), ..) => true,
|
PatKind::Binding(hir::BindingAnnotation::Ref, ..) |
|
||||||
|
PatKind::Binding(hir::BindingAnnotation::RefMut, ..) => true,
|
||||||
|
|
||||||
PatKind::Struct(_, ref field_pats, _) => {
|
PatKind::Struct(_, ref field_pats, _) => {
|
||||||
field_pats.iter().any(|fp| is_binding_pat(&fp.node.pat))
|
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::inhabitedness::DefIdForest;
|
||||||
use ty::maps;
|
use ty::maps;
|
||||||
use ty::steal::Steal;
|
use ty::steal::Steal;
|
||||||
|
use ty::BindingMode;
|
||||||
use util::nodemap::{NodeMap, NodeSet, DefIdSet};
|
use util::nodemap::{NodeMap, NodeSet, DefIdSet};
|
||||||
use util::nodemap::{FxHashMap, FxHashSet};
|
use util::nodemap::{FxHashMap, FxHashSet};
|
||||||
use rustc_data_structures::accumulate_vec::AccumulateVec;
|
use rustc_data_structures::accumulate_vec::AccumulateVec;
|
||||||
|
@ -223,6 +224,9 @@ pub struct TypeckTables<'tcx> {
|
||||||
|
|
||||||
pub adjustments: NodeMap<Vec<ty::adjustment::Adjustment<'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
|
/// Borrows
|
||||||
pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>,
|
pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>,
|
||||||
|
|
||||||
|
@ -274,6 +278,7 @@ impl<'tcx> TypeckTables<'tcx> {
|
||||||
node_types: FxHashMap(),
|
node_types: FxHashMap(),
|
||||||
node_substs: NodeMap(),
|
node_substs: NodeMap(),
|
||||||
adjustments: NodeMap(),
|
adjustments: NodeMap(),
|
||||||
|
pat_binding_modes: NodeMap(),
|
||||||
upvar_capture_map: FxHashMap(),
|
upvar_capture_map: FxHashMap(),
|
||||||
closure_tys: NodeMap(),
|
closure_tys: NodeMap(),
|
||||||
closure_kinds: NodeMap(),
|
closure_kinds: NodeMap(),
|
||||||
|
|
|
@ -74,6 +74,9 @@ pub use self::sty::InferTy::*;
|
||||||
pub use self::sty::RegionKind::*;
|
pub use self::sty::RegionKind::*;
|
||||||
pub use self::sty::TypeVariants::*;
|
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::{TyCtxt, GlobalArenas, tls};
|
||||||
pub use self::context::{Lift, TypeckTables};
|
pub use self::context::{Lift, TypeckTables};
|
||||||
|
|
||||||
|
@ -84,6 +87,7 @@ pub use self::trait_def::TraitDef;
|
||||||
pub use self::maps::queries;
|
pub use self::maps::queries;
|
||||||
|
|
||||||
pub mod adjustment;
|
pub mod adjustment;
|
||||||
|
pub mod binding;
|
||||||
pub mod cast;
|
pub mod cast;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod fast_reject;
|
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) {
|
let pat = match self.tcx.hir.get(node_id) {
|
||||||
hir_map::Node::NodeLocal(pat) => pat,
|
hir_map::Node::NodeLocal(pat) => pat,
|
||||||
node => bug!("bad node for local: {:?}", node)
|
node => bug!("bad node for local: {:?}", node)
|
||||||
};
|
};
|
||||||
|
|
||||||
match pat.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)
|
_ => bug!("local is not a binding: {:?}", pat)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -913,7 +914,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||||
Some(ImmutabilityBlame::ClosureEnv(_)) => {}
|
Some(ImmutabilityBlame::ClosureEnv(_)) => {}
|
||||||
Some(ImmutabilityBlame::ImmLocal(node_id)) => {
|
Some(ImmutabilityBlame::ImmLocal(node_id)) => {
|
||||||
let let_span = self.tcx.hir.span(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) {
|
if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) {
|
||||||
let (_, is_implicit_self) = self.local_ty(node_id);
|
let (_, is_implicit_self) = self.local_ty(node_id);
|
||||||
if is_implicit_self && snippet != "self" {
|
if is_implicit_self && snippet != "self" {
|
||||||
|
@ -930,7 +931,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||||
Some(ImmutabilityBlame::LocalDeref(node_id)) => {
|
Some(ImmutabilityBlame::LocalDeref(node_id)) => {
|
||||||
let let_span = self.tcx.hir.span(node_id);
|
let let_span = self.tcx.hir.span(node_id);
|
||||||
match self.local_binding_mode(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);
|
let snippet = self.tcx.sess.codemap().span_to_snippet(let_span);
|
||||||
if let Ok(snippet) = snippet {
|
if let Ok(snippet) = snippet {
|
||||||
db.span_label(
|
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(local_ty), is_implicit_self) = self.local_ty(node_id) {
|
||||||
if let Some(msg) =
|
if let Some(msg) =
|
||||||
self.suggest_mut_for_immutable(local_ty, is_implicit_self) {
|
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) {
|
fn check_for_bindings_named_the_same_as_variants(cx: &MatchVisitor, pat: &Pat) {
|
||||||
pat.walk(|p| {
|
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);
|
let pat_ty = cx.tables.pat_ty(p);
|
||||||
if let ty::TyAdt(edef, _) = pat_ty.sty {
|
if let ty::TyAdt(edef, _) = pat_ty.sty {
|
||||||
if edef.is_enum() && edef.variants.iter().any(|variant| {
|
if edef.is_enum() && edef.variants.iter().any(|variant| {
|
||||||
|
@ -452,8 +457,9 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
|
||||||
pats: &[P<Pat>]) {
|
pats: &[P<Pat>]) {
|
||||||
let mut by_ref_span = None;
|
let mut by_ref_span = None;
|
||||||
for pat in pats {
|
for pat in pats {
|
||||||
pat.each_binding(|bm, _, span, _path| {
|
pat.each_binding(|_, id, span, _path| {
|
||||||
if let hir::BindByRef(..) = bm {
|
let bm = *cx.tables.pat_binding_modes.get(&id).expect("missing binding mode");
|
||||||
|
if let ty::BindByReference(..) = bm {
|
||||||
by_ref_span = Some(span);
|
by_ref_span = Some(span);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -484,12 +490,18 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
|
||||||
|
|
||||||
for pat in pats {
|
for pat in pats {
|
||||||
pat.walk(|p| {
|
pat.walk(|p| {
|
||||||
if let PatKind::Binding(hir::BindByValue(..), _, _, ref sub) = p.node {
|
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);
|
let pat_ty = cx.tables.node_id_to_type(p.id);
|
||||||
if pat_ty.moves_by_default(cx.tcx, cx.param_env, pat.span) {
|
if pat_ty.moves_by_default(cx.tcx, cx.param_env, pat.span) {
|
||||||
check_move(p, sub.as_ref().map(|p| &**p));
|
check_move(p, sub.as_ref().map(|p| &**p));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
true
|
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 id = self.tcx.hir.as_local_node_id(def_id).unwrap();
|
||||||
let var_ty = self.tables.node_id_to_type(pat.id);
|
let var_ty = self.tables.node_id_to_type(pat.id);
|
||||||
let region = match var_ty.sty {
|
let region = match var_ty.sty {
|
||||||
ty::TyRef(r, _) => Some(r),
|
ty::TyRef(r, _) => Some(r),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
let bm = *self.tables.pat_binding_modes.get(&pat.id)
|
||||||
|
.expect("missing binding mode");
|
||||||
let (mutability, mode) = match bm {
|
let (mutability, mode) = match bm {
|
||||||
hir::BindByValue(hir::MutMutable) =>
|
ty::BindByValue(hir::MutMutable) =>
|
||||||
(Mutability::Mut, BindingMode::ByValue),
|
(Mutability::Mut, BindingMode::ByValue),
|
||||||
hir::BindByValue(hir::MutImmutable) =>
|
ty::BindByValue(hir::MutImmutable) =>
|
||||||
(Mutability::Not, BindingMode::ByValue),
|
(Mutability::Not, BindingMode::ByValue),
|
||||||
hir::BindByRef(hir::MutMutable) =>
|
ty::BindByReference(hir::MutMutable) =>
|
||||||
(Mutability::Not, BindingMode::ByRef(region.unwrap(), BorrowKind::Mut)),
|
(Mutability::Not, BindingMode::ByRef(
|
||||||
hir::BindByRef(hir::MutImmutable) =>
|
region.unwrap(), BorrowKind::Mut)),
|
||||||
(Mutability::Not, BindingMode::ByRef(region.unwrap(), BorrowKind::Shared)),
|
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
|
// 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).
|
// 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 {
|
if let ty::TyRef(_, mt) = ty.sty {
|
||||||
ty = mt.ty;
|
ty = mt.ty;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -44,9 +44,13 @@ impl UnusedMut {
|
||||||
|
|
||||||
let mut mutables = FxHashMap();
|
let mut mutables = FxHashMap();
|
||||||
for p in pats {
|
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;
|
let name = path1.node;
|
||||||
if let hir::BindByValue(hir::MutMutable) = mode {
|
if let ty::BindByValue(hir::MutMutable) = bm {
|
||||||
if !name.as_str().starts_with("_") {
|
if !name.as_str().starts_with("_") {
|
||||||
match mutables.entry(name) {
|
match mutables.entry(name) {
|
||||||
Vacant(entry) => {
|
Vacant(entry) => {
|
||||||
|
|
|
@ -2277,8 +2277,9 @@ impl<'a> Resolver<'a> {
|
||||||
false, pat.span)
|
false, pat.span)
|
||||||
.and_then(LexicalScopeBinding::item);
|
.and_then(LexicalScopeBinding::item);
|
||||||
let resolution = binding.map(NameBinding::def).and_then(|def| {
|
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() ||
|
let always_binding = !pat_src.is_refutable() || opt_pat.is_some() ||
|
||||||
bmode != BindingMode::ByValue(Mutability::Immutable);
|
bmode != ivmode;
|
||||||
match def {
|
match def {
|
||||||
Def::StructCtor(_, CtorKind::Const) |
|
Def::StructCtor(_, CtorKind::Const) |
|
||||||
Def::VariantCtor(_, 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);
|
self.demand_eqtype(pat.span, expected, rhs_ty);
|
||||||
common_type
|
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);
|
let typ = self.local_ty(pat.span, pat.id);
|
||||||
match bm {
|
match bm {
|
||||||
hir::BindByRef(mutbl) => {
|
ty::BindByReference(mutbl) => {
|
||||||
// if the binding is like
|
// if the binding is like
|
||||||
// ref x | ref const x | ref mut x
|
// ref x | ref const x | ref mut x
|
||||||
// then `x` is assigned a value of type `&M T` where M is the mutability
|
// 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);
|
self.demand_eqtype(pat.span, region_ty, typ);
|
||||||
}
|
}
|
||||||
// otherwise the type of x is the expected type T
|
// otherwise the type of x is the expected type T
|
||||||
hir::BindByValue(_) => {
|
ty::BindByValue(_) => {
|
||||||
// As above, `T <: typeof(x)` is required but we
|
// As above, `T <: typeof(x)` is required but we
|
||||||
// use equality, see (*) below.
|
// use equality, see (*) below.
|
||||||
self.demand_eqtype(pat.span, expected, typ);
|
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> {
|
match_src: hir::MatchSource) -> Ty<'tcx> {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
|
|
||||||
// Not entirely obvious: if matches may create ref bindings, we
|
// Not entirely obvious: if matches may create ref bindings, we want to
|
||||||
// want to use the *precise* type of the discriminant, *not* some
|
// use the *precise* type of the discriminant, *not* some supertype, as
|
||||||
// supertype, as the "discriminant type" (issue #23116).
|
// 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()
|
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 {
|
.max_by_key(|m| match *m {
|
||||||
hir::MutMutable => 1,
|
hir::MutMutable => 1,
|
||||||
hir::MutImmutable => 0,
|
hir::MutImmutable => 0,
|
||||||
|
|
|
@ -3999,7 +3999,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
local: &'gcx hir::Local,
|
local: &'gcx hir::Local,
|
||||||
init: &'gcx hir::Expr) -> Ty<'tcx>
|
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);
|
let local_ty = self.local_ty(init.span, local.id);
|
||||||
if let Some(m) = ref_bindings {
|
if let Some(m) = ref_bindings {
|
||||||
|
|
|
@ -1196,10 +1196,14 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
||||||
mc.cat_pattern(discr_cmt, root_pat, |sub_cmt, sub_pat| {
|
mc.cat_pattern(discr_cmt, root_pat, |sub_cmt, sub_pat| {
|
||||||
match sub_pat.node {
|
match sub_pat.node {
|
||||||
// `ref x` pattern
|
// `ref x` pattern
|
||||||
PatKind::Binding(hir::BindByRef(mutbl), ..) => {
|
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,
|
self.link_region_from_node_type(sub_pat.span, sub_pat.id,
|
||||||
mutbl, sub_cmt);
|
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) {
|
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);
|
self.visit_node_id(p.span, p.id);
|
||||||
intravisit::walk_pat(self, p);
|
intravisit::walk_pat(self, p);
|
||||||
}
|
}
|
||||||
|
|
|
@ -867,7 +867,8 @@ mod tests {
|
||||||
pat: P(ast::Pat {
|
pat: P(ast::Pat {
|
||||||
id: ast::DUMMY_NODE_ID,
|
id: ast::DUMMY_NODE_ID,
|
||||||
node: PatKind::Ident(
|
node: PatKind::Ident(
|
||||||
ast::BindingMode::ByValue(ast::Mutability::Immutable),
|
ast::BindingMode::ByValue(
|
||||||
|
ast::Mutability::Immutable),
|
||||||
Spanned{
|
Spanned{
|
||||||
span: sp(6,7),
|
span: sp(6,7),
|
||||||
node: Ident::from_str("b")},
|
node: Ident::from_str("b")},
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue