diff --git a/crates/core/src/README.md b/crates/core/src/README.md index 8ae35d7..9c195d2 100644 --- a/crates/core/src/README.md +++ b/crates/core/src/README.md @@ -4,7 +4,7 @@ | 文件 | 职责 | | --- | --- | -| [lib.rs](lib.rs) | VM 类型导出、objects 类型兼容重导出(含 ReadAccess/CallSignature/CallEffect)、宿主调用与字节码 rustdoc 示例 | +| [lib.rs](lib.rs) | VM 类型导出、objects 类型兼容重导出(含 ReadAccess/CallSignature/CallType/CallEffect)、宿主调用与字节码 rustdoc 示例 | | [vm.rs](vm.rs) | Vm 拥有 ObjectStore 与错误位置记录;对象操作和宿主 new_class 和显式Trait注册/关系查询显式委托给 objects;函数/字段检查统一开关、统一参数区间查询与函数类型配置 | | [frame.rs](frame.rs) | EndorFrame、栈条目、源码与原生委托返回契约执行根、执行位置元数据、ExecutionLimits | | [eval.rs](eval.rs) | execute/call、只读调用与依赖结果、参数绑定、原生实现前数量/类型/效果检查和委托返回检查、可选注解检查、源码类字段环境绑定、帧切换、取指分派、MakeFunction、结果根转移与失败清理 | diff --git a/crates/core/src/eval.rs b/crates/core/src/eval.rs index 38cd724..3919782 100644 --- a/crates/core/src/eval.rs +++ b/crates/core/src/eval.rs @@ -313,14 +313,21 @@ impl Vm { } *executed += 1; if let Some(signature) = self.objects.native_signature(function)? - && !matches!(signature.returns, crate::AnnotationType::Any) + && !signature.returns.is_any() { let check = NativeReturn { name: self.object(function)?.payload().kind_name().into(), expected: signature.returns, }; - if let Some(reference) = check.expected.reference() { - self.retain(reference)?; + let mut retained = Vec::new(); + for reference in check.expected.references() { + if let Err(error) = self.retain(reference) { + for reference in retained { + self.release(reference)?; + } + return Err(error); + } + retained.push(reference); } returns.push(check); } @@ -363,7 +370,7 @@ impl Vm { fn clear_native_returns(&mut self, returns: Vec) { for check in returns { - if let Some(reference) = check.expected.reference() { + for reference in check.expected.references() { self.release(reference) .expect("native return check owns its type"); } diff --git a/crates/core/src/frame.rs b/crates/core/src/frame.rs index 1172f9d..6130e9a 100644 --- a/crates/core/src/frame.rs +++ b/crates/core/src/frame.rs @@ -13,19 +13,12 @@ pub(crate) enum StackEntry { #[derive(Debug)] pub(crate) struct NativeReturn { pub name: String, - pub expected: crate::AnnotationType, + pub expected: crate::CallType, } impl NativeReturn { pub fn check(&self, store: &objects::ObjectStore, value: &Value) -> Result<(), crate::VmError> { - if !store.matches_annotation(value, self.expected)? { - return Err(crate::VmError::TypeMismatch { - function: self.name.clone(), - position: "return".into(), - expected: store.annotation_type_name(self.expected)?, - actual: store.value_type_name(value)?, - }); - } - Ok(()) + self.expected + .check(store, &self.name, "return".into(), value) } } diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index bd82c18..4ca2153 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -50,7 +50,7 @@ pub use objects::{ TypeConstructor, }; pub use objects::{ - CallArity, CallEffect, CallSignature, ChangeBatch, ChangeKey, CodeLayout, CompareOp, + CallArity, CallEffect, CallSignature, CallType, ChangeBatch, ChangeKey, CodeLayout, CompareOp, ContextNativeFunction, DecodedInstruction, EndorBaseExceptionObject, EndorCellObject, EndorCode, EndorCodeObject, EndorDecimal, EndorDictObject, EndorFunctionObject, EndorInteger, EndorNativeCall, EndorNativeFunctionObject, EndorNumber, EndorNumberObject, EndorObject, diff --git a/crates/core/tests/README.md b/crates/core/tests/README.md index 24ff9ba..082cd70 100644 --- a/crates/core/tests/README.md +++ b/crates/core/tests/README.md @@ -8,7 +8,7 @@ | [builtins.rs](builtins.rs) | 无损 Number、Unicode 字符串、Dict 顺序与键、Cell、函数环境/共享代码、异常数据 | | [execution.rs](execution.rs) | wordcode 与校验、控制流、参数/默认值、嵌套帧、字节码函数创建/默认值/环境捕获、闭包、返回值存活、失败清理、限额 | | [types.rs](types.rs) | 名义身份、继承与实例关系、类型边保活/循环回收、只读类型元数据与外来句柄、显式Trait身份/继承/参数约束及后代更新原子性;统一函数分类、原生数量元数据/副作用前拒绝/能力更新/默认参数与返回类型错误根清理;仅远端执行 | -| [native_context.rs](native_context.rs) | 原生作用域根、分配失败清理、原生签名/效果和委托返回根、绑定方法元数据、委托、只读结果分配/写入拒绝/依赖/校验与普通读取区分及失败恢复、弱引用过期及有界变更;仅远端执行 | +| [native_context.rs](native_context.rs) | 原生作用域根、分配失败清理、原生签名/联合与可空类型/效果和委托返回根、绑定方法元数据、委托、只读结果分配/写入拒绝/依赖/校验与普通读取区分及失败恢复、弱引用过期及有界变更;仅远端执行 | 核心对象现由 objects 定义,本目录保留既有 endor_core 导入与 Vm 方法的兼容性检查。独立对象存储检查见 [objects/tests](../../objects/tests/README.md)。堆内部伪造句柄与计数溢出检查在 objects 的 src/heap.rs,公开示例由 src/lib.rs rustdoc 提供。文件职责见 [src](../src/README.md),检查方式和结果边界见 [验证](../../../docs/operations/validation.md)。本地不执行测试;存在测试文件不代表某次提交已通过。返回 [core](../README.md)。 diff --git a/crates/core/tests/native_context.rs b/crates/core/tests/native_context.rs index 7ec4774..13c5a2e 100644 --- a/crates/core/tests/native_context.rs +++ b/crates/core/tests/native_context.rs @@ -505,8 +505,8 @@ fn legacy_native_signatures_check_optional_variadic_types_and_metadata() { NativeFunction::new("legacy", echo).with_signature(CallSignature { arity: CallArity::range(0, usize::MAX), parameters: vec![], - variadic: Some(T::Number), - returns: T::Number, + variadic: Some(T::Number.into()), + returns: T::Number.into(), effect: CallEffect::ReadOnly, }), ) @@ -585,15 +585,13 @@ fn delegated_return_type_survives_removal_of_the_original_signature_edges() { let source = vm .new_function("source", code, globals, vec![], vec![]) .unwrap(); + let mut signature = CallSignature::exact(vec![], T::Any, CallEffect::Mutating); + signature.returns = endor_core::CallType::Union(vec![T::Nominal(definition), T::Number]); let wrapper = vm .allocate(ContextNativeFunction::new( "erased", EraseThenDelegate { - signature: CallSignature::exact( - vec![], - T::Nominal(definition), - CallEffect::Mutating, - ), + signature, target: source, }, vec![source], @@ -601,7 +599,7 @@ fn delegated_return_type_survives_removal_of_the_original_signature_edges() { .unwrap(); vm.release(definition).unwrap(); assert!( - matches!(vm.call(wrapper, &[]), Err(VmError::TypeMismatch { function, expected, .. }) if function == "erased" && expected == "Transient") + matches!(vm.call(wrapper, &[]), Err(VmError::TypeMismatch { function, expected, .. }) if function == "erased" && expected == "Transient | Number") ); assert!(vm.upgrade(weak).unwrap().is_none()); for object in [ @@ -617,3 +615,107 @@ fn delegated_return_type_survives_removal_of_the_original_signature_edges() { vm.collect_cycles(); assert_eq!(vm.object_count(), 0); } + +#[test] +fn native_union_and_nullable_contracts_accept_each_branch_and_reject_invalid_metadata() { + use endor_core::{AnnotationType as T, CallEffect, CallSignature, CallType}; + use std::sync::{ + Arc, + atomic::{AtomicUsize, Ordering}, + }; + let mut vm = Vm::new().unwrap(); + let calls = Arc::new(AtomicUsize::new(0)); + let mut signature = CallSignature::exact(vec![T::Any], T::Any, CallEffect::ReadOnly); + signature.parameters[0] = CallType::Union(vec![T::String, T::Bool]); + signature.returns = signature.parameters[0].clone(); + let function = vm + .allocate(ContextNativeFunction::new( + "union", + TypedNative { + signature, + calls: calls.clone(), + delegate: None, + allocate_result: false, + }, + vec![], + )) + .unwrap(); + for value in [ + Value::Text("capture".into()), + Value::Bool(true), + Value::Bool(false), + ] { + assert_eq!( + vm.call(function, std::slice::from_ref(&value)).unwrap(), + value + ); + } + assert!( + matches!(vm.call(function, &[Value::Number(3.into())]), Err(VmError::TypeMismatch { expected, .. }) if expected == "String | Bool") + ); + assert_eq!(calls.load(Ordering::SeqCst), 3); + let mut signature = CallSignature::exact(vec![T::Any], T::Any, CallEffect::ReadOnly); + signature.parameters[0] = CallType::nullable(T::Number); + signature.returns = signature.parameters[0].clone(); + vm.replace_payload( + function, + ContextNativeFunction::new( + "nullable", + TypedNative { + signature, + calls: calls.clone(), + delegate: None, + allocate_result: false, + }, + vec![], + ), + ) + .unwrap(); + for value in [Value::Nil, Value::Number(2.into())] { + assert_eq!( + vm.call(function, std::slice::from_ref(&value)).unwrap(), + value + ); + } + let record = vm.new_object().unwrap(); + let mut signature = CallSignature::exact(vec![T::Any], T::Any, CallEffect::ReadOnly); + // A matching first branch must not hide a later invalid nominal definition. + signature.parameters[0] = CallType::Union(vec![T::Any, T::Nominal(record)]); + vm.replace_payload( + function, + ContextNativeFunction::new( + "invalid union", + TypedNative { + signature, + calls: calls.clone(), + delegate: None, + allocate_result: false, + }, + vec![], + ), + ) + .unwrap(); + assert!(vm.call(function, &[Value::Nil]).is_err()); + assert_eq!(calls.load(Ordering::SeqCst), 5); + let mut signature = CallSignature::exact(vec![], T::Any, CallEffect::ReadOnly); + signature.returns = CallType::Union(vec![]); + vm.replace_payload( + function, + ContextNativeFunction::new( + "empty union", + TypedNative { + signature, + calls: calls.clone(), + delegate: None, + allocate_result: false, + }, + vec![], + ), + ) + .unwrap(); + assert!(vm.call(function, &[]).is_err()); + assert_eq!(calls.load(Ordering::SeqCst), 5); + vm.release(record).unwrap(); + vm.release(function).unwrap(); + assert_eq!(vm.object_count(), 0); +} diff --git a/crates/objects/src/README.md b/crates/objects/src/README.md index 227b300..0424a4d 100644 --- a/crates/objects/src/README.md +++ b/crates/objects/src/README.md @@ -4,7 +4,7 @@ | 文件 | 职责 | | --- | --- | -| [lib.rs](lib.rs) | 包边界、对象类型/ObjectStore 公开导出(含Trait/MethodRequirement/SourceSignature/AnnotationType/CallArity/CallSignature/CallEffect/ReadAccess)与独立存储 rustdoc 示例 | +| [lib.rs](lib.rs) | 包边界、对象类型/ObjectStore 公开导出(含Trait/MethodRequirement/SourceSignature/AnnotationType/CallArity/CallSignature/CallType/CallEffect/ReadAccess)与独立存储 rustdoc 示例 | | [object.rs](object.rs) | Value、CompareOp、ObjectPayload(含显式函数标记)、ObjectHeader、EndorObject、Record、可发布数量元数据的 NativeFunction | | [types.rs](types.rs) | 托管名义类型、显式 Object/Type 引导、继承查询、受管方法表/接收者绑定、类字段、显式Trait定义/声明/方法参数约束、原生构造委托、统一源码/原生/绑定方法参数区间查询与能力验证、声明环境托管边、字段构造/写入检查与标记为校验读取的注解解析/匹配 | | [native.rs](native.rs) | NativeContext、CallArity/CallSignature 类型与效果元数据、调用前检查、签名类型强边、上下文原生函数、作用域语言函数工厂、显式能力声明入口、函数标记、根与非递归委托调用 | diff --git a/crates/objects/src/lib.rs b/crates/objects/src/lib.rs index aadc271..282e15b 100644 --- a/crates/objects/src/lib.rs +++ b/crates/objects/src/lib.rs @@ -36,8 +36,8 @@ pub use error::VmError; pub use heap::{ObjectRef, ReadAccess, WeakObjectRef}; pub use instruction::{DecodedInstruction, Instruction, Opcode}; pub use native::{ - CallArity, CallEffect, CallSignature, ContextNativeFunction, NativeCallable, NativeContext, - NativeResult, + CallArity, CallEffect, CallSignature, CallType, ContextNativeFunction, NativeCallable, + NativeContext, NativeResult, }; pub use number::{ EndorDecimal, EndorInteger, EndorNumber, EndorNumberObject, EndorRational, EndorReal, diff --git a/crates/objects/src/native.rs b/crates/objects/src/native.rs index 576a6d2..0658b37 100644 --- a/crates/objects/src/native.rs +++ b/crates/objects/src/native.rs @@ -59,14 +59,91 @@ pub enum CallEffect { External, } +/// Resolved native value contract. A union is flat, nonempty and preserves +/// all definition edges even when an earlier alternative already matches. +#[derive(Debug, Clone)] +pub enum CallType { + Single(crate::AnnotationType), + Union(Vec), +} +impl From for CallType { + fn from(value: crate::AnnotationType) -> Self { + Self::Single(value) + } +} +impl CallType { + pub fn nullable(value: crate::AnnotationType) -> Self { + Self::Union(vec![value, crate::AnnotationType::Unit]) + } + fn alternatives(&self) -> &[crate::AnnotationType] { + match self { + Self::Single(value) => std::slice::from_ref(value), + Self::Union(values) => values, + } + } + pub fn references(&self) -> impl Iterator + '_ { + self.alternatives() + .iter() + .copied() + .filter_map(crate::AnnotationType::reference) + } + pub fn is_any(&self) -> bool { + self.alternatives() + .iter() + .any(|value| matches!(value, crate::AnnotationType::Any)) + } + pub fn validate(&self, store: &ObjectStore) -> Result<(), VmError> { + if self.alternatives().is_empty() { + return Err(VmError::InvalidArgument("empty native union type")); + } + for value in self.alternatives() { + match *value { + crate::AnnotationType::Nominal(reference) => { + store.payload::(reference, "Type")?; + } + crate::AnnotationType::Capability(reference) => { + store.payload::(reference, "Trait")?; + } + _ => {} + } + } + Ok(()) + } + pub fn check( + &self, + store: &ObjectStore, + name: &str, + position: String, + value: &Value, + ) -> Result<(), VmError> { + self.validate(store)?; + for expected in self.alternatives() { + if store.matches_annotation(value, *expected)? { + return Ok(()); + } + } + let names = self + .alternatives() + .iter() + .map(|expected| store.annotation_type_name(*expected)) + .collect::, _>>()?; + Err(VmError::TypeMismatch { + function: name.into(), + position, + expected: names.join(" | "), + actual: store.value_type_name(value)?, + }) + } +} + /// Immutable native contract, including an explicit receiver where applicable. /// Missing fixed slots are covered by variadic; optionality comes from arity. #[derive(Debug, Clone)] pub struct CallSignature { pub arity: CallArity, - pub parameters: Vec, - pub variadic: Option, - pub returns: crate::AnnotationType, + pub parameters: Vec, + pub variadic: Option, + pub returns: CallType, pub effect: CallEffect, } impl CallSignature { @@ -77,19 +154,18 @@ impl CallSignature { ) -> Self { Self { arity: CallArity::exact(parameters.len()), - parameters, + parameters: parameters.into_iter().map(CallType::from).collect(), variadic: None, - returns, + returns: returns.into(), effect, } } pub fn references(&self) -> impl Iterator + '_ { self.parameters .iter() - .copied() - .chain(self.variadic) - .chain([self.returns]) - .filter_map(crate::AnnotationType::reference) + .chain(self.variadic.as_ref()) + .chain([&self.returns]) + .flat_map(CallType::references) } pub fn validate(&self, store: &ObjectStore) -> Result<(), VmError> { self.arity.validate()?; @@ -101,19 +177,10 @@ impl CallSignature { for expected in self .parameters .iter() - .copied() - .chain(self.variadic) - .chain([self.returns]) + .chain(self.variadic.as_ref()) + .chain([&self.returns]) { - match expected { - crate::AnnotationType::Nominal(reference) => { - store.payload::(reference, "Type")?; - } - crate::AnnotationType::Capability(reference) => { - store.payload::(reference, "Trait")?; - } - _ => {} - } + expected.validate(store)?; } Ok(()) } @@ -134,16 +201,9 @@ impl CallSignature { let expected = self .parameters .get(index) - .copied() - .or(self.variadic) + .or(self.variadic.as_ref()) .ok_or(VmError::InvalidArgument("incomplete native signature"))?; - self.check_value( - store, - name, - format!("parameter {}", index + 1), - value, - expected, - )?; + expected.check(store, name, format!("parameter {}", index + 1), value)?; } Ok(()) } @@ -153,25 +213,7 @@ impl CallSignature { name: &str, value: &Value, ) -> Result<(), VmError> { - self.check_value(store, name, "return".into(), value, self.returns) - } - fn check_value( - &self, - store: &ObjectStore, - name: &str, - position: String, - value: &Value, - expected: crate::AnnotationType, - ) -> Result<(), VmError> { - if !store.matches_annotation(value, expected)? { - return Err(VmError::TypeMismatch { - function: name.into(), - position, - expected: store.annotation_type_name(expected)?, - actual: store.value_type_name(value)?, - }); - } - Ok(()) + self.returns.check(store, name, "return".into(), value) } } diff --git a/docs/README.md b/docs/README.md index 2eb95ff..e770297 100644 --- a/docs/README.md +++ b/docs/README.md @@ -5,7 +5,7 @@ | 引擎与宿主边界 | [架构](architecture/README.md) | [crates](../crates/README.md) | | 解释执行、资源修订与引擎升级 | [执行与版本](architecture/execution-and-versions.md) | frontend/compiler/core | | EndorObject、句柄、默认操作 | [对象模型](runtime/objects.md) | objects/src | -| 原生上下文、只读调用、子调用读取依赖及校验分类、统一参数数量/类型/效果、委托返回与变更通知 | [原生调用](runtime/native-calls.md) | objects/src/native.rs、changes.rs、core/src/eval.rs | +| 原生上下文、只读调用、子调用读取依赖及校验分类、统一参数数量/类型/联合/效果、委托返回与变更通知 | [原生调用](runtime/native-calls.md) | objects/src/native.rs、changes.rs、core/src/eval.rs | | 托管类型、宿主类注册、原生分配继承、字段存储、显式能力、函数分类、声明字段与可选源码注解检查 | [名义类型](runtime/types.md) | objects/src/types.rs | | Number、String、Dict、Cell、Function | [基本对象](runtime/builtins.md) | objects/src | | 源码读取与来源 | [Reader](runtime/reader.md) | frontend/src/reader.rs | diff --git a/docs/runtime/README.md b/docs/runtime/README.md index 94d8348..4f6225d 100644 --- a/docs/runtime/README.md +++ b/docs/runtime/README.md @@ -4,7 +4,7 @@ | --- | --- | | [types.md](types.md) | 托管 Object/Type、名义继承、声明字段/函数注解检查、构造与类型边生命周期 | | [objects.md](objects.md) | 对象、句柄与默认操作 | -| [native-calls.md](native-calls.md) | 原生上下文、读取分类、统一参数数量/类型/效果、非递归委托返回、弱引用、托管赋值与变更批次 | +| [native-calls.md](native-calls.md) | 原生上下文、读取分类、统一参数数量/类型/联合/效果、非递归委托返回、弱引用、托管赋值与变更批次 | | [builtins.md](builtins.md) | Number、String、Dict、Cell、Function、异常数据 | | [reader.md](reader.md) | 输入、来源和修订标签 | | [frontend.md](frontend.md) | 词法、语法和诊断 | diff --git a/docs/runtime/native-calls.md b/docs/runtime/native-calls.md index fc07f67..8ceb762 100644 --- a/docs/runtime/native-calls.md +++ b/docs/runtime/native-calls.md @@ -90,7 +90,9 @@ Tessera 为原生方法、回调和内部视觉 continuation 发布数量元数 ## 原生参数、返回类型与宿主效果 -CallSignature 保存 CallArity、固定位置的 AnnotationType 列表、可选 variadic 类型、returns 与 CallEffect。exact 提供无默认参数的便捷构造;可选参数仍通过 arity.required/maximum 表示,列表覆盖所有固定位置。开放上界必须有 variadic,有限上界未被固定列表覆盖的部分也必须有 variadic;错误区间、不完整列表、非 Type/Trait 的名义/能力引用和独立 arity 与签名不一致在调用前拒绝。名义类型引用是实际定义,不从字符串或调用者全局环境重新解析。 +CallSignature 保存 CallArity、固定位置的 CallType 列表、可选 variadic 类型、returns 与 CallEffect。exact 提供无默认参数的便捷构造;可选参数仍通过 arity.required/maximum 表示,列表覆盖所有固定位置。开放上界必须有 variadic,有限上界未被固定列表覆盖的部分也必须有 variadic;错误区间、不完整列表、非 Type/Trait 的名义/能力引用和独立 arity 与签名不一致在调用前拒绝。名义类型引用是实际定义,不从字符串或调用者全局环境重新解析。 + +CallType::Single 封装一个现有 AnnotationType;Union 保存非空的平坦分支列表,nullable(T) 等价于 T | Unit。每个分支先完整校验,不能因较早的 Object/匹配分支而隐藏后续错误定义。匹配任一分支即接受,不匹配时报告按声明顺序组合的名称。全部分支的类型/能力引用都参加 trace 与委托返回执行根保活,包括未被本次值选中的分支;根取得中途出错会撤销已取得的根。exact 仍接受原来的单类型列表作便捷构造并转换为 Single。此能力属于原生宿主契约,没有增加 Endor 的联合类型语法。 NativeCallable::signature 默认 None,明确表示尚未发布类型/效果契约;默认 arity 从签名取得。ObjectPayload::call_signature 供自定义直接调用协议发布。ContextNativeFunction 在创建时保存不可变签名并在 trace 中自动登记每个类型/能力引用;其他捕获仍须显式传 captures。NativeFunction::with_signature 同样追踪签名边并设置数量。自定义载荷须在 trace 中登记自己的签名引用,元数据与其他载荷边一样禁止原地改变;更换使用 replace_payload。ObjectStore::native_signature 校验并返回借用描述,不创建隐藏强注册表。 @@ -100,6 +102,8 @@ NativeResult::Invoke 仍是尾委托,不递归进入 Rust/VM。VM 为每层已 CallEffect::ReadOnly 声明只读现存对象,可分配临时结果;Mutating 与 External 在 ObjectStore 只读作用域内、进入实现前拒绝。普通执行允许这些效果。ReadOnly 声明不绕过已有写屏障,也不证明可信 Rust 不会进行隐藏 I/O;未知旧原生函数仍沿原调用/宿主检查,不能把 None 理解为纯函数。这不是静态效果推断、完整 I/O 沙箱或对阻塞原生代码的抢占。 -Tessera 的 measure/arrange/paint/hitTest、Point 几何查询、Window 方法及可表达的 Block/Container/Page 方法发布签名。需要 nullable/union 参数的 Page.open/window 与 Block.on 尚保留无类型元数据;构造器、其他管理 API 和完整源码覆写方差仍未全部接入。能力注册目前继续检查参数数量,不声称已经比较签名类型或效果。 +Tessera 的 measure/arrange/paint/hitTest、Point 几何查询、Window、Block/Container/Page、Mount、Task、Event、Subscription 方法和 ObjectList.at 发布签名。Page.open 的 Window | Unit、Page.window 的 Window | Unit 返回,以及 Block.on 的 Bool | String 可选阶段有准确元数据;Mount 的父/子/同级/Page 弱查询为可空结果。Mount.bounds 现在返回带 Bounds 名义类型的现有几何记录,可直接组合到 Point.inside 或视觉方法。滚动位置/字典等通用记录仍声明 Object,不冒充新语言类型;任务 owner 的具体资源资格仍按原域检查。构造器、其他管理 API 和完整源码覆写方差仍未全部接入。能力注册目前继续检查参数数量,不声称已经比较签名类型或效果。 回归源码 native_context.rs 覆盖参数副作用前拒绝、错误结果清理、跨原生/源码委托检查、单帧限制、名义签名边与绑定方法循环回收、只读效果拒绝、传统直接函数及重复参数和元数据错误。只编译,不本地执行。 + +联合/可空回归另覆盖两个标量分支、nil、数值拒绝、Object 分支不掩盖非法名义类型、空联合拒绝,以及移除签名后联合返回定义仍存活。