Skip to content

Implement type parameter inference from constraints - #84655

Open
agocke wants to merge 11 commits into
dotnet:mainfrom
agocke:infer-generic-constraints
Open

Implement type parameter inference from constraints#84655
agocke wants to merge 11 commits into
dotnet:mainfrom
agocke:infer-generic-constraints

Conversation

@agocke

@agocke agocke commented Jul 28, 2026

Copy link
Copy Markdown
Member

Promote the generic constraints of inferred type parameters into method type inference, so that constraint-only type parameters can be inferred from the values of the type parameters they constrain (dotnet/csharplang#9453).

For example, given:

void M<TEnumerable, TElement>(TEnumerable t)
    where TEnumerable : IEnumerable<TElement>

a call M(new List<int>()) now infers TElement = int from the constraint.

The implementation extends MethodTypeInference in three ways:

  • Dependencies: Xi depends on Xj when Xi occurs in a constraint of Xj, so the constraining parameter is fixed first. Reflexive constraint edges are excluded.
  • Bound precedence: ordinary argument and output inference bounds are stored separately from constraint bounds. Constraint inference fills only parameters without ordinary bounds, preserving existing inference results.
  • Atomic fixing: all parameters selected by the same fixing step are determined from the same bounds state and committed together. Constraint inference occurs only after all selected parameters are fixed, making the result independent of type-parameter declaration order.

The new behavior is gated behind LanguageVersion.Preview via IDS_FeatureTypeParameterInferenceFromConstraints; existing language versions retain the original sequential path.

The dedicated TypeParameterInferenceFromConstraintsTests suite covers positive, negative, ambiguity, nullability, async-lambda/Task<T>, overload-resolution, cyclic/self-referential, order-permutation, and multi-level transitive constraint scenarios. Existing nullable baselines retain ordinary-inference behavior, while the constraint-only output-inference case now succeeds under the feature.

Specification update: dotnet/csharplang#10307

Microsoft Reviewers: Open in CodeFlow

Promote the generic constraints of inferred type parameters into method
type inference, so that constraint-only type parameters can be inferred
from the values of the type parameters they constrain (dotnet/csharplang#9453).

For example, given:

    void M<TEnumerable, TElement>(TEnumerable t)
        where TEnumerable : IEnumerable<TElement>

a call M(new List<int>()) now infers TElement = int from the constraint.

Two changes to MethodTypeInference:
* DependsDirectlyOn: Xi depends on Xj when Xi occurs in Xj's constraint,
  so a constrained parameter is fixed before the parameters mentioned in
  its constraint.
* Fix: after a type parameter is fixed to V, perform a lower-bound
  inference from V into each of its constraint types, seeding bounds for
  the (later-fixed) parameters that appear there.

Both are gated behind LanguageVersion.Preview via the new
IDS_FeatureTypeParameterInferenceFromConstraints feature id.

Adds a dedicated test suite (TypeParameterInferenceFromConstraintsTests)
covering positive, negative, ambiguity, nullable, async-lambda/Task<T>,
overload-resolution, cyclic/self-referential, and multi-level transitive
constraint scenarios, and updates 9 existing nullable tests whose inferred
results legitimately improve under the feature.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI lite review requested due to automatic review settings July 28, 2026 05:28
@agocke
agocke requested a review from a team as a code owner July 28, 2026 05:28
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
1 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends C# method type inference (preview-only) to allow inferring type parameters that appear only in generic constraints, and adds/updates compiler tests and feature-localization resources to support the new behavior.

Changes:

  • Update MethodTypeInference to (1) incorporate constraint-based dependencies and (2) seed inference bounds from fixed type parameters into their constraint types (gated by a new preview feature ID).
  • Add a new dedicated test suite for “type parameter inference from constraints” and update existing nullable reference type tests whose inference results change under preview.
  • Add a new compiler feature string (IDS_FeatureTypeParameterInferenceFromConstraints) and propagate it to localized .xlf files.
Show a summary per file
File Description
src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs Implements preview-gated constraint-based dependency ordering and constraint-driven lower-bound seeding during fixing.
src/Compilers/CSharp/Portable/Errors/MessageID.cs Adds a new preview feature ID for gating the behavior.
src/Compilers/CSharp/Portable/CSharpResources.resx Adds the feature string for diagnostics/feature gating text.
src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf Adds localized XLF entry for the new feature string.
src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf Adds localized XLF entry for the new feature string.
src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf Adds localized XLF entry for the new feature string.
src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf Adds localized XLF entry for the new feature string.
src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf Adds localized XLF entry for the new feature string.
src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf Adds localized XLF entry for the new feature string.
src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf Adds localized XLF entry for the new feature string.
src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf Adds localized XLF entry for the new feature string.
src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf Adds localized XLF entry for the new feature string.
src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf Adds localized XLF entry for the new feature string.
src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf Adds localized XLF entry for the new feature string.
src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf Adds localized XLF entry for the new feature string.
src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf Adds localized XLF entry for the new feature string.
src/Compilers/CSharp/Test/Semantic/Semantics/TypeParameterInferenceFromConstraintsTests.cs New test suite covering positive/negative and edge cases for the new inference behavior.
src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs Updates expected diagnostics where preview inference results (and downstream nullability diagnostics) change.

Copilot's findings

  • Files reviewed: 18/18 changed files
  • Comments generated: 1

Comment thread src/Compilers/CSharp/Portable/Errors/MessageID.cs Outdated
comp1.VerifyDiagnostics(
// (9,9): warning CS8631: The type 'TB1?' cannot be used as type parameter 'TM2' in the generic type or method 'B<TB1>.M1<TM1, TM2>(TM1, TM2)'. Nullability of type argument 'TB1?' doesn't match constraint type 'TB1'.
// M1(b2, a2); // 1
Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterConstraint, "M1").WithArguments("B<TB1>.M1<TM1, TM2>(TM1, TM2)", "TB1", "TM2", "TB1?").WithLocation(9, 9),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider also verifying the original diagnostics under LangVersion=14

}
""";

CreateCompilation(source, parseOptions: TestOptions.Regular14).VerifyDiagnostics(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For a langversion-focused test, consider testing the same snippet under Regular14, RegularNext and RegularPreview.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regular15 now that that work has merged.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test can probably be combined with Basic_IEnumerable under the different langversions.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 7, 2026 17:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 18/18 changed files
  • Comments generated: 0 new

Co-authored-by: Andy Gocke <angocke@microsoft.com>
Copilot AI review requested due to automatic review settings August 7, 2026 18:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 18/18 changed files
  • Comments generated: 0 new

Fix preview constraint inference in simultaneous waves while preserving ordinary argument and output inference bounds.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 1fcf8092-6a5f-485e-891d-26fe95919661
Copilot AI review requested due to automatic review settings August 8, 2026 01:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

  • Files reviewed: 18/18 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@333fred

333fred commented Aug 12, 2026

Copy link
Copy Markdown
Member

Test plan: #84868
(created by new-compiler-feature skill)

Use the specification terms ordinary bounds, effective bounds, and selected fixing parameters throughout the implementation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 1fcf8092-6a5f-485e-891d-26fe95919661
Copilot AI review requested due to automatic review settings August 14, 2026 00:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

  • Files reviewed: 18/18 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

private readonly HashSet<TypeWithAnnotations>[] _upperBounds;
private readonly HashSet<TypeWithAnnotations>[] _lowerBounds;

// Constraint-derived bounds are used only when the corresponding type parameter

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider nullable-enabling these.


if (IsFeatureTypeParameterInferenceFromConstraintsEnabled)
{
if (!FixSelectedParameters(needsFixing, ref useSiteInfo))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's unclear from this code what the actual difference is here; I think a combination of more clear method names and some comments would help clarify why the new path calls a method that appears, at first read, like it should handle both old and new paths.

}

Debug.Assert(IsUnfixed(iParam));
if (!HasEffectiveBound(iParam) || !FixParameter(iParam, ref useSiteInfo))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be HasOrdinaryBound, to match prior language version code?

}
""";

CreateCompilation(source, parseOptions: TestOptions.Regular14).VerifyDiagnostics(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regular15 now that that work has merged.

}
""";

CreateCompilation(source, parseOptions: TestOptions.Regular14).VerifyDiagnostics(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test can probably be combined with Basic_IEnumerable under the different langversions.

""";

CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(
// (11,9): error CS0311: The type 'System.Collections.Generic.List<int>' cannot be used as type parameter 'TEnumerable' in the generic type or method 'C.M<TEnumerable, TElement>(TEnumerable, TElement)'. There is no implicit reference conversion from 'System.Collections.Generic.List<int>' to 'System.Collections.Generic.IEnumerable<string>'.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't a particularly good error, and definitely not what I would have expected out of fixing. We know from ordinary bounds that TEnumerable must be List<int>; the issue is in TElement. Why would we then be erroring on TEnumerable?

…ion/MethodTypeInference.cs

Co-authored-by: Fred Silberberg <fred@silberberg.xyz>
Copilot AI review requested due to automatic review settings August 19, 2026 17:39

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

  • Files reviewed: 18/18 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Copilot AI review requested due to automatic review settings August 19, 2026 17:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

  • Files reviewed: 18/18 changed files
  • Comments generated: 1
  • Review effort level: Lite


// C# preview features.
case MessageID.IDS_FeatureUnsafeEvolution: // https://github.com/dotnet/roslyn/issues/82546: keep this in preview until C# 16
case MessageID.IDS_FeatureTypeParameterInferenceFromConstraints:
agocke added 4 commits August 19, 2026 18:42
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 617fedad-8306-4126-b532-e273eecf2248
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 617fedad-8306-4126-b532-e273eecf2248
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 617fedad-8306-4126-b532-e273eecf2248
Copilot AI review requested due to automatic review settings August 19, 2026 18:57
@agocke
agocke requested review from a team as code owners August 19, 2026 18:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

  • Files reviewed: 32/32 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@333fred 333fred left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like a few comments from previous review are still unaddressed.

Comment on lines +33 to +34
the disabled-feature boundary; retain an explicit `RegularPreview` case when
testing the feature's language-version gate.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

retain an explicit RegularPreview case when testing the feature's language-version gate.

This guidance seems incorrect? To test the gate, you want to test across N and RegularNext.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants