Skip to content

Specify constructor type inference - #3

Draft
MadsTorgersen wants to merge 9 commits into
madstorgersen-type-groupsfrom
madstorgersen-constructor-inference
Draft

Specify constructor type inference#3
MadsTorgersen wants to merge 9 commits into
madstorgersen-type-groupsfrom
madstorgersen-constructor-inference

Conversation

@MadsTorgersen

@MadsTorgersen MadsTorgersen commented Aug 14, 2026

Copy link
Copy Markdown
Owner

Summary

  • consume the shared type_group production directly in object creation
  • infer generic containing-type arguments from constructor arguments and the object creation's target type
  • combine constructors from all eligible non-generic and generic types in the type group into one overload-resolution candidate set
  • preserve existing specialized object-creation paths outside this feature

Depends on #2. This PR is stacked on madstorgersen-type-groups at 85b5a7d32e8faf3f0b13bf915620609948030cf5.

Type-group consumption

Object creation now accepts the type_group production defined by the intervening layer. Constructor binding consumes the set to which that production resolves; it does not duplicate type/type_group_name recognition or lookup and does not use the removed type_designator abstraction.

Explicit bound types resolve to singleton groups. A type-group name can contribute same-name unbound types of multiple arities. Target-typed new supplies an implied type, modeled as a singleton set during constructor binding.

Design choice: one candidate set

The earlier drafts contain both phased-fallback and combined-candidate approaches. This layer uses one combined candidate set because the type-group layer defines a single lookup result containing same-name types of every arity, analogous to a method group whose later binding operation selects among all candidates. A non-generic type is therefore not tried in a separate first phase.

For the shared better-function-member rules, a constructor of a generic type is treated as the generic counterpart of a constructor of a non-generic type, with the containing type's parameters and inferred arguments. This lets existing generic/non-generic and specificity tie-breakers apply without changing the generalized inference algorithm.

Scope

This layer changes only constructor/object-creation inference. It does not modify type-group lookup, the generalized inference phases, method inference, type patterns, or any other proposed type-group consumer.

Semantic impact audit

Required in this layer

  • function-member and type-inference context summaries
  • constructor-specific inference inputs and target-derived result bounds
  • object-creation grammar consumption of type_group
  • candidate construction from every type in the resolved group
  • inferred-type constraint and applicability checks
  • scoped overload-resolution interpretation, result typing, and default-struct processing
  • a singleton bound-type requirement for dynamically bound construction, since generic constructor inference is a compile-time operation

Higher-layer / TBD

  • other type-group consumers, especially type patterns
  • the generalized target-typing model already marked TBD in the base layer
  • any future decision to infer from object/collection initializer contents

Unaffected specialized behavior

  • target-typed new continues to provide an implied bound type
  • constructor initializers operate on an already known containing/base type
  • object and collection initializers remain post-construction processing
  • attributes, nullable wrapping, and anonymous object creation continue to use their existing bound-type paths
  • type-parameter default construction remains its specialized singleton-type path

Breaking-change consequences

  • same-name generic types can add applicable constructors to an object creation that previously selected a non-generic type, causing a different winner or ambiguity
  • type-group ambiguity between same-arity declarations can make object creation fail before the previous arity-specific type lookup would have selected a type
  • target-derived bounds can change an argument-only inference result, admit a new candidate, or make inference fail when bounds conflict
  • dynamically bound construction requires a singleton bound type group; a same-name generic type can therefore make a previously dynamic non-generic construction invalid

Open questions

  • whether the language-design decision accepts the combined candidate set and its compatibility cost, rather than phased fallback
  • whether dynamic object creation should ever support generic constructor inference
  • whether initializer contents should ever contribute inference bounds
  • finalization of the target-type source/model tracked by the base inference layer

Validation

  • git diff --check
  • dotnet run --no-launch-profile --project StandardAnchorTags\StandardAnchorTags.csproj -- --owner dotnet --repo csharpstandard --dryrun from tools\

The anchor dry run passes with only the repository's existing NU1510 warning for System.Text.Json.

@MadsTorgersen
MadsTorgersen changed the base branch from madstorgersen-generalized-type-inference to madstorgersen-type-groups August 14, 2026 17:34
MadsTorgersen and others added 3 commits August 14, 2026 12:23
Consume type groups during object creation, infer generic containing type arguments from constructor arguments and target types, and resolve all arities in one overload set.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Use direct type and type-group-name object creation alternatives, then consume the resolved type group during constructor binding.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@MadsTorgersen
MadsTorgersen force-pushed the madstorgersen-constructor-inference branch from 933c73f to 18792e9 Compare August 14, 2026 19:25
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: b9ac6346-e36b-4201-96bf-2688ecedd2bf
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: b9ac6346-e36b-4201-96bf-2688ecedd2bf
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: b9ac6346-e36b-4201-96bf-2688ecedd2bf
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: b9ac6346-e36b-4201-96bf-2688ecedd2bf
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: b9ac6346-e36b-4201-96bf-2688ecedd2bf
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: b9ac6346-e36b-4201-96bf-2688ecedd2bf
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