docs(objects): explain method binding and capability construction
This commit is contained in:
@@ -512,14 +512,18 @@ impl ObjectStore {
|
||||
Ok(class)
|
||||
}
|
||||
|
||||
/// Store/VM/能力检查沿继承链查最近同名方法,返回借用函数,不自动绑定接收者。
|
||||
pub fn lookup_method(
|
||||
&self,
|
||||
type_object: ObjectRef,
|
||||
name: &str,
|
||||
) -> Result<Option<ObjectRef>, VmError> {
|
||||
// 从类型自身向父链查找,最近声明优先。
|
||||
let mut current = Some(type_object);
|
||||
// 基类固定于创建,逐层校验类型句柄而不是按名称检索。
|
||||
while let Some(type_object) = current {
|
||||
let definition = self.payload::<EndorTypeObject>(type_object, "Type")?;
|
||||
// 找到方法即返回借用身份,不替调用方 retain。
|
||||
if let Some(function) = definition.methods.get(name) {
|
||||
return Ok(Some(*function));
|
||||
}
|
||||
@@ -530,15 +534,22 @@ impl ObjectStore {
|
||||
|
||||
/// Source positional parameters after receiver binding. None means the
|
||||
/// callable uses a native protocol without a source signature.
|
||||
/// 旧式能力检查/宿主查询源码参数总数,扣除所有绑定接收者;原生协议返回 None。
|
||||
pub fn positional_parameter_count(
|
||||
&self,
|
||||
function: ObjectRef,
|
||||
) -> Result<Option<usize>, VmError> {
|
||||
// 从传入可调用对象开始逐层展开 BoundMethod。
|
||||
let mut current = function;
|
||||
// 累计已绑定接收者槽数,不能只扣一层。
|
||||
let mut receivers = 0usize;
|
||||
// 按链迭代而非递归,未知原生元数据保持 None。
|
||||
loop {
|
||||
// 通过 object 验证句柄并记录读取,随后仅借用载荷元数据。
|
||||
let payload = self.object(current)?.payload();
|
||||
// 每层绑定都额外供应一个接收者,继续查询真实目标函数。
|
||||
if let Some(bound) = payload.as_any().downcast_ref::<BoundMethod>() {
|
||||
// 计数使用 checked_add,防极深包装使参数扣减绕回。
|
||||
receivers = receivers
|
||||
.checked_add(1)
|
||||
.ok_or(VmError::ExecutionLimit("bound receivers"))?;
|
||||
@@ -547,6 +558,7 @@ impl ObjectStore {
|
||||
.as_any()
|
||||
.downcast_ref::<crate::EndorFunctionObject>()
|
||||
{
|
||||
// 源码参数列表包含显式 self,默认值不改变总参数槽数。
|
||||
let count = self
|
||||
.payload::<crate::EndorCodeObject>(function.code(), "code")?
|
||||
.code()
|
||||
@@ -564,16 +576,21 @@ impl ObjectStore {
|
||||
}
|
||||
}
|
||||
|
||||
/// Validated direct native metadata. Bound methods delegate to their actual
|
||||
/// target, so receiver slots remain explicit here. Returned handles are borrowed.
|
||||
/// 查询直接原生元数据;完整签名保留显式接收者,返回类型句柄是借用。
|
||||
/// BoundMethod 本身没有完整签名,参数区间查询通过 call_arity 另行解包。
|
||||
/// 原生调用/契约分析查询当前载荷完整签名并校验;不会在这里展开 BoundMethod。
|
||||
pub fn native_signature(
|
||||
&self,
|
||||
function: ObjectRef,
|
||||
) -> Result<Option<crate::CallSignature>, VmError> {
|
||||
// 通过 object 验证句柄并记录读取,随后仅借用载荷元数据。
|
||||
let payload = self.object(function)?.payload();
|
||||
// 查询当前载荷提供的签名快照,不执行回调,也不新增定义根。
|
||||
let signature = payload.call_signature();
|
||||
// 存在完整签名才校验全部类型边及数量元数据一致性。
|
||||
if let Some(signature) = &signature {
|
||||
signature.validate(self)?;
|
||||
// 载荷若同时发布 arity,必须与完整签名完全一致。
|
||||
if payload
|
||||
.call_arity()
|
||||
.is_some_and(|arity| arity != signature.arity)
|
||||
@@ -588,28 +605,38 @@ impl ObjectStore {
|
||||
/// native wrappers and source call graphs with unproved operations remain unknown.
|
||||
/// 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)
|
||||
}
|
||||
|
||||
/// Unified source/native positional interval, after any bound receivers.
|
||||
/// None means no published native metadata (including generic Type construction).
|
||||
/// VM 数量检查统一查询源码/原生区间,先解绑定方法再扣除接收者。
|
||||
pub fn call_arity(&self, function: ObjectRef) -> Result<Option<crate::CallArity>, VmError> {
|
||||
// 从传入可调用对象开始逐层展开 BoundMethod。
|
||||
let mut current = function;
|
||||
// 累计已绑定接收者槽数,不能只扣一层。
|
||||
let mut receivers = 0usize;
|
||||
// 按链迭代而非递归,未知原生元数据保持 None。
|
||||
loop {
|
||||
// 通过 object 验证句柄并记录读取,随后仅借用载荷元数据。
|
||||
let payload = self.object(current)?.payload();
|
||||
// 每层绑定都额外供应一个接收者,继续查询真实目标函数。
|
||||
if let Some(bound) = payload.as_any().downcast_ref::<BoundMethod>() {
|
||||
// 计数使用 checked_add,防极深包装使参数扣减绕回。
|
||||
receivers = receivers
|
||||
.checked_add(1)
|
||||
.ok_or(VmError::ExecutionLimit("bound receivers"))?;
|
||||
current = bound.function;
|
||||
continue;
|
||||
}
|
||||
// 源码区间由总参数数减默认值数;原生优先完整签名,否则兼容独立 arity。
|
||||
let arity = if let Some(function) = payload
|
||||
.as_any()
|
||||
.downcast_ref::<crate::EndorFunctionObject>()
|
||||
{
|
||||
// 源码代码布局已经校验,函数 defaults 数量也经构造校验。
|
||||
let maximum = self
|
||||
.payload::<crate::EndorCodeObject>(function.code(), "code")?
|
||||
.code()
|
||||
@@ -626,7 +653,9 @@ impl ObjectStore {
|
||||
};
|
||||
return arity
|
||||
.map(|arity| {
|
||||
// 先校验原始区间,再调整已绑定接收者造成的可见数量。
|
||||
let arity = arity.validate()?;
|
||||
// 开放上界保持 usize::MAX,有限上界 checked_sub 防绑定超出参数容量。
|
||||
let maximum = if arity.maximum == usize::MAX {
|
||||
usize::MAX
|
||||
} else {
|
||||
@@ -647,9 +676,12 @@ impl ObjectStore {
|
||||
}
|
||||
|
||||
/// Returns one owned root, including for a newly bound inherited method.
|
||||
/// eval LoadAttr/宿主获取可用属性;对象值 retain 一根,方法则分配拥有接收者和函数的绑定对象。
|
||||
pub fn bind_attr(&mut self, receiver: ObjectRef, name: &str) -> Result<Value, VmError> {
|
||||
// 借用查找与拥有结果分开:返回到执行栈的对象必须先取得根。
|
||||
match self.lookup_attr(receiver, name)? {
|
||||
AttributeLookup::Value(value) => {
|
||||
// 标量由 Rust 值直接持有,仅对象属性结果需要 retain。
|
||||
if let Value::Object(object) = value {
|
||||
self.retain(object)?;
|
||||
}
|
||||
@@ -661,43 +693,54 @@ impl ObjectStore {
|
||||
}
|
||||
}
|
||||
|
||||
/// Store get_attr/bind_attr 与效果分析共用借用查找,不分配 BoundMethod 或创建结果根。
|
||||
pub(crate) fn lookup_attr(
|
||||
&self,
|
||||
receiver: ObjectRef,
|
||||
name: &str,
|
||||
) -> Result<AttributeLookup, VmError> {
|
||||
// 保留最初 receiver 身份,用于名义元数据、能力遮蔽检查与方法绑定。
|
||||
let object = self.object(receiver)?;
|
||||
// 已附着类型优先作为保留属性暴露,返回借用类型句柄。
|
||||
if name == "type"
|
||||
&& let Some(type_object) = self.type_of(receiver)?
|
||||
{
|
||||
return Ok(AttributeLookup::Value(Value::Object(type_object)));
|
||||
}
|
||||
// 能力名称元数据优先于普通字段,但仍受方法遮蔽保护。
|
||||
if name == "name"
|
||||
&& let Some(capability) = object.payload().as_any().downcast_ref::<EndorTraitObject>()
|
||||
{
|
||||
self.check_typed_method_write(receiver, name)?;
|
||||
return Ok(AttributeLookup::Value(Value::Text(capability.name.clone())));
|
||||
}
|
||||
// 类型对象先处理自身 name/base 元数据和类方法表,不绑定为实例方法。
|
||||
if let Some(definition) = object.payload().as_any().downcast_ref::<EndorTypeObject>() {
|
||||
// 根类型 base 为 Nil,与没有这个元数据属性不同。
|
||||
let metadata = match name {
|
||||
"name" => Some(Value::Text(definition.name.clone())),
|
||||
"base" => Some(definition.base.map(Value::Object).unwrap_or(Value::Nil)),
|
||||
_ => None,
|
||||
};
|
||||
// 元数据返回前核对类型化能力方法不能被同名属性遮蔽。
|
||||
if let Some(value) = metadata {
|
||||
self.check_typed_method_write(receiver, name)?;
|
||||
return Ok(AttributeLookup::Value(value));
|
||||
}
|
||||
// 直接从类型对象取方法返回函数值,不绑定该类型为 self。
|
||||
if let Some(function) = self.lookup_method(receiver, name)? {
|
||||
self.check_typed_method_write(receiver, name)?;
|
||||
return Ok(AttributeLookup::Value(Value::Object(function)));
|
||||
}
|
||||
}
|
||||
// 普通字段沿 attribute_target 找最终存储,成功路径必非空。
|
||||
let storage = *self
|
||||
.attribute_path(receiver)?
|
||||
.last()
|
||||
.expect("nonempty attribute path");
|
||||
// 存储缺字段/不允许属性时还可尝试实例类型方法;其他错误直接传播。
|
||||
match self.heap.get_attr(storage, name) {
|
||||
// 字段命中仍检查能力方法遮蔽,然后返回借用值。
|
||||
Ok(value) => {
|
||||
self.check_typed_method_write(receiver, name)?;
|
||||
return Ok(AttributeLookup::Value(value));
|
||||
@@ -705,7 +748,9 @@ impl ObjectStore {
|
||||
Err(VmError::AttributeNotFound(_) | VmError::UnsupportedOperation("attributes")) => {}
|
||||
Err(error) => return Err(error),
|
||||
}
|
||||
// 根据接收者有效类型查实例方法,绑定的是原始 receiver 身份。
|
||||
if let Some(type_object) = self.type_of(receiver)? {
|
||||
// 实例方法返回函数/接收者对,由 bind_attr 决定是否分配绑定对象。
|
||||
if let Some(function) = self.lookup_method(type_object, name)? {
|
||||
return Ok(AttributeLookup::Method { function, receiver });
|
||||
}
|
||||
@@ -717,6 +762,7 @@ impl ObjectStore {
|
||||
}
|
||||
}
|
||||
|
||||
/// 内部借用查找结果;Method 延迟绑定,使只读分析不必分配 BoundMethod。
|
||||
pub(crate) enum AttributeLookup {
|
||||
Value(Value),
|
||||
Method {
|
||||
@@ -726,27 +772,36 @@ pub(crate) enum AttributeLookup {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
/// 持有函数和原接收者的托管包装,由 bind_attr 分配一份外部根。
|
||||
struct BoundMethod {
|
||||
// 原始接收者强边,不一定是最终属性存储对象。
|
||||
receiver: ObjectRef,
|
||||
// 底层函数强边,委托调用时由 NativeContext 取得输出根。
|
||||
function: ObjectRef,
|
||||
}
|
||||
impl ObjectPayload for BoundMethod {
|
||||
/// 绑定方法按函数分类,可在 Store 分配时附着 Function 类型。
|
||||
fn is_function(&self) -> bool {
|
||||
true
|
||||
}
|
||||
/// 绑定方法/能力定义不实现原地赋值,允许只读局部重绑定引用。
|
||||
fn reference_assignment_only(&self) -> bool {
|
||||
true
|
||||
}
|
||||
/// Store 的载荷下转型接口,不是语言名义类型判断。
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
/// 错误/诊断载荷类别。
|
||||
fn kind_name(&self) -> &'static str {
|
||||
"bound-method"
|
||||
}
|
||||
/// Heap 分配/更新载荷时枚举拥有边,重复边仍逐条报告。
|
||||
fn trace(&self, visit: &mut dyn FnMut(ObjectRef)) {
|
||||
visit(self.receiver);
|
||||
visit(self.function);
|
||||
}
|
||||
/// VM 取得绑定方法分派器,调用时由上下文保护其载荷边。
|
||||
fn native_callable(&self) -> Option<Arc<dyn NativeCallable>> {
|
||||
Some(Arc::new(CallBoundMethod))
|
||||
}
|
||||
@@ -755,14 +810,17 @@ impl ObjectPayload for BoundMethod {
|
||||
#[derive(Debug)]
|
||||
struct CallBoundMethod;
|
||||
impl NativeCallable for CallBoundMethod {
|
||||
/// VM 分派绑定方法,把接收者插在显式参数前并委托底层函数,不递归运行执行器。
|
||||
fn invoke(
|
||||
&self,
|
||||
cx: &mut NativeContext<'_>,
|
||||
arguments: &[Value],
|
||||
) -> Result<NativeResult, VmError> {
|
||||
// 绑定载荷中的强边由上下文保护,回调只借用其元数据。
|
||||
let bound = cx
|
||||
.store()
|
||||
.payload::<BoundMethod>(cx.callee(), "bound method")?;
|
||||
// 新参数向量先放 self 再放调用方参数,clone 本身不 retain。
|
||||
let mut values = Vec::with_capacity(arguments.len() + 1);
|
||||
values.push(Value::Object(bound.receiver));
|
||||
values.extend_from_slice(arguments);
|
||||
@@ -787,56 +845,73 @@ pub struct TypedMethodRequirement {
|
||||
pub signature: crate::CallSignature,
|
||||
}
|
||||
#[derive(Debug)]
|
||||
/// 显式能力定义:最小数量要求与可选完整签名同属托管载荷,定义本身不可任意替换。
|
||||
pub struct EndorTraitObject {
|
||||
name: String,
|
||||
requirements: Vec<MethodRequirement>,
|
||||
signatures: BTreeMap<String, crate::CallSignature>,
|
||||
}
|
||||
impl EndorTraitObject {
|
||||
/// 宿主/诊断借用能力名称,能力相等仍按身份。
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
/// 能力校验借用最小位置参数要求列表,不含绑定 self。
|
||||
pub fn requirements(&self) -> &[MethodRequirement] {
|
||||
&self.requirements
|
||||
}
|
||||
/// 契约校验借用指定方法完整签名,含显式 self,未声明返回 None。
|
||||
pub fn signature(&self, name: &str) -> Option<&crate::CallSignature> {
|
||||
self.signatures.get(name)
|
||||
}
|
||||
}
|
||||
impl ObjectPayload for EndorTraitObject {
|
||||
/// Heap 分配/更新载荷时枚举拥有边,重复边仍逐条报告。
|
||||
fn trace(&self, visit: &mut dyn FnMut(ObjectRef)) {
|
||||
// 能力完整签名的全部类型定义参与 trace,不只看当前调用到的分支。
|
||||
for signature in self.signatures.values() {
|
||||
// 每个引用都是拥有边,不能按身份去重。
|
||||
for reference in signature.references() {
|
||||
visit(reference);
|
||||
}
|
||||
}
|
||||
}
|
||||
/// 绑定方法/能力定义不实现原地赋值,允许只读局部重绑定引用。
|
||||
fn reference_assignment_only(&self) -> bool {
|
||||
true
|
||||
}
|
||||
/// Store 的载荷下转型接口,不是语言名义类型判断。
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
/// 错误/诊断载荷类别。
|
||||
fn kind_name(&self) -> &'static str {
|
||||
"trait"
|
||||
}
|
||||
/// Store 显示能力名称,不执行方法或展开签名。
|
||||
fn repr(&self, _: ObjectRef) -> Result<String, VmError> {
|
||||
Ok(format!("<trait {}>", self.name))
|
||||
}
|
||||
}
|
||||
|
||||
impl ObjectStore {
|
||||
/// VM/宿主创建只约束方法存在与参数数量的能力,返回一份外部根。
|
||||
pub fn new_trait(
|
||||
&mut self,
|
||||
name: impl Into<String>,
|
||||
requirements: Vec<MethodRequirement>,
|
||||
) -> Result<ObjectRef, VmError> {
|
||||
// 持有能力名称,禁止空名称但不把名称作为名义身份。
|
||||
let name = name.into();
|
||||
// 只约束列表内部去重,避免重复方法要求。
|
||||
let mut names = std::collections::BTreeSet::new();
|
||||
// 能力名称必须非空。
|
||||
if name.is_empty() {
|
||||
return Err(VmError::InvalidArgument("trait name must not be empty"));
|
||||
}
|
||||
// 最小能力要求不含 self,usize::MAX 无法再加 self,提前拒绝。
|
||||
for requirement in &requirements {
|
||||
// 拒绝空/保留名、无法加接收者的数量与重复要求。
|
||||
if requirement.name.is_empty()
|
||||
|| requirement.name == "type"
|
||||
|| requirement.parameters == usize::MAX
|
||||
@@ -854,20 +929,28 @@ impl ObjectStore {
|
||||
})
|
||||
}
|
||||
|
||||
/// VM/宿主创建显式参数/返回/效果能力,要求含 self 的固定规范签名。
|
||||
pub fn new_typed_trait(
|
||||
&mut self,
|
||||
name: impl Into<String>,
|
||||
methods: Vec<TypedMethodRequirement>,
|
||||
) -> Result<ObjectRef, VmError> {
|
||||
// 持有能力名称,禁止空名称但不把名称作为名义身份。
|
||||
let name = name.into();
|
||||
// 能力名称必须非空。
|
||||
if name.is_empty() {
|
||||
return Err(VmError::InvalidArgument("trait name must not be empty"));
|
||||
}
|
||||
// 完整方法签名按名保存,同时派生兼容的最小参数要求。
|
||||
let mut signatures = BTreeMap::new();
|
||||
// 每份规范完整签名生成一个不含 self 的参数数量要求。
|
||||
let mut requirements = Vec::new();
|
||||
// 全部元数据验证完后才分配能力,失败不产生半成品。
|
||||
for method in methods {
|
||||
method.signature.validate(self)?;
|
||||
// 类型化能力使用固定且至少含一接收者的规范签名,不接受可选接收者。
|
||||
let arity = method.signature.arity;
|
||||
// 数量必须 required==maximum 且有限,方法名也不能重复或占用 type。
|
||||
if method.name.is_empty()
|
||||
|| method.name == "type"
|
||||
|| arity.required == 0
|
||||
|
||||
Reference in New Issue
Block a user