Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Desugar type use abbreviation #16

Merged
merged 16 commits into from Jul 20, 2023
Merged

Desugar type use abbreviation #16

merged 16 commits into from Jul 20, 2023

Conversation

tomstuart
Copy link
Owner

As an abbreviation, a type use can be replaced by inline parameter and result declarations: instead of writing e.g. (func (type $t) …) and defining $t elsewhere in the module with (type $t (func (param i32) (result i64))), we can write the more concise and expressive (func (param i32) (result i64) …).

To support this abbreviation, a WebAssembly implementation must automatically insert a type index referring either to a matching type definition in the current module (e.g. $t above) or a newly-inserted type definition if no matching one exists.

This PR implements desugaring for this abbreviation in the preprocessor and removes support for it from the AST parser. It relies upon machinery introduced in #14 and #15 which allows type definitions to be collected while preprocessing a module’s fields and then provided to the deferred result to yield the final S-expressions.

This is where type definitions actually originate from. I’m choosing to
represent a type definition with its originating field verbatim (versus
e.g. only the function type) so that we can use the same array to both
look up existing type definitions and store any new ones which get
generated as a result of desugaring the type use abbreviation.
We’ve filled in the type definitions returned by #process_type_definition,
and we know that all other fields generate no immediate type
definitions. (Notwithstanding the effect of desugaring the type use
abbreviation, but we haven’t implemented that yet.)
The real type definition lists (sometimes legitimately empty!) have now
been filled in everywhere, so we no longer need a dummy value.
When no `(type …)` is present we’ll need to automatically insert one
[0], which is going to be more complicated than simply passing through
the existing one verbatim and desugaring its parameters & results, so it
needs a dedicated code path.

[0] https://webassembly.github.io/spec/core/text/modules.html#abbreviations
This is the simplest case of the type use abbreviation [0]: if we can
find an existing type definition whose type is exactly the same as the
one being used, we insert a reference to that definition.

We’re not yet accounting for (irrelevant) parameter identifier
mismatches, nor for the case where no matching definition is found.

This commit includes a lot of tests. Earlier commits have already
plumbed the type definitions into every place where a type use can
syntactically occur, but this is our first opportunity to check that
it’s actually worked in all those cases.

[0] https://webassembly.github.io/spec/core/text/modules.html#abbreviations
This allows us to extract the parameter and result declarations and
compare them separately, rather than comparing the function type
verbatim. This change is a prerequisite for ignoring parameter
identifiers, which we’ll do next.
This ignores identifiers in type definitions and uses, allowing them to
match even when the identifiers don’t.
Per the spec [0], “if no such index exists, then a new type definition
[…] is inserted at the end of the module”. We’re doing this by mutating
the incoming array of type definitions, which isn’t particularly elegant
but gets the job done without having to worry about threading another
result value (i.e. a separate array of generated type definitions)
through the field-processing methods.

We can’t add tests for this commit’s behaviour in isolation because the
resulting program is syntactically invalid: we’re inserting the index of
a type definition which hasn’t yet been added to the module. In the next
commit we’ll also insert the generated definitions at the end of the
module and add some tests to check that both halves of the solution are
working together correctly.

[0] https://webassembly.github.io/spec/core/text/modules.html#abbreviations
We need a deep copy of the generated type definitions because they
contain object references to parameters and results elsewhere in the
source S-expression; since the AST parser consumes the S-expression
destructively, any structural sharing will cause serious problems.

The approach of “count the type definitions before and after processing
the fields, and the difference between these two counts must be the
newly-generated definitions” is a bit hacky, but it gives us the
behaviour we need. In future we should consider a more elegant approach
to this whole problem of modifying different parts of the S-expression
during preprocessing.
Now that the preprocessor is desugaring all legitimate occurrences of
the type use abbreviation, it’s safe for the parser to assume that a
block type contains an optional value type [0] if the `type` keyword is
missing.

[0] https://webassembly.github.io/spec/core/text/instructions.html#text-blocktype
This is desugared by the preprocessor now.
This is desugared by the preprocessor now.
The preprocessor has already generated all necessary type definitions
while desugaring the type use abbreviation.
The initial context is no longer mutated during parsing because the
preprocessor has already done the work to insert whatever type
definitions are needed, so we don’t need to worry about allowing methods
to update it. We’re therefore switching to an explicit argument since
it’s clearer and easier to understand.

For now we have to be careful to use the modified context (i.e.
`self.context`) inside #with_context blocks instead of the `context`
local variable. In the next commit we’ll be able to undo this when we
remove #with_context calls entirely.
The previous commit switched to an explicit `context:` argument, so we
no longer need to update the current context.
…arser

We now pass the context around explicitly.
@tomstuart tomstuart merged commit 59e4f32 into main Jul 20, 2023
1 check passed
@tomstuart tomstuart deleted the desugar-type-uses branch July 20, 2023 16:47
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.

None yet

1 participant