From 7c50fb16557dcd82a895bcfdc90df14f5f610502 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Wed, 21 May 2025 11:35:00 +0300 Subject: [PATCH] checker: reallow passing closures as voidptr parameters with no warning, to enable convenient interfacing with C libs --- vlib/v/checker/fn.v | 2 +- ..._method_passed_to_voidptr_parameter_test.v | 62 +++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 vlib/v/tests/fns/closure_of_instance_method_passed_to_voidptr_parameter_test.v diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index ec7426012..f6f0f3144 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -1783,7 +1783,7 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast. else if param.typ == ast.voidptr_type && func.language == .v && arg_typ !in [ast.voidptr_type, ast.nil_type] && arg_typ.nr_muls() == 0 && func.name !in ['isnil', 'ptr_str'] && !func.name.starts_with('json.') - && arg_typ_sym.kind !in [.float_literal, .int_literal, .charptr] + && arg_typ_sym.kind !in [.float_literal, .int_literal, .charptr, .function] && !c.pref.backend.is_js() { c.warn('automatic ${arg_typ_sym.name} referencing/dereferencing into voidptr is deprecated and will be removed soon; use `foo(&x)` instead of `foo(x)`', call_arg.pos) diff --git a/vlib/v/tests/fns/closure_of_instance_method_passed_to_voidptr_parameter_test.v b/vlib/v/tests/fns/closure_of_instance_method_passed_to_voidptr_parameter_test.v new file mode 100644 index 000000000..ff0577041 --- /dev/null +++ b/vlib/v/tests/fns/closure_of_instance_method_passed_to_voidptr_parameter_test.v @@ -0,0 +1,62 @@ +type AudioCallback = fn (buffer voidptr, frames u32) + +@[heap] +struct App { +mut: + id int +} + +fn (mut app App) callback(buffer voidptr, frames u32) { + assert voidptr(app) != unsafe { nil } + assert buffer != unsafe { nil } + assert frames == 256 + + assert app.id == 12345 + app.id = 98765 + + unsafe { + p := &u8(buffer) + assert p[0] == 59 + assert p[1] == 58 + assert p[2] == 51 + assert p[3] == 52 + p[0] = 12 + p[1] = 22 + p[2] = 32 + p[3] = 42 + } +} + +fn set_audio_callback(p voidptr) { + println(p) + cb := AudioCallback(p) + mut buf := [1024]u8{} + buf[0] = 59 + buf[1] = 58 + buf[2] = 51 + buf[3] = 52 + cb(&buf[0], 256) + assert buf[0] == 12 + assert buf[1] == 22 + assert buf[2] == 32 + assert buf[3] == 42 +} + +fn test_creating_a_closure_from_instance_method_through_explicit_cast_works() { + mut app := &App{ + id: 12345 + } + audio_closure := AudioCallback(app.callback) + set_audio_callback(audio_closure) + assert app.id == 98765 +} + +fn test_creating_a_closure_from_instance_method_passed_to_voidptr_fn_parameter_works() { + mut app := &App{ + id: 12345 + } + // TODO: the code below should work, but does not yet, because it just passes the fn address + // of the method implementation itself, without creating a closure to wrap the instance. + // set_audio_callback(app.callback) + // assert app.id == 98765 +} -- 2.39.5