From ca61378c928be29a3bb55743fc56a765ee298300 Mon Sep 17 00:00:00 2001 From: Codex Bot Date: Sun, 15 Nov 2026 19:39:21 +0800 Subject: [PATCH] docs(objects): clarify type capability and effect query contracts --- crates/objects/src/effects.rs | 8 ++++-- crates/objects/src/types.rs | 49 ++++++++++++++++++++++++----------- 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/crates/objects/src/effects.rs b/crates/objects/src/effects.rs index 45f6c46..fb0086b 100644 --- a/crates/objects/src/effects.rs +++ b/crates/objects/src/effects.rs @@ -1,5 +1,6 @@ //! Store::call_effect 的当前快照证明;None 表示无法证明,不代表确定有副作用。 //! 查询经过 Store 读取追踪,但不执行源码或分配托管对象;所有身份仅借用。 +//! 返回效果不会保留目标或冻结全局/Cell/方法表;缓存者需在追踪作用域收集观察并在使用前重验。 //! Snapshot proof of read-only call graphs. All identities are borrowed and all //! traversals iterative; analysis neither executes code nor allocates VM objects. use super::{AttributeLookup, BoundMethod}; @@ -10,8 +11,11 @@ use crate::{ use std::collections::{BTreeSet, VecDeque}; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +/// infer_call_effect 队列与去重集合中的借用调用身份,read_only_callees 识别直接/绑定调用后构造。 struct Target { + /// 底层被调函数身份;队列本身不新增拥有根。 function: ObjectRef, + /// 已知的首个接收者,可用于解析 LoadFast(0) 和方法;未知时保持 None。 receiver: Option, } #[derive(Clone, Copy, PartialEq, Eq)] @@ -26,7 +30,7 @@ enum Fact { Method(Target), } impl Fact { - // 把实际值降为抽象身份事实,直接标量不保留其内容。 + // read_only_callees 对常量、全局值及 Cell 内容降为身份事实,直接标量不保留其内容。 fn value(value: Value) -> Self { // 对象保留借用身份,标量统一变成 Unknown;不把抽象事实当作实际求值结果。 match value { @@ -34,7 +38,7 @@ impl Fact { _ => Self::Unknown, } } - // 只从普通对象事实提取身份,不把方法对当作对象。 + // read_only_callees 的属性接收者/调用参数识别只提取普通对象身份,不把方法对当作对象。 fn object(self) -> Option { // 仅 Object 事实可用于属性接收者或调用身份,Unknown/Null/Method 都不冒充普通对象。 match self { diff --git a/crates/objects/src/types.rs b/crates/objects/src/types.rs index 487d6e8..35c9f3e 100644 --- a/crates/objects/src/types.rs +++ b/crates/objects/src/types.rs @@ -44,13 +44,17 @@ impl Drop for AttributeCheckGuard<'_> { } #[derive(Debug, Clone, Copy)] +/// 宿主在 new_type 中选择,源码 new_class 依父策略继承;其中对象句柄在类型分配后才由 trace 持边。 pub enum TypeConstructor { /// Allocate a plain, attribute-bearing instance of this type. + /// Construct 分配 Record,附请求类型,再按完整字段布局写入实参。 Record, /// Delegate to a managed callable. It must return an instance of this type. + /// 原实参直接委托宿主分配器;正确名义返回类型是分配器责任,Construct 本身不追加该返回检查。 Native(ObjectRef), /// Opt-in allocator inheritance. The requested nominal type is prepended /// to the constructor arguments; the allocator must create that real type. + /// 源码子类可沿用分配器,首参是实际请求 Type;分配器负责附着此身份,而非固定原生基类。 NativeTyped(ObjectRef), /// 禁止直接构造,源码派生沿用该策略后仍为抽象类型。 Abstract, @@ -61,12 +65,14 @@ pub struct ClassField { /// 字段存储名称,源码类创建时检查重复及保留名。 pub name: String, /// Source annotation resolved at checked construction/field writes. + /// 字段类型名文本,开启检查时按原声明类及其环境解析,不在解析源码时固定为全局句柄。 pub type_name: String, } /// Nominal definition with immutable identity/base and a managed method table. /// Its base, constructor and metatype are traced /// edges; no registry outside the heap keeps unused definitions alive. +/// 载荷 trace 登记基类等私有字段,元类型边由 EndorObject 的头部追踪,二者不重复登记。 #[derive(Debug, Clone)] pub struct EndorTypeObject { /// 诊断名称,名义身份仍由对象句柄决定。 @@ -210,6 +216,7 @@ impl NativeCallable for Construct { /// Each field owns one external root; the caller must release both. #[derive(Debug, Clone, Copy)] +/// bootstrap_types 的原始返回值携带两份拥有根;复制此 Copy 结构不 retain,不能按副本重复 release。 pub struct RootTypes { /// Object 根类型的一份外部拥有根,调用方须 release。 pub object: ObjectRef, @@ -311,7 +318,7 @@ impl ObjectStore { type_object: ObjectRef, ) -> Result<(), VmError> { self.payload::(type_object, "Type")?; - // 逐项登记已声明能力,重复引用也按拥有次数计算。 + // 逐项校验目标类型已有/继承能力对当前实例存储的约束;实际类型强边稍后由 Heap 登记。 for capability in self.inherited_traits(type_object)? { self.check_capability_storage(object, capability)?; } @@ -333,7 +340,7 @@ impl ObjectStore { "cyclic shared-reference type target", )); } - // 分配临时根后再附着类型/写字段,失败时上下文统一清理半成品。 + // 借用当前转发对象并记录其版本读取,尚未分配实例或增加任何拥有根。 let instance = self.object(current)?; // 有转发目标则继续,无目标时读取当前对象头部名义类型。 match instance.payload().type_target(self)? { @@ -361,7 +368,8 @@ impl ObjectStore { Ok(false) } - /// VM/宿主判断实例有效类型是否为 expected 的子类型,无类型旧对象返回 false。 + /// VM/宿主判断实例有效类型是否为 expected 的子类型,有效但无名义类型的旧对象返回 false。 + /// 异堆或失效句柄仍报错,不能把错误当作普通不匹配。 pub fn is_instance(&self, object: ObjectRef, expected: ObjectRef) -> Result { self.payload::(expected, "Type")?; // 有效类型可来自转发对象;无类型不是 InvalidHandle,而是正常 false。 @@ -373,6 +381,7 @@ impl ObjectStore { /// Updating the managed method table preserves nominal identity and base. /// 宿主/VM 受控更新方法表,身份/基类不变,先验证覆盖及能力约束再替换载荷。 + /// 方法对象需为有效句柄;无相关契约时此处不单独证明可调用性,实际调用仍由 VM 分派。 pub fn define_method( &mut self, type_object: ObjectRef, @@ -382,7 +391,7 @@ impl ObjectStore { self.object(function)?; // 持有名称用于新载荷与诊断,后续校验借用该字符串。 let name = name.into(); - // 类型名称不允许空串,但身份判断仍使用句柄而非文本。 + // 方法名称不能为空或占用保留属性 type;这不是类型声明名校验。 if name.is_empty() || name == "type" { return Err(VmError::InvalidArgument("reserved or empty method name")); } @@ -473,7 +482,7 @@ impl ObjectStore { // 方法提交前验证函数句柄,拒绝与完整继承字段序列重名。 for (name, method) in &methods { self.object(*method)?; - // 类型名称不允许空串,但身份判断仍使用句柄而非文本。 + // 方法名不能为空、占用 type 或与字段冲突;完整可调用契约在对应能力/覆盖检查中核对。 if name.is_empty() || name == "type" || fields.iter().any(|field| field.name == *name) { return Err(VmError::InvalidArgument( "method conflicts with class field", @@ -607,6 +616,7 @@ impl ObjectStore { /// This query follows current globals, closure Cells and known receivers without /// executing code, freezing targets or retaining a cross-query cache. /// VM/契约通过 effects 分析当前调用图快照,None 表示无法证明整体效果。 + /// 结果不冻结目标或提供跨次缓存;追踪到的读取只在当前读取作用域收集,后续变更需重新证明。 pub fn call_effect(&self, function: ObjectRef) -> Result, VmError> { self.infer_call_effect(function) } @@ -785,7 +795,7 @@ impl ObjectPayload for BoundMethod { fn is_function(&self) -> bool { true } - /// 绑定方法/能力定义不实现原地赋值,允许只读局部重绑定引用。 + /// 绑定方法不实现原地赋值,允许只读局部重绑定引用。 fn reference_assignment_only(&self) -> bool { true } @@ -836,20 +846,27 @@ impl NativeCallable for CallBoundMethod { /// Use TypedMethodRequirement for parameter/return/effect contracts. #[derive(Debug, Clone, PartialEq, Eq)] pub struct MethodRequirement { + /// 能力要求存在的方法名,new_trait 检查非空、保留名及重复。 pub name: String, + /// 不含 self 的位置实参数量;实现的区间需接受此数量加一,不要求区间本身是精确数量。 pub parameters: usize, } /// Typed capability requirement, including the explicit receiver slot. #[derive(Debug, Clone)] pub struct TypedMethodRequirement { + /// 完整契约所属方法名,new_typed_trait 按名保存并拒绝重复。 pub name: String, + /// 含显式接收者的固定数量签名,参数/返回类型及效果按替换规则验证。 pub signature: crate::CallSignature, } #[derive(Debug)] /// 显式能力定义:最小数量要求与可选完整签名同属托管载荷,定义本身不可任意替换。 pub struct EndorTraitObject { + /// 诊断名称,能力相等仍以对象身份判断。 name: String, + /// 最小数量要求;类型化能力也从规范签名派生这份兼容视图。 requirements: Vec, + /// 按方法名保存的完整类型/效果契约,签名中的定义引用由本载荷 trace 保活。 signatures: BTreeMap, } impl EndorTraitObject { @@ -867,7 +884,7 @@ impl EndorTraitObject { } } impl ObjectPayload for EndorTraitObject { - /// Heap 分配/更新载荷时枚举拥有边,重复边仍逐条报告。 + /// Heap 分配能力载荷时枚举签名拥有边,重复边仍逐条报告。 fn trace(&self, visit: &mut dyn FnMut(ObjectRef)) { // 能力完整签名的全部类型定义参与 trace,不只看当前调用到的分支。 for signature in self.signatures.values() { @@ -877,7 +894,7 @@ impl ObjectPayload for EndorTraitObject { } } } - /// 绑定方法/能力定义不实现原地赋值,允许只读局部重绑定引用。 + /// 能力定义不实现原地赋值,允许只读局部重绑定引用。 fn reference_assignment_only(&self) -> bool { true } @@ -1193,7 +1210,7 @@ impl ObjectStore { self.payload::(capability, "Trait")?; // 显式声明或继承才算支持能力,方法形状相同也不会自动成为声明。 let declared = self.inherited_traits(definition)?.contains(&capability); - // 命中声明后重验当前方法/实例,避免把历史声明当作永久有效证明。 + // 命中声明后重验类型的方法契约;此 API 不检查某个实例存储,值级查询另经 supports。 if declared { self.validate_trait(definition, capability, false)?; } @@ -1300,7 +1317,8 @@ impl ObjectStore { /// Method names whose instance storage participates in typed capability /// validity. Hosts can subscribe to these attribute keys when caching. - /// 宿主缓存查询当前类型化能力涉及的属性键,返回去重名称,不建立订阅。 + /// 宿主缓存(如 Tessera 快照检查)查询当前类型化能力涉及的属性键,返回去重名称,不建立订阅。 + /// 名称枚举本身不证明实例存储合规;绕过属性查找分派前另调用 check_typed_instance_storage。 pub fn typed_method_names(&self, object: ObjectRef) -> Result, VmError> { // 按名称去重,多个能力共用方法名只返回一次。 let mut names = std::collections::BTreeSet::new(); @@ -1456,7 +1474,8 @@ impl ObjectStore { /// NativeTyped allocators can validate their field suffix before any effects. /// Count is always checked; annotation matching follows the opt-in setting. - /// Record/NativeTyped 构造器在副作用前校验字段后缀;数量始终检查,类型匹配由开关控制。 + /// Record/NativeTyped 分配器用它检查完整声明字段值列表(含继承字段),不包含分配器自己的额外参数。 + /// 数量始终检查,类型匹配由开关控制;应在分配或其他副作用前显式调用。 pub fn check_class_field_arguments( &self, definition: ObjectRef, @@ -1506,7 +1525,7 @@ impl ObjectStore { } else { return Err(VmError::UnknownAnnotation(field.type_name.clone())); }; - // 类型化能力才需要扫描实例存储,最小数量能力没有遮蔽签名要求。 + // 按刚解析的字段约束匹配当前值,失败时报告字段位置与实际类型,不提交任何写入。 if !self.matches_annotation(value, expected)? { return Err(VmError::TypeMismatch { function: definition.name.clone(), @@ -1525,7 +1544,7 @@ impl ObjectStore { name: &str, receiver: Option, ) -> Result { - // 先验证定义/函数载荷,再访问字段表或声明环境。 + // 先验证源码函数载荷,后续从其代码签名、全局和已捕获内置字典解析注解。 let data = self.payload::(function, "function")?; // 方法 owner 解析需要代码中的源码声明元数据,函数本身只持有代码引用。 let signature = self @@ -1566,7 +1585,7 @@ impl ObjectStore { }); // 普通名称必须指向 Type 或 Trait 载荷,其他值不能充当类型注解。 if let Some(Value::Object(definition)) = value { - // 查询原对象固有属性身份,而不是只查看转发终点。 + // 按环境绑定值的实际载荷确认它是 Type 或 Trait 定义,不把普通对象当作注解。 let payload = self.object(definition)?.payload(); // 识别名义类型,描述符只借用该定义身份。 if payload.as_any().is::() { @@ -1641,7 +1660,7 @@ impl ObjectStore { } /// 类型错误诊断格式化预期名称;名义/能力定义仍验证句柄和载荷。 pub fn annotation_type_name(&self, expected: AnnotationType) -> Result { - // 直接类别与名义/能力匹配分开;Type/Function 类别不等于任意可调用对象。 + // 内建类别使用固定显示名,名义/能力注解从有效定义载荷取名,不在这里匹配实际值。 Ok(match expected { AnnotationType::Any => "Object".into(), AnnotationType::Unit => "Unit".into(),