fe_mir/db/queries/
function.rs

1use std::{collections::BTreeMap, rc::Rc};
2
3use fe_analyzer::display::Displayable;
4use fe_analyzer::namespace::items as analyzer_items;
5use fe_analyzer::namespace::items::Item;
6use fe_analyzer::namespace::types as analyzer_types;
7
8use smol_str::SmolStr;
9
10use crate::{
11    db::MirDb,
12    ir::{self, function::Linkage, FunctionSignature, TypeId},
13    lower::function::{lower_func_body, lower_func_signature, lower_monomorphized_func_signature},
14};
15
16pub fn mir_lowered_func_signature(
17    db: &dyn MirDb,
18    analyzer_func: analyzer_items::FunctionId,
19) -> ir::FunctionId {
20    lower_func_signature(db, analyzer_func)
21}
22
23pub fn mir_lowered_monomorphized_func_signature(
24    db: &dyn MirDb,
25    analyzer_func: analyzer_items::FunctionId,
26    resolved_generics: BTreeMap<SmolStr, analyzer_types::TypeId>,
27) -> ir::FunctionId {
28    lower_monomorphized_func_signature(db, analyzer_func, resolved_generics)
29}
30
31/// Generate MIR function and monomorphize generic parameters as if they were called with unit type
32/// NOTE: THIS SHOULD ONLY BE USED IN TEST CODE
33pub fn mir_lowered_pseudo_monomorphized_func_signature(
34    db: &dyn MirDb,
35    analyzer_func: analyzer_items::FunctionId,
36) -> ir::FunctionId {
37    let resolved_generics = analyzer_func
38        .sig(db.upcast())
39        .generic_params(db.upcast())
40        .iter()
41        .map(|generic| (generic.name(), analyzer_types::TypeId::unit(db.upcast())))
42        .collect::<BTreeMap<_, _>>();
43    lower_monomorphized_func_signature(db, analyzer_func, resolved_generics)
44}
45
46pub fn mir_lowered_func_body(db: &dyn MirDb, func: ir::FunctionId) -> Rc<ir::FunctionBody> {
47    lower_func_body(db, func)
48}
49
50impl ir::FunctionId {
51    pub fn signature(self, db: &dyn MirDb) -> Rc<FunctionSignature> {
52        db.lookup_mir_intern_function(self)
53    }
54
55    pub fn return_type(self, db: &dyn MirDb) -> Option<TypeId> {
56        self.signature(db).return_type
57    }
58
59    pub fn linkage(self, db: &dyn MirDb) -> Linkage {
60        self.signature(db).linkage
61    }
62
63    pub fn analyzer_func(self, db: &dyn MirDb) -> analyzer_items::FunctionId {
64        self.signature(db).analyzer_func_id
65    }
66
67    pub fn body(self, db: &dyn MirDb) -> Rc<ir::FunctionBody> {
68        db.mir_lowered_func_body(self)
69    }
70
71    pub fn module(self, db: &dyn MirDb) -> analyzer_items::ModuleId {
72        let analyzer_func = self.analyzer_func(db);
73        analyzer_func.module(db.upcast())
74    }
75
76    pub fn is_contract_init(self, db: &dyn MirDb) -> bool {
77        self.analyzer_func(db)
78            .data(db.upcast())
79            .sig
80            .is_constructor(db.upcast())
81    }
82
83    /// Returns a type suffix if a generic function was monomorphized
84    pub fn type_suffix(&self, db: &dyn MirDb) -> SmolStr {
85        self.signature(db)
86            .resolved_generics
87            .values()
88            .fold(String::new(), |acc, param| {
89                format!("{}_{}", acc, param.display(db.upcast()))
90            })
91            .into()
92    }
93
94    pub fn name(&self, db: &dyn MirDb) -> SmolStr {
95        let analyzer_func = self.analyzer_func(db);
96        analyzer_func.name(db.upcast())
97    }
98
99    /// Returns `class_name::fn_name` if a function is a method else `fn_name`.
100    pub fn debug_name(self, db: &dyn MirDb) -> SmolStr {
101        let analyzer_func = self.analyzer_func(db);
102        let func_name = format!(
103            "{}{}",
104            analyzer_func.name(db.upcast()),
105            self.type_suffix(db)
106        );
107
108        match analyzer_func.sig(db.upcast()).self_item(db.upcast()) {
109            Some(Item::Impl(id)) => {
110                let class_name = format!(
111                    "<{} as {}>",
112                    id.receiver(db.upcast()).display(db.upcast()),
113                    id.trait_id(db.upcast()).name(db.upcast())
114                );
115                format!("{class_name}::{func_name}").into()
116            }
117            Some(class) => {
118                let class_name = class.name(db.upcast());
119                format!("{class_name}::{func_name}").into()
120            }
121            _ => func_name.into(),
122        }
123    }
124
125    pub fn returns_aggregate(self, db: &dyn MirDb) -> bool {
126        self.return_type(db)
127            .map(|ty| ty.is_aggregate(db))
128            .unwrap_or_default()
129    }
130}