Repository: ergoplatform/sigma-rust (language: rust)

Issue:
"Unbox" Expr and SType variants in favor of boxing variant's struct members
### Motivation
Ergonomics of `Expr` enum variant creation is not good enough (needs boxing). 

### Solution
Instead of boxing a struct in each `Expr` variant box relevant members of IR node struct.


Discussion / hints:

Fix patch:
diff --git a/ergo-lib/src/ast/apply.rs b/ergo-lib/src/ast/apply.rs
index 8a5e6fd5d..65623f9b7 100644
--- a/ergo-lib/src/ast/apply.rs
+++ b/ergo-lib/src/ast/apply.rs
@@ -17,7 +17,7 @@ use super::value::Value;
 
 #[derive(PartialEq, Eq, Debug, Clone)]
 pub struct Apply {
-    func: Expr,
+    func: Box<Expr>,
     args: Vec<Expr>,
 }
 
@@ -41,13 +41,16 @@ impl Apply {
                 func.tpe(),
             ))),
         }?;
-        Ok(Apply { func, args })
+        Ok(Apply {
+            func: Box::new(func),
+            args,
+        })
     }
 
     pub fn tpe(&self) -> SType {
         match self.func.tpe() {
             SType::SColl(_) => todo!(),
-            SType::SFunc(f) => f.t_range,
+            SType::SFunc(f) => *f.t_range,
             _ => panic!("unexpected Apply::func: {0:?}", self.func.tpe()),
         }
     }
@@ -117,17 +120,19 @@ mod tests {
         fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
             (any::<Expr>(), vec(any::<Expr>(), 1..10))
                 .prop_map(|(body, args)| {
-                    let func = Box::new(FuncValue::new(
-                        args.iter()
-                            .enumerate()
-                            .map(|(idx, arg)| FuncArg {
-                                idx: (idx as u32).into(),
-                                tpe: arg.tpe(),
-                            })
-                            .collect(),
-                        body,
-                    ))
-                    .into();
+                    let func = Box::new(
+                        FuncValue::new(
+                            args.iter()
+                                .enumerate()
+                                .map(|(idx, arg)| FuncArg {
+                                    idx: (idx as u32).into(),
+                                    tpe: arg.tpe(),
+                                })
+                                .collect(),
+                            body,
+                        )
+                        .into(),
+                    );
                     Self { func, args }
                 })
                 .boxed()
@@ -144,35 +149,44 @@ mod tests {
 
     #[test]
     fn eval_user_defined_func_call() {
-        let arg = Expr::Const(Box::new(1i32.into()));
-        let bin_op = Expr::BinOp(Box::new(BinOp {
+        let arg = Expr::Const(1i32.into());
+        let bin_op = Expr::BinOp(BinOp {
             kind: LogicOp::Eq.into(),
-            left: Expr::ValUse(Box::new(ValUse {
-                val_id: 1.into(),
-                tpe: SType::SInt,
-            })),
-            right: Expr::ValUse(Box::new(ValUse {
-                val_id: 2.into(),
-                tpe: SType::SInt,
-            })),
-        }));
-        let body = Expr::BlockValue(Box::new(BlockValue {
+            left: Box::new(
+                ValUse {
+                    val_id: 1.into(),
+                    tpe: SType::SInt,
+                }
+                .into(),
+            ),
+            right: Box::new(
+                ValUse {
+                    val_id: 2.into(),
+                    tpe: SType::SInt,
+                }
+                .into(),
+            ),
+        });
+        let body = Expr::BlockValue(BlockValue {
             items: vec![ValDef {
                 id: 2.into(),
-                rhs: Expr::Const(Box::new(1i32.into())),
+                rhs: Box::new(Expr::Const(1i32.into())),
             }],
-            result: bin_op,
-        }));
-        let apply: Expr = Box::new(Apply {
-            func: Expr::FuncValue(Box::new(FuncValue::new(
-                vec![FuncArg {
-                    idx: 1.into(),
-                    tpe: SType::SInt,
-                }],
-                body,
-            ))),
+            result: Box::new(bin_op),
+        });
+        let apply: Expr = Apply {
+            func: Box::new(
+                FuncValue::new(
+                    vec![FuncArg {
+                        idx: 1.into(),
+                        tpe: SType::SInt,
+                    }],
+                    body,
+                )
+                .into(),
+            ),
             args: vec![arg],
-        })
+        }
         .into();
         let ctx = Rc::new(force_any_val::<Context>());
         assert!(eval_out::<bool>(&apply, ctx));
diff --git a/ergo-lib/src/ast/bin_op.rs b/ergo-lib/src/ast/bin_op.rs
index ad32b7a61..bfb954cc5 100644
--- a/ergo-lib/src/ast/bin_op.rs
+++ b/ergo-lib/src/ast/bin_op.rs
@@ -73,8 +73,8 @@ impl From<BinOpKind> for OpCode {
 #[derive(PartialEq, Eq, Debug, Clone)]
 pub struct BinOp {
     pub kind: BinOpKind,
-    pub left: Expr,
-    pub right: Expr,
+    pub left: Box<Expr>,
+    pub right: Box<Expr>,
 }
 
 impl BinOp {
@@ -147,7 +147,11 @@ pub mod tests {
                         depth: args.depth,
                     }),
                 )
-                    .prop_map(|(kind, left, right)| BinOp { kind, left, right }),
+                    .prop_map(|(kind, left, right)| BinOp {
+                        kind,
+                        left: Box::new(left),
+                        right: Box::new(right),
+                    }),
 
                 _ => todo!(),
                 // SType::SByte => {}
@@ -161,18 +165,18 @@ pub mod tests {
     }
 
     fn check_eq_neq(left: Constant, right: Constant) -> bool {
-        let eq_op: Expr = Box::new(BinOp {
+        let eq_op: Expr = BinOp {
             kind: BinOpKind::Logic(LogicOp::Eq),
-            left: Box::new(left.clone()).into(),
-            right: Box::new(right.clone()).into(),
-        })
+            left: Box::new(left.clone().into()),
+            right: Box::new(right.clone().into()),
+        }
         .into();
         let ctx = Rc::new(force_any_val::<Context>());
-        let neq_op: Expr = Box::new(BinOp {
+        let neq_op: Expr = BinOp {
             kind: BinOpKind::Logic(LogicOp::NEq),
-            left: Box::new(left).into(),
-            right: Box::new(right).into(),
-        })
+            left: Box::new(left.into()),
+            right: Box::new(right.into()),
+        }
         .into();
         let ctx1 = Rc::new(force_any_val::<Context>());
         eval_out::<bool>(&eq_op, ctx) && !eval_out::<bool>(&neq_op, ctx1)
diff --git a/ergo-lib/src/ast/block.rs b/ergo-lib/src/ast/block.rs
index 3831b96b5..21244d361 100644
--- a/ergo-lib/src/ast/block.rs
+++ b/ergo-lib/src/ast/block.rs
@@ -25,7 +25,7 @@ use super::value::Value;
 #[derive(PartialEq, Eq, Debug, Clone)]
 pub struct BlockValue {
     pub items: Vec<ValDef>,
-    pub result: Expr,
+    pub result: Box<Expr>,
 }
 
 impl BlockValue {
@@ -58,7 +58,10 @@ impl SigmaSerializable for BlockValue {
     fn sigma_parse<R: SigmaByteRead>(r: &mut R) -> Result<Self, SerializationError> {
         let items = Vec::<ValDef>::sigma_parse(r)?;
         let result = Expr::sigma_parse(r)?;
-        Ok(BlockValue { items, result })
+        Ok(BlockValue {
+            items,
+            result: Box::new(result),
+        })
     }
 }
 
@@ -78,7 +81,10 @@ mod tests {
 
         fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
             (any::<Expr>(), vec(any::<ValDef>(), 0..10))
-                .prop_map(|(result, items)| Self { items, result })
+                .prop_map(|(result, items)| Self {
+                    items,
+                    result: Box::new(result),
+                })
                 .boxed()
         }
     }
@@ -87,7 +93,7 @@ mod tests {
 
         #[test]
         fn ser_roundtrip(block in any::<BlockValue>()) {
-            let e = Expr::BlockValue(block.into());
+            let e = Expr::BlockValue(block);
             prop_assert_eq![sigma_serialize_roundtrip(&e), e];
         }
     }
diff --git a/ergo-lib/src/ast/coll_fold.rs b/ergo-lib/src/ast/coll_fold.rs
index 3b8b8f69f..2999814a1 100644
--- a/ergo-lib/src/ast/coll_fold.rs
+++ b/ergo-lib/src/ast/coll_fold.rs
@@ -20,18 +20,18 @@ use super::value::Value;
 #[derive(PartialEq, Eq, Debug, Clone)]
 pub struct Fold {
     /// Collection
-    input: Expr,
+    input: Box<Expr>,
     /// Initial value for accumulator
-    zero: Expr,
+    zero: Box<Expr>,
     /// Function (lambda)
-    fold_op: Expr,
+    fold_op: Box<Expr>,
 }
 
 impl Fold {
     pub fn new(input: Expr, zero: Expr, fold_op: Expr) -> Result<Self, InvalidArgumentError> {
         let input_elem_type: SType = *match input.tpe() {
             SType::SColl(elem_type) => Ok(elem_type),
-            SType::SFunc(sfunc) => match sfunc.t_range {
+            SType::SFunc(sfunc) => match *sfunc.t_range {
                 SType::SColl(elem_type) => Ok(elem_type),
                 _ => Err(InvalidArgumentError(format!(
                     "Expected Fold input to be SColl, got {0:?}",
@@ -48,9 +48,9 @@ impl Fold {
                 if sfunc.t_dom == vec![STuple::pair(zero.tpe(), input_elem_type).into()] =>
             {
                 Ok(Fold {
-                    input,
-                    zero,
-                    fold_op,
+                    input: input.into(),
+                    zero: zero.into(),
+                    fold_op: fold_op.into(),
                 })
             }
             _ => Err(InvalidArgumentError(format!(
@@ -73,9 +73,9 @@ impl SigmaSerializable for Fold {
     }
 
     fn sigma_parse<R: SigmaByteRead>(r: &mut R) -> Result<Self, SerializationError> {
-        let input = Expr::sigma_parse(r)?;
-        let zero = Expr::sigma_parse(r)?;
-        let fold_op = Expr::sigma_parse(r)?;
+        let input = Expr::sigma_parse(r)?.into();
+        let zero = Expr::sigma_parse(r)?.into();
+        let fold_op = Expr::sigma_parse(r)?.into();
         Ok(Fold {
             input,
             zero,
@@ -152,47 +152,46 @@ mod tests {
 
     #[test]
     fn eval_box_value() {
-        let data_inputs: Expr = Box::new(PropertyCall {
-            obj: Expr::Context,
+        let data_inputs: Expr = PropertyCall {
+            obj: Box::new(Expr::Context),
             method: scontext::DATA_INPUTS_PROPERTY.clone(),
-        })
+        }
         .into();
-        let tuple: Expr = Box::new(ValUse {
+        let tuple: Expr = ValUse {
             val_id: 1.into(),
             tpe: SType::STuple(STuple {
                 items: TupleItems::pair(SType::SLong, SType::SBox),
             }),
-        })
+        }
         .into();
-        let fold_op_body: Expr = Box::new(BinOp {
+        let fold_op_body: Expr = BinOp {
             kind: NumOp::Add.into(),
-            left: Expr::SelectField(
+            left: Box::new(Expr::SelectField(
                 SelectField::new(tuple.clone(), 1.try_into().unwrap()).unwrap(),
-            ),
-            right: Expr::ExtractAmount(
+            )),
+            right: Box::new(Expr::ExtractAmount(
                 ExtractAmount::new(Expr::SelectField(
                     SelectField::new(tuple, 2.try_into().unwrap()).unwrap(),
                 ))
                 .unwrap(),
-            ),
-        })
+            )),
+        }
         .into();
-        let expr: Expr = Box::new(
-            Fold::new(
-                data_inputs,
-                Expr::Const(Box::new(0i64.into())),
-                Expr::FuncValue(Box::new(FuncValue::new(
-                    vec![FuncArg {
-                        idx: 1.into(),
-                        tpe: SType::STuple(STuple {
-                            items: TupleItems::pair(SType::SLong, SType::SBox),
-                        }),
-                    }],
-                    fold_op_body,
-                ))),
+        let expr: Expr = Fold::new(
+            data_inputs,
+            Expr::Const(0i64.into()),
+            FuncValue::new(
+                vec![FuncArg {
+                    idx: 1.into(),
+                    tpe: SType::STuple(STuple {
+                        items: TupleItems::pair(SType::SLong, SType::SBox),
+                    }),
+                }],
+                fold_op_body,
             )
-            .unwrap(),
+            .into(),
         )
+        .unwrap()
         .into();
         let ctx = Rc::new(force_any_val::<Context>());
         assert_eq!(
@@ -210,9 +209,9 @@ mod tests {
         fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
             (any::<Expr>(), any::<Expr>(), any::<Expr>())
                 .prop_map(|(input, zero, fold_op)| Self {
-                    input,
-                    zero,
-                    fold_op,
+                    input: input.into(),
+                    zero: zero.into(),
+                    fold_op: fold_op.into(),
                 })
                 .boxed()
         }
diff --git a/ergo-lib/src/ast/expr.rs b/ergo-lib/src/ast/expr.rs
index 85d7d60f7..d8d037dba 100644
--- a/ergo-lib/src/ast/expr.rs
+++ b/ergo-lib/src/ast/expr.rs
@@ -27,37 +27,37 @@ use derive_more::From;
 /// Expression in ErgoTree
 pub enum Expr {
     /// Constant value
-    Const(Box<Constant>),
+    Const(Constant),
     /// Placeholder for a constant
-    ConstPlaceholder(Box<ConstantPlaceholder>),
+    ConstPlaceholder(ConstantPlaceholder),
     /// Predefined functions (global)
-    PredefFunc(Box<PredefFunc>),
+    PredefFunc(PredefFunc),
     Context,
     // Global(Global),
     /// Predefined global variables
-    GlobalVars(Box<GlobalVars>),
+    GlobalVars(GlobalVars),
     /// Function definition
-    FuncValue(Box<FuncValue>),
+    FuncValue(FuncValue),
     /// Function application
-    Apply(Box<Apply>),
+    Apply(Apply),
     /// Method call
-    MethodCall(Box<MethodCall>),
+    MethodCall(MethodCall),
     /// Property call
-    ProperyCall(Box<PropertyCall>),
+    ProperyCall(PropertyCall),
     /// Block (statements, followed by an expression)
-    BlockValue(Box<BlockValue>),
+    BlockValue(BlockValue),
     /// let-bound expression
-    ValDef(Box<ValDef>),
+    ValDef(ValDef),
     /// Reference to ValDef
-    ValUse(Box<ValUse>),
+    ValUse(ValUse),
     /// Binary operation
-    BinOp(Box<BinOp>),
+    BinOp(BinOp),
     /// Option get method
-    OptionGet(Box<OptionGet>),
+    OptionGet(OptionGet),
     /// Extract register's value (box.RX properties)
-    ExtractRegisterAs(Box<ExtractRegisterAs>),
+    ExtractRegisterAs(ExtractRegisterAs),
     /// Collection fold op
-    Fold(Box<Fold>),
+    Fold(Fold),
     /// Tuple field access
     SelectField(SelectField),
     /// Box monetary value
@@ -143,7 +143,6 @@ pub mod tests {
             tpe: SType::SBoolean,
             depth
         })
-        .prop_map(Box::new)
         .prop_map_into()]
         .boxed()
     }
@@ -162,7 +161,7 @@ pub mod tests {
     }
 
     fn int_non_nested_expr() -> BoxedStrategy<Expr> {
-        prop_oneof![Just(Box::new(GlobalVars::Height).into()),].boxed()
+        prop_oneof![Just(GlobalVars::Height.into()),].boxed()
     }
 
     fn any_non_nested_expr() -> BoxedStrategy<Expr> {
@@ -185,7 +184,6 @@ pub mod tests {
             if args.depth == 0 {
                 prop_oneof![
                     any_with::<Constant>(args.tpe.clone())
-                        .prop_map(Box::new)
                         .prop_map(Expr::Const)
                         .boxed(),
                     non_nested_expr(&args.tpe)
diff --git a/ergo-lib/src/ast/extract_amount.rs b/ergo-lib/src/ast/extract_amount.rs
index 8d6ad673c..354b3ea43 100644
--- a/ergo-lib/src/ast/extract_amount.rs
+++ b/ergo-lib/src/ast/extract_amount.rs
@@ -76,7 +76,7 @@ mod tests {
     #[test]
     fn ser_roundtrip() {
         let e: Expr = ExtractAmount {
-            input: Box::new(Box::new(GlobalVars::SelfBox).into()),
+            input: Box::new(GlobalVars::SelfBox.into()),
         }
         .into();
         assert_eq![sigma_serialize_roundtrip(&e), e];
diff --git a/ergo-lib/src/ast/extract_reg_as.rs b/ergo-lib/src/ast/extract_reg_as.rs
index aa7ea9178..3fefdac6d 100644
--- a/ergo-lib/src/ast/extract_reg_as.rs
+++ b/ergo-lib/src/ast/extract_reg_as.rs
@@ -18,7 +18,7 @@ use super::value::Value;
 #[derive(PartialEq, Eq, Debug, Clone)]
 pub struct ExtractRegisterAs {
     /// Box
-    pub input: Expr,
+    pub input: Box<Expr>,
     /// Register id to extract value from
     pub register_id: RegisterId,
     /// Type
@@ -55,7 +55,7 @@ impl SigmaSerializable for ExtractRegisterAs {
         let register_id = RegisterId::sigma_parse(r)?;
         let tpe = SType::sigma_parse(r)?;
         Ok(ExtractRegisterAs {
-            input,
+            input: Box::new(input),
             register_id,
             tpe,
         })
@@ -77,13 +77,13 @@ mod tests {
 
     #[test]
     fn eval_box_get_reg() {
-        let get_reg_expr: Expr = Box::new(ExtractRegisterAs {
-            input: Box::new(GlobalVars::SelfBox).into(),
+        let get_reg_expr: Expr = ExtractRegisterAs {
+            input: Box::new(GlobalVars::SelfBox.into()),
             register_id: RegisterId::R0,
             tpe: SType::SOption(SType::SLong.into()),
-        })
+        }
         .into();
-        let option_get_expr: Expr = Box::new(OptionGet::new(get_reg_expr).unwrap()).into();
+        let option_get_expr: Expr = OptionGet::new(get_reg_expr).unwrap().into();
         let ctx = Rc::new(force_any_val::<Context>());
         let v = eval_out::<i64>(&option_get_expr, ctx.clone());
         assert_eq!(v, ctx.self_box.value.as_i64());
@@ -91,11 +91,11 @@ mod tests {
 
     #[test]
     fn ser_roundtrip() {
-        let e: Expr = Box::new(ExtractRegisterAs {
-            input: Box::new(GlobalVars::SelfBox).into(),
+        let e: Expr = ExtractRegisterAs {
+            input: Box::new(GlobalVars::SelfBox.into()),
             register_id: RegisterId::R0,
             tpe: SType::SOption(SType::SLong.into()),
-        })
+        }
         .into();
         assert_eq![sigma_serialize_roundtrip(&e), e];
     }
diff --git a/ergo-lib/src/ast/func_value.rs b/ergo-lib/src/ast/func_value.rs
index a466e636f..0af9e69db 100644
--- a/ergo-lib/src/ast/func_value.rs
+++ b/ergo-lib/src/ast/func_value.rs
@@ -42,7 +42,7 @@ impl SigmaSerializable for FuncArg {
 #[derive(PartialEq, Eq, Debug, Clone)]
 pub struct FuncValue {
     args: Vec<FuncArg>,
-    body: Expr,
+    body: Box<Expr>,
     tpe: SType,
 }
 
@@ -50,12 +50,16 @@ impl FuncValue {
     pub fn new(args: Vec<FuncArg>, body: Expr) -> Self {
         let t_dom = args.iter().map(|fa| fa.tpe.clone()).collect();
         let t_range = body.tpe();
-        let tpe = SType::SFunc(Box::new(SFunc {
+        let tpe = SType::SFunc(SFunc {
             t_dom,
-            t_range,
+            t_range: Box::new(t_range),
             tpe_params: vec![],
-        }));
-        FuncValue { args, body, tpe }
+        });
+        FuncValue {
+            args,
+            body: Box::new(body),
+            tpe,
+        }
     }
 
     pub fn args(&self) -> &[FuncArg] {
@@ -121,7 +125,7 @@ mod tests {
 
         #[test]
         fn ser_roundtrip(func_value in any::<FuncValue>()) {
-            let e = Expr::FuncValue(func_value.into());
+            let e = Expr::FuncValue(func_value);
             prop_assert_eq![sigma_serialize_roundtrip(&e), e];
         }
     }
diff --git a/ergo-lib/src/ast/method_call.rs b/ergo-lib/src/ast/method_call.rs
index 4077355fa..03e380a38 100644
--- a/ergo-lib/src/ast/method_call.rs
+++ b/ergo-lib/src/ast/method_call.rs
@@ -6,7 +6,7 @@ use super::expr::Expr;
 
 #[derive(PartialEq, Eq, Debug, Clone)]
 pub struct MethodCall {
-    pub obj: Expr,
+    pub obj: Box<Expr>,
     pub method: SMethod,
     pub args: Vec<Expr>,
 }
@@ -14,7 +14,7 @@ pub struct MethodCall {
 impl MethodCall {
     pub fn tpe(&self) -> SType {
         match self.method.tpe() {
-            SType::SFunc(sfunc) => sfunc.t_range.clone(),
+            SType::SFunc(sfunc) => *sfunc.t_range.clone(),
             tpe => tpe.clone(),
         }
     }
diff --git a/ergo-lib/src/ast/option_get.rs b/ergo-lib/src/ast/option_get.rs
index d389c6d1a..1d20bc80c 100644
--- a/ergo-lib/src/ast/option_get.rs
+++ b/ergo-lib/src/ast/option_get.rs
@@ -14,13 +14,15 @@ use crate::types::stype::SType;
 
 #[derive(PartialEq, Eq, Debug, Clone)]
 pub struct OptionGet {
-    input: Expr,
+    input: Box<Expr>,
 }
 
 impl OptionGet {
     pub fn new(input: Expr) -> Result<Self, InvalidArgumentError> {
         match input.tpe() {
-            SType::SOption(_) => Ok(OptionGet { input }),
+            SType::SOption(_) => Ok(OptionGet {
+                input: Box::new(input),
+            }),
             _ => Err(InvalidArgumentError(format!(
                 "expected OptionGet::input type to be SOption, got: {0:?}",
                 input.tpe(),
@@ -86,15 +88,15 @@ mod tests {
 
     #[test]
     fn eval_get() {
-        let get_reg_expr: Expr = Box::new(ExtractRegisterAs {
-            input: Box::new(GlobalVars::SelfBox).into(),
+        let get_reg_expr: Expr = ExtractRegisterAs {
+            input: Box::new(GlobalVars::SelfBox.into()),
             register_id: RegisterId::R0,
             tpe: SType::SOption(SType::SLong.into()),
-        })
+        }
         .into();
-        let option_get_expr: Expr = Box::new(OptionGet {
-            input: get_reg_expr,
-        })
+        let option_get_expr: Expr = OptionGet {
+            input: Box::new(get_reg_expr),
+        }
         .into();
         let ctx = Rc::new(force_any_val::<Context>());
         let v = eval_out::<i64>(&option_get_expr, ctx.clone());
@@ -103,15 +105,15 @@ mod tests {
 
     #[test]
     fn ser_roundtrip() {
-        let get_reg_expr: Expr = Box::new(ExtractRegisterAs {
-            input: Box::new(GlobalVars::SelfBox).into(),
+        let get_reg_expr: Expr = ExtractRegisterAs {
+            input: Box::new(GlobalVars::SelfBox.into()),
             register_id: RegisterId::R0,
             tpe: SType::SOption(SType::SLong.into()),
-        })
+        }
         .into();
-        let e: Expr = Box::new(OptionGet {
-            input: get_reg_expr,
-        })
+        let e: Expr = OptionGet {
+            input: Box::new(get_reg_expr),
+        }
         .into();
         assert_eq![sigma_serialize_roundtrip(&e), e];
     }
diff --git a/ergo-lib/src/ast/property_call.rs b/ergo-lib/src/ast/property_call.rs
index 02a5a88a7..80d368ce0 100644
--- a/ergo-lib/src/ast/property_call.rs
+++ b/ergo-lib/src/ast/property_call.rs
@@ -6,7 +6,7 @@ use super::expr::Expr;
 
 #[derive(PartialEq, Eq, Debug, Clone)]
 pub struct PropertyCall {
-    pub obj: Expr,
+    pub obj: Box<Expr>,
     pub method: SMethod,
 }
 
diff --git a/ergo-lib/src/ast/select_field.rs b/ergo-lib/src/ast/select_field.rs
index ad7033639..631d240bc 100644
--- a/ergo-lib/src/ast/select_field.rs
+++ b/ergo-lib/src/ast/select_field.rs
@@ -140,12 +140,9 @@ mod tests {
 
     #[test]
     fn ser_roundtrip() {
-        let e: Expr = SelectField::new(
-            Expr::Const(Box::new((1i64, true).into())),
-            1u8.try_into().unwrap(),
-        )
-        .unwrap()
-        .into();
+        let e: Expr = SelectField::new(Expr::Const((1i64, true).into()), 1u8.try_into().unwrap())
+            .unwrap()
+            .into();
         assert_eq![sigma_serialize_roundtrip(&e), e];
     }
 }
diff --git a/ergo-lib/src/ast/val_def.rs b/ergo-lib/src/ast/val_def.rs
index 297bd1462..37dba6d8a 100644
--- a/ergo-lib/src/ast/val_def.rs
+++ b/ergo-lib/src/ast/val_def.rs
@@ -38,7 +38,7 @@ impl SigmaSerializable for ValId {
 #[cfg_attr(test, derive(Arbitrary))]
 pub struct ValDef {
     pub id: ValId,
-    pub rhs: Expr,
+    pub rhs: Box<Expr>,
 }
 
 impl ValDef {
@@ -61,7 +61,10 @@ impl SigmaSerializable for ValDef {
         let id = ValId::sigma_parse(r)?;
         let rhs = Expr::sigma_parse(r)?;
         r.val_def_type_store().insert(id, rhs.tpe());
-        Ok(ValDef { id, rhs })
+        Ok(ValDef {
+            id,
+            rhs: Box::new(rhs),
+        })
     }
 }
 
@@ -77,7 +80,7 @@ mod tests {
 
         #[test]
         fn ser_roundtrip(v in any::<ValDef>()) {
-            let e = Expr::ValDef(v.into());
+            let e = Expr::ValDef(v);
             prop_assert_eq![sigma_serialize_roundtrip(&e), e];
         }
     }
diff --git a/ergo-lib/src/ast/val_use.rs b/ergo-lib/src/ast/val_use.rs
index 8d357d2e3..766304270 100644
--- a/ergo-lib/src/ast/val_use.rs
+++ b/ergo-lib/src/ast/val_use.rs
@@ -69,19 +69,17 @@ mod tests {
         #[test]
         fn ser_roundtrip_block_value(v in any::<ValDef>()) {
             // ValDef should put the type into the ValDefStore for ValUse to read
-            let block = Expr::BlockValue(Box::new(BlockValue {
+            let block: Expr = BlockValue {
                 items: vec![v.clone()],
-                result: Box::new(ValUse{ val_id: v.id, tpe: v.tpe() }).into(),
-            }));
+                result: Box::new(ValUse{ val_id: v.id, tpe: v.tpe() }.into()),
+            }.into();
             prop_assert_eq![sigma_serialize_roundtrip(&block), block];
         }
 
         #[test]
         fn ser_roundtrip_func_value(v in any::<FuncArg>()) {
-            let body = Box::new(ValUse{ val_id: v.idx, tpe: v.tpe.clone() }).into();
-            let func = Expr::FuncValue(Box::new(
-                    FuncValue::new(vec![v], body)
-                    ));
+            let body = ValUse{ val_id: v.idx, tpe: v.tpe.clone() }.into();
+            let func: Expr = FuncValue::new(vec![v], body).into();
             prop_assert_eq![sigma_serialize_roundtrip(&func), func];
         }
 
diff --git a/ergo-lib/src/chain/address.rs b/ergo-lib/src/chain/address.rs
index dee1bbf0f..85b7cbf23 100644
--- a/ergo-lib/src/chain/address.rs
+++ b/ergo-lib/src/chain/address.rs
@@ -86,7 +86,7 @@ impl Address {
     pub fn recreate_from_ergo_tree(tree: &ErgoTree) -> Result<Address, AddressError> {
         match tree.proposition() {
             Ok(expr) => Ok(match &*expr {
-                Expr::Const(c) => match &**c {
+                Expr::Const(c) => match c {
                     Constant {
                         tpe: SType::SSigmaProp,
                         v,
@@ -121,12 +121,12 @@ impl Address {
     /// script encoded in the address
     pub fn script(&self) -> Result<ErgoTree, SerializationError> {
         match self {
-            Address::P2PK(prove_dlog) => Ok(ErgoTree::from(Rc::new(Expr::Const(Box::new(
+            Address::P2PK(prove_dlog) => Ok(ErgoTree::from(Rc::new(Expr::Const(
                 SigmaProp::new(SigmaBoolean::ProofOfKnowledge(
                     SigmaProofOfKnowledgeTree::ProveDlog(prove_dlog.clone()),
                 ))
                 .into(),
-            ))))),
+            )))),
             Address::P2S(bytes) => ErgoTree::sigma_parse_bytes(bytes.to_vec()),
         }
     }
diff --git a/ergo-lib/src/ergo_tree.rs b/ergo-lib/src/ergo_tree.rs
index 8d93984a4..a94b34d76 100644
--- a/ergo-lib/src/ergo_tree.rs
+++ b/ergo-lib/src/ergo_tree.rs
@@ -141,7 +141,7 @@ impl ErgoTree {
 impl From<Rc<Expr>> for ErgoTree {
     fn from(expr: Rc<Expr>) -> Self {
         match expr.as_ref() {
-            Expr::Const(c) => match &**c {
+            Expr::Const(c) => match c {
                 Constant { tpe, .. } if *tpe == SType::SSigmaProp => {
                     ErgoTree::without_segregation(expr)
                 }
@@ -280,7 +280,7 @@ impl TryFrom<ErgoTree> for ProveDlog {
             .proposition()
             .map_err(|_| TryExtractFromError("cannot read root expr".to_string()))?;
         match expr {
-            Expr::Const(c) => match &**c {
+            Expr::Const(c) => match c {
                 Constant {
                     tpe: SType::SSigmaProp,
                     v,
@@ -315,9 +315,9 @@ mod tests {
         fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
             prop_oneof![
                 // make sure that P2PK tree is included
-                any::<ProveDlog>().prop_map(|p| ErgoTree::from(Rc::new(Expr::Const(Box::new(
+                any::<ProveDlog>().prop_map(|p| ErgoTree::from(Rc::new(Expr::Const(
                     Constant::from(SigmaProp::from(SigmaBoolean::from(p)))
-                ))))),
+                )))),
             ]
             .boxed()
         }
@@ -364,13 +364,10 @@ mod tests {
 
     #[test]
     fn test_constant_segregation() {
-        let expr = Expr::Const(
-            Constant {
-                tpe: SType::SBoolean,
-                v: Value::Boolean(true),
-            }
-            .into(),
-        );
+        let expr = Expr::Const(Constant {
+            tpe: SType::SBoolean,
+            v: Value::Boolean(true),
+        });
         let ergo_tree = ErgoTree::with_segregation(Rc::new(expr.clone()));
         let bytes = ergo_tree.sigma_serialize_bytes();
         let parsed_expr = ErgoTree::sigma_parse_bytes(bytes)
diff --git a/ergo-lib/src/eval/global_vars.rs b/ergo-lib/src/eval/global_vars.rs
index 3fd32886b..4e01d7dec 100644
--- a/ergo-lib/src/eval/global_vars.rs
+++ b/ergo-lib/src/eval/global_vars.rs
@@ -35,7 +35,7 @@ mod tests {
     fn eval_height() {
         let ctx = Rc::new(force_any_val::<Context>());
         assert_eq!(
-            eval_out::<i32>(&Box::new(GlobalVars::Height).into(), ctx.clone()),
+            eval_out::<i32>(&GlobalVars::Height.into(), ctx.clone()),
             ctx.height
         );
     }
@@ -44,7 +44,7 @@ mod tests {
     fn eval_self_box() {
         let ctx = Rc::new(force_any_val::<Context>());
         assert_eq!(
-            eval_out::<ErgoBox>(&Box::new(GlobalVars::SelfBox).into(), ctx.clone()),
+            eval_out::<ErgoBox>(&GlobalVars::SelfBox.into(), ctx.clone()),
             ctx.self_box
         );
     }
@@ -53,7 +53,7 @@ mod tests {
     fn eval_outputs() {
         let ctx = Rc::new(force_any_val::<Context>());
         assert_eq!(
-            eval_out::<Vec<ErgoBox>>(&Box::new(GlobalVars::Outputs).into(), ctx.clone()),
+            eval_out::<Vec<ErgoBox>>(&GlobalVars::Outputs.into(), ctx.clone()),
             ctx.outputs
         );
     }
diff --git a/ergo-lib/src/eval/method_call.rs b/ergo-lib/src/eval/method_call.rs
index c5d4a4afd..9bd572b37 100644
--- a/ergo-lib/src/eval/method_call.rs
+++ b/ergo-lib/src/eval/method_call.rs
@@ -32,13 +32,13 @@ mod tests {
 
     #[test]
     fn eval_box_get_reg() {
-        let mc: Expr = Box::new(MethodCall {
-            obj: Box::new(GlobalVars::SelfBox).into(),
+        let mc: Expr = MethodCall {
+            obj: Box::new(GlobalVars::SelfBox.into()),
             method: sbox::GET_REG_METHOD.clone(),
-            args: vec![Box::new(Constant::from(0i8)).into()],
-        })
+            args: vec![Constant::from(0i8).into()],
+        }
         .into();
-        let option_get_expr: Expr = Box::new(OptionGet::new(mc).unwrap()).into();
+        let option_get_expr: Expr = OptionGet::new(mc).unwrap().into();
         let ctx = Rc::new(force_any_val::<Context>());
         assert_eq!(
             eval_out::<i64>(&option_get_expr, ctx.clone()),
diff --git a/ergo-lib/src/eval/property_call.rs b/ergo-lib/src/eval/property_call.rs
index 14ccf2490..9c9d84bdc 100644
--- a/ergo-lib/src/eval/property_call.rs
+++ b/ergo-lib/src/eval/property_call.rs
@@ -28,10 +28,10 @@ mod tests {
 
     #[test]
     fn eval_context_data_inputs() {
-        let pc: Expr = Box::new(PropertyCall {
-            obj: Expr::Context,
+        let pc: Expr = PropertyCall {
+            obj: Box::new(Expr::Context),
             method: scontext::DATA_INPUTS_PROPERTY.clone(),
-        })
+        }
         .into();
         let ctx = Rc::new(force_any_val::<Context>());
         assert_eq!(eval_out::<Vec<ErgoBox>>(&pc, ctx.clone()), ctx.data_inputs);
diff --git a/ergo-lib/src/serialization/bin_op.rs b/ergo-lib/src/serialization/bin_op.rs
index ef39a35b5..20f65043b 100644
--- a/ergo-lib/src/serialization/bin_op.rs
+++ b/ergo-lib/src/serialization/bin_op.rs
@@ -21,11 +21,11 @@ pub fn bin_op_sigma_parse<R: SigmaByteRead>(
 ) -> Result<Expr, SerializationError> {
     let left = Expr::sigma_parse(r)?;
     let right = Expr::sigma_parse(r)?;
-    Ok(Box::new(BinOp {
+    Ok(BinOp {
         kind: op_kind,
-        left,
-        right,
-    })
+        left: Box::new(left),
+        right: Box::new(right),
+    }
     .into())
 }
 
@@ -39,7 +39,12 @@ mod tests {
     use crate::types::stype::SType;
 
     fn test_ser_roundtrip(kind: BinOpKind, left: Expr, right: Expr) {
-        let eq_op: Expr = Box::new(BinOp { kind, left, right }).into();
+        let eq_op: Expr = BinOp {
+            kind,
+            left: Box::new(left),
+            right: Box::new(right),
+        }
+        .into();
         assert_eq![sigma_serialize_roundtrip(&eq_op), eq_op];
     }
 
diff --git a/ergo-lib/src/serialization/expr.rs b/ergo-lib/src/serialization/expr.rs
index 122759a8a..776de4f29 100644
--- a/ergo-lib/src/serialization/expr.rs
+++ b/ergo-lib/src/serialization/expr.rs
@@ -28,7 +28,7 @@ impl SigmaSerializable for Expr {
         match self {
             Expr::Const(c) => match w.constant_store() {
                 Some(cs) => {
-                    let ph = cs.put(*c.clone());
+                    let ph = cs.put(c.clone());
                     ph.op_code().sigma_serialize(w)?;
                     ph.sigma_serialize(w)
                 }
@@ -70,41 +70,37 @@ impl SigmaSerializable for Expr {
         }?;
         if first_byte <= OpCode::LAST_CONSTANT_CODE.value() {
             let constant = Constant::sigma_parse(r)?;
-            Ok(Expr::Const(constant.into()))
+            Ok(Expr::Const(constant))
         } else {
             let op_code = OpCode::sigma_parse(r)?;
             match op_code {
-                OpCode::FOLD => Ok(Box::new(Fold::sigma_parse(r)?).into()),
+                OpCode::FOLD => Ok(Fold::sigma_parse(r)?.into()),
                 ConstantPlaceholder::OP_CODE => {
                     let cp = ConstantPlaceholder::sigma_parse(r)?;
                     if r.substitute_placeholders() {
                         // ConstantPlaceholder itself can be created only if a corresponding
                         // constant is in the constant_store, thus unwrap() is safe here
                         let c = r.constant_store().get(cp.id).unwrap();
-                        Ok(Expr::Const(c.clone().into()))
+                        Ok(Expr::Const(c.clone()))
                     } else {
-                        Ok(Expr::ConstPlaceholder(cp.into()))
+                        Ok(Expr::ConstPlaceholder(cp))
                     }
                 }
-                OpCode::HEIGHT => Ok(Expr::GlobalVars(GlobalVars::Height.into())),
-                OpCode::SELF_BOX => Ok(Expr::GlobalVars(GlobalVars::SelfBox.into())),
-                OpCode::INPUTS => Ok(Expr::GlobalVars(GlobalVars::Inputs.into())),
-                OpCode::OUTPUTS => Ok(Expr::GlobalVars(GlobalVars::Outputs.into())),
-                OpCode::PROPERTY_CALL => {
-                    Ok(Expr::ProperyCall(PropertyCall::sigma_parse(r)?.into()))
-                }
-                OpCode::METHOD_CALL => Ok(Expr::MethodCall(MethodCall::sigma_parse(r)?.into())),
+                OpCode::HEIGHT => Ok(Expr::GlobalVars(GlobalVars::Height)),
+                OpCode::SELF_BOX => Ok(Expr::GlobalVars(GlobalVars::SelfBox)),
+                OpCode::INPUTS => Ok(Expr::GlobalVars(GlobalVars::Inputs)),
+                OpCode::OUTPUTS => Ok(Expr::GlobalVars(GlobalVars::Outputs)),
+                OpCode::PROPERTY_CALL => Ok(Expr::ProperyCall(PropertyCall::sigma_parse(r)?)),
+                OpCode::METHOD_CALL => Ok(Expr::MethodCall(MethodCall::sigma_parse(r)?)),
                 OpCode::CONTEXT => Ok(Expr::Context),
-                OpCode::OPTION_GET => Ok(Box::new(OptionGet::sigma_parse(r)?).into()),
-                OpCode::EXTRACT_REGISTER_AS => {
-                    Ok(Box::new(ExtractRegisterAs::sigma_parse(r)?).into())
-                }
+                OpCode::OPTION_GET => Ok(OptionGet::sigma_parse(r)?.into()),
+                OpCode::EXTRACT_REGISTER_AS => Ok(ExtractRegisterAs::sigma_parse(r)?.into()),
                 OpCode::EQ => Ok(bin_op_sigma_parse(LogicOp::Eq.into(), r)?),
                 OpCode::NEQ => Ok(bin_op_sigma_parse(LogicOp::NEq.into(), r)?),
-                OpCode::BLOCK_VALUE => Ok(Expr::BlockValue(BlockValue::sigma_parse(r)?.into())),
-                OpCode::FUNC_VALUE => Ok(Expr::FuncValue(FuncValue::sigma_parse(r)?.into())),
-                OpCode::VAL_DEF => Ok(Expr::ValDef(ValDef::sigma_parse(r)?.into())),
-                OpCode::VAL_USE => Ok(Expr::ValUse(ValUse::sigma_parse(r)?.into())),
+                OpCode::BLOCK_VALUE => Ok(Expr::BlockValue(BlockValue::sigma_parse(r)?)),
+                OpCode::FUNC_VALUE => Ok(Expr::FuncValue(FuncValue::sigma_parse(r)?)),
+                OpCode::VAL_DEF => Ok(Expr::ValDef(ValDef::sigma_parse(r)?)),
+                OpCode::VAL_USE => Ok(Expr::ValUse(ValUse::sigma_parse(r)?)),
                 OpCode::EXTRACT_AMOUNT => Ok(Expr::ExtractAmount(ExtractAmount::sigma_parse(r)?)),
                 OpCode::SELECT_FIELD => Ok(Expr::SelectField(SelectField::sigma_parse(r)?)),
                 o => Err(SerializationError::NotImplementedOpCode(o.value())),
diff --git a/ergo-lib/src/serialization/global_vars.rs b/ergo-lib/src/serialization/global_vars.rs
index 0c2475fc0..83498be41 100644
--- a/ergo-lib/src/serialization/global_vars.rs
+++ b/ergo-lib/src/serialization/global_vars.rs
@@ -10,7 +10,7 @@ mod tests {
 
         #[test]
         fn ser_roundtrip(v in any::<GlobalVars>()) {
-            let expr = Expr::GlobalVars(v.into());
+            let expr = Expr::GlobalVars(v);
             prop_assert_eq![sigma_serialize_roundtrip(&expr), expr];
         }
     }
diff --git a/ergo-lib/src/serialization/method_call.rs b/ergo-lib/src/serialization/method_call.rs
index 094434b98..b5a18e956 100644
--- a/ergo-lib/src/serialization/method_call.rs
+++ b/ergo-lib/src/serialization/method_call.rs
@@ -26,7 +26,11 @@ impl SigmaSerializable for MethodCall {
         let obj = Expr::sigma_parse(r)?;
         let args = Vec::<Expr>::sigma_parse(r)?;
         let method = SMethod::from_ids(type_id, method_id);
-        Ok(MethodCall { obj, method, args })
+        Ok(MethodCall {
+            obj: Box::new(obj),
+            method,
+            args,
+        })
     }
 }
 
@@ -41,11 +45,11 @@ mod tests {
 
     #[test]
     fn ser_roundtrip_property() {
-        let mc: Expr = Box::new(MethodCall {
-            obj: Box::new(GlobalVars::SelfBox).into(),
+        let mc: Expr = MethodCall {
+            obj: Box::new(GlobalVars::SelfBox.into()),
             method: sbox::GET_REG_METHOD.clone(),
-            args: vec![Box::new(Constant::from(0i8)).into()],
-        })
+            args: vec![Constant::from(0i8).into()],
+        }
         .into();
         assert_eq![sigma_serialize_roundtrip(&mc), mc];
     }
diff --git a/ergo-lib/src/serialization/property_call.rs b/ergo-lib/src/serialization/property_call.rs
index abbe7e9b0..89a126353 100644
--- a/ergo-lib/src/serialization/property_call.rs
+++ b/ergo-lib/src/serialization/property_call.rs
@@ -24,7 +24,7 @@ impl SigmaSerializable for PropertyCall {
         let method_id = MethodId::sigma_parse(r)?;
         let obj = Expr::sigma_parse(r)?;
         Ok(PropertyCall {
-            obj,
+            obj: Box::new(obj),
             method: SMethod::from_ids(type_id, method_id),
         })
     }
@@ -40,10 +40,9 @@ mod tests {
     #[test]
     fn ser_roundtrip_property() {
         let mc = PropertyCall {
-            obj: Expr::Context,
+            obj: Box::new(Expr::Context),
             method: scontext::DATA_INPUTS_PROPERTY.clone(),
-        }
-        .into();
+        };
         let expr = Expr::ProperyCall(mc);
         assert_eq![sigma_serialize_roundtrip(&expr), expr];
     }
diff --git a/ergo-lib/src/sigma_protocol/fiat_shamir.rs b/ergo-lib/src/sigma_protocol/fiat_shamir.rs
index 61498bd85..54f6cb477 100644
--- a/ergo-lib/src/sigma_protocol/fiat_shamir.rs
+++ b/ergo-lib/src/sigma_protocol/fiat_shamir.rs
@@ -76,9 +76,9 @@ pub fn fiat_shamir_tree_to_bytes(tree: &ProofTree) -> Vec<u8> {
         _ => todo!(),
     };
 
-    let prop_tree = ErgoTree::with_segregation(Rc::new(Expr::Const(Box::new(
+    let prop_tree = ErgoTree::with_segregation(Rc::new(Expr::Const(
         SigmaProp::new(leaf.proposition()).into(),
-    ))));
+    )));
     let mut prop_bytes = prop_tree.sigma_serialize_bytes();
     // TODO: is unwrap safe here? Create new type with non-optional commitment? Decide when other scenarios
     // are implemented (leafs and trees)
diff --git a/ergo-lib/src/sigma_protocol/prover.rs b/ergo-lib/src/sigma_protocol/prover.rs
index 6a0601e8f..4d8fdbf5e 100644
--- a/ergo-lib/src/sigma_protocol/prover.rs
+++ b/ergo-lib/src/sigma_protocol/prover.rs
@@ -312,13 +312,10 @@ mod tests {
 
     #[test]
     fn test_prove_true_prop() {
-        let bool_true_tree = ErgoTree::from(Rc::new(Expr::Const(
-            Constant {
-                tpe: SType::SBoolean,
-                v: Value::Boolean(true),
-            }
-            .into(),
-        )));
+        let bool_true_tree = ErgoTree::from(Rc::new(Expr::Const(Constant {
+            tpe: SType::SBoolean,
+            v: Value::Boolean(true),
+        })));
         let message = vec![0u8; 100];
 
         let prover = TestProver { secrets: vec![] };
@@ -334,13 +331,10 @@ mod tests {
 
     #[test]
     fn test_prove_false_prop() {
-        let bool_false_tree = ErgoTree::from(Rc::new(Expr::Const(
-            Constant {
-                tpe: SType::SBoolean,
-                v: Value::Boolean(false),
-            }
-            .into(),
-        )));
+        let bool_false_tree = ErgoTree::from(Rc::new(Expr::Const(Constant {
+            tpe: SType::SBoolean,
+            v: Value::Boolean(false),
+        })));
         let message = vec![0u8; 100];
 
         let prover = TestProver { secrets: vec![] };
@@ -358,13 +352,10 @@ mod tests {
     fn test_prove_pk_prop() {
         let secret = DlogProverInput::random();
         let pk = secret.public_image();
-        let tree = ErgoTree::from(Rc::new(Expr::Const(
-            Constant {
-                tpe: SType::SSigmaProp,
-                v: pk.into(),
-            }
-            .into(),
-        )));
+        let tree = ErgoTree::from(Rc::new(Expr::Const(Constant {
+            tpe: SType::SSigmaProp,
+            v: pk.into(),
+        })));
         let message = vec![0u8; 100];
 
         let prover = TestProver {
diff --git a/ergo-lib/src/sigma_protocol/verifier.rs b/ergo-lib/src/sigma_protocol/verifier.rs
index f3cfaa8d4..d3b4ba89a 100644
--- a/ergo-lib/src/sigma_protocol/verifier.rs
+++ b/ergo-lib/src/sigma_protocol/verifier.rs
@@ -143,7 +143,7 @@ mod tests {
             let tree = ErgoTree::from(Rc::new(Expr::Const(Constant {
                 tpe: SType::SSigmaProp,
                 v: pk.into(),
-            }.into())));
+            })));
 
             let prover = TestProver {
                 secrets: vec![PrivateInput::DlogProverInput(secret)],
diff --git a/ergo-lib/src/types/sbox.rs b/ergo-lib/src/types/sbox.rs
index 2812e92e0..cea9966fd 100644
--- a/ergo-lib/src/types/sbox.rs
+++ b/ergo-lib/src/types/sbox.rs
@@ -45,11 +45,11 @@ lazy_static! {
     static ref GET_REG_METHOD_DESC: SMethodDesc = SMethodDesc {
         method_id: MethodId(7),
         name: "getReg",
-        tpe: SType::SFunc(Box::new(SFunc {
+        tpe: SType::SFunc(SFunc {
             t_dom: vec![SType::SBox, SType::SByte],
-            t_range: SType::SOption(Box::new(SType::STypeVar(STypeVar::T))),
+            t_range: Box::new(SType::SOption(Box::new(SType::STypeVar(STypeVar::T)))),
             tpe_params: vec![],
-        })),
+        }),
         eval_fn: GET_REG_EVAL_FN,
     };
 }
@@ -63,11 +63,11 @@ lazy_static! {
     static ref VALUE_METHOD_DESC: SMethodDesc = SMethodDesc {
         method_id: MethodId(1),
         name: "getReg",
-        tpe: SType::SFunc(Box::new(SFunc {
+        tpe: SType::SFunc(SFunc {
             t_dom: vec![SType::SBox],
-            t_range: SType::SLong,
+            t_range: Box::new(SType::SLong),
             tpe_params: vec![],
-        })),
+        }),
         eval_fn: VALUE_EVAL_FN,
     };
 }
@@ -97,10 +97,10 @@ mod tests {
 
     #[test]
     fn eval_box_value() {
-        let expr: Expr = Box::new(PropertyCall {
-            obj: Box::new(GlobalVars::SelfBox).into(),
+        let expr: Expr = PropertyCall {
+            obj: Box::new(GlobalVars::SelfBox.into()),
             method: VALUE_METHOD.clone(),
-        })
+        }
         .into();
         let ctx = Rc::new(force_any_val::<Context>());
         assert_eq!(
diff --git a/ergo-lib/src/types/scontext.rs b/ergo-lib/src/types/scontext.rs
index a6512e59d..46b472875 100644
--- a/ergo-lib/src/types/scontext.rs
+++ b/ergo-lib/src/types/scontext.rs
@@ -41,11 +41,11 @@ lazy_static! {
     static ref DATA_INPUTS_PROPERTY_METHOD_DESC: SMethodDesc = SMethodDesc {
         method_id: MethodId(1),
         name: "dataInputs",
-        tpe: SType::SFunc(Box::new(SFunc {
+        tpe: SType::SFunc(SFunc {
             t_dom: vec![SType::SContext(SContext())],
-            t_range: SType::SColl(Box::new(SType::SBox)),
+            t_range: Box::new(SType::SColl(Box::new(SType::SBox))),
             tpe_params: vec![],
-        })),
+        }),
         eval_fn: DATA_INPUTS_EVAL_FN,
     };
 }
diff --git a/ergo-lib/src/types/sfunc.rs b/ergo-lib/src/types/sfunc.rs
index 53bafa264..15731aa7b 100644
--- a/ergo-lib/src/types/sfunc.rs
+++ b/ergo-lib/src/types/sfunc.rs
@@ -6,7 +6,7 @@ pub struct SFunc {
     /// Function parameter types
     pub t_dom: Vec<SType>,
     /// Result type
-    pub t_range: SType,
+    pub t_range: Box<SType>,
     /// Type parameters if the function is generic
     pub tpe_params: Vec<STypeParam>,
 }
diff --git a/ergo-lib/src/types/stype.rs b/ergo-lib/src/types/stype.rs
index a2c926ceb..f2af5883e 100644
--- a/ergo-lib/src/types/stype.rs
+++ b/ergo-lib/src/types/stype.rs
@@ -52,7 +52,7 @@ pub enum SType {
     /// Tuple (elements can have different types)
     STuple(STuple),
     /// Function (signature)
-    SFunc(Box<SFunc>),
+    SFunc(SFunc),
     /// Context object ("CONTEXT" in ErgoScript)
     SContext(SContext),
 }
diff --git a/ergo-lib/src/wallet/signing.rs b/ergo-lib/src/wallet/signing.rs
index 0d3191bec..b516b8eb6 100644
--- a/ergo-lib/src/wallet/signing.rs
+++ b/ergo-lib/src/wallet/signing.rs
@@ -139,7 +139,7 @@ mod tests {
                 let tree = ErgoTree::from(Rc::new(Expr::Const(Constant {
                     tpe: SType::SSigmaProp,
                     v: pk.into(),
-                }.into())));
+                })));
                 ErgoBox::new(BoxValue::SAFE_USER_MIN,
                              tree,
                              vec![],
@@ -155,7 +155,7 @@ mod tests {
             let ergo_tree = ErgoTree::from(Rc::new(Expr::Const(Constant {
                     tpe: SType::SSigmaProp,
                     v: secrets.get(0).unwrap().public_image().into(),
-            }.into())));
+            })));
             let candidate = ErgoBoxCandidateBuilder::new(BoxValue::SAFE_USER_MIN, ergo_tree, 0)
                 .build().unwrap();
             let output_candidates = vec![candidate];


Test patch: