diff --git a/crates/analyzer/src/db/queries/functions.rs b/crates/analyzer/src/db/queries/functions.rs index 13d5575d31..c0e3835d55 100644 --- a/crates/analyzer/src/db/queries/functions.rs +++ b/crates/analyzer/src/db/queries/functions.rs @@ -131,6 +131,14 @@ pub fn function_signature( }); if let Some(context_type) = scope.get_context_type() { + if arg.name() == "ctx" && typ.as_ref().map(|val| val.deref(db)) != Ok(context_type) { + scope.error( + "`ctx` is reserved for instances of `Context`", + arg.span, + "`ctx` must be an instance of `Context`", + ); + }; + if typ.as_ref().map(|val| val.deref(db)) == Ok(context_type) { if arg.name() != "ctx" { scope.error( diff --git a/crates/analyzer/src/db/queries/module.rs b/crates/analyzer/src/db/queries/module.rs index d673b55785..37286fa1e9 100644 --- a/crates/analyzer/src/db/queries/module.rs +++ b/crates/analyzer/src/db/queries/module.rs @@ -177,23 +177,33 @@ pub fn module_item_map( if function.is_test(db) { if !sig_ast.generic_params.kind.is_empty() { diagnostics.push(errors::fancy_error( - "generic function parameters are not supported on test functions", + "generic parameters are not supported on test functions", vec![Label::primary( sig_ast.generic_params.span, - "this cannot appear here", + "invalid generic parameters", )], vec!["Hint: remove the generic parameters".into()], )); } - if !sig_ast.args.is_empty() { - let span = - sig_ast.args.first().unwrap().span + sig_ast.args.last().unwrap().span; - diagnostics.push(errors::fancy_error( - "function parameters are not supported on test functions", - vec![Label::primary(span, "this cannot appear here")], - vec!["Hint: remove the parameters".into()], - )); + if let Some(arg) = sig_ast.args.first() { + if arg.name() != "ctx" { + diagnostics.push(errors::fancy_error( + "function parameters other than `ctx` are not supported on test functions", + vec![Label::primary(arg.span, "invalid function parameter")], + vec!["Hint: remove the parameter".into()], + )); + } + } + + for arg in sig_ast.args.iter().skip(1) { + if arg.name() != "ctx" { + diagnostics.push(errors::fancy_error( + "function parameters other than `ctx` are not supported on test functions", + vec![Label::primary(arg.span, "invalid function parameter")], + vec!["Hint: remove the parameter".into()], + )); + } } } } diff --git a/crates/analyzer/tests/errors.rs b/crates/analyzer/tests/errors.rs index 1e109116e3..cd91992c8b 100644 --- a/crates/analyzer/tests/errors.rs +++ b/crates/analyzer/tests/errors.rs @@ -341,6 +341,7 @@ test_ingot! { mainless_ingot } test_ingot! { bad_visibility } test_file! { ctx_not_first } +test_file! { ctx_not_ctx_type } test_file! { ctx_not_after_self } test_file! { ctx_init } test_file! { ctx_undeclared } diff --git a/crates/analyzer/tests/snapshots/errors___test_fn_params.snap b/crates/analyzer/tests/snapshots/errors___test_fn_params.snap index fc6657e8d2..752486b112 100644 --- a/crates/analyzer/tests/snapshots/errors___test_fn_params.snap +++ b/crates/analyzer/tests/snapshots/errors___test_fn_params.snap @@ -2,21 +2,37 @@ source: crates/analyzer/tests/errors.rs expression: "error_string(&path, test_files::fixture(path))" --- -error: generic function parameters are not supported on test functions +error: generic parameters are not supported on test functions ┌─ compile_errors/_test_fn_params.fe:4:9 │ 4 │ fn test1() { } - │ ^^^^^^^^^^^^ this cannot appear here + │ ^^^^^^^^^^^^ invalid generic parameters │ = Hint: remove the generic parameters -error: function parameters are not supported on test functions +error: function parameters other than `ctx` are not supported on test functions ┌─ compile_errors/_test_fn_params.fe:7:10 │ 7 │ fn test2(x: u256) { } - │ ^^^^^^^ this cannot appear here + │ ^^^^^^^ invalid function parameter │ - = Hint: remove the parameters + = Hint: remove the parameter + +error: function parameters other than `ctx` are not supported on test functions + ┌─ compile_errors/_test_fn_params.fe:10:10 + │ +10 │ fn test3(foo: u256, ctx: Context) { } + │ ^^^^^^^^^ invalid function parameter + │ + = Hint: remove the parameter + +error: function parameters other than `ctx` are not supported on test functions + ┌─ compile_errors/_test_fn_params.fe:13:24 + │ +13 │ fn test4(ctx: Context, foo: u256) { } + │ ^^^^^^^^^ invalid function parameter + │ + = Hint: remove the parameter error: generic function parameters aren't yet supported outside of struct functions ┌─ compile_errors/_test_fn_params.fe:4:9 @@ -26,4 +42,10 @@ error: generic function parameters aren't yet supported outside of struct functi │ = Hint: Struct functions can have generic parameters +error: invalid parameter order + ┌─ compile_errors/_test_fn_params.fe:10:21 + │ +10 │ fn test3(foo: u256, ctx: Context) { } + │ ^^^^^^^^^^^^ `ctx: Context` must be the first parameter + diff --git a/crates/analyzer/tests/snapshots/errors__ctx_not_ctx_type.snap b/crates/analyzer/tests/snapshots/errors__ctx_not_ctx_type.snap new file mode 100644 index 0000000000..f504f8d047 --- /dev/null +++ b/crates/analyzer/tests/snapshots/errors__ctx_not_ctx_type.snap @@ -0,0 +1,11 @@ +--- +source: crates/analyzer/tests/errors.rs +expression: "error_string(&path, test_files::fixture(path))" +--- +error: `ctx` is reserved for instances of `Context` + ┌─ compile_errors/ctx_not_ctx_type.fe:2:16 + │ +2 │ pub fn bar(ctx: u256) {} + │ ^^^^^^^^^ `ctx` must be an instance of `Context` + + diff --git a/crates/test-files/fixtures/compile_errors/_test_fn_params.fe b/crates/test-files/fixtures/compile_errors/_test_fn_params.fe index 898a4cdef1..acb10740f0 100644 --- a/crates/test-files/fixtures/compile_errors/_test_fn_params.fe +++ b/crates/test-files/fixtures/compile_errors/_test_fn_params.fe @@ -4,4 +4,10 @@ trait MyTrait { } fn test1() { } #test -fn test2(x: u256) { } \ No newline at end of file +fn test2(x: u256) { } + +#test +fn test3(foo: u256, ctx: Context) { } + +#test +fn test4(ctx: Context, foo: u256) { } \ No newline at end of file diff --git a/crates/test-files/fixtures/compile_errors/ctx_not_ctx_type.fe b/crates/test-files/fixtures/compile_errors/ctx_not_ctx_type.fe new file mode 100644 index 0000000000..8e10ccf660 --- /dev/null +++ b/crates/test-files/fixtures/compile_errors/ctx_not_ctx_type.fe @@ -0,0 +1,3 @@ +contract Foo { + pub fn bar(ctx: u256) {} +} diff --git a/crates/tests/fixtures/files/address_bytes10_map.fe b/crates/tests/fixtures/files/address_bytes10_map.fe index f0669ec8a6..008dad00ab 100644 --- a/crates/tests/fixtures/files/address_bytes10_map.fe +++ b/crates/tests/fixtures/files/address_bytes10_map.fe @@ -13,8 +13,7 @@ contract Foo { } #test -unsafe fn test_foo() { - let mut ctx: Context = Context() +fn test_foo(mut ctx: Context) { let mut foo: Foo = Foo.create(ctx, 0) let address1: address = address(0x01) diff --git a/crates/tests/fixtures/files/arrays.fe b/crates/tests/fixtures/files/arrays.fe index 578ed75044..d4c53e8b49 100644 --- a/crates/tests/fixtures/files/arrays.fe +++ b/crates/tests/fixtures/files/arrays.fe @@ -18,8 +18,7 @@ contract Foo { } #test -unsafe fn test_foo() { - let mut ctx: Context = Context() +unsafe fn test_foo(mut ctx: Context) { let foo: Foo = Foo.create(ctx, 0) assert foo.get_from_storage(index: 3) == 3 assert Foo::get_from_memory(index: 3) == 4 @@ -37,8 +36,7 @@ const FREE_MEM_PTR: u256 = 1024 const CALL_GAS: u256 = 100000 #test -unsafe fn test_array_oob_dyn() { - let mut ctx: Context = Context() +unsafe fn test_array_oob_dyn(mut ctx: Context) { let array_index_oob: ArrayIndexOobDyn = ArrayIndexOobDyn.create(ctx, value: 0) let expected_revert_data: Array = [78, 72, 123, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50] @@ -76,8 +74,7 @@ unsafe fn test_array_oob_dyn() { // } // #test -// unsafe fn test_array_oob_static() { -// let mut ctx: Context = Context() +// unsafe fn test_array_oob_static(mut ctx: Context) { // let array_index_oob: ArrayIndexOobStatic = ArrayIndexOobStatic.create(ctx, value: 0) // let expected_revert_data: Array = [78, 72, 123, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50] diff --git a/crates/tests/fixtures/files/associated_fns.fe b/crates/tests/fixtures/files/associated_fns.fe index da0cfa60a0..5624b2c2f7 100644 --- a/crates/tests/fixtures/files/associated_fns.fe +++ b/crates/tests/fixtures/files/associated_fns.fe @@ -22,8 +22,7 @@ contract Foo { } #test -unsafe fn test_foo() { - let mut ctx: Context = Context() +fn test_foo(mut ctx: Context) { let mut foo: Foo = Foo.create(ctx, 0) assert foo.bar(val: 12) == 144 } \ No newline at end of file diff --git a/crates/tests/fixtures/files/call_fn.fe b/crates/tests/fixtures/files/call_fn.fe index ea905db3e6..eb977eae00 100644 --- a/crates/tests/fixtures/files/call_fn.fe +++ b/crates/tests/fixtures/files/call_fn.fe @@ -20,8 +20,7 @@ contract Foo { } #test -unsafe fn test_foo() { - let mut ctx: Context = Context() +unsafe fn test_foo(mut ctx: Context) { let foo: Foo = Foo.create(ctx, 0) // 0x01 selector call diff --git a/newsfragments/880.feature.md b/newsfragments/880.feature.md new file mode 100644 index 0000000000..a3b889ee69 --- /dev/null +++ b/newsfragments/880.feature.md @@ -0,0 +1,10 @@ +The `ctx` parameter can now be passed into test functions. + +example: + +``` +#test +fn my_test(ctx: Context) { + assert ctx.block_number() == 0 +} +```