G# + cs2gs: generalized variadic carriers — ...X[T] ≡ C# params X<T> (ADR-0173, #3627) - #3630
Merged
Conversation
…T>` (ADR-0173, #3627) The type written after `...` is now interpreted like C#13 params collections: when it is a supported collection shape it is the CARRIER (the exact CLR parameter type), else it stays the ADR-0101 element type with the implicit slice carrier. Supported carriers: `...[]T` (explicit array), `List[T]`, the five IEnumerable-family interfaces, `Span[T]`, `ReadOnlySpan[T]`. gsc: - VariadicCarriers resolver shared by all eight ADR-0101/0102 declaration sites (functions, methods, ctors, primary ctors, interfaces, delegates, lambdas, function-type clauses). - Call sites mirror C#: element coercion (#1493) then pack — array as-is, interface upcast, `new List[T](T[])`, span `T[]` ctor; a single trailing argument already convertible to the carrier passes through. - Metadata: array family keeps [ParamArrayAttribute]; other carriers stamp C#13 [ParamCollectionAttribute], so csc sees `params X<T>`. - New GS0544 when a List/span carrier's element is a same-compilation erased type with no closed CLR construction shape. cs2gs: - `params X<T>` declarations translate to `...X[T]` for supported carriers — retiring the `params ReadOnlySpan<T>` gap (#3627), the last Cs2Gs.Tests translate wall in the selfmig nightly. - Expanded calls on source-declared callees stay in natural form (gsc packs); referenced/BCL callees keep the existing lowerings. - Array params with carrier-shaped elements keep explicit spellings (`params byte[][]` → `...[][]uint8`) to avoid reinterpretation. - The deliberately untranslatable `params HashSet<int>` test fixture is now compiled in-memory so Cs2Gs.Tests' own source stays translatable. Breaking note (ADR-0173): carrier-shaped `...X` spellings are reinterpreted; no in-tree usage existed, escape hatch is `...[]X`. Fixes #3627 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nng28yiBdPVdeML7mSZphs
DavidObando
enabled auto-merge (squash)
August 29, 2026 07:32
…load context; ADR-0173 allowlist rationale
The List/span pack path resolved the element CLR type via
GetEffectiveClrType (runtime typeofs) and passed it into the carrier's
GetConstructor — under the SDK compile path the carrier comes from a
MetadataLoadContext, so mixing contexts threw ArgumentException ("Type
must be a type provided by the MetadataLoadContext") and failed the
cs2gs-corpus CI gate on G09-Functions-Console. The element is now taken
from the carrier's own generic arguments, which are always in the
carrier's context. In-process tests (runtime reflection end to end)
could not catch this; the corpus diagnostic-run repro is green now.
Also records in ADR-0173 WHY the carrier set is a closed allowlist
versus C#13's open collection-expression rule (ADR-0101 element-spelling
collision + no collection-expression lowering), and lists widening it as
explicit future work.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nng28yiBdPVdeML7mSZphs
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.
Fixes #3627 — the
params ReadOnlySpan<T>cs2gs gap, the last Cs2Gs.Tests translate wall in the #3501 selfmig nightly. Implements the agreed scope:...X[T]becomes semantically equivalent to C#13params X<T>, with no magicspantypes or new sugar (design for those stays in #3627's discussion).Semantics (ADR-0173)
The type written after
...is interpreted like C#'s params type:...[]T(explicit array),...List[T], the five IEnumerable-family interfaces (IEnumerable/ICollection/IList/IReadOnlyCollection/IReadOnlyList),...Span[T],...ReadOnlySpan[T]....int32≡params int[];...HashSet[int32]is still a params array of HashSets (HashSet is not a supported carrier).Call sites mirror C#: expanded trailing args are element-coerced (#1493 rules) and packed — array as-is, interface upcast,
new List[T](T[]), spanT[]ctor (heap-allocating v1); a single trailing arg already convertible to the carrier passes through unchanged. Parser needed zero changes.Metadata: array family keeps
[ParamArrayAttribute]; every other carrier stamps C#13's[ParamCollectionAttribute], so csc consumers see a genuineparams X<T>member (verified by reflection + runtime invoke witness).New GS0544 when a List/span carrier's element is a same-compilation erased type with no closed CLR construction shape (the array carrier still covers that case).
cs2gs
params X<T>declarations translate to...X[T]for supported carriers — spans included, retiring the gap.[ParamCollection]expanded calls are a recorded follow-up; pass-through works).params byte[][]→...[][]uint8,params List<int>[]→...[]List[int32]) so they don't reinterpret.params HashSet<int>fixture in Cs2Gs.Tests is now compiled in-memory by its test, so the project's own source is fully translatable.Breaking-change note
Carrier-shaped
...Xspellings are reinterpreted (previously: params array ofXelements). No in-tree G# used such spellings; the escape hatch for the old meaning is...[]X. Bare...Tfor non-collectionTis unchanged.Coverage
One shared resolver (
VariadicCarriers) feeds all eight ADR-0101/0102 declaration sites: free functions, methods, constructors, primary constructors, interface methods, named delegates, lambdas, and function-type clauses.Verification
Issue3627VariadicCarrierTests(13 binder/eval tests) +Issue3627VariadicCarrierEmitTests(attribute reflection, ILVerify, E2E run) — all green.Issue1727params byte[][],Issue3466params-collection demotion) — first exposed a real translator bug (array-of-array spelling), both fixed and green; Issue1901/Issue3460 suites green.samples/VariadicCarriers.gs+ golden; PE baseline regenerated (+1 entry).Docs
ADR-0173 (new), GS0544 in diagnostics docs + website mirror, spec variadic section, coverage-matrix inventory row (regenerated via
cs2gs coverage --write).🤖 Generated with Claude Code
https://claude.ai/code/session_01Nng28yiBdPVdeML7mSZphs