docs(core): explain nominal type and callable arity regressions
This commit is contained in:
+106
-2
@@ -1,14 +1,23 @@
|
||||
//! 通过公开 Vm API 验证名义类型、显式能力和调用数量协议,由 Rust 测试框架逐场景调用。
|
||||
//! 同名不是同身份;继承与实例关系分开;所有类型、方法、实例都由托管强边和外部根保活。
|
||||
|
||||
use endor_core::{TypeConstructor, Value, Vm, VmError};
|
||||
|
||||
#[test]
|
||||
/// 区分子类型/实例关系、同名类型身份、不可变头部类型,以及实例独立保活定义图。
|
||||
fn nominal_types_have_distinct_inheritance_and_instance_relations() {
|
||||
// 各测试建立独立堆,不把其他场景的类型身份带入。
|
||||
let mut vm = Vm::new().unwrap();
|
||||
assert_eq!(vm.object_count(), 0);
|
||||
// 显式自举 Object/Type 两个拥有根,新 VM 本身不预建语言类型。
|
||||
let roots = vm.bootstrap_types().unwrap();
|
||||
// 抽象 Block 作为继承基类,不代表其派生不能使用显式 Record 构造策略。
|
||||
let block = vm
|
||||
.new_type("Block", roots.object, TypeConstructor::Abstract)
|
||||
.unwrap();
|
||||
// Page 是 Block 子类型,同时自身是 Type 的实例。
|
||||
let page = vm.new_type("Page", block, TypeConstructor::Record).unwrap();
|
||||
// 同名 Page 再分配一次必须得到另一名义身份。
|
||||
let other = vm.new_type("Page", block, TypeConstructor::Record).unwrap();
|
||||
assert!(vm.is_subtype(page, block).unwrap());
|
||||
assert!(!vm.is_subtype(block, page).unwrap());
|
||||
@@ -17,6 +26,7 @@ fn nominal_types_have_distinct_inheritance_and_instance_relations() {
|
||||
assert!(vm.is_instance(roots.object, roots.type_type).unwrap());
|
||||
assert!(vm.is_instance(roots.type_type, roots.type_type).unwrap());
|
||||
assert!(!vm.is_subtype(roots.object, roots.type_type).unwrap());
|
||||
// call 构造的实例结果拥有一份根,后续清理必须显式 release。
|
||||
let Value::Object(instance) = vm.call(page, &[]).unwrap() else {
|
||||
panic!("instance required")
|
||||
};
|
||||
@@ -27,24 +37,32 @@ fn nominal_types_have_distinct_inheritance_and_instance_relations() {
|
||||
assert!(vm.set_attr(instance, "type", Value::Object(other)).is_err());
|
||||
assert!(vm.attach_type(instance, other).is_err());
|
||||
assert!(vm.replace_payload(page, endor_core::Record).is_err());
|
||||
// 归还每份测试拥有根,内部类型/基类/方法边不手动重复释放。
|
||||
for object in [roots.object, roots.type_type, block, page, other] {
|
||||
vm.release(object).unwrap();
|
||||
}
|
||||
// 清除无外部根的类型/元类型环;仍由实例可达的定义不得回收。
|
||||
vm.collect_cycles();
|
||||
// The instance keeps its definition, base and metatype reachable without
|
||||
// any host-owned type registry. The unrelated same-name type was collected.
|
||||
// 仅保留实例根仍可达定义、基类和元类型,无关的同名类型应被收集;没有堆外拥有注册表。
|
||||
assert_eq!(vm.object_count(), 5);
|
||||
assert!(vm.is_instance(instance, block).unwrap());
|
||||
// 实例最后根归还后,其类型图不再因该实例保活。
|
||||
vm.release(instance).unwrap();
|
||||
// 清除无外部根的类型/元类型环;仍由实例可达的定义不得回收。
|
||||
vm.collect_cycles();
|
||||
assert_eq!(vm.object_count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// 异堆类型附着失败不得改变头部;已有动态 type 字段也不得被托管类型附着覆盖。
|
||||
fn foreign_type_edges_fail_without_changing_the_target() {
|
||||
// 第一个 VM 拥有类型定义,不能把它附着到第二个 VM 的对象。
|
||||
let mut first = Vm::new().unwrap();
|
||||
// 第二个 VM 独立拥有对象和自己的类型自举图。
|
||||
let mut second = Vm::new().unwrap();
|
||||
// 显式自举 Object/Type 两个拥有根,新 VM 本身不预建语言类型。
|
||||
let roots = first.bootstrap_types().unwrap();
|
||||
// 待附着对象在第二堆,初始无名义类型且只有一根。
|
||||
let object = second.new_object().unwrap();
|
||||
assert_eq!(
|
||||
second.attach_type(object, roots.object),
|
||||
@@ -55,6 +73,7 @@ fn foreign_type_edges_fail_without_changing_the_target() {
|
||||
second
|
||||
.set_attr(object, "type", Value::Text("existing field".into()))
|
||||
.unwrap();
|
||||
// 同堆类型虽有效,仍应因对象已有动态 type 字段冲突而拒绝附着。
|
||||
let local = second.bootstrap_types().unwrap();
|
||||
assert!(second.attach_type(object, local.object).is_err());
|
||||
assert_eq!(
|
||||
@@ -64,9 +83,12 @@ fn foreign_type_edges_fail_without_changing_the_target() {
|
||||
assert_eq!(second.type_of(object).unwrap(), None);
|
||||
}
|
||||
|
||||
/// 能力测试辅助,生成指定显式参数数目的源码函数,含 self,总返回 Nil,不附完整类型签名。
|
||||
fn contract_method(vm: &mut Vm, parameters: usize) -> endor_core::ObjectRef {
|
||||
use endor_core::{CodeLayout, EndorCode, EndorCodeObject, Instruction, Opcode};
|
||||
// 生成唯一参数名称,使 CodeLayout 参数前缀与局部布局一致。
|
||||
let names: Vec<_> = (0..parameters).map(|index| format!("arg{index}")).collect();
|
||||
// 测试用已验证指令,返回常量 Nil;数量由参数布局决定。
|
||||
let code = EndorCode::from_instructions(
|
||||
&[
|
||||
Instruction::new(Opcode::LoadConst, 0),
|
||||
@@ -80,27 +102,39 @@ fn contract_method(vm: &mut Vm, parameters: usize) -> endor_core::ObjectRef {
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
// 分配代码载荷使常量引用(如有)成为托管边。
|
||||
let code = vm.allocate(EndorCodeObject::new(code)).unwrap();
|
||||
// 函数全局字典用于注解解析和环境持有,函数内部边不依赖测试根。
|
||||
let globals = vm.new_dict().unwrap();
|
||||
// 函数构造校验布局并持有代码/全局/默认值引用,返回一份根。
|
||||
let function = vm
|
||||
.new_function("contract method", code, globals, vec![], vec![])
|
||||
.unwrap();
|
||||
// 辅助函数归还临时代码根,函数内部边仍保留代码。
|
||||
vm.release(code).unwrap();
|
||||
// 辅助函数归还临时全局根,函数环境边继续保活。
|
||||
vm.release(globals).unwrap();
|
||||
function
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// 显式能力可继承且按身份区分,错误方法/派生声明不能破坏已有契约,能力边维持定义存活。
|
||||
fn explicit_traits_inherit_validate_overrides_and_own_definition_edges() {
|
||||
use endor_core::MethodRequirement;
|
||||
// 各测试建立独立堆,不把其他场景的类型身份带入。
|
||||
let mut vm = Vm::new().unwrap();
|
||||
// 显式自举 Object/Type 两个拥有根,新 VM 本身不预建语言类型。
|
||||
let roots = vm.bootstrap_types().unwrap();
|
||||
// 可构造基类作为能力继承与方法更新测试起点。
|
||||
let base = vm
|
||||
.new_type("Base", roots.object, TypeConstructor::Record)
|
||||
.unwrap();
|
||||
// 含 self 和一个普通参数,满足 render 的最小能力数量要求。
|
||||
let valid = contract_method(&mut vm, 2);
|
||||
// 仅 self 一个参数,无法接受 render 所需普通参数。
|
||||
let invalid = contract_method(&mut vm, 1);
|
||||
vm.define_method(base, "render", valid).unwrap();
|
||||
// 最小能力声明只要求方法及显式参数数,不推断结构等价。
|
||||
let capability = vm
|
||||
.new_trait(
|
||||
"Drawable",
|
||||
@@ -110,10 +144,12 @@ fn explicit_traits_inherit_validate_overrides_and_own_definition_edges() {
|
||||
}],
|
||||
)
|
||||
.unwrap();
|
||||
// 同名能力仍为不同身份,声明一个不会自动支持另一个。
|
||||
let same_name = vm.new_trait("Drawable", vec![]).unwrap();
|
||||
assert!(!vm.implements_trait(base, capability).unwrap());
|
||||
vm.implement_trait(base, capability).unwrap();
|
||||
assert!(!vm.implements_trait(base, same_name).unwrap());
|
||||
// 已有派生类用于核对继承能力/覆盖方法,方法来源由真实继承查找决定。
|
||||
let child = vm
|
||||
.new_class("Child", base, vec![], std::collections::BTreeMap::new())
|
||||
.unwrap();
|
||||
@@ -130,12 +166,15 @@ fn explicit_traits_inherit_validate_overrides_and_own_definition_edges() {
|
||||
vm.new_class("Bad", base, vec![], [("render".into(), invalid)].into())
|
||||
.is_err()
|
||||
);
|
||||
// call 构造的实例结果拥有一份根,后续清理必须显式 release。
|
||||
let Value::Object(instance) = vm.call(child, &[]).unwrap() else {
|
||||
panic!("instance required");
|
||||
};
|
||||
// 归还测试根后类型声明的能力强边仍应保活,supports 不能依赖堆外注册表。
|
||||
vm.release(capability).unwrap();
|
||||
assert!(vm.supports(instance, capability).unwrap());
|
||||
assert!(vm.replace_payload(capability, endor_core::Record).is_err());
|
||||
// 归还每份测试拥有根,内部类型/基类/方法边不手动重复释放。
|
||||
for object in [
|
||||
roots.object,
|
||||
roots.type_type,
|
||||
@@ -148,24 +187,33 @@ fn explicit_traits_inherit_validate_overrides_and_own_definition_edges() {
|
||||
] {
|
||||
vm.release(object).unwrap();
|
||||
}
|
||||
// 清除无外部根的类型/元类型环;仍由实例可达的定义不得回收。
|
||||
vm.collect_cycles();
|
||||
assert_eq!(vm.object_count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// 后注册能力必须核对已有后代,父方法更新也不能破坏后代自己声明的能力。
|
||||
fn late_trait_registration_and_ancestor_updates_validate_existing_descendants() {
|
||||
use endor_core::MethodRequirement;
|
||||
// 各测试建立独立堆,不把其他场景的类型身份带入。
|
||||
let mut vm = Vm::new().unwrap();
|
||||
// 显式自举 Object/Type 两个拥有根,新 VM 本身不预建语言类型。
|
||||
let roots = vm.bootstrap_types().unwrap();
|
||||
// 可构造基类作为能力继承与方法更新测试起点。
|
||||
let base = vm
|
||||
.new_type("Base", roots.object, TypeConstructor::Record)
|
||||
.unwrap();
|
||||
// 满足 self 加一个参数的源码函数,用于恢复合法方法。
|
||||
let good = contract_method(&mut vm, 2);
|
||||
// 少一个参数的源码函数,不可用于已声明能力的方法。
|
||||
let bad = contract_method(&mut vm, 1);
|
||||
vm.define_method(base, "render", good).unwrap();
|
||||
// 已有派生类用于核对继承能力/覆盖方法,方法来源由真实继承查找决定。
|
||||
let child = vm
|
||||
.new_class("Child", base, vec![], [("render".into(), bad)].into())
|
||||
.unwrap();
|
||||
// 最小能力声明只要求方法及显式参数数,不推断结构等价。
|
||||
let capability = vm
|
||||
.new_trait(
|
||||
"Drawable",
|
||||
@@ -178,6 +226,7 @@ fn late_trait_registration_and_ancestor_updates_validate_existing_descendants()
|
||||
assert!(vm.implement_trait(base, capability).is_err());
|
||||
assert!(!vm.implements_trait(base, capability).unwrap());
|
||||
vm.define_method(child, "render", good).unwrap();
|
||||
// 不覆盖父方法的后代自行声明能力,父方法替换也必须顾及它。
|
||||
let inheriting = vm
|
||||
.new_class(
|
||||
"Inheriting",
|
||||
@@ -192,6 +241,7 @@ fn late_trait_registration_and_ancestor_updates_validate_existing_descendants()
|
||||
vm.object_store().lookup_method(base, "render").unwrap(),
|
||||
Some(good)
|
||||
);
|
||||
// 第三堆查询已有类型/能力应报 ForeignHandle,不是简单 false。
|
||||
let foreign = Vm::new().unwrap();
|
||||
assert_eq!(
|
||||
foreign.implements_trait(base, capability),
|
||||
@@ -200,21 +250,28 @@ fn late_trait_registration_and_ancestor_updates_validate_existing_descendants()
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// Function 配置覆盖源码/原生/绑定方法,但普通可调用类不属于函数;配置不能切换。
|
||||
fn configured_function_identity_covers_source_native_and_bound_methods() {
|
||||
use endor_core::{NativeFunction, SourceSignature};
|
||||
// 各测试建立独立堆,不把其他场景的类型身份带入。
|
||||
let mut vm = Vm::new().unwrap();
|
||||
// 显式自举 Object/Type 两个拥有根,新 VM 本身不预建语言类型。
|
||||
let roots = vm.bootstrap_types().unwrap();
|
||||
// 显式注册函数名义类型,构造为 Abstract 避免把普通记录伪造成函数载荷。
|
||||
let function_type = vm
|
||||
.new_type("Function", roots.object, TypeConstructor::Abstract)
|
||||
.unwrap();
|
||||
vm.set_function_type(function_type).unwrap();
|
||||
// 源码函数应由分配入口自动附着已配置 Function。
|
||||
let source = contract_method(&mut vm, 1);
|
||||
// 原生载荷也按 is_function 分类附着类型,数量协议仍独立。
|
||||
let native = vm
|
||||
.allocate(NativeFunction::new("native", |_| Ok(Value::Nil)))
|
||||
.unwrap();
|
||||
assert!(vm.is_instance(source, function_type).unwrap());
|
||||
assert!(vm.is_instance(native, function_type).unwrap());
|
||||
vm.attach_type(source, function_type).unwrap();
|
||||
// 普通类可调用但不是 Function;类方法表持有函数边。
|
||||
let class = vm
|
||||
.new_class(
|
||||
"Data",
|
||||
@@ -223,15 +280,18 @@ fn configured_function_identity_covers_source_native_and_bound_methods() {
|
||||
[("read".into(), source)].into(),
|
||||
)
|
||||
.unwrap();
|
||||
// call 构造的实例结果拥有一份根,后续清理必须显式 release。
|
||||
let Value::Object(instance) = vm.call(class, &[]).unwrap() else {
|
||||
panic!("instance required");
|
||||
};
|
||||
// 绑定结果持有函数与 receiver,且本身应自动取得 Function 类型。
|
||||
let Value::Object(bound) = vm.bind_attr(instance, "read").unwrap() else {
|
||||
panic!("method required");
|
||||
};
|
||||
assert!(vm.is_instance(bound, function_type).unwrap());
|
||||
assert!(!vm.is_instance(class, function_type).unwrap());
|
||||
assert!(vm.set_function_type(class).is_err());
|
||||
// 零参数代码却附一项参数注解,源码签名构造阶段即应拒绝。
|
||||
let invalid = endor_core::EndorCode::from_instructions(
|
||||
&[
|
||||
endor_core::Instruction::new(endor_core::Opcode::LoadConst, 0),
|
||||
@@ -247,6 +307,7 @@ fn configured_function_identity_covers_source_native_and_bound_methods() {
|
||||
method_owner: None,
|
||||
});
|
||||
assert!(invalid.is_err());
|
||||
// 归还每份测试拥有根,内部类型/基类/方法边不手动重复释放。
|
||||
for object in [
|
||||
source,
|
||||
native,
|
||||
@@ -259,27 +320,34 @@ fn configured_function_identity_covers_source_native_and_bound_methods() {
|
||||
] {
|
||||
vm.release(object).unwrap();
|
||||
}
|
||||
// 清除无外部根的类型/元类型环;仍由实例可达的定义不得回收。
|
||||
vm.collect_cycles();
|
||||
assert_eq!(vm.object_count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// 源码返回类型不符时检查结果和已解析类型根的计数恢复,无隐藏执行根泄漏。
|
||||
fn failed_nominal_return_releases_value_and_captured_type_roots() {
|
||||
use endor_core::{
|
||||
CodeLayout, EndorCode, EndorCodeObject, Instruction, Opcode, SourceSignature,
|
||||
};
|
||||
// 各测试建立独立堆,不把其他场景的类型身份带入。
|
||||
let mut vm = Vm::new().unwrap();
|
||||
vm.set_source_type_checks(true).unwrap();
|
||||
// 显式自举 Object/Type 两个拥有根,新 VM 本身不预建语言类型。
|
||||
let roots = vm.bootstrap_types().unwrap();
|
||||
// 预期返回类型通过全局字典解析,执行时另保留返回定义根。
|
||||
let expected = vm
|
||||
.new_type("Expected", roots.object, TypeConstructor::Record)
|
||||
.unwrap();
|
||||
let other = vm
|
||||
.new_type("Other", roots.object, TypeConstructor::Record)
|
||||
.unwrap();
|
||||
// 错误返回对象先有测试根,代码常量表还会独立持有它。
|
||||
let Value::Object(value) = vm.call(other, &[]).unwrap() else {
|
||||
panic!("instance required");
|
||||
};
|
||||
// 函数全局字典用于注解解析和环境持有,函数内部边不依赖测试根。
|
||||
let globals = vm.new_dict().unwrap();
|
||||
vm.dict_set(
|
||||
globals,
|
||||
@@ -287,6 +355,7 @@ fn failed_nominal_return_releases_value_and_captured_type_roots() {
|
||||
Value::Object(expected),
|
||||
)
|
||||
.unwrap();
|
||||
// 测试用已验证指令,返回常量 Nil;数量由参数布局决定。
|
||||
let code = EndorCode::from_instructions(
|
||||
&[
|
||||
Instruction::new(Opcode::LoadConst, 0),
|
||||
@@ -302,11 +371,15 @@ fn failed_nominal_return_releases_value_and_captured_type_roots() {
|
||||
method_owner: None,
|
||||
})
|
||||
.unwrap();
|
||||
// 分配代码载荷使常量引用(如有)成为托管边。
|
||||
let code = vm.allocate(EndorCodeObject::new(code)).unwrap();
|
||||
// 函数构造校验布局并持有代码/全局/默认值引用,返回一份根。
|
||||
let function = vm
|
||||
.new_function("bad return", code, globals, vec![], vec![])
|
||||
.unwrap();
|
||||
// 记录调用前定义计数,返回失败后帧持有的类型根应全部归还。
|
||||
let before_type = vm.ref_count(expected).unwrap();
|
||||
// 记录错误结果计数,失败后不应遗留栈根或交付根。
|
||||
let before_value = vm.ref_count(value).unwrap();
|
||||
assert!(matches!(
|
||||
vm.call(function, &[]),
|
||||
@@ -314,6 +387,7 @@ fn failed_nominal_return_releases_value_and_captured_type_roots() {
|
||||
));
|
||||
assert_eq!(vm.ref_count(expected).unwrap(), before_type);
|
||||
assert_eq!(vm.ref_count(value).unwrap(), before_value);
|
||||
// 归还每份测试拥有根,内部类型/基类/方法边不手动重复释放。
|
||||
for object in [
|
||||
function,
|
||||
code,
|
||||
@@ -326,33 +400,43 @@ fn failed_nominal_return_releases_value_and_captured_type_roots() {
|
||||
] {
|
||||
vm.release(object).unwrap();
|
||||
}
|
||||
// 清除无外部根的类型/元类型环;仍由实例可达的定义不得回收。
|
||||
vm.collect_cycles();
|
||||
assert_eq!(vm.object_count(), 0);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
/// 借用状态身份的测试分派器,包装载荷通过 captures 显式 trace 保活它。
|
||||
struct CountedNative(endor_core::ObjectRef);
|
||||
impl endor_core::NativeCallable for CountedNative {
|
||||
/// CountedNative 发布含 self 的原生位置参数区间,供 VM 在副作用前检查。
|
||||
fn arity(&self) -> Option<endor_core::CallArity> {
|
||||
Some(endor_core::CallArity::range(1, 2))
|
||||
}
|
||||
/// 数量检查通过后才设置 called 标志,返回直接 Nil,用于观测是否进入回调。
|
||||
fn invoke(
|
||||
&self,
|
||||
cx: &mut endor_core::NativeContext<'_>,
|
||||
_: &[Value],
|
||||
) -> Result<endor_core::NativeResult, VmError> {
|
||||
// 回调唯一副作用,错误数量调用后的 called=false 可证明回调未进入。
|
||||
cx.set_attr(self.0, "called", Value::Bool(true))?;
|
||||
Ok(endor_core::NativeResult::Return(Value::Nil))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// 验证数量错误先于副作用、绑定参数扣减、能力更新拒绝未知/错误数量及畸形元数据禁止执行。
|
||||
fn native_arity_checks_precede_effects_and_traits_require_published_signatures() {
|
||||
use endor_core::{CallArity, ContextNativeFunction, MethodRequirement, NativeFunction};
|
||||
// 各测试建立独立堆,不把其他场景的类型身份带入。
|
||||
let mut vm = Vm::new().unwrap();
|
||||
// 显式自举 Object/Type 两个拥有根,新 VM 本身不预建语言类型。
|
||||
let roots = vm.bootstrap_types().unwrap();
|
||||
// 副作用标志载体被 CountedNative 的显式 captures 边保活。
|
||||
let state = vm.new_object().unwrap();
|
||||
vm.set_attr(state, "called", Value::Bool(false)).unwrap();
|
||||
// 原生载荷也按 is_function 分类附着类型,数量协议仍独立。
|
||||
let native = vm
|
||||
.allocate(ContextNativeFunction::new(
|
||||
"counted",
|
||||
@@ -366,6 +450,7 @@ fn native_arity_checks_precede_effects_and_traits_require_published_signatures()
|
||||
Err(VmError::ArgumentCount { .. })
|
||||
));
|
||||
assert_eq!(vm.get_attr(state, "called").unwrap(), Value::Bool(false));
|
||||
// 普通类可调用但不是 Function;类方法表持有函数边。
|
||||
let class = vm
|
||||
.new_class(
|
||||
"Data",
|
||||
@@ -374,6 +459,7 @@ fn native_arity_checks_precede_effects_and_traits_require_published_signatures()
|
||||
[("run".into(), native)].into(),
|
||||
)
|
||||
.unwrap();
|
||||
// 最小能力声明只要求方法及显式参数数,不推断结构等价。
|
||||
let capability = vm
|
||||
.new_trait(
|
||||
"Runnable",
|
||||
@@ -384,20 +470,24 @@ fn native_arity_checks_precede_effects_and_traits_require_published_signatures()
|
||||
)
|
||||
.unwrap();
|
||||
vm.implement_trait(class, capability).unwrap();
|
||||
// call 构造的实例结果拥有一份根,后续清理必须显式 release。
|
||||
let Value::Object(instance) = vm.call(class, &[]).unwrap() else {
|
||||
panic!("instance")
|
||||
};
|
||||
// 绑定结果持有函数与 receiver,且本身应自动取得 Function 类型。
|
||||
let Value::Object(bound) = vm.bind_attr(instance, "run").unwrap() else {
|
||||
panic!("bound")
|
||||
};
|
||||
assert_eq!(vm.call_arity(bound).unwrap(), Some(CallArity::range(0, 1)));
|
||||
assert_eq!(vm.call(bound, &[]).unwrap(), Value::Nil);
|
||||
assert_eq!(vm.get_attr(state, "called").unwrap(), Value::Bool(true));
|
||||
// 未发布 arity 的旧原生函数可独立调用,但不能证明满足已声明最小能力。
|
||||
let unknown = vm
|
||||
.allocate(NativeFunction::new("unknown", |_| Ok(Value::Nil)))
|
||||
.unwrap();
|
||||
assert_eq!(vm.call_arity(unknown).unwrap(), None);
|
||||
assert!(vm.define_method(class, "run", unknown).is_err());
|
||||
// 固定三参数函数与要求 self-only 的 run 不兼容,替换不能提交。
|
||||
let wrong = vm
|
||||
.allocate(NativeFunction::new("wrong", |_| Ok(Value::Nil)).with_arity(CallArity::exact(3)))
|
||||
.unwrap();
|
||||
@@ -406,6 +496,7 @@ fn native_arity_checks_precede_effects_and_traits_require_published_signatures()
|
||||
vm.object_store().lookup_method(class, "run").unwrap(),
|
||||
Some(native)
|
||||
);
|
||||
// 开放上界的原生区间,绑定后只扣下界 self,最大值仍须保持 usize::MAX。
|
||||
let variadic = vm
|
||||
.allocate(
|
||||
NativeFunction::new("variadic", |_| Ok(Value::Nil))
|
||||
@@ -413,6 +504,7 @@ fn native_arity_checks_precede_effects_and_traits_require_published_signatures()
|
||||
)
|
||||
.unwrap();
|
||||
vm.define_method(class, "many", variadic).unwrap();
|
||||
// 绑定开放区间函数,测试可见数量而不实际执行任意多参数。
|
||||
let Value::Object(variadic_bound) = vm.bind_attr(instance, "many").unwrap() else {
|
||||
panic!("bound")
|
||||
};
|
||||
@@ -422,6 +514,7 @@ fn native_arity_checks_precede_effects_and_traits_require_published_signatures()
|
||||
);
|
||||
vm.release(variadic_bound).unwrap();
|
||||
vm.release(variadic).unwrap();
|
||||
// 颠倒区间并放置 panic 回调,数量元数据错误必须在调用回调前返回。
|
||||
let malformed = vm
|
||||
.allocate(
|
||||
NativeFunction::new("malformed", |_| panic!("invalid metadata must not execute"))
|
||||
@@ -430,6 +523,7 @@ fn native_arity_checks_precede_effects_and_traits_require_published_signatures()
|
||||
.unwrap();
|
||||
assert!(vm.call_arity(malformed).is_err());
|
||||
assert!(vm.call(malformed, &[]).is_err());
|
||||
// 归还每份测试拥有根,内部类型/基类/方法边不手动重复释放。
|
||||
for object in [
|
||||
roots.object,
|
||||
roots.type_type,
|
||||
@@ -445,15 +539,20 @@ fn native_arity_checks_precede_effects_and_traits_require_published_signatures()
|
||||
] {
|
||||
vm.release(object).unwrap();
|
||||
}
|
||||
// 清除无外部根的类型/元类型环;仍由实例可达的定义不得回收。
|
||||
vm.collect_cycles();
|
||||
assert_eq!(vm.object_count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// 验证源码默认值缩小必填区间,同时没有数量元数据的旧原生调用仍保持可调用。
|
||||
fn unified_arity_preserves_source_defaults_and_legacy_native_calls() {
|
||||
use endor_core::{CallArity, CodeLayout, EndorCode, Instruction, NativeFunction, Opcode};
|
||||
// 各测试建立独立堆,不把其他场景的类型身份带入。
|
||||
let mut vm = Vm::new().unwrap();
|
||||
// 函数全局字典用于注解解析和环境持有,函数内部边不依赖测试根。
|
||||
let globals = vm.new_dict().unwrap();
|
||||
// 测试用已验证指令,返回常量 Nil;数量由参数布局决定。
|
||||
let code = EndorCode::from_instructions(
|
||||
&[
|
||||
Instruction::new(Opcode::LoadConst, 0),
|
||||
@@ -467,7 +566,9 @@ fn unified_arity_preserves_source_defaults_and_legacy_native_calls() {
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
// 统一分配代码拥有根,后续函数也持代码内部边。
|
||||
let code = vm.new_code(code).unwrap();
|
||||
// 函数构造校验布局并持有代码/全局/默认值引用,返回一份根。
|
||||
let function = vm
|
||||
.new_function("optional", code, globals, vec![Value::Nil], vec![])
|
||||
.unwrap();
|
||||
@@ -476,14 +577,17 @@ fn unified_arity_preserves_source_defaults_and_legacy_native_calls() {
|
||||
Some(CallArity::range(0, 1))
|
||||
);
|
||||
assert_eq!(vm.call(function, &[]).unwrap(), Value::Nil);
|
||||
// 无数量元数据仍是兼容原生函数,None 不应被误解为不支持调用。
|
||||
let legacy = vm
|
||||
.allocate(NativeFunction::new("legacy", |_| Ok(Value::Nil)))
|
||||
.unwrap();
|
||||
assert_eq!(vm.call_arity(legacy).unwrap(), None);
|
||||
assert_eq!(vm.call(legacy, &[]).unwrap(), Value::Nil);
|
||||
// 归还每份测试拥有根,内部类型/基类/方法边不手动重复释放。
|
||||
for object in [globals, code, function, legacy] {
|
||||
vm.release(object).unwrap();
|
||||
}
|
||||
// 清除无外部根的类型/元类型环;仍由实例可达的定义不得回收。
|
||||
vm.collect_cycles();
|
||||
assert_eq!(vm.object_count(), 0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user