Skip to content

Fix cross-module ref-type iterator bug and add return/for-of type checks#727

Merged
gfx merged 9 commits intomainfrom
claude/fix-cross-module-bug-u2g8B
Mar 29, 2026
Merged

Fix cross-module ref-type iterator bug and add return/for-of type checks#727
gfx merged 9 commits intomainfrom
claude/fix-cross-module-bug-u2g8B

Conversation

@gfx
Copy link
Copy Markdown
Member

@gfx gfx commented Mar 29, 2026

Summary

  • Fix cross-module ref-type iterator monomorphization bug: The monomorphizer selected Array^IntoIterator::into_iter (returns ArrayIter) instead of &^IntoIterator::into_iter (returns ArrayRefIter) when iterating &Array<T> inside generic functions. Root cause: resolve_method_call_substitution overwrote base_struct_name from "&" to "Array" by unwrapping the receiver's reference, and the resolver didn't propagate is_ref_impl to LocalMethodName.
  • Fix Array::iter() and TreeSet::iter(): Both called self.into_iter() which dispatched to the &T impl returning the wrong iterator type. Now construct iterators directly.
  • Add return type mismatch check: fn foo() -> i32 { return "hello"; } previously compiled silently — now emits a compile error. Uses strict TypeId comparison (no base_type_name fallback). Found and fixed a real stdlib bug: u8::try_from(u16) was returning Result::<u16, ConvertError>.
  • Add for-of trait checks: Emit "does not implement IntoIterator" / "does not implement Iterator" instead of generic "no method found" errors.
  • Cross-module same-name type test: Verifies that same-name structs from different modules correctly produce a type mismatch error on return.

Test plan

  • 4380 e2e tests pass (0 failures)
  • 317 unit tests pass
  • on-task-done passes (format, clippy, golden fixtures, test-wado)
  • 4 previously-#![TODO] fixtures now pass: cross_module_variant_iter, test_world_variant_generic, test_world_variant_generic_run, single_module_variant_iter
  • New error test fixtures: error_return_type_mismatch, error_return_cross_module_same_name, error_for_of_no_into_iterator, error_for_of_no_iterator

https://claude.ai/code/session_01Psntc941Uh8sx4iWuvy8Fa

claude added 5 commits March 29, 2026 11:53
The monomorphizer incorrectly selected Array<T>^IntoIterator::into_iter
instead of &^IntoIterator::into_iter when iterating &Array<T> inside
generic functions. This caused Wasm GC type mismatches when ArrayIter
and ArrayRefIter had different type indices across module boundaries.

Root cause: resolve_method_call_substitution in func_inst.rs overwrote
the LocalMethodName's base_struct_name from "&" to "Array" by unwrapping
the receiver's reference type. This lost the ref-type impl identity,
causing the wrong generic template to be instantiated.

Three fixes:
1. Propagate is_ref_impl from MethodInfo to LocalMethodName in resolver
2. Preserve base_struct_name for ref-type impls in monomorphizer
3. Fix Array::iter() to construct ArrayIter directly instead of calling
   self.into_iter() which returns ArrayRefIter (type mismatch)

https://claude.ai/code/session_01Psntc941Uh8sx4iWuvy8Fa
The cross_module_type_identity test is no longer TODO-marked — the
loader fix for duplicate ModuleSource identities is already in place.

https://claude.ai/code/session_01Psntc941Uh8sx4iWuvy8Fa
on-task-done regenerated WIR golden files reflecting the correct
iterator template selection for ref-type impls.

https://claude.ai/code/session_01Psntc941Uh8sx4iWuvy8Fa
Same pattern as the Array::iter() fix — calling self.into_iter() on
&self dispatches to the wrong IntoIterator impl after the ref-type
monomorphization fix.

https://claude.ai/code/session_01Psntc941Uh8sx4iWuvy8Fa
- Emit "does not implement IntoIterator" when for-of iterable lacks the trait
- Emit "does not implement Iterator" when the iterator type lacks next()
- Add e2e test fixtures for both error cases
- Fix TreeSet::iter() to construct TreeSetIter directly (same pattern as
  the Array::iter() fix)

https://claude.ai/code/session_01Psntc941Uh8sx4iWuvy8Fa
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 29, 2026

Working tree is dirty

Integrity checks produced the following changes:

 wado-compiler/src/resolver/coercion.rs             | 25 +++++++++++-----------
 .../tests/format.fixtures.golden/all.lower.wado    |  4 ++--
 .../tests/format.fixtures.golden/mess.lower.wado   |  4 ++--
 .../format.fixtures.golden/ops.all.lower.wado      |  4 ++--
 .../format.fixtures.golden/ops.mess.lower.wado     |  4 ++--
 5 files changed, 20 insertions(+), 21 deletions(-)

Please run mise run on-task-done locally and commit the changes.

claude added 4 commits March 29, 2026 12:36
Previously `fn foo() -> i32 { return "hello"; }` compiled without error,
producing invalid Wasm. Now the resolver checks that the return value's
type matches the declared return type and emits a compile error on
mismatch.

https://claude.ai/code/session_01Psntc941Uh8sx4iWuvy8Fa
Remove base_type_name fallback — cross-module types must have the same
TypeId. Add test for same-name structs from different modules correctly
producing a type mismatch error.

Also fix a real bug found by this check: u8::try_from(u16) was
returning Result::<u16, ConvertError> instead of Result::<u8, ...>.

Skip unresolved generics (TypeParam, TypePack, AssocTypeProjection,
GenericInstance with params) and function types from the check, as
these are resolved after monomorphization.

https://claude.ai/code/session_01Psntc941Uh8sx4iWuvy8Fa
@gfx gfx changed the title Fix cross-module ref-type iterator monomorphization bug Fix cross-module ref-type iterator bug and add return/for-of type checks Mar 29, 2026
@gfx gfx enabled auto-merge March 29, 2026 13:18
@gfx gfx merged commit d1261f4 into main Mar 29, 2026
10 checks passed
@gfx gfx deleted the claude/fix-cross-module-bug-u2g8B branch March 29, 2026 13:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants