1use std::{collections::BTreeMap, rc::Rc, vec};
2
3use fe_analyzer::{
4 builtins::{ContractTypeMethod, GlobalFunction, ValueMethod},
5 constants::{EMITTABLE_TRAIT_NAME, EMIT_FN_NAME},
6 context::{Adjustment, AdjustmentKind, CallType as AnalyzerCallType, NamedThing},
7 namespace::{
8 items as analyzer_items,
9 types::{self as analyzer_types, Type},
10 },
11};
12use fe_common::numeric::Literal;
13use fe_parser::{ast, node::Node};
14use fxhash::FxHashMap;
15use id_arena::{Arena, Id};
16use num_bigint::BigInt;
17use smol_str::SmolStr;
18
19use crate::{
20 db::MirDb,
21 ir::{
22 self,
23 body_builder::BodyBuilder,
24 constant::ConstantValue,
25 function::Linkage,
26 inst::{CallType, InstKind},
27 value::{AssignableValue, Local},
28 BasicBlockId, Constant, FunctionBody, FunctionId, FunctionParam, FunctionSignature, InstId,
29 SourceInfo, TypeId, Value, ValueId,
30 },
31};
32
33type ScopeId = Id<Scope>;
34
35pub fn lower_func_signature(db: &dyn MirDb, func: analyzer_items::FunctionId) -> FunctionId {
36 lower_monomorphized_func_signature(db, func, BTreeMap::new())
37}
38pub fn lower_monomorphized_func_signature(
39 db: &dyn MirDb,
40 func: analyzer_items::FunctionId,
41 resolved_generics: BTreeMap<SmolStr, analyzer_types::TypeId>,
42) -> FunctionId {
43 let mut params = vec![];
45
46 if func.takes_self(db.upcast()) {
47 let self_ty = func.self_type(db.upcast()).unwrap();
48 let source = self_arg_source(db, func);
49 params.push(make_param(db, "self", self_ty, source));
50 }
51 let analyzer_signature = func.signature(db.upcast());
52
53 for param in analyzer_signature.params.iter() {
54 let source = arg_source(db, func, ¶m.name);
55
56 let param_type =
57 if let Type::Generic(generic) = param.typ.clone().unwrap().deref_typ(db.upcast()) {
58 *resolved_generics.get(&generic.name).unwrap()
59 } else {
60 param.typ.clone().unwrap()
61 };
62
63 params.push(make_param(db, param.clone().name, param_type, source))
64 }
65
66 let return_type = db.mir_lowered_type(analyzer_signature.return_type.clone().unwrap());
67
68 let linkage = if func.is_public(db.upcast()) {
69 if func.is_contract_func(db.upcast()) && !func.is_constructor(db.upcast()) {
70 Linkage::Export
71 } else {
72 Linkage::Public
73 }
74 } else {
75 Linkage::Private
76 };
77
78 let sig = FunctionSignature {
79 params,
80 resolved_generics,
81 return_type: Some(return_type),
82 module_id: func.module(db.upcast()),
83 analyzer_func_id: func,
84 linkage,
85 };
86
87 db.mir_intern_function(sig.into())
88}
89
90pub fn lower_func_body(db: &dyn MirDb, func: FunctionId) -> Rc<FunctionBody> {
91 let analyzer_func = func.analyzer_func(db);
92 let ast = &analyzer_func.data(db.upcast()).ast;
93 let analyzer_body = analyzer_func.body(db.upcast());
94
95 BodyLowerHelper::new(db, func, ast, analyzer_body.as_ref())
96 .lower()
97 .into()
98}
99
100pub(super) struct BodyLowerHelper<'db, 'a> {
101 pub(super) db: &'db dyn MirDb,
102 pub(super) builder: BodyBuilder,
103 ast: &'a Node<ast::Function>,
104 func: FunctionId,
105 analyzer_body: &'a fe_analyzer::context::FunctionBody,
106 scopes: Arena<Scope>,
107 current_scope: ScopeId,
108}
109
110impl<'db, 'a> BodyLowerHelper<'db, 'a> {
111 pub(super) fn lower_stmt(&mut self, stmt: &Node<ast::FuncStmt>) {
112 match &stmt.kind {
113 ast::FuncStmt::Return { value } => {
114 let value = if let Some(expr) = value {
115 self.lower_expr_to_value(expr)
116 } else {
117 self.make_unit()
118 };
119 self.builder.ret(value, stmt.into());
120 let next_block = self.builder.make_block();
121 self.builder.move_to_block(next_block);
122 }
123
124 ast::FuncStmt::VarDecl { target, value, .. } => {
125 self.lower_var_decl(target, value.as_ref(), stmt.into());
126 }
127
128 ast::FuncStmt::ConstantDecl { name, value, .. } => {
129 let ty = self.lower_analyzer_type(self.analyzer_body.var_types[&name.id]);
130
131 let value = self.analyzer_body.expressions[&value.id]
132 .const_value
133 .clone()
134 .unwrap();
135
136 let constant =
137 self.make_local_constant(name.kind.clone(), ty, value.into(), stmt.into());
138 self.scope_mut().declare_var(&name.kind, constant);
139 }
140
141 ast::FuncStmt::Assign { target, value } => {
142 let result = self.lower_assignable_value(target);
143 let (expr, _ty) = self.lower_expr(value);
144 self.builder.map_result(expr, result)
145 }
146
147 ast::FuncStmt::AugAssign { target, op, value } => {
148 let result = self.lower_assignable_value(target);
149 let lhs = self.lower_expr_to_value(target);
150 let rhs = self.lower_expr_to_value(value);
151
152 let inst = self.lower_binop(op.kind, lhs, rhs, stmt.into());
153 self.builder.map_result(inst, result)
154 }
155
156 ast::FuncStmt::For { target, iter, body } => self.lower_for_loop(target, iter, body),
157
158 ast::FuncStmt::While { test, body } => {
159 let header_bb = self.builder.make_block();
160 let exit_bb = self.builder.make_block();
161
162 let cond = self.lower_expr_to_value(test);
163 self.builder
164 .branch(cond, header_bb, exit_bb, SourceInfo::dummy());
165
166 self.builder.move_to_block(header_bb);
168 self.enter_loop_scope(header_bb, exit_bb);
169 for stmt in body {
170 self.lower_stmt(stmt);
171 }
172 let cond = self.lower_expr_to_value(test);
173 self.builder
174 .branch(cond, header_bb, exit_bb, SourceInfo::dummy());
175
176 self.leave_scope();
177
178 self.builder.move_to_block(exit_bb);
180 }
181
182 ast::FuncStmt::If {
183 test,
184 body,
185 or_else,
186 } => self.lower_if(test, body, or_else),
187
188 ast::FuncStmt::Match { expr, arms } => {
189 let matrix = &self.analyzer_body.matches[&stmt.id];
190 super::pattern_match::lower_match(self, matrix, expr, arms);
191 }
192
193 ast::FuncStmt::Assert { test, msg } => {
194 let then_bb = self.builder.make_block();
195 let false_bb = self.builder.make_block();
196
197 let cond = self.lower_expr_to_value(test);
198 self.builder
199 .branch(cond, then_bb, false_bb, SourceInfo::dummy());
200
201 self.builder.move_to_block(false_bb);
202
203 let msg = match msg {
204 Some(msg) => self.lower_expr_to_value(msg),
205 None => self.make_u256_imm(1),
206 };
207 self.builder.revert(Some(msg), stmt.into());
208 self.builder.move_to_block(then_bb);
209 }
210
211 ast::FuncStmt::Expr { value } => {
212 self.lower_expr_to_value(value);
213 }
214
215 ast::FuncStmt::Break => {
216 let exit = self.scope().loop_exit(&self.scopes);
217 self.builder.jump(exit, stmt.into());
218 let next_block = self.builder.make_block();
219 self.builder.move_to_block(next_block);
220 }
221
222 ast::FuncStmt::Continue => {
223 let entry = self.scope().loop_entry(&self.scopes);
224 if let Some(loop_idx) = self.scope().loop_idx(&self.scopes) {
225 let imm_one = self.make_u256_imm(1u32);
226 let inc = self.builder.add(loop_idx, imm_one, SourceInfo::dummy());
227 self.builder.map_result(inc, loop_idx.into());
228 let maximum_iter_count = self.scope().maximum_iter_count(&self.scopes).unwrap();
229 let exit = self.scope().loop_exit(&self.scopes);
230 self.branch_eq(loop_idx, maximum_iter_count, exit, entry, stmt.into());
231 } else {
232 self.builder.jump(entry, stmt.into());
233 }
234 let next_block = self.builder.make_block();
235 self.builder.move_to_block(next_block);
236 }
237
238 ast::FuncStmt::Revert { error } => {
239 let error = error.as_ref().map(|err| self.lower_expr_to_value(err));
240 self.builder.revert(error, stmt.into());
241 let next_block = self.builder.make_block();
242 self.builder.move_to_block(next_block);
243 }
244
245 ast::FuncStmt::Unsafe(stmts) => {
246 self.enter_scope();
247 for stmt in stmts {
248 self.lower_stmt(stmt)
249 }
250 self.leave_scope()
251 }
252 }
253 }
254
255 pub(super) fn lower_var_decl(
256 &mut self,
257 var: &Node<ast::VarDeclTarget>,
258 init: Option<&Node<ast::Expr>>,
259 source: SourceInfo,
260 ) {
261 match &var.kind {
262 ast::VarDeclTarget::Name(name) => {
263 let ty = self.lower_analyzer_type(self.analyzer_body.var_types[&var.id]);
264 let value = self.declare_var(name, ty, var.into());
265 if let Some(init) = init {
266 let (init, _init_ty) = self.lower_expr(init);
267 self.builder.map_result(init, value.into());
271 }
272 }
273
274 ast::VarDeclTarget::Tuple(decls) => {
275 if let Some(init) = init {
276 if let ast::Expr::Tuple { elts } = &init.kind {
277 debug_assert_eq!(decls.len(), elts.len());
278 for (decl, init_elem) in decls.iter().zip(elts.iter()) {
279 self.lower_var_decl(decl, Some(init_elem), source.clone());
280 }
281 } else {
282 let init_ty = self.expr_ty(init);
283 let init_value = self.lower_expr_to_value(init);
284 self.lower_var_decl_unpack(var, init_value, init_ty, source);
285 };
286 } else {
287 for decl in decls {
288 self.lower_var_decl(decl, None, source.clone())
289 }
290 }
291 }
292 }
293 }
294
295 pub(super) fn declare_var(
296 &mut self,
297 name: &SmolStr,
298 ty: TypeId,
299 source: SourceInfo,
300 ) -> ValueId {
301 let local = Local::user_local(name.clone(), ty, source);
302 let value = self.builder.declare(local);
303 self.scope_mut().declare_var(name, value);
304 value
305 }
306
307 pub(super) fn lower_var_decl_unpack(
308 &mut self,
309 var: &Node<ast::VarDeclTarget>,
310 init: ValueId,
311 init_ty: TypeId,
312 source: SourceInfo,
313 ) {
314 match &var.kind {
315 ast::VarDeclTarget::Name(name) => {
316 let ty = self.lower_analyzer_type(self.analyzer_body.var_types[&var.id]);
317 let local = Local::user_local(name.clone(), ty, var.into());
318
319 let lhs = self.builder.declare(local);
320 self.scope_mut().declare_var(name, lhs);
321 let bind = self.builder.bind(init, source);
322 self.builder.map_result(bind, lhs.into());
323 }
324
325 ast::VarDeclTarget::Tuple(decls) => {
326 for (index, decl) in decls.iter().enumerate() {
327 let elem_ty = init_ty.projection_ty_imm(self.db, index);
328 let index_value = self.make_u256_imm(index);
329 let elem_inst =
330 self.builder
331 .aggregate_access(init, vec![index_value], source.clone());
332 let elem_value = self.map_to_tmp(elem_inst, elem_ty);
333 self.lower_var_decl_unpack(decl, elem_value, elem_ty, source.clone())
334 }
335 }
336 }
337 }
338
339 pub(super) fn lower_expr(&mut self, expr: &Node<ast::Expr>) -> (InstId, TypeId) {
340 let mut ty = self.expr_ty(expr);
341 let mut inst = match &expr.kind {
342 ast::Expr::Ternary {
343 if_expr,
344 test,
345 else_expr,
346 } => {
347 let true_bb = self.builder.make_block();
348 let false_bb = self.builder.make_block();
349 let merge_bb = self.builder.make_block();
350
351 let tmp = self
352 .builder
353 .declare(Local::tmp_local("$ternary_tmp".into(), ty));
354
355 let cond = self.lower_expr_to_value(test);
356 self.builder
357 .branch(cond, true_bb, false_bb, SourceInfo::dummy());
358
359 self.builder.move_to_block(true_bb);
360 let (value, _) = self.lower_expr(if_expr);
361 self.builder.map_result(value, tmp.into());
362 self.builder.jump(merge_bb, SourceInfo::dummy());
363
364 self.builder.move_to_block(false_bb);
365 let (value, _) = self.lower_expr(else_expr);
366 self.builder.map_result(value, tmp.into());
367 self.builder.jump(merge_bb, SourceInfo::dummy());
368
369 self.builder.move_to_block(merge_bb);
370 self.builder.bind(tmp, SourceInfo::dummy())
371 }
372
373 ast::Expr::BoolOperation { left, op, right } => {
374 self.lower_bool_op(op.kind, left, right, ty)
375 }
376
377 ast::Expr::BinOperation { left, op, right } => {
378 let lhs = self.lower_expr_to_value(left);
379 let rhs = self.lower_expr_to_value(right);
380 self.lower_binop(op.kind, lhs, rhs, expr.into())
381 }
382
383 ast::Expr::UnaryOperation { op, operand } => {
384 let value = self.lower_expr_to_value(operand);
385 match op.kind {
386 ast::UnaryOperator::Invert => self.builder.inv(value, expr.into()),
387 ast::UnaryOperator::Not => self.builder.not(value, expr.into()),
388 ast::UnaryOperator::USub => self.builder.neg(value, expr.into()),
389 }
390 }
391
392 ast::Expr::CompOperation { left, op, right } => {
393 let lhs = self.lower_expr_to_value(left);
394 let rhs = self.lower_expr_to_value(right);
395 self.lower_comp_op(op.kind, lhs, rhs, expr.into())
396 }
397
398 ast::Expr::Attribute { .. } => {
399 let mut indices = vec![];
400 let value = self.lower_aggregate_access(expr, &mut indices);
401 self.builder.aggregate_access(value, indices, expr.into())
402 }
403
404 ast::Expr::Subscript { value, index } => {
405 let value_ty = self.expr_ty(value).deref(self.db);
406 if value_ty.is_aggregate(self.db) {
407 let mut indices = vec![];
408 let value = self.lower_aggregate_access(expr, &mut indices);
409 self.builder.aggregate_access(value, indices, expr.into())
410 } else if value_ty.is_map(self.db) {
411 let value = self.lower_expr_to_value(value);
412 let key = self.lower_expr_to_value(index);
413 self.builder.map_access(value, key, expr.into())
414 } else {
415 unreachable!()
416 }
417 }
418
419 ast::Expr::Call {
420 func,
421 generic_args,
422 args,
423 } => {
424 let ty = self.expr_ty(expr);
425 self.lower_call(func, generic_args, &args.kind, ty, expr.into())
426 }
427
428 ast::Expr::List { elts } | ast::Expr::Tuple { elts } => {
429 let args = elts
430 .iter()
431 .map(|elem| self.lower_expr_to_value(elem))
432 .collect();
433 let ty = self.expr_ty(expr);
434 self.builder.aggregate_construct(ty, args, expr.into())
435 }
436
437 ast::Expr::Repeat { value, len: _ } => {
438 let array_type = if let Type::Array(array_type) = self.analyzer_body.expressions
439 [&expr.id]
440 .typ
441 .typ(self.db.upcast())
442 {
443 array_type
444 } else {
445 panic!("not an array");
446 };
447
448 let args = vec![self.lower_expr_to_value(value); array_type.size];
449 let ty = self.expr_ty(expr);
450 self.builder.aggregate_construct(ty, args, expr.into())
451 }
452
453 ast::Expr::Bool(b) => {
454 let imm = self.builder.make_imm_from_bool(*b, ty);
455 self.builder.bind(imm, expr.into())
456 }
457
458 ast::Expr::Name(name) => {
459 let value = self.resolve_name(name);
460 self.builder.bind(value, expr.into())
461 }
462
463 ast::Expr::Path(path) => {
464 let value = self.resolve_path(path, expr.into());
465 self.builder.bind(value, expr.into())
466 }
467
468 ast::Expr::Num(num) => {
469 let imm = Literal::new(num).parse().unwrap();
470 let imm = self.builder.make_imm(imm, ty);
471 self.builder.bind(imm, expr.into())
472 }
473
474 ast::Expr::Str(s) => {
475 let ty = self.expr_ty(expr);
476 let const_value = self.make_local_constant(
477 "str_in_func".into(),
478 ty,
479 ConstantValue::Str(s.clone()),
480 expr.into(),
481 );
482 self.builder.bind(const_value, expr.into())
483 }
484
485 ast::Expr::Unit => {
486 let value = self.make_unit();
487 self.builder.bind(value, expr.into())
488 }
489 };
490
491 for Adjustment { into, kind } in &self.analyzer_body.expressions[&expr.id].type_adjustments
492 {
493 let into_ty = self.lower_analyzer_type(*into);
494
495 match kind {
496 AdjustmentKind::Copy => {
497 let val = self.inst_result_or_tmp(inst, ty);
498 inst = self.builder.mem_copy(val, expr.into());
499 }
500 AdjustmentKind::Load => {
501 let val = self.inst_result_or_tmp(inst, ty);
502 inst = self.builder.load(val, expr.into());
503 }
504 AdjustmentKind::IntSizeIncrease => {
505 let val = self.inst_result_or_tmp(inst, ty);
506 inst = self.builder.primitive_cast(val, into_ty, expr.into())
507 }
508 AdjustmentKind::StringSizeIncrease => {} }
510 ty = into_ty;
511 }
512 (inst, ty)
513 }
514
515 fn inst_result_or_tmp(&mut self, inst: InstId, ty: TypeId) -> ValueId {
516 self.builder
517 .inst_result(inst)
518 .and_then(|r| r.value_id())
519 .unwrap_or_else(|| self.map_to_tmp(inst, ty))
520 }
521
522 pub(super) fn lower_expr_to_value(&mut self, expr: &Node<ast::Expr>) -> ValueId {
523 let (inst, ty) = self.lower_expr(expr);
524 self.map_to_tmp(inst, ty)
525 }
526
527 pub(super) fn enter_scope(&mut self) {
528 let new_scope = Scope::with_parent(self.current_scope);
529 self.current_scope = self.scopes.alloc(new_scope);
530 }
531
532 pub(super) fn leave_scope(&mut self) {
533 self.current_scope = self.scopes[self.current_scope].parent.unwrap();
534 }
535
536 pub(super) fn make_imm(&mut self, imm: impl Into<BigInt>, ty: TypeId) -> ValueId {
537 self.builder.make_value(Value::Immediate {
538 imm: imm.into(),
539 ty,
540 })
541 }
542
543 pub(super) fn make_u256_imm(&mut self, value: impl Into<BigInt>) -> ValueId {
544 let u256_ty = self.u256_ty();
545 self.make_imm(value, u256_ty)
546 }
547
548 pub(super) fn map_to_tmp(&mut self, inst: InstId, ty: TypeId) -> ValueId {
549 match &self.builder.inst_data(inst).kind {
550 InstKind::Bind { src } => {
551 let value = *src;
552 self.builder.remove_inst(inst);
553 value
554 }
555 _ => {
556 let tmp = Value::Temporary { inst, ty };
557 let result = self.builder.make_value(tmp);
558 self.builder.map_result(inst, result.into());
559 result
560 }
561 }
562 }
563
564 fn new(
565 db: &'db dyn MirDb,
566 func: FunctionId,
567 ast: &'a Node<ast::Function>,
568 analyzer_body: &'a fe_analyzer::context::FunctionBody,
569 ) -> Self {
570 let mut builder = BodyBuilder::new(func, ast.into());
571 let mut scopes = Arena::new();
572
573 let root = Scope::root(db, func, &mut builder);
576 let current_scope = scopes.alloc(root);
577 Self {
578 db,
579 builder,
580 ast,
581 func,
582 analyzer_body,
583 scopes,
584 current_scope,
585 }
586 }
587
588 fn lower_analyzer_type(&self, analyzer_ty: analyzer_types::TypeId) -> TypeId {
589 if let analyzer_types::Type::Generic(generic) = analyzer_ty.deref_typ(self.db.upcast()) {
592 let resolved_type = self
593 .func
594 .signature(self.db)
595 .resolved_generics
596 .get(&generic.name)
597 .cloned()
598 .expect("expected generic to be resolved");
599
600 return self.db.mir_lowered_type(resolved_type);
601 }
602
603 self.db.mir_lowered_type(analyzer_ty)
604 }
605
606 fn lower(mut self) -> FunctionBody {
607 for stmt in &self.ast.kind.body {
608 self.lower_stmt(stmt)
609 }
610
611 let last_block = self.builder.current_block();
612 if !self.builder.is_block_terminated(last_block) {
613 let unit = self.make_unit();
614 self.builder.ret(unit, SourceInfo::dummy());
615 }
616
617 self.builder.build()
618 }
619
620 fn branch_eq(
621 &mut self,
622 v1: ValueId,
623 v2: ValueId,
624 true_bb: BasicBlockId,
625 false_bb: BasicBlockId,
626 source: SourceInfo,
627 ) {
628 let cond = self.builder.eq(v1, v2, source.clone());
629 let bool_ty = self.bool_ty();
630 let cond = self.map_to_tmp(cond, bool_ty);
631 self.builder.branch(cond, true_bb, false_bb, source);
632 }
633
634 fn lower_if(
635 &mut self,
636 cond: &Node<ast::Expr>,
637 then: &[Node<ast::FuncStmt>],
638 else_: &[Node<ast::FuncStmt>],
639 ) {
640 let cond = self.lower_expr_to_value(cond);
641
642 if else_.is_empty() {
643 let then_bb = self.builder.make_block();
644 let merge_bb = self.builder.make_block();
645
646 self.builder
647 .branch(cond, then_bb, merge_bb, SourceInfo::dummy());
648
649 self.builder.move_to_block(then_bb);
651 self.enter_scope();
652 for stmt in then {
653 self.lower_stmt(stmt);
654 }
655 self.builder.jump(merge_bb, SourceInfo::dummy());
656 self.builder.move_to_block(merge_bb);
657 self.leave_scope();
658 } else {
659 let then_bb = self.builder.make_block();
660 let else_bb = self.builder.make_block();
661
662 self.builder
663 .branch(cond, then_bb, else_bb, SourceInfo::dummy());
664
665 self.builder.move_to_block(then_bb);
667 self.enter_scope();
668 for stmt in then {
669 self.lower_stmt(stmt);
670 }
671 self.leave_scope();
672 let then_block_end_bb = self.builder.current_block();
673
674 self.builder.move_to_block(else_bb);
676 self.enter_scope();
677 for stmt in else_ {
678 self.lower_stmt(stmt);
679 }
680 self.leave_scope();
681 let else_block_end_bb = self.builder.current_block();
682
683 let merge_bb = self.builder.make_block();
684 if !self.builder.is_block_terminated(then_block_end_bb) {
685 self.builder.move_to_block(then_block_end_bb);
686 self.builder.jump(merge_bb, SourceInfo::dummy());
687 }
688 if !self.builder.is_block_terminated(else_block_end_bb) {
689 self.builder.move_to_block(else_block_end_bb);
690 self.builder.jump(merge_bb, SourceInfo::dummy());
691 }
692 self.builder.move_to_block(merge_bb);
693 }
694 }
695
696 fn lower_for_loop(
699 &mut self,
700 loop_variable: &Node<SmolStr>,
701 iter: &Node<ast::Expr>,
702 body: &[Node<ast::FuncStmt>],
703 ) {
704 let preheader_bb = self.builder.make_block();
705 let entry_bb = self.builder.make_block();
706 let exit_bb = self.builder.make_block();
707
708 let iter_elem_ty = self.analyzer_body.var_types[&loop_variable.id];
709 let iter_elem_ty = self.lower_analyzer_type(iter_elem_ty);
710
711 self.builder.jump(preheader_bb, SourceInfo::dummy());
712
713 self.enter_loop_scope(entry_bb, exit_bb);
715
716 self.builder.move_to_block(preheader_bb);
718
719 let loop_value = self.builder.declare(Local::user_local(
721 loop_variable.kind.clone(),
722 iter_elem_ty,
723 loop_variable.into(),
724 ));
725 self.scope_mut()
726 .declare_var(&loop_variable.kind, loop_value);
727
728 let loop_idx = Local::tmp_local("$loop_idx_tmp".into(), self.u256_ty());
730 let loop_idx = self.builder.declare(loop_idx);
731 let imm_zero = self.make_u256_imm(0u32);
732 let imm_zero = self.builder.bind(imm_zero, SourceInfo::dummy());
733 self.builder.map_result(imm_zero, loop_idx.into());
734
735 let iter_ty = self.expr_ty(iter);
737 let iter = self.lower_expr_to_value(iter);
738
739 let maximum_iter_count = match &iter_ty.deref(self.db).data(self.db).kind {
741 ir::TypeKind::Array(ir::types::ArrayDef { len, .. }) => *len,
742 _ => unreachable!(),
743 };
744 let maximum_iter_count = self.make_u256_imm(maximum_iter_count);
745 self.branch_eq(
746 loop_idx,
747 maximum_iter_count,
748 exit_bb,
749 entry_bb,
750 SourceInfo::dummy(),
751 );
752 self.scope_mut().loop_idx = Some(loop_idx);
753 self.scope_mut().maximum_iter_count = Some(maximum_iter_count);
754
755 self.builder.move_to_block(entry_bb);
757
758 let iter_elem = self
760 .builder
761 .aggregate_access(iter, vec![loop_idx], SourceInfo::dummy());
762 self.builder
763 .map_result(iter_elem, AssignableValue::Value(loop_value));
764
765 for stmt in body {
766 self.lower_stmt(stmt);
767 }
768
769 let imm_one = self.make_u256_imm(1u32);
771 let inc = self.builder.add(loop_idx, imm_one, SourceInfo::dummy());
772 self.builder
773 .map_result(inc, AssignableValue::Value(loop_idx));
774 self.branch_eq(
775 loop_idx,
776 maximum_iter_count,
777 exit_bb,
778 entry_bb,
779 SourceInfo::dummy(),
780 );
781
782 self.leave_scope();
784 self.builder.move_to_block(exit_bb);
785 }
786
787 fn lower_assignable_value(&mut self, expr: &Node<ast::Expr>) -> AssignableValue {
788 match &expr.kind {
789 ast::Expr::Attribute { value, attr } => {
790 let idx = self.expr_ty(value).index_from_fname(self.db, &attr.kind);
791 let idx = self.make_u256_imm(idx);
792 let lhs = self.lower_assignable_value(value).into();
793 AssignableValue::Aggregate { lhs, idx }
794 }
795 ast::Expr::Subscript { value, index } => {
796 let lhs = self.lower_assignable_value(value).into();
797 let attr = self.lower_expr_to_value(index);
798 let value_ty = self.expr_ty(value).deref(self.db);
799 if value_ty.is_aggregate(self.db) {
800 AssignableValue::Aggregate { lhs, idx: attr }
801 } else if value_ty.is_map(self.db) {
802 AssignableValue::Map { lhs, key: attr }
803 } else {
804 unreachable!()
805 }
806 }
807 ast::Expr::Name(name) => self.resolve_name(name).into(),
808 ast::Expr::Path(path) => self.resolve_path(path, expr.into()).into(),
809 _ => self.lower_expr_to_value(expr).into(),
810 }
811 }
812
813 fn expr_ty(&self, expr: &Node<ast::Expr>) -> TypeId {
815 let analyzer_ty = self.analyzer_body.expressions[&expr.id].typ;
816 self.lower_analyzer_type(analyzer_ty)
817 }
818
819 fn lower_bool_op(
820 &mut self,
821 op: ast::BoolOperator,
822 lhs: &Node<ast::Expr>,
823 rhs: &Node<ast::Expr>,
824 ty: TypeId,
825 ) -> InstId {
826 let true_bb = self.builder.make_block();
827 let false_bb = self.builder.make_block();
828 let merge_bb = self.builder.make_block();
829
830 let lhs = self.lower_expr_to_value(lhs);
831 let tmp = self
832 .builder
833 .declare(Local::tmp_local(format!("${op}_tmp").into(), ty));
834
835 match op {
836 ast::BoolOperator::And => {
837 self.builder
838 .branch(lhs, true_bb, false_bb, SourceInfo::dummy());
839
840 self.builder.move_to_block(true_bb);
841 let (rhs, _rhs_ty) = self.lower_expr(rhs);
842 self.builder.map_result(rhs, tmp.into());
843 self.builder.jump(merge_bb, SourceInfo::dummy());
844
845 self.builder.move_to_block(false_bb);
846 let false_imm = self.builder.make_imm_from_bool(false, ty);
847 let false_imm_copy = self.builder.bind(false_imm, SourceInfo::dummy());
848 self.builder.map_result(false_imm_copy, tmp.into());
849 self.builder.jump(merge_bb, SourceInfo::dummy());
850 }
851
852 ast::BoolOperator::Or => {
853 self.builder
854 .branch(lhs, true_bb, false_bb, SourceInfo::dummy());
855
856 self.builder.move_to_block(true_bb);
857 let true_imm = self.builder.make_imm_from_bool(true, ty);
858 let true_imm_copy = self.builder.bind(true_imm, SourceInfo::dummy());
859 self.builder.map_result(true_imm_copy, tmp.into());
860 self.builder.jump(merge_bb, SourceInfo::dummy());
861
862 self.builder.move_to_block(false_bb);
863 let (rhs, _rhs_ty) = self.lower_expr(rhs);
864 self.builder.map_result(rhs, tmp.into());
865 self.builder.jump(merge_bb, SourceInfo::dummy());
866 }
867 }
868
869 self.builder.move_to_block(merge_bb);
870 self.builder.bind(tmp, SourceInfo::dummy())
871 }
872
873 fn lower_binop(
874 &mut self,
875 op: ast::BinOperator,
876 lhs: ValueId,
877 rhs: ValueId,
878 source: SourceInfo,
879 ) -> InstId {
880 match op {
881 ast::BinOperator::Add => self.builder.add(lhs, rhs, source),
882 ast::BinOperator::Sub => self.builder.sub(lhs, rhs, source),
883 ast::BinOperator::Mult => self.builder.mul(lhs, rhs, source),
884 ast::BinOperator::Div => self.builder.div(lhs, rhs, source),
885 ast::BinOperator::Mod => self.builder.modulo(lhs, rhs, source),
886 ast::BinOperator::Pow => self.builder.pow(lhs, rhs, source),
887 ast::BinOperator::LShift => self.builder.shl(lhs, rhs, source),
888 ast::BinOperator::RShift => self.builder.shr(lhs, rhs, source),
889 ast::BinOperator::BitOr => self.builder.bit_or(lhs, rhs, source),
890 ast::BinOperator::BitXor => self.builder.bit_xor(lhs, rhs, source),
891 ast::BinOperator::BitAnd => self.builder.bit_and(lhs, rhs, source),
892 }
893 }
894
895 fn lower_comp_op(
896 &mut self,
897 op: ast::CompOperator,
898 lhs: ValueId,
899 rhs: ValueId,
900 source: SourceInfo,
901 ) -> InstId {
902 match op {
903 ast::CompOperator::Eq => self.builder.eq(lhs, rhs, source),
904 ast::CompOperator::NotEq => self.builder.ne(lhs, rhs, source),
905 ast::CompOperator::Lt => self.builder.lt(lhs, rhs, source),
906 ast::CompOperator::LtE => self.builder.le(lhs, rhs, source),
907 ast::CompOperator::Gt => self.builder.gt(lhs, rhs, source),
908 ast::CompOperator::GtE => self.builder.ge(lhs, rhs, source),
909 }
910 }
911
912 fn resolve_generics_args(
913 &mut self,
914 method: &analyzer_items::FunctionId,
915 args: &[Id<Value>],
916 ) -> BTreeMap<SmolStr, analyzer_types::TypeId> {
917 method
918 .signature(self.db.upcast())
919 .params
920 .iter()
921 .zip(args.iter().map(|val| {
922 self.builder
923 .value_ty(*val)
924 .analyzer_ty(self.db)
925 .expect("invalid parameter")
926 }))
927 .filter_map(|(param, typ)| {
928 if let Type::Generic(generic) =
929 param.typ.clone().unwrap().deref_typ(self.db.upcast())
930 {
931 Some((generic.name, typ))
932 } else {
933 None
934 }
935 })
936 .collect::<BTreeMap<_, _>>()
937 }
938
939 fn lower_function_id(
940 &mut self,
941 function: &analyzer_items::FunctionId,
942 args: &[Id<Value>],
943 ) -> FunctionId {
944 let resolved_generics = self.resolve_generics_args(function, args);
945 if function.is_generic(self.db.upcast()) {
946 self.db
947 .mir_lowered_monomorphized_func_signature(*function, resolved_generics)
948 } else {
949 self.db.mir_lowered_func_signature(*function)
950 }
951 }
952
953 fn lower_call(
954 &mut self,
955 func: &Node<ast::Expr>,
956 _generic_args: &Option<Node<Vec<ast::GenericArg>>>,
957 args: &[Node<ast::CallArg>],
958 ty: TypeId,
959 source: SourceInfo,
960 ) -> InstId {
961 let call_type = &self.analyzer_body.calls[&func.id];
962
963 let mut args: Vec<_> = args
964 .iter()
965 .map(|arg| self.lower_expr_to_value(&arg.kind.value))
966 .collect();
967
968 match call_type {
969 AnalyzerCallType::BuiltinFunction(GlobalFunction::Keccak256) => {
970 self.builder.keccak256(args[0], source)
971 }
972
973 AnalyzerCallType::Intrinsic(intrinsic) => {
974 self.builder
975 .yul_intrinsic((*intrinsic).into(), args, source)
976 }
977
978 AnalyzerCallType::BuiltinValueMethod { method, .. } => {
979 let arg = self.lower_method_receiver(func);
980 match method {
981 ValueMethod::ToMem => self.builder.mem_copy(arg, source),
982 ValueMethod::AbiEncode => self.builder.abi_encode(arg, source),
983 }
984 }
985
986 AnalyzerCallType::BuiltinAssociatedFunction { contract, function } => match function {
988 ContractTypeMethod::Create => self.builder.create(args[1], *contract, source),
989 ContractTypeMethod::Create2 => {
990 self.builder.create2(args[1], args[2], *contract, source)
991 }
992 },
993
994 AnalyzerCallType::AssociatedFunction { function, .. }
995 | AnalyzerCallType::Pure(function) => {
996 let func_id = self.lower_function_id(function, &args);
997 self.builder.call(func_id, args, CallType::Internal, source)
998 }
999
1000 AnalyzerCallType::ValueMethod { method, .. } => {
1001 let mut method_args = vec![self.lower_method_receiver(func)];
1002 let func_id = self.lower_function_id(method, &args);
1003
1004 method_args.append(&mut args);
1005
1006 self.builder
1007 .call(func_id, method_args, CallType::Internal, source)
1008 }
1009 AnalyzerCallType::TraitValueMethod {
1010 trait_id, method, ..
1011 } if trait_id.is_std_trait(self.db.upcast(), EMITTABLE_TRAIT_NAME)
1012 && method.name(self.db.upcast()) == EMIT_FN_NAME =>
1013 {
1014 let event = self.lower_method_receiver(func);
1015 self.builder.emit(event, source)
1016 }
1017 AnalyzerCallType::TraitValueMethod {
1018 method,
1019 trait_id,
1020 generic_type,
1021 ..
1022 } => {
1023 let mut method_args = vec![self.lower_method_receiver(func)];
1024 method_args.append(&mut args);
1025
1026 let concrete_type = self
1027 .func
1028 .signature(self.db)
1029 .resolved_generics
1030 .get(&generic_type.name)
1031 .cloned()
1032 .expect("unresolved generic type");
1033
1034 let impl_ = concrete_type
1035 .get_impl_for(self.db.upcast(), *trait_id)
1036 .expect("missing impl");
1037
1038 let function = impl_
1039 .function(self.db.upcast(), &method.name(self.db.upcast()))
1040 .expect("missing function");
1041
1042 let func_id = self.db.mir_lowered_func_signature(function);
1043 self.builder
1044 .call(func_id, method_args, CallType::Internal, source)
1045 }
1046 AnalyzerCallType::External { function, .. } => {
1047 let receiver = self.lower_method_receiver(func);
1048 debug_assert!(self.builder.value_ty(receiver).is_address(self.db));
1049
1050 let mut method_args = vec![receiver];
1051 method_args.append(&mut args);
1052 let func_id = self.db.mir_lowered_func_signature(*function);
1053 self.builder
1054 .call(func_id, method_args, CallType::External, source)
1055 }
1056
1057 AnalyzerCallType::TypeConstructor(to_ty) => {
1058 if to_ty.is_string(self.db.upcast()) {
1059 let arg = *args.last().unwrap();
1060 self.builder.mem_copy(arg, source)
1061 } else if ty.is_primitive(self.db) {
1062 let arg = *args.last().unwrap();
1064 let arg_ty = self.builder.value_ty(arg);
1065 if arg_ty == ty {
1066 self.builder.bind(arg, source)
1067 } else {
1068 debug_assert!(!arg_ty.is_ptr(self.db)); self.builder.primitive_cast(arg, ty, source)
1070 }
1071 } else if ty.is_aggregate(self.db) {
1072 self.builder.aggregate_construct(ty, args, source)
1073 } else {
1074 unreachable!()
1075 }
1076 }
1077
1078 AnalyzerCallType::EnumConstructor(variant) => {
1079 let tag_type = ty.enum_disc_type(self.db);
1080 let tag = self.make_imm(variant.disc(self.db.upcast()), tag_type);
1081 let data_ty = ty.enum_variant_type(self.db, *variant);
1082 let enum_args = if data_ty.is_unit(self.db) {
1083 vec![tag, self.make_unit()]
1084 } else {
1085 std::iter::once(tag).chain(args).collect()
1086 };
1087 self.builder.aggregate_construct(ty, enum_args, source)
1088 }
1089 }
1090 }
1091
1092 fn lower_method_receiver(&mut self, receiver: &Node<ast::Expr>) -> ValueId {
1094 match &receiver.kind {
1095 ast::Expr::Attribute { value, .. } => self.lower_expr_to_value(value),
1096 _ => unreachable!(),
1097 }
1098 }
1099
1100 fn lower_aggregate_access(
1101 &mut self,
1102 expr: &Node<ast::Expr>,
1103 indices: &mut Vec<ValueId>,
1104 ) -> ValueId {
1105 match &expr.kind {
1106 ast::Expr::Attribute { value, attr } => {
1107 let index = self.expr_ty(value).index_from_fname(self.db, &attr.kind);
1108 let value = self.lower_aggregate_access(value, indices);
1109 indices.push(self.make_u256_imm(index));
1110 value
1111 }
1112
1113 ast::Expr::Subscript { value, index }
1114 if self.expr_ty(value).deref(self.db).is_aggregate(self.db) =>
1115 {
1116 let value = self.lower_aggregate_access(value, indices);
1117 indices.push(self.lower_expr_to_value(index));
1118 value
1119 }
1120
1121 _ => self.lower_expr_to_value(expr),
1122 }
1123 }
1124
1125 fn make_unit(&mut self) -> ValueId {
1126 let unit_ty = analyzer_types::TypeId::unit(self.db.upcast());
1127 let unit_ty = self.db.mir_lowered_type(unit_ty);
1128 self.builder.make_unit(unit_ty)
1129 }
1130
1131 fn make_local_constant(
1132 &mut self,
1133 name: SmolStr,
1134 ty: TypeId,
1135 value: ConstantValue,
1136 source: SourceInfo,
1137 ) -> ValueId {
1138 let function_id = self.builder.func_id();
1139 let constant = Constant {
1140 name,
1141 value,
1142 ty,
1143 module_id: function_id.module(self.db),
1144 source,
1145 };
1146
1147 let constant_id = self.db.mir_intern_const(constant.into());
1148 self.builder.make_constant(constant_id, ty)
1149 }
1150
1151 fn u256_ty(&mut self) -> TypeId {
1152 self.db
1153 .mir_intern_type(ir::Type::new(ir::TypeKind::U256, None).into())
1154 }
1155
1156 fn bool_ty(&mut self) -> TypeId {
1157 self.db
1158 .mir_intern_type(ir::Type::new(ir::TypeKind::Bool, None).into())
1159 }
1160
1161 fn enter_loop_scope(&mut self, entry: BasicBlockId, exit: BasicBlockId) {
1162 let new_scope = Scope::loop_scope(self.current_scope, entry, exit);
1163 self.current_scope = self.scopes.alloc(new_scope);
1164 }
1165
1166 fn resolve_name(&mut self, name: &str) -> ValueId {
1169 if let Some(value) = self.scopes[self.current_scope].resolve_name(&self.scopes, name) {
1170 value
1172 } else {
1173 let func_id = self.builder.func_id();
1175 let module = func_id.module(self.db);
1176 let constant = match module
1177 .resolve_name(self.db.upcast(), name)
1178 .unwrap()
1179 .unwrap()
1180 {
1181 NamedThing::Item(analyzer_items::Item::Constant(id)) => {
1182 self.db.mir_lowered_constant(id)
1183 }
1184 _ => panic!("name defined in global must be constant"),
1185 };
1186 let ty = constant.ty(self.db);
1187 self.builder.make_constant(constant, ty)
1188 }
1189 }
1190
1191 fn resolve_path(&mut self, path: &ast::Path, source: SourceInfo) -> ValueId {
1194 let func_id = self.builder.func_id();
1195 let module = func_id.module(self.db);
1196 match module.resolve_path(self.db.upcast(), path).value.unwrap() {
1197 NamedThing::Item(analyzer_items::Item::Constant(id)) => {
1198 let constant = self.db.mir_lowered_constant(id);
1199 let ty = constant.ty(self.db);
1200 self.builder.make_constant(constant, ty)
1201 }
1202 NamedThing::EnumVariant(variant) => {
1203 let enum_ty = self
1204 .db
1205 .mir_lowered_type(variant.parent(self.db.upcast()).as_type(self.db.upcast()));
1206 let tag_type = enum_ty.enum_disc_type(self.db);
1207 let tag = self.make_imm(variant.disc(self.db.upcast()), tag_type);
1208 let data = self.make_unit();
1209 let enum_args = vec![tag, data];
1210 let inst = self.builder.aggregate_construct(enum_ty, enum_args, source);
1211 self.map_to_tmp(inst, enum_ty)
1212 }
1213 _ => panic!("path defined in global must be constant"),
1214 }
1215 }
1216
1217 fn scope(&self) -> &Scope {
1218 &self.scopes[self.current_scope]
1219 }
1220
1221 fn scope_mut(&mut self) -> &mut Scope {
1222 &mut self.scopes[self.current_scope]
1223 }
1224}
1225
1226#[derive(Debug)]
1227struct Scope {
1228 parent: Option<ScopeId>,
1229 loop_entry: Option<BasicBlockId>,
1230 loop_exit: Option<BasicBlockId>,
1231 variables: FxHashMap<SmolStr, ValueId>,
1232 loop_idx: Option<ValueId>,
1234 maximum_iter_count: Option<ValueId>,
1235}
1236
1237impl Scope {
1238 fn root(db: &dyn MirDb, func: FunctionId, builder: &mut BodyBuilder) -> Self {
1239 let mut root = Self {
1240 parent: None,
1241 loop_entry: None,
1242 loop_exit: None,
1243 variables: FxHashMap::default(),
1244 loop_idx: None,
1245 maximum_iter_count: None,
1246 };
1247
1248 for param in &func.signature(db).params {
1250 let local = Local::arg_local(param.name.clone(), param.ty, param.source.clone());
1251 let value_id = builder.store_func_arg(local);
1252 root.declare_var(¶m.name, value_id)
1253 }
1254
1255 root
1256 }
1257
1258 fn with_parent(parent: ScopeId) -> Self {
1259 Self {
1260 parent: parent.into(),
1261 loop_entry: None,
1262 loop_exit: None,
1263 variables: FxHashMap::default(),
1264 loop_idx: None,
1265 maximum_iter_count: None,
1266 }
1267 }
1268
1269 fn loop_scope(parent: ScopeId, loop_entry: BasicBlockId, loop_exit: BasicBlockId) -> Self {
1270 Self {
1271 parent: parent.into(),
1272 loop_entry: loop_entry.into(),
1273 loop_exit: loop_exit.into(),
1274 variables: FxHashMap::default(),
1275 loop_idx: None,
1276 maximum_iter_count: None,
1277 }
1278 }
1279
1280 fn loop_entry(&self, scopes: &Arena<Scope>) -> BasicBlockId {
1281 match self.loop_entry {
1282 Some(entry) => entry,
1283 None => scopes[self.parent.unwrap()].loop_entry(scopes),
1284 }
1285 }
1286
1287 fn loop_exit(&self, scopes: &Arena<Scope>) -> BasicBlockId {
1288 match self.loop_exit {
1289 Some(exit) => exit,
1290 None => scopes[self.parent.unwrap()].loop_exit(scopes),
1291 }
1292 }
1293
1294 fn loop_idx(&self, scopes: &Arena<Scope>) -> Option<ValueId> {
1295 match self.loop_idx {
1296 Some(idx) => Some(idx),
1297 None => scopes[self.parent?].loop_idx(scopes),
1298 }
1299 }
1300
1301 fn maximum_iter_count(&self, scopes: &Arena<Scope>) -> Option<ValueId> {
1302 match self.maximum_iter_count {
1303 Some(count) => Some(count),
1304 None => scopes[self.parent?].maximum_iter_count(scopes),
1305 }
1306 }
1307
1308 fn declare_var(&mut self, name: &SmolStr, value: ValueId) {
1309 debug_assert!(!self.variables.contains_key(name));
1310
1311 self.variables.insert(name.clone(), value);
1312 }
1313
1314 fn resolve_name(&self, scopes: &Arena<Scope>, name: &str) -> Option<ValueId> {
1315 match self.variables.get(name) {
1316 Some(id) => Some(*id),
1317 None => scopes[self.parent?].resolve_name(scopes, name),
1318 }
1319 }
1320}
1321
1322fn self_arg_source(db: &dyn MirDb, func: analyzer_items::FunctionId) -> SourceInfo {
1323 func.data(db.upcast())
1324 .ast
1325 .kind
1326 .sig
1327 .kind
1328 .args
1329 .iter()
1330 .find(|arg| matches!(arg.kind, ast::FunctionArg::Self_ { .. }))
1331 .unwrap()
1332 .into()
1333}
1334
1335fn arg_source(db: &dyn MirDb, func: analyzer_items::FunctionId, arg_name: &str) -> SourceInfo {
1336 func.data(db.upcast())
1337 .ast
1338 .kind
1339 .sig
1340 .kind
1341 .args
1342 .iter()
1343 .find_map(|arg| match &arg.kind {
1344 ast::FunctionArg::Regular { name, .. } => {
1345 if name.kind == arg_name {
1346 Some(name.into())
1347 } else {
1348 None
1349 }
1350 }
1351 ast::FunctionArg::Self_ { .. } => None,
1352 })
1353 .unwrap()
1354}
1355
1356fn make_param(
1357 db: &dyn MirDb,
1358 name: impl Into<SmolStr>,
1359 ty: analyzer_types::TypeId,
1360 source: SourceInfo,
1361) -> FunctionParam {
1362 FunctionParam {
1363 name: name.into(),
1364 ty: db.mir_lowered_type(ty),
1365 source,
1366 }
1367}