Skip to content

Add map support#1562

Merged
alexcrichton merged 19 commits intobytecodealliance:mainfrom
yordis:yordis/feat-map-support
Apr 9, 2026
Merged

Add map support#1562
alexcrichton merged 19 commits intobytecodealliance:mainfrom
yordis:yordis/feat-map-support

Conversation

@yordis
Copy link
Copy Markdown
Contributor

@yordis yordis commented Mar 11, 2026

Summary

  • add end-to-end map<K, V> support in wit-bindgen core ABI and backend codegen paths (C, C++, C#, Go, MoonBit), plus Markdown type rendering
  • add map-focused codegen/runtime coverage in tests/codegen/map.wit and tests/runtime/map/*
  • fix Go test harness module replacement in crates/test/src/go.rs so generated map bindings resolve go.bytecodealliance.org/pkg/wit/* correctly

Test plan

  • cargo fmt
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo check
  • cargo check -p wit-bindgen-core
  • cargo check -p wit-bindgen-c
  • cargo check -p wit-bindgen-cpp
  • cargo check -p wit-bindgen-csharp
  • cargo check -p wit-bindgen-go
  • cargo check -p wit-bindgen-moonbit
  • cargo check -p wit-bindgen-markdown
  • cargo run test --artifacts target/artifacts --runner cargo --languages go --filter map.wit tests/codegen

@yordis yordis marked this pull request as draft March 11, 2026 04:51
Implement map type rendering plus lowering/lifting/deallocation support across the C, C++, C#, Go, MoonBit, and Markdown backends, and add map codegen/runtime tests.

This aligns non-Rust generators with core map ABI support and fixes the Go test harness module replacement path needed for map codegen verification.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis yordis force-pushed the yordis/feat-map-support branch from d9c32e0 to 0a302d8 Compare March 24, 2026 14:58
yordis added 7 commits March 24, 2026 11:34
Defer map codegen for MoonBit, Go, C#, C++, and C to future PRs
that include runtime tests and review from language-specific
maintainers. Only todo!() stubs for the new MapLower/MapLift/
IterMapKey/IterMapValue/GuestDeallocateMap instruction variants
are kept so exhaustive matches compile.
This change was a fix for a latent bug from the vanity imports migration
but is unrelated to map support. Removing to keep the PR focused on Rust.
- Make `InterfaceGenerator::type_map` a required trait method instead of
  providing a default `todo!()` impl, so missing implementations are
  caught at compile time rather than runtime.
- Remove `RuntimeItem::MapType` indirection in the Rust backend; reference
  `{rt}::Map` directly instead of emitting a `pub use` re-export.
- Fix borrowed map rendering to use `&Map<K, V>` instead of the
  incorrect `&[(K, V)]` slice syntax that was copy-pasted from lists.
- Add explanatory comments on map ABI methods that reuse list
  read/write helpers (maps share the list<tuple<K, V>> memory layout).
- Add explicit `type_map` todo stubs to C, C++, C#, Go, and MoonBit
  backends.
- Make `anonymous_type_map` a required method on `AnonymousTypeGenerator`
  trait (no default impl), consistent with all other methods in the trait.
- Add explicit `anonymous_type_map` todo!() implementation to C backend.
- Fix map runner test to construct proper Map types instead of passing
  slice literals, matching the generated `&Map<K, V>` parameter signatures.
The map.wit codegen test hits todo!() panics in backends that don't yet
implement map support (C, C++, C#, Go, MoonBit). Add map.wit to each
backend's should_fail_verify so CI treats these as expected failures.
- Run cargo fmt to fix formatting in c/lib.rs, test/c.rs, test/moonbit.rs.
- Use starts_with("map.wit") for the C backend's should_fail_verify to
  catch all codegen test variants (no-sig-flattening, autodrop, async).
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis yordis requested a review from alexcrichton March 28, 2026 15:56
yordis added 3 commits March 29, 2026 16:53
Add runtime tests for empty maps, option values, maps inside records,
inline anonymous map types, and a 100-entry stress test. Expand codegen
tests with option values, nested maps, record values, bool keys, and
char keys.
Exercise additional ABI code paths: nested map<K, map<K2, V>> with
recursive lower/lift blocks, multiple map parameters with independent
ptr/len pairs, map as a variant arm payload, map inside result<ok, err>,
and tuple-with-map in codegen.
Exercise map inside an anonymous tuple (filter_mode_preserve_top path)
and the single-entry boundary case.
Copy link
Copy Markdown
Member

@alexcrichton alexcrichton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok thinking a bit more about this and the Rust side of things. Ultimately I feel that neither HashMap nor BTreeMap are the right types to use here. Given that I'm thinking that this needs to be more configurable in Rust to select the desired type, with some semi-reasonable default. What I'm thinking is something like this:

  • Bindgen accepts a new map_type: Foo-style option. Basically this makes it customizable as to what type exactly is used and enables users to specify their own types. For example if users wanted to do Vec<(K, V)> that would be possible.
  • There's a trait in wit-bindgen-the-crate called something like trait WitMap. This would have methods for creation (pushing items into it) and iteration. These methods would be delegated to in the generated code (e.g. via WitMap::push(&mut map, key, value). This provides a clear interface between generated code and the needs of the type that a map has.
  • Probably the default map is a BTreeMap for now. I don't think it's a slam dunk over HashMap but neither is the other way around either. With this support it should be relatively easily interchangeable.

yordis added 6 commits April 7, 2026 16:47
Instead of hardcoding HashMap/BTreeMap, introduce a WitMap trait that
generated code delegates to for map construction, insertion, and length.
This lets users swap in their own map type via the new `map_type`
bindgen option. The default is BTreeMap (always, regardless of std).
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
- Unit tests for WitMap trait impls (BTreeMap, HashMap, reference blanket)
- Proc-macro integration tests exercising map_type with HashMap and default
- Codegen test variant running all .wit files with --map-type=HashMap
Remove `type Iter` and `wit_map_into_iter` from the `WitMap` trait and
drop the `IntoIterator` bound from the blanket `&T` impl. This allows
the blanket impl to apply at any reference depth (e.g. `&&BTreeMap`)
which is needed when codegen emits `WitMap::wit_map_len(&map)` on an
already-borrowed map.

Generated lowering code now uses `IntoIterator::into_iter(map)` for
iteration, which the standard library already provides for both owned
and borrowed map types.
Use method syntax (.wit_map_len() and .into_iter()) in generated
MapLower code instead of UFCS. This lets Rust's auto-deref handle
&&BTreeMap operands that arise when the borrow-mode param wrapper
adds an extra & prefix to already-borrowed map arguments.

A scoped `use WitMap;` import is emitted so method resolution finds
the trait's wit_map_len method.
Revert MapLower to use method syntax for length and iteration, matching
the original pre-WitMap code. Method syntax auto-derefs through &&Map
operands that arise in borrowed ownership modes.

Simplify WitMap trait to just new/push (used only in MapLift). The map
type must also provide .len() and implement IntoIterator, which all
standard map types already do.
@yordis yordis requested a review from alexcrichton April 8, 2026 01:04
Copy link
Copy Markdown
Member

@alexcrichton alexcrichton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Only one more minor thing and otherwise this looks good to me

yordis added 2 commits April 8, 2026 14:52
Instead of calling .len() directly (which bypasses the WitMap trait and
would break custom map types), generated code now calls .wit_map_len()
using method syntax. The WitMap trait is brought into scope via a
module-level `use _rt::WitMap;` import, avoiding the scoping issues
that arose from emitting `use` inside nested blocks.
@yordis yordis requested a review from alexcrichton April 8, 2026 19:04
@yordis yordis marked this pull request as ready for review April 9, 2026 22:47
@alexcrichton alexcrichton added this pull request to the merge queue Apr 9, 2026
Merged via the queue into bytecodealliance:main with commit 958027c Apr 9, 2026
28 checks passed
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