Skip to content

Commit

Permalink
Allow using a generic function which cross the ingot bound
Browse files Browse the repository at this point in the history
  • Loading branch information
Y-Nak committed Dec 7, 2022
1 parent 5fb3bd1 commit 56bcfd8
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 31 deletions.
4 changes: 4 additions & 0 deletions crates/analyzer/src/namespace/items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1211,6 +1211,10 @@ impl FunctionSigId {
self.data(db).module
}

pub fn ingot(&self, db: &dyn AnalyzerDb) -> IngotId {
self.module(db).ingot(db)
}

pub fn is_contract_func(self, db: &dyn AnalyzerDb) -> bool {
matches! {self.parent(db), Item::Type(TypeDef::Contract(_))}
}
Expand Down
72 changes: 52 additions & 20 deletions crates/codegen/src/db/queries/cgu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
//! function call. If generic function calls are found, monomorphizes them and
//! add them to the worklist.
//!
//! 4. Add the current function to the CGU of the module.
//! 4. Add the current function to the CGU of the module.
//!
//! 5. Repeat steps 2-4 until the worklist is empty.
Expand All @@ -28,6 +28,7 @@ use fe_mir::ir::{
body_cursor::{BodyCursor, CursorLocation},
function::BodyDataStore,
inst::InstKind,
types::TypeParamDef,
FunctionBody, FunctionParam, FunctionSigId, FunctionSignature, InstId, TypeId, TypeKind,
ValueId,
};
Expand Down Expand Up @@ -114,7 +115,7 @@ impl<'db> CguFunctionBuilder<'db> {
{
if callee.is_generic(self.db.upcast()) {
let (mono_sig, mono_body) =
self.monomorphize_func(&cursor.body().store, inst);
self.monomorphize_func(sig, &cursor.body().store, inst);
// Rewrite the callee to the mono function.
cursor.body_mut().store.rewrite_callee(inst, mono_sig);

Expand All @@ -136,29 +137,32 @@ impl<'db> CguFunctionBuilder<'db> {

fn monomorphize_func(
&self,
caller: FunctionSigId,
store: &BodyDataStore,
inst: InstId,
) -> (FunctionSigId, FunctionBody) {
let InstKind::Call {func: callee, args, ..} = &store.inst_data(inst).kind else {
let InstKind::Call {func: callee, args, generic_type, ..} = &store.inst_data(inst).kind else {
panic!("expected a call instruction");
};
debug_assert!(callee.is_generic(self.db.upcast()));

let callee = *callee;
let subst = self.get_subst(store, callee, args);

let mono_sig = self.monomorphize_sig(callee, &subst);
let mono_sig = self.monomorphize_sig(caller, callee, &subst, generic_type);
let mono_body = self.monomorphize_body(callee, &subst);

(self.db.mir_intern_function(mono_sig.into()), mono_body)
}

fn monomorphize_sig(
&self,
sig: FunctionSigId,
caller: FunctionSigId,
callee: FunctionSigId,
subst: &FxHashMap<SmolStr, TypeId>,
generic_type: &Option<TypeParamDef>,
) -> FunctionSignature {
let params = sig
let params = callee
.data(self.db.upcast())
.params
.iter()
Expand All @@ -176,19 +180,25 @@ impl<'db> CguFunctionBuilder<'db> {
})
.collect();

let return_type = sig.return_type(self.db.upcast()).clone();
let module_id = sig.module(self.db.upcast());
let linkage = sig.linkage(self.db.upcast());
let analyzer_id = self.resolve_function(sig.analyzer_sig(self.db.upcast()), subst);
let return_type = callee.return_type(self.db.upcast());
// If the callee and caller are in different ingots, we need to generate a
// function in the caller's module.
let module_id = if callee.ingot(self.db.upcast()) != caller.ingot(self.db.upcast()) {
caller.module(self.db.upcast())
} else {
callee.module(self.db.upcast())
};
let linkage = callee.linkage(self.db.upcast());
let analyzer_id =
self.resolve_function(callee.analyzer_sig(self.db.upcast()), subst, generic_type);

FunctionSignature {
name: self.mono_func_name(analyzer_id, subst),
name: self.mono_func_name(caller, analyzer_id, subst),
params,
return_type,
module_id,
analyzer_id,
linkage,
has_self: sig.has_self(self.db.upcast()),
}
}

Expand All @@ -204,12 +214,9 @@ impl<'db> CguFunctionBuilder<'db> {

let mut body = (*self.db.mir_lowered_func_body(func_id)).clone();
for value in body.store.values_mut() {
match &value.ty().data(self.db.upcast()).kind {
TypeKind::TypeParam(def) => {
let subst_ty = subst[&def.name];
*value.ty_mut() = subst_ty;
}
_ => {}
if let TypeKind::TypeParam(def) = &value.ty().data(self.db.upcast()).kind {
let subst_ty = subst[&def.name];
*value.ty_mut() = subst_ty;
}
}

Expand All @@ -222,21 +229,46 @@ impl<'db> CguFunctionBuilder<'db> {
&self,
callee: AnalyzerFuncSigId,
subst: &FxHashMap<SmolStr, TypeId>,
generic_type: &Option<TypeParamDef>,
) -> AnalyzerFuncSigId {
let trait_id = match callee.parent(self.db.upcast()) {
Item::Trait(id) => id,
_ => return callee,
};

todo!()
let concrete_type = subst[&generic_type.as_ref().unwrap().name];
let impl_ = concrete_type
.analyzer_ty(self.db.upcast())
.unwrap()
.get_impl_for(self.db.upcast(), trait_id)
.unwrap();

let resolved = impl_
.function(self.db.upcast(), &callee.name(self.db.upcast()))
.expect("missing function");
resolved.sig(self.db.upcast())
}

fn mono_func_name(
&self,
caller: FunctionSigId,
callee: AnalyzerFuncSigId,
subst: &FxHashMap<SmolStr, TypeId>,
) -> SmolStr {
todo!()
let callee_ingot = callee.ingot(self.db.upcast());
let mut func_name = if caller.ingot(self.db.upcast()) != callee_ingot {
format!(
"{}${}",
callee_ingot.name(self.db.upcast()),
callee.name(self.db.upcast())
)
} else {
callee.name(self.db.upcast()).to_string()
};
for ty in subst.values() {
func_name.push_str(&format!("${}", ty.as_string(self.db.upcast())))
}
func_name.into()
}

fn get_subst(
Expand Down
4 changes: 3 additions & 1 deletion crates/codegen/src/db/queries/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ pub fn legalized_body(db: &dyn CodegenDb, func: FunctionId) -> Rc<FunctionBody>
pub fn symbol_name(db: &dyn CodegenDb, function: FunctionSigId) -> Rc<String> {
let module = function.data(db.upcast()).module_id;
let module_name = module.name(db.upcast());
let ingot = module.ingot(db.upcast());
let ingot_name = ingot.name(db.upcast());

let analyzer_func = function.analyzer_sig(db.upcast());
let func_name = format!("{}", analyzer_func.name(db.upcast()),);
Expand All @@ -48,7 +50,7 @@ pub fn symbol_name(db: &dyn CodegenDb, function: FunctionSigId) -> Rc<String> {
_ => func_name,
};

format!("{}${}", module_name, func_name).into()
format!("{}${}${}", ingot_name, module_name, func_name).into()
}

fn safe_name(db: &dyn CodegenDb, ty: TypeId) -> SmolStr {
Expand Down
1 change: 1 addition & 0 deletions crates/codegen/src/yul/isel/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ impl<'db, 'a> FuncLowerHelper<'db, 'a> {
func,
args,
call_type,
..
} => {
let args: Vec<_> = args.iter().map(|arg| self.value_expr(*arg)).collect();
let result = match call_type {
Expand Down
11 changes: 5 additions & 6 deletions crates/mir/src/db/queries/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,11 @@ impl ir::FunctionSigId {
}

pub fn module(self, db: &dyn MirDb) -> analyzer_items::ModuleId {
let analyzer_func = self.analyzer_sig(db);
analyzer_func.module(db.upcast())
self.analyzer_sig(db).module(db.upcast())
}

pub fn ingot(self, db: &dyn MirDb) -> analyzer_items::IngotId {
self.analyzer_sig(db).ingot(db.upcast())
}

pub fn is_contract_init(self, db: &dyn MirDb) -> bool {
Expand All @@ -74,10 +77,6 @@ impl ir::FunctionSigId {
self.data(db).name.clone()
}

pub fn has_self(self, db: &dyn MirDb) -> bool {
self.data(db).has_self
}

/// Returns `class_name::fn_name` if a function is a method else `fn_name`.
pub fn debug_name(self, db: &dyn MirDb) -> SmolStr {
let analyzer_func = self.analyzer_sig(db);
Expand Down
2 changes: 1 addition & 1 deletion crates/mir/src/lower/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ pub fn lower_func_signature(db: &dyn MirDb, func: analyzer_items::FunctionSigId)
};

let sig = FunctionSignature {
name: func.name(db.upcast()).clone(),
name: func.name(db.upcast()),
params,
return_type: Some(return_type),
module_id: func.module(db.upcast()),
Expand Down
6 changes: 3 additions & 3 deletions crates/mir/src/lower/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ pub fn lower_type(db: &dyn MirDb, analyzer_ty: analyzer_types::TypeId) -> TypeId
analyzer_types::Type::SelfContract(contract) => lower_contract(db, contract),
analyzer_types::Type::Struct(struct_) => lower_struct(db, struct_),
analyzer_types::Type::Enum(enum_) => lower_enum(db, enum_),
analyzer_types::Type::Generic(generic) => TypeKind::TypeParam(TypeParamDef {
name: generic.name.clone(),
}),
analyzer_types::Type::Generic(generic) => {
TypeKind::TypeParam(TypeParamDef { name: generic.name })
}
};

intern_type(db, ty_kind, Some(analyzer_ty.deref(db.upcast())))
Expand Down

0 comments on commit 56bcfd8

Please sign in to comment.