1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
use crate::serialization::op_code::OpCode;
use crate::types::smethod::SMethod;
use crate::types::stype::SType;
use super::expr::Expr;
use super::expr::InvalidArgumentError;
use crate::has_opcode::HasStaticOpCode;
/** Represents in ErgoTree an invocation of method of the object `obj` with arguments `args`.
* The SMethod instances in STypeCompanions may have type STypeIdent in methods types,
* but valid ErgoTree should have SMethod instances specialized for specific types of
* obj and args using `specializeFor`.
* This means, if we save typeId, methodId, and we save all the arguments,
* we can restore the specialized SMethod instance.
* This work by induction, if we assume all arguments are monomorphic,
* then we can make MethodCall monomorphic.
* Thus, all ErgoTree instances are monomorphic by construction.
*/
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct MethodCall {
/// Object on which method will be invoked
pub obj: Box<Expr>,
/// Method to be invoked
pub method: SMethod,
/// Arguments passed to the method on invocation
pub args: Vec<Expr>,
}
impl MethodCall {
/// Create new object, returns an error if any of the requirements failed
pub fn new(obj: Expr, method: SMethod, args: Vec<Expr>) -> Result<Self, InvalidArgumentError> {
if method.tpe().t_dom.len() != args.len() + 1 {
return Err(InvalidArgumentError(format!(
"MethodCall: expected arguments count {} does not match provided arguments count {}",
method.tpe().t_dom.len(), args.len() + 1)));
}
let mut expected_types: Vec<SType> = vec![obj.tpe()];
let arg_types: Vec<SType> = args.clone().into_iter().map(|a| a.tpe()).collect();
expected_types.extend(arg_types);
if !method
.tpe()
.t_dom
.iter()
.zip(&expected_types)
.all(|(expected, actual)| expected == actual)
{
return Err(InvalidArgumentError(format!(
"MethodCall: expected types {expected_types:?} do not match provided obj and args types {:?}",
method.tpe().t_dom,
)));
}
Ok(Self {
obj: obj.into(),
method,
args,
})
}
/// Type
pub fn tpe(&self) -> SType {
*self.method.tpe().t_range.clone()
}
}
impl HasStaticOpCode for MethodCall {
const OP_CODE: OpCode = OpCode::METHOD_CALL;
}