Skip to content

gsc: keep named-tuple-bearing generic arguments symbolic at every projection gate (ADR-0172) - #3632

Merged
DavidObando merged 1 commit into
mainfrom
fix/nested-named-tuple-projection
Aug 29, 2026
Merged

gsc: keep named-tuple-bearing generic arguments symbolic at every projection gate (ADR-0172)#3632
DavidObando merged 1 commit into
mainfrom
fix/nested-named-tuple-projection

Conversation

@DavidObando

Copy link
Copy Markdown
Owner

Fixes the remaining systemic failure in the second 2026-08-29 selfmig nightly (run 33260247720, which already included #3630/#3631): 32/52 green against floor 33, with migrated Cs2Gs.Translator failing GS0158 Cannot find member Symbol / GS0159 Cannot find function Contains / GS0116 not indexable at CSharpToGSharpTranslator.Constructors.gs:1537-38candidate[0].Symbol and reach[head].Contains(symbol) over List[List[(syntax …, symbol …)]] — cascading into 11 downstream apps.

Root cause

A named tuple nested inside a generic type argument shares its CLR backing with the unnamed shape (ValueTuple<…>), so any keep-symbolic gate that consults only RequiresSymbolicProjection (or a direct is TupleTypeSymbol) collapses the constructed type to its erased CLR form — and the element names vanish, so member access by name fails. The #3622 projection-gate family covered direct named-tuple arguments (List[(a, b)], one level), but not List[List[(a, b)]], List[[](a, b)], or Dictionary[K, (a, b)] reached through construction, indexing, or iteration. Minimal repro (failed before, runs now):

let groups = List[List[(a int32, b string)]]()
…
groups[0][0].a          // was GS0158: Cannot find member a

Fix

Widened six keep-symbolic gates with TypeSymbol.ContainsNamedTupleElements (already recursive through every constructor shape): the generic ctor-call type-argument resolution (the erasure at the root), the constructed-generic receiver form, the indexer element substitution + its #2365 recursive projection filter, the generic-return construction and indexer property projection in MemberLookup, the conversion-classifier parameter substitution, and the type-clause ProjectGenericArgument. Deliberately did not widen ImportedTypeSymbol.HasSubstitutableTypeArgument itself — it feeds conversion/lowering decisions with broader meaning, and widening it regressed working cases during investigation.

Verification

  • New NestedNamedTupleProjectionTests (4 end-to-end oracle tests) pin all shapes, including the exact selfmig iteration+index+member chain with an imported interface element type.
  • Full Core.Tests: 8218/8218 passed.
  • Local selfmig proof over the cs2gs subtree: Cs2Gs.Translator's three real compile errors are gone (the only remaining local failures are the known subtree-proof artifact — GSharpRoundTrip.gs referencing GSharp.Core, which the subtree run excludes from migration; the nightly migrates it).

With this plus #3630/#3631, the next nightly should clear the b7a89d8f22f8/0a665d0d062c/ebe7e1f2f6f8 fingerprint family. The !! ceiling breach (17516 vs 17400) is a separate ratchet question.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Nng28yiBdPVdeML7mSZphs

…jection gate (ADR-0172)

The 2026-08-29 nightly (run 33260247720, post-#3631) still failed
32/52 vs floor 33: migrated Cs2Gs.Translator hit GS0158/GS0159/GS0116 at
CSharpToGSharpTranslator.Constructors.gs:1537-38 — `candidate[0].Symbol`
and `reach[head].Contains(...)` over
`List[List[(syntax LocalFunctionStatementSyntax, symbol IMethodSymbol)]]`
— and the errors cascaded into 11 downstream apps.

Root cause: a named tuple nested INSIDE a generic type argument shares
its CLR backing with the unnamed shape, so every keep-symbolic decision
that consults only RequiresSymbolicProjection (or a direct
`is TupleTypeSymbol`) collapsed the constructed type to its erased CLR
form and the element names vanished; member access by name then failed.
The #3622 projection-gate family covered direct named-tuple arguments
(`List[(a, b)]` one level deep) but not `List[List[(a, b)]]`,
`List[[](a, b)]`, or `Dictionary[K, (a, b)]` reached through
construction, indexing, or iteration.

Widened six gates with TypeSymbol.ContainsNamedTupleElements (which
already recurses through every constructor shape):

- ExpressionBinder.Calls.cs TryResolveClrConstructionTypeArgs — the
  generic ctor call kept no symbolic view, erasing at the root.
- ExpressionBinder.Access.Accessor.cs constructed-generic receiver —
  same for the `Type[args]` receiver form.
- ExpressionBinder.Access.MemberLookup.cs MapErasedIndexerElementType —
  indexer elements skipped substitution when HasSubstitutableTypeArgument
  saw no direct named tuple; also the #2365 recursive projection filter.
- MemberLookup.cs generic-return construction (anyParam) and the indexer
  property projection.
- ConversionClassifier.cs parameter substitution.
- Binder.cs ProjectGenericArgument (type-clause path).

New NestedNamedTupleProjectionTests pin all four shapes end to end,
including the exact selfmig iteration+index+member chain. Full
Core.Tests green (8218), local selfmig proof shows the three real
Translator compile errors gone.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nng28yiBdPVdeML7mSZphs
@DavidObando
DavidObando merged commit 7379da6 into main Aug 29, 2026
36 checks passed
@DavidObando
DavidObando deleted the fix/nested-named-tuple-projection branch August 29, 2026 17:35
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.

1 participant