Repository navigation
Exact func externtype types - #102
Conversation
And struct.new_default_desc. Also update the valiation for struct.new and struct.new_default to require empty descriptors. Add an explanation of expansion to desctype to the validation conventions section and teach SpecTec about the new ExpandDesc relation to avoid errors during rendering.
Update the syntax of func externtypes and func types in the typing context to include exactness. This allows specifying exact function imports and properly typing ref.func as exact for exact imports and defined functions and otherwise as inexact.
| def $exactheaptype(exact, typeuse) : heaptype | ||
|
|
||
| def $exactheaptype(EXACT, typeuse) = EXACT typeuse | ||
| def $exactheaptype(INEXACT, typeuse) = typeuse |
There was a problem hiding this comment.
Having the externtype and context store explicitly EXACT or INEXACT exactness instead of just containing an EXACT? is important for ensuring that both cases are handled everywhere. At the same time, it is annoying because heaptype has a different representation of exactness (... | typeuse | EXACT typeuse), so we require this auxiliary conversion function.
Do you have a recommendation for how to simplify this? I'm thinking that maybe we should be using heaptype instead of deftype/typeuse in the externtype and context definitions because heaptype already has exactness information built-in, and we would be able to avoid conversions that way. But then we might need a new form of expansion that can fish the type use out of both exact and inexact heap types instead :/
Previously the definition of `heaptype` was `... | EXACT typeuse | typeuse`, but this made it impossible to treat the exactness as a variable. Refactor the definition to `... | _HT exact? typeuse` instead. This is similar to how nullability is treated in reference types, except that the `_HT` tag will not be displayed in the rendered spec.
…nctype Update the typing context to store heap types for functions.
rossberg
left a comment
There was a problem hiding this comment.
Generalising the syntax of function types to arbitrary heaptypes is a bit nasty. Maybe we need an auxiliary form of type representing qualified type uses like exact? typeuse? Having a name and meta variable for that might also avoid the intrusive appearance of the _HT constructor everywhere, like in the other PR.
|
Oh interesting, I used to have an |
# Conflicts: # specification/wasm-latest/1.2-syntax.types.spectec # specification/wasm-latest/1.3-syntax.instructions.spectec # spectec/src/backend-prose/gen.ml # spectec/test-frontend/TEST.md
…nctype # Conflicts: # document/core/valid/conventions.rst # specification/wasm-latest/1.2-syntax.types.spectec # specification/wasm-latest/2.4-validation.modules.spectec # spectec/test-frontend/TEST.md
|
@rossberg, I updated the approach here to match your suggestion in #102 (review). This is ready for another look. |
| C |- FUNC x : FUNC exact? dt | ||
| -- if C.FUNCS[x] = exact? dt |
There was a problem hiding this comment.
| C |- FUNC x : FUNC exact? dt | |
| -- if C.FUNCS[x] = exact? dt | |
| C |- FUNC x : FUNC edt | |
| -- if C.FUNCS[x] = edt |
There was a problem hiding this comment.
Same issue here. We can't use an exactdeftype here because externtype is defined as ... | FUNC exact? typeuse. The same fix might apply.
| -- (Externaddr_ok: s |- FUNC funcaddr : FUNC exact? dt_F)* | ||
| -- if edt_F* = (exact? dt_F)* |
There was a problem hiding this comment.
| -- (Externaddr_ok: s |- FUNC funcaddr : FUNC exact? dt_F)* | |
| -- if edt_F* = (exact? dt_F)* | |
| -- (Externaddr_ok: s |- FUNC funcaddr : FUNC exactdeftype)* |
There was a problem hiding this comment.
AI explanation for the change here, if you're interested:
Defining syntax
exacttypeuse = exact? typeuseand using_HT exacttypeusein heaptype causes non-exact heap types like_HT xto elaborate with a nested CaseE for exacttypeuse, whose mixop ([None; None; None]) has no leading constructor atom (hd = None).Previously in spectec/src/backend-prose/render.ml:
- case_to_el_exprs only stripped EpsE (omitted optional arguments) when hd <> None (in order to preserve \epsilon on the LHS of infix notations like \epsilon \rightarrow t^\ast, where elal is None :: Some _ :: _).
- al_to_el_expr wrapped any non-infix CaseE with non-empty elel in ParenE.
As a result, headless juxtaposition types like
exacttypeuserendered omitted optionals as (\epsilon~x) in generated prose (the same issue also affectedglobaltype = mut? valtypeandfieldtype = mut? storagetypein test-prose/TEST.md, which rendered immutable types as (\epsilon~t) and (\epsilon~zt)).Stripping EpsE for all non-infix mixops (not is_infix, where is_infix is None :: Some _ :: _) and omitting ParenE when a headless mixop reduces to a single element (None :: _, , []) fixes the prose rendering.
| -- (Memtype_ok: C_0 |- mt : OK)* | ||
| -- (Tabletype_ok: C_0 |- tt : OK)* | ||
| -- if edt_F* = (exact? dt_F)* | ||
| -- if edt* = (exact? dt_F)* |
There was a problem hiding this comment.
This line might suggest that we should introduce Exactdeftype_ok for completeness.
There was a problem hiding this comment.
Unless we also add Expand_exactdt, we'll still need this destructing line. The Exactdeftype_ok line would just replace the Deftype_ok line below. I'm not sure that's worth it.
There was a problem hiding this comment.
I uploaded #117 so you can see what that looks like. I'm happy to include those changes here or drop them, whatever you prefer.
There was a problem hiding this comment.
Ah okay, you're right. In that case I agree it's not worth it.
| C |- REF.FUNC x : eps -> (REF (_HT exact? dt)) | ||
| -- if C.FUNCS[x] = exact? dt |
There was a problem hiding this comment.
The crash shouldn't be, but yes, you can only combine proper variant types that way.
The trick would be to move the _HT constructor (under some appropriate rename) into exacttypeuse, which turns it into a variant type. Then the constructor is only needed when an exacttypeuse is de/composed, and not each time a typeuse is injected into heaptype.
|
@rossberg, any other comments on this one? |
rossberg
left a comment
There was a problem hiding this comment.
Ah, sorry, I wasn't sure if you planned to also do the _HT change here. LGTM
I looked into this, but typeuse isn't a subtype of exacttypeuse, so injecting a typeuse into heaptype still requires using a constructor. As a result, we can remove the constructor in the two places that inject an exactdeftype variable into heaptype ( Alternatively, #119 hacks up spectec to make the _HT unnecessary. |
|
Yeah, I suppose the rules rarely ever care about typeuses that are not type indices, because those don't arise during validation. But thanks for looking into it anyway. |
Update the syntax of func externtypes and func types in the typing context to include exactness. This allows specifying exact function imports and properly typing ref.func as exact for exact imports and defined functions and otherwise as inexact.