// Add bindings to a formula using an implication or
        // conjunction. The bindings themselves will be flattened as well,
        // which might introduce further bindings
        private VCExpr AddBindings(List <VCExprLetBinding /*!*/> /*!*/ bindings, VCExpr body, FlattenerState state)
        {
            Contract.Requires(body != null);
            Contract.Requires(cce.NonNullElements(bindings));
            Contract.Requires((body.Type.IsBool));
            Contract.Ensures(Contract.Result <VCExpr>() != null);

            List <VCExprLetBinding /*!*/> /*!*/ mutatedBindings = FlattenBindings(bindings, state);

            Contract.Assert(mutatedBindings != null);
            VCExpr /*!*/ bindingEquations = Gen.AsEquations(mutatedBindings);

            Contract.Assert(bindingEquations != null);
            switch (state.Polarity)
            {
            case 1:
                return(Gen.Implies(bindingEquations, body));

            case -1:
                return(Gen.And(bindingEquations, body));

            case 0:
                // also add explicit quantifiers for the bound variables
                List <VCExprVar /*!*/> /*!*/ vars = new List <VCExprVar /*!*/> ();
                foreach (VCExprLetBinding /*!*/ binding in mutatedBindings)
                {
                    Contract.Assert(binding != null);
                    vars.Add(binding.V);
                }
                return(Gen.Forall(vars, new List <VCTrigger /*!*/>(),
                                  Gen.Implies(bindingEquations, body)));
            }
            Contract.Assert(false); throw new cce.UnreachableException();
        }