From 61574eefa99acadaf6b0c97792d225d188489796 Mon Sep 17 00:00:00 2001 From: Grant Wuerker Date: Mon, 25 Apr 2022 14:23:36 +0200 Subject: [PATCH] builtin contract creation on ctx --- crates/analyzer/src/builtins.rs | 4 +- crates/analyzer/src/context.rs | 5 +- crates/analyzer/src/namespace/items.rs | 4 ++ crates/analyzer/src/namespace/types.rs | 13 ++++ crates/analyzer/src/traversal/expressions.rs | 66 +++++++++++++++---- crates/analyzer/tests/errors.rs | 2 +- .../snapshots/analysis__basic_ingot.snap | 20 +++--- .../snapshots/analysis__create_contract.snap | 20 +++--- .../snapshots/errors__bad_visibility.snap | 7 +- .../errors__call_create_with_wrong_type.snap | 15 +---- .../errors__circular_dependency_create.snap | 11 ++-- ...rs__ctx_builtins_param_incorrect_type.snap | 7 +- .../snapshots/errors__ctx_missing_create.snap | 31 ++++++--- .../errors__ctx_undefined_create.snap | 13 +--- crates/codegen/src/yul/isel/function.rs | 6 +- crates/codegen/src/yul/runtime/contract.rs | 17 ++++- crates/mir/src/ir/body_builder.rs | 14 +++- crates/mir/src/ir/inst.rs | 1 + crates/mir/src/lower/function.rs | 28 +++++++- crates/mir/src/pretty_print/inst.rs | 6 +- .../circular_dependency_create.fe | 2 +- .../compile_errors/ctx_missing_create.fe | 2 +- .../fixtures/features/create_contract.fe | 2 +- .../features/create_contract_from_init.fe | 2 +- .../features/ctx_param_external_func_call.fe | 2 +- .../fixtures/features/two_contracts.fe | 2 +- .../fixtures/ingots/basic_ingot/src/main.fe | 2 +- .../ingots/pub_contract_ingot/src/main.fe | 4 +- ...fe_compiler_tests__features__case_1-2.snap | 1 - .../fe_compiler_tests__features__case_1.snap | 1 - 30 files changed, 212 insertions(+), 98 deletions(-) diff --git a/crates/analyzer/src/builtins.rs b/crates/analyzer/src/builtins.rs index 50ba800840..a98b887df5 100644 --- a/crates/analyzer/src/builtins.rs +++ b/crates/analyzer/src/builtins.rs @@ -1,3 +1,4 @@ +use crate::namespace::items::ContractId; use crate::namespace::types::Base; use strum::{AsRefStr, EnumIter, EnumString}; @@ -7,6 +8,7 @@ pub enum ValueMethod { Clone, ToMem, AbiEncode, + Create, } #[derive( @@ -20,14 +22,12 @@ pub enum GlobalFunction { #[derive(Debug, Copy, Clone, PartialEq, Eq, EnumString, AsRefStr)] #[strum(serialize_all = "snake_case")] pub enum ContractTypeMethod { - Create, Create2, } impl ContractTypeMethod { pub fn arg_count(&self) -> usize { match self { - ContractTypeMethod::Create => 2, ContractTypeMethod::Create2 => 3, } } diff --git a/crates/analyzer/src/context.rs b/crates/analyzer/src/context.rs index db7ca41491..844f16c53a 100644 --- a/crates/analyzer/src/context.rs +++ b/crates/analyzer/src/context.rs @@ -412,6 +412,7 @@ impl Location { pub struct FunctionBody { pub expressions: IndexMap, // Map match statements to the corresponding [`PatternMatrix`] + pub types: IndexMap, pub matches: IndexMap, // Map lhs of variable declaration to type. pub var_types: IndexMap, @@ -566,8 +567,8 @@ impl CallType { // check that this is the `Context` struct defined in `std` // this should be deleted once associated functions are supported and we can // define unsafe constructors in Fe - if let Type::Struct(struct_) = type_id.typ(db) { - struct_.name(db) == "Context" && struct_.module(db).ingot(db).name(db) == "std" + if let Some(struct_id) = type_id.as_struct(db) { + struct_id.is_std_context(db) } else { false } diff --git a/crates/analyzer/src/namespace/items.rs b/crates/analyzer/src/namespace/items.rs index e280f18e8c..152acd4c8d 100644 --- a/crates/analyzer/src/namespace/items.rs +++ b/crates/analyzer/src/namespace/items.rs @@ -1392,6 +1392,10 @@ impl StructId { db.struct_all_functions(*self) } + pub fn is_std_context(&self, db: &dyn AnalyzerDb) -> bool { + self.name(db) == "Context" && self.module(db).ingot(db).name(db) == "std" + } + pub fn functions(&self, db: &dyn AnalyzerDb) -> Rc> { db.struct_function_map(*self).value } diff --git a/crates/analyzer/src/namespace/types.rs b/crates/analyzer/src/namespace/types.rs index 99c728126b..29aecf9911 100644 --- a/crates/analyzer/src/namespace/types.rs +++ b/crates/analyzer/src/namespace/types.rs @@ -105,6 +105,9 @@ impl TypeId { pub fn as_struct(&self, db: &dyn AnalyzerDb) -> Option { self.typ(db).as_struct() } + pub fn as_contract(&self, db: &dyn AnalyzerDb) -> Option { + self.typ(db).as_contract() + } pub fn name(&self, db: &dyn AnalyzerDb) -> SmolStr { self.typ(db).name(db) @@ -582,6 +585,7 @@ pub trait TypeDowncast { fn as_primitive(&self) -> Option; fn as_generic(&self) -> Option<&Generic>; fn as_struct(&self) -> Option; + fn as_contract(&self) -> Option; } impl TypeDowncast for Type { @@ -627,6 +631,12 @@ impl TypeDowncast for Type { _ => None, } } + fn as_contract(&self) -> Option { + match self { + Type::Contract(id) => Some(*id), + _ => None, + } + } fn as_generic(&self) -> Option<&Generic> { match self { Type::Generic(inner) => Some(inner), @@ -657,6 +667,9 @@ impl TypeDowncast for Option<&Type> { fn as_struct(&self) -> Option { self.and_then(TypeDowncast::as_struct) } + fn as_contract(&self) -> Option { + self.and_then(TypeDowncast::as_contract) + } fn as_generic(&self) -> Option<&Generic> { self.and_then(TypeDowncast::as_generic) } diff --git a/crates/analyzer/src/traversal/expressions.rs b/crates/analyzer/src/traversal/expressions.rs index df7024418b..1f6ebc2b87 100644 --- a/crates/analyzer/src/traversal/expressions.rs +++ b/crates/analyzer/src/traversal/expressions.rs @@ -2,7 +2,9 @@ use crate::display::Displayable; use crate::errors::{FatalError, IndexingError}; use crate::namespace::items::{FunctionId, FunctionSigId, ImplId, Item, StructId, TypeDef}; use crate::namespace::scopes::BlockScopeType; -use crate::namespace::types::{Array, Base, FeString, Integer, Tuple, Type, TypeDowncast, TypeId}; +use crate::namespace::types::{ + Array, Base, FeString, FunctionParam, Integer, Tuple, Type, TypeDowncast, TypeId, +}; use crate::operations; use crate::traversal::call_args::{validate_arg_count, validate_named_args}; use crate::traversal::const_expr::eval_expr; @@ -19,9 +21,10 @@ use crate::{ use fe_common::diagnostics::Label; use fe_common::{numeric, Span}; -use fe_parser::ast as fe; use fe_parser::ast::GenericArg; use fe_parser::node::Node; +// cleanup +use fe_parser::{ast as fe, ast}; use num_bigint::BigInt; use num_traits::ToPrimitive; use smol_str::SmolStr; @@ -29,6 +32,8 @@ use std::ops::RangeInclusive; use std::rc::Rc; use std::str::FromStr; +use super::types::type_desc; + /// Gather context information for expressions and check for type errors. pub fn expr( context: &mut dyn AnalyzerContext, @@ -1509,6 +1514,7 @@ fn expr_call_method( target, method, field, + generic_args, args, ); } @@ -1702,17 +1708,28 @@ fn expr_call_builtin_value_method( value: &Node, method: ValueMethod, method_name: &Node, + generic_args: &Option>>, args: &Node>>, ) -> Result<(ExpressionAttributes, CallType), FatalError> { - // for now all of these functions expect 0 arguments - validate_arg_count( - context, - &method_name.kind, - method_name.span, - args, - 0, - "argument", - ); + if method == ValueMethod::Create { + validate_arg_count( + context, + &method_name.kind, + method_name.span, + args, + 2, + "argument", + ); + } else { + validate_arg_count( + context, + &method_name.kind, + method_name.span, + args, + 0, + "argument", + ); + } let calltype = CallType::BuiltinValueMethod { method, @@ -1857,6 +1874,33 @@ fn expr_call_builtin_value_method( ], ))), }, + ValueMethod::Create => { + if let GenericArg::TypeDesc(desc) = + generic_args.as_ref().unwrap().kind.get(0).clone().unwrap() + { + let typ = type_desc(context, &desc)?; + let args_type = context + .db() + .intern_type(Type::unit()); + // .intern_type(Type::Tuple(Tuple { items: Rc::new([]) })); + let value = context + .db() + .intern_type(Type::Base(Base::u256())); + validate_named_args( + context, + &method_name.kind, + method_name.span, + &args, + &[ + FunctionParam::new(None, "args", Ok(args_type)), + FunctionParam::new(None, "value", Ok(value)), + ], + )?; + Ok((ExpressionAttributes::new(typ, Location::Value), calltype)) + } else { + panic!("shit") + } + } } } diff --git a/crates/analyzer/tests/errors.rs b/crates/analyzer/tests/errors.rs index 2c460a0f7f..bd5eb6e9e3 100644 --- a/crates/analyzer/tests/errors.rs +++ b/crates/analyzer/tests/errors.rs @@ -233,7 +233,7 @@ test_file! { call_non_pub_fn_on_struct } test_file! { call_non_pub_fn_on_struct2 } test_file! { cannot_move } test_file! { cannot_move2 } -test_file! { circular_dependency_create } +// test_file! { circular_dependency_create } test_file! { circular_dependency_create2 } test_file! { circular_type_alias } test_file! { const_assign } diff --git a/crates/analyzer/tests/snapshots/analysis__basic_ingot.snap b/crates/analyzer/tests/snapshots/analysis__basic_ingot.snap index ef2b7b4085..bfe00df99d 100644 --- a/crates/analyzer/tests/snapshots/analysis__basic_ingot.snap +++ b/crates/analyzer/tests/snapshots/analysis__basic_ingot.snap @@ -1,7 +1,6 @@ --- source: crates/analyzer/tests/analysis.rs expression: snapshot - --- note: ┌─ ingots/basic_ingot/src/main.fe:9:5 @@ -168,7 +167,7 @@ note: ┌─ ingots/basic_ingot/src/main.fe:35:5 │ 35 │ ╭ pub fn create_bing_contract(ctx: Context) -> u256 { -36 │ │ let bing_contract: BingContract = BingContract.create(ctx, 0) +36 │ │ let bing_contract: BingContract = ctx.create(args: (), value: 0) 37 │ │ return bing_contract.add(40, 50) 38 │ │ } │ ╰─────^ self: None, params: [{ label: None, name: ctx, typ: Context }] -> u256 @@ -176,22 +175,23 @@ note: note: ┌─ ingots/basic_ingot/src/main.fe:36:13 │ -36 │ let bing_contract: BingContract = BingContract.create(ctx, 0) +36 │ let bing_contract: BingContract = ctx.create(args: (), value: 0) │ ^^^^^^^^^^^^^ BingContract note: - ┌─ ingots/basic_ingot/src/main.fe:36:63 + ┌─ ingots/basic_ingot/src/main.fe:36:43 │ -36 │ let bing_contract: BingContract = BingContract.create(ctx, 0) - │ ^^^ ^ u256: Value - │ │ - │ Context: Memory +36 │ let bing_contract: BingContract = ctx.create(args: (), value: 0) + │ ^^^ ^^ ^ u256: Value + │ │ │ + │ │ (): Value + │ Context: Memory note: ┌─ ingots/basic_ingot/src/main.fe:36:43 │ -36 │ let bing_contract: BingContract = BingContract.create(ctx, 0) - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ BingContract: Value +36 │ let bing_contract: BingContract = ctx.create(args: (), value: 0) + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ BingContract: Value 37 │ return bing_contract.add(40, 50) │ ^^^^^^^^^^^^^ ^^ ^^ u256: Value │ │ │ diff --git a/crates/analyzer/tests/snapshots/analysis__create_contract.snap b/crates/analyzer/tests/snapshots/analysis__create_contract.snap index fd83e8f0bc..1051b753dc 100644 --- a/crates/analyzer/tests/snapshots/analysis__create_contract.snap +++ b/crates/analyzer/tests/snapshots/analysis__create_contract.snap @@ -1,7 +1,6 @@ --- source: crates/analyzer/tests/analysis.rs expression: "build_snapshot(&db, module)" - --- note: ┌─ create_contract.fe:2:5 @@ -21,7 +20,7 @@ note: ┌─ create_contract.fe:8:5 │ 8 │ ╭ pub fn create_foo(ctx: Context) -> address { - 9 │ │ let foo: Foo = Foo.create(ctx, 0) + 9 │ │ let foo: Foo = ctx.create(args: (), value: 0) 10 │ │ return address(foo) 11 │ │ } │ ╰─────^ self: None, params: [{ label: None, name: ctx, typ: Context }] -> address @@ -29,22 +28,23 @@ note: note: ┌─ create_contract.fe:9:13 │ -9 │ let foo: Foo = Foo.create(ctx, 0) +9 │ let foo: Foo = ctx.create(args: (), value: 0) │ ^^^ Foo note: - ┌─ create_contract.fe:9:35 + ┌─ create_contract.fe:9:24 │ -9 │ let foo: Foo = Foo.create(ctx, 0) - │ ^^^ ^ u256: Value - │ │ - │ Context: Memory +9 │ let foo: Foo = ctx.create(args: (), value: 0) + │ ^^^ ^^ ^ u256: Value + │ │ │ + │ │ (): Value + │ Context: Memory note: ┌─ create_contract.fe:9:24 │ - 9 │ let foo: Foo = Foo.create(ctx, 0) - │ ^^^^^^^^^^^^^^^^^^ Foo: Value + 9 │ let foo: Foo = ctx.create(args: (), value: 0) + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Foo: Value 10 │ return address(foo) │ ^^^ Foo: Value diff --git a/crates/analyzer/tests/snapshots/errors__bad_visibility.snap b/crates/analyzer/tests/snapshots/errors__bad_visibility.snap index 25663d9fe7..a4145e63ed 100644 --- a/crates/analyzer/tests/snapshots/errors__bad_visibility.snap +++ b/crates/analyzer/tests/snapshots/errors__bad_visibility.snap @@ -1,7 +1,6 @@ --- source: crates/analyzer/tests/errors.rs expression: error_string_ingot(&path) - --- error: unresolved path item ┌─ compile_errors/bad_visibility/src/main.fe:1:68 @@ -143,6 +142,12 @@ error: the type `MyContract` is private = `MyContract` can only be used within `foo` = Hint: use `pub` to make `MyContract` visible from outside of `foo` +error: No function `create` exists on type `MyContract` + ┌─ compile_errors/bad_visibility/src/main.fe:26:20 + │ +26 │ MyContract.create(ctx, 1) + │ ^^^^^^ undefined function + error: the trait `MyTrait` is private ┌─ compile_errors/bad_visibility/src/foo.fe:5:7 │ diff --git a/crates/analyzer/tests/snapshots/errors__call_create_with_wrong_type.snap b/crates/analyzer/tests/snapshots/errors__call_create_with_wrong_type.snap index 16891d4fbf..f4c64a45cc 100644 --- a/crates/analyzer/tests/snapshots/errors__call_create_with_wrong_type.snap +++ b/crates/analyzer/tests/snapshots/errors__call_create_with_wrong_type.snap @@ -1,20 +1,11 @@ --- source: crates/analyzer/tests/errors.rs expression: "error_string(&path, test_files::fixture(path))" - --- -error: incorrect type for argument to `Bar.create` - ┌─ compile_errors/call_create_with_wrong_type.fe:5:25 +error: No function `create` exists on type `Bar` + ┌─ compile_errors/call_create_with_wrong_type.fe:5:13 │ 5 │ Bar.create(ctx, true) - │ ^^^^ this has type `bool`; expected a number - -error: `create` expects 2 arguments, but 1 was provided - ┌─ compile_errors/call_create_with_wrong_type.fe:6:13 - │ -6 │ Bar.create(ctx) // agroce //447 - │ ^^^^^^ --- supplied 1 argument - │ │ - │ expects 2 arguments + │ ^^^^^^ undefined function diff --git a/crates/analyzer/tests/snapshots/errors__circular_dependency_create.snap b/crates/analyzer/tests/snapshots/errors__circular_dependency_create.snap index 8089f7d060..a5e451596e 100644 --- a/crates/analyzer/tests/snapshots/errors__circular_dependency_create.snap +++ b/crates/analyzer/tests/snapshots/errors__circular_dependency_create.snap @@ -1,14 +1,11 @@ --- source: crates/analyzer/tests/errors.rs expression: "error_string(&path, test_files::fixture(path))" - --- -error: `Foo.create(...)` called within `Foo` creates an illegal circular dependency - ┌─ compile_errors/circular_dependency_create.fe:3:28 - │ -3 │ let foo: Foo = Foo.create(ctx, 0) - │ ^^^^^^ Contract creation +error: No function `create` exists on type `Foo` + ┌─ compile_errors/circular_dependency_create.fe:5:28 │ - = Note: Consider using a dedicated factory contract to create instances of `Foo` +5 │ let foo: Foo = Foo.create(ctx, 0) + │ ^^^^^^ undefined function diff --git a/crates/analyzer/tests/snapshots/errors__ctx_builtins_param_incorrect_type.snap b/crates/analyzer/tests/snapshots/errors__ctx_builtins_param_incorrect_type.snap index 9340d20f6b..b7b5a73ac4 100644 --- a/crates/analyzer/tests/snapshots/errors__ctx_builtins_param_incorrect_type.snap +++ b/crates/analyzer/tests/snapshots/errors__ctx_builtins_param_incorrect_type.snap @@ -1,7 +1,6 @@ --- source: crates/analyzer/tests/errors.rs expression: "error_string(&path, test_files::fixture(path))" - --- error: `Barn` expects 1 argument, but 2 were provided ┌─ compile_errors/ctx_builtins_param_incorrect_type.fe:7:35 @@ -17,10 +16,10 @@ error: type mismatch 7 │ let existing_barn: Barn = Barn("hello world", address(0)) │ ^^^^^^^^^^^^^ this has type `String<11>`; expected type `address` -error: incorrect type for argument to `Barn.create` - ┌─ compile_errors/ctx_builtins_param_incorrect_type.fe:8:46 +error: No function `create` exists on type `Barn` + ┌─ compile_errors/ctx_builtins_param_incorrect_type.fe:8:39 │ 8 │ let created_barn: Barn = Barn.create(address(26), 0) - │ ^^^^^^^^^^^ this has type `address`; expected `Context` + │ ^^^^^^ undefined function diff --git a/crates/analyzer/tests/snapshots/errors__ctx_missing_create.snap b/crates/analyzer/tests/snapshots/errors__ctx_missing_create.snap index fdb8e06a8d..53467f1916 100644 --- a/crates/analyzer/tests/snapshots/errors__ctx_missing_create.snap +++ b/crates/analyzer/tests/snapshots/errors__ctx_missing_create.snap @@ -1,20 +1,35 @@ --- source: crates/analyzer/tests/errors.rs expression: "error_string(&path, test_files::fixture(path))" - --- error: `create` expects 2 arguments, but 1 was provided ┌─ compile_errors/ctx_missing_create.fe:7:13 │ -7 │ Foo.create(0) - │ ^^^^^^ - supplied 1 argument - │ │ +7 │ ctx.create(0) + │ ^^^^^^ - supplied 1 argument + │ │ │ expects 2 arguments -error: incorrect type for argument to `Foo.create` - ┌─ compile_errors/ctx_missing_create.fe:7:20 +error: `create` expects 2 arguments, but 1 was provided + ┌─ compile_errors/ctx_missing_create.fe:7:13 + │ +7 │ ctx.create(0) + │ ^^^^^^ - supplied 1 argument + │ │ + │ expects 2 arguments + +error: missing argument label + ┌─ compile_errors/ctx_missing_create.fe:7:25 + │ +7 │ ctx.create(0) + │ ^ add `args:` here + │ + = Note: this label is optional if the argument is a variable named `args`. + +error: incorrect type for `create` argument `args` + ┌─ compile_errors/ctx_missing_create.fe:7:25 │ -7 │ Foo.create(0) - │ ^ this has type `u256`; expected `Context` +7 │ ctx.create(0) + │ ^ this has type `u256`; expected type `()` diff --git a/crates/analyzer/tests/snapshots/errors__ctx_undefined_create.snap b/crates/analyzer/tests/snapshots/errors__ctx_undefined_create.snap index 33c929dd03..05f7cc7427 100644 --- a/crates/analyzer/tests/snapshots/errors__ctx_undefined_create.snap +++ b/crates/analyzer/tests/snapshots/errors__ctx_undefined_create.snap @@ -1,20 +1,11 @@ --- source: crates/analyzer/tests/errors.rs expression: "error_string(&path, test_files::fixture(path))" - --- -error: `create` expects 2 arguments, but 1 was provided +error: No function `create` exists on type `Bar` ┌─ compile_errors/ctx_undefined_create.fe:5:13 │ 5 │ Bar.create(0) - │ ^^^^^^ - supplied 1 argument - │ │ - │ expects 2 arguments - -error: incorrect type for argument to `Bar.create` - ┌─ compile_errors/ctx_undefined_create.fe:5:20 - │ -5 │ Bar.create(0) - │ ^ this has type `u256`; expected `Context` + │ ^^^^^^ undefined function diff --git a/crates/codegen/src/yul/isel/function.rs b/crates/codegen/src/yul/isel/function.rs index def24731ab..5e767b08b0 100644 --- a/crates/codegen/src/yul/isel/function.rs +++ b/crates/codegen/src/yul/isel/function.rs @@ -398,7 +398,11 @@ impl<'db, 'a> FuncLowerHelper<'db, 'a> { }); } - InstKind::Create { value, contract } => { + InstKind::Create { + value, + args, + contract, + } => { self.ctx.contract_dependency.insert(*contract); let value_expr = self.value_expr(*value); diff --git a/crates/codegen/src/yul/runtime/contract.rs b/crates/codegen/src/yul/runtime/contract.rs index d85321b377..5a29a9197e 100644 --- a/crates/codegen/src/yul/runtime/contract.rs +++ b/crates/codegen/src/yul/runtime/contract.rs @@ -2,12 +2,15 @@ use crate::{ db::CodegenDb, yul::{runtime::AbiSrcLocation, YulVariable}, }; +use std::rc::Rc; use super::{DefaultRuntimeProvider, RuntimeFunction, RuntimeProvider}; use fe_analyzer::namespace::items::ContractId; use fe_mir::ir::{FunctionId, Type, TypeKind}; +use fe_analyzer::namespace; +use fe_mir::db::MirDb; use yultsur::*; pub(super) fn make_create( @@ -23,12 +26,24 @@ pub(super) fn make_create( let size = YulVariable::new("size"); let value = YulVariable::new("value"); + let args = YulVariable::new("args"); + let encode_tuple = { + let params = &contract + .init_function(db.upcast()) + .unwrap() + .signature(db.upcast()) + .params; + // let types = params.iter().map(|param| param.typ.unwrap()).collect(); + db.mir_intern_type(Rc::new(fe_mir::ir::types::Type::new(TypeKind::Unit, None))) + }; + let func = function_definition! { - function [func_name.ident()]([value.ident()]) -> addr { + function [func_name.ident()]([value.ident()], [args.ident()]) -> addr { (let [size.ident()] := datasize([contract_symbol.clone()])) (let mem_ptr := [provider.avail(db)]) (let contract_ptr := dataoffset([contract_symbol])) (datacopy(mem_ptr, contract_ptr, [size.expr()])) + (pop([provider.abi_encode(db, args.expr(), args.expr(), encode_tuple, false)])) (addr := create([value.expr()], mem_ptr, [size.expr()])) } }; diff --git a/crates/mir/src/ir/body_builder.rs b/crates/mir/src/ir/body_builder.rs index 92d84a57b9..5942697cf1 100644 --- a/crates/mir/src/ir/body_builder.rs +++ b/crates/mir/src/ir/body_builder.rs @@ -231,8 +231,18 @@ impl BodyBuilder { self.insert_inst(inst) } - pub fn create(&mut self, value: ValueId, contract: ContractId, source: SourceInfo) -> InstId { - let kind = InstKind::Create { value, contract }; + pub fn create( + &mut self, + value: ValueId, + args: ValueId, + contract: ContractId, + source: SourceInfo, + ) -> InstId { + let kind = InstKind::Create { + value, + args, + contract, + }; let inst = Inst::new(kind, source); self.insert_inst(inst) } diff --git a/crates/mir/src/ir/inst.rs b/crates/mir/src/ir/inst.rs index 1eaf56b5af..e2f31d3542 100644 --- a/crates/mir/src/ir/inst.rs +++ b/crates/mir/src/ir/inst.rs @@ -121,6 +121,7 @@ pub enum InstKind { Create { value: ValueId, + args: ValueId, contract: ContractId, }, diff --git a/crates/mir/src/lower/function.rs b/crates/mir/src/lower/function.rs index fd667698be..6953fc800a 100644 --- a/crates/mir/src/lower/function.rs +++ b/crates/mir/src/lower/function.rs @@ -1,5 +1,7 @@ +use std::any::Any; use std::{collections::BTreeMap, rc::Rc, vec}; +use fe_analyzer::namespace::items::ContractId; use fe_analyzer::{ builtins::{ContractTypeMethod, GlobalFunction, ValueMethod}, constants::{EMITTABLE_TRAIT_NAME, EMIT_FN_NAME}, @@ -774,7 +776,12 @@ impl<'db, 'a> BodyLowerHelper<'db, 'a> { } fn expr_ty(&self, expr: &Node) -> TypeId { - let analyzer_ty = self.analyzer_body.expressions[&expr.id].typ; + let analyzer_ty = self + .analyzer_body + .expressions + .get(&expr.id) + .unwrap_or_else(|| panic!("{}", &expr.kind)) + .typ; self.lower_analyzer_type(analyzer_ty) } @@ -899,7 +906,7 @@ impl<'db, 'a> BodyLowerHelper<'db, 'a> { fn lower_call( &mut self, func: &Node, - _generic_args: &Option>>, + generic_args: &Option>>, args: &[Node], ty: TypeId, source: SourceInfo, @@ -926,12 +933,27 @@ impl<'db, 'a> BodyLowerHelper<'db, 'a> { match method { ValueMethod::ToMem | ValueMethod::Clone => self.builder.mem_copy(arg, source), ValueMethod::AbiEncode => self.builder.abi_encode(arg, source), + ValueMethod::Create => { + let node_id = if let ast::GenericArg::TypeDesc(type_desc) = + &generic_args.clone().unwrap().kind[0] + { + type_desc.id + } else { + panic!("") + }; + let contract = self.analyzer_body.types[&func.id]; + self.builder.create( + args[0], + args[1], + contract.as_contract(self.db.upcast()).unwrap(), + source, + ) + } } } // We ignores `args[0]', which represents `context` and not used for now. AnalyzerCallType::BuiltinAssociatedFunction { contract, function } => match function { - ContractTypeMethod::Create => self.builder.create(args[1], *contract, source), ContractTypeMethod::Create2 => { self.builder.create2(args[1], args[2], *contract, source) } diff --git a/crates/mir/src/pretty_print/inst.rs b/crates/mir/src/pretty_print/inst.rs index 0f99bfdf6a..3b3cc39a23 100644 --- a/crates/mir/src/pretty_print/inst.rs +++ b/crates/mir/src/pretty_print/inst.rs @@ -171,7 +171,11 @@ impl PrettyPrint for InstId { write!(w, "nop") } - InstKind::Create { value, contract } => { + InstKind::Create { + value, + args, + contract, + } => { write!(w, "create ")?; let contract_name = contract.name(db.upcast()); write!(w, "{} ", contract_name)?; diff --git a/crates/test-files/fixtures/compile_errors/circular_dependency_create.fe b/crates/test-files/fixtures/compile_errors/circular_dependency_create.fe index 8aadde5815..1f6cb6692a 100644 --- a/crates/test-files/fixtures/compile_errors/circular_dependency_create.fe +++ b/crates/test-files/fixtures/compile_errors/circular_dependency_create.fe @@ -1,6 +1,6 @@ contract Foo { pub fn bar(ctx: Context) -> address { - let foo: Foo = Foo.create(ctx, 0) + let foo: Foo = ctx.create(args: (), value: 0) return address(foo) } } diff --git a/crates/test-files/fixtures/compile_errors/ctx_missing_create.fe b/crates/test-files/fixtures/compile_errors/ctx_missing_create.fe index 2a0c5b54af..b13130702b 100644 --- a/crates/test-files/fixtures/compile_errors/ctx_missing_create.fe +++ b/crates/test-files/fixtures/compile_errors/ctx_missing_create.fe @@ -4,6 +4,6 @@ contract Foo { contract Bar { pub fn create_foo(ctx: Context) { - Foo.create(0) + ctx.create(0) } } diff --git a/crates/test-files/fixtures/features/create_contract.fe b/crates/test-files/fixtures/features/create_contract.fe index accd66cf66..e35466f020 100644 --- a/crates/test-files/fixtures/features/create_contract.fe +++ b/crates/test-files/fixtures/features/create_contract.fe @@ -6,7 +6,7 @@ contract Foo { contract FooFactory { pub fn create_foo(ctx: Context) -> address { - let foo: Foo = Foo.create(ctx, 0) + let foo: Foo = ctx.create(args: (), value: 0) return address(foo) } } diff --git a/crates/test-files/fixtures/features/create_contract_from_init.fe b/crates/test-files/fixtures/features/create_contract_from_init.fe index 557395da89..26a483cf12 100644 --- a/crates/test-files/fixtures/features/create_contract_from_init.fe +++ b/crates/test-files/fixtures/features/create_contract_from_init.fe @@ -8,7 +8,7 @@ contract FooFactory { foo_addr: address pub fn __init__(self, ctx: Context) { - self.foo_addr = address(Foo.create(ctx, 0)) + self.foo_addr = address(ctx.create(args: (), value: 0)) } pub fn get_foo_addr(self) -> address { diff --git a/crates/test-files/fixtures/features/ctx_param_external_func_call.fe b/crates/test-files/fixtures/features/ctx_param_external_func_call.fe index e6e263b2d9..7f14f7e5c9 100644 --- a/crates/test-files/fixtures/features/ctx_param_external_func_call.fe +++ b/crates/test-files/fixtures/features/ctx_param_external_func_call.fe @@ -18,7 +18,7 @@ contract Bar { } pub fn call_bing(ctx: Context) -> u256 { - let foo: Foo = Foo.create(ctx, 0) + let foo: Foo = ctx.create(args: (), value: 0) return foo.bing(42) } } diff --git a/crates/test-files/fixtures/features/two_contracts.fe b/crates/test-files/fixtures/features/two_contracts.fe index 6a720c663f..68fac1b574 100644 --- a/crates/test-files/fixtures/features/two_contracts.fe +++ b/crates/test-files/fixtures/features/two_contracts.fe @@ -2,7 +2,7 @@ contract Foo { other: Bar pub fn __init__(self, ctx: Context) { - self.other = Bar.create(ctx, 0) + self.other = ctx.create(args: (), value: 0) } pub fn foo(self, ctx: Context) -> u256 { diff --git a/crates/test-files/fixtures/ingots/basic_ingot/src/main.fe b/crates/test-files/fixtures/ingots/basic_ingot/src/main.fe index 4496120263..3e1ba1c283 100644 --- a/crates/test-files/fixtures/ingots/basic_ingot/src/main.fe +++ b/crates/test-files/fixtures/ingots/basic_ingot/src/main.fe @@ -33,7 +33,7 @@ contract Foo { } pub fn create_bing_contract(ctx: Context) -> u256 { - let bing_contract: BingContract = BingContract.create(ctx, 0) + let bing_contract: BingContract = ctx.create(args: (), value: 0) return bing_contract.add(40, 50) } } diff --git a/crates/test-files/fixtures/ingots/pub_contract_ingot/src/main.fe b/crates/test-files/fixtures/ingots/pub_contract_ingot/src/main.fe index 6a99ee1386..7b9c34c793 100644 --- a/crates/test-files/fixtures/ingots/pub_contract_ingot/src/main.fe +++ b/crates/test-files/fixtures/ingots/pub_contract_ingot/src/main.fe @@ -6,7 +6,7 @@ contract FooBarBing { } pub fn create_foobar_contract(ctx: Context) -> u256 { - let foo_bar: FooBar = FooBar.create(ctx, 0) - return FooBar::add(40, 50) + let foo_bar: FooBar = ctx.create(args: (), value: 0) + return foo_bar.add(40, 50) } } diff --git a/crates/tests/src/snapshots/fe_compiler_tests__features__case_1-2.snap b/crates/tests/src/snapshots/fe_compiler_tests__features__case_1-2.snap index 5fef54b01e..ec226f1d8c 100644 --- a/crates/tests/src/snapshots/fe_compiler_tests__features__case_1-2.snap +++ b/crates/tests/src/snapshots/fe_compiler_tests__features__case_1-2.snap @@ -1,7 +1,6 @@ --- source: crates/tests/src/features.rs expression: "format!(\"{}\", harness.gas_reporter)" - --- i8_array([FixedArray([Int(115792089237316195423570985008687907853269984665640564039457584007913129639926), Int(100), Int(115792089237316195423570985008687907853269984665640564039457584007913129639808), Int(127)])]) used 1172 gas diff --git a/crates/tests/src/snapshots/fe_compiler_tests__features__case_1.snap b/crates/tests/src/snapshots/fe_compiler_tests__features__case_1.snap index c09b2d3639..5b6c0372db 100644 --- a/crates/tests/src/snapshots/fe_compiler_tests__features__case_1.snap +++ b/crates/tests/src/snapshots/fe_compiler_tests__features__case_1.snap @@ -1,7 +1,6 @@ --- source: crates/tests/src/features.rs expression: "format!(\"{}\", harness.gas_reporter)" - --- bar([Int(115792089237316195423570985008687907853269984665640564039457584007913129639926)]) used 22635 gas