2014-04-21 18:21:53 -05: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 20:17:11 -06: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 18:21:53 -05:00
|
|
|
|
2014-11-06 02:05:53 -06:00
|
|
|
pub use self::MutateMode::*;
|
|
|
|
pub use self::LoanCause::*;
|
|
|
|
pub use self::ConsumeMode::*;
|
|
|
|
pub use self::MoveReason::*;
|
2014-09-16 08:24:56 -05:00
|
|
|
pub use self::MatchMode::*;
|
|
|
|
use self::TrackMatchMode::*;
|
2014-11-06 02:05:53 -06:00
|
|
|
use self::OverloadedCallType::*;
|
|
|
|
|
2014-11-23 05:14:35 -06:00
|
|
|
use middle::{def, region, pat_util};
|
2014-08-18 10:29:44 -05:00
|
|
|
use middle::mem_categorization as mc;
|
2014-09-14 15:55:25 -05:00
|
|
|
use middle::mem_categorization::Typer;
|
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 19:01:33 -06:00
|
|
|
use middle::ty::{mod, ParameterEnvironment, Ty};
|
2014-11-25 13:21:20 -06:00
|
|
|
use middle::ty::{MethodCall, MethodObject, MethodTraitObject};
|
|
|
|
use middle::ty::{MethodOrigin, MethodParam, MethodTypeParam};
|
|
|
|
use middle::ty::{MethodStatic, MethodStaticUnboxedClosure};
|
2014-04-21 18:21:53 -05:00
|
|
|
use util::ppaux::Repr;
|
|
|
|
|
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 19:01:33 -06:00
|
|
|
use std::kinds;
|
2014-12-01 13:47:06 -06:00
|
|
|
use syntax::{ast, ast_util};
|
2014-09-07 12:09:06 -05:00
|
|
|
use syntax::ptr::P;
|
2014-07-01 16:30:33 -05:00
|
|
|
use syntax::codemap::Span;
|
2014-05-16 12:15:33 -05:00
|
|
|
|
2014-04-21 18:21:53 -05:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// The Delegate trait
|
|
|
|
|
2014-04-30 19:22:36 -05:00
|
|
|
/// This trait defines the callbacks you can expect to receive when
|
|
|
|
/// employing the ExprUseVisitor.
|
2014-09-29 14:11:30 -05:00
|
|
|
pub trait Delegate<'tcx> {
|
2014-04-21 18:21:53 -05:00
|
|
|
// The value found at `cmt` is either copied or moved, depending
|
|
|
|
// on mode.
|
|
|
|
fn consume(&mut self,
|
2014-04-28 07:50:50 -05:00
|
|
|
consume_id: ast::NodeId,
|
|
|
|
consume_span: Span,
|
2014-09-29 14:11:30 -05:00
|
|
|
cmt: mc::cmt<'tcx>,
|
2014-04-28 07:50:50 -05:00
|
|
|
mode: ConsumeMode);
|
2014-04-21 18:21:53 -05:00
|
|
|
|
2014-09-16 08:24:56 -05: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,
|
|
|
|
matched_pat: &ast::Pat,
|
|
|
|
cmt: mc::cmt<'tcx>,
|
|
|
|
mode: MatchMode);
|
|
|
|
|
2014-04-21 18:21:53 -05: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,
|
2014-04-28 07:50:50 -05:00
|
|
|
consume_pat: &ast::Pat,
|
2014-09-29 14:11:30 -05:00
|
|
|
cmt: mc::cmt<'tcx>,
|
2014-04-28 07:50:50 -05:00
|
|
|
mode: ConsumeMode);
|
2014-04-21 18:21:53 -05: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 07:50:50 -05:00
|
|
|
borrow_id: ast::NodeId,
|
|
|
|
borrow_span: Span,
|
2014-09-29 14:11:30 -05:00
|
|
|
cmt: mc::cmt<'tcx>,
|
2014-04-28 07:50:50 -05:00
|
|
|
loan_region: ty::Region,
|
|
|
|
bk: ty::BorrowKind,
|
|
|
|
loan_cause: LoanCause);
|
2014-04-21 18:21:53 -05:00
|
|
|
|
|
|
|
// The local variable `id` is declared but not initialized.
|
|
|
|
fn decl_without_init(&mut self,
|
2014-05-19 00:53:01 -05:00
|
|
|
id: ast::NodeId,
|
|
|
|
span: Span);
|
2014-04-21 18:21:53 -05:00
|
|
|
|
|
|
|
// The path at `cmt` is being assigned to.
|
|
|
|
fn mutate(&mut self,
|
2014-04-28 07:50:50 -05:00
|
|
|
assignment_id: ast::NodeId,
|
|
|
|
assignment_span: Span,
|
2014-09-29 14:11:30 -05:00
|
|
|
assignee_cmt: mc::cmt<'tcx>,
|
2014-04-28 07:50:50 -05:00
|
|
|
mode: MutateMode);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
|
2014-12-14 22:03:34 -06:00
|
|
|
#[deriving(Copy, PartialEq, Show)]
|
2014-04-30 19:22:36 -05:00
|
|
|
pub enum LoanCause {
|
|
|
|
ClosureCapture(Span),
|
|
|
|
AddrOf,
|
|
|
|
AutoRef,
|
|
|
|
RefBinding,
|
|
|
|
OverloadedOperator,
|
2014-07-21 22:54:28 -05:00
|
|
|
ClosureInvocation,
|
|
|
|
ForLoop,
|
2014-09-20 12:32:18 -05:00
|
|
|
MatchDiscriminant
|
2014-04-30 19:22:36 -05:00
|
|
|
}
|
|
|
|
|
2014-12-14 22:03:34 -06:00
|
|
|
#[deriving(Copy, PartialEq, Show)]
|
2014-04-30 19:22:36 -05:00
|
|
|
pub enum ConsumeMode {
|
2014-06-06 13:59:33 -05:00
|
|
|
Copy, // reference to x where x has a type that copies
|
|
|
|
Move(MoveReason), // reference to x where x has a type that moves
|
|
|
|
}
|
|
|
|
|
2014-12-14 22:03:34 -06:00
|
|
|
#[deriving(Copy, PartialEq, Show)]
|
2014-06-06 13:59:33 -05:00
|
|
|
pub enum MoveReason {
|
|
|
|
DirectRefMove,
|
|
|
|
PatBindingMove,
|
|
|
|
CaptureMove,
|
2014-04-30 19:22:36 -05:00
|
|
|
}
|
|
|
|
|
2014-12-14 22:03:34 -06:00
|
|
|
#[deriving(Copy, PartialEq, Show)]
|
2014-09-16 08:24:56 -05:00
|
|
|
pub enum MatchMode {
|
|
|
|
NonBindingMatch,
|
|
|
|
BorrowingMatch,
|
|
|
|
CopyingMatch,
|
|
|
|
MovingMatch,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[deriving(PartialEq,Show)]
|
|
|
|
enum TrackMatchMode<T> {
|
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 19:01:33 -06:00
|
|
|
Unknown,
|
|
|
|
Definite(MatchMode),
|
|
|
|
Conflicting,
|
2014-09-16 08:24:56 -05:00
|
|
|
}
|
|
|
|
|
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 19:01:33 -06:00
|
|
|
impl<T> kinds::Copy for TrackMatchMode<T> {}
|
|
|
|
|
2014-09-16 08:24:56 -05:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-14 22:03:34 -06:00
|
|
|
#[deriving(Copy, PartialEq, Show)]
|
2014-04-30 19:22:36 -05:00
|
|
|
pub enum MutateMode {
|
2014-06-06 13:59:32 -05:00
|
|
|
Init,
|
2014-04-30 19:22:36 -05:00
|
|
|
JustWrite, // x = y
|
|
|
|
WriteAndRead, // x += y
|
|
|
|
}
|
|
|
|
|
2014-12-14 22:03:34 -06:00
|
|
|
#[deriving(Copy)]
|
2014-07-01 16:30:33 -05:00
|
|
|
enum OverloadedCallType {
|
|
|
|
FnOverloadedCall,
|
|
|
|
FnMutOverloadedCall,
|
|
|
|
FnOnceOverloadedCall,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl OverloadedCallType {
|
|
|
|
fn from_trait_id(tcx: &ty::ctxt, trait_id: ast::DefId)
|
|
|
|
-> OverloadedCallType {
|
|
|
|
for &(maybe_function_trait, overloaded_call_type) in [
|
|
|
|
(tcx.lang_items.fn_once_trait(), FnOnceOverloadedCall),
|
|
|
|
(tcx.lang_items.fn_mut_trait(), FnMutOverloadedCall),
|
|
|
|
(tcx.lang_items.fn_trait(), FnOverloadedCall)
|
|
|
|
].iter() {
|
|
|
|
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")
|
|
|
|
}
|
|
|
|
|
|
|
|
fn from_method_id(tcx: &ty::ctxt, method_id: ast::DefId)
|
|
|
|
-> OverloadedCallType {
|
2014-08-20 11:12:16 -05:00
|
|
|
let method_descriptor = match ty::impl_or_trait_item(tcx, method_id) {
|
|
|
|
ty::MethodTraitItem(ref method_descriptor) => {
|
|
|
|
(*method_descriptor).clone()
|
|
|
|
}
|
2014-08-05 21:44:21 -05:00
|
|
|
ty::TypeTraitItem(_) => {
|
|
|
|
tcx.sess.bug("overloaded call method wasn't in method map")
|
|
|
|
}
|
2014-08-20 11:12:16 -05:00
|
|
|
};
|
2014-07-01 16:30:33 -05:00
|
|
|
let impl_id = match method_descriptor.container {
|
|
|
|
ty::TraitContainer(_) => {
|
|
|
|
tcx.sess.bug("statically resolved overloaded call method \
|
|
|
|
belonged to a trait?!")
|
|
|
|
}
|
|
|
|
ty::ImplContainer(impl_id) => impl_id,
|
|
|
|
};
|
|
|
|
let trait_ref = match ty::impl_trait_ref(tcx, impl_id) {
|
|
|
|
None => {
|
|
|
|
tcx.sess.bug("statically resolved overloaded call impl \
|
|
|
|
didn't implement a trait?!")
|
|
|
|
}
|
|
|
|
Some(ref trait_ref) => (*trait_ref).clone(),
|
|
|
|
};
|
|
|
|
OverloadedCallType::from_trait_id(tcx, trait_ref.def_id)
|
|
|
|
}
|
|
|
|
|
2014-08-20 11:12:16 -05:00
|
|
|
fn from_unboxed_closure(tcx: &ty::ctxt, closure_did: ast::DefId)
|
|
|
|
-> OverloadedCallType {
|
|
|
|
let trait_did =
|
|
|
|
tcx.unboxed_closures
|
|
|
|
.borrow()
|
2014-11-06 11:25:16 -06:00
|
|
|
.get(&closure_did)
|
2014-08-20 11:12:16 -05:00
|
|
|
.expect("OverloadedCallType::from_unboxed_closure: didn't \
|
|
|
|
find closure id")
|
|
|
|
.kind
|
|
|
|
.trait_did(tcx);
|
|
|
|
OverloadedCallType::from_trait_id(tcx, trait_did)
|
|
|
|
}
|
|
|
|
|
2014-07-01 16:30:33 -05:00
|
|
|
fn from_method_origin(tcx: &ty::ctxt, origin: &MethodOrigin)
|
|
|
|
-> OverloadedCallType {
|
|
|
|
match *origin {
|
|
|
|
MethodStatic(def_id) => {
|
|
|
|
OverloadedCallType::from_method_id(tcx, def_id)
|
|
|
|
}
|
2014-05-29 00:26:56 -05:00
|
|
|
MethodStaticUnboxedClosure(def_id) => {
|
2014-08-20 11:12:16 -05:00
|
|
|
OverloadedCallType::from_unboxed_closure(tcx, def_id)
|
2014-05-29 00:26:56 -05:00
|
|
|
}
|
2014-10-05 19:36:53 -05:00
|
|
|
MethodTypeParam(MethodParam { ref trait_ref, .. }) |
|
|
|
|
MethodTraitObject(MethodObject { ref trait_ref, .. }) => {
|
2014-09-12 10:42:58 -05:00
|
|
|
OverloadedCallType::from_trait_id(tcx, trait_ref.def_id)
|
2014-07-01 16:30:33 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-21 18:21:53 -05: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.
|
|
|
|
|
2014-09-29 14:11:30 -05:00
|
|
|
pub struct ExprUseVisitor<'d,'t,'tcx,TYPER:'t> {
|
2014-08-27 20:46:52 -05:00
|
|
|
typer: &'t TYPER,
|
|
|
|
mc: mc::MemCategorizationContext<'t,TYPER>,
|
2014-11-20 14:08:02 -06:00
|
|
|
delegate: &'d mut (Delegate<'tcx>+'d),
|
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 19:01:33 -06:00
|
|
|
param_env: ParameterEnvironment<'tcx>,
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
|
2014-12-02 23:39:53 -06:00
|
|
|
/// Whether the elements of an overloaded operation are passed by value or by reference
|
|
|
|
enum PassArgs {
|
|
|
|
ByValue,
|
|
|
|
ByRef,
|
|
|
|
}
|
|
|
|
|
2014-09-29 14:11:30 -05:00
|
|
|
impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|
|
|
pub fn new(delegate: &'d mut Delegate<'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 19:01:33 -06:00
|
|
|
typer: &'t TYPER,
|
|
|
|
param_env: ParameterEnvironment<'tcx>)
|
2014-09-29 14:11:30 -05:00
|
|
|
-> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
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 19:01:33 -06:00
|
|
|
ExprUseVisitor {
|
|
|
|
typer: typer,
|
|
|
|
mc: mc::MemCategorizationContext::new(typer),
|
|
|
|
delegate: delegate,
|
|
|
|
param_env: param_env,
|
|
|
|
}
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn walk_fn(&mut self,
|
|
|
|
decl: &ast::FnDecl,
|
|
|
|
body: &ast::Block) {
|
|
|
|
self.walk_arg_patterns(decl, body);
|
|
|
|
self.walk_block(body);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn walk_arg_patterns(&mut self,
|
|
|
|
decl: &ast::FnDecl,
|
|
|
|
body: &ast::Block) {
|
|
|
|
for arg in decl.inputs.iter() {
|
2014-12-03 12:30:02 -06:00
|
|
|
let arg_ty = self.typer.node_ty(arg.pat.id);
|
2014-04-21 18:21:53 -05:00
|
|
|
|
2014-11-18 07:22:59 -06:00
|
|
|
let fn_body_scope = region::CodeExtent::from_node_id(body.id);
|
2014-04-21 18:21:53 -05:00
|
|
|
let arg_cmt = self.mc.cat_rvalue(
|
|
|
|
arg.id,
|
|
|
|
arg.pat.span,
|
2014-11-18 07:22:59 -06:00
|
|
|
ty::ReScope(fn_body_scope), // Args live only as long as the fn body.
|
2014-04-21 18:21:53 -05:00
|
|
|
arg_ty);
|
|
|
|
|
2014-09-16 08:24:56 -05:00
|
|
|
self.walk_irrefutable_pat(arg_cmt, &*arg.pat);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-22 07:56:37 -05:00
|
|
|
fn tcx(&self) -> &'t ty::ctxt<'tcx> {
|
2014-04-21 18:21:53 -05:00
|
|
|
self.typer.tcx()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn delegate_consume(&mut self,
|
|
|
|
consume_id: ast::NodeId,
|
|
|
|
consume_span: Span,
|
2014-09-29 14:11: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 19:01:33 -06:00
|
|
|
let mode = copy_or_move(self.tcx(),
|
|
|
|
cmt.ty,
|
|
|
|
&self.param_env,
|
|
|
|
DirectRefMove);
|
2014-04-21 18:21:53 -05:00
|
|
|
self.delegate.consume(consume_id, consume_span, cmt, mode);
|
|
|
|
}
|
|
|
|
|
2014-09-07 12:09:06 -05:00
|
|
|
fn consume_exprs(&mut self, exprs: &Vec<P<ast::Expr>>) {
|
2014-05-16 12:15:33 -05:00
|
|
|
for expr in exprs.iter() {
|
|
|
|
self.consume_expr(&**expr);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
rustc: Add `const` globals to the language
This change is an implementation of [RFC 69][rfc] which adds a third kind of
global to the language, `const`. This global is most similar to what the old
`static` was, and if you're unsure about what to use then you should use a
`const`.
The semantics of these three kinds of globals are:
* A `const` does not represent a memory location, but only a value. Constants
are translated as rvalues, which means that their values are directly inlined
at usage location (similar to a #define in C/C++). Constant values are, well,
constant, and can not be modified. Any "modification" is actually a
modification to a local value on the stack rather than the actual constant
itself.
Almost all values are allowed inside constants, whether they have interior
mutability or not. There are a few minor restrictions listed in the RFC, but
they should in general not come up too often.
* A `static` now always represents a memory location (unconditionally). Any
references to the same `static` are actually a reference to the same memory
location. Only values whose types ascribe to `Sync` are allowed in a `static`.
This restriction is in place because many threads may access a `static`
concurrently. Lifting this restriction (and allowing unsafe access) is a
future extension not implemented at this time.
* A `static mut` continues to always represent a memory location. All references
to a `static mut` continue to be `unsafe`.
This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:
* Statics may no longer be used in patterns. Statics now always represent a
memory location, which can sometimes be modified. To fix code, repurpose the
matched-on-`static` to a `const`.
static FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
change this code to:
const FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
* Statics may no longer refer to other statics by value. Due to statics being
able to change at runtime, allowing them to reference one another could
possibly lead to confusing semantics. If you are in this situation, use a
constant initializer instead. Note, however, that statics may reference other
statics by address, however.
* Statics may no longer be used in constant expressions, such as array lengths.
This is due to the same restrictions as listed above. Use a `const` instead.
[breaking-change]
[rfc]: https://github.com/rust-lang/rfcs/pull/246
2014-10-06 10:17:01 -05:00
|
|
|
pub fn consume_expr(&mut self, expr: &ast::Expr) {
|
2014-04-21 18:21:53 -05:00
|
|
|
debug!("consume_expr(expr={})", expr.repr(self.tcx()));
|
|
|
|
|
2014-12-03 12:30:02 -06:00
|
|
|
let cmt = self.mc.cat_expr(expr);
|
2014-04-21 18:21:53 -05:00
|
|
|
self.delegate_consume(expr.id, expr.span, cmt);
|
2014-05-21 07:49:16 -05:00
|
|
|
self.walk_expr(expr);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn mutate_expr(&mut self,
|
|
|
|
assignment_expr: &ast::Expr,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
mode: MutateMode) {
|
2014-12-03 12:30:02 -06:00
|
|
|
let cmt = self.mc.cat_expr(expr);
|
2014-04-21 18:21:53 -05:00
|
|
|
self.delegate.mutate(assignment_expr.id, assignment_expr.span, cmt, mode);
|
|
|
|
self.walk_expr(expr);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn borrow_expr(&mut self,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
r: ty::Region,
|
|
|
|
bk: ty::BorrowKind,
|
|
|
|
cause: LoanCause) {
|
|
|
|
debug!("borrow_expr(expr={}, r={}, bk={})",
|
|
|
|
expr.repr(self.tcx()), r.repr(self.tcx()), bk.repr(self.tcx()));
|
|
|
|
|
2014-12-03 12:30:02 -06:00
|
|
|
let cmt = self.mc.cat_expr(expr);
|
2014-04-21 18:21:53 -05:00
|
|
|
self.delegate.borrow(expr.id, expr.span, cmt, r, bk, cause);
|
|
|
|
|
|
|
|
// Note: Unlike consume, we can ignore ExprParen. cat_expr
|
|
|
|
// already skips over them, and walk will uncover any
|
|
|
|
// attachments or whatever.
|
|
|
|
self.walk_expr(expr)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn select_from_expr(&mut self, expr: &ast::Expr) {
|
|
|
|
self.walk_expr(expr)
|
|
|
|
}
|
|
|
|
|
librustc: Disallow mutation and assignment in pattern guards, and modify
the CFG for match statements.
There were two bugs in issue #14684. One was simply that the borrow
check didn't know about the correct CFG for match statements: the
pattern must be a predecessor of the guard. This disallows the bad
behavior if there are bindings in the pattern. But it isn't enough to
prevent the memory safety problem, because of wildcards; thus, this
patch introduces a more restrictive rule, which disallows assignments
and mutable borrows inside guards outright.
I discussed this with Niko and we decided this was the best plan of
action.
This breaks code that performs mutable borrows in pattern guards. Most
commonly, the code looks like this:
impl Foo {
fn f(&mut self, ...) {}
fn g(&mut self, ...) {
match bar {
Baz if self.f(...) => { ... }
_ => { ... }
}
}
}
Change this code to not use a guard. For example:
impl Foo {
fn f(&mut self, ...) {}
fn g(&mut self, ...) {
match bar {
Baz => {
if self.f(...) {
...
} else {
...
}
}
_ => { ... }
}
}
}
Sometimes this can result in code duplication, but often it illustrates
a hidden memory safety problem.
Closes #14684.
[breaking-change]
2014-07-25 17:18:19 -05:00
|
|
|
pub fn walk_expr(&mut self, expr: &ast::Expr) {
|
2014-04-21 18:21:53 -05:00
|
|
|
debug!("walk_expr(expr={})", expr.repr(self.tcx()));
|
|
|
|
|
|
|
|
self.walk_adjustment(expr);
|
|
|
|
|
|
|
|
match expr.node {
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprParen(ref subexpr) => {
|
|
|
|
self.walk_expr(&**subexpr)
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
ast::ExprPath(..) => { }
|
|
|
|
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprUnary(ast::UnDeref, ref base) => { // *base
|
2014-12-02 23:39:53 -06:00
|
|
|
if !self.walk_overloaded_operator(expr, &**base, Vec::new(), PassArgs::ByRef) {
|
2014-05-16 12:15:33 -05:00
|
|
|
self.select_from_expr(&**base);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-23 05:14:35 -06:00
|
|
|
ast::ExprField(ref base, _) => { // base.f
|
2014-05-16 12:15:33 -05:00
|
|
|
self.select_from_expr(&**base);
|
2014-08-09 22:54:33 -05:00
|
|
|
}
|
|
|
|
|
2014-11-23 05:14:35 -06:00
|
|
|
ast::ExprTupField(ref base, _) => { // base.<n>
|
2014-08-09 22:54:33 -05:00
|
|
|
self.select_from_expr(&**base);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
|
2014-09-07 12:09:06 -05:00
|
|
|
ast::ExprIndex(ref lhs, ref rhs) => { // lhs[rhs]
|
2014-12-02 23:39:53 -06:00
|
|
|
if !self.walk_overloaded_operator(expr, &**lhs, vec![&**rhs], PassArgs::ByRef) {
|
2014-05-16 12:15:33 -05:00
|
|
|
self.select_from_expr(&**lhs);
|
|
|
|
self.consume_expr(&**rhs);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-15 03:48:58 -05:00
|
|
|
ast::ExprSlice(ref base, ref start, ref end, _) => { // base[start..end]
|
|
|
|
let args = match (start, end) {
|
|
|
|
(&Some(ref e1), &Some(ref e2)) => vec![&**e1, &**e2],
|
|
|
|
(&Some(ref e), &None) => vec![&**e],
|
|
|
|
(&None, &Some(ref e)) => vec![&**e],
|
|
|
|
(&None, &None) => Vec::new()
|
|
|
|
};
|
2014-12-02 23:39:53 -06:00
|
|
|
let overloaded =
|
|
|
|
self.walk_overloaded_operator(expr, &**base, args, PassArgs::ByRef);
|
2014-09-15 03:48:58 -05:00
|
|
|
assert!(overloaded);
|
|
|
|
}
|
|
|
|
|
2014-12-14 18:17:11 -06:00
|
|
|
ast::ExprRange(ref start, ref end) => {
|
|
|
|
self.consume_expr(&**start);
|
|
|
|
end.as_ref().map(|e| self.consume_expr(&**e));
|
2014-12-12 23:41:02 -06:00
|
|
|
}
|
|
|
|
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprCall(ref callee, ref args) => { // callee(args)
|
|
|
|
self.walk_callee(expr, &**callee);
|
2014-04-21 18:21:53 -05:00
|
|
|
self.consume_exprs(args);
|
|
|
|
}
|
|
|
|
|
|
|
|
ast::ExprMethodCall(_, _, ref args) => { // callee.m(args)
|
|
|
|
self.consume_exprs(args);
|
|
|
|
}
|
|
|
|
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprStruct(_, ref fields, ref opt_with) => {
|
2014-09-07 12:09:06 -05:00
|
|
|
self.walk_struct_expr(expr, fields, opt_with);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
ast::ExprTup(ref exprs) => {
|
|
|
|
self.consume_exprs(exprs);
|
|
|
|
}
|
|
|
|
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprIf(ref cond_expr, ref then_blk, ref opt_else_expr) => {
|
|
|
|
self.consume_expr(&**cond_expr);
|
|
|
|
self.walk_block(&**then_blk);
|
2014-04-21 18:21:53 -05:00
|
|
|
for else_expr in opt_else_expr.iter() {
|
2014-05-16 12:15:33 -05:00
|
|
|
self.consume_expr(&**else_expr);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-27 23:34:03 -05:00
|
|
|
ast::ExprIfLet(..) => {
|
|
|
|
self.tcx().sess.span_bug(expr.span, "non-desugared ExprIfLet");
|
|
|
|
}
|
2014-08-24 21:08:48 -05:00
|
|
|
|
2014-08-25 16:55:00 -05:00
|
|
|
ast::ExprMatch(ref discr, ref arms, _) => {
|
2014-12-03 12:30:02 -06:00
|
|
|
let discr_cmt = self.mc.cat_expr(&**discr);
|
2014-09-20 12:32:18 -05:00
|
|
|
self.borrow_expr(&**discr, ty::ReEmpty, ty::ImmBorrow, MatchDiscriminant);
|
|
|
|
|
|
|
|
// treatment of the discriminant is handled while walking the arms.
|
2014-04-21 18:21:53 -05:00
|
|
|
for arm in arms.iter() {
|
2014-09-16 08:24:56 -05: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 18:21:53 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ast::ExprVec(ref exprs) => {
|
|
|
|
self.consume_exprs(exprs);
|
|
|
|
}
|
|
|
|
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprAddrOf(m, ref base) => { // &base
|
2014-04-21 18:21:53 -05:00
|
|
|
// make sure that the thing we are pointing out stays valid
|
|
|
|
// for the lifetime `scope_r` of the resulting ptr:
|
|
|
|
let expr_ty = ty::expr_ty(self.tcx(), expr);
|
2014-10-24 14:14:37 -05:00
|
|
|
let r = ty::ty_region(self.tcx(), expr.span, expr_ty);
|
|
|
|
let bk = ty::BorrowKind::from_mutbl(m);
|
|
|
|
self.borrow_expr(&**base, r, bk, AddrOf);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
ast::ExprInlineAsm(ref ia) => {
|
2014-05-16 12:15:33 -05:00
|
|
|
for &(_, ref input) in ia.inputs.iter() {
|
|
|
|
self.consume_expr(&**input);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
|
2014-08-19 14:39:26 -05:00
|
|
|
for &(_, ref output, is_rw) in ia.outputs.iter() {
|
|
|
|
self.mutate_expr(expr, &**output,
|
|
|
|
if is_rw { WriteAndRead } else { JustWrite });
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ast::ExprBreak(..) |
|
|
|
|
ast::ExprAgain(..) |
|
|
|
|
ast::ExprLit(..) => {}
|
|
|
|
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprLoop(ref blk, _) => {
|
|
|
|
self.walk_block(&**blk);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
|
2014-07-25 19:12:51 -05:00
|
|
|
ast::ExprWhile(ref cond_expr, ref blk, _) => {
|
2014-05-16 12:15:33 -05:00
|
|
|
self.consume_expr(&**cond_expr);
|
|
|
|
self.walk_block(&**blk);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
|
2014-10-02 23:41:24 -05:00
|
|
|
ast::ExprWhileLet(..) => {
|
|
|
|
self.tcx().sess.span_bug(expr.span, "non-desugared ExprWhileLet");
|
|
|
|
}
|
|
|
|
|
2014-07-21 22:54:28 -05:00
|
|
|
ast::ExprForLoop(ref pat, ref head, ref blk, _) => {
|
|
|
|
// The pattern lives as long as the block.
|
|
|
|
debug!("walk_expr for loop case: blk id={}", blk.id);
|
2014-08-12 14:51:23 -05:00
|
|
|
self.consume_expr(&**head);
|
2014-07-21 22:54:28 -05:00
|
|
|
|
2014-08-12 14:51:23 -05:00
|
|
|
// Fetch the type of the value that the iteration yields to
|
|
|
|
// produce the pattern's categorized mutable type.
|
2014-12-03 12:30:02 -06:00
|
|
|
let pattern_type = self.typer.node_ty(pat.id);
|
2014-11-18 07:22:59 -06:00
|
|
|
let blk_scope = region::CodeExtent::from_node_id(blk.id);
|
2014-08-12 14:51:23 -05:00
|
|
|
let pat_cmt = self.mc.cat_rvalue(pat.id,
|
|
|
|
pat.span,
|
2014-11-18 07:22:59 -06:00
|
|
|
ty::ReScope(blk_scope),
|
2014-08-12 14:51:23 -05:00
|
|
|
pattern_type);
|
2014-09-16 08:24:56 -05:00
|
|
|
self.walk_irrefutable_pat(pat_cmt, &**pat);
|
2014-07-21 22:54:28 -05:00
|
|
|
|
|
|
|
self.walk_block(&**blk);
|
|
|
|
}
|
2014-04-21 18:21:53 -05:00
|
|
|
|
2014-12-15 15:16:48 -06:00
|
|
|
ast::ExprUnary(op, ref lhs) => {
|
|
|
|
let pass_args = if ast_util::is_by_value_unop(op) {
|
|
|
|
PassArgs::ByValue
|
|
|
|
} else {
|
|
|
|
PassArgs::ByRef
|
|
|
|
};
|
|
|
|
|
|
|
|
if !self.walk_overloaded_operator(expr, &**lhs, Vec::new(), pass_args) {
|
2014-05-16 12:15:33 -05:00
|
|
|
self.consume_expr(&**lhs);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-01 13:47:06 -06:00
|
|
|
ast::ExprBinary(op, ref lhs, ref rhs) => {
|
2014-12-02 23:39:53 -06:00
|
|
|
let pass_args = if ast_util::is_by_value_binop(op) {
|
|
|
|
PassArgs::ByValue
|
|
|
|
} else {
|
|
|
|
PassArgs::ByRef
|
|
|
|
};
|
|
|
|
|
|
|
|
if !self.walk_overloaded_operator(expr, &**lhs, vec![&**rhs], pass_args) {
|
2014-05-16 12:15:33 -05:00
|
|
|
self.consume_expr(&**lhs);
|
|
|
|
self.consume_expr(&**rhs);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprBlock(ref blk) => {
|
|
|
|
self.walk_block(&**blk);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
ast::ExprRet(ref opt_expr) => {
|
|
|
|
for expr in opt_expr.iter() {
|
2014-05-16 12:15:33 -05:00
|
|
|
self.consume_expr(&**expr);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprAssign(ref lhs, ref rhs) => {
|
|
|
|
self.mutate_expr(expr, &**lhs, JustWrite);
|
|
|
|
self.consume_expr(&**rhs);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprCast(ref base, _) => {
|
|
|
|
self.consume_expr(&**base);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprAssignOp(_, ref lhs, ref rhs) => {
|
2014-04-24 05:17:58 -05:00
|
|
|
// This will have to change if/when we support
|
|
|
|
// overloaded operators for `+=` and so forth.
|
2014-05-16 12:15:33 -05:00
|
|
|
self.mutate_expr(expr, &**lhs, WriteAndRead);
|
|
|
|
self.consume_expr(&**rhs);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprRepeat(ref base, ref count) => {
|
|
|
|
self.consume_expr(&**base);
|
|
|
|
self.consume_expr(&**count);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
|
2014-11-26 09:07:22 -06:00
|
|
|
ast::ExprClosure(..) => {
|
2014-04-21 18:21:53 -05:00
|
|
|
self.walk_captures(expr)
|
|
|
|
}
|
|
|
|
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::ExprBox(ref place, ref base) => {
|
2014-12-16 07:30:30 -06:00
|
|
|
match *place {
|
|
|
|
Some(ref place) => self.consume_expr(&**place),
|
|
|
|
None => {}
|
|
|
|
}
|
2014-05-16 12:15:33 -05:00
|
|
|
self.consume_expr(&**base);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
ast::ExprMac(..) => {
|
|
|
|
self.tcx().sess.span_bug(
|
|
|
|
expr.span,
|
|
|
|
"macro expression remains after expansion");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn walk_callee(&mut self, call: &ast::Expr, callee: &ast::Expr) {
|
2014-12-03 12:30:02 -06:00
|
|
|
let callee_ty = self.typer.expr_ty_adjusted(callee);
|
2014-04-21 18:21:53 -05:00
|
|
|
debug!("walk_callee: callee={} callee_ty={}",
|
|
|
|
callee.repr(self.tcx()), callee_ty.repr(self.tcx()));
|
2014-11-18 07:22:59 -06:00
|
|
|
let call_scope = region::CodeExtent::from_node_id(call.id);
|
2014-10-31 03:51:16 -05:00
|
|
|
match callee_ty.sty {
|
2014-04-21 18:21:53 -05:00
|
|
|
ty::ty_bare_fn(..) => {
|
|
|
|
self.consume_expr(callee);
|
|
|
|
}
|
|
|
|
ty::ty_closure(ref f) => {
|
|
|
|
match f.onceness {
|
|
|
|
ast::Many => {
|
|
|
|
self.borrow_expr(callee,
|
2014-11-18 07:22:59 -06:00
|
|
|
ty::ReScope(call_scope),
|
2014-04-21 18:21:53 -05:00
|
|
|
ty::UniqueImmBorrow,
|
|
|
|
ClosureInvocation);
|
|
|
|
}
|
|
|
|
ast::Once => {
|
|
|
|
self.consume_expr(callee);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
2014-07-01 16:30:33 -05:00
|
|
|
let overloaded_call_type =
|
|
|
|
match self.tcx()
|
|
|
|
.method_map
|
|
|
|
.borrow()
|
2014-11-06 11:25:16 -06:00
|
|
|
.get(&MethodCall::expr(call.id)) {
|
2014-07-01 16:30:33 -05:00
|
|
|
Some(ref method_callee) => {
|
|
|
|
OverloadedCallType::from_method_origin(
|
|
|
|
self.tcx(),
|
|
|
|
&method_callee.origin)
|
2014-06-01 18:35:01 -05:00
|
|
|
}
|
|
|
|
None => {
|
|
|
|
self.tcx().sess.span_bug(
|
|
|
|
callee.span,
|
2014-06-08 23:00:52 -05:00
|
|
|
format!("unexpected callee type {}",
|
2014-12-10 21:46:38 -06:00
|
|
|
callee_ty.repr(self.tcx()))[])
|
2014-07-01 16:30:33 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
match overloaded_call_type {
|
|
|
|
FnMutOverloadedCall => {
|
|
|
|
self.borrow_expr(callee,
|
2014-11-18 07:22:59 -06:00
|
|
|
ty::ReScope(call_scope),
|
2014-07-01 16:30:33 -05:00
|
|
|
ty::MutBorrow,
|
|
|
|
ClosureInvocation);
|
|
|
|
}
|
|
|
|
FnOverloadedCall => {
|
|
|
|
self.borrow_expr(callee,
|
2014-11-18 07:22:59 -06:00
|
|
|
ty::ReScope(call_scope),
|
2014-07-01 16:30:33 -05:00
|
|
|
ty::ImmBorrow,
|
|
|
|
ClosureInvocation);
|
2014-06-01 18:35:01 -05:00
|
|
|
}
|
2014-07-01 16:30:33 -05:00
|
|
|
FnOnceOverloadedCall => self.consume_expr(callee),
|
2014-06-01 18:35:01 -05:00
|
|
|
}
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn walk_stmt(&mut self, stmt: &ast::Stmt) {
|
|
|
|
match stmt.node {
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::StmtDecl(ref decl, _) => {
|
2014-04-21 18:21:53 -05:00
|
|
|
match decl.node {
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::DeclLocal(ref local) => {
|
2014-09-07 12:09:06 -05:00
|
|
|
self.walk_local(&**local);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
ast::DeclItem(_) => {
|
|
|
|
// we don't visit nested items in this visitor,
|
|
|
|
// only the fn body we were given.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-16 12:15:33 -05:00
|
|
|
ast::StmtExpr(ref expr, _) |
|
|
|
|
ast::StmtSemi(ref expr, _) => {
|
|
|
|
self.consume_expr(&**expr);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
ast::StmtMac(..) => {
|
2014-05-16 12:45:16 -05:00
|
|
|
self.tcx().sess.span_bug(stmt.span, "unexpanded stmt macro");
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-07 12:09:06 -05:00
|
|
|
fn walk_local(&mut self, local: &ast::Local) {
|
2014-04-21 18:21:53 -05:00
|
|
|
match local.init {
|
|
|
|
None => {
|
|
|
|
let delegate = &mut self.delegate;
|
2014-05-16 12:15:33 -05:00
|
|
|
pat_util::pat_bindings(&self.typer.tcx().def_map, &*local.pat,
|
|
|
|
|_, id, span, _| {
|
2014-04-21 18:21:53 -05:00
|
|
|
delegate.decl_without_init(id, span);
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2014-05-16 12:15:33 -05:00
|
|
|
Some(ref expr) => {
|
2014-04-21 18:21:53 -05:00
|
|
|
// Variable declarations with
|
|
|
|
// initializers are considered
|
|
|
|
// "assigns", which is handled by
|
|
|
|
// `walk_pat`:
|
2014-05-16 12:15:33 -05:00
|
|
|
self.walk_expr(&**expr);
|
2014-12-03 12:30:02 -06:00
|
|
|
let init_cmt = self.mc.cat_expr(&**expr);
|
2014-09-16 08:24:56 -05:00
|
|
|
self.walk_irrefutable_pat(init_cmt, &*local.pat);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-25 20:17:11 -06:00
|
|
|
/// Indicates that the value of `blk` will be consumed, meaning either copied or moved
|
|
|
|
/// depending on its type.
|
2014-04-21 18:21:53 -05:00
|
|
|
fn walk_block(&mut self, blk: &ast::Block) {
|
2014-10-15 01:25:34 -05:00
|
|
|
debug!("walk_block(blk.id={})", blk.id);
|
2014-04-21 18:21:53 -05:00
|
|
|
|
|
|
|
for stmt in blk.stmts.iter() {
|
2014-05-16 12:15:33 -05:00
|
|
|
self.walk_stmt(&**stmt);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
for tail_expr in blk.expr.iter() {
|
2014-05-16 12:15:33 -05:00
|
|
|
self.consume_expr(&**tail_expr);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn walk_struct_expr(&mut self,
|
|
|
|
_expr: &ast::Expr,
|
|
|
|
fields: &Vec<ast::Field>,
|
2014-09-07 12:09:06 -05:00
|
|
|
opt_with: &Option<P<ast::Expr>>) {
|
2014-04-21 18:21:53 -05:00
|
|
|
// Consume the expressions supplying values for each field.
|
|
|
|
for field in fields.iter() {
|
2014-05-16 12:15:33 -05:00
|
|
|
self.consume_expr(&*field.expr);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
|
2014-09-07 12:09:06 -05:00
|
|
|
let with_expr = match *opt_with {
|
|
|
|
Some(ref w) => &**w,
|
2014-04-21 18:21:53 -05:00
|
|
|
None => { return; }
|
|
|
|
};
|
|
|
|
|
2014-12-03 12:30:02 -06:00
|
|
|
let with_cmt = self.mc.cat_expr(&*with_expr);
|
2014-04-21 18:21:53 -05:00
|
|
|
|
|
|
|
// Select just those fields of the `with`
|
|
|
|
// expression that will actually be used
|
2014-10-31 03:51:16 -05:00
|
|
|
let with_fields = match with_cmt.ty.sty {
|
2014-04-21 18:21:53 -05:00
|
|
|
ty::ty_struct(did, ref substs) => {
|
|
|
|
ty::struct_fields(self.tcx(), did, substs)
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
self.tcx().sess.span_bug(
|
|
|
|
with_expr.span,
|
2014-05-16 12:45:16 -05:00
|
|
|
"with expression doesn't evaluate to a struct");
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Consume those fields of the with expression that are needed.
|
|
|
|
for with_field in with_fields.iter() {
|
|
|
|
if !contains_field_named(with_field, fields) {
|
2014-05-16 12:15:33 -05:00
|
|
|
let cmt_field = self.mc.cat_field(&*with_expr,
|
2014-04-21 18:21:53 -05:00
|
|
|
with_cmt.clone(),
|
2014-09-30 19:11:34 -05:00
|
|
|
with_field.name,
|
2014-04-21 18:21:53 -05:00
|
|
|
with_field.mt.ty);
|
|
|
|
self.delegate_consume(with_expr.id, with_expr.span, cmt_field);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-05 17:05:01 -06:00
|
|
|
// walk the with expression so that complex expressions
|
|
|
|
// are properly handled.
|
|
|
|
self.walk_expr(with_expr);
|
|
|
|
|
2014-04-21 18:21:53 -05:00
|
|
|
fn contains_field_named(field: &ty::field,
|
|
|
|
fields: &Vec<ast::Field>)
|
|
|
|
-> bool
|
|
|
|
{
|
|
|
|
fields.iter().any(
|
2014-09-30 19:11:34 -05:00
|
|
|
|f| f.ident.node.name == field.name)
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Invoke the appropriate delegate calls for anything that gets
|
|
|
|
// consumed or borrowed as part of the automatic adjustment
|
|
|
|
// process.
|
|
|
|
fn walk_adjustment(&mut self, expr: &ast::Expr) {
|
|
|
|
let typer = self.typer;
|
2014-11-06 11:25:16 -06:00
|
|
|
match typer.adjustments().borrow().get(&expr.id) {
|
2014-04-21 18:21:53 -05:00
|
|
|
None => { }
|
|
|
|
Some(adjustment) => {
|
|
|
|
match *adjustment {
|
2014-11-26 05:36:09 -06:00
|
|
|
ty::AdjustAddEnv(..) |
|
|
|
|
ty::AdjustReifyFnPointer(..) => {
|
|
|
|
// Creating a closure/fn-pointer consumes the
|
|
|
|
// input and stores it into the resulting
|
|
|
|
// rvalue.
|
|
|
|
debug!("walk_adjustment(AutoAddEnv|AdjustReifyFnPointer)");
|
2014-04-21 18:21:53 -05:00
|
|
|
let cmt_unadjusted =
|
2014-12-03 12:30:02 -06:00
|
|
|
self.mc.cat_expr_unadjusted(expr);
|
2014-04-21 18:21:53 -05:00
|
|
|
self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
|
|
|
|
}
|
2014-09-11 00:07:49 -05:00
|
|
|
ty::AdjustDerefRef(ty::AutoDerefRef {
|
2014-04-21 18:21:53 -05:00
|
|
|
autoref: ref opt_autoref,
|
|
|
|
autoderefs: n
|
|
|
|
}) => {
|
|
|
|
self.walk_autoderefs(expr, n);
|
|
|
|
|
|
|
|
match *opt_autoref {
|
|
|
|
None => { }
|
|
|
|
Some(ref r) => {
|
|
|
|
self.walk_autoref(expr, r, n);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-25 20:17:11 -06: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 18:21:53 -05:00
|
|
|
fn walk_autoderefs(&mut self,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
autoderefs: uint) {
|
|
|
|
debug!("walk_autoderefs expr={} autoderefs={}", expr.repr(self.tcx()), autoderefs);
|
|
|
|
|
|
|
|
for i in range(0, autoderefs) {
|
2014-11-25 13:21:20 -06:00
|
|
|
let deref_id = ty::MethodCall::autoderef(expr.id, i);
|
2014-04-21 18:21:53 -05:00
|
|
|
match self.typer.node_method_ty(deref_id) {
|
|
|
|
None => {}
|
|
|
|
Some(method_ty) => {
|
2014-12-03 12:30:02 -06:00
|
|
|
let cmt = self.mc.cat_expr_autoderefd(expr, i);
|
2014-10-15 01:05:01 -05:00
|
|
|
let self_ty = ty::ty_fn_args(method_ty)[0];
|
2014-10-31 03:51:16 -05:00
|
|
|
let (m, r) = match self_ty.sty {
|
2014-04-21 18:21:53 -05:00
|
|
|
ty::ty_rptr(r, ref m) => (m.mutbl, r),
|
|
|
|
_ => self.tcx().sess.span_bug(expr.span,
|
|
|
|
format!("bad overloaded deref type {}",
|
2014-12-10 21:46:38 -06:00
|
|
|
method_ty.repr(self.tcx()))[])
|
2014-04-21 18:21:53 -05:00
|
|
|
};
|
|
|
|
let bk = ty::BorrowKind::from_mutbl(m);
|
|
|
|
self.delegate.borrow(expr.id, expr.span, cmt,
|
|
|
|
r, bk, AutoRef);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn walk_autoref(&mut self,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
autoref: &ty::AutoRef,
|
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 07:20:11 -05:00
|
|
|
n: uint) {
|
|
|
|
debug!("walk_autoref expr={}", expr.repr(self.tcx()));
|
2014-04-21 18:21:53 -05:00
|
|
|
|
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 07:20:11 -05:00
|
|
|
// Match for unique trait coercions first, since we don't need the
|
|
|
|
// call to cat_expr_autoderefd.
|
|
|
|
match *autoref {
|
|
|
|
ty::AutoUnsizeUniq(ty::UnsizeVtable(..)) |
|
|
|
|
ty::AutoUnsize(ty::UnsizeVtable(..)) => {
|
|
|
|
assert!(n == 1, format!("Expected exactly 1 deref with Uniq \
|
|
|
|
AutoRefs, found: {}", n));
|
|
|
|
let cmt_unadjusted =
|
2014-12-03 12:30:02 -06:00
|
|
|
self.mc.cat_expr_unadjusted(expr);
|
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 07:20:11 -05:00
|
|
|
self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
2014-04-21 18:21:53 -05:00
|
|
|
|
2014-12-03 12:30:02 -06:00
|
|
|
let cmt_derefd = self.mc.cat_expr_autoderefd(expr, n);
|
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 07:20:11 -05:00
|
|
|
debug!("walk_adjustment: cmt_derefd={}",
|
|
|
|
cmt_derefd.repr(self.tcx()));
|
2014-04-21 18:21:53 -05:00
|
|
|
|
|
|
|
match *autoref {
|
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 07:20:11 -05:00
|
|
|
ty::AutoPtr(r, m, _) => {
|
2014-04-21 18:21:53 -05:00
|
|
|
self.delegate.borrow(expr.id,
|
|
|
|
expr.span,
|
|
|
|
cmt_derefd,
|
|
|
|
r,
|
|
|
|
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 07:20:11 -05:00
|
|
|
AutoRef);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
2014-08-27 00:07:28 -05:00
|
|
|
ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) | ty::AutoUnsafe(..) => {}
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn walk_overloaded_operator(&mut self,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
receiver: &ast::Expr,
|
2014-12-01 13:47:06 -06:00
|
|
|
rhs: Vec<&ast::Expr>,
|
2014-12-02 23:39:53 -06:00
|
|
|
pass_args: PassArgs)
|
2014-04-21 18:21:53 -05:00
|
|
|
-> bool
|
|
|
|
{
|
|
|
|
if !self.typer.is_method_call(expr.id) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-12-02 23:39:53 -06:00
|
|
|
match pass_args {
|
|
|
|
PassArgs::ByValue => {
|
2014-12-01 13:47:06 -06:00
|
|
|
self.consume_expr(receiver);
|
2014-12-15 15:16:48 -06:00
|
|
|
for &arg in rhs.iter() {
|
|
|
|
self.consume_expr(arg);
|
|
|
|
}
|
2014-12-01 13:47:06 -06:00
|
|
|
|
|
|
|
return true;
|
|
|
|
},
|
2014-12-02 23:39:53 -06:00
|
|
|
PassArgs::ByRef => {},
|
2014-12-01 13:47:06 -06:00
|
|
|
}
|
|
|
|
|
2014-04-21 18:21:53 -05: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.
|
|
|
|
|
2014-11-18 07:22:59 -06:00
|
|
|
let r = ty::ReScope(region::CodeExtent::from_node_id(expr.id));
|
2014-04-21 18:21:53 -05:00
|
|
|
let bk = ty::ImmBorrow;
|
|
|
|
|
2014-09-07 12:09:06 -05:00
|
|
|
for &arg in rhs.iter() {
|
|
|
|
self.borrow_expr(arg, r, bk, OverloadedOperator);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-09-16 08:24:56 -05:00
|
|
|
fn arm_move_mode(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &ast::Arm) -> TrackMatchMode<Span> {
|
|
|
|
let mut mode = Unknown;
|
2014-09-07 12:09:06 -05:00
|
|
|
for pat in arm.pats.iter() {
|
2014-09-16 08:24:56 -05:00
|
|
|
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);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
for guard in arm.guard.iter() {
|
2014-05-16 12:15:33 -05:00
|
|
|
self.consume_expr(&**guard);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
|
2014-05-16 12:15:33 -05:00
|
|
|
self.consume_expr(&*arm.body);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
|
2014-09-16 08:24:56 -05:00
|
|
|
/// 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()));
|
2014-12-03 12:30:02 -06:00
|
|
|
self.mc.cat_pattern(cmt_discr, pat, |_mc, cmt_pat, pat| {
|
2014-09-16 08:24:56 -05:00
|
|
|
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(_), _, _) => {
|
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 19:01:33 -06:00
|
|
|
match copy_or_move(tcx,
|
|
|
|
cmt_pat.ty,
|
|
|
|
&self.param_env,
|
|
|
|
PatBindingMove) {
|
2014-09-16 08:24:56 -05:00
|
|
|
Copy => mode.lub(CopyingMatch),
|
|
|
|
Move(_) => mode.lub(MovingMatch),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
tcx.sess.span_bug(
|
|
|
|
pat.span,
|
|
|
|
"binding pattern not an identifier");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-12-03 12:30:02 -06:00
|
|
|
});
|
2014-09-16 08:24:56 -05: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>,
|
|
|
|
pat: &ast::Pat,
|
|
|
|
match_mode: MatchMode) {
|
2014-04-21 18:21:53 -05:00
|
|
|
debug!("walk_pat cmt_discr={} pat={}", cmt_discr.repr(self.tcx()),
|
|
|
|
pat.repr(self.tcx()));
|
2014-09-16 08:24:56 -05:00
|
|
|
|
2014-04-21 18:21:53 -05:00
|
|
|
let mc = &self.mc;
|
|
|
|
let typer = self.typer;
|
|
|
|
let def_map = &self.typer.tcx().def_map;
|
|
|
|
let delegate = &mut self.delegate;
|
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 19:01:33 -06:00
|
|
|
let param_env = &mut self.param_env;
|
2014-12-03 12:30:02 -06:00
|
|
|
|
|
|
|
mc.cat_pattern(cmt_discr.clone(), pat, |mc, cmt_pat, pat| {
|
2014-04-21 18:21:53 -05:00
|
|
|
if pat_util::pat_is_binding(def_map, pat) {
|
|
|
|
let tcx = typer.tcx();
|
|
|
|
|
2014-09-16 08:24:56 -05:00
|
|
|
debug!("binding cmt_pat={} pat={} match_mode={}",
|
2014-04-21 18:21:53 -05:00
|
|
|
cmt_pat.repr(tcx),
|
2014-09-16 08:24:56 -05:00
|
|
|
pat.repr(tcx),
|
|
|
|
match_mode);
|
2014-04-21 18:21:53 -05:00
|
|
|
|
|
|
|
// pat_ty: the type of the binding being produced.
|
2014-12-03 12:30:02 -06:00
|
|
|
let pat_ty = typer.node_ty(pat.id);
|
2014-04-21 18:21:53 -05:00
|
|
|
|
|
|
|
// Each match binding is effectively an assignment to the
|
|
|
|
// binding being produced.
|
2014-11-07 13:35:18 -06:00
|
|
|
let def = def_map.borrow()[pat.id].clone();
|
2014-12-03 12:30:02 -06:00
|
|
|
let binding_cmt = mc.cat_def(pat.id, pat.span, pat_ty, def);
|
|
|
|
delegate.mutate(pat.id, pat.span, binding_cmt, Init);
|
2014-04-21 18:21:53 -05:00
|
|
|
|
|
|
|
// It is also a borrow or copy/move of the value being matched.
|
|
|
|
match pat.node {
|
|
|
|
ast::PatIdent(ast::BindByRef(m), _, _) => {
|
|
|
|
let (r, bk) = {
|
|
|
|
(ty::ty_region(tcx, pat.span, pat_ty),
|
|
|
|
ty::BorrowKind::from_mutbl(m))
|
|
|
|
};
|
|
|
|
delegate.borrow(pat.id, pat.span, cmt_pat,
|
|
|
|
r, bk, RefBinding);
|
|
|
|
}
|
|
|
|
ast::PatIdent(ast::BindByValue(_), _, _) => {
|
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 19:01:33 -06:00
|
|
|
let mode = copy_or_move(typer.tcx(),
|
|
|
|
cmt_pat.ty,
|
|
|
|
param_env,
|
|
|
|
PatBindingMove);
|
2014-08-12 14:51:23 -05:00
|
|
|
debug!("walk_pat binding consuming pat");
|
2014-04-21 18:21:53 -05:00
|
|
|
delegate.consume_pat(pat, cmt_pat, mode);
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
typer.tcx().sess.span_bug(
|
|
|
|
pat.span,
|
|
|
|
"binding pattern not an identifier");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
match pat.node {
|
2014-09-07 12:09:06 -05:00
|
|
|
ast::PatVec(_, Some(ref slice_pat), _) => {
|
2014-04-21 18:21:53 -05: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 12:30:02 -06:00
|
|
|
let (slice_cmt, slice_mutbl, slice_r) =
|
|
|
|
mc.cat_slice_pattern(cmt_pat, &**slice_pat);
|
2014-04-21 18:21:53 -05:00
|
|
|
|
|
|
|
// Note: We declare here that the borrow
|
|
|
|
// occurs upon entering the `[...]`
|
|
|
|
// pattern. This implies that something like
|
|
|
|
// `[a, ..b]` where `a` is a move is illegal,
|
|
|
|
// 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
|
|
|
|
// only work for `~` vectors. It seems simpler
|
|
|
|
// 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 08:24:56 -05:00
|
|
|
}
|
2014-12-03 12:30:02 -06:00
|
|
|
});
|
2014-09-16 08:24:56 -05: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.
|
2014-12-03 12:30:02 -06:00
|
|
|
mc.cat_pattern(cmt_discr, pat, |mc, cmt_pat, pat| {
|
2014-09-16 08:24:56 -05:00
|
|
|
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);
|
2014-12-10 21:46:38 -06:00
|
|
|
tcx.sess.span_bug(pat.span, msg[])
|
2014-09-16 08:24:56 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
Some(def) => {
|
|
|
|
// Remaining cases are e.g. DefFn, to
|
|
|
|
// which identifiers within patterns
|
|
|
|
// should not resolve.
|
|
|
|
|
|
|
|
let msg = format!("Pattern has unexpected def: {}", def);
|
2014-12-10 21:46:38 -06:00
|
|
|
tcx.sess.span_bug(pat.span, msg[])
|
2014-09-16 08:24:56 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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.
|
|
|
|
}
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
2014-12-03 12:30:02 -06:00
|
|
|
});
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn walk_captures(&mut self, closure_expr: &ast::Expr) {
|
|
|
|
debug!("walk_captures({})", closure_expr.repr(self.tcx()));
|
|
|
|
|
|
|
|
let tcx = self.typer.tcx();
|
2014-09-14 15:55:25 -05:00
|
|
|
ty::with_freevars(tcx, closure_expr.id, |freevars| {
|
|
|
|
match self.tcx().capture_mode(closure_expr.id) {
|
|
|
|
ast::CaptureByRef => {
|
2014-04-21 18:21:53 -05:00
|
|
|
self.walk_by_ref_captures(closure_expr, freevars);
|
|
|
|
}
|
2014-09-14 15:55:25 -05:00
|
|
|
ast::CaptureByValue => {
|
2014-04-21 18:21:53 -05:00
|
|
|
self.walk_by_value_captures(closure_expr, freevars);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
fn walk_by_ref_captures(&mut self,
|
|
|
|
closure_expr: &ast::Expr,
|
2014-09-14 15:55:25 -05:00
|
|
|
freevars: &[ty::Freevar]) {
|
2014-04-21 18:21:53 -05:00
|
|
|
for freevar in freevars.iter() {
|
2014-05-14 14:31:30 -05:00
|
|
|
let id_var = freevar.def.def_id().node;
|
2014-12-03 12:30:02 -06:00
|
|
|
let cmt_var = self.cat_captured_var(closure_expr.id,
|
|
|
|
closure_expr.span,
|
|
|
|
freevar.def);
|
2014-04-21 18:21:53 -05:00
|
|
|
|
|
|
|
// Lookup the kind of borrow the callee requires, as
|
|
|
|
// inferred by regionbk
|
|
|
|
let upvar_id = ty::UpvarId { var_id: id_var,
|
|
|
|
closure_expr_id: closure_expr.id };
|
2014-12-03 12:04:49 -06:00
|
|
|
let upvar_borrow = self.typer.upvar_borrow(upvar_id);
|
2014-04-21 18:21:53 -05:00
|
|
|
|
|
|
|
self.delegate.borrow(closure_expr.id,
|
|
|
|
closure_expr.span,
|
|
|
|
cmt_var,
|
|
|
|
upvar_borrow.region,
|
|
|
|
upvar_borrow.kind,
|
|
|
|
ClosureCapture(freevar.span));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn walk_by_value_captures(&mut self,
|
|
|
|
closure_expr: &ast::Expr,
|
2014-09-14 15:55:25 -05:00
|
|
|
freevars: &[ty::Freevar]) {
|
2014-04-21 18:21:53 -05:00
|
|
|
for freevar in freevars.iter() {
|
2014-12-03 12:30:02 -06:00
|
|
|
let cmt_var = self.cat_captured_var(closure_expr.id,
|
|
|
|
closure_expr.span,
|
|
|
|
freevar.def);
|
|
|
|
let mode = copy_or_move(self.tcx(), cmt_var.ty,
|
|
|
|
&self.param_env, CaptureMove);
|
2014-06-06 13:59:33 -05:00
|
|
|
self.delegate.consume(closure_expr.id, freevar.span, cmt_var, mode);
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn cat_captured_var(&mut self,
|
|
|
|
closure_id: ast::NodeId,
|
|
|
|
closure_span: Span,
|
2014-05-14 14:31:30 -05:00
|
|
|
upvar_def: def::Def)
|
2014-12-03 12:30:02 -06:00
|
|
|
-> mc::cmt<'tcx> {
|
2014-04-21 18:21:53 -05:00
|
|
|
// Create the cmt for the variable being borrowed, from the
|
|
|
|
// caller's perspective
|
2014-05-14 14:31:30 -05:00
|
|
|
let var_id = upvar_def.def_id().node;
|
2014-12-03 12:30:02 -06:00
|
|
|
let var_ty = self.typer.node_ty(var_id);
|
2014-04-21 18:21:53 -05:00
|
|
|
self.mc.cat_def(closure_id, closure_span, var_ty, upvar_def)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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 19:01:33 -06:00
|
|
|
fn copy_or_move<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|
|
|
ty: Ty<'tcx>,
|
|
|
|
param_env: &ParameterEnvironment<'tcx>,
|
|
|
|
move_reason: MoveReason)
|
|
|
|
-> ConsumeMode {
|
|
|
|
if ty::type_moves_by_default(tcx, ty, param_env) {
|
|
|
|
Move(move_reason)
|
|
|
|
} else {
|
|
|
|
Copy
|
|
|
|
}
|
2014-04-21 18:21:53 -05:00
|
|
|
}
|
|
|
|
|