docs(objects): explain type construction and definition lifecycle

This commit is contained in:
2026-11-15 17:36:56 +08:00
parent c05d60cbc9
commit 7a40e85b94
+97
View File
@@ -1,3 +1,5 @@
//! 类型、能力与实例共享同一托管堆;Store 定义身份/继承规则,VM 负责构造调用的执行调度。
//! contracts 校验方法替换与能力契约,effects 查询当前快照的调用效果。
//! Nominal type identities in the same managed heap as their instances.
#[path = "contracts.rs"]
mod contracts;
@@ -13,21 +15,28 @@ use crate::{
// A host type_target may read its receiver's raw attributes. Validate the
// outer lookup after resolution without recursively re-entering its guard.
struct AttributeCheckGuard<'a> {
/// 借用当前 Store 的属性检查递归表。
store: &'a ObjectStore,
/// 进入检查时的线程,用于隔离递归标记。
thread: std::thread::ThreadId,
/// 当前被检查对象,守卫不为其建立根。
object: ObjectRef,
}
impl Drop for AttributeCheckGuard<'_> {
/// 属性/类型重入检查的 RAII 清理,移除本线程当前对象,不清除其他活跃检查。
fn drop(&mut self) {
// 锁内定位递归检查表,守卫保证当前项此前已插入。
let mut checks = self
.store
.active_attribute_checks
.lock()
.expect("attribute checker poisoned");
// 仅删除本线程该对象的检查项,嵌套其他对象仍保持活跃。
let active = checks
.get_mut(&self.thread)
.expect("active attribute check");
active.remove(&self.object);
// 线程内无剩余对象检查时移除空集合。
if active.is_empty() {
checks.remove(&self.thread);
}
@@ -43,11 +52,13 @@ pub enum TypeConstructor {
/// Opt-in allocator inheritance. The requested nominal type is prepended
/// to the constructor arguments; the allocator must create that real type.
NativeTyped(ObjectRef),
/// 禁止直接构造,源码派生沿用该策略后仍为抽象类型。
Abstract,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ClassField {
/// 字段存储名称,源码类创建时检查重复及保留名。
pub name: String,
/// Source annotation resolved at checked construction/field writes.
pub type_name: String,
@@ -58,60 +69,81 @@ pub struct ClassField {
/// edges; no registry outside the heap keeps unused definitions alive.
#[derive(Debug, Clone)]
pub struct EndorTypeObject {
/// 诊断名称,名义身份仍由对象句柄决定。
name: String,
/// 固定基类强边,根 Object 为 None。
base: Option<ObjectRef>,
/// 实例创建策略,类型可调用路径按此分派。
constructor: TypeConstructor,
/// 方法名到函数的拥有边,更新走 define_method。
methods: BTreeMap<String, ObjectRef>,
/// 继承字段在前的完整构造布局。
fields: Vec<ClassField>,
// Declaring execution environment; a managed edge, never an external root.
/// 自有字段注解的声明函数环境强边,不是外部根。
field_scope: Option<ObjectRef>,
/// 本层显式能力定义的强边,继承能力另沿基类查询。
traits: Vec<ObjectRef>,
}
impl EndorTypeObject {
/// 宿主/诊断借用类型声明名称,不代表仅按名称判断类型相等。
pub fn name(&self) -> &str {
&self.name
}
/// 继承查找借用固定基类句柄,不产生外部根。
pub fn base(&self) -> Option<ObjectRef> {
self.base
}
/// 构造器和宿主借用完整字段序列,包含从父类复制的字段。
pub fn fields(&self) -> &[ClassField] {
&self.fields
}
}
impl ObjectPayload for EndorTypeObject {
/// 类型定义不实现旧式原地赋值,允许只读局部重绑定引用。
fn reference_assignment_only(&self) -> bool {
true
}
/// Store 下转型为具体类型载荷的入口。
fn as_any(&self) -> &dyn std::any::Any {
self
}
/// 错误与默认诊断使用载荷类别,名义类型关系另外判断。
fn kind_name(&self) -> &'static str {
"type"
}
/// Heap 分配/受控更新类型时登记基类、构造器、字段环境、能力及方法强边。
fn trace(&self, visit: &mut dyn FnMut(ObjectRef)) {
// 基类本身是一条拥有边,不依赖堆外注册表维持存活。
if let Some(base) = self.base {
visit(base);
}
// 两类原生构造都持有函数强边;Record/Abstract 不包含函数。
if let TypeConstructor::Native(function) | TypeConstructor::NativeTyped(function) =
self.constructor
{
visit(function);
}
// 字段声明环境必须由类型拥有,否则稍后注解解析可能失去环境。
if let Some(scope) = self.field_scope {
visit(scope);
}
// 逐项登记已声明能力,重复引用也按拥有次数计算。
for capability in &self.traits {
visit(*capability);
}
// 方法表每个槽拥有函数强边,不因同一函数多名注册而去重。
for method in self.methods.values() {
visit(*method);
}
}
/// Store 显示类型名称,不展开方法表或执行构造器。
fn repr(&self, _: ObjectRef) -> Result<String, VmError> {
Ok(format!("<type {}>", self.name))
}
/// VM 把类型作为可调用对象时取得构造分派器;Type 可调用但不是函数分类。
fn native_callable(&self) -> Option<Arc<dyn NativeCallable>> {
Some(Arc::new(Construct))
}
@@ -120,19 +152,24 @@ impl ObjectPayload for EndorTypeObject {
#[derive(Debug)]
struct Construct;
impl NativeCallable for Construct {
/// NativeContext 构造入口:按类型的构造策略返回实例或委托 VM 调用分配器。
fn invoke(
&self,
cx: &mut NativeContext<'_>,
arguments: &[Value],
) -> Result<NativeResult, VmError> {
// 当前被调用对象就是类型,借用身份已由上下文保护。
let type_object = cx.callee();
// 只读借用构造策略;下方修改前先复制需要跨修改使用的元数据。
let definition = cx.store().payload::<EndorTypeObject>(type_object, "Type")?;
// 原生委托交回 VM 帧循环,不能递归调用执行器;抽象类型明确拒绝。
match definition.constructor {
TypeConstructor::Native(function) => Ok(NativeResult::Invoke {
function,
arguments: arguments.to_vec(),
}),
TypeConstructor::NativeTyped(function) => {
// NativeTyped 把实际请求类型放在首位,让继承分配器创建正确的派生载荷。
let mut values = Vec::with_capacity(arguments.len() + 1);
values.push(Value::Object(type_object));
values.extend_from_slice(arguments);
@@ -145,6 +182,7 @@ impl NativeCallable for Construct {
Err(VmError::UnsupportedOperation("abstract type construction"))
}
TypeConstructor::Record => {
// Record 字段按位置一一对应,缺少或多余都在分配实例前拒绝。
if arguments.len() != definition.fields.len() {
return Err(VmError::ArgumentCount {
name: definition.name.clone(),
@@ -153,11 +191,14 @@ impl NativeCallable for Construct {
provided: arguments.len(),
});
}
// 释放类型载荷借用后仍需要字段名,因此复制布局,不复制托管对象。
let fields = definition.fields.clone();
cx.store()
.check_class_field_arguments(type_object, arguments)?;
// 分配临时根后再附着类型/写字段,失败时上下文统一清理半成品。
let instance = cx.new_object()?;
cx.attach_type(instance, type_object)?;
// 按继承字段在前的布局依次写入,克隆 Value 不自动 retain,由属性拥有边承担持有。
for (field, value) in fields.iter().zip(arguments) {
cx.set_attr(instance, &field.name, value.clone())?;
}
@@ -170,14 +211,18 @@ impl NativeCallable for Construct {
/// Each field owns one external root; the caller must release both.
#[derive(Debug, Clone, Copy)]
pub struct RootTypes {
/// Object 根类型的一份外部拥有根,调用方须 release。
pub object: ObjectRef,
/// Type 元类型的一份外部拥有根,调用方须 release。
pub type_type: ObjectRef,
}
impl ObjectStore {
/// Explicit bootstrap preserves the empty-store contract. Inheritance:
/// Type -> Object; instance relations: Object : Type and Type : Type.
/// 宿主/VM 显式创建 Object/Type;不改变 Store::new 保持空堆的约定。
pub fn bootstrap_types(&mut self) -> Result<RootTypes, VmError> {
// 先创建无元类型的 Object 定义,随后建立自举关系。
let object = self.allocate(EndorTypeObject {
name: "Object".into(),
base: None,
@@ -187,8 +232,11 @@ impl ObjectStore {
field_scope: None,
traits: Vec::new(),
})?;
// 记录第二次分配是否成功,便于后续任何错误清理已建对象。
let mut allocated_type = None;
// 闭包归拢 Type 分配与关系附着错误,外层统一释放自举临时根。
let result = (|| {
// Type 以 Object 为基类,随后自己以 Type 为类型,形成合法类型图环。
let type_type = self.allocate(EndorTypeObject {
name: "Type".into(),
base: Some(object),
@@ -203,7 +251,9 @@ impl ObjectStore {
self.attach_type(type_type, type_type)?;
Ok(RootTypes { object, type_type })
})();
// 自举失败归还已有根并收集可能形成的环,避免半初始化定义泄漏。
if result.is_err() {
// 只有成功分配 Type 后才需要归还其根。
if let Some(type_type) = allocated_type {
self.release(type_type)?;
}
@@ -214,23 +264,29 @@ impl ObjectStore {
}
/// Base links are fixed at allocation, preventing inheritance cycles.
/// 宿主创建派生类型,复制父字段布局并沿用元类型;返回一份外部拥有根。
pub fn new_type(
&mut self,
name: impl Into<String>,
base: ObjectRef,
constructor: TypeConstructor,
) -> Result<ObjectRef, VmError> {
// 父字段复制成新类型布局;后续不能私自改变继承前缀。
let fields = self
.payload::<EndorTypeObject>(base, "Type")?
.fields
.clone();
// 新类型继承基类的有效元类型,缺失元类型时拒绝构造。
let metatype = self
.type_of(base)?
.ok_or(VmError::InvalidArgument("base type has no metatype"))?;
// 持有名称用于新载荷与诊断,后续校验借用该字符串。
let name = name.into();
// 类型名称不允许空串,但身份判断仍使用句柄而非文本。
if name.is_empty() {
return Err(VmError::InvalidArgument("type name must not be empty"));
}
// 分配时基类/构造器/方法环境等由 trace 登记边,返回一份外部根。
let definition = self.allocate(EndorTypeObject {
name,
base: Some(base),
@@ -240,6 +296,7 @@ impl ObjectStore {
field_scope: None,
traits: Vec::new(),
})?;
// 元类型附着失败则归还新定义根,不交付无元类型半成品。
if let Err(error) = self.attach_type(definition, metatype) {
self.release(definition)?;
return Err(error);
@@ -247,12 +304,14 @@ impl ObjectStore {
Ok(definition)
}
/// 宿主/构造器先检查类型和能力存储约束,再交 Heap 建立不可替换的类型强边。
pub fn attach_type(
&mut self,
object: ObjectRef,
type_object: ObjectRef,
) -> Result<(), VmError> {
self.payload::<EndorTypeObject>(type_object, "Type")?;
// 逐项登记已声明能力,重复引用也按拥有次数计算。
for capability in self.inherited_traits(type_object)? {
self.check_capability_storage(object, capability)?;
}
@@ -260,16 +319,23 @@ impl ObjectStore {
}
/// Borrowed type reference; legacy/untyped host objects return None.
/// VM/契约查询有效类型,沿 type_target 转发,最终返回头部的借用类型或 None。
pub fn type_of(&self, object: ObjectRef) -> Result<Option<ObjectRef>, VmError> {
// 从门面对象出发追踪实际类型目标,不直接忽略 type_target 协议。
let mut current = object;
// 保存已访问身份,防宿主转发环导致无限循环。
let mut visited = std::collections::BTreeSet::new();
// 逐跳验证存活句柄和载荷,直到无类型转发目标。
loop {
// 同一身份再出现说明转发环,返回明确协议错误。
if !visited.insert(current) {
return Err(VmError::InvalidArgument(
"cyclic shared-reference type target",
));
}
// 分配临时根后再附着类型/写字段,失败时上下文统一清理半成品。
let instance = self.object(current)?;
// 有转发目标则继续,无目标时读取当前对象头部名义类型。
match instance.payload().type_target(self)? {
Some(target) => current = target,
None => return Ok(instance.header().type_object()),
@@ -277,11 +343,16 @@ impl ObjectStore {
}
}
/// 注解/替换检查沿单继承链比较名义身份,包含类型自身。
pub fn is_subtype(&self, candidate: ObjectRef, expected: ObjectRef) -> Result<bool, VmError> {
self.payload::<EndorTypeObject>(expected, "Type")?;
// 从候选类型本身开始,因此自反子类型关系成立。
let mut current = Some(candidate);
// 基类在创建时固定且指向已有类型,正常类型图不会出现继承环。
while let Some(type_object) = current {
// 借用类型载荷验证身份和种类,再读字段、基类或方法表。
let definition = self.payload::<EndorTypeObject>(type_object, "Type")?;
// 比较完整名义身份,不接受仅同名的另一个类型。
if type_object == expected {
return Ok(true);
}
@@ -290,8 +361,10 @@ impl ObjectStore {
Ok(false)
}
/// VM/宿主判断实例有效类型是否为 expected 的子类型,无类型旧对象返回 false。
pub fn is_instance(&self, object: ObjectRef, expected: ObjectRef) -> Result<bool, VmError> {
self.payload::<EndorTypeObject>(expected, "Type")?;
// 有效类型可来自转发对象;无类型不是 InvalidHandle,而是正常 false。
match self.type_of(object)? {
Some(type_object) => self.is_subtype(type_object, expected),
None => Ok(false),
@@ -299,6 +372,7 @@ impl ObjectStore {
}
/// Updating the managed method table preserves nominal identity and base.
/// 宿主/VM 受控更新方法表,身份/基类不变,先验证覆盖及能力约束再替换载荷。
pub fn define_method(
&mut self,
type_object: ObjectRef,
@@ -306,20 +380,26 @@ impl ObjectStore {
function: ObjectRef,
) -> Result<(), VmError> {
self.object(function)?;
// 持有名称用于新载荷与诊断,后续校验借用该字符串。
let name = name.into();
// 类型名称不允许空串,但身份判断仍使用句柄而非文本。
if name.is_empty() || name == "type" {
return Err(VmError::InvalidArgument("reserved or empty method name"));
}
// 借用类型载荷验证身份和种类,再读字段、基类或方法表。
let definition = self.payload::<EndorTypeObject>(type_object, "Type")?;
// 实例字段与类型方法不能同名,避免构造/查找产生歧义。
if definition.fields.iter().any(|field| field.name == name) {
return Err(VmError::InvalidArgument(
"method conflicts with class field",
));
}
// 先准备独立方法表副本,契约失败时真实载荷保持原状。
let mut methods = definition.methods.clone();
self.validate_override_update(type_object, &name, function)?;
self.validate_method_update(type_object, &name, function)?;
methods.insert(name, function);
// 保留名称、基类、构造、字段和能力,只替换方法表;Heap 再更新强边和版本。
let updated = EndorTypeObject {
name: definition.name.clone(),
base: definition.base,
@@ -335,6 +415,7 @@ impl ObjectStore {
/// Atomically build a source class, including inherited constructor fields.
/// Only explicitly inheritable native allocators are reused. Abstract
/// subclasses remain abstract; no Record can forge a native payload.
/// eval/宿主创建源码类的无字段声明环境入口,转交统一构造路径。
pub fn new_class(
&mut self,
name: impl Into<String>,
@@ -347,6 +428,7 @@ impl ObjectStore {
/// Source class builder with a traced function environment for field names.
/// None supports primitive annotations and the declaring class itself.
/// eval 创建源码类,组合继承字段、当前方法与声明环境,完成契约检查后才交付根。
pub fn new_class_with_scope(
&mut self,
name: impl Into<String>,
@@ -355,19 +437,27 @@ impl ObjectStore {
methods: BTreeMap<String, ObjectRef>,
scope: Option<ObjectRef>,
) -> Result<ObjectRef, VmError> {
// 字段声明环境必须由类型拥有,否则稍后注解解析可能失去环境。
if let Some(scope) = scope {
self.payload::<crate::EndorFunctionObject>(scope, "function")?;
}
// 没有自有字段时无需持有当前声明环境,继承字段仍通过其声明层解析。
let field_scope = if own_fields.is_empty() { None } else { scope };
// 借用类型载荷验证身份和种类,再读字段、基类或方法表。
let definition = self.payload::<EndorTypeObject>(base, "Type")?;
// Native 未显式允许源码继承分配,不能用普通 Record 伪造原生载荷。
if matches!(definition.constructor, TypeConstructor::Native(_)) {
return Err(VmError::UnsupportedOperation(
"native allocator does not opt into source subclass construction",
));
}
// 源码派生沿用允许继承的策略,Abstract 仍为 Abstract,NativeTyped 得到请求类型。
let constructor = definition.constructor;
// 继承字段保持前缀,再按源码顺序附加新字段。
let mut fields = definition.fields.clone();
// 逐个检查重复、保留名及继承方法冲突,不允许覆盖已有字段布局。
for field in own_fields {
// 名称与注解都不能空,字段不能重复或遮蔽父方法。
if field.name.is_empty()
|| field.type_name.is_empty()
|| field.name == "type"
@@ -380,21 +470,27 @@ impl ObjectStore {
}
fields.push(field);
}
// 方法提交前验证函数句柄,拒绝与完整继承字段序列重名。
for (name, method) in &methods {
self.object(*method)?;
// 类型名称不允许空串,但身份判断仍使用句柄而非文本。
if name.is_empty() || name == "type" || fields.iter().any(|field| field.name == *name) {
return Err(VmError::InvalidArgument(
"method conflicts with class field",
));
}
}
// 新类型继承基类的有效元类型,缺失元类型时拒绝构造。
let metatype = self
.type_of(base)?
.ok_or(VmError::InvalidArgument("base type has no metatype"))?;
// 持有名称用于新载荷与诊断,后续校验借用该字符串。
let name = name.into();
// 类型名称不允许空串,但身份判断仍使用句柄而非文本。
if name.is_empty() {
return Err(VmError::InvalidArgument("type name must not be empty"));
}
// 一次构造完整类载荷,后面的验证失败只需释放这份新根。
let class = self.allocate(EndorTypeObject {
name,
base: Some(base),
@@ -404,6 +500,7 @@ impl ObjectStore {
field_scope,
traits: Vec::new(),
})?;
// 继承能力、普通覆盖和元类型附着按顺序完成,任一失败都不交付该类。
if let Err(error) = self
.validate_inherited_traits(class)
.and_then(|()| self.validate_class_overrides(class))