]> Repositorios git - scryer-prolog.git/commitdiff
fix mthom/scryer-prolog#3073
authorSkgland <[email protected]>
Sat, 27 Sep 2025 20:48:05 +0000 (22:48 +0200)
committerBennet Bleßmann <[email protected]>
Sat, 27 Sep 2025 20:48:05 +0000 (22:48 +0200)
src/ffi.rs
src/machine/machine_errors.rs
tests/scryer/cli/issues/ffi_alloc_mismatched_args.md

index b780e7b3e6b5364c23d6361f2334973e6ad06cb7..7c7c94127ce662e13c4fd55cc993b121e9c3b8af 100644 (file)
@@ -180,10 +180,17 @@ impl StructImpl {
 
     fn build(
         &self,
+        name: Atom,
         structs_table: &HashMap<Atom, StructImpl>,
         struct_args: &mut [Value],
     ) -> Result<FfiStruct, FfiError> {
-        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<Atom, StructImpl>,
     ) -> Result<Vec<Self>, 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)
index d43a8cfae75399142a09fb40910ff95617a2d44f..9b56b4fb67acb7780ea469b1fdba6670de0ce3c6 100644 (file)
@@ -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),
 }
 
index 8dc5448c242e5de204c03d384d04dc27c0b44fb8..426d2463884ca9a2d6889b64f2d89fe6882f7a97 100644 (file)
@@ -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