1fn try_lower_expression_assignments(
2 expr: &Expression,
3 ctx: &mut LoweringContext,
4 instructions: &mut Vec<Instruction>,
5) -> Option<bool> {
6 match expr {
7 Expression::AssignAdd(_, lhs, rhs) => Some(lower_compound_assignment(
8 lhs,
9 rhs,
10 ctx,
11 instructions,
12 BinaryOperator::Add,
13 )),
14 Expression::AssignSubtract(_, lhs, rhs) => Some(lower_compound_assignment(
15 lhs,
16 rhs,
17 ctx,
18 instructions,
19 BinaryOperator::Sub,
20 )),
21 Expression::AssignShiftLeft(_, lhs, rhs) => Some(lower_compound_assignment(
22 lhs,
23 rhs,
24 ctx,
25 instructions,
26 BinaryOperator::Shl,
27 )),
28 Expression::AssignShiftRight(_, lhs, rhs) => Some(lower_compound_assignment(
29 lhs,
30 rhs,
31 ctx,
32 instructions,
33 BinaryOperator::Shr,
34 )),
35 Expression::AssignAnd(_, lhs, rhs) => Some(lower_compound_assignment(
36 lhs,
37 rhs,
38 ctx,
39 instructions,
40 BinaryOperator::BitAnd,
41 )),
42 Expression::AssignOr(_, lhs, rhs) => Some(lower_compound_assignment(
43 lhs,
44 rhs,
45 ctx,
46 instructions,
47 BinaryOperator::BitOr,
48 )),
49 Expression::AssignXor(_, lhs, rhs) => Some(lower_compound_assignment(
50 lhs,
51 rhs,
52 ctx,
53 instructions,
54 BinaryOperator::BitXor,
55 )),
56 Expression::AssignMultiply(_, lhs, rhs) => Some(lower_compound_assignment(
57 lhs,
58 rhs,
59 ctx,
60 instructions,
61 BinaryOperator::Mul,
62 )),
63 Expression::AssignDivide(_, lhs, rhs) => Some(lower_compound_assignment(
64 lhs,
65 rhs,
66 ctx,
67 instructions,
68 BinaryOperator::Div,
69 )),
70 Expression::AssignModulo(_, lhs, rhs) => Some(lower_compound_assignment(
71 lhs,
72 rhs,
73 ctx,
74 instructions,
75 BinaryOperator::Mod,
76 )),
77 Expression::Assign(_, lhs, rhs) => {
78 lower_assignment(lhs, rhs, ctx, instructions);
79 Some(true)
80 }
81 Expression::PostIncrement(_, inner) => Some(lower_post_inc_dec(inner, ctx, instructions, true)),
82 Expression::PostDecrement(_, inner) => {
83 Some(lower_post_inc_dec(inner, ctx, instructions, false))
84 }
85 Expression::PreIncrement(_, inner) => Some(lower_pre_inc_dec(inner, ctx, instructions, true)),
86 Expression::PreDecrement(_, inner) => Some(lower_pre_inc_dec(inner, ctx, instructions, false)),
87 Expression::Delete(_, target) => {
88 Some(lower_delete(target, ctx, instructions))
89 }
90 _ => None,
91 }
92}
93
94fn lower_delete(
95 target: &Expression,
96 ctx: &mut LoweringContext,
97 instructions: &mut Vec<Instruction>,
98) -> bool {
99 if let Some(reference) = resolve_storage_reference(target, ctx) {
101 if !ctx.ensure_state_writable(reference.state_index) {
102 return false;
103 }
104
105 if matches!(reference.value_type, ValueType::Mapping { .. }) {
107 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
108 BigInt::zero(),
109 )));
110 return true;
111 }
112
113 push_default_for_storage_value_type(&reference.value_type, ctx, instructions);
114 if !emit_storage_store(&reference, ctx, instructions) {
115 instructions.push(Instruction::Drop(ValueType::Any));
116 }
117
118 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
121 BigInt::zero(),
122 )));
123 return true;
124 }
125
126 if let Expression::Variable(identifier) = target {
128 if let Some(local_index) = ctx.resolve_local(&identifier.name) {
129 if let Some(value_type) = ctx.local_type(local_index).cloned() {
130 push_default_for_value_type(&value_type, ctx, instructions);
131 } else {
132 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
133 BigInt::zero(),
134 )));
135 }
136 ctx.clear_call_data_local(local_index);
137 instructions.push(Instruction::StoreLocal(local_index));
138 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
139 BigInt::zero(),
140 )));
141 return true;
142 }
143
144 if let Some(state_index) = ctx.state_index_map.get(&identifier.name).copied() {
145 if !ctx.ensure_state_writable(state_index) {
146 return false;
147 }
148
149 if let Some(state_type) = ctx.state_type(state_index).cloned() {
150 if matches!(state_type, ValueType::Mapping { .. }) {
151 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
152 BigInt::zero(),
153 )));
154 return true;
155 }
156
157 if matches!(state_type, ValueType::Struct { .. }) {
158 let reference = StorageReference {
159 state_index,
160 key_expressions: Vec::new(),
161 key_types: Vec::new(),
162 value_type: state_type.clone(),
163 field_path: Vec::new(),
164 };
165
166 push_default_for_storage_value_type(&reference.value_type, ctx, instructions);
167 if !emit_storage_store(&reference, ctx, instructions) {
168 instructions.push(Instruction::Drop(ValueType::Any));
169 }
170 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
171 BigInt::zero(),
172 )));
173 return true;
174 }
175
176 push_default_for_storage_value_type(&state_type, ctx, instructions);
177 instructions.push(Instruction::StoreState(state_index));
178 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
179 BigInt::zero(),
180 )));
181 return true;
182 }
183 }
184 }
185
186 if let Expression::ArraySubscript(_, array, Some(index)) = target {
188 if let Some(ValueType::Array(element_type)) = infer_type_from_expression(array, ctx) {
189 let tmp_id = ctx.next_label();
190 let array_local = ctx.allocate_local(format!("__delete_arr_{tmp_id}"), None);
191 let index_local = ctx.allocate_local(format!("__delete_idx_{tmp_id}"), None);
192
193 if !lower_expression(array, ctx, instructions) {
194 return false;
195 }
196 instructions.push(Instruction::StoreLocal(array_local));
197
198 if !lower_expression(index, ctx, instructions) {
199 return false;
200 }
201 instructions.push(Instruction::StoreLocal(index_local));
202
203 instructions.push(Instruction::LoadLocal(array_local));
204 instructions.push(Instruction::LoadLocal(index_local));
205 push_default_for_value_type(element_type.as_ref(), ctx, instructions);
206 instructions.push(Instruction::ArraySet);
207 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
208 BigInt::zero(),
209 )));
210 return true;
211 }
212 }
213
214 if let Expression::MemberAccess(_, inner, member) = target {
216 if let Expression::Variable(base) = inner.as_ref() {
217 if let Some(local_index) = ctx.resolve_local(&base.name) {
218 if let Some(ValueType::Struct { fields, .. }) = infer_type_from_expression(inner, ctx)
219 {
220 if let Some((field_index, field)) = fields
221 .iter()
222 .enumerate()
223 .find(|(_, field)| field.name == member.name)
224 {
225 instructions.push(Instruction::LoadLocal(local_index));
226 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
227 BigInt::from(field_index as u64),
228 )));
229 push_default_for_value_type(&field.ty, ctx, instructions);
230 instructions.push(Instruction::ArraySet);
231 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
232 BigInt::zero(),
233 )));
234 return true;
235 }
236 }
237 }
238 }
239 }
240
241 ctx.record_error_with_suggestion(
242 "unsupported delete target",
243 "delete is supported for state variables, mapping entries, and local variables",
244 );
245 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(BigInt::zero())));
246 true
247}