From f33f0f068494a0b4643c24d88b4a825032fe5b24 Mon Sep 17 00:00:00 2001 From: Sean Billig Date: Mon, 30 May 2022 16:08:59 -0700 Subject: [PATCH] ctx rule change (contract type cast, external fn calls) - not required for contract type cast, eg `Foo(address(0))` - is required when calling external contract fn that takes ctx --- crates/analyzer/src/namespace/types.rs | 25 -- crates/analyzer/src/traversal/call_args.rs | 1 + crates/analyzer/src/traversal/expressions.rs | 68 +--- crates/analyzer/tests/errors.rs | 3 +- .../analysis__external_contract.snap | 65 ++-- .../snapshots/analysis__two_contracts.snap | 35 +- .../tests/snapshots/analysis__uniswap.snap | 340 ++++++++---------- .../snapshots/errors__bad_visibility.snap | 4 +- .../errors__call_address_with_label.snap | 12 + ..._call_non_pub_fn_on_external_contract.snap | 6 +- ...defined_function_on_external_contract.snap | 6 +- ...rs__ctx_builtins_param_incorrect_type.snap | 10 +- .../snapshots/errors__ctx_missing_load.snap | 10 +- .../errors__external_call_type_error.snap | 6 +- ..._external_call_wrong_number_of_params.snap | 16 +- ...eled_call_args_external_contract_call.snap | 14 + .../compile_errors/bad_visibility/src/main.fe | 2 +- .../call_call_on_external_contract.fe | 2 +- .../call_non_pub_fn_on_external_contract.fe | 4 +- ...undefined_function_on_external_contract.fe | 4 +- .../ctx_passed_external_call.fe | 16 - .../ctx_undefined_contract_init.fe | 7 - .../external_call_type_error.fe | 4 +- .../external_call_wrong_number_of_params.fe | 4 +- .../init_call_on_external_contract.fe | 2 +- crates/test-files/fixtures/demos/uniswap.fe | 34 +- .../features/ctx_param_external_func_call.fe | 4 +- .../fixtures/features/external_contract.fe | 8 +- .../fixtures/features/two_contracts.fe | 4 +- .../fixtures/stress/external_calls.fe | 4 +- ...ests__demo_uniswap__uniswap_contracts.snap | 3 +- docs/validate_doc_examples.py | 3 + newsfragments/703.feature.md | 22 ++ newsfragments/707.feature.md | 2 +- 34 files changed, 309 insertions(+), 441 deletions(-) create mode 100644 crates/analyzer/tests/snapshots/errors__call_address_with_label.snap delete mode 100644 crates/test-files/fixtures/compile_errors/ctx_passed_external_call.fe delete mode 100644 crates/test-files/fixtures/compile_errors/ctx_undefined_contract_init.fe create mode 100644 newsfragments/703.feature.md diff --git a/crates/analyzer/src/namespace/types.rs b/crates/analyzer/src/namespace/types.rs index 050db6e422..68d7b3fec1 100644 --- a/crates/analyzer/src/namespace/types.rs +++ b/crates/analyzer/src/namespace/types.rs @@ -394,31 +394,6 @@ impl FunctionSignature { pub fn expect_return_type(&self) -> Type { self.return_type.clone().expect("fn return type error") } - - /// Parameters without `ctx`, if it is a contract function that declares it. - /// - /// This is used when calling a contract method externally. - pub fn external_params(&self) -> &[FunctionParam] { - if self.ctx_decl.is_some() { - &self.params[1..] - } else { - &self.params - } - } - - /// Parameter types without `ctx`, if it is a contract function that - /// declares it. - /// - /// This is used when calling a contract method externally. - /// - /// # Panics - /// Panics if any param type is an `Err` - pub fn external_param_types(&self) -> Vec { - self.external_params() - .iter() - .map(|param| param.typ.clone().expect("fn param type error")) - .collect() - } } impl Type { diff --git a/crates/analyzer/src/traversal/call_args.rs b/crates/analyzer/src/traversal/call_args.rs index cd78bed940..9238a0a045 100644 --- a/crates/analyzer/src/traversal/call_args.rs +++ b/crates/analyzer/src/traversal/call_args.rs @@ -97,6 +97,7 @@ pub fn validate_named_args( params: &[impl LabeledParameter], ) -> Result<(), FatalError> { validate_arg_count(context, name, name_span, args, params.len(), "argument"); + // TODO: if the first arg is missing, every other arg will get a label and type error for (index, (param, arg)) in params.iter().zip(args.kind.iter()).enumerate() { let expected_label = param.label(); diff --git a/crates/analyzer/src/traversal/expressions.rs b/crates/analyzer/src/traversal/expressions.rs index 1d0fe3c9f3..30e061c07f 100644 --- a/crates/analyzer/src/traversal/expressions.rs +++ b/crates/analyzer/src/traversal/expressions.rs @@ -1147,15 +1147,9 @@ fn expr_call_type_constructor( _ => {} } - if matches!(typ, Type::Contract(_)) { - validate_arg_count(context, &format!("{}", typ), name_span, args, 2, "argument"); - expect_no_label_on_arg(context, args, 0); - expect_no_label_on_arg(context, args, 1); - } else { - // These all expect 1 arg, for now. - validate_arg_count(context, &format!("{}", typ), name_span, args, 1, "argument"); - expect_no_label_on_arg(context, args, 0); - } + // These all expect 1 arg, for now. + validate_arg_count(context, &format!("{}", typ), name_span, args, 1, "argument"); + expect_no_label_on_arg(context, args, 0); let expr_attrs = match &typ { Type::String(string_type) => { @@ -1166,50 +1160,10 @@ fn expr_call_type_constructor( ExpressionAttributes::new(typ.clone(), Location::Memory) } Type::Contract(_) => { - if let Some(first_arg) = &args.kind.get(0) { - let first_arg_attr = assignable_expr(context, &first_arg.kind.value, None)?; - if let Some(context_type) = context.get_context_type() { - if first_arg_attr.typ != Type::Struct(context_type.clone()) { - context.type_error( - "type mismatch", - first_arg.span, - &context_type, - &first_arg_attr.typ, - ); - } - } else { - context.fancy_error( - "`Context` is not defined", - vec![ - Label::primary( - args.span, - "`ctx` must be defined and passed into the contract constructor", - ), - Label::secondary( - context.parent_function().name_span(context.db()), - "Note: declare `ctx` in this function signature", - ), - Label::secondary( - context.parent_function().name_span(context.db()), - "Example: `pub fn foo(ctx: Context, ...)`", - ), - ], - vec![ - "Note: import context with `use std::context::Context`".into(), - "Example: MyContract(ctx, contract_address)".into(), - ], - ); - } - } - if let Some(second_arg) = &args.kind.get(1) { - let second_arg_attr = assignable_expr(context, &second_arg.kind.value, None)?; - if second_arg_attr.typ != Type::Base(Base::Address) { - context.type_error( - "type mismatch", - second_arg.span, - &Base::Address, - &second_arg_attr.typ, - ); + if let Some(arg) = &args.kind.get(0) { + let arg_attr = assignable_expr(context, &arg.kind.value, None)?; + if arg_attr.typ != Type::Base(Base::Address) { + context.type_error("type mismatch", arg.span, &Base::Address, &arg_attr.typ); } } ExpressionAttributes::new(typ.clone(), Location::Value) @@ -1397,13 +1351,7 @@ fn expr_call_method( } let sig = method.signature(context.db()); - - let params = if is_self { - &sig.params - } else { - sig.external_params() - }; - validate_named_args(context, &field.kind, field.span, args, params)?; + validate_named_args(context, &field.kind, field.span, args, &sig.params)?; let calltype = match class { Class::Contract(contract) => { diff --git a/crates/analyzer/tests/errors.rs b/crates/analyzer/tests/errors.rs index 0def76286f..4b36fe3bf8 100644 --- a/crates/analyzer/tests/errors.rs +++ b/crates/analyzer/tests/errors.rs @@ -118,6 +118,7 @@ test_stmt! { break_without_loop, "break" } test_stmt! { break_without_loop_2, "if true { break }" } test_stmt! { call_undefined_function_on_contract, "self.doesnt_exist()" } test_stmt! { call_address_with_wrong_type, "address(true)" } +test_stmt! { call_address_with_label, "address(val: 0)" } test_stmt! { call_keccak_without_parameter, "keccak256()" } test_stmt! { call_keccak_with_wrong_type, "keccak256(true)" } test_stmt! { call_keccak_with_2_args, "keccak256(1, 2)" } @@ -323,12 +324,10 @@ test_file! { ctx_init } test_file! { ctx_pure } test_file! { ctx_undeclared } test_file! { ctx_missing_internal_call } -test_file! { ctx_passed_external_call } test_file! { ctx_missing_create } test_file! { ctx_missing_load } test_file! { ctx_missing_event } test_file! { ctx_builtins_param_incorrect_type } -test_file! { ctx_undefined_contract_init } test_file! { ctx_undefined_create } test_file! { ctx_undefined_create2 } test_file! { ctx_undefined_event } diff --git a/crates/analyzer/tests/snapshots/analysis__external_contract.snap b/crates/analyzer/tests/snapshots/analysis__external_contract.snap index 10037f97cc..ebc7c963dc 100644 --- a/crates/analyzer/tests/snapshots/analysis__external_contract.snap +++ b/crates/analyzer/tests/snapshots/analysis__external_contract.snap @@ -247,8 +247,8 @@ note: ┌─ external_contract.fe:24:5 │ 24 │ ╭ pub fn call_emit_event(ctx: Context, foo_address: address, my_num: u256, my_addrs: Array, my_string: String<11>) { -25 │ │ let foo: Foo = Foo(ctx, foo_address) -26 │ │ foo.emit_event(my_num, my_addrs, my_string) +25 │ │ let foo: Foo = Foo(foo_address) +26 │ │ foo.emit_event(ctx, my_num, my_addrs, my_string) 27 │ │ } │ ╰─────^ attributes hash: 11744736773867210426 │ @@ -324,62 +324,47 @@ note: note: ┌─ external_contract.fe:25:18 │ -25 │ let foo: Foo = Foo(ctx, foo_address) +25 │ let foo: Foo = Foo(foo_address) │ ^^^ Foo note: ┌─ external_contract.fe:25:28 │ -25 │ let foo: Foo = Foo(ctx, foo_address) - │ ^^^ ^^^^^^^^^^^ address: Value - │ │ - │ Context: Memory +25 │ let foo: Foo = Foo(foo_address) + │ ^^^^^^^^^^^ address: Value note: ┌─ external_contract.fe:25:24 │ -25 │ let foo: Foo = Foo(ctx, foo_address) - │ ^^^^^^^^^^^^^^^^^^^^^ Foo: Value -26 │ foo.emit_event(my_num, my_addrs, my_string) - │ ^^^ ^^^^^^ ^^^^^^^^ ^^^^^^^^^ String<11>: Memory - │ │ │ │ - │ │ │ Array: Memory - │ │ u256: Value +25 │ let foo: Foo = Foo(foo_address) + │ ^^^^^^^^^^^^^^^^ Foo: Value +26 │ foo.emit_event(ctx, my_num, my_addrs, my_string) + │ ^^^ ^^^ ^^^^^^ ^^^^^^^^ ^^^^^^^^^ String<11>: Memory + │ │ │ │ │ + │ │ │ │ Array: Memory + │ │ │ u256: Value + │ │ Context: Memory │ Foo: Value note: ┌─ external_contract.fe:26:9 │ -26 │ foo.emit_event(my_num, my_addrs, my_string) - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (): Value +26 │ foo.emit_event(ctx, my_num, my_addrs, my_string) + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (): Value note: ┌─ external_contract.fe:29:5 │ -29 │ ╭ pub fn call_build_array(ctx: Context, foo_address: address, a: u256, b: u256) -> Array { -30 │ │ let foo: Foo = Foo(ctx, foo_address) +29 │ ╭ pub fn call_build_array(foo_address: address, a: u256, b: u256) -> Array { +30 │ │ let foo: Foo = Foo(foo_address) 31 │ │ return foo.build_array(a, b) 32 │ │ } - │ ╰─────^ attributes hash: 14801245347360386258 + │ ╰─────^ attributes hash: 4627171240003453976 │ = FunctionSignature { self_decl: None, - ctx_decl: Some( - Mutable, - ), + ctx_decl: None, params: [ - FunctionParam { - label: None, - name: "ctx", - typ: Ok( - Struct( - Struct { - name: "Context", - field_count: 0, - }, - ), - ), - }, FunctionParam { label: None, name: "foo_address", @@ -427,22 +412,20 @@ note: note: ┌─ external_contract.fe:30:18 │ -30 │ let foo: Foo = Foo(ctx, foo_address) +30 │ let foo: Foo = Foo(foo_address) │ ^^^ Foo note: ┌─ external_contract.fe:30:28 │ -30 │ let foo: Foo = Foo(ctx, foo_address) - │ ^^^ ^^^^^^^^^^^ address: Value - │ │ - │ Context: Memory +30 │ let foo: Foo = Foo(foo_address) + │ ^^^^^^^^^^^ address: Value note: ┌─ external_contract.fe:30:24 │ -30 │ let foo: Foo = Foo(ctx, foo_address) - │ ^^^^^^^^^^^^^^^^^^^^^ Foo: Value +30 │ let foo: Foo = Foo(foo_address) + │ ^^^^^^^^^^^^^^^^ Foo: Value 31 │ return foo.build_array(a, b) │ ^^^ ^ ^ u256: Value │ │ │ diff --git a/crates/analyzer/tests/snapshots/analysis__two_contracts.snap b/crates/analyzer/tests/snapshots/analysis__two_contracts.snap index eb5476cbcd..b0a320d34e 100644 --- a/crates/analyzer/tests/snapshots/analysis__two_contracts.snap +++ b/crates/analyzer/tests/snapshots/analysis__two_contracts.snap @@ -159,31 +159,17 @@ note: note: ┌─ two_contracts.fe:23:5 │ -23 │ ╭ pub fn set_foo_addr(self, ctx: Context, _ addr: address) { -24 │ │ self.other = Foo(ctx, addr) +23 │ ╭ pub fn set_foo_addr(self, _ addr: address) { +24 │ │ self.other = Foo(addr) 25 │ │ } - │ ╰─────^ attributes hash: 736575608159807992 + │ ╰─────^ attributes hash: 3263176293298741376 │ = FunctionSignature { self_decl: Some( Mutable, ), - ctx_decl: Some( - Mutable, - ), + ctx_decl: None, params: [ - FunctionParam { - label: None, - name: "ctx", - typ: Ok( - Struct( - Struct { - name: "Context", - field_count: 0, - }, - ), - ), - }, FunctionParam { label: Some( "_", @@ -206,23 +192,22 @@ note: note: ┌─ two_contracts.fe:24:9 │ -24 │ self.other = Foo(ctx, addr) +24 │ self.other = Foo(addr) │ ^^^^ Bar: Value note: ┌─ two_contracts.fe:24:9 │ -24 │ self.other = Foo(ctx, addr) - │ ^^^^^^^^^^ ^^^ ^^^^ address: Value - │ │ │ - │ │ Context: Memory +24 │ self.other = Foo(addr) + │ ^^^^^^^^^^ ^^^^ address: Value + │ │ │ Foo: Storage { nonce: Some(0) } note: ┌─ two_contracts.fe:24:22 │ -24 │ self.other = Foo(ctx, addr) - │ ^^^^^^^^^^^^^^ Foo: Value +24 │ self.other = Foo(addr) + │ ^^^^^^^^^ Foo: Value note: ┌─ two_contracts.fe:27:5 diff --git a/crates/analyzer/tests/snapshots/analysis__uniswap.snap b/crates/analyzer/tests/snapshots/analysis__uniswap.snap index 8e33374d76..f04e8465e5 100644 --- a/crates/analyzer/tests/snapshots/analysis__uniswap.snap +++ b/crates/analyzer/tests/snapshots/analysis__uniswap.snap @@ -105,10 +105,10 @@ note: 22 │ 23 │ factory: address │ ^^^^^^^^^^^^^^^^ address -24 │ token0: address - │ ^^^^^^^^^^^^^^^ address -25 │ token1: address - │ ^^^^^^^^^^^^^^^ address +24 │ token0: ERC20 + │ ^^^^^^^^^^^^^ ERC20 +25 │ token1: ERC20 + │ ^^^^^^^^^^^^^ ERC20 26 │ 27 │ reserve0: u256 │ ^^^^^^^^^^^^^^ u256 @@ -227,7 +227,7 @@ note: ┌─ uniswap.fe:82:5 │ 82 │ ╭ pub fn token0(self) -> address { -83 │ │ return self.token0 +83 │ │ return address(self.token0) 84 │ │ } │ ╰─────^ attributes hash: 227275695522088782 │ @@ -245,22 +245,28 @@ note: } note: - ┌─ uniswap.fe:83:16 + ┌─ uniswap.fe:83:24 │ -83 │ return self.token0 - │ ^^^^ UniswapV2Pair: Value +83 │ return address(self.token0) + │ ^^^^ UniswapV2Pair: Value + +note: + ┌─ uniswap.fe:83:24 + │ +83 │ return address(self.token0) + │ ^^^^^^^^^^^ ERC20: Storage { nonce: Some(5) } => Value note: ┌─ uniswap.fe:83:16 │ -83 │ return self.token0 - │ ^^^^^^^^^^^ address: Storage { nonce: Some(5) } => Value +83 │ return address(self.token0) + │ ^^^^^^^^^^^^^^^^^^^^ address: Value note: ┌─ uniswap.fe:86:5 │ 86 │ ╭ pub fn token1(self) -> address { -87 │ │ return self.token1 +87 │ │ return address(self.token1) 88 │ │ } │ ╰─────^ attributes hash: 227275695522088782 │ @@ -278,16 +284,22 @@ note: } note: - ┌─ uniswap.fe:87:16 + ┌─ uniswap.fe:87:24 │ -87 │ return self.token1 - │ ^^^^ UniswapV2Pair: Value +87 │ return address(self.token1) + │ ^^^^ UniswapV2Pair: Value + +note: + ┌─ uniswap.fe:87:24 + │ +87 │ return address(self.token1) + │ ^^^^^^^^^^^ ERC20: Storage { nonce: Some(6) } => Value note: ┌─ uniswap.fe:87:16 │ -87 │ return self.token1 - │ ^^^^^^^^^^^ address: Storage { nonce: Some(6) } => Value +87 │ return address(self.token1) + │ ^^^^^^^^^^^^^^^^^^^^ address: Value note: ┌─ uniswap.fe:90:5 @@ -1480,12 +1492,12 @@ note: note: ┌─ uniswap.fe:139:5 │ -139 │ ╭ pub fn initialize(self, ctx: Context, token0: address, token1: address) { +139 │ ╭ pub fn initialize(self, ctx: Context, token0: ERC20, token1: ERC20) { 140 │ │ assert ctx.msg_sender() == self.factory, "UniswapV2: FORBIDDEN" 141 │ │ self.token0 = token0 142 │ │ self.token1 = token1 143 │ │ } - │ ╰─────^ attributes hash: 10460756106041683522 + │ ╰─────^ attributes hash: 18170027042989505865 │ = FunctionSignature { self_decl: Some( @@ -1511,8 +1523,10 @@ note: label: None, name: "token0", typ: Ok( - Base( - Address, + Contract( + Contract { + name: "ERC20", + }, ), ), }, @@ -1520,8 +1534,10 @@ note: label: None, name: "token1", typ: Ok( - Base( - Address, + Contract( + Contract { + name: "ERC20", + }, ), ), }, @@ -1567,9 +1583,9 @@ note: ┌─ uniswap.fe:141:9 │ 141 │ self.token0 = token0 - │ ^^^^^^^^^^^ ^^^^^^ address: Value + │ ^^^^^^^^^^^ ^^^^^^ ERC20: Value │ │ - │ address: Storage { nonce: Some(5) } + │ ERC20: Storage { nonce: Some(5) } 142 │ self.token1 = token1 │ ^^^^ UniswapV2Pair: Value @@ -1577,9 +1593,9 @@ note: ┌─ uniswap.fe:142:9 │ 142 │ self.token1 = token1 - │ ^^^^^^^^^^^ ^^^^^^ address: Value + │ ^^^^^^^^^^^ ^^^^^^ ERC20: Value │ │ - │ address: Storage { nonce: Some(6) } + │ ERC20: Storage { nonce: Some(6) } note: ┌─ uniswap.fe:146:5 @@ -1921,7 +1937,7 @@ note: ┌─ uniswap.fe:161:5 │ 161 │ ╭ fn _mint_fee(self, ctx: Context, reserve0: u256, reserve1: u256) -> bool { -162 │ │ let fee_to: address = UniswapV2Factory(ctx, self.factory).fee_to() +162 │ │ let fee_to: address = UniswapV2Factory(self.factory).fee_to() 163 │ │ let fee_on: bool = fee_to != address(0) 164 │ │ let k_last: u256 = self.k_last · │ @@ -1982,7 +1998,7 @@ note: note: ┌─ uniswap.fe:162:21 │ -162 │ let fee_to: address = UniswapV2Factory(ctx, self.factory).fee_to() +162 │ let fee_to: address = UniswapV2Factory(self.factory).fee_to() │ ^^^^^^^ address 163 │ let fee_on: bool = fee_to != address(0) │ ^^^^ bool @@ -2004,28 +2020,26 @@ note: note: ┌─ uniswap.fe:162:48 │ -162 │ let fee_to: address = UniswapV2Factory(ctx, self.factory).fee_to() - │ ^^^ ^^^^ UniswapV2Pair: Value - │ │ - │ Context: Memory +162 │ let fee_to: address = UniswapV2Factory(self.factory).fee_to() + │ ^^^^ UniswapV2Pair: Value note: - ┌─ uniswap.fe:162:53 + ┌─ uniswap.fe:162:48 │ -162 │ let fee_to: address = UniswapV2Factory(ctx, self.factory).fee_to() - │ ^^^^^^^^^^^^ address: Storage { nonce: Some(4) } => Value +162 │ let fee_to: address = UniswapV2Factory(self.factory).fee_to() + │ ^^^^^^^^^^^^ address: Storage { nonce: Some(4) } => Value note: ┌─ uniswap.fe:162:31 │ -162 │ let fee_to: address = UniswapV2Factory(ctx, self.factory).fee_to() - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UniswapV2Factory: Value +162 │ let fee_to: address = UniswapV2Factory(self.factory).fee_to() + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UniswapV2Factory: Value note: ┌─ uniswap.fe:162:31 │ -162 │ let fee_to: address = UniswapV2Factory(ctx, self.factory).fee_to() - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ address: Value +162 │ let fee_to: address = UniswapV2Factory(self.factory).fee_to() + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ address: Value 163 │ let fee_on: bool = fee_to != address(0) │ ^^^^^^ ^ u256: Value │ │ @@ -2255,9 +2269,9 @@ note: │ ^^^^ u256 188 │ let reserve1: u256 = self.reserve1 │ ^^^^ u256 -189 │ let balance0: u256 = ERC20(ctx, self.token0).balanceOf(ctx.self_address()) +189 │ let balance0: u256 = self.token0.balanceOf(ctx.self_address()) │ ^^^^ u256 -190 │ let balance1: u256 = ERC20(ctx, self.token1).balanceOf(ctx.self_address()) +190 │ let balance1: u256 = self.token1.balanceOf(ctx.self_address()) │ ^^^^ u256 191 │ let amount0: u256 = balance0 - self.reserve0 │ ^^^^ u256 @@ -2291,66 +2305,50 @@ note: │ 188 │ let reserve1: u256 = self.reserve1 │ ^^^^^^^^^^^^^ u256: Storage { nonce: Some(8) } => Value -189 │ let balance0: u256 = ERC20(ctx, self.token0).balanceOf(ctx.self_address()) - │ ^^^ ^^^^ UniswapV2Pair: Value - │ │ - │ Context: Memory - -note: - ┌─ uniswap.fe:189:41 - │ -189 │ let balance0: u256 = ERC20(ctx, self.token0).balanceOf(ctx.self_address()) - │ ^^^^^^^^^^^ address: Storage { nonce: Some(5) } => Value +189 │ let balance0: u256 = self.token0.balanceOf(ctx.self_address()) + │ ^^^^ UniswapV2Pair: Value note: ┌─ uniswap.fe:189:30 │ -189 │ let balance0: u256 = ERC20(ctx, self.token0).balanceOf(ctx.self_address()) - │ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^ Context: Memory - │ │ - │ ERC20: Value +189 │ let balance0: u256 = self.token0.balanceOf(ctx.self_address()) + │ ^^^^^^^^^^^ ^^^ Context: Memory + │ │ + │ ERC20: Storage { nonce: Some(5) } => Value note: - ┌─ uniswap.fe:189:64 + ┌─ uniswap.fe:189:52 │ -189 │ let balance0: u256 = ERC20(ctx, self.token0).balanceOf(ctx.self_address()) - │ ^^^^^^^^^^^^^^^^^^ address: Value +189 │ let balance0: u256 = self.token0.balanceOf(ctx.self_address()) + │ ^^^^^^^^^^^^^^^^^^ address: Value note: ┌─ uniswap.fe:189:30 │ -189 │ let balance0: u256 = ERC20(ctx, self.token0).balanceOf(ctx.self_address()) - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ u256: Value -190 │ let balance1: u256 = ERC20(ctx, self.token1).balanceOf(ctx.self_address()) - │ ^^^ ^^^^ UniswapV2Pair: Value - │ │ - │ Context: Memory - -note: - ┌─ uniswap.fe:190:41 - │ -190 │ let balance1: u256 = ERC20(ctx, self.token1).balanceOf(ctx.self_address()) - │ ^^^^^^^^^^^ address: Storage { nonce: Some(6) } => Value +189 │ let balance0: u256 = self.token0.balanceOf(ctx.self_address()) + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ u256: Value +190 │ let balance1: u256 = self.token1.balanceOf(ctx.self_address()) + │ ^^^^ UniswapV2Pair: Value note: ┌─ uniswap.fe:190:30 │ -190 │ let balance1: u256 = ERC20(ctx, self.token1).balanceOf(ctx.self_address()) - │ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^ Context: Memory - │ │ - │ ERC20: Value +190 │ let balance1: u256 = self.token1.balanceOf(ctx.self_address()) + │ ^^^^^^^^^^^ ^^^ Context: Memory + │ │ + │ ERC20: Storage { nonce: Some(6) } => Value note: - ┌─ uniswap.fe:190:64 + ┌─ uniswap.fe:190:52 │ -190 │ let balance1: u256 = ERC20(ctx, self.token1).balanceOf(ctx.self_address()) - │ ^^^^^^^^^^^^^^^^^^ address: Value +190 │ let balance1: u256 = self.token1.balanceOf(ctx.self_address()) + │ ^^^^^^^^^^^^^^^^^^ address: Value note: ┌─ uniswap.fe:190:30 │ -190 │ let balance1: u256 = ERC20(ctx, self.token1).balanceOf(ctx.self_address()) - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ u256: Value +190 │ let balance1: u256 = self.token1.balanceOf(ctx.self_address()) + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ u256: Value 191 │ let amount0: u256 = balance0 - self.reserve0 │ ^^^^^^^^ ^^^^ UniswapV2Pair: Value │ │ @@ -2626,7 +2624,7 @@ note: 213 │ ╭ pub fn burn(self, ctx: Context, to: address) -> (u256, u256) { 214 │ │ let reserve0: u256 = self.reserve0 215 │ │ let reserve1: u256 = self.reserve1 -216 │ │ let token0: ERC20 = ERC20(ctx, self.token0) +216 │ │ let token0: ERC20 = self.token0 · │ 237 │ │ return (amount0, amount1) 238 │ │ } @@ -2689,9 +2687,9 @@ note: │ ^^^^ u256 215 │ let reserve1: u256 = self.reserve1 │ ^^^^ u256 -216 │ let token0: ERC20 = ERC20(ctx, self.token0) +216 │ let token0: ERC20 = self.token0 │ ^^^^^ ERC20 -217 │ let token1: ERC20 = ERC20(ctx, self.token1) +217 │ let token1: ERC20 = self.token1 │ ^^^^^ ERC20 218 │ let balance0: u256 = token0.balanceOf(ctx.self_address()) │ ^^^^ u256 @@ -2728,38 +2726,22 @@ note: │ 215 │ let reserve1: u256 = self.reserve1 │ ^^^^^^^^^^^^^ u256: Storage { nonce: Some(8) } => Value -216 │ let token0: ERC20 = ERC20(ctx, self.token0) - │ ^^^ ^^^^ UniswapV2Pair: Value - │ │ - │ Context: Memory - -note: - ┌─ uniswap.fe:216:40 - │ -216 │ let token0: ERC20 = ERC20(ctx, self.token0) - │ ^^^^^^^^^^^ address: Storage { nonce: Some(5) } => Value +216 │ let token0: ERC20 = self.token0 + │ ^^^^ UniswapV2Pair: Value note: ┌─ uniswap.fe:216:29 │ -216 │ let token0: ERC20 = ERC20(ctx, self.token0) - │ ^^^^^^^^^^^^^^^^^^^^^^^ ERC20: Value -217 │ let token1: ERC20 = ERC20(ctx, self.token1) - │ ^^^ ^^^^ UniswapV2Pair: Value - │ │ - │ Context: Memory - -note: - ┌─ uniswap.fe:217:40 - │ -217 │ let token1: ERC20 = ERC20(ctx, self.token1) - │ ^^^^^^^^^^^ address: Storage { nonce: Some(6) } => Value +216 │ let token0: ERC20 = self.token0 + │ ^^^^^^^^^^^ ERC20: Storage { nonce: Some(5) } => Value +217 │ let token1: ERC20 = self.token1 + │ ^^^^ UniswapV2Pair: Value note: ┌─ uniswap.fe:217:29 │ -217 │ let token1: ERC20 = ERC20(ctx, self.token1) - │ ^^^^^^^^^^^^^^^^^^^^^^^ ERC20: Value +217 │ let token1: ERC20 = self.token1 + │ ^^^^^^^^^^^ ERC20: Storage { nonce: Some(6) } => Value 218 │ let balance0: u256 = token0.balanceOf(ctx.self_address()) │ ^^^^^^ ^^^ Context: Memory │ │ @@ -3163,9 +3145,9 @@ note: 246 │ let reserve1: u256 = self.reserve1 │ ^^^^ u256 · -249 │ let token0: ERC20 = ERC20(ctx, self.token0) +249 │ let token0: ERC20 = self.token0 │ ^^^^^ ERC20 -250 │ let token1: ERC20 = ERC20(ctx, self.token1) +250 │ let token1: ERC20 = self.token1 │ ^^^^^ ERC20 · 265 │ let balance0: u256 = token0.balanceOf(ctx.self_address()) @@ -3257,38 +3239,22 @@ note: │ │ │ bool: Value 248 │ -249 │ let token0: ERC20 = ERC20(ctx, self.token0) - │ ^^^ ^^^^ UniswapV2Pair: Value - │ │ - │ Context: Memory - -note: - ┌─ uniswap.fe:249:40 - │ -249 │ let token0: ERC20 = ERC20(ctx, self.token0) - │ ^^^^^^^^^^^ address: Storage { nonce: Some(5) } => Value +249 │ let token0: ERC20 = self.token0 + │ ^^^^ UniswapV2Pair: Value note: ┌─ uniswap.fe:249:29 │ -249 │ let token0: ERC20 = ERC20(ctx, self.token0) - │ ^^^^^^^^^^^^^^^^^^^^^^^ ERC20: Value -250 │ let token1: ERC20 = ERC20(ctx, self.token1) - │ ^^^ ^^^^ UniswapV2Pair: Value - │ │ - │ Context: Memory - -note: - ┌─ uniswap.fe:250:40 - │ -250 │ let token1: ERC20 = ERC20(ctx, self.token1) - │ ^^^^^^^^^^^ address: Storage { nonce: Some(6) } => Value +249 │ let token0: ERC20 = self.token0 + │ ^^^^^^^^^^^ ERC20: Storage { nonce: Some(5) } => Value +250 │ let token1: ERC20 = self.token1 + │ ^^^^ UniswapV2Pair: Value note: ┌─ uniswap.fe:250:29 │ -250 │ let token1: ERC20 = ERC20(ctx, self.token1) - │ ^^^^^^^^^^^^^^^^^^^^^^^ ERC20: Value +250 │ let token1: ERC20 = self.token1 + │ ^^^^^^^^^^^ ERC20: Storage { nonce: Some(6) } => Value · 253 │ assert to != address(token0) and to != address(token1), "UniswapV2: INVALID_TO" │ ^^ ^^^^^^ ERC20: Value @@ -3726,8 +3692,8 @@ note: ┌─ uniswap.fe:283:5 │ 283 │ ╭ pub fn skim(self, ctx: Context, to: address) { -284 │ │ let token0: ERC20 = ERC20(ctx, self.token0) # gas savings -285 │ │ let token1: ERC20 = ERC20(ctx, self.token1) # gas savings +284 │ │ let token0: ERC20 = self.token0 # gas savings +285 │ │ let token1: ERC20 = self.token1 # gas savings 286 │ │ token0.transfer(to, token0.balanceOf(ctx.self_address()) - self.reserve0) 287 │ │ token1.transfer(to, token1.balanceOf(ctx.self_address()) - self.reserve1) 288 │ │ } @@ -3773,46 +3739,30 @@ note: note: ┌─ uniswap.fe:284:21 │ -284 │ let token0: ERC20 = ERC20(ctx, self.token0) # gas savings +284 │ let token0: ERC20 = self.token0 # gas savings │ ^^^^^ ERC20 -285 │ let token1: ERC20 = ERC20(ctx, self.token1) # gas savings +285 │ let token1: ERC20 = self.token1 # gas savings │ ^^^^^ ERC20 -note: - ┌─ uniswap.fe:284:35 - │ -284 │ let token0: ERC20 = ERC20(ctx, self.token0) # gas savings - │ ^^^ ^^^^ UniswapV2Pair: Value - │ │ - │ Context: Memory - -note: - ┌─ uniswap.fe:284:40 - │ -284 │ let token0: ERC20 = ERC20(ctx, self.token0) # gas savings - │ ^^^^^^^^^^^ address: Storage { nonce: Some(5) } => Value - note: ┌─ uniswap.fe:284:29 │ -284 │ let token0: ERC20 = ERC20(ctx, self.token0) # gas savings - │ ^^^^^^^^^^^^^^^^^^^^^^^ ERC20: Value -285 │ let token1: ERC20 = ERC20(ctx, self.token1) # gas savings - │ ^^^ ^^^^ UniswapV2Pair: Value - │ │ - │ Context: Memory +284 │ let token0: ERC20 = self.token0 # gas savings + │ ^^^^ UniswapV2Pair: Value note: - ┌─ uniswap.fe:285:40 + ┌─ uniswap.fe:284:29 │ -285 │ let token1: ERC20 = ERC20(ctx, self.token1) # gas savings - │ ^^^^^^^^^^^ address: Storage { nonce: Some(6) } => Value +284 │ let token0: ERC20 = self.token0 # gas savings + │ ^^^^^^^^^^^ ERC20: Storage { nonce: Some(5) } => Value +285 │ let token1: ERC20 = self.token1 # gas savings + │ ^^^^ UniswapV2Pair: Value note: ┌─ uniswap.fe:285:29 │ -285 │ let token1: ERC20 = ERC20(ctx, self.token1) # gas savings - │ ^^^^^^^^^^^^^^^^^^^^^^^ ERC20: Value +285 │ let token1: ERC20 = self.token1 # gas savings + │ ^^^^^^^^^^^ ERC20: Storage { nonce: Some(6) } => Value 286 │ token0.transfer(to, token0.balanceOf(ctx.self_address()) - self.reserve0) │ ^^^^^^ ^^ ^^^^^^ ^^^ Context: Memory │ │ │ │ @@ -3894,8 +3844,8 @@ note: ┌─ uniswap.fe:291:5 │ 291 │ ╭ pub fn sync(self, ctx: Context) { -292 │ │ let token0: ERC20 = ERC20(ctx, self.token0) -293 │ │ let token1: ERC20 = ERC20(ctx, self.token1) +292 │ │ let token0: ERC20 = self.token0 +293 │ │ let token1: ERC20 = self.token1 294 │ │ self._update(ctx, · │ 298 │ │ reserve1: self.reserve1) @@ -3933,46 +3883,30 @@ note: note: ┌─ uniswap.fe:292:21 │ -292 │ let token0: ERC20 = ERC20(ctx, self.token0) +292 │ let token0: ERC20 = self.token0 │ ^^^^^ ERC20 -293 │ let token1: ERC20 = ERC20(ctx, self.token1) +293 │ let token1: ERC20 = self.token1 │ ^^^^^ ERC20 -note: - ┌─ uniswap.fe:292:35 - │ -292 │ let token0: ERC20 = ERC20(ctx, self.token0) - │ ^^^ ^^^^ UniswapV2Pair: Value - │ │ - │ Context: Memory - -note: - ┌─ uniswap.fe:292:40 - │ -292 │ let token0: ERC20 = ERC20(ctx, self.token0) - │ ^^^^^^^^^^^ address: Storage { nonce: Some(5) } => Value - note: ┌─ uniswap.fe:292:29 │ -292 │ let token0: ERC20 = ERC20(ctx, self.token0) - │ ^^^^^^^^^^^^^^^^^^^^^^^ ERC20: Value -293 │ let token1: ERC20 = ERC20(ctx, self.token1) - │ ^^^ ^^^^ UniswapV2Pair: Value - │ │ - │ Context: Memory +292 │ let token0: ERC20 = self.token0 + │ ^^^^ UniswapV2Pair: Value note: - ┌─ uniswap.fe:293:40 + ┌─ uniswap.fe:292:29 │ -293 │ let token1: ERC20 = ERC20(ctx, self.token1) - │ ^^^^^^^^^^^ address: Storage { nonce: Some(6) } => Value +292 │ let token0: ERC20 = self.token0 + │ ^^^^^^^^^^^ ERC20: Storage { nonce: Some(5) } => Value +293 │ let token1: ERC20 = self.token1 + │ ^^^^ UniswapV2Pair: Value note: ┌─ uniswap.fe:293:29 │ -293 │ let token1: ERC20 = ERC20(ctx, self.token1) - │ ^^^^^^^^^^^^^^^^^^^^^^^ ERC20: Value +293 │ let token1: ERC20 = self.token1 + │ ^^^^^^^^^^^ ERC20: Storage { nonce: Some(6) } => Value 294 │ self._update(ctx, │ ^^^^ ^^^ Context: Memory │ │ @@ -4386,17 +4320,31 @@ note: │ 343 │ let pair: UniswapV2Pair = UniswapV2Pair.create2(ctx, 0, salt) │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UniswapV2Pair: Value -344 │ pair.initialize(token0, token1) - │ ^^^^ ^^^^^^ ^^^^^^ address: Value - │ │ │ - │ │ address: Value +344 │ pair.initialize(ctx, token0: ERC20(token0), token1: ERC20(token1)) + │ ^^^^ ^^^ ^^^^^^ address: Value + │ │ │ + │ │ Context: Memory │ UniswapV2Pair: Value +note: + ┌─ uniswap.fe:344:38 + │ +344 │ pair.initialize(ctx, token0: ERC20(token0), token1: ERC20(token1)) + │ ^^^^^^^^^^^^^ ^^^^^^ address: Value + │ │ + │ ERC20: Value + +note: + ┌─ uniswap.fe:344:61 + │ +344 │ pair.initialize(ctx, token0: ERC20(token0), token1: ERC20(token1)) + │ ^^^^^^^^^^^^^ ERC20: Value + note: ┌─ uniswap.fe:344:9 │ -344 │ pair.initialize(token0, token1) - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (): Value +344 │ pair.initialize(ctx, token0: ERC20(token0), token1: ERC20(token1)) + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (): Value 345 │ 346 │ self.pairs[token0][token1] = address(pair) │ ^^^^ UniswapV2Factory: Value diff --git a/crates/analyzer/tests/snapshots/errors__bad_visibility.snap b/crates/analyzer/tests/snapshots/errors__bad_visibility.snap index c3a0da1ab1..1470def937 100644 --- a/crates/analyzer/tests/snapshots/errors__bad_visibility.snap +++ b/crates/analyzer/tests/snapshots/errors__bad_visibility.snap @@ -148,7 +148,7 @@ error: the function `my_func` is private error: the type `MyContract` is private ┌─ compile_errors/bad_visibility/src/main.fe:27:16 │ -27 │ let _: MyContract = MyContract(ctx, addr) +27 │ let _: MyContract = MyContract(addr) │ ^^^^^^^^^^ this type is not `pub` │ ┌─ compile_errors/bad_visibility/src/foo.fe:15:10 @@ -162,7 +162,7 @@ error: the type `MyContract` is private error: the type `MyContract` is private ┌─ compile_errors/bad_visibility/src/main.fe:27:29 │ -27 │ let _: MyContract = MyContract(ctx, addr) +27 │ let _: MyContract = MyContract(addr) │ ^^^^^^^^^^ this type is not `pub` │ ┌─ compile_errors/bad_visibility/src/foo.fe:15:10 diff --git a/crates/analyzer/tests/snapshots/errors__call_address_with_label.snap b/crates/analyzer/tests/snapshots/errors__call_address_with_label.snap new file mode 100644 index 0000000000..105913a34f --- /dev/null +++ b/crates/analyzer/tests/snapshots/errors__call_address_with_label.snap @@ -0,0 +1,12 @@ +--- +source: crates/analyzer/tests/errors.rs +expression: "error_string(\"[snippet]\", &src)" + +--- +error: argument should not be labeled + ┌─ [snippet]:3:11 + │ +3 │ address(val: 0) + │ ^^^ remove this label + + diff --git a/crates/analyzer/tests/snapshots/errors__call_non_pub_fn_on_external_contract.snap b/crates/analyzer/tests/snapshots/errors__call_non_pub_fn_on_external_contract.snap index a902afe449..e5f8c8da80 100644 --- a/crates/analyzer/tests/snapshots/errors__call_non_pub_fn_on_external_contract.snap +++ b/crates/analyzer/tests/snapshots/errors__call_non_pub_fn_on_external_contract.snap @@ -4,14 +4,14 @@ expression: "error_string(&path, test_files::fixture(path))" --- error: the function `do_private_thingz` on `contract Foo` is private - ┌─ compile_errors/call_non_pub_fn_on_external_contract.fe:13:30 + ┌─ compile_errors/call_non_pub_fn_on_external_contract.fe:13:25 │ 6 │ ╭ fn do_private_thingz(self) { 7 │ │ self.val = 100 8 │ │ } │ ╰─────' `do_private_thingz` is defined here · │ -13 │ Foo(ctx, address(0)).do_private_thingz() - │ ^^^^^^^^^^^^^^^^^ this function is not `pub` +13 │ Foo(address(0)).do_private_thingz() + │ ^^^^^^^^^^^^^^^^^ this function is not `pub` diff --git a/crates/analyzer/tests/snapshots/errors__call_undefined_function_on_external_contract.snap b/crates/analyzer/tests/snapshots/errors__call_undefined_function_on_external_contract.snap index efbbf739ad..3add5d1192 100644 --- a/crates/analyzer/tests/snapshots/errors__call_undefined_function_on_external_contract.snap +++ b/crates/analyzer/tests/snapshots/errors__call_undefined_function_on_external_contract.snap @@ -4,9 +4,9 @@ expression: "error_string(&path, test_files::fixture(path))" --- error: No function `doesnt_exist` exists on type `Foo` - ┌─ compile_errors/call_undefined_function_on_external_contract.fe:9:30 + ┌─ compile_errors/call_undefined_function_on_external_contract.fe:9:25 │ -9 │ Foo(ctx, address(0)).doesnt_exist() - │ ^^^^^^^^^^^^ undefined function +9 │ Foo(address(0)).doesnt_exist() + │ ^^^^^^^^^^^^ 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 385926345b..0de7c91454 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 @@ -3,11 +3,19 @@ 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:13:35 + │ +13 │ let existing_barn: Barn = Barn("hello world", address(0)) + │ ^^^^ ------------- ---------- supplied 2 arguments + │ │ + │ expects 1 argument + error: type mismatch ┌─ compile_errors/ctx_builtins_param_incorrect_type.fe:13:40 │ 13 │ let existing_barn: Barn = Barn("hello world", address(0)) - │ ^^^^^^^^^^^^^ this has type `String<11>`; expected type `Context` + │ ^^^^^^^^^^^^^ this has type `String<11>`; expected type `address` error: incorrect type for argument to `Barn.create` ┌─ compile_errors/ctx_builtins_param_incorrect_type.fe:14:46 diff --git a/crates/analyzer/tests/snapshots/errors__ctx_missing_load.snap b/crates/analyzer/tests/snapshots/errors__ctx_missing_load.snap index 36b6261eb5..43e249b020 100644 --- a/crates/analyzer/tests/snapshots/errors__ctx_missing_load.snap +++ b/crates/analyzer/tests/snapshots/errors__ctx_missing_load.snap @@ -3,18 +3,10 @@ source: crates/analyzer/tests/errors.rs expression: "error_string(&path, test_files::fixture(path))" --- -error: `Foo` expects 2 arguments, but 1 was provided - ┌─ compile_errors/ctx_missing_load.fe:9:9 - │ -9 │ Foo(0) - │ ^^^ - supplied 1 argument - │ │ - │ expects 2 arguments - error: type mismatch ┌─ compile_errors/ctx_missing_load.fe:9:13 │ 9 │ Foo(0) - │ ^ this has type `u256`; expected type `Context` + │ ^ this has type `u256`; expected type `address` diff --git a/crates/analyzer/tests/snapshots/errors__external_call_type_error.snap b/crates/analyzer/tests/snapshots/errors__external_call_type_error.snap index 9dcacfec6d..10e5107b62 100644 --- a/crates/analyzer/tests/snapshots/errors__external_call_type_error.snap +++ b/crates/analyzer/tests/snapshots/errors__external_call_type_error.snap @@ -4,9 +4,9 @@ expression: "error_string(&path, test_files::fixture(path))" --- error: incorrect type for `bar` argument at position 0 - ┌─ compile_errors/external_call_type_error.fe:9:34 + ┌─ compile_errors/external_call_type_error.fe:9:29 │ -9 │ Foo(ctx, address(0)).bar("hello world") - │ ^^^^^^^^^^^^^ this has type `String<11>`; expected type `u256` +9 │ Foo(address(0)).bar("hello world") + │ ^^^^^^^^^^^^^ this has type `String<11>`; expected type `u256` diff --git a/crates/analyzer/tests/snapshots/errors__external_call_wrong_number_of_params.snap b/crates/analyzer/tests/snapshots/errors__external_call_wrong_number_of_params.snap index bb99fd353a..35adf72d4b 100644 --- a/crates/analyzer/tests/snapshots/errors__external_call_wrong_number_of_params.snap +++ b/crates/analyzer/tests/snapshots/errors__external_call_wrong_number_of_params.snap @@ -4,18 +4,18 @@ expression: "error_string(&path, test_files::fixture(path))" --- error: `bar` expects 2 arguments, but 1 was provided - ┌─ compile_errors/external_call_wrong_number_of_params.fe:9:30 + ┌─ compile_errors/external_call_wrong_number_of_params.fe:9:25 │ -9 │ Foo(ctx, address(0)).bar(42) - │ ^^^ -- supplied 1 argument - │ │ - │ expects 2 arguments +9 │ Foo(address(0)).bar(42) + │ ^^^ -- supplied 1 argument + │ │ + │ expects 2 arguments error: missing argument label - ┌─ compile_errors/external_call_wrong_number_of_params.fe:9:34 + ┌─ compile_errors/external_call_wrong_number_of_params.fe:9:29 │ -9 │ Foo(ctx, address(0)).bar(42) - │ ^ add `a:` here +9 │ Foo(address(0)).bar(42) + │ ^ add `a:` here │ = Note: this label is optional if the argument is a variable named `a`. diff --git a/crates/analyzer/tests/snapshots/errors__mislabeled_call_args_external_contract_call.snap b/crates/analyzer/tests/snapshots/errors__mislabeled_call_args_external_contract_call.snap index 0102c190d4..6d5dd0c516 100644 --- a/crates/analyzer/tests/snapshots/errors__mislabeled_call_args_external_contract_call.snap +++ b/crates/analyzer/tests/snapshots/errors__mislabeled_call_args_external_contract_call.snap @@ -3,6 +3,20 @@ source: crates/analyzer/tests/errors.rs expression: "error_string(&path, test_files::fixture(path))" --- +error: `Foo` expects 1 argument, but 2 were provided + ┌─ compile_errors/mislabeled_call_args_external_contract_call.fe:11:9 + │ +11 │ Foo(ctx, address(0)).baz(doesnt_exist: 1, me_neither: 4) + │ ^^^ --- ---------- supplied 2 arguments + │ │ + │ expects 1 argument + +error: type mismatch + ┌─ compile_errors/mislabeled_call_args_external_contract_call.fe:11:13 + │ +11 │ Foo(ctx, address(0)).baz(doesnt_exist: 1, me_neither: 4) + │ ^^^ this has type `Context`; expected type `address` + error: argument label mismatch ┌─ compile_errors/mislabeled_call_args_external_contract_call.fe:11:34 │ diff --git a/crates/test-files/fixtures/compile_errors/bad_visibility/src/main.fe b/crates/test-files/fixtures/compile_errors/bad_visibility/src/main.fe index e66ba402fb..ab55b559c8 100644 --- a/crates/test-files/fixtures/compile_errors/bad_visibility/src/main.fe +++ b/crates/test-files/fixtures/compile_errors/bad_visibility/src/main.fe @@ -24,7 +24,7 @@ contract Main { } pub fn priv_contract(ctx: Context, addr: address) { - let _: MyContract = MyContract(ctx, addr) + let _: MyContract = MyContract(addr) MyContract.create(ctx, 1) } } diff --git a/crates/test-files/fixtures/compile_errors/call_call_on_external_contract.fe b/crates/test-files/fixtures/compile_errors/call_call_on_external_contract.fe index 1f5a704ec5..e5d44e5811 100644 --- a/crates/test-files/fixtures/compile_errors/call_call_on_external_contract.fe +++ b/crates/test-files/fixtures/compile_errors/call_call_on_external_contract.fe @@ -8,7 +8,7 @@ contract Foo { contract Bar { fn b(ctx: Context) { - let foo: Foo = Foo(ctx, address(0)) + let foo: Foo = Foo(address(0)) foo.__call__() } } diff --git a/crates/test-files/fixtures/compile_errors/call_non_pub_fn_on_external_contract.fe b/crates/test-files/fixtures/compile_errors/call_non_pub_fn_on_external_contract.fe index 93869ae5df..897120d42a 100644 --- a/crates/test-files/fixtures/compile_errors/call_non_pub_fn_on_external_contract.fe +++ b/crates/test-files/fixtures/compile_errors/call_non_pub_fn_on_external_contract.fe @@ -9,7 +9,7 @@ contract Foo { } contract Bar { - fn test(ctx: Context) { - Foo(ctx, address(0)).do_private_thingz() + fn test() { + Foo(address(0)).do_private_thingz() } } diff --git a/crates/test-files/fixtures/compile_errors/call_undefined_function_on_external_contract.fe b/crates/test-files/fixtures/compile_errors/call_undefined_function_on_external_contract.fe index cc108a5d7a..ecf4fb4b45 100644 --- a/crates/test-files/fixtures/compile_errors/call_undefined_function_on_external_contract.fe +++ b/crates/test-files/fixtures/compile_errors/call_undefined_function_on_external_contract.fe @@ -5,7 +5,7 @@ contract Foo { } contract Bar { - pub fn test(ctx: Context) { - Foo(ctx, address(0)).doesnt_exist() + pub fn test() { + Foo(address(0)).doesnt_exist() } } diff --git a/crates/test-files/fixtures/compile_errors/ctx_passed_external_call.fe b/crates/test-files/fixtures/compile_errors/ctx_passed_external_call.fe deleted file mode 100644 index 22a1397cf8..0000000000 --- a/crates/test-files/fixtures/compile_errors/ctx_passed_external_call.fe +++ /dev/null @@ -1,16 +0,0 @@ -use std::context::Context - -contract Foo { - pub fn bar(ctx: Context) -> u256 { - return ctx.block_number() - } -} - -contract Bing { - favorite_number: u256 - - pub fn baz(self, ctx: Context) { - let foo: Foo = Foo.create(ctx, 0) - self.favorite_number = foo.bar(ctx) - } -} diff --git a/crates/test-files/fixtures/compile_errors/ctx_undefined_contract_init.fe b/crates/test-files/fixtures/compile_errors/ctx_undefined_contract_init.fe deleted file mode 100644 index 916fb95cd6..0000000000 --- a/crates/test-files/fixtures/compile_errors/ctx_undefined_contract_init.fe +++ /dev/null @@ -1,7 +0,0 @@ -contract Bar {} - -contract Foo { - pub fn baz() { - Bar(address(0)) - } -} diff --git a/crates/test-files/fixtures/compile_errors/external_call_type_error.fe b/crates/test-files/fixtures/compile_errors/external_call_type_error.fe index 33398e30b6..62feff65dd 100644 --- a/crates/test-files/fixtures/compile_errors/external_call_type_error.fe +++ b/crates/test-files/fixtures/compile_errors/external_call_type_error.fe @@ -5,7 +5,7 @@ contract Foo { } contract FooProxy { - pub fn baz(ctx: Context) { - Foo(ctx, address(0)).bar("hello world") + pub fn baz() { + Foo(address(0)).bar("hello world") } } diff --git a/crates/test-files/fixtures/compile_errors/external_call_wrong_number_of_params.fe b/crates/test-files/fixtures/compile_errors/external_call_wrong_number_of_params.fe index 29dd9b068f..d2b3466ac7 100644 --- a/crates/test-files/fixtures/compile_errors/external_call_wrong_number_of_params.fe +++ b/crates/test-files/fixtures/compile_errors/external_call_wrong_number_of_params.fe @@ -5,7 +5,7 @@ contract Foo { } contract FooProxy { - pub fn baz(ctx: Context) { - Foo(ctx, address(0)).bar(42) + pub fn baz() { + Foo(address(0)).bar(42) } } diff --git a/crates/test-files/fixtures/compile_errors/init_call_on_external_contract.fe b/crates/test-files/fixtures/compile_errors/init_call_on_external_contract.fe index 75fa1f96c0..b29515abdd 100644 --- a/crates/test-files/fixtures/compile_errors/init_call_on_external_contract.fe +++ b/crates/test-files/fixtures/compile_errors/init_call_on_external_contract.fe @@ -8,7 +8,7 @@ contract Foo { contract Bar { fn b(ctx: Context) { - let foo: Foo = Foo(ctx, address(0)) + let foo: Foo = Foo(address(0)) foo.f() foo.__init__() } diff --git a/crates/test-files/fixtures/demos/uniswap.fe b/crates/test-files/fixtures/demos/uniswap.fe index 7fbc0eda1e..0051203085 100644 --- a/crates/test-files/fixtures/demos/uniswap.fe +++ b/crates/test-files/fixtures/demos/uniswap.fe @@ -21,8 +21,8 @@ contract UniswapV2Pair { nonces: Map factory: address - token0: address - token1: address + token0: ERC20 + token1: ERC20 reserve0: u256 reserve1: u256 @@ -80,11 +80,11 @@ contract UniswapV2Pair { } pub fn token0(self) -> address { - return self.token0 + return address(self.token0) } pub fn token1(self) -> address { - return self.token1 + return address(self.token1) } fn _mint(self, ctx: Context, to: address, value: u256) { @@ -136,7 +136,7 @@ contract UniswapV2Pair { } # called once by the factory at time of deployment - pub fn initialize(self, ctx: Context, token0: address, token1: address) { + pub fn initialize(self, ctx: Context, token0: ERC20, token1: ERC20) { assert ctx.msg_sender() == self.factory, "UniswapV2: FORBIDDEN" self.token0 = token0 self.token1 = token1 @@ -159,7 +159,7 @@ contract UniswapV2Pair { } fn _mint_fee(self, ctx: Context, reserve0: u256, reserve1: u256) -> bool { - let fee_to: address = UniswapV2Factory(ctx, self.factory).fee_to() + let fee_to: address = UniswapV2Factory(self.factory).fee_to() let fee_on: bool = fee_to != address(0) let k_last: u256 = self.k_last if fee_on { @@ -186,8 +186,8 @@ contract UniswapV2Pair { let MINIMUM_LIQUIDITY: u256 = 1000 let reserve0: u256 = self.reserve0 let reserve1: u256 = self.reserve1 - let balance0: u256 = ERC20(ctx, self.token0).balanceOf(ctx.self_address()) - let balance1: u256 = ERC20(ctx, self.token1).balanceOf(ctx.self_address()) + let balance0: u256 = self.token0.balanceOf(ctx.self_address()) + let balance1: u256 = self.token1.balanceOf(ctx.self_address()) let amount0: u256 = balance0 - self.reserve0 let amount1: u256 = balance1 - self.reserve1 let fee_on: bool = self._mint_fee(ctx, reserve0, reserve1) @@ -213,8 +213,8 @@ contract UniswapV2Pair { pub fn burn(self, ctx: Context, to: address) -> (u256, u256) { let reserve0: u256 = self.reserve0 let reserve1: u256 = self.reserve1 - let token0: ERC20 = ERC20(ctx, self.token0) - let token1: ERC20 = ERC20(ctx, self.token1) + let token0: ERC20 = self.token0 + let token1: ERC20 = self.token1 let balance0: u256 = token0.balanceOf(ctx.self_address()) let balance1: u256 = token1.balanceOf(ctx.self_address()) let liquidity: u256 = self.balances[ctx.self_address()] @@ -246,8 +246,8 @@ contract UniswapV2Pair { let reserve1: u256 = self.reserve1 assert amount0_out < reserve0 and amount1_out < reserve1, "UniswapV2: INSUFFICIENT_LIQUIDITY" - let token0: ERC20 = ERC20(ctx, self.token0) - let token1: ERC20 = ERC20(ctx, self.token1) + let token0: ERC20 = self.token0 + let token1: ERC20 = self.token1 # TODO: we should be using `token0.address` (https://github.com/ethereum/fe/issues/287) assert to != address(token0) and to != address(token1), "UniswapV2: INVALID_TO" @@ -281,16 +281,16 @@ contract UniswapV2Pair { # force balances to match reserves pub fn skim(self, ctx: Context, to: address) { - let token0: ERC20 = ERC20(ctx, self.token0) # gas savings - let token1: ERC20 = ERC20(ctx, self.token1) # gas savings + let token0: ERC20 = self.token0 # gas savings + let token1: ERC20 = self.token1 # gas savings token0.transfer(to, token0.balanceOf(ctx.self_address()) - self.reserve0) token1.transfer(to, token1.balanceOf(ctx.self_address()) - self.reserve1) } # force reserves to match balances pub fn sync(self, ctx: Context) { - let token0: ERC20 = ERC20(ctx, self.token0) - let token1: ERC20 = ERC20(ctx, self.token1) + let token0: ERC20 = self.token0 + let token1: ERC20 = self.token1 self._update(ctx, balance0: token0.balanceOf(ctx.self_address()), balance1: token1.balanceOf(ctx.self_address()), @@ -341,7 +341,7 @@ contract UniswapV2Factory { let salt: u256 = keccak256((token0, token1).abi_encode()) let pair: UniswapV2Pair = UniswapV2Pair.create2(ctx, 0, salt) - pair.initialize(token0, token1) + pair.initialize(ctx, token0: ERC20(token0), token1: ERC20(token1)) self.pairs[token0][token1] = address(pair) self.pairs[token1][token0] = address(pair) 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 c4e6e7c43b..c959e2b315 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 @@ -15,8 +15,8 @@ contract Foo { contract Bar { pub fn call_baz(ctx: Context, foo_addr: address) -> u256 { - let foo: Foo = Foo(ctx, foo_addr) - return foo.baz() + let foo: Foo = Foo(foo_addr) + return foo.baz(ctx) } pub fn call_bing(ctx: Context) -> u256 { diff --git a/crates/test-files/fixtures/features/external_contract.fe b/crates/test-files/fixtures/features/external_contract.fe index 9a04e61aa9..54a0512960 100644 --- a/crates/test-files/fixtures/features/external_contract.fe +++ b/crates/test-files/fixtures/features/external_contract.fe @@ -22,12 +22,12 @@ contract Foo { contract FooProxy { pub fn call_emit_event(ctx: Context, foo_address: address, my_num: u256, my_addrs: Array, my_string: String<11>) { - let foo: Foo = Foo(ctx, foo_address) - foo.emit_event(my_num, my_addrs, my_string) + let foo: Foo = Foo(foo_address) + foo.emit_event(ctx, my_num, my_addrs, my_string) } - pub fn call_build_array(ctx: Context, foo_address: address, a: u256, b: u256) -> Array { - let foo: Foo = Foo(ctx, foo_address) + pub fn call_build_array(foo_address: address, a: u256, b: u256) -> Array { + let foo: Foo = Foo(foo_address) return foo.build_array(a, b) } } diff --git a/crates/test-files/fixtures/features/two_contracts.fe b/crates/test-files/fixtures/features/two_contracts.fe index 63662b4f5d..93d89c1f7f 100644 --- a/crates/test-files/fixtures/features/two_contracts.fe +++ b/crates/test-files/fixtures/features/two_contracts.fe @@ -20,8 +20,8 @@ contract Foo { contract Bar { other: Foo - pub fn set_foo_addr(self, ctx: Context, _ addr: address) { - self.other = Foo(ctx, addr) + pub fn set_foo_addr(self, _ addr: address) { + self.other = Foo(addr) } pub fn answer(self) -> u256 { diff --git a/crates/test-files/fixtures/stress/external_calls.fe b/crates/test-files/fixtures/stress/external_calls.fe index 56dbf5c0d7..78b5281404 100644 --- a/crates/test-files/fixtures/stress/external_calls.fe +++ b/crates/test-files/fixtures/stress/external_calls.fe @@ -61,8 +61,8 @@ contract Foo { contract FooProxy { foo: Foo - pub fn __init__(self, ctx: Context, foo_addr: address) { - self.foo = Foo(ctx, foo_addr) + pub fn __init__(self, foo_addr: address) { + self.foo = Foo(foo_addr) } pub fn call_set_my_string(self, some_string: String<100>) { diff --git a/crates/tests/src/snapshots/fe_compiler_tests__demo_uniswap__uniswap_contracts.snap b/crates/tests/src/snapshots/fe_compiler_tests__demo_uniswap__uniswap_contracts.snap index 6d53efabb0..797759f9dd 100644 --- a/crates/tests/src/snapshots/fe_compiler_tests__demo_uniswap__uniswap_contracts.snap +++ b/crates/tests/src/snapshots/fe_compiler_tests__demo_uniswap__uniswap_contracts.snap @@ -1,6 +1,7 @@ --- source: crates/tests/src/demo_uniswap.rs expression: "format!(\"{}\", pair_harness.gas_reporter)" + --- factory([]) used 275 gas token0([]) used 297 gas @@ -11,7 +12,7 @@ balanceOf([Address(0x0000000000000000000000000000000000000000)]) used 628 gas get_reserves([]) used 801 gas swap([Uint(1993), Uint(0), Address(0x0000000000000000000000000000000000000042)]) used 36368 gas get_reserves([]) used 801 gas -transfer([Address(0xffb8f605926b517aff3e271e76904afb4b9999b2), Uint(141421356237309503880)]) used 5802 gas +transfer([Address(0xfe56bcfd2347f902e355bce7d8616526aa5c064c), Uint(141421356237309503880)]) used 5802 gas burn([Address(0x1000000000000000000000000000000000000001)]) used 3650 gas get_reserves([]) used 801 gas diff --git a/docs/validate_doc_examples.py b/docs/validate_doc_examples.py index b4dfbaebc9..3ba113830c 100755 --- a/docs/validate_doc_examples.py +++ b/docs/validate_doc_examples.py @@ -8,6 +8,7 @@ THIS_DIR = pathlib.Path(__file__).parent BOOK_SRC_DIR = THIS_DIR / 'src' TMP_SNIPPET_DIR = THIS_DIR / 'tmp_snippets' +NEWS_DIR = THIS_DIR.parent / 'newsfragments' # use ```fe,ignore on snippets that shouldn't be tested CODE_SNIPPET_START_MARKER = '```fe' @@ -30,6 +31,8 @@ def unique_name(self) -> str: def get_all_doc_files() -> Iterable[pathlib.Path]: for path in BOOK_SRC_DIR.rglob('*.md'): yield path + for path in NEWS_DIR.rglob('*.md'): + yield path def get_all_snippets_in_file(path: pathlib.Path) -> Iterable[CodeSnippet]: with open(path) as f: diff --git a/newsfragments/703.feature.md b/newsfragments/703.feature.md new file mode 100644 index 0000000000..de64478c31 --- /dev/null +++ b/newsfragments/703.feature.md @@ -0,0 +1,22 @@ +Made some small changes to how the `Context` object is used. + +- `ctx` is not required when casting an address to a contract type. Eg `let foo: Foo = Foo(address(0))` +- `ctx` is required when calling an external contract function that requires ctx + +Example: + +```fe +use std::context::Context # see issue #679 + +contract Foo { + pub fn emit_stuff(ctx: Context) { + emit Stuff(ctx) # will be `ctx.emit(Stuff{})` someday + } +} +contract Bar { + pub fn call_foo_emit_stuff(ctx: Context) { + Foo(address(0)).emit_stuff(ctx) + } +} +event Stuff {} +``` diff --git a/newsfragments/707.feature.md b/newsfragments/707.feature.md index 379441dfb3..1c7725d697 100644 --- a/newsfragments/707.feature.md +++ b/newsfragments/707.feature.md @@ -5,7 +5,7 @@ In addition, `elif` is now spelled `else if`, and the `pass` statement no longer exists. Example: -``` +```fe pub struct SomeError {} contract Foo {