neo_solidity/ir/context/
helpers.rs

1fn load_expression(
2    expr: &Expression,
3    ctx: &mut LoweringContext,
4    instructions: &mut Vec<Instruction>,
5) {
6    let mut tmp = Vec::new();
7    if lower_expression(expr, ctx, &mut tmp) {
8        instructions.append(&mut tmp);
9    }
10}
11
12fn push_default_for_type(ty: &PtType, instructions: &mut Vec<Instruction>) {
13    match ty {
14        PtType::Address | PtType::AddressPayable => {
15            instructions.push(Instruction::PushLiteral(LiteralValue::Address(vec![
16                0u8;
17                20
18            ])));
19        }
20        PtType::Bool => instructions.push(Instruction::PushLiteral(LiteralValue::Boolean(false))),
21        PtType::String => {
22            instructions.push(Instruction::PushLiteral(LiteralValue::String(Vec::new())))
23        }
24        PtType::Uint(_) | PtType::Int(_) => {
25            instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
26                BigInt::zero(),
27            )));
28        }
29        PtType::Bytes(len) => instructions.push(Instruction::PushLiteral(LiteralValue::ByteArray(
30            vec![0u8; *len as usize],
31        ))),
32        PtType::DynamicBytes => instructions.push(Instruction::PushLiteral(
33            LiteralValue::ByteArray(Vec::new()),
34        )),
35        _ => instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
36            BigInt::zero(),
37        ))),
38    }
39}
40
41fn push_default_for_value_type(
42    value_type: &ValueType,
43    ctx: &mut LoweringContext,
44    instructions: &mut Vec<Instruction>,
45) -> bool {
46    match value_type {
47        ValueType::Integer { .. } => {
48            instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
49                BigInt::zero(),
50            )));
51            true
52        }
53        ValueType::Boolean => {
54            instructions.push(Instruction::PushLiteral(LiteralValue::Boolean(false)));
55            true
56        }
57        ValueType::String => {
58            instructions.push(Instruction::PushLiteral(LiteralValue::String(Vec::new())));
59            true
60        }
61        ValueType::Address => {
62            instructions.push(Instruction::PushLiteral(LiteralValue::Address(vec![
63                0u8;
64                20
65            ])));
66            true
67        }
68        ValueType::ByteArray { fixed_len } => {
69            let bytes = fixed_len
70                .map(|len| vec![0u8; len as usize])
71                .unwrap_or_else(Vec::new);
72            instructions.push(Instruction::PushLiteral(LiteralValue::ByteArray(bytes)));
73            true
74        }
75        ValueType::Array(element_type) => {
76            instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
77                BigInt::zero(),
78            )));
79            instructions.push(Instruction::NewArray {
80                element_type: (**element_type).clone(),
81            });
82            true
83        }
84        ValueType::Struct { fields, .. } => {
85            let tmp_id = ctx.next_label();
86            let struct_local = ctx.allocate_local(
87                format!("__default_struct_{tmp_id}"),
88                Some(ValueType::Array(Box::new(ValueType::Any))),
89            );
90
91            instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
92                BigInt::from(fields.len() as u64),
93            )));
94            instructions.push(Instruction::NewArray {
95                element_type: ValueType::Any,
96            });
97            instructions.push(Instruction::StoreLocal(struct_local));
98
99            for (index, field) in fields.iter().enumerate() {
100                instructions.push(Instruction::LoadLocal(struct_local));
101                instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
102                    BigInt::from(index as u64),
103                )));
104                push_default_for_value_type(&field.ty, ctx, instructions);
105                instructions.push(Instruction::ArraySet);
106            }
107
108            instructions.push(Instruction::LoadLocal(struct_local));
109            true
110        }
111        ValueType::Mapping { .. } | ValueType::Any => {
112            instructions.push(Instruction::PushLiteral(LiteralValue::Null));
113            true
114        }
115    }
116}
117
118fn push_default_for_storage_value_type(
119    value_type: &ValueType,
120    ctx: &mut LoweringContext,
121    instructions: &mut Vec<Instruction>,
122) -> bool {
123    match value_type {
124        // Storage arrays are represented by their length stored at the base slot.
125        ValueType::Array(_) => {
126            instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
127                BigInt::zero(),
128            )));
129            true
130        }
131        // Structs are stored field-by-field; represent the default as an array whose elements
132        // match the per-field storage encoding (notably: nested arrays use their length).
133        ValueType::Struct { fields, .. } => {
134            let tmp_id = ctx.next_label();
135            let struct_local = ctx.allocate_local(
136                format!("__default_storage_struct_{tmp_id}"),
137                Some(ValueType::Array(Box::new(ValueType::Any))),
138            );
139
140            instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
141                BigInt::from(fields.len() as u64),
142            )));
143            instructions.push(Instruction::NewArray {
144                element_type: ValueType::Any,
145            });
146            instructions.push(Instruction::StoreLocal(struct_local));
147
148            for (index, field) in fields.iter().enumerate() {
149                instructions.push(Instruction::LoadLocal(struct_local));
150                instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
151                    BigInt::from(index as u64),
152                )));
153                push_default_for_storage_value_type(&field.ty, ctx, instructions);
154                instructions.push(Instruction::ArraySet);
155            }
156
157            instructions.push(Instruction::LoadLocal(struct_local));
158            true
159        }
160        _ => push_default_for_value_type(value_type, ctx, instructions),
161    }
162}