Skip to content

Centralize recognized feature flags#81591

Merged
jcouv merged 6 commits intodotnet:mainfrom
jcouv:feature-flags
Dec 10, 2025
Merged

Centralize recognized feature flags#81591
jcouv merged 6 commits intodotnet:mainfrom
jcouv:feature-flags

Conversation

@jcouv
Copy link
Member

@jcouv jcouv commented Dec 9, 2025

The compiler recognizes some magic feature flag strings. This PR moves those known strings to a centralized location and funnels most of the feature flag checks through common helpers.

@jcouv jcouv self-assigned this Dec 9, 2025
@jcouv jcouv marked this pull request as ready for review December 9, 2025 21:04
@jcouv jcouv requested a review from a team as a code owner December 9, 2025 21:04
Copy link
Member

Choose a reason for hiding this comment

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

This file makes it clear that we have sinned in our naming.

}
}

/// <remarks>Known feature flags should use <see cref="FeatureFlag"/></remarks>
Copy link
Member

@333fred 333fred Dec 9, 2025

Choose a reason for hiding this comment

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

Is there a reflection-based assert we could write to verify this? #Resolved

Copy link
Member Author

Choose a reason for hiding this comment

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

We have some tests that pass arbitrary feature flags into the APIs, so I didn't tighten this with assertions.
Let me take a look at how many tests would need updating.

var testData0 = new CompilationTestData();
var bytes0 = compilation0.EmitToArray(testData: testData0);
var generation0 = CreateInitialBaseline(compilation0,
ModuleMetadata.CreateFromImage(bytes0),
Copy link
Member

@333fred 333fred Dec 9, 2025

Choose a reason for hiding this comment

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

Whitespace changes? #Resolved

Copy link
Member Author

@jcouv jcouv Dec 9, 2025

Choose a reason for hiding this comment

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

Thanks. Will revert.
No sure what's happening here. For some reason the file after update looks correct in VS... Stupid mistake, confused two worktrees


namespace Microsoft.CodeAnalysis;

internal static class FeatureFlag
Copy link
Contributor

@AlekseyTs AlekseyTs Dec 10, 2025

Choose a reason for hiding this comment

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

FeatureFlag

Consider adding a comment for each of the "flags" #Resolved

Copy link
Contributor

Choose a reason for hiding this comment

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

BTW, the members do not look like flags. I think we used to refer to them simply as features or "compiler features".

Copy link
Member Author

Choose a reason for hiding this comment

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

Renamed to "Feature" to remove "Flag"
For comments, that's beyond what I intend for this PR. There's more work we could do here, for instance we have an open issue to remove pdb-path-determinism, but I'll leave that for later.

@AlekseyTs
Copy link
Contributor

Done with review pass (commit 1)

if (!_lazyEmitNullablePublicOnly.HasValue())
{
bool value = SyntaxTrees.FirstOrDefault()?.Options?.Features?.ContainsKey("nullablePublicOnly") == true;
bool value = SyntaxTrees.FirstOrDefault()?.Options?.HasFeature(CodeAnalysis.Feature.NullablePublicOnly) == true;
Copy link
Member

@jjonescz jjonescz Dec 10, 2025

Choose a reason for hiding this comment

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

This doesn't seem strictly equivalent to the previous code - null value in the feature dictionary would previously be accepted.

There are other changes like this in the PR (replacing Features?.ContainsKey with HasFeature).

But I guess the new behavior is better, just wanted to point out this is a small breaking change. #Resolved

Copy link
Member Author

Choose a reason for hiding this comment

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

Yup, that's correct. That's intended. I normalized the behavior

Assert.Equal("experimental-data-section-string-literals", Feature.ExperimentalDataSectionStringLiterals);
var expectedDiagnostics = new[]
{
// (15,26): error CS8103: Combined length of user strings used by the program exceeds allowed limit. Try to decrease use of string literals or try the EXPERIMENTAL feature flag 'experimental-data-section-string-literals'.
Copy link
Member

@jjonescz jjonescz Dec 10, 2025

Choose a reason for hiding this comment

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

Probably orthogonal to this PR, but consider adding a parameter for the feature flag name in the error message (instead of just the assert above), so we also ensure it's not getting localized. #WontFix

new[] { ".cctor", "F1" };
#endif

Assert.Equal("run-nullable-analysis", Feature.RunNullableAnalysis);
Copy link
Member

@jjonescz jjonescz Dec 10, 2025

Choose a reason for hiding this comment

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

This assert looks unnecessary. #Resolved

internal bool HasFeature(string feature)
{
CodeAnalysis.Feature.AssertValidFeature(feature);
return _features.TryGetValue(feature, out var value) && value is not null;
Copy link
Member

@jjonescz jjonescz Dec 10, 2025

Choose a reason for hiding this comment

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

Perhaps we could simplify this to just:

internal bool HasFeature(string feature) => Feature(feature) != null;
``` #Resolved

@jcouv jcouv marked this pull request as draft December 10, 2025 17:17
@jcouv jcouv marked this pull request as ready for review December 10, 2025 20:12
@jcouv jcouv enabled auto-merge (squash) December 10, 2025 21:21
internal const string InterceptorsNamespaces = "InterceptorsNamespaces";
internal const string NoRefSafetyRulesAttribute = "noRefSafetyRulesAttribute";
internal const string DisableLengthBasedSwitch = "disable-length-based-switch";
internal const string ExperimentalDataSectionStringLiterals = "experimental-data-section-string-literals";
Copy link
Member

@RikkiGibson RikkiGibson Dec 10, 2025

Choose a reason for hiding this comment

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

Just curious, was there any specific reason for the ordering? Was this maybe the order the flags were encountered during your refactoring pass? #Resolved

Copy link
Member Author

Choose a reason for hiding this comment

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

Random and aesthetics :-P

/// <summary>
/// Enable some experimental language features for testing.
/// </summary>
// Note: use Feature entry for known feature flags.
Copy link
Member

@RikkiGibson RikkiGibson Dec 10, 2025

Choose a reason for hiding this comment

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

I guess this is intentionally not included in the doc comment, since this is talking about an internal API with respect to this public API? #Resolved

Copy link
Member Author

Choose a reason for hiding this comment

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

Right, the known values are only internal but this API is public

@RikkiGibson
Copy link
Member

Thank you!

@jcouv jcouv merged commit 7da6b9c into dotnet:main Dec 10, 2025
24 of 25 checks passed
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone Dec 10, 2025
jjonescz added a commit that referenced this pull request Dec 19, 2025
Test plan: #81207

Only one trivial conflict due to a variable rename from
#81651 (in PEMethodSymbol.cs on
line 1042).
Plus need to fixup the feature flag otherwise it fails on assert as an
unknown feature flag due to #81591
- commit
0ae3719.
@davidwengier davidwengier modified the milestones: Next, 18.3 Jan 6, 2026
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.

6 participants