Compiled: default/optional params on class members (#705 #723 #737 #739 #738)#787
Merged
Conversation
#738) Closes the compiled-mode default/optional-parameter cluster for class members. The interpreter was already correct; this brings compiled mode to parity. #723/#705 — value-type defaults now fire on instance and static methods. ParameterTypeResolver widens a value-type-defaulted param to an `object` slot so the entry prologue can observe the `$Undefined` sentinel. Static methods widen directly (non-virtual). Instance methods widen *hierarchy-consistently*: a position is widened across the whole override group when any member makes it an optional value-type param, so every override keeps one CLR signature and virtual dispatch is preserved (regression-guarded). Adds TypeMap.ClassTypes. #737 — generator and async-generator methods now run a default-parameter prologue (GeneratorMoveNextEmitter / AsyncGeneratorMoveNextEmitter), placed after the state switch so it runs once on initial entry. #739 — a direct instance/static method or constructor call pads an omitted trailing optional with the `undefined` sentinel, not CLR null, so `typeof` reads "undefined". Centralized as a shared EmitOmittedArgument helper (object slot -> $Undefined, else CLR default) across the call-emission sites. #738 — under `--compile --ref-asm`, a function-expression value-call shifted its arguments because the reference-assembly rewrite strips parameter names, breaking the runtime `params[0].Name == "__this"` receiver-slot check. Adds a `$ExpectsThis` marker attribute (survives the rewrite) that backstops the name check in $TSFunction's _expectsThis computation. Also fixes a latent generator/async nullish-coalescing bug surfaced by the correct #739 padding: StateMachineEmitHelpers.EmitNullishCoalescing only tested CLR null and missed the `$Undefined` sentinel, so `x ?? rhs` returned undefined inside a state machine (manifesting as an infinite loop in the real yaml parser's `error ?? stack.pop()`). Now mirrors the sync ILEmitter override. Filed #778 (compiled static generator methods don't compile — pre-existing). Full suite green (13173).
This was referenced Jun 16, 2026
Closed
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.
Closes the compiled-mode default/optional-parameter cluster for class members. The interpreter was already correct; this brings compiled mode to parity. All run in both modes to pin interp/compiler parity.
Fixes #705, #723, #737, #739, #738.
What was broken
In compiled mode, class-member default/optional parameters were mishandled: value-type defaults never fired on methods, generator/async-generator methods ran no default prologue at all, omitted optionals read as CLR
null(sotypeofwas"object"), and a--ref-asmfunction-expression value-call shifted its arguments.Changes
#723 / #705 — value-type defaults fire on instance & static methods.
ParameterTypeResolverwidens a value-type-defaulted param to anobjectslot so the entry prologue can observe the$Undefinedsentinel (adouble/boolslot cannot — it coerces toNaN/false).Override_DerivedAddsDefault_StillOverrides). Reference-type defaults are left alone (they already fire via null-padding without a slot change). Adds aTypeMap.ClassTypesaccessor for the override-group walk.#737 — generator & async-generator method defaults.
GeneratorMoveNextEmitterandAsyncGeneratorMoveNextEmitternow run a default-parameter prologue (operating on the hoisted state-machine fields), placed right after the state-dispatch switch so it runs exactly once on initial entry (resume states jump past it; no guard field needed).#739 — omitted optional reads
undefined, not null. A direct instance/static method or constructor call pads an omitted trailing optional param with the$Undefinedsentinel instead of CLR null. Centralized as a sharedEmitOmittedArgument(slot)helper (object slot →$Undefined, else CLR default) applied across the call-emission sites (sync + async/generator + call handlers).#738 —
--ref-asmvalue-call no longer shifts arguments. Root cause: the reference-assembly rewrite (externalNickNa.PEPacker) strips parameter names, breaking the runtimeparams[0].Name == "__this"receiver-slot check in$TSFunction, so the synthetic__thisslot was miscounted as a real argument. Adds a$ExpectsThismarker attribute (custom attributes survive the rewrite) applied at the function-expression/arrow__thissites;EmitComputeExpectsThisnow OR-sIsDefined($ExpectsThis)with the name check — identical behavior under--compile, fixed under--ref-asm.Bonus fix — generator/async
??ignored the$Undefinedsentinel. The correct #739 padding surfaced a latent state-machine bug:StateMachineEmitHelpers.EmitNullishCoalescingonly tested CLR null (brfalse) and missed$Undefined(a non-null reference), sox ?? rhsreturnedundefinedinside a generator/async body. In the realyamlparser this was an infinite loop (*pop(error) { error ?? stack.pop() }with an omittederrornever popped the stack). Now mirrors the syncILEmitteroverride (also testsisinst $Undefined).Testing
ClassMethodDefaultParameterTests(instance/static/generator/async-generator value-type defaults, omitted-optionaltypeof, the override omit-fires-derived-default case, the generator??regression, and an IL-verification guard).ReferenceAssemblyTests.RefAsm_FunctionExpressionValueCall_DoesNotShiftArguments(runtime).Follow-up filed
static *m()) fail with “Yield not supported in this context” (pre-existing;EmitStaticMethodBodyhas noIsGeneratorrouting). Once routed, they’ll pick up the Compiled: value-type default parameters on (virtual) instance & static methods are not applied #737 prologue automatically.