From c05d60cbc9431aa8af83278f95f47b1bf9a00311 Mon Sep 17 00:00:00 2001 From: Codex Bot Date: Sun, 15 Nov 2026 17:35:00 +0800 Subject: [PATCH] docs(objects): explain method substitution contracts --- crates/objects/src/contracts.rs | 114 ++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/crates/objects/src/contracts.rs b/crates/objects/src/contracts.rs index f44f491..1f91292 100644 --- a/crates/objects/src/contracts.rs +++ b/crates/objects/src/contracts.rs @@ -1,3 +1,6 @@ +//! Store 类型/能力方法的替换约束;types 子模块可读取方法表,无需向宿主公开可变内部布局。 +//! 参数要求逆变、返回要求协变;检查只观察当前定义,拟议更新通过 Patch 预演,不先修改再回滚。 +//! UnknownAnnotation 仅在显式 defer_unknown 时暂缓,调用时检查使用完整解析路径。 //! Method substitution rules. This is a child of types so validation can inspect //! method tables without exporting mutable definition internals. use super::{AnnotationType, EndorTypeObject}; @@ -7,18 +10,25 @@ use crate::{ }; struct Contract { + /// 可接受的位置参数区间,包括接收者。 arity: CallArity, + /// 固定位置参数约束。 parameters: Vec, + /// 固定部分之后的统一参数约束。 variadic: Option, + /// 实现返回值必须落入父契约或能力允许范围。 returns: CallType, + /// 已知整体效果,None 表示不能证明,不等于 ReadOnly。 effect: Option, } impl Contract { + /// 签名替换检查按位置选固定参数,超出固定部分回退可变参数约束。 fn parameter(&self, index: usize) -> Option<&CallType> { self.parameters.get(index).or(self.variadic.as_ref()) } } impl From for Contract { + /// 原生签名转内部契约,Delegated 不是已知整次调用效果,转换为 None。 fn from(value: CallSignature) -> Self { Self { arity: value.arity, @@ -35,25 +45,35 @@ impl From for Contract { } #[derive(Clone, Copy)] struct Patch<'a> { + /// 拟议更新所属的类型身份,借用。 owner: ObjectRef, + /// 拟议更新的方法名,仅精确匹配此名。 name: &'a str, + /// 拟议的新函数身份,不由 Patch 保留根。 function: ObjectRef, } struct TraitCheckGuard<'a> { + /// 借用递归校验状态表。 store: &'a ObjectStore, + /// 创建守卫时的线程身份。 thread: std::thread::ThreadId, + /// 当前定义/能力对,Drop 时移除。 key: (ObjectRef, ObjectRef), } impl Drop for TraitCheckGuard<'_> { + /// 递归校验 RAII 清理,正常/报错/展开路径都移除本线程当前定义与能力对。 fn drop(&mut self) { + // 取得线程校验表的锁,守卫只会在成功插入 key 后创建。 let mut checks = self .store .active_trait_checks .lock() .expect("trait checker poisoned"); + // 只删除当前递归对,不影响同线程其他活跃校验。 let active = checks.get_mut(&self.thread).expect("active trait check"); active.remove(&self.key); + // 线程没有剩余递归检查时移除空项。 if active.is_empty() { checks.remove(&self.thread); } @@ -64,12 +84,18 @@ impl CallType { /// Whether every value admitted by provided is admitted by self. /// Nominal inheritance and explicit capabilities participate; no structural /// or callable-signature inference is implied by this relation. + /// 替换校验的值集合包含关系:provided 的每项都必须被 self 的至少一项接纳。 pub fn accepts_type(&self, store: &ObjectStore, provided: &Self) -> Result { + // 先验证联合全部定义边,再做包含/匹配判断,不能让无效分支藏在后面。 self.validate(store)?; provided.validate(store)?; + // provided 是待被接纳的值集合,必须逐个候选分支都被覆盖。 for actual in provided.alternatives() { + // 每个 provided 分支单独寻找一个可接受它的 self 分支。 let mut accepted = false; + // self 联合只需一个分支能接纳当前 actual,不要求所有分支都匹配。 for expected in self.alternatives() { + // Any 接受所有值;名义继承和显式能力参与,不推断结构相似或可调用签名。 accepted = match (*expected, *actual) { (AnnotationType::Any, _) => true, (AnnotationType::Nominal(base), AnnotationType::Nominal(child)) => { @@ -81,10 +107,12 @@ impl CallType { ) => store.implements_trait(definition, capability)?, (expected, actual) => expected == actual, }; + // 当前 actual 已找到覆盖分支即可结束内层循环。 if accepted { break; } } + // 存在一个未被接纳的 provided 分支即整体不包含。 if !accepted { return Ok(false); } @@ -94,14 +122,18 @@ impl CallType { } impl ObjectStore { + /// types::validate_trait 调用的递归守卫;同线程同定义/能力对重入时暂不重复展开。 pub(super) fn with_trait_check( &self, definition: ObjectRef, capability: ObjectRef, check: impl FnOnce() -> Result<(), VmError>, ) -> Result<(), VmError> { + // 递归重入按线程隔离,避免把其他线程的检查误作当前递归。 let thread = std::thread::current().id(); + // 重入身份包含类型定义与能力,不仅是单个类型。 let key = (definition, capability); + // 同线程同定义/能力对已经在检查时返回,避免递归契约无限展开。 if !self .active_trait_checks .lock() @@ -112,6 +144,7 @@ impl ObjectStore { { return Ok(()); } + // 锁已释放,守卫负责退出时清除 key;执行 check 时不持全局校验锁。 let _guard = TraitCheckGuard { store: self, thread, @@ -119,14 +152,17 @@ impl ObjectStore { }; check() } + /// 替换检查读取原生签名或解析源码签名,缺失元数据返回 None,不猜测类型。 fn method_contract( &self, function: ObjectRef, owner: ObjectRef, ) -> Result, VmError> { + // 优先使用已解析原生签名,其引用有效性由 Store 的签名入口校验。 if let Some(native) = self.native_signature(function)? { return Ok(Some(native.into())); } + // 既非原生完整签名又非源码函数时无法取得契约。 let Some(data) = self .object(function)? .payload() @@ -135,15 +171,23 @@ impl ObjectStore { else { return Ok(None); }; + // 源码类型声明在函数指向的代码对象内,不从函数名字猜测。 let code = self.payload::(data.code(), "code")?.code(); + // 源码没有声明就返回 None,调用方决定缺失元数据是否允许。 let Some(signature) = code.source_signature() else { return Ok(None); }; + // 解析源码 owner 名称时考虑继承中的真实声明,避免只查全局同名对象。 let resolve = |name: &str| { + // 仅源码声明的 owner 名称走特殊继承解析,其余名称回退常规注解解析。 if signature.method_owner.as_deref() == Some(name) { + // 从当前声明 owner 向基类查找,不扫描任意后代。 let mut current = Some(owner); + // 逐层读取不可变类型定义,必要时确认父层方法身份仍是当前函数。 while let Some(definition) = current { + // 读取类型载荷并验证句柄,后续方法表与基类访问都基于该借用。 let data = self.payload::(definition, "Type")?; + // 名称相同还需属于当前 owner 或确实在父方法表持有该函数。 if data.name == name && (definition == owner || data @@ -158,6 +202,7 @@ impl ObjectStore { } self.annotation_type(function, name, None) }; + // 逐个解析全部参数注解,首个错误即传播,不返回部分契约。 let parameters = signature .parameters .iter() @@ -173,12 +218,14 @@ impl ObjectStore { effect: self.call_effect(function)?, })) } + /// 查类型自身方法,若 Patch 精确匹配该类型/名称则读取拟议替代函数。 fn own_method( &self, owner: ObjectRef, name: &str, patch: Option>, ) -> Result, VmError> { + // 只在 owner 和 name 都相同的查询位置替换视图,不修改真实方法表。 if let Some(patch) = patch && patch.owner == owner && patch.name == name @@ -191,13 +238,16 @@ impl ObjectStore { .get(name) .copied()) } + /// 沿单继承链寻找最近方法及声明 owner,支持拟议 Patch 的查找视图。 fn inherited_method( &self, mut owner: Option, name: &str, patch: Option>, ) -> Result, VmError> { + // 向基类遍历;不假定候选函数一定是接收者当前生效的方法。 while let Some(definition) = owner { + // 最靠近当前类型的声明遮蔽更远的同名父方法。 if let Some(function) = self.own_method(definition, name, patch)? { return Ok(Some((definition, function))); } @@ -205,6 +255,7 @@ impl ObjectStore { } Ok(None) } + /// 检查当前方法替换最近父方法是否可代换;父方法无类型元数据时保持兼容。 fn check_override( &self, owner: ObjectRef, @@ -213,32 +264,40 @@ impl ObjectStore { patch: Option>, defer_unknown: bool, ) -> Result<(), VmError> { + // 检查 owner 类型载荷,诊断使用其声明名称。 let definition = self.payload::(owner, "Type")?; + // 没有同名父方法即不是 override,无需普通替换检查。 let Some((base_owner, base_function)) = self.inherited_method(definition.base, name, patch)? else { return Ok(()); }; + // 闭包收集解析/校验结果,外层仅在允许时暂缓 UnknownAnnotation。 let checked = (|| { + // 父方法没有完整元数据时不新增更严格的旧接口约束。 let Some(base) = self.method_contract(base_function, base_owner)? else { return Ok(()); }; + // 按当前调用用途构造带类型/能力与方法定位的错误,不改变验证逻辑。 let invalid = |reason| VmError::OverrideViolation { definition: definition.name.clone(), method: name.into(), reason, }; + // 父契约存在时,派生实现也必须提供完整可检查的类型元数据。 let derived = self .method_contract(function, owner)? .ok_or_else(|| invalid("override lacks type metadata"))?; self.check_substitution(owner, &derived, &base, invalid)?; Ok(()) })(); + // 只有 UnknownAnnotation 可在 defer_unknown 时暂缓,其他失败始终传播。 match checked { Err(VmError::UnknownAnnotation(_)) if defer_unknown => Ok(()), result => result, } } + /// 父方法/能力签名的公共替换算法;所有不兼容原因交给调用方构造具体错误。 fn check_substitution( &self, owner: ObjectRef, @@ -246,12 +305,15 @@ impl ObjectStore { base: &Contract, invalid: impl Fn(&'static str) -> VmError, ) -> Result<(), VmError> { + // 实现不得要求更多必填参数,也不得缩小最多可接收参数数量。 if derived.arity.required > base.arity.required || derived.arity.maximum < base.arity.maximum { return Err(invalid("override narrows accepted argument counts")); } + // 接收者按实现声明类型核对,不能只对比两份签名的第零项文本。 let receiver = CallType::from(AnnotationType::Nominal(owner)); + // 派生签名必须接受它自己声明类型的实例作为接收者。 if !derived .parameter(0) .ok_or_else(|| invalid("override lacks receiver"))? @@ -259,6 +321,7 @@ impl ObjectStore { { return Err(invalid("override receiver rejects its declaring type")); } + // 父/能力签名必须接纳实现类型,返回值则必须落在父约束范围。 if !base .parameter(0) .ok_or_else(|| invalid("required signature lacks receiver"))? @@ -266,48 +329,62 @@ impl ObjectStore { { return Err(invalid("required receiver rejects implementing type")); } + // 检查双方固定参数覆盖到的最大位置,但不超过父方法允许上界。 let fixed = base .parameters .len() .max(derived.parameters.len()) .min(base.arity.maximum); + // 跳过已单独核对的接收者,第一个普通参数起检查逆变。 for index in 1..fixed { + // 调用方按父契约可传的类型集合,实现必须全部接纳。 let expected = base .parameter(index) .ok_or_else(|| invalid("incomplete base parameter metadata"))?; + // 实现的实际参数/方法契约必须存在,不能通过缺失元数据绕过检查。 let actual = derived .parameter(index) .ok_or_else(|| invalid("incomplete override parameter metadata"))?; + // 逆变方向是 actual 接纳 expected,反过来会错误允许缩窄参数。 if !actual.accepts_type(self, expected)? { return Err(invalid("override narrows a parameter type")); } } + // 父契约还有固定段之后的位置时,用该位置的尾部约束核对其余参数。 if base.arity.maximum > fixed { + // 调用方按父契约可传的类型集合,实现必须全部接纳。 let expected = base .parameter(fixed) .ok_or_else(|| invalid("incomplete base variadic metadata"))?; + // 实现的实际参数/方法契约必须存在,不能通过缺失元数据绕过检查。 let actual = derived .parameter(fixed) .ok_or_else(|| invalid("incomplete override variadic metadata"))?; + // 逆变方向是 actual 接纳 expected,反过来会错误允许缩窄参数。 if !actual.accepts_type(self, expected)? { return Err(invalid("override narrows a variadic parameter type")); } } + // 父/能力签名必须接纳实现类型,返回值则必须落在父约束范围。 if !base.returns.accepts_type(self, &derived.returns)? { return Err(invalid("override widens the return type")); } + // 仅双方效果都已知时比较;未知效果不在此处强行推断。 if let (Some(expected), Some(actual)) = (base.effect, derived.effect) { + // 只读只能替换为只读;Mutating 不接受 External;External/Delegated 不再收紧。 let compatible = match expected { CallEffect::ReadOnly => actual == CallEffect::ReadOnly, CallEffect::Mutating => actual != CallEffect::External, CallEffect::External | CallEffect::Delegated => true, }; + // 效果扩大报替换错误,不靠实际执行检测。 if !compatible { return Err(invalid("override expands known effects")); } } Ok(()) } + /// types 能力验证把实现方法与声明签名比较,报 TraitViolation 而非普通覆盖错误。 pub(super) fn validate_typed_requirement( &self, definition: ObjectRef, @@ -317,6 +394,7 @@ impl ObjectStore { expected: &CallSignature, defer_unknown: bool, ) -> Result<(), VmError> { + // 按当前调用用途构造带类型/能力与方法定位的错误,不改变验证逻辑。 let invalid = |reason| VmError::TraitViolation { capability: self .payload::(capability, "Trait") @@ -326,38 +404,49 @@ impl ObjectStore { method: name.into(), reason, }; + // 闭包收集解析/校验结果,外层仅在允许时暂缓 UnknownAnnotation。 let checked = (|| { + // 实现的实际参数/方法契约必须存在,不能通过缺失元数据绕过检查。 let actual = self .method_contract(function, definition)? .ok_or_else(|| invalid("required member lacks type metadata"))?; self.check_substitution(definition, &actual, &expected.clone().into(), invalid) })(); + // 只有 UnknownAnnotation 可在 defer_unknown 时暂缓,其他失败始终传播。 match checked { Err(VmError::UnknownAnnotation(_)) if defer_unknown => Ok(()), result => result, } } + /// 类型构造时按开关校验自身方法覆盖,允许暂缓尚未解析的注解。 pub(super) fn validate_class_overrides(&self, definition: ObjectRef) -> Result<(), VmError> { + // 类定义/更新阶段普通 override 检查受配置开关控制。 if self.field_type_checks { + // 逐个检查当前类型自身方法,不把继承方法当作自身声明。 for (name, function) in &self.payload::(definition, "Type")?.methods { self.check_override(definition, name, *function, None, true)?; } } Ok(()) } + /// set_method 提交前,以 Patch 校验受影响后代,避免先改表再发现错误。 pub(super) fn validate_override_update( &self, owner: ObjectRef, name: &str, function: ObjectRef, ) -> Result<(), VmError> { + // 类定义/更新阶段普通 override 检查受配置开关控制。 if self.field_type_checks { + // 拟议 owner/name/function 只作为查询视图,验证完成前不提交。 let patch = Some(Patch { owner, name, function, }); + // 父方法变化可能破坏已有子方法的替换关系,所以检查全部后代。 for descendant in self.descendant_types(owner)? { + // 最靠近当前类型的声明遮蔽更远的同名父方法。 if let Some(function) = self.own_method(descendant, name, patch)? { self.check_override(descendant, name, function, patch, true)?; } @@ -366,6 +455,7 @@ impl ObjectStore { Ok(()) } /// Explicit override validation, including any typed capabilities. + /// VM/宿主显式启用普通覆盖检查,同时校验接收者的类型化能力约束。 pub fn check_method_override_call( &self, function: ObjectRef, @@ -376,25 +466,35 @@ impl ObjectStore { } /// Typed capabilities are explicit opt-ins and always checked. Ordinary /// override checking remains configurable by the VM's source-check flag. + /// eval 原生调用前核对实际方法;能力约束始终检查,普通覆盖由 overrides 控制。 pub fn check_method_contract_call( &self, function: ObjectRef, receiver: ObjectRef, overrides: bool, ) -> Result { + // 返回值表示是否命中类型化能力约束,不代表普通覆盖检查是否执行。 let mut typed = false; + // 接收者的有效类型可能经 type_target 转发;无类型时不会枚举名义方法。 let actual = self.type_of(receiver)?; + // 从实际类型开始向基类枚举可能声明当前函数的方法名。 let mut owner = actual; + // 向基类遍历;不假定候选函数一定是接收者当前生效的方法。 while let Some(definition) = owner { + // 读取类型载荷并验证句柄,后续方法表与基类访问都基于该借用。 let data = self.payload::(definition, "Type")?; + // 同一函数可出现在多个方法名下,各自可能承担不同能力契约。 for (name, candidate) in &data.methods { + // 这里只处理正在调用的函数身份,其余方法不检查。 if *candidate != function { continue; } self.check_typed_instance_storage(receiver)?; + // 普通 override 检查由调用方选择,能力约束不受该开关豁免。 if overrides { self.check_override(definition, name, function, None, false)?; } + // 实际方法查找仍选中该函数时按实际类型能力检查,否则按当前声明层处理。 let effective = if self .lookup_method(actual.expect("method receiver has a type"), name)? == Some(function) @@ -403,7 +503,9 @@ impl ObjectStore { } else { definition }; + // 有效类型继承的全部能力都参与,不能只检查第一个匹配能力。 for capability in self.inherited_traits(effective)? { + // 只有该能力声明当前方法的完整类型签名时才有约束可检查。 if let Some(expected) = self .payload::(capability, "Trait")? .signatures @@ -423,20 +525,29 @@ impl ObjectStore { /// Borrowed expected results for all typed capabilities of this effective /// method. The evaluator retains definitions before entering the body. + /// eval/NativeContext 收集有效方法的全部能力返回约束;返回类型句柄仍为借用。 pub fn method_trait_returns( &self, function: ObjectRef, receiver: ObjectRef, ) -> Result, VmError> { + // 接收者的有效类型可能经 type_target 转发;无类型时不会枚举名义方法。 let actual = self.type_of(receiver)?; + // 从实际类型开始向基类枚举可能声明当前函数的方法名。 let mut owner = actual; + // 累计所有能力返回约束,clone 不保留其中托管定义根。 let mut returns = Vec::new(); + // 向基类遍历;不假定候选函数一定是接收者当前生效的方法。 while let Some(definition) = owner { + // 读取类型载荷并验证句柄,后续方法表与基类访问都基于该借用。 let data = self.payload::(definition, "Type")?; + // 同一函数可出现在多个方法名下,各自可能承担不同能力契约。 for (name, candidate) in &data.methods { + // 这里只处理正在调用的函数身份,其余方法不检查。 if *candidate != function { continue; } + // 实际方法查找仍选中该函数时按实际类型能力检查,否则按当前声明层处理。 let effective = if self .lookup_method(actual.expect("method receiver has a type"), name)? == Some(function) @@ -445,8 +556,11 @@ impl ObjectStore { } else { definition }; + // 有效类型继承的全部能力都参与,不能只检查第一个匹配能力。 for capability in self.inherited_traits(effective)? { + // 读取能力签名表,名称用于返回错误的定位。 let contract = self.payload::(capability, "Trait")?; + // 只有该能力声明当前方法的完整类型签名时才有约束可检查。 if let Some(expected) = contract.signatures.get(name) { returns.push(( format!("{}.{}", contract.name, name),