Validate unified source and native positional call contracts
This commit is contained in:
@@ -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、结果根转移与失败清理 |
|
||||
|
||||
## 常见修改入口
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -25,6 +25,10 @@ impl Vm {
|
||||
self.source_type_checks = enabled;
|
||||
Ok(())
|
||||
}
|
||||
pub fn call_arity(&self, function: ObjectRef) -> Result<Option<objects::CallArity>, VmError> {
|
||||
self.objects.call_arity(function)
|
||||
}
|
||||
|
||||
pub fn set_function_type(&mut self, definition: ObjectRef) -> Result<(), VmError> {
|
||||
self.objects.set_function_type(definition)
|
||||
}
|
||||
|
||||
@@ -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)。
|
||||
|
||||
@@ -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<endor_core::CallArity> {
|
||||
Some(endor_core::CallArity::range(1, 2))
|
||||
}
|
||||
fn invoke(
|
||||
&self,
|
||||
cx: &mut endor_core::NativeContext<'_>,
|
||||
_: &[Value],
|
||||
) -> Result<endor_core::NativeResult, VmError> {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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 边、语言函数标记 |
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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<Self, VmError> {
|
||||
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<CallArity> {
|
||||
None
|
||||
}
|
||||
|
||||
fn invoke(
|
||||
&self,
|
||||
context: &mut NativeContext<'_>,
|
||||
@@ -149,6 +191,12 @@ impl<'a> NativeContext<'a> {
|
||||
arguments: &[Value],
|
||||
callable: Arc<dyn NativeCallable>,
|
||||
) -> Result<NativeResult, VmError> {
|
||||
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(),
|
||||
|
||||
@@ -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<crate::CallArity> {
|
||||
self.native_callable().and_then(|callable| callable.arity())
|
||||
}
|
||||
|
||||
fn call(&self, _arguments: &[Value]) -> Result<Value, VmError> {
|
||||
Err(VmError::UnsupportedOperation("call"))
|
||||
}
|
||||
@@ -176,6 +181,7 @@ pub type NativeCall = EndorNativeCall;
|
||||
pub struct EndorNativeFunctionObject {
|
||||
name: String,
|
||||
function: NativeCall,
|
||||
arity: Option<crate::CallArity>,
|
||||
}
|
||||
|
||||
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!("<native-function {}>", self.name))
|
||||
}
|
||||
|
||||
fn call_arity(&self) -> Option<crate::CallArity> {
|
||||
self.arity
|
||||
}
|
||||
fn call(&self, arguments: &[Value]) -> Result<Value, VmError> {
|
||||
if let Some(arity) = self.arity {
|
||||
arity.check(self.name.clone(), arguments.len())?;
|
||||
}
|
||||
(self.function)(arguments)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Option<crate::CallArity>, 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::<BoundMethod>() {
|
||||
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::<crate::EndorFunctionObject>()
|
||||
{
|
||||
let maximum = self
|
||||
.payload::<crate::EndorCodeObject>(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<Value, VmError> {
|
||||
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(())
|
||||
}
|
||||
|
||||
+1
-1
@@ -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 |
|
||||
|
||||
@@ -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 的共享引用章节。
|
||||
|
||||
## 工作约定
|
||||
|
||||
|
||||
@@ -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) | 词法、语法和诊断 |
|
||||
|
||||
@@ -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#统一位置参数数量)。
|
||||
|
||||
@@ -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 回调要求接受零参数,登记前拒绝无元数据/不兼容函数;普通旧原生调用的兼容性不等于允许其参加这些严格回调契约。
|
||||
|
||||
@@ -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 根。宿主应在创建函数前配置,并通过正常对象边保活定义。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user