Merge pull request #3108 from Skgland/issue-3073
emit a more appropriate error when passing the wrong argument count when constructing an ffi struct with the wrong argument count
This commit is contained in:
51
src/ffi.rs
51
src/ffi.rs
@@ -180,10 +180,17 @@ impl StructImpl {
|
|||||||
|
|
||||||
fn build(
|
fn build(
|
||||||
&self,
|
&self,
|
||||||
|
name: Atom,
|
||||||
structs_table: &HashMap<Atom, StructImpl>,
|
structs_table: &HashMap<Atom, StructImpl>,
|
||||||
struct_args: &mut [Value],
|
struct_args: &mut [Value],
|
||||||
) -> Result<FfiStruct, FfiError> {
|
) -> 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)?;
|
let alloc = FfiStruct::new(self.layout()?, FfiAllocator::Rust)?;
|
||||||
|
|
||||||
@@ -530,19 +537,30 @@ impl<'val> ArgValue<'val> {
|
|||||||
return Err(FfiError::StructNotFound(*arg_type_name));
|
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),
|
FfiType::Void => Err(FfiError::VoidArgumentType),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_args(
|
fn build_args(
|
||||||
|
name: Atom,
|
||||||
|
kind: ArgCountMismatchKind,
|
||||||
args: &'val mut [Value],
|
args: &'val mut [Value],
|
||||||
types: &[FfiType],
|
types: &[FfiType],
|
||||||
structs_table: &HashMap<Atom, StructImpl>,
|
structs_table: &HashMap<Atom, StructImpl>,
|
||||||
) -> Result<Vec<Self>, FfiError> {
|
) -> Result<Vec<Self>, FfiError> {
|
||||||
if types.len() != args.len() {
|
if types.len() != args.len() {
|
||||||
return Err(FfiError::ArgCountMismatch);
|
return Err(FfiError::ArgCountMismatch {
|
||||||
|
name,
|
||||||
|
kind,
|
||||||
|
expected: types.len(),
|
||||||
|
got: args.len(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
args.iter_mut()
|
args.iter_mut()
|
||||||
@@ -699,9 +717,15 @@ impl ForeignFunctionTable {
|
|||||||
let fn_impl = self
|
let fn_impl = self
|
||||||
.table
|
.table
|
||||||
.get(&fn_name)
|
.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);
|
let args = PointerArgs::new(&args);
|
||||||
|
|
||||||
@@ -760,7 +784,7 @@ impl ForeignFunctionTable {
|
|||||||
|
|
||||||
let (_, args) = args.as_struct()?;
|
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;
|
let ptr = ManuallyDrop::new(ffi_struct).ptr;
|
||||||
|
|
||||||
@@ -946,9 +970,14 @@ pub enum FfiError {
|
|||||||
ValueCast(Atom, Atom),
|
ValueCast(Atom, Atom),
|
||||||
ValueOutOfRange(DomainErrorType, Value),
|
ValueOutOfRange(DomainErrorType, Value),
|
||||||
VoidArgumentType,
|
VoidArgumentType,
|
||||||
FunctionNotFound(Atom),
|
FunctionNotFound(Atom, usize),
|
||||||
StructNotFound(Atom),
|
StructNotFound(Atom),
|
||||||
ArgCountMismatch,
|
ArgCountMismatch {
|
||||||
|
name: Atom, // ffi function or struct
|
||||||
|
kind: ArgCountMismatchKind,
|
||||||
|
expected: usize,
|
||||||
|
got: usize,
|
||||||
|
},
|
||||||
AllocationFailed,
|
AllocationFailed,
|
||||||
// LayoutError should never occour
|
// LayoutError should never occour
|
||||||
LayoutError,
|
LayoutError,
|
||||||
@@ -958,6 +987,12 @@ pub enum FfiError {
|
|||||||
NullPtr,
|
NullPtr,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) enum ArgCountMismatchKind {
|
||||||
|
Function,
|
||||||
|
Struct,
|
||||||
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for FfiError {
|
impl std::fmt::Display for FfiError {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
std::fmt::Debug::fmt(self, f)
|
std::fmt::Debug::fmt(self, f)
|
||||||
|
|||||||
@@ -447,10 +447,26 @@ impl MachineState {
|
|||||||
location: None,
|
location: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExistenceError::FfiFunction(atom) => {
|
ExistenceError::FfiFunction(name, arity) => {
|
||||||
|
let culprit = functor!(atom!("/"), [atom_as_cell(name), fixnum(arity)]);
|
||||||
let stub = functor!(
|
let stub = functor!(
|
||||||
atom!("existence_error"),
|
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 {
|
MachineError {
|
||||||
@@ -688,13 +704,25 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
FfiError::ValueOutOfRange(domain, culprit) => self.domain_error(domain, culprit),
|
FfiError::ValueOutOfRange(domain, culprit) => self.domain_error(domain, culprit),
|
||||||
FfiError::FunctionNotFound(name) => {
|
FfiError::FunctionNotFound(name, arity) => {
|
||||||
self.existence_error(ExistenceError::FfiFunction(name))
|
self.existence_error(ExistenceError::FfiFunction(name, arity))
|
||||||
}
|
}
|
||||||
FfiError::StructNotFound(name) => {
|
FfiError::StructNotFound(name) => {
|
||||||
self.existence_error(ExistenceError::FfiStructType(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 {
|
FfiError::AllocationFailed => MachineError {
|
||||||
stub: functor!(atom!("resource_error"), [atom_as_cell((atom!("heap")))]),
|
stub: functor!(atom!("resource_error"), [atom_as_cell((atom!("heap")))]),
|
||||||
location: None,
|
location: None,
|
||||||
@@ -1137,7 +1165,8 @@ pub enum ExistenceError {
|
|||||||
SourceSink(HeapCellValue),
|
SourceSink(HeapCellValue),
|
||||||
Stream(HeapCellValue),
|
Stream(HeapCellValue),
|
||||||
Process(HeapCellValue),
|
Process(HeapCellValue),
|
||||||
FfiFunction(Atom),
|
FfiFunction(Atom, usize),
|
||||||
|
FfiStructConstructor(Atom, usize),
|
||||||
FfiStructType(Atom),
|
FfiStructType(Atom),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
:- use_module(library(ffi)).
|
||||||
|
|
||||||
|
|
||||||
|
test :- ffi:array_type(u8, 2, Type), ffi:allocate(rust, Type, [Type, 0], _ArrayPtr).
|
||||||
|
|
||||||
|
?- test.
|
||||||
|
error(existence_error(ffi_struct_constructor,'$[u8;2]'/1),'$ffi_allocate'/4).
|
||||||
5
tests/scryer/cli/issues/ffi_alloc_mismatched_args.md
Normal file
5
tests/scryer/cli/issues/ffi_alloc_mismatched_args.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
```trycmd
|
||||||
|
$ scryer-prolog -f --no-add-history input.pl -g test -g halt
|
||||||
|
test causes: error(existence_error(ffi_struct_constructor,$[u8;2]/1),$ffi_allocate/4)
|
||||||
|
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user