diff --git a/a.fe b/a.fe new file mode 100644 index 0000000000..774b0fddeb --- /dev/null +++ b/a.fe @@ -0,0 +1,12 @@ +pub struct Field { + row: u8 + column: u8 + value: u8 +} + +pub struct Board { + state: Array, 4> +} + +pub contract Foo { +} \ No newline at end of file diff --git a/crates/analyzer/src/traversal/expressions.rs b/crates/analyzer/src/traversal/expressions.rs index 70a4f83250..a97c39f2c5 100644 --- a/crates/analyzer/src/traversal/expressions.rs +++ b/crates/analyzer/src/traversal/expressions.rs @@ -1691,13 +1691,13 @@ fn expr_call_method( vec!["Hint: rename one of the methods to disambiguate".into()], ); let return_type = first.signature(context.db()).return_type.clone()?; - return Ok(( + Ok(( ExpressionAttributes::new(return_type), CallType::ValueMethod { typ: obj_type, sig: *first, }, - )); + )) } } } diff --git a/crates/codegen/src/db/queries/cgu.rs b/crates/codegen/src/db/queries/cgu.rs index 5a290ed9bb..292bd7f1eb 100644 --- a/crates/codegen/src/db/queries/cgu.rs +++ b/crates/codegen/src/db/queries/cgu.rs @@ -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, }; @@ -139,7 +140,7 @@ impl<'db> CguFunctionBuilder<'db> { 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())); @@ -147,7 +148,7 @@ impl<'db> CguFunctionBuilder<'db> { 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(callee, &subst, generic_type); let mono_body = self.monomorphize_body(callee, &subst); (self.db.mir_intern_function(mono_sig.into()), mono_body) @@ -157,6 +158,7 @@ impl<'db> CguFunctionBuilder<'db> { &self, sig: FunctionSigId, subst: &FxHashMap, + generic_type: &Option, ) -> FunctionSignature { let params = sig .data(self.db.upcast()) @@ -176,10 +178,11 @@ impl<'db> CguFunctionBuilder<'db> { }) .collect(); - let return_type = sig.return_type(self.db.upcast()).clone(); + let return_type = sig.return_type(self.db.upcast()); 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 analyzer_id = + self.resolve_function(sig.analyzer_sig(self.db.upcast()), subst, generic_type); FunctionSignature { name: self.mono_func_name(analyzer_id, subst), @@ -204,12 +207,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; } } @@ -222,13 +222,24 @@ impl<'db> CguFunctionBuilder<'db> { &self, callee: AnalyzerFuncSigId, subst: &FxHashMap, + generic_type: &Option, ) -> 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( @@ -236,7 +247,11 @@ impl<'db> CguFunctionBuilder<'db> { callee: AnalyzerFuncSigId, subst: &FxHashMap, ) -> SmolStr { - todo!() + let mut func_name = 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( diff --git a/crates/codegen/src/yul/isel/context.rs b/crates/codegen/src/yul/isel/context.rs index fea327aa18..6b812e9962 100644 --- a/crates/codegen/src/yul/isel/context.rs +++ b/crates/codegen/src/yul/isel/context.rs @@ -1,7 +1,7 @@ +use fe_mir::ir::FunctionSigId; use indexmap::IndexSet; use fe_analyzer::namespace::items::ContractId; -use fe_mir::ir::FunctionId; use fxhash::FxHashSet; use yultsur::yul; @@ -15,9 +15,9 @@ use super::{lower_contract_deployable, lower_function}; pub struct Context { pub runtime: Box, pub(super) contract_dependency: IndexSet, - pub(super) function_dependency: IndexSet, pub(super) string_constants: IndexSet, - pub(super) lowered_functions: FxHashSet, + pub(super) function_dependency: IndexSet, + lowered_functions: FxHashSet, } impl Default for Context { @@ -48,7 +48,15 @@ impl Context { // Ignore dependency if it's already lowered. continue; } else { - funcs.push(lower_function(db, self, dependency)) + // Intrinsic functions are already inlined in the legalization phase. + // TODO: Add linker to allow linking to external functions. + let func = dependency + .analyzer_sig(db.upcast()) + .function(db.upcast()) + .unwrap_or_else(|| { + panic!("`{}` is not defined", dependency.name(db.upcast())) + }); + funcs.push(lower_function(db, self, dependency, func)) } } } diff --git a/crates/codegen/src/yul/isel/contract.rs b/crates/codegen/src/yul/isel/contract.rs index 3703381d8e..3b8516dc9d 100644 --- a/crates/codegen/src/yul/isel/contract.rs +++ b/crates/codegen/src/yul/isel/contract.rs @@ -1,5 +1,5 @@ use fe_analyzer::namespace::items::ContractId; -use fe_mir::ir::{function::Linkage, FunctionId}; +use fe_mir::ir::{function::Linkage, FunctionSigId}; use yultsur::{yul, *}; use crate::{ @@ -12,9 +12,10 @@ use super::context::Context; pub fn lower_contract_deployable(db: &dyn CodegenDb, contract: ContractId) -> yul::Object { let mut context = Context::default(); - let constructor = if let Some(init) = contract.init_function(db.upcast()) { - let init = db.mir_lowered_func_signature(init); - make_init(db, &mut context, contract, init) + let constructor = if let Some(init_func) = contract.init_function(db.upcast()) { + let init_sig = init_func.sig(db.upcast()); + let init_sig = db.mir_lowered_func_signature(init_sig); + make_init(db, &mut context, contract, init_sig) } else { statements! {} }; @@ -65,9 +66,9 @@ pub fn lower_contract(db: &dyn CodegenDb, contract: ContractId) -> yul::Object { let exported_funcs: Vec<_> = db .mir_lower_contract_all_functions(contract) .iter() - .filter_map(|fid| { - if fid.signature(db.upcast()).linkage == Linkage::Export { - Some(*fid) + .filter_map(|(sig, _)| { + if sig.linkage(db.upcast()) == Linkage::Export { + Some(*sig) } else { None } @@ -76,9 +77,10 @@ pub fn lower_contract(db: &dyn CodegenDb, contract: ContractId) -> yul::Object { let mut context = Context::default(); let dispatcher = if let Some(call_fn) = contract.call_function(db.upcast()) { - let call_fn = db.mir_lowered_func_signature(call_fn); - context.function_dependency.insert(call_fn); - let call_symbol = identifier! { (db.codegen_function_symbol_name(call_fn)) }; + let call_fn_sig = call_fn.sig(db.upcast()); + let call_fn_sig = db.mir_lowered_func_signature(call_fn_sig); + context.function_dependency.insert(call_fn_sig); + let call_symbol = identifier! { (db.codegen_function_symbol_name(call_fn_sig)) }; statement! { ([call_symbol]()) } @@ -122,11 +124,11 @@ pub fn lower_contract(db: &dyn CodegenDb, contract: ContractId) -> yul::Object { fn make_dispatcher( db: &dyn CodegenDb, context: &mut Context, - funcs: &[FunctionId], + funcs: &[FunctionSigId], ) -> yul::Statement { let arms = funcs .iter() - .map(|func| dispatch_arm(db, context, *func)) + .map(|sig| dispatch_arm(db, context, *sig)) .collect::>(); if arms.is_empty() { @@ -143,9 +145,9 @@ fn make_dispatcher( } } -fn dispatch_arm(db: &dyn CodegenDb, context: &mut Context, func: FunctionId) -> yul::Case { - context.function_dependency.insert(func); - let func_sig = db.codegen_legalized_signature(func); +fn dispatch_arm(db: &dyn CodegenDb, context: &mut Context, sig: FunctionSigId) -> yul::Case { + context.function_dependency.insert(sig); + let func_sig = db.codegen_legalized_signature(sig); let mut param_vars = Vec::with_capacity(func_sig.params.len()); let mut param_tys = Vec::with_capacity(func_sig.params.len()); func_sig.params.iter().for_each(|param| { @@ -165,7 +167,7 @@ fn dispatch_arm(db: &dyn CodegenDb, context: &mut Context, func: FunctionId) -> }; let call_and_encode_return = { - let name = identifier! { (db.codegen_function_symbol_name(func)) }; + let name = identifier! { (db.codegen_function_symbol_name(sig)) }; // we pass in a `0` for the expected `Context` argument let call = expression! {[name]([(param_vars.iter().map(YulVariable::expr).collect::>())...])}; if let Some(mut return_type) = func_sig.return_type { @@ -197,7 +199,7 @@ fn dispatch_arm(db: &dyn CodegenDb, context: &mut Context, func: FunctionId) -> } }; - let abi_sig = db.codegen_abi_function(func); + let abi_sig = db.codegen_abi_function(sig); let selector = literal! { (format!("0x{}", abi_sig.selector().hex())) }; case! { case [selector] { @@ -211,13 +213,13 @@ fn make_init( db: &dyn CodegenDb, context: &mut Context, contract: ContractId, - init: FunctionId, + init_sig: FunctionSigId, ) -> Vec { - context.function_dependency.insert(init); - let init_func_name = identifier! { (db.codegen_function_symbol_name(init)) }; + context.function_dependency.insert(init_sig); + let init_func_name = identifier! { (db.codegen_function_symbol_name(init_sig)) }; let contract_name = identifier_expression! { (format!{r#""{}""#, db.codegen_contract_deployer_symbol_name(contract)}) }; - let func_sig = db.codegen_legalized_signature(init); + let func_sig = db.codegen_legalized_signature(init_sig); let mut param_vars = Vec::with_capacity(func_sig.params.len()); let mut param_tys = Vec::with_capacity(func_sig.params.len()); let program_size = YulVariable::new("$program_size"); diff --git a/crates/codegen/src/yul/isel/function.rs b/crates/codegen/src/yul/isel/function.rs index dbbd427cb4..560a013538 100644 --- a/crates/codegen/src/yul/isel/function.rs +++ b/crates/codegen/src/yul/isel/function.rs @@ -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 { diff --git a/crates/mir/src/lower/function.rs b/crates/mir/src/lower/function.rs index c8316194ad..09bea4cfbf 100644 --- a/crates/mir/src/lower/function.rs +++ b/crates/mir/src/lower/function.rs @@ -67,7 +67,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()), diff --git a/crates/mir/src/lower/types.rs b/crates/mir/src/lower/types.rs index 3be9e32731..76762a8442 100644 --- a/crates/mir/src/lower/types.rs +++ b/crates/mir/src/lower/types.rs @@ -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())))