diff --git a/crates/core/src/README.md b/crates/core/src/README.md index d30a784..9e32590 100644 --- a/crates/core/src/README.md +++ b/crates/core/src/README.md @@ -5,9 +5,9 @@ | 文件 | 职责 | | --- | --- | | [lib.rs](lib.rs) | VM 类型导出、objects 类型兼容重导出、宿主调用与字节码 rustdoc 示例 | -| [vm.rs](vm.rs) | Vm 拥有 ObjectStore 与错误位置记录;对象操作和宿主 new_class 和显式Trait注册/关系查询显式委托给 objects;函数/字段检查统一开关与函数类型配置 | +| [vm.rs](vm.rs) | Vm 拥有 ObjectStore 与错误位置记录;对象操作和宿主 new_class 和显式Trait注册/关系查询显式委托给 objects;函数/字段检查统一开关、统一参数区间查询与函数类型配置 | | [frame.rs](frame.rs) | EndorFrame、栈条目、返回类型执行根、执行位置元数据、ExecutionLimits | -| [eval.rs](eval.rs) | execute/call、只读调用与依赖结果、参数绑定、可选注解检查、源码类字段环境绑定、帧切换、取指分派、MakeFunction、结果根转移与失败清理 | +| [eval.rs](eval.rs) | execute/call、只读调用与依赖结果、参数绑定、原生实现前数量检查、可选注解检查、源码类字段环境绑定、帧切换、取指分派、MakeFunction、结果根转移与失败清理 | ## 常见修改入口 diff --git a/crates/core/src/eval.rs b/crates/core/src/eval.rs index 970e6d1..50a84dd 100644 --- a/crates/core/src/eval.rs +++ b/crates/core/src/eval.rs @@ -260,6 +260,16 @@ impl Vm { for argument in arguments { self.validate_value(argument)?; } + if let Some(arity) = self.objects.call_arity(function)? + && !arity.accepts(arguments.len()) + { + return Err(VmError::ArgumentCount { + name: self.object(function)?.payload().kind_name().into(), + required: arity.required, + maximum: arity.maximum, + provided: arguments.len(), + }); + } if let Some(callable) = self.object(function)?.payload().native_callable() { return NativeContext::execute(&mut self.objects, function, arguments, callable); } diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index 1a19fc6..4bc1506 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -50,12 +50,12 @@ pub use objects::{ TypeConstructor, }; pub use objects::{ - ChangeBatch, ChangeKey, CodeLayout, CompareOp, ContextNativeFunction, DecodedInstruction, - EndorBaseExceptionObject, EndorCellObject, EndorCode, EndorCodeObject, EndorDecimal, - EndorDictObject, EndorFunctionObject, EndorInteger, EndorNativeCall, EndorNativeFunctionObject, - EndorNumber, EndorNumberObject, EndorObject, EndorRational, EndorReal, EndorStringObject, - EndorTracebackEntry, Instruction, NativeCall, NativeCallable, NativeContext, NativeFunction, - NativeResult, ObjectChange, ObjectHeader, ObjectPayload, ObjectRef, Opcode, Record, - SourceSignature, Value, VmError, WeakObjectRef, + CallArity, ChangeBatch, ChangeKey, CodeLayout, CompareOp, ContextNativeFunction, + DecodedInstruction, EndorBaseExceptionObject, EndorCellObject, EndorCode, EndorCodeObject, + EndorDecimal, EndorDictObject, EndorFunctionObject, EndorInteger, EndorNativeCall, + EndorNativeFunctionObject, EndorNumber, EndorNumberObject, EndorObject, EndorRational, + EndorReal, EndorStringObject, EndorTracebackEntry, Instruction, NativeCall, NativeCallable, + NativeContext, NativeFunction, NativeResult, ObjectChange, ObjectHeader, ObjectPayload, + ObjectRef, Opcode, Record, SourceSignature, Value, VmError, WeakObjectRef, }; pub use vm::Vm; diff --git a/crates/core/src/vm.rs b/crates/core/src/vm.rs index ad2261c..749d3ed 100644 --- a/crates/core/src/vm.rs +++ b/crates/core/src/vm.rs @@ -25,6 +25,10 @@ impl Vm { self.source_type_checks = enabled; Ok(()) } + pub fn call_arity(&self, function: ObjectRef) -> Result, VmError> { + self.objects.call_arity(function) + } + pub fn set_function_type(&mut self, definition: ObjectRef) -> Result<(), VmError> { self.objects.set_function_type(definition) } diff --git a/crates/core/tests/README.md b/crates/core/tests/README.md index 916ece6..5745a1c 100644 --- a/crates/core/tests/README.md +++ b/crates/core/tests/README.md @@ -7,7 +7,7 @@ | [runtime.rs](runtime.rs) | 空堆启动、默认操作、引用/借用、属性原子性、稳定地址、长链/循环、原生回调、VM 销毁 | | [builtins.rs](builtins.rs) | 无损 Number、Unicode 字符串、Dict 顺序与键、Cell、函数环境/共享代码、异常数据 | | [execution.rs](execution.rs) | wordcode 与校验、控制流、参数/默认值、嵌套帧、字节码函数创建/默认值/环境捕获、闭包、返回值存活、失败清理、限额 | -| [types.rs](types.rs) | 名义身份、继承与实例关系、类型边保活/循环回收、只读类型元数据与外来句柄、显式Trait身份/继承/参数约束及后代更新原子性;统一函数分类与返回类型错误根清理;仅远端执行 | +| [types.rs](types.rs) | 名义身份、继承与实例关系、类型边保活/循环回收、只读类型元数据与外来句柄、显式Trait身份/继承/参数约束及后代更新原子性;统一函数分类、原生数量元数据/副作用前拒绝/能力更新/默认参数与返回类型错误根清理;仅远端执行 | | [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/types.rs b/crates/core/tests/types.rs index b05a32f..8b91548 100644 --- a/crates/core/tests/types.rs +++ b/crates/core/tests/types.rs @@ -329,3 +329,161 @@ fn failed_nominal_return_releases_value_and_captured_type_roots() { vm.collect_cycles(); assert_eq!(vm.object_count(), 0); } + +#[derive(Debug)] +struct CountedNative(endor_core::ObjectRef); +impl endor_core::NativeCallable for CountedNative { + fn arity(&self) -> Option { + Some(endor_core::CallArity::range(1, 2)) + } + fn invoke( + &self, + cx: &mut endor_core::NativeContext<'_>, + _: &[Value], + ) -> Result { + 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(); + let roots = vm.bootstrap_types().unwrap(); + let state = vm.new_object().unwrap(); + vm.set_attr(state, "called", Value::Bool(false)).unwrap(); + let native = vm + .allocate(ContextNativeFunction::new( + "counted", + CountedNative(state), + vec![state], + )) + .unwrap(); + assert_eq!(vm.call_arity(native).unwrap(), Some(CallArity::range(1, 2))); + assert!(matches!( + vm.call(native, &[]), + Err(VmError::ArgumentCount { .. }) + )); + assert_eq!(vm.get_attr(state, "called").unwrap(), Value::Bool(false)); + let class = vm + .new_class( + "Data", + roots.object, + vec![], + [("run".into(), native)].into(), + ) + .unwrap(); + let capability = vm + .new_trait( + "Runnable", + vec![MethodRequirement { + name: "run".into(), + parameters: 0, + }], + ) + .unwrap(); + vm.implement_trait(class, capability).unwrap(); + let Value::Object(instance) = vm.call(class, &[]).unwrap() else { + panic!("instance") + }; + 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)); + 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()); + let wrong = vm + .allocate(NativeFunction::new("wrong", |_| Ok(Value::Nil)).with_arity(CallArity::exact(3))) + .unwrap(); + assert!(vm.define_method(class, "run", wrong).is_err()); + assert_eq!( + vm.object_store().lookup_method(class, "run").unwrap(), + Some(native) + ); + let variadic = vm + .allocate( + NativeFunction::new("variadic", |_| Ok(Value::Nil)) + .with_arity(CallArity::range(1, usize::MAX)), + ) + .unwrap(); + vm.define_method(class, "many", variadic).unwrap(); + let Value::Object(variadic_bound) = vm.bind_attr(instance, "many").unwrap() else { + panic!("bound") + }; + assert_eq!( + vm.call_arity(variadic_bound).unwrap(), + Some(CallArity::range(0, usize::MAX)) + ); + vm.release(variadic_bound).unwrap(); + vm.release(variadic).unwrap(); + let malformed = vm + .allocate( + NativeFunction::new("malformed", |_| panic!("invalid metadata must not execute")) + .with_arity(CallArity::range(2, 1)), + ) + .unwrap(); + assert!(vm.call_arity(malformed).is_err()); + assert!(vm.call(malformed, &[]).is_err()); + for object in [ + roots.object, + roots.type_type, + state, + native, + class, + capability, + instance, + bound, + unknown, + wrong, + malformed, + ] { + 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(); + let code = EndorCode::from_instructions( + &[ + Instruction::new(Opcode::LoadConst, 0), + Instruction::simple(Opcode::ReturnValue), + ], + vec![Value::Nil], + CodeLayout { + parameters: vec!["value".into()], + locals: vec!["value".into()], + ..CodeLayout::default() + }, + ) + .unwrap(); + let code = vm.new_code(code).unwrap(); + let function = vm + .new_function("optional", code, globals, vec![Value::Nil], vec![]) + .unwrap(); + assert_eq!( + vm.call_arity(function).unwrap(), + Some(CallArity::range(0, 1)) + ); + assert_eq!(vm.call(function, &[]).unwrap(), Value::Nil); + 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); +} diff --git a/crates/objects/src/README.md b/crates/objects/src/README.md index bcf5f61..464074b 100644 --- a/crates/objects/src/README.md +++ b/crates/objects/src/README.md @@ -4,10 +4,10 @@ | 文件 | 职责 | | --- | --- | -| [lib.rs](lib.rs) | 包边界、对象类型/ObjectStore 公开导出(含Trait/MethodRequirement/SourceSignature/AnnotationType)与独立存储 rustdoc 示例 | -| [object.rs](object.rs) | Value、CompareOp、ObjectPayload(含显式函数标记)、ObjectHeader、EndorObject、Record、NativeFunction | -| [types.rs](types.rs) | 托管名义类型、显式 Object/Type 引导、继承查询、受管方法表/接收者绑定、类字段、显式Trait定义/声明/方法参数约束、原生构造委托、声明环境托管边、字段构造/写入检查与注解解析/匹配 | -| [native.rs](native.rs) | NativeContext、上下文原生函数、作用域语言函数工厂、显式能力声明入口、函数标记、根与非递归委托调用 | +| [lib.rs](lib.rs) | 包边界、对象类型/ObjectStore 公开导出(含Trait/MethodRequirement/SourceSignature/AnnotationType/CallArity)与独立存储 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 元数据与调用前数量检查、上下文原生函数、作用域语言函数工厂、显式能力声明入口、函数标记、根与非递归委托调用 | | [changes.rs](changes.rs) | 合并变更批次、变更键与有界通知额度 | | [number.rs](number.rs) | Integer/Decimal/Rational/BinaryFloat/Complex 的无损表示和装箱载荷 | | [builtins.rs](builtins.rs) | String、Dict、Cell、Function、BaseException 载荷与 trace 边、语言函数标记 | diff --git a/crates/objects/src/lib.rs b/crates/objects/src/lib.rs index f31089c..0e9051d 100644 --- a/crates/objects/src/lib.rs +++ b/crates/objects/src/lib.rs @@ -35,7 +35,7 @@ pub use code::{CodeLayout, EndorCode, EndorCodeObject, SourceSignature}; pub use error::VmError; pub use heap::{ObjectRef, WeakObjectRef}; pub use instruction::{DecodedInstruction, Instruction, Opcode}; -pub use native::{ContextNativeFunction, NativeCallable, NativeContext, NativeResult}; +pub use native::{CallArity, 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 c5dfc89..c05262a 100644 --- a/crates/objects/src/native.rs +++ b/crates/objects/src/native.rs @@ -13,7 +13,49 @@ pub enum NativeResult { }, } +/// Accepted positional argument interval, including explicit receivers. +/// The store validates metadata before use; usize::MAX denotes an open upper bound. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct CallArity { + pub required: usize, + pub maximum: usize, +} +impl CallArity { + pub const fn exact(count: usize) -> Self { + Self::range(count, count) + } + pub const fn range(required: usize, maximum: usize) -> Self { + Self { required, maximum } + } + pub fn accepts(self, count: usize) -> bool { + (self.required..=self.maximum).contains(&count) + } + pub(crate) fn validate(self) -> Result { + if self.required > self.maximum { + return Err(VmError::InvalidArgument("invalid callable arity metadata")); + } + Ok(self) + } + pub(crate) fn check(self, name: String, provided: usize) -> Result<(), VmError> { + self.validate()?; + if !self.accepts(provided) { + return Err(VmError::ArgumentCount { + name, + required: self.required, + maximum: self.maximum, + provided, + }); + } + Ok(()) + } +} + pub trait NativeCallable: fmt::Debug + Send + Sync + 'static { + /// Optional positional contract. Missing metadata remains an explicit legacy gap. + fn arity(&self) -> Option { + None + } + fn invoke( &self, context: &mut NativeContext<'_>, @@ -149,6 +191,12 @@ impl<'a> NativeContext<'a> { arguments: &[Value], callable: Arc, ) -> Result { + if let Some(arity) = callable.arity() { + arity.check( + store.object(function)?.payload().kind_name().into(), + arguments.len(), + )?; + } let mut context = Self { store, roots: Vec::new(), diff --git a/crates/objects/src/object.rs b/crates/objects/src/object.rs index 0eec937..291d28b 100644 --- a/crates/objects/src/object.rs +++ b/crates/objects/src/object.rs @@ -117,6 +117,11 @@ pub trait ObjectPayload: Any + fmt::Debug + Send + Sync { /// Host-call entry: arguments and raw results are borrowed handles. The VM /// validates/retains the result before exposing it as an owned call result. /// Language functions are dispatched by Vm's frame evaluator instead. + /// Positional metadata for native call protocols; source code is queried by the store. + fn call_arity(&self) -> Option { + self.native_callable().and_then(|callable| callable.arity()) + } + fn call(&self, _arguments: &[Value]) -> Result { Err(VmError::UnsupportedOperation("call")) } @@ -176,6 +181,7 @@ pub type NativeCall = EndorNativeCall; pub struct EndorNativeFunctionObject { name: String, function: NativeCall, + arity: Option, } impl EndorNativeFunctionObject { @@ -183,12 +189,17 @@ impl EndorNativeFunctionObject { Self { name: name.into(), function, + arity: None, } } pub fn name(&self) -> &str { &self.name } + pub fn with_arity(mut self, arity: crate::CallArity) -> Self { + self.arity = Some(arity); + self + } } /// Compatibility name for existing embedders. @@ -213,7 +224,13 @@ impl ObjectPayload for EndorNativeFunctionObject { Ok(format!("", self.name)) } + fn call_arity(&self) -> Option { + self.arity + } fn call(&self, arguments: &[Value]) -> Result { + if let Some(arity) = self.arity { + arity.check(self.name.clone(), arguments.len())?; + } (self.function)(arguments) } } diff --git a/crates/objects/src/types.rs b/crates/objects/src/types.rs index ca41ba6..8ffa606 100644 --- a/crates/objects/src/types.rs +++ b/crates/objects/src/types.rs @@ -434,6 +434,58 @@ impl ObjectStore { } } + /// Unified source/native positional interval, after any bound receivers. + /// None means no published native metadata (including generic Type construction). + pub fn call_arity(&self, function: ObjectRef) -> Result, VmError> { + let mut current = function; + let mut receivers = 0usize; + loop { + let payload = self.object(current)?.payload(); + if let Some(bound) = payload.as_any().downcast_ref::() { + receivers = receivers + .checked_add(1) + .ok_or(VmError::ExecutionLimit("bound receivers"))?; + current = bound.function; + continue; + } + let arity = if let Some(function) = payload + .as_any() + .downcast_ref::() + { + let maximum = self + .payload::(function.code(), "code")? + .code() + .parameters() + .len(); + Some(crate::CallArity::range( + maximum - function.defaults().len(), + maximum, + )) + } else { + payload.call_arity() + }; + return arity + .map(|arity| { + let arity = arity.validate()?; + let maximum = if arity.maximum == usize::MAX { + usize::MAX + } else { + arity + .maximum + .checked_sub(receivers) + .ok_or(VmError::InvalidArgument( + "method receiver exceeds parameter count", + ))? + }; + Ok(crate::CallArity::range( + arity.required.saturating_sub(receivers), + maximum, + )) + }) + .transpose(); + } + } + /// Returns one owned root, including for a newly bound inherited method. pub fn bind_attr(&mut self, receiver: ObjectRef, name: &str) -> Result { match self.lookup_attr(receiver, name)? { @@ -641,14 +693,13 @@ impl ObjectStore { reason, }; let function = function.ok_or_else(|| invalid("required method is missing"))?; - if let Some(count) = self.positional_parameter_count(function)? { - if count != requirement.parameters + 1 { - return Err(invalid( - "positional parameter count does not match (including self)", - )); - } - } else if self.object(function)?.payload().native_callable().is_none() { - return Err(invalid("required member is not callable")); + let arity = self + .call_arity(function)? + .ok_or_else(|| invalid("required member has no positional signature"))?; + if !arity.accepts(requirement.parameters + 1) { + return Err(invalid( + "positional parameter count does not match (including self)", + )); } Ok(()) } diff --git a/docs/README.md b/docs/README.md index 484306a..aba3970 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/contributing/handoff.md b/docs/contributing/handoff.md index 99c1397..c022e55 100644 --- a/docs/contributing/handoff.md +++ b/docs/contributing/handoff.md @@ -21,7 +21,7 @@ Aster 是可嵌入引擎,只保留 objects、core、frontend、compiler。Obje ## 当前缺口 -平台资源版本/依赖锁、源码闭包、数值算术、完整异常传播、内存配额、可靠取消、不可信代码沙箱、自动 GC 和宿主 panic 后执行根恢复尚未完成。源码函数参数/返回注解已支持默认关闭的运行时检查,Tessera 显式启用;普通名称按调用时函数全局解析,声明字段构造/写入检查已接入同一可选开关;完整初始化、静态类型/效果与原生统一签名仍未完成,见[类型机制](../runtime/types.md#源码函数注解检查)。不引入 Python 元类。UI 接入适配由 Tessera 实现。通用 ObjectPayload::assign_from 允许宿主对象选择共享引用赋值;协议和根计数归 Aster,UI 挂载、布局、绘制仍归 Tessera,见字节码 VM 的共享引用章节。 +平台资源版本/依赖锁、源码闭包、数值算术、完整异常传播、内存配额、可靠取消、不可信代码沙箱、自动 GC 和宿主 panic 后执行根恢复尚未完成。源码函数参数/返回注解已支持默认关闭的运行时检查,Tessera 显式启用;普通名称按调用时函数全局解析,声明字段构造/写入检查已接入同一可选开关;完整初始化、静态类型/效果与原生参数/返回类型签名仍未完成;统一位置参数数量已接入原生调用与显式能力检查,见[类型机制](../runtime/types.md#源码函数注解检查)。不引入 Python 元类。UI 接入适配由 Tessera 实现。通用 ObjectPayload::assign_from 允许宿主对象选择共享引用赋值;协议和根计数归 Aster,UI 挂载、布局、绘制仍归 Tessera,见字节码 VM 的共享引用章节。 ## 工作约定 diff --git a/docs/runtime/README.md b/docs/runtime/README.md index 7f30e6a..6d7d74f 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/builtins.md b/docs/runtime/builtins.md index ca8f8f3..687b174 100644 --- a/docs/runtime/builtins.md +++ b/docs/runtime/builtins.md @@ -136,3 +136,5 @@ Endor 当前用 `EndorBaseExceptionObject` 保存公共数据,名称只是错 ## 验证入口 独立存储行为在 [objects/tests](../../crates/objects/tests/README.md) 检查;既有 Vm 对象入口在 [core/tests](../../crates/core/tests/README.md) 的 builtins.rs 检查,执行行为在 execution.rs;验证方式见 [验证](../operations/validation.md)。文档描述当前契约,不代表某次 CI 已通过。CPython 284 项研究表保持为工作区外的研究材料,不纳入项目文档或 Git。 + +原生函数可通过 NativeFunction::with_arity 提供位置参数数量;源码、原生、绑定方法的统一查询与兼容边界见[原生调用](native-calls.md#统一位置参数数量)。 diff --git a/docs/runtime/native-calls.md b/docs/runtime/native-calls.md index 75ff07b..decc37e 100644 --- a/docs/runtime/native-calls.md +++ b/docs/runtime/native-calls.md @@ -66,3 +66,16 @@ take_changes 按对象与变更键合并同一批写入,返回最终版本。 远端回归用例见 [native_context.rs](../../crates/core/tests/native_context.rs);本地不执行测试。 声明字段检查启用时,NativeContext::set_attr 使用同一字段写入屏障。NativeTyped 分配器应在副作用前调用 ObjectStore::check_class_field_arguments 检查自己的字段参数切片,具体参数组合仍由宿主定义;配置、声明环境与生命周期的唯一契约见[名义类型](types.md#声明字段注解检查)。 + + +## 统一位置参数数量 + +`CallArity { required, maximum }` 表示接受的位置参数区间,包含未绑定的显式接收者;`exact(n)` 与 `range(min,max)` 提供构造方式,`accepts(n)` 查询接受性。`usize::MAX` 表示开放上界。公开字段不能绕过使用时校验:required 大于 maximum 时,查询/调用报告 InvalidArgument,不能进入实现。此元数据只描述数量,不描述参数类型、返回类型或效果。 + +上下文原生实现通过 `NativeCallable::arity()` 提供 `Some(CallArity)`;默认 None 明确表示旧实现没有元数据。ObjectPayload::call_arity 默认委托该入口,也供直接 call 协议发布元数据;传统 NativeFunction 可使用 `with_arity(...)`。VM 在进入原生实现前检查数量,NativeContext::execute 也检查其 NativeCallable 元数据,失败不调用业务实现。传统无元数据的普通原生调用仍保留原协议,不伪造精确签名。 + +`ObjectStore::call_arity(function)`/`Vm::call_arity(function)` 统一查询源码与原生函数。源码从真实形参和默认值计算区间;绑定方法沿实际函数扣除每层接收者,最大值不足时报错,最小值饱和到零。查询返回无托管引用的复制数据,不增加 GC 根。旧 positional_parameter_count 保留“源码总形参数量减绑定接收者”的兼容语义,不用于新的原生回调分派。通用 Type 构造器的参数组合由宿主决定,返回 None;NativeTyped 内部委托和宿主实际构造仍各自检查。 + +显式 Trait 声明、源码派生及方法表更新使用统一区间检查“规范参数数量加 self”是否被接受;缺少元数据的原生方法不能再登记为能力实现。可选参数允许实现接受规范调用数量之外的额外形式。更新仍先检查后代再修改,无隐藏类型根。类型注解兼容性、方差、参数名称及效果检查尚未接入此结构。 + +Tessera 为原生方法、回调和内部视觉 continuation 发布数量元数据,事件监听要求接受零参数或一个 Event;两者都接受时优先传 Event。绑定计算和 Task 回调要求接受零参数,登记前拒绝无元数据/不兼容函数;普通旧原生调用的兼容性不等于允许其参加这些严格回调契约。 diff --git a/docs/runtime/types.md b/docs/runtime/types.md index 677be3c..291bd0b 100644 --- a/docs/runtime/types.md +++ b/docs/runtime/types.md @@ -72,7 +72,7 @@ ObjectPayload 可选择实现 `attribute_target(store)`,把实例字段放在 implement_trait(Type, Trait)明确建立能力关系并校验必需方法。只有同名成员不算实现。implements_trait(Type, Trait)检查声明和继承;supports(instance, Trait)先查实际类型;未分类对象返回false,非法句柄或非定义参数报错。一个类型可显式实现多个能力,派生类继承关系。声明由Type的受管强边持有,查询和临时后代扫描不保活定义。 -源码函数必须具有要求数量加self的参数;原生可调用对象的签名由注册宿主保证,当前没有原生形参元数据。缺少方法、非可调用成员或参数数量错误以TraitViolation报告能力名、方法名和原因。本子集不验证注解、关联类型、返回类型、效果或可选形参的替换兼容性;没有默认实现和trait源码语法。 +源码与原生方法通过统一 CallArity 验证是否接受规范数量加 self;无元数据的原生方法不能登记能力。数量区间包括源码默认参数与原生可选参数,详见[原生调用](native-calls.md#统一位置参数数量)。缺少方法、非可调用成员或参数数量错误以TraitViolation报告能力名、方法名和原因。本子集只验证数量接受性,不验证注解、关联类型、返回类型、效果或完整替换兼容性;没有默认实现和trait源码语法。 建立声明前检查已有后代;构造源码子类检查继承的所有能力。define_method更新前检查受影响后代的显式/继承契约,被后代自己的覆盖遮蔽的方法不受该祖先更新影响。失败保留原方法表和关系。内部扫描只枚举当前借用句柄,不引入全局强类型注册表。声明更新通过普通堆写屏障与trace进行,既有类型的只读作用域内变更会被拒绝。NativeContext也可使用同一implement_trait入口,仍受该屏障约束。 @@ -96,7 +96,7 @@ implement_trait(Type, Trait)明确建立能力关系并校验必需方法。只 | Type/Trait | 真实 Type/Trait 定义载荷 | | 其他名称 | 从函数自己的 globals、其次创建时捕获的 builtins 找到实际 Type 或 Trait;前者检查名义实例/继承,后者检查显式能力 | -普通名称每次调用重新解析,不是静态推断或定义时冻结的类型绑定。同名新定义不等于旧定义;自由函数可观察后续全局类型名重绑定。方法注解中指向自身声明类的名称,优先从实际接收者祖先中查找仍持有该函数的方法定义,因此 REPL 重定义全局类名后,原实例保存的绑定方法仍可调用。其他类型名仍遵循上述全局解析规则。此机制不提供重写方差、泛型、效果类型或原生函数的统一签名元数据。字段赋值检查见下文。 +普通名称每次调用重新解析,不是静态推断或定义时冻结的类型绑定。同名新定义不等于旧定义;自由函数可观察后续全局类型名重绑定。方法注解中指向自身声明类的名称,优先从实际接收者祖先中查找仍持有该函数的方法定义,因此 REPL 重定义全局类名后,原实例保存的绑定方法仍可调用。其他类型名仍遵循上述全局解析规则。此机制不提供重写方差、泛型、效果类型或原生参数/返回类型与效果签名;位置参数数量元数据见[原生调用](native-calls.md#统一位置参数数量)。字段赋值检查见下文。 源码与原生函数的统一名义分类由 `ObjectStore::set_function_type`/`Vm::set_function_type` 显式配置。配置验证 Type、拒绝只读修改,只保留弱引用且不可改成另一个定义;设置后新分配的显式 `ObjectPayload::is_function` 载荷自动附加该类型,已有对象不追溯改写。语言函数、两类原生函数及绑定方法提供此标记;仅有 call 能力不算函数。配置类型过期则函数分配报错并清理新对象,不引入隐藏 GC 根。宿主应在创建函数前配置,并通过正常对象边保活定义。