feat(phase-9.78b): Complete plugin Box inheritance and argument support
ChatGPT5による大規模改善: - ✅ プラグインBox継承サポート完成 - ✅ from Parent.method()でプラグインメソッド呼び出し - ✅ 引数・戻り値のTLVエンコード/デコード - ✅ 借用チェッカーエラー全解決 - ✅ MIRビルダーのクローン修正 次期作業: - Phase 9.78b Step 3: BoxFactory dyn化 - アーキテクチャ改善継続 Co-authored-by: ChatGPT5 <noreply@openai.com>
This commit is contained in:
@ -680,6 +680,27 @@ impl NyashInterpreter {
|
||||
}
|
||||
}
|
||||
|
||||
// プラグイン親のメソッド呼び出し(__plugin_content)
|
||||
#[cfg(all(feature = "plugins", not(target_arch = "wasm32")))]
|
||||
{
|
||||
if let Some(plugin_shared) = instance.get_field_legacy("__plugin_content") {
|
||||
let plugin_ref = &*plugin_shared;
|
||||
if let Some(plugin) = plugin_ref.as_any().downcast_ref::<crate::runtime::plugin_loader_v2::PluginBoxV2>() {
|
||||
let mut arg_values: Vec<Box<dyn NyashBox>> = Vec::new();
|
||||
for arg in arguments {
|
||||
arg_values.push(self.execute_expression(arg)?);
|
||||
}
|
||||
let loader = crate::runtime::get_global_loader_v2();
|
||||
let loader = loader.read().unwrap();
|
||||
match loader.invoke_instance_method(&plugin.box_type, method, plugin.instance_id, &arg_values) {
|
||||
Ok(Some(result_box)) => return Ok(result_box),
|
||||
Ok(None) => return Ok(Box::new(VoidBox::new())),
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// メソッドが見つからない
|
||||
Err(RuntimeError::InvalidOperation {
|
||||
message: format!("Method '{}' not found in {}", method, instance.class_name),
|
||||
@ -710,16 +731,16 @@ impl NyashInterpreter {
|
||||
|
||||
// 2. 現在のクラスのデリゲーション関係を検証
|
||||
let current_class = ¤t_instance.class_name;
|
||||
let box_declarations = self.shared.box_declarations.read().unwrap();
|
||||
|
||||
let current_box_decl = box_declarations.get(current_class)
|
||||
.ok_or(RuntimeError::UndefinedClass {
|
||||
name: current_class.clone()
|
||||
})?;
|
||||
|
||||
// ここでは短期ロックで必要な情報だけ抜き出してすぐ解放する
|
||||
let (has_parent_in_ext, has_parent_in_impl) = {
|
||||
let box_declarations = self.shared.box_declarations.read().unwrap();
|
||||
let current_box_decl = box_declarations.get(current_class)
|
||||
.ok_or(RuntimeError::UndefinedClass { name: current_class.clone() })?;
|
||||
(current_box_decl.extends.contains(&parent.to_string()),
|
||||
current_box_decl.implements.contains(&parent.to_string()))
|
||||
};
|
||||
// extendsまたはimplementsでparentが指定されているか確認 (Multi-delegation) 🚀
|
||||
let is_valid_delegation = current_box_decl.extends.contains(&parent.to_string()) ||
|
||||
current_box_decl.implements.contains(&parent.to_string());
|
||||
let is_valid_delegation = has_parent_in_ext || has_parent_in_impl;
|
||||
|
||||
if !is_valid_delegation {
|
||||
return Err(RuntimeError::InvalidOperation {
|
||||
@ -730,34 +751,53 @@ impl NyashInterpreter {
|
||||
|
||||
// 🔥 Phase 8.8: pack透明化システム - ビルトインBox判定
|
||||
use crate::box_trait::is_builtin_box;
|
||||
|
||||
let mut is_builtin = is_builtin_box(parent);
|
||||
|
||||
// GUI機能が有効な場合はEguiBoxも追加判定
|
||||
// GUI機能が有効な場合はEguiBoxも追加判定(mut不要の形に)
|
||||
#[cfg(all(feature = "gui", not(target_arch = "wasm32")))]
|
||||
{
|
||||
if parent == "EguiBox" {
|
||||
is_builtin = true;
|
||||
}
|
||||
}
|
||||
let is_builtin = is_builtin_box(parent) || parent == "EguiBox";
|
||||
#[cfg(not(all(feature = "gui", not(target_arch = "wasm32"))))]
|
||||
let is_builtin = is_builtin_box(parent);
|
||||
|
||||
// 🔥 Phase 8.9: Transparency system removed - all delegation must be explicit
|
||||
// Removed: if is_builtin && method == parent { ... execute_builtin_constructor_call ... }
|
||||
|
||||
if is_builtin {
|
||||
// ビルトインBoxの場合、ロックを解放してからメソッド呼び出し
|
||||
drop(box_declarations);
|
||||
// ビルトインBoxの場合、直接ビルトインメソッドを実行
|
||||
return self.execute_builtin_box_method(parent, method, current_instance_val.clone_box(), arguments);
|
||||
}
|
||||
|
||||
// プラグイン親(__plugin_content)
|
||||
#[cfg(all(feature = "plugins", not(target_arch = "wasm32")))]
|
||||
{
|
||||
// 親がユーザー定義に見つからない場合は、プラグインとして試行
|
||||
// 現在のインスタンスから __plugin_content を参照
|
||||
if let Some(plugin_shared) = current_instance.get_field_legacy("__plugin_content") {
|
||||
// 引数を評価(ロックは既に解放済みの設計)
|
||||
let plugin_ref = &*plugin_shared;
|
||||
if let Some(plugin) = plugin_ref.as_any().downcast_ref::<crate::runtime::plugin_loader_v2::PluginBoxV2>() {
|
||||
let mut arg_values: Vec<Box<dyn NyashBox>> = Vec::new();
|
||||
for arg in arguments {
|
||||
arg_values.push(self.execute_expression(arg)?);
|
||||
}
|
||||
let loader = crate::runtime::get_global_loader_v2();
|
||||
let loader = loader.read().unwrap();
|
||||
match loader.invoke_instance_method(&plugin.box_type, method, plugin.instance_id, &arg_values) {
|
||||
Ok(Some(result_box)) => return Ok(result_box),
|
||||
Ok(None) => return Ok(Box::new(VoidBox::new())),
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 親クラスのBox宣言を取得(ユーザー定義Boxの場合)
|
||||
let parent_box_decl = box_declarations.get(parent)
|
||||
let parent_box_decl = {
|
||||
let box_declarations = self.shared.box_declarations.read().unwrap();
|
||||
box_declarations.get(parent)
|
||||
.ok_or(RuntimeError::UndefinedClass {
|
||||
name: parent.to_string()
|
||||
})?
|
||||
.clone();
|
||||
|
||||
drop(box_declarations); // ロック早期解放
|
||||
.clone()
|
||||
};
|
||||
|
||||
// 4. constructorまたはinitまたはpackまたはbirthの場合の特別処理
|
||||
if method == "constructor" || method == "init" || method == "pack" || method == "birth" || method == parent {
|
||||
|
||||
@ -817,7 +817,27 @@ impl NyashInterpreter {
|
||||
// 🌍 革命的実装:Environment tracking廃止
|
||||
|
||||
// Create Arc outside if block so it's available in all scopes
|
||||
let instance_arc = Arc::from(instance_box);
|
||||
let instance_arc: Arc<dyn NyashBox> = Arc::from(instance_box);
|
||||
|
||||
// プラグイン親(extendsに含まれる場合)の生成と保持(__plugin_content)
|
||||
#[cfg(all(feature = "plugins", not(target_arch = "wasm32")))]
|
||||
{
|
||||
use crate::runtime::get_global_loader_v2;
|
||||
use crate::box_trait::SharedNyashBox;
|
||||
let loader = get_global_loader_v2();
|
||||
let loader = loader.read().unwrap();
|
||||
if !final_box_decl.extends.is_empty() {
|
||||
for parent in &final_box_decl.extends {
|
||||
if let Ok(plugin_box) = loader.create_box(parent, &[]) {
|
||||
if let Some(inst) = (&*instance_arc).as_any().downcast_ref::<InstanceBox>() {
|
||||
let shared: SharedNyashBox = Arc::from(plugin_box);
|
||||
let _ = inst.set_field_legacy("__plugin_content", shared);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// コンストラクタを呼び出す
|
||||
// 🌟 birth()統一システム: "birth/引数数"のみを許可(Box名コンストラクタ無効化)
|
||||
|
||||
@ -35,6 +35,10 @@ pub struct MirBuilder {
|
||||
/// Pending phi functions to be inserted
|
||||
#[allow(dead_code)]
|
||||
pub(super) pending_phis: Vec<(BasicBlockId, ValueId, String)>,
|
||||
|
||||
/// Origin tracking for simple optimizations (e.g., object.method after new)
|
||||
/// Maps a ValueId to the class name if it was produced by NewBox of that class
|
||||
pub(super) value_origin_newbox: HashMap<ValueId, String>,
|
||||
}
|
||||
|
||||
impl MirBuilder {
|
||||
@ -48,6 +52,7 @@ impl MirBuilder {
|
||||
block_gen: BasicBlockIdGenerator::new(),
|
||||
variable_map: HashMap::new(),
|
||||
pending_phis: Vec::new(),
|
||||
value_origin_newbox: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -796,10 +801,13 @@ impl MirBuilder {
|
||||
// VM will handle optimization for basic types internally
|
||||
self.emit_instruction(MirInstruction::NewBox {
|
||||
dst,
|
||||
box_type: class,
|
||||
box_type: class.clone(),
|
||||
args: arg_values.clone(),
|
||||
})?;
|
||||
|
||||
// Record origin for optimization: dst was created by NewBox of class
|
||||
self.value_origin_newbox.insert(dst, class);
|
||||
|
||||
// Immediately call birth(...) on the created instance to run constructor semantics.
|
||||
// birth typically returns void; we don't capture the result here (dst: None)
|
||||
self.emit_instruction(MirInstruction::BoxCall {
|
||||
@ -1001,15 +1009,32 @@ impl MirBuilder {
|
||||
})?;
|
||||
Ok(result_id)
|
||||
} else {
|
||||
// Fallback: Emit a BoxCall instruction for regular method calls
|
||||
self.emit_instruction(MirInstruction::BoxCall {
|
||||
dst: Some(result_id),
|
||||
box_val: object_value,
|
||||
method,
|
||||
args: arg_values,
|
||||
effects: EffectMask::READ.add(Effect::ReadHeap), // Method calls may have side effects
|
||||
})?;
|
||||
Ok(result_id)
|
||||
// If the object originates from a NewBox in this function, we can lower to Call as well
|
||||
if let Some(class_name) = self.value_origin_newbox.get(&object_value).cloned() {
|
||||
let func_name = format!("{}.{}{}", class_name, method, format!("/{}", arg_values.len()));
|
||||
let func_val = self.value_gen.next();
|
||||
self.emit_instruction(MirInstruction::Const { dst: func_val, value: ConstValue::String(func_name) })?;
|
||||
let mut call_args = Vec::with_capacity(arg_values.len() + 1);
|
||||
call_args.push(object_value);
|
||||
call_args.extend(arg_values);
|
||||
self.emit_instruction(MirInstruction::Call {
|
||||
dst: Some(result_id),
|
||||
func: func_val,
|
||||
args: call_args,
|
||||
effects: EffectMask::READ.add(Effect::ReadHeap),
|
||||
})?;
|
||||
Ok(result_id)
|
||||
} else {
|
||||
// Fallback: Emit a BoxCall instruction for regular method calls
|
||||
self.emit_instruction(MirInstruction::BoxCall {
|
||||
dst: Some(result_id),
|
||||
box_val: object_value,
|
||||
method,
|
||||
args: arg_values,
|
||||
effects: EffectMask::READ.add(Effect::ReadHeap), // Method calls may have side effects
|
||||
})?;
|
||||
Ok(result_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ mod enabled {
|
||||
use crate::config::nyash_toml_v2::{NyashConfigV2, LibraryDefinition};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::ffi::c_void;
|
||||
// use std::ffi::c_void; // unused
|
||||
use std::any::Any;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user