diff --git a/crates/core/tests/types.rs b/crates/core/tests/types.rs index 8b91548..4655662 100644 --- a/crates/core/tests/types.rs +++ b/crates/core/tests/types.rs @@ -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 { Some(endor_core::CallArity::range(1, 2)) } + /// 数量检查通过后才设置 called 标志,返回直接 Nil,用于观测是否进入回调。 fn invoke( &self, cx: &mut endor_core::NativeContext<'_>, _: &[Value], ) -> Result { + // 回调唯一副作用,错误数量调用后的 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); }