Track what drop obligations are established on match arms.
This is accomplished by: 1. Add `MatchMode` enum to `expr_use_visitor`. 2. Computing the match mode for each pattern via a pre-pass, and then passing the mode along when visiting the pattern in expr_use_visitor. 3. Adding a `fn matched_pat` callback to expr_use_visitor, which is called on interior struct and enum nodes of the pattern (as opposed to `fn consume_pat`, which is only invoked for identifiers at the leaves of the pattern), and invoking it accordingly. Of particular interest are the `cat_downcast` instances established when matching enum variants.
This commit is contained in:
parent
6f7cb8c618
commit
09d67fd777
@ -103,6 +103,11 @@ fn consume(&mut self,
|
|||||||
self.consume_common(consume_id, consume_span, cmt, mode);
|
self.consume_common(consume_id, consume_span, cmt, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn matched_pat(&mut self,
|
||||||
|
_matched_pat: &ast::Pat,
|
||||||
|
_cmt: mc::cmt,
|
||||||
|
_mode: euv::MatchMode) { }
|
||||||
|
|
||||||
fn consume_pat(&mut self,
|
fn consume_pat(&mut self,
|
||||||
consume_pat: &ast::Pat,
|
consume_pat: &ast::Pat,
|
||||||
cmt: mc::cmt<'tcx>,
|
cmt: mc::cmt<'tcx>,
|
||||||
|
@ -88,6 +88,16 @@ fn consume(&mut self,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn matched_pat(&mut self,
|
||||||
|
matched_pat: &ast::Pat,
|
||||||
|
cmt: mc::cmt<'tcx>,
|
||||||
|
mode: euv::MatchMode) {
|
||||||
|
debug!("matched_pat(matched_pat={}, cmt={}, mode={})",
|
||||||
|
matched_pat.repr(self.tcx()),
|
||||||
|
cmt.repr(self.tcx()),
|
||||||
|
mode);
|
||||||
|
}
|
||||||
|
|
||||||
fn consume_pat(&mut self,
|
fn consume_pat(&mut self,
|
||||||
consume_pat: &ast::Pat,
|
consume_pat: &ast::Pat,
|
||||||
cmt: mc::cmt<'tcx>,
|
cmt: mc::cmt<'tcx>,
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
use middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Init};
|
use middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Init};
|
||||||
use middle::expr_use_visitor::{JustWrite, LoanCause, MutateMode};
|
use middle::expr_use_visitor::{JustWrite, LoanCause, MutateMode};
|
||||||
use middle::expr_use_visitor::{WriteAndRead};
|
use middle::expr_use_visitor::{WriteAndRead};
|
||||||
|
use middle::expr_use_visitor as euv;
|
||||||
use middle::mem_categorization::cmt;
|
use middle::mem_categorization::cmt;
|
||||||
use middle::pat_util::*;
|
use middle::pat_util::*;
|
||||||
use middle::ty::*;
|
use middle::ty::*;
|
||||||
@ -1024,6 +1025,7 @@ struct MutationChecker<'a, 'tcx: 'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'tcx> {
|
impl<'a, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'tcx> {
|
||||||
|
fn matched_pat(&mut self, _: &Pat, _: cmt, _: euv::MatchMode) {}
|
||||||
fn consume(&mut self, _: NodeId, _: Span, _: cmt, _: ConsumeMode) {}
|
fn consume(&mut self, _: NodeId, _: Span, _: cmt, _: ConsumeMode) {}
|
||||||
fn consume_pat(&mut self, _: &Pat, _: cmt, _: ConsumeMode) {}
|
fn consume_pat(&mut self, _: &Pat, _: cmt, _: ConsumeMode) {}
|
||||||
fn borrow(&mut self,
|
fn borrow(&mut self,
|
||||||
|
@ -59,6 +59,11 @@ fn consume(&mut self,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn matched_pat(&mut self,
|
||||||
|
_matched_pat: &ast::Pat,
|
||||||
|
_cmt: mc::cmt,
|
||||||
|
_mode: euv::MatchMode) {}
|
||||||
|
|
||||||
fn consume_pat(&mut self,
|
fn consume_pat(&mut self,
|
||||||
_consume_pat: &ast::Pat,
|
_consume_pat: &ast::Pat,
|
||||||
_cmt: mc::cmt,
|
_cmt: mc::cmt,
|
||||||
|
@ -325,6 +325,12 @@ fn mutate(&mut self,
|
|||||||
_assignment_span: Span,
|
_assignment_span: Span,
|
||||||
_assignee_cmt: mc::cmt,
|
_assignee_cmt: mc::cmt,
|
||||||
_mode: euv::MutateMode) {}
|
_mode: euv::MutateMode) {}
|
||||||
|
|
||||||
|
fn matched_pat(&mut self,
|
||||||
|
_: &ast::Pat,
|
||||||
|
_: mc::cmt,
|
||||||
|
_: euv::MatchMode) {}
|
||||||
|
|
||||||
fn consume_pat(&mut self,
|
fn consume_pat(&mut self,
|
||||||
_consume_pat: &ast::Pat,
|
_consume_pat: &ast::Pat,
|
||||||
_cmt: mc::cmt,
|
_cmt: mc::cmt,
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
pub use self::LoanCause::*;
|
pub use self::LoanCause::*;
|
||||||
pub use self::ConsumeMode::*;
|
pub use self::ConsumeMode::*;
|
||||||
pub use self::MoveReason::*;
|
pub use self::MoveReason::*;
|
||||||
|
pub use self::MatchMode::*;
|
||||||
|
use self::TrackMatchMode::*;
|
||||||
use self::OverloadedCallType::*;
|
use self::OverloadedCallType::*;
|
||||||
|
|
||||||
use middle::{def, region, pat_util};
|
use middle::{def, region, pat_util};
|
||||||
@ -48,6 +50,23 @@ fn consume(&mut self,
|
|||||||
cmt: mc::cmt<'tcx>,
|
cmt: mc::cmt<'tcx>,
|
||||||
mode: ConsumeMode);
|
mode: ConsumeMode);
|
||||||
|
|
||||||
|
// The value found at `cmt` has been determined to match the
|
||||||
|
// pattern binding `matched_pat`, and its subparts are being
|
||||||
|
// copied or moved depending on `mode`. Note that `matched_pat`
|
||||||
|
// is called on all variant/structs in the pattern (i.e., the
|
||||||
|
// interior nodes of the pattern's tree structure) while
|
||||||
|
// consume_pat is called on the binding identifiers in the pattern
|
||||||
|
// (which are leaves of the pattern's tree structure).
|
||||||
|
//
|
||||||
|
// Note that variants/structs and identifiers are disjoint; thus
|
||||||
|
// `matched_pat` and `consume_pat` are never both called on the
|
||||||
|
// same input pattern structure (though of `consume_pat` can be
|
||||||
|
// called on a subpart of an input passed to `matched_pat).
|
||||||
|
fn matched_pat(&mut self,
|
||||||
|
matched_pat: &ast::Pat,
|
||||||
|
cmt: mc::cmt<'tcx>,
|
||||||
|
mode: MatchMode);
|
||||||
|
|
||||||
// The value found at `cmt` is either copied or moved via the
|
// The value found at `cmt` is either copied or moved via the
|
||||||
// pattern binding `consume_pat`, depending on mode.
|
// pattern binding `consume_pat`, depending on mode.
|
||||||
fn consume_pat(&mut self,
|
fn consume_pat(&mut self,
|
||||||
@ -103,6 +122,79 @@ pub enum MoveReason {
|
|||||||
CaptureMove,
|
CaptureMove,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[deriving(PartialEq,Show)]
|
||||||
|
pub enum MatchMode {
|
||||||
|
NonBindingMatch,
|
||||||
|
BorrowingMatch,
|
||||||
|
CopyingMatch,
|
||||||
|
MovingMatch,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deriving(PartialEq,Show)]
|
||||||
|
enum TrackMatchMode<T> {
|
||||||
|
Unknown, Definite(MatchMode), Conflicting,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> TrackMatchMode<T> {
|
||||||
|
// Builds up the whole match mode for a pattern from its constituent
|
||||||
|
// parts. The lattice looks like this:
|
||||||
|
//
|
||||||
|
// Conflicting
|
||||||
|
// / \
|
||||||
|
// / \
|
||||||
|
// Borrowing Moving
|
||||||
|
// \ /
|
||||||
|
// \ /
|
||||||
|
// Copying
|
||||||
|
// |
|
||||||
|
// NonBinding
|
||||||
|
// |
|
||||||
|
// Unknown
|
||||||
|
//
|
||||||
|
// examples:
|
||||||
|
//
|
||||||
|
// * `(_, some_int)` pattern is Copying, since
|
||||||
|
// NonBinding + Copying => Copying
|
||||||
|
//
|
||||||
|
// * `(some_int, some_box)` pattern is Moving, since
|
||||||
|
// Copying + Moving => Moving
|
||||||
|
//
|
||||||
|
// * `(ref x, some_box)` pattern is Conflicting, since
|
||||||
|
// Borrowing + Moving => Conflicting
|
||||||
|
//
|
||||||
|
// Note that the `Unknown` and `Conflicting` states are
|
||||||
|
// represented separately from the other more interesting
|
||||||
|
// `Definite` states, which simplifies logic here somewhat.
|
||||||
|
fn lub(&mut self, mode: MatchMode) {
|
||||||
|
*self = match (*self, mode) {
|
||||||
|
// Note that clause order below is very significant.
|
||||||
|
(Unknown, new) => Definite(new),
|
||||||
|
(Definite(old), new) if old == new => Definite(old),
|
||||||
|
|
||||||
|
(Definite(old), NonBindingMatch) => Definite(old),
|
||||||
|
(Definite(NonBindingMatch), new) => Definite(new),
|
||||||
|
|
||||||
|
(Definite(old), CopyingMatch) => Definite(old),
|
||||||
|
(Definite(CopyingMatch), new) => Definite(new),
|
||||||
|
|
||||||
|
(Definite(_), _) => Conflicting,
|
||||||
|
(Conflicting, _) => *self,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn match_mode(&self) -> MatchMode {
|
||||||
|
match *self {
|
||||||
|
Unknown => NonBindingMatch,
|
||||||
|
Definite(mode) => mode,
|
||||||
|
Conflicting => {
|
||||||
|
// Conservatively return MovingMatch to let the
|
||||||
|
// compiler continue to make progress.
|
||||||
|
MovingMatch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[deriving(PartialEq,Show)]
|
#[deriving(PartialEq,Show)]
|
||||||
pub enum MutateMode {
|
pub enum MutateMode {
|
||||||
Init,
|
Init,
|
||||||
@ -251,7 +343,7 @@ fn walk_arg_patterns(&mut self,
|
|||||||
ty::ReScope(fn_body_scope), // Args live only as long as the fn body.
|
ty::ReScope(fn_body_scope), // Args live only as long as the fn body.
|
||||||
arg_ty);
|
arg_ty);
|
||||||
|
|
||||||
self.walk_pat(arg_cmt, &*arg.pat);
|
self.walk_irrefutable_pat(arg_cmt, &*arg.pat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,7 +482,9 @@ pub fn walk_expr(&mut self, expr: &ast::Expr) {
|
|||||||
|
|
||||||
// treatment of the discriminant is handled while walking the arms.
|
// treatment of the discriminant is handled while walking the arms.
|
||||||
for arm in arms.iter() {
|
for arm in arms.iter() {
|
||||||
self.walk_arm(discr_cmt.clone(), arm);
|
let mode = self.arm_move_mode(discr_cmt.clone(), arm);
|
||||||
|
let mode = mode.match_mode();
|
||||||
|
self.walk_arm(discr_cmt.clone(), arm, mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -448,7 +542,7 @@ pub fn walk_expr(&mut self, expr: &ast::Expr) {
|
|||||||
pat.span,
|
pat.span,
|
||||||
ty::ReScope(blk_scope),
|
ty::ReScope(blk_scope),
|
||||||
pattern_type);
|
pattern_type);
|
||||||
self.walk_pat(pat_cmt, &**pat);
|
self.walk_irrefutable_pat(pat_cmt, &**pat);
|
||||||
|
|
||||||
self.walk_block(&**blk);
|
self.walk_block(&**blk);
|
||||||
}
|
}
|
||||||
@ -617,7 +711,7 @@ fn walk_local(&mut self, local: &ast::Local) {
|
|||||||
// `walk_pat`:
|
// `walk_pat`:
|
||||||
self.walk_expr(&**expr);
|
self.walk_expr(&**expr);
|
||||||
let init_cmt = return_if_err!(self.mc.cat_expr(&**expr));
|
let init_cmt = return_if_err!(self.mc.cat_expr(&**expr));
|
||||||
self.walk_pat(init_cmt, &*local.pat);
|
self.walk_irrefutable_pat(init_cmt, &*local.pat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -824,9 +918,17 @@ fn walk_overloaded_operator(&mut self,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn walk_arm(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &ast::Arm) {
|
fn arm_move_mode(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &ast::Arm) -> TrackMatchMode<Span> {
|
||||||
|
let mut mode = Unknown;
|
||||||
for pat in arm.pats.iter() {
|
for pat in arm.pats.iter() {
|
||||||
self.walk_pat(discr_cmt.clone(), &**pat);
|
self.determine_pat_move_mode(discr_cmt.clone(), &**pat, &mut mode);
|
||||||
|
}
|
||||||
|
mode
|
||||||
|
}
|
||||||
|
|
||||||
|
fn walk_arm(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &ast::Arm, mode: MatchMode) {
|
||||||
|
for pat in arm.pats.iter() {
|
||||||
|
self.walk_pat(discr_cmt.clone(), &**pat, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
for guard in arm.guard.iter() {
|
for guard in arm.guard.iter() {
|
||||||
@ -836,21 +938,71 @@ fn walk_arm(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &ast::Arm) {
|
|||||||
self.consume_expr(&*arm.body);
|
self.consume_expr(&*arm.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn walk_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &ast::Pat) {
|
/// Walks an pat that occurs in isolation (i.e. top-level of fn
|
||||||
|
/// arg or let binding. *Not* a match arm or nested pat.)
|
||||||
|
fn walk_irrefutable_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &ast::Pat) {
|
||||||
|
let mut mode = Unknown;
|
||||||
|
self.determine_pat_move_mode(cmt_discr.clone(), pat, &mut mode);
|
||||||
|
let mode = mode.match_mode();
|
||||||
|
self.walk_pat(cmt_discr, pat, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Identifies any bindings within `pat` and accumulates within
|
||||||
|
/// `mode` whether the overall pattern/match structure is a move,
|
||||||
|
/// copy, or borrow.
|
||||||
|
fn determine_pat_move_mode(&mut self,
|
||||||
|
cmt_discr: mc::cmt<'tcx>,
|
||||||
|
pat: &ast::Pat,
|
||||||
|
mode: &mut TrackMatchMode<Span>) {
|
||||||
|
debug!("determine_pat_move_mode cmt_discr={} pat={}", cmt_discr.repr(self.tcx()),
|
||||||
|
pat.repr(self.tcx()));
|
||||||
|
return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |_mc, cmt_pat, pat| {
|
||||||
|
let tcx = self.typer.tcx();
|
||||||
|
let def_map = &self.typer.tcx().def_map;
|
||||||
|
if pat_util::pat_is_binding(def_map, pat) {
|
||||||
|
match pat.node {
|
||||||
|
ast::PatIdent(ast::BindByRef(_), _, _) =>
|
||||||
|
mode.lub(BorrowingMatch),
|
||||||
|
ast::PatIdent(ast::BindByValue(_), _, _) => {
|
||||||
|
match copy_or_move(tcx, cmt_pat.ty, PatBindingMove) {
|
||||||
|
Copy => mode.lub(CopyingMatch),
|
||||||
|
Move(_) => mode.lub(MovingMatch),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
tcx.sess.span_bug(
|
||||||
|
pat.span,
|
||||||
|
"binding pattern not an identifier");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The core driver for walking a pattern; `match_mode` must be
|
||||||
|
/// established up front, e.g. via `determine_pat_move_mode` (see
|
||||||
|
/// also `walk_irrefutable_pat` for patterns that stand alone).
|
||||||
|
fn walk_pat(&mut self,
|
||||||
|
cmt_discr: mc::cmt<'tcx>,
|
||||||
|
pat: &ast::Pat,
|
||||||
|
match_mode: MatchMode) {
|
||||||
debug!("walk_pat cmt_discr={} pat={}", cmt_discr.repr(self.tcx()),
|
debug!("walk_pat cmt_discr={} pat={}", cmt_discr.repr(self.tcx()),
|
||||||
pat.repr(self.tcx()));
|
pat.repr(self.tcx()));
|
||||||
|
|
||||||
let mc = &self.mc;
|
let mc = &self.mc;
|
||||||
let typer = self.typer;
|
let typer = self.typer;
|
||||||
let tcx = typer.tcx();
|
let tcx = typer.tcx();
|
||||||
let def_map = &self.typer.tcx().def_map;
|
let def_map = &self.typer.tcx().def_map;
|
||||||
let delegate = &mut self.delegate;
|
let delegate = &mut self.delegate;
|
||||||
return_if_err!(mc.cat_pattern(cmt_discr, &*pat, |mc, cmt_pat, pat| {
|
|
||||||
|
return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |mc, cmt_pat, pat| {
|
||||||
if pat_util::pat_is_binding(def_map, pat) {
|
if pat_util::pat_is_binding(def_map, pat) {
|
||||||
let tcx = typer.tcx();
|
let tcx = typer.tcx();
|
||||||
|
|
||||||
debug!("binding cmt_pat={} pat={}",
|
debug!("binding cmt_pat={} pat={} match_mode={}",
|
||||||
cmt_pat.repr(tcx),
|
cmt_pat.repr(tcx),
|
||||||
pat.repr(tcx));
|
pat.repr(tcx),
|
||||||
|
match_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!(typer.node_ty(pat.id));
|
let pat_ty = return_if_err!(typer.node_ty(pat.id));
|
||||||
@ -933,6 +1085,93 @@ fn walk_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &ast::Pat) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// Do a second pass over the pattern, calling `matched_pat` on
|
||||||
|
// the interior nodes (enum variants and structs), as opposed
|
||||||
|
// to the above loop's visit of than the bindings that form
|
||||||
|
// the leaves of the pattern tree structure.
|
||||||
|
return_if_err!(mc.cat_pattern(cmt_discr, pat, |mc, cmt_pat, pat| {
|
||||||
|
let def_map = def_map.borrow();
|
||||||
|
let tcx = typer.tcx();
|
||||||
|
|
||||||
|
match pat.node {
|
||||||
|
ast::PatEnum(_, _) | ast::PatIdent(_, _, None) | ast::PatStruct(..) => {
|
||||||
|
match def_map.get(&pat.id) {
|
||||||
|
None => {
|
||||||
|
// no definition found: pat is not a
|
||||||
|
// struct or enum pattern.
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(&def::DefVariant(enum_did, variant_did, _is_struct)) => {
|
||||||
|
let downcast_cmt =
|
||||||
|
if ty::enum_is_univariant(tcx, enum_did) {
|
||||||
|
cmt_pat
|
||||||
|
} else {
|
||||||
|
let cmt_pat_ty = cmt_pat.ty;
|
||||||
|
mc.cat_downcast(pat, cmt_pat, cmt_pat_ty, variant_did)
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("variant downcast_cmt={} pat={}",
|
||||||
|
downcast_cmt.repr(tcx),
|
||||||
|
pat.repr(tcx));
|
||||||
|
|
||||||
|
delegate.matched_pat(pat, downcast_cmt, match_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(&def::DefStruct(..)) | Some(&def::DefTy(_, false)) => {
|
||||||
|
// A struct (in either the value or type
|
||||||
|
// namespace; we encounter the former on
|
||||||
|
// e.g. patterns for unit structs).
|
||||||
|
|
||||||
|
debug!("struct cmt_pat={} pat={}",
|
||||||
|
cmt_pat.repr(tcx),
|
||||||
|
pat.repr(tcx));
|
||||||
|
|
||||||
|
delegate.matched_pat(pat, cmt_pat, match_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(&def::DefConst(..)) |
|
||||||
|
Some(&def::DefLocal(..)) => {
|
||||||
|
// This is a leaf (i.e. identifier binding
|
||||||
|
// or constant value to match); thus no
|
||||||
|
// `matched_pat` call.
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(def @ &def::DefTy(_, true)) => {
|
||||||
|
// An enum's type -- should never be in a
|
||||||
|
// pattern.
|
||||||
|
|
||||||
|
let msg = format!("Pattern has unexpected type: {}", def);
|
||||||
|
tcx.sess.span_bug(pat.span, msg.as_slice())
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(def) => {
|
||||||
|
// Remaining cases are e.g. DefFn, to
|
||||||
|
// which identifiers within patterns
|
||||||
|
// should not resolve.
|
||||||
|
|
||||||
|
let msg = format!("Pattern has unexpected def: {}", def);
|
||||||
|
tcx.sess.span_bug(pat.span, msg.as_slice())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ast::PatIdent(_, _, Some(_)) => {
|
||||||
|
// Do nothing; this is a binding (not a enum
|
||||||
|
// variant or struct), and the cat_pattern call
|
||||||
|
// will visit the substructure recursively.
|
||||||
|
}
|
||||||
|
|
||||||
|
ast::PatWild(_) | ast::PatTup(..) | ast::PatBox(..) |
|
||||||
|
ast::PatRegion(..) | ast::PatLit(..) | ast::PatRange(..) |
|
||||||
|
ast::PatVec(..) | ast::PatMac(..) => {
|
||||||
|
// Similarly, each of these cases does not
|
||||||
|
// correspond to a enum variant or struct, so we
|
||||||
|
// do not do any `matched_pat` calls for these
|
||||||
|
// cases either.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn walk_captures(&mut self, closure_expr: &ast::Expr) {
|
fn walk_captures(&mut self, closure_expr: &ast::Expr) {
|
||||||
|
@ -1274,6 +1274,7 @@ struct ReassignmentChecker {
|
|||||||
|
|
||||||
impl<'tcx> euv::Delegate<'tcx> for ReassignmentChecker {
|
impl<'tcx> euv::Delegate<'tcx> for ReassignmentChecker {
|
||||||
fn consume(&mut self, _: ast::NodeId, _: Span, _: mc::cmt, _: euv::ConsumeMode) {}
|
fn consume(&mut self, _: ast::NodeId, _: Span, _: mc::cmt, _: euv::ConsumeMode) {}
|
||||||
|
fn matched_pat(&mut self, _: &ast::Pat, _: mc::cmt, _: euv::MatchMode) {}
|
||||||
fn consume_pat(&mut self, _: &ast::Pat, _: mc::cmt, _: euv::ConsumeMode) {}
|
fn consume_pat(&mut self, _: &ast::Pat, _: mc::cmt, _: euv::ConsumeMode) {}
|
||||||
fn borrow(&mut self, _: ast::NodeId, _: Span, _: mc::cmt, _: ty::Region,
|
fn borrow(&mut self, _: ast::NodeId, _: Span, _: mc::cmt, _: ty::Region,
|
||||||
_: ty::BorrowKind, _: euv::LoanCause) {}
|
_: ty::BorrowKind, _: euv::LoanCause) {}
|
||||||
|
Loading…
Reference in New Issue
Block a user