You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
winmd-inspect: close over signature-named value types and delegates
Extend the `--closure` walk to pull in the value-type and delegate types a
rendered interface names through its method signatures — the E3 value arm, the
E6 struct-field types, and the E7 delegate signatures — so the closure emits
everything a consumer needs to compile the projection, not the interface surface
alone. Each projected type is an ABI-faithful shape, the way the interface
projects an `@com` protocol that lowers to the COM vtable.
`emit` now dispatches on the row's kind (`found[4]`): a struct through
`structure`, an enum through `enumeration`, a delegate through `delegation`, and
an interface through `interface` (the former inline body, now its own half),
each rendered under exactly one of the template's `{{#struct}}`/`{{#enum}}`/
`{{#delegate}}`/`{{#interface}}` sections. The `walk` seeds and the `requires`
bases carry the kind at index 4 so the walk and emit dispatch on the same column
a `references` row already has.
The projected shapes match how the target language's import models them. A
struct is an `@frozen` struct, its guaranteed layout the C/C++ record it mirrors
field for field, with a public memberwise initialiser (the synthesised one is
internal, so a cross-module caller could not otherwise construct it). Only
instance fields are storage: a static or literal field (the `fdStatic` bit) is
dropped, and the dependency walk applies the same filter so a type named only by
a dropped field is not pulled in. A value type whose ABI layout `@frozen` cannot
reproduce — an explicit layout, a non-default packing, or a declared class size
— is rejected as a frontier rather than misprojected; the `layout` query returns
a row only for such a type (`ClassLayout` is an optional table the adapter now
synthesises empty when absent). An enum projects to an explicitly-stored
raw-value struct newtype, because a native `enum E: <underlying>` does not carry
its raw type's ABI width; a `[flags]` enum (a `System.FlagsAttribute`, detected
through the overridable `flags` query) is the same newtype refined to
`OptionSet`. The `value__` storage field is found by its raw metadata name, so a
`SANITIZE` override respelling it does not drop the enum to the `i4` fallback
width, and each member's value is the constant `value(field:)` already formats
per signedness. A delegate is an `@com(interface:)` protocol carrying a single
`Invoke`, decoding its runtime IID through the `guid` query.
Signature adjacency (E3/E6/E7) runs per kind — an interface over its methods, a
struct over its instance fields, a delegate over its `Invoke` — resolving each
referenced type through `references` by the exact row it was named through,
never by (namespace, name), so two same-named nested types are not conflated. A
resolved runtime `class` stays a frontier; an external `TypeRef`-only reference
resolves to nothing and drops; a nongeneric interface or delegate bearing no
`GuidAttribute` — whose `@com` shape would spell a GUID-less `""` — is dropped,
while a generic one (no static IID by design) is kept and renders through the
generic arm. A reached type the language import already provides — a
`Dialect.known` identity such as `HRESULT` — is a frontier the closure emits no
wrapper for, since the consumer has it from the import.
A signature-named value type or delegate emits at top level by its bare name.
Metadata nesting (`Outer.Inner`) and the namespace disambiguation of same-named
value types are follow-ups; this change lands the per-kind projections and the
signature closure on the unique-name path.
Integration tests over hand-built fixtures cover a struct-returning method (the
`@frozen` struct with its public initialiser, emitted before the interface), an
enum parameter (a stored newtype, a duplicate raw value as two constants, and a
`[flags]` `OptionSet`), a delegate parameter (its `@com` protocol and decoded
IID, plus a parameterised delegate kept through its generic arm and a
keyword-named generic parameter escaped), and a signature-named interface
enqueued and emitted; further tests pin an auto/explicit/packed/sized struct and
a static struct field each dropped, a GUID-less nongeneric interface and a
language-provided type each frontiered, and a unique-named value type emitted
bare with no namespace.
The `fields` render query gains `Flags` and raw-name columns so the walk and the
struct render drop a static field and the enum render finds its `value__`
storage. Render-query shadowing is a supported extension point, though, so a `-I`
override carrying the former two-column shape (`Id`, `Name`) is tolerated rather
than trapping on the absent columns: a field with no `Flags` counts as instance
storage, as it did before the columns existed, and the raw-name read falls back
to the escaped `Name`.
0 commit comments