Add typed trait requirements and enforce actual capability results
This commit is contained in:
@@ -4,16 +4,16 @@
|
||||
|
||||
| 文件 | 职责 |
|
||||
| --- | --- |
|
||||
| [lib.rs](lib.rs) | 包边界、对象类型/ObjectStore 公开导出(含Trait/MethodRequirement/SourceSignature/AnnotationType/CallArity/CallSignature/CallType/CallEffect/ReadAccess)与独立存储 rustdoc 示例 |
|
||||
| [lib.rs](lib.rs) | 包边界、对象类型/ObjectStore 公开导出(含Trait/MethodRequirement/TypedMethodRequirement/SourceSignature/AnnotationType/CallArity/CallSignature/CallType/CallEffect/ReadAccess)与独立存储 rustdoc 示例 |
|
||||
| [object.rs](object.rs) | Value、CompareOp、ObjectPayload(含显式函数标记)、ObjectHeader、EndorObject、Record、可发布数量元数据的 NativeFunction |
|
||||
| [types.rs](types.rs) | 托管名义类型、显式 Object/Type 引导、继承查询、受管方法表/接收者绑定、类字段、显式Trait定义/声明/方法参数约束、原生构造委托、统一源码/原生/绑定方法参数区间查询与能力验证、声明环境托管边、字段构造/写入检查与标记为校验读取的注解解析/匹配 |
|
||||
| [contracts.rs](contracts.rs) | 方法参数逆变/返回协变、名义/能力/联合包含关系、祖先方法更新的后代检查、动态注解调用前复查 |
|
||||
| [types.rs](types.rs) | 托管名义类型、显式 Object/Type 引导、继承查询、受管方法表/接收者绑定、类字段、显式/类型化Trait定义、强类型签名边与声明约束、原生构造委托、统一源码/原生/绑定方法参数区间查询与能力验证、声明环境托管边、字段构造/写入检查与标记为校验读取的注解解析/匹配 |
|
||||
| [contracts.rs](contracts.rs) | 方法参数逆变/返回协变、名义/能力/联合包含关系、祖先方法更新的后代检查、动态注解调用前复查、类型化能力替换/返回约束与临时递归验证集合 |
|
||||
| [native.rs](native.rs) | NativeContext、CallArity/CallSignature 类型与效果元数据、调用前检查、签名类型强边、上下文原生函数、作用域语言函数工厂、显式能力声明入口、函数标记、根与非递归委托调用 |
|
||||
| [changes.rs](changes.rs) | 合并变更批次、变更键与有界通知额度 |
|
||||
| [number.rs](number.rs) | Integer/Decimal/Rational/BinaryFloat/Complex 的无损表示和装箱载荷 |
|
||||
| [builtins.rs](builtins.rs) | String、Dict、Cell、Function、BaseException 载荷与 trace 边、语言函数标记 |
|
||||
| [heap.rs](heap.rs) | 私有 Heap、不可伪造 ObjectRef、稳定 Box、引用事务、迭代释放、循环回收、后代契约更新的私有借用枚举、同类型附加幂等、只读变更屏障/全调用及嵌套子调用读取跟踪(区分注解校验与内容读取)及私有边界测试 |
|
||||
| [store.rs](store.rs) | ObjectStore、空堆创建、字段检查配置/属性写入屏障、详细读取区域结果、对象操作、retain/release 和回收入口、弱 Function 类型配置与分配分类 |
|
||||
| [store.rs](store.rs) | ObjectStore、空堆创建、字段检查配置/属性写入屏障、详细读取区域结果、逐线程临时能力检查集合、对象操作、retain/release 和回收入口、弱 Function 类型配置与分配分类 |
|
||||
| [store_builtins.rs](store_builtins.rs) | 载荷校验、代码/函数工厂、Dict/Cell 操作及键语义 |
|
||||
| [instruction.rs](instruction.rs) | Opcode、Instruction、wordcode 编解码、MakeFunction/比较参数与跳转读取接口 |
|
||||
| [code.rs](code.rs) | CodeLayout、EndorCode/EndorCodeObject、可选源码签名、共享不可变代码和操作数/控制流/栈验证 |
|
||||
|
||||
+223
-58
@@ -36,6 +36,26 @@ struct Patch<'a> {
|
||||
function: ObjectRef,
|
||||
}
|
||||
|
||||
struct TraitCheckGuard<'a> {
|
||||
store: &'a ObjectStore,
|
||||
thread: std::thread::ThreadId,
|
||||
key: (ObjectRef, ObjectRef),
|
||||
}
|
||||
impl Drop for TraitCheckGuard<'_> {
|
||||
fn drop(&mut self) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CallType {
|
||||
/// Whether every value admitted by provided is admitted by self.
|
||||
/// Nominal inheritance and explicit capabilities participate; no structural
|
||||
@@ -70,6 +90,31 @@ impl CallType {
|
||||
}
|
||||
|
||||
impl ObjectStore {
|
||||
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()
|
||||
.expect("trait checker poisoned")
|
||||
.entry(thread)
|
||||
.or_default()
|
||||
.insert(key)
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
let _guard = TraitCheckGuard {
|
||||
store: self,
|
||||
thread,
|
||||
key,
|
||||
};
|
||||
check()
|
||||
}
|
||||
fn method_contract(
|
||||
&self,
|
||||
function: ObjectRef,
|
||||
@@ -182,59 +227,7 @@ impl ObjectStore {
|
||||
let derived = self
|
||||
.method_contract(function, owner)?
|
||||
.ok_or_else(|| invalid("override lacks type metadata"))?;
|
||||
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"))?
|
||||
.accepts_type(self, &receiver)?
|
||||
{
|
||||
return Err(invalid("override receiver rejects its declaring 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"))?;
|
||||
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"))?;
|
||||
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) {
|
||||
let compatible = match expected {
|
||||
CallEffect::ReadOnly => actual == CallEffect::ReadOnly,
|
||||
CallEffect::Mutating => actual != CallEffect::External,
|
||||
CallEffect::External => true,
|
||||
};
|
||||
if !compatible {
|
||||
return Err(invalid("override expands native effects"));
|
||||
}
|
||||
}
|
||||
self.check_substitution(owner, &derived, &base, invalid)?;
|
||||
Ok(())
|
||||
})();
|
||||
match checked {
|
||||
@@ -242,6 +235,104 @@ impl ObjectStore {
|
||||
result => result,
|
||||
}
|
||||
}
|
||||
fn check_substitution(
|
||||
&self,
|
||||
owner: ObjectRef,
|
||||
derived: &Contract,
|
||||
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"))?
|
||||
.accepts_type(self, &receiver)?
|
||||
{
|
||||
return Err(invalid("override receiver rejects its declaring type"));
|
||||
}
|
||||
if !base
|
||||
.parameter(0)
|
||||
.ok_or_else(|| invalid("required signature lacks receiver"))?
|
||||
.accepts_type(self, &receiver)?
|
||||
{
|
||||
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"))?;
|
||||
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"))?;
|
||||
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) {
|
||||
let compatible = match expected {
|
||||
CallEffect::ReadOnly => actual == CallEffect::ReadOnly,
|
||||
CallEffect::Mutating => actual != CallEffect::External,
|
||||
CallEffect::External => true,
|
||||
};
|
||||
if !compatible {
|
||||
return Err(invalid("override expands native effects"));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub(super) fn validate_typed_requirement(
|
||||
&self,
|
||||
definition: ObjectRef,
|
||||
capability: ObjectRef,
|
||||
name: &str,
|
||||
function: ObjectRef,
|
||||
expected: &CallSignature,
|
||||
defer_unknown: bool,
|
||||
) -> Result<(), VmError> {
|
||||
let invalid = |reason| VmError::TraitViolation {
|
||||
capability: self
|
||||
.payload::<super::EndorTraitObject>(capability, "Trait")
|
||||
.expect("checked trait")
|
||||
.name
|
||||
.clone(),
|
||||
method: name.into(),
|
||||
reason,
|
||||
};
|
||||
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)
|
||||
})();
|
||||
match checked {
|
||||
Err(VmError::UnknownAnnotation(_)) if defer_unknown => Ok(()),
|
||||
result => result,
|
||||
}
|
||||
}
|
||||
pub(super) fn validate_class_overrides(&self, definition: ObjectRef) -> Result<(), VmError> {
|
||||
if self.field_type_checks {
|
||||
for (name, function) in &self.payload::<EndorTypeObject>(definition, "Type")?.methods {
|
||||
@@ -270,23 +361,97 @@ impl ObjectStore {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
/// Revalidate dynamic annotation names before a source method body executes.
|
||||
/// Ordinary functions whose first argument is an object are not methods.
|
||||
/// Explicit override validation, including any typed capabilities.
|
||||
pub fn check_method_override_call(
|
||||
&self,
|
||||
function: ObjectRef,
|
||||
receiver: ObjectRef,
|
||||
) -> Result<(), VmError> {
|
||||
let mut owner = self.type_of(receiver)?;
|
||||
self.check_method_contract_call(function, receiver, true)
|
||||
.map(|_| ())
|
||||
}
|
||||
/// Typed capabilities are explicit opt-ins and always checked. Ordinary
|
||||
/// override checking remains configurable by the VM's source-check flag.
|
||||
pub fn check_method_contract_call(
|
||||
&self,
|
||||
function: ObjectRef,
|
||||
receiver: ObjectRef,
|
||||
overrides: bool,
|
||||
) -> Result<bool, VmError> {
|
||||
let mut typed = false;
|
||||
let actual = self.type_of(receiver)?;
|
||||
let mut owner = actual;
|
||||
while let Some(definition) = owner {
|
||||
let data = self.payload::<EndorTypeObject>(definition, "Type")?;
|
||||
for (name, candidate) in &data.methods {
|
||||
if *candidate == function {
|
||||
if *candidate != function {
|
||||
continue;
|
||||
}
|
||||
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)
|
||||
{
|
||||
actual.unwrap()
|
||||
} else {
|
||||
definition
|
||||
};
|
||||
for capability in self.inherited_traits(effective)? {
|
||||
if let Some(expected) = self
|
||||
.payload::<super::EndorTraitObject>(capability, "Trait")?
|
||||
.signatures
|
||||
.get(name)
|
||||
{
|
||||
typed = true;
|
||||
self.validate_typed_requirement(
|
||||
effective, capability, name, function, expected, false,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
owner = data.base;
|
||||
}
|
||||
Ok(())
|
||||
Ok(typed)
|
||||
}
|
||||
|
||||
/// Borrowed expected results for all typed capabilities of this effective
|
||||
/// method. The evaluator retains definitions before entering the body.
|
||||
pub fn method_trait_returns(
|
||||
&self,
|
||||
function: ObjectRef,
|
||||
receiver: ObjectRef,
|
||||
) -> Result<Vec<(String, CallType)>, VmError> {
|
||||
let actual = self.type_of(receiver)?;
|
||||
let mut owner = actual;
|
||||
let mut returns = Vec::new();
|
||||
while let Some(definition) = owner {
|
||||
let data = self.payload::<EndorTypeObject>(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)
|
||||
{
|
||||
actual.unwrap()
|
||||
} else {
|
||||
definition
|
||||
};
|
||||
for capability in self.inherited_traits(effective)? {
|
||||
let contract = self.payload::<super::EndorTraitObject>(capability, "Trait")?;
|
||||
if let Some(expected) = contract.signatures.get(name) {
|
||||
returns.push((
|
||||
format!("{}.{}", contract.name, name),
|
||||
expected.returns.clone(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
owner = data.base;
|
||||
}
|
||||
Ok(returns)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,5 +49,5 @@ pub use object::{
|
||||
pub use store::ObjectStore;
|
||||
pub use types::{
|
||||
AnnotationType, ClassField, EndorTraitObject, EndorTypeObject, MethodRequirement, RootTypes,
|
||||
TypeConstructor,
|
||||
TypeConstructor, TypedMethodRequirement,
|
||||
};
|
||||
|
||||
@@ -375,6 +375,12 @@ impl<'a> NativeContext<'a> {
|
||||
if let Some(signature) = &signature {
|
||||
signature.check_arguments(store, &name, arguments)?;
|
||||
}
|
||||
let trait_returns = if let Some(Value::Object(receiver)) = arguments.first() {
|
||||
store.check_method_contract_call(function, *receiver, false)?;
|
||||
store.method_trait_returns(function, *receiver)?
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
let mut context = Self {
|
||||
store,
|
||||
roots: Vec::new(),
|
||||
@@ -386,6 +392,11 @@ impl<'a> NativeContext<'a> {
|
||||
context.protect(&Value::Object(reference))?;
|
||||
}
|
||||
}
|
||||
for (_, expected) in &trait_returns {
|
||||
for reference in expected.references() {
|
||||
context.protect(&Value::Object(reference))?;
|
||||
}
|
||||
}
|
||||
for argument in arguments {
|
||||
context.protect(argument)?;
|
||||
}
|
||||
@@ -393,6 +404,11 @@ impl<'a> NativeContext<'a> {
|
||||
if let (Some(signature), NativeResult::Return(value)) = (&signature, &result) {
|
||||
signature.check_return(context.store(), &name, value)?;
|
||||
}
|
||||
if let NativeResult::Return(value) = &result {
|
||||
for (name, expected) in &trait_returns {
|
||||
expected.check(context.store(), name, "return".into(), value)?;
|
||||
}
|
||||
}
|
||||
let transferred_from = context.roots.len();
|
||||
match &result {
|
||||
NativeResult::Return(value) => context.protect(value)?,
|
||||
|
||||
@@ -12,6 +12,12 @@ pub struct ObjectStore {
|
||||
pub(crate) heap: Heap,
|
||||
function_type: Option<WeakObjectRef>,
|
||||
pub(crate) field_type_checks: bool,
|
||||
pub(crate) active_trait_checks: std::sync::Mutex<
|
||||
std::collections::HashMap<
|
||||
std::thread::ThreadId,
|
||||
std::collections::BTreeSet<(ObjectRef, ObjectRef)>,
|
||||
>,
|
||||
>,
|
||||
}
|
||||
|
||||
impl ObjectStore {
|
||||
@@ -151,6 +157,7 @@ impl ObjectStore {
|
||||
heap: Heap::new()?,
|
||||
function_type: None,
|
||||
field_type_checks: false,
|
||||
active_trait_checks: std::sync::Mutex::new(std::collections::HashMap::new()),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
+104
-14
@@ -634,16 +634,23 @@ impl NativeCallable for CallBoundMethod {
|
||||
}
|
||||
|
||||
/// Minimal explicit capability contract. Arity excludes the bound receiver.
|
||||
/// Parameter/return types, default implementations and syntax are host concerns.
|
||||
/// Use TypedMethodRequirement for parameter/return/effect contracts.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct MethodRequirement {
|
||||
pub name: String,
|
||||
pub parameters: usize,
|
||||
}
|
||||
/// Typed capability requirement, including the explicit receiver slot.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TypedMethodRequirement {
|
||||
pub name: String,
|
||||
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 {
|
||||
@@ -652,8 +659,18 @@ impl EndorTraitObject {
|
||||
pub fn requirements(&self) -> &[MethodRequirement] {
|
||||
&self.requirements
|
||||
}
|
||||
pub fn signature(&self, name: &str) -> Option<&crate::CallSignature> {
|
||||
self.signatures.get(name)
|
||||
}
|
||||
}
|
||||
impl ObjectPayload for EndorTraitObject {
|
||||
fn trace(&self, visit: &mut dyn FnMut(ObjectRef)) {
|
||||
for signature in self.signatures.values() {
|
||||
for reference in signature.references() {
|
||||
visit(reference);
|
||||
}
|
||||
}
|
||||
}
|
||||
fn reference_assignment_only(&self) -> bool {
|
||||
true
|
||||
}
|
||||
@@ -690,7 +707,49 @@ impl ObjectStore {
|
||||
));
|
||||
}
|
||||
}
|
||||
self.allocate(EndorTraitObject { name, requirements })
|
||||
self.allocate(EndorTraitObject {
|
||||
name,
|
||||
requirements,
|
||||
signatures: BTreeMap::new(),
|
||||
})
|
||||
}
|
||||
|
||||
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();
|
||||
let mut requirements = Vec::new();
|
||||
for method in methods {
|
||||
method.signature.validate(self)?;
|
||||
let arity = method.signature.arity;
|
||||
if method.name.is_empty()
|
||||
|| method.name == "type"
|
||||
|| arity.required == 0
|
||||
|| arity.required != arity.maximum
|
||||
|| arity.maximum == usize::MAX
|
||||
|| signatures.contains_key(&method.name)
|
||||
{
|
||||
return Err(VmError::InvalidArgument(
|
||||
"invalid typed trait canonical signature",
|
||||
));
|
||||
}
|
||||
requirements.push(MethodRequirement {
|
||||
name: method.name.clone(),
|
||||
parameters: arity.maximum - 1,
|
||||
});
|
||||
signatures.insert(method.name, method.signature);
|
||||
}
|
||||
self.allocate(EndorTraitObject {
|
||||
name,
|
||||
requirements,
|
||||
signatures,
|
||||
})
|
||||
}
|
||||
|
||||
fn inherited_traits(&self, definition: ObjectRef) -> Result<Vec<ObjectRef>, VmError> {
|
||||
@@ -708,6 +767,8 @@ impl ObjectStore {
|
||||
capability: ObjectRef,
|
||||
requirement: &MethodRequirement,
|
||||
function: Option<ObjectRef>,
|
||||
definition: ObjectRef,
|
||||
defer_unknown: bool,
|
||||
) -> Result<(), VmError> {
|
||||
let invalid = |reason| VmError::TraitViolation {
|
||||
capability: self
|
||||
@@ -727,22 +788,45 @@ impl ObjectStore {
|
||||
"positional parameter count does not match (including self)",
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn validate_trait(&self, definition: ObjectRef, capability: ObjectRef) -> Result<(), VmError> {
|
||||
let contract = self.payload::<EndorTraitObject>(capability, "Trait")?;
|
||||
for requirement in &contract.requirements {
|
||||
self.validate_requirement(
|
||||
if let Some(expected) = self
|
||||
.payload::<EndorTraitObject>(capability, "Trait")?
|
||||
.signatures
|
||||
.get(&requirement.name)
|
||||
{
|
||||
self.validate_typed_requirement(
|
||||
definition,
|
||||
capability,
|
||||
requirement,
|
||||
self.lookup_method(definition, &requirement.name)?,
|
||||
&requirement.name,
|
||||
function,
|
||||
expected,
|
||||
defer_unknown,
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn validate_trait(
|
||||
&self,
|
||||
definition: ObjectRef,
|
||||
capability: ObjectRef,
|
||||
defer_unknown: bool,
|
||||
) -> Result<(), VmError> {
|
||||
self.with_trait_check(definition, capability, || {
|
||||
let contract = self.payload::<EndorTraitObject>(capability, "Trait")?;
|
||||
for requirement in &contract.requirements {
|
||||
self.validate_requirement(
|
||||
capability,
|
||||
requirement,
|
||||
self.lookup_method(definition, &requirement.name)?,
|
||||
definition,
|
||||
defer_unknown,
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
fn validate_inherited_traits(&self, definition: ObjectRef) -> Result<(), VmError> {
|
||||
for capability in self.inherited_traits(definition)? {
|
||||
self.validate_trait(definition, capability)?;
|
||||
self.validate_trait(definition, capability, true)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -793,7 +877,13 @@ impl ObjectStore {
|
||||
.requirements
|
||||
{
|
||||
if requirement.name == name {
|
||||
self.validate_requirement(capability, requirement, Some(function))?;
|
||||
self.validate_requirement(
|
||||
capability,
|
||||
requirement,
|
||||
Some(function),
|
||||
descendant,
|
||||
true,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -807,7 +897,7 @@ impl ObjectStore {
|
||||
) -> Result<(), VmError> {
|
||||
self.payload::<EndorTraitObject>(capability, "Trait")?;
|
||||
for descendant in self.descendant_types(definition)? {
|
||||
self.validate_trait(descendant, capability)?;
|
||||
self.validate_trait(descendant, capability, false)?;
|
||||
}
|
||||
let mut updated = self.payload::<EndorTypeObject>(definition, "Type")?.clone();
|
||||
if !updated.traits.contains(&capability) {
|
||||
@@ -824,7 +914,7 @@ impl ObjectStore {
|
||||
self.payload::<EndorTraitObject>(capability, "Trait")?;
|
||||
let declared = self.inherited_traits(definition)?.contains(&capability);
|
||||
if declared {
|
||||
self.validate_trait(definition, capability)?;
|
||||
self.validate_trait(definition, capability, false)?;
|
||||
}
|
||||
Ok(declared)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user