docs(objects): clarify type capability and effect query contracts
This commit is contained in:
@@ -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<ObjectRef>,
|
||||
}
|
||||
#[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<ObjectRef> {
|
||||
// 仅 Object 事实可用于属性接收者或调用身份,Unknown/Null/Method 都不冒充普通对象。
|
||||
match self {
|
||||
|
||||
+34
-15
@@ -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::<EndorTypeObject>(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<bool, VmError> {
|
||||
self.payload::<EndorTypeObject>(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<Option<crate::CallEffect>, 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<MethodRequirement>,
|
||||
/// 按方法名保存的完整类型/效果契约,签名中的定义引用由本载荷 trace 保活。
|
||||
signatures: BTreeMap<String, crate::CallSignature>,
|
||||
}
|
||||
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::<EndorTraitObject>(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<Vec<String>, 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<ObjectRef>,
|
||||
) -> Result<AnnotationType, VmError> {
|
||||
// 先验证定义/函数载荷,再访问字段表或声明环境。
|
||||
// 先验证源码函数载荷,后续从其代码签名、全局和已捕获内置字典解析注解。
|
||||
let data = self.payload::<crate::EndorFunctionObject>(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::<EndorTypeObject>() {
|
||||
@@ -1641,7 +1660,7 @@ impl ObjectStore {
|
||||
}
|
||||
/// 类型错误诊断格式化预期名称;名义/能力定义仍验证句柄和载荷。
|
||||
pub fn annotation_type_name(&self, expected: AnnotationType) -> Result<String, VmError> {
|
||||
// 直接类别与名义/能力匹配分开;Type/Function 类别不等于任意可调用对象。
|
||||
// 内建类别使用固定显示名,名义/能力注解从有效定义载荷取名,不在这里匹配实际值。
|
||||
Ok(match expected {
|
||||
AnnotationType::Any => "Object".into(),
|
||||
AnnotationType::Unit => "Unit".into(),
|
||||
|
||||
Reference in New Issue
Block a user