From 410bc8b8b4938956edfabe837fa39b997f8e3d3f Mon Sep 17 00:00:00 2001 From: Ralf Anton Beier Date: Thu, 19 Mar 2026 07:22:57 +0100 Subject: [PATCH] fix: correct callee_defines_resource for sentinel type entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When build_resource_type_to_import uses the Step 4b fallback (sentinel type 0), the callee doesn't truly define the resource — it re-exports from another component. The callee_defines_resource flag now checks for sentinel entries and returns false, enabling SR-33 result conversion and 3-component borrow forwarding for re-exporting intermediates. Also synthesizes caller-side [resource-new] for own results in 3-component chains. Co-Authored-By: Claude Opus 4.6 (1M context) --- meld-core/src/resolver.rs | 41 +++++++++++++++++++++----- meld-core/tests/wit_bindgen_runtime.rs | 1 - 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/meld-core/src/resolver.rs b/meld-core/src/resolver.rs index 44324f1..c59715f 100644 --- a/meld-core/src/resolver.rs +++ b/meld-core/src/resolver.rs @@ -942,13 +942,21 @@ fn resolve_resource_positions( } }); if let Some((module_name, field_name)) = entry { - // Check if the callee defines this resource type. - // Import(_) means the callee imports the resource from another component. - // Defined means the callee's own type section defines it. - let callee_defines_resource = callee_type_defs - .get(pos.resource_type_id as usize) - .map(|def| !matches!(def, crate::parser::ComponentTypeDef::Import(_))) - .unwrap_or(true); // default to true (SR-25 behavior) + // Check if the callee truly defines this resource (has ownership of the + // underlying representation). A callee that re-exports a resource from + // another component has a Defined type entry but doesn't own the rep. + // Use the sentinel check: if the map entry was resolved via sentinel type 0 + // (Step 4b fallback), the callee doesn't define the resource. + let used_sentinel = resource_map.contains_key(&(0u32, field_prefix)) + && !resource_map.contains_key(&(pos.resource_type_id, field_prefix)); + let callee_defines_resource = if used_sentinel { + false // Step 4b fallback means callee imports the resource + } else { + callee_type_defs + .get(pos.resource_type_id as usize) + .map(|def| !matches!(def, crate::parser::ComponentTypeDef::Import(_))) + .unwrap_or(true) + }; resolved.push(ResolvedResourceOp { flat_idx: pos.flat_idx, byte_offset: pos.byte_offset, @@ -1107,13 +1115,30 @@ impl Resolver { site.to_component, )); } - // For 3-component chains: synthesize callee's [resource-new]. + // For 3-component chains: synthesize callee's [resource-new] for borrow params. for op in &site.requirements.resource_params { if !op.is_owned && !op.callee_defines_resource { let new_field = op.import_field.replace("[resource-rep]", "[resource-new]"); needed.push((op.import_module.clone(), new_field, site.to_component)); } } + // For 3-component chains: synthesize CALLER's [resource-new] for own results. + // When callee doesn't define the resource, own results need resource.new + // in the caller's table. + for op in &site.requirements.resource_results { + if op.is_owned && !op.callee_defines_resource { + let new_field = if op.import_field.starts_with("[resource-new]") { + op.import_field.clone() + } else { + op.import_field.replace("[resource-rep]", "[resource-new]") + }; + needed.push(( + op.import_module.clone(), + new_field, + site.from_component, // CALLER's component + )); + } + } } if needed.is_empty() { diff --git a/meld-core/tests/wit_bindgen_runtime.rs b/meld-core/tests/wit_bindgen_runtime.rs index 061b478..589b82c 100644 --- a/meld-core/tests/wit_bindgen_runtime.rs +++ b/meld-core/tests/wit_bindgen_runtime.rs @@ -657,7 +657,6 @@ runtime_test!( test_runtime_wit_bindgen_resource_borrow_in_record, "resource_borrow_in_record" ); -// resource_with_lists: wiring correct (DAG hints), but 3-component resource type mismatch fuse_only_test!( test_fuse_wit_bindgen_resource_with_lists, "resource_with_lists"