diff --git a/crates/core/src/README.md b/crates/core/src/README.md index 90ea377..f0d9deb 100644 --- a/crates/core/src/README.md +++ b/crates/core/src/README.md @@ -5,7 +5,7 @@ | 文件 | 职责 | | --- | --- | | [lib.rs](lib.rs) | VM 类型导出、objects 类型兼容重导出、宿主调用与字节码 rustdoc 示例 | -| [vm.rs](vm.rs) | Vm 拥有 ObjectStore 与错误位置记录;对象操作和宿主 new_class 注册显式委托给 objects | +| [vm.rs](vm.rs) | Vm 拥有 ObjectStore 与错误位置记录;对象操作和宿主 new_class 和显式Trait注册/关系查询显式委托给 objects | | [frame.rs](frame.rs) | EndorFrame、栈条目、执行位置元数据、ExecutionLimits | | [eval.rs](eval.rs) | execute/call、只读调用与依赖结果、参数绑定、帧切换、取指分派、MakeFunction、结果根转移与失败清理 | diff --git a/crates/core/src/eval.rs b/crates/core/src/eval.rs index 1c37112..d69857b 100644 --- a/crates/core/src/eval.rs +++ b/crates/core/src/eval.rs @@ -443,7 +443,7 @@ impl Vm { }; let fields = self .dict_items(fields)? - .into_iter() + .iter() .map(|(name, type_name)| match (name, type_name) { (Value::Text(name), Value::Text(type_name)) => Ok(crate::ClassField { name: name.clone(), @@ -454,7 +454,7 @@ impl Vm { .collect::, _>>()?; let methods = self .dict_items(methods)? - .into_iter() + .iter() .map(|(name, function)| match (name, function) { (Value::Text(name), Value::Object(function)) => Ok((name.clone(), *function)), _ => Err(VmError::ObjectKindMismatch("class method")), diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index 9d638ce..837ba3c 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -54,5 +54,7 @@ pub use objects::{ NativeResult, ObjectChange, ObjectHeader, ObjectPayload, ObjectRef, Opcode, Record, Value, VmError, WeakObjectRef, }; -pub use objects::{ClassField, EndorTypeObject, RootTypes, TypeConstructor}; +pub use objects::{ + ClassField, EndorTraitObject, EndorTypeObject, MethodRequirement, RootTypes, TypeConstructor, +}; pub use vm::Vm; diff --git a/crates/core/src/vm.rs b/crates/core/src/vm.rs index 45fa17b..8e394fd 100644 --- a/crates/core/src/vm.rs +++ b/crates/core/src/vm.rs @@ -14,6 +14,31 @@ pub struct Vm { } impl Vm { + pub fn new_trait( + &mut self, + name: impl Into, + requirements: Vec, + ) -> Result { + self.objects.new_trait(name, requirements) + } + pub fn implement_trait( + &mut self, + definition: ObjectRef, + capability: ObjectRef, + ) -> Result<(), VmError> { + self.objects.implement_trait(definition, capability) + } + pub fn implements_trait( + &self, + definition: ObjectRef, + capability: ObjectRef, + ) -> Result { + self.objects.implements_trait(definition, capability) + } + pub fn supports(&self, object: ObjectRef, capability: ObjectRef) -> Result { + self.objects.supports(object, capability) + } + pub fn define_method( &mut self, type_object: ObjectRef, diff --git a/crates/core/tests/README.md b/crates/core/tests/README.md index 4495768..14365ae 100644 --- a/crates/core/tests/README.md +++ b/crates/core/tests/README.md @@ -7,7 +7,7 @@ | [runtime.rs](runtime.rs) | 空堆启动、默认操作、引用/借用、属性原子性、稳定地址、长链/循环、原生回调、VM 销毁 | | [builtins.rs](builtins.rs) | 无损 Number、Unicode 字符串、Dict 顺序与键、Cell、函数环境/共享代码、异常数据 | | [execution.rs](execution.rs) | wordcode 与校验、控制流、参数/默认值、嵌套帧、字节码函数创建/默认值/环境捕获、闭包、返回值存活、失败清理、限额 | -| [types.rs](types.rs) | 名义身份、继承与实例关系、类型边保活/循环回收、只读类型元数据与外来句柄;仅远端执行 | +| [types.rs](types.rs) | 名义身份、继承与实例关系、类型边保活/循环回收、只读类型元数据与外来句柄、显式Trait身份/继承/参数约束及后代更新原子性;仅远端执行 | | [native_context.rs](native_context.rs) | 原生作用域根、分配失败清理、委托、只读结果分配/写入拒绝/依赖与失败恢复、弱引用过期及有界变更;仅远端执行 | 核心对象现由 objects 定义,本目录保留既有 endor_core 导入与 Vm 方法的兼容性检查。独立对象存储检查见 [objects/tests](../../objects/tests/README.md)。堆内部伪造句柄与计数溢出检查在 objects 的 src/heap.rs,公开示例由 src/lib.rs rustdoc 提供。文件职责见 [src](../src/README.md),检查方式和结果边界见 [验证](../../../docs/operations/validation.md)。本地不执行测试;存在测试文件不代表某次提交已通过。返回 [core](../README.md)。 diff --git a/crates/core/tests/types.rs b/crates/core/tests/types.rs index 4dd88fb..086572d 100644 --- a/crates/core/tests/types.rs +++ b/crates/core/tests/types.rs @@ -63,3 +63,138 @@ fn foreign_type_edges_fail_without_changing_the_target() { ); assert_eq!(second.type_of(object).unwrap(), None); } + +fn contract_method(vm: &mut Vm, parameters: usize) -> endor_core::ObjectRef { + use endor_core::{CodeLayout, EndorCode, EndorCodeObject, Instruction, Opcode}; + let names: Vec<_> = (0..parameters).map(|index| format!("arg{index}")).collect(); + let code = EndorCode::from_instructions( + &[ + Instruction::new(Opcode::LoadConst, 0), + Instruction::simple(Opcode::ReturnValue), + ], + vec![Value::Nil], + CodeLayout { + parameters: names.clone(), + locals: names, + ..CodeLayout::default() + }, + ) + .unwrap(); + let code = vm.allocate(EndorCodeObject::new(code)).unwrap(); + let globals = vm.new_dict().unwrap(); + let function = vm + .new_function("contract method", code, globals, vec![], vec![]) + .unwrap(); + vm.release(code).unwrap(); + vm.release(globals).unwrap(); + function +} + +#[test] +fn explicit_traits_inherit_validate_overrides_and_own_definition_edges() { + use endor_core::MethodRequirement; + let mut vm = Vm::new().unwrap(); + let roots = vm.bootstrap_types().unwrap(); + let base = vm + .new_type("Base", roots.object, TypeConstructor::Record) + .unwrap(); + let valid = contract_method(&mut vm, 2); + let invalid = contract_method(&mut vm, 1); + vm.define_method(base, "render", valid).unwrap(); + let capability = vm + .new_trait( + "Drawable", + vec![MethodRequirement { + name: "render".into(), + parameters: 1, + }], + ) + .unwrap(); + let same_name = vm.new_trait("Drawable", vec![]).unwrap(); + assert!(!vm.implements_trait(base, capability).unwrap()); + vm.implement_trait(base, capability).unwrap(); + assert!(!vm.implements_trait(base, same_name).unwrap()); + let child = vm + .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 { .. }) + )); + assert_eq!( + vm.object_store().lookup_method(base, "render").unwrap(), + Some(valid) + ); + assert!( + vm.new_class("Bad", base, vec![], [("render".into(), invalid)].into()) + .is_err() + ); + let Value::Object(instance) = vm.call(child, &[]).unwrap() else { + panic!("instance required"); + }; + vm.release(capability).unwrap(); + assert!(vm.supports(instance, capability).unwrap()); + assert!(vm.replace_payload(capability, endor_core::Record).is_err()); + for object in [ + roots.object, + roots.type_type, + base, + child, + valid, + invalid, + same_name, + instance, + ] { + vm.release(object).unwrap(); + } + vm.collect_cycles(); + assert_eq!(vm.object_count(), 0); +} + +#[test] +fn late_trait_registration_and_ancestor_updates_validate_existing_descendants() { + use endor_core::MethodRequirement; + let mut vm = Vm::new().unwrap(); + let roots = vm.bootstrap_types().unwrap(); + let base = vm + .new_type("Base", roots.object, TypeConstructor::Record) + .unwrap(); + let good = contract_method(&mut vm, 2); + let bad = contract_method(&mut vm, 1); + vm.define_method(base, "render", good).unwrap(); + let child = vm + .new_class("Child", base, vec![], [("render".into(), bad)].into()) + .unwrap(); + let capability = vm + .new_trait( + "Drawable", + vec![MethodRequirement { + name: "render".into(), + parameters: 1, + }], + ) + .unwrap(); + assert!(vm.implement_trait(base, capability).is_err()); + assert!(!vm.implements_trait(base, capability).unwrap()); + vm.define_method(child, "render", good).unwrap(); + let inheriting = vm + .new_class( + "Inheriting", + base, + vec![], + std::collections::BTreeMap::new(), + ) + .unwrap(); + vm.implement_trait(inheriting, capability).unwrap(); + assert!(vm.define_method(base, "render", bad).is_err()); + assert_eq!( + vm.object_store().lookup_method(base, "render").unwrap(), + Some(good) + ); + let foreign = Vm::new().unwrap(); + assert_eq!( + foreign.implements_trait(base, capability), + Err(VmError::ForeignHandle) + ); +} diff --git a/crates/objects/src/README.md b/crates/objects/src/README.md index 6d2ffee..0cc1ec1 100644 --- a/crates/objects/src/README.md +++ b/crates/objects/src/README.md @@ -4,19 +4,19 @@ | 文件 | 职责 | | --- | --- | -| [lib.rs](lib.rs) | 包边界、对象类型/ObjectStore 公开导出与独立存储 rustdoc 示例 | +| [lib.rs](lib.rs) | 包边界、对象类型/ObjectStore 公开导出(含Trait/MethodRequirement)与独立存储 rustdoc 示例 | | [object.rs](object.rs) | Value、CompareOp、ObjectPayload、ObjectHeader、EndorObject、Record、NativeFunction | -| [types.rs](types.rs) | 托管名义类型、显式 Object/Type 引导、继承查询、受管方法表/接收者绑定、类字段与原生构造委托 | -| [native.rs](native.rs) | NativeContext、上下文原生函数、作用域语言函数工厂、根与非递归委托调用 | +| [types.rs](types.rs) | 托管名义类型、显式 Object/Type 引导、继承查询、受管方法表/接收者绑定、类字段、显式Trait定义/声明/方法参数约束、原生构造委托 | +| [native.rs](native.rs) | NativeContext、上下文原生函数、作用域语言函数工厂、显式能力声明入口、根与非递归委托调用 | | [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、引用事务、迭代释放、循环回收、只读变更屏障/全调用及嵌套子调用读取跟踪及私有边界测试 | +| [heap.rs](heap.rs) | 私有 Heap、不可伪造 ObjectRef、稳定 Box、引用事务、迭代释放、循环回收、后代契约更新的私有借用枚举、只读变更屏障/全调用及嵌套子调用读取跟踪及私有边界测试 | | [store.rs](store.rs) | ObjectStore、空堆创建、对象操作、retain/release 和回收入口 | | [store_builtins.rs](store_builtins.rs) | 载荷校验、代码/函数工厂、Dict/Cell 操作及键语义 | | [instruction.rs](instruction.rs) | Opcode、Instruction、wordcode 编解码、MakeFunction/比较参数与跳转读取接口 | | [code.rs](code.rs) | CodeLayout、EndorCode/EndorCodeObject、共享不可变代码和操作数/控制流/栈验证 | -| [error.rs](error.rs) | 对象、代码与执行共用的 VmError,避免反向依赖 core | +| [error.rs](error.rs) | 对象、代码与执行共用的 VmError(含能力/方法定位的TraitViolation),避免反向依赖 core | 对象操作变更同步 [对象模型](../../../docs/runtime/objects.md),内置载荷同步 [基本对象](../../../docs/runtime/builtins.md)。新增操作码需要同时修改本包 instruction.rs/code.rs 和 core 的 eval.rs 分派,见 [字节码 VM](../../../docs/runtime/bytecode.md)。 diff --git a/crates/objects/src/error.rs b/crates/objects/src/error.rs index fe7f11f..85d137d 100644 --- a/crates/objects/src/error.rs +++ b/crates/objects/src/error.rs @@ -13,6 +13,11 @@ pub enum VmError { UnsupportedOperation(&'static str), InvalidArgument(&'static str), ObjectKindMismatch(&'static str), + TraitViolation { + capability: String, + method: String, + reason: &'static str, + }, EmptyCell, InvalidBytecode { offset: usize, @@ -43,6 +48,11 @@ impl fmt::Display for VmError { } Self::InvalidArgument(message) => f.write_str(message), Self::ObjectKindMismatch(expected) => write!(f, "expected {expected} object"), + Self::TraitViolation { + capability, + method, + reason, + } => write!(f, "trait {capability} method {method}: {reason}"), Self::EmptyCell => f.write_str("cell is empty"), Self::InvalidBytecode { offset, reason } => { write!(f, "invalid bytecode at code unit {offset}: {reason}") diff --git a/crates/objects/src/heap.rs b/crates/objects/src/heap.rs index 0b92471..53308d2 100644 --- a/crates/objects/src/heap.rs +++ b/crates/objects/src/heap.rs @@ -69,6 +69,16 @@ impl Heap { }) } + pub(crate) fn live_references(&self) -> impl Iterator + '_ { + self.slots.iter().enumerate().filter_map(|(index, slot)| { + slot.object.as_ref().map(|_| ObjectRef { + heap_id: self.id, + index, + generation: slot.generation, + }) + }) + } + pub(crate) fn begin_read_only(&mut self) -> usize { let protected = self .slots diff --git a/crates/objects/src/lib.rs b/crates/objects/src/lib.rs index e70b9f3..79a1353 100644 --- a/crates/objects/src/lib.rs +++ b/crates/objects/src/lib.rs @@ -44,4 +44,6 @@ pub use object::{ ObjectHeader, ObjectPayload, Record, Value, }; pub use store::ObjectStore; -pub use types::{ClassField, EndorTypeObject, RootTypes, TypeConstructor}; +pub use types::{ + ClassField, EndorTraitObject, EndorTypeObject, MethodRequirement, RootTypes, TypeConstructor, +}; diff --git a/crates/objects/src/native.rs b/crates/objects/src/native.rs index 937f10d..9e6dee8 100644 --- a/crates/objects/src/native.rs +++ b/crates/objects/src/native.rs @@ -44,6 +44,14 @@ impl<'a> NativeContext<'a> { self.store.attach_type(object, type_object) } + pub fn implement_trait( + &mut self, + definition: ObjectRef, + capability: ObjectRef, + ) -> Result<(), VmError> { + self.store.implement_trait(definition, capability) + } + pub fn store(&self) -> &ObjectStore { self.store } diff --git a/crates/objects/src/store.rs b/crates/objects/src/store.rs index 02a6b50..58aba78 100644 --- a/crates/objects/src/store.rs +++ b/crates/objects/src/store.rs @@ -77,6 +77,16 @@ impl ObjectStore { "replace immutable type definition", )); } + if self + .object(reference)? + .payload() + .as_any() + .is::() + { + return Err(VmError::UnsupportedOperation( + "replace immutable trait definition", + )); + } self.validate_builtin(&payload)?; self.heap.replace_payload(reference, payload) } diff --git a/crates/objects/src/types.rs b/crates/objects/src/types.rs index 0eaa33a..f0c54e7 100644 --- a/crates/objects/src/types.rs +++ b/crates/objects/src/types.rs @@ -28,13 +28,14 @@ pub struct ClassField { /// 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. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct EndorTypeObject { name: String, base: Option, constructor: TypeConstructor, methods: BTreeMap, fields: Vec, + traits: Vec, } impl EndorTypeObject { @@ -68,6 +69,9 @@ impl ObjectPayload for EndorTypeObject { { visit(function); } + for capability in &self.traits { + visit(*capability); + } for method in self.methods.values() { visit(*method); } @@ -145,6 +149,7 @@ impl ObjectStore { constructor: TypeConstructor::Record, methods: BTreeMap::new(), fields: Vec::new(), + traits: Vec::new(), })?; let mut allocated_type = None; let result = (|| { @@ -154,6 +159,7 @@ impl ObjectStore { constructor: TypeConstructor::Abstract, methods: BTreeMap::new(), fields: Vec::new(), + traits: Vec::new(), })?; allocated_type = Some(type_type); self.attach_type(object, type_type)?; @@ -194,6 +200,7 @@ impl ObjectStore { constructor, methods: BTreeMap::new(), fields, + traits: Vec::new(), })?; if let Err(error) = self.attach_type(definition, metatype) { self.release(definition)?; @@ -269,6 +276,7 @@ impl ObjectStore { )); } let mut methods = definition.methods.clone(); + self.validate_method_update(type_object, &name, function)?; methods.insert(name, function); let updated = EndorTypeObject { name: definition.name.clone(), @@ -276,6 +284,7 @@ impl ObjectStore { constructor: definition.constructor, methods, fields: definition.fields.clone(), + traits: definition.traits.clone(), }; self.heap.replace_payload(type_object, updated) } @@ -331,8 +340,12 @@ impl ObjectStore { constructor, methods, fields, + traits: Vec::new(), })?; - if let Err(error) = self.attach_type(class, metatype) { + if let Err(error) = self + .validate_inherited_traits(class) + .and_then(|()| self.attach_type(class, metatype)) + { self.release(class)?; return Err(error); } @@ -417,6 +430,11 @@ impl ObjectStore { { return Ok(AttributeLookup::Value(Value::Object(type_object))); } + if name == "name" + && let Some(capability) = object.payload().as_any().downcast_ref::() + { + return Ok(AttributeLookup::Value(Value::Text(capability.name.clone()))); + } if let Some(definition) = object.payload().as_any().downcast_ref::() { let metadata = match name { "name" => Some(Value::Text(definition.name.clone())), @@ -503,3 +521,208 @@ impl NativeCallable for CallBoundMethod { }) } } + +/// Minimal explicit capability contract. Arity excludes the bound receiver. +/// Parameter/return types, default implementations and syntax are host concerns. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct MethodRequirement { + pub name: String, + pub parameters: usize, +} +#[derive(Debug)] +pub struct EndorTraitObject { + name: String, + requirements: Vec, +} +impl EndorTraitObject { + pub fn name(&self) -> &str { + &self.name + } + pub fn requirements(&self) -> &[MethodRequirement] { + &self.requirements + } +} +impl ObjectPayload for EndorTraitObject { + fn reference_assignment_only(&self) -> bool { + true + } + fn as_any(&self) -> &dyn std::any::Any { + self + } + fn kind_name(&self) -> &'static str { + "trait" + } + fn repr(&self, _: ObjectRef) -> Result { + Ok(format!("", self.name)) + } +} + +impl ObjectStore { + pub fn new_trait( + &mut self, + name: impl Into, + requirements: Vec, + ) -> Result { + 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")); + } + for requirement in &requirements { + if requirement.name.is_empty() + || requirement.name == "type" + || requirement.parameters == usize::MAX + || !names.insert(&requirement.name) + { + return Err(VmError::InvalidArgument( + "invalid or duplicate trait requirement", + )); + } + } + self.allocate(EndorTraitObject { name, requirements }) + } + + fn inherited_traits(&self, definition: ObjectRef) -> Result, VmError> { + let mut found = std::collections::BTreeSet::new(); + let mut current = Some(definition); + while let Some(definition) = current { + let definition = self.payload::(definition, "Type")?; + found.extend(definition.traits.iter().copied()); + current = definition.base; + } + Ok(found.into_iter().collect()) + } + fn validate_requirement( + &self, + capability: ObjectRef, + requirement: &MethodRequirement, + function: Option, + ) -> Result<(), VmError> { + let invalid = |reason| VmError::TraitViolation { + capability: self + .payload::(capability, "Trait") + .expect("validated trait") + .name + .clone(), + method: requirement.name.clone(), + reason, + }; + let function = function.ok_or_else(|| invalid("required method is missing"))?; + if let Some(count) = self.positional_parameter_count(function)? { + if count != requirement.parameters + 1 { + return Err(invalid( + "positional parameter count does not match (including self)", + )); + } + } else if self.object(function)?.payload().native_callable().is_none() { + return Err(invalid("required member is not callable")); + } + Ok(()) + } + fn validate_trait(&self, definition: ObjectRef, capability: ObjectRef) -> Result<(), VmError> { + let contract = self.payload::(capability, "Trait")?; + for requirement in &contract.requirements { + self.validate_requirement( + capability, + requirement, + self.lookup_method(definition, &requirement.name)?, + )?; + } + Ok(()) + } + fn validate_inherited_traits(&self, definition: ObjectRef) -> Result<(), VmError> { + for capability in self.inherited_traits(definition)? { + self.validate_trait(definition, capability)?; + } + Ok(()) + } + // Enumerate borrowed heap handles only while validating a definition update; + // no global type registry or owning descendant index is introduced. + fn descendant_types(&self, base: ObjectRef) -> Result, VmError> { + self.payload::(base, "Type")?; + let mut found = vec![]; + for reference in self.heap.live_references() { + if self + .object(reference)? + .payload() + .as_any() + .is::() + && self.is_subtype(reference, base)? + { + found.push(reference); + } + } + Ok(found) + } + fn validate_method_update( + &self, + changed: ObjectRef, + name: &str, + function: ObjectRef, + ) -> Result<(), VmError> { + for descendant in self.descendant_types(changed)? { + let mut current = Some(descendant); + let mut affected = false; + while let Some(definition) = current { + if definition == changed { + affected = true; + break; + } + let definition = self.payload::(definition, "Type")?; + if definition.methods.contains_key(name) { + break; + } + current = definition.base; + } + if !affected { + continue; + } + for capability in self.inherited_traits(descendant)? { + for requirement in &self + .payload::(capability, "Trait")? + .requirements + { + if requirement.name == name { + self.validate_requirement(capability, requirement, Some(function))?; + } + } + } + } + Ok(()) + } + pub fn implement_trait( + &mut self, + definition: ObjectRef, + capability: ObjectRef, + ) -> Result<(), VmError> { + self.payload::(capability, "Trait")?; + for descendant in self.descendant_types(definition)? { + self.validate_trait(descendant, capability)?; + } + let mut updated = self.payload::(definition, "Type")?.clone(); + if !updated.traits.contains(&capability) { + updated.traits.push(capability); + self.heap.replace_payload(definition, updated)?; + } + Ok(()) + } + pub fn implements_trait( + &self, + definition: ObjectRef, + capability: ObjectRef, + ) -> Result { + self.payload::(capability, "Trait")?; + let declared = self.inherited_traits(definition)?.contains(&capability); + if declared { + self.validate_trait(definition, capability)?; + } + Ok(declared) + } + pub fn supports(&self, object: ObjectRef, capability: ObjectRef) -> Result { + self.payload::(capability, "Trait")?; + match self.type_of(object)? { + Some(definition) => self.implements_trait(definition, capability), + None => Ok(false), + } + } +} diff --git a/docs/README.md b/docs/README.md index c29e3ac..aaeed01 100644 --- a/docs/README.md +++ b/docs/README.md @@ -6,7 +6,7 @@ | 解释执行、资源修订与引擎升级 | [执行与版本](architecture/execution-and-versions.md) | frontend/compiler/core | | EndorObject、句柄、默认操作 | [对象模型](runtime/objects.md) | objects/src | | 原生上下文、只读调用、子调用读取依赖、委托与变更通知 | [原生调用](runtime/native-calls.md) | objects/src/native.rs、changes.rs、core/src/eval.rs | -| 托管类型、宿主类注册、原生分配继承与字段存储 | [名义类型](runtime/types.md) | objects/src/types.rs | +| 托管类型、宿主类注册、原生分配继承、字段存储与显式能力约束 | [名义类型](runtime/types.md) | objects/src/types.rs | | Number、String、Dict、Cell、Function | [基本对象](runtime/builtins.md) | objects/src | | 源码读取与来源 | [Reader](runtime/reader.md) | frontend/src/reader.rs | | 词法、语法、裸赋值和诊断 | [Frontend](runtime/frontend.md) | frontend/src/lexer.peg/grammar.peg | diff --git a/docs/contributing/handoff.md b/docs/contributing/handoff.md index b2697d5..0699b4c 100644 --- a/docs/contributing/handoff.md +++ b/docs/contributing/handoff.md @@ -10,7 +10,7 @@ Aster 是可嵌入引擎,只保留 objects、core、frontend、compiler。Obje ## 已实现 -- EndorObject、稳定 Box、代际句柄、显式强引用及手动循环回收;VM 从空堆启动,宿主可显式引导托管 Object/Type 和名义继承;普通源码 class、字段构造和继承方法分派已接入,显式 NativeTyped 原生分配继承已接入,trait 仍待完成,见[类型机制](../runtime/types.md)。 +- EndorObject、稳定 Box、代际句柄、显式强引用及手动循环回收;VM 从空堆启动,宿主可显式引导托管 Object/Type 和名义继承;普通源码 class、字段构造和继承方法分派已接入,显式 NativeTyped 原生分配继承已接入,宿主显式Trait身份/继承/必需方法及参数约束已接入;正式trait语法和完整类型/效果仍待完成,见[类型机制](../runtime/types.md)。 - Function、NativeFunction、Dict、Cell、异常数据、UTF-8 String 和无损表示优先的 Number。 - 小型 wordcode、共享代码对象、操作数/控制流/栈校验、显式执行帧及 execute/call;MakeFunction 可在执行中创建带默认参数与共享闭包 Cell 的函数。对象返回值持有根,用后 release_value;借用读取不自动 retain。 - EndorReader 在 lexer 前提供字符串/流/文件/宿主 URI provider 输入,产出不可变 SourceUnit,保存来源与不透明修订标签;带来源的词法/语法错误保留行列,Lyra parse 支持文件和 stdin。没有平台 URI 后端或版本锁实现,见 [阅读器](../runtime/reader.md)。 diff --git a/docs/runtime/types.md b/docs/runtime/types.md index 46dc1c0..b7f4112 100644 --- a/docs/runtime/types.md +++ b/docs/runtime/types.md @@ -56,7 +56,7 @@ class DetailedCounter: Counter { 方法表本身是类型对象拥有的托管边。宿主 define_method 可显式替换条目,不改变类型身份、基类或已有绑定方法选中的函数。bind_attr 返回一份拥有式根;get_attr 返回借用值和未绑定方法,宿主不能把两者的调用/释放协议混用。positional_parameter_count 会扣除绑定的接收者,供宿主判断事件回调的剩余源码参数。 -这是一份实现子集说明:构造器只按字段赋值,没有默认值、命名字段构造或隐式 init;字段/参数/返回注解保留名称,尚未实施类型检查。源码类可继承 Record 或 NativeTyped 分配器;未选择支持继承的旧 Native 分配器仍明确报错。继承会保留分配器和父类字段,不能伪造带原生名义身份的普通 Record。字段构造参数如何与原生参数组合由宿主分配器负责;Tessera 使用原生参数在前、继承及本类字段在后的协议。trait 和用户自定义测量/绘制协议仍待实现。正式语言文档的候选语法不因这一实现被自动确认为规范。 +这是一份实现子集说明:构造器只按字段赋值,没有默认值、命名字段构造或隐式 init;字段/参数/返回注解保留名称,尚未实施类型检查。源码类可继承 Record 或 NativeTyped 分配器;未选择支持继承的旧 Native 分配器仍明确报错。继承会保留分配器和父类字段,不能伪造带原生名义身份的普通 Record。字段构造参数如何与原生参数组合由宿主分配器负责;Tessera 使用原生参数在前、继承及本类字段在后的协议。trait 的正式源码语法、参数/返回类型约束和效果系统仍待实现;宿主显式能力子集见下文。正式语言文档的候选语法不因这一实现被自动确认为规范。 ## 可转移的字段存储 @@ -64,3 +64,16 @@ class DetailedCounter: Counter { ObjectPayload 可选择实现 `attribute_target(store)`,把实例字段放在另一个受托管强边保活的对象上。`attribute_path` 验证完整路径,拒绝跨堆句柄及循环;get_attr/set_attr/del_attr 读取或修改最终存储对象。名义类型、方法选择及绑定接收者仍取原对象,字段存储不代替类型身份。默认返回 None,普通对象行为不变。 反应式宿主订阅路径中各中间对象的 Contents,以及最终对象的 Attribute(field);重定向字段存储时必须发布 Contents 变化。否则仅监听外壳字段会漏掉实际存储更新。Tessera 的 Block 把字段存在当前内容的托管 Record 中,共享替换后别名会跟随新存储,旧字段及其引用可正常回收。实现回归见 [attribute_storage.rs](../../crates/objects/tests/attribute_storage.rs);本地仅编译。 + + +## 显式能力关系 + +宿主可调用new_trait(name, requirements)建立EndorTraitObject,每项MethodRequirement记录方法名和绑定接收者之后的固定位置参数数量。定义保持名义身份、不可替换载荷,name只读;同名能力不自动相等。new_trait返回拥有式根,是否附加某个宿主提供的Trait实例类型由宿主决定。 + +implement_trait(Type, Trait)明确建立能力关系并校验必需方法。只有同名成员不算实现。implements_trait(Type, Trait)检查声明和继承;supports(instance, Trait)先查实际类型;未分类对象返回false,非法句柄或非定义参数报错。一个类型可显式实现多个能力,派生类继承关系。声明由Type的受管强边持有,查询和临时后代扫描不保活定义。 + +源码函数必须具有要求数量加self的参数;原生可调用对象的签名由注册宿主保证,当前没有原生形参元数据。缺少方法、非可调用成员或参数数量错误以TraitViolation报告能力名、方法名和原因。本子集不验证注解、关联类型、返回类型、效果或可选形参的替换兼容性;没有默认实现和trait源码语法。 + +建立声明前检查已有后代;构造源码子类检查继承的所有能力。define_method更新前检查受影响后代的显式/继承契约,被后代自己的覆盖遮蔽的方法不受该祖先更新影响。失败保留原方法表和关系。内部扫描只枚举当前借用句柄,不引入全局强类型注册表。声明更新通过普通堆写屏障与trace进行,既有类型的只读作用域内变更会被拒绝。NativeContext也可使用同一implement_trait入口,仍受该屏障约束。 + +相关回归加入core/tests/types.rs,仅编译,不在本地执行。Tessera提供的Visual/EventTarget/Children/Presentable以及运行时返回值校验属于宿主,Aster不内置GUI类型。