feat: parenthetical encoder annotation for public actor methods#5996
Draft
feat: parenthetical encoder annotation for public actor methods#5996
actor methods#5996Conversation
actor methods
Adds syntax `(with encoder = <func>) public func name() : async T = ...` to annotate the serialization encoder for an actor method's return value. - `vis'` type gains `exp option` (the annotation) alongside the deprecation string; moved into the `exp` mutual recursion group to resolve the forward-reference - Parser: `vis → parenthetical PUBLIC` with `%prec VIS_NO_PAREN` to resolve the 3 shift/reduce conflicts from the nullable vis prefix; `--strict` preserved - Type checker: `check_vis_parenthetical` validates the encoder in checking mode against the expected type `ret_typ → Blob` (async peeled via `Promises`/`ts2`); non-method placements warn with M0212; effects forbidden (M0215) - Test: `test/run-drun/parenthetical-public.mo` Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…freedom IR representation: - `FuncE` gains an 8th `exp option` field for the encoder (None everywhere except public actor methods with a `(with encoder = …)` annotation) - All IR passes, rename, subst_var, arrange, freevars, interpreter, and both codegens updated: pass-through or wildcard `_enc` as appropriate Desugaring: - `build_encoders` mirrors `build_stabs` to correctly pair each IR dec with its optional encoder across IncludeD/TypD expansion - In `build_actor` the encoder expression is extracted from the vis parenthetical's `encoder` field and injected into the IR `FuncE` slot Checking: - IR type-checker (`check_ir.ml`): verifies encoder type is `ret_typ → Blob` and effect is `T.Triv` - Source type-checker (`typing.ml`): `check_vis_parenthetical` additionally guards `note_eff = T.Triv`, emitting M0215 if the annotation has effects Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Refactors `ICReplyPrim` to carry an `exp option` encoder slot instead of using a mutable `reply_encoder` field on the compilation environment. The encoder expression (user-supplied `T -> Blob` function) is injected by `desugar.ml`'s `build_actor` into the `FuncE` IR node, propagated through all IR passes (`erase_typ_field`, `show`, `eq`, `await`, `async`), and consumed by `async.ml`'s CPS transform to build the reply continuation `k` as `ICReplyPrim (ts, Some enc')` instead of the default Candid path. Both classical and enhanced backends call the encoder closure and send the raw blob bytes via `IC.reply_with_data`, bypassing Candid serialization. `arrange_ir` and `check_ir` are updated to print/validate the encoder. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
(with encoder = <func>) public func name() : async T = ...syntax, whereencoder : T -> Blobreplaces Candid serialization for the method's replyFuncEIR node at desugaring (build_actor), propagated through all IR passes, and threaded intoICReplyPrim (ts, Some enc)by the async CPS transform inasync.mlIC.reply_with_data, bypassing Candidcheck_irvalidates that the encoder has the right type (T -> Blob) and is effect-freeTest plan
make -C test/run-drun parenthetical-public.onlypasses🤖 Generated with Claude Code