neo_solidity/ir/statements/dispatch/
expressions.rs

1fn lower_expression_statement(
2    expr: &Expression,
3    ctx: &mut LoweringContext,
4    instructions: &mut Vec<Instruction>,
5) -> bool {
6    if let Expression::Assign(_, lhs, rhs) = expr {
7        lower_assignment(lhs, rhs, ctx, instructions);
8    } else if let Expression::FunctionCall(_, func, args) = expr {
9        if let Expression::Variable(identifier) = func.as_ref() {
10            if identifier.name == "require" {
11                lower_require(args, ctx, instructions);
12                return false;
13            }
14            if identifier.name == "assert" {
15                lower_assert(args, ctx, instructions);
16                return false;
17            }
18        }
19        if lower_expression(expr, ctx, instructions) {
20            instructions.push(Instruction::Drop(ValueType::Any));
21        }
22    } else if lower_expression(expr, ctx, instructions) {
23        instructions.push(Instruction::Drop(ValueType::Any));
24    }
25    false
26}
27
28fn lower_variable_definition_statement(
29    decl: &solang_parser::pt::VariableDeclaration,
30    init: Option<&Expression>,
31    ctx: &mut LoweringContext,
32    instructions: &mut Vec<Instruction>,
33) -> bool {
34    if let Some(ident) = &decl.name {
35        if ctx.is_local_in_current_scope(&ident.name) {
36            ctx.record_error_with_suggestion(
37                format!("local variable '{}' redeclared", ident.name),
38                "use a different variable name or assign to the existing variable instead of redeclaring",
39            );
40        } else {
41            let is_storage_reference = matches!(decl.storage, Some(PtStorageLocation::Storage(_)));
42            let mut inferred_type = if is_storage_reference {
43                None
44            } else {
45                infer_type_from_expression(&decl.ty, ctx)
46            };
47
48            // Best-effort: infer user-defined struct types for locals so that member
49            // access (`tmp.field`) can be lowered correctly for memory copies.
50            if !is_storage_reference && inferred_type.is_none() {
51                if let Expression::Variable(type_ident) = &decl.ty {
52                    inferred_type = ctx
53                        .defined_struct_types
54                        .iter()
55                        .chain(ctx.state_types.iter())
56                        .chain(ctx.param_types.iter())
57                        .chain(ctx.return_types.iter())
58                        .chain(ctx.local_types.values())
59                        .find_map(|ty| find_named_struct_type(ty, &type_ident.name));
60                }
61            }
62
63            let slot = ctx.allocate_local(ident.name.clone(), inferred_type.clone());
64            if let Some(initializer) = init {
65                if is_storage_reference {
66                    if let Some(reference) = resolve_storage_reference(initializer, ctx) {
67                        ctx.set_storage_alias(ident.name.clone(), reference);
68                    } else if lower_expression(initializer, ctx, instructions) {
69                        instructions.push(Instruction::Drop(ValueType::Any));
70                    }
71                } else {
72                    match parse_low_level_call_data(initializer, ctx) {
73                        Ok(Some((method_name, encode_args))) => {
74                            // Support `bytes data = abi.encodeWithSignature/encodeWithSelector(...)`
75                            // for subsequent `address.call(data)` lowering.
76                            let mut lowered = true;
77                            for arg in &encode_args {
78                                if !lower_expression(arg, ctx, instructions) {
79                                    lowered = false;
80                                }
81                            }
82
83                            if lowered {
84                                instructions.push(Instruction::CallBuiltin {
85                                    builtin: BuiltinCall::AbiEncode,
86                                    arg_count: encode_args.len(),
87                                });
88                                instructions.push(Instruction::StoreLocal(slot));
89                                ctx.set_call_data_local(slot, method_name);
90                            }
91                        }
92                        Ok(None) => {
93                            if lower_expression(initializer, ctx, instructions) {
94                                instructions.push(Instruction::StoreLocal(slot));
95                                ctx.clear_call_data_local(slot);
96                            }
97                        }
98                        Err(message) => {
99                            ctx.record_error(message);
100                            ctx.clear_call_data_local(slot);
101                        }
102                    }
103                }
104            } else if !is_storage_reference {
105                if let Some(value_type) = inferred_type.as_ref() {
106                    push_default_for_value_type(value_type, ctx, instructions);
107                } else {
108                    instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
109                        BigInt::from(0u8),
110                    )));
111                }
112                instructions.push(Instruction::StoreLocal(slot));
113                ctx.clear_call_data_local(slot);
114            }
115        }
116    } else {
117        ctx.record_error_with_suggestion(
118            "variable declaration missing identifier",
119            "every variable declaration must have a name: e.g. uint256 myVar = 0",
120        );
121    }
122    false
123}
124
125fn lower_emit_statement(
126    call: &Expression,
127    ctx: &mut LoweringContext,
128    instructions: &mut Vec<Instruction>,
129) -> bool {
130    lower_emit(call, ctx, instructions);
131    false
132}
133
134fn lower_assembly_statement(ctx: &mut LoweringContext, instructions: &mut Vec<Instruction>) -> bool {
135    if !lower_special_assembly(ctx, instructions) {
136        ctx.record_error_with_suggestion(
137            "inline assembly is not supported",
138            "Neo N3 uses NeoVM opcodes; use NativeCalls.sol for low-level operations",
139        );
140    }
141    false
142}