docs: 补全 Aster 中文调用链、控制流与生命周期注释 #3
@@ -148,8 +148,10 @@ fn dictionaries_keep_order_and_first_key_and_own_keys_and_values() {
|
||||
);
|
||||
assert_eq!(vm.dict_items(dict).unwrap()[0].0, Value::Object(key));
|
||||
assert_eq!(vm.dict_items(dict).unwrap().len(), 2);
|
||||
// 字典覆盖旧值后,old 已无任何拥有根,访问必须报告失效句柄。
|
||||
assert!(matches!(vm.object(old), Err(VmError::InvalidHandle)));
|
||||
assert!(vm.dict_delete(dict, &text("answer")).unwrap());
|
||||
// 删除 answer 同时释放保留的首键对象,等价 Text 键不会替它延长寿命。
|
||||
assert!(matches!(vm.object(key), Err(VmError::InvalidHandle)));
|
||||
assert!(!vm.dict_delete(dict, &text("missing")).unwrap());
|
||||
vm.dict_clear(dict).unwrap();
|
||||
@@ -227,6 +229,7 @@ fn cells_share_rebinding_distinguish_empty_and_none_and_keep_stable_objects() {
|
||||
vm.cell_set(cell, Value::Object(child)).unwrap();
|
||||
assert_eq!(vm.ref_count(child).unwrap(), 1);
|
||||
vm.cell_clear(cell).unwrap();
|
||||
// 清空 Cell 归还子对象最后的内部边,child 不能仍然可访问。
|
||||
assert!(matches!(vm.object(child), Err(VmError::InvalidHandle)));
|
||||
assert_eq!(vm.cell_get(cell), Err(VmError::EmptyCell));
|
||||
}
|
||||
|
||||
@@ -237,6 +237,7 @@ fn malformed_wordcode_and_unaligned_jumps_are_rejected_at_construction() {
|
||||
vec![255, 1, 255, 1, 255, 1, 255, 1, 1, 0],
|
||||
vec![13, 1],
|
||||
] {
|
||||
// 每份非法物理编码都必须在代码构造阶段拒绝,不能等到 VM 取指才失败。
|
||||
assert!(matches!(
|
||||
EndorCode::new(bytes, vec![Value::Nil], vec![], vec![]),
|
||||
Err(VmError::InvalidBytecode { .. })
|
||||
@@ -482,6 +483,7 @@ fn argument_count_and_foreign_argument_failures_do_not_retain_inputs() {
|
||||
let function = vm
|
||||
.new_function("identity", code, globals, vec![], vec![])
|
||||
.unwrap();
|
||||
// 无实参调用必须准确报告缺少唯一必需参数,不把缺参隐式当作 Nil。
|
||||
assert!(matches!(
|
||||
vm.call(function, &[]),
|
||||
Err(VmError::ArgumentCount {
|
||||
@@ -490,6 +492,7 @@ fn argument_count_and_foreign_argument_failures_do_not_retain_inputs() {
|
||||
..
|
||||
})
|
||||
));
|
||||
// 两个实参超过该函数的最大数量一,预检应在进入函数体前拒绝。
|
||||
assert!(matches!(
|
||||
vm.call(function, &[Value::Nil, Value::Nil]),
|
||||
Err(VmError::ArgumentCount {
|
||||
@@ -1011,6 +1014,7 @@ fn unbound_names_deleted_locals_and_invalid_null_values_fail_cleanly() {
|
||||
vec![],
|
||||
CodeLayout::default(),
|
||||
);
|
||||
// Null 是 VM 协议哨兵而非语言值,源码执行把它用于非法值路径时必须拒绝。
|
||||
assert!(matches!(
|
||||
vm.execute(null, globals),
|
||||
Err(VmError::InvalidBytecode { .. })
|
||||
@@ -1699,6 +1703,7 @@ fn suspended_read_only_call_keeps_roots_and_releases_them_on_completion() {
|
||||
1,
|
||||
)
|
||||
.unwrap();
|
||||
// 首量子只消耗一条 Nop,应保存暂停帧并报告累计一条,不能提前完成。
|
||||
assert!(matches!(
|
||||
progress,
|
||||
ExecutionProgress::Pending { instructions: 1 }
|
||||
@@ -1852,13 +1857,13 @@ fn managed_coroutines_interleave_without_replaying_writes() {
|
||||
let second = vm
|
||||
.new_coroutine(function, &[], ExecutionLimits::default())
|
||||
.unwrap();
|
||||
// 推进第一份到首次 StoreGlobal 之后,累计两条指令。
|
||||
assert!(matches!(
|
||||
// 推进第一份到首次 StoreGlobal 之后,累计两条指令。
|
||||
vm.resume_coroutine(first, 2).unwrap(),
|
||||
CoroutineProgress::Pending { instructions: 2 }
|
||||
));
|
||||
// 第二份也停在首次写入之后,后续都不应重放这个前缀。
|
||||
assert!(matches!(
|
||||
// 第二份也停在首次写入之后,后续都不应重放这个前缀。
|
||||
vm.resume_coroutine(second, 2).unwrap(),
|
||||
CoroutineProgress::Pending { instructions: 2 }
|
||||
));
|
||||
@@ -1965,13 +1970,13 @@ fn managed_coroutine_hard_budget_accumulates_and_error_releases_frames() {
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
// 首量子只执行 Nop 并停放,累计已用一条。
|
||||
assert!(matches!(
|
||||
// 首量子只执行 Nop 并停放,累计已用一条。
|
||||
vm.resume_coroutine(coroutine, 1).unwrap(),
|
||||
CoroutineProgress::Pending { instructions: 1 }
|
||||
));
|
||||
// 第二次执行 LoadConst 后预算耗尽,尚未 Return,因此应终止而非再次 Pending。
|
||||
assert!(matches!(
|
||||
// 第二次执行 LoadConst 后预算耗尽,尚未 Return,因此应终止而非再次 Pending。
|
||||
vm.resume_coroutine(coroutine, 1),
|
||||
Err(VmError::ExecutionLimit("instructions"))
|
||||
));
|
||||
|
||||
@@ -106,6 +106,7 @@ fn source_parameters_are_contravariant_and_returns_covariant_at_class_creation()
|
||||
"Number",
|
||||
Value::Nil,
|
||||
);
|
||||
// 子方法缩窄参数可接受范围会破坏替换关系,必须在建类时报告覆盖违规。
|
||||
assert!(matches!(
|
||||
class(&mut vm, "Narrow", base, narrow),
|
||||
Err(VmError::OverrideViolation {
|
||||
@@ -133,6 +134,7 @@ fn source_parameters_are_contravariant_and_returns_covariant_at_class_creation()
|
||||
"Object",
|
||||
Value::Nil,
|
||||
);
|
||||
// 子方法放宽返回类型会破坏父方法承诺,必须在建类时拒绝。
|
||||
assert!(matches!(
|
||||
class(&mut vm, "Broad", numeric_type, broad),
|
||||
Err(VmError::OverrideViolation {
|
||||
@@ -305,6 +307,7 @@ fn global_rebinding_is_rechecked_before_the_source_body_and_recovers() {
|
||||
vm.attach_type(receiver, child).unwrap();
|
||||
vm.dict_set(globals, Value::Text("Actual".into()), Value::Object(other))
|
||||
.unwrap();
|
||||
// Actual 的全局类型绑定变化后,调用前重新检查覆盖关系,失败时不能运行方法体。
|
||||
assert!(matches!(
|
||||
vm.call(child_fn, &[Value::Object(receiver)]),
|
||||
Err(VmError::OverrideViolation { .. })
|
||||
@@ -404,6 +407,7 @@ fn native_overrides_preserve_union_inputs_and_do_not_expand_effects() {
|
||||
vec![],
|
||||
))
|
||||
.unwrap();
|
||||
// 只读父方法不能被已知有写效果的子方法替换,更新必须在提交前失败。
|
||||
assert!(matches!(
|
||||
vm.define_method(child, "check", effect_fn),
|
||||
Err(VmError::OverrideViolation {
|
||||
@@ -423,6 +427,7 @@ fn native_overrides_preserve_union_inputs_and_do_not_expand_effects() {
|
||||
vec![],
|
||||
))
|
||||
.unwrap();
|
||||
// 子方法仅接受 Number 会丢失父联合参数的 String 候选,不能缩窄父方法可接受的输入。
|
||||
assert!(matches!(
|
||||
vm.define_method(child, "check", narrow_fn),
|
||||
Err(VmError::OverrideViolation {
|
||||
@@ -498,6 +503,7 @@ fn unknown_forward_names_defer_until_call_without_entering_the_body() {
|
||||
.unwrap();
|
||||
vm.dict_set(globals, Value::Text("Later".into()), Value::Object(later))
|
||||
.unwrap();
|
||||
// Later 从未知名解析成不兼容名义类型后,错误应转为覆盖违规且仍在方法体前发生。
|
||||
assert!(matches!(
|
||||
vm.call(
|
||||
child_fn,
|
||||
|
||||
@@ -442,10 +442,12 @@ fn native_types_preflight_arguments_and_clean_wrong_result_roots() {
|
||||
))
|
||||
.unwrap();
|
||||
assert!(
|
||||
// 错误实参在回调前由 parameter 1 约束拒绝,后面的计数零验证未进入宿主代码。
|
||||
matches!(vm.call(function, &[Value::Text("bad".into())]), Err(VmError::TypeMismatch { position, .. }) if position == "parameter 1")
|
||||
);
|
||||
assert_eq!(calls.load(Ordering::SeqCst), 0);
|
||||
assert!(
|
||||
// 合法数值允许回调执行一次,但宿主返回值违约应明确定位 return。
|
||||
matches!(vm.call(function, &[Value::Number(7.into())]), Err(VmError::TypeMismatch { position, .. }) if position == "return")
|
||||
);
|
||||
assert_eq!(calls.load(Ordering::SeqCst), 1);
|
||||
@@ -519,8 +521,10 @@ fn delegated_source_results_obey_every_native_contract_without_extra_frames() {
|
||||
Value::Text("source result".into())
|
||||
);
|
||||
assert!(
|
||||
// 多层原生委托结果返回外层时,仍需兑现 outer 自己的返回约束并标明其名称。
|
||||
matches!(vm.call_with_limits(outer, &[], limits), Err(VmError::TypeMismatch { function, position, .. }) if function == "outer" && position == "return")
|
||||
);
|
||||
// 零源码帧预算必须由受委托源码入口拒绝,不能因原生委托不占帧而绕过限制。
|
||||
assert!(matches!(
|
||||
vm.call_with_limits(
|
||||
outer,
|
||||
@@ -656,7 +660,7 @@ fn legacy_native_signatures_check_optional_variadic_types_and_metadata() {
|
||||
}
|
||||
// 独立堆隔离当前签名/效果场景,计数与拥有根不会跨测试污染。
|
||||
let mut vm = Vm::new().unwrap();
|
||||
// 分配上下文载荷,签名类型与显式 captures 各自通过 trace 保活。
|
||||
// 分配旧式 NativeFunction 载荷,签名引用的类型定义仍通过 trace 保活。
|
||||
let function = vm
|
||||
.allocate(
|
||||
NativeFunction::new("legacy", echo).with_signature(CallSignature {
|
||||
@@ -678,6 +682,7 @@ fn legacy_native_signatures_check_optional_variadic_types_and_metadata() {
|
||||
);
|
||||
assert!(vm.call(function, &[Value::Bool(true)]).is_err());
|
||||
assert!(
|
||||
// 可变参数允许空列表,但旧式 echo 此时返回 Nil,不符合声明的 Number 返回约束。
|
||||
matches!(vm.call(function, &[]), Err(VmError::TypeMismatch { position, .. }) if position == "return")
|
||||
);
|
||||
// 故意同时配置互相矛盾的签名和独立 arity,查询/调用都应报元数据错误。
|
||||
@@ -835,6 +840,7 @@ fn native_union_and_nullable_contracts_accept_each_branch_and_reject_invalid_met
|
||||
);
|
||||
}
|
||||
assert!(
|
||||
// 联合都不匹配时诊断需完整保留 String | Bool 候选,不只显示最后尝试的一项。
|
||||
matches!(vm.call(function, &[Value::Number(3.into())]), Err(VmError::TypeMismatch { expected, .. }) if expected == "String | Bool")
|
||||
);
|
||||
assert_eq!(calls.load(Ordering::SeqCst), 3);
|
||||
|
||||
@@ -164,6 +164,7 @@ fn explicit_references_control_lifetime_and_copies_are_borrowed() {
|
||||
vm.release(owned).unwrap();
|
||||
assert_eq!(drops.load(Ordering::SeqCst), 1);
|
||||
assert_eq!(vm.object_count(), 0);
|
||||
// 最后拥有根释放后,复制来的借用句柄必须失效,不能当作额外拥有根。
|
||||
assert!(matches!(vm.object(borrowed), Err(VmError::InvalidHandle)));
|
||||
assert_eq!(vm.release(borrowed), Err(VmError::InvalidHandle));
|
||||
}
|
||||
@@ -210,6 +211,7 @@ fn replacing_the_same_edge_does_not_destroy_the_target() {
|
||||
assert_eq!(vm.ref_count(target).unwrap(), 1);
|
||||
vm.set_attr(owner, "child", Value::Number(7_i64.into()))
|
||||
.unwrap();
|
||||
// 属性从对象改为数值会归还原目标最后的边,因此旧 target 句柄应失效。
|
||||
assert!(matches!(vm.object(target), Err(VmError::InvalidHandle)));
|
||||
assert_eq!(
|
||||
vm.get_attr(owner, "child").unwrap(),
|
||||
@@ -350,7 +352,9 @@ fn cycles_remain_while_rooted_and_are_collected_when_unreachable() {
|
||||
assert_eq!(vm.collect_cycles(), 2);
|
||||
assert_eq!(vm.collect_cycles(), 0);
|
||||
assert_eq!(drops.load(Ordering::SeqCst), 2);
|
||||
// 无根环回收后第一个旧句柄失效,不能只依赖析构计数判断槽是否仍可访问。
|
||||
assert!(matches!(vm.object(first), Err(VmError::InvalidHandle)));
|
||||
// 同一垃圾环中的第二个对象也必须失效,避免只回收部分环。
|
||||
assert!(matches!(vm.object(second), Err(VmError::InvalidHandle)));
|
||||
}
|
||||
|
||||
|
||||
@@ -224,6 +224,7 @@ fn typed_source_methods_enforce_their_annotations_even_when_global_checks_are_of
|
||||
Some(Value::Number(0.into()))
|
||||
);
|
||||
assert!(
|
||||
// 参数合法时方法体可运行,但违背能力方法的返回约束应在出口定位 return。
|
||||
matches!(vm.call(function, &[Value::Object(receiver), Value::Number(1.into())]), Err(VmError::TypeMismatch { position, .. }) if position=="return")
|
||||
);
|
||||
assert_eq!(
|
||||
|
||||
@@ -154,6 +154,7 @@ fn explicit_traits_inherit_validate_overrides_and_own_definition_edges() {
|
||||
.new_class("Child", base, vec![], std::collections::BTreeMap::new())
|
||||
.unwrap();
|
||||
assert!(vm.implements_trait(child, capability).unwrap());
|
||||
// 祖先方法更新不得破坏已声明后代能力,失败后原方法仍应保持不变。
|
||||
assert!(matches!(
|
||||
vm.define_method(base, "render", invalid),
|
||||
Err(VmError::TraitViolation { .. })
|
||||
@@ -446,6 +447,7 @@ fn native_arity_checks_precede_effects_and_traits_require_published_signatures()
|
||||
))
|
||||
.unwrap();
|
||||
assert_eq!(vm.call_arity(native).unwrap(), Some(CallArity::range(1, 2)));
|
||||
// 零实参违反原生函数声明的 arity,必须在回调修改 called 状态之前拒绝。
|
||||
assert!(matches!(
|
||||
vm.call(native, &[]),
|
||||
Err(VmError::ArgumentCount { .. })
|
||||
|
||||
@@ -26,6 +26,7 @@ fn function_bodies_accept_method_statements_and_optional_trailing_return() {
|
||||
.body
|
||||
.statements
|
||||
.iter()
|
||||
// 两个调用都应是普通 Expression 语句,不能被误识别为返回或绑定。
|
||||
.all(|s| matches!(s.kind, StmtKind::Expression(_)))
|
||||
);
|
||||
assert!(parse_ast("function empty(): Unit {}", ParseMode::Module).is_ok());
|
||||
@@ -258,6 +259,7 @@ fn json_interfaces_reject_unknown_fields_schema_changes_and_invalid_ranges() {
|
||||
kind: ExprKind::Name("値".into()),
|
||||
span: Span::new(1, 3),
|
||||
});
|
||||
// 结构范围虽非逆序,起点切断三字节日文字符,仍须在提供原文的校验阶段失败。
|
||||
assert!(matches!(
|
||||
AstDocument::new(root).unwrap().validate_source("値"),
|
||||
Err(AstError::InvalidSpan(_))
|
||||
|
||||
@@ -291,6 +291,7 @@ fn uri_snapshots_require_a_revision_and_preserve_it_in_source_diagnostics() {
|
||||
revision: " \t",
|
||||
bytes: b"1",
|
||||
};
|
||||
// 字节有效不能补救缺版本身份,空白版本标签应单独报告 MissingRevision。
|
||||
assert!(matches!(
|
||||
EndorReader::from_endor(uri, &missing).unwrap_err().kind,
|
||||
SourceReadErrorKind::MissingRevision
|
||||
@@ -336,6 +337,7 @@ fn invalid_uris_do_not_call_the_provider_and_denials_do_not_fall_back_to_files()
|
||||
"endor:space here",
|
||||
"endor:bad\nname",
|
||||
] {
|
||||
// 每个非法定位符都必须先被基础 URI 校验拒绝,后面的计数零验证未访问宿主。
|
||||
assert!(matches!(
|
||||
EndorReader::from_endor(uri, &provider).unwrap_err().kind,
|
||||
SourceReadErrorKind::InvalidEndorUri
|
||||
|
||||
@@ -190,6 +190,7 @@ fn arithmetic_precedence_and_left_associativity_form_the_expected_tree() {
|
||||
let ExprKind::Unary { operand, .. } = nested.kind else {
|
||||
panic!("expected outer negate");
|
||||
};
|
||||
// 外层负号的操作数仍是 Negate,证明解析器保留两个前缀节点而未提前计算数值。
|
||||
assert!(matches!(
|
||||
operand.kind,
|
||||
ExprKind::Unary {
|
||||
|
||||
@@ -926,7 +926,9 @@ mod tests {
|
||||
generation: 1,
|
||||
..reference
|
||||
};
|
||||
// 槽索引越界时,即使堆身份和代际来自有效对象,也必须拒绝只读访问。
|
||||
assert!(matches!(heap.get(invalid), Err(VmError::InvalidHandle)));
|
||||
// 可变访问同样检查代际,伪造旧代际不能借出当前对象。
|
||||
assert!(matches!(heap.get_mut(stale), Err(VmError::InvalidHandle)));
|
||||
}
|
||||
|
||||
@@ -942,6 +944,7 @@ mod tests {
|
||||
let second = heap.allocate(Box::new(Record)).unwrap();
|
||||
assert_eq!(first.index, second.index);
|
||||
assert_ne!(first.generation, second.generation);
|
||||
// 复用同一槽但代际变化后,旧句柄必须失效,不能别名到新对象。
|
||||
assert!(matches!(heap.get(first), Err(VmError::InvalidHandle)));
|
||||
// 内部故障注入:把槽及对象身份同步改成最高代际,再验证释放后的永久退休。
|
||||
heap.slots[second.index].generation = u64::MAX;
|
||||
|
||||
@@ -119,6 +119,7 @@ impl CallType {
|
||||
pub fn is_any(&self) -> bool {
|
||||
self.alternatives()
|
||||
.iter()
|
||||
// 只检测是否存在 Any 候选,不据此省略联合中其他定义引用的验证或保活。
|
||||
.any(|value| matches!(value, crate::AnnotationType::Any))
|
||||
}
|
||||
/// 调用/签名检查确认联合非空,且每个托管类型/能力引用有效并有正确载荷。
|
||||
|
||||
@@ -608,8 +608,10 @@ impl EndorNumber {
|
||||
CompareOp::Eq => order == Some(Ordering::Equal),
|
||||
CompareOp::Ne => order != Some(Ordering::Equal),
|
||||
CompareOp::Lt => order == Some(Ordering::Less),
|
||||
// 小于等于仅接受已知 Less 或 Equal;NaN 造成的无序 None 不满足关系。
|
||||
CompareOp::Le => matches!(order, Some(Ordering::Less | Ordering::Equal)),
|
||||
CompareOp::Gt => order == Some(Ordering::Greater),
|
||||
// 大于等于仅接受已知 Greater 或 Equal,无序值同样返回 false。
|
||||
CompareOp::Ge => matches!(order, Some(Ordering::Greater | Ordering::Equal)),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1604,21 +1604,29 @@ impl ObjectStore {
|
||||
AnnotationType::Any => true,
|
||||
AnnotationType::Unit => matches!(value, Value::Nil),
|
||||
AnnotationType::Number => {
|
||||
// Number 同时接受直接数值;另一路只认 EndorNumberObject 载荷,不把任意名义类当数值。
|
||||
matches!(value, Value::Number(_))
|
||||
// 对象句柄已在入口验证存活,仍须下转到具体数值载荷以匹配 Number 类别。
|
||||
|| matches!(value,Value::Object(object) if self.object(*object)?.payload().as_any().is::<crate::EndorNumberObject>())
|
||||
}
|
||||
AnnotationType::String => {
|
||||
// String 同时接受直接 Text;对象表示只接受内置字符串载荷。
|
||||
matches!(value, Value::Text(_))
|
||||
// 对象必须确为 EndorStringObject,不通过 str 协议把任意对象隐式转文本。
|
||||
|| matches!(value,Value::Object(object) if self.object(*object)?.payload().as_any().is::<crate::EndorStringObject>())
|
||||
}
|
||||
// Bool 仅匹配直接布尔值,不用真值判断把其他对象归成 Bool。
|
||||
AnnotationType::Bool => matches!(value, Value::Bool(_)),
|
||||
AnnotationType::Function => {
|
||||
// Function 看载荷的函数分类标志;任意可调用 Type 不自动属于 Function。
|
||||
matches!(value,Value::Object(object) if self.object(*object)?.payload().is_function())
|
||||
}
|
||||
AnnotationType::Type => {
|
||||
// Type 要求实际类型定义载荷,不按对象名或是否可调用猜测。
|
||||
matches!(value,Value::Object(object) if self.object(*object)?.payload().as_any().is::<EndorTypeObject>())
|
||||
}
|
||||
AnnotationType::Trait => {
|
||||
// Trait 要求实际能力定义载荷,与实现某能力的普通实例不同。
|
||||
matches!(value,Value::Object(object) if self.object(*object)?.payload().as_any().is::<EndorTraitObject>())
|
||||
}
|
||||
AnnotationType::Nominal(definition) => match value {
|
||||
|
||||
@@ -210,7 +210,7 @@ fn typed_method_storage_cannot_diverge_from_class_dispatch() {
|
||||
// 能力声明失败应保持定义版本和声明集合不变。
|
||||
let version = store.change_version(class).unwrap();
|
||||
assert!(matches!(
|
||||
// 存储冲突消除后能力声明才允许提交。
|
||||
// 当前后端仍有遮蔽字段,能力声明必须在状态提交前失败。
|
||||
store.implement_trait(class, capability),
|
||||
Err(VmError::TraitViolation { .. })
|
||||
));
|
||||
@@ -236,18 +236,22 @@ fn typed_method_storage_cannot_diverge_from_class_dispatch() {
|
||||
store.supports(proxy, capability),
|
||||
Err(VmError::TraitViolation { .. })
|
||||
));
|
||||
// 后端已出现遮蔽方法的冲突字段时,即使只读属性查询也必须拒绝不合法的能力存储。
|
||||
assert!(matches!(
|
||||
store.get_attr(proxy, "check"),
|
||||
Err(VmError::TraitViolation { .. })
|
||||
));
|
||||
// 绑定方法入口不能绕过同一存储校验,不能先创建可调用绑定再放过冲突。
|
||||
assert!(matches!(
|
||||
store.bind_attr(proxy, "check"),
|
||||
Err(VmError::TraitViolation { .. })
|
||||
));
|
||||
// 直接方法契约检查也拒绝代理后端冲突,防止跳过属性查找后绕过门禁。
|
||||
assert!(matches!(
|
||||
store.check_method_contract_call(function, proxy, false),
|
||||
Err(VmError::TraitViolation { .. })
|
||||
));
|
||||
// 显式实例存储检查应给出同类能力违规,保持各调用入口的检查一致。
|
||||
assert!(matches!(
|
||||
store.check_typed_instance_storage(proxy),
|
||||
Err(VmError::TraitViolation { .. })
|
||||
@@ -289,6 +293,7 @@ fn typed_method_storage_cannot_diverge_from_class_dispatch() {
|
||||
Value::Bool(true)
|
||||
);
|
||||
assert!(store.supports(reflective, capability).unwrap());
|
||||
// 带反射检查的载荷第一次非法写入仍须拒绝,递归防护不能误跳过最外层约束。
|
||||
assert!(matches!(
|
||||
store.set_attr(reflective, "check", Value::Nil),
|
||||
Err(VmError::TraitViolation { .. })
|
||||
|
||||
@@ -42,6 +42,7 @@ fn standalone_storage_preserves_identity_validates_edges_and_collects_cycles() {
|
||||
store.release(cell).unwrap();
|
||||
assert_eq!(store.collect_cycles(), 2);
|
||||
assert_eq!(store.object_count(), 0);
|
||||
// 独立 Store 释放完拥有图后,原 Cell 借用句柄也应失效。
|
||||
assert!(matches!(store.object(cell), Err(VmError::InvalidHandle)));
|
||||
other.release(foreign).unwrap();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user