diff --git a/Cargo.lock b/Cargo.lock
index dbe8b1c7df442..59c962d5ccc1d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -11452,6 +11452,7 @@ dependencies = [
  "codespan",
  "codespan-reporting",
  "datatest-stable",
+ "either",
  "internment",
  "itertools 0.13.0",
  "log",
diff --git a/third_party/move/evm/move-to-yul/src/context.rs b/third_party/move/evm/move-to-yul/src/context.rs
index ef8e251ee89e8..a8e9b29deef17 100644
--- a/third_party/move/evm/move-to-yul/src/context.rs
+++ b/third_party/move/evm/move-to-yul/src/context.rs
@@ -784,7 +784,7 @@ impl<'a> Context<'a> {
             Tuple(_)
             | TypeParameter(_)
             | Reference(_, _)
-            | Fun(_, _)
+            | Fun(..)
             | TypeDomain(_)
             | ResourceDomain(_, _, _)
             | Error
diff --git a/third_party/move/evm/move-to-yul/src/solidity_ty.rs b/third_party/move/evm/move-to-yul/src/solidity_ty.rs
index b47d59e5dfa48..7f44b34c35e4e 100644
--- a/third_party/move/evm/move-to-yul/src/solidity_ty.rs
+++ b/third_party/move/evm/move-to-yul/src/solidity_ty.rs
@@ -368,7 +368,7 @@ impl SolidityType {
             },
             TypeParameter(_)
             | Reference(_, _)
-            | Fun(_, _)
+            | Fun(..)
             | TypeDomain(_)
             | ResourceDomain(_, _, _)
             | Error
diff --git a/third_party/move/move-binary-format/src/file_format.rs b/third_party/move/move-binary-format/src/file_format.rs
index 3037cec1eaea5..468bdcca9fd32 100644
--- a/third_party/move/move-binary-format/src/file_format.rs
+++ b/third_party/move/move-binary-format/src/file_format.rs
@@ -851,11 +851,19 @@ impl AbilitySet {
     );
     /// The empty ability set
     pub const EMPTY: Self = Self(0);
-    /// Abilities for `Functions`
+    /// Minimal abilities for all `Functions`
     pub const FUNCTIONS: AbilitySet = Self(Ability::Drop as u8);
+    /// Maximal abilities for all `Functions`.  This is used for identity when unifying function types.
+    pub const MAXIMAL_FUNCTIONS: AbilitySet = Self::PUBLIC_FUNCTIONS;
     /// Abilities for `Bool`, `U8`, `U64`, `U128`, and `Address`
     pub const PRIMITIVES: AbilitySet =
         Self((Ability::Copy as u8) | (Ability::Drop as u8) | (Ability::Store as u8));
+    /// Abilities for `private` user-defined/"primitive" functions (not closures).
+    /// These can be be changed in module upgrades, so should not be stored
+    pub const PRIVATE_FUNCTIONS: AbilitySet = Self((Ability::Copy as u8) | (Ability::Drop as u8));
+    /// Abilities for `public` user-defined/"primitive" functions (not closures)
+    pub const PUBLIC_FUNCTIONS: AbilitySet =
+        Self((Ability::Copy as u8) | (Ability::Drop as u8) | (Ability::Store as u8));
     /// Abilities for `Reference` and `MutableReference`
     pub const REFERENCES: AbilitySet = Self((Ability::Copy as u8) | (Ability::Drop as u8));
     /// Abilities for `Signer`
diff --git a/third_party/move/move-compiler-v2/src/bytecode_generator.rs b/third_party/move/move-compiler-v2/src/bytecode_generator.rs
index 9cb45341d9743..19d571863998a 100644
--- a/third_party/move/move-compiler-v2/src/bytecode_generator.rs
+++ b/third_party/move/move-compiler-v2/src/bytecode_generator.rs
@@ -480,13 +480,13 @@ impl<'env> Generator<'env> {
                 self.emit_with(*id, |attr| Bytecode::SpecBlock(attr, spec));
             },
             // TODO(LAMBDA)
-            ExpData::Lambda(id, _, _) => self.error(
+            ExpData::Lambda(id, _, _, _, _) => self.error(
                 *id,
                 "Function-typed values not yet supported except as parameters to calls to inline functions",
             ),
             // TODO(LAMBDA)
-            ExpData::Invoke(_, exp, _) => self.error(
-                exp.as_ref().node_id(),
+            ExpData::Invoke(id, _exp, _) => self.error(
+                *id,
                 "Calls to function values other than inline function parameters not yet supported",
             ),
             ExpData::Quant(id, _, _, _, _, _) => {
@@ -564,6 +564,12 @@ impl<'env> Generator<'env> {
                     Constant::Bool(false)
                 }
             },
+            Value::Function(_mid, _fid) => {
+                self.error(
+                    id,
+                    "Function-typed values not yet supported except as parameters to calls to inline functions");
+                Constant::Bool(false)
+            },
         }
     }
 }
@@ -785,6 +791,11 @@ impl<'env> Generator<'env> {
             Operation::MoveFunction(m, f) => {
                 self.gen_function_call(targets, id, m.qualified(*f), args)
             },
+            // TODO(LAMBDA)
+            Operation::EarlyBind => self.error(
+                id,
+                "Function-typed values not yet supported except as parameters to calls to inline functions",
+            ),
             Operation::TestVariants(mid, sid, variants) => {
                 self.gen_test_variants(targets, id, mid.qualified(*sid), variants, args)
             },
@@ -813,12 +824,6 @@ impl<'env> Generator<'env> {
 
             Operation::NoOp => {}, // do nothing
 
-            // TODO(LAMBDA)
-            Operation::Closure(..) => self.error(
-                id,
-                "Function-typed values not yet supported except as parameters to calls to inline functions",
-            ),
-
             // Non-supported specification related operations
             Operation::Exists(Some(_))
             | Operation::SpecFunction(_, _, _)
diff --git a/third_party/move/move-compiler-v2/src/env_pipeline/ast_simplifier.rs b/third_party/move/move-compiler-v2/src/env_pipeline/ast_simplifier.rs
index f60012a917544..62c9a6cf63d12 100644
--- a/third_party/move/move-compiler-v2/src/env_pipeline/ast_simplifier.rs
+++ b/third_party/move/move-compiler-v2/src/env_pipeline/ast_simplifier.rs
@@ -359,7 +359,7 @@ fn find_possibly_modified_vars(
                     _ => {},
                 }
             },
-            Lambda(node_id, pat, _) => {
+            Lambda(node_id, pat, _, _, _) => {
                 // Define a new scope for bound vars, and turn off `modifying` within.
                 match pos {
                     VisitorPosition::Pre => {
@@ -978,7 +978,8 @@ impl<'env> ExpRewriterFunctions for SimplifierRewriter<'env> {
                     let ability_set = self
                         .env()
                         .type_abilities(&ty, self.func_env.get_type_parameters_ref());
-                    ability_set.has_ability(Ability::Drop)
+                    // Don't drop a function-valued expression so we don't lose errors.
+                    !ty.has_function() && ability_set.has_ability(Ability::Drop)
                 } else {
                     // We're missing type info, be conservative
                     false
diff --git a/third_party/move/move-compiler-v2/src/env_pipeline/flow_insensitive_checkers.rs b/third_party/move/move-compiler-v2/src/env_pipeline/flow_insensitive_checkers.rs
index dd6dabec91723..72bbd295d5853 100644
--- a/third_party/move/move-compiler-v2/src/env_pipeline/flow_insensitive_checkers.rs
+++ b/third_party/move/move-compiler-v2/src/env_pipeline/flow_insensitive_checkers.rs
@@ -147,7 +147,7 @@ impl<'env, 'params> SymbolVisitor<'env, 'params> {
                 Pre | Post | BeforeBody | MidMutate | BeforeThen | BeforeElse
                 | PreSequenceValue => {},
             },
-            Lambda(_, pat, _) => {
+            Lambda(_, pat, _, _, _) => {
                 match position {
                     Pre => self.seen_uses.enter_scope(),
                     Post => {
diff --git a/third_party/move/move-compiler-v2/src/env_pipeline/function_checker.rs b/third_party/move/move-compiler-v2/src/env_pipeline/function_checker.rs
index d7dbcc3cfce2b..958a13bde6425 100644
--- a/third_party/move/move-compiler-v2/src/env_pipeline/function_checker.rs
+++ b/third_party/move/move-compiler-v2/src/env_pipeline/function_checker.rs
@@ -11,7 +11,7 @@ use move_model::{
     model::{FunId, FunctionEnv, GlobalEnv, Loc, ModuleEnv, NodeId, Parameter, QualifiedId},
     ty::Type,
 };
-use std::{collections::BTreeSet, iter::Iterator, ops::Deref, vec::Vec};
+use std::{collections::BTreeSet, iter::Iterator, vec::Vec};
 
 type QualifiedFunId = QualifiedId<FunId>;
 
@@ -20,8 +20,8 @@ fn identify_function_types_with_functions_in_args(func_types: Vec<Type>) -> Vec<
     func_types
         .into_iter()
         .filter_map(|ty| {
-            if let Type::Fun(argt, _) = &ty {
-                if argt.deref().has_function() {
+            if let Type::Fun(args, _, _) = &ty {
+                if args.as_ref().has_function() {
                     Some(ty)
                 } else {
                     None
@@ -41,8 +41,8 @@ fn identify_function_typed_params_with_functions_in_rets(
     func_types
         .iter()
         .filter_map(|param| {
-            if let Type::Fun(_argt, rest) = &param.1 {
-                let rest_unboxed = rest.deref();
+            if let Type::Fun(_args, result, _) = &param.1 {
+                let rest_unboxed = result.as_ref();
                 if rest_unboxed.has_function() {
                     Some((*param, rest_unboxed))
                 } else {
@@ -270,7 +270,7 @@ fn check_privileged_operations_on_structs(env: &GlobalEnv, fun_env: &FunctionEnv
                 },
                 ExpData::Assign(_, pat, _)
                 | ExpData::Block(_, pat, _, _)
-                | ExpData::Lambda(_, pat, _) => {
+                | ExpData::Lambda(_, pat, _, _, _) => {
                     pat.visit_pre_post(&mut |_, pat| {
                         if let Pattern::Struct(id, str, _, _) = pat {
                             let module_id = str.module_id;
@@ -344,7 +344,7 @@ pub fn check_access_and_use(env: &mut GlobalEnv, before_inlining: bool) {
 
                 // Check that functions being called are accessible.
                 if let Some(def) = caller_func.get_def() {
-                    let callees_with_sites = def.called_funs_with_callsites();
+                    let callees_with_sites = def.used_funs_with_uses();
                     for (callee, sites) in &callees_with_sites {
                         let callee_func = env.get_function(*callee);
                         // Check visibility.
diff --git a/third_party/move/move-compiler-v2/src/env_pipeline/inliner.rs b/third_party/move/move-compiler-v2/src/env_pipeline/inliner.rs
index 636f0d95d6728..06eaa909705dd 100644
--- a/third_party/move/move-compiler-v2/src/env_pipeline/inliner.rs
+++ b/third_party/move/move-compiler-v2/src/env_pipeline/inliner.rs
@@ -90,7 +90,7 @@ pub fn run_inlining(env: &mut GlobalEnv, scope: RewritingScope, keep_inline_func
         let mut visited_targets = BTreeSet::new();
         while let Some(target) = todo.pop_first() {
             if visited_targets.insert(target.clone()) {
-                let callees_with_sites = target.called_funs_with_call_sites(env);
+                let callees_with_sites = target.used_funs_with_uses(env);
                 for (callee, sites) in callees_with_sites {
                     todo.insert(RewriteTarget::MoveFun(callee));
                     targets.entry(RewriteTarget::MoveFun(callee));
@@ -1161,7 +1161,7 @@ impl<'env, 'rewriter> ExpRewriterFunctions for InlinedRewriter<'env, 'rewriter>
         };
         let call_loc = self.env.get_node_loc(id);
         if let Some(lambda_target) = optional_lambda_target {
-            if let ExpData::Lambda(_, pat, body) = lambda_target.as_ref() {
+            if let ExpData::Lambda(_, pat, body, _, _) = lambda_target.as_ref() {
                 let args_vec: Vec<Exp> = args.to_vec();
                 Some(InlinedRewriter::construct_inlined_call_expression(
                     self.env,
diff --git a/third_party/move/move-compiler-v2/src/env_pipeline/lambda_lifter.rs b/third_party/move/move-compiler-v2/src/env_pipeline/lambda_lifter.rs
index 8326c3e8af618..d16593bac2da0 100644
--- a/third_party/move/move-compiler-v2/src/env_pipeline/lambda_lifter.rs
+++ b/third_party/move/move-compiler-v2/src/env_pipeline/lambda_lifter.rs
@@ -13,15 +13,17 @@
 //! not modify free variables.
 //!
 //! Lambda lifting rewrites lambda expressions into construction
-//! of *closures*. A closure refers to a function and contains a partial list
-//! of arguments for that function, essentially currying it. Example:
+//! of *closures* using the `EarlyBind` operation. A closure refers to a function and contains a list
+//! of "early bound" leading arguments for that function, essentially currying it.  We use the
+//! `EarlyBind` operation to construct a closure from a function and set of arguments,
+//! which must be the first `k` arguments to the function argument list.
 //!
 //! ```ignore
 //! let c = 1;
 //! vec.any(|x| x > c)
 //! ==>
 //! let c = 1;
-//! vec.any(Closure(lifted, c))
+//! vec.any(EarlyBind(lifted, c))
 //! where
 //!   fun lifted(c: u64, x: u64): bool { x > c }
 //! ```
@@ -34,19 +36,19 @@
 //! vec.any(|S{x}| x > c)
 //! ==>
 //! let c = 1;
-//! vec.any(Closure(lifted, c))
+//! vec.any(EarlyBind(lifted, c))
 //! where
 //!   fun lifted(c: u64, arg$2: S): bool { let S{x} = arg$2; x > y }
 //! ```
 
 use itertools::Itertools;
-use move_binary_format::file_format::Visibility;
+use move_binary_format::file_format::{AbilitySet, Visibility};
 use move_model::{
-    ast::{Exp, ExpData, Operation, Pattern, TempIndex},
+    ast::{self, Exp, ExpData, LambdaCaptureKind, Operation, Pattern, TempIndex},
     exp_rewriter::{ExpRewriter, ExpRewriterFunctions, RewriteTarget},
-    model::{FunId, FunctionEnv, GlobalEnv, Loc, NodeId, Parameter, TypeParameter},
+    model::{FunId, FunctionEnv, GlobalEnv, Loc, ModuleId, NodeId, Parameter, TypeParameter},
     symbol::Symbol,
-    ty::{ReferenceKind, Type},
+    ty::{AbilityInference, AbilityInferer, ReferenceKind, Type},
 };
 use std::{
     collections::{BTreeMap, BTreeSet},
@@ -185,13 +187,360 @@ impl<'a> LambdaLifter<'a> {
             let env = self.fun_env.module_env.env;
             let body = self.bind(bindings, exp);
             let loc = env.get_node_loc(pat.node_id());
-            let ty = env.get_node_type(body.node_id());
+            let body_id = body.node_id();
+            let ty = env.get_node_type(body_id);
             let new_id = env.new_node(loc, ty);
+            if let Some(inst) = env.get_node_instantiation_opt(body_id) {
+                env.set_node_instantiation(new_id, inst);
+            }
             ExpData::Block(new_id, pat, Some(binding), body).into_exp()
         } else {
             exp
         }
     }
+
+    /// For the current state, calculate: (params, closure_args, param_index_mapping), where
+    /// - `params` = new Parameter for each free var to represent it in the lifted function
+    /// - `closure_args` = corresponding expressions to provide as actual arg for each param
+    /// - `param_index_mapping` = for each free var which is a Parameter from the enclosing function,
+    ///    a mapping from index there to index in the params list
+    fn get_params_for_freevars(
+        &mut self,
+    ) -> Option<(Vec<Parameter>, Vec<Exp>, BTreeMap<usize, usize>)> {
+        let env = self.fun_env.module_env.env;
+        let mut closure_args = vec![];
+
+        // Add captured parameters. We also need to record a mapping of
+        // parameter indices in the lambda context to indices in the lifted
+        // functions (courtesy of #12317)
+        let mut param_index_mapping = BTreeMap::new();
+        let mut params = vec![];
+        let ty_params = self.fun_env.get_type_parameters_ref();
+        let ability_inferer = AbilityInferer::new(env, ty_params);
+        let mut saw_error = false;
+
+        for (used_param_count, (param, var_info)) in
+            mem::take(&mut self.free_params).into_iter().enumerate()
+        {
+            let name = self.fun_env.get_local_name(param);
+            let var_node_id = var_info.node_id;
+            let ty = env.get_node_type(var_node_id);
+            let loc = env.get_node_loc(var_node_id);
+            if var_info.modified {
+                env.error(
+                    &loc,
+                    &format!(
+                        "captured variable `{}` cannot be modified inside of a lambda", // TODO(LAMBDA)
+                        name.display(env.symbol_pool())
+                    ),
+                );
+                saw_error = true;
+            }
+            let param_abilities = ability_inferer.infer_abilities(&ty).1;
+            if !param_abilities.has_copy() {
+                env.error(
+                    &loc,
+                    &format!(
+                        "captured variable `{}` must have a value with `copy` ability", // TODO(LAMBDA)
+                        name.display(env.symbol_pool())
+                    ),
+                );
+                saw_error = true;
+            }
+            params.push(Parameter(name, ty.clone(), loc.clone()));
+            let new_id = env.new_node(loc, ty);
+            if let Some(inst) = env.get_node_instantiation_opt(var_node_id) {
+                env.set_node_instantiation(new_id, inst);
+            }
+            closure_args.push(ExpData::Temporary(new_id, param).into_exp());
+            param_index_mapping.insert(param, used_param_count);
+        }
+
+        // Add captured LocalVar parameters
+        for (name, var_info) in mem::take(&mut self.free_locals) {
+            let var_info_id = var_info.node_id;
+            let ty = env.get_node_type(var_info_id);
+            let loc = env.get_node_loc(var_info_id);
+            if var_info.modified {
+                env.error(
+                    &loc,
+                    &format!(
+                        "captured variable `{}` cannot be modified inside of a lambda", // TODO(LAMBDA)
+                        name.display(env.symbol_pool())
+                    ),
+                );
+                saw_error = true;
+            }
+            params.push(Parameter(name, ty.clone(), loc.clone()));
+            let new_id = env.new_node(loc, ty);
+            if let Some(inst) = env.get_node_instantiation_opt(var_info_id) {
+                env.set_node_instantiation(new_id, inst);
+            }
+            closure_args.push(ExpData::LocalVar(new_id, name).into_exp())
+        }
+
+        if !saw_error {
+            Some((params, closure_args, param_index_mapping))
+        } else {
+            None
+        }
+    }
+
+    // If final `args` match `lambda_params`, and all other args are simple, then returns
+    // the simple prefix of `args`.
+    fn get_args_if_simple<'b>(
+        lambda_params: &[Parameter],
+        args: &'b [Exp],
+    ) -> Option<Vec<&'b Exp>> {
+        if lambda_params.len() <= args.len() {
+            let mut simple_args: Vec<&Exp> =
+                args.iter().filter(|arg| Self::exp_is_simple(arg)).collect();
+            if simple_args.len() == args.len()
+                && lambda_params
+                    .iter()
+                    .rev()
+                    .zip(simple_args.iter().rev())
+                    .all(|(param, arg)| {
+                        if let ExpData::LocalVar(_, name) = arg.as_ref() {
+                            *name == param.get_name()
+                        } else {
+                            false
+                        }
+                    })
+            {
+                let remaining_size = args.len() - lambda_params.len();
+                simple_args.truncate(remaining_size);
+                return Some(simple_args);
+            }
+        }
+        None
+    }
+
+    // Only allow simple expressions which cannot vary or abort, since we are pulling
+    // them out of the lambda expression and evaluating them in order to bind them to
+    // the closure eary.
+    fn exp_is_simple(exp: &Exp) -> bool {
+        use ExpData::*;
+        match exp.as_ref() {
+            Call(_, Operation::EarlyBind, args) => args.iter().all(Self::exp_is_simple),
+            Call(_, op, args) => {
+                op.is_ok_to_remove_from_code() && args.iter().all(Self::exp_is_simple)
+            },
+            Sequence(_, exp_vec) => {
+                if let [exp] = &exp_vec[..] {
+                    Self::exp_is_simple(exp)
+                } else {
+                    false
+                }
+            },
+            IfElse(_, e1, e2, e3) => {
+                Self::exp_is_simple(e1) && Self::exp_is_simple(e2) && Self::exp_is_simple(e3)
+            },
+            Lambda(_, _pat, _body, _capture_kind, _abilities) => {
+                // Maybe could test lambda_is_direct_curry(pat, body)
+                // and do something with it, but it is nontrivial.
+                false
+            },
+            LocalVar(..) | Temporary(..) | Value(..) => true,
+            Invalid(..) | Invoke(..) | Quant(..) | Block(..) | Match(..) | Return(..)
+            | Loop(..) | LoopCont(..) | Assign(..) | Mutate(..) | SpecBlock(..) => false,
+        }
+    }
+
+    fn make_move_fn_exp(
+        &mut self,
+        loc: Loc,
+        fn_type: Type,
+        module_id: ModuleId,
+        fun_id: FunId,
+        instantiation: Option<Vec<Type>>,
+    ) -> Exp {
+        let env = self.fun_env.module_env.env;
+        let id = env.new_node(loc, fn_type);
+        if let Some(inst) = instantiation {
+            env.set_node_instantiation(id, inst);
+        }
+        let fn_exp = ExpData::Value(id, ast::Value::Function(module_id, fun_id));
+        fn_exp.into_exp()
+    }
+
+    fn get_move_fn_type(&mut self, expr_id: NodeId, module_id: ModuleId, fun_id: FunId) -> Type {
+        let env = self.fun_env.module_env.env;
+        let fn_env = env.get_function(module_id.qualified(fun_id));
+        let fun_abilities = if fn_env.visibility().is_public() {
+            AbilitySet::PUBLIC_FUNCTIONS
+        } else {
+            AbilitySet::PRIVATE_FUNCTIONS
+        };
+        let params = fn_env.get_parameters_ref();
+        let param_types = params.iter().map(|param| param.get_type()).collect();
+        let node_instantiation = env.get_node_instantiation(expr_id);
+        let result_type = fn_env.get_result_type();
+        Type::Fun(
+            Box::new(Type::Tuple(param_types)),
+            Box::new(result_type),
+            fun_abilities,
+        )
+        .instantiate(&node_instantiation)
+    }
+
+    // If body is a function call expression with the function value and each parameter a
+    // simple expression (constant, var, or Move function name), with the last arguments the
+    // provided `lambda_params` in sequence, then returns the function name and the prefix
+    // arguments.  Otherwise, returns `None`.
+    fn lambda_reduces_to_curry<'b>(
+        &mut self,
+        lambda_params: &Vec<Parameter>,
+        body: &'b Exp,
+    ) -> Option<(Exp, Vec<&'b Exp>)> {
+        use ExpData::*;
+        let env = self.fun_env.module_env.env;
+        match body.as_ref() {
+            Call(id, oper, args) => {
+                match oper {
+                    Operation::EarlyBind => {
+                        // TODO(LAMBDA): We might be able to to do something with this,
+                        // but skip for now because it will be complicated.
+                        None
+                    },
+                    Operation::MoveFunction(mid, fid) => {
+                        Self::get_args_if_simple(lambda_params, args).map(|args| {
+                            let fn_type = self.get_move_fn_type(*id, *mid, *fid);
+                            let loc = env.get_node_loc(*id);
+                            let fn_exp = self.make_move_fn_exp(
+                                loc,
+                                fn_type,
+                                *mid,
+                                *fid,
+                                env.get_node_instantiation_opt(*id),
+                            );
+                            (fn_exp, args)
+                        })
+                    },
+                    _ => None,
+                }
+            },
+            Invoke(_id, fn_exp, args) => {
+                Self::get_args_if_simple(lambda_params, args).and_then(|args| {
+                    // Function expression may not contain lambda params
+                    let free_vars = fn_exp.as_ref().free_vars();
+                    if lambda_params
+                        .iter()
+                        .all(|param| !free_vars.contains(&param.get_name()))
+                        && Self::exp_is_simple(fn_exp)
+                    {
+                        Some((fn_exp.clone(), args))
+                    } else {
+                        None
+                    }
+                })
+            },
+            ExpData::Sequence(_id, exp_vec) => {
+                if let [exp] = &exp_vec[..] {
+                    self.lambda_reduces_to_curry(lambda_params, exp)
+                } else {
+                    None
+                }
+            },
+            _ => None,
+        }
+    }
+
+    // We can rewrite a lambda directly into a curry expression if:
+    // - lambda parameters are a simple variable tuple (v1, v2, ...) === (bindings.is_empty())
+    // Caller should already check that, and place the tuple of variables in parameter list lambda_params.
+    //
+    // Then, we can reduce to curry if:
+    // - lambda body is a function call with
+    //   - lambda parameters used (in order) as the last arguments to the function call.
+    //   - the function called and every other argument is a simple expression containing only
+    //     constants and free variables which cannot abort
+    // Arguments here are
+    //   - id: original lambda expr NodeId
+    //   - body: body of lambda
+    //   - lambda_params: a Parameter corresponding to each lambda param
+    fn try_to_reduce_lambda_to_curry(
+        &mut self,
+        id: NodeId,
+        body: &Exp,
+        lambda_params: Vec<Parameter>,
+        abilities: &AbilitySet,
+    ) -> Option<Exp> {
+        if let Some((fn_exp, args)) = self.lambda_reduces_to_curry(&lambda_params, body) {
+            // lambda has form |lambda_params| fn_exp(args, ...lambda_params)
+            // where each arg is a constant or simple variable, not in lambda_params,
+            // except the trailing k params which are all lambda_params
+            let mut new_args: Vec<_> = args.into_iter().cloned().collect();
+
+            let env = self.fun_env.module_env.env;
+            let fn_id = fn_exp.node_id();
+            let fn_type = env.get_node_type(fn_id);
+            if let Type::Fun(_fn_param_type, _fn_result_type, fun_abilities) = &fn_type {
+                // First param to EarlyBind is the function expr
+                new_args.insert(0, fn_exp);
+                let ty_params = self.fun_env.get_type_parameters_ref();
+                // Check bound value abilities
+                let ability_inferer = AbilityInferer::new(env, ty_params);
+                let bound_value_abilities: Vec<_> = new_args
+                    .iter()
+                    .map(|exp| {
+                        let node = exp.as_ref().node_id();
+                        let ty = env.get_node_type(node);
+                        let node_abilities = ability_inferer.infer_abilities(&ty).1;
+                        (env.get_node_loc(node), node_abilities)
+                    })
+                    .collect();
+                let mut bound_value_missing_abilities: Vec<_> = bound_value_abilities
+                    .iter()
+                    .filter_map(|(loc, node_abilities)| {
+                        if !abilities.is_subset(*node_abilities) {
+                            let missing = abilities.setminus(*node_abilities);
+                            Some((
+                                loc.clone(),
+                                format!("Captured free value is missing abilities: {}", missing),
+                            ))
+                        } else {
+                            None
+                        }
+                    })
+                    .collect();
+                if !abilities.is_subset(*fun_abilities) {
+                    let missing = abilities.setminus(*fun_abilities);
+                    let tdc = env.get_type_display_ctx();
+                    bound_value_missing_abilities.push((
+                        env.get_node_loc(fn_id),
+                        format!(
+                            "Base function of closure has type {}, is missing abilities: {}",
+                            fn_type.display(&tdc),
+                            missing
+                        ),
+                    ));
+                }
+                let closure_abilities = bound_value_abilities
+                    .iter()
+                    .map(|(_loc, node_abilities)| *node_abilities)
+                    .reduce(|abs1, abs2| abs1.intersect(abs2))
+                    .unwrap_or(*fun_abilities);
+                if !bound_value_missing_abilities.is_empty() {
+                    let missing_abilities = abilities.setminus(closure_abilities);
+                    let loc = env.get_node_loc(id);
+                    env.error_with_labels(
+                        &loc,
+                        &format!("Lambda captures free variables with types that do not have some declared abilities: {}",
+                                 missing_abilities),
+                        bound_value_missing_abilities);
+                    return None;
+                };
+                if new_args.len() == 1 {
+                    // We have no parameters, just use the function directly.
+                    return Some(new_args.pop().unwrap());
+                } else {
+                    return Some(ExpData::Call(id, Operation::EarlyBind, new_args).into_exp());
+                }
+            }
+        }
+        None
+    }
 }
 
 impl<'a> ExpRewriterFunctions for LambdaLifter<'a> {
@@ -288,79 +637,92 @@ impl<'a> ExpRewriterFunctions for LambdaLifter<'a> {
         None
     }
 
-    fn rewrite_lambda(&mut self, id: NodeId, pat: &Pattern, body: &Exp) -> Option<Exp> {
+    fn rewrite_lambda(
+        &mut self,
+        id: NodeId,
+        pat: &Pattern,
+        body: &Exp,
+        capture_kind: LambdaCaptureKind,
+        abilities: AbilitySet, // TODO(LAMBDA): do something with this
+    ) -> Option<Exp> {
         if self.exempted_lambdas.contains(&id) {
             return None;
         }
         let env = self.fun_env.module_env.env;
-        let mut params = vec![];
-        let mut closure_args = vec![];
-        // Add captured parameters. We also need to record a mapping of
-        // parameter indices in the lambda context to indices in the lifted
-        // functions (courtesy of #12317)
-        let mut param_index_mapping = BTreeMap::new();
-        for (used_param_count, (param, var_info)) in
-            mem::take(&mut self.free_params).into_iter().enumerate()
-        {
-            let name = self.fun_env.get_local_name(param);
-            let ty = env.get_node_type(var_info.node_id);
-            let loc = env.get_node_loc(var_info.node_id);
-            if var_info.modified {
-                env.error(
-                    &loc,
-                    &format!(
-                        "captured variable `{}` cannot be modified inside of a lambda", // TODO(LAMBDA)
-                        name.display(env.symbol_pool())
-                    ),
-                );
-            }
-            params.push(Parameter(name, ty.clone(), loc.clone()));
-            let new_id = env.new_node(loc, ty);
-            closure_args.push(ExpData::Temporary(new_id, param).into_exp());
-            param_index_mapping.insert(param, used_param_count);
-        }
-        // Add captured locals
-        for (name, var_info) in mem::take(&mut self.free_locals) {
-            let ty = env.get_node_type(var_info.node_id);
-            let loc = env.get_node_loc(var_info.node_id);
-            if var_info.modified {
+        let module_id = self.fun_env.module_env.get_id();
+
+        match capture_kind {
+            LambdaCaptureKind::Move => {
+                // OK.
+            },
+            LambdaCaptureKind::Default | LambdaCaptureKind::Copy => {
+                let loc = env.get_node_loc(id);
                 env.error(
                     &loc,
-                    &format!(
-                        "captured variable `{}` cannot be modified inside of a lambda", // TODO(LAMBDA)
-                        name.display(env.symbol_pool())
-                    ),
+                    // TODO(LAMBDA)
+                    "Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call."
                 );
-            }
-            params.push(Parameter(name, ty.clone(), loc.clone()));
-            let new_id = env.new_node(loc, ty);
-            closure_args.push(ExpData::LocalVar(new_id, name).into_exp())
-        }
+                return None;
+            },
+        };
+
+        // params = new Parameter for each free var to represent it in the lifted function
+        // closure_args = corresponding expressions to provide as actual arg for each param
+        // param_index_mapping = for each free var which is a Parameter from the enclosing function,
+        //      a mapping from index there to index in the params list; other free vars are
+        //      substituted automatically by using the same symbol for the param
+        let (mut params, mut closure_args, param_index_mapping) = self.get_params_for_freevars()?;
+
+        // Some(ExpData::Invalid(env.clone_node(id)).into_exp());
         // Add lambda args. For dealing with patterns in lambdas (`|S{..}|e`) we need
         // to collect a list of bindings.
         let mut bindings = vec![];
+        let mut lambda_params = vec![];
         for (i, arg) in pat.clone().flatten().into_iter().enumerate() {
             let id = arg.node_id();
             let ty = env.get_node_type(id);
             let loc = env.get_node_loc(id);
             if let Pattern::Var(_, name) = arg {
-                params.push(Parameter(name, ty, loc))
+                lambda_params.push(Parameter(name, ty, loc));
             } else {
                 let name = self.gen_parameter_name(i);
-                params.push(Parameter(name, ty.clone(), loc.clone()));
+                lambda_params.push(Parameter(name, ty.clone(), loc.clone()));
                 let new_id = env.new_node(loc, ty);
+                if let Some(inst) = env.get_node_instantiation_opt(id) {
+                    env.set_node_instantiation(new_id, inst);
+                }
                 bindings.push((arg.clone(), ExpData::LocalVar(new_id, name).into_exp()))
             }
         }
+
+        // We can rewrite a lambda directly into a curry expression if:
+        // - lambda parameters are a simple variable tuple (v1, v2, ...) === (bindings.is_empty())
+        //
+        // - lambda body is a function call with
+        //   - each lambda parameter used exactly once as a call argument, in order (possibly with gaps)
+        //   - every other argument is a simple expression containing only constants and free variables
+        if bindings.is_empty() {
+            let possible_curry_exp =
+                self.try_to_reduce_lambda_to_curry(id, body, lambda_params.clone(), &abilities);
+            if possible_curry_exp.is_some() {
+                return possible_curry_exp;
+            }
+        }
+
+        // Following code assumes params include lambda_params
+        params.append(&mut lambda_params);
+
         // Add new closure function
         let fun_name = self.gen_closure_function_name();
         let lambda_loc = env.get_node_loc(id).clone();
         let lambda_type = env.get_node_type(id);
-        let result_type = if let Type::Fun(_, result_type) = &lambda_type {
+        let lambda_inst_opt = env.get_node_instantiation_opt(id);
+        let result_type = if let Type::Fun(_, result_type, _) = &lambda_type {
             *result_type.clone()
         } else {
             Type::Error // type error reported
         };
+
         // Rewrite references to Temporary in the new functions body (#12317)
         let mut replacer = |id: NodeId, target: RewriteTarget| {
             if let RewriteTarget::Temporary(temp) = target {
@@ -370,23 +732,52 @@ impl<'a> ExpRewriterFunctions for LambdaLifter<'a> {
             None
         };
         let body = ExpRewriter::new(env, &mut replacer).rewrite_exp(body.clone());
+        let fun_id = FunId::new(fun_name);
+        let params_types = params.iter().map(|param| param.get_type()).collect();
+        if abilities.has_store() {
+            let loc = env.get_node_loc(id);
+            env.error(
+                &loc,
+                // TODO(LAMBDA)
+                "Lambdas expressions with `store` ability currently may only be a simple call to an existing `public` function.  This lambda expression requires defining a `public` helper function, which is not yet supported."
+            );
+            return None;
+        };
         self.lifted.push(ClosureFunction {
             loc: lambda_loc.clone(),
-            fun_id: FunId::new(fun_name),
+            fun_id,
             type_params: self.fun_env.get_type_parameters(),
             params,
-            result_type,
+            result_type: result_type.clone(),
             def: self.bind(bindings, body),
         });
-        // Return closure expression
-        let id = env.new_node(lambda_loc, lambda_type);
-        Some(
-            ExpData::Call(
-                id,
-                Operation::Closure(self.fun_env.module_env.get_id(), FunId::new(fun_name)),
-                closure_args,
-            )
-            .into_exp(),
-        )
+
+        // Create an expression for the function reference
+        let fn_type = Type::Fun(
+            Box::new(Type::Tuple(params_types)),
+            Box::new(result_type),
+            abilities,
+        );
+        let fn_exp = self.make_move_fn_exp(
+            lambda_loc.clone(),
+            fn_type,
+            module_id,
+            fun_id,
+            lambda_inst_opt.clone(),
+        );
+
+        let bound_param_count = closure_args.len();
+        if bound_param_count == 0 {
+            // No free variables, just return the function reference
+            Some(fn_exp)
+        } else {
+            // Create and return closure expression
+            let id = env.new_node(lambda_loc, lambda_type);
+            if let Some(inst) = lambda_inst_opt {
+                env.set_node_instantiation(id, inst);
+            }
+            closure_args.insert(0, fn_exp);
+            Some(ExpData::Call(id, Operation::EarlyBind, closure_args).into_exp())
+        }
     }
 }
diff --git a/third_party/move/move-compiler-v2/src/env_pipeline/rewrite_target.rs b/third_party/move/move-compiler-v2/src/env_pipeline/rewrite_target.rs
index 2851f5c2b79c3..9e7adfe62d3b1 100644
--- a/third_party/move/move-compiler-v2/src/env_pipeline/rewrite_target.rs
+++ b/third_party/move/move-compiler-v2/src/env_pipeline/rewrite_target.rs
@@ -159,8 +159,8 @@ impl RewriteTargets {
 }
 
 impl RewriteTarget {
-    /// Gets the call sites for the target.
-    pub fn called_funs_with_call_sites(
+    /// Gets the functions called or referenced in the target.
+    pub fn used_funs_with_uses(
         &self,
         env: &GlobalEnv,
     ) -> BTreeMap<QualifiedId<FunId>, BTreeSet<NodeId>> {
@@ -179,7 +179,7 @@ impl RewriteTarget {
                 .unwrap_or_default(),
             SpecBlock(target) => {
                 let spec = env.get_spec_block(target);
-                spec.called_funs_with_callsites()
+                spec.used_funs_with_uses()
             },
         }
     }
diff --git a/third_party/move/move-compiler-v2/src/env_pipeline/spec_rewriter.rs b/third_party/move/move-compiler-v2/src/env_pipeline/spec_rewriter.rs
index dd9fd65ae1402..1251e40f021ee 100644
--- a/third_party/move/move-compiler-v2/src/env_pipeline/spec_rewriter.rs
+++ b/third_party/move/move-compiler-v2/src/env_pipeline/spec_rewriter.rs
@@ -70,7 +70,7 @@ pub fn run_spec_rewriter(env: &mut GlobalEnv) {
                 if let RewriteState::Def(def) = target.get_env_state(env) {
                     let mut spec_callees = BTreeSet::new();
                     def.visit_inline_specs(&mut |spec| {
-                        spec_callees.extend(spec.called_funs_with_callsites().into_keys());
+                        spec_callees.extend(spec.used_funs_with_uses().into_keys());
                         true // keep going
                     });
                     spec_callees
@@ -78,10 +78,9 @@ pub fn run_spec_rewriter(env: &mut GlobalEnv) {
                     BTreeSet::new()
                 }
             },
-            RewriteTarget::SpecFun(_) | RewriteTarget::SpecBlock(_) => target
-                .called_funs_with_call_sites(env)
-                .into_keys()
-                .collect(),
+            RewriteTarget::SpecFun(_) | RewriteTarget::SpecBlock(_) => {
+                target.used_funs_with_uses(env).into_keys().collect()
+            },
         };
         for callee in callees {
             called_funs.insert(callee);
diff --git a/third_party/move/move-compiler-v2/src/env_pipeline/unused_params_checker.rs b/third_party/move/move-compiler-v2/src/env_pipeline/unused_params_checker.rs
index e9da0d5cbb053..a7a22a0186aca 100644
--- a/third_party/move/move-compiler-v2/src/env_pipeline/unused_params_checker.rs
+++ b/third_party/move/move-compiler-v2/src/env_pipeline/unused_params_checker.rs
@@ -60,7 +60,7 @@ fn used_type_parameters_in_ty(ty: &Type) -> BTreeSet<u16> {
         },
         Type::TypeParameter(i) => BTreeSet::from([*i]),
         Type::Vector(ty) => used_type_parameters_in_ty(ty),
-        Type::Fun(t1, t2) => [t1, t2]
+        Type::Fun(t1, t2, _) => [t1, t2]
             .iter()
             .flat_map(|t| used_type_parameters_in_ty(t))
             .collect(),
diff --git a/third_party/move/move-compiler-v2/src/file_format_generator/module_generator.rs b/third_party/move/move-compiler-v2/src/file_format_generator/module_generator.rs
index ab7c9b862dbd0..ce120a5ca1170 100644
--- a/third_party/move/move-compiler-v2/src/file_format_generator/module_generator.rs
+++ b/third_party/move/move-compiler-v2/src/file_format_generator/module_generator.rs
@@ -367,7 +367,7 @@ impl ModuleGenerator {
                     ReferenceKind::Mutable => FF::SignatureToken::MutableReference(target_ty),
                 }
             },
-            Fun(_param_ty, _result_ty) => {
+            Fun(_param_ty, _result_ty, _abilities) => {
                 // TODO(LAMBDA)
                 ctx.error(
                     loc,
@@ -1077,7 +1077,7 @@ impl<'env> ModuleContext<'env> {
                 if fun.is_inline() {
                     continue;
                 }
-                if let Some(callees) = fun.get_called_functions() {
+                if let Some(callees) = fun.get_used_functions() {
                     let mut usage = usage_map[&fun.get_id()].clone();
                     let count = usage.len();
                     // Extend usage by that of callees from the same module. Acquires is only
diff --git a/third_party/move/move-compiler-v2/tests/checking/inlining/lambda3.exp b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda3.exp
index 7d3fd078fd386..a6dcbc1ea7faf 100644
--- a/third_party/move/move-compiler-v2/tests/checking/inlining/lambda3.exp
+++ b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda3.exp
@@ -2,7 +2,7 @@
 module 0x8675309::M {
     public fun lambda_not_allowed() {
         {
-          let _x: |u64|u64 = |i: u64| Add<u64>(i, 1);
+          let _x: |u64|u64 with copy+store = |i: u64| Add<u64>(i, 1);
           Tuple()
         }
     }
diff --git a/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_cast_err.exp b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_cast_err.exp
index be195864c9919..0ad81c2553b97 100644
--- a/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_cast_err.exp
+++ b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_cast_err.exp
@@ -1,6 +1,6 @@
 
 Diagnostics:
-error: cannot pass `|(u64, integer)|u64` to a function which expects argument of type `|(u64, vector<u8>)|u64`
+error: cannot pass `|(u64, integer)|u64 with copy+store` to a function which expects argument of type `|(u64, vector<u8>)|u64`
   ┌─ tests/checking/inlining/lambda_cast_err.move:7:53
   │
 7 │         vector::fold(gas_schedule_blob, (0 as u64), |sum, addend| sum + (addend as u64))
diff --git a/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_param_mismatch.exp b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_param_mismatch.exp
index 3ed89d4ab8da6..a4c911fe997fd 100644
--- a/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_param_mismatch.exp
+++ b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_param_mismatch.exp
@@ -1,6 +1,6 @@
 
 Diagnostics:
-error: cannot pass `|u64|u64` to a function which expects argument of type `|u64|`
+error: cannot pass `|u64|u64 with copy+store` to a function which expects argument of type `|u64|`
    ┌─ tests/checking/inlining/lambda_param_mismatch.move:12:33
    │
 12 │           vector::for_each(input, |item| {
diff --git a/third_party/move/move-compiler-v2/tests/checking/specs/expressions_err.exp b/third_party/move/move-compiler-v2/tests/checking/specs/expressions_err.exp
index 3e4cf9f7f3155..fccf940f86384 100644
--- a/third_party/move/move-compiler-v2/tests/checking/specs/expressions_err.exp
+++ b/third_party/move/move-compiler-v2/tests/checking/specs/expressions_err.exp
@@ -36,7 +36,7 @@ error: cannot pass `u256` to a function which expects argument of type `bool`
 32 │       wrongly_typed_callee(1, 1) // Wrongly typed function application
    │                               ^
 
-error: cannot pass `|num|bool` to a function which expects argument of type `|num|num`
+error: cannot pass `|num|bool with copy+store` to a function which expects argument of type `|num|num`
    ┌─ tests/checking/specs/expressions_err.move:37:36
    │
 37 │       wrongly_typed_fun_arg_callee(|x| false) // Wrongly typed function argument.
diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/lambda.exp b/third_party/move/move-compiler-v2/tests/checking/typing/lambda.exp
index ebcdc1fcfcfdb..51ad60912dcd3 100644
--- a/third_party/move/move-compiler-v2/tests/checking/typing/lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/checking/typing/lambda.exp
@@ -24,7 +24,7 @@ error: cannot use `()` with an operator which expects a value of type `u64`
 56 │             i = i + action(XVector::borrow(v, i)); // expected to have wrong result type
    │                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: cannot return `u64` from a function with result type `|integer|`
+error: cannot return `u64` from a function with result type `|integer| with copy+store`
    ┌─ tests/checking/typing/lambda.move:61:9
    │
 61 │         x(1) // expected to be not a function
diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/lambda3.exp b/third_party/move/move-compiler-v2/tests/checking/typing/lambda3.exp
index f89935a0c3358..2d5f47f0bb197 100644
--- a/third_party/move/move-compiler-v2/tests/checking/typing/lambda3.exp
+++ b/third_party/move/move-compiler-v2/tests/checking/typing/lambda3.exp
@@ -2,7 +2,7 @@
 module 0x8675309::M {
     public fun lambda_not_allowed() {
         {
-          let _x: |u64|u64 = |i: u64| Add<u64>(i, 1);
+          let _x: |u64|u64 with copy+store = |i: u64| Add<u64>(i, 1);
           Tuple()
         }
     }
diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/lambda_typed.exp b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_typed.exp
index 7817686444d8f..b3c6fa59c5fb7 100644
--- a/third_party/move/move-compiler-v2/tests/checking/typing/lambda_typed.exp
+++ b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_typed.exp
@@ -18,7 +18,7 @@ error: cannot use `()` with an operator which expects a value of type `u64`
 56 │             i = i + action(XVector::borrow(v, i)); // expected to have wrong result type
    │                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: cannot return `u64` from a function with result type `|integer|`
+error: cannot return `u64` from a function with result type `|integer| with copy+store`
    ┌─ tests/checking/typing/lambda_typed.move:61:9
    │
 61 │         x(1) // expected to be not a function
@@ -30,7 +30,7 @@ error: cannot use `&u64` with an operator which expects a value of type `integer
 67 │         foreach(&v, |e: &u64| sum = sum + e) // expected to cannot infer type
    │                                           ^
 
-error: cannot pass `|&u64|u64` to a function which expects argument of type `|&u64|`
+error: cannot pass `|&u64|u64 with copy+store` to a function which expects argument of type `|&u64|`
    ┌─ tests/checking/typing/lambda_typed.move:73:21
    │
 73 │         foreach(&v, |e: &u64| { sum = sum + *e; *e }) // expected to have wrong result type of lambda
diff --git a/third_party/move/move-compiler-v2/tests/lambda-lifting/basic.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda-lifting/basic.lambda.exp
index aecce2d0e9059..0571c26b0aa88 100644
--- a/third_party/move/move-compiler-v2/tests/lambda-lifting/basic.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda-lifting/basic.lambda.exp
@@ -218,114 +218,21 @@ module 0xcafe::m {
 } // end 0xcafe::m
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0xcafe::m {
-    private fun map(x: u64,f: |u64|u64): u64 {
-        (f)(x)
-    }
-    private fun no_name_clash(x: u64,c: u64): u64 {
-        m::map(x, closure m::no_name_clash$lambda$1(c))
-    }
-    private fun with_name_clash1(x: u64,c: u64): u64 {
-        m::map(x, closure m::with_name_clash1$lambda$1(c))
-    }
-    private fun with_name_clash2(x: u64,c: u64): u64 {
-        m::map(x, closure m::with_name_clash2$lambda$1(c))
-    }
-    private fun no_name_clash$lambda$1(c: u64,y: u64): u64 {
-        Add<u64>(y, c)
-    }
-    private fun with_name_clash1$lambda$1(c: u64,x: u64): u64 {
-        Add<u64>(x, c)
-    }
-    private fun with_name_clash2$lambda$1(c: u64,x: u64): u64 {
-        Add<u64>({
-          let x: u64 = Add<u64>(c, 1);
-          x
-        }, x)
-    }
-} // end 0xcafe::m
-
-
-// -- Model dump after env processor specification checker:
-module 0xcafe::m {
-    private fun map(x: u64,f: |u64|u64): u64 {
-        (f)(x)
-    }
-    private fun no_name_clash(x: u64,c: u64): u64 {
-        m::map(x, closure m::no_name_clash$lambda$1(c))
-    }
-    private fun with_name_clash1(x: u64,c: u64): u64 {
-        m::map(x, closure m::with_name_clash1$lambda$1(c))
-    }
-    private fun with_name_clash2(x: u64,c: u64): u64 {
-        m::map(x, closure m::with_name_clash2$lambda$1(c))
-    }
-    private fun no_name_clash$lambda$1(c: u64,y: u64): u64 {
-        Add<u64>(y, c)
-    }
-    private fun with_name_clash1$lambda$1(c: u64,x: u64): u64 {
-        Add<u64>(x, c)
-    }
-    private fun with_name_clash2$lambda$1(c: u64,x: u64): u64 {
-        Add<u64>({
-          let x: u64 = Add<u64>(c, 1);
-          x
-        }, x)
-    }
-} // end 0xcafe::m
-
-
-// -- Model dump after env processor specification rewriter:
-module 0xcafe::m {
-    private fun map(x: u64,f: |u64|u64): u64 {
-        (f)(x)
-    }
-    private fun no_name_clash(x: u64,c: u64): u64 {
-        m::map(x, closure m::no_name_clash$lambda$1(c))
-    }
-    private fun with_name_clash1(x: u64,c: u64): u64 {
-        m::map(x, closure m::with_name_clash1$lambda$1(c))
-    }
-    private fun with_name_clash2(x: u64,c: u64): u64 {
-        m::map(x, closure m::with_name_clash2$lambda$1(c))
-    }
-    private fun no_name_clash$lambda$1(c: u64,y: u64): u64 {
-        Add<u64>(y, c)
-    }
-    private fun with_name_clash1$lambda$1(c: u64,x: u64): u64 {
-        Add<u64>(x, c)
-    }
-    private fun with_name_clash2$lambda$1(c: u64,x: u64): u64 {
-        Add<u64>({
-          let x: u64 = Add<u64>(c, 1);
-          x
-        }, x)
-    }
-} // end 0xcafe::m
-
-
 
 Diagnostics:
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda-lifting/basic.move:5:9
-  │
-5 │         f(x)
-  │         ^
-
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda-lifting/basic.move:10:16
    │
 10 │         map(x, |y| y + c)
    │                ^^^^^^^^^
 
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda-lifting/basic.move:15:16
    │
 15 │         map(x, |x| x + c)
    │                ^^^^^^^^^
 
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda-lifting/basic.move:20:16
    │
 20 │           map(x, |x| {
diff --git a/third_party/move/move-compiler-v2/tests/lambda-lifting/modify.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda-lifting/modify.lambda.exp
index 3664bd2e163bb..74dee022d7295 100644
--- a/third_party/move/move-compiler-v2/tests/lambda-lifting/modify.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda-lifting/modify.lambda.exp
@@ -503,26 +503,52 @@ module 0xcafe::m {
 
 
 Diagnostics:
-error: captured variable `x` cannot be modified inside of a lambda
-   ┌─ tests/lambda-lifting/modify.move:14:13
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda-lifting/modify.move:13:16
    │
-14 │             x = 2;
-   │             ^
+13 │           map(x, |y| {
+   │ ╭────────────────^
+14 │ │             x = 2;
+15 │ │             y + c
+16 │ │         })
+   │ ╰─────────^
 
-error: captured variable `c` cannot be modified inside of a lambda
-   ┌─ tests/lambda-lifting/modify.move:21:26
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda-lifting/modify.move:20:16
    │
-21 │             let r = &mut c;
-   │                          ^
+20 │           map(x, |y| {
+   │ ╭────────────────^
+21 │ │             let r = &mut c;
+22 │ │             y + *r
+23 │ │         })
+   │ ╰─────────^
 
-error: captured variable `z` cannot be modified inside of a lambda
-   ┌─ tests/lambda-lifting/modify.move:29:13
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda-lifting/modify.move:28:16
    │
-29 │             z = 2;
-   │             ^
+28 │           map(x, |y| {
+   │ ╭────────────────^
+29 │ │             z = 2;
+30 │ │             y + c
+31 │ │         })
+   │ ╰─────────^
 
-error: captured variable `z` cannot be modified inside of a lambda
-   ┌─ tests/lambda-lifting/modify.move:37:26
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda-lifting/modify.move:36:16
    │
-37 │             let r = &mut z;
-   │                          ^
+36 │           map(x, |y| {
+   │ ╭────────────────^
+37 │ │             let r = &mut z;
+38 │ │             y + *r
+39 │ │         })
+   │ ╰─────────^
+
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda-lifting/modify.move:44:16
+   │
+44 │           map(x, |y| {
+   │ ╭────────────────^
+45 │ │             let r = &z;
+46 │ │             y + *r
+47 │ │         })
+   │ ╰─────────^
diff --git a/third_party/move/move-compiler-v2/tests/lambda-lifting/nested.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda-lifting/nested.lambda.exp
index cb00e1c4256e8..8686807511bc5 100644
--- a/third_party/move/move-compiler-v2/tests/lambda-lifting/nested.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda-lifting/nested.lambda.exp
@@ -152,87 +152,15 @@ module 0xcafe::m {
 } // end 0xcafe::m
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0xcafe::m {
-    private fun map1(x: u64,f: |u64|u64): u64 {
-        (f)(x)
-    }
-    private fun map2(x: u8,f: |u8|u8): u8 {
-        (f)(x)
-    }
-    private fun nested(x: u64,c: u64): u64 {
-        m::map1(x, closure m::nested$lambda$2(c))
-    }
-    private fun nested$lambda$1(c: u64,y: u8): u8 {
-        Add<u8>(y, Cast<u8>(c))
-    }
-    private fun nested$lambda$2(c: u64,y: u64): u64 {
-        Cast<u64>(m::map2(Cast<u8>(Sub<u64>(y, c)), closure m::nested$lambda$1(c)))
-    }
-} // end 0xcafe::m
-
-
-// -- Model dump after env processor specification checker:
-module 0xcafe::m {
-    private fun map1(x: u64,f: |u64|u64): u64 {
-        (f)(x)
-    }
-    private fun map2(x: u8,f: |u8|u8): u8 {
-        (f)(x)
-    }
-    private fun nested(x: u64,c: u64): u64 {
-        m::map1(x, closure m::nested$lambda$2(c))
-    }
-    private fun nested$lambda$1(c: u64,y: u8): u8 {
-        Add<u8>(y, Cast<u8>(c))
-    }
-    private fun nested$lambda$2(c: u64,y: u64): u64 {
-        Cast<u64>(m::map2(Cast<u8>(Sub<u64>(y, c)), closure m::nested$lambda$1(c)))
-    }
-} // end 0xcafe::m
-
-
-// -- Model dump after env processor specification rewriter:
-module 0xcafe::m {
-    private fun map1(x: u64,f: |u64|u64): u64 {
-        (f)(x)
-    }
-    private fun map2(x: u8,f: |u8|u8): u8 {
-        (f)(x)
-    }
-    private fun nested(x: u64,c: u64): u64 {
-        m::map1(x, closure m::nested$lambda$2(c))
-    }
-    private fun nested$lambda$1(c: u64,y: u8): u8 {
-        Add<u8>(y, Cast<u8>(c))
-    }
-    private fun nested$lambda$2(c: u64,y: u64): u64 {
-        Cast<u64>(m::map2(Cast<u8>(Sub<u64>(y, c)), closure m::nested$lambda$1(c)))
-    }
-} // end 0xcafe::m
-
-
 
 Diagnostics:
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda-lifting/nested.move:5:9
-  │
-5 │         f(x)
-  │         ^
-
-error: Calls to function values other than inline function parameters not yet supported
-   ┌─ tests/lambda-lifting/nested.move:10:9
-   │
-10 │         f(x)
-   │         ^
-
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda-lifting/nested.move:15:42
    │
 15 │         map1(x, |y| (map2((y - c as u8), |y| y + (c as u8)) as u64))
    │                                          ^^^^^^^^^^^^^^^^^
 
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda-lifting/nested.move:15:17
    │
 15 │         map1(x, |y| (map2((y - c as u8), |y| y + (c as u8)) as u64))
diff --git a/third_party/move/move-compiler-v2/tests/lambda-lifting/pattern.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda-lifting/pattern.lambda.exp
index 6a897fa9ce92d..61e3d5839f064 100644
--- a/third_party/move/move-compiler-v2/tests/lambda-lifting/pattern.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda-lifting/pattern.lambda.exp
@@ -185,84 +185,9 @@ module 0xcafe::m {
 } // end 0xcafe::m
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0xcafe::m {
-    struct S<T> {
-        x: T,
-    }
-    private fun consume<T>(s: S<T>,x: T,f: |(S<T>, T)|T): T {
-        (f)(s, x)
-    }
-    private fun pattern(s: S<u64>,x: u64): u64 {
-        m::consume<u64>(s, x, closure m::pattern$lambda$1())
-    }
-    private fun pattern$lambda$1(param$0: S<u64>,_y: u64): u64 {
-        {
-          let m::S<u64>{ x } = param$0;
-          {
-            let y: u64 = x;
-            Add<u64>(x, y)
-          }
-        }
-    }
-} // end 0xcafe::m
-
-
-// -- Model dump after env processor specification checker:
-module 0xcafe::m {
-    struct S<T> {
-        x: T,
-    }
-    private fun consume<T>(s: S<T>,x: T,f: |(S<T>, T)|T): T {
-        (f)(s, x)
-    }
-    private fun pattern(s: S<u64>,x: u64): u64 {
-        m::consume<u64>(s, x, closure m::pattern$lambda$1())
-    }
-    private fun pattern$lambda$1(param$0: S<u64>,_y: u64): u64 {
-        {
-          let m::S<u64>{ x } = param$0;
-          {
-            let y: u64 = x;
-            Add<u64>(x, y)
-          }
-        }
-    }
-} // end 0xcafe::m
-
-
-// -- Model dump after env processor specification rewriter:
-module 0xcafe::m {
-    struct S<T> {
-        x: T,
-    }
-    private fun consume<T>(s: S<T>,x: T,f: |(S<T>, T)|T): T {
-        (f)(s, x)
-    }
-    private fun pattern(s: S<u64>,x: u64): u64 {
-        m::consume<u64>(s, x, closure m::pattern$lambda$1())
-    }
-    private fun pattern$lambda$1(param$0: S<u64>,_y: u64): u64 {
-        {
-          let m::S<u64>{ x } = param$0;
-          {
-            let y: u64 = x;
-            Add<u64>(x, y)
-          }
-        }
-    }
-} // end 0xcafe::m
-
-
 
 Diagnostics:
-error: Calls to function values other than inline function parameters not yet supported
-   ┌─ tests/lambda-lifting/pattern.move:10:9
-   │
-10 │         f(s, x)
-   │         ^
-
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda-lifting/pattern.move:15:23
    │
 15 │         consume(s, x, |S{x}, _y| { let y = x; x + y})
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/break_continue_in_lambda.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/break_continue_in_lambda.lambda.exp
index 356f716bf1076..bb292947347d0 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/break_continue_in_lambda.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/break_continue_in_lambda.lambda.exp
@@ -1043,364 +1043,22 @@ module 0xc0ffee::m {
 } // end 0xc0ffee::m
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0xc0ffee::m {
-    public fun bar(): u64 {
-        {
-          let i: u64 = 0;
-          loop {
-            if Lt<u64>(i, 10) {
-              i: u64 = Add<u64>(i, 1);
-              if Eq<u64>(i, 5) {
-                m::brk2(closure m::bar$lambda$1());
-                m::brk2(closure m::bar$lambda$2());
-                m::brk2(closure m::bar$lambda$3());
-                Tuple()
-              } else {
-                Tuple()
-              }
-            } else {
-              break
-            }
-          };
-          i
-        }
-    }
-    private fun brk() {
-        break;
-        Tuple()
-    }
-    private fun brk2(f: |()|) {
-        (f)();
-        Tuple()
-    }
-    private fun brk3() {
-        loop {
-          if true {
-            break;
-            Tuple()
-          } else {
-            break
-          }
-        }
-    }
-    private fun brk4() {
-        loop {
-          if true {
-            continue;
-            Tuple()
-          } else {
-            break
-          }
-        }
-    }
-    private fun broken() {
-        break;
-        Tuple()
-    }
-    private fun continued() {
-        continue;
-        Tuple()
-    }
-    public fun foo(): u64 {
-        {
-          let i: u64 = 0;
-          loop {
-            if Lt<u64>(i, 10) {
-              i: u64 = Add<u64>(i, 1);
-              if Eq<u64>(i, 5) {
-                m::brk();
-                m::brk3();
-                m::brk4();
-                Tuple()
-              } else {
-                Tuple()
-              }
-            } else {
-              break
-            }
-          };
-          i
-        }
-    }
-    private fun bar$lambda$1() {
-        break
-    }
-    private fun bar$lambda$2() {
-        loop {
-          if true {
-            break
-          } else {
-            break
-          }
-        }
-    }
-    private fun bar$lambda$3() {
-        loop {
-          if true {
-            continue
-          } else {
-            break
-          }
-        }
-    }
-} // end 0xc0ffee::m
-
-
-// -- Model dump after env processor specification checker:
-module 0xc0ffee::m {
-    public fun bar(): u64 {
-        {
-          let i: u64 = 0;
-          loop {
-            if Lt<u64>(i, 10) {
-              i: u64 = Add<u64>(i, 1);
-              if Eq<u64>(i, 5) {
-                m::brk2(closure m::bar$lambda$1());
-                m::brk2(closure m::bar$lambda$2());
-                m::brk2(closure m::bar$lambda$3());
-                Tuple()
-              } else {
-                Tuple()
-              }
-            } else {
-              break
-            }
-          };
-          i
-        }
-    }
-    private fun brk() {
-        break;
-        Tuple()
-    }
-    private fun brk2(f: |()|) {
-        (f)();
-        Tuple()
-    }
-    private fun brk3() {
-        loop {
-          if true {
-            break;
-            Tuple()
-          } else {
-            break
-          }
-        }
-    }
-    private fun brk4() {
-        loop {
-          if true {
-            continue;
-            Tuple()
-          } else {
-            break
-          }
-        }
-    }
-    private fun broken() {
-        break;
-        Tuple()
-    }
-    private fun continued() {
-        continue;
-        Tuple()
-    }
-    public fun foo(): u64 {
-        {
-          let i: u64 = 0;
-          loop {
-            if Lt<u64>(i, 10) {
-              i: u64 = Add<u64>(i, 1);
-              if Eq<u64>(i, 5) {
-                m::brk();
-                m::brk3();
-                m::brk4();
-                Tuple()
-              } else {
-                Tuple()
-              }
-            } else {
-              break
-            }
-          };
-          i
-        }
-    }
-    private fun bar$lambda$1() {
-        break
-    }
-    private fun bar$lambda$2() {
-        loop {
-          if true {
-            break
-          } else {
-            break
-          }
-        }
-    }
-    private fun bar$lambda$3() {
-        loop {
-          if true {
-            continue
-          } else {
-            break
-          }
-        }
-    }
-} // end 0xc0ffee::m
-
-
-// -- Model dump after env processor specification rewriter:
-module 0xc0ffee::m {
-    public fun bar(): u64 {
-        {
-          let i: u64 = 0;
-          loop {
-            if Lt<u64>(i, 10) {
-              i: u64 = Add<u64>(i, 1);
-              if Eq<u64>(i, 5) {
-                m::brk2(closure m::bar$lambda$1());
-                m::brk2(closure m::bar$lambda$2());
-                m::brk2(closure m::bar$lambda$3());
-                Tuple()
-              } else {
-                Tuple()
-              }
-            } else {
-              break
-            }
-          };
-          i
-        }
-    }
-    private fun brk() {
-        break;
-        Tuple()
-    }
-    private fun brk2(f: |()|) {
-        (f)();
-        Tuple()
-    }
-    private fun brk3() {
-        loop {
-          if true {
-            break;
-            Tuple()
-          } else {
-            break
-          }
-        }
-    }
-    private fun brk4() {
-        loop {
-          if true {
-            continue;
-            Tuple()
-          } else {
-            break
-          }
-        }
-    }
-    private fun broken() {
-        break;
-        Tuple()
-    }
-    private fun continued() {
-        continue;
-        Tuple()
-    }
-    public fun foo(): u64 {
-        {
-          let i: u64 = 0;
-          loop {
-            if Lt<u64>(i, 10) {
-              i: u64 = Add<u64>(i, 1);
-              if Eq<u64>(i, 5) {
-                m::brk();
-                m::brk3();
-                m::brk4();
-                Tuple()
-              } else {
-                Tuple()
-              }
-            } else {
-              break
-            }
-          };
-          i
-        }
-    }
-    private fun bar$lambda$1() {
-        break
-    }
-    private fun bar$lambda$2() {
-        loop {
-          if true {
-            break
-          } else {
-            break
-          }
-        }
-    }
-    private fun bar$lambda$3() {
-        loop {
-          if true {
-            continue
-          } else {
-            break
-          }
-        }
-    }
-} // end 0xc0ffee::m
-
-
 
 Diagnostics:
-error: missing enclosing loop statement
-  ┌─ tests/lambda/inline-parity/break_continue_in_lambda.move:3:9
-  │
-3 │         break;
-  │         ^^^^^
-
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda/inline-parity/break_continue_in_lambda.move:7:9
-  │
-7 │         f();
-  │         ^
-
-error: missing enclosing loop statement
-   ┌─ tests/lambda/inline-parity/break_continue_in_lambda.move:40:26
-   │
-40 │                 brk2(| | break);
-   │                          ^^^^^
-
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda/inline-parity/break_continue_in_lambda.move:40:22
    │
 40 │                 brk2(| | break);
    │                      ^^^^^^^^^
 
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda/inline-parity/break_continue_in_lambda.move:41:8
    │
 41 │         brk2(| | while (true) { break });
    │              ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda/inline-parity/break_continue_in_lambda.move:42:8
    │
 42 │         brk2(| | while (true) { continue });
    │              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: missing enclosing loop statement
-   ┌─ tests/lambda/inline-parity/break_continue_in_lambda.move:49:2
-   │
-49 │     break;
-   │     ^^^^^
-
-error: missing enclosing loop statement
-   ┌─ tests/lambda/inline-parity/break_continue_in_lambda.move:53:2
-   │
-53 │     continue;
-   │     ^^^^^^^^
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991.lambda.exp
index fea2410cdc948..b0ca3260fc823 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991.lambda.exp
@@ -174,111 +174,15 @@ module 0x42::Test {
 } // end 0x42::Test
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0x42::Test {
-    private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 {
-        Add<u64>((f)(x, _y), (g)(x, _y))
-    }
-    public fun test() {
-        if Eq<u64>(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 10, 100), 110) {
-          Tuple()
-        } else {
-          Abort(0)
-        };
-        Tuple()
-    }
-    private fun test$lambda$1(x: u64,param$1: u64): u64 {
-        {
-          let _: u64 = param$1;
-          x
-        }
-    }
-    private fun test$lambda$2(param$0: u64,y: u64): u64 {
-        {
-          let _: u64 = param$0;
-          y
-        }
-    }
-} // end 0x42::Test
-
-
-// -- Model dump after env processor specification checker:
-module 0x42::Test {
-    private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 {
-        Add<u64>((f)(x, _y), (g)(x, _y))
-    }
-    public fun test() {
-        if Eq<u64>(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 10, 100), 110) {
-          Tuple()
-        } else {
-          Abort(0)
-        };
-        Tuple()
-    }
-    private fun test$lambda$1(x: u64,param$1: u64): u64 {
-        {
-          let _: u64 = param$1;
-          x
-        }
-    }
-    private fun test$lambda$2(param$0: u64,y: u64): u64 {
-        {
-          let _: u64 = param$0;
-          y
-        }
-    }
-} // end 0x42::Test
-
-
-// -- Model dump after env processor specification rewriter:
-module 0x42::Test {
-    private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 {
-        Add<u64>((f)(x, _y), (g)(x, _y))
-    }
-    public fun test() {
-        if Eq<u64>(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 10, 100), 110) {
-          Tuple()
-        } else {
-          Abort(0)
-        };
-        Tuple()
-    }
-    private fun test$lambda$1(x: u64,param$1: u64): u64 {
-        {
-          let _: u64 = param$1;
-          x
-        }
-    }
-    private fun test$lambda$2(param$0: u64,y: u64): u64 {
-        {
-          let _: u64 = param$0;
-          y
-        }
-    }
-} // end 0x42::Test
-
-
 
 Diagnostics:
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda/inline-parity/bug_10991.move:4:9
-  │
-4 │         f(x, _y) + g(x, _y)
-  │         ^
-
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda/inline-parity/bug_10991.move:4:20
-  │
-4 │         f(x, _y) + g(x, _y)
-  │                    ^
-
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
   ┌─ tests/lambda/inline-parity/bug_10991.move:8:21
   │
 8 │         assert!(foo(|x, _| x, |_, y| y, 10, 100) == 110, 0);
   │                     ^^^^^^^^
 
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
   ┌─ tests/lambda/inline-parity/bug_10991.move:8:31
   │
 8 │         assert!(foo(|x, _| x, |_, y| y, 10, 100) == 110, 0);
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam.lambda.exp
index b1ce2d980a7d7..613fae6c520e4 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam.lambda.exp
@@ -174,129 +174,15 @@ module 0x42::Test {
 } // end 0x42::Test
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0x42::Test {
-    private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 {
-        Add<u64>((f)(x, _y), (g)(x, _y))
-    }
-    public fun test() {
-        if Eq<u64>(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 10, 100), 13) {
-          Tuple()
-        } else {
-          Abort(0)
-        };
-        Tuple()
-    }
-    private fun test$lambda$1(param$0: u64,param$1: u64): u64 {
-        {
-          let _: u64 = param$1;
-          {
-            let _: u64 = param$0;
-            3
-          }
-        }
-    }
-    private fun test$lambda$2(param$0: u64,param$1: u64): u64 {
-        {
-          let _: u64 = param$1;
-          {
-            let _: u64 = param$0;
-            10
-          }
-        }
-    }
-} // end 0x42::Test
-
-
-// -- Model dump after env processor specification checker:
-module 0x42::Test {
-    private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 {
-        Add<u64>((f)(x, _y), (g)(x, _y))
-    }
-    public fun test() {
-        if Eq<u64>(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 10, 100), 13) {
-          Tuple()
-        } else {
-          Abort(0)
-        };
-        Tuple()
-    }
-    private fun test$lambda$1(param$0: u64,param$1: u64): u64 {
-        {
-          let _: u64 = param$1;
-          {
-            let _: u64 = param$0;
-            3
-          }
-        }
-    }
-    private fun test$lambda$2(param$0: u64,param$1: u64): u64 {
-        {
-          let _: u64 = param$1;
-          {
-            let _: u64 = param$0;
-            10
-          }
-        }
-    }
-} // end 0x42::Test
-
-
-// -- Model dump after env processor specification rewriter:
-module 0x42::Test {
-    private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 {
-        Add<u64>((f)(x, _y), (g)(x, _y))
-    }
-    public fun test() {
-        if Eq<u64>(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 10, 100), 13) {
-          Tuple()
-        } else {
-          Abort(0)
-        };
-        Tuple()
-    }
-    private fun test$lambda$1(param$0: u64,param$1: u64): u64 {
-        {
-          let _: u64 = param$1;
-          {
-            let _: u64 = param$0;
-            3
-          }
-        }
-    }
-    private fun test$lambda$2(param$0: u64,param$1: u64): u64 {
-        {
-          let _: u64 = param$1;
-          {
-            let _: u64 = param$0;
-            10
-          }
-        }
-    }
-} // end 0x42::Test
-
-
 
 Diagnostics:
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda/inline-parity/bug_10991_noparam.move:4:9
-  │
-4 │         f(x, _y) + g(x, _y)
-  │         ^
-
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda/inline-parity/bug_10991_noparam.move:4:20
-  │
-4 │         f(x, _y) + g(x, _y)
-  │                    ^
-
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
   ┌─ tests/lambda/inline-parity/bug_10991_noparam.move:8:21
   │
 8 │         assert!(foo(|_, _| 3, |_, _| 10, 10, 100) == 13, 0);
   │                     ^^^^^^^^
 
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
   ┌─ tests/lambda/inline-parity/bug_10991_noparam.move:8:31
   │
 8 │         assert!(foo(|_, _| 3, |_, _| 10, 10, 100) == 13, 0);
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam2.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam2.lambda.exp
index f0eec150641eb..e5934586b182d 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam2.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam2.lambda.exp
@@ -174,111 +174,15 @@ module 0x42::Test {
 } // end 0x42::Test
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0x42::Test {
-    private fun foo(f: |u64|u64,g: |u64|u64,x: u64,_: u64): u64 {
-        Add<u64>((f)(x), (g)(x))
-    }
-    public fun test() {
-        if Eq<u64>(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 10, 100), 13) {
-          Tuple()
-        } else {
-          Abort(0)
-        };
-        Tuple()
-    }
-    private fun test$lambda$1(param$0: u64): u64 {
-        {
-          let _: u64 = param$0;
-          3
-        }
-    }
-    private fun test$lambda$2(param$0: u64): u64 {
-        {
-          let _: u64 = param$0;
-          10
-        }
-    }
-} // end 0x42::Test
-
-
-// -- Model dump after env processor specification checker:
-module 0x42::Test {
-    private fun foo(f: |u64|u64,g: |u64|u64,x: u64,_: u64): u64 {
-        Add<u64>((f)(x), (g)(x))
-    }
-    public fun test() {
-        if Eq<u64>(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 10, 100), 13) {
-          Tuple()
-        } else {
-          Abort(0)
-        };
-        Tuple()
-    }
-    private fun test$lambda$1(param$0: u64): u64 {
-        {
-          let _: u64 = param$0;
-          3
-        }
-    }
-    private fun test$lambda$2(param$0: u64): u64 {
-        {
-          let _: u64 = param$0;
-          10
-        }
-    }
-} // end 0x42::Test
-
-
-// -- Model dump after env processor specification rewriter:
-module 0x42::Test {
-    private fun foo(f: |u64|u64,g: |u64|u64,x: u64,_: u64): u64 {
-        Add<u64>((f)(x), (g)(x))
-    }
-    public fun test() {
-        if Eq<u64>(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 10, 100), 13) {
-          Tuple()
-        } else {
-          Abort(0)
-        };
-        Tuple()
-    }
-    private fun test$lambda$1(param$0: u64): u64 {
-        {
-          let _: u64 = param$0;
-          3
-        }
-    }
-    private fun test$lambda$2(param$0: u64): u64 {
-        {
-          let _: u64 = param$0;
-          10
-        }
-    }
-} // end 0x42::Test
-
-
 
 Diagnostics:
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda/inline-parity/bug_10991_noparam2.move:4:9
-  │
-4 │         f(x) + g(x)
-  │         ^
-
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda/inline-parity/bug_10991_noparam2.move:4:16
-  │
-4 │         f(x) + g(x)
-  │                ^
-
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
   ┌─ tests/lambda/inline-parity/bug_10991_noparam2.move:8:21
   │
 8 │         assert!(foo(|_| 3, |_| 10, 10, 100) == 13, 0);
   │                     ^^^^^
 
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
   ┌─ tests/lambda/inline-parity/bug_10991_noparam2.move:8:28
   │
 8 │         assert!(foo(|_| 3, |_| 10, 10, 100) == 13, 0);
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991a.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991a.lambda.exp
index 172a728293cdf..5638e37c59b27 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991a.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991a.lambda.exp
@@ -174,153 +174,27 @@ module 0x42::Test {
 } // end 0x42::Test
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0x42::Test {
-    private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,h: |(u64, u64)|u64,i: |(u64, u64)|u64,x: u64,y: u64): u64 {
-        Add<u64>(Add<u64>(Add<u64>((f)(x, y), (g)(x, y)), (h)(x, y)), (i)(x, y))
-    }
-    public fun test() {
-        if Eq<u64>(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), closure Test::test$lambda$3(), closure Test::test$lambda$4(), 10, 100), 220) {
-          Tuple()
-        } else {
-          Abort(0)
-        };
-        Tuple()
-    }
-    private fun test$lambda$1(x: u64,param$1: u64): u64 {
-        {
-          let _: u64 = param$1;
-          x
-        }
-    }
-    private fun test$lambda$2(param$0: u64,y: u64): u64 {
-        {
-          let _: u64 = param$0;
-          y
-        }
-    }
-    private fun test$lambda$3(a: u64,_b: u64): u64 {
-        a
-    }
-    private fun test$lambda$4(_c: u64,d: u64): u64 {
-        d
-    }
-} // end 0x42::Test
-
-
-// -- Model dump after env processor specification checker:
-module 0x42::Test {
-    private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,h: |(u64, u64)|u64,i: |(u64, u64)|u64,x: u64,y: u64): u64 {
-        Add<u64>(Add<u64>(Add<u64>((f)(x, y), (g)(x, y)), (h)(x, y)), (i)(x, y))
-    }
-    public fun test() {
-        if Eq<u64>(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), closure Test::test$lambda$3(), closure Test::test$lambda$4(), 10, 100), 220) {
-          Tuple()
-        } else {
-          Abort(0)
-        };
-        Tuple()
-    }
-    private fun test$lambda$1(x: u64,param$1: u64): u64 {
-        {
-          let _: u64 = param$1;
-          x
-        }
-    }
-    private fun test$lambda$2(param$0: u64,y: u64): u64 {
-        {
-          let _: u64 = param$0;
-          y
-        }
-    }
-    private fun test$lambda$3(a: u64,_b: u64): u64 {
-        a
-    }
-    private fun test$lambda$4(_c: u64,d: u64): u64 {
-        d
-    }
-} // end 0x42::Test
-
-
-// -- Model dump after env processor specification rewriter:
-module 0x42::Test {
-    private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,h: |(u64, u64)|u64,i: |(u64, u64)|u64,x: u64,y: u64): u64 {
-        Add<u64>(Add<u64>(Add<u64>((f)(x, y), (g)(x, y)), (h)(x, y)), (i)(x, y))
-    }
-    public fun test() {
-        if Eq<u64>(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), closure Test::test$lambda$3(), closure Test::test$lambda$4(), 10, 100), 220) {
-          Tuple()
-        } else {
-          Abort(0)
-        };
-        Tuple()
-    }
-    private fun test$lambda$1(x: u64,param$1: u64): u64 {
-        {
-          let _: u64 = param$1;
-          x
-        }
-    }
-    private fun test$lambda$2(param$0: u64,y: u64): u64 {
-        {
-          let _: u64 = param$0;
-          y
-        }
-    }
-    private fun test$lambda$3(a: u64,_b: u64): u64 {
-        a
-    }
-    private fun test$lambda$4(_c: u64,d: u64): u64 {
-        d
-    }
-} // end 0x42::Test
-
-
 
 Diagnostics:
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda/inline-parity/bug_10991a.move:6:13
-  │
-6 │             f(x, y) + g(x, y) + h(x, y) + i(x, y)
-  │             ^
-
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda/inline-parity/bug_10991a.move:6:23
-  │
-6 │             f(x, y) + g(x, y) + h(x, y) + i(x, y)
-  │                       ^
-
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda/inline-parity/bug_10991a.move:6:33
-  │
-6 │             f(x, y) + g(x, y) + h(x, y) + i(x, y)
-  │                                 ^
-
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda/inline-parity/bug_10991a.move:6:43
-  │
-6 │             f(x, y) + g(x, y) + h(x, y) + i(x, y)
-  │                                           ^
-
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda/inline-parity/bug_10991a.move:10:21
    │
 10 │         assert!(foo(|x, _| x, |_, y| y,
    │                     ^^^^^^^^
 
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda/inline-parity/bug_10991a.move:10:31
    │
 10 │         assert!(foo(|x, _| x, |_, y| y,
    │                               ^^^^^^^^
 
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda/inline-parity/bug_10991a.move:11:6
    │
 11 │         |a, _b| a, |_c, d| d,
    │         ^^^^^^^^^
 
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda/inline-parity/bug_10991a.move:11:17
    │
 11 │         |a, _b| a, |_c, d| d,
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991b.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991b.lambda.exp
index 4d75c19204ac0..3bacb83364f2b 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991b.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991b.lambda.exp
@@ -174,81 +174,9 @@ module 0x42::Test {
 } // end 0x42::Test
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0x42::Test {
-    private fun foo(g: |(u64, u64)|u64,x: u64,_y: u64): u64 {
-        (g)(x, _y)
-    }
-    public fun test() {
-        if Eq<u64>(Test::foo(closure Test::test$lambda$1(), 10, 100), 100) {
-          Tuple()
-        } else {
-          Abort(0)
-        };
-        Tuple()
-    }
-    private fun test$lambda$1(param$0: u64,y: u64): u64 {
-        {
-          let _: u64 = param$0;
-          y
-        }
-    }
-} // end 0x42::Test
-
-
-// -- Model dump after env processor specification checker:
-module 0x42::Test {
-    private fun foo(g: |(u64, u64)|u64,x: u64,_y: u64): u64 {
-        (g)(x, _y)
-    }
-    public fun test() {
-        if Eq<u64>(Test::foo(closure Test::test$lambda$1(), 10, 100), 100) {
-          Tuple()
-        } else {
-          Abort(0)
-        };
-        Tuple()
-    }
-    private fun test$lambda$1(param$0: u64,y: u64): u64 {
-        {
-          let _: u64 = param$0;
-          y
-        }
-    }
-} // end 0x42::Test
-
-
-// -- Model dump after env processor specification rewriter:
-module 0x42::Test {
-    private fun foo(g: |(u64, u64)|u64,x: u64,_y: u64): u64 {
-        (g)(x, _y)
-    }
-    public fun test() {
-        if Eq<u64>(Test::foo(closure Test::test$lambda$1(), 10, 100), 100) {
-          Tuple()
-        } else {
-          Abort(0)
-        };
-        Tuple()
-    }
-    private fun test$lambda$1(param$0: u64,y: u64): u64 {
-        {
-          let _: u64 = param$0;
-          y
-        }
-    }
-} // end 0x42::Test
-
-
 
 Diagnostics:
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda/inline-parity/bug_10991b.move:4:9
-  │
-4 │         g(x, _y)
-  │         ^
-
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
   ┌─ tests/lambda/inline-parity/bug_10991b.move:8:21
   │
 8 │         assert!(foo(|_, y| y,
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991c.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991c.lambda.exp
index 486526cead33b..43b8d5d0216de 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991c.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991c.lambda.exp
@@ -174,90 +174,9 @@ module 0x42::Test {
 } // end 0x42::Test
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0x42::Test {
-    private fun foo(g: |(u64, u64, u64, u64)|u64,x: u64,y: u64,z: u64,q: u64): u64 {
-        (g)(x, y, z, q)
-    }
-    public fun test() {
-        if Eq<u64>(Test::foo(closure Test::test$lambda$1(), 10, 100, 1000, 10000), 10100) {
-          Tuple()
-        } else {
-          Abort(0)
-        };
-        Tuple()
-    }
-    private fun test$lambda$1(param$0: u64,y: u64,param$2: u64,q: u64): u64 {
-        {
-          let _: u64 = param$2;
-          {
-            let _: u64 = param$0;
-            Add<u64>(y, q)
-          }
-        }
-    }
-} // end 0x42::Test
-
-
-// -- Model dump after env processor specification checker:
-module 0x42::Test {
-    private fun foo(g: |(u64, u64, u64, u64)|u64,x: u64,y: u64,z: u64,q: u64): u64 {
-        (g)(x, y, z, q)
-    }
-    public fun test() {
-        if Eq<u64>(Test::foo(closure Test::test$lambda$1(), 10, 100, 1000, 10000), 10100) {
-          Tuple()
-        } else {
-          Abort(0)
-        };
-        Tuple()
-    }
-    private fun test$lambda$1(param$0: u64,y: u64,param$2: u64,q: u64): u64 {
-        {
-          let _: u64 = param$2;
-          {
-            let _: u64 = param$0;
-            Add<u64>(y, q)
-          }
-        }
-    }
-} // end 0x42::Test
-
-
-// -- Model dump after env processor specification rewriter:
-module 0x42::Test {
-    private fun foo(g: |(u64, u64, u64, u64)|u64,x: u64,y: u64,z: u64,q: u64): u64 {
-        (g)(x, y, z, q)
-    }
-    public fun test() {
-        if Eq<u64>(Test::foo(closure Test::test$lambda$1(), 10, 100, 1000, 10000), 10100) {
-          Tuple()
-        } else {
-          Abort(0)
-        };
-        Tuple()
-    }
-    private fun test$lambda$1(param$0: u64,y: u64,param$2: u64,q: u64): u64 {
-        {
-          let _: u64 = param$2;
-          {
-            let _: u64 = param$0;
-            Add<u64>(y, q)
-          }
-        }
-    }
-} // end 0x42::Test
-
-
 
 Diagnostics:
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda/inline-parity/bug_10991c.move:4:9
-  │
-4 │         g(x, y, z, q)
-  │         ^
-
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
   ┌─ tests/lambda/inline-parity/bug_10991c.move:8:21
   │
 8 │         assert!(foo(|_, y, _, q| y + q,
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/dotdot_valid.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/dotdot_valid.lambda.exp
index de57ae7f20e1a..1855166775783 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/dotdot_valid.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/dotdot_valid.lambda.exp
@@ -3265,940 +3265,9 @@ module 0x42::test {
 } // end 0x42::test
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0x42::test {
-    enum E1 {
-        A {
-            0: u8,
-            1: bool,
-        }
-        B {
-            0: u8,
-        }
-        C {
-            x: u8,
-            y: S1,
-        }
-    }
-    struct S0 {
-        dummy_field: bool,
-    }
-    struct S1 {
-        0: u8,
-    }
-    struct S2 {
-        0: bool,
-        1: S0,
-    }
-    struct S3 {
-        x: bool,
-        y: u8,
-    }
-    struct S4<T> {
-        x: T,
-        y: S3,
-    }
-    struct S5<T,U> {
-        0: T,
-        1: U,
-    }
-    struct S6<T,U> {
-        x: T,
-        y: U,
-    }
-    struct S7 {
-        0: u8,
-        1: u16,
-        2: u32,
-        3: u64,
-    }
-    private fun lambda_param(f: |S2|bool): bool {
-        {
-          let x: S2 = pack test::S2(true, pack test::S0(false));
-          (f)(x)
-        }
-    }
-    private fun nested1(x: S4<bool>) {
-        {
-          let test::S4<bool>{ x: _x, y: _ } = x;
-          {
-            let test::S4<bool>{ x: _, y: _y } = x;
-            {
-              let test::S4<bool>{ x: _, y: test::S3{ x: _, y: _ } } = x;
-              {
-                let test::S4<bool>{ x: _, y: test::S3{ x: _x, y: _ } } = x;
-                {
-                  let test::S4<bool>{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x;
-                  {
-                    let test::S4<bool>{ x: _, y: test::S3{ x: _, y: _y } } = x;
-                    {
-                      let test::S4<bool>{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x;
-                      Tuple()
-                    }
-                  }
-                }
-              }
-            }
-          }
-        }
-    }
-    private fun nested1_ref(x: &S4<bool>) {
-        {
-          let test::S4<bool>{ x: _x, y: _ } = x;
-          {
-            let test::S4<bool>{ x: _, y: _y } = x;
-            {
-              let test::S4<bool>{ x: _, y: test::S3{ x: _, y: _ } } = x;
-              {
-                let test::S4<bool>{ x: _, y: test::S3{ x: _x, y: _ } } = x;
-                {
-                  let test::S4<bool>{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x;
-                  {
-                    let test::S4<bool>{ x: _, y: test::S3{ x: _, y: _y } } = x;
-                    {
-                      let test::S4<bool>{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x;
-                      Tuple()
-                    }
-                  }
-                }
-              }
-            }
-          }
-        }
-    }
-    private fun nested2(x: S5<bool, S1>) {
-        {
-          let test::S5<bool, S1>{ 0: _, 1: test::S1{ 0: _ } } = x;
-          Tuple()
-        }
-    }
-    private fun nested2_ref(x: &S5<bool, S1>) {
-        {
-          let test::S5<bool, S1>{ 0: _, 1: test::S1{ 0: _ } } = x;
-          Tuple()
-        }
-    }
-    private fun nested3(x: S5<bool, S4<bool>>) {
-        {
-          let test::S5<bool, S4<bool>>{ 0: _, 1: test::S4<bool>{ x: _, y: _ } } = x;
-          Tuple()
-        }
-    }
-    private fun nested3_ref(x: &S5<bool, S4<bool>>) {
-        {
-          let test::S5<bool, S4<bool>>{ 0: _, 1: test::S4<bool>{ x: _, y: _ } } = x;
-          Tuple()
-        }
-    }
-    private fun nested4(x: S4<S1>) {
-        {
-          let test::S4<S1>{ x: test::S1{ 0: _ }, y: _ } = x;
-          Tuple()
-        }
-    }
-    private fun nested4_ref(x: &S4<S1>) {
-        {
-          let test::S4<S1>{ x: test::S1{ 0: _ }, y: _ } = x;
-          Tuple()
-        }
-    }
-    private fun simple_0(x: S0) {
-        {
-          let test::S0{ dummy_field: _ } = x;
-          Tuple()
-        }
-    }
-    private fun simple_0_ref(x: &S0) {
-        {
-          let test::S0{ dummy_field: _ } = x;
-          Tuple()
-        }
-    }
-    private fun simple_1(x: S1) {
-        {
-          let test::S1{ 0: _ } = x;
-          Tuple()
-        }
-    }
-    private fun simple_1_ref(x: &mut S1) {
-        {
-          let test::S1{ 0: _ } = x;
-          Tuple()
-        }
-    }
-    private fun simple_2(x: S2) {
-        {
-          let test::S2{ 0: _, 1: _ } = x;
-          {
-            let test::S2{ 0: _x, 1: _ } = x;
-            {
-              let test::S2{ 0: _, 1: _x } = x;
-              {
-                let test::S2{ 0: _, 1: _ } = x;
-                {
-                  let test::S2{ 0: _, 1: _ } = x;
-                  {
-                    let test::S2{ 0: _x, 1: _y } = x;
-                    {
-                      let test::S2{ 0: _x, 1: _y } = x;
-                      {
-                        let test::S2{ 0: _x, 1: _y } = x;
-                        Tuple()
-                      }
-                    }
-                  }
-                }
-              }
-            }
-          }
-        }
-    }
-    private fun simple_2_ref(x: &S2) {
-        {
-          let test::S2{ 0: _, 1: _ } = x;
-          {
-            let test::S2{ 0: _x, 1: _ } = x;
-            {
-              let test::S2{ 0: _, 1: _x } = x;
-              {
-                let test::S2{ 0: _, 1: _ } = x;
-                {
-                  let test::S2{ 0: _, 1: _ } = x;
-                  {
-                    let test::S2{ 0: _x, 1: _y } = x;
-                    {
-                      let test::S2{ 0: _x, 1: _y } = x;
-                      {
-                        let test::S2{ 0: _x, 1: _y } = x;
-                        Tuple()
-                      }
-                    }
-                  }
-                }
-              }
-            }
-          }
-        }
-    }
-    private fun simple_3(x: S3) {
-        {
-          let test::S3{ x: _, y: _ } = x;
-          {
-            let test::S3{ x: _x, y: _ } = x;
-            {
-              let test::S3{ x: _, y: _y } = x;
-              Tuple()
-            }
-          }
-        }
-    }
-    private fun simple_3_ref(x: S3) {
-        {
-          let test::S3{ x: _, y: _ } = x;
-          {
-            let test::S3{ x: _x, y: _ } = x;
-            {
-              let test::S3{ x: _, y: _y } = x;
-              Tuple()
-            }
-          }
-        }
-    }
-    private fun simple_4(x: E1): u8 {
-        match (x) {
-          test::E1::A{ 0: x, 1: _ } => {
-            x
-          }
-          test::E1::B{ 0: x } => {
-            x
-          }
-          test::E1::C{ x, y: _ } => {
-            x
-          }
-        }
-
-    }
-    private fun simple_4_ref(x: &E1): &u8 {
-        match (x) {
-          test::E1::A{ 0: x, 1: _ } => {
-            x
-          }
-          test::E1::B{ 0: x } => {
-            x
-          }
-        }
-
-    }
-    private fun simple_5(x: E1): u8 {
-        match (x) {
-          test::E1::A{ 0: _, 1: y } => {
-            if y {
-              1
-            } else {
-              0
-            }
-          }
-          test::E1::B{ 0: x } => {
-            x
-          }
-          test::E1::C{ x: _, y: test::S1{ 0: x } } => {
-            x
-          }
-        }
-
-    }
-    private fun simple_6(x: &S7) {
-        {
-          let test::S7{ 0: _w, 1: _, 2: _, 3: _z } = x;
-          {
-            let test::S7{ 0: _w, 1: _x, 2: _y, 3: _z } = x;
-            Tuple()
-          }
-        }
-    }
-    private fun test_lambda_param(): bool {
-        test::lambda_param(closure test::test_lambda_param$lambda$1())
-    }
-    private fun test_lambda_param$lambda$1(param$0: S2): bool {
-        {
-          let test::S2{ 0: x, 1: _ } = param$0;
-          x
-        }
-    }
-} // end 0x42::test
-
-
-// -- Model dump after env processor specification checker:
-module 0x42::test {
-    enum E1 {
-        A {
-            0: u8,
-            1: bool,
-        }
-        B {
-            0: u8,
-        }
-        C {
-            x: u8,
-            y: S1,
-        }
-    }
-    struct S0 {
-        dummy_field: bool,
-    }
-    struct S1 {
-        0: u8,
-    }
-    struct S2 {
-        0: bool,
-        1: S0,
-    }
-    struct S3 {
-        x: bool,
-        y: u8,
-    }
-    struct S4<T> {
-        x: T,
-        y: S3,
-    }
-    struct S5<T,U> {
-        0: T,
-        1: U,
-    }
-    struct S6<T,U> {
-        x: T,
-        y: U,
-    }
-    struct S7 {
-        0: u8,
-        1: u16,
-        2: u32,
-        3: u64,
-    }
-    private fun lambda_param(f: |S2|bool): bool {
-        {
-          let x: S2 = pack test::S2(true, pack test::S0(false));
-          (f)(x)
-        }
-    }
-    private fun nested1(x: S4<bool>) {
-        {
-          let test::S4<bool>{ x: _x, y: _ } = x;
-          {
-            let test::S4<bool>{ x: _, y: _y } = x;
-            {
-              let test::S4<bool>{ x: _, y: test::S3{ x: _, y: _ } } = x;
-              {
-                let test::S4<bool>{ x: _, y: test::S3{ x: _x, y: _ } } = x;
-                {
-                  let test::S4<bool>{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x;
-                  {
-                    let test::S4<bool>{ x: _, y: test::S3{ x: _, y: _y } } = x;
-                    {
-                      let test::S4<bool>{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x;
-                      Tuple()
-                    }
-                  }
-                }
-              }
-            }
-          }
-        }
-    }
-    private fun nested1_ref(x: &S4<bool>) {
-        {
-          let test::S4<bool>{ x: _x, y: _ } = x;
-          {
-            let test::S4<bool>{ x: _, y: _y } = x;
-            {
-              let test::S4<bool>{ x: _, y: test::S3{ x: _, y: _ } } = x;
-              {
-                let test::S4<bool>{ x: _, y: test::S3{ x: _x, y: _ } } = x;
-                {
-                  let test::S4<bool>{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x;
-                  {
-                    let test::S4<bool>{ x: _, y: test::S3{ x: _, y: _y } } = x;
-                    {
-                      let test::S4<bool>{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x;
-                      Tuple()
-                    }
-                  }
-                }
-              }
-            }
-          }
-        }
-    }
-    private fun nested2(x: S5<bool, S1>) {
-        {
-          let test::S5<bool, S1>{ 0: _, 1: test::S1{ 0: _ } } = x;
-          Tuple()
-        }
-    }
-    private fun nested2_ref(x: &S5<bool, S1>) {
-        {
-          let test::S5<bool, S1>{ 0: _, 1: test::S1{ 0: _ } } = x;
-          Tuple()
-        }
-    }
-    private fun nested3(x: S5<bool, S4<bool>>) {
-        {
-          let test::S5<bool, S4<bool>>{ 0: _, 1: test::S4<bool>{ x: _, y: _ } } = x;
-          Tuple()
-        }
-    }
-    private fun nested3_ref(x: &S5<bool, S4<bool>>) {
-        {
-          let test::S5<bool, S4<bool>>{ 0: _, 1: test::S4<bool>{ x: _, y: _ } } = x;
-          Tuple()
-        }
-    }
-    private fun nested4(x: S4<S1>) {
-        {
-          let test::S4<S1>{ x: test::S1{ 0: _ }, y: _ } = x;
-          Tuple()
-        }
-    }
-    private fun nested4_ref(x: &S4<S1>) {
-        {
-          let test::S4<S1>{ x: test::S1{ 0: _ }, y: _ } = x;
-          Tuple()
-        }
-    }
-    private fun simple_0(x: S0) {
-        {
-          let test::S0{ dummy_field: _ } = x;
-          Tuple()
-        }
-    }
-    private fun simple_0_ref(x: &S0) {
-        {
-          let test::S0{ dummy_field: _ } = x;
-          Tuple()
-        }
-    }
-    private fun simple_1(x: S1) {
-        {
-          let test::S1{ 0: _ } = x;
-          Tuple()
-        }
-    }
-    private fun simple_1_ref(x: &mut S1) {
-        {
-          let test::S1{ 0: _ } = x;
-          Tuple()
-        }
-    }
-    private fun simple_2(x: S2) {
-        {
-          let test::S2{ 0: _, 1: _ } = x;
-          {
-            let test::S2{ 0: _x, 1: _ } = x;
-            {
-              let test::S2{ 0: _, 1: _x } = x;
-              {
-                let test::S2{ 0: _, 1: _ } = x;
-                {
-                  let test::S2{ 0: _, 1: _ } = x;
-                  {
-                    let test::S2{ 0: _x, 1: _y } = x;
-                    {
-                      let test::S2{ 0: _x, 1: _y } = x;
-                      {
-                        let test::S2{ 0: _x, 1: _y } = x;
-                        Tuple()
-                      }
-                    }
-                  }
-                }
-              }
-            }
-          }
-        }
-    }
-    private fun simple_2_ref(x: &S2) {
-        {
-          let test::S2{ 0: _, 1: _ } = x;
-          {
-            let test::S2{ 0: _x, 1: _ } = x;
-            {
-              let test::S2{ 0: _, 1: _x } = x;
-              {
-                let test::S2{ 0: _, 1: _ } = x;
-                {
-                  let test::S2{ 0: _, 1: _ } = x;
-                  {
-                    let test::S2{ 0: _x, 1: _y } = x;
-                    {
-                      let test::S2{ 0: _x, 1: _y } = x;
-                      {
-                        let test::S2{ 0: _x, 1: _y } = x;
-                        Tuple()
-                      }
-                    }
-                  }
-                }
-              }
-            }
-          }
-        }
-    }
-    private fun simple_3(x: S3) {
-        {
-          let test::S3{ x: _, y: _ } = x;
-          {
-            let test::S3{ x: _x, y: _ } = x;
-            {
-              let test::S3{ x: _, y: _y } = x;
-              Tuple()
-            }
-          }
-        }
-    }
-    private fun simple_3_ref(x: S3) {
-        {
-          let test::S3{ x: _, y: _ } = x;
-          {
-            let test::S3{ x: _x, y: _ } = x;
-            {
-              let test::S3{ x: _, y: _y } = x;
-              Tuple()
-            }
-          }
-        }
-    }
-    private fun simple_4(x: E1): u8 {
-        match (x) {
-          test::E1::A{ 0: x, 1: _ } => {
-            x
-          }
-          test::E1::B{ 0: x } => {
-            x
-          }
-          test::E1::C{ x, y: _ } => {
-            x
-          }
-        }
-
-    }
-    private fun simple_4_ref(x: &E1): &u8 {
-        match (x) {
-          test::E1::A{ 0: x, 1: _ } => {
-            x
-          }
-          test::E1::B{ 0: x } => {
-            x
-          }
-        }
-
-    }
-    private fun simple_5(x: E1): u8 {
-        match (x) {
-          test::E1::A{ 0: _, 1: y } => {
-            if y {
-              1
-            } else {
-              0
-            }
-          }
-          test::E1::B{ 0: x } => {
-            x
-          }
-          test::E1::C{ x: _, y: test::S1{ 0: x } } => {
-            x
-          }
-        }
-
-    }
-    private fun simple_6(x: &S7) {
-        {
-          let test::S7{ 0: _w, 1: _, 2: _, 3: _z } = x;
-          {
-            let test::S7{ 0: _w, 1: _x, 2: _y, 3: _z } = x;
-            Tuple()
-          }
-        }
-    }
-    private fun test_lambda_param(): bool {
-        test::lambda_param(closure test::test_lambda_param$lambda$1())
-    }
-    private fun test_lambda_param$lambda$1(param$0: S2): bool {
-        {
-          let test::S2{ 0: x, 1: _ } = param$0;
-          x
-        }
-    }
-} // end 0x42::test
-
-
-// -- Model dump after env processor specification rewriter:
-module 0x42::test {
-    enum E1 {
-        A {
-            0: u8,
-            1: bool,
-        }
-        B {
-            0: u8,
-        }
-        C {
-            x: u8,
-            y: S1,
-        }
-    }
-    struct S0 {
-        dummy_field: bool,
-    }
-    struct S1 {
-        0: u8,
-    }
-    struct S2 {
-        0: bool,
-        1: S0,
-    }
-    struct S3 {
-        x: bool,
-        y: u8,
-    }
-    struct S4<T> {
-        x: T,
-        y: S3,
-    }
-    struct S5<T,U> {
-        0: T,
-        1: U,
-    }
-    struct S6<T,U> {
-        x: T,
-        y: U,
-    }
-    struct S7 {
-        0: u8,
-        1: u16,
-        2: u32,
-        3: u64,
-    }
-    private fun lambda_param(f: |S2|bool): bool {
-        {
-          let x: S2 = pack test::S2(true, pack test::S0(false));
-          (f)(x)
-        }
-    }
-    private fun nested1(x: S4<bool>) {
-        {
-          let test::S4<bool>{ x: _x, y: _ } = x;
-          {
-            let test::S4<bool>{ x: _, y: _y } = x;
-            {
-              let test::S4<bool>{ x: _, y: test::S3{ x: _, y: _ } } = x;
-              {
-                let test::S4<bool>{ x: _, y: test::S3{ x: _x, y: _ } } = x;
-                {
-                  let test::S4<bool>{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x;
-                  {
-                    let test::S4<bool>{ x: _, y: test::S3{ x: _, y: _y } } = x;
-                    {
-                      let test::S4<bool>{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x;
-                      Tuple()
-                    }
-                  }
-                }
-              }
-            }
-          }
-        }
-    }
-    private fun nested1_ref(x: &S4<bool>) {
-        {
-          let test::S4<bool>{ x: _x, y: _ } = x;
-          {
-            let test::S4<bool>{ x: _, y: _y } = x;
-            {
-              let test::S4<bool>{ x: _, y: test::S3{ x: _, y: _ } } = x;
-              {
-                let test::S4<bool>{ x: _, y: test::S3{ x: _x, y: _ } } = x;
-                {
-                  let test::S4<bool>{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x;
-                  {
-                    let test::S4<bool>{ x: _, y: test::S3{ x: _, y: _y } } = x;
-                    {
-                      let test::S4<bool>{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x;
-                      Tuple()
-                    }
-                  }
-                }
-              }
-            }
-          }
-        }
-    }
-    private fun nested2(x: S5<bool, S1>) {
-        {
-          let test::S5<bool, S1>{ 0: _, 1: test::S1{ 0: _ } } = x;
-          Tuple()
-        }
-    }
-    private fun nested2_ref(x: &S5<bool, S1>) {
-        {
-          let test::S5<bool, S1>{ 0: _, 1: test::S1{ 0: _ } } = x;
-          Tuple()
-        }
-    }
-    private fun nested3(x: S5<bool, S4<bool>>) {
-        {
-          let test::S5<bool, S4<bool>>{ 0: _, 1: test::S4<bool>{ x: _, y: _ } } = x;
-          Tuple()
-        }
-    }
-    private fun nested3_ref(x: &S5<bool, S4<bool>>) {
-        {
-          let test::S5<bool, S4<bool>>{ 0: _, 1: test::S4<bool>{ x: _, y: _ } } = x;
-          Tuple()
-        }
-    }
-    private fun nested4(x: S4<S1>) {
-        {
-          let test::S4<S1>{ x: test::S1{ 0: _ }, y: _ } = x;
-          Tuple()
-        }
-    }
-    private fun nested4_ref(x: &S4<S1>) {
-        {
-          let test::S4<S1>{ x: test::S1{ 0: _ }, y: _ } = x;
-          Tuple()
-        }
-    }
-    private fun simple_0(x: S0) {
-        {
-          let test::S0{ dummy_field: _ } = x;
-          Tuple()
-        }
-    }
-    private fun simple_0_ref(x: &S0) {
-        {
-          let test::S0{ dummy_field: _ } = x;
-          Tuple()
-        }
-    }
-    private fun simple_1(x: S1) {
-        {
-          let test::S1{ 0: _ } = x;
-          Tuple()
-        }
-    }
-    private fun simple_1_ref(x: &mut S1) {
-        {
-          let test::S1{ 0: _ } = x;
-          Tuple()
-        }
-    }
-    private fun simple_2(x: S2) {
-        {
-          let test::S2{ 0: _, 1: _ } = x;
-          {
-            let test::S2{ 0: _x, 1: _ } = x;
-            {
-              let test::S2{ 0: _, 1: _x } = x;
-              {
-                let test::S2{ 0: _, 1: _ } = x;
-                {
-                  let test::S2{ 0: _, 1: _ } = x;
-                  {
-                    let test::S2{ 0: _x, 1: _y } = x;
-                    {
-                      let test::S2{ 0: _x, 1: _y } = x;
-                      {
-                        let test::S2{ 0: _x, 1: _y } = x;
-                        Tuple()
-                      }
-                    }
-                  }
-                }
-              }
-            }
-          }
-        }
-    }
-    private fun simple_2_ref(x: &S2) {
-        {
-          let test::S2{ 0: _, 1: _ } = x;
-          {
-            let test::S2{ 0: _x, 1: _ } = x;
-            {
-              let test::S2{ 0: _, 1: _x } = x;
-              {
-                let test::S2{ 0: _, 1: _ } = x;
-                {
-                  let test::S2{ 0: _, 1: _ } = x;
-                  {
-                    let test::S2{ 0: _x, 1: _y } = x;
-                    {
-                      let test::S2{ 0: _x, 1: _y } = x;
-                      {
-                        let test::S2{ 0: _x, 1: _y } = x;
-                        Tuple()
-                      }
-                    }
-                  }
-                }
-              }
-            }
-          }
-        }
-    }
-    private fun simple_3(x: S3) {
-        {
-          let test::S3{ x: _, y: _ } = x;
-          {
-            let test::S3{ x: _x, y: _ } = x;
-            {
-              let test::S3{ x: _, y: _y } = x;
-              Tuple()
-            }
-          }
-        }
-    }
-    private fun simple_3_ref(x: S3) {
-        {
-          let test::S3{ x: _, y: _ } = x;
-          {
-            let test::S3{ x: _x, y: _ } = x;
-            {
-              let test::S3{ x: _, y: _y } = x;
-              Tuple()
-            }
-          }
-        }
-    }
-    private fun simple_4(x: E1): u8 {
-        match (x) {
-          test::E1::A{ 0: x, 1: _ } => {
-            x
-          }
-          test::E1::B{ 0: x } => {
-            x
-          }
-          test::E1::C{ x, y: _ } => {
-            x
-          }
-        }
-
-    }
-    private fun simple_4_ref(x: &E1): &u8 {
-        match (x) {
-          test::E1::A{ 0: x, 1: _ } => {
-            x
-          }
-          test::E1::B{ 0: x } => {
-            x
-          }
-        }
-
-    }
-    private fun simple_5(x: E1): u8 {
-        match (x) {
-          test::E1::A{ 0: _, 1: y } => {
-            if y {
-              1
-            } else {
-              0
-            }
-          }
-          test::E1::B{ 0: x } => {
-            x
-          }
-          test::E1::C{ x: _, y: test::S1{ 0: x } } => {
-            x
-          }
-        }
-
-    }
-    private fun simple_6(x: &S7) {
-        {
-          let test::S7{ 0: _w, 1: _, 2: _, 3: _z } = x;
-          {
-            let test::S7{ 0: _w, 1: _x, 2: _y, 3: _z } = x;
-            Tuple()
-          }
-        }
-    }
-    private fun test_lambda_param(): bool {
-        test::lambda_param(closure test::test_lambda_param$lambda$1())
-    }
-    private fun test_lambda_param$lambda$1(param$0: S2): bool {
-        {
-          let test::S2{ 0: x, 1: _ } = param$0;
-          x
-        }
-    }
-} // end 0x42::test
-
-
 
 Diagnostics:
-error: match not exhaustive
-    ┌─ tests/lambda/inline-parity/dotdot_valid.move:142:16
-    │
-142 │         match (x) {
-    │                ^
-    │
-    = missing `E1::C{..}`
-
-error: match not exhaustive
-    ┌─ tests/lambda/inline-parity/dotdot_valid.move:153:16
-    │
-153 │         match (x) {
-    │                ^
-    │
-    = missing `E1::C{..}`
-
-error: Calls to function values other than inline function parameters not yet supported
-    ┌─ tests/lambda/inline-parity/dotdot_valid.move:177:9
-    │
-177 │         f(x)
-    │         ^
-
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
     ┌─ tests/lambda/inline-parity/dotdot_valid.move:181:22
     │
 181 │         lambda_param(|S2(x, ..)| x)
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eq_inline.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eq_inline.lambda.exp
index 7fc8364520041..b512cde064cf7 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eq_inline.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eq_inline.lambda.exp
@@ -141,54 +141,6 @@ module 0x42::m {
 } // end 0x42::m
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0x42::m {
-    private fun foo(f: |&u64|) {
-        Tuple()
-    }
-    private fun g() {
-        m::foo(closure m::g$lambda$1());
-        Tuple()
-    }
-    private fun g$lambda$1(v: &u64) {
-        Eq<u64>(v, Borrow(Immutable)(1));
-        Tuple()
-    }
-} // end 0x42::m
-
-
-// -- Model dump after env processor specification checker:
-module 0x42::m {
-    private fun foo(f: |&u64|) {
-        Tuple()
-    }
-    private fun g() {
-        m::foo(closure m::g$lambda$1());
-        Tuple()
-    }
-    private fun g$lambda$1(v: &u64) {
-        Eq<u64>(v, Borrow(Immutable)(1));
-        Tuple()
-    }
-} // end 0x42::m
-
-
-// -- Model dump after env processor specification rewriter:
-module 0x42::m {
-    private fun foo(f: |&u64|) {
-        Tuple()
-    }
-    private fun g() {
-        m::foo(closure m::g$lambda$1());
-        Tuple()
-    }
-    private fun g$lambda$1(v: &u64) {
-        Eq<u64>(v, Borrow(Immutable)(1));
-        Tuple()
-    }
-} // end 0x42::m
-
-
 
 Diagnostics:
 warning: Unused parameter `f`. Consider removing or prefixing with an underscore: `_f`
@@ -197,9 +149,7 @@ warning: Unused parameter `f`. Consider removing or prefixing with an underscore
 3 │     fun foo(f: |&u64|) {
   │             ^
 
-
-Diagnostics:
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
   ┌─ tests/lambda/inline-parity/eq_inline.move:7:13
   │
 7 │           foo(|v| {
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eval_ignored_param.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eval_ignored_param.lambda.exp
index 2bbc4c4bfd603..678e8fa29367f 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eval_ignored_param.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eval_ignored_param.lambda.exp
@@ -339,165 +339,15 @@ module 0x42::Test {
 } // end 0x42::Test
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0x42::Test {
-    private fun foo(f: |(u64, u64, u64)|u64,g: |(u64, u64, u64)|u64,x: u64,_: u64,y: u64,z: u64): u64 {
-        {
-          let r1: u64 = (f)(x: u64 = Add<u64>(x, 1);
-          x, y: u64 = Add<u64>(y, 1);
-          y, z: u64 = Add<u64>(z, 1);
-          z);
-          {
-            let r2: u64 = (g)(x: u64 = Add<u64>(x, 1);
-            x, y: u64 = Add<u64>(y, 1);
-            y, z: u64 = Add<u64>(z, 1);
-            z);
-            Add<u64>(Add<u64>(Add<u64>(Add<u64>(r1, r2), Mul<u64>(3, x)), Mul<u64>(5, y)), Mul<u64>(7, z))
-          }
-        }
-    }
-    public fun test() {
-        {
-          let r: u64 = Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 1, 10, 100, 1000);
-          if Eq<u64>(r, 9637) {
-            Tuple()
-          } else {
-            Abort(r)
-          };
-          Tuple()
-        }
-    }
-    private fun test$lambda$1(x: u64,param$1: u64,z: u64): u64 {
-        {
-          let _: u64 = param$1;
-          Mul<u64>(x, z)
-        }
-    }
-    private fun test$lambda$2(param$0: u64,y: u64,param$2: u64): u64 {
-        {
-          let _: u64 = param$2;
-          {
-            let _: u64 = param$0;
-            y
-          }
-        }
-    }
-} // end 0x42::Test
-
-
-// -- Model dump after env processor specification checker:
-module 0x42::Test {
-    private fun foo(f: |(u64, u64, u64)|u64,g: |(u64, u64, u64)|u64,x: u64,_: u64,y: u64,z: u64): u64 {
-        {
-          let r1: u64 = (f)(x: u64 = Add<u64>(x, 1);
-          x, y: u64 = Add<u64>(y, 1);
-          y, z: u64 = Add<u64>(z, 1);
-          z);
-          {
-            let r2: u64 = (g)(x: u64 = Add<u64>(x, 1);
-            x, y: u64 = Add<u64>(y, 1);
-            y, z: u64 = Add<u64>(z, 1);
-            z);
-            Add<u64>(Add<u64>(Add<u64>(Add<u64>(r1, r2), Mul<u64>(3, x)), Mul<u64>(5, y)), Mul<u64>(7, z))
-          }
-        }
-    }
-    public fun test() {
-        {
-          let r: u64 = Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 1, 10, 100, 1000);
-          if Eq<u64>(r, 9637) {
-            Tuple()
-          } else {
-            Abort(r)
-          };
-          Tuple()
-        }
-    }
-    private fun test$lambda$1(x: u64,param$1: u64,z: u64): u64 {
-        {
-          let _: u64 = param$1;
-          Mul<u64>(x, z)
-        }
-    }
-    private fun test$lambda$2(param$0: u64,y: u64,param$2: u64): u64 {
-        {
-          let _: u64 = param$2;
-          {
-            let _: u64 = param$0;
-            y
-          }
-        }
-    }
-} // end 0x42::Test
-
-
-// -- Model dump after env processor specification rewriter:
-module 0x42::Test {
-    private fun foo(f: |(u64, u64, u64)|u64,g: |(u64, u64, u64)|u64,x: u64,_: u64,y: u64,z: u64): u64 {
-        {
-          let r1: u64 = (f)(x: u64 = Add<u64>(x, 1);
-          x, y: u64 = Add<u64>(y, 1);
-          y, z: u64 = Add<u64>(z, 1);
-          z);
-          {
-            let r2: u64 = (g)(x: u64 = Add<u64>(x, 1);
-            x, y: u64 = Add<u64>(y, 1);
-            y, z: u64 = Add<u64>(z, 1);
-            z);
-            Add<u64>(Add<u64>(Add<u64>(Add<u64>(r1, r2), Mul<u64>(3, x)), Mul<u64>(5, y)), Mul<u64>(7, z))
-          }
-        }
-    }
-    public fun test() {
-        {
-          let r: u64 = Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 1, 10, 100, 1000);
-          if Eq<u64>(r, 9637) {
-            Tuple()
-          } else {
-            Abort(r)
-          };
-          Tuple()
-        }
-    }
-    private fun test$lambda$1(x: u64,param$1: u64,z: u64): u64 {
-        {
-          let _: u64 = param$1;
-          Mul<u64>(x, z)
-        }
-    }
-    private fun test$lambda$2(param$0: u64,y: u64,param$2: u64): u64 {
-        {
-          let _: u64 = param$2;
-          {
-            let _: u64 = param$0;
-            y
-          }
-        }
-    }
-} // end 0x42::Test
-
-
 
 Diagnostics:
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda/inline-parity/eval_ignored_param.move:4:11
-  │
-4 │     let r1 = f({x = x + 1; x}, {y = y + 1; y}, {z = z + 1; z});
-  │              ^
-
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda/inline-parity/eval_ignored_param.move:5:11
-  │
-5 │     let r2 = g({x = x + 1; x}, {y = y + 1; y}, {z  = z + 1 ; z});
-  │              ^
-
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda/inline-parity/eval_ignored_param.move:10:14
    │
 10 │     let r = foo(|x, _, z| x*z, |_, y, _| y, 1, 10, 100, 1000);
    │                 ^^^^^^^^^^^^^
 
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda/inline-parity/eval_ignored_param.move:10:29
    │
 10 │     let r = foo(|x, _, z| x*z, |_, y, _| y, 1, 10, 100, 1000);
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generic_calls.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generic_calls.lambda.exp
index 3381b1bbcf75c..6f699942c47f1 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generic_calls.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generic_calls.lambda.exp
@@ -460,150 +460,9 @@ module 0x42::m {
 } // end 0x42::m
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0x42::m {
-    struct S<T> {
-        x: T,
-    }
-    private fun id<T>(self: S<T>): S<T> {
-        self
-    }
-    private fun inlined<T>(f: |S<T>|S<T>,s: S<T>) {
-        (f)(s);
-        Tuple()
-    }
-    private fun receiver<T>(self: S<T>,y: T) {
-        select m::S.x<S<T>>(self) = y;
-        Tuple()
-    }
-    private fun receiver_more_generics<T,R>(self: S<T>,_y: R) {
-        Tuple()
-    }
-    private fun receiver_needs_type_args<T,R>(self: S<T>,_y: T) {
-        Abort(1)
-    }
-    private fun receiver_ref<T>(self: &S<T>,_y: T) {
-        Tuple()
-    }
-    private fun receiver_ref_mut<T>(self: &mut S<T>,y: T) {
-        select m::S.x<&mut S<T>>(self) = y
-    }
-    private fun test_call_styles(s: S<u64>,x: u64) {
-        m::receiver<u64>(s, x);
-        m::receiver_ref<u64>(Borrow(Immutable)(s), x);
-        m::receiver_ref_mut<u64>(Borrow(Mutable)(s), x);
-        m::receiver_more_generics<u64, u64>(s, 22);
-        m::receiver_needs_type_args<u64, u8>(s, x);
-        Tuple()
-    }
-    private fun test_receiver_inference(s: S<u64>) {
-        m::inlined<u64>(closure m::test_receiver_inference$lambda$1(), s)
-    }
-    private fun test_receiver_inference$lambda$1(s: S<u64>): S<u64> {
-        m::id<u64>(s)
-    }
-} // end 0x42::m
-
-
-// -- Model dump after env processor specification checker:
-module 0x42::m {
-    struct S<T> {
-        x: T,
-    }
-    private fun id<T>(self: S<T>): S<T> {
-        self
-    }
-    private fun inlined<T>(f: |S<T>|S<T>,s: S<T>) {
-        (f)(s);
-        Tuple()
-    }
-    private fun receiver<T>(self: S<T>,y: T) {
-        select m::S.x<S<T>>(self) = y;
-        Tuple()
-    }
-    private fun receiver_more_generics<T,R>(self: S<T>,_y: R) {
-        Tuple()
-    }
-    private fun receiver_needs_type_args<T,R>(self: S<T>,_y: T) {
-        Abort(1)
-    }
-    private fun receiver_ref<T>(self: &S<T>,_y: T) {
-        Tuple()
-    }
-    private fun receiver_ref_mut<T>(self: &mut S<T>,y: T) {
-        select m::S.x<&mut S<T>>(self) = y
-    }
-    private fun test_call_styles(s: S<u64>,x: u64) {
-        m::receiver<u64>(s, x);
-        m::receiver_ref<u64>(Borrow(Immutable)(s), x);
-        m::receiver_ref_mut<u64>(Borrow(Mutable)(s), x);
-        m::receiver_more_generics<u64, u64>(s, 22);
-        m::receiver_needs_type_args<u64, u8>(s, x);
-        Tuple()
-    }
-    private fun test_receiver_inference(s: S<u64>) {
-        m::inlined<u64>(closure m::test_receiver_inference$lambda$1(), s)
-    }
-    private fun test_receiver_inference$lambda$1(s: S<u64>): S<u64> {
-        m::id<u64>(s)
-    }
-} // end 0x42::m
-
-
-// -- Model dump after env processor specification rewriter:
-module 0x42::m {
-    struct S<T> {
-        x: T,
-    }
-    private fun id<T>(self: S<T>): S<T> {
-        self
-    }
-    private fun inlined<T>(f: |S<T>|S<T>,s: S<T>) {
-        (f)(s);
-        Tuple()
-    }
-    private fun receiver<T>(self: S<T>,y: T) {
-        select m::S.x<S<T>>(self) = y;
-        Tuple()
-    }
-    private fun receiver_more_generics<T,R>(self: S<T>,_y: R) {
-        Tuple()
-    }
-    private fun receiver_needs_type_args<T,R>(self: S<T>,_y: T) {
-        Abort(1)
-    }
-    private fun receiver_ref<T>(self: &S<T>,_y: T) {
-        Tuple()
-    }
-    private fun receiver_ref_mut<T>(self: &mut S<T>,y: T) {
-        select m::S.x<&mut S<T>>(self) = y
-    }
-    private fun test_call_styles(s: S<u64>,x: u64) {
-        m::receiver<u64>(s, x);
-        m::receiver_ref<u64>(Borrow(Immutable)(s), x);
-        m::receiver_ref_mut<u64>(Borrow(Mutable)(s), x);
-        m::receiver_more_generics<u64, u64>(s, 22);
-        m::receiver_needs_type_args<u64, u8>(s, x);
-        Tuple()
-    }
-    private fun test_receiver_inference(s: S<u64>) {
-        m::inlined<u64>(closure m::test_receiver_inference$lambda$1(), s)
-    }
-    private fun test_receiver_inference$lambda$1(s: S<u64>): S<u64> {
-        m::id<u64>(s)
-    }
-} // end 0x42::m
-
-
 
 Diagnostics:
-error: Calls to function values other than inline function parameters not yet supported
-   ┌─ tests/lambda/inline-parity/generic_calls.move:36:9
-   │
-36 │         f(s);
-   │         ^
-
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda/inline-parity/generic_calls.move:47:17
    │
 47 │         inlined(|s| s.id(), s)
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generics.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generics.lambda.exp
index 2a10fb8eecd8e..e1e6a42e3dc86 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generics.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generics.lambda.exp
@@ -327,8 +327,8 @@ module 0x42::Test {
 
 
 Diagnostics:
-error: captured variable `sum` cannot be modified inside of a lambda
-   ┌─ tests/lambda/inline-parity/generics.move:16:30
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/generics.move:16:26
    │
 16 │         foreach<u64>(&v, |e| sum = sum + *e);
-   │                              ^^^
+   │                          ^^^^^^^^^^^^^^^^^^
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inline_fun_in_spec.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inline_fun_in_spec.lambda.exp
index d4783a884aa54..10d5cf390bb96 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inline_fun_in_spec.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inline_fun_in_spec.lambda.exp
@@ -483,163 +483,10 @@ module 0x42::m {
 } // end 0x42::m
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0x42::m {
-    spec {
-      invariant forall a: address: TypeDomain<address>(): Implies(exists<0x42::m::S>(a), m::exec<address, bool>(|a: address| Lt(select m::S.f<0x42::m::S>({
-      let (a: address): (address) = Tuple(a);
-      BorrowGlobal(Immutable)<0x42::m::S>(a)
-    }), 10), a));
-    }
-
-    struct S {
-        f: u64,
-    }
-    spec {
-      invariant m::exec<num, bool>(|x: num| Gt(x, 0), select m::S.f());
-    }
-
-    private fun exec<T,R>(f: |T|R,x: T): R {
-        {
-          let r: R = (f)(x);
-          spec {
-            assert Eq<#1>(r, (f)($t1));
-          }
-          ;
-          r
-        }
-    }
-    private fun function_code_spec_block(x: u64): u64 {
-        spec {
-          assert m::exec<num, bool>(closure m::function_code_spec_block$lambda$1(), $t0);
-        }
-        ;
-        Add<u64>(x, 1)
-    }
-    private fun function_spec_block(x: u64): u64 {
-        Add<u64>(x, 1)
-    }
-    spec {
-      ensures Eq<u64>(result0(), m::exec<num, num>(|x: num| Add(x, 1), $t0));
-    }
-
-    private inline fun get<R>(a: address): &R {
-        BorrowGlobal(Immutable)<R>(a)
-    }
-    private fun function_code_spec_block$lambda$1(y: num): bool {
-        Gt(y, 0)
-    }
-} // end 0x42::m
-
-
-// -- Model dump after env processor specification checker:
-module 0x42::m {
-    spec {
-      invariant forall a: address: TypeDomain<address>(): Implies(exists<0x42::m::S>(a), m::exec<address, bool>(|a: address| Lt(select m::S.f<0x42::m::S>({
-      let (a: address): (address) = Tuple(a);
-      BorrowGlobal(Immutable)<0x42::m::S>(a)
-    }), 10), a));
-    }
-
-    struct S {
-        f: u64,
-    }
-    spec {
-      invariant m::exec<num, bool>(|x: num| Gt(x, 0), select m::S.f());
-    }
-
-    private fun exec<T,R>(f: |T|R,x: T): R {
-        {
-          let r: R = (f)(x);
-          spec {
-            assert Eq<#1>(r, (f)($t1));
-          }
-          ;
-          r
-        }
-    }
-    private fun function_code_spec_block(x: u64): u64 {
-        spec {
-          assert m::exec<num, bool>(closure m::function_code_spec_block$lambda$1(), $t0);
-        }
-        ;
-        Add<u64>(x, 1)
-    }
-    private fun function_spec_block(x: u64): u64 {
-        Add<u64>(x, 1)
-    }
-    spec {
-      ensures Eq<u64>(result0(), m::exec<num, num>(|x: num| Add(x, 1), $t0));
-    }
-
-    private inline fun get<R>(a: address): &R {
-        BorrowGlobal(Immutable)<R>(a)
-    }
-    private fun function_code_spec_block$lambda$1(y: num): bool {
-        Gt(y, 0)
-    }
-} // end 0x42::m
-
-
-// -- Model dump after env processor specification rewriter:
-module 0x42::m {
-    spec {
-      invariant forall a: address: TypeDomain<address>(): Implies(exists<0x42::m::S>(a), m::$exec<address, bool>(|a: address| Lt(select m::S.f<0x42::m::S>({
-      let (a: address): (address) = Tuple(a);
-      global<0x42::m::S>(a)
-    }), 10), a));
-    }
-
-    struct S {
-        f: u64,
-    }
-    spec {
-      invariant m::$exec<num, bool>(|x: num| Gt(x, 0), select m::S.f());
-    }
-
-    private fun exec<T,R>(f: |T|R,x: T): R {
-        {
-          let r: R = (f)(x);
-          spec {
-            assert Eq<#1>(r, (f)($t1));
-          }
-          ;
-          r
-        }
-    }
-    private fun function_code_spec_block(x: u64): u64 {
-        spec {
-          assert m::$exec<num, bool>(closure m::function_code_spec_block$lambda$1(), $t0);
-        }
-        ;
-        Add<u64>(x, 1)
-    }
-    private fun function_spec_block(x: u64): u64 {
-        Add<u64>(x, 1)
-    }
-    spec {
-      ensures Eq<u64>(result0(), m::$exec<num, num>(|x: num| Add(x, 1), $t0));
-    }
-
-    private inline fun get<R>(a: address): &R {
-        BorrowGlobal(Immutable)<R>(a)
-    }
-    private fun function_code_spec_block$lambda$1(y: num): bool {
-        Gt(y, 0)
-    }
-    spec fun $exec<T,R>(f: |#0|#1,x: #0): #1 {
-        {
-          let r: #1 = (f)(x);
-          r
-        }
-    }
-} // end 0x42::m
-
-
 
 Diagnostics:
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda/inline-parity/inline_fun_in_spec.move:4:17
-  │
-4 │         let r = f(x);
-  │                 ^
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/inline_fun_in_spec.move:19:28
+   │
+19 │         spec { assert exec(|y| y > 0, x); };
+   │                            ^^^^^^^^^
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inlining1.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inlining1.lambda.exp
index ccd5c61991485..c94277a84e19c 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inlining1.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inlining1.lambda.exp
@@ -207,90 +207,9 @@ module 0x42::Test {
 } // end 0x42::Test
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0x42::Test {
-    private fun foo(f: |u64|u64,x: u64): u64 {
-        (f)(x)
-    }
-    public fun main() {
-        if Eq<u64>(Test::test(), 3) {
-          Tuple()
-        } else {
-          Abort(5)
-        };
-        Tuple()
-    }
-    public fun test(): u64 {
-        Test::foo(closure Test::test$lambda$1(), 10)
-    }
-    private fun test$lambda$1(param$0: u64): u64 {
-        {
-          let _: u64 = param$0;
-          3
-        }
-    }
-} // end 0x42::Test
-
-
-// -- Model dump after env processor specification checker:
-module 0x42::Test {
-    private fun foo(f: |u64|u64,x: u64): u64 {
-        (f)(x)
-    }
-    public fun main() {
-        if Eq<u64>(Test::test(), 3) {
-          Tuple()
-        } else {
-          Abort(5)
-        };
-        Tuple()
-    }
-    public fun test(): u64 {
-        Test::foo(closure Test::test$lambda$1(), 10)
-    }
-    private fun test$lambda$1(param$0: u64): u64 {
-        {
-          let _: u64 = param$0;
-          3
-        }
-    }
-} // end 0x42::Test
-
-
-// -- Model dump after env processor specification rewriter:
-module 0x42::Test {
-    private fun foo(f: |u64|u64,x: u64): u64 {
-        (f)(x)
-    }
-    public fun main() {
-        if Eq<u64>(Test::test(), 3) {
-          Tuple()
-        } else {
-          Abort(5)
-        };
-        Tuple()
-    }
-    public fun test(): u64 {
-        Test::foo(closure Test::test$lambda$1(), 10)
-    }
-    private fun test$lambda$1(param$0: u64): u64 {
-        {
-          let _: u64 = param$0;
-          3
-        }
-    }
-} // end 0x42::Test
-
-
 
 Diagnostics:
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda/inline-parity/inlining1.move:4:9
-  │
-4 │         f(x)
-  │         ^
-
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
   ┌─ tests/lambda/inline-parity/inlining1.move:8:13
   │
 8 │         foo(|_| 3, 10)
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda.lambda.exp
index 0edf647447ceb..affdfc91b8e16 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda.lambda.exp
@@ -745,8 +745,53 @@ module 0x42::LambdaTest {
 
 
 Diagnostics:
-error: captured variable `product` cannot be modified inside of a lambda
-   ┌─ tests/lambda/inline-parity/lambda.move:30:18
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/lambda.move:30:14
    │
 30 │     foreach(&v, |e| product = LambdaTest1::inline_mul(product, *e));
-   │                     ^^^^^^^
+   │                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/lambda.move:34:29
+   │
+34 │     LambdaTest1::inline_apply1(|z|z, g(LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(|x|x, 3)))) + 2
+   │                                ^^^^
+
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/lambda.move:34:90
+   │
+34 │     LambdaTest1::inline_apply1(|z|z, g(LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(|x|x, 3)))) + 2
+   │                                                                                             ^^^^
+
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/lambda.move:40:29
+   │
+40 │         LambdaTest1::inline_apply(|y|y, x)
+   │                                   ^^^^
+
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/lambda.move:39:59
+   │
+39 │           LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(|x| {
+   │ ╭──────────────────────────────────────────────────────────────^
+40 │ │         LambdaTest1::inline_apply(|y|y, x)
+41 │ │         },
+   │ ╰─────────^
+
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/lambda.move:54:29
+   │
+54 │     LambdaTest2::inline_apply2(|x| x + 1, 3) +
+   │                                ^^^^^^^^^
+
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/lambda.move:55:29
+   │
+55 │     LambdaTest2::inline_apply2(|x| x * x, inline_apply(|y|y, 3))
+   │                                ^^^^^^^^^
+
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/lambda.move:55:53
+   │
+55 │     LambdaTest2::inline_apply2(|x| x * x, inline_apply(|y|y, 3))
+   │                                                        ^^^^
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast.lambda.exp
index cc4db35759051..277584ca7ef3f 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast.lambda.exp
@@ -434,8 +434,20 @@ module 0x12391283::M {
 
 
 Diagnostics:
-error: captured variable `accu` cannot be modified inside of a lambda
-   ┌─ tests/lambda/inline-parity/lambda_cast.move:18:35
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/lambda_cast.move:18:28
    │
 18 │         vector_for_each(v, |elem| accu = f(accu, elem));
-   │                                   ^^^^
+   │                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/lambda_cast.move:26:61
+   │
+26 │         vector_fold<u64, u8>(gas_schedule_blob, (0 as u64), |sum, addend| sum + (addend as u64))
+   │                                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/lambda_cast.move:33:52
+   │
+33 │         vector_fold(gas_schedule_blob, (0 as u64), |sum, addend| sum + (addend as u64))
+   │                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast_err.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast_err.exp
index d9cd9d072137b..95c37d67c6f26 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast_err.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast_err.exp
@@ -1,6 +1,6 @@
 
 Diagnostics:
-error: cannot pass `|(u64, integer)|u64` to a function which expects argument of type `|(u64, vector<u8>)|u64`
+error: cannot pass `|(u64, integer)|u64 with copy+store` to a function which expects argument of type `|(u64, vector<u8>)|u64`
    ┌─ tests/lambda/inline-parity/lambda_cast_err.move:26:52
    │
 26 │         vector_fold(gas_schedule_blob, (0 as u64), |sum, addend| sum + (addend as u64))
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast_err.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast_err.lambda.exp
index d9cd9d072137b..95c37d67c6f26 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast_err.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast_err.lambda.exp
@@ -1,6 +1,6 @@
 
 Diagnostics:
-error: cannot pass `|(u64, integer)|u64` to a function which expects argument of type `|(u64, vector<u8>)|u64`
+error: cannot pass `|(u64, integer)|u64 with copy+store` to a function which expects argument of type `|(u64, vector<u8>)|u64`
    ┌─ tests/lambda/inline-parity/lambda_cast_err.move:26:52
    │
 26 │         vector_fold(gas_schedule_blob, (0 as u64), |sum, addend| sum + (addend as u64))
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_no_param.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_no_param.lambda.exp
index eb23c97b263b2..dd01bdee97745 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_no_param.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_no_param.lambda.exp
@@ -207,102 +207,15 @@ module 0xdecafbad::m {
 } // end 0xdecafbad::m
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0xdecafbad::m {
-    private fun bar(f: |()|u64): u64 {
-        (f)()
-    }
-    private fun foo(f: |()|) {
-        (f)();
-        Tuple()
-    }
-    public fun one() {
-        m::foo(closure m::one$lambda$1());
-        Tuple()
-    }
-    public fun two(x: u64): u64 {
-        m::bar(closure m::two$lambda$1(x))
-    }
-    private fun one$lambda$1() {
-        Tuple()
-    }
-    private fun two$lambda$1(x: u64): u64 {
-        x
-    }
-} // end 0xdecafbad::m
-
-
-// -- Model dump after env processor specification checker:
-module 0xdecafbad::m {
-    private fun bar(f: |()|u64): u64 {
-        (f)()
-    }
-    private fun foo(f: |()|) {
-        (f)();
-        Tuple()
-    }
-    public fun one() {
-        m::foo(closure m::one$lambda$1());
-        Tuple()
-    }
-    public fun two(x: u64): u64 {
-        m::bar(closure m::two$lambda$1(x))
-    }
-    private fun one$lambda$1() {
-        Tuple()
-    }
-    private fun two$lambda$1(x: u64): u64 {
-        x
-    }
-} // end 0xdecafbad::m
-
-
-// -- Model dump after env processor specification rewriter:
-module 0xdecafbad::m {
-    private fun bar(f: |()|u64): u64 {
-        (f)()
-    }
-    private fun foo(f: |()|) {
-        (f)();
-        Tuple()
-    }
-    public fun one() {
-        m::foo(closure m::one$lambda$1());
-        Tuple()
-    }
-    public fun two(x: u64): u64 {
-        m::bar(closure m::two$lambda$1(x))
-    }
-    private fun one$lambda$1() {
-        Tuple()
-    }
-    private fun two$lambda$1(x: u64): u64 {
-        x
-    }
-} // end 0xdecafbad::m
-
-
 
 Diagnostics:
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda/inline-parity/lambda_no_param.move:3:9
-  │
-3 │         f();
-  │         ^
-
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
   ┌─ tests/lambda/inline-parity/lambda_no_param.move:7:13
   │
 7 │         foo(|| {});
   │             ^^^^^
 
-error: Calls to function values other than inline function parameters not yet supported
-   ┌─ tests/lambda/inline-parity/lambda_no_param.move:11:9
-   │
-11 │         f()
-   │         ^
-
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda/inline-parity/lambda_no_param.move:15:13
    │
 15 │         bar(||x)
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param.lambda.exp
index b3587c0f077ef..5e54032b12b92 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param.lambda.exp
@@ -603,234 +603,27 @@ module 0x42::LambdaParam {
 } // end 0x42::LambdaParam
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0x42::LambdaParam {
-    public fun inline_apply(f: |u64|u64,b: u64): u64 {
-        (f)(b)
-    }
-    public fun inline_apply2(f: |u64|u64,b: u64): u64 {
-        LambdaParam::inline_apply(f, b)
-    }
-    public fun inline_apply3(f: |u64|u64,b: u64): u64 {
-        LambdaParam::inline_apply4(f, b)
-    }
-    public fun inline_apply4(_f: |u64|u64,b: u64): u64 {
-        b
-    }
-    private fun test_lambda_symbol_param1() {
-        {
-          let a: u64 = LambdaParam::inline_apply2(closure LambdaParam::test_lambda_symbol_param1$lambda$1(), 3);
-          if Eq<u64>(a, 3) {
-            Tuple()
-          } else {
-            Abort(0)
-          };
-          Tuple()
-        }
-    }
-    private fun test_lambda_symbol_param2() {
-        {
-          let a: u64 = LambdaParam::inline_apply2(closure LambdaParam::test_lambda_symbol_param2$lambda$1(), 3);
-          if Eq<u64>(a, 3) {
-            Tuple()
-          } else {
-            Abort(0)
-          };
-          {
-            let b: u64 = LambdaParam::inline_apply(closure LambdaParam::test_lambda_symbol_param2$lambda$2(), 3);
-            if Eq<u64>(b, 3) {
-              Tuple()
-            } else {
-              Abort(0)
-            };
-            {
-              let b: u64 = LambdaParam::inline_apply3(closure LambdaParam::test_lambda_symbol_param2$lambda$3(), 3);
-              if Eq<u64>(b, 3) {
-                Tuple()
-              } else {
-                Abort(0)
-              };
-              Tuple()
-            }
-          }
-        }
-    }
-    private fun test_lambda_symbol_param1$lambda$1(x: u64): u64 {
-        x
-    }
-    private fun test_lambda_symbol_param2$lambda$1(x: u64): u64 {
-        x
-    }
-    private fun test_lambda_symbol_param2$lambda$2(x: u64): u64 {
-        x
-    }
-    private fun test_lambda_symbol_param2$lambda$3(x: u64): u64 {
-        x
-    }
-} // end 0x42::LambdaParam
-
-
-// -- Model dump after env processor specification checker:
-module 0x42::LambdaParam {
-    public fun inline_apply(f: |u64|u64,b: u64): u64 {
-        (f)(b)
-    }
-    public fun inline_apply2(f: |u64|u64,b: u64): u64 {
-        LambdaParam::inline_apply(f, b)
-    }
-    public fun inline_apply3(f: |u64|u64,b: u64): u64 {
-        LambdaParam::inline_apply4(f, b)
-    }
-    public fun inline_apply4(_f: |u64|u64,b: u64): u64 {
-        b
-    }
-    private fun test_lambda_symbol_param1() {
-        {
-          let a: u64 = LambdaParam::inline_apply2(closure LambdaParam::test_lambda_symbol_param1$lambda$1(), 3);
-          if Eq<u64>(a, 3) {
-            Tuple()
-          } else {
-            Abort(0)
-          };
-          Tuple()
-        }
-    }
-    private fun test_lambda_symbol_param2() {
-        {
-          let a: u64 = LambdaParam::inline_apply2(closure LambdaParam::test_lambda_symbol_param2$lambda$1(), 3);
-          if Eq<u64>(a, 3) {
-            Tuple()
-          } else {
-            Abort(0)
-          };
-          {
-            let b: u64 = LambdaParam::inline_apply(closure LambdaParam::test_lambda_symbol_param2$lambda$2(), 3);
-            if Eq<u64>(b, 3) {
-              Tuple()
-            } else {
-              Abort(0)
-            };
-            {
-              let b: u64 = LambdaParam::inline_apply3(closure LambdaParam::test_lambda_symbol_param2$lambda$3(), 3);
-              if Eq<u64>(b, 3) {
-                Tuple()
-              } else {
-                Abort(0)
-              };
-              Tuple()
-            }
-          }
-        }
-    }
-    private fun test_lambda_symbol_param1$lambda$1(x: u64): u64 {
-        x
-    }
-    private fun test_lambda_symbol_param2$lambda$1(x: u64): u64 {
-        x
-    }
-    private fun test_lambda_symbol_param2$lambda$2(x: u64): u64 {
-        x
-    }
-    private fun test_lambda_symbol_param2$lambda$3(x: u64): u64 {
-        x
-    }
-} // end 0x42::LambdaParam
-
-
-// -- Model dump after env processor specification rewriter:
-module 0x42::LambdaParam {
-    public fun inline_apply(f: |u64|u64,b: u64): u64 {
-        (f)(b)
-    }
-    public fun inline_apply2(f: |u64|u64,b: u64): u64 {
-        LambdaParam::inline_apply(f, b)
-    }
-    public fun inline_apply3(f: |u64|u64,b: u64): u64 {
-        LambdaParam::inline_apply4(f, b)
-    }
-    public fun inline_apply4(_f: |u64|u64,b: u64): u64 {
-        b
-    }
-    private fun test_lambda_symbol_param1() {
-        {
-          let a: u64 = LambdaParam::inline_apply2(closure LambdaParam::test_lambda_symbol_param1$lambda$1(), 3);
-          if Eq<u64>(a, 3) {
-            Tuple()
-          } else {
-            Abort(0)
-          };
-          Tuple()
-        }
-    }
-    private fun test_lambda_symbol_param2() {
-        {
-          let a: u64 = LambdaParam::inline_apply2(closure LambdaParam::test_lambda_symbol_param2$lambda$1(), 3);
-          if Eq<u64>(a, 3) {
-            Tuple()
-          } else {
-            Abort(0)
-          };
-          {
-            let b: u64 = LambdaParam::inline_apply(closure LambdaParam::test_lambda_symbol_param2$lambda$2(), 3);
-            if Eq<u64>(b, 3) {
-              Tuple()
-            } else {
-              Abort(0)
-            };
-            {
-              let b: u64 = LambdaParam::inline_apply3(closure LambdaParam::test_lambda_symbol_param2$lambda$3(), 3);
-              if Eq<u64>(b, 3) {
-                Tuple()
-              } else {
-                Abort(0)
-              };
-              Tuple()
-            }
-          }
-        }
-    }
-    private fun test_lambda_symbol_param1$lambda$1(x: u64): u64 {
-        x
-    }
-    private fun test_lambda_symbol_param2$lambda$1(x: u64): u64 {
-        x
-    }
-    private fun test_lambda_symbol_param2$lambda$2(x: u64): u64 {
-        x
-    }
-    private fun test_lambda_symbol_param2$lambda$3(x: u64): u64 {
-        x
-    }
-} // end 0x42::LambdaParam
-
-
 
 Diagnostics:
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda/inline-parity/lambda_param.move:3:2
-  │
-3 │     f(b)
-  │     ^
-
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda/inline-parity/lambda_param.move:19:24
    │
 19 │     let a = inline_apply2(|x| x, 3);
    │                           ^^^^^
 
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda/inline-parity/lambda_param.move:24:24
    │
 24 │     let a = inline_apply2(|x| x, 3);
    │                           ^^^^^
 
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda/inline-parity/lambda_param.move:26:23
    │
 26 │     let b = inline_apply(|x| x, 3);
    │                          ^^^^^
 
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda/inline-parity/lambda_param.move:28:24
    │
 28 │     let b = inline_apply3(|x| x, 3);
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_mismatch.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_mismatch.exp
index 33468b26f118d..64614096d6592 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_mismatch.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_mismatch.exp
@@ -1,6 +1,6 @@
 
 Diagnostics:
-error: cannot pass `|u64|u64` to a function which expects argument of type `|u64|`
+error: cannot pass `|u64|u64 with copy+store` to a function which expects argument of type `|u64|`
    ┌─ tests/lambda/inline-parity/lambda_param_mismatch.move:20:32
    │
 20 │           vector_for_each(input, |item| {
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_mismatch.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_mismatch.lambda.exp
index 33468b26f118d..64614096d6592 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_mismatch.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_mismatch.lambda.exp
@@ -1,6 +1,6 @@
 
 Diagnostics:
-error: cannot pass `|u64|u64` to a function which expects argument of type `|u64|`
+error: cannot pass `|u64|u64 with copy+store` to a function which expects argument of type `|u64|`
    ┌─ tests/lambda/inline-parity/lambda_param_mismatch.move:20:32
    │
 20 │           vector_for_each(input, |item| {
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_return.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_return.lambda.exp
index 2b9ffb4ba4160..1ea24d42e88ac 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_return.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_return.lambda.exp
@@ -207,81 +207,9 @@ module 0x42::LambdaReturn {
 } // end 0x42::LambdaReturn
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0x42::LambdaReturn {
-    public fun inline_apply2(f: |u64|u64,b: u64): u64 {
-        return (f)(b)
-    }
-    private fun test_lambda_symbol_param() {
-        {
-          let a: u64 = LambdaReturn::inline_apply2(closure LambdaReturn::test_lambda_symbol_param$lambda$1(), 3);
-          if Eq<u64>(a, 3) {
-            Tuple()
-          } else {
-            Abort(0)
-          };
-          Tuple()
-        }
-    }
-    private fun test_lambda_symbol_param$lambda$1(x: u64): u64 {
-        x
-    }
-} // end 0x42::LambdaReturn
-
-
-// -- Model dump after env processor specification checker:
-module 0x42::LambdaReturn {
-    public fun inline_apply2(f: |u64|u64,b: u64): u64 {
-        return (f)(b)
-    }
-    private fun test_lambda_symbol_param() {
-        {
-          let a: u64 = LambdaReturn::inline_apply2(closure LambdaReturn::test_lambda_symbol_param$lambda$1(), 3);
-          if Eq<u64>(a, 3) {
-            Tuple()
-          } else {
-            Abort(0)
-          };
-          Tuple()
-        }
-    }
-    private fun test_lambda_symbol_param$lambda$1(x: u64): u64 {
-        x
-    }
-} // end 0x42::LambdaReturn
-
-
-// -- Model dump after env processor specification rewriter:
-module 0x42::LambdaReturn {
-    public fun inline_apply2(f: |u64|u64,b: u64): u64 {
-        return (f)(b)
-    }
-    private fun test_lambda_symbol_param() {
-        {
-          let a: u64 = LambdaReturn::inline_apply2(closure LambdaReturn::test_lambda_symbol_param$lambda$1(), 3);
-          if Eq<u64>(a, 3) {
-            Tuple()
-          } else {
-            Abort(0)
-          };
-          Tuple()
-        }
-    }
-    private fun test_lambda_symbol_param$lambda$1(x: u64): u64 {
-        x
-    }
-} // end 0x42::LambdaReturn
-
-
 
 Diagnostics:
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda/inline-parity/lambda_return.move:3:9
-  │
-3 │     return f(b)
-  │            ^
-
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
   ┌─ tests/lambda/inline-parity/lambda_return.move:7:24
   │
 7 │     let a = inline_apply2(|x| { x }, 3);
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_typed.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_typed.lambda.exp
index 396fdaf35ada9..ffe457423462b 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_typed.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_typed.lambda.exp
@@ -1285,325 +1285,19 @@ module 0x42::LambdaTest {
 } // end 0x42::LambdaTest
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0x42::LambdaTest1 {
-    public inline fun inline_apply(f: |u64|u64,b: u64): u64 {
-        (f)(b)
-    }
-    public inline fun inline_apply1(f: |u64|u64,b: u64): u64 {
-        {
-          let (a: u64, b: u64): (u64, u64) = Tuple(Add<u64>((f)(b), 1), 12);
-          Mul<u64>(a, 12)
-        }
-    }
-    public inline fun inline_mul(a: u64,b: u64): u64 {
-        Mul<u64>(a, b)
-    }
-} // end 0x42::LambdaTest1
-module 0x42::LambdaTest2 {
-    use 0x42::LambdaTest1; // resolved as: 0x42::LambdaTest1
-    use std::vector;
-    public inline fun foreach<T>(v: &vector<T>,action: |&T|) {
-        {
-          let i: u64 = 0;
-          loop {
-            if Lt<u64>(i, vector::length<T>(v)) {
-              (action)(vector::borrow<T>(v, i));
-              i: u64 = Add<u64>(i, 1);
-              Tuple()
-            } else {
-              break
-            }
-          }
-        }
-    }
-    public inline fun inline_apply2(g: |u64|u64,c: u64): u64 {
-        Add<u64>({
-          let (b: u64): (u64) = Tuple((g)({
-            let (a: u64, b: u64): (u64, u64) = Tuple(c, 3);
-            Mul<u64>(a, 3)
-          }));
-          {
-            let (a: u64, b: u64): (u64, u64) = Tuple(Add<u64>({
-              let (z: u64): (u64) = Tuple(b);
-              z
-            }, 1), 12);
-            Mul<u64>(a, 12)
-          }
-        }, 2)
-    }
-    public inline fun inline_apply3(g: |u64|u64,c: u64): u64 {
-        Add<u64>(LambdaTest1::inline_apply1(g, LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(closure LambdaTest2::inline_apply3$lambda$2(), 3))), 4)
-    }
-    public fun test_inline_lambda() {
-        {
-          let product: u64 = 1;
-          {
-            let (v: &vector<u64>): (&vector<u64>) = Tuple(Borrow(Immutable)([Number(1), Number(2), Number(3)]));
-            {
-              let i: u64 = 0;
-              loop {
-                if Lt<u64>(i, vector::length<u64>(v)) {
-                  {
-                    let (e: &u64): (&u64) = Tuple(vector::borrow<u64>(v, i));
-                    product: u64 = {
-                      let (a: u64, b: u64): (u64, u64) = Tuple(product, Deref(e));
-                      Mul<u64>(a, b)
-                    }
-                  };
-                  i: u64 = Add<u64>(i, 1);
-                  Tuple()
-                } else {
-                  break
-                }
-              }
-            }
-          };
-          Tuple()
-        }
-    }
-    private fun inline_apply3$lambda$1(y: u64): u64 {
-        y
-    }
-    private fun inline_apply3$lambda$2(x: u64): u64 {
-        LambdaTest1::inline_apply(closure LambdaTest2::inline_apply3$lambda$1(), x)
-    }
-} // end 0x42::LambdaTest2
-module 0x42::LambdaTest {
-    use 0x42::LambdaTest2; // resolved as: 0x42::LambdaTest2
-    public inline fun inline_apply(f: |u64|u64,b: u64): u64 {
-        (f)(b)
-    }
-    public inline fun inline_apply_test(): u64 {
-        1120
-    }
-    private fun test_lambda() {
-        if false {
-          Tuple()
-        } else {
-          Abort(0)
-        };
-        Tuple()
-    }
-} // end 0x42::LambdaTest
-
-
-// -- Model dump after env processor specification checker:
-module 0x42::LambdaTest1 {
-    public inline fun inline_apply(f: |u64|u64,b: u64): u64 {
-        (f)(b)
-    }
-    public inline fun inline_apply1(f: |u64|u64,b: u64): u64 {
-        {
-          let (a: u64, b: u64): (u64, u64) = Tuple(Add<u64>((f)(b), 1), 12);
-          Mul<u64>(a, 12)
-        }
-    }
-    public inline fun inline_mul(a: u64,b: u64): u64 {
-        Mul<u64>(a, b)
-    }
-} // end 0x42::LambdaTest1
-module 0x42::LambdaTest2 {
-    use 0x42::LambdaTest1; // resolved as: 0x42::LambdaTest1
-    use std::vector;
-    public inline fun foreach<T>(v: &vector<T>,action: |&T|) {
-        {
-          let i: u64 = 0;
-          loop {
-            if Lt<u64>(i, vector::length<T>(v)) {
-              (action)(vector::borrow<T>(v, i));
-              i: u64 = Add<u64>(i, 1);
-              Tuple()
-            } else {
-              break
-            }
-          }
-        }
-    }
-    public inline fun inline_apply2(g: |u64|u64,c: u64): u64 {
-        Add<u64>({
-          let (b: u64): (u64) = Tuple((g)({
-            let (a: u64, b: u64): (u64, u64) = Tuple(c, 3);
-            Mul<u64>(a, 3)
-          }));
-          {
-            let (a: u64, b: u64): (u64, u64) = Tuple(Add<u64>({
-              let (z: u64): (u64) = Tuple(b);
-              z
-            }, 1), 12);
-            Mul<u64>(a, 12)
-          }
-        }, 2)
-    }
-    public inline fun inline_apply3(g: |u64|u64,c: u64): u64 {
-        Add<u64>(LambdaTest1::inline_apply1(g, LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(closure LambdaTest2::inline_apply3$lambda$2(), 3))), 4)
-    }
-    public fun test_inline_lambda() {
-        {
-          let product: u64 = 1;
-          {
-            let (v: &vector<u64>): (&vector<u64>) = Tuple(Borrow(Immutable)([Number(1), Number(2), Number(3)]));
-            {
-              let i: u64 = 0;
-              loop {
-                if Lt<u64>(i, vector::length<u64>(v)) {
-                  {
-                    let (e: &u64): (&u64) = Tuple(vector::borrow<u64>(v, i));
-                    product: u64 = {
-                      let (a: u64, b: u64): (u64, u64) = Tuple(product, Deref(e));
-                      Mul<u64>(a, b)
-                    }
-                  };
-                  i: u64 = Add<u64>(i, 1);
-                  Tuple()
-                } else {
-                  break
-                }
-              }
-            }
-          };
-          Tuple()
-        }
-    }
-    private fun inline_apply3$lambda$1(y: u64): u64 {
-        y
-    }
-    private fun inline_apply3$lambda$2(x: u64): u64 {
-        LambdaTest1::inline_apply(closure LambdaTest2::inline_apply3$lambda$1(), x)
-    }
-} // end 0x42::LambdaTest2
-module 0x42::LambdaTest {
-    use 0x42::LambdaTest2; // resolved as: 0x42::LambdaTest2
-    public inline fun inline_apply(f: |u64|u64,b: u64): u64 {
-        (f)(b)
-    }
-    public inline fun inline_apply_test(): u64 {
-        1120
-    }
-    private fun test_lambda() {
-        if false {
-          Tuple()
-        } else {
-          Abort(0)
-        };
-        Tuple()
-    }
-} // end 0x42::LambdaTest
-
-
-// -- Model dump after env processor specification rewriter:
-module 0x42::LambdaTest1 {
-    public inline fun inline_apply(f: |u64|u64,b: u64): u64 {
-        (f)(b)
-    }
-    public inline fun inline_apply1(f: |u64|u64,b: u64): u64 {
-        {
-          let (a: u64, b: u64): (u64, u64) = Tuple(Add<u64>((f)(b), 1), 12);
-          Mul<u64>(a, 12)
-        }
-    }
-    public inline fun inline_mul(a: u64,b: u64): u64 {
-        Mul<u64>(a, b)
-    }
-} // end 0x42::LambdaTest1
-module 0x42::LambdaTest2 {
-    use 0x42::LambdaTest1; // resolved as: 0x42::LambdaTest1
-    use std::vector;
-    public inline fun foreach<T>(v: &vector<T>,action: |&T|) {
-        {
-          let i: u64 = 0;
-          loop {
-            if Lt<u64>(i, vector::length<T>(v)) {
-              (action)(vector::borrow<T>(v, i));
-              i: u64 = Add<u64>(i, 1);
-              Tuple()
-            } else {
-              break
-            }
-          }
-        }
-    }
-    public inline fun inline_apply2(g: |u64|u64,c: u64): u64 {
-        Add<u64>({
-          let (b: u64): (u64) = Tuple((g)({
-            let (a: u64, b: u64): (u64, u64) = Tuple(c, 3);
-            Mul<u64>(a, 3)
-          }));
-          {
-            let (a: u64, b: u64): (u64, u64) = Tuple(Add<u64>({
-              let (z: u64): (u64) = Tuple(b);
-              z
-            }, 1), 12);
-            Mul<u64>(a, 12)
-          }
-        }, 2)
-    }
-    public inline fun inline_apply3(g: |u64|u64,c: u64): u64 {
-        Add<u64>(LambdaTest1::inline_apply1(g, LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(closure LambdaTest2::inline_apply3$lambda$2(), 3))), 4)
-    }
-    public fun test_inline_lambda() {
-        {
-          let product: u64 = 1;
-          {
-            let (v: &vector<u64>): (&vector<u64>) = Tuple(Borrow(Immutable)([Number(1), Number(2), Number(3)]));
-            {
-              let i: u64 = 0;
-              loop {
-                if Lt<u64>(i, vector::length<u64>(v)) {
-                  {
-                    let (e: &u64): (&u64) = Tuple(vector::borrow<u64>(v, i));
-                    product: u64 = {
-                      let (a: u64, b: u64): (u64, u64) = Tuple(product, Deref(e));
-                      Mul<u64>(a, b)
-                    }
-                  };
-                  i: u64 = Add<u64>(i, 1);
-                  Tuple()
-                } else {
-                  break
-                }
-              }
-            }
-          };
-          Tuple()
-        }
-    }
-    private fun inline_apply3$lambda$1(y: u64): u64 {
-        y
-    }
-    private fun inline_apply3$lambda$2(x: u64): u64 {
-        LambdaTest1::inline_apply(closure LambdaTest2::inline_apply3$lambda$1(), x)
-    }
-} // end 0x42::LambdaTest2
-module 0x42::LambdaTest {
-    use 0x42::LambdaTest2; // resolved as: 0x42::LambdaTest2
-    public inline fun inline_apply(f: |u64|u64,b: u64): u64 {
-        (f)(b)
-    }
-    public inline fun inline_apply_test(): u64 {
-        1120
-    }
-    private fun test_lambda() {
-        if false {
-          Tuple()
-        } else {
-          Abort(0)
-        };
-        Tuple()
-    }
-} // end 0x42::LambdaTest
-
-
 
 Diagnostics:
-error: Calls to function values other than inline function parameters not yet supported
-   ┌─ tests/lambda/inline-parity/lambda_typed.move:11:2
-   │
-11 │     f(b)
-   │     ^
-
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda/inline-parity/lambda_typed.move:40:29
    │
 40 │         LambdaTest1::inline_apply(|y: u64|y, x)
    │                                   ^^^^^^^^^
+
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/lambda_typed.move:39:59
+   │
+39 │           LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(|x:u64| {
+   │ ╭──────────────────────────────────────────────────────────────^
+40 │ │         LambdaTest1::inline_apply(|y: u64|y, x)
+41 │ │         },
+   │ ╰─────────^
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/masking.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/masking.lambda.exp
index a89c6271195d1..4f3bf689cb56b 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/masking.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/masking.lambda.exp
@@ -119,96 +119,15 @@ module 0x42::Test {
 } // end 0x42::Test
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0x42::Test {
-    private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 {
-        Add<u64>((f)(x, _y), (g)(x, _y))
-    }
-    public fun main(): u64 {
-        Test::foo(closure Test::main$lambda$1(), closure Test::main$lambda$2(), 10, 100)
-    }
-    private fun main$lambda$1(x: u64,param$1: u64): u64 {
-        {
-          let _: u64 = param$1;
-          x
-        }
-    }
-    private fun main$lambda$2(param$0: u64,y: u64): u64 {
-        {
-          let _: u64 = param$0;
-          y
-        }
-    }
-} // end 0x42::Test
-
-
-// -- Model dump after env processor specification checker:
-module 0x42::Test {
-    private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 {
-        Add<u64>((f)(x, _y), (g)(x, _y))
-    }
-    public fun main(): u64 {
-        Test::foo(closure Test::main$lambda$1(), closure Test::main$lambda$2(), 10, 100)
-    }
-    private fun main$lambda$1(x: u64,param$1: u64): u64 {
-        {
-          let _: u64 = param$1;
-          x
-        }
-    }
-    private fun main$lambda$2(param$0: u64,y: u64): u64 {
-        {
-          let _: u64 = param$0;
-          y
-        }
-    }
-} // end 0x42::Test
-
-
-// -- Model dump after env processor specification rewriter:
-module 0x42::Test {
-    private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 {
-        Add<u64>((f)(x, _y), (g)(x, _y))
-    }
-    public fun main(): u64 {
-        Test::foo(closure Test::main$lambda$1(), closure Test::main$lambda$2(), 10, 100)
-    }
-    private fun main$lambda$1(x: u64,param$1: u64): u64 {
-        {
-          let _: u64 = param$1;
-          x
-        }
-    }
-    private fun main$lambda$2(param$0: u64,y: u64): u64 {
-        {
-          let _: u64 = param$0;
-          y
-        }
-    }
-} // end 0x42::Test
-
-
 
 Diagnostics:
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda/inline-parity/masking.move:4:9
-  │
-4 │         f(x, _y) + g(x, _y)
-  │         ^
-
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda/inline-parity/masking.move:4:20
-  │
-4 │         f(x, _y) + g(x, _y)
-  │                    ^
-
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
   ┌─ tests/lambda/inline-parity/masking.move:8:13
   │
 8 │         foo(|x, _| x, |_, y| y, 10, 100)
   │             ^^^^^^^^
 
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
   ┌─ tests/lambda/inline-parity/masking.move:8:23
   │
 8 │         foo(|x, _| x, |_, y| y, 10, 100)
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/multi_param.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/multi_param.lambda.exp
index 79df5cae6a545..855a868e5dcb4 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/multi_param.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/multi_param.lambda.exp
@@ -451,8 +451,18 @@ module 0x42::Test {
 
 
 Diagnostics:
-error: captured variable `result` cannot be modified inside of a lambda
-   ┌─ tests/lambda/inline-parity/multi_param.move:21:13
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/multi_param.move:19:29
    │
-21 │             result = result + f(&elem.k, &mut elem.v);
-   │             ^^^^^^
+19 │           for_each_ref_mut(v, |elem| {
+   │ ╭─────────────────────────────^
+20 │ │             let elem: &mut Elem<K, V> = elem; // Checks whether scoping is fine
+21 │ │             result = result + f(&elem.k, &mut elem.v);
+22 │ │         });
+   │ ╰─────────^
+
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/multi_param.move:27:64
+   │
+27 │         assert!(elem_for_each_ref(&mut vector[Elem{k:1, v:2}], |x,y| *x + *y) == 3, 0)
+   │                                                                ^^^^^^^^^^^^^
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda.lambda.exp
index 019feaaebebc4..7793f33a9f484 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda.lambda.exp
@@ -119,72 +119,15 @@ module 0x42::Test {
 } // end 0x42::Test
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0x42::Test {
-    public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 {
-        (f)(x, y)
-    }
-    public fun test(): u64 {
-        Test::apply(closure Test::test$lambda$1(), 1, Test::apply(closure Test::test$lambda$2(), 2, 1))
-    }
-    private fun test$lambda$1(x: u64,y: u64): u64 {
-        Add<u64>(x, y)
-    }
-    private fun test$lambda$2(x: u64,y: u64): u64 {
-        Mul<u64>(x, y)
-    }
-} // end 0x42::Test
-
-
-// -- Model dump after env processor specification checker:
-module 0x42::Test {
-    public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 {
-        (f)(x, y)
-    }
-    public fun test(): u64 {
-        Test::apply(closure Test::test$lambda$1(), 1, Test::apply(closure Test::test$lambda$2(), 2, 1))
-    }
-    private fun test$lambda$1(x: u64,y: u64): u64 {
-        Add<u64>(x, y)
-    }
-    private fun test$lambda$2(x: u64,y: u64): u64 {
-        Mul<u64>(x, y)
-    }
-} // end 0x42::Test
-
-
-// -- Model dump after env processor specification rewriter:
-module 0x42::Test {
-    public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 {
-        (f)(x, y)
-    }
-    public fun test(): u64 {
-        Test::apply(closure Test::test$lambda$1(), 1, Test::apply(closure Test::test$lambda$2(), 2, 1))
-    }
-    private fun test$lambda$1(x: u64,y: u64): u64 {
-        Add<u64>(x, y)
-    }
-    private fun test$lambda$2(x: u64,y: u64): u64 {
-        Mul<u64>(x, y)
-    }
-} // end 0x42::Test
-
-
 
 Diagnostics:
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda/inline-parity/nested_lambda.move:5:9
-  │
-5 │         f(x, y)
-  │         ^
-
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
   ┌─ tests/lambda/inline-parity/nested_lambda.move:9:15
   │
 9 │         apply(|x, y| x + y, 1, apply(|x, y| x * y, 2, 1))
   │               ^^^^^^^^^^^^
 
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
   ┌─ tests/lambda/inline-parity/nested_lambda.move:9:38
   │
 9 │         apply(|x, y| x + y, 1, apply(|x, y| x * y, 2, 1))
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda_module.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda_module.lambda.exp
index f5ed4cea4f283..7b08cadad410f 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda_module.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda_module.lambda.exp
@@ -152,81 +152,15 @@ module 0x42::Test {
 } // end 0x42::Test
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0x42::Test1 {
-    public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 {
-        (f)(x, y)
-    }
-} // end 0x42::Test1
-module 0x42::Test {
-    use 0x42::Test1; // resolved as: 0x42::Test1
-    public fun test(): u64 {
-        Test1::apply(closure Test::test$lambda$1(), 1, Test1::apply(closure Test::test$lambda$2(), 2, 1))
-    }
-    private fun test$lambda$1(x: u64,y: u64): u64 {
-        Add<u64>(x, y)
-    }
-    private fun test$lambda$2(x: u64,y: u64): u64 {
-        Mul<u64>(x, y)
-    }
-} // end 0x42::Test
-
-
-// -- Model dump after env processor specification checker:
-module 0x42::Test1 {
-    public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 {
-        (f)(x, y)
-    }
-} // end 0x42::Test1
-module 0x42::Test {
-    use 0x42::Test1; // resolved as: 0x42::Test1
-    public fun test(): u64 {
-        Test1::apply(closure Test::test$lambda$1(), 1, Test1::apply(closure Test::test$lambda$2(), 2, 1))
-    }
-    private fun test$lambda$1(x: u64,y: u64): u64 {
-        Add<u64>(x, y)
-    }
-    private fun test$lambda$2(x: u64,y: u64): u64 {
-        Mul<u64>(x, y)
-    }
-} // end 0x42::Test
-
-
-// -- Model dump after env processor specification rewriter:
-module 0x42::Test1 {
-    public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 {
-        (f)(x, y)
-    }
-} // end 0x42::Test1
-module 0x42::Test {
-    use 0x42::Test1; // resolved as: 0x42::Test1
-    public fun test(): u64 {
-        Test1::apply(closure Test::test$lambda$1(), 1, Test1::apply(closure Test::test$lambda$2(), 2, 1))
-    }
-    private fun test$lambda$1(x: u64,y: u64): u64 {
-        Add<u64>(x, y)
-    }
-    private fun test$lambda$2(x: u64,y: u64): u64 {
-        Mul<u64>(x, y)
-    }
-} // end 0x42::Test
-
-
 
 Diagnostics:
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda/inline-parity/nested_lambda_module.move:4:9
-  │
-4 │         f(x, y)
-  │         ^
-
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda/inline-parity/nested_lambda_module.move:13:22
    │
 13 │         Test1::apply(|x, y| x + y, 1, Test1::apply(|x, y| x * y, 2, 1))
    │                      ^^^^^^^^^^^^
 
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda/inline-parity/nested_lambda_module.move:13:52
    │
 13 │         Test1::apply(|x, y| x + y, 1, Test1::apply(|x, y| x * y, 2, 1))
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/non_lambda_arg.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/non_lambda_arg.lambda.exp
index 1095994a02a62..2f733050cb6bd 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/non_lambda_arg.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/non_lambda_arg.lambda.exp
@@ -404,13 +404,3 @@ error: local `a_less_b` of type `|(T, T)|bool` does not have the `copy` ability
    │             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ copy needed here because value is still in use
 13 │             incorrect_sort_recursive(arr, pi + 1, high, a_less_b);
    │             ----------------------------------------------------- used here
-
-error: local `a_less_b` of type `|(T, T)|bool` does not have the `drop` ability
-   ┌─ tests/lambda/inline-parity/non_lambda_arg.move:10:9
-   │
-10 │ ╭         if (low < high) {
-11 │ │             let pi = low + high / 2;
-12 │ │             incorrect_sort_recursive(arr, low, pi - 1, a_less_b);
-13 │ │             incorrect_sort_recursive(arr, pi + 1, high, a_less_b);
-14 │ │         };
-   │ ╰─────────^ implicitly dropped here since it is no longer used
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/op_with_side_effect_49.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/op_with_side_effect_49.lambda.exp
index a9a1dc063d69f..21ea4435d9a91 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/op_with_side_effect_49.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/op_with_side_effect_49.lambda.exp
@@ -176,14 +176,14 @@ module 0xc0ffee::m {
 
 
 Diagnostics:
-error: captured variable `x` cannot be modified inside of a lambda
-  ┌─ tests/lambda/inline-parity/op_with_side_effect_49.move:9:22
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+  ┌─ tests/lambda/inline-parity/op_with_side_effect_49.move:9:18
   │
 9 │         x + call(|| {x = x + 1; x}) + call(|| {x = x + 7; x})
-  │                      ^
+  │                  ^^^^^^^^^^^^^^^^^
 
-error: captured variable `x` cannot be modified inside of a lambda
-  ┌─ tests/lambda/inline-parity/op_with_side_effect_49.move:9:48
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+  ┌─ tests/lambda/inline-parity/op_with_side_effect_49.move:9:44
   │
 9 │         x + call(|| {x = x + 1; x}) + call(|| {x = x + 7; x})
-  │                                                ^
+  │                                            ^^^^^^^^^^^^^^^^^
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/options.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/options.lambda.exp
index 01a7a59635ddc..a0a20d5e7701d 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/options.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/options.lambda.exp
@@ -284,102 +284,9 @@ module 0x42::Test {
 } // end 0x42::Test
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0x42::map_opt {
-    use std::option;
-    public fun map<Element,OtherElement>(t: 0x1::option::Option<Element>,f: |Element|OtherElement): 0x1::option::Option<OtherElement> {
-        if option::is_some<Element>(Borrow(Immutable)(t)) {
-          option::some<OtherElement>((f)(option::extract<Element>(Borrow(Mutable)(t))))
-        } else {
-          option::none<OtherElement>()
-        }
-    }
-} // end 0x42::map_opt
-module 0x42::Test {
-    use std::option;
-    use 0x42::map_opt; // resolved as: 0x42::map_opt
-    public fun test(): u64 {
-        {
-          let t: 0x1::option::Option<u64> = option::some<u64>(1);
-          {
-            let x: 0x1::option::Option<u64> = map_opt::map<u64, u64>(t, closure Test::test$lambda$1());
-            option::extract<u64>(Borrow(Mutable)(x))
-          }
-        }
-    }
-    private fun test$lambda$1(e: u64): u64 {
-        Add<u64>(e, 1)
-    }
-} // end 0x42::Test
-
-
-// -- Model dump after env processor specification checker:
-module 0x42::map_opt {
-    use std::option;
-    public fun map<Element,OtherElement>(t: 0x1::option::Option<Element>,f: |Element|OtherElement): 0x1::option::Option<OtherElement> {
-        if option::is_some<Element>(Borrow(Immutable)(t)) {
-          option::some<OtherElement>((f)(option::extract<Element>(Borrow(Mutable)(t))))
-        } else {
-          option::none<OtherElement>()
-        }
-    }
-} // end 0x42::map_opt
-module 0x42::Test {
-    use std::option;
-    use 0x42::map_opt; // resolved as: 0x42::map_opt
-    public fun test(): u64 {
-        {
-          let t: 0x1::option::Option<u64> = option::some<u64>(1);
-          {
-            let x: 0x1::option::Option<u64> = map_opt::map<u64, u64>(t, closure Test::test$lambda$1());
-            option::extract<u64>(Borrow(Mutable)(x))
-          }
-        }
-    }
-    private fun test$lambda$1(e: u64): u64 {
-        Add<u64>(e, 1)
-    }
-} // end 0x42::Test
-
-
-// -- Model dump after env processor specification rewriter:
-module 0x42::map_opt {
-    use std::option;
-    public fun map<Element,OtherElement>(t: 0x1::option::Option<Element>,f: |Element|OtherElement): 0x1::option::Option<OtherElement> {
-        if option::is_some<Element>(Borrow(Immutable)(t)) {
-          option::some<OtherElement>((f)(option::extract<Element>(Borrow(Mutable)(t))))
-        } else {
-          option::none<OtherElement>()
-        }
-    }
-} // end 0x42::map_opt
-module 0x42::Test {
-    use std::option;
-    use 0x42::map_opt; // resolved as: 0x42::map_opt
-    public fun test(): u64 {
-        {
-          let t: 0x1::option::Option<u64> = option::some<u64>(1);
-          {
-            let x: 0x1::option::Option<u64> = map_opt::map<u64, u64>(t, closure Test::test$lambda$1());
-            option::extract<u64>(Borrow(Mutable)(x))
-          }
-        }
-    }
-    private fun test$lambda$1(e: u64): u64 {
-        Add<u64>(e, 1)
-    }
-} // end 0x42::Test
-
-
 
 Diagnostics:
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda/inline-parity/options.move:7:26
-  │
-7 │             option::some(f(option::extract(&mut t)))
-  │                          ^
-
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda/inline-parity/options.move:22:33
    │
 22 │         let x = map_opt::map(t, |e| e + 1);
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/return_in_lambda.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/return_in_lambda.lambda.exp
index bf94c6a9de653..15cec56dd1a58 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/return_in_lambda.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/return_in_lambda.lambda.exp
@@ -152,66 +152,9 @@ module 0x42::Test {
 } // end 0x42::Test
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0x42::Test {
-    private fun adder(x: u64,y: u64): u64 {
-        Add<u64>(x, y)
-    }
-    private fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 {
-        (f)(x, y)
-    }
-    public fun main(): u64 {
-        Test::apply(closure Test::main$lambda$1(), 10, 100)
-    }
-    private fun main$lambda$1(x: u64,y: u64): u64 {
-        return Test::adder(x, y)
-    }
-} // end 0x42::Test
-
-
-// -- Model dump after env processor specification checker:
-module 0x42::Test {
-    private fun adder(x: u64,y: u64): u64 {
-        Add<u64>(x, y)
-    }
-    private fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 {
-        (f)(x, y)
-    }
-    public fun main(): u64 {
-        Test::apply(closure Test::main$lambda$1(), 10, 100)
-    }
-    private fun main$lambda$1(x: u64,y: u64): u64 {
-        return Test::adder(x, y)
-    }
-} // end 0x42::Test
-
-
-// -- Model dump after env processor specification rewriter:
-module 0x42::Test {
-    private fun adder(x: u64,y: u64): u64 {
-        Add<u64>(x, y)
-    }
-    private fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 {
-        (f)(x, y)
-    }
-    public fun main(): u64 {
-        Test::apply(closure Test::main$lambda$1(), 10, 100)
-    }
-    private fun main$lambda$1(x: u64,y: u64): u64 {
-        return Test::adder(x, y)
-    }
-} // end 0x42::Test
-
-
 
 Diagnostics:
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda/inline-parity/return_in_lambda.move:4:9
-  │
-4 │         f(x, y)
-  │         ^
-
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda/inline-parity/return_in_lambda.move:12:15
    │
 12 │           apply(|x, y| {
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/same_names.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/same_names.lambda.exp
index c473f81866042..5037745a0d988 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/same_names.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/same_names.lambda.exp
@@ -361,123 +361,9 @@ module 0x42::c {
 } // end 0x42::c
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0x42::b {
-    struct MyOtherList {
-        len: u64,
-    }
-    public fun len(self: &MyOtherList): u64 {
-        select b::MyOtherList.len<&MyOtherList>(self)
-    }
-} // end 0x42::b
-module 0x42::a {
-    struct MyList {
-        len: u64,
-    }
-    public fun len(self: &MyList): u64 {
-        select a::MyList.len<&MyList>(self)
-    }
-} // end 0x42::a
-module 0x42::c {
-    use 0x42::a; // resolved as: 0x42::a
-    use 0x42::b; // resolved as: 0x42::b
-    private fun foo(f: |(a::MyList, b::MyOtherList)|,x: a::MyList,y: b::MyOtherList) {
-        (f)(x, y)
-    }
-    private fun test(x: a::MyList,y: b::MyOtherList) {
-        c::foo(closure c::test$lambda$1(), x, y)
-    }
-    private fun test$lambda$1(x: a::MyList,y: b::MyOtherList) {
-        if Eq<u64>(Add<u64>(a::len(Borrow(Immutable)(x)), b::len(Borrow(Immutable)(y))), 1) {
-          Tuple()
-        } else {
-          Abort(1)
-        }
-    }
-} // end 0x42::c
-
-
-// -- Model dump after env processor specification checker:
-module 0x42::b {
-    struct MyOtherList {
-        len: u64,
-    }
-    public fun len(self: &MyOtherList): u64 {
-        select b::MyOtherList.len<&MyOtherList>(self)
-    }
-} // end 0x42::b
-module 0x42::a {
-    struct MyList {
-        len: u64,
-    }
-    public fun len(self: &MyList): u64 {
-        select a::MyList.len<&MyList>(self)
-    }
-} // end 0x42::a
-module 0x42::c {
-    use 0x42::a; // resolved as: 0x42::a
-    use 0x42::b; // resolved as: 0x42::b
-    private fun foo(f: |(a::MyList, b::MyOtherList)|,x: a::MyList,y: b::MyOtherList) {
-        (f)(x, y)
-    }
-    private fun test(x: a::MyList,y: b::MyOtherList) {
-        c::foo(closure c::test$lambda$1(), x, y)
-    }
-    private fun test$lambda$1(x: a::MyList,y: b::MyOtherList) {
-        if Eq<u64>(Add<u64>(a::len(Borrow(Immutable)(x)), b::len(Borrow(Immutable)(y))), 1) {
-          Tuple()
-        } else {
-          Abort(1)
-        }
-    }
-} // end 0x42::c
-
-
-// -- Model dump after env processor specification rewriter:
-module 0x42::b {
-    struct MyOtherList {
-        len: u64,
-    }
-    public fun len(self: &MyOtherList): u64 {
-        select b::MyOtherList.len<&MyOtherList>(self)
-    }
-} // end 0x42::b
-module 0x42::a {
-    struct MyList {
-        len: u64,
-    }
-    public fun len(self: &MyList): u64 {
-        select a::MyList.len<&MyList>(self)
-    }
-} // end 0x42::a
-module 0x42::c {
-    use 0x42::a; // resolved as: 0x42::a
-    use 0x42::b; // resolved as: 0x42::b
-    private fun foo(f: |(a::MyList, b::MyOtherList)|,x: a::MyList,y: b::MyOtherList) {
-        (f)(x, y)
-    }
-    private fun test(x: a::MyList,y: b::MyOtherList) {
-        c::foo(closure c::test$lambda$1(), x, y)
-    }
-    private fun test$lambda$1(x: a::MyList,y: b::MyOtherList) {
-        if Eq<u64>(Add<u64>(a::len(Borrow(Immutable)(x)), b::len(Borrow(Immutable)(y))), 1) {
-          Tuple()
-        } else {
-          Abort(1)
-        }
-    }
-} // end 0x42::c
-
-
 
 Diagnostics:
-error: Calls to function values other than inline function parameters not yet supported
-   ┌─ tests/lambda/inline-parity/same_names.move:24:9
-   │
-24 │         f(x, y)
-   │         ^
-
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda/inline-parity/same_names.move:30:13
    │
 30 │         foo(|x, y| { assert!(x.len() + y.len() == 1, 1) }, x, y)
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing.lambda.exp
index 813306a5f3a94..6220c5ae1c85e 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing.lambda.exp
@@ -250,8 +250,12 @@ module 0x42::Test {
 
 
 Diagnostics:
-error: captured variable `_x` cannot be modified inside of a lambda
-   ┌─ tests/lambda/inline-parity/shadowing.move:12:13
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/shadowing.move:11:13
    │
-12 │             _x = y  // We expect this to assign 3 via foo if renaming works correctly. If not it would
-   │             ^^
+11 │           foo(|y| {
+   │ ╭─────────────^
+12 │ │             _x = y  // We expect this to assign 3 via foo if renaming works correctly. If not it would
+13 │ │                     // have the value 1.
+14 │ │         });
+   │ ╰─────────^
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed.lambda.exp
index 57fbdb400d002..80dc09bd1544b 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed.lambda.exp
@@ -250,8 +250,12 @@ module 0x42::Test {
 
 
 Diagnostics:
-error: captured variable `x` cannot be modified inside of a lambda
-   ┌─ tests/lambda/inline-parity/shadowing_renamed.move:12:13
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/shadowing_renamed.move:11:13
    │
-12 │             x = y  // We expect this to assign 3 via foo if renaming works correctly. If not it would
-   │             ^
+11 │           foo(|y| {
+   │ ╭─────────────^
+12 │ │             x = y  // We expect this to assign 3 via foo if renaming works correctly. If not it would
+13 │ │                     // have the value 1.
+14 │ │         });
+   │ ╰─────────^
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed_param.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed_param.lambda.exp
index bf8fa10008821..3b95647c560af 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed_param.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed_param.lambda.exp
@@ -561,26 +561,42 @@ module 0x42::Test {
 
 
 Diagnostics:
-error: captured variable `x` cannot be modified inside of a lambda
-   ┌─ tests/lambda/inline-parity/shadowing_renamed_param.move:15:13
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/shadowing_renamed_param.move:14:13
    │
-15 │             x = y  // We expect this to assign 3 via foo if renaming works correctly. If not it would
-   │             ^
+14 │           foo(|y| {
+   │ ╭─────────────^
+15 │ │             x = y  // We expect this to assign 3 via foo if renaming works correctly. If not it would
+16 │ │                     // have the value 1.
+17 │ │         }, 3);
+   │ ╰─────────^
 
-error: captured variable `x` cannot be modified inside of a lambda
-   ┌─ tests/lambda/inline-parity/shadowing_renamed_param.move:21:13
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/shadowing_renamed_param.move:20:14
    │
-21 │             x = y  // We expect this to assign 3 via foo if renaming works correctly. If not it would
-   │             ^
+20 │           foo2(|y| {
+   │ ╭──────────────^
+21 │ │             x = y  // We expect this to assign 3 via foo if renaming works correctly. If not it would
+22 │ │                     // have the value 1.
+23 │ │         }, 5);
+   │ ╰─────────^
 
-error: captured variable `x` cannot be modified inside of a lambda
-   ┌─ tests/lambda/inline-parity/shadowing_renamed_param.move:30:13
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/shadowing_renamed_param.move:29:13
    │
-30 │             x = y  // We expect this to assign 3 via foo if renaming works correctly. If not it would
-   │             ^
+29 │           foo(|y| {
+   │ ╭─────────────^
+30 │ │             x = y  // We expect this to assign 3 via foo if renaming works correctly. If not it would
+31 │ │                     // have the value 1.
+32 │ │         }, 3);
+   │ ╰─────────^
 
-error: captured variable `x` cannot be modified inside of a lambda
-   ┌─ tests/lambda/inline-parity/shadowing_renamed_param.move:36:13
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/shadowing_renamed_param.move:35:14
    │
-36 │             x = y  // We expect this to assign 3 via foo if renaming works correctly. If not it would
-   │             ^
+35 │           foo2(|y| {
+   │ ╭──────────────^
+36 │ │             x = y  // We expect this to assign 3 via foo if renaming works correctly. If not it would
+37 │ │                     // have the value 1.
+38 │ │         }, 5);
+   │ ╰─────────^
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused.lambda.exp
index 7c4b85b3b4291..227fec78406e9 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused.lambda.exp
@@ -505,14 +505,28 @@ module 0x42::Test {
 
 
 Diagnostics:
-error: captured variable `_x` cannot be modified inside of a lambda
-   ┌─ tests/lambda/inline-parity/shadowing_unused.move:18:13
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/shadowing_unused.move:11:14
    │
-18 │             _x = y  // We expect this to assign 3 via foo if renaming works correctly. If not it would
-   │             ^^
+11 │         quux(|a, b| f(a, b), z);
+   │              ^^^^^^^^^^^^^^
 
-error: captured variable `_x` cannot be modified inside of a lambda
-   ┌─ tests/lambda/inline-parity/shadowing_unused.move:28:13
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/shadowing_unused.move:17:13
    │
-28 │             _x = y  // We expect this to assign 3 via foo if renaming works correctly. If not it would
-   │             ^^
+17 │           foo(|y, _q| {
+   │ ╭─────────────^
+18 │ │             _x = y  // We expect this to assign 3 via foo if renaming works correctly. If not it would
+19 │ │                     // have the value 1.
+20 │ │         }, z);
+   │ ╰─────────^
+
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/shadowing_unused.move:27:14
+   │
+27 │           quux(|y, _q| {
+   │ ╭──────────────^
+28 │ │             _x = y  // We expect this to assign 3 via foo if renaming works correctly. If not it would
+29 │ │                     // have the value 1.
+30 │ │         }, z);
+   │ ╰─────────^
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused_nodecl.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused_nodecl.lambda.exp
index ccbae64fbd2f7..e2abb7639d5de 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused_nodecl.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused_nodecl.lambda.exp
@@ -511,14 +511,28 @@ warning: Unused parameter `z`. Consider removing or prefixing with an underscore
 6 │     public fun quux(f:|u64, u64|, z: u64) {
   │                                   ^
 
-error: captured variable `_x` cannot be modified inside of a lambda
-   ┌─ tests/lambda/inline-parity/shadowing_unused_nodecl.move:20:13
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/shadowing_unused_nodecl.move:13:14
    │
-20 │             _x = y  // We expect this to assign 3 via foo if renaming works correctly. If not it would
-   │             ^^
+13 │         quux(|a, b| f(a, b), z);
+   │              ^^^^^^^^^^^^^^
 
-error: captured variable `_x` cannot be modified inside of a lambda
-   ┌─ tests/lambda/inline-parity/shadowing_unused_nodecl.move:30:13
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/shadowing_unused_nodecl.move:19:13
    │
-30 │             _x = y  // We expect this to assign 3 via foo if renaming works correctly. If not it would
-   │             ^^
+19 │           foo(|y, _q| {
+   │ ╭─────────────^
+20 │ │             _x = y  // We expect this to assign 3 via foo if renaming works correctly. If not it would
+21 │ │                     // have the value 1.
+22 │ │         }, z);
+   │ ╰─────────^
+
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/shadowing_unused_nodecl.move:29:14
+   │
+29 │           quux(|y, _q| {
+   │ ╭──────────────^
+30 │ │             _x = y  // We expect this to assign 3 via foo if renaming works correctly. If not it would
+31 │ │                     // have the value 1.
+32 │ │         }, z);
+   │ ╰─────────^
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/simple_map_keys.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/simple_map_keys.lambda.exp
index 90288bcbca57e..3085fc6816985 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/simple_map_keys.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/simple_map_keys.lambda.exp
@@ -682,8 +682,18 @@ module 0x42::simple_map {
 
 
 Diagnostics:
-error: captured variable `result` cannot be modified inside of a lambda
-   ┌─ tests/lambda/inline-parity/simple_map_keys.move:28:55
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/simple_map_keys.move:17:28
+   │
+17 │           map_ref(&map.data, |e| {
+   │ ╭────────────────────────────^
+18 │ │             let e: &Element<Key, Value> = e;
+19 │ │             e.key
+20 │ │         })
+   │ ╰─────────^
+
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+   ┌─ tests/lambda/inline-parity/simple_map_keys.move:28:25
    │
 28 │         for_each_ref(v, |elem| vector::push_back(&mut result, f(elem)));
-   │                                                       ^^^^^^
+   │                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/spec_inlining.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/spec_inlining.lambda.exp
index 82da96e292c71..53b72c72daafa 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/spec_inlining.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/spec_inlining.lambda.exp
@@ -427,156 +427,15 @@ module 0x42::Test {
 } // end 0x42::Test
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0x42::Test {
-    private fun apply(v: u64,predicate: |u64|bool): bool {
-        spec {
-          assert Ge($t0, 0);
-        }
-        ;
-        (predicate)(v)
-    }
-    public fun test_apply(x: u64) {
-        {
-          let r1: bool = Test::apply(x, closure Test::test_apply$lambda$1());
-          spec {
-            assert r1;
-          }
-          ;
-          if r1 {
-            Tuple()
-          } else {
-            Abort(1)
-          };
-          {
-            let r2: bool = Test::apply(x, closure Test::test_apply$lambda$2());
-            spec {
-              assert r2;
-            }
-            ;
-            if r2 {
-              Tuple()
-            } else {
-              Abort(2)
-            };
-            Tuple()
-          }
-        }
-    }
-    private fun test_apply$lambda$1(v: u64): bool {
-        Ge<u64>(v, 0)
-    }
-    private fun test_apply$lambda$2(v: u64): bool {
-        Neq<u64>(v, 0)
-    }
-} // end 0x42::Test
-
-
-// -- Model dump after env processor specification checker:
-module 0x42::Test {
-    private fun apply(v: u64,predicate: |u64|bool): bool {
-        spec {
-          assert Ge($t0, 0);
-        }
-        ;
-        (predicate)(v)
-    }
-    public fun test_apply(x: u64) {
-        {
-          let r1: bool = Test::apply(x, closure Test::test_apply$lambda$1());
-          spec {
-            assert r1;
-          }
-          ;
-          if r1 {
-            Tuple()
-          } else {
-            Abort(1)
-          };
-          {
-            let r2: bool = Test::apply(x, closure Test::test_apply$lambda$2());
-            spec {
-              assert r2;
-            }
-            ;
-            if r2 {
-              Tuple()
-            } else {
-              Abort(2)
-            };
-            Tuple()
-          }
-        }
-    }
-    private fun test_apply$lambda$1(v: u64): bool {
-        Ge<u64>(v, 0)
-    }
-    private fun test_apply$lambda$2(v: u64): bool {
-        Neq<u64>(v, 0)
-    }
-} // end 0x42::Test
-
-
-// -- Model dump after env processor specification rewriter:
-module 0x42::Test {
-    private fun apply(v: u64,predicate: |u64|bool): bool {
-        spec {
-          assert Ge($t0, 0);
-        }
-        ;
-        (predicate)(v)
-    }
-    public fun test_apply(x: u64) {
-        {
-          let r1: bool = Test::apply(x, closure Test::test_apply$lambda$1());
-          spec {
-            assert r1;
-          }
-          ;
-          if r1 {
-            Tuple()
-          } else {
-            Abort(1)
-          };
-          {
-            let r2: bool = Test::apply(x, closure Test::test_apply$lambda$2());
-            spec {
-              assert r2;
-            }
-            ;
-            if r2 {
-              Tuple()
-            } else {
-              Abort(2)
-            };
-            Tuple()
-          }
-        }
-    }
-    private fun test_apply$lambda$1(v: u64): bool {
-        Ge<u64>(v, 0)
-    }
-    private fun test_apply$lambda$2(v: u64): bool {
-        Neq<u64>(v, 0)
-    }
-} // end 0x42::Test
-
-
 
 Diagnostics:
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda/inline-parity/spec_inlining.move:6:9
-  │
-6 │         predicate(v)
-  │         ^^^^^^^^^
-
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda/inline-parity/spec_inlining.move:10:27
    │
 10 │         let r1 = apply(x, |v| v >= 0);
    │                           ^^^^^^^^^^
 
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda/inline-parity/spec_inlining.move:16:27
    │
 16 │         let r2 = apply(x, |v| v != 0);
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/subtype_args.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/subtype_args.lambda.exp
index 51316f7cd9c17..13fdcad48d3be 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/subtype_args.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/subtype_args.lambda.exp
@@ -536,10 +536,10 @@ error: Calls to function values other than inline function parameters not yet su
    ┌─ tests/lambda/inline-parity/subtype_args.move:24:9
    │
 24 │         f(&mut 0, &mut 0);
-   │         ^
+   │         ^^^^^^^^^^^^^^^^^
 
 error: Calls to function values other than inline function parameters not yet supported
    ┌─ tests/lambda/inline-parity/subtype_args.move:25:9
    │
 25 │         f(&0, &mut 0);
-   │         ^
+   │         ^^^^^^^^^^^^^
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unnecessary_numerical_extreme_comparisons_warn.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unnecessary_numerical_extreme_comparisons_warn.lambda.exp
index 2506246844937..57b8fafd070d9 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unnecessary_numerical_extreme_comparisons_warn.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unnecessary_numerical_extreme_comparisons_warn.lambda.exp
@@ -1395,405 +1395,9 @@ module 0xc0ffee::no_warn {
 } // end 0xc0ffee::no_warn
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0xc0ffee::m {
-    private fun apply(f: |u8|bool,x: u8): bool {
-        (f)(x)
-    }
-    private fun bar() {
-        Tuple()
-    }
-    private fun foo<T>(x: T): T {
-        x
-    }
-    public fun test1(x: u8) {
-        if Gt<u8>(Add<u8>(x, 1), 255) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        Tuple()
-    }
-    public fun test2(x: &u8,y: &u8) {
-        if Eq<bool>(Gt<u8>(Add<u8>(Deref(x), Deref(y)), 255), true) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        Tuple()
-    }
-    public fun test3(x: u8) {
-        if Or(Lt<u8>(x, 0), Gt<u8>(0, x)) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Le<u8>(m::foo<u8>(x), 0) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Ge<u8>(0, m::foo<u8>(x)) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Gt<u8>(m::foo<u8>(x), 0) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Lt<u8>(0, m::foo<u8>(x)) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Ge<u8>(m::foo<u8>(x), 0) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Le<u8>(0, m::foo<u8>(x)) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        Tuple()
-    }
-    public fun test4(a: u8,b: u16,c: u32,d: u64,e: u128,f: u256) {
-        if Or(Gt<u8>(a, 255), Gt<u256>(f, 255)) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Ge<u16>(b, 65535) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Lt<u32>(4294967295, c) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Le<u64>(18446744073709551615, d) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Lt<u128>(e, 340282366920938463463374607431768211455) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Le<u256>(f, 115792089237316195423570985008687907853269984665640564039457584007913129639935) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Ge<u256>(115792089237316195423570985008687907853269984665640564039457584007913129639935, f) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Gt<u128>(340282366920938463463374607431768211455, e) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        spec {
-          assert Le($t0, 255);
-        }
-
-    }
-    public fun test5(x: u8): bool {
-        m::apply(closure m::test5$lambda$1(), x)
-    }
-    private fun test5$lambda$1(x: u8): bool {
-        Gt<u8>(x, 255)
-    }
-} // end 0xc0ffee::m
-module 0xc0ffee::no_warn {
-    public fun test(x: u8) {
-        if Lt<u8>(x, 0) {
-          Abort(1)
-        } else {
-          Tuple()
-        };
-        Tuple()
-    }
-} // end 0xc0ffee::no_warn
-
-
-// -- Model dump after env processor specification checker:
-module 0xc0ffee::m {
-    private fun apply(f: |u8|bool,x: u8): bool {
-        (f)(x)
-    }
-    private fun bar() {
-        Tuple()
-    }
-    private fun foo<T>(x: T): T {
-        x
-    }
-    public fun test1(x: u8) {
-        if Gt<u8>(Add<u8>(x, 1), 255) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        Tuple()
-    }
-    public fun test2(x: &u8,y: &u8) {
-        if Eq<bool>(Gt<u8>(Add<u8>(Deref(x), Deref(y)), 255), true) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        Tuple()
-    }
-    public fun test3(x: u8) {
-        if Or(Lt<u8>(x, 0), Gt<u8>(0, x)) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Le<u8>(m::foo<u8>(x), 0) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Ge<u8>(0, m::foo<u8>(x)) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Gt<u8>(m::foo<u8>(x), 0) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Lt<u8>(0, m::foo<u8>(x)) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Ge<u8>(m::foo<u8>(x), 0) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Le<u8>(0, m::foo<u8>(x)) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        Tuple()
-    }
-    public fun test4(a: u8,b: u16,c: u32,d: u64,e: u128,f: u256) {
-        if Or(Gt<u8>(a, 255), Gt<u256>(f, 255)) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Ge<u16>(b, 65535) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Lt<u32>(4294967295, c) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Le<u64>(18446744073709551615, d) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Lt<u128>(e, 340282366920938463463374607431768211455) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Le<u256>(f, 115792089237316195423570985008687907853269984665640564039457584007913129639935) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Ge<u256>(115792089237316195423570985008687907853269984665640564039457584007913129639935, f) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Gt<u128>(340282366920938463463374607431768211455, e) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        spec {
-          assert Le($t0, 255);
-        }
-
-    }
-    public fun test5(x: u8): bool {
-        m::apply(closure m::test5$lambda$1(), x)
-    }
-    private fun test5$lambda$1(x: u8): bool {
-        Gt<u8>(x, 255)
-    }
-} // end 0xc0ffee::m
-module 0xc0ffee::no_warn {
-    public fun test(x: u8) {
-        if Lt<u8>(x, 0) {
-          Abort(1)
-        } else {
-          Tuple()
-        };
-        Tuple()
-    }
-} // end 0xc0ffee::no_warn
-
-
-// -- Model dump after env processor specification rewriter:
-module 0xc0ffee::m {
-    private fun apply(f: |u8|bool,x: u8): bool {
-        (f)(x)
-    }
-    private fun bar() {
-        Tuple()
-    }
-    private fun foo<T>(x: T): T {
-        x
-    }
-    public fun test1(x: u8) {
-        if Gt<u8>(Add<u8>(x, 1), 255) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        Tuple()
-    }
-    public fun test2(x: &u8,y: &u8) {
-        if Eq<bool>(Gt<u8>(Add<u8>(Deref(x), Deref(y)), 255), true) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        Tuple()
-    }
-    public fun test3(x: u8) {
-        if Or(Lt<u8>(x, 0), Gt<u8>(0, x)) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Le<u8>(m::foo<u8>(x), 0) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Ge<u8>(0, m::foo<u8>(x)) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Gt<u8>(m::foo<u8>(x), 0) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Lt<u8>(0, m::foo<u8>(x)) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Ge<u8>(m::foo<u8>(x), 0) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Le<u8>(0, m::foo<u8>(x)) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        Tuple()
-    }
-    public fun test4(a: u8,b: u16,c: u32,d: u64,e: u128,f: u256) {
-        if Or(Gt<u8>(a, 255), Gt<u256>(f, 255)) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Ge<u16>(b, 65535) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Lt<u32>(4294967295, c) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Le<u64>(18446744073709551615, d) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Lt<u128>(e, 340282366920938463463374607431768211455) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Le<u256>(f, 115792089237316195423570985008687907853269984665640564039457584007913129639935) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Ge<u256>(115792089237316195423570985008687907853269984665640564039457584007913129639935, f) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        if Gt<u128>(340282366920938463463374607431768211455, e) {
-          m::bar()
-        } else {
-          Tuple()
-        };
-        spec {
-          assert Le($t0, 255);
-        }
-
-    }
-    public fun test5(x: u8): bool {
-        m::apply(closure m::test5$lambda$1(), x)
-    }
-    private fun test5$lambda$1(x: u8): bool {
-        Gt<u8>(x, 255)
-    }
-} // end 0xc0ffee::m
-module 0xc0ffee::no_warn {
-    public fun test(x: u8) {
-        if Lt<u8>(x, 0) {
-          Abort(1)
-        } else {
-          Tuple()
-        };
-        Tuple()
-    }
-} // end 0xc0ffee::no_warn
-
-
 
 Diagnostics:
-error: Calls to function values other than inline function parameters not yet supported
-   ┌─ tests/lambda/inline-parity/unnecessary_numerical_extreme_comparisons_warn.move:50:9
-   │
-50 │         f(x)
-   │         ^
-
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda/inline-parity/unnecessary_numerical_extreme_comparisons_warn.move:54:15
    │
 54 │         apply(|x| x > U8_MAX, x)
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unpack_generic_struct.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unpack_generic_struct.lambda.exp
index 2bdecc21d6698..ccb4d76ab98ae 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unpack_generic_struct.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unpack_generic_struct.lambda.exp
@@ -504,177 +504,9 @@ module 0x42::m {
 } // end 0x42::m
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0x42::m {
-    use std::vector;
-    struct E<Key> {
-        key: Key,
-    }
-    struct Option<Element> {
-        vec: vector<Element>,
-    }
-    public fun destroy_none<Element>(t: Option<Element>) {
-        if m::is_none<Element>(Borrow(Immutable)(t)) {
-          Tuple()
-        } else {
-          Abort(262144)
-        };
-        {
-          let m::Option<Element>{ vec } = t;
-          vector::destroy_empty<Element>(vec)
-        }
-    }
-    public fun foo<Key>(data: E<Key>,v: &mut Key) {
-        {
-          let f: E<Key> = m::h<Key>(data, closure m::foo$lambda$1());
-          m::g<Key>(f, closure m::foo$lambda$2(v));
-          Tuple()
-        }
-    }
-    public fun g<Key>(x: E<Key>,v: |E<Key>|) {
-        (v)(x)
-    }
-    public fun h<Key>(x: E<Key>,v: |Key|E<Key>): E<Key> {
-        {
-          let m::E<Key>{ key } = x;
-          (v)(key)
-        }
-    }
-    public fun is_none<Element>(t: &Option<Element>): bool {
-        vector::is_empty<Element>(Borrow(Immutable)(select m::Option.vec<&Option<Element>>(t)))
-    }
-    private fun foo$lambda$1<Key>(e: Key): E<Key> {
-        pack m::E<Key>(e)
-    }
-    private fun foo$lambda$2<Key>(v: &mut Key,e: E<Key>) {
-        {
-          let (m::E<Key>{ key }, _x: u64): (E<Key>, u64) = Tuple(e, 3);
-          v = key;
-          Tuple()
-        }
-    }
-} // end 0x42::m
-
-
-// -- Model dump after env processor specification checker:
-module 0x42::m {
-    use std::vector;
-    struct E<Key> {
-        key: Key,
-    }
-    struct Option<Element> {
-        vec: vector<Element>,
-    }
-    public fun destroy_none<Element>(t: Option<Element>) {
-        if m::is_none<Element>(Borrow(Immutable)(t)) {
-          Tuple()
-        } else {
-          Abort(262144)
-        };
-        {
-          let m::Option<Element>{ vec } = t;
-          vector::destroy_empty<Element>(vec)
-        }
-    }
-    public fun foo<Key>(data: E<Key>,v: &mut Key) {
-        {
-          let f: E<Key> = m::h<Key>(data, closure m::foo$lambda$1());
-          m::g<Key>(f, closure m::foo$lambda$2(v));
-          Tuple()
-        }
-    }
-    public fun g<Key>(x: E<Key>,v: |E<Key>|) {
-        (v)(x)
-    }
-    public fun h<Key>(x: E<Key>,v: |Key|E<Key>): E<Key> {
-        {
-          let m::E<Key>{ key } = x;
-          (v)(key)
-        }
-    }
-    public fun is_none<Element>(t: &Option<Element>): bool {
-        vector::is_empty<Element>(Borrow(Immutable)(select m::Option.vec<&Option<Element>>(t)))
-    }
-    private fun foo$lambda$1<Key>(e: Key): E<Key> {
-        pack m::E<Key>(e)
-    }
-    private fun foo$lambda$2<Key>(v: &mut Key,e: E<Key>) {
-        {
-          let (m::E<Key>{ key }, _x: u64): (E<Key>, u64) = Tuple(e, 3);
-          v = key;
-          Tuple()
-        }
-    }
-} // end 0x42::m
-
-
-// -- Model dump after env processor specification rewriter:
-module 0x42::m {
-    use std::vector;
-    struct E<Key> {
-        key: Key,
-    }
-    struct Option<Element> {
-        vec: vector<Element>,
-    }
-    public fun destroy_none<Element>(t: Option<Element>) {
-        if m::is_none<Element>(Borrow(Immutable)(t)) {
-          Tuple()
-        } else {
-          Abort(262144)
-        };
-        {
-          let m::Option<Element>{ vec } = t;
-          vector::destroy_empty<Element>(vec)
-        }
-    }
-    public fun foo<Key>(data: E<Key>,v: &mut Key) {
-        {
-          let f: E<Key> = m::h<Key>(data, closure m::foo$lambda$1());
-          m::g<Key>(f, closure m::foo$lambda$2(v));
-          Tuple()
-        }
-    }
-    public fun g<Key>(x: E<Key>,v: |E<Key>|) {
-        (v)(x)
-    }
-    public fun h<Key>(x: E<Key>,v: |Key|E<Key>): E<Key> {
-        {
-          let m::E<Key>{ key } = x;
-          (v)(key)
-        }
-    }
-    public fun is_none<Element>(t: &Option<Element>): bool {
-        vector::is_empty<Element>(Borrow(Immutable)(select m::Option.vec<&Option<Element>>(t)))
-    }
-    private fun foo$lambda$1<Key>(e: Key): E<Key> {
-        pack m::E<Key>(e)
-    }
-    private fun foo$lambda$2<Key>(v: &mut Key,e: E<Key>) {
-        {
-          let (m::E<Key>{ key }, _x: u64): (E<Key>, u64) = Tuple(e, 3);
-          v = key;
-          Tuple()
-        }
-    }
-} // end 0x42::m
-
-
 
 Diagnostics:
-error: Calls to function values other than inline function parameters not yet supported
-   ┌─ tests/lambda/inline-parity/unpack_generic_struct.move:24:9
-   │
-24 │         v(key)
-   │         ^
-
-error: Calls to function values other than inline function parameters not yet supported
-   ┌─ tests/lambda/inline-parity/unpack_generic_struct.move:28:9
-   │
-28 │         v(x)
-   │         ^
-
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda/inline-parity/unpack_generic_struct.move:33:25
    │
 33 │           let f = h(data, |e| {
@@ -683,7 +515,7 @@ error: Function-typed values not yet supported except as parameters to calls to
 35 │ │         });
    │ ╰─────────^
 
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda/inline-parity/unpack_generic_struct.move:36:14
    │
 36 │           g(f, |e| {
diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unused_lambda_param.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unused_lambda_param.lambda.exp
index a720df7124c63..5843e39307da4 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unused_lambda_param.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unused_lambda_param.lambda.exp
@@ -218,102 +218,6 @@ module 0xc0ffee::m {
 } // end 0xc0ffee::m
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0xc0ffee::m {
-    private fun test(p: u64,f: |u64|u64): u64 {
-        (f)(p)
-    }
-    private fun unused_lambda() {
-        m::test(0, closure m::unused_lambda$lambda$1());
-        Tuple()
-    }
-    private fun unused_lambda_suppressed1() {
-        m::test(0, closure m::unused_lambda_suppressed1$lambda$1());
-        Tuple()
-    }
-    private fun unused_lambda_suppressed2() {
-        m::test(0, closure m::unused_lambda_suppressed2$lambda$1());
-        Tuple()
-    }
-    private fun unused_lambda$lambda$1(x: u64): u64 {
-        1
-    }
-    private fun unused_lambda_suppressed1$lambda$1(_x: u64): u64 {
-        1
-    }
-    private fun unused_lambda_suppressed2$lambda$1(param$0: u64): u64 {
-        {
-          let _: u64 = param$0;
-          1
-        }
-    }
-} // end 0xc0ffee::m
-
-
-// -- Model dump after env processor specification checker:
-module 0xc0ffee::m {
-    private fun test(p: u64,f: |u64|u64): u64 {
-        (f)(p)
-    }
-    private fun unused_lambda() {
-        m::test(0, closure m::unused_lambda$lambda$1());
-        Tuple()
-    }
-    private fun unused_lambda_suppressed1() {
-        m::test(0, closure m::unused_lambda_suppressed1$lambda$1());
-        Tuple()
-    }
-    private fun unused_lambda_suppressed2() {
-        m::test(0, closure m::unused_lambda_suppressed2$lambda$1());
-        Tuple()
-    }
-    private fun unused_lambda$lambda$1(x: u64): u64 {
-        1
-    }
-    private fun unused_lambda_suppressed1$lambda$1(_x: u64): u64 {
-        1
-    }
-    private fun unused_lambda_suppressed2$lambda$1(param$0: u64): u64 {
-        {
-          let _: u64 = param$0;
-          1
-        }
-    }
-} // end 0xc0ffee::m
-
-
-// -- Model dump after env processor specification rewriter:
-module 0xc0ffee::m {
-    private fun test(p: u64,f: |u64|u64): u64 {
-        (f)(p)
-    }
-    private fun unused_lambda() {
-        m::test(0, closure m::unused_lambda$lambda$1());
-        Tuple()
-    }
-    private fun unused_lambda_suppressed1() {
-        m::test(0, closure m::unused_lambda_suppressed1$lambda$1());
-        Tuple()
-    }
-    private fun unused_lambda_suppressed2() {
-        m::test(0, closure m::unused_lambda_suppressed2$lambda$1());
-        Tuple()
-    }
-    private fun unused_lambda$lambda$1(x: u64): u64 {
-        1
-    }
-    private fun unused_lambda_suppressed1$lambda$1(_x: u64): u64 {
-        1
-    }
-    private fun unused_lambda_suppressed2$lambda$1(param$0: u64): u64 {
-        {
-          let _: u64 = param$0;
-          1
-        }
-    }
-} // end 0xc0ffee::m
-
-
 
 Diagnostics:
 warning: Unused anonymous function parameter `x`. Consider removing or prefixing with an underscore: `_x`
@@ -322,27 +226,19 @@ warning: Unused anonymous function parameter `x`. Consider removing or prefixing
 7 │         test(0, |x| 1);
   │                  ^
 
-
-Diagnostics:
-error: Calls to function values other than inline function parameters not yet supported
-  ┌─ tests/lambda/inline-parity/unused_lambda_param.move:3:9
-  │
-3 │         f(p)
-  │         ^
-
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
   ┌─ tests/lambda/inline-parity/unused_lambda_param.move:7:17
   │
 7 │         test(0, |x| 1);
   │                 ^^^^^
 
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda/inline-parity/unused_lambda_param.move:11:17
    │
 11 │         test(0, |_x| 1);
    │                 ^^^^^^
 
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda/inline-parity/unused_lambda_param.move:15:17
    │
 15 │         test(0, |_| 1);
diff --git a/third_party/move/move-compiler-v2/tests/lambda/lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/lambda.exp
index 4f17028adb675..7328ae7924537 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/lambda.exp
@@ -24,7 +24,7 @@ error: cannot use `()` with an operator which expects a value of type `u64`
 56 │             i = i + action(XVector::borrow(v, i)); // expected to have wrong result type
    │                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: cannot return `u64` from a function with result type `|integer|`
+error: cannot return `u64` from a function with result type `|integer| with copy+store`
    ┌─ tests/lambda/lambda.move:61:9
    │
 61 │         x(1) // expected to be not a function
diff --git a/third_party/move/move-compiler-v2/tests/lambda/lambda.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/lambda.lambda.exp
index 4f17028adb675..7328ae7924537 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/lambda.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/lambda.lambda.exp
@@ -24,7 +24,7 @@ error: cannot use `()` with an operator which expects a value of type `u64`
 56 │             i = i + action(XVector::borrow(v, i)); // expected to have wrong result type
    │                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: cannot return `u64` from a function with result type `|integer|`
+error: cannot return `u64` from a function with result type `|integer| with copy+store`
    ┌─ tests/lambda/lambda.move:61:9
    │
 61 │         x(1) // expected to be not a function
diff --git a/third_party/move/move-compiler-v2/tests/lambda/lambda3.exp b/third_party/move/move-compiler-v2/tests/lambda/lambda3.exp
index b7104b3811ed1..9eb746fa166b1 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/lambda3.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/lambda3.exp
@@ -2,7 +2,7 @@
 module 0x8675309::M {
     public fun lambda_not_allowed() {
         {
-          let _x: |u64|u64 = |i: u64| Add<u64>(i, 1);
+          let _x: |u64|u64 with copy+store = |i: u64| Add<u64>(i, 1);
           Tuple()
         }
     }
diff --git a/third_party/move/move-compiler-v2/tests/lambda/lambda3.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/lambda3.lambda.exp
index db9ce1b64dc58..cca732666e1ef 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/lambda3.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/lambda3.lambda.exp
@@ -2,7 +2,7 @@
 module 0x8675309::M {
     public fun lambda_not_allowed() {
         {
-          let _x: |u64|u64 = |i: u64| Add<u64>(i, 1);
+          let _x: |u64|u64 with copy+store = |i: u64| Add<u64>(i, 1);
           Tuple()
         }
     }
@@ -13,7 +13,7 @@ module 0x8675309::M {
 module 0x8675309::M {
     public fun lambda_not_allowed() {
         {
-          let _x: |u64|u64 = |i: u64| Add<u64>(i, 1);
+          let _x: |u64|u64 with copy+store = |i: u64| Add<u64>(i, 1);
           Tuple()
         }
     }
@@ -24,7 +24,7 @@ module 0x8675309::M {
 module 0x8675309::M {
     public fun lambda_not_allowed() {
         {
-          let _x: |u64|u64 = |i: u64| Add<u64>(i, 1);
+          let _x: |u64|u64 with copy+store = |i: u64| Add<u64>(i, 1);
           Tuple()
         }
     }
@@ -35,7 +35,7 @@ module 0x8675309::M {
 module 0x8675309::M {
     public fun lambda_not_allowed() {
         {
-          let _x: |u64|u64 = |i: u64| Add<u64>(i, 1);
+          let _x: |u64|u64 with copy+store = |i: u64| Add<u64>(i, 1);
           Tuple()
         }
     }
@@ -46,7 +46,7 @@ module 0x8675309::M {
 module 0x8675309::M {
     public fun lambda_not_allowed() {
         {
-          let _x: |u64|u64 = |i: u64| Add<u64>(i, 1);
+          let _x: |u64|u64 with copy+store = |i: u64| Add<u64>(i, 1);
           Tuple()
         }
     }
@@ -57,7 +57,7 @@ module 0x8675309::M {
 module 0x8675309::M {
     public fun lambda_not_allowed() {
         {
-          let _x: |u64|u64 = |i: u64| Add<u64>(i, 1);
+          let _x: |u64|u64 with copy+store = |i: u64| Add<u64>(i, 1);
           Tuple()
         }
     }
@@ -68,7 +68,7 @@ module 0x8675309::M {
 module 0x8675309::M {
     public fun lambda_not_allowed() {
         {
-          let _x: |u64|u64 = |i: u64| Add<u64>(i, 1);
+          let _x: |u64|u64 with copy+store = |i: u64| Add<u64>(i, 1);
           Tuple()
         }
     }
@@ -79,7 +79,7 @@ module 0x8675309::M {
 module 0x8675309::M {
     public fun lambda_not_allowed() {
         {
-          let _x: |u64|u64 = |i: u64| Add<u64>(i, 1);
+          let _x: |u64|u64 with copy+store = |i: u64| Add<u64>(i, 1);
           Tuple()
         }
     }
@@ -90,7 +90,7 @@ module 0x8675309::M {
 module 0x8675309::M {
     public fun lambda_not_allowed() {
         {
-          let _x: |u64|u64 = |i: u64| Add<u64>(i, 1);
+          let _x: |u64|u64 with copy+store = |i: u64| Add<u64>(i, 1);
           Tuple()
         }
     }
@@ -101,7 +101,7 @@ module 0x8675309::M {
 module 0x8675309::M {
     public fun lambda_not_allowed() {
         {
-          let _x: |u64|u64 = |i: u64| Add<u64>(i, 1);
+          let _x: |u64|u64 with copy+store = |i: u64| Add<u64>(i, 1);
           Tuple()
         }
     }
@@ -112,58 +112,16 @@ module 0x8675309::M {
 module 0x8675309::M {
     public fun lambda_not_allowed() {
         {
-          let _x: |u64|u64 = |i: u64| Add<u64>(i, 1);
+          let _x: |u64|u64 with copy+store = |i: u64| Add<u64>(i, 1);
           Tuple()
         }
     }
 } // end 0x8675309::M
 
 
-// -- Model dump after env processor lambda-lifting:
-module 0x8675309::M {
-    public fun lambda_not_allowed() {
-        {
-          let _x: |u64|u64 = closure M::lambda_not_allowed$lambda$1();
-          Tuple()
-        }
-    }
-    private fun lambda_not_allowed$lambda$1(i: u64): u64 {
-        Add<u64>(i, 1)
-    }
-} // end 0x8675309::M
-
-
-// -- Model dump after env processor specification checker:
-module 0x8675309::M {
-    public fun lambda_not_allowed() {
-        {
-          let _x: |u64|u64 = closure M::lambda_not_allowed$lambda$1();
-          Tuple()
-        }
-    }
-    private fun lambda_not_allowed$lambda$1(i: u64): u64 {
-        Add<u64>(i, 1)
-    }
-} // end 0x8675309::M
-
-
-// -- Model dump after env processor specification rewriter:
-module 0x8675309::M {
-    public fun lambda_not_allowed() {
-        {
-          let _x: |u64|u64 = closure M::lambda_not_allowed$lambda$1();
-          Tuple()
-        }
-    }
-    private fun lambda_not_allowed$lambda$1(i: u64): u64 {
-        Add<u64>(i, 1)
-    }
-} // end 0x8675309::M
-
-
 
 Diagnostics:
-error: Function-typed values not yet supported except as parameters to calls to inline functions
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
    ┌─ tests/lambda/lambda3.move:77:18
    │
 77 │         let _x = |i| i + 1; // expected lambda not allowed
diff --git a/third_party/move/move-compiler-v2/tests/lambda/non_lambda_arg.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/non_lambda_arg.lambda.exp
index 0a35235798063..8949035e6a9d3 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/non_lambda_arg.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/non_lambda_arg.lambda.exp
@@ -404,13 +404,3 @@ error: local `a_less_b` of type `|(T, T)|bool` does not have the `copy` ability
    │             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ copy needed here because value is still in use
 13 │             incorrect_sort_recursive(arr, pi + 1, high, a_less_b);
    │             ----------------------------------------------------- used here
-
-error: local `a_less_b` of type `|(T, T)|bool` does not have the `drop` ability
-   ┌─ tests/lambda/non_lambda_arg.move:10:9
-   │
-10 │ ╭         if (low < high) {
-11 │ │             let pi = low + high / 2;
-12 │ │             incorrect_sort_recursive(arr, low, pi - 1, a_less_b);
-13 │ │             incorrect_sort_recursive(arr, pi + 1, high, a_less_b);
-14 │ │         };
-   │ ╰─────────^ implicitly dropped here since it is no longer used
diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/doable_func.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/doable_func.exp
new file mode 100644
index 0000000000000..bee6d7e4e76c2
--- /dev/null
+++ b/third_party/move/move-compiler-v2/tests/lambda/storable/doable_func.exp
@@ -0,0 +1,127 @@
+
+Diagnostics:
+error: unsupported language construct
+   ┌─ tests/lambda/storable/doable_func.move:43:17
+   │
+43 │                 move |x| mod3::multiply(4, x)
+   │                 ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/doable_func.move:46:17
+   │
+46 │                 move |y| alt_multiply(x, y)
+   │                 ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/doable_func.move:49:17
+   │
+49 │                 move |y| mod3::multiply(y, x)
+   │                 ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/doable_func.move:51:17
+   │
+51 │                 move |x| multiply3(x, 3, 2)
+   │                 ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/doable_func.move:53:17
+   │
+53 │                 move |x| mod3::multiply(x, 7)
+   │                 ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/doable_func.move:55:17
+   │
+55 │                 move |x| multiply3(4, x, 2)
+   │                 ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/doable_func.move:57:17
+   │
+57 │                 move |x| multiply3(3, 3, x)
+   │                 ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/doable_func.move:61:17
+   │
+61 │                 move |z| multiply3(x, y, z)
+   │                 ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/doable_func.move:64:17
+   │
+64 │                 move |x| alt_multiply(x, z) with copy
+   │                 ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/doable_func.move:64:45
+   │
+64 │                 move |x| alt_multiply(x, z) with copy
+   │                                             ^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/doable_func.move:66:25
+   │
+66 │                 let g = move |x, y| mod3::multiply(x, y) with copy+drop;
+   │                         ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/doable_func.move:66:58
+   │
+66 │                 let g = move |x, y| mod3::multiply(x, y) with copy+drop;
+   │                                                          ^^^^^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/doable_func.move:67:17
+   │
+67 │                 move |x| g(x, 11)
+   │                 ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/doable_func.move:69:25
+   │
+69 │                 let h = move |x| mod3::multiply(x, 12) with copy;
+   │                         ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/doable_func.move:69:56
+   │
+69 │                 let h = move |x| mod3::multiply(x, 12) with copy;
+   │                                                        ^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/doable_func.move:70:17
+   │
+70 │                 move |x| { h(x) } with copy + drop
+   │                 ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/doable_func.move:70:35
+   │
+70 │                 move |x| { h(x) } with copy + drop
+   │                                   ^^^^^^^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/doable_func.move:72:25
+   │
+72 │                 let i = move |x| multiply3(2, x, 2);
+   │                         ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/doable_func.move:73:17
+   │
+73 │                 move |z| i(z)
+   │                 ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/doable_func.move:75:25
+   │
+75 │                 let i = move |x, y| { let q = y - 1; 0x42::mod3::multiply(x, q + 1)  };
+   │                         ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/doable_func.move:76:17
+   │
+76 │                 move |x| i(x, 15)
+   │                 ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/doable_func.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/doable_func.lambda.exp
new file mode 100644
index 0000000000000..e39fd4deaeb18
--- /dev/null
+++ b/third_party/move/move-compiler-v2/tests/lambda/storable/doable_func.lambda.exp
@@ -0,0 +1,2465 @@
+// -- Model dump before env processor pipeline:
+module 0x42::mod4 {
+    public fun alt_multiply(x: u64,y: u64): u64 {
+        Mul<u64>(x, y)
+    }
+} // end 0x42::mod4
+module 0x42::mod3 {
+    public fun multiply(x: u64,y: u64): u64 {
+        Mul<u64>(x, y)
+    }
+} // end 0x42::mod3
+module 0x42::mod2 {
+    friend fun double(x: u64): u64 {
+        Mul<u64>(x, 2)
+    }
+} // end 0x42::mod2
+module 0x42::mod1 {
+    friend fun triple(x: u64): u64 {
+        Mul<u64>(x, 3)
+    }
+} // end 0x42::mod1
+module 0x42::test {
+    use 0x42::mod1; // resolved as: 0x42::mod1
+    use 0x42::mod2; // resolved as: 0x42::mod2
+    use 0x42::mod3; // resolved as: 0x42::mod3
+    use 0x42::mod4::{alt_multiply}; // resolved as: 0x42::mod4
+    private fun add_mul(x: u64,y: u64,z: u64): u64 {
+        Mul<u64>(z, Add<u64>(x, y))
+    }
+    private fun choose_function1(key: u64,x: u64): u64 {
+        {
+          let f: |u64|u64 with copy = if Eq<u64>(key, 0) {
+            mod2::double
+          } else {
+            if Eq<u64>(key, 1) {
+              mod1::triple
+            } else {
+              if Eq<u64>(key, 2) {
+                 move|x: u64| mod3::multiply(4, x)
+              } else {
+                if Eq<u64>(key, 3) {
+                  {
+                    let x: u64 = 5;
+                     move|y: u64| mod4::alt_multiply(x, y)
+                  }
+                } else {
+                  if Eq<u64>(key, 4) {
+                    {
+                      let x: u64 = 6;
+                       move|y: u64| mod3::multiply(y, x)
+                    }
+                  } else {
+                    if Eq<u64>(key, 5) {
+                       move|x: u64| test::multiply3(x, 3, 2)
+                    } else {
+                      if Eq<u64>(key, 6) {
+                         move|x: u64| mod3::multiply(x, 7)
+                      } else {
+                        if Eq<u64>(key, 7) {
+                           move|x: u64| test::multiply3(4, x, 2)
+                        } else {
+                          if Eq<u64>(key, 8) {
+                             move|x: u64| test::multiply3(3, 3, x)
+                          } else {
+                            if Eq<u64>(key, 9) {
+                              {
+                                let x: u64 = 2;
+                                {
+                                  let y: u64 = 5;
+                                   move|z: u64| test::multiply3(x, y, z)
+                                }
+                              }
+                            } else {
+                              if Eq<u64>(key, 10) {
+                                {
+                                  let z: u64 = 11;
+                                   move|x: u64| mod4::alt_multiply(x, z) with copy, drop
+                                }
+                              } else {
+                                if Eq<u64>(key, 11) {
+                                  {
+                                    let g: |(u64, u64)|u64 with copy+store =  move|(x: u64, y: u64): (u64, u64)| mod3::multiply(x, y) with copy, drop;
+                                     move|x: u64| (g)(x, 11)
+                                  }
+                                } else {
+                                  if Eq<u64>(key, 12) {
+                                    {
+                                      let h: |u64|u64 with copy+store =  move|x: u64| mod3::multiply(x, 12) with copy, drop;
+                                       move|x: u64| (h)(x) with copy, drop
+                                    }
+                                  } else {
+                                    if Eq<u64>(key, 14) {
+                                      {
+                                        let i: |u64|u64 with copy+store =  move|x: u64| test::multiply3(2, x, 2);
+                                         move|z: u64| (i)(z)
+                                      }
+                                    } else {
+                                      {
+                                        let i: |(u64, u64)|u64 with copy+store =  move|(x: u64, y: u64): (u64, u64)| {
+                                          let q: u64 = Sub<u64>(y, 1);
+                                          mod3::multiply(x, Add<u64>(q, 1))
+                                        };
+                                         move|x: u64| (i)(x, 15)
+                                      }
+                                    }
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          };
+          (f)(x)
+        }
+    }
+    private fun multiply3(x: u64,y: u64,z: u64): u64 {
+        Mul<u64>(Mul<u64>(x, y), z)
+    }
+    public fun test_functions() {
+        {
+          let x: u64 = 3;
+          {
+            let i: u64 = 0;
+            {
+              let __update_iter_flag: bool = false;
+              {
+                let __upper_bound_value: u64 = 15;
+                loop {
+                  if true {
+                    if __update_iter_flag {
+                      i: u64 = Add<u64>(i, 1)
+                    } else {
+                      __update_iter_flag: bool = true
+                    };
+                    if Lt<u64>(i, __upper_bound_value) {
+                      {
+                        let y: u64 = test::choose_function1(i, 3);
+                        if Eq<u64>(y, Mul<u64>(Add<u64>(i, 2), x)) {
+                          Tuple()
+                        } else {
+                          Abort(i)
+                        };
+                        Tuple()
+                      }
+                    } else {
+                      break
+                    };
+                    Tuple()
+                  } else {
+                    break
+                  }
+                };
+                Tuple()
+              }
+            }
+          }
+        }
+    }
+} // end 0x42::test
+
+
+// -- Model dump after env processor unused checks:
+module 0x42::mod4 {
+    public fun alt_multiply(x: u64,y: u64): u64 {
+        Mul<u64>(x, y)
+    }
+} // end 0x42::mod4
+module 0x42::mod3 {
+    public fun multiply(x: u64,y: u64): u64 {
+        Mul<u64>(x, y)
+    }
+} // end 0x42::mod3
+module 0x42::mod2 {
+    friend fun double(x: u64): u64 {
+        Mul<u64>(x, 2)
+    }
+} // end 0x42::mod2
+module 0x42::mod1 {
+    friend fun triple(x: u64): u64 {
+        Mul<u64>(x, 3)
+    }
+} // end 0x42::mod1
+module 0x42::test {
+    use 0x42::mod1; // resolved as: 0x42::mod1
+    use 0x42::mod2; // resolved as: 0x42::mod2
+    use 0x42::mod3; // resolved as: 0x42::mod3
+    use 0x42::mod4::{alt_multiply}; // resolved as: 0x42::mod4
+    private fun add_mul(x: u64,y: u64,z: u64): u64 {
+        Mul<u64>(z, Add<u64>(x, y))
+    }
+    private fun choose_function1(key: u64,x: u64): u64 {
+        {
+          let f: |u64|u64 with copy = if Eq<u64>(key, 0) {
+            mod2::double
+          } else {
+            if Eq<u64>(key, 1) {
+              mod1::triple
+            } else {
+              if Eq<u64>(key, 2) {
+                 move|x: u64| mod3::multiply(4, x)
+              } else {
+                if Eq<u64>(key, 3) {
+                  {
+                    let x: u64 = 5;
+                     move|y: u64| mod4::alt_multiply(x, y)
+                  }
+                } else {
+                  if Eq<u64>(key, 4) {
+                    {
+                      let x: u64 = 6;
+                       move|y: u64| mod3::multiply(y, x)
+                    }
+                  } else {
+                    if Eq<u64>(key, 5) {
+                       move|x: u64| test::multiply3(x, 3, 2)
+                    } else {
+                      if Eq<u64>(key, 6) {
+                         move|x: u64| mod3::multiply(x, 7)
+                      } else {
+                        if Eq<u64>(key, 7) {
+                           move|x: u64| test::multiply3(4, x, 2)
+                        } else {
+                          if Eq<u64>(key, 8) {
+                             move|x: u64| test::multiply3(3, 3, x)
+                          } else {
+                            if Eq<u64>(key, 9) {
+                              {
+                                let x: u64 = 2;
+                                {
+                                  let y: u64 = 5;
+                                   move|z: u64| test::multiply3(x, y, z)
+                                }
+                              }
+                            } else {
+                              if Eq<u64>(key, 10) {
+                                {
+                                  let z: u64 = 11;
+                                   move|x: u64| mod4::alt_multiply(x, z) with copy, drop
+                                }
+                              } else {
+                                if Eq<u64>(key, 11) {
+                                  {
+                                    let g: |(u64, u64)|u64 with copy+store =  move|(x: u64, y: u64): (u64, u64)| mod3::multiply(x, y) with copy, drop;
+                                     move|x: u64| (g)(x, 11)
+                                  }
+                                } else {
+                                  if Eq<u64>(key, 12) {
+                                    {
+                                      let h: |u64|u64 with copy+store =  move|x: u64| mod3::multiply(x, 12) with copy, drop;
+                                       move|x: u64| (h)(x) with copy, drop
+                                    }
+                                  } else {
+                                    if Eq<u64>(key, 14) {
+                                      {
+                                        let i: |u64|u64 with copy+store =  move|x: u64| test::multiply3(2, x, 2);
+                                         move|z: u64| (i)(z)
+                                      }
+                                    } else {
+                                      {
+                                        let i: |(u64, u64)|u64 with copy+store =  move|(x: u64, y: u64): (u64, u64)| {
+                                          let q: u64 = Sub<u64>(y, 1);
+                                          mod3::multiply(x, Add<u64>(q, 1))
+                                        };
+                                         move|x: u64| (i)(x, 15)
+                                      }
+                                    }
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          };
+          (f)(x)
+        }
+    }
+    private fun multiply3(x: u64,y: u64,z: u64): u64 {
+        Mul<u64>(Mul<u64>(x, y), z)
+    }
+    public fun test_functions() {
+        {
+          let x: u64 = 3;
+          {
+            let i: u64 = 0;
+            {
+              let __update_iter_flag: bool = false;
+              {
+                let __upper_bound_value: u64 = 15;
+                loop {
+                  if true {
+                    if __update_iter_flag {
+                      i: u64 = Add<u64>(i, 1)
+                    } else {
+                      __update_iter_flag: bool = true
+                    };
+                    if Lt<u64>(i, __upper_bound_value) {
+                      {
+                        let y: u64 = test::choose_function1(i, 3);
+                        if Eq<u64>(y, Mul<u64>(Add<u64>(i, 2), x)) {
+                          Tuple()
+                        } else {
+                          Abort(i)
+                        };
+                        Tuple()
+                      }
+                    } else {
+                      break
+                    };
+                    Tuple()
+                  } else {
+                    break
+                  }
+                };
+                Tuple()
+              }
+            }
+          }
+        }
+    }
+} // end 0x42::test
+
+
+// -- Model dump after env processor type parameter check:
+module 0x42::mod4 {
+    public fun alt_multiply(x: u64,y: u64): u64 {
+        Mul<u64>(x, y)
+    }
+} // end 0x42::mod4
+module 0x42::mod3 {
+    public fun multiply(x: u64,y: u64): u64 {
+        Mul<u64>(x, y)
+    }
+} // end 0x42::mod3
+module 0x42::mod2 {
+    friend fun double(x: u64): u64 {
+        Mul<u64>(x, 2)
+    }
+} // end 0x42::mod2
+module 0x42::mod1 {
+    friend fun triple(x: u64): u64 {
+        Mul<u64>(x, 3)
+    }
+} // end 0x42::mod1
+module 0x42::test {
+    use 0x42::mod1; // resolved as: 0x42::mod1
+    use 0x42::mod2; // resolved as: 0x42::mod2
+    use 0x42::mod3; // resolved as: 0x42::mod3
+    use 0x42::mod4::{alt_multiply}; // resolved as: 0x42::mod4
+    private fun add_mul(x: u64,y: u64,z: u64): u64 {
+        Mul<u64>(z, Add<u64>(x, y))
+    }
+    private fun choose_function1(key: u64,x: u64): u64 {
+        {
+          let f: |u64|u64 with copy = if Eq<u64>(key, 0) {
+            mod2::double
+          } else {
+            if Eq<u64>(key, 1) {
+              mod1::triple
+            } else {
+              if Eq<u64>(key, 2) {
+                 move|x: u64| mod3::multiply(4, x)
+              } else {
+                if Eq<u64>(key, 3) {
+                  {
+                    let x: u64 = 5;
+                     move|y: u64| mod4::alt_multiply(x, y)
+                  }
+                } else {
+                  if Eq<u64>(key, 4) {
+                    {
+                      let x: u64 = 6;
+                       move|y: u64| mod3::multiply(y, x)
+                    }
+                  } else {
+                    if Eq<u64>(key, 5) {
+                       move|x: u64| test::multiply3(x, 3, 2)
+                    } else {
+                      if Eq<u64>(key, 6) {
+                         move|x: u64| mod3::multiply(x, 7)
+                      } else {
+                        if Eq<u64>(key, 7) {
+                           move|x: u64| test::multiply3(4, x, 2)
+                        } else {
+                          if Eq<u64>(key, 8) {
+                             move|x: u64| test::multiply3(3, 3, x)
+                          } else {
+                            if Eq<u64>(key, 9) {
+                              {
+                                let x: u64 = 2;
+                                {
+                                  let y: u64 = 5;
+                                   move|z: u64| test::multiply3(x, y, z)
+                                }
+                              }
+                            } else {
+                              if Eq<u64>(key, 10) {
+                                {
+                                  let z: u64 = 11;
+                                   move|x: u64| mod4::alt_multiply(x, z) with copy, drop
+                                }
+                              } else {
+                                if Eq<u64>(key, 11) {
+                                  {
+                                    let g: |(u64, u64)|u64 with copy+store =  move|(x: u64, y: u64): (u64, u64)| mod3::multiply(x, y) with copy, drop;
+                                     move|x: u64| (g)(x, 11)
+                                  }
+                                } else {
+                                  if Eq<u64>(key, 12) {
+                                    {
+                                      let h: |u64|u64 with copy+store =  move|x: u64| mod3::multiply(x, 12) with copy, drop;
+                                       move|x: u64| (h)(x) with copy, drop
+                                    }
+                                  } else {
+                                    if Eq<u64>(key, 14) {
+                                      {
+                                        let i: |u64|u64 with copy+store =  move|x: u64| test::multiply3(2, x, 2);
+                                         move|z: u64| (i)(z)
+                                      }
+                                    } else {
+                                      {
+                                        let i: |(u64, u64)|u64 with copy+store =  move|(x: u64, y: u64): (u64, u64)| {
+                                          let q: u64 = Sub<u64>(y, 1);
+                                          mod3::multiply(x, Add<u64>(q, 1))
+                                        };
+                                         move|x: u64| (i)(x, 15)
+                                      }
+                                    }
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          };
+          (f)(x)
+        }
+    }
+    private fun multiply3(x: u64,y: u64,z: u64): u64 {
+        Mul<u64>(Mul<u64>(x, y), z)
+    }
+    public fun test_functions() {
+        {
+          let x: u64 = 3;
+          {
+            let i: u64 = 0;
+            {
+              let __update_iter_flag: bool = false;
+              {
+                let __upper_bound_value: u64 = 15;
+                loop {
+                  if true {
+                    if __update_iter_flag {
+                      i: u64 = Add<u64>(i, 1)
+                    } else {
+                      __update_iter_flag: bool = true
+                    };
+                    if Lt<u64>(i, __upper_bound_value) {
+                      {
+                        let y: u64 = test::choose_function1(i, 3);
+                        if Eq<u64>(y, Mul<u64>(Add<u64>(i, 2), x)) {
+                          Tuple()
+                        } else {
+                          Abort(i)
+                        };
+                        Tuple()
+                      }
+                    } else {
+                      break
+                    };
+                    Tuple()
+                  } else {
+                    break
+                  }
+                };
+                Tuple()
+              }
+            }
+          }
+        }
+    }
+} // end 0x42::test
+
+
+// -- Model dump after env processor check recursive struct definition:
+module 0x42::mod4 {
+    public fun alt_multiply(x: u64,y: u64): u64 {
+        Mul<u64>(x, y)
+    }
+} // end 0x42::mod4
+module 0x42::mod3 {
+    public fun multiply(x: u64,y: u64): u64 {
+        Mul<u64>(x, y)
+    }
+} // end 0x42::mod3
+module 0x42::mod2 {
+    friend fun double(x: u64): u64 {
+        Mul<u64>(x, 2)
+    }
+} // end 0x42::mod2
+module 0x42::mod1 {
+    friend fun triple(x: u64): u64 {
+        Mul<u64>(x, 3)
+    }
+} // end 0x42::mod1
+module 0x42::test {
+    use 0x42::mod1; // resolved as: 0x42::mod1
+    use 0x42::mod2; // resolved as: 0x42::mod2
+    use 0x42::mod3; // resolved as: 0x42::mod3
+    use 0x42::mod4::{alt_multiply}; // resolved as: 0x42::mod4
+    private fun add_mul(x: u64,y: u64,z: u64): u64 {
+        Mul<u64>(z, Add<u64>(x, y))
+    }
+    private fun choose_function1(key: u64,x: u64): u64 {
+        {
+          let f: |u64|u64 with copy = if Eq<u64>(key, 0) {
+            mod2::double
+          } else {
+            if Eq<u64>(key, 1) {
+              mod1::triple
+            } else {
+              if Eq<u64>(key, 2) {
+                 move|x: u64| mod3::multiply(4, x)
+              } else {
+                if Eq<u64>(key, 3) {
+                  {
+                    let x: u64 = 5;
+                     move|y: u64| mod4::alt_multiply(x, y)
+                  }
+                } else {
+                  if Eq<u64>(key, 4) {
+                    {
+                      let x: u64 = 6;
+                       move|y: u64| mod3::multiply(y, x)
+                    }
+                  } else {
+                    if Eq<u64>(key, 5) {
+                       move|x: u64| test::multiply3(x, 3, 2)
+                    } else {
+                      if Eq<u64>(key, 6) {
+                         move|x: u64| mod3::multiply(x, 7)
+                      } else {
+                        if Eq<u64>(key, 7) {
+                           move|x: u64| test::multiply3(4, x, 2)
+                        } else {
+                          if Eq<u64>(key, 8) {
+                             move|x: u64| test::multiply3(3, 3, x)
+                          } else {
+                            if Eq<u64>(key, 9) {
+                              {
+                                let x: u64 = 2;
+                                {
+                                  let y: u64 = 5;
+                                   move|z: u64| test::multiply3(x, y, z)
+                                }
+                              }
+                            } else {
+                              if Eq<u64>(key, 10) {
+                                {
+                                  let z: u64 = 11;
+                                   move|x: u64| mod4::alt_multiply(x, z) with copy, drop
+                                }
+                              } else {
+                                if Eq<u64>(key, 11) {
+                                  {
+                                    let g: |(u64, u64)|u64 with copy+store =  move|(x: u64, y: u64): (u64, u64)| mod3::multiply(x, y) with copy, drop;
+                                     move|x: u64| (g)(x, 11)
+                                  }
+                                } else {
+                                  if Eq<u64>(key, 12) {
+                                    {
+                                      let h: |u64|u64 with copy+store =  move|x: u64| mod3::multiply(x, 12) with copy, drop;
+                                       move|x: u64| (h)(x) with copy, drop
+                                    }
+                                  } else {
+                                    if Eq<u64>(key, 14) {
+                                      {
+                                        let i: |u64|u64 with copy+store =  move|x: u64| test::multiply3(2, x, 2);
+                                         move|z: u64| (i)(z)
+                                      }
+                                    } else {
+                                      {
+                                        let i: |(u64, u64)|u64 with copy+store =  move|(x: u64, y: u64): (u64, u64)| {
+                                          let q: u64 = Sub<u64>(y, 1);
+                                          mod3::multiply(x, Add<u64>(q, 1))
+                                        };
+                                         move|x: u64| (i)(x, 15)
+                                      }
+                                    }
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          };
+          (f)(x)
+        }
+    }
+    private fun multiply3(x: u64,y: u64,z: u64): u64 {
+        Mul<u64>(Mul<u64>(x, y), z)
+    }
+    public fun test_functions() {
+        {
+          let x: u64 = 3;
+          {
+            let i: u64 = 0;
+            {
+              let __update_iter_flag: bool = false;
+              {
+                let __upper_bound_value: u64 = 15;
+                loop {
+                  if true {
+                    if __update_iter_flag {
+                      i: u64 = Add<u64>(i, 1)
+                    } else {
+                      __update_iter_flag: bool = true
+                    };
+                    if Lt<u64>(i, __upper_bound_value) {
+                      {
+                        let y: u64 = test::choose_function1(i, 3);
+                        if Eq<u64>(y, Mul<u64>(Add<u64>(i, 2), x)) {
+                          Tuple()
+                        } else {
+                          Abort(i)
+                        };
+                        Tuple()
+                      }
+                    } else {
+                      break
+                    };
+                    Tuple()
+                  } else {
+                    break
+                  }
+                };
+                Tuple()
+              }
+            }
+          }
+        }
+    }
+} // end 0x42::test
+
+
+// -- Model dump after env processor check cyclic type instantiation:
+module 0x42::mod4 {
+    public fun alt_multiply(x: u64,y: u64): u64 {
+        Mul<u64>(x, y)
+    }
+} // end 0x42::mod4
+module 0x42::mod3 {
+    public fun multiply(x: u64,y: u64): u64 {
+        Mul<u64>(x, y)
+    }
+} // end 0x42::mod3
+module 0x42::mod2 {
+    friend fun double(x: u64): u64 {
+        Mul<u64>(x, 2)
+    }
+} // end 0x42::mod2
+module 0x42::mod1 {
+    friend fun triple(x: u64): u64 {
+        Mul<u64>(x, 3)
+    }
+} // end 0x42::mod1
+module 0x42::test {
+    use 0x42::mod1; // resolved as: 0x42::mod1
+    use 0x42::mod2; // resolved as: 0x42::mod2
+    use 0x42::mod3; // resolved as: 0x42::mod3
+    use 0x42::mod4::{alt_multiply}; // resolved as: 0x42::mod4
+    private fun add_mul(x: u64,y: u64,z: u64): u64 {
+        Mul<u64>(z, Add<u64>(x, y))
+    }
+    private fun choose_function1(key: u64,x: u64): u64 {
+        {
+          let f: |u64|u64 with copy = if Eq<u64>(key, 0) {
+            mod2::double
+          } else {
+            if Eq<u64>(key, 1) {
+              mod1::triple
+            } else {
+              if Eq<u64>(key, 2) {
+                 move|x: u64| mod3::multiply(4, x)
+              } else {
+                if Eq<u64>(key, 3) {
+                  {
+                    let x: u64 = 5;
+                     move|y: u64| mod4::alt_multiply(x, y)
+                  }
+                } else {
+                  if Eq<u64>(key, 4) {
+                    {
+                      let x: u64 = 6;
+                       move|y: u64| mod3::multiply(y, x)
+                    }
+                  } else {
+                    if Eq<u64>(key, 5) {
+                       move|x: u64| test::multiply3(x, 3, 2)
+                    } else {
+                      if Eq<u64>(key, 6) {
+                         move|x: u64| mod3::multiply(x, 7)
+                      } else {
+                        if Eq<u64>(key, 7) {
+                           move|x: u64| test::multiply3(4, x, 2)
+                        } else {
+                          if Eq<u64>(key, 8) {
+                             move|x: u64| test::multiply3(3, 3, x)
+                          } else {
+                            if Eq<u64>(key, 9) {
+                              {
+                                let x: u64 = 2;
+                                {
+                                  let y: u64 = 5;
+                                   move|z: u64| test::multiply3(x, y, z)
+                                }
+                              }
+                            } else {
+                              if Eq<u64>(key, 10) {
+                                {
+                                  let z: u64 = 11;
+                                   move|x: u64| mod4::alt_multiply(x, z) with copy, drop
+                                }
+                              } else {
+                                if Eq<u64>(key, 11) {
+                                  {
+                                    let g: |(u64, u64)|u64 with copy+store =  move|(x: u64, y: u64): (u64, u64)| mod3::multiply(x, y) with copy, drop;
+                                     move|x: u64| (g)(x, 11)
+                                  }
+                                } else {
+                                  if Eq<u64>(key, 12) {
+                                    {
+                                      let h: |u64|u64 with copy+store =  move|x: u64| mod3::multiply(x, 12) with copy, drop;
+                                       move|x: u64| (h)(x) with copy, drop
+                                    }
+                                  } else {
+                                    if Eq<u64>(key, 14) {
+                                      {
+                                        let i: |u64|u64 with copy+store =  move|x: u64| test::multiply3(2, x, 2);
+                                         move|z: u64| (i)(z)
+                                      }
+                                    } else {
+                                      {
+                                        let i: |(u64, u64)|u64 with copy+store =  move|(x: u64, y: u64): (u64, u64)| {
+                                          let q: u64 = Sub<u64>(y, 1);
+                                          mod3::multiply(x, Add<u64>(q, 1))
+                                        };
+                                         move|x: u64| (i)(x, 15)
+                                      }
+                                    }
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          };
+          (f)(x)
+        }
+    }
+    private fun multiply3(x: u64,y: u64,z: u64): u64 {
+        Mul<u64>(Mul<u64>(x, y), z)
+    }
+    public fun test_functions() {
+        {
+          let x: u64 = 3;
+          {
+            let i: u64 = 0;
+            {
+              let __update_iter_flag: bool = false;
+              {
+                let __upper_bound_value: u64 = 15;
+                loop {
+                  if true {
+                    if __update_iter_flag {
+                      i: u64 = Add<u64>(i, 1)
+                    } else {
+                      __update_iter_flag: bool = true
+                    };
+                    if Lt<u64>(i, __upper_bound_value) {
+                      {
+                        let y: u64 = test::choose_function1(i, 3);
+                        if Eq<u64>(y, Mul<u64>(Add<u64>(i, 2), x)) {
+                          Tuple()
+                        } else {
+                          Abort(i)
+                        };
+                        Tuple()
+                      }
+                    } else {
+                      break
+                    };
+                    Tuple()
+                  } else {
+                    break
+                  }
+                };
+                Tuple()
+              }
+            }
+          }
+        }
+    }
+} // end 0x42::test
+
+
+// -- Model dump after env processor unused struct params check:
+module 0x42::mod4 {
+    public fun alt_multiply(x: u64,y: u64): u64 {
+        Mul<u64>(x, y)
+    }
+} // end 0x42::mod4
+module 0x42::mod3 {
+    public fun multiply(x: u64,y: u64): u64 {
+        Mul<u64>(x, y)
+    }
+} // end 0x42::mod3
+module 0x42::mod2 {
+    friend fun double(x: u64): u64 {
+        Mul<u64>(x, 2)
+    }
+} // end 0x42::mod2
+module 0x42::mod1 {
+    friend fun triple(x: u64): u64 {
+        Mul<u64>(x, 3)
+    }
+} // end 0x42::mod1
+module 0x42::test {
+    use 0x42::mod1; // resolved as: 0x42::mod1
+    use 0x42::mod2; // resolved as: 0x42::mod2
+    use 0x42::mod3; // resolved as: 0x42::mod3
+    use 0x42::mod4::{alt_multiply}; // resolved as: 0x42::mod4
+    private fun add_mul(x: u64,y: u64,z: u64): u64 {
+        Mul<u64>(z, Add<u64>(x, y))
+    }
+    private fun choose_function1(key: u64,x: u64): u64 {
+        {
+          let f: |u64|u64 with copy = if Eq<u64>(key, 0) {
+            mod2::double
+          } else {
+            if Eq<u64>(key, 1) {
+              mod1::triple
+            } else {
+              if Eq<u64>(key, 2) {
+                 move|x: u64| mod3::multiply(4, x)
+              } else {
+                if Eq<u64>(key, 3) {
+                  {
+                    let x: u64 = 5;
+                     move|y: u64| mod4::alt_multiply(x, y)
+                  }
+                } else {
+                  if Eq<u64>(key, 4) {
+                    {
+                      let x: u64 = 6;
+                       move|y: u64| mod3::multiply(y, x)
+                    }
+                  } else {
+                    if Eq<u64>(key, 5) {
+                       move|x: u64| test::multiply3(x, 3, 2)
+                    } else {
+                      if Eq<u64>(key, 6) {
+                         move|x: u64| mod3::multiply(x, 7)
+                      } else {
+                        if Eq<u64>(key, 7) {
+                           move|x: u64| test::multiply3(4, x, 2)
+                        } else {
+                          if Eq<u64>(key, 8) {
+                             move|x: u64| test::multiply3(3, 3, x)
+                          } else {
+                            if Eq<u64>(key, 9) {
+                              {
+                                let x: u64 = 2;
+                                {
+                                  let y: u64 = 5;
+                                   move|z: u64| test::multiply3(x, y, z)
+                                }
+                              }
+                            } else {
+                              if Eq<u64>(key, 10) {
+                                {
+                                  let z: u64 = 11;
+                                   move|x: u64| mod4::alt_multiply(x, z) with copy, drop
+                                }
+                              } else {
+                                if Eq<u64>(key, 11) {
+                                  {
+                                    let g: |(u64, u64)|u64 with copy+store =  move|(x: u64, y: u64): (u64, u64)| mod3::multiply(x, y) with copy, drop;
+                                     move|x: u64| (g)(x, 11)
+                                  }
+                                } else {
+                                  if Eq<u64>(key, 12) {
+                                    {
+                                      let h: |u64|u64 with copy+store =  move|x: u64| mod3::multiply(x, 12) with copy, drop;
+                                       move|x: u64| (h)(x) with copy, drop
+                                    }
+                                  } else {
+                                    if Eq<u64>(key, 14) {
+                                      {
+                                        let i: |u64|u64 with copy+store =  move|x: u64| test::multiply3(2, x, 2);
+                                         move|z: u64| (i)(z)
+                                      }
+                                    } else {
+                                      {
+                                        let i: |(u64, u64)|u64 with copy+store =  move|(x: u64, y: u64): (u64, u64)| {
+                                          let q: u64 = Sub<u64>(y, 1);
+                                          mod3::multiply(x, Add<u64>(q, 1))
+                                        };
+                                         move|x: u64| (i)(x, 15)
+                                      }
+                                    }
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          };
+          (f)(x)
+        }
+    }
+    private fun multiply3(x: u64,y: u64,z: u64): u64 {
+        Mul<u64>(Mul<u64>(x, y), z)
+    }
+    public fun test_functions() {
+        {
+          let x: u64 = 3;
+          {
+            let i: u64 = 0;
+            {
+              let __update_iter_flag: bool = false;
+              {
+                let __upper_bound_value: u64 = 15;
+                loop {
+                  if true {
+                    if __update_iter_flag {
+                      i: u64 = Add<u64>(i, 1)
+                    } else {
+                      __update_iter_flag: bool = true
+                    };
+                    if Lt<u64>(i, __upper_bound_value) {
+                      {
+                        let y: u64 = test::choose_function1(i, 3);
+                        if Eq<u64>(y, Mul<u64>(Add<u64>(i, 2), x)) {
+                          Tuple()
+                        } else {
+                          Abort(i)
+                        };
+                        Tuple()
+                      }
+                    } else {
+                      break
+                    };
+                    Tuple()
+                  } else {
+                    break
+                  }
+                };
+                Tuple()
+              }
+            }
+          }
+        }
+    }
+} // end 0x42::test
+
+
+// -- Model dump after env processor access and use check before inlining:
+module 0x42::mod4 {
+    public fun alt_multiply(x: u64,y: u64): u64 {
+        Mul<u64>(x, y)
+    }
+} // end 0x42::mod4
+module 0x42::mod3 {
+    public fun multiply(x: u64,y: u64): u64 {
+        Mul<u64>(x, y)
+    }
+} // end 0x42::mod3
+module 0x42::mod2 {
+    friend fun double(x: u64): u64 {
+        Mul<u64>(x, 2)
+    }
+} // end 0x42::mod2
+module 0x42::mod1 {
+    friend fun triple(x: u64): u64 {
+        Mul<u64>(x, 3)
+    }
+} // end 0x42::mod1
+module 0x42::test {
+    use 0x42::mod1; // resolved as: 0x42::mod1
+    use 0x42::mod2; // resolved as: 0x42::mod2
+    use 0x42::mod3; // resolved as: 0x42::mod3
+    use 0x42::mod4::{alt_multiply}; // resolved as: 0x42::mod4
+    private fun add_mul(x: u64,y: u64,z: u64): u64 {
+        Mul<u64>(z, Add<u64>(x, y))
+    }
+    private fun choose_function1(key: u64,x: u64): u64 {
+        {
+          let f: |u64|u64 with copy = if Eq<u64>(key, 0) {
+            mod2::double
+          } else {
+            if Eq<u64>(key, 1) {
+              mod1::triple
+            } else {
+              if Eq<u64>(key, 2) {
+                 move|x: u64| mod3::multiply(4, x)
+              } else {
+                if Eq<u64>(key, 3) {
+                  {
+                    let x: u64 = 5;
+                     move|y: u64| mod4::alt_multiply(x, y)
+                  }
+                } else {
+                  if Eq<u64>(key, 4) {
+                    {
+                      let x: u64 = 6;
+                       move|y: u64| mod3::multiply(y, x)
+                    }
+                  } else {
+                    if Eq<u64>(key, 5) {
+                       move|x: u64| test::multiply3(x, 3, 2)
+                    } else {
+                      if Eq<u64>(key, 6) {
+                         move|x: u64| mod3::multiply(x, 7)
+                      } else {
+                        if Eq<u64>(key, 7) {
+                           move|x: u64| test::multiply3(4, x, 2)
+                        } else {
+                          if Eq<u64>(key, 8) {
+                             move|x: u64| test::multiply3(3, 3, x)
+                          } else {
+                            if Eq<u64>(key, 9) {
+                              {
+                                let x: u64 = 2;
+                                {
+                                  let y: u64 = 5;
+                                   move|z: u64| test::multiply3(x, y, z)
+                                }
+                              }
+                            } else {
+                              if Eq<u64>(key, 10) {
+                                {
+                                  let z: u64 = 11;
+                                   move|x: u64| mod4::alt_multiply(x, z) with copy, drop
+                                }
+                              } else {
+                                if Eq<u64>(key, 11) {
+                                  {
+                                    let g: |(u64, u64)|u64 with copy+store =  move|(x: u64, y: u64): (u64, u64)| mod3::multiply(x, y) with copy, drop;
+                                     move|x: u64| (g)(x, 11)
+                                  }
+                                } else {
+                                  if Eq<u64>(key, 12) {
+                                    {
+                                      let h: |u64|u64 with copy+store =  move|x: u64| mod3::multiply(x, 12) with copy, drop;
+                                       move|x: u64| (h)(x) with copy, drop
+                                    }
+                                  } else {
+                                    if Eq<u64>(key, 14) {
+                                      {
+                                        let i: |u64|u64 with copy+store =  move|x: u64| test::multiply3(2, x, 2);
+                                         move|z: u64| (i)(z)
+                                      }
+                                    } else {
+                                      {
+                                        let i: |(u64, u64)|u64 with copy+store =  move|(x: u64, y: u64): (u64, u64)| {
+                                          let q: u64 = Sub<u64>(y, 1);
+                                          mod3::multiply(x, Add<u64>(q, 1))
+                                        };
+                                         move|x: u64| (i)(x, 15)
+                                      }
+                                    }
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          };
+          (f)(x)
+        }
+    }
+    private fun multiply3(x: u64,y: u64,z: u64): u64 {
+        Mul<u64>(Mul<u64>(x, y), z)
+    }
+    public fun test_functions() {
+        {
+          let x: u64 = 3;
+          {
+            let i: u64 = 0;
+            {
+              let __update_iter_flag: bool = false;
+              {
+                let __upper_bound_value: u64 = 15;
+                loop {
+                  if true {
+                    if __update_iter_flag {
+                      i: u64 = Add<u64>(i, 1)
+                    } else {
+                      __update_iter_flag: bool = true
+                    };
+                    if Lt<u64>(i, __upper_bound_value) {
+                      {
+                        let y: u64 = test::choose_function1(i, 3);
+                        if Eq<u64>(y, Mul<u64>(Add<u64>(i, 2), x)) {
+                          Tuple()
+                        } else {
+                          Abort(i)
+                        };
+                        Tuple()
+                      }
+                    } else {
+                      break
+                    };
+                    Tuple()
+                  } else {
+                    break
+                  }
+                };
+                Tuple()
+              }
+            }
+          }
+        }
+    }
+} // end 0x42::test
+
+
+// -- Model dump after env processor inlining:
+module 0x42::mod4 {
+    public fun alt_multiply(x: u64,y: u64): u64 {
+        Mul<u64>(x, y)
+    }
+} // end 0x42::mod4
+module 0x42::mod3 {
+    public fun multiply(x: u64,y: u64): u64 {
+        Mul<u64>(x, y)
+    }
+} // end 0x42::mod3
+module 0x42::mod2 {
+    friend fun double(x: u64): u64 {
+        Mul<u64>(x, 2)
+    }
+} // end 0x42::mod2
+module 0x42::mod1 {
+    friend fun triple(x: u64): u64 {
+        Mul<u64>(x, 3)
+    }
+} // end 0x42::mod1
+module 0x42::test {
+    use 0x42::mod1; // resolved as: 0x42::mod1
+    use 0x42::mod2; // resolved as: 0x42::mod2
+    use 0x42::mod3; // resolved as: 0x42::mod3
+    use 0x42::mod4::{alt_multiply}; // resolved as: 0x42::mod4
+    private fun add_mul(x: u64,y: u64,z: u64): u64 {
+        Mul<u64>(z, Add<u64>(x, y))
+    }
+    private fun choose_function1(key: u64,x: u64): u64 {
+        {
+          let f: |u64|u64 with copy = if Eq<u64>(key, 0) {
+            mod2::double
+          } else {
+            if Eq<u64>(key, 1) {
+              mod1::triple
+            } else {
+              if Eq<u64>(key, 2) {
+                 move|x: u64| mod3::multiply(4, x)
+              } else {
+                if Eq<u64>(key, 3) {
+                  {
+                    let x: u64 = 5;
+                     move|y: u64| mod4::alt_multiply(x, y)
+                  }
+                } else {
+                  if Eq<u64>(key, 4) {
+                    {
+                      let x: u64 = 6;
+                       move|y: u64| mod3::multiply(y, x)
+                    }
+                  } else {
+                    if Eq<u64>(key, 5) {
+                       move|x: u64| test::multiply3(x, 3, 2)
+                    } else {
+                      if Eq<u64>(key, 6) {
+                         move|x: u64| mod3::multiply(x, 7)
+                      } else {
+                        if Eq<u64>(key, 7) {
+                           move|x: u64| test::multiply3(4, x, 2)
+                        } else {
+                          if Eq<u64>(key, 8) {
+                             move|x: u64| test::multiply3(3, 3, x)
+                          } else {
+                            if Eq<u64>(key, 9) {
+                              {
+                                let x: u64 = 2;
+                                {
+                                  let y: u64 = 5;
+                                   move|z: u64| test::multiply3(x, y, z)
+                                }
+                              }
+                            } else {
+                              if Eq<u64>(key, 10) {
+                                {
+                                  let z: u64 = 11;
+                                   move|x: u64| mod4::alt_multiply(x, z) with copy, drop
+                                }
+                              } else {
+                                if Eq<u64>(key, 11) {
+                                  {
+                                    let g: |(u64, u64)|u64 with copy+store =  move|(x: u64, y: u64): (u64, u64)| mod3::multiply(x, y) with copy, drop;
+                                     move|x: u64| (g)(x, 11)
+                                  }
+                                } else {
+                                  if Eq<u64>(key, 12) {
+                                    {
+                                      let h: |u64|u64 with copy+store =  move|x: u64| mod3::multiply(x, 12) with copy, drop;
+                                       move|x: u64| (h)(x) with copy, drop
+                                    }
+                                  } else {
+                                    if Eq<u64>(key, 14) {
+                                      {
+                                        let i: |u64|u64 with copy+store =  move|x: u64| test::multiply3(2, x, 2);
+                                         move|z: u64| (i)(z)
+                                      }
+                                    } else {
+                                      {
+                                        let i: |(u64, u64)|u64 with copy+store =  move|(x: u64, y: u64): (u64, u64)| {
+                                          let q: u64 = Sub<u64>(y, 1);
+                                          mod3::multiply(x, Add<u64>(q, 1))
+                                        };
+                                         move|x: u64| (i)(x, 15)
+                                      }
+                                    }
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          };
+          (f)(x)
+        }
+    }
+    private fun multiply3(x: u64,y: u64,z: u64): u64 {
+        Mul<u64>(Mul<u64>(x, y), z)
+    }
+    public fun test_functions() {
+        {
+          let x: u64 = 3;
+          {
+            let i: u64 = 0;
+            {
+              let __update_iter_flag: bool = false;
+              {
+                let __upper_bound_value: u64 = 15;
+                loop {
+                  if true {
+                    if __update_iter_flag {
+                      i: u64 = Add<u64>(i, 1)
+                    } else {
+                      __update_iter_flag: bool = true
+                    };
+                    if Lt<u64>(i, __upper_bound_value) {
+                      {
+                        let y: u64 = test::choose_function1(i, 3);
+                        if Eq<u64>(y, Mul<u64>(Add<u64>(i, 2), x)) {
+                          Tuple()
+                        } else {
+                          Abort(i)
+                        };
+                        Tuple()
+                      }
+                    } else {
+                      break
+                    };
+                    Tuple()
+                  } else {
+                    break
+                  }
+                };
+                Tuple()
+              }
+            }
+          }
+        }
+    }
+} // end 0x42::test
+
+
+// -- Model dump after env processor access and use check after inlining:
+module 0x42::mod4 {
+    public fun alt_multiply(x: u64,y: u64): u64 {
+        Mul<u64>(x, y)
+    }
+} // end 0x42::mod4
+module 0x42::mod3 {
+    public fun multiply(x: u64,y: u64): u64 {
+        Mul<u64>(x, y)
+    }
+} // end 0x42::mod3
+module 0x42::mod2 {
+    friend fun double(x: u64): u64 {
+        Mul<u64>(x, 2)
+    }
+} // end 0x42::mod2
+module 0x42::mod1 {
+    friend fun triple(x: u64): u64 {
+        Mul<u64>(x, 3)
+    }
+} // end 0x42::mod1
+module 0x42::test {
+    use 0x42::mod1; // resolved as: 0x42::mod1
+    use 0x42::mod2; // resolved as: 0x42::mod2
+    use 0x42::mod3; // resolved as: 0x42::mod3
+    use 0x42::mod4::{alt_multiply}; // resolved as: 0x42::mod4
+    private fun add_mul(x: u64,y: u64,z: u64): u64 {
+        Mul<u64>(z, Add<u64>(x, y))
+    }
+    private fun choose_function1(key: u64,x: u64): u64 {
+        {
+          let f: |u64|u64 with copy = if Eq<u64>(key, 0) {
+            mod2::double
+          } else {
+            if Eq<u64>(key, 1) {
+              mod1::triple
+            } else {
+              if Eq<u64>(key, 2) {
+                 move|x: u64| mod3::multiply(4, x)
+              } else {
+                if Eq<u64>(key, 3) {
+                  {
+                    let x: u64 = 5;
+                     move|y: u64| mod4::alt_multiply(x, y)
+                  }
+                } else {
+                  if Eq<u64>(key, 4) {
+                    {
+                      let x: u64 = 6;
+                       move|y: u64| mod3::multiply(y, x)
+                    }
+                  } else {
+                    if Eq<u64>(key, 5) {
+                       move|x: u64| test::multiply3(x, 3, 2)
+                    } else {
+                      if Eq<u64>(key, 6) {
+                         move|x: u64| mod3::multiply(x, 7)
+                      } else {
+                        if Eq<u64>(key, 7) {
+                           move|x: u64| test::multiply3(4, x, 2)
+                        } else {
+                          if Eq<u64>(key, 8) {
+                             move|x: u64| test::multiply3(3, 3, x)
+                          } else {
+                            if Eq<u64>(key, 9) {
+                              {
+                                let x: u64 = 2;
+                                {
+                                  let y: u64 = 5;
+                                   move|z: u64| test::multiply3(x, y, z)
+                                }
+                              }
+                            } else {
+                              if Eq<u64>(key, 10) {
+                                {
+                                  let z: u64 = 11;
+                                   move|x: u64| mod4::alt_multiply(x, z) with copy, drop
+                                }
+                              } else {
+                                if Eq<u64>(key, 11) {
+                                  {
+                                    let g: |(u64, u64)|u64 with copy+store =  move|(x: u64, y: u64): (u64, u64)| mod3::multiply(x, y) with copy, drop;
+                                     move|x: u64| (g)(x, 11)
+                                  }
+                                } else {
+                                  if Eq<u64>(key, 12) {
+                                    {
+                                      let h: |u64|u64 with copy+store =  move|x: u64| mod3::multiply(x, 12) with copy, drop;
+                                       move|x: u64| (h)(x) with copy, drop
+                                    }
+                                  } else {
+                                    if Eq<u64>(key, 14) {
+                                      {
+                                        let i: |u64|u64 with copy+store =  move|x: u64| test::multiply3(2, x, 2);
+                                         move|z: u64| (i)(z)
+                                      }
+                                    } else {
+                                      {
+                                        let i: |(u64, u64)|u64 with copy+store =  move|(x: u64, y: u64): (u64, u64)| {
+                                          let q: u64 = Sub<u64>(y, 1);
+                                          mod3::multiply(x, Add<u64>(q, 1))
+                                        };
+                                         move|x: u64| (i)(x, 15)
+                                      }
+                                    }
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          };
+          (f)(x)
+        }
+    }
+    private fun multiply3(x: u64,y: u64,z: u64): u64 {
+        Mul<u64>(Mul<u64>(x, y), z)
+    }
+    public fun test_functions() {
+        {
+          let x: u64 = 3;
+          {
+            let i: u64 = 0;
+            {
+              let __update_iter_flag: bool = false;
+              {
+                let __upper_bound_value: u64 = 15;
+                loop {
+                  if true {
+                    if __update_iter_flag {
+                      i: u64 = Add<u64>(i, 1)
+                    } else {
+                      __update_iter_flag: bool = true
+                    };
+                    if Lt<u64>(i, __upper_bound_value) {
+                      {
+                        let y: u64 = test::choose_function1(i, 3);
+                        if Eq<u64>(y, Mul<u64>(Add<u64>(i, 2), x)) {
+                          Tuple()
+                        } else {
+                          Abort(i)
+                        };
+                        Tuple()
+                      }
+                    } else {
+                      break
+                    };
+                    Tuple()
+                  } else {
+                    break
+                  }
+                };
+                Tuple()
+              }
+            }
+          }
+        }
+    }
+} // end 0x42::test
+
+
+// -- Model dump after env processor acquires check:
+module 0x42::mod4 {
+    public fun alt_multiply(x: u64,y: u64): u64 {
+        Mul<u64>(x, y)
+    }
+} // end 0x42::mod4
+module 0x42::mod3 {
+    public fun multiply(x: u64,y: u64): u64 {
+        Mul<u64>(x, y)
+    }
+} // end 0x42::mod3
+module 0x42::mod2 {
+    friend fun double(x: u64): u64 {
+        Mul<u64>(x, 2)
+    }
+} // end 0x42::mod2
+module 0x42::mod1 {
+    friend fun triple(x: u64): u64 {
+        Mul<u64>(x, 3)
+    }
+} // end 0x42::mod1
+module 0x42::test {
+    use 0x42::mod1; // resolved as: 0x42::mod1
+    use 0x42::mod2; // resolved as: 0x42::mod2
+    use 0x42::mod3; // resolved as: 0x42::mod3
+    use 0x42::mod4::{alt_multiply}; // resolved as: 0x42::mod4
+    private fun add_mul(x: u64,y: u64,z: u64): u64 {
+        Mul<u64>(z, Add<u64>(x, y))
+    }
+    private fun choose_function1(key: u64,x: u64): u64 {
+        {
+          let f: |u64|u64 with copy = if Eq<u64>(key, 0) {
+            mod2::double
+          } else {
+            if Eq<u64>(key, 1) {
+              mod1::triple
+            } else {
+              if Eq<u64>(key, 2) {
+                 move|x: u64| mod3::multiply(4, x)
+              } else {
+                if Eq<u64>(key, 3) {
+                  {
+                    let x: u64 = 5;
+                     move|y: u64| mod4::alt_multiply(x, y)
+                  }
+                } else {
+                  if Eq<u64>(key, 4) {
+                    {
+                      let x: u64 = 6;
+                       move|y: u64| mod3::multiply(y, x)
+                    }
+                  } else {
+                    if Eq<u64>(key, 5) {
+                       move|x: u64| test::multiply3(x, 3, 2)
+                    } else {
+                      if Eq<u64>(key, 6) {
+                         move|x: u64| mod3::multiply(x, 7)
+                      } else {
+                        if Eq<u64>(key, 7) {
+                           move|x: u64| test::multiply3(4, x, 2)
+                        } else {
+                          if Eq<u64>(key, 8) {
+                             move|x: u64| test::multiply3(3, 3, x)
+                          } else {
+                            if Eq<u64>(key, 9) {
+                              {
+                                let x: u64 = 2;
+                                {
+                                  let y: u64 = 5;
+                                   move|z: u64| test::multiply3(x, y, z)
+                                }
+                              }
+                            } else {
+                              if Eq<u64>(key, 10) {
+                                {
+                                  let z: u64 = 11;
+                                   move|x: u64| mod4::alt_multiply(x, z) with copy, drop
+                                }
+                              } else {
+                                if Eq<u64>(key, 11) {
+                                  {
+                                    let g: |(u64, u64)|u64 with copy+store =  move|(x: u64, y: u64): (u64, u64)| mod3::multiply(x, y) with copy, drop;
+                                     move|x: u64| (g)(x, 11)
+                                  }
+                                } else {
+                                  if Eq<u64>(key, 12) {
+                                    {
+                                      let h: |u64|u64 with copy+store =  move|x: u64| mod3::multiply(x, 12) with copy, drop;
+                                       move|x: u64| (h)(x) with copy, drop
+                                    }
+                                  } else {
+                                    if Eq<u64>(key, 14) {
+                                      {
+                                        let i: |u64|u64 with copy+store =  move|x: u64| test::multiply3(2, x, 2);
+                                         move|z: u64| (i)(z)
+                                      }
+                                    } else {
+                                      {
+                                        let i: |(u64, u64)|u64 with copy+store =  move|(x: u64, y: u64): (u64, u64)| {
+                                          let q: u64 = Sub<u64>(y, 1);
+                                          mod3::multiply(x, Add<u64>(q, 1))
+                                        };
+                                         move|x: u64| (i)(x, 15)
+                                      }
+                                    }
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          };
+          (f)(x)
+        }
+    }
+    private fun multiply3(x: u64,y: u64,z: u64): u64 {
+        Mul<u64>(Mul<u64>(x, y), z)
+    }
+    public fun test_functions() {
+        {
+          let x: u64 = 3;
+          {
+            let i: u64 = 0;
+            {
+              let __update_iter_flag: bool = false;
+              {
+                let __upper_bound_value: u64 = 15;
+                loop {
+                  if true {
+                    if __update_iter_flag {
+                      i: u64 = Add<u64>(i, 1)
+                    } else {
+                      __update_iter_flag: bool = true
+                    };
+                    if Lt<u64>(i, __upper_bound_value) {
+                      {
+                        let y: u64 = test::choose_function1(i, 3);
+                        if Eq<u64>(y, Mul<u64>(Add<u64>(i, 2), x)) {
+                          Tuple()
+                        } else {
+                          Abort(i)
+                        };
+                        Tuple()
+                      }
+                    } else {
+                      break
+                    };
+                    Tuple()
+                  } else {
+                    break
+                  }
+                };
+                Tuple()
+              }
+            }
+          }
+        }
+    }
+} // end 0x42::test
+
+
+// -- Model dump after env processor simplifier:
+module 0x42::mod4 {
+    public fun alt_multiply(x: u64,y: u64): u64 {
+        Mul<u64>(x, y)
+    }
+} // end 0x42::mod4
+module 0x42::mod3 {
+    public fun multiply(x: u64,y: u64): u64 {
+        Mul<u64>(x, y)
+    }
+} // end 0x42::mod3
+module 0x42::mod2 {
+    friend fun double(x: u64): u64 {
+        Mul<u64>(x, 2)
+    }
+} // end 0x42::mod2
+module 0x42::mod1 {
+    friend fun triple(x: u64): u64 {
+        Mul<u64>(x, 3)
+    }
+} // end 0x42::mod1
+module 0x42::test {
+    use 0x42::mod1; // resolved as: 0x42::mod1
+    use 0x42::mod2; // resolved as: 0x42::mod2
+    use 0x42::mod3; // resolved as: 0x42::mod3
+    use 0x42::mod4::{alt_multiply}; // resolved as: 0x42::mod4
+    private fun add_mul(x: u64,y: u64,z: u64): u64 {
+        Mul<u64>(z, Add<u64>(x, y))
+    }
+    private fun choose_function1(key: u64,x: u64): u64 {
+        {
+          let f: |u64|u64 with copy = if Eq<u64>(key, 0) {
+            mod2::double
+          } else {
+            if Eq<u64>(key, 1) {
+              mod1::triple
+            } else {
+              if Eq<u64>(key, 2) {
+                 move|x: u64| mod3::multiply(4, x)
+              } else {
+                if Eq<u64>(key, 3) {
+                   move|y: u64| mod4::alt_multiply(5, y)
+                } else {
+                  if Eq<u64>(key, 4) {
+                     move|y: u64| mod3::multiply(y, 6)
+                  } else {
+                    if Eq<u64>(key, 5) {
+                       move|x: u64| test::multiply3(x, 3, 2)
+                    } else {
+                      if Eq<u64>(key, 6) {
+                         move|x: u64| mod3::multiply(x, 7)
+                      } else {
+                        if Eq<u64>(key, 7) {
+                           move|x: u64| test::multiply3(4, x, 2)
+                        } else {
+                          if Eq<u64>(key, 8) {
+                             move|x: u64| test::multiply3(3, 3, x)
+                          } else {
+                            if Eq<u64>(key, 9) {
+                               move|z: u64| test::multiply3(2, 5, z)
+                            } else {
+                              if Eq<u64>(key, 10) {
+                                 move|x: u64| mod4::alt_multiply(x, 11) with copy, drop
+                              } else {
+                                if Eq<u64>(key, 11) {
+                                  {
+                                    let g: |(u64, u64)|u64 with copy+store =  move|(x: u64, y: u64): (u64, u64)| mod3::multiply(x, y) with copy, drop;
+                                     move|x: u64| (g)(x, 11)
+                                  }
+                                } else {
+                                  if Eq<u64>(key, 12) {
+                                    {
+                                      let h: |u64|u64 with copy+store =  move|x: u64| mod3::multiply(x, 12) with copy, drop;
+                                       move|x: u64| (h)(x) with copy, drop
+                                    }
+                                  } else {
+                                    if Eq<u64>(key, 14) {
+                                      {
+                                        let i: |u64|u64 with copy+store =  move|x: u64| test::multiply3(2, x, 2);
+                                         move|z: u64| (i)(z)
+                                      }
+                                    } else {
+                                      {
+                                        let i: |(u64, u64)|u64 with copy+store =  move|(x: u64, y: u64): (u64, u64)| {
+                                          let q: u64 = Sub<u64>(y, 1);
+                                          mod3::multiply(x, Add<u64>(q, 1))
+                                        };
+                                         move|x: u64| (i)(x, 15)
+                                      }
+                                    }
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          };
+          (f)(x)
+        }
+    }
+    private fun multiply3(x: u64,y: u64,z: u64): u64 {
+        Mul<u64>(Mul<u64>(x, y), z)
+    }
+    public fun test_functions() {
+        {
+          let i: u64 = 0;
+          {
+            let __update_iter_flag: bool = false;
+            loop {
+              if true {
+                if __update_iter_flag {
+                  i: u64 = Add<u64>(i, 1)
+                } else {
+                  __update_iter_flag: bool = true
+                };
+                if Lt<u64>(i, 15) {
+                  {
+                    let y: u64 = test::choose_function1(i, 3);
+                    if Eq<u64>(y, Mul<u64>(Add<u64>(i, 2), 3)) {
+                      Tuple()
+                    } else {
+                      Abort(i)
+                    };
+                    Tuple()
+                  }
+                } else {
+                  break
+                };
+                Tuple()
+              } else {
+                break
+              }
+            };
+            Tuple()
+          }
+        }
+    }
+} // end 0x42::test
+
+
+// -- Model dump after env processor lambda-lifting:
+module 0x42::mod4 {
+    public fun alt_multiply(x: u64,y: u64): u64 {
+        Mul<u64>(x, y)
+    }
+} // end 0x42::mod4
+module 0x42::mod3 {
+    public fun multiply(x: u64,y: u64): u64 {
+        Mul<u64>(x, y)
+    }
+} // end 0x42::mod3
+module 0x42::mod2 {
+    friend fun double(x: u64): u64 {
+        Mul<u64>(x, 2)
+    }
+} // end 0x42::mod2
+module 0x42::mod1 {
+    friend fun triple(x: u64): u64 {
+        Mul<u64>(x, 3)
+    }
+} // end 0x42::mod1
+module 0x42::test {
+    use 0x42::mod1; // resolved as: 0x42::mod1
+    use 0x42::mod2; // resolved as: 0x42::mod2
+    use 0x42::mod3; // resolved as: 0x42::mod3
+    use 0x42::mod4::{alt_multiply}; // resolved as: 0x42::mod4
+    private fun add_mul(x: u64,y: u64,z: u64): u64 {
+        Mul<u64>(z, Add<u64>(x, y))
+    }
+    private fun choose_function1(key: u64,x: u64): u64 {
+        {
+          let f: |u64|u64 with copy = if Eq<u64>(key, 0) {
+            mod2::double
+          } else {
+            if Eq<u64>(key, 1) {
+              mod1::triple
+            } else {
+              if Eq<u64>(key, 2) {
+                earlybind(mod3::multiply, 4)
+              } else {
+                if Eq<u64>(key, 3) {
+                  earlybind(mod4::alt_multiply, 5)
+                } else {
+                  if Eq<u64>(key, 4) {
+                    test::choose_function1$lambda$1
+                  } else {
+                    if Eq<u64>(key, 5) {
+                      test::choose_function1$lambda$2
+                    } else {
+                      if Eq<u64>(key, 6) {
+                        test::choose_function1$lambda$3
+                      } else {
+                        if Eq<u64>(key, 7) {
+                          test::choose_function1$lambda$4
+                        } else {
+                          if Eq<u64>(key, 8) {
+                            earlybind(test::multiply3, 3, 3)
+                          } else {
+                            if Eq<u64>(key, 9) {
+                              earlybind(test::multiply3, 2, 5)
+                            } else {
+                              if Eq<u64>(key, 10) {
+                                test::choose_function1$lambda$5
+                              } else {
+                                if Eq<u64>(key, 11) {
+                                  {
+                                    let g: |(u64, u64)|u64 with copy+store = mod3::multiply;
+                                    earlybind(test::choose_function1$lambda$6, g)
+                                  }
+                                } else {
+                                  if Eq<u64>(key, 12) {
+                                    {
+                                      let h: |u64|u64 with copy+store = test::choose_function1$lambda$7;
+                                      h
+                                    }
+                                  } else {
+                                    if Eq<u64>(key, 14) {
+                                      {
+                                        let i: |u64|u64 with copy+store = test::choose_function1$lambda$8;
+                                        i
+                                      }
+                                    } else {
+                                      {
+                                        let i: |(u64, u64)|u64 with copy+store = test::choose_function1$lambda$9;
+                                        earlybind(test::choose_function1$lambda$10, i)
+                                      }
+                                    }
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          };
+          (f)(x)
+        }
+    }
+    private fun multiply3(x: u64,y: u64,z: u64): u64 {
+        Mul<u64>(Mul<u64>(x, y), z)
+    }
+    public fun test_functions() {
+        {
+          let i: u64 = 0;
+          {
+            let __update_iter_flag: bool = false;
+            loop {
+              if true {
+                if __update_iter_flag {
+                  i: u64 = Add<u64>(i, 1)
+                } else {
+                  __update_iter_flag: bool = true
+                };
+                if Lt<u64>(i, 15) {
+                  {
+                    let y: u64 = test::choose_function1(i, 3);
+                    if Eq<u64>(y, Mul<u64>(Add<u64>(i, 2), 3)) {
+                      Tuple()
+                    } else {
+                      Abort(i)
+                    };
+                    Tuple()
+                  }
+                } else {
+                  break
+                };
+                Tuple()
+              } else {
+                break
+              }
+            };
+            Tuple()
+          }
+        }
+    }
+    private fun choose_function1$lambda$1(y: u64): u64 {
+        mod3::multiply(y, 6)
+    }
+    private fun choose_function1$lambda$2(x: u64): u64 {
+        test::multiply3(x, 3, 2)
+    }
+    private fun choose_function1$lambda$3(x: u64): u64 {
+        mod3::multiply(x, 7)
+    }
+    private fun choose_function1$lambda$4(x: u64): u64 {
+        test::multiply3(4, x, 2)
+    }
+    private fun choose_function1$lambda$5(x: u64): u64 {
+        mod4::alt_multiply(x, 11)
+    }
+    private fun choose_function1$lambda$6(g: |(u64, u64)|u64 with copy+store,x: u64): u64 {
+        (g)(x, 11)
+    }
+    private fun choose_function1$lambda$7(x: u64): u64 {
+        mod3::multiply(x, 12)
+    }
+    private fun choose_function1$lambda$8(x: u64): u64 {
+        test::multiply3(2, x, 2)
+    }
+    private fun choose_function1$lambda$9(x: u64,y: u64): u64 {
+        {
+          let q: u64 = Sub<u64>(y, 1);
+          mod3::multiply(x, Add<u64>(q, 1))
+        }
+    }
+    private fun choose_function1$lambda$10(i: |(u64, u64)|u64 with copy+store,x: u64): u64 {
+        (i)(x, 15)
+    }
+} // end 0x42::test
+
+
+// -- Model dump after env processor specification checker:
+module 0x42::mod4 {
+    public fun alt_multiply(x: u64,y: u64): u64 {
+        Mul<u64>(x, y)
+    }
+} // end 0x42::mod4
+module 0x42::mod3 {
+    public fun multiply(x: u64,y: u64): u64 {
+        Mul<u64>(x, y)
+    }
+} // end 0x42::mod3
+module 0x42::mod2 {
+    friend fun double(x: u64): u64 {
+        Mul<u64>(x, 2)
+    }
+} // end 0x42::mod2
+module 0x42::mod1 {
+    friend fun triple(x: u64): u64 {
+        Mul<u64>(x, 3)
+    }
+} // end 0x42::mod1
+module 0x42::test {
+    use 0x42::mod1; // resolved as: 0x42::mod1
+    use 0x42::mod2; // resolved as: 0x42::mod2
+    use 0x42::mod3; // resolved as: 0x42::mod3
+    use 0x42::mod4::{alt_multiply}; // resolved as: 0x42::mod4
+    private fun add_mul(x: u64,y: u64,z: u64): u64 {
+        Mul<u64>(z, Add<u64>(x, y))
+    }
+    private fun choose_function1(key: u64,x: u64): u64 {
+        {
+          let f: |u64|u64 with copy = if Eq<u64>(key, 0) {
+            mod2::double
+          } else {
+            if Eq<u64>(key, 1) {
+              mod1::triple
+            } else {
+              if Eq<u64>(key, 2) {
+                earlybind(mod3::multiply, 4)
+              } else {
+                if Eq<u64>(key, 3) {
+                  earlybind(mod4::alt_multiply, 5)
+                } else {
+                  if Eq<u64>(key, 4) {
+                    test::choose_function1$lambda$1
+                  } else {
+                    if Eq<u64>(key, 5) {
+                      test::choose_function1$lambda$2
+                    } else {
+                      if Eq<u64>(key, 6) {
+                        test::choose_function1$lambda$3
+                      } else {
+                        if Eq<u64>(key, 7) {
+                          test::choose_function1$lambda$4
+                        } else {
+                          if Eq<u64>(key, 8) {
+                            earlybind(test::multiply3, 3, 3)
+                          } else {
+                            if Eq<u64>(key, 9) {
+                              earlybind(test::multiply3, 2, 5)
+                            } else {
+                              if Eq<u64>(key, 10) {
+                                test::choose_function1$lambda$5
+                              } else {
+                                if Eq<u64>(key, 11) {
+                                  {
+                                    let g: |(u64, u64)|u64 with copy+store = mod3::multiply;
+                                    earlybind(test::choose_function1$lambda$6, g)
+                                  }
+                                } else {
+                                  if Eq<u64>(key, 12) {
+                                    {
+                                      let h: |u64|u64 with copy+store = test::choose_function1$lambda$7;
+                                      h
+                                    }
+                                  } else {
+                                    if Eq<u64>(key, 14) {
+                                      {
+                                        let i: |u64|u64 with copy+store = test::choose_function1$lambda$8;
+                                        i
+                                      }
+                                    } else {
+                                      {
+                                        let i: |(u64, u64)|u64 with copy+store = test::choose_function1$lambda$9;
+                                        earlybind(test::choose_function1$lambda$10, i)
+                                      }
+                                    }
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          };
+          (f)(x)
+        }
+    }
+    private fun multiply3(x: u64,y: u64,z: u64): u64 {
+        Mul<u64>(Mul<u64>(x, y), z)
+    }
+    public fun test_functions() {
+        {
+          let i: u64 = 0;
+          {
+            let __update_iter_flag: bool = false;
+            loop {
+              if true {
+                if __update_iter_flag {
+                  i: u64 = Add<u64>(i, 1)
+                } else {
+                  __update_iter_flag: bool = true
+                };
+                if Lt<u64>(i, 15) {
+                  {
+                    let y: u64 = test::choose_function1(i, 3);
+                    if Eq<u64>(y, Mul<u64>(Add<u64>(i, 2), 3)) {
+                      Tuple()
+                    } else {
+                      Abort(i)
+                    };
+                    Tuple()
+                  }
+                } else {
+                  break
+                };
+                Tuple()
+              } else {
+                break
+              }
+            };
+            Tuple()
+          }
+        }
+    }
+    private fun choose_function1$lambda$1(y: u64): u64 {
+        mod3::multiply(y, 6)
+    }
+    private fun choose_function1$lambda$2(x: u64): u64 {
+        test::multiply3(x, 3, 2)
+    }
+    private fun choose_function1$lambda$3(x: u64): u64 {
+        mod3::multiply(x, 7)
+    }
+    private fun choose_function1$lambda$4(x: u64): u64 {
+        test::multiply3(4, x, 2)
+    }
+    private fun choose_function1$lambda$5(x: u64): u64 {
+        mod4::alt_multiply(x, 11)
+    }
+    private fun choose_function1$lambda$6(g: |(u64, u64)|u64 with copy+store,x: u64): u64 {
+        (g)(x, 11)
+    }
+    private fun choose_function1$lambda$7(x: u64): u64 {
+        mod3::multiply(x, 12)
+    }
+    private fun choose_function1$lambda$8(x: u64): u64 {
+        test::multiply3(2, x, 2)
+    }
+    private fun choose_function1$lambda$9(x: u64,y: u64): u64 {
+        {
+          let q: u64 = Sub<u64>(y, 1);
+          mod3::multiply(x, Add<u64>(q, 1))
+        }
+    }
+    private fun choose_function1$lambda$10(i: |(u64, u64)|u64 with copy+store,x: u64): u64 {
+        (i)(x, 15)
+    }
+} // end 0x42::test
+
+
+// -- Model dump after env processor specification rewriter:
+module 0x42::mod4 {
+    public fun alt_multiply(x: u64,y: u64): u64 {
+        Mul<u64>(x, y)
+    }
+} // end 0x42::mod4
+module 0x42::mod3 {
+    public fun multiply(x: u64,y: u64): u64 {
+        Mul<u64>(x, y)
+    }
+} // end 0x42::mod3
+module 0x42::mod2 {
+    friend fun double(x: u64): u64 {
+        Mul<u64>(x, 2)
+    }
+} // end 0x42::mod2
+module 0x42::mod1 {
+    friend fun triple(x: u64): u64 {
+        Mul<u64>(x, 3)
+    }
+} // end 0x42::mod1
+module 0x42::test {
+    use 0x42::mod1; // resolved as: 0x42::mod1
+    use 0x42::mod2; // resolved as: 0x42::mod2
+    use 0x42::mod3; // resolved as: 0x42::mod3
+    use 0x42::mod4::{alt_multiply}; // resolved as: 0x42::mod4
+    private fun add_mul(x: u64,y: u64,z: u64): u64 {
+        Mul<u64>(z, Add<u64>(x, y))
+    }
+    private fun choose_function1(key: u64,x: u64): u64 {
+        {
+          let f: |u64|u64 with copy = if Eq<u64>(key, 0) {
+            mod2::double
+          } else {
+            if Eq<u64>(key, 1) {
+              mod1::triple
+            } else {
+              if Eq<u64>(key, 2) {
+                earlybind(mod3::multiply, 4)
+              } else {
+                if Eq<u64>(key, 3) {
+                  earlybind(mod4::alt_multiply, 5)
+                } else {
+                  if Eq<u64>(key, 4) {
+                    test::choose_function1$lambda$1
+                  } else {
+                    if Eq<u64>(key, 5) {
+                      test::choose_function1$lambda$2
+                    } else {
+                      if Eq<u64>(key, 6) {
+                        test::choose_function1$lambda$3
+                      } else {
+                        if Eq<u64>(key, 7) {
+                          test::choose_function1$lambda$4
+                        } else {
+                          if Eq<u64>(key, 8) {
+                            earlybind(test::multiply3, 3, 3)
+                          } else {
+                            if Eq<u64>(key, 9) {
+                              earlybind(test::multiply3, 2, 5)
+                            } else {
+                              if Eq<u64>(key, 10) {
+                                test::choose_function1$lambda$5
+                              } else {
+                                if Eq<u64>(key, 11) {
+                                  {
+                                    let g: |(u64, u64)|u64 with copy+store = mod3::multiply;
+                                    earlybind(test::choose_function1$lambda$6, g)
+                                  }
+                                } else {
+                                  if Eq<u64>(key, 12) {
+                                    {
+                                      let h: |u64|u64 with copy+store = test::choose_function1$lambda$7;
+                                      h
+                                    }
+                                  } else {
+                                    if Eq<u64>(key, 14) {
+                                      {
+                                        let i: |u64|u64 with copy+store = test::choose_function1$lambda$8;
+                                        i
+                                      }
+                                    } else {
+                                      {
+                                        let i: |(u64, u64)|u64 with copy+store = test::choose_function1$lambda$9;
+                                        earlybind(test::choose_function1$lambda$10, i)
+                                      }
+                                    }
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          };
+          (f)(x)
+        }
+    }
+    private fun multiply3(x: u64,y: u64,z: u64): u64 {
+        Mul<u64>(Mul<u64>(x, y), z)
+    }
+    public fun test_functions() {
+        {
+          let i: u64 = 0;
+          {
+            let __update_iter_flag: bool = false;
+            loop {
+              if true {
+                if __update_iter_flag {
+                  i: u64 = Add<u64>(i, 1)
+                } else {
+                  __update_iter_flag: bool = true
+                };
+                if Lt<u64>(i, 15) {
+                  {
+                    let y: u64 = test::choose_function1(i, 3);
+                    if Eq<u64>(y, Mul<u64>(Add<u64>(i, 2), 3)) {
+                      Tuple()
+                    } else {
+                      Abort(i)
+                    };
+                    Tuple()
+                  }
+                } else {
+                  break
+                };
+                Tuple()
+              } else {
+                break
+              }
+            };
+            Tuple()
+          }
+        }
+    }
+    private fun choose_function1$lambda$1(y: u64): u64 {
+        mod3::multiply(y, 6)
+    }
+    private fun choose_function1$lambda$2(x: u64): u64 {
+        test::multiply3(x, 3, 2)
+    }
+    private fun choose_function1$lambda$3(x: u64): u64 {
+        mod3::multiply(x, 7)
+    }
+    private fun choose_function1$lambda$4(x: u64): u64 {
+        test::multiply3(4, x, 2)
+    }
+    private fun choose_function1$lambda$5(x: u64): u64 {
+        mod4::alt_multiply(x, 11)
+    }
+    private fun choose_function1$lambda$6(g: |(u64, u64)|u64 with copy+store,x: u64): u64 {
+        (g)(x, 11)
+    }
+    private fun choose_function1$lambda$7(x: u64): u64 {
+        mod3::multiply(x, 12)
+    }
+    private fun choose_function1$lambda$8(x: u64): u64 {
+        test::multiply3(2, x, 2)
+    }
+    private fun choose_function1$lambda$9(x: u64,y: u64): u64 {
+        {
+          let q: u64 = Sub<u64>(y, 1);
+          mod3::multiply(x, Add<u64>(q, 1))
+        }
+    }
+    private fun choose_function1$lambda$10(i: |(u64, u64)|u64 with copy+store,x: u64): u64 {
+        (i)(x, 15)
+    }
+} // end 0x42::test
+
+
+
+Diagnostics:
+error: Function-typed values not yet supported except as parameters to calls to inline functions
+   ┌─ tests/lambda/storable/doable_func.move:39:17
+   │
+39 │                 mod2::double
+   │                 ^^^^^^^^^^^^
+
+error: Function-typed values not yet supported except as parameters to calls to inline functions
+   ┌─ tests/lambda/storable/doable_func.move:41:17
+   │
+41 │                 mod1::triple
+   │                 ^^^^^^^^^^^^
+
+error: Function-typed values not yet supported except as parameters to calls to inline functions
+   ┌─ tests/lambda/storable/doable_func.move:43:17
+   │
+43 │                 move |x| mod3::multiply(4, x)
+   │                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Function-typed values not yet supported except as parameters to calls to inline functions
+   ┌─ tests/lambda/storable/doable_func.move:46:17
+   │
+46 │                 move |y| alt_multiply(x, y)
+   │                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Function-typed values not yet supported except as parameters to calls to inline functions
+   ┌─ tests/lambda/storable/doable_func.move:49:17
+   │
+49 │                 move |y| mod3::multiply(y, x)
+   │                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Function-typed values not yet supported except as parameters to calls to inline functions
+   ┌─ tests/lambda/storable/doable_func.move:51:17
+   │
+51 │                 move |x| multiply3(x, 3, 2)
+   │                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Function-typed values not yet supported except as parameters to calls to inline functions
+   ┌─ tests/lambda/storable/doable_func.move:53:17
+   │
+53 │                 move |x| mod3::multiply(x, 7)
+   │                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Function-typed values not yet supported except as parameters to calls to inline functions
+   ┌─ tests/lambda/storable/doable_func.move:55:17
+   │
+55 │                 move |x| multiply3(4, x, 2)
+   │                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Function-typed values not yet supported except as parameters to calls to inline functions
+   ┌─ tests/lambda/storable/doable_func.move:57:17
+   │
+57 │                 move |x| multiply3(3, 3, x)
+   │                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Function-typed values not yet supported except as parameters to calls to inline functions
+   ┌─ tests/lambda/storable/doable_func.move:61:17
+   │
+61 │                 move |z| multiply3(x, y, z)
+   │                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Function-typed values not yet supported except as parameters to calls to inline functions
+   ┌─ tests/lambda/storable/doable_func.move:64:17
+   │
+64 │                 move |x| alt_multiply(x, z) with copy
+   │                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Function-typed values not yet supported except as parameters to calls to inline functions
+   ┌─ tests/lambda/storable/doable_func.move:66:37
+   │
+66 │                 let g = move |x, y| mod3::multiply(x, y) with copy+drop;
+   │                                     ^^^^^^^^^^^^^^^^^^^^
+
+error: Calls to function values other than inline function parameters not yet supported
+   ┌─ tests/lambda/storable/doable_func.move:67:26
+   │
+67 │                 move |x| g(x, 11)
+   │                          ^^^^^^^^
+
+error: Function-typed values not yet supported except as parameters to calls to inline functions
+   ┌─ tests/lambda/storable/doable_func.move:67:17
+   │
+67 │                 move |x| g(x, 11)
+   │                 ^^^^^^^^^^^^^^^^^
+
+error: Function-typed values not yet supported except as parameters to calls to inline functions
+   ┌─ tests/lambda/storable/doable_func.move:69:25
+   │
+69 │                 let h = move |x| mod3::multiply(x, 12) with copy;
+   │                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Function-typed values not yet supported except as parameters to calls to inline functions
+   ┌─ tests/lambda/storable/doable_func.move:72:25
+   │
+72 │                 let i = move |x| multiply3(2, x, 2);
+   │                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Function-typed values not yet supported except as parameters to calls to inline functions
+   ┌─ tests/lambda/storable/doable_func.move:75:25
+   │
+75 │                 let i = move |x, y| { let q = y - 1; 0x42::mod3::multiply(x, q + 1)  };
+   │                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Calls to function values other than inline function parameters not yet supported
+   ┌─ tests/lambda/storable/doable_func.move:76:26
+   │
+76 │                 move |x| i(x, 15)
+   │                          ^^^^^^^^
+
+error: Function-typed values not yet supported except as parameters to calls to inline functions
+   ┌─ tests/lambda/storable/doable_func.move:76:17
+   │
+76 │                 move |x| i(x, 15)
+   │                 ^^^^^^^^^^^^^^^^^
+
+error: Calls to function values other than inline function parameters not yet supported
+   ┌─ tests/lambda/storable/doable_func.move:78:9
+   │
+78 │         f(x)
+   │         ^^^^
diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/doable_func.move b/third_party/move/move-compiler-v2/tests/lambda/storable/doable_func.move
new file mode 100644
index 0000000000000..e53e9c9d3dc45
--- /dev/null
+++ b/third_party/move/move-compiler-v2/tests/lambda/storable/doable_func.move
@@ -0,0 +1,93 @@
+module 0x42::mod1 {
+    package fun triple(x: u64) : u64 {
+        x * 3
+    }
+}
+
+module 0x42::mod2 {
+    friend 0x42::test;
+    friend fun double(x: u64): u64 {
+        x * 2
+    }
+}
+
+module 0x42::mod3 {
+    public fun multiply(x: u64, y: u64): u64 {
+        x * y
+    }
+}
+
+module 0x42::mod4 {
+    public fun alt_multiply(x: u64, y: u64): u64 {
+        x * y
+    }
+}
+
+module 0x42::test {
+    use 0x42::mod1;
+    use 0x42::mod2;
+    use 0x42::mod3;
+    use 0x42::mod4::alt_multiply;
+    fun multiply3(x: u64, y: u64, z: u64): u64 {
+        x * y * z
+    }
+
+    // compute ((key + 2) * x) in different ways
+    fun choose_function1(key: u64, x: u64): u64 {
+        let f =
+            if (key == 0) {
+                mod2::double
+            } else if (key == 1) {
+                mod1::triple
+            } else if (key == 2) {
+                move |x| mod3::multiply(4, x)
+            } else if (key == 3) {
+                let x = 5;
+                move |y| alt_multiply(x, y)
+            } else if (key == 4) {
+                let x = 6;
+                move |y| mod3::multiply(y, x)
+            } else if (key == 5) {
+                move |x| multiply3(x, 3, 2)
+            } else if (key == 6) {
+                move |x| mod3::multiply(x, 7)
+            } else if (key == 7) {
+                move |x| multiply3(4, x, 2)
+            } else if (key == 8) {
+                move |x| multiply3(3, 3, x)
+            } else if (key == 9) {
+                let x = 2;
+                let y = 5;
+                move |z| multiply3(x, y, z)
+            } else if (key == 10) {
+                let z = 11;
+                move |x| alt_multiply(x, z) with copy
+            } else if (key == 11) {
+                let g = move |x, y| mod3::multiply(x, y) with copy+drop;
+                move |x| g(x, 11)
+            } else if (key == 12) {
+                let h = move |x| mod3::multiply(x, 12) with copy;
+                move |x| { h(x) } with copy + drop
+            } else if (key == 14) {
+                let i = move |x| multiply3(2, x, 2);
+                move |z| i(z)
+            } else {
+                let i = move |x, y| { let q = y - 1; 0x42::mod3::multiply(x, q + 1)  };
+                move |x| i(x, 15)
+            };
+        f(x)
+    }
+
+    fun add_mul(x: u64, y: u64, z: u64): u64 {
+        z * (x + y)
+    }
+
+    public fun test_functions() {
+        let x = 3;
+
+        for (i in 0..15) {
+            let y = choose_function1(i, 3);
+            assert!(y == (i + 2) * x, i);
+        }
+    }
+}
diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/parse_errors.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/parse_errors.exp
new file mode 100644
index 0000000000000..a10657000e3ac
--- /dev/null
+++ b/third_party/move/move-compiler-v2/tests/lambda/storable/parse_errors.exp
@@ -0,0 +1,10 @@
+
+Diagnostics:
+error: unexpected token
+   ┌─ tests/lambda/storable/parse_errors.move:10:15
+   │
+10 │         x.y[3](27)
+   │               ^
+   │               │
+   │               Unexpected '('
+   │               Expected ';'
diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/parse_errors.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/parse_errors.lambda.exp
new file mode 100644
index 0000000000000..a10657000e3ac
--- /dev/null
+++ b/third_party/move/move-compiler-v2/tests/lambda/storable/parse_errors.lambda.exp
@@ -0,0 +1,10 @@
+
+Diagnostics:
+error: unexpected token
+   ┌─ tests/lambda/storable/parse_errors.move:10:15
+   │
+10 │         x.y[3](27)
+   │               ^
+   │               │
+   │               Unexpected '('
+   │               Expected ';'
diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/parse_errors.move b/third_party/move/move-compiler-v2/tests/lambda/storable/parse_errors.move
new file mode 100644
index 0000000000000..2c39942fb7a24
--- /dev/null
+++ b/third_party/move/move-compiler-v2/tests/lambda/storable/parse_errors.move
@@ -0,0 +1,107 @@
+module 0x42::mod1 {
+    package fun triple(x: u64) : u64 {
+        x * 3
+    }
+}
+
+module 0x42::mod2 {
+    friend 0x42::test;
+    friend fun double(x: u64): u64 {
+        x.y[3](27)
+    }
+}
+
+module 0x42::mod3 {
+    public fun multiply(x: u64, y: u64): u64 {
+        x * y
+    }
+}
+
+module 0x42::mod4 {
+    public fun alt_multiply(x: u64, y: u64): u64 {
+        x * y
+    }
+}
+
+module 0x42::mod5 {
+    struct S {
+        f: u64,
+        y: |u64|u64 with copy,
+    }
+    fun f(s: S): S {
+        let x = s.y(3);
+        let z = S { f: 4, y: s.y };
+        z
+    }
+}
+
+
+module 0x42::test {
+    use 0x42::mod1;
+    use 0x42::mod2;
+    use 0x42::mod3;
+    use 0x42::mod4::alt_multiply;
+    fun multiply3(x: u64, y: u64, z: u64): u64 {
+        x * y * z
+    }
+
+    // compute ((key + 2) * x) in different ways
+    fun choose_function1(key: u64, x: u64): u64 {
+        let f =
+            if (key == 0) {
+                mod2::double
+            } else if (key == 1) {
+                mod1::triple
+            } else if (key == 2) {
+                move |x| mod3::multiply(4, x)
+            } else if (key == 3) {
+                let x = 5;
+                move |y| alt_multiply(x, y)
+            } else if (key == 4) {
+                let x = 6;
+                move |y| mod3::multiply(y, x)
+            } else if (key == 5) {
+                move |x| multiply3(x, 3, 2)
+            } else if (key == 6) {
+                move |x| mod3::multiply(x, 7)
+            } else if (key == 7) {
+                move |x| multiply3(4, x, 2)
+            } else if (key == 8) {
+                move |x| multiply3(3, 3, x)
+            } else if (key == 9) {
+                let x = 2;
+                let y = 5;
+                move |z| multiply3(x, y, z)
+            } else if (key == 10) {
+                let z = 11;
+                move |x| alt_multiply(x, z) with copy
+            } else if (key == 11) {
+                let g = move |x, y| mod3::multiply(x, y) has copy+drop;
+                move |x| g(x, 11)
+            } else if (key == 12) {
+                let h = move |x| mod3::multiply(x, 12) with copy;
+                move |x| { h(x) } with copy + drop
+            } else if (key == 14) {
+                let i = move |x| multiply3(2, x, 2);
+                move |z| i(z)
+            } else {
+                let i = move |x, y| { let q = y - 1; 0x42::mod3::multiply(x, q + 1)  };
+                move |x| i(x, 15)
+            };
+        f(x)
+    }
+
+    fun add_mul(x: u64, y: u64, z: u64): u64 {
+        z * (x + y)
+    }
+
+    public fun test_functions() {
+        // let sum = vector[];
+        let x = 3;
+
+        for (i in 0..15) {
+            let y = choose_function1(i, 3);
+            assert!(y == (i + 2) * x, i);
+        }
+    }
+}
diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/registry.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/registry.exp
deleted file mode 100644
index a196cfcde9c4c..0000000000000
--- a/third_party/move/move-compiler-v2/tests/lambda/storable/registry.exp
+++ /dev/null
@@ -1,9 +0,0 @@
-
-Diagnostics:
-error: unexpected token
-  ┌─ tests/lambda/storable/registry.move:7:22
-  │
-6 │     struct Function {
-  │                     - To match this '{'
-7 │         f: |u64| u64 has store,
-  │                      ^ Expected '}'
diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/registry.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/registry.lambda.exp
deleted file mode 100644
index a196cfcde9c4c..0000000000000
--- a/third_party/move/move-compiler-v2/tests/lambda/storable/registry.lambda.exp
+++ /dev/null
@@ -1,9 +0,0 @@
-
-Diagnostics:
-error: unexpected token
-  ┌─ tests/lambda/storable/registry.move:7:22
-  │
-6 │     struct Function {
-  │                     - To match this '{'
-7 │         f: |u64| u64 has store,
-  │                      ^ Expected '}'
diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/registry.move b/third_party/move/move-compiler-v2/tests/lambda/storable/registry.move
deleted file mode 100644
index a6fd8bfab655c..0000000000000
--- a/third_party/move/move-compiler-v2/tests/lambda/storable/registry.move
+++ /dev/null
@@ -1,109 +0,0 @@
-module 0x42::test {
-    struct Registry {
-        functions: vector<Function>
-    }
-
-    struct Function {
-        f: |u64| u64 has store,
-        key: u64
-    }
-
-    enum Option<T> {
-        None(),
-        Some(T)
-    };
-
-    fun get_function(v: &vector<Function>, k: u64): Option<Function> {
-        mut x = Option<Function>::None;
-        for_each_ref(v, |f: &Function| {
-            if f.key == k {
-                x = f.f
-            }
-        });
-        x
-    }
-
-    fun replace_or_add_function(v: &mut vector<Function>, k: u64, f: |u64| u64 has store): Option<Function> {
-        mut done = false;
-        for_each_mut(v, |f: &mut Function| {
-            if f.key == k {
-                f.f = f;
-                done = true;
-            }
-        });
-        if !done {
-            let new_record = Function { f: f, key: k };
-            v.append(new_record);
-        }
-    }
-
-    fun register(owner: &signer, f: |u64| u64 has store, k: u64) acquires Registry {
-        let addr = owner.address;
-        if !exists<Registry>(addr) {
-            let new_registry = Registry {
-                functions: vector[]
-            };
-            move_to<Registry>(owner, registry);
-        }
-        let registry = borrow_global_mut<Registry>(addr);
-        replace_or_add_function(&mut registry.functions, k, f);
-    }
-
-    fun invoke(addr: address, k: u64, x: u64): Option<u64> acquires Registry {
-        if !exists<Registry>(addr) {
-            return Option<u64>::None
-        }
-        let registry = borrow_global<Registry>(addr);
-        match get_function(registry.functions, k) {
-            Some(func) => {
-                let Function { f: f, key: key } = &func;
-                Some(f(x))
-            },
-            _ => {
-                Option<u64>::None
-            }
-        }
-    }
-
-    fun double(x: u64):u64 {
-        x * 2
-    }
-
-    fun triple(x: u64):u64 {
-        x * 3
-    }
-
-    public fun multiply(x: u64, y: u64): u64 {
-        x * y
-    }
-
-    fun multiply_by_x(x: u64): |u64|u64 has store {
-        curry(&multiply, x)
-    }
-
-
-    #[test(a = @0x42)]
-    test_registry1(a; signer) {
-        register(a, &double, 2);
-        register(a, &negate, 3);
-        register(a, multiply_by_x(4), 4);
-        register(a, multiply_by_x(5), 5);
-
-        match invoke(a, 2, 10) {
-            Some(x) => { assert!(x == 20); }
-            _ => assert!(false);
-        }
-        match invoke(a, 3, 11) {
-            Some(x) => { assert!(x == 33); }
-            _ => assert!(false);
-        }
-        match invoke(a, 4, 2) {
-            Some(x) => { assert!(x == 8); }
-            _ => assert!(false);
-        }
-        match invoke(a, 5, 3) {
-            Some(x) => { assert!(x == 15); }
-            _ => assert!(false);
-        }
-    }
-}
diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/registry_errors.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/registry_errors.exp
new file mode 100644
index 0000000000000..7c9e57dffddbf
--- /dev/null
+++ b/third_party/move/move-compiler-v2/tests/lambda/storable/registry_errors.exp
@@ -0,0 +1,37 @@
+
+Diagnostics:
+error: unsupported language construct
+  ┌─ tests/lambda/storable/registry_errors.move:9:22
+  │
+9 │         f: |u64| u64 with store,
+  │                      ^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/registry_errors.move:28:80
+   │
+28 │     fun replace_or_add_function(v: &mut vector<Function>, k: u64, f: |u64| u64 with store): Option<Function> {
+   │                                                                                ^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/registry_errors.move:42:47
+   │
+42 │     fun register(owner: &signer, f: |u64| u64 with store, k: u64) acquires Registry {
+   │                                               ^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/registry_errors.move:91:41
+   │
+91 │     fun multiply_by_x(x: u64): |u64|u64 with store {
+   │                                         ^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/registry_errors.move:95:42
+   │
+95 │     fun multiply_by_x2(x: u64): |u64|u64 with store {
+   │                                          ^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/registry_errors.move:96:9
+   │
+96 │         move |y| multiply(x, y)
+   │         ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/registry_errors.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/registry_errors.lambda.exp
new file mode 100644
index 0000000000000..0cc07aff247e8
--- /dev/null
+++ b/third_party/move/move-compiler-v2/tests/lambda/storable/registry_errors.lambda.exp
@@ -0,0 +1,83 @@
+
+Diagnostics:
+error: function type `|u64|u64 with store` is not allowed as a field type
+  ┌─ tests/lambda/storable/registry_errors.move:9:12
+  │
+9 │         f: |u64| u64 with store,
+  │            ^^^^^^^^^^^^^^^^^^^^
+  │
+  = required by declaration of field `f`
+
+error: function type `|u64|u64 with store` is not allowed as a type argument (type was inferred)
+   ┌─ tests/lambda/storable/registry_errors.move:22:21
+   │
+13 │     enum Option<T> {
+   │                 - declaration of type parameter `T`
+   ·
+22 │                 x = Option::Some(f.f)
+   │                     ^^^^^^^^^^^^
+   │
+   = required by instantiating type parameter `T` of struct `Option`
+
+error: expected `&mut Function` but found a value of type `|u64|u64 with store`
+   ┌─ tests/lambda/storable/registry_errors.move:32:17
+   │
+32 │                 f.f = f;
+   │                 ^^^
+
+error: undeclared receiver function `append` for type `vector<Function>`
+   ┌─ tests/lambda/storable/registry_errors.move:38:13
+   │
+38 │             v.append(new_record);
+   │             ^^^^^^^^^^^^^^^^^^^^
+
+error: cannot return nothing from a function with result type `Option<Function>`
+   ┌─ tests/lambda/storable/registry_errors.move:38:33
+   │
+38 │             v.append(new_record);
+   │                                 ^
+
+error: cannot return nothing from a function with result type `Option<Function>`
+   ┌─ tests/lambda/storable/registry_errors.move:36:9
+   │
+36 │ ╭         if (!done) {
+37 │ │             let new_record = Function { f: f, key: k };
+38 │ │             v.append(new_record);
+39 │ │         }
+   │ ╰─────────^
+
+error: expected a struct with field `address` but found `signer`
+   ┌─ tests/lambda/storable/registry_errors.move:43:20
+   │
+43 │         let addr = owner.address;
+   │                    ^^^^^
+
+error: undeclared `registry`
+   ┌─ tests/lambda/storable/registry_errors.move:48:38
+   │
+48 │             move_to<Registry>(owner, registry);
+   │                                      ^^^^^^^^
+
+error: cannot pass `vector<Function>` to a function which expects argument of type `&vector<Function>`
+   ┌─ tests/lambda/storable/registry_errors.move:68:29
+   │
+68 │         match (get_function(registry.functions, k)) {
+   │                             ^^^^^^^^^^^^^^^^^^
+
+error: undeclared struct `test::Some`
+   ┌─ tests/lambda/storable/registry_errors.move:69:13
+   │
+69 │             Some(func) => {
+   │             ^^^^
+
+error: undeclared `func`
+   ┌─ tests/lambda/storable/registry_errors.move:70:52
+   │
+70 │                 let Function { f: f, key: key } = &func;
+   │                                                    ^^^^
+
+error: expected `|u64|u64 with copy+store` but found a value of type `&|u64|u64 with store`
+   ┌─ tests/lambda/storable/registry_errors.move:71:22
+   │
+71 │                 Some(f(x))
+   │                      ^^^^
diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/registry_errors.move b/third_party/move/move-compiler-v2/tests/lambda/storable/registry_errors.move
new file mode 100644
index 0000000000000..e79347c2f55ed
--- /dev/null
+++ b/third_party/move/move-compiler-v2/tests/lambda/storable/registry_errors.move
@@ -0,0 +1,128 @@
+module 0x42::test {
+    use std::vector;
+
+    struct Registry has key {
+        functions: vector<Function>
+    }
+
+    struct Function has store {
+        f: |u64| u64 with store,
+        key: u64
+    }
+
+    enum Option<T> {
+        None(),
+        Some(T)
+    }
+
+    fun get_function(v: &vector<Function>, k: u64): Option<Function> {
+        let x = Option::None();
+        vector::for_each_ref(v, |f: &Function| {
+            if (f.key == k) {
+                x = Option::Some(f.f)
+            }
+        });
+        x
+    }
+
+    fun replace_or_add_function(v: &mut vector<Function>, k: u64, f: |u64| u64 with store): Option<Function> {
+        let done = false;
+        vector::for_each_mut(v, |f: &mut Function| {
+            if (f.key == k) {
+                f.f = f;
+                done = true;
+            }
+        });
+        if (!done) {
+            let new_record = Function { f: f, key: k };
+            v.append(new_record);
+        }
+    }
+
+    fun register(owner: &signer, f: |u64| u64 with store, k: u64) acquires Registry {
+        let addr = owner.address;
+        if (!exists<Registry>(addr)) {
+            let new_registry = Registry {
+                functions: vector[]
+            };
+            move_to<Registry>(owner, registry);
+        };
+        let registry = borrow_global_mut<Registry>(addr);
+        replace_or_add_function(&mut registry.functions, k, f);
+    }
+
+    fun invoke(addr: address, k: u64, x: u64): Option<u64> acquires Registry {
+        if (!exists<Registry>(addr)) {
+            return Option::None;
+        };
+        let registry = borrow_global<Registry>(addr);
+        if (x == 1) {
+            return Option::None;
+        };
+        if (x == 2) {
+            return Option::None();
+        };
+        if (x == 6) {
+            return Option::None()
+        };
+        match (get_function(registry.functions, k)) {
+            Some(func) => {
+                let Function { f: f, key: key } = &func;
+                Some(f(x))
+            },
+            _ => {
+                Option::None()
+            }
+        }
+    }
+
+    fun double(x: u64):u64 {
+        x * 2
+    }
+
+    fun triple(x: u64):u64 {
+        x * 3
+    }
+
+    public fun multiply(x: u64, y: u64): u64 {
+        x * y
+    }
+
+    fun multiply_by_x(x: u64): |u64|u64 with store {
+        |y| multiply(x, y)
+    }
+
+    fun multiply_by_x2(x: u64): |u64|u64 with store {
+        move |y| multiply(x, y)
+    }
+
+    #[test(a = @0x42)]
+    fun test_registry1(a: signer) {
+        register(a, double, 2);
+        register(a, negate, 3);
+        register(a, multiply_by_x(4), 4);
+        register(a, multiply_by_x(5), 5);
+        register(a, multiply_by_x2(6), 6);
+
+        match (invoke(a, 2, 10)) {
+            Some(x) => { assert!(x == 20); }
+            _ => assert!(false),
+        };
+        match (invoke(a, 3, 11)) {
+            Some(x) => { assert!(x == 33); }
+            _ => assert!(false),
+        };
+        match (invoke(a, 4, 2)) {
+            Some(x) => { assert!(x == 8); },
+            _ => assert!(false),
+        };
+        match (invoke(a, 5, 3)) {
+            Some(x) => { assert!(x == 15); }
+            _ => assert!(false),
+        };
+        match (invoke(a, 6, 3)) {
+            Some(x) => { assert!(x == 18); }
+            _ => assert!(false),
+        };
+    }
+}
diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/registry_ok.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/registry_ok.exp
new file mode 100644
index 0000000000000..9292304f56251
--- /dev/null
+++ b/third_party/move/move-compiler-v2/tests/lambda/storable/registry_ok.exp
@@ -0,0 +1,43 @@
+
+Diagnostics:
+error: unsupported language construct
+   ┌─ tests/lambda/storable/registry_ok.move:10:22
+   │
+10 │         f: |u64| u64 with store+copy,
+   │                      ^^^^^^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/registry_ok.move:29:84
+   │
+29 │     fun replace_or_add_function(v: &mut vector<Function>, k: u64, new_f: |u64| u64 with store+copy): Option<|u64| u64 with store+copy> {
+   │                                                                                    ^^^^^^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/registry_ok.move:29:119
+   │
+29 │     fun replace_or_add_function(v: &mut vector<Function>, k: u64, new_f: |u64| u64 with store+copy): Option<|u64| u64 with store+copy> {
+   │                                                                                                                       ^^^^^^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/registry_ok.move:53:47
+   │
+53 │     fun register(owner: &signer, f: |u64| u64 with store+copy, k: u64) acquires Registry {
+   │                                               ^^^^^^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types
+
+error: unsupported language construct
+    ┌─ tests/lambda/storable/registry_ok.move:106:41
+    │
+106 │     fun multiply_by_x(x: u64): |u64|u64 with store {
+    │                                         ^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types
+
+error: unsupported language construct
+    ┌─ tests/lambda/storable/registry_ok.move:110:42
+    │
+110 │     fun multiply_by_x2(x: u64): |u64|u64 with store {
+    │                                          ^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types
+
+error: unsupported language construct
+    ┌─ tests/lambda/storable/registry_ok.move:111:9
+    │
+111 │         move |y| multiply(x, y)
+    │         ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/registry_ok.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/registry_ok.lambda.exp
new file mode 100644
index 0000000000000..cfe0567301c9b
--- /dev/null
+++ b/third_party/move/move-compiler-v2/tests/lambda/storable/registry_ok.lambda.exp
@@ -0,0 +1,42 @@
+
+Diagnostics:
+error: function type `|u64|u64 with copy+store` is not allowed as a field type
+   ┌─ tests/lambda/storable/registry_ok.move:10:12
+   │
+10 │         f: |u64| u64 with store+copy,
+   │            ^^^^^^^^^^^^^^^^^^^^^^^^^
+   │
+   = required by declaration of field `f`
+
+error: function type `|u64|u64 with copy+store` is not allowed as a type argument (type was inferred)
+   ┌─ tests/lambda/storable/registry_ok.move:23:21
+   │
+14 │     enum Option<T> {
+   │                 - declaration of type parameter `T`
+   ·
+23 │                 x = Option::Some(f.f)
+   │                     ^^^^^^^^^^^^
+   │
+   = required by instantiating type parameter `T` of struct `Option`
+
+error: function type `|u64|u64 with copy+store` is not allowed as a type argument
+   ┌─ tests/lambda/storable/registry_ok.move:29:109
+   │
+14 │     enum Option<T> {
+   │                 - declaration of type parameter `T`
+   ·
+29 │     fun replace_or_add_function(v: &mut vector<Function>, k: u64, new_f: |u64| u64 with store+copy): Option<|u64| u64 with store+copy> {
+   │                                                                                                             ^^^^^^^^^^^^^^^^^^^^^^^^^
+   │
+   = required by instantiating type parameter `T` of struct `Option`
+
+error: function type `|u64|u64 with copy+store` is not allowed as a type argument (type was inferred)
+   ┌─ tests/lambda/storable/registry_ok.move:33:26
+   │
+14 │     enum Option<T> {
+   │                 - declaration of type parameter `T`
+   ·
+33 │                 result = Option::Some(f.f);
+   │                          ^^^^^^^^^^^^
+   │
+   = required by instantiating type parameter `T` of struct `Option`
diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/registry_ok.move b/third_party/move/move-compiler-v2/tests/lambda/storable/registry_ok.move
new file mode 100644
index 0000000000000..047415e26d4ef
--- /dev/null
+++ b/third_party/move/move-compiler-v2/tests/lambda/storable/registry_ok.move
@@ -0,0 +1,182 @@
+module 0x42::test {
+    use std::vector;
+    use std::signer;
+
+    struct Registry has key {
+        functions: vector<Function>
+    }
+
+    struct Function has store {
+        f: |u64| u64 with store+copy,
+        key: u64
+    }
+
+    enum Option<T> {
+        None(),
+        Some(T)
+    }
+
+    fun get_function(v: &vector<Function>, k: u64): Option<Function> {
+        let x = Option::None;
+        vector::for_each_ref(v, |f: &Function| {
+            if (f.key == k) {
+                x = Option::Some(f.f)
+            }
+        });
+        x
+    }
+
+    fun replace_or_add_function(v: &mut vector<Function>, k: u64, new_f: |u64| u64 with store+copy): Option<|u64| u64 with store+copy> {
+        let result = Option::None;
+        vector::for_each_mut(v, |f: &mut Function| {
+            if (f.key == k) {
+                result = Option::Some(f.f);
+                f.f = new_f;
+            }
+        });
+        if (result == Option::None) {
+            let new_record = Function { f: new_f, key: k };
+            vector::push_back(v, new_record);
+        };
+        result
+    }
+
+    public fun alt_call_selected_function(v: &vector<Function>, k: u64, x: u64): Option<u64> {
+        for (i in 0..(vector::length(v))) {
+            if (v[i].key == k) {
+                return Option::Some((v[i].f)(x))
+            }
+        };
+        None
+    }
+
+    fun register(owner: &signer, f: |u64| u64 with store+copy, k: u64) acquires Registry {
+        let addr = signer::address_of(owner);
+        if (!exists<Registry>(addr)) {
+            let new_registry = Registry {
+                functions: vector[]
+            };
+            move_to<Registry>(owner, new_registry);
+        };
+        let registry = borrow_global_mut<Registry>(addr);
+        replace_or_add_function(&mut registry.functions, k, f);
+    }
+
+    fun invoke(addr: address, k: u64, x: u64): Option<u64> acquires Registry {
+        if (!exists<Registry>(addr)) {
+            return Option::None
+        };
+        let registry = borrow_global<Registry>(addr);
+        match (get_function(&registry.functions, k)) {
+            Some(func) => {
+                let Function { f: f, key: key } = func;
+                Option::Some(f(x))
+            },
+            _ => {
+                Option::None
+            }
+        }
+    }
+
+    fun invoke2(addr: address, k: u64, x: u64): Option<u64> acquires Registry {
+        if (!exists<Registry>(addr)) {
+            return Option::None
+        };
+        let registry = borrow_global<Registry>(addr);
+        for (i in 0..(vector::length(&registry.functions))) {
+            if (registry.functions[i].key == k) {
+                return Option::Some((registry.functions[i].f)(x))
+            }
+        };
+        None
+    }
+
+    fun double(x: u64):u64 {
+        x * 2
+    }
+
+    fun triple(x: u64):u64 {
+        x * 3
+    }
+
+    public fun multiply(x: u64, y: u64): u64 {
+        x * y
+    }
+
+    fun multiply_by_x(x: u64): |u64|u64 with store {
+        |y| multiply(x, y)
+    }
+
+    fun multiply_by_x2(x: u64): |u64|u64 with store {
+        move |y| multiply(x, y)
+    }
+
+    #[test(a = @0x42)]
+    fun test_registry1(a: signer) {
+        register(a, double, 2);
+        register(a, negate, 3);
+        register(a, multiply_by_x(4), 4);
+        register(a, multiply_by_x(5), 5);
+        register(a, multiply_by_x2(6), 6);
+
+        match (invoke(a, 2, 10)) {
+            Option::Some(x) => { assert!(x == 20); }
+            _ => assert!(false)
+        };
+        match (invoke(a, 3, 11)) {
+            Option::Some(x) => { assert!(x == 33); }
+            _ => assert!(false)
+        };
+        match (invoke(a, 4, 2)) {
+            Option::Some(x) => { assert!(x == 8); }
+            _ => assert!(false)
+        };
+        match (invoke(a, 5, 3)) {
+            Option::Some(x) => { assert!(x == 15); }
+            _ => assert!(false)
+        };
+        match (invoke(a, 6, 3)) {
+            Option::Some(x) => { assert!(x == 18); }
+            _ => assert!(false)
+        };
+    }
+
+    #[test(a = @0x42)]
+    fun test_registry2(a: signer) {
+        register(a, double, 2);
+        register(a, negate, 3);
+        register(a, multiply_by_x(4), 4);
+        register(a, multiply_by_x(5), 5);
+        register(a, multiply_by_x2(6), 6);
+
+        match (invoke2(a, 2, 10)) {
+            Some(x) => { assert!(x == 20); }
+            _ => assert!(false)
+        };
+        match (invoke2(a, 3, 11)) {
+            Some(x) => { assert!(x == 33); }
+            _ => assert!(false)
+        };
+        match (invoke2(a, 4, 2)) {
+            Some(x) => { assert!(x == 8); }
+            _ => assert!(false)
+        };
+        match (invoke2(a, 5, 3)) {
+            Some(x) => { assert!(x == 15); }
+            _ => assert!(false)
+        };
+        match (invoke2(a, 6, 3)) {
+            Some(x) => { assert!(x == 18); }
+            _ => assert!(false)
+        };
+    }
+
+
+    #[test(a = @0x42)]
+    fun test_registry3(a: signer) {
+        register(a, double, 2);
+        let registry = borrow_global<Registry>(a);
+        assert!(registry.functions[0].key == 2);
+        assert!((registry.functions[0].func)(3) == 6);
+    }
+}
diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/retain_funcs.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/retain_funcs.exp
new file mode 100644
index 0000000000000..66d4547f944b1
--- /dev/null
+++ b/third_party/move/move-compiler-v2/tests/lambda/storable/retain_funcs.exp
@@ -0,0 +1,7 @@
+
+Diagnostics:
+error: expected `bool` but found a value of type `integer`
+  ┌─ tests/lambda/storable/retain_funcs.move:6:23
+  │
+6 │         let f = |x| { if (x) { 2 } else { false } };
+  │                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/retain_funcs.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/retain_funcs.lambda.exp
new file mode 100644
index 0000000000000..66d4547f944b1
--- /dev/null
+++ b/third_party/move/move-compiler-v2/tests/lambda/storable/retain_funcs.lambda.exp
@@ -0,0 +1,7 @@
+
+Diagnostics:
+error: expected `bool` but found a value of type `integer`
+  ┌─ tests/lambda/storable/retain_funcs.move:6:23
+  │
+6 │         let f = |x| { if (x) { 2 } else { false } };
+  │                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/retain_funcs.move b/third_party/move/move-compiler-v2/tests/lambda/storable/retain_funcs.move
new file mode 100644
index 0000000000000..81d75d4fa41ad
--- /dev/null
+++ b/third_party/move/move-compiler-v2/tests/lambda/storable/retain_funcs.move
@@ -0,0 +1,20 @@
+//# publish
+module 0x8675::M {
+    inline fun test1(r: u64): u64 {
+        let t = r;       // t = 10
+        let t2 = 0;      // t2 = 0
+        let f = |x| { if (x) { 2 } else { false } };
+        while (r > 0) {
+            let x = r;   // x = 10,  9,  8,  7,  6,  5,  4,  3,  2,  1
+            r = r - 1;   // r =  9,  8,  7,  6,  5,  4,  3,  2,  1,  0
+            t2 = t2 + x; // t2= 10, 19, 27, 34, 40, 45, 49, 52, 54, 55
+        };
+        let t3 = r + t + t2; // 0 + 10 + 55 = 65
+        t3 // 65
+    }
+    public fun test(): u64 {
+        test1(10)
+    }
+}
+
+//# run 0x8675::M::test
diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.exp
index 38e1020313014..bcd14792c5468 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.exp
@@ -1,10 +1,187 @@
 
 Diagnostics:
-error: unexpected token
-   ┌─ tests/lambda/storable/return_func.move:14:41
-   │
-14 │     fun multiply_by_x(x: u64): |u64|u64 has store {
-   │                                         ^^^
-   │                                         │
-   │                                         Unexpected 'has'
-   │                                         Expected '{'
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:20:41
+   │
+20 │     fun multiply_by_x(x: u64): |u64|u64 with store {
+   │                                         ^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:21:9
+   │
+21 │         move |y| multiply(x, y) with store
+   │         ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:21:33
+   │
+21 │         move |y| multiply(x, y) with store
+   │                                 ^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:24:46
+   │
+24 │     fun choose_function(key: u64) : |u64|u64 with store {
+   │                                              ^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:34:46
+   │
+34 │     fun choose_function2(key: u64): |u64|u64 with store {
+   │                                              ^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:36:13
+   │
+36 │             move |x| double(x) with store
+   │             ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:36:32
+   │
+36 │             move |x| double(x) with store
+   │                                ^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:38:13
+   │
+38 │             move |x| triple(x) with store
+   │             ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:38:32
+   │
+38 │             move |x| triple(x) with store
+   │                                ^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:41:13
+   │
+41 │             move |x| f(x) with store
+   │             ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:41:27
+   │
+41 │             move |x| f(x) with store
+   │                           ^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:44:13
+   │
+44 │             move |x| f(x) with store
+   │             ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:44:27
+   │
+44 │             move |x| f(x) with store
+   │                           ^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:46:21
+   │
+46 │             let f = move |y| multiply(6, y) with store;
+   │                     ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:46:45
+   │
+46 │             let f = move |y| multiply(6, y) with store;
+   │                                             ^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:49:13
+   │
+49 │             move |y| multiply(y, 7) with store
+   │             ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:49:37
+   │
+49 │             move |y| multiply(y, 7) with store
+   │                                     ^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:51:21
+   │
+51 │             let f = move |y| multiply(6, y) with store;
+   │                     ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:51:45
+   │
+51 │             let f = move |y| multiply(6, y) with store;
+   │                                             ^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:52:13
+   │
+52 │             move |x| f(x) with store
+   │             ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:52:27
+   │
+52 │             move |x| f(x) with store
+   │                           ^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:55:13
+   │
+55 │             move |x| f(x) with store
+   │             ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:55:27
+   │
+55 │             move |x| f(x) with store
+   │                           ^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:57:13
+   │
+57 │             move |y| multiply3(y, 3, 4) with store
+   │             ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:57:41
+   │
+57 │             move |y| multiply3(y, 3, 4) with store
+   │                                         ^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:61:47
+   │
+61 │     fun choose_function3(key: u64) : |u64|u64 with store {
+   │                                               ^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:63:21
+   │
+63 │             let f = move |x| double(x) with store;
+   │                     ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:63:40
+   │
+63 │             let f = move |x| double(x) with store;
+   │                                        ^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:66:21
+   │
+66 │             let g = move |x| triple(x) with store;
+   │                     ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:66:40
+   │
+66 │             let g = move |x| triple(x) with store;
+   │                                        ^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions
+
+error: unsupported language construct
+   ┌─ tests/lambda/storable/return_func.move:74:63
+   │
+74 │     public fun test_functions(choose_function: |u64|(|u64|u64 with store)) {
+   │                                                               ^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types
diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.lambda.exp
index 38e1020313014..7dd9a43a5339c 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.lambda.exp
+++ b/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.lambda.exp
@@ -1,10 +1,47 @@
 
 Diagnostics:
-error: unexpected token
-   ┌─ tests/lambda/storable/return_func.move:14:41
-   │
-14 │     fun multiply_by_x(x: u64): |u64|u64 has store {
-   │                                         ^^^
-   │                                         │
-   │                                         Unexpected 'has'
-   │                                         Expected '{'
+error: type `|u64|u64 with copy` is missing required ability `store`
+   ┌─ tests/lambda/storable/return_func.move:26:13
+   │
+26 │             double
+   │             ^^^^^^
+
+error: type `|u64|u64 with copy` is missing required ability `store`
+   ┌─ tests/lambda/storable/return_func.move:28:13
+   │
+28 │             triple
+   │             ^^^^^^
+
+error: expected `|integer|_ with copy+store` but found a value of type `u64`
+   ┌─ tests/lambda/storable/return_func.move:85:37
+   │
+85 │         vector::push_back(&mut sum, f(5));
+   │                                     ^^^^
+
+error: expected `|integer|_ with copy+store` but found a value of type `u64`
+   ┌─ tests/lambda/storable/return_func.move:86:37
+   │
+86 │         vector::push_back(&mut sum, g(7));
+   │                                     ^^^^
+
+error: expected `|integer|_ with copy+store` but found a value of type `u64`
+   ┌─ tests/lambda/storable/return_func.move:87:37
+   │
+87 │         vector::push_back(&mut sum, h(6));
+   │                                     ^^^^
+
+error: function type `|integer|_` is not allowed as a type argument (type was inferred)
+   ┌─ tests/lambda/storable/return_func.move:89:21
+   │
+89 │         let funcs = vector[choose_function(0), choose_function(1), choose_function(2)];
+   │                     ^^^^^^
+   │
+   = required by instantiating vector type parameter
+
+error: function type `|u64|u64 with store` is not allowed as a type argument (type was inferred)
+   ┌─ tests/lambda/storable/return_func.move:89:21
+   │
+89 │         let funcs = vector[choose_function(0), choose_function(1), choose_function(2)];
+   │                     ^^^^^^
+   │
+   = required by instantiating vector type parameter
diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.move b/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.move
index 4f6e078d8a460..40c0e4966cf03 100644
--- a/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.move
+++ b/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.move
@@ -1,4 +1,6 @@
 module 0x42::test {
+    use std::vector;
+
     fun double(x: u64): u64 {
         x * 2
     }
@@ -11,36 +13,57 @@ module 0x42::test {
         x * y
     }
 
-    fun multiply_by_x(x: u64): |u64|u64 has store {
-        curry(&multiply, x)
+    public fun multiply3(x: u64, y: u64, z: u64): u64 {
+        x * y * z
+    }
+
+    fun multiply_by_x(x: u64): |u64|u64 with store {
+        move |y| multiply(x, y) with store
     }
 
-    fun choose_function(key: u64) : |u64|u64 has store {
-        if key == 0 {
-            &double
-        } else if key == 1 {
-            &triple
+    fun choose_function(key: u64) : |u64|u64 with store {
+        if (key == 0) {
+            double
+        } else if (key == 1) {
+            triple
         } else {
             multiply_by_x(4)
         }
     }
 
-    fun choose_function2(key: u64) : |u64|u64 has store {
-        if key == 0 {
-            |x| double(x);
-        } else if key == 1 {
-            |x| triple(x);
+    fun choose_function2(key: u64): |u64|u64 with store {
+        if (key == 0) {
+            move |x| double(x) with store
+        } else if (key == 1) {
+            move |x| triple(x) with store
+        } else if (key == 2) {
+            let f = multiply_by_x(4);
+            move |x| f(x) with store
+        } else if (key == 3) {
+            let f = multiply_by_x(5);
+            move |x| f(x) with store
+        } else if (key == 4) {
+            let f = move |y| multiply(6, y) with store;
+            f
+        } else if (key == 5) {
+            move |y| multiply(y, 7) with store
+        } else if (key == 6) {
+            let f = move |y| multiply(6, y) with store;
+            move |x| f(x) with store
+        } else if (key == 7) {
+            let f = multiply_by_x(5);
+            move |x| f(x) with store
         } else {
-            |x| multiply_by_x(4)(x)
+            move |y| multiply3(y, 3, 4) with store
         }
     }
 
-    fun choose_function3(key: u64) : |u64|u64 has store {
-        if key == 0 {
-            let f = |x| double(x);
+    fun choose_function3(key: u64) : |u64|u64 with store {
+        if (key == 0) {
+            let f = move |x| double(x) with store;
             f
-        } else if key == 1 {
-            let g = |x| triple(x);
+        } else if (key == 1) {
+            let g = move |x| triple(x) with store;
             g
         } else {
             let h = multiply_by_x(4);
@@ -48,32 +71,32 @@ module 0x42::test {
         }
     }
 
-    public fun test_functions(choose_function: |u64|(|u64|u64 has store)) {
-        let sum = vector[];
+    public fun test_functions(choose_function: |u64|(|u64|u64 with store)) {
+        let sum = vector<u64>[];
         let x = 3;
-        sum.push_back(choose_function(0)(x));
-        sum.push_back(choose_function(1)(x));
-        sum.push_back(choose_function(2)(x));
+        vector::push_back(&mut sum, (choose_function(0))(x));
+        vector::push_back(&mut sum, (choose_function(1))(x));
+        vector::push_back(&mut sum, (choose_function(2))(x));
 
         let g = choose_function(1)(x);
         let h = choose_function(2)(x);
         let f = choose_function(0)(x);
 
-        sum.push_back(f(5));
-        sum.push_back(g(7));
-        sum.push_back(h(6));
+        vector::push_back(&mut sum, f(5));
+        vector::push_back(&mut sum, g(7));
+        vector::push_back(&mut sum, h(6));
 
         let funcs = vector[choose_function(0), choose_function(1), choose_function(2)];
-        sum.push_back(f[0](9));
-        sum.push_back(f[1](11));
-        sum.push_back(f[2](13));
+        vector::push_back(&mut sum, (funcs[0])(9));
+        vector::push_back(&mut sum, (funcs[1])(11));
+        vector::push_back(&mut sum, (funcs[2])(13));
 
-        assert!(vector<u64>[6, 9, 12, 10, 21, 24, 18, 33, 52])
+        assert!(sum == vector<u64>[6, 9, 12, 10, 21, 24, 18, 33, 52])
     }
 
     public fun test_function_choosers() {
-        test_functions(&choose_function);
-        test_functions(&choose_function2);
-        test_functions(&choose_function3);
+        test_functions(choose_function);
+        test_functions(choose_function2);
+        test_functions(choose_function3);
     }
 }
diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/simplifier_func.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/simplifier_func.exp
new file mode 100644
index 0000000000000..cbd7f88334ab1
--- /dev/null
+++ b/third_party/move/move-compiler-v2/tests/lambda/storable/simplifier_func.exp
@@ -0,0 +1,51 @@
+
+Diagnostics:
+warning: Unused local variable `f`. Consider removing or prefixing with an underscore: `_f`
+  ┌─ tests/lambda/storable/simplifier_func.move:7:13
+  │
+7 │         let f = |x: u64| { let t = S { x: 3 }; x };
+  │             ^
+
+warning: Unused local variable `t`. Consider removing or prefixing with an underscore: `_t`
+  ┌─ tests/lambda/storable/simplifier_func.move:7:32
+  │
+7 │         let f = |x: u64| { let t = S { x: 3 }; x };
+  │                                ^
+
+// -- Model dump before bytecode pipeline
+module 0x42::mod1 {
+    struct S {
+        x: u64,
+    }
+    public fun triple(x: u64): u64 {
+        {
+          let f: |u64|u64 with copy+store = |x: u64| {
+            let t: S = pack mod1::S(3);
+            x
+          };
+          Mul<u64>(x, 3)
+        }
+    }
+} // end 0x42::mod1
+
+// -- Sourcified model before bytecode pipeline
+module 0x42::mod1 {
+    struct S {
+        x: u64,
+    }
+    public fun triple(x: u64): u64 {
+        let f = |x| {
+            let t = S{x: 3};
+            x
+        };
+        x * 3
+    }
+}
+
+
+Diagnostics:
+error: Function-typed values not yet supported except as parameters to calls to inline functions
+  ┌─ tests/lambda/storable/simplifier_func.move:7:17
+  │
+7 │         let f = |x: u64| { let t = S { x: 3 }; x };
+  │                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/simplifier_func.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/simplifier_func.lambda.exp
new file mode 100644
index 0000000000000..233e8b77f24dd
--- /dev/null
+++ b/third_party/move/move-compiler-v2/tests/lambda/storable/simplifier_func.lambda.exp
@@ -0,0 +1,206 @@
+// -- Model dump before env processor pipeline:
+module 0x42::mod1 {
+    struct S {
+        x: u64,
+    }
+    public fun triple(x: u64): u64 {
+        {
+          let f: |u64|u64 with copy+store = |x: u64| {
+            let t: S = pack mod1::S(3);
+            x
+          };
+          Mul<u64>(x, 3)
+        }
+    }
+} // end 0x42::mod1
+
+
+// -- Model dump after env processor unused checks:
+module 0x42::mod1 {
+    struct S {
+        x: u64,
+    }
+    public fun triple(x: u64): u64 {
+        {
+          let f: |u64|u64 with copy+store = |x: u64| {
+            let t: S = pack mod1::S(3);
+            x
+          };
+          Mul<u64>(x, 3)
+        }
+    }
+} // end 0x42::mod1
+
+
+// -- Model dump after env processor type parameter check:
+module 0x42::mod1 {
+    struct S {
+        x: u64,
+    }
+    public fun triple(x: u64): u64 {
+        {
+          let f: |u64|u64 with copy+store = |x: u64| {
+            let t: S = pack mod1::S(3);
+            x
+          };
+          Mul<u64>(x, 3)
+        }
+    }
+} // end 0x42::mod1
+
+
+// -- Model dump after env processor check recursive struct definition:
+module 0x42::mod1 {
+    struct S {
+        x: u64,
+    }
+    public fun triple(x: u64): u64 {
+        {
+          let f: |u64|u64 with copy+store = |x: u64| {
+            let t: S = pack mod1::S(3);
+            x
+          };
+          Mul<u64>(x, 3)
+        }
+    }
+} // end 0x42::mod1
+
+
+// -- Model dump after env processor check cyclic type instantiation:
+module 0x42::mod1 {
+    struct S {
+        x: u64,
+    }
+    public fun triple(x: u64): u64 {
+        {
+          let f: |u64|u64 with copy+store = |x: u64| {
+            let t: S = pack mod1::S(3);
+            x
+          };
+          Mul<u64>(x, 3)
+        }
+    }
+} // end 0x42::mod1
+
+
+// -- Model dump after env processor unused struct params check:
+module 0x42::mod1 {
+    struct S {
+        x: u64,
+    }
+    public fun triple(x: u64): u64 {
+        {
+          let f: |u64|u64 with copy+store = |x: u64| {
+            let t: S = pack mod1::S(3);
+            x
+          };
+          Mul<u64>(x, 3)
+        }
+    }
+} // end 0x42::mod1
+
+
+// -- Model dump after env processor access and use check before inlining:
+module 0x42::mod1 {
+    struct S {
+        x: u64,
+    }
+    public fun triple(x: u64): u64 {
+        {
+          let f: |u64|u64 with copy+store = |x: u64| {
+            let t: S = pack mod1::S(3);
+            x
+          };
+          Mul<u64>(x, 3)
+        }
+    }
+} // end 0x42::mod1
+
+
+// -- Model dump after env processor inlining:
+module 0x42::mod1 {
+    struct S {
+        x: u64,
+    }
+    public fun triple(x: u64): u64 {
+        {
+          let f: |u64|u64 with copy+store = |x: u64| {
+            let t: S = pack mod1::S(3);
+            x
+          };
+          Mul<u64>(x, 3)
+        }
+    }
+} // end 0x42::mod1
+
+
+// -- Model dump after env processor access and use check after inlining:
+module 0x42::mod1 {
+    struct S {
+        x: u64,
+    }
+    public fun triple(x: u64): u64 {
+        {
+          let f: |u64|u64 with copy+store = |x: u64| {
+            let t: S = pack mod1::S(3);
+            x
+          };
+          Mul<u64>(x, 3)
+        }
+    }
+} // end 0x42::mod1
+
+
+// -- Model dump after env processor acquires check:
+module 0x42::mod1 {
+    struct S {
+        x: u64,
+    }
+    public fun triple(x: u64): u64 {
+        {
+          let f: |u64|u64 with copy+store = |x: u64| {
+            let t: S = pack mod1::S(3);
+            x
+          };
+          Mul<u64>(x, 3)
+        }
+    }
+} // end 0x42::mod1
+
+
+// -- Model dump after env processor simplifier:
+module 0x42::mod1 {
+    struct S {
+        x: u64,
+    }
+    public fun triple(x: u64): u64 {
+        {
+          let f: |u64|u64 with copy+store = |x: u64| {
+            let t: S = pack mod1::S(3);
+            x
+          };
+          Mul<u64>(x, 3)
+        }
+    }
+} // end 0x42::mod1
+
+
+
+Diagnostics:
+warning: Unused local variable `f`. Consider removing or prefixing with an underscore: `_f`
+  ┌─ tests/lambda/storable/simplifier_func.move:7:13
+  │
+7 │         let f = |x: u64| { let t = S { x: 3 }; x };
+  │             ^
+
+warning: Unused local variable `t`. Consider removing or prefixing with an underscore: `_t`
+  ┌─ tests/lambda/storable/simplifier_func.move:7:32
+  │
+7 │         let f = |x: u64| { let t = S { x: 3 }; x };
+  │                                ^
+
+error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call.
+  ┌─ tests/lambda/storable/simplifier_func.move:7:17
+  │
+7 │         let f = |x: u64| { let t = S { x: 3 }; x };
+  │                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/simplifier_func.move b/third_party/move/move-compiler-v2/tests/lambda/storable/simplifier_func.move
new file mode 100644
index 0000000000000..a418d25cf855a
--- /dev/null
+++ b/third_party/move/move-compiler-v2/tests/lambda/storable/simplifier_func.move
@@ -0,0 +1,10 @@
+module 0x42::mod1 {
+    struct S {  // no drop
+        x: u64
+    }
+
+    public fun triple(x: u64) : u64 {
+        let f = |x: u64| { let t = S { x: 3 }; x };
+        x * 3
+    }
+}
diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_complex_expression.exp b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_complex_expression.exp
index eb41afe8197db..83950af3cd058 100644
--- a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_complex_expression.exp
+++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_complex_expression.exp
@@ -1,10 +1,19 @@
 
 Diagnostics:
-error: unexpected token
-  ┌─ tests/more-v1/parser/invalid_call_lhs_complex_expression.move:3:29
+error: expected `|()|_` but found a value of type `integer`
+  ┌─ tests/more-v1/parser/invalid_call_lhs_complex_expression.move:3:20
   │
 3 │         (if (true) 5 else 0)();
-  │                             ^
-  │                             │
-  │                             Unexpected '('
-  │                             Expected ';'
+  │                    ^
+
+error: expected `|()|_` but found a value of type `integer`
+  ┌─ tests/more-v1/parser/invalid_call_lhs_complex_expression.move:3:27
+  │
+3 │         (if (true) 5 else 0)();
+  │                           ^
+
+error: expected `|(integer, integer)|_` but found a value of type `()`
+  ┌─ tests/more-v1/parser/invalid_call_lhs_complex_expression.move:4:9
+  │
+4 │         (while (false) {})(0, 1);
+  │         ^^^^^^^^^^^^^^^^^^
diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_complex_expression2.exp b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_complex_expression2.exp
index 03ed8ceb2af6f..6e260fff7fec5 100644
--- a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_complex_expression2.exp
+++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_complex_expression2.exp
@@ -1,10 +1,19 @@
 
 Diagnostics:
-error: unexpected token
-  ┌─ tests/more-v1/parser/invalid_call_lhs_complex_expression2.move:3:29
+error: expected `|()|_` but found a value of type `integer`
+  ┌─ tests/more-v1/parser/invalid_call_lhs_complex_expression2.move:3:20
   │
 3 │         (if (true) 5 else 0)();
-  │                             ^
-  │                             │
-  │                             Unexpected '('
-  │                             Expected ';'
+  │                    ^
+
+error: expected `|()|_` but found a value of type `integer`
+  ┌─ tests/more-v1/parser/invalid_call_lhs_complex_expression2.move:3:27
+  │
+3 │         (if (true) 5 else 0)();
+  │                           ^
+
+error: expected `|(integer, integer)|_` but found a value of type `()`
+  ┌─ tests/more-v1/parser/invalid_call_lhs_complex_expression2.move:4:9
+  │
+4 │         (while (false) {})(0, 1);
+  │         ^^^^^^^^^^^^^^^^^^
diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_parens_around_name.exp b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_parens_around_name.exp
index 222dec853b372..8d362e905076d 100644
--- a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_parens_around_name.exp
+++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_parens_around_name.exp
@@ -1,10 +1,7 @@
 
 Diagnostics:
-error: unexpected token
-  ┌─ tests/more-v1/parser/invalid_call_lhs_parens_around_name.move:3:14
+error: Calls to function values other than inline function parameters not yet supported
+  ┌─ tests/more-v1/parser/invalid_call_lhs_parens_around_name.move:3:9
   │
 3 │         (foo)()
-  │              ^
-  │              │
-  │              Unexpected '('
-  │              Expected ';'
+  │         ^^^^^^^
diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_parens_around_name2.exp b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_parens_around_name2.exp
index f47f13fe5ecb6..7429935364695 100644
--- a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_parens_around_name2.exp
+++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_parens_around_name2.exp
@@ -1,10 +1,7 @@
 
 Diagnostics:
-error: unexpected token
-  ┌─ tests/more-v1/parser/invalid_call_lhs_parens_around_name2.move:3:14
+error: Calls to function values other than inline function parameters not yet supported
+  ┌─ tests/more-v1/parser/invalid_call_lhs_parens_around_name2.move:3:9
   │
 3 │         (foo)()
-  │              ^
-  │              │
-  │              Unexpected '('
-  │              Expected ';'
+  │         ^^^^^^^
diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_return.exp b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_return.exp
index 332165ecd3108..4890ecb1afef1 100644
--- a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_return.exp
+++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_return.exp
@@ -1,10 +1,7 @@
 
 Diagnostics:
-error: unexpected token
-  ┌─ tests/more-v1/parser/invalid_call_lhs_return.move:3:20
+error: Calls to function values other than inline function parameters not yet supported
+  ┌─ tests/more-v1/parser/invalid_call_lhs_return.move:3:9
   │
 3 │         (return ())(0, 1);
-  │                    ^
-  │                    │
-  │                    Unexpected '('
-  │                    Expected ';'
+  │         ^^^^^^^^^^^^^^^^^
diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_return2.exp b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_return2.exp
index b9972c50113c3..9b0ec32618792 100644
--- a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_return2.exp
+++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_return2.exp
@@ -1,10 +1,7 @@
 
 Diagnostics:
-error: unexpected token
-  ┌─ tests/more-v1/parser/invalid_call_lhs_return2.move:3:20
+error: Calls to function values other than inline function parameters not yet supported
+  ┌─ tests/more-v1/parser/invalid_call_lhs_return2.move:3:9
   │
 3 │         (return ())(0, 1);
-  │                    ^
-  │                    │
-  │                    Unexpected '('
-  │                    Expected ';'
+  │         ^^^^^^^^^^^^^^^^^
diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_value.exp b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_value.exp
index d17d58623b224..6df708c2205eb 100644
--- a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_value.exp
+++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_value.exp
@@ -1,10 +1,13 @@
 
 Diagnostics:
-error: unexpected token
-  ┌─ tests/more-v1/parser/invalid_call_lhs_value.move:3:10
+error: expected `|()|_` but found a value of type `integer`
+  ┌─ tests/more-v1/parser/invalid_call_lhs_value.move:3:9
   │
 3 │         5();
-  │          ^
-  │          │
-  │          Unexpected '('
-  │          Expected ';'
+  │         ^
+
+error: expected `|(integer, integer)|_` but found a value of type `integer`
+  ┌─ tests/more-v1/parser/invalid_call_lhs_value.move:4:9
+  │
+4 │         5(0, 1);
+  │         ^
diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_value2.exp b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_value2.exp
index e2f3d92b38d92..34a3e9e9a6b5b 100644
--- a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_value2.exp
+++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_value2.exp
@@ -1,10 +1,13 @@
 
 Diagnostics:
-error: unexpected token
-  ┌─ tests/more-v1/parser/invalid_call_lhs_value2.move:3:10
+error: expected `|()|_` but found a value of type `integer`
+  ┌─ tests/more-v1/parser/invalid_call_lhs_value2.move:3:9
   │
 3 │         5();
-  │          ^
-  │          │
-  │          Unexpected '('
-  │          Expected ';'
+  │         ^
+
+error: expected `|(integer, integer)|_` but found a value of type `integer`
+  ┌─ tests/more-v1/parser/invalid_call_lhs_value2.move:4:9
+  │
+4 │         5(0, 1);
+  │         ^
diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/spec_parsing_ok.exp b/third_party/move/move-compiler-v2/tests/more-v1/parser/spec_parsing_ok.exp
index 729c903a835a0..bec31b588f3e5 100644
--- a/third_party/move/move-compiler-v2/tests/more-v1/parser/spec_parsing_ok.exp
+++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/spec_parsing_ok.exp
@@ -48,7 +48,7 @@ error: expression construct not supported in specifications
 69 │         ensures RET = {let y = x; y + 1};
    │                 ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: cannot pass `|(num, num)|num` to a function which expects argument of type `|(num, num)|bool`
+error: cannot pass `|(num, num)|num with copy+store` to a function which expects argument of type `|(num, num)|bool`
    ┌─ tests/more-v1/parser/spec_parsing_ok.move:77:24
    │
 77 │         ensures all(x, |y, z| x + y + z);
diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/unexpected_token_after_ability_function_constraint.exp b/third_party/move/move-compiler-v2/tests/more-v1/parser/unexpected_token_after_ability_function_constraint.exp
index b9eafd1f9f753..9808aa198bb4b 100644
--- a/third_party/move/move-compiler-v2/tests/more-v1/parser/unexpected_token_after_ability_function_constraint.exp
+++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/unexpected_token_after_ability_function_constraint.exp
@@ -4,7 +4,6 @@ error: unexpected token
   ┌─ tests/more-v1/parser/unexpected_token_after_ability_function_constraint.move:4:21
   │
 4 │     fun foo<T: copy & drop>() {}
-  │                     ^
-  │                     │
-  │                     Unexpected '&'
-  │                     Expected one of: '+', '>', or ','
+  │            -        ^ Expected '>'
+  │            │
+  │            To match this '<'
diff --git a/third_party/move/move-compiler-v2/tests/testsuite.rs b/third_party/move/move-compiler-v2/tests/testsuite.rs
index acbab3106d398..eff9be3737cf6 100644
--- a/third_party/move/move-compiler-v2/tests/testsuite.rs
+++ b/third_party/move/move-compiler-v2/tests/testsuite.rs
@@ -174,7 +174,8 @@ const TEST_CONFIGS: Lazy<BTreeMap<&str, TestConfig>> = Lazy::new(|| {
                 .set_experiment(Experiment::LAMBDA_IN_PARAMS, true)
                 .set_experiment(Experiment::LAMBDA_IN_RETURNS, true)
                 .set_experiment(Experiment::LAMBDA_VALUES, true)
-                .set_experiment(Experiment::LAMBDA_LIFTING, true),
+                .set_experiment(Experiment::LAMBDA_LIFTING, true)
+                .set_language_version(LanguageVersion::V2_LAMBDA),
             stop_after: StopAfter::FileFormat,
             dump_ast: DumpLevel::AllStages,
             dump_bytecode: DumpLevel::EndStage,
diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/multi_param_typed.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/multi_param_typed.exp
index a4bb458cc6f57..e368f5af7f888 100644
--- a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/multi_param_typed.exp
+++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/multi_param_typed.exp
@@ -24,7 +24,7 @@ comparison between v1 and v2 failed:
 = 
 - error[E01013]: unsupported language construct
 -    ┌─ TEMPFILE:24:73
-+ error: cannot pass `|(u64, u64)|integer` to a function which expects argument of type `|(&integer, &mut integer)|u64`
++ error: cannot pass `|(u64, u64)|integer with copy+store` to a function which expects argument of type `|(&integer, &mut integer)|u64`
 +    ┌─ TEMPFILE:24:64
 =    │
 = 24 │         assert!(elem_for_each_ref(&mut vector[Elem{k:1, v:2}], |x: u64, y: u64| *x + *y) == 3, 0)
diff --git a/third_party/move/move-compiler/src/expansion/ast.rs b/third_party/move/move-compiler/src/expansion/ast.rs
index 47db86f2654ba..8a241a6091ae3 100644
--- a/third_party/move/move-compiler/src/expansion/ast.rs
+++ b/third_party/move/move-compiler/src/expansion/ast.rs
@@ -6,8 +6,8 @@ use crate::{
     expansion::translate::is_valid_struct_constant_or_schema_name,
     parser::ast::{
         self as P, Ability, Ability_, BinOp, CallKind, ConstantName, Field, FunctionName, Label,
-        ModuleName, QuantKind, SpecApplyPattern, StructName, UnaryOp, UseDecl, Var, VariantName,
-        ENTRY_MODIFIER,
+        LambdaCaptureKind, ModuleName, QuantKind, SpecApplyPattern, StructName, UnaryOp, UseDecl,
+        Var, VariantName, ENTRY_MODIFIER,
     },
     shared::{
         ast_debug::*,
@@ -401,7 +401,7 @@ pub enum Type_ {
     Multiple(Vec<Type>),
     Apply(ModuleAccess, Vec<Type>),
     Ref(bool, Box<Type>),
-    Fun(Vec<Type>, Box<Type>),
+    Fun(Vec<Type>, Box<Type>, AbilitySet),
     UnresolvedError,
 }
 pub type Type = Spanned<Type_>;
@@ -498,6 +498,7 @@ pub enum Exp_ {
 
     Name(ModuleAccess, Option<Vec<Type>>),
     Call(ModuleAccess, CallKind, Option<Vec<Type>>, Spanned<Vec<Exp>>),
+    ExpCall(Box<Exp>, Spanned<Vec<Exp>>),
     Pack(ModuleAccess, Option<Vec<Type>>, Fields<Exp>),
     Vector(Loc, Option<Vec<Type>>, Spanned<Vec<Exp>>),
 
@@ -506,7 +507,7 @@ pub enum Exp_ {
     While(Option<Label>, Box<Exp>, Box<Exp>),
     Loop(Option<Label>, Box<Exp>),
     Block(Sequence),
-    Lambda(TypedLValueList, Box<Exp>),
+    Lambda(TypedLValueList, Box<Exp>, LambdaCaptureKind, AbilitySet),
     Quant(
         QuantKind,
         LValueWithRangeList,
@@ -908,6 +909,17 @@ impl fmt::Display for Visibility {
     }
 }
 
+impl fmt::Display for AbilitySet {
+    fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
+        if !self.is_empty() {
+            write!(f, ": ")?;
+            write!(f, "{}", format_delim(self, "+"))
+        } else {
+            Ok(())
+        }
+    }
+}
+
 impl fmt::Display for Type_ {
     fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
         use Type_::*;
@@ -916,19 +928,18 @@ impl fmt::Display for Type_ {
             Apply(n, tys) => {
                 write!(f, "{}", n)?;
                 if !tys.is_empty() {
-                    write!(f, "<")?;
-                    write!(f, "{}", format_comma(tys))?;
-                    write!(f, ">")?;
+                    write!(f, "<{}>", format_comma(tys))
+                } else {
+                    Ok(())
                 }
-                Ok(())
             },
             Ref(mut_, ty) => write!(f, "&{}{}", if *mut_ { "mut " } else { "" }, ty),
-            Fun(args, result) => write!(f, "({}):{}", format_comma(args), result),
+            Fun(args, result, abilities) => {
+                write!(f, "({}):{}{}", format_comma(args), result, abilities)
+            },
             Unit => write!(f, "()"),
             Multiple(tys) => {
-                write!(f, "(")?;
-                write!(f, "{}", format_comma(tys))?;
-                write!(f, ")")
+                write!(f, "({})", format_comma(tys))
             },
         }
     }
@@ -1444,11 +1455,12 @@ impl AstDebug for Type_ {
                 }
                 s.ast_debug(w)
             },
-            Type_::Fun(args, result) => {
+            Type_::Fun(args, result, abilities) => {
                 w.write("|");
                 w.comma(args, |w, ty| ty.ast_debug(w));
                 w.write("|");
                 result.ast_debug(w);
+                ability_constraints_ast_debug(w, abilities);
             },
             Type_::UnresolvedError => w.write("_|_"),
         }
@@ -1609,6 +1621,12 @@ impl AstDebug for Exp_ {
                 w.comma(rhs, |w, e| e.ast_debug(w));
                 w.write(")");
             },
+            E::ExpCall(fexp, sp!(_, rhs)) => {
+                fexp.ast_debug(w);
+                w.write("(");
+                w.comma(rhs, |w, e| e.ast_debug(w));
+                w.write(")");
+            },
             E::Pack(ma, tys_opt, fields) => {
                 ma.ast_debug(w);
                 if let Some(ss) = tys_opt {
@@ -1674,11 +1692,15 @@ impl AstDebug for Exp_ {
                 }
             },
             E::Block(seq) => w.block(|w| seq.ast_debug(w)),
-            E::Lambda(sp!(_, bs), e) => {
+            E::Lambda(sp!(_, bs), e, capture_kind, abilities) => {
+                if *capture_kind != LambdaCaptureKind::Default {
+                    w.write(format!(" {}", capture_kind));
+                }
                 w.write("|");
                 bs.ast_debug(w);
                 w.write("|");
                 e.ast_debug(w);
+                ability_constraints_ast_debug(w, abilities)
             },
             E::Quant(kind, sp!(_, rs), trs, c_opt, e) => {
                 kind.ast_debug(w);
diff --git a/third_party/move/move-compiler/src/expansion/dependency_ordering.rs b/third_party/move/move-compiler/src/expansion/dependency_ordering.rs
index 732161adb2bc5..c18086f59d530 100644
--- a/third_party/move/move-compiler/src/expansion/dependency_ordering.rs
+++ b/third_party/move/move-compiler/src/expansion/dependency_ordering.rs
@@ -373,7 +373,7 @@ fn type_(context: &mut Context, sp!(_, ty_): &E::Type) {
             types(context, tys);
         },
         T::Multiple(tys) => types(context, tys),
-        T::Fun(tys, ret_ty) => {
+        T::Fun(tys, ret_ty, _abilities) => {
             types(context, tys);
             type_(context, ret_ty)
         },
@@ -451,6 +451,10 @@ fn exp(context: &mut Context, sp!(_loc, e_): &E::Exp) {
             types_opt(context, tys_opt);
             args_.iter().for_each(|e| exp(context, e))
         },
+        E::ExpCall(fexp, sp!(_, args_)) => {
+            exp(context, fexp);
+            args_.iter().for_each(|e| exp(context, e))
+        },
         E::Pack(ma, tys_opt, fields) => {
             module_access(context, ma);
             types_opt(context, tys_opt);
@@ -512,7 +516,7 @@ fn exp(context: &mut Context, sp!(_loc, e_): &E::Exp) {
             tys.iter().for_each(|ty| type_(context, ty))
         },
 
-        E::Lambda(ll, e) => {
+        E::Lambda(ll, e, _capture_kind, _abilities) => {
             use crate::expansion::ast::TypedLValue_;
             let mapped = ll.value.iter().map(|sp!(_, TypedLValue_(lv, _opt_ty))| lv);
             lvalues(context, mapped);
diff --git a/third_party/move/move-compiler/src/expansion/translate.rs b/third_party/move/move-compiler/src/expansion/translate.rs
index b8ea685e454d7..fdd72da1469f7 100644
--- a/third_party/move/move-compiler/src/expansion/translate.rs
+++ b/third_party/move/move-compiler/src/expansion/translate.rs
@@ -2243,10 +2243,11 @@ fn type_(context: &mut Context, sp!(loc, pt_): P::Type) -> E::Type {
             }
         },
         PT::Ref(mut_, inner) => ET::Ref(mut_, Box::new(type_(context, *inner))),
-        PT::Fun(args, result) => {
+        PT::Fun(args, result, abilities_vec) => {
             let args = types(context, args);
             let result = type_(context, *result);
-            ET::Fun(args, Box::new(result))
+            let abilities = ability_set(context, "modifier", abilities_vec);
+            ET::Fun(args, Box::new(result), abilities)
         },
     };
     sp(loc, t_)
@@ -2561,6 +2562,11 @@ fn exp_(context: &mut Context, sp!(loc, pe_): P::Exp) -> E::Exp {
                 },
             }
         },
+        PE::ExpCall(boxed_fexp, sp!(rloc, args)) => {
+            let e_fexp = exp(context, *boxed_fexp);
+            let e_args = sp(rloc, exps(context, args));
+            EE::ExpCall(e_fexp, e_args)
+        },
         PE::Pack(pn, ptys_opt, pfields) => {
             let en_opt = name_access_chain(
                 context,
@@ -2623,11 +2629,12 @@ fn exp_(context: &mut Context, sp!(loc, pe_): P::Exp) -> E::Exp {
         PE::While(label, pb, ploop) => EE::While(label, exp(context, *pb), exp(context, *ploop)),
         PE::Loop(label, ploop) => EE::Loop(label, exp(context, *ploop)),
         PE::Block(seq) => EE::Block(sequence(context, loc, seq)),
-        PE::Lambda(pbs, pe) => {
+        PE::Lambda(pbs, pe, capture_kind, abilities_vec) => {
             let tbs_opt = typed_bind_list(context, pbs);
             let e = exp_(context, *pe);
+            let abilities = ability_set(context, "lambda expression", abilities_vec);
             match tbs_opt {
-                Some(tbs) => EE::Lambda(tbs, Box::new(e)),
+                Some(tbs) => EE::Lambda(tbs, Box::new(e), capture_kind, abilities),
                 None => {
                     assert!(context.env.has_errors());
                     EE::UnresolvedError
@@ -3326,6 +3333,10 @@ fn unbound_names_exp(unbound: &mut UnboundNames, sp!(_, e_): &E::Exp) {
             }
             unbound_names_exps(unbound, es_);
         },
+        EE::ExpCall(fexp, sp!(_, es_)) => {
+            unbound_names_exp(unbound, fexp);
+            unbound_names_exps(unbound, es_);
+        },
         EE::Vector(_, _, sp!(_, es_)) => unbound_names_exps(unbound, es_),
         EE::Pack(_, _, es) => unbound_names_exps(unbound, es.iter().map(|(_, _, (_, e))| e)),
         EE::IfElse(econd, et, ef) => {
@@ -3350,7 +3361,7 @@ fn unbound_names_exp(unbound: &mut UnboundNames, sp!(_, e_): &E::Exp) {
         EE::Loop(_, eloop) => unbound_names_exp(unbound, eloop),
 
         EE::Block(seq) => unbound_names_sequence(unbound, seq),
-        EE::Lambda(ls, er) => {
+        EE::Lambda(ls, er, _capture_kind, _abilities) => {
             unbound_names_exp(unbound, er);
             // remove anything in `ls`
             unbound_names_typed_binds(unbound, ls);
diff --git a/third_party/move/move-compiler/src/naming/translate.rs b/third_party/move/move-compiler/src/naming/translate.rs
index ee37a1d68a8ac..7d9f03c0df593 100644
--- a/third_party/move/move-compiler/src/naming/translate.rs
+++ b/third_party/move/move-compiler/src/naming/translate.rs
@@ -807,7 +807,7 @@ fn type_(context: &mut Context, sp!(loc, ety_): E::Type) -> N::Type {
                 }
             },
         },
-        ET::Fun(args, result) => {
+        ET::Fun(args, result, _abilities) => {
             let mut args = types(context, args);
             args.push(type_(context, *result));
             NT::builtin_(sp(loc, N::BuiltinTypeName_::Fun), args)
@@ -941,7 +941,7 @@ fn exp_(context: &mut Context, e: E::Exp) -> N::Exp {
         EE::While(_, eb, el) => NE::While(exp(context, *eb), exp(context, *el)),
         EE::Loop(_, el) => NE::Loop(exp(context, *el)),
         EE::Block(seq) => NE::Block(sequence(context, seq)),
-        EE::Lambda(args, body) => {
+        EE::Lambda(args, body, _lambda_capture_kind, _abilities) => {
             let bind_opt = bind_typed_list(context, args);
             match bind_opt {
                 None => {
@@ -1088,6 +1088,23 @@ fn exp_(context: &mut Context, e: E::Exp) -> N::Exp {
                 },
             }
         },
+        EE::ExpCall(efunc, eargs, ..) => {
+            let nfunc = exp(context, *efunc);
+            let nargs = call_args(context, eargs);
+            match *nfunc {
+                sp!(_loc, NE::Use(Var(v))) => NE::VarCall(Var(v), nargs),
+                sp!(loc, _) => {
+                    context.env.add_diag(diag!(
+                        Syntax::UnsupportedLanguageItem,
+                        (
+                            loc,
+                            "Calls through computed functions not supported by this compiler"
+                        )
+                    ));
+                    NE::UnresolvedError
+                },
+            }
+        },
         EE::Vector(vec_loc, tys_opt, rhs) => {
             let ty_args = tys_opt.map(|tys| types(context, tys));
             let nes = call_args(context, rhs);
diff --git a/third_party/move/move-compiler/src/parser/ast.rs b/third_party/move/move-compiler/src/parser/ast.rs
index 86be3a5cdcdd2..1981d00013cb9 100644
--- a/third_party/move/move-compiler/src/parser/ast.rs
+++ b/third_party/move/move-compiler/src/parser/ast.rs
@@ -487,8 +487,8 @@ pub enum Type_ {
     // &t
     // &mut t
     Ref(bool, Box<Type>),
-    // (t1,...,tn):t
-    Fun(Vec<Type>, Box<Type>),
+    // |t1,...,tn|t with store+copy
+    Fun(Vec<Type>, Box<Type>, Vec<Ability>),
     // ()
     Unit,
     // (t1, t2, ... , tn)
@@ -645,6 +645,31 @@ pub enum CallKind {
     Receiver,
 }
 
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Default)]
+pub enum LambdaCaptureKind {
+    /// Direct use (e.g., inlining)
+    #[default]
+    Default,
+    /// Copy
+    Copy,
+    /// Move
+    Move,
+}
+
+impl fmt::Display for LambdaCaptureKind {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            LambdaCaptureKind::Default => {
+                write!(f, "")
+            },
+            LambdaCaptureKind::Copy => {
+                write!(f, "copy")
+            },
+            LambdaCaptureKind::Move => write!(f, "move"),
+        }
+    }
+}
+
 #[derive(Debug, Clone, PartialEq)]
 #[allow(clippy::large_enum_variant)]
 pub enum Exp_ {
@@ -666,6 +691,9 @@ pub enum Exp_ {
         Spanned<Vec<Exp>>,
     ),
 
+    // e(earg,* [..]?)
+    ExpCall(Box<Exp>, Spanned<Vec<Exp>>),
+
     // tn {f1: e1, ... , f_n: e_n }
     Pack(NameAccessChain, Option<Vec<Type>>, Vec<(Field, Exp)>),
 
@@ -688,8 +716,8 @@ pub enum Exp_ {
 
     // { seq }
     Block(Sequence),
-    // | x1 [: t1], ..., xn [: tn] | e
-    Lambda(TypedBindList, Box<Exp>),
+    // | x1 [: t1], ..., xn [: tn] | e [ with <abilities> ]
+    Lambda(TypedBindList, Box<Exp>, LambdaCaptureKind, Vec<Ability>),
     // forall/exists x1 : e1, ..., xn [{ t1, .., tk } *] [where cond]: en.
     Quant(
         QuantKind,
@@ -1733,11 +1761,12 @@ impl AstDebug for Type_ {
                 }
                 s.ast_debug(w)
             },
-            Type_::Fun(args, result) => {
+            Type_::Fun(args, result, abilities) => {
                 w.write("(");
                 w.comma(args, |w, ty| ty.ast_debug(w));
                 w.write("):");
                 result.ast_debug(w);
+                ability_constraints_ast_debug(w, abilities);
             },
         }
     }
@@ -1834,6 +1863,12 @@ impl AstDebug for Exp_ {
                 w.comma(rhs, |w, e| e.ast_debug(w));
                 w.write(")");
             },
+            E::ExpCall(arg, sp!(_, rhs)) => {
+                arg.ast_debug(w);
+                w.write("(");
+                w.comma(rhs, |w, e| e.ast_debug(w));
+                w.write(")");
+            },
             E::Pack(ma, tys_opt, fields) => {
                 ma.ast_debug(w);
                 if let Some(ss) = tys_opt {
@@ -1900,11 +1935,21 @@ impl AstDebug for Exp_ {
                 e.ast_debug(w);
             },
             E::Block(seq) => w.block(|w| seq.ast_debug(w)),
-            E::Lambda(sp!(_, tbs), e) => {
+            E::Lambda(sp!(_, tbs), e, capture_kind, abilities) => {
+                if *capture_kind != LambdaCaptureKind::Default {
+                    w.write(format!("{} ", capture_kind));
+                }
                 w.write("|");
                 tbs.ast_debug(w);
                 w.write("|");
                 e.ast_debug(w);
+                if !abilities.is_empty() {
+                    w.write(" with ");
+                    w.list(abilities, ", ", |w, ab_mod| {
+                        ab_mod.ast_debug(w);
+                        false
+                    });
+                }
             },
             E::Quant(kind, sp!(_, rs), trs, c_opt, e) => {
                 kind.ast_debug(w);
diff --git a/third_party/move/move-compiler/src/parser/syntax.rs b/third_party/move/move-compiler/src/parser/syntax.rs
index 98071ea2b7a16..e093ffde9fd67 100644
--- a/third_party/move/move-compiler/src/parser/syntax.rs
+++ b/third_party/move/move-compiler/src/parser/syntax.rs
@@ -90,6 +90,23 @@ fn require_move_2(context: &mut Context, loc: Loc, description: &str) -> bool {
     )
 }
 
+fn require_move_version(
+    min_language_version: LanguageVersion,
+    context: &mut Context,
+    loc: Loc,
+    description: &str,
+) -> bool {
+    require_language_version_msg(
+        context,
+        loc,
+        min_language_version,
+        &format!(
+            "Move {} language construct is not enabled: {}",
+            min_language_version, description
+        ),
+    )
+}
+
 fn require_language_version(
     context: &mut Context,
     loc: Loc,
@@ -132,6 +149,21 @@ fn require_move_2_and_advance(
     Ok(require_move_2(context, loc, description))
 }
 
+fn require_move_version_and_advance(
+    min_language_version: LanguageVersion,
+    context: &mut Context,
+    description: &str,
+) -> Result<bool, Box<Diagnostic>> {
+    let loc = current_token_loc(context.tokens);
+    context.tokens.advance()?;
+    Ok(require_move_version(
+        min_language_version,
+        context,
+        loc,
+        description,
+    ))
+}
+
 pub fn make_loc(file_hash: FileHash, start: usize, end: usize) -> Loc {
     Loc::new(file_hash, start as u32, end as u32)
 }
@@ -1131,6 +1163,7 @@ fn parse_sequence(context: &mut Context) -> Result<Sequence, Box<Diagnostic>> {
 //          | "abort" <Exp>
 //          | "for" "(" <Exp> "in" <Exp> ".." <Exp> ")" "{" <Exp> "}"
 //          | <NameExp>
+//          | <Term> <CallArgs>              // --> ExpCall
 fn parse_term(context: &mut Context) -> Result<Exp, Box<Diagnostic>> {
     const VECTOR_IDENT: &str = "vector";
     const FOR_IDENT: &str = "for";
@@ -1286,12 +1319,14 @@ fn parse_term(context: &mut Context) -> Result<Exp, Box<Diagnostic>> {
         },
     };
     let end_loc = context.tokens.previous_end_loc();
-    Ok(spanned(
-        context.tokens.file_hash(),
-        start_loc,
-        end_loc,
-        term,
-    ))
+    let mut result_term = spanned(context.tokens.file_hash(), start_loc, end_loc, term);
+    while matches!(context.tokens.peek(), Tok::LParen) {
+        let args = parse_call_args(context)?;
+        let term = Exp_::ExpCall(Box::new(result_term), args);
+        let end_loc = context.tokens.previous_end_loc();
+        result_term = spanned(context.tokens.file_hash(), start_loc, end_loc, term);
+    }
+    Ok(result_term)
 }
 
 fn parse_cast_or_test_exp(
@@ -1842,6 +1877,7 @@ fn parse_name_exp(context: &mut Context) -> Result<Exp_, Box<Diagnostic>> {
 // Parse the arguments to a call:
 //      CallArgs =
 //          "(" Comma<Exp> ")"
+// Result is a list <args>
 fn parse_call_args(context: &mut Context) -> Result<Spanned<Vec<Exp>>, Box<Diagnostic>> {
     let start_loc = context.tokens.start_loc();
     let args = parse_comma_list(
@@ -1901,9 +1937,43 @@ fn at_start_of_exp(context: &mut Context) -> bool {
     )
 }
 
+// Parse the rest of a lambda expression, after already processing any capture designator (move/copy).
+//       LambdaRest =
+//                      <LambdaBindList> <Exp> <WithAbilities>
+fn parse_lambda(
+    context: &mut Context,
+    start_loc: usize,
+    capture_kind: LambdaCaptureKind,
+    token: Tok,
+) -> Result<Exp_, Box<Diagnostic>> {
+    let bindings = if token == Tok::Pipe {
+        parse_lambda_bind_list(context)?
+    } else {
+        // token is Tok::PipePipe, i.e., empty bind list in this context.
+        consume_token(context.tokens, Tok::PipePipe)?;
+        let end_loc = context.tokens.previous_end_loc();
+        spanned(context.tokens.file_hash(), start_loc, end_loc, vec![])
+    };
+    let body = Box::new(parse_exp(context)?);
+    let abilities_start = context.tokens.start_loc();
+    let abilities = parse_with_abilities(context)?;
+    if !abilities.is_empty() {
+        let abilities_end = context.tokens.previous_end_loc();
+        let loc = make_loc(context.tokens.file_hash(), abilities_start, abilities_end);
+        require_move_version(
+            LanguageVersion::V2_2,
+            context,
+            loc,
+            "Abilities on function expressions",
+        );
+    }
+
+    Ok(Exp_::Lambda(bindings, body, capture_kind, abilities))
+}
+
 // Parse an expression:
 //      Exp =
-//            <LambdaBindList> <Exp>
+//            ( "move" | "copy" )? <LambdaBindList> <Exp> <WithAbilities>
 //          | <Quantifier>                  spec only
 //          | <BinOpExp>
 //          | <UnaryExp> "=" <Exp>
@@ -1913,16 +1983,33 @@ fn parse_exp(context: &mut Context) -> Result<Exp, Box<Diagnostic>> {
     let start_loc = context.tokens.start_loc();
     let token = context.tokens.peek();
     let exp = match token {
-        Tok::Pipe | Tok::PipePipe => {
-            let bindings = if token == Tok::Pipe {
-                parse_lambda_bind_list(context)?
-            } else {
-                // token is Tok::PipePipe, i.e., empty bind list in this context.
-                consume_token(context.tokens, Tok::PipePipe)?;
-                spanned(context.tokens.file_hash(), start_loc, start_loc + 1, vec![])
+        Tok::Move | Tok::Copy
+            if matches!(
+                context.tokens.lookahead_with_start_loc(),
+                Ok((Tok::Pipe | Tok::PipePipe, _))
+            ) =>
+        {
+            let _ = require_move_version_and_advance(
+                LanguageVersion::V2_2,
+                context,
+                "Modifier on lambda expression",
+            ); // consume the Move/Copy
+            let capture_kind = match token {
+                Tok::Move => LambdaCaptureKind::Move,
+                Tok::Copy => LambdaCaptureKind::Copy,
+                _ => {
+                    panic!("can't happen");
+                },
             };
-            let body = Box::new(parse_exp(context)?);
-            Exp_::Lambda(bindings, body)
+            parse_lambda(
+                context,
+                context.tokens.start_loc(),
+                capture_kind,
+                context.tokens.peek(),
+            )?
+        },
+        Tok::Pipe | Tok::PipePipe => {
+            parse_lambda(context, start_loc, LambdaCaptureKind::default(), token)?
         },
         Tok::Identifier if is_quant(context) => parse_quant(context)?,
         _ => {
@@ -2118,7 +2205,7 @@ fn parse_binop_exp(context: &mut Context, lhs: Exp, min_prec: u32) -> Result<Exp
 //          | "*" <UnaryExp>
 //          | "move" <Var>
 //          | "copy" <Var>
-//          | <DotOrIndexChain>
+//          | <DotOrIndexOrCallChain>
 fn parse_unary_exp(context: &mut Context) -> Result<Exp, Box<Diagnostic>> {
     let start_loc = context.tokens.start_loc();
     let exp = match context.tokens.peek() {
@@ -2165,7 +2252,8 @@ fn parse_unary_exp(context: &mut Context) -> Result<Exp, Box<Diagnostic>> {
     Ok(spanned(context.tokens.file_hash(), start_loc, end_loc, exp))
 }
 
-// Parse an expression term optionally followed by a chain of dot or index accesses:
+// Parse an expression term optionally followed by a chain of dot accesses and/or index accesses
+// and/or calls of function values.
 //      DotOrIndexChain =
 //          <DotOrIndexChain> "." <Identifier> [ ["::" "<" Comma<Type> ">"]? <CallArgs> ]?
 //          | <DotOrIndexChain> "[" <Exp> "]"
@@ -2398,10 +2486,10 @@ fn make_builtin_call(loc: Loc, name: Symbol, type_args: Option<Vec<Type>>, args:
 
 // Parse a Type:
 //      Type =
-//          <NameAccessChain> ('<' Comma<Type> ">")?
+//          <NameAccessChain> ("<" Comma<Type> ">")?
 //          | "&" <Type>
 //          | "&mut" <Type>
-//          | "|" Comma<Type> "|" <Type>?
+//          | "|" Comma<Type> "|" <Type>? <WithAbilities>
 //          | "(" Comma<Type> ")"
 fn parse_type(context: &mut Context) -> Result<Type, Box<Diagnostic>> {
     let start_loc = context.tokens.start_loc();
@@ -2443,11 +2531,23 @@ fn parse_type(context: &mut Context) -> Result<Type, Box<Diagnostic>> {
                     Type_::Unit,
                 )
             };
+            let abilities_start = context.tokens.start_loc();
+            let abilities = parse_with_abilities(context)?;
+            if !abilities.is_empty() {
+                let abilities_end = context.tokens.previous_end_loc();
+                let loc = make_loc(context.tokens.file_hash(), abilities_start, abilities_end);
+                require_move_version(
+                    LanguageVersion::V2_2,
+                    context,
+                    loc,
+                    "Ability constraints on function types",
+                );
+            }
             return Ok(spanned(
                 context.tokens.file_hash(),
                 start_loc,
                 context.tokens.previous_end_loc(),
-                Type_::Fun(args, Box::new(result)),
+                Type_::Fun(args, Box::new(result), abilities),
             ));
         },
         _ => {
@@ -2522,6 +2622,43 @@ fn parse_ability(context: &mut Context) -> Result<Ability, Box<Diagnostic>> {
     }
 }
 
+// Parse an optional "with" type constraint:
+//      WithAbilities =
+//          ( "with" <Ability> (+ <Ability>)* )?
+fn parse_with_abilities(context: &mut Context) -> Result<Vec<Ability>, Box<Diagnostic>> {
+    if context.tokens.peek() == Tok::Identifier && context.tokens.content() == "with" {
+        context.tokens.advance()?;
+        parse_type_constraints_core(context)
+    } else {
+        Ok(vec![])
+    }
+}
+
+// Parse an optional type constraint:
+//      Constraint =
+//          ( ":" <Ability> (+ <Ability>)* )?
+fn parse_type_constraints(context: &mut Context) -> Result<Vec<Ability>, Box<Diagnostic>> {
+    if match_token(context.tokens, Tok::Colon)? {
+        parse_type_constraints_core(context)
+    } else {
+        Ok(vec![])
+    }
+}
+
+fn parse_type_constraints_core(context: &mut Context) -> Result<Vec<Ability>, Box<Diagnostic>> {
+    parse_list(
+        context,
+        |context| match context.tokens.peek() {
+            Tok::Plus => {
+                context.tokens.advance()?;
+                Ok(true)
+            },
+            _ => Ok(false),
+        },
+        parse_ability,
+    )
+}
+
 // Parse a type parameter:
 //      TypeParameter =
 //          <Identifier> <Constraint>?
@@ -2530,30 +2667,7 @@ fn parse_ability(context: &mut Context) -> Result<Ability, Box<Diagnostic>> {
 fn parse_type_parameter(context: &mut Context) -> Result<(Name, Vec<Ability>), Box<Diagnostic>> {
     let n = parse_identifier(context)?;
 
-    let ability_constraints = if match_token(context.tokens, Tok::Colon)? {
-        parse_list(
-            context,
-            |context| match context.tokens.peek() {
-                Tok::Plus => {
-                    context.tokens.advance()?;
-                    Ok(true)
-                },
-                Tok::Greater | Tok::Comma => Ok(false),
-                _ => Err(unexpected_token_error(
-                    context.tokens,
-                    &format!(
-                        "one of: '{}', '{}', or '{}'",
-                        Tok::Plus,
-                        Tok::Greater,
-                        Tok::Comma
-                    ),
-                )),
-            },
-            parse_ability,
-        )?
-    } else {
-        vec![]
-    };
+    let ability_constraints = parse_type_constraints(context)?;
     Ok((n, ability_constraints))
 }
 
diff --git a/third_party/move/move-compiler/src/shared/ast_debug.rs b/third_party/move/move-compiler/src/shared/ast_debug.rs
index e26578f6306b8..00db7d7502c65 100644
--- a/third_party/move/move-compiler/src/shared/ast_debug.rs
+++ b/third_party/move/move-compiler/src/shared/ast_debug.rs
@@ -24,6 +24,7 @@
 ///     }
 /// }
 /// ```
+
 pub trait AstDebug {
     fn ast_debug(&self, w: &mut AstWriter);
 }
diff --git a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_complex_expression.exp b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_complex_expression.exp
index fee0df0f4e049..84b113412d052 100644
--- a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_complex_expression.exp
+++ b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_complex_expression.exp
@@ -1,9 +1,18 @@
-error[E01002]: unexpected token
-  ┌─ tests/move_check/parser/invalid_call_lhs_complex_expression.move:3:29
+error[E02004]: invalid 'module' declaration
+  ┌─ tests/move_check/parser/invalid_call_lhs_complex_expression.move:1:8
+  │
+1 │ module M {
+  │        ^ Invalid module declaration. The module does not have a specified address. Either declare it inside of an 'address <address> {' block or declare it with an address 'module <address>::M''
+
+error[E01013]: unsupported language construct
+  ┌─ tests/move_check/parser/invalid_call_lhs_complex_expression.move:3:9
   │
 3 │         (if (true) 5 else 0)();
-  │                             ^
-  │                             │
-  │                             Unexpected '('
-  │                             Expected ';'
+  │         ^^^^^^^^^^^^^^^^^^^^ Calls through computed functions not supported by this compiler
+
+error[E01013]: unsupported language construct
+  ┌─ tests/move_check/parser/invalid_call_lhs_complex_expression.move:4:9
+  │
+4 │         (while (false) {})(0, 1);
+  │         ^^^^^^^^^^^^^^^^^^ Calls through computed functions not supported by this compiler
 
diff --git a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_complex_expression2.exp b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_complex_expression2.exp
index 7201cb27d3396..f66a597b72ba6 100644
--- a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_complex_expression2.exp
+++ b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_complex_expression2.exp
@@ -1,9 +1,12 @@
-error[E01002]: unexpected token
-  ┌─ tests/move_check/parser/invalid_call_lhs_complex_expression2.move:3:29
+error[E01013]: unsupported language construct
+  ┌─ tests/move_check/parser/invalid_call_lhs_complex_expression2.move:3:9
   │
 3 │         (if (true) 5 else 0)();
-  │                             ^
-  │                             │
-  │                             Unexpected '('
-  │                             Expected ';'
+  │         ^^^^^^^^^^^^^^^^^^^^ Calls through computed functions not supported by this compiler
+
+error[E01013]: unsupported language construct
+  ┌─ tests/move_check/parser/invalid_call_lhs_complex_expression2.move:4:9
+  │
+4 │         (while (false) {})(0, 1);
+  │         ^^^^^^^^^^^^^^^^^^ Calls through computed functions not supported by this compiler
 
diff --git a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_parens_around_name.exp b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_parens_around_name.exp
index 49558ae3304f2..90b98ee3c2b8f 100644
--- a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_parens_around_name.exp
+++ b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_parens_around_name.exp
@@ -1,9 +1,12 @@
-error[E01002]: unexpected token
-  ┌─ tests/move_check/parser/invalid_call_lhs_parens_around_name.move:3:14
+error[E02004]: invalid 'module' declaration
+  ┌─ tests/move_check/parser/invalid_call_lhs_parens_around_name.move:1:8
+  │
+1 │ module M {
+  │        ^ Invalid module declaration. The module does not have a specified address. Either declare it inside of an 'address <address> {' block or declare it with an address 'module <address>::M''
+
+error[E03009]: unbound variable
+  ┌─ tests/move_check/parser/invalid_call_lhs_parens_around_name.move:3:10
   │
 3 │         (foo)()
-  │              ^
-  │              │
-  │              Unexpected '('
-  │              Expected ';'
+  │          ^^^ Invalid function usage. Unbound variable 'foo'
 
diff --git a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_parens_around_name2.exp b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_parens_around_name2.exp
index fefac05537b4b..fe742a0fa5cae 100644
--- a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_parens_around_name2.exp
+++ b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_parens_around_name2.exp
@@ -1,9 +1,6 @@
-error[E01002]: unexpected token
-  ┌─ tests/move_check/parser/invalid_call_lhs_parens_around_name2.move:3:14
+error[E03009]: unbound variable
+  ┌─ tests/move_check/parser/invalid_call_lhs_parens_around_name2.move:3:10
   │
 3 │         (foo)()
-  │              ^
-  │              │
-  │              Unexpected '('
-  │              Expected ';'
+  │          ^^^ Invalid function usage. Unbound variable 'foo'
 
diff --git a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_return.exp b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_return.exp
index 89356898a0db1..e5b94f2d457bb 100644
--- a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_return.exp
+++ b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_return.exp
@@ -1,9 +1,12 @@
-error[E01002]: unexpected token
-  ┌─ tests/move_check/parser/invalid_call_lhs_return.move:3:20
+error[E02004]: invalid 'module' declaration
+  ┌─ tests/move_check/parser/invalid_call_lhs_return.move:1:8
+  │
+1 │ module M {
+  │        ^ Invalid module declaration. The module does not have a specified address. Either declare it inside of an 'address <address> {' block or declare it with an address 'module <address>::M''
+
+error[E01013]: unsupported language construct
+  ┌─ tests/move_check/parser/invalid_call_lhs_return.move:3:9
   │
 3 │         (return ())(0, 1);
-  │                    ^
-  │                    │
-  │                    Unexpected '('
-  │                    Expected ';'
+  │         ^^^^^^^^^^^ Calls through computed functions not supported by this compiler
 
diff --git a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_return2.exp b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_return2.exp
index 2527998d56005..de8427768b4df 100644
--- a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_return2.exp
+++ b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_return2.exp
@@ -1,9 +1,6 @@
-error[E01002]: unexpected token
-  ┌─ tests/move_check/parser/invalid_call_lhs_return2.move:3:20
+error[E01013]: unsupported language construct
+  ┌─ tests/move_check/parser/invalid_call_lhs_return2.move:3:9
   │
 3 │         (return ())(0, 1);
-  │                    ^
-  │                    │
-  │                    Unexpected '('
-  │                    Expected ';'
+  │         ^^^^^^^^^^^ Calls through computed functions not supported by this compiler
 
diff --git a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_value.exp b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_value.exp
index e75abc53ec0b7..c6ca3545b9588 100644
--- a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_value.exp
+++ b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_value.exp
@@ -1,9 +1,18 @@
-error[E01002]: unexpected token
-  ┌─ tests/move_check/parser/invalid_call_lhs_value.move:3:10
+error[E02004]: invalid 'module' declaration
+  ┌─ tests/move_check/parser/invalid_call_lhs_value.move:1:8
+  │
+1 │ module M {
+  │        ^ Invalid module declaration. The module does not have a specified address. Either declare it inside of an 'address <address> {' block or declare it with an address 'module <address>::M''
+
+error[E01013]: unsupported language construct
+  ┌─ tests/move_check/parser/invalid_call_lhs_value.move:3:9
   │
 3 │         5();
-  │          ^
-  │          │
-  │          Unexpected '('
-  │          Expected ';'
+  │         ^ Calls through computed functions not supported by this compiler
+
+error[E01013]: unsupported language construct
+  ┌─ tests/move_check/parser/invalid_call_lhs_value.move:4:9
+  │
+4 │         5(0, 1);
+  │         ^ Calls through computed functions not supported by this compiler
 
diff --git a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_value2.exp b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_value2.exp
index cd650973ac819..fd6099db101c0 100644
--- a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_value2.exp
+++ b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_value2.exp
@@ -1,9 +1,12 @@
-error[E01002]: unexpected token
-  ┌─ tests/move_check/parser/invalid_call_lhs_value2.move:3:10
+error[E01013]: unsupported language construct
+  ┌─ tests/move_check/parser/invalid_call_lhs_value2.move:3:9
   │
 3 │         5();
-  │          ^
-  │          │
-  │          Unexpected '('
-  │          Expected ';'
+  │         ^ Calls through computed functions not supported by this compiler
+
+error[E01013]: unsupported language construct
+  ┌─ tests/move_check/parser/invalid_call_lhs_value2.move:4:9
+  │
+4 │         5(0, 1);
+  │         ^ Calls through computed functions not supported by this compiler
 
diff --git a/third_party/move/move-compiler/tests/move_check/parser/unexpected_token_after_ability_function_constraint.exp b/third_party/move/move-compiler/tests/move_check/parser/unexpected_token_after_ability_function_constraint.exp
index 2482eef2ec13f..4ff6fe24775c0 100644
--- a/third_party/move/move-compiler/tests/move_check/parser/unexpected_token_after_ability_function_constraint.exp
+++ b/third_party/move/move-compiler/tests/move_check/parser/unexpected_token_after_ability_function_constraint.exp
@@ -2,8 +2,7 @@ error[E01002]: unexpected token
   ┌─ tests/move_check/parser/unexpected_token_after_ability_function_constraint.move:4:21
   │
 4 │     fun foo<T: copy & drop>() {}
-  │                     ^
-  │                     │
-  │                     Unexpected '&'
-  │                     Expected one of: '+', '>', or ','
+  │            -        ^ Expected '>'
+  │            │         
+  │            To match this '<'
 
diff --git a/third_party/move/move-model/Cargo.toml b/third_party/move/move-model/Cargo.toml
index 49f76a32dfdf1..820a2b5b5af9b 100644
--- a/third_party/move/move-model/Cargo.toml
+++ b/third_party/move/move-model/Cargo.toml
@@ -21,6 +21,7 @@ move-symbol-pool = { path = "../move-symbol-pool" }
 # external dependencies
 codespan = { workspace = true }
 codespan-reporting = { workspace = true }
+either = { workspace = true }
 internment = { workspace = true, features = ["arc"] }
 itertools = { workspace = true }
 log = { workspace = true }
diff --git a/third_party/move/move-model/bytecode/ast-generator-tests/tests/testsuite.rs b/third_party/move/move-model/bytecode/ast-generator-tests/tests/testsuite.rs
index d1d392fcde9ca..dcd03c9ca3eb9 100644
--- a/third_party/move/move-model/bytecode/ast-generator-tests/tests/testsuite.rs
+++ b/third_party/move/move-model/bytecode/ast-generator-tests/tests/testsuite.rs
@@ -96,22 +96,22 @@ fn generate_output(target: &FunctionTarget, test_output: &mut String) -> Option<
     };
     *test_output += &format!(
         "--- Raw Generated AST\n{}\n\n",
-        exp.display_for_fun(target.func_env.clone())
+        exp.display_for_fun(target.func_env)
     );
     let exp = astifier::transform_assigns(target, exp);
     *test_output += &format!(
         "--- Assign-Transformed Generated AST\n{}\n\n",
-        exp.display_for_fun(target.func_env.clone())
+        exp.display_for_fun(target.func_env)
     );
     let exp = astifier::transform_conditionals(target, exp);
     *test_output += &format!(
         "--- If-Transformed Generated AST\n{}\n\n",
-        exp.display_for_fun(target.func_env.clone())
+        exp.display_for_fun(target.func_env)
     );
     let exp = astifier::bind_free_vars(target, exp);
     *test_output += &format!(
         "--- Var-Bound Generated AST\n{}\n\n",
-        exp.display_for_fun(target.func_env.clone())
+        exp.display_for_fun(target.func_env)
     );
     Some(exp)
 }
diff --git a/third_party/move/move-model/bytecode/src/function_target_pipeline.rs b/third_party/move/move-model/bytecode/src/function_target_pipeline.rs
index 6834b82844cb3..4fd4d5b0e0485 100644
--- a/third_party/move/move-model/bytecode/src/function_target_pipeline.rs
+++ b/third_party/move/move-model/bytecode/src/function_target_pipeline.rs
@@ -368,7 +368,7 @@ impl FunctionTargetPipeline {
             let src_idx = nodes.get(&fun_id).unwrap();
             let fun_env = env.get_function(fun_id);
             for callee in fun_env
-                .get_called_functions()
+                .get_used_functions()
                 .expect("called functions must be computed")
             {
                 let dst_idx = nodes
diff --git a/third_party/move/move-model/src/ast.rs b/third_party/move/move-model/src/ast.rs
index e1c91a3e29b3a..7c5e120fd9de7 100644
--- a/third_party/move/move-model/src/ast.rs
+++ b/third_party/move/move-model/src/ast.rs
@@ -14,11 +14,12 @@ use crate::{
     symbol::{Symbol, SymbolPool},
     ty::{ReferenceKind, Type, TypeDisplayContext},
 };
+use either::Either;
 use internment::LocalIntern;
 use itertools::{EitherOrBoth, Itertools};
 use move_binary_format::{
     file_format,
-    file_format::{CodeOffset, Visibility},
+    file_format::{AbilitySet, CodeOffset, Visibility},
 };
 use move_core_types::account_address::AccountAddress;
 use num::BigInt;
@@ -349,6 +350,23 @@ impl Spec {
         self.any(move |c| c.kind == kind)
     }
 
+    /// Returns the functions used (called or loaded as a function value) in this spec, along with
+    /// the sites of the calls or loads.
+    pub fn used_funs_with_uses(&self) -> BTreeMap<QualifiedId<FunId>, BTreeSet<NodeId>> {
+        let mut result = BTreeMap::new();
+        for cond in self.conditions.iter().chain(self.update_map.values()) {
+            for exp in cond.all_exps() {
+                result.append(&mut exp.used_funs_with_uses())
+            }
+        }
+        for on_impl in self.on_impl.values() {
+            result.append(&mut on_impl.used_funs_with_uses())
+        }
+        result
+    }
+
+    /// Returns the functions called in this spec.  Does not include any functions used
+    /// as function values.
     pub fn called_funs_with_callsites(&self) -> BTreeMap<QualifiedId<FunId>, BTreeSet<NodeId>> {
         let mut result = BTreeMap::new();
         for cond in self.conditions.iter().chain(self.update_map.values()) {
@@ -512,6 +530,31 @@ pub enum AddressSpecifier {
     Call(QualifiedInstId<FunId>, Symbol),
 }
 
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, Default)]
+pub enum LambdaCaptureKind {
+    /// No modifier (e.g., inlining)
+    #[default]
+    Default,
+    /// Copy
+    Copy,
+    /// Move
+    Move,
+}
+
+impl fmt::Display for LambdaCaptureKind {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            LambdaCaptureKind::Default => {
+                write!(f, "")
+            },
+            LambdaCaptureKind::Copy => {
+                write!(f, "copy")
+            },
+            LambdaCaptureKind::Move => write!(f, "move"),
+        }
+    }
+}
+
 impl ResourceSpecifier {
     /// Checks whether this resource specifier matches the given struct. A function
     /// instantiation is passed to instantiate the specifier in the calling context
@@ -598,7 +641,7 @@ pub enum ExpData {
     /// Represents an invocation of a function value, as a lambda.
     Invoke(NodeId, Exp, Vec<Exp>),
     /// Represents a lambda.
-    Lambda(NodeId, Pattern, Exp),
+    Lambda(NodeId, Pattern, Exp, LambdaCaptureKind, AbilitySet),
     /// Represents a quantified formula over multiple variables and ranges.
     Quant(
         NodeId,
@@ -889,12 +932,12 @@ impl ExpData {
             use ExpData::*;
             use VisitorPosition::*;
             match (e, pos) {
-                (Lambda(_, pat, _), Pre) | (Block(_, pat, _, _), BeforeBody) => {
+                (Lambda(_, pat, ..), Pre) | (Block(_, pat, _, _), BeforeBody) => {
                     // Add declared variables to shadow; in the Block case,
                     // do it only after processing bindings.
                     for_syms_in_pat_shadow_or_unshadow(pat, true, &mut shadow_map);
                 },
-                (Lambda(_, pat, _), Post) | (Block(_, pat, _, _), Post) => {
+                (Lambda(_, pat, ..), Post) | (Block(_, pat, _, _), Post) => {
                     // Remove declared variables from shadow
                     for_syms_in_pat_shadow_or_unshadow(pat, false, &mut shadow_map);
                 },
@@ -1044,20 +1087,52 @@ impl ExpData {
         temps
     }
 
-    /// Returns the Move functions called by this expression
-    pub fn called_funs(&self) -> BTreeSet<QualifiedId<FunId>> {
-        let mut called = BTreeSet::new();
+    /// Returns the Move functions referenced by this expression
+    pub fn used_funs(&self) -> BTreeSet<QualifiedId<FunId>> {
+        let mut used = BTreeSet::new();
         let mut visitor = |e: &ExpData| {
             match e {
                 ExpData::Call(_, Operation::MoveFunction(mid, fid), _)
-                | ExpData::Call(_, Operation::Closure(mid, fid), _) => {
-                    called.insert(mid.qualified(*fid));
+                | ExpData::Value(_, Value::Function(mid, fid)) => {
+                    used.insert(mid.qualified(*fid));
                 },
                 _ => {},
             }
             true // keep going
         };
         self.visit_post_order(&mut visitor);
+        used
+    }
+
+    /// Returns the Move functions called or referenced by this expression, along with nodes of call sites or references.
+    pub fn used_funs_with_uses(&self) -> BTreeMap<QualifiedId<FunId>, BTreeSet<NodeId>> {
+        let mut used: BTreeMap<_, BTreeSet<_>> = BTreeMap::new();
+        let mut visitor = |e: &ExpData| {
+            match e {
+                ExpData::Call(node_id, Operation::MoveFunction(mid, fid), _)
+                | ExpData::Value(node_id, Value::Function(mid, fid)) => {
+                    used.entry(mid.qualified(*fid))
+                        .or_default()
+                        .insert(*node_id);
+                },
+                _ => {},
+            };
+            true // keep going
+        };
+        self.visit_post_order(&mut visitor);
+        used
+    }
+
+    /// Returns the Move functions called by this expression
+    pub fn called_funs(&self) -> BTreeSet<QualifiedId<FunId>> {
+        let mut called = BTreeSet::new();
+        let mut visitor = |e: &ExpData| {
+            if let ExpData::Call(_, Operation::MoveFunction(mid, fid), _) = e {
+                called.insert(mid.qualified(*fid));
+            };
+            true // keep going
+        };
+        self.visit_post_order(&mut visitor);
         called
     }
 
@@ -1366,7 +1441,7 @@ impl ExpData {
                     exp.visit_positions_impl(visitor)?;
                 }
             },
-            Lambda(_, _, body) => body.visit_positions_impl(visitor)?,
+            Lambda(_, _, body, _, _) => body.visit_positions_impl(visitor)?,
             Quant(_, _, ranges, triggers, condition, body) => {
                 for (_, range) in ranges {
                     range.visit_positions_impl(visitor)?;
@@ -1739,6 +1814,14 @@ impl ExpRewriterFunctions for LoopNestRewriter {
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum Operation {
     MoveFunction(ModuleId, FunId),
+    /// Build a closure by binding 1 or more leading arguments to a function value.
+    /// First argument to the operation must be a function; the remaining
+    /// arguments will be bound, in order, to the leading parameters of that function,
+    /// generating a function which takes the remaining parameters and then calls
+    /// the function with the complete set of parameters.
+    ///     (move |x, y| f(z, x, y)) === ExpData::Call(_, EarlyBind, vec![f, z])
+    ///     (move || f(z, x, y)) === ExpData::Call(_, EarlyBind, vec![f, z, x, y])
+    EarlyBind,
     Pack(ModuleId, StructId, /*variant*/ Option<Symbol>),
     Tuple,
     Select(ModuleId, StructId, FieldId),
@@ -1751,7 +1834,6 @@ pub enum Operation {
 
     // Specification specific
     SpecFunction(ModuleId, SpecFunId, Option<Vec<MemoryLabel>>),
-    Closure(ModuleId, FunId),
     UpdateField(ModuleId, StructId, FieldId),
     Result(usize),
     Index,
@@ -2221,7 +2303,7 @@ impl Pattern {
         PatDisplay {
             env: fun_env.module_env.env,
             pat: self,
-            fun_env: Some(fun_env.clone()),
+            fun_env: Some(fun_env),
             show_type: false,
         }
         .to_string()
@@ -2240,7 +2322,7 @@ impl Pattern {
         PatDisplay {
             env: other.env,
             pat: self,
-            fun_env: other.fun_env.clone(),
+            fun_env: other.fun_env,
             show_type: other.show_type,
         }
     }
@@ -2249,7 +2331,7 @@ impl Pattern {
         PatDisplay {
             env: other.env,
             pat: self,
-            fun_env: other.fun_env.clone(),
+            fun_env: other.fun_env,
             show_type: true,
         }
     }
@@ -2259,7 +2341,7 @@ impl Pattern {
 pub struct PatDisplay<'a> {
     env: &'a GlobalEnv,
     pat: &'a Pattern,
-    fun_env: Option<FunctionEnv<'a>>,
+    fun_env: Option<&'a FunctionEnv<'a>>,
     show_type: bool,
 }
 
@@ -2403,6 +2485,8 @@ pub enum Value {
     AddressArray(Vec<Address>), // TODO: merge AddressArray to Vector type in the future
     Vector(Vec<Value>),
     Tuple(Vec<Value>),
+    /// Represents a reference to a Move Function as a function value.
+    Function(ModuleId, FunId),
 }
 
 impl Value {
@@ -2491,6 +2575,9 @@ impl Value {
                         Some(false)
                     }
                 },
+                (Value::Function(mid1, sid1), Value::Function(mid2, sid2)) => {
+                    Some(mid1 == mid2 && sid1 == sid2)
+                },
                 _ => Some(false),
             }
         } else {
@@ -2511,6 +2598,14 @@ impl<'a> fmt::Display for EnvDisplay<'a, Value> {
             Value::AddressArray(array) => write!(f, "a{:?}", array),
             Value::Vector(array) => write!(f, "{:?}", array),
             Value::Tuple(array) => write!(f, "({:?})", array),
+            Value::Function(mid, fid) => write!(
+                f,
+                "{}",
+                self.env
+                    .get_function_opt(mid.qualified(*fid))
+                    .map(|fun| fun.get_full_name_str())
+                    .unwrap_or_else(|| "<?unknown function?>".to_string())
+            ),
         }
     }
 }
@@ -2574,12 +2669,12 @@ impl Operation {
         match self {
             MoveFunction(..) => false, // could abort
             SpecFunction(..) => false, // Spec
-            Closure(..) => false,      // Spec
             Pack(..) => false,         // Could yield an undroppable value
             Tuple => true,
             Select(..) => false,         // Move-related
             SelectVariants(..) => false, // Move-related
             UpdateField(..) => false,    // Move-related
+            EarlyBind => true,
 
             // Specification specific
             Result(..) => false, // Spec
@@ -3035,28 +3130,32 @@ impl ExpData {
             fun_env: None,
             verbose: false,
             annotator: None,
+            tctx: Either::Left(TypeDisplayContext::new(env)),
         }
     }
 
     /// Creates a display of an expression which can be used in formatting, based
     /// on a function env for getting names of locals and type parameters.
-    pub fn display_for_fun<'a>(&'a self, fun_env: FunctionEnv<'a>) -> ExpDisplay<'a> {
+    pub fn display_for_fun<'a>(&'a self, fun_env: &'a FunctionEnv<'a>) -> ExpDisplay<'a> {
+        let tctx = Either::Left(fun_env.get_type_display_ctx());
         ExpDisplay {
             env: fun_env.module_env.env,
             exp: self,
             fun_env: Some(fun_env),
             verbose: false,
             annotator: None,
+            tctx,
         }
     }
 
-    fn display_cont<'a>(&'a self, other: &ExpDisplay<'a>) -> ExpDisplay<'a> {
+    fn display_cont<'a>(&'a self, other: &'a ExpDisplay<'a>) -> ExpDisplay<'a> {
         ExpDisplay {
             env: other.env,
             exp: self,
-            fun_env: other.fun_env.clone(),
+            fun_env: other.fun_env,
             verbose: other.verbose,
             annotator: other.annotator,
+            tctx: Either::Right(other.get_tctx()),
         }
     }
 
@@ -3067,6 +3166,7 @@ impl ExpData {
             fun_env: None,
             verbose: true,
             annotator: None,
+            tctx: Either::Left(TypeDisplayContext::new(env)),
         }
     }
 
@@ -3084,6 +3184,7 @@ impl ExpData {
             fun_env: None,
             verbose: false,
             annotator: Some(annotator),
+            tctx: Either::Left(TypeDisplayContext::new(env)),
         }
     }
 }
@@ -3092,9 +3193,19 @@ impl ExpData {
 pub struct ExpDisplay<'a> {
     env: &'a GlobalEnv,
     exp: &'a ExpData,
-    fun_env: Option<FunctionEnv<'a>>,
+    fun_env: Option<&'a FunctionEnv<'a>>,
     verbose: bool,
     annotator: Option<&'a dyn Fn(NodeId) -> String>,
+    tctx: Either<TypeDisplayContext<'a>, &'a TypeDisplayContext<'a>>,
+}
+
+impl<'a> ExpDisplay<'a> {
+    fn get_tctx(&'a self) -> &'a TypeDisplayContext<'a> {
+        match &self.tctx {
+            Either::Left(tctx) => tctx,
+            Either::Right(tctx_ref) => tctx_ref,
+        }
+    }
 }
 
 impl<'a> fmt::Display for ExpDisplay<'a> {
@@ -3140,22 +3251,44 @@ impl<'a> fmt::Display for ExpDisplay<'a> {
                     self.fmt_exps(args)
                 )
             },
-            Lambda(id, pat, body) => {
+            Lambda(id, pat, body, capture_kind, abilities) => {
                 if self.verbose {
                     write!(
                         f,
-                        "{}: |{}| {}",
+                        "{}: {}{}|{}| {}",
                         id.as_usize(),
+                        if *capture_kind != LambdaCaptureKind::Default {
+                            " "
+                        } else {
+                            ""
+                        },
+                        capture_kind,
                         pat.display_for_exp(self),
                         body.display_cont(self)
-                    )
+                    )?;
                 } else {
                     write!(
                         f,
-                        "|{}| {}",
+                        "{}{}|{}| {}",
+                        if *capture_kind != LambdaCaptureKind::Default {
+                            " "
+                        } else {
+                            ""
+                        },
+                        capture_kind,
                         pat.display_for_exp(self),
                         body.display_cont(self)
-                    )
+                    )?;
+                }
+                if !abilities.is_subset(AbilitySet::FUNCTIONS) {
+                    let abilities_as_str = abilities
+                        .iter()
+                        .map(|a| a.to_string())
+                        .reduce(|l, r| format!("{}, {}", l, r))
+                        .unwrap_or_default();
+                    write!(f, " with {}", abilities_as_str)
+                } else {
+                    Ok(())
                 }
             },
             Block(id, pat, binding, body) => {
@@ -3349,7 +3482,21 @@ impl Operation {
             env,
             oper: self,
             node_id,
-            tctx,
+            tctx: Either::Left(tctx),
+        }
+    }
+
+    fn display_with_context_ref<'a>(
+        &'a self,
+        env: &'a GlobalEnv,
+        node_id: NodeId,
+        tctx: &'a TypeDisplayContext<'a>,
+    ) -> OperationDisplay<'a> {
+        OperationDisplay {
+            env,
+            oper: self,
+            node_id,
+            tctx: Either::Right(tctx),
         }
     }
 
@@ -3373,17 +3520,8 @@ impl Operation {
         exp_display: &'a ExpDisplay,
         node_id: NodeId,
     ) -> OperationDisplay<'a> {
-        let tctx = if let Some(fe) = &exp_display.fun_env {
-            fe.get_type_display_ctx()
-        } else {
-            TypeDisplayContext::new(exp_display.env)
-        };
-        OperationDisplay {
-            env: exp_display.env,
-            oper: self,
-            node_id,
-            tctx,
-        }
+        let tctx = exp_display.get_tctx();
+        self.display_with_context_ref(exp_display.env, node_id, tctx)
     }
 }
 
@@ -3392,7 +3530,16 @@ pub struct OperationDisplay<'a> {
     env: &'a GlobalEnv,
     node_id: NodeId,
     oper: &'a Operation,
-    tctx: TypeDisplayContext<'a>,
+    tctx: Either<TypeDisplayContext<'a>, &'a TypeDisplayContext<'a>>,
+}
+
+impl<'a> OperationDisplay<'a> {
+    fn get_tctx(&'a self) -> &'a TypeDisplayContext<'a> {
+        match &self.tctx {
+            Either::Left(tctx) => tctx,
+            Either::Right(tctx_ref) => tctx_ref,
+        }
+    }
 }
 
 impl<'a> fmt::Display for OperationDisplay<'a> {
@@ -3401,7 +3548,7 @@ impl<'a> fmt::Display for OperationDisplay<'a> {
         match self.oper {
             Cast => {
                 let ty = self.env.get_node_type(self.node_id);
-                write!(f, "{:?}<{}>", self.oper, ty.display(&self.tctx))
+                write!(f, "{:?}<{}>", self.oper, ty.display(self.get_tctx()))
             },
             SpecFunction(mid, fid, labels_opt) => {
                 write!(f, "{}", self.fun_str(mid, fid))?;
@@ -3419,18 +3566,13 @@ impl<'a> fmt::Display for OperationDisplay<'a> {
                     f,
                     "{}",
                     self.env
-                        .get_function(mid.qualified(*fid))
-                        .get_full_name_str()
+                        .get_function_opt(mid.qualified(*fid))
+                        .map(|fun| fun.get_full_name_str())
+                        .unwrap_or_else(|| "<?unknown function?>".to_string())
                 )
             },
-            Closure(mid, fid) => {
-                write!(
-                    f,
-                    "closure {}",
-                    self.env
-                        .get_function(mid.qualified(*fid))
-                        .get_full_name_str()
-                )
+            EarlyBind => {
+                write!(f, "earlybind")
             },
             Global(label_opt) => {
                 write!(f, "global")?;
@@ -3488,7 +3630,10 @@ impl<'a> fmt::Display for OperationDisplay<'a> {
             write!(
                 f,
                 "<{}>",
-                type_inst.iter().map(|ty| ty.display(&self.tctx)).join(", ")
+                type_inst
+                    .iter()
+                    .map(|ty| ty.display(self.get_tctx()))
+                    .join(", ")
             )?;
         }
         Ok(())
@@ -3507,12 +3652,23 @@ impl<'a> OperationDisplay<'a> {
     }
 
     fn struct_str(&self, mid: &ModuleId, sid: &StructId) -> String {
-        let module_env = self.env.get_module(*mid);
-        let struct_env = module_env.get_struct(*sid);
+        let module_env_opt = self.env.get_module_opt(*mid);
+        let struct_env_str = module_env_opt
+            .clone()
+            .map(|module_env| {
+                module_env
+                    .get_struct(*sid)
+                    .get_name()
+                    .display(self.env.symbol_pool())
+                    .to_string()
+            })
+            .unwrap_or_else(|| "None".to_string());
         format!(
             "{}::{}",
-            module_env.get_name().display(self.env),
-            struct_env.get_name().display(self.env.symbol_pool()),
+            module_env_opt
+                .map(|module_env| module_env.get_name().display(self.env).to_string())
+                .unwrap_or_else(|| "None".to_string()),
+            struct_env_str
         )
     }
 
diff --git a/third_party/move/move-model/src/builder/exp_builder.rs b/third_party/move/move-model/src/builder/exp_builder.rs
index 8f16fa60111de..f91e4dd28bd9f 100644
--- a/third_party/move/move-model/src/builder/exp_builder.rs
+++ b/third_party/move/move-model/src/builder/exp_builder.rs
@@ -4,9 +4,9 @@
 
 use crate::{
     ast::{
-        AccessSpecifier, Address, AddressSpecifier, Exp, ExpData, MatchArm, ModuleName, Operation,
-        Pattern, QualifiedSymbol, QuantKind, ResourceSpecifier, RewriteResult, Spec, TempIndex,
-        Value,
+        AccessSpecifier, Address, AddressSpecifier, Exp, ExpData, LambdaCaptureKind, MatchArm,
+        ModuleName, Operation, Pattern, QualifiedSymbol, QuantKind, ResourceSpecifier,
+        RewriteResult, Spec, TempIndex, Value,
     },
     builder::{
         model_builder::{
@@ -178,9 +178,28 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
         et
     }
 
-    pub fn check_language_version(&self, loc: &Loc, feature: &str, version_min: LanguageVersion) {
+    /// Returns `true` if language version is ok. Otherwise,
+    /// issues an error message and returns `false`.
+    pub fn test_language_version(
+        &self,
+        loc: &Loc,
+        feature: &str,
+        version_min: LanguageVersion,
+    ) -> bool {
+        self.parent.test_language_version(loc, feature, version_min)
+    }
+
+    /// Returns `Some(())` if language version checks out.  Otherwise,
+    /// issues an error message and returns `None`.
+    pub fn check_language_version(
+        &self,
+        loc: &Loc,
+        feature: &str,
+        version_min: LanguageVersion,
+    ) -> Option<()> {
         self.parent
-            .check_language_version(loc, feature, version_min);
+            .test_language_version(loc, feature, version_min)
+            .then_some(())
     }
 
     pub fn set_spec_block_map(&mut self, map: BTreeMap<EA::SpecId, EA::SpecBlock>) {
@@ -891,6 +910,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
                                 self.translate_hlir_base_types(&args[0..args.len() - 1]),
                             )),
                             Box::new(self.translate_hlir_base_type(&args[args.len() - 1])),
+                            AbilitySet::FUNCTIONS,
                         ),
                     },
                     ModuleType(m, n) => {
@@ -1061,9 +1081,10 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
                 ReferenceKind::from_is_mut(*is_mut),
                 Box::new(self.translate_type(ty)),
             ),
-            Fun(args, result) => Type::Fun(
+            Fun(args, result, abilities) => Type::Fun(
                 Box::new(Type::tuple(self.translate_types(args.as_ref()))),
                 Box::new(self.translate_type(result)),
+                AbilitySet::FUNCTIONS | self.parent.translate_abilities(abilities),
             ),
             Unit => Type::Tuple(vec![]),
             Multiple(vst) => Type::Tuple(self.translate_types(vst.as_ref())),
@@ -1147,16 +1168,16 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
                 &loc,
                 "read/write access specifiers. Try `acquires` instead.",
                 LanguageVersion::V2_0,
-            )
+            )?;
         } else if *negated {
-            self.check_language_version(&loc, "access specifier negation", LanguageVersion::V2_0)
+            self.check_language_version(&loc, "access specifier negation", LanguageVersion::V2_0)?;
         } else if type_args.is_some() && !type_args.as_ref().unwrap().is_empty() {
             self.check_language_version(
                 &loc,
                 "access specifier type instantiation. Try removing the type instantiation.",
                 LanguageVersion::V2_0,
-            )
-        }
+            )?;
+        };
         let resource = match (module_address, module_name, resource_name) {
             (None, None, None) => {
                 // This stems from a  specifier of the form `acquires *(0x1)`
@@ -1248,8 +1269,8 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
                 &loc,
                 "address and wildcard access specifiers. Only resource type names can be provided.",
                 LanguageVersion::V2_0,
-            );
-        }
+            )?;
+        };
         let address = self.translate_address_specifier(address)?;
         Some(AccessSpecifier {
             loc: loc.clone(),
@@ -1272,7 +1293,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
                     &loc,
                     "wildcard address specifiers",
                     LanguageVersion::V2_0,
-                );
+                )?;
                 (loc, AddressSpecifier::Any)
             },
             EA::AddressSpecifier_::Literal(addr) => {
@@ -1280,7 +1301,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
                     &loc,
                     "literal address specifiers",
                     LanguageVersion::V2_0,
-                );
+                )?;
                 (
                     loc,
                     AddressSpecifier::Address(Address::Numerical(addr.into_inner())),
@@ -1291,7 +1312,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
                     &loc,
                     "named address specifiers",
                     LanguageVersion::V2_0,
-                );
+                )?;
                 // Construct an expansion name exp for regular type check
                 let maccess = sp(name.loc, EA::ModuleAccess_::Name(*name));
                 self.translate_name(
@@ -1311,7 +1332,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
                     &loc,
                     "derived address specifiers",
                     LanguageVersion::V2_0,
-                );
+                )?;
                 // Construct an expansion function call for regular type check
                 let name_exp = sp(
                     name.loc,
@@ -1380,6 +1401,15 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
         self.translate_exp_in_context(exp, expected_type, &ErrorMessageContext::General)
     }
 
+    /// Translates LambdaCaptureKind
+    pub fn translate_lambda_capture_kind(kind: PA::LambdaCaptureKind) -> LambdaCaptureKind {
+        match kind {
+            PA::LambdaCaptureKind::Default => LambdaCaptureKind::Default,
+            PA::LambdaCaptureKind::Copy => LambdaCaptureKind::Copy,
+            PA::LambdaCaptureKind::Move => LambdaCaptureKind::Move,
+        }
+    }
+
     /// Translates an expression in a specific error message context.
     pub fn translate_exp_in_context(
         &mut self,
@@ -1511,6 +1541,19 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
                     )
                 }
             },
+            EA::Exp_::ExpCall(efexp, args) => {
+                let args_ref: Vec<_> = args.value.iter().collect();
+                let (arg_types, args) = self.translate_exp_list(&args_ref);
+
+                let fun_t = Type::Fun(
+                    Box::new(Type::tuple(arg_types)),
+                    Box::new(expected_type.clone()),
+                    AbilitySet::FUNCTIONS,
+                );
+                let fexp = self.translate_exp(efexp, &fun_t);
+                let id = self.new_node_id_with_type_loc(expected_type, &loc);
+                ExpData::Invoke(id, fexp.into_exp(), args)
+            },
             EA::Exp_::Pack(maccess, generics, fields) => self
                 .translate_pack(
                     &loc,
@@ -1608,9 +1651,15 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
                 ExpData::LoopCont(id, nest, true)
             },
             EA::Exp_::Block(seq) => self.translate_seq(&loc, seq, expected_type, context),
-            EA::Exp_::Lambda(bindings, exp) => {
-                self.translate_lambda(&loc, bindings, exp, expected_type, context)
-            },
+            EA::Exp_::Lambda(bindings, exp, capture_kind, abilities) => self.translate_lambda(
+                &loc,
+                bindings,
+                exp,
+                expected_type,
+                context,
+                Self::translate_lambda_capture_kind(*capture_kind),
+                AbilitySet::FUNCTIONS | self.parent.translate_abilities(abilities),
+            ),
             EA::Exp_::Quant(kind, ranges, triggers, condition, body) => self.translate_quant(
                 &loc,
                 *kind,
@@ -3143,7 +3192,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
         // handles call of struct/variant with positional fields
         let expected_type = &self.subs.specialize(expected_type);
         if self.can_resolve_to_struct(expected_type, maccess) {
-            self.check_language_version(loc, "positional fields", LanguageVersion::V2_0);
+            self.check_language_version(loc, "positional fields", LanguageVersion::V2_0)?;
             // translates StructName(e0, e1, ...) to pack<StructName> { 0: e0, 1: e1, ... }
             let fields: EA::Fields<_> =
                 EA::Fields::maybe_from_iter(args.iter().enumerate().map(|(i, &arg)| {
@@ -3185,8 +3234,15 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
                 let fun_t = Type::Fun(
                     Box::new(Type::tuple(arg_types)),
                     Box::new(expected_type.clone()),
+                    if let Type::Fun(.., abilities) = &sym_ty {
+                        *abilities
+                    } else {
+                        // Don't constraint Abilities of sym_ty.
+                        AbilitySet::MAXIMAL_FUNCTIONS
+                    },
                 );
                 let sym_ty = self.check_type(loc, &sym_ty, &fun_t, context);
+
                 let local_id = self.new_node_id_with_type_loc(&sym_ty, &self.to_loc(&n.loc));
                 let local_var = ExpData::LocalVar(local_id, sym);
                 let id = self.new_node_id_with_type_loc(expected_type, loc);
@@ -3289,8 +3345,9 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
     /// translated expression.
     pub fn translate_exp_free(&mut self, exp: &EA::Exp) -> (Type, ExpData) {
         let tvar = self.fresh_type_var();
-        let exp = self.translate_exp(exp, &tvar);
-        (self.subs.specialize(&tvar), exp)
+        let exp_out = self.translate_exp(exp, &tvar);
+        let tsub = self.subs.specialize(&tvar);
+        (tsub, exp_out)
     }
 
     /// Translates a sequence expression.
@@ -3520,6 +3577,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
             let instantiation = self.translate_types(type_args.as_slice());
             let ty = ty.instantiate(&instantiation);
             let ty = self.check_type(loc, &ty, expected_type, context);
+
             // Create expression global<GhostMem>(@0).v which backs up the ghost variable.
             let ghost_mem_id = StructId::new(
                 self.parent
@@ -3549,6 +3607,45 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
                 vec![global_access.into_exp()],
             );
         }
+
+        if let Some(entry) = self.parent.parent.fun_table.get(&global_var_sym) {
+            let module_id = entry.module_id;
+            let fun_id = entry.fun_id;
+            let fun_abilities = if entry.visibility.is_public() {
+                AbilitySet::PUBLIC_FUNCTIONS
+            } else {
+                AbilitySet::PRIVATE_FUNCTIONS
+            };
+            let result_type = entry.result_type.clone();
+            let type_params = entry.type_params.clone();
+            let param_types = entry
+                .params
+                .iter()
+                .map(|param| param.get_type())
+                .collect_vec();
+            let Some(instantiation) = self.make_instantiation_or_report(
+                loc,
+                false,
+                global_var_sym.symbol,
+                &type_params,
+                type_args,
+            ) else {
+                return self.new_error_exp();
+            };
+            let fun_type = Type::Fun(
+                Box::new(Type::tuple(param_types)),
+                Box::new(result_type),
+                fun_abilities,
+            );
+            let fun_type = fun_type.instantiate(&instantiation);
+            let fun_type = self.check_type(loc, &fun_type, expected_type, context);
+
+            let id = self.env().new_node(loc.clone(), fun_type);
+            self.env().set_node_instantiation(id, instantiation);
+            let fn_exp = ExpData::Value(id, Value::Function(module_id, fun_id));
+            return fn_exp;
+        }
+
         // If a qualified name is not explicitly specified, do not print it out
         let qualified_display = if let EA::ModuleAccess_::ModuleAccess(..) = maccess.value {
             global_var_sym.display(self.env())
@@ -3768,7 +3865,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
                 .struct_table
                 .contains_key(&global_var_sym)
             {
-                self.check_language_version(loc, "resource indexing", LanguageVersion::V2_0);
+                self.check_language_version(loc, "resource indexing", LanguageVersion::V2_0)?;
                 if self
                     .parent
                     .parent
@@ -3798,7 +3895,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
             }
         }
         if !self.is_spec_mode() {
-            self.check_language_version(loc, "vector indexing", LanguageVersion::V2_0);
+            self.check_language_version(loc, "vector indexing", LanguageVersion::V2_0)?;
             // Translate to vector indexing in impl mode if the target is not a resource or a spec schema
             // spec mode is handled in `translate_index`
             if call.is_none() {
@@ -4125,7 +4222,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
         expected_type: &Type,
         context: &ErrorMessageContext,
     ) -> ExpData {
-        // Translate arguments.
+        // Translate arguments: arg_types is needed to do candidate matching.
         let (mut arg_types, mut translated_args) = self.translate_exp_list(args);
 
         // Special handling of receiver call functions
@@ -4224,6 +4321,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
             self.error(loc, &format!("no function named `{}` found", display));
             return self.new_error_exp();
         }
+
         // Partition candidates in those which matched and which have been outruled.
         let mut outruled = vec![];
         let mut matching = vec![];
@@ -4283,6 +4381,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
                     continue;
                 }
             }
+
             // Process arguments
             let mut success = true;
             for (i, arg_ty) in arg_types.iter().enumerate() {
@@ -4369,6 +4468,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
                 let (cand, subs, instantiation) = matching.remove(0);
                 let (_, _, result_type) = cand.get_signature();
                 let result_type = result_type.instantiate(&instantiation);
+
                 // Commit the candidate substitution to this expression translator.
                 self.subs = subs;
 
@@ -4409,8 +4509,10 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
                         .add_used_spec_fun(module_id.qualified(spec_fun_id));
                     self.called_spec_funs.insert((module_id, spec_fun_id));
                 }
+
                 let translated_args = self.add_conversions(cand, &instantiation, translated_args);
                 let specialized_expected_type = self.subs.specialize(expected_type);
+
                 let call_exp = ExpData::Call(id, oper, translated_args).into_exp();
                 // Insert freeze for the return value
                 let call_exp = if let (Type::Tuple(ref result_tys), Type::Tuple(expected_tys)) =
@@ -4553,7 +4655,11 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
         args: Vec<Exp>,
         expected_type: &Type,
     ) -> ExpData {
-        self.check_language_version(loc, "receiver style function calls", LanguageVersion::V2_0);
+        if !self.test_language_version(loc, "receiver style function calls", LanguageVersion::V2_0)
+        {
+            let id = self.new_node_id_with_type_loc(&Type::Error, loc);
+            return ExpData::Invalid(id);
+        }
         let generics = generics
             .as_ref()
             .map(|tys| self.translate_types_with_loc(tys));
@@ -4586,16 +4692,12 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
 
     /// Translate a list of expressions and deliver them together with their types.
     fn translate_exp_list(&mut self, exps: &[&EA::Exp]) -> (Vec<Type>, Vec<Exp>) {
-        let mut types = vec![];
-        let exps = exps
-            .iter()
+        exps.iter()
             .map(|e| {
                 let (t, e) = self.translate_exp_free(e);
-                types.push(t);
-                e.into_exp()
+                (t, e.into_exp())
             })
-            .collect_vec();
-        (types, exps)
+            .unzip()
     }
 
     /// Creates a type instantiation using optionally provided type arguments.
@@ -5135,6 +5237,8 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
         body: &EA::Exp,
         expected_type: &Type,
         context: &ErrorMessageContext,
+        capture_kind: LambdaCaptureKind,
+        abilities: AbilitySet,
     ) -> ExpData {
         // Translate the argument list
         let arg_type = self.fresh_type_var();
@@ -5155,14 +5259,18 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
         let ty = self.fresh_type_var();
         let rty = self.check_type(
             loc,
-            &Type::Fun(Box::new(arg_type), Box::new(ty.clone())),
+            &Type::Fun(
+                Box::new(arg_type.clone()),
+                Box::new(ty.clone()),
+                abilities.union(AbilitySet::MAXIMAL_FUNCTIONS),
+            ),
             expected_type,
             context,
         );
         let rbody = self.translate_exp(body, &ty);
         self.exit_scope();
         let id = self.new_node_id_with_type_loc(&rty, loc);
-        ExpData::Lambda(id, pat, rbody.into_exp())
+        ExpData::Lambda(id, pat, rbody.into_exp(), capture_kind, abilities)
     }
 
     fn translate_quant(
@@ -5257,6 +5365,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
         ExpData::Quant(id, rkind, rranges, rtriggers, rcondition, rbody.into_exp())
     }
 
+    /// Unify types with order `LeftToRight` and shallow variance
     pub fn check_type(
         &mut self,
         loc: &Loc,
@@ -5267,6 +5376,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
         self.check_type_with_order(WideningOrder::LeftToRight, loc, ty, expected, context)
     }
 
+    /// Unify types with order `Join` and shallow variance, and specified error message override
     pub fn join_type(
         &mut self,
         loc: &Loc,
@@ -5277,6 +5387,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
         self.check_type_with_order(WideningOrder::Join, loc, ty1, ty2, context)
     }
 
+    /// Unify types with shallow variance, and specified error message override
     fn check_type_with_order(
         &mut self,
         order: WideningOrder,
@@ -5293,6 +5404,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
             })
     }
 
+    /// Unify types with specified variance and order
     fn unify_types(
         &mut self,
         variance: Variance,
@@ -5379,8 +5491,8 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
             | (Type::TypeParameter(_), MoveValue::Struct(_))
             | (Type::Reference(_, _), MoveValue::Vector(_))
             | (Type::Reference(_, _), MoveValue::Struct(_))
-            | (Type::Fun(_, _), MoveValue::Vector(_))
-            | (Type::Fun(_, _), MoveValue::Struct(_))
+            | (Type::Fun(..), MoveValue::Vector(_))
+            | (Type::Fun(..), MoveValue::Struct(_))
             | (Type::TypeDomain(_), MoveValue::Vector(_))
             | (Type::TypeDomain(_), MoveValue::Struct(_))
             | (Type::ResourceDomain(_, _, _), MoveValue::Vector(_))
diff --git a/third_party/move/move-model/src/builder/model_builder.rs b/third_party/move/move-model/src/builder/model_builder.rs
index 79586773981db..55c3b34520c19 100644
--- a/third_party/move/move-model/src/builder/model_builder.rs
+++ b/third_party/move/move-model/src/builder/model_builder.rs
@@ -496,20 +496,24 @@ impl<'env> ModelBuilder<'env> {
         for cur_mod in target_modules {
             let cur_mod_env = self.env.get_module(cur_mod);
             let cur_mod_name = cur_mod_env.get_name().clone();
-            for need_to_be_friended_by in cur_mod_env.need_to_be_friended_by() {
-                let need_to_be_friend_with = self.env.get_module_data_mut(need_to_be_friended_by);
+            let needed = cur_mod_env.need_to_be_friended_by();
+            for need_to_be_friended_by in needed {
+                let need_to_be_friend_with = self.env.get_module(need_to_be_friended_by);
                 let already_friended = need_to_be_friend_with
-                    .friend_decls
+                    .get_friend_decls()
                     .iter()
                     .any(|friend_decl| friend_decl.module_name == cur_mod_name);
                 if !already_friended {
-                    let loc = need_to_be_friend_with.loc.clone();
+                    let loc = need_to_be_friend_with.get_loc();
                     let friend_decl = FriendDecl {
                         loc,
                         module_name: cur_mod_name.clone(),
                         module_id: Some(cur_mod),
                     };
-                    need_to_be_friend_with.friend_decls.push(friend_decl);
+                    self.env
+                        .get_module_data_mut(need_to_be_friended_by)
+                        .friend_decls
+                        .push(friend_decl);
                 }
             }
         }
diff --git a/third_party/move/move-model/src/builder/module_builder.rs b/third_party/move/move-model/src/builder/module_builder.rs
index e6e1f65ff313f..048b68444e709 100644
--- a/third_party/move/move-model/src/builder/module_builder.rs
+++ b/third_party/move/move-model/src/builder/module_builder.rs
@@ -918,7 +918,14 @@ impl<'env, 'translator> ModuleBuilder<'env, 'translator> {
 /// # Definition Analysis
 
 impl<'env, 'translator> ModuleBuilder<'env, 'translator> {
-    pub fn check_language_version(&self, loc: &Loc, feature: &str, version_min: LanguageVersion) {
+    /// Returns `true` if language version is ok. Otherwise,
+    /// issues an error message and returns `false`.
+    pub fn test_language_version(
+        &self,
+        loc: &Loc,
+        feature: &str,
+        version_min: LanguageVersion,
+    ) -> bool {
         if !self.parent.env.language_version().is_at_least(version_min) {
             self.parent.env.error(
                 loc,
@@ -926,7 +933,10 @@ impl<'env, 'translator> ModuleBuilder<'env, 'translator> {
                     "not supported before language version `{}`: {}",
                     version_min, feature
                 ),
-            )
+            );
+            false
+        } else {
+            true
         }
     }
 
@@ -1012,11 +1022,13 @@ impl<'env, 'translator> ModuleBuilder<'env, 'translator> {
                 if !self.parent.const_table.contains_key(&qsym) {
                     continue;
                 }
-                self.check_language_version(
+                if !self.test_language_version(
                     &loc,
                     "constant definitions referring to other constants",
                     LanguageVersion::V2_0,
-                );
+                ) {
+                    continue;
+                }
                 if visited.contains(&const_name) {
                     continue;
                 }
@@ -2634,10 +2646,13 @@ impl<'env, 'translator> ModuleBuilder<'env, 'translator> {
     ) {
         // Type check and translate lhs and rhs. They must have the same type.
         let mut et = self.exp_translator_for_context(loc, context, &ConditionKind::Requires);
-        let (expected_ty, lhs) = et.translate_exp_free(lhs);
-        let rhs = et.translate_exp(rhs, &expected_ty);
+        let (expected_ty, translated_lhs) = et.translate_exp_free(lhs);
+        let translated_rhs = et.translate_exp(rhs, &expected_ty);
         et.finalize_types();
-        if lhs.extract_ghost_mem_access(self.parent.env).is_some() {
+        if translated_lhs
+            .extract_ghost_mem_access(self.parent.env)
+            .is_some()
+        {
             // Add as a condition to the context.
             self.add_conditions_to_context(
                 context,
@@ -2646,15 +2661,15 @@ impl<'env, 'translator> ModuleBuilder<'env, 'translator> {
                     loc: loc.clone(),
                     kind: ConditionKind::Update,
                     properties: Default::default(),
-                    exp: rhs.into_exp(),
-                    additional_exps: vec![lhs.into_exp()],
+                    exp: translated_rhs.into_exp(),
+                    additional_exps: vec![translated_lhs.into_exp()],
                 }],
                 PropertyBag::default(),
                 "",
             );
         } else {
             self.parent.error(
-                &self.parent.env.get_node_loc(lhs.node_id()),
+                &self.parent.env.get_node_loc(translated_lhs.node_id()),
                 "target of `update` restricted to specification variables",
             )
         }
@@ -3726,6 +3741,7 @@ impl<'env, 'translator> ModuleBuilder<'env, 'translator> {
             let spec = self.fun_specs.remove(&name.symbol).unwrap_or_default();
             let def = self.fun_defs.remove(&name.symbol);
             let called_funs = Some(def.as_ref().map(|e| e.called_funs()).unwrap_or_default());
+            let used_funs = Some(def.as_ref().map(|e| e.used_funs()).unwrap_or_default());
             let access_specifiers = self.fun_access_specifiers.remove(&name.symbol);
             let fun_id = FunId::new(name.symbol);
             let data = FunctionData {
@@ -3751,6 +3767,9 @@ impl<'env, 'translator> ModuleBuilder<'env, 'translator> {
                 called_funs,
                 calling_funs: RefCell::default(),
                 transitive_closure_of_called_funs: RefCell::default(),
+                used_funs,
+                using_funs: RefCell::default(),
+                transitive_closure_of_used_funs: RefCell::default(),
             };
             function_data.insert(fun_id, data);
         }
diff --git a/third_party/move/move-model/src/exp_rewriter.rs b/third_party/move/move-model/src/exp_rewriter.rs
index d55b7842c3e1f..af93e0e72553f 100644
--- a/third_party/move/move-model/src/exp_rewriter.rs
+++ b/third_party/move/move-model/src/exp_rewriter.rs
@@ -4,15 +4,17 @@
 
 use crate::{
     ast::{
-        Condition, Exp, ExpData, MatchArm, MemoryLabel, Operation, Pattern, Spec, SpecBlockTarget,
-        TempIndex, Value,
+        Condition, Exp, ExpData, LambdaCaptureKind, MatchArm, MemoryLabel, Operation, Pattern,
+        Spec, SpecBlockTarget, TempIndex, Value,
     },
     model::{GlobalEnv, Loc, ModuleId, NodeId, SpecVarId},
     symbol::Symbol,
     ty::Type,
+    FunId,
 };
 use codespan_reporting::diagnostic::Severity;
 use itertools::Itertools;
+use move_binary_format::file_format::AbilitySet;
 use std::collections::{BTreeMap, BTreeSet};
 
 /// Rewriter for expressions, allowing to substitute locals by expressions as well as instantiate
@@ -179,6 +181,9 @@ pub trait ExpRewriterFunctions {
     fn rewrite_value(&mut self, id: NodeId, value: &Value) -> Option<Exp> {
         None
     }
+    fn rewrite_move_function(&mut self, id: NodeId, mid: ModuleId, fid: FunId) -> Option<Exp> {
+        None
+    }
     fn rewrite_spec_var(
         &mut self,
         id: NodeId,
@@ -194,7 +199,14 @@ pub trait ExpRewriterFunctions {
     fn rewrite_invoke(&mut self, id: NodeId, target: &Exp, args: &[Exp]) -> Option<Exp> {
         None
     }
-    fn rewrite_lambda(&mut self, id: NodeId, pat: &Pattern, body: &Exp) -> Option<Exp> {
+    fn rewrite_lambda(
+        &mut self,
+        id: NodeId,
+        pat: &Pattern,
+        body: &Exp,
+        capture_kind: LambdaCaptureKind,
+        abilities: AbilitySet,
+    ) -> Option<Exp> {
         None
     }
     // Optionally can rewrite pat and return new value, otherwise is unchanged.
@@ -351,16 +363,18 @@ pub trait ExpRewriterFunctions {
                     exp
                 }
             },
-            Lambda(id, pat, body) => {
+            Lambda(id, pat, body, capture_kind, abilities) => {
                 let (id_changed, new_id) = self.internal_rewrite_id(*id);
                 let (pat_changed, new_pat) = self.internal_rewrite_pattern(pat, true);
                 self.rewrite_enter_scope(new_id, new_pat.vars().iter());
                 let (body_changed, new_body) = self.internal_rewrite_exp(body);
                 self.rewrite_exit_scope(new_id);
-                if let Some(new_exp) = self.rewrite_lambda(new_id, &new_pat, &new_body) {
+                if let Some(new_exp) =
+                    self.rewrite_lambda(new_id, &new_pat, &new_body, *capture_kind, *abilities)
+                {
                     new_exp
                 } else if id_changed || pat_changed || body_changed {
-                    Lambda(new_id, new_pat, new_body).into_exp()
+                    Lambda(new_id, new_pat, new_body, *capture_kind, *abilities).into_exp()
                 } else {
                     exp
                 }
diff --git a/third_party/move/move-model/src/metadata.rs b/third_party/move/move-model/src/metadata.rs
index 0a6bacc5e7330..a26a67ffef4f1 100644
--- a/third_party/move/move-model/src/metadata.rs
+++ b/third_party/move/move-model/src/metadata.rs
@@ -207,6 +207,11 @@ pub enum LanguageVersion {
     V2_2,
 }
 
+impl LanguageVersion {
+    /// Leave this symbolic for now in case of more versions.
+    pub const V2_LAMBDA: Self = Self::V2_2;
+}
+
 impl Default for LanguageVersion {
     fn default() -> Self {
         static MOVE_LANGUAGE_V2: Lazy<bool> = Lazy::new(|| read_bool_env_var("MOVE_LANGUAGE_V2"));
diff --git a/third_party/move/move-model/src/model.rs b/third_party/move/move-model/src/model.rs
index 9428d08ec9617..e7a87dd266c74 100644
--- a/third_party/move/move-model/src/model.rs
+++ b/third_party/move/move-model/src/model.rs
@@ -44,7 +44,7 @@ use codespan_reporting::{
 };
 use itertools::Itertools;
 #[allow(unused_imports)]
-use log::{info, warn};
+use log::{debug, info, warn};
 pub use move_binary_format::file_format::{AbilitySet, Visibility};
 #[allow(deprecated)]
 use move_binary_format::normalized::Type as MType;
@@ -85,6 +85,8 @@ use std::{
     rc::Rc,
 };
 
+static DEBUG_TRACE: bool = true;
+
 // =================================================================================================
 /// # Constants
 
@@ -200,13 +202,21 @@ impl Loc {
             && self.inlined_from_loc == other.inlined_from_loc
             && GlobalEnv::enclosing_span(self.span, other.span)
     }
+
+    /// Returns true if this location is the default one.
+    pub fn is_default(&self) -> bool {
+        *self == Loc::default()
+    }
 }
 
 impl Default for Loc {
     fn default() -> Self {
-        let mut files = Files::new();
-        let dummy_id = files.add(String::new(), String::new());
-        Loc::new(dummy_id, Span::default())
+        static DEFAULT: Lazy<Loc> = Lazy::new(|| {
+            let mut files = Files::new();
+            let dummy_id = files.add(String::new(), String::new());
+            Loc::new(dummy_id, Span::default())
+        });
+        DEFAULT.clone()
     }
 }
 
@@ -884,11 +894,15 @@ impl GlobalEnv {
         });
         if *DUMP_BACKTRACE {
             let bt = Backtrace::capture();
-            if BacktraceStatus::Captured == bt.status() {
+            let msg_out = if BacktraceStatus::Captured == bt.status() {
                 format!("{}\nBacktrace: {:#?}", msg, bt)
             } else {
                 msg.to_owned()
+            };
+            if DEBUG_TRACE {
+                debug!("{}", msg_out);
             }
+            msg_out
         } else {
             msg.to_owned()
         }
@@ -1628,11 +1642,16 @@ impl GlobalEnv {
                 FunId(self.symbol_pool.make(name_str))
             };
 
-            // While releasing any mutation, compute the called functions if needed.
+            // While releasing any mutation, compute the used/called functions if needed.
             let fun_data = &self.module_data[module_id.0 as usize]
                 .function_data
                 .get(&fun_id)
                 .unwrap();
+            let used_funs = if fun_data.used_funs.is_none() {
+                Some(self.get_used_funs_from_bytecode(&module, def_idx))
+            } else {
+                None
+            };
             let called_funs = if fun_data.called_funs.is_none() {
                 Some(self.get_called_funs_from_bytecode(&module, def_idx))
             } else {
@@ -1644,6 +1663,9 @@ impl GlobalEnv {
                 fun_data.def_idx = Some(def_idx);
                 fun_data.handle_idx = Some(handle_idx);
                 mod_data.function_idx_to_id.insert(def_idx, fun_id);
+                if let Some(used_funs) = used_funs {
+                    fun_data.used_funs = Some(used_funs);
+                }
                 if let Some(called_funs) = called_funs {
                     fun_data.called_funs = Some(called_funs);
                 }
@@ -1660,6 +1682,15 @@ impl GlobalEnv {
         mod_data.source_map = Some(source_map);
     }
 
+    fn get_used_funs_from_bytecode(
+        &self,
+        module: &CompiledModule,
+        def_idx: FunctionDefinitionIndex,
+    ) -> BTreeSet<QualifiedId<FunId>> {
+        // TODO(LAMBDA) -- fix when we extend bytecode with function values
+        self.get_called_funs_from_bytecode(module, def_idx)
+    }
+
     fn get_called_funs_from_bytecode(
         &self,
         module: &CompiledModule,
@@ -1865,6 +1896,11 @@ impl GlobalEnv {
         self.get_module(fun.module_id).into_function(fun.id)
     }
 
+    pub fn get_function_opt(&self, fun: QualifiedId<FunId>) -> Option<FunctionEnv<'_>> {
+        self.get_module_opt(fun.module_id)
+            .map(|module| module.into_function(fun.id))
+    }
+
     /// Sets the AST based definition of the function.
     pub fn set_function_def(&mut self, fun: QualifiedId<FunId>, def: Exp) {
         let data = self
@@ -1874,6 +1910,7 @@ impl GlobalEnv {
             .function_data
             .get_mut(&fun.id)
             .unwrap();
+        data.used_funs = Some(def.used_funs());
         data.called_funs = Some(def.called_funs());
         data.def = Some(def);
     }
@@ -1891,6 +1928,7 @@ impl GlobalEnv {
         result_type: Type,
         def: Exp,
     ) {
+        let used_funs = def.used_funs();
         let called_funs = def.called_funs();
         let data = FunctionData {
             name,
@@ -1915,6 +1953,9 @@ impl GlobalEnv {
             called_funs: Some(called_funs),
             calling_funs: RefCell::new(None),
             transitive_closure_of_called_funs: RefCell::new(None),
+            used_funs: Some(used_funs),
+            using_funs: RefCell::new(None),
+            transitive_closure_of_used_funs: RefCell::new(None),
         };
         assert!(self
             .module_data
@@ -2032,6 +2073,15 @@ impl GlobalEnv {
         }
     }
 
+    /// Gets a module by id.
+    pub fn get_module_opt(&self, id: ModuleId) -> Option<ModuleEnv<'_>> {
+        let module_data = self.module_data.get(id.0 as usize);
+        module_data.map(|module_data| ModuleEnv {
+            env: self,
+            data: module_data,
+        })
+    }
+
     pub(crate) fn get_module_data_mut(&mut self, id: ModuleId) -> &mut ModuleData {
         &mut self.module_data[id.0 as usize]
     }
@@ -2354,7 +2404,7 @@ impl GlobalEnv {
 
     // Removes all functions not matching the predicate from
     //   module_data fields function_data and function_idx_to_id
-    //   remaining function_data fields called_funs and calling_funs
+    //   remaining function_data fields used_funs and using_funs
     pub fn filter_functions<F>(&mut self, mut predicate: F)
     where
         F: FnMut(&QualifiedId<FunId>) -> bool,
@@ -2368,11 +2418,11 @@ impl GlobalEnv {
                 .function_idx_to_id
                 .retain(|_, fun_id| predicate(&module_id.qualified(*fun_id)));
             module_data.function_data.values_mut().for_each(|fun_data| {
-                if let Some(called_funs) = fun_data.called_funs.as_mut() {
-                    called_funs.retain(|qfun_id| predicate(qfun_id))
+                if let Some(used_funs) = fun_data.used_funs.as_mut() {
+                    used_funs.retain(|qfun_id| predicate(qfun_id))
                 }
-                if let Some(calling_funs) = &mut *fun_data.calling_funs.borrow_mut() {
-                    calling_funs.retain(|qfun_id| predicate(qfun_id))
+                if let Some(using_funs) = &mut *fun_data.using_funs.borrow_mut() {
+                    using_funs.retain(|qfun_id| predicate(qfun_id))
                 }
             });
         }
@@ -2608,7 +2658,7 @@ impl GlobalEnv {
         if let Some(exp) = fun_def {
             emitln!(writer, " {");
             writer.indent();
-            emitln!(writer, "{}", exp.display_for_fun(fun.clone()));
+            emitln!(writer, "{}", exp.display_for_fun(fun));
             writer.unindent();
             emitln!(writer, "}");
         } else {
@@ -2811,6 +2861,11 @@ impl<'env> ModuleEnv<'env> {
         &self.data.use_decls
     }
 
+    /// Returns the friend declarations of this module.
+    pub fn get_friend_decls(&self) -> &[FriendDecl] {
+        &self.data.friend_decls
+    }
+
     /// Does this module declare `module_id` as a friend?
     pub fn has_friend(&self, module_id: &ModuleId) -> bool {
         self.data.friend_modules.contains(module_id)
@@ -2921,7 +2976,7 @@ impl<'env> ModuleEnv<'env> {
     }
 
     /// Returns the set of modules in the current package,
-    /// whose public(package) functions are called in the current module.
+    /// whose public(package) functions are called or referenced in the current module.
     /// Requires: `self` is a primary target.
     pub fn need_to_be_friended_by(&self) -> BTreeSet<ModuleId> {
         debug_assert!(self.is_primary_target());
@@ -2930,17 +2985,18 @@ impl<'env> ModuleEnv<'env> {
             return deps;
         }
         for fun_env in self.get_functions() {
-            let called_funs = fun_env.get_called_functions().expect("called functions");
-            for fun in called_funs {
-                let mod_id = fun.module_id;
-                if self.get_id() == mod_id {
+            for used_fun in fun_env.get_used_functions().expect("used functions") {
+                let used_mod_id = used_fun.module_id;
+                if self.get_id() == used_mod_id {
                     // no need to friend self
                     continue;
                 }
-                let mod_env = self.env.get_module(mod_id);
-                let fun_env = mod_env.get_function(fun.id);
-                if fun_env.has_package_visibility() && self.can_call_package_fun_in(&mod_env) {
-                    deps.insert(mod_id);
+                let used_mod_env = self.env.get_module(used_mod_id);
+                let used_fun_env = used_mod_env.get_function(used_fun.id);
+                if used_fun_env.has_package_visibility()
+                    && self.can_call_package_fun_in(&used_mod_env)
+                {
+                    deps.insert(used_mod_id);
                 }
             }
         }
@@ -3309,7 +3365,7 @@ impl<'env> ModuleEnv<'env> {
         self.data.module_spec.borrow()
     }
 
-    /// Returns whether a spec fun is ever called or not.
+    /// Returns whether a spec fun is ever called/referenced or not.
     pub fn spec_fun_is_used(&self, spec_fun_id: SpecFunId) -> bool {
         self.env
             .used_spec_funs
@@ -4056,6 +4112,20 @@ impl Default for TypeParameterKind {
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct Parameter(pub Symbol, pub Type, pub Loc);
 
+impl Parameter {
+    pub fn get_name(&self) -> Symbol {
+        self.0
+    }
+
+    pub fn get_type(&self) -> Type {
+        self.1.clone()
+    }
+
+    pub fn get_loc(&self) -> Loc {
+        self.2.clone()
+    }
+}
+
 impl EqIgnoringLoc for Parameter {
     /// equal ignoring Loc
     fn eq_ignoring_loc(&self, other: &Self) -> bool {
@@ -4147,6 +4217,15 @@ pub struct FunctionData {
 
     /// A cache for the transitive closure of the called functions.
     pub(crate) transitive_closure_of_called_funs: RefCell<Option<BTreeSet<QualifiedId<FunId>>>>,
+
+    /// A cache for the used functions.  Used functions are those called or with values taken here.
+    pub(crate) used_funs: Option<BTreeSet<QualifiedId<FunId>>>,
+
+    /// A cache for the using functions.  Using functions are those which call or take value of this.
+    pub(crate) using_funs: RefCell<Option<BTreeSet<QualifiedId<FunId>>>>,
+
+    /// A cache for the transitive closure of the used functions.
+    pub(crate) transitive_closure_of_used_funs: RefCell<Option<BTreeSet<QualifiedId<FunId>>>>,
 }
 
 impl FunctionData {
@@ -4170,6 +4249,9 @@ impl FunctionData {
             called_funs: None,
             calling_funs: RefCell::new(None),
             transitive_closure_of_called_funs: RefCell::new(None),
+            used_funs: None,
+            using_funs: RefCell::new(None),
+            transitive_closure_of_used_funs: RefCell::new(None),
         }
     }
 }
@@ -4790,6 +4872,58 @@ impl<'env> FunctionEnv<'env> {
         !matches!(scope, VerificationScope::Only(..)) && self.is_pragma_false(VERIFY_PRAGMA)
     }
 
+    /// Get the functions that use this one, if available.
+    pub fn get_using_functions(&self) -> Option<BTreeSet<QualifiedId<FunId>>> {
+        if let Some(using) = &*self.data.using_funs.borrow() {
+            return Some(using.clone());
+        }
+        let mut set: BTreeSet<QualifiedId<FunId>> = BTreeSet::new();
+        for module_env in self.module_env.env.get_modules() {
+            for fun_env in module_env.get_functions() {
+                if fun_env
+                    .get_used_functions()?
+                    .contains(&self.get_qualified_id())
+                {
+                    set.insert(fun_env.get_qualified_id());
+                }
+            }
+        }
+        *self.data.using_funs.borrow_mut() = Some(set.clone());
+        Some(set)
+    }
+
+    /// Get the functions that this one uses, if available.
+    pub fn get_used_functions(&self) -> Option<&'_ BTreeSet<QualifiedId<FunId>>> {
+        self.data.used_funs.as_ref()
+    }
+
+    /// Get the transitive closure of the used functions. This requires that all functions
+    /// in the closure have `get_used_functions` available; if one of them not, this
+    /// function panics.
+    pub fn get_transitive_closure_of_used_functions(&self) -> BTreeSet<QualifiedId<FunId>> {
+        if let Some(trans_used) = &*self.data.transitive_closure_of_used_funs.borrow() {
+            return trans_used.clone();
+        }
+
+        let mut set = BTreeSet::new();
+        let mut reachable_funcs = VecDeque::new();
+        reachable_funcs.push_back(self.clone());
+
+        // BFS in reachable_funcs to collect all reachable functions
+        while !reachable_funcs.is_empty() {
+            let fnc = reachable_funcs.pop_front().unwrap();
+            for callee in fnc.get_used_functions().expect("call info available") {
+                let f = self.module_env.env.get_function(*callee);
+                let qualified_id = f.get_qualified_id();
+                if set.insert(qualified_id) {
+                    reachable_funcs.push_back(f.clone());
+                }
+            }
+        }
+        *self.data.transitive_closure_of_used_funs.borrow_mut() = Some(set.clone());
+        set
+    }
+
     /// Get the functions that call this one, if available.
     pub fn get_calling_functions(&self) -> Option<BTreeSet<QualifiedId<FunId>>> {
         if let Some(calling) = &*self.data.calling_funs.borrow() {
@@ -5035,6 +5169,20 @@ impl GetNameString for QualifiedId<SpecFunId> {
     }
 }
 
+impl<'a, T> fmt::Display for EnvDisplay<'a, Vec<T>>
+where
+    EnvDisplay<'a, T>: std::fmt::Display,
+{
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        let xs = self
+            .val
+            .iter()
+            .map(|x| format!("{}", self.env.display(x)))
+            .collect_vec();
+        write!(f, "({})", xs.iter().join(","))
+    }
+}
+
 impl<'a, Id: Clone> fmt::Display for EnvDisplay<'a, QualifiedId<Id>>
 where
     QualifiedId<Id>: GetNameString,
@@ -5069,3 +5217,15 @@ impl<'a> fmt::Display for EnvDisplay<'a, Symbol> {
         write!(f, "{}", self.val.display(self.env.symbol_pool()))
     }
 }
+
+impl<'a> fmt::Display for EnvDisplay<'a, Parameter> {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        let p = self.val;
+        write!(
+            f,
+            "{}:{}",
+            p.get_name().display(self.env.symbol_pool()),
+            p.get_type().display(&self.env.get_type_display_ctx())
+        )
+    }
+}
diff --git a/third_party/move/move-model/src/sourcifier.rs b/third_party/move/move-model/src/sourcifier.rs
index d185f1dd2db4e..fb5e2754c9d7c 100644
--- a/third_party/move/move-model/src/sourcifier.rs
+++ b/third_party/move/move-model/src/sourcifier.rs
@@ -4,7 +4,8 @@
 
 use crate::{
     ast::{
-        AddressSpecifier, Exp, ExpData, Operation, Pattern, ResourceSpecifier, TempIndex, Value,
+        self, AddressSpecifier, Exp, ExpData, LambdaCaptureKind, Operation, Pattern,
+        ResourceSpecifier, TempIndex, Value,
     },
     code_writer::CodeWriter,
     emit, emitln,
@@ -284,6 +285,15 @@ impl<'a> Sourcifier<'a> {
                     emit!(self.writer, "{}", self.env().display(address))
                 })
             },
+            Value::Function(mid, fid) => {
+                emit!(
+                    self.writer,
+                    "{}",
+                    self.env()
+                        .get_function(mid.qualified(*fid))
+                        .get_full_name_str()
+                );
+            },
         }
     }
 
@@ -525,9 +535,22 @@ impl<'a> ExpSourcifier<'a> {
         match exp.as_ref() {
             // Following forms are all atomic and do not require parenthesis
             Invalid(_) => emit!(self.wr(), "*invalid*"),
-            Value(_, v) => {
+            Value(id, v) => {
                 let ty = self.env().get_node_type(exp.node_id());
-                self.parent.print_value(v, Some(&ty))
+                self.parent.print_value(v, Some(&ty));
+                if let ast::Value::Function(..) = v {
+                    let type_inst = self.env().get_node_instantiation(*id);
+                    if !type_inst.is_empty() {
+                        emit!(
+                            self.wr(),
+                            "<{}>",
+                            type_inst
+                                .iter()
+                                .map(|ty| ty.display(&self.type_display_context))
+                                .join(", ")
+                        );
+                    }
+                }
             },
             LocalVar(_, name) => {
                 emit!(self.wr(), "{}", self.sym(*name))
@@ -540,12 +563,19 @@ impl<'a> ExpSourcifier<'a> {
                 }
             },
             // Following forms may require parenthesis
-            Lambda(_, pat, body) => {
+            Lambda(_, pat, body, capture_kind, abilities) => {
                 self.parenthesize(context_prio, Prio::General, || {
+                    if *capture_kind != LambdaCaptureKind::Default {
+                        emit!(self.wr(), "{} ", capture_kind);
+                    };
                     emit!(self.wr(), "|");
                     self.print_pat(pat);
                     emit!(self.wr(), "| ");
-                    self.print_exp(Prio::General, true, body)
+                    self.print_exp(Prio::General, true, body);
+                    if !abilities.is_subset(AbilitySet::FUNCTIONS) {
+                        let abilities_as_str = abilities.iter().map(|a| a.to_string()).join("+");
+                        emit!(self.wr(), " with {}", abilities_as_str);
+                    }
                 });
             },
             Block(..) | Sequence(..) => {
@@ -793,6 +823,11 @@ impl<'a> ExpSourcifier<'a> {
                     self.print_exp_list("(", ")", args)
                 })
             },
+            Operation::EarlyBind => self.parenthesize(context_prio, Prio::Postfix, || {
+                emit!(self.wr(), "earlybind");
+                self.print_node_inst(id);
+                self.print_exp_list("(", ")", args)
+            }),
             Operation::Pack(mid, sid, variant) => {
                 self.parenthesize(context_prio, Prio::Postfix, || {
                     let qid = mid.qualified_inst(*sid, self.env().get_node_instantiation(id));
@@ -962,7 +997,6 @@ impl<'a> ExpSourcifier<'a> {
             | Operation::EventStoreIncludes
             | Operation::EventStoreIncludedIn
             | Operation::SpecFunction(_, _, _)
-            | Operation::Closure(_, _)
             | Operation::UpdateField(_, _, _)
             | Operation::Result(_)
             | Operation::Index
@@ -1024,7 +1058,11 @@ impl<'a> ExpSourcifier<'a> {
         self.parenthesize(context_prio, prio, || {
             self.print_exp(prio, false, &args[0]);
             emit!(self.wr(), " {} ", repr);
-            self.print_exp(prio + 1, false, &args[1])
+            if args.len() > 1 {
+                self.print_exp(prio + 1, false, &args[1])
+            } else {
+                emit!(self.wr(), "ERROR")
+            }
         })
     }
 
diff --git a/third_party/move/move-model/src/ty.rs b/third_party/move/move-model/src/ty.rs
index 6e947c60d7442..485bd3c273a96 100644
--- a/third_party/move/move-model/src/ty.rs
+++ b/third_party/move/move-model/src/ty.rs
@@ -44,7 +44,11 @@ pub enum Type {
     Vector(Box<Type>),
     Struct(ModuleId, StructId, /*type-params*/ Vec<Type>),
     TypeParameter(u16),
-    Fun(/*args*/ Box<Type>, /*result*/ Box<Type>),
+    Fun(
+        /* known args */ Box<Type>,
+        /*result*/ Box<Type>,
+        AbilitySet,
+    ),
 
     // Types only appearing in programs.
     Reference(ReferenceKind, Box<Type>),
@@ -968,7 +972,7 @@ impl Type {
         use Type::*;
         match self {
             Primitive(p) => p.is_spec(),
-            Fun(args, result) => args.is_spec() || result.is_spec(),
+            Fun(args, result, _) => args.is_spec() || result.is_spec(),
             TypeDomain(..) | ResourceDomain(..) | Error => true,
             Var(..) | TypeParameter(..) => false,
             Tuple(ts) => ts.iter().any(|t| t.is_spec()),
@@ -1195,9 +1199,10 @@ impl Type {
                 Type::Reference(*kind, Box::new(bt.replace(params, subs, use_constr)))
             },
             Type::Struct(mid, sid, args) => Type::Struct(*mid, *sid, replace_vec(args)),
-            Type::Fun(arg, result) => Type::Fun(
+            Type::Fun(arg, result, abilities) => Type::Fun(
                 Box::new(arg.replace(params, subs, use_constr)),
                 Box::new(result.replace(params, subs, use_constr)),
+                *abilities,
             ),
             Type::Tuple(args) => Type::Tuple(replace_vec(args)),
             Type::Vector(et) => Type::Vector(Box::new(et.replace(params, subs, use_constr))),
@@ -1223,7 +1228,7 @@ impl Type {
             match self {
                 Type::Reference(_, bt) => bt.contains(p),
                 Type::Struct(_, _, args) => contains_vec(args),
-                Type::Fun(arg, result) => arg.contains(p) || result.contains(p),
+                Type::Fun(arg, result, _) => arg.contains(p) || result.contains(p),
                 Type::Tuple(args) => contains_vec(args),
                 Type::Vector(et) => et.contains(p),
                 _ => false,
@@ -1237,7 +1242,7 @@ impl Type {
         match self {
             Var(_) => true,
             Tuple(ts) => ts.iter().any(|t| t.is_incomplete()),
-            Fun(a, r) => a.is_incomplete() || r.is_incomplete(),
+            Fun(a, r, _) => a.is_incomplete() || r.is_incomplete(),
             Struct(_, _, ts) => ts.iter().any(|t| t.is_incomplete()),
             Vector(et) => et.is_incomplete(),
             Reference(_, bt) => bt.is_incomplete(),
@@ -1258,7 +1263,7 @@ impl Type {
         use Type::*;
         match self {
             Tuple(ts) => ts.iter().for_each(|t| t.module_usage(usage)),
-            Fun(a, r) => {
+            Fun(a, r, _) => {
                 a.module_usage(usage);
                 r.module_usage(usage);
             },
@@ -1424,7 +1429,7 @@ impl Type {
                 vars.insert(*id);
             },
             Tuple(ts) => ts.iter().for_each(|t| t.internal_get_vars(vars)),
-            Fun(a, r) => {
+            Fun(a, r, _) => {
                 a.internal_get_vars(vars);
                 r.internal_get_vars(vars);
             },
@@ -1447,7 +1452,7 @@ impl Type {
             Type::Vector(bt) => bt.visit(visitor),
             Type::Struct(_, _, tys) => visit_slice(tys, visitor),
             Type::Reference(_, ty) => ty.visit(visitor),
-            Type::Fun(a, ty) => {
+            Type::Fun(a, ty, _) => {
                 a.visit(visitor);
                 ty.visit(visitor);
             },
@@ -2050,7 +2055,10 @@ impl Substitution {
                     Ok(())
                 }
             },
-            Fun(_, _) => check(AbilitySet::FUNCTIONS),
+            Fun(_, _, abilities) => {
+                assert!(AbilitySet::FUNCTIONS.is_subset(*abilities));
+                check(*abilities)
+            },
             Reference(_, _) => check(AbilitySet::REFERENCES),
             TypeDomain(_) | ResourceDomain(_, _, _) => check(AbilitySet::EMPTY),
             Error => Ok(()),
@@ -2312,13 +2320,15 @@ impl Substitution {
                     .map_err(TypeUnificationError::lift(order, t1, t2))?,
                 ));
             },
-            (Type::Fun(a1, r1), Type::Fun(a2, r2)) => {
+            (Type::Fun(a1, r1, abilities1), Type::Fun(a2, r2, abilities2)) => {
                 // Same as for tuples, we pass on `variance` not `sub_variance`, allowing
                 // conversion for arguments. We also have contra-variance of arguments:
                 //   |T1|R1 <= |T2|R2  <==>  T1 >= T2 && R1 <= R2
                 // Intuitively, function f1 can safely _substitute_ function f2 if any argument
                 // of type T2 can be passed as a T1 -- which is the case since T1 >= T2 (every
                 // T2 is also a T1).
+                //
+                // We test for abilities match last, to give more intuitive error messages.
                 return Ok(Type::Fun(
                     Box::new(
                         self.unify(context, variance, order.swap(), a1, a2)
@@ -2328,6 +2338,25 @@ impl Substitution {
                         self.unify(context, variance, order, r1, r2)
                             .map_err(TypeUnificationError::lift(order, t1, t2))?,
                     ),
+                    {
+                        // Widening/conversion can remove abilities, not add them.  So check that
+                        // the target has no more abilities than the source.
+                        let (missing_abilities, bad_ty) = match order {
+                            WideningOrder::LeftToRight => (abilities2.setminus(*abilities1), t1),
+                            WideningOrder::RightToLeft => (abilities1.setminus(*abilities2), t2),
+                            WideningOrder::Join => (AbilitySet::EMPTY, t1),
+                        };
+                        if missing_abilities.is_empty() {
+                            abilities1.intersect(*abilities2)
+                        } else {
+                            return Err(TypeUnificationError::MissingAbilities(
+                                Loc::default(),
+                                bad_ty.clone(),
+                                missing_abilities,
+                                None,
+                            ));
+                        }
+                    },
                 ));
             },
             (Type::Struct(m1, s1, ts1), Type::Struct(m2, s2, ts2)) => {
@@ -2980,6 +3009,7 @@ impl TypeUnificationError {
             | TypeUnificationError::MissingAbilities(loc, ..) => Some(loc.clone()),
             _ => None,
         }
+        .and_then(|loc| if loc.is_default() { None } else { Some(loc) })
     }
 
     /// Return the message for this error.
@@ -3584,12 +3614,22 @@ impl<'a> fmt::Display for TypeDisplay<'a> {
                 }
                 f.write_str(">")
             },
-            Fun(a, t) => {
+            Fun(a, t, abilities) => {
                 f.write_str("|")?;
                 write!(f, "{}", a.display(self.context))?;
                 f.write_str("|")?;
                 if !t.is_unit() {
-                    write!(f, "{}", t.display(self.context))
+                    write!(f, "{}", t.display(self.context))?;
+                }
+                if !abilities.is_subset(AbilitySet::FUNCTIONS) {
+                    // Default formatter for Abilities is not compact, manually convert here.
+                    let abilities_as_str = abilities
+                        .setminus(AbilitySet::FUNCTIONS)
+                        .iter()
+                        .map(|a| a.to_string())
+                        .reduce(|l, r| format!("{}+{}", l, r))
+                        .unwrap_or_default();
+                    write!(f, " with {}", abilities_as_str)
                 } else {
                     Ok(())
                 }
@@ -3731,7 +3771,7 @@ pub trait AbilityInference: AbilityContext {
     /// Infers the abilities of the type. The returned boolean indicates whether
     /// the type is a phantom type parameter,
     fn infer_abilities(&self, ty: &Type) -> (bool, AbilitySet) {
-        match ty {
+        let res = match ty {
             Type::Primitive(p) => match p {
                 PrimitiveType::Bool
                 | PrimitiveType::U8
@@ -3767,10 +3807,12 @@ pub trait AbilityInference: AbilityContext {
                     .reduce(|a, b| a.intersect(b))
                     .unwrap_or(AbilitySet::PRIMITIVES),
             ),
-            Type::Fun(_, _) | Type::TypeDomain(_) | Type::ResourceDomain(_, _, _) | Type::Error => {
+            Type::Fun(_, _, abilities) => (false, *abilities),
+            Type::TypeDomain(_) | Type::ResourceDomain(_, _, _) | Type::Error => {
                 (false, AbilitySet::EMPTY)
             },
-        }
+        };
+        res
     }
 
     fn infer_struct_abilities(&self, qid: QualifiedId<StructId>, ty_args: &[Type]) -> AbilitySet {
diff --git a/third_party/move/move-model/tests/sources/expressions_err.exp b/third_party/move/move-model/tests/sources/expressions_err.exp
index e9ce7d95a641f..7de3fb7c474b4 100644
--- a/third_party/move/move-model/tests/sources/expressions_err.exp
+++ b/third_party/move/move-model/tests/sources/expressions_err.exp
@@ -34,7 +34,7 @@ error: cannot pass `u256` to a function which expects argument of type `bool`
 37 │     fun wrongly_typed_caller(): num { wrongly_typed_callee(1, 1) }
    │                                                               ^
 
-error: cannot pass `|num|bool` to a function which expects argument of type `|num|num`
+error: cannot pass `|num|bool with copy+store` to a function which expects argument of type `|num|num`
    ┌─ tests/sources/expressions_err.move:41:76
    │
 41 │     fun wrongly_typed_fun_arg_caller(): num { wrongly_typed_fun_arg_callee(|x| false) }
diff --git a/third_party/move/move-model/tests/sources/expressions_err.v2_exp b/third_party/move/move-model/tests/sources/expressions_err.v2_exp
index e9ce7d95a641f..7de3fb7c474b4 100644
--- a/third_party/move/move-model/tests/sources/expressions_err.v2_exp
+++ b/third_party/move/move-model/tests/sources/expressions_err.v2_exp
@@ -34,7 +34,7 @@ error: cannot pass `u256` to a function which expects argument of type `bool`
 37 │     fun wrongly_typed_caller(): num { wrongly_typed_callee(1, 1) }
    │                                                               ^
 
-error: cannot pass `|num|bool` to a function which expects argument of type `|num|num`
+error: cannot pass `|num|bool with copy+store` to a function which expects argument of type `|num|num`
    ┌─ tests/sources/expressions_err.move:41:76
    │
 41 │     fun wrongly_typed_fun_arg_caller(): num { wrongly_typed_fun_arg_callee(|x| false) }
diff --git a/third_party/move/move-prover/boogie-backend/src/boogie_helpers.rs b/third_party/move/move-prover/boogie-backend/src/boogie_helpers.rs
index 0062a401306a7..0b58373ba8267 100644
--- a/third_party/move/move-prover/boogie-backend/src/boogie_helpers.rs
+++ b/third_party/move/move-prover/boogie-backend/src/boogie_helpers.rs
@@ -592,6 +592,7 @@ pub fn boogie_value(env: &GlobalEnv, _options: &BoogieOptions, val: &Value) -> S
                 .collect_vec(),
         ),
         Value::Tuple(vec) => format!("<<unsupported Tuple({:?})>>", vec),
+        Value::Function(mid, fid) => format!("<unsupported Function({:?}, {:?}>", mid, fid), // TODO(LAMBDA)
     }
 }
 
diff --git a/third_party/move/move-prover/boogie-backend/src/boogie_wrapper.rs b/third_party/move/move-prover/boogie-backend/src/boogie_wrapper.rs
index c2a45a85651b1..bf8d80391edb4 100644
--- a/third_party/move/move-prover/boogie-backend/src/boogie_wrapper.rs
+++ b/third_party/move/move-prover/boogie-backend/src/boogie_wrapper.rs
@@ -1436,7 +1436,7 @@ impl ModelValue {
             },
             Type::Tuple(_)
             | Type::Primitive(_)
-            | Type::Fun(_, _)
+            | Type::Fun(..)
             | Type::TypeDomain(_)
             | Type::ResourceDomain(_, _, _)
             | Type::Error
diff --git a/third_party/move/move-prover/boogie-backend/src/bytecode_translator.rs b/third_party/move/move-prover/boogie-backend/src/bytecode_translator.rs
index c6f7d71839415..350e912f8f284 100644
--- a/third_party/move/move-prover/boogie-backend/src/bytecode_translator.rs
+++ b/third_party/move/move-prover/boogie-backend/src/bytecode_translator.rs
@@ -2071,7 +2071,7 @@ impl<'env> FunctionTranslator<'env> {
                             | Type::Struct(_, _, _)
                             | Type::TypeParameter(_)
                             | Type::Reference(_, _)
-                            | Type::Fun(_, _)
+                            | Type::Fun(..)
                             | Type::TypeDomain(_)
                             | Type::ResourceDomain(_, _, _)
                             | Type::Error
@@ -2108,7 +2108,7 @@ impl<'env> FunctionTranslator<'env> {
                                 | Type::Struct(_, _, _)
                                 | Type::TypeParameter(_)
                                 | Type::Reference(_, _)
-                                | Type::Fun(_, _)
+                                | Type::Fun(..)
                                 | Type::TypeDomain(_)
                                 | Type::ResourceDomain(_, _, _)
                                 | Type::Error
@@ -2165,7 +2165,7 @@ impl<'env> FunctionTranslator<'env> {
                             | Type::Struct(_, _, _)
                             | Type::TypeParameter(_)
                             | Type::Reference(_, _)
-                            | Type::Fun(_, _)
+                            | Type::Fun(..)
                             | Type::TypeDomain(_)
                             | Type::ResourceDomain(_, _, _)
                             | Type::Error
@@ -2202,7 +2202,7 @@ impl<'env> FunctionTranslator<'env> {
                                 | Type::Struct(_, _, _)
                                 | Type::TypeParameter(_)
                                 | Type::Reference(_, _)
-                                | Type::Fun(_, _)
+                                | Type::Fun(..)
                                 | Type::TypeDomain(_)
                                 | Type::ResourceDomain(_, _, _)
                                 | Type::Error
@@ -2242,7 +2242,7 @@ impl<'env> FunctionTranslator<'env> {
                                 | Type::Struct(_, _, _)
                                 | Type::TypeParameter(_)
                                 | Type::Reference(_, _)
-                                | Type::Fun(_, _)
+                                | Type::Fun(..)
                                 | Type::TypeDomain(_)
                                 | Type::ResourceDomain(_, _, _)
                                 | Type::Error
@@ -2283,7 +2283,7 @@ impl<'env> FunctionTranslator<'env> {
                                 | Type::Struct(_, _, _)
                                 | Type::TypeParameter(_)
                                 | Type::Reference(_, _)
-                                | Type::Fun(_, _)
+                                | Type::Fun(..)
                                 | Type::TypeDomain(_)
                                 | Type::ResourceDomain(_, _, _)
                                 | Type::Error
@@ -2314,7 +2314,7 @@ impl<'env> FunctionTranslator<'env> {
                                 | Type::Struct(_, _, _)
                                 | Type::TypeParameter(_)
                                 | Type::Reference(_, _)
-                                | Type::Fun(_, _)
+                                | Type::Fun(..)
                                 | Type::TypeDomain(_)
                                 | Type::ResourceDomain(_, _, _)
                                 | Type::Error
@@ -2354,7 +2354,7 @@ impl<'env> FunctionTranslator<'env> {
                                     | Type::Struct(_, _, _)
                                     | Type::TypeParameter(_)
                                     | Type::Reference(_, _)
-                                    | Type::Fun(_, _)
+                                    | Type::Fun(..)
                                     | Type::TypeDomain(_)
                                     | Type::ResourceDomain(_, _, _)
                                     | Type::Error
@@ -2448,7 +2448,7 @@ impl<'env> FunctionTranslator<'env> {
                                     | Type::Struct(_, _, _)
                                     | Type::TypeParameter(_)
                                     | Type::Reference(_, _)
-                                    | Type::Fun(_, _)
+                                    | Type::Fun(..)
                                     | Type::TypeDomain(_)
                                     | Type::ResourceDomain(_, _, _)
                                     | Type::Error
@@ -3017,7 +3017,7 @@ pub fn has_native_equality(env: &GlobalEnv, options: &BoogieOptions, ty: &Type)
         | Type::Tuple(_)
         | Type::TypeParameter(_)
         | Type::Reference(_, _)
-        | Type::Fun(_, _)
+        | Type::Fun(..)
         | Type::TypeDomain(_)
         | Type::ResourceDomain(_, _, _)
         | Type::Error
diff --git a/third_party/move/move-prover/boogie-backend/src/spec_translator.rs b/third_party/move/move-prover/boogie-backend/src/spec_translator.rs
index 43e54ef7ceff7..b674d30b855b9 100644
--- a/third_party/move/move-prover/boogie-backend/src/spec_translator.rs
+++ b/third_party/move/move-prover/boogie-backend/src/spec_translator.rs
@@ -528,7 +528,7 @@ impl<'env> SpecTranslator<'env> {
                 | Type::Struct(_, _, _)
                 | Type::TypeParameter(_)
                 | Type::Reference(_, _)
-                | Type::Fun(_, _)
+                | Type::Fun(..)
                 | Type::TypeDomain(_)
                 | Type::ResourceDomain(_, _, _)
                 | Type::Error
@@ -774,6 +774,10 @@ impl<'env> SpecTranslator<'env> {
                 let loc = self.env.get_node_loc(node_id);
                 self.error(&loc, &format!("tuple value not yet supported: {:#?}", val))
             },
+            Value::Function(_mid, _fid) => {
+                let loc = self.env.get_node_loc(node_id);
+                self.error(&loc, "Function values not yet supported") // TODO(LAMBDA)
+            },
         }
     }
 
@@ -836,7 +840,6 @@ impl<'env> SpecTranslator<'env> {
             .get_extension::<GlobalNumberOperationState>()
             .expect("global number operation state");
         match oper {
-            Operation::Closure(..) => unimplemented!("closures in specs"),
             // Operators we introduced in the top level public entry `SpecTranslator::translate`,
             // mapping between Boogies single value domain and our typed world.
             Operation::BoxValue | Operation::UnboxValue => panic!("unexpected box/unbox"),
@@ -1012,6 +1015,7 @@ impl<'env> SpecTranslator<'env> {
             | Operation::Deref
             | Operation::MoveTo
             | Operation::MoveFrom
+            | Operation::EarlyBind
             | Operation::Old => {
                 self.env.error(
                     &self.env.get_node_loc(node_id),
@@ -1464,7 +1468,7 @@ impl<'env> SpecTranslator<'env> {
                 | Type::Tuple(_)
                 | Type::TypeParameter(_)
                 | Type::Reference(_, _)
-                | Type::Fun(_, _)
+                | Type::Fun(..)
                 | Type::TypeDomain(_)
                 | Type::ResourceDomain(_, _, _)
                 | Type::Error
@@ -1627,7 +1631,7 @@ impl<'env> SpecTranslator<'env> {
                 | Type::Tuple(_)
                 | Type::TypeParameter(_)
                 | Type::Reference(_, _)
-                | Type::Fun(_, _)
+                | Type::Fun(..)
                 | Type::Error
                 | Type::Var(_) => panic!("unexpected type"),
             }
diff --git a/third_party/move/move-prover/bytecode-pipeline/src/memory_instrumentation.rs b/third_party/move/move-prover/bytecode-pipeline/src/memory_instrumentation.rs
index 0839554ad8db5..5b94625163859 100644
--- a/third_party/move/move-prover/bytecode-pipeline/src/memory_instrumentation.rs
+++ b/third_party/move/move-prover/bytecode-pipeline/src/memory_instrumentation.rs
@@ -99,7 +99,7 @@ impl<'a> Instrumenter<'a> {
             | Tuple(_)
             | TypeParameter(_)
             | Reference(_, _)
-            | Fun(_, _)
+            | Fun(..)
             | TypeDomain(_)
             | ResourceDomain(_, _, _)
             | Error
diff --git a/third_party/move/move-prover/move-abigen/src/abigen.rs b/third_party/move/move-prover/move-abigen/src/abigen.rs
index bcc86cd7ae149..c4af6d2ae4e4a 100644
--- a/third_party/move/move-prover/move-abigen/src/abigen.rs
+++ b/third_party/move/move-prover/move-abigen/src/abigen.rs
@@ -324,7 +324,7 @@ impl<'env> Abigen<'env> {
             },
             Tuple(_)
             | TypeParameter(_)
-            | Fun(_, _)
+            | Fun(..)
             | TypeDomain(_)
             | ResourceDomain(..)
             | Error
diff --git a/third_party/move/move-prover/move-docgen/src/docgen.rs b/third_party/move/move-prover/move-docgen/src/docgen.rs
index 88aa960f6a468..c0941a2b946ee 100644
--- a/third_party/move/move-prover/move-docgen/src/docgen.rs
+++ b/third_party/move/move-prover/move-docgen/src/docgen.rs
@@ -925,9 +925,9 @@ impl<'env> Docgen<'env> {
             let curr_env = self.env.get_function(id);
             let curr_name = name_of(&curr_env);
             let next_list = if is_forward {
-                curr_env.get_called_functions().cloned().unwrap_or_default()
+                curr_env.get_used_functions().cloned().unwrap_or_default()
             } else {
-                curr_env.get_calling_functions().unwrap_or_default()
+                curr_env.get_using_functions().unwrap_or_default()
             };
 
             if fun_env.module_env.get_id() == curr_env.module_env.get_id() {