Skip to content

[Code review] Compiler changes for extension members on typeless receivers#83407

Draft
CyrusNajmabadi wants to merge 7 commits intodotnet:mainfrom
CyrusNajmabadi:extension-members-on-typeless-receivers/code-review
Draft

[Code review] Compiler changes for extension members on typeless receivers#83407
CyrusNajmabadi wants to merge 7 commits intodotnet:mainfrom
CyrusNajmabadi:extension-members-on-typeless-receivers/code-review

Conversation

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor

@CyrusNajmabadi CyrusNajmabadi commented Apr 25, 2026

Championed issue: TBD
Speclet: TBD
Test plan: TBD

Summary

Internal review aid. Combines the production code changes from the entire stack of upstream draft PRs into a single self-contained commit so the binder + feature flag changes can be reviewed end-to-end without sifting through test additions. Will be closed once the code is approved; the upstream stack remains intact.

Scope (20 files, no new test files):

  • Binder_Expressions.cs - `TryBindMemberAccessOnTypelessReceiver` helper + inclusion list, `GetExtensionMemberAccess` relaxation, `BindInstanceMemberAccess` typeless-`leftType` branch, `ResolveExtension` assertion / pruning relaxations.
  • Binder_Invocation.cs - skip `ReplaceTypeOrValueReceiver` for typeless extension receivers (covers both classic `invokedAsExtensionMethod` and modern `isExtensionBlockMethod` paths).
  • ConversionsBase.cs - classic extension this-arg conversion fallback to `ClassifyImplicitConversionFromExpression` when the source has no type.
  • OverloadResolution.cs - skip the strict identity / reference / boxing whitelist for the extension this-arg when `argument.Type is null`.
  • MessageID + CSharpResources.resx + 13 xlf - new `IDS_FeatureExtensionMembersOnTypelessReceivers` preview feature flag.
  • CollectionExpressionTests.cs - 8 obsolete pre-feature error expectations updated to match the new feature behavior.

Mirrors the union of the code in:

Microsoft Reviewers: Open in CodeFlow

@dotnet-policy-service dotnet-policy-service Bot added the Community The pull request was submitted by a contributor who is not a Microsoft employee. label Apr 25, 2026
…view-only)

Combines the production code from all stacked support PRs into a single
commit for end-to-end review. Excludes the new test files added by the
test PRs in the stack; only the binder, feature-flag, and necessary
obsolete-test expectation updates are here.

Files in scope:

  - Binder_Expressions.cs: TryBindMemberAccessOnTypelessReceiver helper +
    inclusion list, GetExtensionMemberAccess relaxation, BindInstanceMember
    Access typeless-leftType branch, ResolveExtension assertion / pruning
    relaxations.
  - Binder_Invocation.cs: skip ReplaceTypeOrValueReceiver for typeless
    extension receivers (covers both classic and modern extension paths).
  - ConversionsBase.cs: classic-extension this-arg conversion fallback to
    ClassifyImplicitConversionFromExpression for typeless source.
  - OverloadResolution.cs: skip strict identity/reference/boxing whitelist
    when the extension this-arg has no type.
  - MessageID + resx + 13 xlf: IDS_FeatureExtensionMembersOnTypelessReceivers
    feature flag.
  - CollectionExpressionTests.cs: 8 obsolete pre-feature error expectations
    updated to match the new feature behavior.

Co-authored-by: Isaac
@CyrusNajmabadi CyrusNajmabadi force-pushed the extension-members-on-typeless-receivers/code-review branch from 289aae3 to 87da92e Compare April 25, 2026 23:37
Cyrus Najmabadi added 6 commits April 26, 2026 02:19
Aligns the typeless-extension feature gate with GetMethodGroupDelegateType
so we treat the same set of method groups as "valid receiver" in both
places, and excludes inaccessible / ambiguous lookups that the previous
LookupError-only check let through.

Co-authored-by: Isaac
… feature gate

Previously, every member access on a supported typeless form
(`[expr].M`, `(() => {}).M`, etc.) routed through the new feature path,
which meant any unrelated typo on a typeless receiver got the misleading
"feature is in Preview, upgrade to use it" diagnostic on older language
versions even when no extension would have applied.

Now the helper first checks whether at least one extension member named
`M` is in scope. If not, it returns null and lets the existing
kind-specific rejections produce their pre-feature diagnostics. If a
candidate exists, the feature gate fires and binding proceeds - even
when the call ultimately fails on argument matching, the user did write
a typeless-extension call and should be told why it requires a
language-version upgrade.

Co-authored-by: Isaac
…GroupReceiver doc

- Move typeArgumentsSyntax / typeArgumentsWithAnnotations past the speculative
  HasExtensionMemberCandidateInScope check so we don't pay BindTypeArguments
  when speculation returns null.
- Collapse the type-args conditionals onto single lines using property-pattern
  matching.
- Clarify IsValidMethodGroupReceiver doc comment - it's the same conceptual
  ResultKind == Viable gate that GetUniqueSignatureFromMethodGroup applies
  inline, not a shared helper.

Co-authored-by: Isaac
The helper was a single boolean expression; inlining it as a property
pattern (`when boundLeft is BoundMethodGroup { ResultKind: Viable,
Methods.Length: > 0 }`) keeps the switch self-contained and removes
indirection. The reasoning that previously lived in the helper's doc
comment moves to a comment above the case.

Co-authored-by: Isaac
For the new code in TryBindMemberAccessOnTypelessReceiver and
HasExtensionMemberCandidateInScope:

- Single-line condition + single-line body if-statements no longer wrap
  the body in braces.
- Block-like statements are followed by a blank line unless they are the
  last statement before a closing brace.

Co-authored-by: Isaac
…s receiver

BindMethodGroupInvocation's dynamic-extension error path asserted that
methodGroup.ReceiverOpt.Type was non-null when emitting CS1973
(ERR_BadArgTypeDynamicExtension). For typeless receivers that's never
true, so debug builds tripped the assert before the diagnostic was
emitted. Fall back to the receiver's Display string when Type is null
and force the receiver through BindToNaturalType so flow analysis
doesn't trip on an unconverted child.

Co-authored-by: Isaac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-Compilers Community The pull request was submitted by a contributor who is not a Microsoft employee.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant