2014-04-21 19:21:53 -04:00
|
|
|
// Copyright 2014 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.
|
|
|
|
|
2014-11-25 21:17:11 -05:00
|
|
|
//! A different sort of visitor for walking fn bodies. Unlike the
|
|
|
|
//! normal visitor, which just walks the entire body in one shot, the
|
|
|
|
//! `ExprUseVisitor` determines how expressions are being used.
|
2014-04-21 19:21:53 -04:00
|
|
|
|
2014-11-06 00:05:53 -08:00
|
|
|
pub use self::LoanCause::*;
|
|
|
|
pub use self::ConsumeMode::*;
|
|
|
|
pub use self::MoveReason::*;
|
2014-09-16 15:24:56 +02:00
|
|
|
pub use self::MatchMode::*;
|
|
|
|
use self::TrackMatchMode::*;
|
2014-11-06 00:05:53 -08:00
|
|
|
use self::OverloadedCallType::*;
|
|
|
|
|
2016-01-20 22:31:10 +03:00
|
|
|
use middle::pat_util;
|
|
|
|
use middle::def::Def;
|
2015-08-16 06:32:28 -04:00
|
|
|
use middle::def_id::{DefId};
|
2015-06-29 17:46:24 -07:00
|
|
|
use middle::infer;
|
2014-08-18 08:29:44 -07:00
|
|
|
use middle::mem_categorization as mc;
|
2016-02-29 23:36:51 +00:00
|
|
|
use middle::ty::{self, TyCtxt, adjustment};
|
2014-04-21 19:21:53 -04:00
|
|
|
|
2016-02-14 15:25:12 +03:00
|
|
|
use rustc_front::hir::{self, PatKind};
|
2015-07-31 00:04:06 -07:00
|
|
|
|
|
|
|
use syntax::ast;
|
2014-09-07 20:09:06 +03:00
|
|
|
use syntax::ptr::P;
|
2014-07-01 14:30:33 -07:00
|
|
|
use syntax::codemap::Span;
|
2014-05-16 10:15:33 -07:00
|
|
|
|
2014-04-21 19:21:53 -04:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// The Delegate trait
|
|
|
|
|
2014-04-30 20:22:36 -04:00
|
|
|
/// This trait defines the callbacks you can expect to receive when
|
|
|
|
/// employing the ExprUseVisitor.
|
2014-09-29 22:11:30 +03:00
|
|
|
pub trait Delegate<'tcx> {
|
2014-04-21 19:21:53 -04:00
|
|
|
// The value found at `cmt` is either copied or moved, depending
|
|
|
|
// on mode.
|
|
|
|
fn consume(&mut self,
|
2014-04-28 08:50:50 -04:00
|
|
|
consume_id: ast::NodeId,
|
|
|
|
consume_span: Span,
|
2014-09-29 22:11:30 +03:00
|
|
|
cmt: mc::cmt<'tcx>,
|
2014-04-28 08:50:50 -04:00
|
|
|
mode: ConsumeMode);
|
2014-04-21 19:21:53 -04:00
|
|
|
|
2014-09-16 15:24:56 +02:00
|
|
|
// 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,
|
2015-07-31 00:04:06 -07:00
|
|
|
matched_pat: &hir::Pat,
|
2014-09-16 15:24:56 +02:00
|
|
|
cmt: mc::cmt<'tcx>,
|
|
|
|
mode: MatchMode);
|
|
|
|
|
2014-04-21 19:21:53 -04:00
|
|
|
// The value found at `cmt` is either copied or moved via the
|
|
|
|
// pattern binding `consume_pat`, depending on mode.
|
|
|
|
fn consume_pat(&mut self,
|
2015-07-31 00:04:06 -07:00
|
|
|
consume_pat: &hir::Pat,
|
2014-09-29 22:11:30 +03:00
|
|
|
cmt: mc::cmt<'tcx>,
|
2014-04-28 08:50:50 -04:00
|
|
|
mode: ConsumeMode);
|
2014-04-21 19:21:53 -04:00
|
|
|
|
|
|
|
// The value found at `borrow` is being borrowed at the point
|
|
|
|
// `borrow_id` for the region `loan_region` with kind `bk`.
|
|
|
|
fn borrow(&mut self,
|
2014-04-28 08:50:50 -04:00
|
|
|
borrow_id: ast::NodeId,
|
|
|
|
borrow_span: Span,
|
2014-09-29 22:11:30 +03:00
|
|
|
cmt: mc::cmt<'tcx>,
|
2014-04-28 08:50:50 -04:00
|
|
|
loan_region: ty::Region,
|
|
|
|
bk: ty::BorrowKind,
|
|
|
|
loan_cause: LoanCause);
|
2014-04-21 19:21:53 -04:00
|
|
|
|
|
|
|
// The local variable `id` is declared but not initialized.
|
|
|
|
fn decl_without_init(&mut self,
|
2014-05-18 22:53:01 -07:00
|
|
|
id: ast::NodeId,
|
|
|
|
span: Span);
|
2014-04-21 19:21:53 -04:00
|
|
|
|
|
|
|
// The path at `cmt` is being assigned to.
|
|
|
|
fn mutate(&mut self,
|
2014-04-28 08:50:50 -04:00
|
|
|
assignment_id: ast::NodeId,
|
|
|
|
assignment_span: Span,
|
2014-09-29 22:11:30 +03:00
|
|
|
assignee_cmt: mc::cmt<'tcx>,
|
2014-04-28 08:50:50 -04:00
|
|
|
mode: MutateMode);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
|
2015-03-30 09:38:44 -04:00
|
|
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
2014-04-30 20:22:36 -04:00
|
|
|
pub enum LoanCause {
|
|
|
|
ClosureCapture(Span),
|
|
|
|
AddrOf,
|
|
|
|
AutoRef,
|
2015-04-08 04:31:51 -04:00
|
|
|
AutoUnsafe,
|
2014-04-30 20:22:36 -04:00
|
|
|
RefBinding,
|
|
|
|
OverloadedOperator,
|
2014-07-21 20:54:28 -07:00
|
|
|
ClosureInvocation,
|
|
|
|
ForLoop,
|
2014-09-20 19:32:18 +02:00
|
|
|
MatchDiscriminant
|
2014-04-30 20:22:36 -04:00
|
|
|
}
|
|
|
|
|
2015-03-30 09:38:44 -04:00
|
|
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
2014-04-30 20:22:36 -04:00
|
|
|
pub enum ConsumeMode {
|
2014-06-06 11:59:33 -07:00
|
|
|
Copy, // reference to x where x has a type that copies
|
|
|
|
Move(MoveReason), // reference to x where x has a type that moves
|
|
|
|
}
|
|
|
|
|
2015-03-30 09:38:44 -04:00
|
|
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
2014-06-06 11:59:33 -07:00
|
|
|
pub enum MoveReason {
|
|
|
|
DirectRefMove,
|
|
|
|
PatBindingMove,
|
|
|
|
CaptureMove,
|
2014-04-30 20:22:36 -04:00
|
|
|
}
|
|
|
|
|
2015-03-30 09:38:44 -04:00
|
|
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
2014-09-16 15:24:56 +02:00
|
|
|
pub enum MatchMode {
|
|
|
|
NonBindingMatch,
|
|
|
|
BorrowingMatch,
|
|
|
|
CopyingMatch,
|
|
|
|
MovingMatch,
|
|
|
|
}
|
|
|
|
|
2015-03-30 09:38:44 -04:00
|
|
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
2015-02-12 12:32:37 -05:00
|
|
|
enum TrackMatchMode {
|
librustc: Make `Copy` opt-in.
This change makes the compiler no longer infer whether types (structures
and enumerations) implement the `Copy` trait (and thus are implicitly
copyable). Rather, you must implement `Copy` yourself via `impl Copy for
MyType {}`.
A new warning has been added, `missing_copy_implementations`, to warn
you if a non-generic public type has been added that could have
implemented `Copy` but didn't.
For convenience, you may *temporarily* opt out of this behavior by using
`#![feature(opt_out_copy)]`. Note though that this feature gate will never be
accepted and will be removed by the time that 1.0 is released, so you should
transition your code away from using it.
This breaks code like:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
Change this code to:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
impl Copy for Point2D {}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
This is the backwards-incompatible part of #13231.
Part of RFC #3.
[breaking-change]
2014-12-05 17:01:33 -08:00
|
|
|
Unknown,
|
|
|
|
Definite(MatchMode),
|
|
|
|
Conflicting,
|
2014-09-16 15:24:56 +02:00
|
|
|
}
|
|
|
|
|
2015-02-12 12:32:37 -05:00
|
|
|
impl TrackMatchMode {
|
2014-09-16 15:24:56 +02:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-30 09:38:44 -04:00
|
|
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
2014-04-30 20:22:36 -04:00
|
|
|
pub enum MutateMode {
|
2014-06-06 11:59:32 -07:00
|
|
|
Init,
|
2014-04-30 20:22:36 -04:00
|
|
|
JustWrite, // x = y
|
|
|
|
WriteAndRead, // x += y
|
|
|
|
}
|
|
|
|
|
2015-03-30 09:38:44 -04:00
|
|
|
#[derive(Copy, Clone)]
|
2014-07-01 14:30:33 -07:00
|
|
|
enum OverloadedCallType {
|
|
|
|
FnOverloadedCall,
|
|
|
|
FnMutOverloadedCall,
|
|
|
|
FnOnceOverloadedCall,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl OverloadedCallType {
|
2016-02-29 23:36:51 +00:00
|
|
|
fn from_trait_id(tcx: &TyCtxt, trait_id: DefId)
|
2014-07-01 14:30:33 -07:00
|
|
|
-> OverloadedCallType {
|
2015-06-10 17:22:20 +01:00
|
|
|
for &(maybe_function_trait, overloaded_call_type) in &[
|
2014-07-01 14:30:33 -07:00
|
|
|
(tcx.lang_items.fn_once_trait(), FnOnceOverloadedCall),
|
|
|
|
(tcx.lang_items.fn_mut_trait(), FnMutOverloadedCall),
|
|
|
|
(tcx.lang_items.fn_trait(), FnOverloadedCall)
|
2015-06-10 17:22:20 +01:00
|
|
|
] {
|
2014-07-01 14:30:33 -07:00
|
|
|
match maybe_function_trait {
|
|
|
|
Some(function_trait) if function_trait == trait_id => {
|
|
|
|
return overloaded_call_type
|
|
|
|
}
|
|
|
|
_ => continue,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
tcx.sess.bug("overloaded call didn't map to known function trait")
|
|
|
|
}
|
|
|
|
|
2016-02-29 23:36:51 +00:00
|
|
|
fn from_method_id(tcx: &TyCtxt, method_id: DefId)
|
2014-07-01 14:30:33 -07:00
|
|
|
-> OverloadedCallType {
|
2015-07-02 08:52:36 +03:00
|
|
|
let method = tcx.impl_or_trait_item(method_id);
|
|
|
|
OverloadedCallType::from_trait_id(tcx, method.container().id())
|
2014-07-01 14:30:33 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-21 19:21:53 -04:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// The ExprUseVisitor type
|
|
|
|
//
|
|
|
|
// This is the code that actually walks the tree. Like
|
|
|
|
// mem_categorization, it requires a TYPER, which is a type that
|
|
|
|
// supplies types from the tree. After type checking is complete, you
|
|
|
|
// can just use the tcx as the typer.
|
2015-09-30 00:51:12 +03:00
|
|
|
pub struct ExprUseVisitor<'d, 't, 'a: 't, 'tcx:'a+'d> {
|
2015-06-29 17:46:24 -07:00
|
|
|
typer: &'t infer::InferCtxt<'a, 'tcx>,
|
|
|
|
mc: mc::MemCategorizationContext<'t, 'a, 'tcx>,
|
2015-09-01 11:31:09 -04:00
|
|
|
delegate: &'d mut Delegate<'tcx>,
|
2015-01-02 04:09:35 -05:00
|
|
|
}
|
|
|
|
|
2015-01-02 03:51:49 -05:00
|
|
|
// If the TYPER results in an error, it's because the type check
|
|
|
|
// failed (or will fail, when the error is uncovered and reported
|
|
|
|
// during writeback). In this case, we just ignore this part of the
|
|
|
|
// code.
|
|
|
|
//
|
|
|
|
// Note that this macro appears similar to try!(), but, unlike try!(),
|
|
|
|
// it does not propagate the error.
|
|
|
|
macro_rules! return_if_err {
|
|
|
|
($inp: expr) => (
|
|
|
|
match $inp {
|
|
|
|
Ok(v) => v,
|
2015-07-17 08:21:11 -04:00
|
|
|
Err(()) => {
|
|
|
|
debug!("mc reported err");
|
|
|
|
return
|
|
|
|
}
|
2015-01-02 03:51:49 -05:00
|
|
|
}
|
|
|
|
)
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
|
2014-12-03 00:39:53 -05:00
|
|
|
/// Whether the elements of an overloaded operation are passed by value or by reference
|
|
|
|
enum PassArgs {
|
|
|
|
ByValue,
|
|
|
|
ByRef,
|
|
|
|
}
|
|
|
|
|
2015-06-29 17:46:24 -07:00
|
|
|
impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
|
2015-12-22 17:24:26 -05:00
|
|
|
pub fn new(delegate: &'d mut (Delegate<'tcx>+'d),
|
2015-06-29 17:46:24 -07:00
|
|
|
typer: &'t infer::InferCtxt<'a, 'tcx>)
|
2015-10-27 00:46:11 +09:00
|
|
|
-> ExprUseVisitor<'d,'t,'a,'tcx> where 'tcx:'a+'d
|
2015-08-07 10:48:13 -04:00
|
|
|
{
|
2015-09-09 14:23:43 -04:00
|
|
|
let mc: mc::MemCategorizationContext<'t, 'a, 'tcx> =
|
|
|
|
mc::MemCategorizationContext::new(typer);
|
|
|
|
ExprUseVisitor { typer: typer, mc: mc, delegate: delegate }
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn walk_fn(&mut self,
|
2015-07-31 00:04:06 -07:00
|
|
|
decl: &hir::FnDecl,
|
|
|
|
body: &hir::Block) {
|
2014-04-21 19:21:53 -04:00
|
|
|
self.walk_arg_patterns(decl, body);
|
|
|
|
self.walk_block(body);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn walk_arg_patterns(&mut self,
|
2015-07-31 00:04:06 -07:00
|
|
|
decl: &hir::FnDecl,
|
|
|
|
body: &hir::Block) {
|
2015-01-31 12:20:46 -05:00
|
|
|
for arg in &decl.inputs {
|
2015-01-02 03:51:49 -05:00
|
|
|
let arg_ty = return_if_err!(self.typer.node_ty(arg.pat.id));
|
2014-04-21 19:21:53 -04:00
|
|
|
|
2015-08-20 01:46:28 +03:00
|
|
|
let fn_body_scope = self.tcx().region_maps.node_extent(body.id);
|
2014-04-21 19:21:53 -04:00
|
|
|
let arg_cmt = self.mc.cat_rvalue(
|
|
|
|
arg.id,
|
|
|
|
arg.pat.span,
|
2014-11-18 14:22:59 +01:00
|
|
|
ty::ReScope(fn_body_scope), // Args live only as long as the fn body.
|
2014-04-21 19:21:53 -04:00
|
|
|
arg_ty);
|
|
|
|
|
2016-02-09 22:00:20 +01:00
|
|
|
self.walk_irrefutable_pat(arg_cmt, &arg.pat);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-29 23:36:51 +00:00
|
|
|
fn tcx(&self) -> &'t TyCtxt<'tcx> {
|
2015-06-30 02:18:03 -07:00
|
|
|
self.typer.tcx
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
fn delegate_consume(&mut self,
|
|
|
|
consume_id: ast::NodeId,
|
|
|
|
consume_span: Span,
|
2014-09-29 22:11:30 +03:00
|
|
|
cmt: mc::cmt<'tcx>) {
|
2015-06-18 20:25:05 +03:00
|
|
|
debug!("delegate_consume(consume_id={}, cmt={:?})",
|
|
|
|
consume_id, cmt);
|
2015-01-24 17:25:07 -05:00
|
|
|
|
2015-01-02 04:01:30 -05:00
|
|
|
let mode = copy_or_move(self.typer, &cmt, DirectRefMove);
|
2014-04-21 19:21:53 -04:00
|
|
|
self.delegate.consume(consume_id, consume_span, cmt, mode);
|
|
|
|
}
|
|
|
|
|
2015-12-17 20:41:28 +03:00
|
|
|
fn consume_exprs(&mut self, exprs: &[P<hir::Expr>]) {
|
2015-01-31 12:20:46 -05:00
|
|
|
for expr in exprs {
|
2016-02-09 22:00:20 +01:00
|
|
|
self.consume_expr(&expr);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
pub fn consume_expr(&mut self, expr: &hir::Expr) {
|
2015-06-18 20:25:05 +03:00
|
|
|
debug!("consume_expr(expr={:?})", expr);
|
2014-04-21 19:21:53 -04:00
|
|
|
|
2015-01-02 03:51:49 -05:00
|
|
|
let cmt = return_if_err!(self.mc.cat_expr(expr));
|
2014-04-21 19:21:53 -04:00
|
|
|
self.delegate_consume(expr.id, expr.span, cmt);
|
2014-05-21 14:49:16 +02:00
|
|
|
self.walk_expr(expr);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
fn mutate_expr(&mut self,
|
2015-07-31 00:04:06 -07:00
|
|
|
assignment_expr: &hir::Expr,
|
|
|
|
expr: &hir::Expr,
|
2014-04-21 19:21:53 -04:00
|
|
|
mode: MutateMode) {
|
2015-01-02 03:51:49 -05:00
|
|
|
let cmt = return_if_err!(self.mc.cat_expr(expr));
|
2014-04-21 19:21:53 -04:00
|
|
|
self.delegate.mutate(assignment_expr.id, assignment_expr.span, cmt, mode);
|
|
|
|
self.walk_expr(expr);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn borrow_expr(&mut self,
|
2015-07-31 00:04:06 -07:00
|
|
|
expr: &hir::Expr,
|
2014-04-21 19:21:53 -04:00
|
|
|
r: ty::Region,
|
|
|
|
bk: ty::BorrowKind,
|
|
|
|
cause: LoanCause) {
|
2015-06-18 20:25:05 +03:00
|
|
|
debug!("borrow_expr(expr={:?}, r={:?}, bk={:?})",
|
|
|
|
expr, r, bk);
|
2014-04-21 19:21:53 -04:00
|
|
|
|
2015-01-02 03:51:49 -05:00
|
|
|
let cmt = return_if_err!(self.mc.cat_expr(expr));
|
2014-04-21 19:21:53 -04:00
|
|
|
self.delegate.borrow(expr.id, expr.span, cmt, r, bk, cause);
|
|
|
|
|
|
|
|
self.walk_expr(expr)
|
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
fn select_from_expr(&mut self, expr: &hir::Expr) {
|
2014-04-21 19:21:53 -04:00
|
|
|
self.walk_expr(expr)
|
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
pub fn walk_expr(&mut self, expr: &hir::Expr) {
|
2015-06-18 20:25:05 +03:00
|
|
|
debug!("walk_expr(expr={:?})", expr);
|
2014-04-21 19:21:53 -04:00
|
|
|
|
|
|
|
self.walk_adjustment(expr);
|
|
|
|
|
|
|
|
match expr.node {
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprPath(..) => { }
|
2014-04-21 19:21:53 -04:00
|
|
|
|
2015-02-01 09:59:46 +02:00
|
|
|
hir::ExprType(ref subexpr, _) => {
|
2016-02-09 22:00:20 +01:00
|
|
|
self.walk_expr(&subexpr)
|
2015-02-01 09:59:46 +02:00
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprUnary(hir::UnDeref, ref base) => { // *base
|
2016-02-09 22:00:20 +01:00
|
|
|
if !self.walk_overloaded_operator(expr, &base, Vec::new(), PassArgs::ByRef) {
|
|
|
|
self.select_from_expr(&base);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprField(ref base, _) => { // base.f
|
2016-02-09 22:00:20 +01:00
|
|
|
self.select_from_expr(&base);
|
2014-08-10 15:54:33 +12:00
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprTupField(ref base, _) => { // base.<n>
|
2016-02-09 22:00:20 +01:00
|
|
|
self.select_from_expr(&base);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprIndex(ref lhs, ref rhs) => { // lhs[rhs]
|
2015-01-03 13:33:54 +13:00
|
|
|
if !self.walk_overloaded_operator(expr,
|
2016-02-09 22:00:20 +01:00
|
|
|
&lhs,
|
|
|
|
vec![&rhs],
|
2015-03-21 19:30:06 -04:00
|
|
|
PassArgs::ByValue) {
|
2016-02-09 22:00:20 +01:00
|
|
|
self.select_from_expr(&lhs);
|
|
|
|
self.consume_expr(&rhs);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprCall(ref callee, ref args) => { // callee(args)
|
2016-02-09 22:00:20 +01:00
|
|
|
self.walk_callee(expr, &callee);
|
2014-04-21 19:21:53 -04:00
|
|
|
self.consume_exprs(args);
|
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprMethodCall(_, _, ref args) => { // callee.m(args)
|
2014-04-21 19:21:53 -04:00
|
|
|
self.consume_exprs(args);
|
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprStruct(_, ref fields, ref opt_with) => {
|
2014-09-07 20:09:06 +03:00
|
|
|
self.walk_struct_expr(expr, fields, opt_with);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprTup(ref exprs) => {
|
2014-04-21 19:21:53 -04:00
|
|
|
self.consume_exprs(exprs);
|
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprIf(ref cond_expr, ref then_blk, ref opt_else_expr) => {
|
2016-02-09 22:00:20 +01:00
|
|
|
self.consume_expr(&cond_expr);
|
|
|
|
self.walk_block(&then_blk);
|
2015-01-31 12:20:46 -05:00
|
|
|
if let Some(ref else_expr) = *opt_else_expr {
|
2016-02-09 22:00:20 +01:00
|
|
|
self.consume_expr(&else_expr);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprMatch(ref discr, ref arms, _) => {
|
2016-02-09 22:00:20 +01:00
|
|
|
let discr_cmt = return_if_err!(self.mc.cat_expr(&discr));
|
|
|
|
self.borrow_expr(&discr, ty::ReEmpty, ty::ImmBorrow, MatchDiscriminant);
|
2014-09-20 19:32:18 +02:00
|
|
|
|
|
|
|
// treatment of the discriminant is handled while walking the arms.
|
2015-01-31 12:20:46 -05:00
|
|
|
for arm in arms {
|
2014-09-16 15:24:56 +02:00
|
|
|
let mode = self.arm_move_mode(discr_cmt.clone(), arm);
|
|
|
|
let mode = mode.match_mode();
|
|
|
|
self.walk_arm(discr_cmt.clone(), arm, mode);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprVec(ref exprs) => {
|
2014-04-21 19:21:53 -04:00
|
|
|
self.consume_exprs(exprs);
|
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprAddrOf(m, ref base) => { // &base
|
2014-04-21 19:21:53 -04:00
|
|
|
// make sure that the thing we are pointing out stays valid
|
|
|
|
// for the lifetime `scope_r` of the resulting ptr:
|
2015-01-02 03:51:49 -05:00
|
|
|
let expr_ty = return_if_err!(self.typer.node_ty(expr.id));
|
2015-06-25 23:42:17 +03:00
|
|
|
if let ty::TyRef(&r, _) = expr_ty.sty {
|
|
|
|
let bk = ty::BorrowKind::from_mutbl(m);
|
2016-02-09 22:00:20 +01:00
|
|
|
self.borrow_expr(&base, r, bk, AddrOf);
|
2015-06-25 23:42:17 +03:00
|
|
|
}
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
|
2016-03-09 22:17:02 +02:00
|
|
|
hir::ExprInlineAsm(ref ia, ref outputs, ref inputs) => {
|
|
|
|
for (o, output) in ia.outputs.iter().zip(outputs) {
|
|
|
|
if o.is_indirect {
|
|
|
|
self.consume_expr(output);
|
2015-11-06 13:31:02 +00:00
|
|
|
} else {
|
2016-03-09 22:17:02 +02:00
|
|
|
self.mutate_expr(expr, output,
|
|
|
|
if o.is_rw {
|
2016-01-06 13:16:30 +01:00
|
|
|
MutateMode::WriteAndRead
|
|
|
|
} else {
|
|
|
|
MutateMode::JustWrite
|
|
|
|
});
|
2015-11-06 13:31:02 +00:00
|
|
|
}
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
2016-03-09 22:17:02 +02:00
|
|
|
self.consume_exprs(inputs);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprBreak(..) |
|
|
|
|
hir::ExprAgain(..) |
|
|
|
|
hir::ExprLit(..) => {}
|
2014-04-21 19:21:53 -04:00
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprLoop(ref blk, _) => {
|
2016-02-09 22:00:20 +01:00
|
|
|
self.walk_block(&blk);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprWhile(ref cond_expr, ref blk, _) => {
|
2016-02-09 22:00:20 +01:00
|
|
|
self.consume_expr(&cond_expr);
|
|
|
|
self.walk_block(&blk);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprUnary(op, ref lhs) => {
|
|
|
|
let pass_args = if ::rustc_front::util::is_by_value_unop(op) {
|
2014-12-15 16:16:48 -05:00
|
|
|
PassArgs::ByValue
|
|
|
|
} else {
|
|
|
|
PassArgs::ByRef
|
|
|
|
};
|
|
|
|
|
2016-02-09 22:00:20 +01:00
|
|
|
if !self.walk_overloaded_operator(expr, &lhs, Vec::new(), pass_args) {
|
|
|
|
self.consume_expr(&lhs);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprBinary(op, ref lhs, ref rhs) => {
|
|
|
|
let pass_args = if ::rustc_front::util::is_by_value_binop(op.node) {
|
2014-12-03 00:39:53 -05:00
|
|
|
PassArgs::ByValue
|
|
|
|
} else {
|
|
|
|
PassArgs::ByRef
|
|
|
|
};
|
|
|
|
|
2016-02-09 22:00:20 +01:00
|
|
|
if !self.walk_overloaded_operator(expr, &lhs, vec![&rhs], pass_args) {
|
|
|
|
self.consume_expr(&lhs);
|
|
|
|
self.consume_expr(&rhs);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprBlock(ref blk) => {
|
2016-02-09 22:00:20 +01:00
|
|
|
self.walk_block(&blk);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprRet(ref opt_expr) => {
|
2015-01-31 12:20:46 -05:00
|
|
|
if let Some(ref expr) = *opt_expr {
|
2016-02-09 22:00:20 +01:00
|
|
|
self.consume_expr(&expr);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprAssign(ref lhs, ref rhs) => {
|
2016-02-09 22:00:20 +01:00
|
|
|
self.mutate_expr(expr, &lhs, MutateMode::JustWrite);
|
|
|
|
self.consume_expr(&rhs);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprCast(ref base, _) => {
|
2016-02-09 22:00:20 +01:00
|
|
|
self.consume_expr(&base);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
|
2015-09-10 19:16:57 -05:00
|
|
|
hir::ExprAssignOp(op, ref lhs, ref rhs) => {
|
2015-09-17 00:29:26 -05:00
|
|
|
// NB All our assignment operations take the RHS by value
|
|
|
|
assert!(::rustc_front::util::is_by_value_binop(op.node));
|
2015-09-10 19:16:57 -05:00
|
|
|
|
2015-09-17 00:29:26 -05:00
|
|
|
if !self.walk_overloaded_operator(expr, lhs, vec![rhs], PassArgs::ByValue) {
|
2016-02-09 22:00:20 +01:00
|
|
|
self.mutate_expr(expr, &lhs, MutateMode::WriteAndRead);
|
|
|
|
self.consume_expr(&rhs);
|
2015-09-10 19:16:57 -05:00
|
|
|
}
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprRepeat(ref base, ref count) => {
|
2016-02-09 22:00:20 +01:00
|
|
|
self.consume_expr(&base);
|
|
|
|
self.consume_expr(&count);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprClosure(..) => {
|
2014-04-21 19:21:53 -04:00
|
|
|
self.walk_captures(expr)
|
|
|
|
}
|
|
|
|
|
2015-09-24 18:00:08 +03:00
|
|
|
hir::ExprBox(ref base) => {
|
2016-02-09 22:00:20 +01:00
|
|
|
self.consume_expr(&base);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
fn walk_callee(&mut self, call: &hir::Expr, callee: &hir::Expr) {
|
2015-01-02 03:51:49 -05:00
|
|
|
let callee_ty = return_if_err!(self.typer.expr_ty_adjusted(callee));
|
2015-06-18 20:25:05 +03:00
|
|
|
debug!("walk_callee: callee={:?} callee_ty={:?}",
|
|
|
|
callee, callee_ty);
|
2015-08-20 01:46:28 +03:00
|
|
|
let call_scope = self.tcx().region_maps.node_extent(call.id);
|
2014-10-31 10:51:16 +02:00
|
|
|
match callee_ty.sty {
|
2015-06-13 13:15:03 -07:00
|
|
|
ty::TyFnDef(..) | ty::TyFnPtr(_) => {
|
2014-04-21 19:21:53 -04:00
|
|
|
self.consume_expr(callee);
|
|
|
|
}
|
2015-06-11 16:21:46 -07:00
|
|
|
ty::TyError => { }
|
2014-04-21 19:21:53 -04:00
|
|
|
_ => {
|
2014-07-01 14:30:33 -07:00
|
|
|
let overloaded_call_type =
|
2015-07-02 08:52:36 +03:00
|
|
|
match self.typer.node_method_id(ty::MethodCall::expr(call.id)) {
|
|
|
|
Some(method_id) => {
|
|
|
|
OverloadedCallType::from_method_id(self.tcx(), method_id)
|
2014-12-09 13:20:25 -05:00
|
|
|
}
|
|
|
|
None => {
|
|
|
|
self.tcx().sess.span_bug(
|
|
|
|
callee.span,
|
2015-06-18 20:25:05 +03:00
|
|
|
&format!("unexpected callee type {}", callee_ty))
|
2014-12-09 13:20:25 -05:00
|
|
|
}
|
|
|
|
};
|
2014-07-01 14:30:33 -07:00
|
|
|
match overloaded_call_type {
|
|
|
|
FnMutOverloadedCall => {
|
|
|
|
self.borrow_expr(callee,
|
2014-11-18 14:22:59 +01:00
|
|
|
ty::ReScope(call_scope),
|
2014-07-01 14:30:33 -07:00
|
|
|
ty::MutBorrow,
|
|
|
|
ClosureInvocation);
|
|
|
|
}
|
|
|
|
FnOverloadedCall => {
|
|
|
|
self.borrow_expr(callee,
|
2014-11-18 14:22:59 +01:00
|
|
|
ty::ReScope(call_scope),
|
2014-07-01 14:30:33 -07:00
|
|
|
ty::ImmBorrow,
|
|
|
|
ClosureInvocation);
|
2014-06-01 16:35:01 -07:00
|
|
|
}
|
2014-07-01 14:30:33 -07:00
|
|
|
FnOnceOverloadedCall => self.consume_expr(callee),
|
2014-06-01 16:35:01 -07:00
|
|
|
}
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
fn walk_stmt(&mut self, stmt: &hir::Stmt) {
|
2014-04-21 19:21:53 -04:00
|
|
|
match stmt.node {
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::StmtDecl(ref decl, _) => {
|
2014-04-21 19:21:53 -04:00
|
|
|
match decl.node {
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::DeclLocal(ref local) => {
|
2016-02-09 22:00:20 +01:00
|
|
|
self.walk_local(&local);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::DeclItem(_) => {
|
2014-04-21 19:21:53 -04:00
|
|
|
// we don't visit nested items in this visitor,
|
|
|
|
// only the fn body we were given.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::StmtExpr(ref expr, _) |
|
|
|
|
hir::StmtSemi(ref expr, _) => {
|
2016-02-09 22:00:20 +01:00
|
|
|
self.consume_expr(&expr);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
fn walk_local(&mut self, local: &hir::Local) {
|
2014-04-21 19:21:53 -04:00
|
|
|
match local.init {
|
|
|
|
None => {
|
|
|
|
let delegate = &mut self.delegate;
|
2016-02-09 22:00:20 +01:00
|
|
|
pat_util::pat_bindings(&self.typer.tcx.def_map, &local.pat,
|
2014-05-16 10:15:33 -07:00
|
|
|
|_, id, span, _| {
|
2014-04-21 19:21:53 -04:00
|
|
|
delegate.decl_without_init(id, span);
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2014-05-16 10:15:33 -07:00
|
|
|
Some(ref expr) => {
|
2014-04-21 19:21:53 -04:00
|
|
|
// Variable declarations with
|
|
|
|
// initializers are considered
|
|
|
|
// "assigns", which is handled by
|
|
|
|
// `walk_pat`:
|
2016-02-09 22:00:20 +01:00
|
|
|
self.walk_expr(&expr);
|
|
|
|
let init_cmt = return_if_err!(self.mc.cat_expr(&expr));
|
|
|
|
self.walk_irrefutable_pat(init_cmt, &local.pat);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-25 21:17:11 -05:00
|
|
|
/// Indicates that the value of `blk` will be consumed, meaning either copied or moved
|
|
|
|
/// depending on its type.
|
2015-07-31 00:04:06 -07:00
|
|
|
fn walk_block(&mut self, blk: &hir::Block) {
|
2014-10-15 02:25:34 -04:00
|
|
|
debug!("walk_block(blk.id={})", blk.id);
|
2014-04-21 19:21:53 -04:00
|
|
|
|
2015-01-31 12:20:46 -05:00
|
|
|
for stmt in &blk.stmts {
|
2015-12-07 17:17:41 +03:00
|
|
|
self.walk_stmt(stmt);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
|
2015-01-31 12:20:46 -05:00
|
|
|
if let Some(ref tail_expr) = blk.expr {
|
2016-02-09 22:00:20 +01:00
|
|
|
self.consume_expr(&tail_expr);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn walk_struct_expr(&mut self,
|
2015-07-31 00:04:06 -07:00
|
|
|
_expr: &hir::Expr,
|
2015-12-17 20:41:28 +03:00
|
|
|
fields: &[hir::Field],
|
2015-07-31 00:04:06 -07:00
|
|
|
opt_with: &Option<P<hir::Expr>>) {
|
2014-04-21 19:21:53 -04:00
|
|
|
// Consume the expressions supplying values for each field.
|
2015-01-31 12:20:46 -05:00
|
|
|
for field in fields {
|
2016-02-09 22:00:20 +01:00
|
|
|
self.consume_expr(&field.expr);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
|
2014-09-07 20:09:06 +03:00
|
|
|
let with_expr = match *opt_with {
|
|
|
|
Some(ref w) => &**w,
|
2014-04-21 19:21:53 -04:00
|
|
|
None => { return; }
|
|
|
|
};
|
|
|
|
|
2016-02-09 22:00:20 +01:00
|
|
|
let with_cmt = return_if_err!(self.mc.cat_expr(&with_expr));
|
2014-04-21 19:21:53 -04:00
|
|
|
|
|
|
|
// Select just those fields of the `with`
|
|
|
|
// expression that will actually be used
|
2015-08-02 22:52:50 +03:00
|
|
|
if let ty::TyStruct(def, substs) = with_cmt.ty.sty {
|
|
|
|
// Consume those fields of the with expression that are needed.
|
|
|
|
for with_field in &def.struct_variant().fields {
|
|
|
|
if !contains_field_named(with_field, fields) {
|
|
|
|
let cmt_field = self.mc.cat_field(
|
|
|
|
&*with_expr,
|
|
|
|
with_cmt.clone(),
|
|
|
|
with_field.name,
|
|
|
|
with_field.ty(self.tcx(), substs)
|
|
|
|
);
|
|
|
|
self.delegate_consume(with_expr.id, with_expr.span, cmt_field);
|
2015-01-02 03:57:50 -05:00
|
|
|
}
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
2015-08-02 22:52:50 +03:00
|
|
|
} else {
|
|
|
|
// the base expression should always evaluate to a
|
|
|
|
// struct; however, when EUV is run during typeck, it
|
|
|
|
// may not. This will generate an error earlier in typeck,
|
|
|
|
// so we can just ignore it.
|
|
|
|
if !self.tcx().sess.has_errors() {
|
|
|
|
self.tcx().sess.span_bug(
|
|
|
|
with_expr.span,
|
|
|
|
"with expression doesn't evaluate to a struct");
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
2015-08-02 22:52:50 +03:00
|
|
|
};
|
2014-04-21 19:21:53 -04:00
|
|
|
|
2014-11-05 15:05:01 -08:00
|
|
|
// walk the with expression so that complex expressions
|
|
|
|
// are properly handled.
|
|
|
|
self.walk_expr(with_expr);
|
|
|
|
|
2015-08-07 14:41:33 +03:00
|
|
|
fn contains_field_named(field: ty::FieldDef,
|
2015-12-17 20:41:28 +03:00
|
|
|
fields: &[hir::Field])
|
2014-04-21 19:21:53 -04:00
|
|
|
-> bool
|
|
|
|
{
|
|
|
|
fields.iter().any(
|
2015-09-20 14:00:18 +03:00
|
|
|
|f| f.name.node == field.name)
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Invoke the appropriate delegate calls for anything that gets
|
|
|
|
// consumed or borrowed as part of the automatic adjustment
|
|
|
|
// process.
|
2015-07-31 00:04:06 -07:00
|
|
|
fn walk_adjustment(&mut self, expr: &hir::Expr) {
|
2014-04-21 19:21:53 -04:00
|
|
|
let typer = self.typer;
|
2015-06-24 13:40:54 -07:00
|
|
|
//NOTE(@jroesch): mixed RefCell borrow causes crash
|
|
|
|
let adj = typer.adjustments().get(&expr.id).map(|x| x.clone());
|
|
|
|
if let Some(adjustment) = adj {
|
|
|
|
match adjustment {
|
2015-09-14 14:55:56 +03:00
|
|
|
adjustment::AdjustReifyFnPointer |
|
2016-02-11 18:31:20 +02:00
|
|
|
adjustment::AdjustUnsafeFnPointer |
|
|
|
|
adjustment::AdjustMutToConstPointer => {
|
2015-03-16 18:45:01 +02:00
|
|
|
// Creating a closure/fn-pointer or unsizing consumes
|
|
|
|
// the input and stores it into the resulting rvalue.
|
2016-02-11 18:31:20 +02:00
|
|
|
debug!("walk_adjustment: trivial adjustment");
|
2015-03-16 18:45:01 +02:00
|
|
|
let cmt_unadjusted =
|
|
|
|
return_if_err!(self.mc.cat_expr_unadjusted(expr));
|
|
|
|
self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
|
|
|
|
}
|
2015-09-14 14:55:56 +03:00
|
|
|
adjustment::AdjustDerefRef(ref adj) => {
|
2015-04-10 12:25:40 +12:00
|
|
|
self.walk_autoderefref(expr, adj);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-25 21:17:11 -05:00
|
|
|
/// Autoderefs for overloaded Deref calls in fact reference their receiver. That is, if we have
|
|
|
|
/// `(*x)` where `x` is of type `Rc<T>`, then this in fact is equivalent to `x.deref()`. Since
|
|
|
|
/// `deref()` is declared with `&self`, this is an autoref of `x`.
|
2014-04-21 19:21:53 -04:00
|
|
|
fn walk_autoderefs(&mut self,
|
2015-07-31 00:04:06 -07:00
|
|
|
expr: &hir::Expr,
|
2015-03-25 17:06:52 -07:00
|
|
|
autoderefs: usize) {
|
2015-06-18 20:25:05 +03:00
|
|
|
debug!("walk_autoderefs expr={:?} autoderefs={}", expr, autoderefs);
|
2014-04-21 19:21:53 -04:00
|
|
|
|
2015-01-26 15:46:12 -05:00
|
|
|
for i in 0..autoderefs {
|
2015-03-16 18:45:01 +02:00
|
|
|
let deref_id = ty::MethodCall::autoderef(expr.id, i as u32);
|
2014-04-21 19:21:53 -04:00
|
|
|
match self.typer.node_method_ty(deref_id) {
|
|
|
|
None => {}
|
|
|
|
Some(method_ty) => {
|
2015-01-02 03:51:49 -05:00
|
|
|
let cmt = return_if_err!(self.mc.cat_expr_autoderefd(expr, i));
|
2015-01-06 05:03:42 -05:00
|
|
|
|
|
|
|
// the method call infrastructure should have
|
|
|
|
// replaced all late-bound regions with variables:
|
2015-06-24 08:24:13 +03:00
|
|
|
let self_ty = method_ty.fn_sig().input(0);
|
2015-06-25 23:42:17 +03:00
|
|
|
let self_ty = self.tcx().no_late_bound_regions(&self_ty).unwrap();
|
2015-01-06 05:03:42 -05:00
|
|
|
|
2014-10-31 10:51:16 +02:00
|
|
|
let (m, r) = match self_ty.sty {
|
2015-06-11 16:21:46 -07:00
|
|
|
ty::TyRef(r, ref m) => (m.mutbl, r),
|
2014-04-21 19:21:53 -04:00
|
|
|
_ => self.tcx().sess.span_bug(expr.span,
|
2015-06-18 20:25:05 +03:00
|
|
|
&format!("bad overloaded deref type {:?}",
|
|
|
|
method_ty))
|
2014-04-21 19:21:53 -04:00
|
|
|
};
|
|
|
|
let bk = ty::BorrowKind::from_mutbl(m);
|
|
|
|
self.delegate.borrow(expr.id, expr.span, cmt,
|
2014-12-04 16:52:57 -08:00
|
|
|
*r, bk, AutoRef);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-08 04:31:51 -04:00
|
|
|
fn walk_autoderefref(&mut self,
|
2015-07-31 00:04:06 -07:00
|
|
|
expr: &hir::Expr,
|
2015-09-14 14:55:56 +03:00
|
|
|
adj: &adjustment::AutoDerefRef<'tcx>) {
|
2015-06-18 20:25:05 +03:00
|
|
|
debug!("walk_autoderefref expr={:?} adj={:?}",
|
|
|
|
expr,
|
|
|
|
adj);
|
2015-04-08 04:31:51 -04:00
|
|
|
|
|
|
|
self.walk_autoderefs(expr, adj.autoderefs);
|
|
|
|
|
2015-04-14 11:44:26 +12:00
|
|
|
let cmt_derefd =
|
|
|
|
return_if_err!(self.mc.cat_expr_autoderefd(expr, adj.autoderefs));
|
2015-04-08 04:31:51 -04:00
|
|
|
|
2015-04-14 11:44:26 +12:00
|
|
|
let cmt_refd =
|
|
|
|
self.walk_autoref(expr, cmt_derefd, adj.autoref);
|
|
|
|
|
|
|
|
if adj.unsize.is_some() {
|
|
|
|
// Unsizing consumes the thin pointer and produces a fat one.
|
|
|
|
self.delegate_consume(expr.id, expr.span, cmt_refd);
|
|
|
|
}
|
2015-04-08 04:31:51 -04:00
|
|
|
}
|
|
|
|
|
2015-04-10 12:25:40 +12:00
|
|
|
|
2015-04-08 04:31:51 -04:00
|
|
|
/// Walks the autoref `opt_autoref` applied to the autoderef'd
|
|
|
|
/// `expr`. `cmt_derefd` is the mem-categorized form of `expr`
|
|
|
|
/// after all relevant autoderefs have occurred. Because AutoRefs
|
|
|
|
/// can be recursive, this function is recursive: it first walks
|
|
|
|
/// deeply all the way down the autoref chain, and then processes
|
|
|
|
/// the autorefs on the way out. At each point, it returns the
|
|
|
|
/// `cmt` for the rvalue that will be produced by introduced an
|
|
|
|
/// autoref.
|
2014-04-21 19:21:53 -04:00
|
|
|
fn walk_autoref(&mut self,
|
2015-07-31 00:04:06 -07:00
|
|
|
expr: &hir::Expr,
|
2015-04-10 12:25:40 +12:00
|
|
|
cmt_base: mc::cmt<'tcx>,
|
2015-09-14 14:55:56 +03:00
|
|
|
opt_autoref: Option<adjustment::AutoRef<'tcx>>)
|
2015-04-08 04:31:51 -04:00
|
|
|
-> mc::cmt<'tcx>
|
|
|
|
{
|
2015-06-18 20:25:05 +03:00
|
|
|
debug!("walk_autoref(expr.id={} cmt_derefd={:?} opt_autoref={:?})",
|
2015-04-08 04:31:51 -04:00
|
|
|
expr.id,
|
2015-06-18 20:25:05 +03:00
|
|
|
cmt_base,
|
2015-04-08 04:31:51 -04:00
|
|
|
opt_autoref);
|
|
|
|
|
2015-04-10 12:25:40 +12:00
|
|
|
let cmt_base_ty = cmt_base.ty;
|
|
|
|
|
2015-04-08 04:31:51 -04:00
|
|
|
let autoref = match opt_autoref {
|
2015-04-10 12:25:40 +12:00
|
|
|
Some(ref autoref) => autoref,
|
2015-04-08 04:31:51 -04:00
|
|
|
None => {
|
2015-04-10 12:25:40 +12:00
|
|
|
// No AutoRef.
|
|
|
|
return cmt_base;
|
2015-04-08 04:31:51 -04:00
|
|
|
}
|
|
|
|
};
|
2014-04-21 19:21:53 -04:00
|
|
|
|
2015-03-16 18:45:01 +02:00
|
|
|
match *autoref {
|
2015-09-14 14:55:56 +03:00
|
|
|
adjustment::AutoPtr(r, m) => {
|
2014-04-21 19:21:53 -04:00
|
|
|
self.delegate.borrow(expr.id,
|
|
|
|
expr.span,
|
2015-04-10 12:25:40 +12:00
|
|
|
cmt_base,
|
2015-03-16 18:45:01 +02:00
|
|
|
*r,
|
2014-04-21 19:21:53 -04:00
|
|
|
ty::BorrowKind::from_mutbl(m),
|
DST coercions and DST structs
[breaking-change]
1. The internal layout for traits has changed from (vtable, data) to (data, vtable). If you were relying on this in unsafe transmutes, you might get some very weird and apparently unrelated errors. You should not be doing this! Prefer not to do this at all, but if you must, you should use raw::TraitObject rather than hardcoding rustc's internal representation into your code.
2. The minimal type of reference-to-vec-literals (e.g., `&[1, 2, 3]`) is now a fixed size vec (e.g., `&[int, ..3]`) where it used to be an unsized vec (e.g., `&[int]`). If you want the unszied type, you must explicitly give the type (e.g., `let x: &[_] = &[1, 2, 3]`). Note in particular where multiple blocks must have the same type (e.g., if and else clauses, vec elements), the compiler will not coerce to the unsized type without a hint. E.g., `[&[1], &[1, 2]]` used to be a valid expression of type '[&[int]]'. It no longer type checks since the first element now has type `&[int, ..1]` and the second has type &[int, ..2]` which are incompatible.
3. The type of blocks (including functions) must be coercible to the expected type (used to be a subtype). Mostly this makes things more flexible and not less (in particular, in the case of coercing function bodies to the return type). However, in some rare cases, this is less flexible. TBH, I'm not exactly sure of the exact effects. I think the change causes us to resolve inferred type variables slightly earlier which might make us slightly more restrictive. Possibly it only affects blocks with unreachable code. E.g., `if ... { fail!(); "Hello" }` used to type check, it no longer does. The fix is to add a semicolon after the string.
2014-08-04 14:20:11 +02:00
|
|
|
AutoRef);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
2015-04-08 04:31:51 -04:00
|
|
|
|
2015-09-14 14:55:56 +03:00
|
|
|
adjustment::AutoUnsafe(m) => {
|
2015-06-18 20:25:05 +03:00
|
|
|
debug!("walk_autoref: expr.id={} cmt_base={:?}",
|
2015-04-08 04:31:51 -04:00
|
|
|
expr.id,
|
2015-06-18 20:25:05 +03:00
|
|
|
cmt_base);
|
2015-04-08 04:31:51 -04:00
|
|
|
|
|
|
|
// Converting from a &T to *T (or &mut T to *mut T) is
|
|
|
|
// treated as borrowing it for the enclosing temporary
|
|
|
|
// scope.
|
2015-08-20 01:46:28 +03:00
|
|
|
let r = ty::ReScope(self.tcx().region_maps.node_extent(expr.id));
|
2015-04-08 04:31:51 -04:00
|
|
|
|
|
|
|
self.delegate.borrow(expr.id,
|
|
|
|
expr.span,
|
|
|
|
cmt_base,
|
|
|
|
r,
|
|
|
|
ty::BorrowKind::from_mutbl(m),
|
|
|
|
AutoUnsafe);
|
2015-03-16 16:26:28 -04:00
|
|
|
}
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
2015-04-08 04:31:51 -04:00
|
|
|
|
|
|
|
// Construct the categorization for the result of the autoref.
|
|
|
|
// This is always an rvalue, since we are producing a new
|
|
|
|
// (temporary) indirection.
|
|
|
|
|
2015-06-25 23:42:17 +03:00
|
|
|
let adj_ty = cmt_base_ty.adjust_for_autoref(self.tcx(), opt_autoref);
|
2015-04-08 04:31:51 -04:00
|
|
|
|
|
|
|
self.mc.cat_rvalue_node(expr.id, expr.span, adj_ty)
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
|
2015-04-08 04:31:51 -04:00
|
|
|
|
2015-03-30 14:03:18 +02:00
|
|
|
// When this returns true, it means that the expression *is* a
|
|
|
|
// method-call (i.e. via the operator-overload). This true result
|
|
|
|
// also implies that walk_overloaded_operator already took care of
|
|
|
|
// recursively processing the input arguments, and thus the caller
|
|
|
|
// should not do so.
|
2014-04-21 19:21:53 -04:00
|
|
|
fn walk_overloaded_operator(&mut self,
|
2015-07-31 00:04:06 -07:00
|
|
|
expr: &hir::Expr,
|
|
|
|
receiver: &hir::Expr,
|
|
|
|
rhs: Vec<&hir::Expr>,
|
2014-12-03 00:39:53 -05:00
|
|
|
pass_args: PassArgs)
|
2014-04-21 19:21:53 -04:00
|
|
|
-> bool
|
|
|
|
{
|
|
|
|
if !self.typer.is_method_call(expr.id) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-12-03 00:39:53 -05:00
|
|
|
match pass_args {
|
|
|
|
PassArgs::ByValue => {
|
2014-12-01 14:47:06 -05:00
|
|
|
self.consume_expr(receiver);
|
2015-01-31 12:20:46 -05:00
|
|
|
for &arg in &rhs {
|
2014-12-15 16:16:48 -05:00
|
|
|
self.consume_expr(arg);
|
|
|
|
}
|
2014-12-01 14:47:06 -05:00
|
|
|
|
|
|
|
return true;
|
|
|
|
},
|
2014-12-03 00:39:53 -05:00
|
|
|
PassArgs::ByRef => {},
|
2014-12-01 14:47:06 -05:00
|
|
|
}
|
|
|
|
|
2014-04-21 19:21:53 -04:00
|
|
|
self.walk_expr(receiver);
|
|
|
|
|
|
|
|
// Arguments (but not receivers) to overloaded operator
|
|
|
|
// methods are implicitly autoref'd which sadly does not use
|
|
|
|
// adjustments, so we must hardcode the borrow here.
|
|
|
|
|
2015-08-20 01:46:28 +03:00
|
|
|
let r = ty::ReScope(self.tcx().region_maps.node_extent(expr.id));
|
2014-04-21 19:21:53 -04:00
|
|
|
let bk = ty::ImmBorrow;
|
|
|
|
|
2015-01-31 12:20:46 -05:00
|
|
|
for &arg in &rhs {
|
2014-09-07 20:09:06 +03:00
|
|
|
self.borrow_expr(arg, r, bk, OverloadedOperator);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
fn arm_move_mode(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &hir::Arm) -> TrackMatchMode {
|
2014-09-16 15:24:56 +02:00
|
|
|
let mut mode = Unknown;
|
2015-01-31 12:20:46 -05:00
|
|
|
for pat in &arm.pats {
|
2016-02-09 22:00:20 +01:00
|
|
|
self.determine_pat_move_mode(discr_cmt.clone(), &pat, &mut mode);
|
2014-09-16 15:24:56 +02:00
|
|
|
}
|
|
|
|
mode
|
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
fn walk_arm(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &hir::Arm, mode: MatchMode) {
|
2015-01-31 12:20:46 -05:00
|
|
|
for pat in &arm.pats {
|
2016-02-09 22:00:20 +01:00
|
|
|
self.walk_pat(discr_cmt.clone(), &pat, mode);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
|
2015-01-31 12:20:46 -05:00
|
|
|
if let Some(ref guard) = arm.guard {
|
2016-02-09 22:00:20 +01:00
|
|
|
self.consume_expr(&guard);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
|
2016-02-09 22:00:20 +01:00
|
|
|
self.consume_expr(&arm.body);
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
|
2015-10-07 23:11:25 +01:00
|
|
|
/// Walks a pat that occurs in isolation (i.e. top-level of fn
|
2014-09-16 15:24:56 +02:00
|
|
|
/// arg or let binding. *Not* a match arm or nested pat.)
|
2015-07-31 00:04:06 -07:00
|
|
|
fn walk_irrefutable_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat) {
|
2014-09-16 15:24:56 +02:00
|
|
|
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>,
|
2015-07-31 00:04:06 -07:00
|
|
|
pat: &hir::Pat,
|
2015-02-12 12:32:37 -05:00
|
|
|
mode: &mut TrackMatchMode) {
|
2015-06-18 20:25:05 +03:00
|
|
|
debug!("determine_pat_move_mode cmt_discr={:?} pat={:?}", cmt_discr,
|
|
|
|
pat);
|
2015-01-02 03:51:49 -05:00
|
|
|
return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |_mc, cmt_pat, pat| {
|
2015-01-02 03:57:50 -05:00
|
|
|
let tcx = self.tcx();
|
|
|
|
let def_map = &self.tcx().def_map;
|
2015-11-04 06:26:00 -06:00
|
|
|
if pat_util::pat_is_binding(&def_map.borrow(), pat) {
|
2014-09-16 15:24:56 +02:00
|
|
|
match pat.node {
|
2016-02-14 15:25:12 +03:00
|
|
|
PatKind::Ident(hir::BindByRef(_), _, _) =>
|
2014-09-16 15:24:56 +02:00
|
|
|
mode.lub(BorrowingMatch),
|
2016-02-14 15:25:12 +03:00
|
|
|
PatKind::Ident(hir::BindByValue(_), _, _) => {
|
2015-01-02 04:01:30 -05:00
|
|
|
match copy_or_move(self.typer, &cmt_pat, PatBindingMove) {
|
2014-09-16 15:24:56 +02:00
|
|
|
Copy => mode.lub(CopyingMatch),
|
|
|
|
Move(_) => mode.lub(MovingMatch),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
tcx.sess.span_bug(
|
|
|
|
pat.span,
|
|
|
|
"binding pattern not an identifier");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-01-02 03:51:49 -05:00
|
|
|
}));
|
2014-09-16 15:24:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/// 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>,
|
2015-07-31 00:04:06 -07:00
|
|
|
pat: &hir::Pat,
|
2014-09-16 15:24:56 +02:00
|
|
|
match_mode: MatchMode) {
|
2015-06-18 20:25:05 +03:00
|
|
|
debug!("walk_pat cmt_discr={:?} pat={:?}", cmt_discr,
|
|
|
|
pat);
|
2014-09-16 15:24:56 +02:00
|
|
|
|
2014-04-21 19:21:53 -04:00
|
|
|
let mc = &self.mc;
|
|
|
|
let typer = self.typer;
|
2015-01-02 03:57:50 -05:00
|
|
|
let def_map = &self.tcx().def_map;
|
2014-04-21 19:21:53 -04:00
|
|
|
let delegate = &mut self.delegate;
|
2015-01-02 03:51:49 -05:00
|
|
|
return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |mc, cmt_pat, pat| {
|
2015-11-04 06:26:00 -06:00
|
|
|
if pat_util::pat_is_binding(&def_map.borrow(), pat) {
|
2015-06-30 02:18:03 -07:00
|
|
|
let tcx = typer.tcx;
|
2014-04-21 19:21:53 -04:00
|
|
|
|
2015-06-18 20:25:05 +03:00
|
|
|
debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}",
|
|
|
|
cmt_pat,
|
|
|
|
pat,
|
2014-09-16 15:24:56 +02:00
|
|
|
match_mode);
|
2014-04-21 19:21:53 -04:00
|
|
|
|
|
|
|
// pat_ty: the type of the binding being produced.
|
2015-01-02 03:51:49 -05:00
|
|
|
let pat_ty = return_if_err!(typer.node_ty(pat.id));
|
2014-04-21 19:21:53 -04:00
|
|
|
|
|
|
|
// Each match binding is effectively an assignment to the
|
|
|
|
// binding being produced.
|
2015-03-21 21:15:47 -04:00
|
|
|
let def = def_map.borrow().get(&pat.id).unwrap().full_def();
|
2015-01-02 03:57:50 -05:00
|
|
|
match mc.cat_def(pat.id, pat.span, pat_ty, def) {
|
|
|
|
Ok(binding_cmt) => {
|
2016-01-06 13:16:30 +01:00
|
|
|
delegate.mutate(pat.id, pat.span, binding_cmt, MutateMode::Init);
|
2015-01-02 03:57:50 -05:00
|
|
|
}
|
|
|
|
Err(_) => { }
|
|
|
|
}
|
2014-04-21 19:21:53 -04:00
|
|
|
|
|
|
|
// It is also a borrow or copy/move of the value being matched.
|
|
|
|
match pat.node {
|
2016-02-14 15:25:12 +03:00
|
|
|
PatKind::Ident(hir::BindByRef(m), _, _) => {
|
2015-06-25 23:42:17 +03:00
|
|
|
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);
|
|
|
|
}
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
2016-02-14 15:25:12 +03:00
|
|
|
PatKind::Ident(hir::BindByValue(_), _, _) => {
|
2015-01-02 04:01:30 -05:00
|
|
|
let mode = copy_or_move(typer, &cmt_pat, PatBindingMove);
|
2014-08-12 12:51:23 -07:00
|
|
|
debug!("walk_pat binding consuming pat");
|
2014-04-21 19:21:53 -04:00
|
|
|
delegate.consume_pat(pat, cmt_pat, mode);
|
|
|
|
}
|
|
|
|
_ => {
|
2015-01-02 03:57:50 -05:00
|
|
|
tcx.sess.span_bug(
|
2014-04-21 19:21:53 -04:00
|
|
|
pat.span,
|
|
|
|
"binding pattern not an identifier");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
match pat.node {
|
2016-02-14 15:25:12 +03:00
|
|
|
PatKind::Vec(_, Some(ref slice_pat), _) => {
|
2014-04-21 19:21:53 -04:00
|
|
|
// The `slice_pat` here creates a slice into
|
|
|
|
// the original vector. This is effectively a
|
|
|
|
// borrow of the elements of the vector being
|
|
|
|
// matched.
|
|
|
|
|
2014-12-03 13:30:02 -05:00
|
|
|
let (slice_cmt, slice_mutbl, slice_r) =
|
2016-02-09 22:00:20 +01:00
|
|
|
return_if_err!(mc.cat_slice_pattern(cmt_pat, &slice_pat));
|
2014-04-21 19:21:53 -04:00
|
|
|
|
|
|
|
// Note: We declare here that the borrow
|
|
|
|
// occurs upon entering the `[...]`
|
|
|
|
// pattern. This implies that something like
|
2014-12-30 21:19:41 +13:00
|
|
|
// `[a; b]` where `a` is a move is illegal,
|
2014-04-21 19:21:53 -04:00
|
|
|
// because the borrow is already in effect.
|
|
|
|
// In fact such a move would be safe-ish, but
|
|
|
|
// it effectively *requires* that we use the
|
|
|
|
// nulling out semantics to indicate when a
|
|
|
|
// value has been moved, which we are trying
|
|
|
|
// to move away from. Otherwise, how can we
|
|
|
|
// indicate that the first element in the
|
|
|
|
// vector has been moved? Eventually, we
|
|
|
|
// could perhaps modify this rule to permit
|
|
|
|
// `[..a, b]` where `b` is a move, because in
|
|
|
|
// that case we can adjust the length of the
|
|
|
|
// original vec accordingly, but we'd have to
|
|
|
|
// make trans do the right thing, and it would
|
2015-05-04 21:33:51 -04:00
|
|
|
// only work for `Box<[T]>`s. It seems simpler
|
2014-04-21 19:21:53 -04:00
|
|
|
// to just require that people call
|
|
|
|
// `vec.pop()` or `vec.unshift()`.
|
|
|
|
let slice_bk = ty::BorrowKind::from_mutbl(slice_mutbl);
|
|
|
|
delegate.borrow(pat.id, pat.span,
|
|
|
|
slice_cmt, slice_r,
|
|
|
|
slice_bk, RefBinding);
|
|
|
|
}
|
|
|
|
_ => { }
|
|
|
|
}
|
2014-09-16 15:24:56 +02:00
|
|
|
}
|
2015-01-02 03:51:49 -05:00
|
|
|
}));
|
2014-09-16 15:24:56 +02:00
|
|
|
|
|
|
|
// 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.
|
2015-01-02 03:51:49 -05:00
|
|
|
return_if_err!(mc.cat_pattern(cmt_discr, pat, |mc, cmt_pat, pat| {
|
2014-09-16 15:24:56 +02:00
|
|
|
let def_map = def_map.borrow();
|
2015-06-30 02:18:03 -07:00
|
|
|
let tcx = typer.tcx;
|
2014-09-16 15:24:56 +02:00
|
|
|
|
|
|
|
match pat.node {
|
2016-02-16 00:40:38 +03:00
|
|
|
PatKind::TupleStruct(..) | PatKind::Path(..) | PatKind::QPath(..) |
|
2016-02-14 15:25:12 +03:00
|
|
|
PatKind::Ident(_, _, None) | PatKind::Struct(..) => {
|
2015-02-17 06:44:23 +02:00
|
|
|
match def_map.get(&pat.id).map(|d| d.full_def()) {
|
2014-09-16 15:24:56 +02:00
|
|
|
None => {
|
|
|
|
// no definition found: pat is not a
|
|
|
|
// struct or enum pattern.
|
|
|
|
}
|
|
|
|
|
2016-01-20 22:31:10 +03:00
|
|
|
Some(Def::Variant(enum_did, variant_did)) => {
|
2014-09-16 15:24:56 +02:00
|
|
|
let downcast_cmt =
|
2015-08-02 22:52:50 +03:00
|
|
|
if tcx.lookup_adt_def(enum_did).is_univariant() {
|
2014-09-16 15:24:56 +02:00
|
|
|
cmt_pat
|
|
|
|
} else {
|
|
|
|
let cmt_pat_ty = cmt_pat.ty;
|
|
|
|
mc.cat_downcast(pat, cmt_pat, cmt_pat_ty, variant_did)
|
|
|
|
};
|
|
|
|
|
2015-06-18 20:25:05 +03:00
|
|
|
debug!("variant downcast_cmt={:?} pat={:?}",
|
|
|
|
downcast_cmt,
|
|
|
|
pat);
|
2014-09-16 15:24:56 +02:00
|
|
|
|
|
|
|
delegate.matched_pat(pat, downcast_cmt, match_mode);
|
|
|
|
}
|
|
|
|
|
2016-01-20 22:31:10 +03:00
|
|
|
Some(Def::Struct(..)) | Some(Def::TyAlias(..)) => {
|
2014-09-16 15:24:56 +02:00
|
|
|
// A struct (in either the value or type
|
|
|
|
// namespace; we encounter the former on
|
|
|
|
// e.g. patterns for unit structs).
|
|
|
|
|
2015-06-18 20:25:05 +03:00
|
|
|
debug!("struct cmt_pat={:?} pat={:?}",
|
|
|
|
cmt_pat,
|
|
|
|
pat);
|
2014-09-16 15:24:56 +02:00
|
|
|
|
|
|
|
delegate.matched_pat(pat, cmt_pat, match_mode);
|
|
|
|
}
|
|
|
|
|
2016-01-20 22:31:10 +03:00
|
|
|
Some(Def::Const(..)) |
|
|
|
|
Some(Def::AssociatedConst(..)) |
|
|
|
|
Some(Def::Local(..)) => {
|
2014-09-16 15:24:56 +02:00
|
|
|
// This is a leaf (i.e. identifier binding
|
|
|
|
// or constant value to match); thus no
|
|
|
|
// `matched_pat` call.
|
|
|
|
}
|
|
|
|
|
|
|
|
Some(def) => {
|
2016-01-17 22:57:54 +03:00
|
|
|
// An enum type should never be in a pattern.
|
2016-01-20 22:31:10 +03:00
|
|
|
// Remaining cases are e.g. Def::Fn, to
|
2014-09-16 15:24:56 +02:00
|
|
|
// which identifiers within patterns
|
2015-01-02 03:57:50 -05:00
|
|
|
// should not resolve. However, we do
|
|
|
|
// encouter this when using the
|
|
|
|
// expr-use-visitor during typeck. So just
|
|
|
|
// ignore it, an error should have been
|
|
|
|
// reported.
|
|
|
|
|
|
|
|
if !tcx.sess.has_errors() {
|
2015-06-18 20:25:05 +03:00
|
|
|
let msg = format!("Pattern has unexpected def: {:?} and type {:?}",
|
2015-01-02 03:57:50 -05:00
|
|
|
def,
|
2015-06-18 20:25:05 +03:00
|
|
|
cmt_pat.ty);
|
2015-02-18 14:48:57 -05:00
|
|
|
tcx.sess.span_bug(pat.span, &msg[..])
|
2015-01-02 03:57:50 -05:00
|
|
|
}
|
2014-09-16 15:24:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-14 15:25:12 +03:00
|
|
|
PatKind::Ident(_, _, Some(_)) => {
|
2015-10-07 23:11:25 +01:00
|
|
|
// Do nothing; this is a binding (not an enum
|
2014-09-16 15:24:56 +02:00
|
|
|
// variant or struct), and the cat_pattern call
|
|
|
|
// will visit the substructure recursively.
|
|
|
|
}
|
|
|
|
|
2016-02-14 15:25:12 +03:00
|
|
|
PatKind::Wild | PatKind::Tup(..) | PatKind::Box(..) |
|
|
|
|
PatKind::Ref(..) | PatKind::Lit(..) | PatKind::Range(..) |
|
|
|
|
PatKind::Vec(..) => {
|
2014-09-16 15:24:56 +02:00
|
|
|
// Similarly, each of these cases does not
|
2015-10-07 23:11:25 +01:00
|
|
|
// correspond to an enum variant or struct, so we
|
2014-09-16 15:24:56 +02:00
|
|
|
// do not do any `matched_pat` calls for these
|
|
|
|
// cases either.
|
|
|
|
}
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
2015-01-02 03:51:49 -05:00
|
|
|
}));
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
fn walk_captures(&mut self, closure_expr: &hir::Expr) {
|
2015-06-18 20:25:05 +03:00
|
|
|
debug!("walk_captures({:?})", closure_expr);
|
2014-04-21 19:21:53 -04:00
|
|
|
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx().with_freevars(closure_expr.id, |freevars| {
|
2015-01-31 12:20:46 -05:00
|
|
|
for freevar in freevars {
|
2015-09-07 14:10:25 -04:00
|
|
|
let id_var = freevar.def.var_id();
|
2015-01-24 15:54:52 -05:00
|
|
|
let upvar_id = ty::UpvarId { var_id: id_var,
|
|
|
|
closure_expr_id: closure_expr.id };
|
|
|
|
let upvar_capture = self.typer.upvar_capture(upvar_id).unwrap();
|
|
|
|
let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.id,
|
|
|
|
closure_expr.span,
|
|
|
|
freevar.def));
|
|
|
|
match upvar_capture {
|
|
|
|
ty::UpvarCapture::ByValue => {
|
|
|
|
let mode = copy_or_move(self.typer, &cmt_var, CaptureMove);
|
|
|
|
self.delegate.consume(closure_expr.id, freevar.span, cmt_var, mode);
|
|
|
|
}
|
|
|
|
ty::UpvarCapture::ByRef(upvar_borrow) => {
|
|
|
|
self.delegate.borrow(closure_expr.id,
|
|
|
|
closure_expr.span,
|
|
|
|
cmt_var,
|
|
|
|
upvar_borrow.region,
|
|
|
|
upvar_borrow.kind,
|
|
|
|
ClosureCapture(freevar.span));
|
|
|
|
}
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
fn cat_captured_var(&mut self,
|
|
|
|
closure_id: ast::NodeId,
|
|
|
|
closure_span: Span,
|
2016-01-20 22:31:10 +03:00
|
|
|
upvar_def: Def)
|
2015-01-02 03:51:49 -05:00
|
|
|
-> mc::McResult<mc::cmt<'tcx>> {
|
2014-04-21 19:21:53 -04:00
|
|
|
// Create the cmt for the variable being borrowed, from the
|
|
|
|
// caller's perspective
|
2015-09-07 14:10:25 -04:00
|
|
|
let var_id = upvar_def.var_id();
|
2015-01-02 03:51:49 -05:00
|
|
|
let var_ty = try!(self.typer.node_ty(var_id));
|
2014-04-21 19:21:53 -04:00
|
|
|
self.mc.cat_def(closure_id, closure_span, var_ty, upvar_def)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-30 02:18:03 -07:00
|
|
|
fn copy_or_move<'a, 'tcx>(typer: &infer::InferCtxt<'a, 'tcx>,
|
2015-01-02 04:01:30 -05:00
|
|
|
cmt: &mc::cmt<'tcx>,
|
librustc: Make `Copy` opt-in.
This change makes the compiler no longer infer whether types (structures
and enumerations) implement the `Copy` trait (and thus are implicitly
copyable). Rather, you must implement `Copy` yourself via `impl Copy for
MyType {}`.
A new warning has been added, `missing_copy_implementations`, to warn
you if a non-generic public type has been added that could have
implemented `Copy` but didn't.
For convenience, you may *temporarily* opt out of this behavior by using
`#![feature(opt_out_copy)]`. Note though that this feature gate will never be
accepted and will be removed by the time that 1.0 is released, so you should
transition your code away from using it.
This breaks code like:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
Change this code to:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
impl Copy for Point2D {}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
This is the backwards-incompatible part of #13231.
Part of RFC #3.
[breaking-change]
2014-12-05 17:01:33 -08:00
|
|
|
move_reason: MoveReason)
|
2015-01-02 04:01:30 -05:00
|
|
|
-> ConsumeMode
|
|
|
|
{
|
2015-06-25 23:42:17 +03:00
|
|
|
if typer.type_moves_by_default(cmt.ty, cmt.span) {
|
librustc: Make `Copy` opt-in.
This change makes the compiler no longer infer whether types (structures
and enumerations) implement the `Copy` trait (and thus are implicitly
copyable). Rather, you must implement `Copy` yourself via `impl Copy for
MyType {}`.
A new warning has been added, `missing_copy_implementations`, to warn
you if a non-generic public type has been added that could have
implemented `Copy` but didn't.
For convenience, you may *temporarily* opt out of this behavior by using
`#![feature(opt_out_copy)]`. Note though that this feature gate will never be
accepted and will be removed by the time that 1.0 is released, so you should
transition your code away from using it.
This breaks code like:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
Change this code to:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
impl Copy for Point2D {}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
This is the backwards-incompatible part of #13231.
Part of RFC #3.
[breaking-change]
2014-12-05 17:01:33 -08:00
|
|
|
Move(move_reason)
|
|
|
|
} else {
|
|
|
|
Copy
|
|
|
|
}
|
2014-04-21 19:21:53 -04:00
|
|
|
}
|