<commit_before>// 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.

//! **Canonicalization** is the key to constructing a query in the
//! middle of type inference. Ordinarily, it is not possible to store
//! types from type inference in query keys, because they contain
//! references to inference variables whose lifetimes are too short
//! and so forth. Canonicalizing a value T1 using `canonicalize_query`
//! produces two things:
//!
//! - a value T2 where each unbound inference variable has been
//!   replaced with a **canonical variable**;
//! - a map M (of type `CanonicalVarValues`) from those canonical
//!   variables back to the original.
//!
//! We can then do queries using T2. These will give back constriants
//! on the canonical variables which can be translated, using the map
//! M, into constraints in our source context. This process of
//! translating the results back is done by the
//! `instantiate_query_result` method.
//!
//! For a more detailed look at what is happening here, check
//! out the [chapter in the rustc guide][c].
//!
//! [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html

use infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin};
use rustc_data_structures::indexed_vec::IndexVec;
use smallvec::SmallVec;
use rustc_data_structures::sync::Lrc;
use serialize::UseSpecializedDecodable;
use std::ops::Index;
use syntax::source_map::Span;
use ty::fold::TypeFoldable;
use ty::subst::Kind;
use ty::{self, CanonicalVar, Lift, Region, List, TyCtxt};

mod canonicalizer;

pub mod query_response;

mod substitute;

/// A "canonicalized" type `V` is one where all free inference
/// variables have been rewritten to "canonical vars". These are
/// numbered starting from 0 in order of first appearance.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
pub struct Canonical<'gcx, V> {
    pub variables: CanonicalVarInfos<'gcx>,
    pub value: V,
}

pub type CanonicalVarInfos<'gcx> = &'gcx List<CanonicalVarInfo>;

impl<'gcx> UseSpecializedDecodable for CanonicalVarInfos<'gcx> {}

/// A set of values corresponding to the canonical variables from some
/// `Canonical`. You can give these values to
/// `canonical_value.substitute` to substitute them into the canonical
/// value at the right places.
///
/// When you canonicalize a value `V`, you get back one of these
/// vectors with the original values that were replaced by canonical
/// variables. You will need to supply it later to instantiate the
/// canonicalized query response.
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
pub struct CanonicalVarValues<'tcx> {
    pub var_values: IndexVec<CanonicalVar, Kind<'tcx>>,
}

/// When we canonicalize a value to form a query, we wind up replacing
/// various parts of it with canonical variables. This struct stores
/// those replaced bits to remember for when we process the query
/// result.
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
pub struct OriginalQueryValues<'tcx> {
    /// This is equivalent to `CanonicalVarValues`, but using a
    /// `SmallVec` yields a significant performance win.
    pub var_values: SmallVec<[Kind<'tcx>; 8]>,
}

/// Information about a canonical variable that is included with the
/// canonical value. This is sufficient information for code to create
/// a copy of the canonical value in some other inference context,
/// with fresh inference variables replacing the canonical values.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
pub struct CanonicalVarInfo {
    pub kind: CanonicalVarKind,
}

/// Describes the "kind" of the canonical variable. This is a "kind"
/// in the type-theory sense of the term -- i.e., a "meta" type system
/// that analyzes type-like values.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
pub enum CanonicalVarKind {
    /// Some kind of type inference variable.
    Ty(CanonicalTyVarKind),

    /// Region variable `'?R`.
    Region,
}

/// Rust actually has more than one category of type variables;
/// notably, the type variables we create for literals (e.g., 22 or
/// 22.) can only be instantiated with integral/float types (e.g.,
/// usize or f32). In order to faithfully reproduce a type, we need to
/// know what set of types a given type variable can be unified with.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
pub enum CanonicalTyVarKind {
    /// General type variable `?T` that can be unified with arbitrary types.
    General,

    /// Integral type variable `?I` (that can only be unified with integral types).
    Int,

    /// Floating-point type variable `?F` (that can only be unified with float types).
    Float,
}

/// After we execute a query with a canonicalized key, we get back a
/// `Canonical<QueryResponse<..>>`. You can use
/// `instantiate_query_result` to access the data in this result.
#[derive(Clone, Debug)]
pub struct QueryResponse<'tcx, R> {
    pub var_values: CanonicalVarValues<'tcx>,
    pub region_constraints: Vec<QueryRegionConstraint<'tcx>>,
    pub certainty: Certainty,
    pub value: R,
}

pub type Canonicalized<'gcx, V> = Canonical<'gcx, <V as Lift<'gcx>>::Lifted>;

pub type CanonicalizedQueryResponse<'gcx, T> =
    Lrc<Canonical<'gcx, QueryResponse<'gcx, <T as Lift<'gcx>>::Lifted>>>;

/// Indicates whether or not we were able to prove the query to be
/// true.
#[derive(Copy, Clone, Debug)]
pub enum Certainty {
    /// The query is known to be true, presuming that you apply the
    /// given `var_values` and the region-constraints are satisfied.
    Proven,

    /// The query is not known to be true, but also not known to be
    /// false. The `var_values` represent *either* values that must
    /// hold in order for the query to be true, or helpful tips that
    /// *might* make it true. Currently rustc's trait solver cannot
    /// distinguish the two (e.g., due to our preference for where
    /// clauses over impls).
    ///
    /// After some unifiations and things have been done, it makes
    /// sense to try and prove again -- of course, at that point, the
    /// canonical form will be different, making this a distinct
    /// query.
    Ambiguous,
}

impl Certainty {
    pub fn is_proven(&self) -> bool {
        match self {
            Certainty::Proven => true,
            Certainty::Ambiguous => false,
        }
    }

    pub fn is_ambiguous(&self) -> bool {
        !self.is_proven()
    }
}

impl<'tcx, R> QueryResponse<'tcx, R> {
    pub fn is_proven(&self) -> bool {
        self.certainty.is_proven()
    }

    pub fn is_ambiguous(&self) -> bool {
        !self.is_proven()
    }
}

impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> {
    pub fn is_proven(&self) -> bool {
        self.value.is_proven()
    }

    pub fn is_ambiguous(&self) -> bool {
        !self.is_proven()
    }
}

impl<'gcx, V> Canonical<'gcx, V> {
    /// Allows you to map the `value` of a canonical while keeping the
    /// same set of bound variables.
    ///
    /// **WARNING:** This function is very easy to mis-use, hence the
    /// name!  In particular, the new value `W` must use all **the
    /// same type/region variables** in **precisely the same order**
    /// as the original! (The ordering is defined by the
    /// `TypeFoldable` implementation of the type in question.)
    ///
    /// An example of a **correct** use of this:
    ///
    /// ```rust,ignore (not real code)
    /// let a: Canonical<'_, T> = ...;
    /// let b: Canonical<'_, (T,)> = a.unchecked_map(|v| (v, ));
    /// ```
    ///
    /// An example of an **incorrect** use of this:
    ///
    /// ```rust,ignore (not real code)
    /// let a: Canonical<'tcx, T> = ...;
    /// let ty: Ty<'tcx> = ...;
    /// let b: Canonical<'tcx, (T, Ty<'tcx>)> = a.unchecked_map(|v| (v, ty));
    /// ```
    pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<'gcx, W> {
        let Canonical { variables, value } = self;
        Canonical { variables, value: map_op(value) }
    }
}

pub type QueryRegionConstraint<'tcx> = ty::Binder<ty::OutlivesPredicate<Kind<'tcx>, Region<'tcx>>>;

impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
    /// Creates a substitution S for the canonical value with fresh
    /// inference variables and applies it to the canonical value.
    /// Returns both the instantiated result *and* the substitution S.
    ///
    /// This is only meant to be invoked as part of constructing an
    /// inference context at the start of a query (see
    /// `InferCtxtBuilder::enter_with_canonical`).  It basically
    /// brings the canonical value "into scope" within your new infcx.
    ///
    /// At the end of processing, the substitution S (once
    /// canonicalized) then represents the values that you computed
    /// for each of the canonical inputs to your query.

    pub(in infer) fn instantiate_canonical_with_fresh_inference_vars<T>(
        &self,
        span: Span,
        canonical: &Canonical<'tcx, T>,
    ) -> (T, CanonicalVarValues<'tcx>)
    where
        T: TypeFoldable<'tcx>,
    {
        assert_eq!(self.universe(), ty::UniverseIndex::ROOT, "infcx not newly created");
        assert_eq!(self.type_variables.borrow().num_vars(), 0, "infcx not newly created");

        let canonical_inference_vars =
            self.fresh_inference_vars_for_canonical_vars(span, canonical.variables);
        let result = canonical.substitute(self.tcx, &canonical_inference_vars);
        (result, canonical_inference_vars)
    }

    /// Given the "infos" about the canonical variables from some
    /// canonical, creates fresh inference variables with the same
    /// characteristics. You can then use `substitute` to instantiate
    /// the canonical variable with these inference variables.
    fn fresh_inference_vars_for_canonical_vars(
        &self,
        span: Span,
        variables: &List<CanonicalVarInfo>,
    ) -> CanonicalVarValues<'tcx> {
        let var_values: IndexVec<CanonicalVar, Kind<'tcx>> = variables
            .iter()
            .map(|info| self.fresh_inference_var_for_canonical_var(span, *info))
            .collect();

        CanonicalVarValues { var_values }
    }

    /// Given the "info" about a canonical variable, creates a fresh
    /// inference variable with the same characteristics.
    fn fresh_inference_var_for_canonical_var(
        &self,
        span: Span,
        cv_info: CanonicalVarInfo,
    ) -> Kind<'tcx> {
        match cv_info.kind {
            CanonicalVarKind::Ty(ty_kind) => {
                let ty = match ty_kind {
                    CanonicalTyVarKind::General => {
                        self.next_ty_var(TypeVariableOrigin::MiscVariable(span))
                    }

                    CanonicalTyVarKind::Int => self.tcx.mk_int_var(self.next_int_var_id()),

                    CanonicalTyVarKind::Float => self.tcx.mk_float_var(self.next_float_var_id()),
                };
                ty.into()
            }

            CanonicalVarKind::Region => self
                .next_region_var(RegionVariableOrigin::MiscVariable(span))
                .into(),
        }
    }
}

CloneTypeFoldableAndLiftImpls! {
    ::infer::canonical::Certainty,
    ::infer::canonical::CanonicalVarInfo,
    ::infer::canonical::CanonicalVarKind,
}

CloneTypeFoldableImpls! {
    for <'tcx> {
        ::infer::canonical::CanonicalVarInfos<'tcx>,
    }
}

BraceStructTypeFoldableImpl! {
    impl<'tcx, C> TypeFoldable<'tcx> for Canonical<'tcx, C> {
        variables,
        value,
    } where C: TypeFoldable<'tcx>
}

BraceStructLiftImpl! {
    impl<'a, 'tcx, T> Lift<'tcx> for Canonical<'a, T> {
        type Lifted = Canonical<'tcx, T::Lifted>;
        variables, value
    } where T: Lift<'tcx>
}

impl<'tcx> CanonicalVarValues<'tcx> {
    fn len(&self) -> usize {
        self.var_values.len()
    }
}

impl<'a, 'tcx> IntoIterator for &'a CanonicalVarValues<'tcx> {
    type Item = Kind<'tcx>;
    type IntoIter = ::std::iter::Cloned<::std::slice::Iter<'a, Kind<'tcx>>>;

    fn into_iter(self) -> Self::IntoIter {
        self.var_values.iter().cloned()
    }
}

BraceStructLiftImpl! {
    impl<'a, 'tcx> Lift<'tcx> for CanonicalVarValues<'a> {
        type Lifted = CanonicalVarValues<'tcx>;
        var_values,
    }
}

BraceStructTypeFoldableImpl! {
    impl<'tcx> TypeFoldable<'tcx> for CanonicalVarValues<'tcx> {
        var_values,
    }
}

BraceStructTypeFoldableImpl! {
    impl<'tcx, R> TypeFoldable<'tcx> for QueryResponse<'tcx, R> {
        var_values, region_constraints, certainty, value
    } where R: TypeFoldable<'tcx>,
}

BraceStructLiftImpl! {
    impl<'a, 'tcx, R> Lift<'tcx> for QueryResponse<'a, R> {
        type Lifted = QueryResponse<'tcx, R::Lifted>;
        var_values, region_constraints, certainty, value
    } where R: Lift<'tcx>
}

impl<'tcx> Index<CanonicalVar> for CanonicalVarValues<'tcx> {
    type Output = Kind<'tcx>;

    fn index(&self, value: CanonicalVar) -> &Kind<'tcx> {
        &self.var_values[value]
    }
}
<commit_msg>make `instantiate_canonical_with_fresh_inference_vars` public again<commit_after>// 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.

//! **Canonicalization** is the key to constructing a query in the
//! middle of type inference. Ordinarily, it is not possible to store
//! types from type inference in query keys, because they contain
//! references to inference variables whose lifetimes are too short
//! and so forth. Canonicalizing a value T1 using `canonicalize_query`
//! produces two things:
//!
//! - a value T2 where each unbound inference variable has been
//!   replaced with a **canonical variable**;
//! - a map M (of type `CanonicalVarValues`) from those canonical
//!   variables back to the original.
//!
//! We can then do queries using T2. These will give back constriants
//! on the canonical variables which can be translated, using the map
//! M, into constraints in our source context. This process of
//! translating the results back is done by the
//! `instantiate_query_result` method.
//!
//! For a more detailed look at what is happening here, check
//! out the [chapter in the rustc guide][c].
//!
//! [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html

use infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin};
use rustc_data_structures::indexed_vec::IndexVec;
use smallvec::SmallVec;
use rustc_data_structures::sync::Lrc;
use serialize::UseSpecializedDecodable;
use std::ops::Index;
use syntax::source_map::Span;
use ty::fold::TypeFoldable;
use ty::subst::Kind;
use ty::{self, CanonicalVar, Lift, Region, List, TyCtxt};

mod canonicalizer;

pub mod query_response;

mod substitute;

/// A "canonicalized" type `V` is one where all free inference
/// variables have been rewritten to "canonical vars". These are
/// numbered starting from 0 in order of first appearance.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
pub struct Canonical<'gcx, V> {
    pub variables: CanonicalVarInfos<'gcx>,
    pub value: V,
}

pub type CanonicalVarInfos<'gcx> = &'gcx List<CanonicalVarInfo>;

impl<'gcx> UseSpecializedDecodable for CanonicalVarInfos<'gcx> {}

/// A set of values corresponding to the canonical variables from some
/// `Canonical`. You can give these values to
/// `canonical_value.substitute` to substitute them into the canonical
/// value at the right places.
///
/// When you canonicalize a value `V`, you get back one of these
/// vectors with the original values that were replaced by canonical
/// variables. You will need to supply it later to instantiate the
/// canonicalized query response.
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
pub struct CanonicalVarValues<'tcx> {
    pub var_values: IndexVec<CanonicalVar, Kind<'tcx>>,
}

/// When we canonicalize a value to form a query, we wind up replacing
/// various parts of it with canonical variables. This struct stores
/// those replaced bits to remember for when we process the query
/// result.
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
pub struct OriginalQueryValues<'tcx> {
    /// This is equivalent to `CanonicalVarValues`, but using a
    /// `SmallVec` yields a significant performance win.
    pub var_values: SmallVec<[Kind<'tcx>; 8]>,
}

/// Information about a canonical variable that is included with the
/// canonical value. This is sufficient information for code to create
/// a copy of the canonical value in some other inference context,
/// with fresh inference variables replacing the canonical values.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
pub struct CanonicalVarInfo {
    pub kind: CanonicalVarKind,
}

/// Describes the "kind" of the canonical variable. This is a "kind"
/// in the type-theory sense of the term -- i.e., a "meta" type system
/// that analyzes type-like values.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
pub enum CanonicalVarKind {
    /// Some kind of type inference variable.
    Ty(CanonicalTyVarKind),

    /// Region variable `'?R`.
    Region,
}

/// Rust actually has more than one category of type variables;
/// notably, the type variables we create for literals (e.g., 22 or
/// 22.) can only be instantiated with integral/float types (e.g.,
/// usize or f32). In order to faithfully reproduce a type, we need to
/// know what set of types a given type variable can be unified with.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
pub enum CanonicalTyVarKind {
    /// General type variable `?T` that can be unified with arbitrary types.
    General,

    /// Integral type variable `?I` (that can only be unified with integral types).
    Int,

    /// Floating-point type variable `?F` (that can only be unified with float types).
    Float,
}

/// After we execute a query with a canonicalized key, we get back a
/// `Canonical<QueryResponse<..>>`. You can use
/// `instantiate_query_result` to access the data in this result.
#[derive(Clone, Debug)]
pub struct QueryResponse<'tcx, R> {
    pub var_values: CanonicalVarValues<'tcx>,
    pub region_constraints: Vec<QueryRegionConstraint<'tcx>>,
    pub certainty: Certainty,
    pub value: R,
}

pub type Canonicalized<'gcx, V> = Canonical<'gcx, <V as Lift<'gcx>>::Lifted>;

pub type CanonicalizedQueryResponse<'gcx, T> =
    Lrc<Canonical<'gcx, QueryResponse<'gcx, <T as Lift<'gcx>>::Lifted>>>;

/// Indicates whether or not we were able to prove the query to be
/// true.
#[derive(Copy, Clone, Debug)]
pub enum Certainty {
    /// The query is known to be true, presuming that you apply the
    /// given `var_values` and the region-constraints are satisfied.
    Proven,

    /// The query is not known to be true, but also not known to be
    /// false. The `var_values` represent *either* values that must
    /// hold in order for the query to be true, or helpful tips that
    /// *might* make it true. Currently rustc's trait solver cannot
    /// distinguish the two (e.g., due to our preference for where
    /// clauses over impls).
    ///
    /// After some unifiations and things have been done, it makes
    /// sense to try and prove again -- of course, at that point, the
    /// canonical form will be different, making this a distinct
    /// query.
    Ambiguous,
}

impl Certainty {
    pub fn is_proven(&self) -> bool {
        match self {
            Certainty::Proven => true,
            Certainty::Ambiguous => false,
        }
    }

    pub fn is_ambiguous(&self) -> bool {
        !self.is_proven()
    }
}

impl<'tcx, R> QueryResponse<'tcx, R> {
    pub fn is_proven(&self) -> bool {
        self.certainty.is_proven()
    }

    pub fn is_ambiguous(&self) -> bool {
        !self.is_proven()
    }
}

impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> {
    pub fn is_proven(&self) -> bool {
        self.value.is_proven()
    }

    pub fn is_ambiguous(&self) -> bool {
        !self.is_proven()
    }
}

impl<'gcx, V> Canonical<'gcx, V> {
    /// Allows you to map the `value` of a canonical while keeping the
    /// same set of bound variables.
    ///
    /// **WARNING:** This function is very easy to mis-use, hence the
    /// name!  In particular, the new value `W` must use all **the
    /// same type/region variables** in **precisely the same order**
    /// as the original! (The ordering is defined by the
    /// `TypeFoldable` implementation of the type in question.)
    ///
    /// An example of a **correct** use of this:
    ///
    /// ```rust,ignore (not real code)
    /// let a: Canonical<'_, T> = ...;
    /// let b: Canonical<'_, (T,)> = a.unchecked_map(|v| (v, ));
    /// ```
    ///
    /// An example of an **incorrect** use of this:
    ///
    /// ```rust,ignore (not real code)
    /// let a: Canonical<'tcx, T> = ...;
    /// let ty: Ty<'tcx> = ...;
    /// let b: Canonical<'tcx, (T, Ty<'tcx>)> = a.unchecked_map(|v| (v, ty));
    /// ```
    pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<'gcx, W> {
        let Canonical { variables, value } = self;
        Canonical { variables, value: map_op(value) }
    }
}

pub type QueryRegionConstraint<'tcx> = ty::Binder<ty::OutlivesPredicate<Kind<'tcx>, Region<'tcx>>>;

impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
    /// Creates a substitution S for the canonical value with fresh
    /// inference variables and applies it to the canonical value.
    /// Returns both the instantiated result *and* the substitution S.
    ///
    /// This is only meant to be invoked as part of constructing an
    /// inference context at the start of a query (see
    /// `InferCtxtBuilder::enter_with_canonical`).  It basically
    /// brings the canonical value "into scope" within your new infcx.
    ///
    /// At the end of processing, the substitution S (once
    /// canonicalized) then represents the values that you computed
    /// for each of the canonical inputs to your query.

    pub fn instantiate_canonical_with_fresh_inference_vars<T>(
        &self,
        span: Span,
        canonical: &Canonical<'tcx, T>,
    ) -> (T, CanonicalVarValues<'tcx>)
    where
        T: TypeFoldable<'tcx>,
    {
        let canonical_inference_vars =
            self.fresh_inference_vars_for_canonical_vars(span, canonical.variables);
        let result = canonical.substitute(self.tcx, &canonical_inference_vars);
        (result, canonical_inference_vars)
    }

    /// Given the "infos" about the canonical variables from some
    /// canonical, creates fresh inference variables with the same
    /// characteristics. You can then use `substitute` to instantiate
    /// the canonical variable with these inference variables.
    fn fresh_inference_vars_for_canonical_vars(
        &self,
        span: Span,
        variables: &List<CanonicalVarInfo>,
    ) -> CanonicalVarValues<'tcx> {
        let var_values: IndexVec<CanonicalVar, Kind<'tcx>> = variables
            .iter()
            .map(|info| self.fresh_inference_var_for_canonical_var(span, *info))
            .collect();

        CanonicalVarValues { var_values }
    }

    /// Given the "info" about a canonical variable, creates a fresh
    /// inference variable with the same characteristics.
    fn fresh_inference_var_for_canonical_var(
        &self,
        span: Span,
        cv_info: CanonicalVarInfo,
    ) -> Kind<'tcx> {
        match cv_info.kind {
            CanonicalVarKind::Ty(ty_kind) => {
                let ty = match ty_kind {
                    CanonicalTyVarKind::General => {
                        self.next_ty_var(TypeVariableOrigin::MiscVariable(span))
                    }

                    CanonicalTyVarKind::Int => self.tcx.mk_int_var(self.next_int_var_id()),

                    CanonicalTyVarKind::Float => self.tcx.mk_float_var(self.next_float_var_id()),
                };
                ty.into()
            }

            CanonicalVarKind::Region => self
                .next_region_var(RegionVariableOrigin::MiscVariable(span))
                .into(),
        }
    }
}

CloneTypeFoldableAndLiftImpls! {
    ::infer::canonical::Certainty,
    ::infer::canonical::CanonicalVarInfo,
    ::infer::canonical::CanonicalVarKind,
}

CloneTypeFoldableImpls! {
    for <'tcx> {
        ::infer::canonical::CanonicalVarInfos<'tcx>,
    }
}

BraceStructTypeFoldableImpl! {
    impl<'tcx, C> TypeFoldable<'tcx> for Canonical<'tcx, C> {
        variables,
        value,
    } where C: TypeFoldable<'tcx>
}

BraceStructLiftImpl! {
    impl<'a, 'tcx, T> Lift<'tcx> for Canonical<'a, T> {
        type Lifted = Canonical<'tcx, T::Lifted>;
        variables, value
    } where T: Lift<'tcx>
}

impl<'tcx> CanonicalVarValues<'tcx> {
    fn len(&self) -> usize {
        self.var_values.len()
    }
}

impl<'a, 'tcx> IntoIterator for &'a CanonicalVarValues<'tcx> {
    type Item = Kind<'tcx>;
    type IntoIter = ::std::iter::Cloned<::std::slice::Iter<'a, Kind<'tcx>>>;

    fn into_iter(self) -> Self::IntoIter {
        self.var_values.iter().cloned()
    }
}

BraceStructLiftImpl! {
    impl<'a, 'tcx> Lift<'tcx> for CanonicalVarValues<'a> {
        type Lifted = CanonicalVarValues<'tcx>;
        var_values,
    }
}

BraceStructTypeFoldableImpl! {
    impl<'tcx> TypeFoldable<'tcx> for CanonicalVarValues<'tcx> {
        var_values,
    }
}

BraceStructTypeFoldableImpl! {
    impl<'tcx, R> TypeFoldable<'tcx> for QueryResponse<'tcx, R> {
        var_values, region_constraints, certainty, value
    } where R: TypeFoldable<'tcx>,
}

BraceStructLiftImpl! {
    impl<'a, 'tcx, R> Lift<'tcx> for QueryResponse<'a, R> {
        type Lifted = QueryResponse<'tcx, R::Lifted>;
        var_values, region_constraints, certainty, value
    } where R: Lift<'tcx>
}

impl<'tcx> Index<CanonicalVar> for CanonicalVarValues<'tcx> {
    type Output = Kind<'tcx>;

    fn index(&self, value: CanonicalVar) -> &Kind<'tcx> {
        &self.var_values[value]
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 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.

//! See docs in build/expr/mod.rs

use build::expr::category::{Category, RvalueFunc};
use build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
use hair::*;
use rustc::mir::*;
use rustc::ty;

use rustc_target::spec::abi::Abi;

impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
    /// Compile `expr`, storing the result into `destination`, which
    /// is assumed to be uninitialized.
    pub fn into_expr(
        &mut self,
        destination: &Place<'tcx>,
        mut block: BasicBlock,
        expr: Expr<'tcx>,
    ) -> BlockAnd<()> {
        debug!(
            "into_expr(destination={:?}, block={:?}, expr={:?})",
            destination, block, expr
        );

        // since we frequently have to reference `self` from within a
        // closure, where `self` would be shadowed, it's easier to
        // just use the name `this` uniformly
        let this = self;
        let expr_span = expr.span;
        let source_info = this.source_info(expr_span);

        let expr_is_block_or_scope = match expr.kind {
            ExprKind::Block { .. } => true,
            ExprKind::Scope { .. } => true,
            _ => false,
        };

        if !expr_is_block_or_scope {
            this.block_context.push(BlockFrame::SubExpr);
        }

        let block_and = match expr.kind {
            ExprKind::Scope {
                region_scope,
                lint_level,
                value,
            } => {
                let region_scope = (region_scope, source_info);
                this.in_scope(region_scope, lint_level, block, |this| {
                    this.into(destination, block, value)
                })
            }
            ExprKind::Block { body: ast_block } => {
                this.ast_block(destination, block, ast_block, source_info)
            }
            ExprKind::Match { discriminant, arms } => {
                this.match_expr(destination, expr_span, block, discriminant, arms)
            }
            ExprKind::NeverToAny { source } => {
                let source = this.hir.mirror(source);
                let is_call = match source.kind {
                    ExprKind::Call { .. } => true,
                    _ => false,
                };

                unpack!(block = this.as_local_rvalue(block, source));

                // This is an optimization. If the expression was a call then we already have an
                // unreachable block. Don't bother to terminate it and create a new one.
                if is_call {
                    block.unit()
                } else {
                    this.cfg
                        .terminate(block, source_info, TerminatorKind::Unreachable);
                    let end_block = this.cfg.start_new_block();
                    end_block.unit()
                }
            }
            ExprKind::If {
                condition: cond_expr,
                then: then_expr,
                otherwise: else_expr,
            } => {
                let operand = unpack!(block = this.as_local_operand(block, cond_expr));

                let mut then_block = this.cfg.start_new_block();
                let mut else_block = this.cfg.start_new_block();
                let term = TerminatorKind::if_(this.hir.tcx(), operand, then_block, else_block);
                this.cfg.terminate(block, source_info, term);

                unpack!(then_block = this.into(destination, then_block, then_expr));
                else_block = if let Some(else_expr) = else_expr {
                    unpack!(this.into(destination, else_block, else_expr))
                } else {
                    // Body of the `if` expression without an `else` clause must return `()`, thus
                    // we implicitly generate a `else {}` if it is not specified.
                    this.cfg
                        .push_assign_unit(else_block, source_info, destination);
                    else_block
                };

                let join_block = this.cfg.start_new_block();
                this.cfg.terminate(
                    then_block,
                    source_info,
                    TerminatorKind::Goto { target: join_block },
                );
                this.cfg.terminate(
                    else_block,
                    source_info,
                    TerminatorKind::Goto { target: join_block },
                );

                join_block.unit()
            }
            ExprKind::LogicalOp { op, lhs, rhs } => {
                // And:
                //
                // [block: If(lhs)] -true-> [else_block: If(rhs)] -true-> [true_block]
                //        |                          | (false)
                //        +----------false-----------+------------------> [false_block]
                //
                // Or:
                //
                // [block: If(lhs)] -false-> [else_block: If(rhs)] -true-> [true_block]
                //        | (true)                   | (false)
                //  [true_block]               [false_block]

                let (true_block, false_block, mut else_block, join_block) = (
                    this.cfg.start_new_block(),
                    this.cfg.start_new_block(),
                    this.cfg.start_new_block(),
                    this.cfg.start_new_block(),
                );

                let lhs = unpack!(block = this.as_local_operand(block, lhs));
                let blocks = match op {
                    LogicalOp::And => (else_block, false_block),
                    LogicalOp::Or => (true_block, else_block),
                };
                let term = TerminatorKind::if_(this.hir.tcx(), lhs, blocks.0, blocks.1);
                this.cfg.terminate(block, source_info, term);

                let rhs = unpack!(else_block = this.as_local_operand(else_block, rhs));
                let term = TerminatorKind::if_(this.hir.tcx(), rhs, true_block, false_block);
                this.cfg.terminate(else_block, source_info, term);

                this.cfg.push_assign_constant(
                    true_block,
                    source_info,
                    destination,
                    Constant {
                        span: expr_span,
                        ty: this.hir.bool_ty(),
                        user_ty: None,
                        literal: this.hir.true_literal(),
                    },
                );

                this.cfg.push_assign_constant(
                    false_block,
                    source_info,
                    destination,
                    Constant {
                        span: expr_span,
                        ty: this.hir.bool_ty(),
                        user_ty: None,
                        literal: this.hir.false_literal(),
                    },
                );

                this.cfg.terminate(
                    true_block,
                    source_info,
                    TerminatorKind::Goto { target: join_block },
                );
                this.cfg.terminate(
                    false_block,
                    source_info,
                    TerminatorKind::Goto { target: join_block },
                );

                join_block.unit()
            }
            ExprKind::Loop {
                condition: opt_cond_expr,
                body,
            } => {
                // [block] --> [loop_block] -/eval. cond./-> [loop_block_end] -1-> [exit_block]
                //                  ^                               |
                //                  |                               0
                //                  |                               |
                //                  |                               v
                //           [body_block_end] <-/eval. body/-- [body_block]
                //
                // If `opt_cond_expr` is `None`, then the graph is somewhat simplified:
                //
                // [block]
                //    |
                //   [loop_block] -> [body_block] -/eval. body/-> [body_block_end]
                //    |        ^                                         |
                // false link  |                                         |
                //    |        +-----------------------------------------+
                //    +-> [diverge_cleanup]
                // The false link is required to make sure borrowck considers unwinds through the
                // body, even when the exact code in the body cannot unwind

                let loop_block = this.cfg.start_new_block();
                let exit_block = this.cfg.start_new_block();

                // start the loop
                this.cfg.terminate(
                    block,
                    source_info,
                    TerminatorKind::Goto { target: loop_block },
                );

                this.in_breakable_scope(
                    Some(loop_block),
                    exit_block,
                    destination.clone(),
                    move |this| {
                        // conduct the test, if necessary
                        let body_block;
                        if let Some(cond_expr) = opt_cond_expr {
                            let loop_block_end;
                            let cond = unpack!(
                                loop_block_end = this.as_local_operand(loop_block, cond_expr)
                            );
                            body_block = this.cfg.start_new_block();
                            let term =
                                TerminatorKind::if_(this.hir.tcx(), cond, body_block, exit_block);
                            this.cfg.terminate(loop_block_end, source_info, term);

                            // if the test is false, there's no `break` to assign `destination`, so
                            // we have to do it; this overwrites any `break`-assigned value but it's
                            // always `()` anyway
                            this.cfg
                                .push_assign_unit(exit_block, source_info, destination);
                        } else {
                            body_block = this.cfg.start_new_block();
                            let diverge_cleanup = this.diverge_cleanup();
                            this.cfg.terminate(
                                loop_block,
                                source_info,
                                TerminatorKind::FalseUnwind {
                                    real_target: body_block,
                                    unwind: Some(diverge_cleanup),
                                },
                            )
                        }

                        // The “return” value of the loop body must always be an unit. We therefore
                        // introduce a unit temporary as the destination for the loop body.
                        let tmp = this.get_unit_temp();
                        // Execute the body, branching back to the test.
                        let body_block_end = unpack!(this.into(&tmp, body_block, body));
                        this.cfg.terminate(
                            body_block_end,
                            source_info,
                            TerminatorKind::Goto { target: loop_block },
                        );
                    },
                );
                exit_block.unit()
            }
            ExprKind::Call { ty, fun, args, from_hir_call } => {
                let intrinsic = match ty.sty {
                    ty::FnDef(def_id, _) => {
                        let f = ty.fn_sig(this.hir.tcx());
                        if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic {
                            Some(this.hir.tcx().item_name(def_id).as_str())
                        } else {
                            None
                        }
                    }
                    _ => None,
                };
                let intrinsic = intrinsic.as_ref().map(|s| &s[..]);
                let fun = unpack!(block = this.as_local_operand(block, fun));
                if intrinsic == Some("move_val_init") {
                    // `move_val_init` has "magic" semantics - the second argument is
                    // always evaluated "directly" into the first one.

                    let mut args = args.into_iter();
                    let ptr = args.next().expect("0 arguments to `move_val_init`");
                    let val = args.next().expect("1 argument to `move_val_init`");
                    assert!(args.next().is_none(), ">2 arguments to `move_val_init`");

                    let ptr = this.hir.mirror(ptr);
                    let ptr_ty = ptr.ty;
                    // Create an *internal* temp for the pointer, so that unsafety
                    // checking won't complain about the raw pointer assignment.
                    let ptr_temp = this.local_decls.push(LocalDecl {
                        mutability: Mutability::Mut,
                        ty: ptr_ty,
                        user_ty: UserTypeProjections::none(),
                        name: None,
                        source_info,
                        visibility_scope: source_info.scope,
                        internal: true,
                        is_user_variable: None,
                        is_block_tail: None,
                    });
                    let ptr_temp = Place::Local(ptr_temp);
                    let block = unpack!(this.into(&ptr_temp, block, ptr));
                    this.into(&ptr_temp.deref(), block, val)
                } else {
                    let args: Vec<_> = args
                        .into_iter()
                        .map(|arg| unpack!(block = this.as_local_operand(block, arg)))
                        .collect();

                    let success = this.cfg.start_new_block();
                    let cleanup = this.diverge_cleanup();
                    this.cfg.terminate(
                        block,
                        source_info,
                        TerminatorKind::Call {
                            func: fun,
                            args,
                            cleanup: Some(cleanup),
                            destination:
                                if expr.ty.conservative_is_privately_uninhabited(this.hir.tcx()) {
                                    None
                                } else {
                                    Some((destination.clone(), success))
                                },
                            from_hir_call,
                        },
                    );
                    success.unit()
                }
            }

            // These cases don't actually need a destination
            ExprKind::Assign { .. }
            | ExprKind::AssignOp { .. }
            | ExprKind::Continue { .. }
            | ExprKind::Break { .. }
            | ExprKind::InlineAsm { .. }
            | ExprKind::Return { .. } => {
                unpack!(block = this.stmt_expr(block, expr, None));
                this.cfg.push_assign_unit(block, source_info, destination);
                block.unit()
            }

            // Avoid creating a temporary
            ExprKind::VarRef { .. } |
            ExprKind::SelfRef |
            ExprKind::StaticRef { .. } |
            ExprKind::PlaceTypeAscription { .. } |
            ExprKind::ValueTypeAscription { .. } => {
                debug_assert!(Category::of(&expr.kind) == Some(Category::Place));

                let place = unpack!(block = this.as_place(block, expr));
                let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
                this.cfg
                    .push_assign(block, source_info, destination, rvalue);
                block.unit()
            }
            ExprKind::Index { .. } | ExprKind::Deref { .. } | ExprKind::Field { .. } => {
                debug_assert!(Category::of(&expr.kind) == Some(Category::Place));

                // Create a "fake" temporary variable so that we check that the
                // value is Sized. Usually, this is caught in type checking, but
                // in the case of box expr there is no such check.
                if let Place::Projection(..) = destination {
                    this.local_decls
                        .push(LocalDecl::new_temp(expr.ty, expr.span));
                }

                debug_assert!(Category::of(&expr.kind) == Some(Category::Place));

                let place = unpack!(block = this.as_place(block, expr));
                let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
                this.cfg
                    .push_assign(block, source_info, destination, rvalue);
                block.unit()
            }

            // these are the cases that are more naturally handled by some other mode
            ExprKind::Unary { .. }
            | ExprKind::Binary { .. }
            | ExprKind::Box { .. }
            | ExprKind::Cast { .. }
            | ExprKind::Use { .. }
            | ExprKind::ReifyFnPointer { .. }
            | ExprKind::ClosureFnPointer { .. }
            | ExprKind::UnsafeFnPointer { .. }
            | ExprKind::Unsize { .. }
            | ExprKind::Repeat { .. }
            | ExprKind::Borrow { .. }
            | ExprKind::Array { .. }
            | ExprKind::Tuple { .. }
            | ExprKind::Adt { .. }
            | ExprKind::Closure { .. }
            | ExprKind::Literal { .. }
            | ExprKind::Yield { .. } => {
                debug_assert!(match Category::of(&expr.kind).unwrap() {
                    // should be handled above
                    Category::Rvalue(RvalueFunc::Into) => false,

                    // must be handled above or else we get an
                    // infinite loop in the builder; see
                    // e.g., `ExprKind::VarRef` above
                    Category::Place => false,

                    _ => true,
                });

                let rvalue = unpack!(block = this.as_local_rvalue(block, expr));
                this.cfg.push_assign(block, source_info, destination, rvalue);
                block.unit()
            }
        };

        if !expr_is_block_or_scope {
            let popped = this.block_context.pop();
            assert!(popped.is_some());
        }

        block_and
    }
}
<commit_msg>Add a FIXME for mir build unreachable destination checking<commit_after>// Copyright 2015 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.

//! See docs in build/expr/mod.rs

use build::expr::category::{Category, RvalueFunc};
use build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
use hair::*;
use rustc::mir::*;
use rustc::ty;

use rustc_target::spec::abi::Abi;

impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
    /// Compile `expr`, storing the result into `destination`, which
    /// is assumed to be uninitialized.
    pub fn into_expr(
        &mut self,
        destination: &Place<'tcx>,
        mut block: BasicBlock,
        expr: Expr<'tcx>,
    ) -> BlockAnd<()> {
        debug!(
            "into_expr(destination={:?}, block={:?}, expr={:?})",
            destination, block, expr
        );

        // since we frequently have to reference `self` from within a
        // closure, where `self` would be shadowed, it's easier to
        // just use the name `this` uniformly
        let this = self;
        let expr_span = expr.span;
        let source_info = this.source_info(expr_span);

        let expr_is_block_or_scope = match expr.kind {
            ExprKind::Block { .. } => true,
            ExprKind::Scope { .. } => true,
            _ => false,
        };

        if !expr_is_block_or_scope {
            this.block_context.push(BlockFrame::SubExpr);
        }

        let block_and = match expr.kind {
            ExprKind::Scope {
                region_scope,
                lint_level,
                value,
            } => {
                let region_scope = (region_scope, source_info);
                this.in_scope(region_scope, lint_level, block, |this| {
                    this.into(destination, block, value)
                })
            }
            ExprKind::Block { body: ast_block } => {
                this.ast_block(destination, block, ast_block, source_info)
            }
            ExprKind::Match { discriminant, arms } => {
                this.match_expr(destination, expr_span, block, discriminant, arms)
            }
            ExprKind::NeverToAny { source } => {
                let source = this.hir.mirror(source);
                let is_call = match source.kind {
                    ExprKind::Call { .. } => true,
                    _ => false,
                };

                unpack!(block = this.as_local_rvalue(block, source));

                // This is an optimization. If the expression was a call then we already have an
                // unreachable block. Don't bother to terminate it and create a new one.
                if is_call {
                    block.unit()
                } else {
                    this.cfg
                        .terminate(block, source_info, TerminatorKind::Unreachable);
                    let end_block = this.cfg.start_new_block();
                    end_block.unit()
                }
            }
            ExprKind::If {
                condition: cond_expr,
                then: then_expr,
                otherwise: else_expr,
            } => {
                let operand = unpack!(block = this.as_local_operand(block, cond_expr));

                let mut then_block = this.cfg.start_new_block();
                let mut else_block = this.cfg.start_new_block();
                let term = TerminatorKind::if_(this.hir.tcx(), operand, then_block, else_block);
                this.cfg.terminate(block, source_info, term);

                unpack!(then_block = this.into(destination, then_block, then_expr));
                else_block = if let Some(else_expr) = else_expr {
                    unpack!(this.into(destination, else_block, else_expr))
                } else {
                    // Body of the `if` expression without an `else` clause must return `()`, thus
                    // we implicitly generate a `else {}` if it is not specified.
                    this.cfg
                        .push_assign_unit(else_block, source_info, destination);
                    else_block
                };

                let join_block = this.cfg.start_new_block();
                this.cfg.terminate(
                    then_block,
                    source_info,
                    TerminatorKind::Goto { target: join_block },
                );
                this.cfg.terminate(
                    else_block,
                    source_info,
                    TerminatorKind::Goto { target: join_block },
                );

                join_block.unit()
            }
            ExprKind::LogicalOp { op, lhs, rhs } => {
                // And:
                //
                // [block: If(lhs)] -true-> [else_block: If(rhs)] -true-> [true_block]
                //        |                          | (false)
                //        +----------false-----------+------------------> [false_block]
                //
                // Or:
                //
                // [block: If(lhs)] -false-> [else_block: If(rhs)] -true-> [true_block]
                //        | (true)                   | (false)
                //  [true_block]               [false_block]

                let (true_block, false_block, mut else_block, join_block) = (
                    this.cfg.start_new_block(),
                    this.cfg.start_new_block(),
                    this.cfg.start_new_block(),
                    this.cfg.start_new_block(),
                );

                let lhs = unpack!(block = this.as_local_operand(block, lhs));
                let blocks = match op {
                    LogicalOp::And => (else_block, false_block),
                    LogicalOp::Or => (true_block, else_block),
                };
                let term = TerminatorKind::if_(this.hir.tcx(), lhs, blocks.0, blocks.1);
                this.cfg.terminate(block, source_info, term);

                let rhs = unpack!(else_block = this.as_local_operand(else_block, rhs));
                let term = TerminatorKind::if_(this.hir.tcx(), rhs, true_block, false_block);
                this.cfg.terminate(else_block, source_info, term);

                this.cfg.push_assign_constant(
                    true_block,
                    source_info,
                    destination,
                    Constant {
                        span: expr_span,
                        ty: this.hir.bool_ty(),
                        user_ty: None,
                        literal: this.hir.true_literal(),
                    },
                );

                this.cfg.push_assign_constant(
                    false_block,
                    source_info,
                    destination,
                    Constant {
                        span: expr_span,
                        ty: this.hir.bool_ty(),
                        user_ty: None,
                        literal: this.hir.false_literal(),
                    },
                );

                this.cfg.terminate(
                    true_block,
                    source_info,
                    TerminatorKind::Goto { target: join_block },
                );
                this.cfg.terminate(
                    false_block,
                    source_info,
                    TerminatorKind::Goto { target: join_block },
                );

                join_block.unit()
            }
            ExprKind::Loop {
                condition: opt_cond_expr,
                body,
            } => {
                // [block] --> [loop_block] -/eval. cond./-> [loop_block_end] -1-> [exit_block]
                //                  ^                               |
                //                  |                               0
                //                  |                               |
                //                  |                               v
                //           [body_block_end] <-/eval. body/-- [body_block]
                //
                // If `opt_cond_expr` is `None`, then the graph is somewhat simplified:
                //
                // [block]
                //    |
                //   [loop_block] -> [body_block] -/eval. body/-> [body_block_end]
                //    |        ^                                         |
                // false link  |                                         |
                //    |        +-----------------------------------------+
                //    +-> [diverge_cleanup]
                // The false link is required to make sure borrowck considers unwinds through the
                // body, even when the exact code in the body cannot unwind

                let loop_block = this.cfg.start_new_block();
                let exit_block = this.cfg.start_new_block();

                // start the loop
                this.cfg.terminate(
                    block,
                    source_info,
                    TerminatorKind::Goto { target: loop_block },
                );

                this.in_breakable_scope(
                    Some(loop_block),
                    exit_block,
                    destination.clone(),
                    move |this| {
                        // conduct the test, if necessary
                        let body_block;
                        if let Some(cond_expr) = opt_cond_expr {
                            let loop_block_end;
                            let cond = unpack!(
                                loop_block_end = this.as_local_operand(loop_block, cond_expr)
                            );
                            body_block = this.cfg.start_new_block();
                            let term =
                                TerminatorKind::if_(this.hir.tcx(), cond, body_block, exit_block);
                            this.cfg.terminate(loop_block_end, source_info, term);

                            // if the test is false, there's no `break` to assign `destination`, so
                            // we have to do it; this overwrites any `break`-assigned value but it's
                            // always `()` anyway
                            this.cfg
                                .push_assign_unit(exit_block, source_info, destination);
                        } else {
                            body_block = this.cfg.start_new_block();
                            let diverge_cleanup = this.diverge_cleanup();
                            this.cfg.terminate(
                                loop_block,
                                source_info,
                                TerminatorKind::FalseUnwind {
                                    real_target: body_block,
                                    unwind: Some(diverge_cleanup),
                                },
                            )
                        }

                        // The “return” value of the loop body must always be an unit. We therefore
                        // introduce a unit temporary as the destination for the loop body.
                        let tmp = this.get_unit_temp();
                        // Execute the body, branching back to the test.
                        let body_block_end = unpack!(this.into(&tmp, body_block, body));
                        this.cfg.terminate(
                            body_block_end,
                            source_info,
                            TerminatorKind::Goto { target: loop_block },
                        );
                    },
                );
                exit_block.unit()
            }
            ExprKind::Call { ty, fun, args, from_hir_call } => {
                let intrinsic = match ty.sty {
                    ty::FnDef(def_id, _) => {
                        let f = ty.fn_sig(this.hir.tcx());
                        if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic {
                            Some(this.hir.tcx().item_name(def_id).as_str())
                        } else {
                            None
                        }
                    }
                    _ => None,
                };
                let intrinsic = intrinsic.as_ref().map(|s| &s[..]);
                let fun = unpack!(block = this.as_local_operand(block, fun));
                if intrinsic == Some("move_val_init") {
                    // `move_val_init` has "magic" semantics - the second argument is
                    // always evaluated "directly" into the first one.

                    let mut args = args.into_iter();
                    let ptr = args.next().expect("0 arguments to `move_val_init`");
                    let val = args.next().expect("1 argument to `move_val_init`");
                    assert!(args.next().is_none(), ">2 arguments to `move_val_init`");

                    let ptr = this.hir.mirror(ptr);
                    let ptr_ty = ptr.ty;
                    // Create an *internal* temp for the pointer, so that unsafety
                    // checking won't complain about the raw pointer assignment.
                    let ptr_temp = this.local_decls.push(LocalDecl {
                        mutability: Mutability::Mut,
                        ty: ptr_ty,
                        user_ty: UserTypeProjections::none(),
                        name: None,
                        source_info,
                        visibility_scope: source_info.scope,
                        internal: true,
                        is_user_variable: None,
                        is_block_tail: None,
                    });
                    let ptr_temp = Place::Local(ptr_temp);
                    let block = unpack!(this.into(&ptr_temp, block, ptr));
                    this.into(&ptr_temp.deref(), block, val)
                } else {
                    let args: Vec<_> = args
                        .into_iter()
                        .map(|arg| unpack!(block = this.as_local_operand(block, arg)))
                        .collect();

                    let success = this.cfg.start_new_block();
                    let cleanup = this.diverge_cleanup();
                    this.cfg.terminate(
                        block,
                        source_info,
                        TerminatorKind::Call {
                            func: fun,
                            args,
                            cleanup: Some(cleanup),
                            // FIXME(varkor): replace this with an uninhabitedness-based check.
                            // This requires getting access to the current module to call
                            // `tcx.is_ty_uninhabited_from`, which is currently tricky to do.
                            destination: if expr.ty.is_never() {
                                None
                            } else {
                                Some((destination.clone(), success))
                            },
                            from_hir_call,
                        },
                    );
                    success.unit()
                }
            }

            // These cases don't actually need a destination
            ExprKind::Assign { .. }
            | ExprKind::AssignOp { .. }
            | ExprKind::Continue { .. }
            | ExprKind::Break { .. }
            | ExprKind::InlineAsm { .. }
            | ExprKind::Return { .. } => {
                unpack!(block = this.stmt_expr(block, expr, None));
                this.cfg.push_assign_unit(block, source_info, destination);
                block.unit()
            }

            // Avoid creating a temporary
            ExprKind::VarRef { .. } |
            ExprKind::SelfRef |
            ExprKind::StaticRef { .. } |
            ExprKind::PlaceTypeAscription { .. } |
            ExprKind::ValueTypeAscription { .. } => {
                debug_assert!(Category::of(&expr.kind) == Some(Category::Place));

                let place = unpack!(block = this.as_place(block, expr));
                let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
                this.cfg
                    .push_assign(block, source_info, destination, rvalue);
                block.unit()
            }
            ExprKind::Index { .. } | ExprKind::Deref { .. } | ExprKind::Field { .. } => {
                debug_assert!(Category::of(&expr.kind) == Some(Category::Place));

                // Create a "fake" temporary variable so that we check that the
                // value is Sized. Usually, this is caught in type checking, but
                // in the case of box expr there is no such check.
                if let Place::Projection(..) = destination {
                    this.local_decls
                        .push(LocalDecl::new_temp(expr.ty, expr.span));
                }

                debug_assert!(Category::of(&expr.kind) == Some(Category::Place));

                let place = unpack!(block = this.as_place(block, expr));
                let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
                this.cfg
                    .push_assign(block, source_info, destination, rvalue);
                block.unit()
            }

            // these are the cases that are more naturally handled by some other mode
            ExprKind::Unary { .. }
            | ExprKind::Binary { .. }
            | ExprKind::Box { .. }
            | ExprKind::Cast { .. }
            | ExprKind::Use { .. }
            | ExprKind::ReifyFnPointer { .. }
            | ExprKind::ClosureFnPointer { .. }
            | ExprKind::UnsafeFnPointer { .. }
            | ExprKind::Unsize { .. }
            | ExprKind::Repeat { .. }
            | ExprKind::Borrow { .. }
            | ExprKind::Array { .. }
            | ExprKind::Tuple { .. }
            | ExprKind::Adt { .. }
            | ExprKind::Closure { .. }
            | ExprKind::Literal { .. }
            | ExprKind::Yield { .. } => {
                debug_assert!(match Category::of(&expr.kind).unwrap() {
                    // should be handled above
                    Category::Rvalue(RvalueFunc::Into) => false,

                    // must be handled above or else we get an
                    // infinite loop in the builder; see
                    // e.g., `ExprKind::VarRef` above
                    Category::Place => false,

                    _ => true,
                });

                let rvalue = unpack!(block = this.as_local_rvalue(block, expr));
                this.cfg.push_assign(block, source_info, destination, rvalue);
                block.unit()
            }
        };

        if !expr_is_block_or_scope {
            let popped = this.block_context.pop();
            assert!(popped.is_some());
        }

        block_and
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use std::io;
use std::path::Path;
use std::process::{Command, Stdio};
use url::Url;

pub struct Git;

impl Git {
  pub fn clone(url: Url, dest: &Path, depth: Option<i32>) -> Result<i32, io::Error> {
    let depth = depth.map(|depth| format!("--depth={}", depth));
    let mut args = vec!["clone", url.as_str(), dest.to_str().unwrap()];
    if let Some(ref depth) = depth {
      args.push(&depth);
    }

    wait_exec("git", args.as_slice(), None)
  }

  pub fn update(dest: &Path) -> Result<i32, io::Error> {
    wait_exec("git", &["pull", "--ff-only"], Some(dest))
  }
}

pub struct Mercurial;

impl Mercurial {
  pub fn clone(url: Url, dest: &Path, _: Option<i32>) -> Result<i32, io::Error> {
    wait_exec("hg", &["clone", url.as_str(), dest.to_str().unwrap()], None)
  }

  pub fn update(path: &Path) -> Result<i32, io::Error> {
    wait_exec("hg", &["pull", "--update"], Some(path))
  }
}

fn wait_exec(cmd: &str, args: &[&str], curr_dir: Option<&Path>) -> Result<i32, io::Error> {
  let mut command = Command::new(cmd);
  command.args(args)
    .stdin(Stdio::inherit())
    .stdout(Stdio::inherit())
    .stderr(Stdio::inherit());
  if let Some(curr_dir) = curr_dir {
    command.current_dir(curr_dir);
  }

  let mut child = try!(command.spawn());
  child.wait()
    .and_then(|st| st.code().ok_or(io::Error::new(io::ErrorKind::Other, "")))
}
<commit_msg>remove Mercurial<commit_after>#![allow(dead_code)]

use std::io;
use std::path::Path;
use std::process::{Command, Stdio};
use url::Url;

pub struct Git;

impl Git {
  pub fn clone(url: Url, dest: &Path, depth: Option<i32>) -> Result<i32, io::Error> {
    let depth = depth.map(|depth| format!("--depth={}", depth));
    let mut args = vec!["clone", url.as_str(), dest.to_str().unwrap()];
    if let Some(ref depth) = depth {
      args.push(&depth);
    }

    wait_exec("git", args.as_slice(), None)
  }

  pub fn update(dest: &Path) -> Result<i32, io::Error> {
    wait_exec("git", &["pull", "--ff-only"], Some(dest))
  }
}

fn wait_exec(cmd: &str, args: &[&str], curr_dir: Option<&Path>) -> Result<i32, io::Error> {
  let mut command = Command::new(cmd);
  command.args(args)
    .stdin(Stdio::inherit())
    .stdout(Stdio::inherit())
    .stderr(Stdio::inherit());
  if let Some(curr_dir) = curr_dir {
    command.current_dir(curr_dir);
  }

  let mut child = try!(command.spawn());
  child.wait()
    .and_then(|st| st.code().ok_or(io::Error::new(io::ErrorKind::Other, "")))
}
<|endoftext|>


<commit_before>use crate::result::TockResult;
use crate::util;
use core::cell::Cell;
use core::mem;
use libtock_core::{callback, syscalls};

const DRIVER_NUMBER: usize = 0x30003;

mod command_nr {
    pub const CHECK: usize = 0;
    pub const TRANSMIT: usize = 1;
    pub const RECEIVE: usize = 2;
    pub const EMULATE: usize = 3;
    pub const CONFIGURE: usize = 4;
    pub const FRAMEDELAYMAX: usize = 5;
}

mod subscribe_nr {
    pub const TRANSMIT: usize = 1;
    pub const RECEIVE: usize = 2;
    pub const SELECT: usize = 3;
}

mod allow_nr {
    pub const TRANSMIT: usize = 1;
    pub const RECEIVE: usize = 2;
}

#[allow(dead_code)]
pub struct RecvOp {
    pub result_code: usize,
    pub recv_amount: usize,
}

pub struct NfcTag {}

impl NfcTag {
    /// Check the existence of an NFC driver.
    pub fn setup() -> bool {
        syscalls::command(DRIVER_NUMBER, command_nr::CHECK, 0, 0).is_ok()
    }

    pub fn enable_emulation() -> bool {
        NfcTag::emulate(true)
    }

    pub fn disable_emulation() -> bool {
        NfcTag::emulate(false)
    }

    fn emulate(enabled: bool) -> bool {
        syscalls::command(DRIVER_NUMBER, command_nr::EMULATE, enabled as usize, 0).is_ok()
    }

    /// Subscribe to the tag being SELECTED callback.
    pub fn selected() -> bool {
        let is_selected = Cell::new(false);
        let mut is_selected_alarm = || is_selected.set(true);
        let subscription = syscalls::subscribe::<callback::Identity0Consumer, _>(
            DRIVER_NUMBER,
            subscribe_nr::SELECT,
            &mut is_selected_alarm,
        );
        if subscription.is_err() {
            return false;
        }

        util::yieldk_for(|| is_selected.get());
        true
    }

    /// Configure the tag type command.
    pub fn configure(tag_type: u8) -> bool {
        syscalls::command(DRIVER_NUMBER, command_nr::CONFIGURE, tag_type as usize, 0).is_ok()
    }

    /// Set the maximum frame delay value to support transmission with the reader.
    pub fn set_framedelaymax(delay: u32) -> bool {
        syscalls::command(DRIVER_NUMBER, command_nr::FRAMEDELAYMAX, delay as usize, 0).is_ok()
    }

    /// 1. Share with the driver a buffer.
    /// 2. Subscribe to having a successful receive callback.
    /// 3. Issue the request for reception.
    pub fn receive(buf: &mut [u8; 256]) -> TockResult<RecvOp> {
        let result = syscalls::allow(DRIVER_NUMBER, allow_nr::RECEIVE, buf)?;
        // set callback with 2 arguments, to receive ReturnCode and RX Amount
        let result_code = Cell::new(None);
        let recv_amount = Cell::new(None);
        let mut callback = |result, amount| {
            result_code.set(Some(result));
            recv_amount.set(Some(amount))
        };
        let subscription = syscalls::subscribe::<callback::Identity2Consumer, _>(
            DRIVER_NUMBER,
            subscribe_nr::RECEIVE,
            &mut callback,
        )?;
        syscalls::command(DRIVER_NUMBER, command_nr::RECEIVE, 0, 0)?;
        util::yieldk_for(|| recv_amount.get().is_some());
        mem::drop(subscription);
        mem::drop(result);
        Ok(RecvOp {
            result_code: result_code.get().unwrap(),
            recv_amount: recv_amount.get().unwrap(),
        })
    }

    /// 1. Share with the driver a buffer containing the app's reply.
    /// 2. Subscribe to having a successful transmission callback.
    /// 3. Issue the request for transmitting.
    pub fn transmit(buf: &mut [u8], amount: usize) -> TockResult<usize> {
        let result = syscalls::allow(DRIVER_NUMBER, allow_nr::TRANSMIT, buf)?;
        // set callback with 1 argument, to receive ReturnCode
        let result_code = Cell::new(None);
        let mut callback = |result| result_code.set(Some(result));
        let subscription = syscalls::subscribe::<callback::Identity1Consumer, _>(
            DRIVER_NUMBER,
            subscribe_nr::TRANSMIT,
            &mut callback,
        )?;
        syscalls::command(DRIVER_NUMBER, command_nr::TRANSMIT, amount, 0)?;
        util::yieldk_for(|| result_code.get().is_some());
        mem::drop(subscription);
        mem::drop(result);
        Ok(result_code.get().unwrap())
    }
}
<commit_msg>Resolve Comments<commit_after>use crate::result::TockResult;
use crate::util;
use core::cell::Cell;
use core::mem;
use libtock_core::{callback, syscalls};

const DRIVER_NUMBER: usize = 0x30003;

mod command_nr {
    pub const CHECK: usize = 0;
    pub const TRANSMIT: usize = 1;
    pub const RECEIVE: usize = 2;
    pub const EMULATE: usize = 3;
    pub const CONFIGURE: usize = 4;
    pub const FRAMEDELAYMAX: usize = 5;
    pub const SELECTED: usize = 6;
}

mod subscribe_nr {
    pub const TRANSMIT: usize = 1;
    pub const RECEIVE: usize = 2;
    pub const SELECT: usize = 3;
}

mod allow_nr {
    pub const TRANSMIT: usize = 1;
    pub const RECEIVE: usize = 2;
}

#[allow(dead_code)]
#[derive(Clone, Copy)]
pub struct RecvOp {
    pub result_code: usize,
    pub recv_amount: usize,
}

pub struct NfcTag {}

impl NfcTag {
    /// Check the existence of an NFC driver.
    pub fn setup() -> bool {
        syscalls::command(DRIVER_NUMBER, command_nr::CHECK, 0, 0).is_ok()
    }

    pub fn enable_emulation() -> bool {
        NfcTag::emulate(true)
    }

    pub fn disable_emulation() -> bool {
        NfcTag::emulate(false)
    }

    fn emulate(enabled: bool) -> bool {
        syscalls::command(DRIVER_NUMBER, command_nr::EMULATE, enabled as usize, 0).is_ok()
    }

    /// Subscribe to the tag being SELECTED callback.
    pub fn selected() -> bool {
        let is_selected = Cell::new(false);
        let mut is_selected_alarm = || is_selected.set(true);
        let subscription = syscalls::subscribe::<callback::Identity0Consumer, _>(
            DRIVER_NUMBER,
            subscribe_nr::SELECT,
            &mut is_selected_alarm,
        );
        if subscription.is_err() {
            return false;
        }

        let result = syscalls::command(DRIVER_NUMBER, command_nr::SELECTED, 0, 0);
        if result.is_err() {
            return false;
        }

        util::yieldk_for(|| is_selected.get());
        true
    }

    /// Configure the tag type command.
    pub fn configure(tag_type: u8) -> bool {
        syscalls::command(DRIVER_NUMBER, command_nr::CONFIGURE, tag_type as usize, 0).is_ok()
    }

    /// Set the maximum frame delay value to support transmission with the reader.
    pub fn set_framedelaymax(delay: u32) -> bool {
        syscalls::command(DRIVER_NUMBER, command_nr::FRAMEDELAYMAX, delay as usize, 0).is_ok()
    }

    /// 1. Share with the driver a buffer.
    /// 2. Subscribe to having a successful receive callback.
    /// 3. Issue the request for reception.
    pub fn receive(buf: &mut [u8; 256]) -> TockResult<RecvOp> {
        let _result = syscalls::allow(DRIVER_NUMBER, allow_nr::RECEIVE, buf)?;
        // set callback with 2 arguments, to receive ReturnCode and RX Amount
        let recv_data = Cell::new(None);
        let mut callback = |result, amount| {
            recv_data.set(Some(RecvOp {
                result_code: result,
                recv_amount: amount,
            }))
        };
        let _subscription = syscalls::subscribe::<callback::Identity2Consumer, _>(
            DRIVER_NUMBER,
            subscribe_nr::RECEIVE,
            &mut callback,
        )?;
        syscalls::command(DRIVER_NUMBER, command_nr::RECEIVE, 0, 0)?;
        util::yieldk_for(|| recv_data.get().is_some());
        Ok(recv_data.get().unwrap())
    }

    /// 1. Share with the driver a buffer containing the app's reply.
    /// 2. Subscribe to having a successful transmission callback.
    /// 3. Issue the request for transmitting.
    pub fn transmit(buf: &mut [u8], amount: usize) -> TockResult<usize> {
        let result = syscalls::allow(DRIVER_NUMBER, allow_nr::TRANSMIT, buf)?;
        // set callback with 1 argument, to receive ReturnCode
        let result_code = Cell::new(None);
        let mut callback = |result| result_code.set(Some(result));
        let subscription = syscalls::subscribe::<callback::Identity1Consumer, _>(
            DRIVER_NUMBER,
            subscribe_nr::TRANSMIT,
            &mut callback,
        )?;
        syscalls::command(DRIVER_NUMBER, command_nr::TRANSMIT, amount, 0)?;
        util::yieldk_for(|| result_code.get().is_some());
        mem::drop(subscription);
        mem::drop(result);
        Ok(result_code.get().unwrap())
    }
}
<|endoftext|>


<commit_before>// Copyright 2012 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.

/*!
 * Computes moves.
 */

use core::prelude::*;
use mc = middle::mem_categorization;
use middle::borrowck::*;
use middle::borrowck::move_data::*;
use middle::moves;
use middle::ty;
use syntax::ast;
use syntax::ast_util;
use syntax::codemap::span;
use util::ppaux::{UserString};

pub fn gather_decl(bccx: @BorrowckCtxt,
                   move_data: &mut MoveData,
                   decl_id: ast::node_id,
                   _decl_span: span,
                   var_id: ast::node_id) {
    let loan_path = @LpVar(var_id);
    move_data.add_move(bccx.tcx, loan_path, decl_id, Declared);
}

pub fn gather_move_from_expr(bccx: @BorrowckCtxt,
                             move_data: &mut MoveData,
                             move_expr: @ast::expr,
                             cmt: mc::cmt) {
    gather_move_from_expr_or_pat(bccx, move_data, move_expr.id,
                                 MoveExpr(move_expr), cmt);
}

pub fn gather_move_from_pat(bccx: @BorrowckCtxt,
                            move_data: &mut MoveData,
                            move_pat: @ast::pat,
                            cmt: mc::cmt) {
    gather_move_from_expr_or_pat(bccx, move_data, move_pat.id,
                                 MovePat(move_pat), cmt);
}

fn gather_move_from_expr_or_pat(bccx: @BorrowckCtxt,
                                move_data: &mut MoveData,
                                move_id: ast::node_id,
                                move_kind: MoveKind,
                                cmt: mc::cmt) {
    if !check_is_legal_to_move_from(bccx, cmt, cmt) {
        return;
    }

    match opt_loan_path(cmt) {
        Some(loan_path) => {
            move_data.add_move(bccx.tcx, loan_path, move_id, move_kind);
        }
        None => {
            // move from rvalue or unsafe pointer, hence ok
        }
    }
}

pub fn gather_captures(bccx: @BorrowckCtxt,
                       move_data: &mut MoveData,
                       closure_expr: @ast::expr) {
    let captured_vars = bccx.capture_map.get(&closure_expr.id);
    for captured_vars.each |captured_var| {
        match captured_var.mode {
            moves::CapMove => {
                let fvar_id = ast_util::def_id_of_def(captured_var.def).node;
                let loan_path = @LpVar(fvar_id);
                move_data.add_move(bccx.tcx, loan_path, closure_expr.id,
                                   Captured(closure_expr));
            }
            moves::CapCopy | moves::CapRef => {}
        }
    }
}

pub fn gather_assignment(bccx: @BorrowckCtxt,
                         move_data: &mut MoveData,
                         assignment_id: ast::node_id,
                         assignment_span: span,
                         assignee_loan_path: @LoanPath,
                         assignee_id: ast::node_id) {
    move_data.add_assignment(bccx.tcx,
                             assignee_loan_path,
                             assignment_id,
                             assignment_span,
                             assignee_id);
}

fn check_is_legal_to_move_from(bccx: @BorrowckCtxt,
                               cmt0: mc::cmt,
                               cmt: mc::cmt) -> bool {
    match cmt.cat {
        mc::cat_stack_upvar(*) |
        mc::cat_implicit_self(*) |
        mc::cat_copied_upvar(*) |
        mc::cat_deref(_, _, mc::region_ptr(*)) |
        mc::cat_deref(_, _, mc::gc_ptr(*)) => {
            bccx.span_err(
                cmt0.span,
                fmt!("cannot move out of %s",
                     bccx.cmt_to_str(cmt)));
            false
        }

        // It seems strange to allow a move out of a static item,
        // but what happens in practice is that you have a
        // reference to a constant with a type that should be
        // moved, like `None::<~int>`.  The type of this constant
        // is technically `Option<~int>`, which moves, but we know
        // that the content of static items will never actually
        // contain allocated pointers, so we can just memcpy it.
        // Since static items can never have allocated memory,
        // this is ok. For now anyhow.
        mc::cat_static_item => {
            true
        }

        mc::cat_rvalue(*) |
        mc::cat_local(*) |
        mc::cat_arg(*) |
        mc::cat_self(*) |
        mc::cat_deref(_, _, mc::unsafe_ptr(*)) => {
            true
        }

        mc::cat_downcast(b) |
        mc::cat_interior(b, _) => {
            match ty::get(b.ty).sty {
                ty::ty_struct(did, _) | ty::ty_enum(did, _) => {
                    if ty::has_dtor(bccx.tcx, did) {
                        bccx.span_err(
                            cmt0.span,
                            fmt!("cannot move out of type `%s`, \
                                  which defines the `Drop` trait",
                                 b.ty.user_string(bccx.tcx)));
                        false
                    } else {
                        check_is_legal_to_move_from(bccx, cmt0, b)
                    }
                }
                _ => {
                    check_is_legal_to_move_from(bccx, cmt0, b)
                }
            }
        }

        mc::cat_deref(b, _, mc::uniq_ptr(*)) |
        mc::cat_discr(b, _) => {
            check_is_legal_to_move_from(bccx, cmt0, b)
        }
    }
}
<commit_msg>Make it illegal to move from *T. This interacts poorly with moves-based-on-type, since it creates moves that were not apparent. It also turns out to be not widely used.<commit_after>// Copyright 2012 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.

/*!
 * Computes moves.
 */

use core::prelude::*;
use mc = middle::mem_categorization;
use middle::borrowck::*;
use middle::borrowck::move_data::*;
use middle::moves;
use middle::ty;
use syntax::ast;
use syntax::ast_util;
use syntax::codemap::span;
use util::ppaux::{UserString};

pub fn gather_decl(bccx: @BorrowckCtxt,
                   move_data: &mut MoveData,
                   decl_id: ast::node_id,
                   _decl_span: span,
                   var_id: ast::node_id) {
    let loan_path = @LpVar(var_id);
    move_data.add_move(bccx.tcx, loan_path, decl_id, Declared);
}

pub fn gather_move_from_expr(bccx: @BorrowckCtxt,
                             move_data: &mut MoveData,
                             move_expr: @ast::expr,
                             cmt: mc::cmt) {
    gather_move_from_expr_or_pat(bccx, move_data, move_expr.id,
                                 MoveExpr(move_expr), cmt);
}

pub fn gather_move_from_pat(bccx: @BorrowckCtxt,
                            move_data: &mut MoveData,
                            move_pat: @ast::pat,
                            cmt: mc::cmt) {
    gather_move_from_expr_or_pat(bccx, move_data, move_pat.id,
                                 MovePat(move_pat), cmt);
}

fn gather_move_from_expr_or_pat(bccx: @BorrowckCtxt,
                                move_data: &mut MoveData,
                                move_id: ast::node_id,
                                move_kind: MoveKind,
                                cmt: mc::cmt) {
    if !check_is_legal_to_move_from(bccx, cmt, cmt) {
        return;
    }

    match opt_loan_path(cmt) {
        Some(loan_path) => {
            move_data.add_move(bccx.tcx, loan_path, move_id, move_kind);
        }
        None => {
            // move from rvalue or unsafe pointer, hence ok
        }
    }
}

pub fn gather_captures(bccx: @BorrowckCtxt,
                       move_data: &mut MoveData,
                       closure_expr: @ast::expr) {
    let captured_vars = bccx.capture_map.get(&closure_expr.id);
    for captured_vars.each |captured_var| {
        match captured_var.mode {
            moves::CapMove => {
                let fvar_id = ast_util::def_id_of_def(captured_var.def).node;
                let loan_path = @LpVar(fvar_id);
                move_data.add_move(bccx.tcx, loan_path, closure_expr.id,
                                   Captured(closure_expr));
            }
            moves::CapCopy | moves::CapRef => {}
        }
    }
}

pub fn gather_assignment(bccx: @BorrowckCtxt,
                         move_data: &mut MoveData,
                         assignment_id: ast::node_id,
                         assignment_span: span,
                         assignee_loan_path: @LoanPath,
                         assignee_id: ast::node_id) {
    move_data.add_assignment(bccx.tcx,
                             assignee_loan_path,
                             assignment_id,
                             assignment_span,
                             assignee_id);
}

fn check_is_legal_to_move_from(bccx: @BorrowckCtxt,
                               cmt0: mc::cmt,
                               cmt: mc::cmt) -> bool {
    match cmt.cat {
        mc::cat_stack_upvar(*) |
        mc::cat_implicit_self(*) |
        mc::cat_copied_upvar(*) |
        mc::cat_deref(_, _, mc::region_ptr(*)) |
        mc::cat_deref(_, _, mc::gc_ptr(*)) |
        mc::cat_deref(_, _, mc::unsafe_ptr(*)) => {
            bccx.span_err(
                cmt0.span,
                fmt!("cannot move out of %s",
                     bccx.cmt_to_str(cmt)));
            false
        }

        // It seems strange to allow a move out of a static item,
        // but what happens in practice is that you have a
        // reference to a constant with a type that should be
        // moved, like `None::<~int>`.  The type of this constant
        // is technically `Option<~int>`, which moves, but we know
        // that the content of static items will never actually
        // contain allocated pointers, so we can just memcpy it.
        // Since static items can never have allocated memory,
        // this is ok. For now anyhow.
        mc::cat_static_item => {
            true
        }

        mc::cat_rvalue(*) |
        mc::cat_local(*) |
        mc::cat_arg(*) |
        mc::cat_self(*) => {
            true
        }

        mc::cat_downcast(b) |
        mc::cat_interior(b, _) => {
            match ty::get(b.ty).sty {
                ty::ty_struct(did, _) | ty::ty_enum(did, _) => {
                    if ty::has_dtor(bccx.tcx, did) {
                        bccx.span_err(
                            cmt0.span,
                            fmt!("cannot move out of type `%s`, \
                                  which defines the `Drop` trait",
                                 b.ty.user_string(bccx.tcx)));
                        false
                    } else {
                        check_is_legal_to_move_from(bccx, cmt0, b)
                    }
                }
                _ => {
                    check_is_legal_to_move_from(bccx, cmt0, b)
                }
            }
        }

        mc::cat_deref(b, _, mc::uniq_ptr(*)) |
        mc::cat_discr(b, _) => {
            check_is_legal_to_move_from(bccx, cmt0, b)
        }
    }
}
<|endoftext|>


<commit_before>extern crate armstrong_numbers;
use armstrong_numbers::*;

#[test]
fn test_single_digit_numbers_are_armstrong_numbers() {
    assert!(is_armstrong_number(5))
}

#[test]
#[ignore]
fn test_there_are_no_2_digit_armstring_numbers() {
    assert!(!is_armstrong_number(10))
}

#[test]
#[ignore]
fn test_three_digit_armstrong_number() {
    assert!(is_armstrong_number(153))
}

#[test]
#[ignore]
fn test_three_digit_non_armstrong_number() {
    assert!(!is_armstrong_number(100))
}

#[test]
#[ignore]
fn test_four_digit_armstrong_number() {
    assert!(is_armstrong_number(9474))
}

#[test]
#[ignore]
fn test_four_digit_non_armstrong_number() {
    assert!(!is_armstrong_number(9475))
}

#[test]
#[ignore]
fn test_seven_digit_armstrong_number() {
    assert!(is_armstrong_number(9926315))
}

#[test]
#[ignore]
fn test_seven_digit_non_armstrong_number() {
    assert!(!is_armstrong_number(9926316))
}
<commit_msg>armstrong-numbers: fix misspelling<commit_after>extern crate armstrong_numbers;
use armstrong_numbers::*;

#[test]
fn test_single_digit_numbers_are_armstrong_numbers() {
    assert!(is_armstrong_number(5))
}

#[test]
#[ignore]
fn test_there_are_no_2_digit_armstrong_numbers() {
    assert!(!is_armstrong_number(10))
}

#[test]
#[ignore]
fn test_three_digit_armstrong_number() {
    assert!(is_armstrong_number(153))
}

#[test]
#[ignore]
fn test_three_digit_non_armstrong_number() {
    assert!(!is_armstrong_number(100))
}

#[test]
#[ignore]
fn test_four_digit_armstrong_number() {
    assert!(is_armstrong_number(9474))
}

#[test]
#[ignore]
fn test_four_digit_non_armstrong_number() {
    assert!(!is_armstrong_number(9475))
}

#[test]
#[ignore]
fn test_seven_digit_armstrong_number() {
    assert!(is_armstrong_number(9926315))
}

#[test]
#[ignore]
fn test_seven_digit_non_armstrong_number() {
    assert!(!is_armstrong_number(9926316))
}
<|endoftext|>


<commit_before>/*!

A task that takes a URL and streams back the binary data

*/

export ControlMsg, Load, Exit;
export ProgressMsg, Payload, Done;
export ResourceTask, ResourceManager, LoaderTaskFactory;

import comm::{chan, port, methods};
import task::{spawn, spawn_listener};
import std::net::url;
import std::net::url::url;
import result::{result, ok, err};

enum ControlMsg {
    Load(url, chan<ProgressMsg>),
    Exit
}

enum ProgressMsg {
    Payload(~[u8]),
    Done(result<(), ()>)
}

type ResourceTask = chan<ControlMsg>;
/// Creates a task to load a specific resource
type LoaderTaskFactory = fn~(url: url, chan<ProgressMsg>);

fn ResourceTask() -> ResourceTask {
    let loaders = ~[
        (~"file", file_loader::factory),
        (~"http", http_loader::factory)
    ];
    create_resource_task_with_loaders(loaders)
}

fn create_resource_task_with_loaders(+loaders: ~[(~str, LoaderTaskFactory)]) -> ResourceTask {
    do spawn_listener |from_client| {
        ResourceManager(from_client, loaders).start()
    }
}

class ResourceManager {
    let from_client: port<ControlMsg>;
    /// Per-scheme resource loaders
    let loaders: ~[(~str, LoaderTaskFactory)];

    new(from_client: port<ControlMsg>, loaders: ~[(~str, LoaderTaskFactory)]) {
        self.from_client = from_client;
        self.loaders = loaders;
    }

    fn start() {
        loop {
            alt self.from_client.recv() {
              Load(url, progress_chan) {
                self.load(url, progress_chan)
              }
              Exit {
                break
              }
            }
        }
    }

    fn load(url: url, progress_chan: chan<ProgressMsg>) {

        alt self.get_loader_factory(url) {
          some(loader_factory) {
            #debug("resource_task: loading url: %s", url::to_str(url));
            loader_factory(url, progress_chan);
          }
          none {
            #debug("resource_task: no loader for scheme %s", url.scheme);
            progress_chan.send(Done(err(())));
          }
        }
    }

    fn get_loader_factory(url: url) -> option<LoaderTaskFactory> {
        for self.loaders.each |scheme_loader| {
            let (scheme, loader_factory) = scheme_loader;
            if scheme == url.scheme {
                ret some(loader_factory);
            }
        }
        ret none;
    }
}

#[test]
fn test_exit() {
    let resource_task = ResourceTask();
    resource_task.send(Exit);
}

#[test]
fn test_bad_scheme() {
    let resource_task = ResourceTask();
    let progress = port();
    resource_task.send(Load(url::from_str(~"bogus://whatever").get(), progress.chan()));
    alt check progress.recv() {
      Done(result) { assert result.is_err() }
    }
    resource_task.send(Exit);
}

#[test]
fn should_delegate_to_scheme_loader() {
    let payload = ~[1, 2, 3];
    let loader_factory = fn~(url: url, progress_chan: chan<ProgressMsg>) {
        progress_chan.send(Payload(payload));
        progress_chan.send(Done(ok(())));
    };
    let loader_factories = ~[(~"snicklefritz", loader_factory)];
    let resource_task = create_resource_task_with_loaders(loader_factories);
    let progress = port();
    resource_task.send(Load(url::from_str(~"snicklefritz://heya").get(), progress.chan()));
    assert progress.recv() == Payload(payload);
    assert progress.recv() == Done(ok(()));
    resource_task.send(Exit);
}<commit_msg>Add more resource_task docs<commit_after>/*!

A task that takes a URL and streams back the binary data

*/

export ControlMsg, Load, Exit;
export ProgressMsg, Payload, Done;
export ResourceTask, ResourceManager, LoaderTaskFactory;

import comm::{chan, port, methods};
import task::{spawn, spawn_listener};
import std::net::url;
import std::net::url::url;
import result::{result, ok, err};

enum ControlMsg {
    /// Request the data associated with a particular URL
    Load(url, chan<ProgressMsg>),
    Exit
}

/// Messages sent in response to a `Load` message
enum ProgressMsg {
    /// Binary data - there may be multiple of these
    Payload(~[u8]),
    /// Indicates loading is complete, either successfully or not
    Done(result<(), ()>)
}

/// Handle to a resource task
type ResourceTask = chan<ControlMsg>;

/**
Creates a task to load a specific resource

The ResourceManager delegates loading to a different type of loader task for
each URL scheme
*/
type LoaderTaskFactory = fn~(url: url, chan<ProgressMsg>);

/// Create a ResourceTask with the default loaders
fn ResourceTask() -> ResourceTask {
    let loaders = ~[
        (~"file", file_loader::factory),
        (~"http", http_loader::factory)
    ];
    create_resource_task_with_loaders(loaders)
}

fn create_resource_task_with_loaders(+loaders: ~[(~str, LoaderTaskFactory)]) -> ResourceTask {
    do spawn_listener |from_client| {
        ResourceManager(from_client, loaders).start()
    }
}

class ResourceManager {
    let from_client: port<ControlMsg>;
    /// Per-scheme resource loaders
    let loaders: ~[(~str, LoaderTaskFactory)];

    new(from_client: port<ControlMsg>, loaders: ~[(~str, LoaderTaskFactory)]) {
        self.from_client = from_client;
        self.loaders = loaders;
    }

    fn start() {
        loop {
            alt self.from_client.recv() {
              Load(url, progress_chan) {
                self.load(url, progress_chan)
              }
              Exit {
                break
              }
            }
        }
    }

    fn load(url: url, progress_chan: chan<ProgressMsg>) {

        alt self.get_loader_factory(url) {
          some(loader_factory) {
            #debug("resource_task: loading url: %s", url::to_str(url));
            loader_factory(url, progress_chan);
          }
          none {
            #debug("resource_task: no loader for scheme %s", url.scheme);
            progress_chan.send(Done(err(())));
          }
        }
    }

    fn get_loader_factory(url: url) -> option<LoaderTaskFactory> {
        for self.loaders.each |scheme_loader| {
            let (scheme, loader_factory) = scheme_loader;
            if scheme == url.scheme {
                ret some(loader_factory);
            }
        }
        ret none;
    }
}

#[test]
fn test_exit() {
    let resource_task = ResourceTask();
    resource_task.send(Exit);
}

#[test]
fn test_bad_scheme() {
    let resource_task = ResourceTask();
    let progress = port();
    resource_task.send(Load(url::from_str(~"bogus://whatever").get(), progress.chan()));
    alt check progress.recv() {
      Done(result) { assert result.is_err() }
    }
    resource_task.send(Exit);
}

#[test]
fn should_delegate_to_scheme_loader() {
    let payload = ~[1, 2, 3];
    let loader_factory = fn~(url: url, progress_chan: chan<ProgressMsg>) {
        progress_chan.send(Payload(payload));
        progress_chan.send(Done(ok(())));
    };
    let loader_factories = ~[(~"snicklefritz", loader_factory)];
    let resource_task = create_resource_task_with_loaders(loader_factories);
    let progress = port();
    resource_task.send(Load(url::from_str(~"snicklefritz://heya").get(), progress.chan()));
    assert progress.recv() == Payload(payload);
    assert progress.recv() == Done(ok(()));
    resource_task.send(Exit);
}<|endoftext|>