fe_mir/lower/
function.rs

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    // TODO: Remove this when an analyzer's function signature contains `self` type.
44    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, &param.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                // Lower while body.
167                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                // Move to while exit bb.
179                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                    // debug_assert_eq!(ty.deref(self.db), init_ty, "vardecl init type mismatch: {} != {}",
268                    //                  ty.as_string(self.db),
269                    //                  init_ty.as_string(self.db));
270                    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 => {} // XXX
509            }
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        // Make a root scope. A root scope collects function parameters and module
574        // constants.
575        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 the analyzer type is generic we first need to resolve it to its concrete
590        // type before lowering to a MIR type
591        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            // Lower then block.
650            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            // Lower then block.
666            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            // Lower else_block.
675            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    // NOTE: we assume a type of `iter` is array.
697    // TODO: Desugar to `loop` + `match` like rustc in HIR to generate better MIR.
698    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        // `For` has its scope from preheader block.
714        self.enter_loop_scope(entry_bb, exit_bb);
715
716        /* Lower preheader. */
717        self.builder.move_to_block(preheader_bb);
718
719        // Declare loop_variable.
720        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        // Declare and initialize `loop_idx` to 0.
729        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        // Evaluates loop variable.
736        let iter_ty = self.expr_ty(iter);
737        let iter = self.lower_expr_to_value(iter);
738
739        // Create maximum loop count.
740        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        /* Lower body. */
756        self.builder.move_to_block(entry_bb);
757
758        // loop_variable = array[loop_idx]
759        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        // loop_idx += 1
770        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        /* Move to exit bb */
783        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    /// Returns the pre-adjustment type of the given `Expr`
814    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            // We ignores `args[0]', which represents `context` and not used for now.
987            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                    // TODO: Ignore `ctx` for now.
1063                    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)); // Should be explicitly `Load`ed
1069                        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    // FIXME: This is ugly hack to properly analyze method call. Remove this when  https://github.com/ethereum/fe/issues/670 is resolved.
1093    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    /// Resolve a name appeared in an expression.
1167    /// NOTE: Don't call this to resolve method receiver.
1168    fn resolve_name(&mut self, name: &str) -> ValueId {
1169        if let Some(value) = self.scopes[self.current_scope].resolve_name(&self.scopes, name) {
1170            // Name is defined in local.
1171            value
1172        } else {
1173            // Name is defined in global.
1174            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    /// Resolve a path appeared in an expression.
1192    /// NOTE: Don't call this to resolve method receiver.
1193    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    // TODO: Remove the below two fields when `for` loop desugaring is implemented.
1233    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        // Declare function parameters.
1249        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(&param.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}