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

// #![warn(deprecated_mode)]

pub use self::WfConstraint::*;

use middle::subst::{ParamSpace, Subst, Substs};
use middle::ty::{mod, Ty};
use middle::ty_fold::{TypeFolder};

use syntax::ast;

use util::ppaux::Repr;

// Helper functions related to manipulating region types.

pub enum WfConstraint<'tcx> {
    RegionSubRegionConstraint(Option<Ty<'tcx>>, ty::Region, ty::Region),
    RegionSubParamConstraint(Option<Ty<'tcx>>, ty::Region, ty::ParamTy),
}

struct Wf<'a, 'tcx: 'a> {
    tcx: &'a ty::ctxt<'tcx>,
    stack: Vec<(ty::Region, Option<Ty<'tcx>>)>,
    out: Vec<WfConstraint<'tcx>>,
}

/// This routine computes the well-formedness constraints that must hold for the type `ty` to
/// appear in a context with lifetime `outer_region`
pub fn region_wf_constraints<'tcx>(
    tcx: &ty::ctxt<'tcx>,
    ty: Ty<'tcx>,
    outer_region: ty::Region)
    -> Vec<WfConstraint<'tcx>>
{
    let mut stack = Vec::new();
    stack.push((outer_region, None));
    let mut wf = Wf { tcx: tcx,
                      stack: stack,
                      out: Vec::new() };
    wf.accumulate_from_ty(ty);
    wf.out
}

impl<'a, 'tcx> Wf<'a, 'tcx> {
    fn accumulate_from_ty(&mut self, ty: Ty<'tcx>) {
        debug!("Wf::accumulate_from_ty(ty={})",
               ty.repr(self.tcx));

        match ty.sty {
            ty::ty_bool |
            ty::ty_char |
            ty::ty_int(..) |
            ty::ty_uint(..) |
            ty::ty_float(..) |
            ty::ty_bare_fn(..) |
            ty::ty_err |
            ty::ty_str => {
                // No borrowed content reachable here.
            }

            ty::ty_closure(box ref c) => {
                self.accumulate_from_closure_ty(ty, c);
            }

            ty::ty_unboxed_closure(_, region, _) => {
                // An "unboxed closure type" is basically
                // modeled here as equivalent to a struct like
                //
                //     struct TheClosure<'b> {
                //         ...
                //     }
                //
                // where the `'b` is the lifetime bound of the
                // contents (i.e., all contents must outlive 'b).
                //
                // Even though unboxed closures are glorified structs
                // of upvars, we do not need to consider them as they
                // can't generate any new constraints.  The
                // substitutions on the closure are equal to the free
                // substitutions of the enclosing parameter
                // environment.  An upvar captured by value has the
                // same type as the original local variable which is
                // already checked for consistency.  If the upvar is
                // captured by reference it must also outlive the
                // region bound on the closure, but this is explicitly
                // handled by logic in regionck.
                self.push_region_constraint_from_top(*region);
            }

            ty::ty_trait(ref t) => {
                let required_region_bounds =
                    ty::object_region_bounds(self.tcx, Some(&t.principal), t.bounds.builtin_bounds);
                self.accumulate_from_object_ty(ty, t.bounds.region_bound, required_region_bounds)
            }

            ty::ty_enum(def_id, substs) |
            ty::ty_struct(def_id, substs) => {
                let item_scheme = ty::lookup_item_type(self.tcx, def_id);
                self.accumulate_from_adt(ty, def_id, &item_scheme.generics, substs)
            }

            ty::ty_vec(t, _) |
            ty::ty_ptr(ty::mt { ty: t, .. }) |
            ty::ty_uniq(t) => {
                self.accumulate_from_ty(t)
            }

            ty::ty_rptr(r_b, mt) => {
                self.accumulate_from_rptr(ty, *r_b, mt.ty);
            }

            ty::ty_param(p) => {
                self.push_param_constraint_from_top(p);
            }

            ty::ty_projection(ref data) => {
                // `<T as TraitRef<..>>::Name`

                // TODO What region constraints are necessary here, if any??

                // this seems like a minimal requirement:
                let trait_def = ty::lookup_trait_def(self.tcx, data.trait_ref.def_id);
                self.accumulate_from_adt(ty, data.trait_ref.def_id,
                                         &trait_def.generics, &data.trait_ref.substs)
            }

            ty::ty_tup(ref tuptys) => {
                for &tupty in tuptys.iter() {
                    self.accumulate_from_ty(tupty);
                }
            }

            ty::ty_infer(_) => {
                // This should not happen, BUT:
                //
                //   Currently we uncover region relationships on
                //   entering the fn check. We should do this after
                //   the fn check, then we can call this case a bug().
            }

            ty::ty_open(_) => {
                self.tcx.sess.bug(
                    format!("Unexpected type encountered while doing wf check: {}",
                            ty.repr(self.tcx))[]);
            }
        }
    }

    fn accumulate_from_rptr(&mut self,
                            ty: Ty<'tcx>,
                            r_b: ty::Region,
                            ty_b: Ty<'tcx>) {
        // We are walking down a type like this, and current
        // position is indicated by caret:
        //
        //     &'a &'b ty_b
        //         ^
        //
        // At this point, top of stack will be `'a`. We must
        // require that `'a <= 'b`.

        self.push_region_constraint_from_top(r_b);

        // Now we push `'b` onto the stack, because it must
        // constrain any borrowed content we find within `T`.

        self.stack.push((r_b, Some(ty)));
        self.accumulate_from_ty(ty_b);
        self.stack.pop().unwrap();
    }

    /// Pushes a constraint that `r_b` must outlive the top region on the stack.
    fn push_region_constraint_from_top(&mut self,
                                       r_b: ty::Region) {

        // Indicates that we have found borrowed content with a lifetime
        // of at least `r_b`. This adds a constraint that `r_b` must
        // outlive the region `r_a` on top of the stack.
        //
        // As an example, imagine walking a type like:
        //
        //     &'a &'b T
        //         ^
        //
        // when we hit the inner pointer (indicated by caret), `'a` will
        // be on top of stack and `'b` will be the lifetime of the content
        // we just found. So we add constraint that `'a <= 'b`.

        let &(r_a, opt_ty) = self.stack.last().unwrap();
        self.push_sub_region_constraint(opt_ty, r_a, r_b);
    }

    /// Pushes a constraint that `r_a <= r_b`, due to `opt_ty`
    fn push_sub_region_constraint(&mut self,
                                  opt_ty: Option<Ty<'tcx>>,
                                  r_a: ty::Region,
                                  r_b: ty::Region) {
        self.out.push(RegionSubRegionConstraint(opt_ty, r_a, r_b));
    }

    /// Pushes a constraint that `param_ty` must outlive the top region on the stack.
    fn push_param_constraint_from_top(&mut self,
                                      param_ty: ty::ParamTy) {
        let &(region, opt_ty) = self.stack.last().unwrap();
        self.push_param_constraint(region, opt_ty, param_ty);
    }

    /// Pushes a constraint that `region <= param_ty`, due to `opt_ty`
    fn push_param_constraint(&mut self,
                             region: ty::Region,
                             opt_ty: Option<Ty<'tcx>>,
                             param_ty: ty::ParamTy) {
        self.out.push(RegionSubParamConstraint(opt_ty, region, param_ty));
    }

    fn accumulate_from_adt(&mut self,
                           ty: Ty<'tcx>,
                           def_id: ast::DefId,
                           generics: &ty::Generics<'tcx>,
                           substs: &Substs<'tcx>)
    {
        // The generic declarations from the type, appropriately
        // substituted for the actual substitutions.
        let generics = generics.subst(self.tcx, substs);

        // Variance of each type/region parameter.
        let variances = ty::item_variances(self.tcx, def_id);

        for &space in ParamSpace::all().iter() {
            let region_params = substs.regions().get_slice(space);
            let region_variances = variances.regions.get_slice(space);
            let region_param_defs = generics.regions.get_slice(space);
            assert_eq!(region_params.len(), region_variances.len());
            for (&region_param, (&region_variance, region_param_def)) in
                region_params.iter().zip(
                    region_variances.iter().zip(
                        region_param_defs.iter()))
            {
                match region_variance {
                    ty::Covariant | ty::Bivariant => {
                        // Ignore covariant or bivariant region
                        // parameters.  To understand why, consider a
                        // struct `Foo<'a>`. If `Foo` contains any
                        // references with lifetime `'a`, then `'a` must
                        // be at least contravariant (and possibly
                        // invariant). The only way to have a covariant
                        // result is if `Foo` contains only a field with a
                        // type like `fn() -> &'a T`; i.e., a bare
                        // function that can produce a reference of
                        // lifetime `'a`. In this case, there is no
                        // *actual data* with lifetime `'a` that is
                        // reachable. (Presumably this bare function is
                        // really returning static data.)
                    }

                    ty::Contravariant | ty::Invariant => {
                        // If the parameter is contravariant or
                        // invariant, there may indeed be reachable
                        // data with this lifetime. See other case for
                        // more details.
                        self.push_region_constraint_from_top(region_param);
                    }
                }

                for &region_bound in region_param_def.bounds.iter() {
                    // The type declared a constraint like
                    //
                    //     'b : 'a
                    //
                    // which means that `'a <= 'b` (after
                    // substitution).  So take the region we
                    // substituted for `'a` (`region_bound`) and make
                    // it a subregion of the region we substituted
                    // `'b` (`region_param`).
                    self.push_sub_region_constraint(
                        Some(ty), region_bound, region_param);
                }
            }

            let types = substs.types.get_slice(space);
            let type_variances = variances.types.get_slice(space);
            let type_param_defs = generics.types.get_slice(space);
            assert_eq!(types.len(), type_variances.len());
            for (&type_param_ty, (&variance, type_param_def)) in
                types.iter().zip(
                    type_variances.iter().zip(
                        type_param_defs.iter()))
            {
                debug!("type_param_ty={} variance={}",
                       type_param_ty.repr(self.tcx),
                       variance.repr(self.tcx));

                match variance {
                    ty::Contravariant | ty::Bivariant => {
                        // As above, except that in this it is a
                        // *contravariant* reference that indices that no
                        // actual data of type T is reachable.
                    }

                    ty::Covariant | ty::Invariant => {
                        self.accumulate_from_ty(type_param_ty);
                    }
                }

                // Inspect bounds on this type parameter for any
                // region bounds.
                for &r in type_param_def.bounds.region_bounds.iter() {
                    self.stack.push((r, Some(ty)));
                    self.accumulate_from_ty(type_param_ty);
                    self.stack.pop().unwrap();
                }
            }
        }
    }

    fn accumulate_from_closure_ty(&mut self,
                                  ty: Ty<'tcx>,
                                  c: &ty::ClosureTy<'tcx>)
    {
        match c.store {
            ty::RegionTraitStore(r_b, _) => {
                self.push_region_constraint_from_top(r_b);
            }
            ty::UniqTraitStore => { }
        }

        let required_region_bounds =
            ty::object_region_bounds(self.tcx, None, c.bounds.builtin_bounds);
        self.accumulate_from_object_ty(ty, c.bounds.region_bound, required_region_bounds);
    }

    fn accumulate_from_object_ty(&mut self,
                                 ty: Ty<'tcx>,
                                 region_bound: ty::Region,
                                 required_region_bounds: Vec<ty::Region>)
    {
        // Imagine a type like this:
        //
        //     trait Foo { }
        //     trait Bar<'c> : 'c { }
        //
        //     &'b (Foo+'c+Bar<'d>)
        //         ^
        //
        // In this case, the following relationships must hold:
        //
        //     'b <= 'c
        //     'd <= 'c
        //
        // The first conditions is due to the normal region pointer
        // rules, which say that a reference cannot outlive its
        // referent.
        //
        // The final condition may be a bit surprising. In particular,
        // you may expect that it would have been `'c <= 'd`, since
        // usually lifetimes of outer things are conservative
        // approximations for inner things. However, it works somewhat
        // differently with trait objects: here the idea is that if the
        // user specifies a region bound (`'c`, in this case) it is the
        // "master bound" that *implies* that bounds from other traits are
        // all met. (Remember that *all bounds* in a type like
        // `Foo+Bar+Zed` must be met, not just one, hence if we write
        // `Foo<'x>+Bar<'y>`, we know that the type outlives *both* 'x and
        // 'y.)
        //
        // Note: in fact we only permit builtin traits, not `Bar<'d>`, I
        // am looking forward to the future here.

        // The content of this object type must outlive
        // `bounds.region_bound`:
        let r_c = region_bound;
        self.push_region_constraint_from_top(r_c);

        // And then, in turn, to be well-formed, the
        // `region_bound` that user specified must imply the
        // region bounds required from all of the trait types:
        for &r_d in required_region_bounds.iter() {
            // Each of these is an instance of the `'c <= 'b`
            // constraint above
            self.out.push(RegionSubRegionConstraint(Some(ty), r_d, r_c));
        }
    }
}

impl<'tcx> Repr<'tcx> for WfConstraint<'tcx> {
    fn repr(&self, tcx: &ty::ctxt) -> String {
        match *self {
            RegionSubRegionConstraint(_, r_a, r_b) => {
                format!("RegionSubRegionConstraint({}, {})",
                        r_a.repr(tcx),
                        r_b.repr(tcx))
            }

            RegionSubParamConstraint(_, r, p) => {
                format!("RegionSubParamConstraint({}, {})",
                        r.repr(tcx),
                        p.repr(tcx))
            }
        }
    }
}

<commit_msg>Add a FIXME relating to regions and projection types<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.

// #![warn(deprecated_mode)]

pub use self::WfConstraint::*;

use middle::subst::{ParamSpace, Subst, Substs};
use middle::ty::{mod, Ty};
use middle::ty_fold::{TypeFolder};

use syntax::ast;

use util::ppaux::Repr;

// Helper functions related to manipulating region types.

pub enum WfConstraint<'tcx> {
    RegionSubRegionConstraint(Option<Ty<'tcx>>, ty::Region, ty::Region),
    RegionSubParamConstraint(Option<Ty<'tcx>>, ty::Region, ty::ParamTy),
}

struct Wf<'a, 'tcx: 'a> {
    tcx: &'a ty::ctxt<'tcx>,
    stack: Vec<(ty::Region, Option<Ty<'tcx>>)>,
    out: Vec<WfConstraint<'tcx>>,
}

/// This routine computes the well-formedness constraints that must hold for the type `ty` to
/// appear in a context with lifetime `outer_region`
pub fn region_wf_constraints<'tcx>(
    tcx: &ty::ctxt<'tcx>,
    ty: Ty<'tcx>,
    outer_region: ty::Region)
    -> Vec<WfConstraint<'tcx>>
{
    let mut stack = Vec::new();
    stack.push((outer_region, None));
    let mut wf = Wf { tcx: tcx,
                      stack: stack,
                      out: Vec::new() };
    wf.accumulate_from_ty(ty);
    wf.out
}

impl<'a, 'tcx> Wf<'a, 'tcx> {
    fn accumulate_from_ty(&mut self, ty: Ty<'tcx>) {
        debug!("Wf::accumulate_from_ty(ty={})",
               ty.repr(self.tcx));

        match ty.sty {
            ty::ty_bool |
            ty::ty_char |
            ty::ty_int(..) |
            ty::ty_uint(..) |
            ty::ty_float(..) |
            ty::ty_bare_fn(..) |
            ty::ty_err |
            ty::ty_str => {
                // No borrowed content reachable here.
            }

            ty::ty_closure(box ref c) => {
                self.accumulate_from_closure_ty(ty, c);
            }

            ty::ty_unboxed_closure(_, region, _) => {
                // An "unboxed closure type" is basically
                // modeled here as equivalent to a struct like
                //
                //     struct TheClosure<'b> {
                //         ...
                //     }
                //
                // where the `'b` is the lifetime bound of the
                // contents (i.e., all contents must outlive 'b).
                //
                // Even though unboxed closures are glorified structs
                // of upvars, we do not need to consider them as they
                // can't generate any new constraints.  The
                // substitutions on the closure are equal to the free
                // substitutions of the enclosing parameter
                // environment.  An upvar captured by value has the
                // same type as the original local variable which is
                // already checked for consistency.  If the upvar is
                // captured by reference it must also outlive the
                // region bound on the closure, but this is explicitly
                // handled by logic in regionck.
                self.push_region_constraint_from_top(*region);
            }

            ty::ty_trait(ref t) => {
                let required_region_bounds =
                    ty::object_region_bounds(self.tcx, Some(&t.principal), t.bounds.builtin_bounds);
                self.accumulate_from_object_ty(ty, t.bounds.region_bound, required_region_bounds)
            }

            ty::ty_enum(def_id, substs) |
            ty::ty_struct(def_id, substs) => {
                let item_scheme = ty::lookup_item_type(self.tcx, def_id);
                self.accumulate_from_adt(ty, def_id, &item_scheme.generics, substs)
            }

            ty::ty_vec(t, _) |
            ty::ty_ptr(ty::mt { ty: t, .. }) |
            ty::ty_uniq(t) => {
                self.accumulate_from_ty(t)
            }

            ty::ty_rptr(r_b, mt) => {
                self.accumulate_from_rptr(ty, *r_b, mt.ty);
            }

            ty::ty_param(p) => {
                self.push_param_constraint_from_top(p);
            }

            ty::ty_projection(ref data) => {
                // `<T as TraitRef<..>>::Name`

                // FIXME(#20303) -- gain ability to require that ty_projection : in-scope region,
                // like a type parameter

                // this seems like a minimal requirement:
                let trait_def = ty::lookup_trait_def(self.tcx, data.trait_ref.def_id);
                self.accumulate_from_adt(ty, data.trait_ref.def_id,
                                         &trait_def.generics, &data.trait_ref.substs)
            }

            ty::ty_tup(ref tuptys) => {
                for &tupty in tuptys.iter() {
                    self.accumulate_from_ty(tupty);
                }
            }

            ty::ty_infer(_) => {
                // This should not happen, BUT:
                //
                //   Currently we uncover region relationships on
                //   entering the fn check. We should do this after
                //   the fn check, then we can call this case a bug().
            }

            ty::ty_open(_) => {
                self.tcx.sess.bug(
                    format!("Unexpected type encountered while doing wf check: {}",
                            ty.repr(self.tcx))[]);
            }
        }
    }

    fn accumulate_from_rptr(&mut self,
                            ty: Ty<'tcx>,
                            r_b: ty::Region,
                            ty_b: Ty<'tcx>) {
        // We are walking down a type like this, and current
        // position is indicated by caret:
        //
        //     &'a &'b ty_b
        //         ^
        //
        // At this point, top of stack will be `'a`. We must
        // require that `'a <= 'b`.

        self.push_region_constraint_from_top(r_b);

        // Now we push `'b` onto the stack, because it must
        // constrain any borrowed content we find within `T`.

        self.stack.push((r_b, Some(ty)));
        self.accumulate_from_ty(ty_b);
        self.stack.pop().unwrap();
    }

    /// Pushes a constraint that `r_b` must outlive the top region on the stack.
    fn push_region_constraint_from_top(&mut self,
                                       r_b: ty::Region) {

        // Indicates that we have found borrowed content with a lifetime
        // of at least `r_b`. This adds a constraint that `r_b` must
        // outlive the region `r_a` on top of the stack.
        //
        // As an example, imagine walking a type like:
        //
        //     &'a &'b T
        //         ^
        //
        // when we hit the inner pointer (indicated by caret), `'a` will
        // be on top of stack and `'b` will be the lifetime of the content
        // we just found. So we add constraint that `'a <= 'b`.

        let &(r_a, opt_ty) = self.stack.last().unwrap();
        self.push_sub_region_constraint(opt_ty, r_a, r_b);
    }

    /// Pushes a constraint that `r_a <= r_b`, due to `opt_ty`
    fn push_sub_region_constraint(&mut self,
                                  opt_ty: Option<Ty<'tcx>>,
                                  r_a: ty::Region,
                                  r_b: ty::Region) {
        self.out.push(RegionSubRegionConstraint(opt_ty, r_a, r_b));
    }

    /// Pushes a constraint that `param_ty` must outlive the top region on the stack.
    fn push_param_constraint_from_top(&mut self,
                                      param_ty: ty::ParamTy) {
        let &(region, opt_ty) = self.stack.last().unwrap();
        self.push_param_constraint(region, opt_ty, param_ty);
    }

    /// Pushes a constraint that `region <= param_ty`, due to `opt_ty`
    fn push_param_constraint(&mut self,
                             region: ty::Region,
                             opt_ty: Option<Ty<'tcx>>,
                             param_ty: ty::ParamTy) {
        self.out.push(RegionSubParamConstraint(opt_ty, region, param_ty));
    }

    fn accumulate_from_adt(&mut self,
                           ty: Ty<'tcx>,
                           def_id: ast::DefId,
                           generics: &ty::Generics<'tcx>,
                           substs: &Substs<'tcx>)
    {
        // The generic declarations from the type, appropriately
        // substituted for the actual substitutions.
        let generics = generics.subst(self.tcx, substs);

        // Variance of each type/region parameter.
        let variances = ty::item_variances(self.tcx, def_id);

        for &space in ParamSpace::all().iter() {
            let region_params = substs.regions().get_slice(space);
            let region_variances = variances.regions.get_slice(space);
            let region_param_defs = generics.regions.get_slice(space);
            assert_eq!(region_params.len(), region_variances.len());
            for (&region_param, (&region_variance, region_param_def)) in
                region_params.iter().zip(
                    region_variances.iter().zip(
                        region_param_defs.iter()))
            {
                match region_variance {
                    ty::Covariant | ty::Bivariant => {
                        // Ignore covariant or bivariant region
                        // parameters.  To understand why, consider a
                        // struct `Foo<'a>`. If `Foo` contains any
                        // references with lifetime `'a`, then `'a` must
                        // be at least contravariant (and possibly
                        // invariant). The only way to have a covariant
                        // result is if `Foo` contains only a field with a
                        // type like `fn() -> &'a T`; i.e., a bare
                        // function that can produce a reference of
                        // lifetime `'a`. In this case, there is no
                        // *actual data* with lifetime `'a` that is
                        // reachable. (Presumably this bare function is
                        // really returning static data.)
                    }

                    ty::Contravariant | ty::Invariant => {
                        // If the parameter is contravariant or
                        // invariant, there may indeed be reachable
                        // data with this lifetime. See other case for
                        // more details.
                        self.push_region_constraint_from_top(region_param);
                    }
                }

                for &region_bound in region_param_def.bounds.iter() {
                    // The type declared a constraint like
                    //
                    //     'b : 'a
                    //
                    // which means that `'a <= 'b` (after
                    // substitution).  So take the region we
                    // substituted for `'a` (`region_bound`) and make
                    // it a subregion of the region we substituted
                    // `'b` (`region_param`).
                    self.push_sub_region_constraint(
                        Some(ty), region_bound, region_param);
                }
            }

            let types = substs.types.get_slice(space);
            let type_variances = variances.types.get_slice(space);
            let type_param_defs = generics.types.get_slice(space);
            assert_eq!(types.len(), type_variances.len());
            for (&type_param_ty, (&variance, type_param_def)) in
                types.iter().zip(
                    type_variances.iter().zip(
                        type_param_defs.iter()))
            {
                debug!("type_param_ty={} variance={}",
                       type_param_ty.repr(self.tcx),
                       variance.repr(self.tcx));

                match variance {
                    ty::Contravariant | ty::Bivariant => {
                        // As above, except that in this it is a
                        // *contravariant* reference that indices that no
                        // actual data of type T is reachable.
                    }

                    ty::Covariant | ty::Invariant => {
                        self.accumulate_from_ty(type_param_ty);
                    }
                }

                // Inspect bounds on this type parameter for any
                // region bounds.
                for &r in type_param_def.bounds.region_bounds.iter() {
                    self.stack.push((r, Some(ty)));
                    self.accumulate_from_ty(type_param_ty);
                    self.stack.pop().unwrap();
                }
            }
        }
    }

    fn accumulate_from_closure_ty(&mut self,
                                  ty: Ty<'tcx>,
                                  c: &ty::ClosureTy<'tcx>)
    {
        match c.store {
            ty::RegionTraitStore(r_b, _) => {
                self.push_region_constraint_from_top(r_b);
            }
            ty::UniqTraitStore => { }
        }

        let required_region_bounds =
            ty::object_region_bounds(self.tcx, None, c.bounds.builtin_bounds);
        self.accumulate_from_object_ty(ty, c.bounds.region_bound, required_region_bounds);
    }

    fn accumulate_from_object_ty(&mut self,
                                 ty: Ty<'tcx>,
                                 region_bound: ty::Region,
                                 required_region_bounds: Vec<ty::Region>)
    {
        // Imagine a type like this:
        //
        //     trait Foo { }
        //     trait Bar<'c> : 'c { }
        //
        //     &'b (Foo+'c+Bar<'d>)
        //         ^
        //
        // In this case, the following relationships must hold:
        //
        //     'b <= 'c
        //     'd <= 'c
        //
        // The first conditions is due to the normal region pointer
        // rules, which say that a reference cannot outlive its
        // referent.
        //
        // The final condition may be a bit surprising. In particular,
        // you may expect that it would have been `'c <= 'd`, since
        // usually lifetimes of outer things are conservative
        // approximations for inner things. However, it works somewhat
        // differently with trait objects: here the idea is that if the
        // user specifies a region bound (`'c`, in this case) it is the
        // "master bound" that *implies* that bounds from other traits are
        // all met. (Remember that *all bounds* in a type like
        // `Foo+Bar+Zed` must be met, not just one, hence if we write
        // `Foo<'x>+Bar<'y>`, we know that the type outlives *both* 'x and
        // 'y.)
        //
        // Note: in fact we only permit builtin traits, not `Bar<'d>`, I
        // am looking forward to the future here.

        // The content of this object type must outlive
        // `bounds.region_bound`:
        let r_c = region_bound;
        self.push_region_constraint_from_top(r_c);

        // And then, in turn, to be well-formed, the
        // `region_bound` that user specified must imply the
        // region bounds required from all of the trait types:
        for &r_d in required_region_bounds.iter() {
            // Each of these is an instance of the `'c <= 'b`
            // constraint above
            self.out.push(RegionSubRegionConstraint(Some(ty), r_d, r_c));
        }
    }
}

impl<'tcx> Repr<'tcx> for WfConstraint<'tcx> {
    fn repr(&self, tcx: &ty::ctxt) -> String {
        match *self {
            RegionSubRegionConstraint(_, r_a, r_b) => {
                format!("RegionSubRegionConstraint({}, {})",
                        r_a.repr(tcx),
                        r_b.repr(tcx))
            }

            RegionSubParamConstraint(_, r, p) => {
                format!("RegionSubParamConstraint({}, {})",
                        r.repr(tcx),
                        p.repr(tcx))
            }
        }
    }
}

<|endoftext|>


<commit_before>use std::marker::PhantomData;

use backend::*;
use expression::{AsExpression, Expression, SelectableExpression, NonAggregate};
use pg::{Pg, PgQueryBuilder};
use query_builder::*;
use query_builder::debug::DebugQueryBuilder;
use result::QueryResult;
use types::{Array, HasSqlType};

/// Creates a PostgreSQL `ANY` expression.
///
/// As with most bare functions, this is not exported by default. You can import
/// it specifically from `diesel::expression::any`, or glob import
/// `diesel::expression::dsl::*`
///
/// # Example
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # include!("src/doctest_setup.rs");
/// # use diesel::expression::dsl::*;
/// #
/// # table! {
/// #     users {
/// #         id -> Serial,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # fn main() {
/// #     use self::users::dsl::*;
/// #     let connection = establish_connection();
/// #     connection.execute("INSERT INTO users (name) VALUES ('Jim')").unwrap();
/// let sean = (1, "Sean".to_string());
/// let jim = (3, "Jim".to_string());
/// let data = users.filter(name.eq(any(vec!["Sean", "Jim"])));
/// assert_eq!(Ok(vec![sean, jim]), data.load(&connection));
/// # }
/// ```
pub fn any<ST, T>(vals: T) -> Any<T::Expression, ST> where
    Pg: HasSqlType<ST>,
    T: AsExpression<Array<ST>>,
{
    Any::new(vals.as_expression())
}

/// Creates a PostgreSQL `ALL` expression.
///
/// As with most bare functions, this is not exported by default. You can import
/// it specifically from `diesel::expression::all`, or glob import
/// `diesel::expression::dsl::*`
///
/// # Example
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # include!("src/doctest_setup.rs");
/// # use diesel::expression::dsl::*;
/// #
/// # table! {
/// #     users {
/// #         id -> Serial,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # fn main() {
/// #     use self::users::dsl::*;
/// #     let connection = establish_connection();
/// #     connection.execute("INSERT INTO users (name) VALUES ('Jim')").unwrap();
/// let tess = (2, "Tess".to_string());
/// let data = users.filter(name.ne(all(vec!["Sean", "Jim"])));
/// assert_eq!(Ok(vec![tess]), data.load(&connection));
/// # }
/// ```
pub fn all<ST, T>(vals: T) -> All<T::Expression, ST> where
    Pg: HasSqlType<ST>,
    T: AsExpression<Array<ST>>,
{
    All::new(vals.as_expression())
}

#[doc(hidden)]
#[derive(Debug, Copy, Clone)]
pub struct Any<Expr, ST> {
    expr: Expr,
    _marker: PhantomData<ST>,
}

impl<Expr, ST> Any<Expr, ST> {
    fn new(expr: Expr) -> Self {
        Any {
            expr: expr,
            _marker: PhantomData,
        }
    }
}

impl<Expr, ST> Expression for Any<Expr, ST> where
    Pg: HasSqlType<ST>,
    Expr: Expression<SqlType=Array<ST>>,
{
    type SqlType = ST;
}

impl<Expr, ST> QueryFragment<Pg> for Any<Expr, ST> where
    Expr: QueryFragment<Pg>,
{
    fn to_sql(&self, out: &mut PgQueryBuilder) -> BuildQueryResult {
        out.push_sql("ANY(");
        try!(self.expr.to_sql(out));
        out.push_sql(")");
        Ok(())
    }

    fn collect_binds(&self, out: &mut <Pg as Backend>::BindCollector) -> QueryResult<()> {
        try!(self.expr.collect_binds(out));
        Ok(())
    }

    fn is_safe_to_cache_prepared(&self) -> bool {
        self.expr.is_safe_to_cache_prepared()
    }
}

impl<Expr, ST> QueryFragment<Debug> for Any<Expr, ST> where
    Expr: QueryFragment<Debug>,
{
    fn to_sql(&self, out: &mut DebugQueryBuilder) -> BuildQueryResult {
        out.push_sql("ANY(");
        try!(self.expr.to_sql(out));
        out.push_sql(")");
        Ok(())
    }

    fn collect_binds(&self, out: &mut <Debug as Backend>::BindCollector) -> QueryResult<()> {
        try!(self.expr.collect_binds(out));
        Ok(())
    }

    fn is_safe_to_cache_prepared(&self) -> bool {
        self.expr.is_safe_to_cache_prepared()
    }
}

impl_query_id!(Any<Expr, ST>);

impl<Expr, ST, QS> SelectableExpression<QS> for Any<Expr, ST> where
    Pg: HasSqlType<ST>,
    Any<Expr, ST>: Expression,
    Expr: SelectableExpression<QS>,
{
}

impl<Expr, ST> NonAggregate for Any<Expr, ST> where
    Expr: NonAggregate,
    Any<Expr, ST>: Expression,
{
}

#[doc(hidden)]
#[derive(Debug, Copy, Clone)]
pub struct All<Expr, ST> {
    expr: Expr,
    _marker: PhantomData<ST>,
}

impl<Expr, ST> All<Expr, ST> {
    fn new(expr: Expr) -> Self {
        All {
            expr: expr,
            _marker: PhantomData,
        }
    }
}

impl<Expr, ST> Expression for All<Expr, ST> where
    Pg: HasSqlType<ST>,
    Expr: Expression<SqlType=Array<ST>>,
{
    type SqlType = ST;
}

impl<Expr, ST> QueryFragment<Pg> for All<Expr, ST> where
    Expr: QueryFragment<Pg>,
{
    fn to_sql(&self, out: &mut PgQueryBuilder) -> BuildQueryResult {
        out.push_sql("ALL(");
        try!(self.expr.to_sql(out));
        out.push_sql(")");
        Ok(())
    }

    fn collect_binds(&self, out: &mut <Pg as Backend>::BindCollector) -> QueryResult<()> {
        try!(self.expr.collect_binds(out));
        Ok(())
    }

    fn is_safe_to_cache_prepared(&self) -> bool {
        self.expr.is_safe_to_cache_prepared()
    }
}

impl<Expr, ST> QueryFragment<Debug> for All<Expr, ST> where
    Expr: QueryFragment<Debug>,
{
    fn to_sql(&self, out: &mut DebugQueryBuilder) -> BuildQueryResult {
        out.push_sql("ALL(");
        try!(self.expr.to_sql(out));
        out.push_sql(")");
        Ok(())
    }

    fn collect_binds(&self, out: &mut <Debug as Backend>::BindCollector) -> QueryResult<()> {
        try!(self.expr.collect_binds(out));
        Ok(())
    }

    fn is_safe_to_cache_prepared(&self) -> bool {
        self.expr.is_safe_to_cache_prepared()
    }
}

impl_query_id!(All<Expr, ST>);

impl<Expr, ST, QS> SelectableExpression<QS> for All<Expr, ST> where
    Pg: HasSqlType<ST>,
    All<Expr, ST>: Expression,
    Expr: SelectableExpression<QS>,
{
}

impl<Expr, ST> NonAggregate for All<Expr, ST> where
    Expr: NonAggregate,
    All<Expr, ST>: Expression,
{
}
<commit_msg>Remove unused bounds and `PhantomData` from `any` and `all`<commit_after>use backend::*;
use expression::{AsExpression, Expression, SelectableExpression, NonAggregate};
use pg::{Pg, PgQueryBuilder};
use query_builder::*;
use query_builder::debug::DebugQueryBuilder;
use result::QueryResult;
use types::Array;

/// Creates a PostgreSQL `ANY` expression.
///
/// As with most bare functions, this is not exported by default. You can import
/// it specifically from `diesel::expression::any`, or glob import
/// `diesel::expression::dsl::*`
///
/// # Example
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # include!("src/doctest_setup.rs");
/// # use diesel::expression::dsl::*;
/// #
/// # table! {
/// #     users {
/// #         id -> Serial,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # fn main() {
/// #     use self::users::dsl::*;
/// #     let connection = establish_connection();
/// #     connection.execute("INSERT INTO users (name) VALUES ('Jim')").unwrap();
/// let sean = (1, "Sean".to_string());
/// let jim = (3, "Jim".to_string());
/// let data = users.filter(name.eq(any(vec!["Sean", "Jim"])));
/// assert_eq!(Ok(vec![sean, jim]), data.load(&connection));
/// # }
/// ```
pub fn any<ST, T>(vals: T) -> Any<T::Expression> where
    T: AsExpression<Array<ST>>,
{
    Any::new(vals.as_expression())
}

/// Creates a PostgreSQL `ALL` expression.
///
/// As with most bare functions, this is not exported by default. You can import
/// it specifically from `diesel::expression::all`, or glob import
/// `diesel::expression::dsl::*`
///
/// # Example
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # include!("src/doctest_setup.rs");
/// # use diesel::expression::dsl::*;
/// #
/// # table! {
/// #     users {
/// #         id -> Serial,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # fn main() {
/// #     use self::users::dsl::*;
/// #     let connection = establish_connection();
/// #     connection.execute("INSERT INTO users (name) VALUES ('Jim')").unwrap();
/// let tess = (2, "Tess".to_string());
/// let data = users.filter(name.ne(all(vec!["Sean", "Jim"])));
/// assert_eq!(Ok(vec![tess]), data.load(&connection));
/// # }
/// ```
pub fn all<ST, T>(vals: T) -> All<T::Expression> where
    T: AsExpression<Array<ST>>,
{
    All::new(vals.as_expression())
}

#[doc(hidden)]
#[derive(Debug, Copy, Clone)]
pub struct Any<Expr> {
    expr: Expr,
}

impl<Expr> Any<Expr> {
    fn new(expr: Expr) -> Self {
        Any {
            expr: expr,
        }
    }
}

impl<Expr, ST> Expression for Any<Expr> where
    Expr: Expression<SqlType=Array<ST>>,
{
    type SqlType = ST;
}

impl<Expr> QueryFragment<Pg> for Any<Expr> where
    Expr: QueryFragment<Pg>,
{
    fn to_sql(&self, out: &mut PgQueryBuilder) -> BuildQueryResult {
        out.push_sql("ANY(");
        try!(self.expr.to_sql(out));
        out.push_sql(")");
        Ok(())
    }

    fn collect_binds(&self, out: &mut <Pg as Backend>::BindCollector) -> QueryResult<()> {
        try!(self.expr.collect_binds(out));
        Ok(())
    }

    fn is_safe_to_cache_prepared(&self) -> bool {
        self.expr.is_safe_to_cache_prepared()
    }
}

impl<Expr> QueryFragment<Debug> for Any<Expr> where
    Expr: QueryFragment<Debug>,
{
    fn to_sql(&self, out: &mut DebugQueryBuilder) -> BuildQueryResult {
        out.push_sql("ANY(");
        try!(self.expr.to_sql(out));
        out.push_sql(")");
        Ok(())
    }

    fn collect_binds(&self, out: &mut <Debug as Backend>::BindCollector) -> QueryResult<()> {
        try!(self.expr.collect_binds(out));
        Ok(())
    }

    fn is_safe_to_cache_prepared(&self) -> bool {
        self.expr.is_safe_to_cache_prepared()
    }
}

impl_query_id!(Any<Expr>);

impl<Expr, QS> SelectableExpression<QS> for Any<Expr> where
    Any<Expr>: Expression,
    Expr: SelectableExpression<QS>,
{
}

impl<Expr> NonAggregate for Any<Expr> where
    Expr: NonAggregate,
{
}

#[doc(hidden)]
#[derive(Debug, Copy, Clone)]
pub struct All<Expr> {
    expr: Expr,
}

impl<Expr> All<Expr> {
    fn new(expr: Expr) -> Self {
        All {
            expr: expr,
        }
    }
}

impl<Expr, ST> Expression for All<Expr> where
    Expr: Expression<SqlType=Array<ST>>,
{
    type SqlType = ST;
}

impl<Expr> QueryFragment<Pg> for All<Expr> where
    Expr: QueryFragment<Pg>,
{
    fn to_sql(&self, out: &mut PgQueryBuilder) -> BuildQueryResult {
        out.push_sql("ALL(");
        try!(self.expr.to_sql(out));
        out.push_sql(")");
        Ok(())
    }

    fn collect_binds(&self, out: &mut <Pg as Backend>::BindCollector) -> QueryResult<()> {
        try!(self.expr.collect_binds(out));
        Ok(())
    }

    fn is_safe_to_cache_prepared(&self) -> bool {
        self.expr.is_safe_to_cache_prepared()
    }
}

impl<Expr> QueryFragment<Debug> for All<Expr> where
    Expr: QueryFragment<Debug>,
{
    fn to_sql(&self, out: &mut DebugQueryBuilder) -> BuildQueryResult {
        out.push_sql("ALL(");
        try!(self.expr.to_sql(out));
        out.push_sql(")");
        Ok(())
    }

    fn collect_binds(&self, out: &mut <Debug as Backend>::BindCollector) -> QueryResult<()> {
        try!(self.expr.collect_binds(out));
        Ok(())
    }

    fn is_safe_to_cache_prepared(&self) -> bool {
        self.expr.is_safe_to_cache_prepared()
    }
}

impl_query_id!(All<Expr>);

impl<Expr, QS> SelectableExpression<QS> for All<Expr> where
    All<Expr>: Expression,
    Expr: SelectableExpression<QS>,
{
}

impl<Expr> NonAggregate for All<Expr> where
    Expr: NonAggregate,
{
}
<|endoftext|>


<commit_before>use serde_yaml::from_slice;
use std::collections::HashMap;

use data::types::*;
use data::components::*;

static MODULE_LIST: &'static [u8] = include_bytes!("../../module_data.yml");

#[derive(Debug, PartialEq, Deserialize)]
pub struct Module {
    pub name: ModuleTypes,
    pub dependencies: Option<Vec<ResearchTypes>>,
    pub level: Vec<Level>,
}

#[derive(Debug, PartialEq, Deserialize)]
pub struct Level {
    pub level: i32,
    pub resources: Vec<(ResourceTypes, i64)>,
    pub shoots: Option<Shoots>,
    pub generates_energy: Option<GeneratesEnergy>,
}

pub fn get_module_list() -> HashMap<ModuleTypes, Module> {
    let result = from_slice::<HashMap<ModuleTypes, Module>>(MODULE_LIST);
    match result {
        Ok(v) => v,
        Err(e) => panic!("{:?}", e),
    }
}
<commit_msg>Implement HasDependencies for Module<commit_after>use serde_yaml::from_slice;
use std::collections::HashMap;

use data::types::*;
use data::components::*;
use data::helper::HasDependencies;

static MODULE_LIST: &'static [u8] = include_bytes!("../../module_data.yml");

#[derive(Debug, PartialEq, Deserialize)]
pub struct Module {
    pub name: ModuleTypes,
    pub dependencies: Option<Vec<(ResearchTypes, i32)>>,
    pub level: Vec<Level>,
}

impl HasDependencies for Module {
    fn get_dependencies(&self) -> Option<&Vec<(ResearchTypes, i32)>> {
        self.dependencies.as_ref()
    }
}

#[derive(Debug, PartialEq, Deserialize)]
pub struct Level {
    pub level: i32,
    pub resources: Vec<(ResourceTypes, i64)>,
    pub shoots: Option<Shoots>,
    pub generates_energy: Option<GeneratesEnergy>,
}

pub fn get_module_list() -> HashMap<ModuleTypes, Module> {
    let result = from_slice::<HashMap<ModuleTypes, Module>>(MODULE_LIST);
    match result {
        Ok(v) => v,
        Err(e) => panic!("{:?}", e),
    }
}
<|endoftext|>


<commit_before>use std::mem::{transmute};
use sync::{Arc, Mutex};
use conn::{MyInnerConn, MyOpts, MyResult, Stmt, QueryResult};

struct MyInnerPool {
    opts: MyOpts,
    pool: Vec<*()>,
    cap: uint,
    count: uint
}

impl Drop for MyInnerPool {
    fn drop(&mut self) {
        loop {
            match self.pool.pop() {
                Some(conn) => unsafe {
                    drop(transmute::<*(), Box<MyInnerConn>>(conn));
                },
                None => break
            }
        }
    }
}

impl MyInnerPool {
    fn new_conn(&mut self) -> MyResult<()> {
        match MyInnerConn::new(self.opts.clone()) {
            Ok(conn) => {
                unsafe { self.pool.push(transmute(box conn)) };
                Ok(())
            },
            Err(err) => Err(err)
        }
    }
}

#[deriving(Clone)]
pub struct MyPool {
    pool: Arc<Mutex<MyInnerPool>>
}

impl MyPool {
    pub fn new(cap: uint, opts: MyOpts) -> MyPool {
        let pool = MyInnerPool {
            opts: opts,
            pool: Vec::new(),
            cap: cap,
            count: 0
        };
        MyPool{ pool: Arc::new(Mutex::new(pool)) }
    }

    pub fn get_conn(&self) -> MyResult<MyPooledConn> {
        let mut pool = self.pool.lock();

        while pool.pool.is_empty() {
            if pool.cap == 0 || pool.count < pool.cap {
                match pool.new_conn() {
                    Ok(()) => {
                        pool.count += 1;
                        break;
                    },
                    Err(err) => return Err(err)
                }
            } else {
                pool.cond.wait();
            }
        }

        Ok(MyPooledConn {
            pool: self.clone(),
            conn: unsafe { transmute(pool.pool.pop().unwrap()) }
        })
    }
}

pub struct MyPooledConn {
    pool: MyPool,
    conn: Option<Box<MyInnerConn>>
}

#[unsafe_destructor]
impl Drop for MyPooledConn {
    fn drop(&mut self) {
        let conn = unsafe { transmute(self.conn.take_unwrap()) };
        let mut pool = self.pool.pool.lock();
        pool.pool.push(conn);
        pool.cond.signal();
    }
}

impl MyPooledConn {
    pub fn query<'a>(&'a mut self, query: &str) -> MyResult<QueryResult<'a>> {
        self.conn.get_mut_ref().query(query)
    }
    pub fn prepare<'a>(&'a mut self, query: &str) -> MyResult<Stmt<'a>> {
        self.conn.get_mut_ref().prepare(query)
    }
}

#[cfg(test)]
mod test {
    use conn::{MyOpts};
    use std::default::{Default};
    use super::{MyPool};

    #[test]
    fn test_query() {
        let pool = MyPool::new(3, MyOpts{user: Some("root".to_string()),
                                         ..Default::default()});
        for _ in range(0, 10) {
            let pool = pool.clone();
            spawn(proc() {
                let conn = pool.get_conn();
                assert!(conn.is_ok());
                let mut conn = conn.unwrap();
                assert!(conn.query("SELECT 1").is_ok());
            });
        }
    }

    #[test]
    fn test_prepared_query() {
        let pool = MyPool::new(3, MyOpts{user: Some("root".to_string()),
                                         ..Default::default()});
        for _ in range(0, 10) {
            let pool = pool.clone();
            spawn(proc() {
                let conn = pool.get_conn();
                assert!(conn.is_ok());
                let mut conn = conn.unwrap();
                let stmt = conn.prepare("SELECT 1");
                assert!(stmt.is_ok());
                let mut stmt = stmt.unwrap();
                assert!(stmt.execute([]).is_ok());
            });
        }
    }

    #[test]
    fn test_zero_cap() {
        let pool = MyPool::new(0, MyOpts{user: Some("root".to_string()),
                                         ..Default::default()});
        for _ in range(0, 10) {
            let pool = pool.clone();
            spawn(proc() {
                let conn = pool.get_conn();
                assert!(conn.is_ok());
                let mut conn = conn.unwrap();
                assert!(conn.query("SELECT 1").is_ok());
            });
        }
    }
}
<commit_msg>Remove frumious pool hack (thanks to sfackler)<commit_after>use sync::{Arc, Mutex};
use conn::{MyInnerConn, MyOpts, MyResult, Stmt, QueryResult};

struct MyInnerPool {
    opts: MyOpts,
    pool: Vec<MyInnerConn>,
    cap: uint,
    count: uint
}

impl MyInnerPool {
    fn new_conn(&mut self) -> MyResult<()> {
        match MyInnerConn::new(self.opts.clone()) {
            Ok(conn) => {
                self.pool.push(conn);
                Ok(())
            },
            Err(err) => Err(err)
        }
    }
}

#[deriving(Clone)]
pub struct MyPool {
    pool: Arc<Mutex<MyInnerPool>>
}

impl MyPool {
    pub fn new(cap: uint, opts: MyOpts) -> MyPool {
        let pool = MyInnerPool {
            opts: opts,
            pool: Vec::new(),
            cap: cap,
            count: 0
        };
        MyPool{ pool: Arc::new(Mutex::new(pool)) }
    }

    pub fn get_conn(&self) -> MyResult<MyPooledConn> {
        let mut pool = self.pool.lock();

        while pool.pool.is_empty() {
            if pool.cap == 0 || pool.count < pool.cap {
                match pool.new_conn() {
                    Ok(()) => {
                        pool.count += 1;
                        break;
                    },
                    Err(err) => return Err(err)
                }
            } else {
                pool.cond.wait();
            }
        }

        Ok(MyPooledConn {
            pool: self.clone(),
            conn: Some(pool.pool.pop().unwrap())
        })
    }
}

pub struct MyPooledConn {
    pool: MyPool,
    conn: Option<MyInnerConn>
}

#[unsafe_destructor]
impl Drop for MyPooledConn {
    fn drop(&mut self) {
        let mut pool = self.pool.pool.lock();
        pool.pool.push(self.conn.take_unwrap());
        pool.cond.signal();
    }
}

impl MyPooledConn {
    pub fn query<'a>(&'a mut self, query: &str) -> MyResult<QueryResult<'a>> {
        self.conn.get_mut_ref().query(query)
    }
    pub fn prepare<'a>(&'a mut self, query: &str) -> MyResult<Stmt<'a>> {
        self.conn.get_mut_ref().prepare(query)
    }
}

#[cfg(test)]
mod test {
    use conn::{MyOpts};
    use std::default::{Default};
    use super::{MyPool};

    #[test]
    fn test_query() {
        let pool = MyPool::new(3, MyOpts{user: Some("root".to_string()),
                                         ..Default::default()});
        for _ in range(0, 10) {
            let pool = pool.clone();
            spawn(proc() {
                let conn = pool.get_conn();
                assert!(conn.is_ok());
                let mut conn = conn.unwrap();
                assert!(conn.query("SELECT 1").is_ok());
            });
        }
    }

    #[test]
    fn test_prepared_query() {
        let pool = MyPool::new(3, MyOpts{user: Some("root".to_string()),
                                         ..Default::default()});
        for _ in range(0, 10) {
            let pool = pool.clone();
            spawn(proc() {
                let conn = pool.get_conn();
                assert!(conn.is_ok());
                let mut conn = conn.unwrap();
                let stmt = conn.prepare("SELECT 1");
                assert!(stmt.is_ok());
                let mut stmt = stmt.unwrap();
                assert!(stmt.execute([]).is_ok());
            });
        }
    }

    #[test]
    fn test_zero_cap() {
        let pool = MyPool::new(0, MyOpts{user: Some("root".to_string()),
                                         ..Default::default()});
        for _ in range(0, 10) {
            let pool = pool.clone();
            spawn(proc() {
                let conn = pool.get_conn();
                assert!(conn.is_ok());
                let mut conn = conn.unwrap();
                assert!(conn.query("SELECT 1").is_ok());
            });
        }
    }
}
<|endoftext|>


<commit_before>//
// Mnemosyne: a functional systems programming language.
// (c) 2015 Hawk Weisman
//
// Mnemosyne is released under the MIT License. Please refer to
// the LICENSE file at the top-level directory of this distribution
// or at https://github.com/hawkw/mnemosyne/.
//

use std::borrow::Borrow;
use std::collections::HashMap;
use std::hash::Hash;
use std::{ fmt
         , iter
         };
use std::fmt::Write;
use std::rc::Rc;

use ::position::Positional;
use super::annotations::{ Annotated
                        , ScopednessTypestate
                        , ScopedState
                        , Scoped
                        };
use super::types;
use super::SymbolTable;

pub type Ident = Positional<String>;

pub type Expr<'a, S: ScopednessTypestate>
    = Annotated<'a
               , Form<'a, S>
               , S>;

pub type Body<'a, S: ScopednessTypestate> = Vec<Expr<'a, S>>;

pub type Bindings<'a, S: ScopednessTypestate>
    = Vec<Annotated<'a
                   , Binding<'a, S>
                   , S>>;

/// Trait for a node in the abstract syntax tree.
///
/// This provides a visitor method for semantic analysis (which may be split
/// into multiple transforms later), and a method for formatting the AST node
/// as an S-expression.
pub trait Node {

   /// Pretty-print the AST node as an S-expression at the desired
   /// indentation level.]
   ///
   /// Note that this prints the desugared form and may not be a perfect
   /// match for the original source code.
   fn to_sexpr(&self, level: usize) -> String;

}

impl fmt::Display for Node + Sized {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_sexpr(0))
    }
}

pub trait AnnotateTypes<'a>: Sized {

   #[allow(unused_variables)]
   fn annotate_types(self, scope: SymbolTable) -> Scoped<'a, Self> {
       unimplemented!() //TODO: implement
   }
}

#[derive(PartialEq, Clone, Debug)]
pub struct Module<'a, S: ScopednessTypestate> {
    pub name: Ident
  , pub exporting: Vec<Ident>
  , pub body: Body<'a, S>
}

impl<'a, S> Module<'a, S> where S: ScopednessTypestate {

    /// Returns true if the namespace is exporting any nages
    #[inline] pub fn is_lib (&self) -> bool { !self.exporting.is_empty() }

}

impl<'a> Scoped<'a, Module<'a, ScopedState>>{

    pub fn contains_name<Q: ?Sized>(&self, name: &Q) -> bool
    where String: Borrow<Q>
        , String: PartialEq<Q>
        , Q: Hash + Eq
    {
        self.is_defined_here(name) &&
        self.node.exporting
            .iter()
            .find(|ref i| &i.value == name)
            .is_some()
    }

}

#[derive(PartialEq, Clone, Debug)]
pub enum Form<'a, S: ScopednessTypestate> {
    // TODO: maybe definitions aren't expressions?
    // (they don't return a value...)
    Define(DefForm<'a, S>)
  , If { condition: Rc<Expr<'a, S>>
       , if_clause: Rc<Expr<'a, S>>
       , else_clause: Option<Rc<Expr<'a, S>>>
       }
  , Let(LetForm<'a, S>)
  , Call { fun: Ident
         , body: Body<'a, S>
         }
  , Lambda(Function<'a, S>)
  , Logical(Logical<'a, S>)
  , Constant(Const)
  , NameRef(NameRef)
}

#[derive(PartialEq, Clone, Debug)]
pub enum NameRef { Owned(Ident)
                 , Borrowed(Ident)
                 , Deref(Ident)
                 , Unique(Ident)
                 }

#[derive(PartialEq, Clone, Debug)]
pub struct Formal { pub name: Ident
                  , pub annot: Ident
                  }

#[derive(PartialEq, Clone, Debug)]
pub enum DefForm<'a, S: ScopednessTypestate> {
    TopLevel { name: Ident
             , annot: types::Type
             , value: Rc<Expr<'a, S>>
             }
  , Function { name: Ident
             , fun: Function<'a,S>
             }
}

#[derive(PartialEq, Clone, Debug)]
pub struct Class<'a, S: ScopednessTypestate> {
    pub name: Ident
  , pub ty_param: Ident
  , pub defs: Vec<Prototype<'a, S>>
}

#[derive(PartialEq, Clone, Debug)]
pub struct Instance<'a, S: ScopednessTypestate> {
    pub class: Ident
  , pub ty: types::Type
  , pub functions: Vec<Function<'a, S>>
}

/// Logical `and` and `or` expressions
///
/// The general expectation is that these will generally be parsed as infix.
#[derive(PartialEq, Clone, Debug)]
pub enum Logical<'a, S: ScopednessTypestate> {
    And { a: Rc<Expr<'a, S>>
        , b: Rc<Expr<'a, S>>
        }
  , Or { a: Rc<Expr<'a, S>>
       , b: Rc<Expr<'a, S>>
       }
}

#[derive(PartialEq, Clone, Debug)]
pub enum Const { IntConst(i64)
               , UintConst(u64)
               }

impl fmt::Display for Const {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self { Const::IntConst(ref n)    => write!(f, "{}", n)
                    , Const::UintConst(ref n)   => write!(f, "{}", n)
                    }
    }
}

#[derive(PartialEq, Clone, Debug)]
pub enum LetForm<'a, S: ScopednessTypestate> {
    Let { bindings: Bindings<'a, S>
        , body: Body<'a, S>
        }
  , Invocation { proc_id: Ident
               , init: Binding<'a, S>
               , body: Body<'a, S>
               }
  , LetRec { bindings: Bindings<'a, S>
           , body: Body<'a, S>
           }
  , LetSplat { bindings: Bindings<'a, S>
             , body: Body<'a, S>
             }
}

#[derive(PartialEq, Clone, Debug)]
pub struct Binding<'a, S: ScopednessTypestate> {
    pub name: Ident
  , pub typ: types::Type
  , pub value: Rc<Expr<'a, S>>
}

#[derive(PartialEq, Clone, Debug)]
pub struct Function<'a, S: ScopednessTypestate> {
    pub sig: types::Signature
  , pub equations: Vec<Equation<'a,S>>
}

/// A pattern is a vector of pattern elements.
///
/// When entering a function scope that binds using patterns, we should
/// check that the pattern's length matches the arity of the function,
/// until autocurrying is implemented (after the Glorious Revolution).
pub type Pattern = Vec<PatElement>;

/// An element in a pattern-matching expression.
///
/// A pattern element can be a name binding, a typed name binding,
/// a literal, or the magic underscore (anything). Destructuring bind
/// will come later, as will equality.
#[derive(PartialEq, Clone, Debug)]
pub enum PatElement { Name(Ident)
                    , TypedName { name: Ident, ty: types::Type }
                    , Literal(Const)
                    , Anything
                    }

/// A function equation definition
#[derive(PartialEq, Clone, Debug)]
pub struct Equation<'a, S: ScopednessTypestate> {
    pub pattern: Pattern
 ,  pub body: Body<'a, S>
}

#[derive(PartialEq, Clone, Debug)]
pub struct Prototype<'a, S: ScopednessTypestate> {
    pub formals: Vec<Annotated<'a, Formal, S>>
  , pub annot: Ident
}

pub type Variant<'a, S: ScopednessTypestate>
    = Vec<Annotated<'a, Formal, S>>;

#[derive(PartialEq, Clone, Debug)]
pub struct Data<'a, S: ScopednessTypestate> {
    pub name: Ident
  , pub variants: HashMap<Ident, Variant<'a, S>>
}

// #[derive(PartialEq, Clone, Debug)]
// pub enum Data<'a, S: ScopednessTypestate> {
//     Sum { name: Ident
//         , variants: Vec<Type> }
//   , Product { name: Ident
//             , fields: Vec<Binding<'a, S>> }
// }

impl<'a, S> Data<'a, S>
where S: ScopednessTypestate {

    /// Returns true if this ADT is a sum type
    pub fn is_sum_type(&self) -> bool {
        self.variants.len() > 1
    }

    /// Returns true if this ADT is a product type
    #[inline] pub fn is_product_type(&self) -> bool {
        !self.is_sum_type()
    }

    /// Returns the fields of a product type.
    ///
    /// # Returns
    ///  + A `Some<Vec<Annotated<'a, Formal, S>>>` representing
    ///    this type's fields, if this is the definition of a
    ///    product type.
    ///  + Otherwise, `None`
    pub fn get_product_fields(&self) -> Option<&Variant<'a, S>> {
        self.variants.get(&self.name)
    }
}

impl<'a, S> Node for Form<'a, S>
where S: ScopednessTypestate {
   #[allow(unused_variables)]
   fn to_sexpr(&self, level: usize) -> String {
       match *self {
           Form::Define(ref form)  => form.to_sexpr(level)
         , Form::Let(ref form)     => form.to_sexpr(level)
         , Form::If { .. }         => unimplemented!()
         , Form::Call { ref fun, ref body } =>
               format!( "({}{})"
                      , fun.to_sexpr(level)
                      , body.iter()
                            .fold(String::new(), |mut s, expr| {
                                  write!(s, " {}", expr.to_sexpr(level))
                                      .expect("Could not write to string!");
                                  s
                             }))
         , Form::Lambda(ref fun)   => fun.to_sexpr(level)
         , Form::Logical(ref form) => form.to_sexpr(level)
         , Form::Constant(ref c)   => format!("{}", c)
         , Form::NameRef(ref n)    => n.to_sexpr(level)
       }
   }

}

impl<'a, S> Node for DefForm<'a, S>
where S: ScopednessTypestate {

    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            DefForm::TopLevel { ref name, ref annot, ref value } =>
                format!("{}(define {} {} {})"
                  , indent!(level)
                  , name.to_sexpr(level)
                  , annot
                  , value.to_sexpr(level + 1)
                  )
          , DefForm::Function { ref name, ref fun } =>
                format!("{}(define {} {}\n)"
                  , indent!(level)
                  , name.to_sexpr(level)
                  , fun.to_sexpr(level)
                  )
        }
    }

}

impl<'a, S> Node for LetForm<'a, S>
where S: ScopednessTypestate {

    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            LetForm::Let { ref bindings, ref body } =>
                format!("{}(let [{}]\n{})"
                    , indent!(level)
                    , bindings.iter()
                              .fold(String::new(), |mut s, binding| {
                                    write!(s, "{}\n", binding.to_sexpr(level))
                                        .expect("Could not write to string!");
                                    s
                                 })
                    , body.iter()
                          .fold(String::new(), |mut s, expr| {
                              write!(s, "{}", expr.to_sexpr(level + 1))
                                .expect("Could not write to string!");
                              s
                          })
                       )
          , LetForm::LetRec { ref bindings, ref body } =>
                format!("{}(letrec [{}]\n{})"
                    , indent!(level)
                    , bindings.iter()
                              .fold(String::new(), |mut s, binding| {
                                    write!(s, "{}\n", binding.to_sexpr(level))
                                        .expect("Could not write to string!");
                                    s
                               })
                    , body.iter()
                          .fold(String::new(), |mut s, expr| {
                                write!(s, "{}", expr.to_sexpr(level + 1)); s
                            })
                          )
          , LetForm::LetSplat { ref bindings, ref body } =>
                format!("{}(let* [{}]\n{})"
                    , indent!(level)
                    , bindings.iter()
                              .fold(String::new(), |mut s, binding| {
                                    write!(s, "{}\n", binding.to_sexpr(level))
                                        .expect("Could not write to string!");
                                    s
                               })
                    , body.iter()
                          .fold(String::new(), |mut s, expr| {
                                write!(s, "{}", expr.to_sexpr(level + 1))
                                    .expect("Could not write to string!");
                                s
                            })
                          )
          , _ => unimplemented!()
        }
    }

}

impl<'a, S> Node for Logical<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            Logical::And { ref a, ref b } =>
                format!( "(and {} {})"
                       , a.to_sexpr(level)
                       , b.to_sexpr(level)
                       )
         ,  Logical::Or { ref a, ref b }  =>
                format!( "(and {} {})"
                       , a.to_sexpr(level)
                       , b.to_sexpr(level)
                       )
        }
    }
}

impl<'a, S> Node for Function<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        unimplemented!()
    }
}

impl<'a, S> Node for Binding<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        unimplemented!()
    }
}

impl Node for Formal {
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        format!("{}: {}", *(self.name), *(self.annot))
    }

}

impl Node for NameRef {
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        match *self  { NameRef::Owned(ref name)      => format!("{}", **name)
                     , NameRef::Borrowed(ref name)   => format!("&{}", **name)
                     , NameRef::Deref(ref name)      => format!("*{}", **name)
                     , NameRef::Unique(ref name)     => format!("@{}", **name)
                     }

    }
}

impl Node for Ident {
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String { self.value.clone() }

}
<commit_msg>Additional work on pattern matching stuff in AST<commit_after>//
// Mnemosyne: a functional systems programming language.
// (c) 2015 Hawk Weisman
//
// Mnemosyne is released under the MIT License. Please refer to
// the LICENSE file at the top-level directory of this distribution
// or at https://github.com/hawkw/mnemosyne/.
//

use std::borrow::Borrow;
use std::collections::HashMap;
use std::hash::Hash;
use std::{ fmt
         , iter
         };
use std::fmt::Write;
use std::rc::Rc;

use ::position::Positional;
use super::annotations::{ Annotated
                        , ScopednessTypestate
                        , ScopedState
                        , Scoped
                        };
use super::types;
use super::SymbolTable;

pub type Ident = Positional<String>;

pub type Expr<'a, S: ScopednessTypestate>
    = Annotated<'a
               , Form<'a, S>
               , S>;

pub type Body<'a, S: ScopednessTypestate> = Vec<Expr<'a, S>>;

pub type Bindings<'a, S: ScopednessTypestate>
    = Vec<Annotated<'a
                   , Binding<'a, S>
                   , S>>;

/// Trait for a node in the abstract syntax tree.
///
/// This provides a visitor method for semantic analysis (which may be split
/// into multiple transforms later), and a method for formatting the AST node
/// as an S-expression.
pub trait Node {

   /// Pretty-print the AST node as an S-expression at the desired
   /// indentation level.]
   ///
   /// Note that this prints the desugared form and may not be a perfect
   /// match for the original source code.
   fn to_sexpr(&self, level: usize) -> String;

}

impl fmt::Display for Node + Sized {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_sexpr(0))
    }
}

pub trait AnnotateTypes<'a>: Sized {

   #[allow(unused_variables)]
   fn annotate_types(self, scope: SymbolTable) -> Scoped<'a, Self> {
       unimplemented!() //TODO: implement
   }
}

#[derive(PartialEq, Clone, Debug)]
pub struct Module<'a, S: ScopednessTypestate> {
    pub name: Ident
  , pub exporting: Vec<Ident>
  , pub body: Body<'a, S>
}

impl<'a, S> Module<'a, S> where S: ScopednessTypestate {

    /// Returns true if the namespace is exporting any nages
    #[inline] pub fn is_lib (&self) -> bool { !self.exporting.is_empty() }

}

impl<'a> Scoped<'a, Module<'a, ScopedState>>{

    pub fn contains_name<Q: ?Sized>(&self, name: &Q) -> bool
    where String: Borrow<Q>
        , String: PartialEq<Q>
        , Q: Hash + Eq
    {
        self.is_defined_here(name) &&
        self.node.exporting
            .iter()
            .find(|ref i| &i.value == name)
            .is_some()
    }

}

#[derive(PartialEq, Clone, Debug)]
pub enum Form<'a, S: ScopednessTypestate> {
    // TODO: maybe definitions aren't expressions?
    // (they don't return a value...)
    Define(DefForm<'a, S>)
  , If { condition: Rc<Expr<'a, S>>
       , if_clause: Rc<Expr<'a, S>>
       , else_clause: Option<Rc<Expr<'a, S>>>
       }
  , Let(LetForm<'a, S>)
  , Call { fun: Ident
         , body: Body<'a, S>
         }
  , Lambda(Function<'a, S>)
  , Logical(Logical<'a, S>)
  , Constant(Const)
  , NameRef(NameRef)
}

#[derive(PartialEq, Clone, Debug)]
pub enum NameRef { Owned(Ident)
                 , Borrowed(Ident)
                 , Deref(Ident)
                 , Unique(Ident)
                 }

#[derive(PartialEq, Clone, Debug)]
pub struct Formal { pub name: Ident
                  , pub annot: Ident
                  }

#[derive(PartialEq, Clone, Debug)]
pub enum DefForm<'a, S: ScopednessTypestate> {
    TopLevel { name: Ident
             , annot: types::Type
             , value: Rc<Expr<'a, S>>
             }
  , Function { name: Ident
             , fun: Function<'a,S>
             }
}

#[derive(PartialEq, Clone, Debug)]
pub struct Class<'a, S: ScopednessTypestate> {
    pub name: Ident
  , pub ty_param: Ident
  , pub defs: Vec<Prototype<'a, S>>
}

#[derive(PartialEq, Clone, Debug)]
pub struct Instance<'a, S: ScopednessTypestate> {
    pub class: Ident
  , pub ty: types::Type
  , pub functions: Vec<Function<'a, S>>
}

/// Logical `and` and `or` expressions
///
/// The general expectation is that these will generally be parsed as infix.
#[derive(PartialEq, Clone, Debug)]
pub enum Logical<'a, S: ScopednessTypestate> {
    And { a: Rc<Expr<'a, S>>
        , b: Rc<Expr<'a, S>>
        }
  , Or { a: Rc<Expr<'a, S>>
       , b: Rc<Expr<'a, S>>
       }
}

#[derive(PartialEq, Clone, Debug)]
pub enum Const { IntConst(i64)
               , UintConst(u64)
               }

impl fmt::Display for Const {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self { Const::IntConst(ref n)    => write!(f, "{}", n)
                    , Const::UintConst(ref n)   => write!(f, "{}", n)
                    }
    }
}

#[derive(PartialEq, Clone, Debug)]
pub enum LetForm<'a, S: ScopednessTypestate> {
    Let { bindings: Bindings<'a, S>
        , body: Body<'a, S>
        }
  , Invocation { proc_id: Ident
               , init: Binding<'a, S>
               , body: Body<'a, S>
               }
  , LetRec { bindings: Bindings<'a, S>
           , body: Body<'a, S>
           }
  , LetSplat { bindings: Bindings<'a, S>
             , body: Body<'a, S>
             }
}

#[derive(PartialEq, Clone, Debug)]
pub struct Binding<'a, S: ScopednessTypestate> {
    pub name: Ident
  , pub typ: types::Type
  , pub value: Rc<Expr<'a, S>>
}

#[derive(PartialEq, Clone, Debug)]
pub struct Function<'a, S: ScopednessTypestate> {
    pub sig: types::Signature
  , pub equations: Vec<Equation<'a, S>>
}

/// A pattern is a vector of pattern elements.
///
/// When entering a function scope that binds using patterns, we should
/// check that the pattern's length matches the arity of the function,
/// until autocurrying is implemented (after the Glorious Revolution).
pub type Pattern = Vec<PatElement>;

impl Node for Pattern {
   #[allow(unused_variables)]
   fn to_sexpr(&self, level: usize) -> String {
       format!( "({})"
              , self.iter()
                    .fold(String::new(), |mut s, expr| {
                       write!(s, " {} ", expr.to_sexpr(level))
                           .expect("Could not write to string!");
                       s
                  })
               )
   }

}

/// An element in a pattern-matching expression.
///
/// A pattern element can be a name binding, a typed name binding,
/// a literal, or the magic underscore (anything). Destructuring bind
/// will come later, as will equality.
#[derive(PartialEq, Clone, Debug)]
pub enum PatElement { // eventually this could just be implemented using an Expr,
                      // but it's currently this way because the types of patterns
                      // that you can write are currently quite limited
                      Name(Ident)
                    , TypedName { name: Ident, ty: types::Type }
                    , Literal(Const)
                      // TODO: write literal types for other things (i.e. lists)
                    , Anything
                    }

impl Node for PatElement {
   #[allow(unused_variables)]
   fn to_sexpr(&self, level: usize) -> String {
       match *self {
           PatElement::Name(ref n) => n.to_sexpr(level)
         , PatElement::TypedName{ ref name, ref ty } =>
            format!("{}: {}", name.to_sexpr(level), ty)
        , PatElement::Literal(ref c) => format!("{}", c)
        , PatElement::Anything => String::from("_")
       }
   }

}

/// A function equation definition
#[derive(PartialEq, Clone, Debug)]
pub struct Equation<'a, S: ScopednessTypestate> {
    pub pattern: Pattern
 ,  pub body: Body<'a, S>
}

#[derive(PartialEq, Clone, Debug)]
pub struct Prototype<'a, S: ScopednessTypestate> {
    pub formals: Vec<Annotated<'a, Formal, S>>
  , pub annot: Ident
}

pub type Variant<'a, S: ScopednessTypestate>
    = Vec<Annotated<'a, Formal, S>>;

#[derive(PartialEq, Clone, Debug)]
pub struct Data<'a, S: ScopednessTypestate> {
    pub name: Ident
  , pub variants: HashMap<Ident, Variant<'a, S>>
}

// #[derive(PartialEq, Clone, Debug)]
// pub enum Data<'a, S: ScopednessTypestate> {
//     Sum { name: Ident
//         , variants: Vec<Type> }
//   , Product { name: Ident
//             , fields: Vec<Binding<'a, S>> }
// }

impl<'a, S> Data<'a, S>
where S: ScopednessTypestate {

    /// Returns true if this ADT is a sum type
    pub fn is_sum_type(&self) -> bool {
        self.variants.len() > 1
    }

    /// Returns true if this ADT is a product type
    #[inline] pub fn is_product_type(&self) -> bool {
        !self.is_sum_type()
    }

    /// Returns the fields of a product type.
    ///
    /// # Returns
    ///  + A `Some<Vec<Annotated<'a, Formal, S>>>` representing
    ///    this type's fields, if this is the definition of a
    ///    product type.
    ///  + Otherwise, `None`
    pub fn get_product_fields(&self) -> Option<&Variant<'a, S>> {
        self.variants.get(&self.name)
    }
}

impl<'a, S> Node for Form<'a, S>
where S: ScopednessTypestate {
   #[allow(unused_variables)]
   fn to_sexpr(&self, level: usize) -> String {
       match *self {
           Form::Define(ref form)  => form.to_sexpr(level)
         , Form::Let(ref form)     => form.to_sexpr(level)
         , Form::If { .. }         => unimplemented!()
         , Form::Call { ref fun, ref body } =>
               format!( "({}{})"
                      , fun.to_sexpr(level)
                      , body.iter()
                            .fold(String::new(), |mut s, expr| {
                                  write!(s, " {}", expr.to_sexpr(level))
                                      .expect("Could not write to string!");
                                  s
                             }))
         , Form::Lambda(ref fun)   => fun.to_sexpr(level)
         , Form::Logical(ref form) => form.to_sexpr(level)
         , Form::Constant(ref c)   => format!("{}", c)
         , Form::NameRef(ref n)    => n.to_sexpr(level)
       }
   }

}

impl<'a, S> Node for DefForm<'a, S>
where S: ScopednessTypestate {

    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            DefForm::TopLevel { ref name, ref annot, ref value } =>
                format!("{}(define {} {} {})"
                  , indent!(level)
                  , name.to_sexpr(level)
                  , annot
                  , value.to_sexpr(level + 1)
                  )
          , DefForm::Function { ref name, ref fun } =>
                format!("{}(define {} {}\n)"
                  , indent!(level)
                  , name.to_sexpr(level)
                  , fun.to_sexpr(level)
                  )
        }
    }

}

impl<'a, S> Node for LetForm<'a, S>
where S: ScopednessTypestate {

    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            LetForm::Let { ref bindings, ref body } =>
                format!("{}(let [{}]\n{})"
                    , indent!(level)
                    , bindings.iter()
                              .fold(String::new(), |mut s, binding| {
                                    write!(s, "{}\n", binding.to_sexpr(level))
                                        .expect("Could not write to string!");
                                    s
                                 })
                    , body.iter()
                          .fold(String::new(), |mut s, expr| {
                              write!(s, "{}", expr.to_sexpr(level + 1))
                                .expect("Could not write to string!");
                              s
                          })
                       )
          , LetForm::LetRec { ref bindings, ref body } =>
                format!("{}(letrec [{}]\n{})"
                    , indent!(level)
                    , bindings.iter()
                              .fold(String::new(), |mut s, binding| {
                                    write!(s, "{}\n", binding.to_sexpr(level))
                                        .expect("Could not write to string!");
                                    s
                               })
                    , body.iter()
                          .fold(String::new(), |mut s, expr| {
                                write!(s, "{}", expr.to_sexpr(level + 1)); s
                            })
                          )
          , LetForm::LetSplat { ref bindings, ref body } =>
                format!("{}(let* [{}]\n{})"
                    , indent!(level)
                    , bindings.iter()
                              .fold(String::new(), |mut s, binding| {
                                    write!(s, "{}\n", binding.to_sexpr(level))
                                        .expect("Could not write to string!");
                                    s
                               })
                    , body.iter()
                          .fold(String::new(), |mut s, expr| {
                                write!(s, "{}", expr.to_sexpr(level + 1))
                                    .expect("Could not write to string!");
                                s
                            })
                          )
          , _ => unimplemented!()
        }
    }

}

impl<'a, S> Node for Logical<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            Logical::And { ref a, ref b } =>
                format!( "(and {} {})"
                       , a.to_sexpr(level)
                       , b.to_sexpr(level)
                       )
         ,  Logical::Or { ref a, ref b }  =>
                format!( "(and {} {})"
                       , a.to_sexpr(level)
                       , b.to_sexpr(level)
                       )
        }
    }
}

impl<'a, S> Node for Function<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        unimplemented!()
    }
}

impl<'a, S> Node for Binding<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        unimplemented!()
    }
}

impl Node for Formal {
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        format!("{}: {}", *(self.name), *(self.annot))
    }

}

impl Node for NameRef {
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        match *self  { NameRef::Owned(ref name)      => format!("{}", **name)
                     , NameRef::Borrowed(ref name)   => format!("&{}", **name)
                     , NameRef::Deref(ref name)      => format!("*{}", **name)
                     , NameRef::Unique(ref name)     => format!("@{}", **name)
                     }

    }
}

impl Node for Ident {
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String { self.value.clone() }

}
<|endoftext|>


<commit_before>use std::{
    collections::HashMap,
    fs,
    path::{Path, PathBuf},
};

use clap::{App, Arg, SubCommand};
use failure::bail;

use tools::{
    collect_tests, generate,install_format_hook, run, run_rustfmt,
    Mode, Overwrite, Result, Test, Verify, project_root, run_fuzzer
};

const GRAMMAR_DIR: &str = "crates/ra_syntax/src/grammar";
const OK_INLINE_TESTS_DIR: &str = "crates/ra_syntax/tests/data/parser/inline/ok";
const ERR_INLINE_TESTS_DIR: &str = "crates/ra_syntax/tests/data/parser/inline/err";

fn main() -> Result<()> {
    let matches = App::new("tasks")
        .setting(clap::AppSettings::SubcommandRequiredElseHelp)
        .arg(
            Arg::with_name("verify")
                .long("--verify")
                .help("Verify that generated code is up-to-date")
                .global(true),
        )
        .subcommand(SubCommand::with_name("gen-syntax"))
        .subcommand(SubCommand::with_name("gen-tests"))
        .subcommand(SubCommand::with_name("install-code"))
        .subcommand(SubCommand::with_name("format"))
        .subcommand(SubCommand::with_name("format-hook"))
        .subcommand(SubCommand::with_name("fuzz-tests"))
        .get_matches();
    let mode = if matches.is_present("verify") {
        Verify
    } else {
        Overwrite
    };
    match matches
        .subcommand_name()
        .expect("Subcommand must be specified")
    {
        "install-code" => install_code_extension()?,
        "gen-tests" => gen_tests(mode)?,
        "gen-syntax" => generate(Overwrite)?,
        "format" => run_rustfmt(mode)?,
        "format-hook" => install_format_hook()?,
        "fuzz-tests" => run_fuzzer()?,
        _ => unreachable!(),
    }
    Ok(())
}

fn gen_tests(mode: Mode) -> Result<()> {
    let tests = tests_from_dir(Path::new(GRAMMAR_DIR))?;
    fn install_tests(tests: &HashMap<String, Test>, into: &str, mode: Mode) -> Result<()> {
        let tests_dir = project_root().join(into);
        if !tests_dir.is_dir() {
            fs::create_dir_all(&tests_dir)?;
        }
        // ok is never actually read, but it needs to be specified to create a Test in existing_tests
        let existing = existing_tests(&tests_dir, true)?;
        for t in existing.keys().filter(|&t| !tests.contains_key(t)) {
            panic!("Test is deleted: {}", t);
        }

        let mut new_idx = existing.len() + 1;
        for (name, test) in tests {
            let path = match existing.get(name) {
                Some((path, _test)) => path.clone(),
                None => {
                    let file_name = format!("{:04}_{}.rs", new_idx, name);
                    new_idx += 1;
                    tests_dir.join(file_name)
                }
            };
            teraron::update(&path, &test.text, mode)?;
        }
        Ok(())
    }
    install_tests(&tests.ok, OK_INLINE_TESTS_DIR, mode)?;
    install_tests(&tests.err, ERR_INLINE_TESTS_DIR, mode)
}

#[derive(Default, Debug)]
struct Tests {
    pub ok: HashMap<String, Test>,
    pub err: HashMap<String, Test>,
}

fn tests_from_dir(dir: &Path) -> Result<Tests> {
    let mut res = Tests::default();
    for entry in ::walkdir::WalkDir::new(dir) {
        let entry = entry.unwrap();
        if !entry.file_type().is_file() {
            continue;
        }
        if entry.path().extension().unwrap_or_default() != "rs" {
            continue;
        }
        process_file(&mut res, entry.path())?;
    }
    let grammar_rs = dir.parent().unwrap().join("grammar.rs");
    process_file(&mut res, &grammar_rs)?;
    return Ok(res);
    fn process_file(res: &mut Tests, path: &Path) -> Result<()> {
        let text = fs::read_to_string(path)?;

        for (_, test) in collect_tests(&text) {
            if test.ok {
                if let Some(old_test) = res.ok.insert(test.name.clone(), test) {
                    bail!("Duplicate test: {}", old_test.name)
                }
            } else {
                if let Some(old_test) = res.err.insert(test.name.clone(), test) {
                    bail!("Duplicate test: {}", old_test.name)
                }
            }
        }
        Ok(())
    }
}

fn existing_tests(dir: &Path, ok: bool) -> Result<HashMap<String, (PathBuf, Test)>> {
    let mut res = HashMap::new();
    for file in fs::read_dir(dir)? {
        let file = file?;
        let path = file.path();
        if path.extension().unwrap_or_default() != "rs" {
            continue;
        }
        let name = {
            let file_name = path.file_name().unwrap().to_str().unwrap();
            file_name[5..file_name.len() - 3].to_string()
        };
        let text = fs::read_to_string(&path)?;
        let test = Test {
            name: name.clone(),
            text,
            ok,
        };
        if let Some(old) = res.insert(name, (path, test)) {
            println!("Duplicate test: {:?}", old);
        }
    }
    Ok(res)
}

fn install_code_extension() -> Result<()> {
    run("cargo install --path crates/ra_lsp_server --force", ".")?;
    if cfg!(windows) {
        run(r"cmd.exe /c npm.cmd install", "./editors/code")?;
        run(r"cmd.exe /c npm.cmd run package", "./editors/code")?;
    } else {
        run(r"npm install", "./editors/code")?;
        run(r"npm run package", "./editors/code")?;
    }
    if cfg!(windows) {
        run(
            r"cmd.exe /c code.cmd --install-extension ./ra-lsp-0.0.1.vsix --force",
            "./editors/code",
        )?;
    } else {
        run(
            r"code --install-extension ./ra-lsp-0.0.1.vsix --force",
            "./editors/code",
        )?;
    }
    Ok(())
}
<commit_msg>Use npm ci instead of install<commit_after>use std::{
    collections::HashMap,
    fs,
    path::{Path, PathBuf},
};

use clap::{App, Arg, SubCommand};
use failure::bail;

use tools::{
    collect_tests, generate,install_format_hook, run, run_rustfmt,
    Mode, Overwrite, Result, Test, Verify, project_root, run_fuzzer
};

const GRAMMAR_DIR: &str = "crates/ra_syntax/src/grammar";
const OK_INLINE_TESTS_DIR: &str = "crates/ra_syntax/tests/data/parser/inline/ok";
const ERR_INLINE_TESTS_DIR: &str = "crates/ra_syntax/tests/data/parser/inline/err";

fn main() -> Result<()> {
    let matches = App::new("tasks")
        .setting(clap::AppSettings::SubcommandRequiredElseHelp)
        .arg(
            Arg::with_name("verify")
                .long("--verify")
                .help("Verify that generated code is up-to-date")
                .global(true),
        )
        .subcommand(SubCommand::with_name("gen-syntax"))
        .subcommand(SubCommand::with_name("gen-tests"))
        .subcommand(SubCommand::with_name("install-code"))
        .subcommand(SubCommand::with_name("format"))
        .subcommand(SubCommand::with_name("format-hook"))
        .subcommand(SubCommand::with_name("fuzz-tests"))
        .get_matches();
    let mode = if matches.is_present("verify") {
        Verify
    } else {
        Overwrite
    };
    match matches
        .subcommand_name()
        .expect("Subcommand must be specified")
    {
        "install-code" => install_code_extension()?,
        "gen-tests" => gen_tests(mode)?,
        "gen-syntax" => generate(Overwrite)?,
        "format" => run_rustfmt(mode)?,
        "format-hook" => install_format_hook()?,
        "fuzz-tests" => run_fuzzer()?,
        _ => unreachable!(),
    }
    Ok(())
}

fn gen_tests(mode: Mode) -> Result<()> {
    let tests = tests_from_dir(Path::new(GRAMMAR_DIR))?;
    fn install_tests(tests: &HashMap<String, Test>, into: &str, mode: Mode) -> Result<()> {
        let tests_dir = project_root().join(into);
        if !tests_dir.is_dir() {
            fs::create_dir_all(&tests_dir)?;
        }
        // ok is never actually read, but it needs to be specified to create a Test in existing_tests
        let existing = existing_tests(&tests_dir, true)?;
        for t in existing.keys().filter(|&t| !tests.contains_key(t)) {
            panic!("Test is deleted: {}", t);
        }

        let mut new_idx = existing.len() + 1;
        for (name, test) in tests {
            let path = match existing.get(name) {
                Some((path, _test)) => path.clone(),
                None => {
                    let file_name = format!("{:04}_{}.rs", new_idx, name);
                    new_idx += 1;
                    tests_dir.join(file_name)
                }
            };
            teraron::update(&path, &test.text, mode)?;
        }
        Ok(())
    }
    install_tests(&tests.ok, OK_INLINE_TESTS_DIR, mode)?;
    install_tests(&tests.err, ERR_INLINE_TESTS_DIR, mode)
}

#[derive(Default, Debug)]
struct Tests {
    pub ok: HashMap<String, Test>,
    pub err: HashMap<String, Test>,
}

fn tests_from_dir(dir: &Path) -> Result<Tests> {
    let mut res = Tests::default();
    for entry in ::walkdir::WalkDir::new(dir) {
        let entry = entry.unwrap();
        if !entry.file_type().is_file() {
            continue;
        }
        if entry.path().extension().unwrap_or_default() != "rs" {
            continue;
        }
        process_file(&mut res, entry.path())?;
    }
    let grammar_rs = dir.parent().unwrap().join("grammar.rs");
    process_file(&mut res, &grammar_rs)?;
    return Ok(res);
    fn process_file(res: &mut Tests, path: &Path) -> Result<()> {
        let text = fs::read_to_string(path)?;

        for (_, test) in collect_tests(&text) {
            if test.ok {
                if let Some(old_test) = res.ok.insert(test.name.clone(), test) {
                    bail!("Duplicate test: {}", old_test.name)
                }
            } else {
                if let Some(old_test) = res.err.insert(test.name.clone(), test) {
                    bail!("Duplicate test: {}", old_test.name)
                }
            }
        }
        Ok(())
    }
}

fn existing_tests(dir: &Path, ok: bool) -> Result<HashMap<String, (PathBuf, Test)>> {
    let mut res = HashMap::new();
    for file in fs::read_dir(dir)? {
        let file = file?;
        let path = file.path();
        if path.extension().unwrap_or_default() != "rs" {
            continue;
        }
        let name = {
            let file_name = path.file_name().unwrap().to_str().unwrap();
            file_name[5..file_name.len() - 3].to_string()
        };
        let text = fs::read_to_string(&path)?;
        let test = Test {
            name: name.clone(),
            text,
            ok,
        };
        if let Some(old) = res.insert(name, (path, test)) {
            println!("Duplicate test: {:?}", old);
        }
    }
    Ok(res)
}

fn install_code_extension() -> Result<()> {
    run("cargo install --path crates/ra_lsp_server --force", ".")?;
    if cfg!(windows) {
        run(r"cmd.exe /c npm.cmd ci", "./editors/code")?;
        run(r"cmd.exe /c npm.cmd run package", "./editors/code")?;
    } else {
        run(r"npm ci", "./editors/code")?;
        run(r"npm run package", "./editors/code")?;
    }
    if cfg!(windows) {
        run(
            r"cmd.exe /c code.cmd --install-extension ./ra-lsp-0.0.1.vsix --force",
            "./editors/code",
        )?;
    } else {
        run(
            r"code --install-extension ./ra-lsp-0.0.1.vsix --force",
            "./editors/code",
        )?;
    }
    Ok(())
}
<|endoftext|>