From 9376bc6369df72c460fd3a432fbd5dd5a8ab1023 Mon Sep 17 00:00:00 2001 From: Skgland Date: Sat, 27 Sep 2025 22:48:05 +0200 Subject: [PATCH] fix mthom/scryer-prolog#3073 --- src/ffi.rs | 51 ++++++++++++++++--- src/machine/machine_errors.rs | 41 ++++++++++++--- .../cli/issues/ffi_alloc_mismatched_args.md | 2 +- 3 files changed, 79 insertions(+), 15 deletions(-) diff --git a/src/ffi.rs b/src/ffi.rs index b780e7b3..7c7c9412 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -180,10 +180,17 @@ impl StructImpl { fn build( &self, + name: Atom, structs_table: &HashMap, struct_args: &mut [Value], ) -> Result { - let args = ArgValue::build_args(struct_args, &self.fields, structs_table)?; + let args = ArgValue::build_args( + name, + ArgCountMismatchKind::Struct, + struct_args, + &self.fields, + structs_table, + )?; let alloc = FfiStruct::new(self.layout()?, FfiAllocator::Rust)?; @@ -490,19 +497,30 @@ impl<'val> ArgValue<'val> { return Err(FfiError::StructNotFound(*arg_type_name)); }; - Ok(Self::Struct(struct_type.build(structs_table, args)?)) + Ok(Self::Struct(struct_type.build( + *arg_type_name, + structs_table, + args, + )?)) } FfiType::Void => Err(FfiError::VoidArgumentType), } } fn build_args( + name: Atom, + kind: ArgCountMismatchKind, args: &'val mut [Value], types: &[FfiType], structs_table: &HashMap, ) -> Result, FfiError> { if types.len() != args.len() { - return Err(FfiError::ArgCountMismatch); + return Err(FfiError::ArgCountMismatch { + name, + kind, + expected: types.len(), + got: args.len(), + }); } args.iter_mut() @@ -659,9 +677,15 @@ impl ForeignFunctionTable { let fn_impl = self .table .get(&fn_name) - .ok_or(FfiError::FunctionNotFound(fn_name))?; + .ok_or(FfiError::FunctionNotFound(fn_name, args.len()))?; - let args = ArgValue::build_args(&mut args, &fn_impl.args, &self.structs)?; + let args = ArgValue::build_args( + fn_name, + ArgCountMismatchKind::Function, + &mut args, + &fn_impl.args, + &self.structs, + )?; let args = PointerArgs::new(&args); @@ -720,7 +744,7 @@ impl ForeignFunctionTable { let (_, args) = args.as_struct()?; - let ffi_struct = struct_impl.build(&self.structs, args)?; + let ffi_struct = struct_impl.build(kind, &self.structs, args)?; let ptr = ManuallyDrop::new(ffi_struct).ptr; @@ -906,9 +930,14 @@ pub enum FfiError { ValueCast(Atom, Atom), ValueOutOfRange(DomainErrorType, Value), VoidArgumentType, - FunctionNotFound(Atom), + FunctionNotFound(Atom, usize), StructNotFound(Atom), - ArgCountMismatch, + ArgCountMismatch { + name: Atom, // ffi function or struct + kind: ArgCountMismatchKind, + expected: usize, + got: usize, + }, AllocationFailed, // LayoutError should never occour LayoutError, @@ -918,6 +947,12 @@ pub enum FfiError { NullPtr, } +#[derive(Debug)] +pub(crate) enum ArgCountMismatchKind { + Function, + Struct, +} + impl std::fmt::Display for FfiError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Debug::fmt(self, f) diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index d43a8cfa..9b56b4fb 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -447,10 +447,26 @@ impl MachineState { location: None, } } - ExistenceError::FfiFunction(atom) => { + ExistenceError::FfiFunction(name, arity) => { + let culprit = functor!(atom!("/"), [atom_as_cell(name), fixnum(arity)]); let stub = functor!( atom!("existence_error"), - [atom_as_cell((atom!("ffi_function"))), atom_as_cell(atom)] + [atom_as_cell((atom!("ffi_function"))), functor(culprit)] + ); + + MachineError { + stub, + location: None, + } + } + ExistenceError::FfiStructConstructor(name, arity) => { + let culprit = functor!(atom!("/"), [atom_as_cell(name), fixnum(arity)]); + let stub = functor!( + atom!("existence_error"), + [ + atom_as_cell((atom!("ffi_struct_constructor"))), + functor(culprit) + ] ); MachineError { @@ -688,13 +704,25 @@ impl MachineState { } } FfiError::ValueOutOfRange(domain, culprit) => self.domain_error(domain, culprit), - FfiError::FunctionNotFound(name) => { - self.existence_error(ExistenceError::FfiFunction(name)) + FfiError::FunctionNotFound(name, arity) => { + self.existence_error(ExistenceError::FfiFunction(name, arity)) } FfiError::StructNotFound(name) => { self.existence_error(ExistenceError::FfiStructType(name)) } - FfiError::ArgCountMismatch => self.unreachable_error(), + FfiError::ArgCountMismatch { + name, + kind, + expected: _, + got, + } => match kind { + ffi::ArgCountMismatchKind::Function => { + self.existence_error(ExistenceError::FfiFunction(name, got)) + } + ffi::ArgCountMismatchKind::Struct => { + self.existence_error(ExistenceError::FfiStructConstructor(name, got)) + } + }, FfiError::AllocationFailed => MachineError { stub: functor!(atom!("resource_error"), [atom_as_cell((atom!("heap")))]), location: None, @@ -1137,7 +1165,8 @@ pub enum ExistenceError { SourceSink(HeapCellValue), Stream(HeapCellValue), Process(HeapCellValue), - FfiFunction(Atom), + FfiFunction(Atom, usize), + FfiStructConstructor(Atom, usize), FfiStructType(Atom), } diff --git a/tests/scryer/cli/issues/ffi_alloc_mismatched_args.md b/tests/scryer/cli/issues/ffi_alloc_mismatched_args.md index 8dc5448c..426d2463 100644 --- a/tests/scryer/cli/issues/ffi_alloc_mismatched_args.md +++ b/tests/scryer/cli/issues/ffi_alloc_mismatched_args.md @@ -1,5 +1,5 @@ ```trycmd $ scryer-prolog -f --no-add-history input.pl -g test -g halt -test causes: error(system_error,$ffi_allocate/4) +test causes: error(existence_error(ffi_struct_constructor,$[u8;2]/1),$ffi_allocate/4) ``` \ No newline at end of file -- 2.54.0