Skip to content

Commit 6f47f3d

Browse files
authored
Merge pull request #46358 from dotnet/revert-45993-default-constraint
Revert "Support nullable annotations on unconstrained type parameters"
2 parents a263eca + 0aa5e14 commit 6f47f3d

File tree

62 files changed

+761
-6859
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+761
-6859
lines changed

docs/contributing/Compiler Test Plan.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ This document provides guidance for thinking about language interactions and tes
6464
- Ref structs, Readonly structs
6565
- Readonly members on structs (methods, property/indexer accessors, custom event accessors)
6666
- SkipLocalsInit
67-
- Method override or explicit implementation with `where T : { class, struct, default }`
6867

6968
# Code
7069
- Operators (see Eric's list below)

src/Compilers/CSharp/Portable/Binder/Binder_Constraints.cs

Lines changed: 6 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ internal ImmutableArray<TypeParameterConstraintClause> BindTypeParameterConstrai
139139
{
140140
if (!reportedOverrideWithConstraints)
141141
{
142-
reportTypeConstraintsMustBeUniqueAndFirst(syntax, diagnostics);
142+
diagnostics.Add(ErrorCode.ERR_TypeConstraintsMustBeUniqueAndFirst, syntax.GetFirstToken().GetLocation());
143143
}
144144

145145
if (isForOverride && (constraints & (TypeParameterConstraintKind.ValueType | TypeParameterConstraintKind.ReferenceType)) != 0)
@@ -180,7 +180,7 @@ internal ImmutableArray<TypeParameterConstraintClause> BindTypeParameterConstrai
180180
{
181181
if (!reportedOverrideWithConstraints)
182182
{
183-
reportTypeConstraintsMustBeUniqueAndFirst(syntax, diagnostics);
183+
diagnostics.Add(ErrorCode.ERR_TypeConstraintsMustBeUniqueAndFirst, syntax.GetFirstToken().GetLocation());
184184
}
185185

186186
if (isForOverride && (constraints & (TypeParameterConstraintKind.ValueType | TypeParameterConstraintKind.ReferenceType)) != 0)
@@ -214,27 +214,6 @@ internal ImmutableArray<TypeParameterConstraintClause> BindTypeParameterConstrai
214214

215215
constraints |= TypeParameterConstraintKind.Constructor;
216216
continue;
217-
case SyntaxKind.DefaultConstraint:
218-
if (!isForOverride)
219-
{
220-
diagnostics.Add(ErrorCode.ERR_DefaultConstraintOverrideOnly, syntax.GetLocation());
221-
}
222-
223-
if (i != 0)
224-
{
225-
if (!reportedOverrideWithConstraints)
226-
{
227-
reportTypeConstraintsMustBeUniqueAndFirst(syntax, diagnostics);
228-
}
229-
230-
if (isForOverride && (constraints & (TypeParameterConstraintKind.ValueType | TypeParameterConstraintKind.ReferenceType)) != 0)
231-
{
232-
continue;
233-
}
234-
}
235-
236-
constraints |= TypeParameterConstraintKind.Default;
237-
continue;
238217
case SyntaxKind.TypeConstraint:
239218
if (isForOverride)
240219
{
@@ -260,7 +239,7 @@ internal ImmutableArray<TypeParameterConstraintClause> BindTypeParameterConstrai
260239
case ConstraintContextualKeyword.Unmanaged:
261240
if (i != 0)
262241
{
263-
reportTypeConstraintsMustBeUniqueAndFirst(typeSyntax, diagnostics);
242+
diagnostics.Add(ErrorCode.ERR_TypeConstraintsMustBeUniqueAndFirst, typeSyntax.GetLocation());
264243
continue;
265244
}
266245

@@ -274,7 +253,7 @@ internal ImmutableArray<TypeParameterConstraintClause> BindTypeParameterConstrai
274253
case ConstraintContextualKeyword.NotNull:
275254
if (i != 0)
276255
{
277-
reportTypeConstraintsMustBeUniqueAndFirst(typeSyntax, diagnostics);
256+
diagnostics.Add(ErrorCode.ERR_TypeConstraintsMustBeUniqueAndFirst, typeSyntax.GetLocation());
278257
}
279258

280259
constraints |= TypeParameterConstraintKind.NotNull;
@@ -313,11 +292,6 @@ static void reportOverrideWithConstraints(ref bool reportedOverrideWithConstrain
313292
reportedOverrideWithConstraints = true;
314293
}
315294
}
316-
317-
static void reportTypeConstraintsMustBeUniqueAndFirst(CSharpSyntaxNode syntax, DiagnosticBag diagnostics)
318-
{
319-
diagnostics.Add(ErrorCode.ERR_TypeConstraintsMustBeUniqueAndFirst, syntax.GetLocation());
320-
}
321295
}
322296

323297
internal ImmutableArray<TypeParameterConstraintClause> GetDefaultTypeParameterConstraintClauses(TypeParameterListSyntax typeParameterList)
@@ -377,7 +351,7 @@ private static TypeParameterConstraintClause RemoveInvalidConstraints(
377351
// since, in general, it may be difficult to support all invalid types.
378352
// In the future, we may want to include some invalid types
379353
// though so the public binding API has the most information.
380-
if (IsValidConstraint(typeParameter.Name, syntax, constraintType, constraintClause.Constraints, constraintTypeBuilder, diagnostics))
354+
if (Binder.IsValidConstraint(typeParameter.Name, syntax, constraintType, constraintClause.Constraints, constraintTypeBuilder, diagnostics))
381355
{
382356
CheckConstraintTypeVisibility(containingSymbol, syntax.Location, constraintType, diagnostics);
383357
constraintTypeBuilder.Add(constraintType);
@@ -414,7 +388,7 @@ private static void CheckConstraintTypeVisibility(
414388
/// Returns true if the constraint is valid. Otherwise
415389
/// returns false and generates a diagnostic.
416390
/// </summary>
417-
private static bool IsValidConstraint(
391+
internal static bool IsValidConstraint(
418392
string typeParameterName,
419393
TypeConstraintSyntax syntax,
420394
TypeWithAnnotations type,

src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1029,7 +1029,7 @@ private BoundPattern BindVarDesignation(
10291029
}
10301030
case SyntaxKind.SingleVariableDesignation:
10311031
{
1032-
var declType = TypeWithState.ForType(inputType).ToTypeWithAnnotations(Compilation);
1032+
var declType = TypeWithState.ForType(inputType).ToTypeWithAnnotations();
10331033
BindPatternDesignation(
10341034
designation: node, declType: declType, inputValEscape: inputValEscape, permitDesignations: permitDesignations,
10351035
typeSyntax: null, diagnostics: diagnostics, hasErrors: ref hasErrors,

src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ NamespaceOrTypeOrAliasSymbolWithAnnotations bindNullable()
512512

513513
if (!ShouldCheckConstraints)
514514
{
515-
diagnostics.Add(new LazyUseSiteDiagnosticsInfoForNullableType(Compilation.LanguageVersion, constructedType), syntax.GetLocation());
515+
diagnostics.Add(new LazyUseSiteDiagnosticsInfoForNullableType(constructedType), syntax.GetLocation());
516516
}
517517
else if (constructedType.IsNullableType())
518518
{
@@ -521,9 +521,9 @@ NamespaceOrTypeOrAliasSymbolWithAnnotations bindNullable()
521521
var location = syntax.Location;
522522
type.CheckConstraints(new ConstraintsHelper.CheckConstraintsArgs(this.Compilation, this.Conversions, includeNullability: true, location, diagnostics));
523523
}
524-
else if (GetNullableUnconstrainedTypeParameterDiagnosticIfNecessary(Compilation.LanguageVersion, constructedType) is { } diagnosticInfo)
524+
else if (constructedType.Type.IsTypeParameterDisallowingAnnotation())
525525
{
526-
diagnostics.Add(diagnosticInfo, syntax.Location);
526+
diagnostics.Add(ErrorCode.ERR_NullableUnconstrainedTypeParameter, syntax.Location);
527527
}
528528

529529
return constructedType;
@@ -571,21 +571,6 @@ NamespaceOrTypeOrAliasSymbolWithAnnotations createErrorType()
571571
return TypeWithAnnotations.Create(CreateErrorType());
572572
}
573573
}
574-
575-
internal static CSDiagnosticInfo? GetNullableUnconstrainedTypeParameterDiagnosticIfNecessary(LanguageVersion languageVersion, in TypeWithAnnotations type)
576-
{
577-
if (type.Type.IsTypeParameterDisallowingAnnotationInCSharp8())
578-
{
579-
// Check IDS_FeatureDefaultTypeParameterConstraint feature since `T?` and `where ... : default`
580-
// are treated as a single feature, even though the errors reported for the two cases are distinct.
581-
var requiredVersion = MessageID.IDS_FeatureDefaultTypeParameterConstraint.RequiredVersion();
582-
if (requiredVersion > languageVersion)
583-
{
584-
return new CSDiagnosticInfo(ErrorCode.ERR_NullableUnconstrainedTypeParameter, new CSharpRequiredLanguageVersion(requiredVersion));
585-
}
586-
}
587-
return null;
588-
}
589574
#nullable restore
590575

591576
private TypeWithAnnotations BindArrayType(

src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1517,14 +1517,12 @@ internal bool HasTopLevelNullabilityIdentityConversion(TypeWithAnnotations sourc
15171517
return true;
15181518
}
15191519

1520-
var sourceIsPossiblyNullableTypeParameter = IsPossiblyNullableTypeTypeParameter(source);
1521-
var destinationIsPossiblyNullableTypeParameter = IsPossiblyNullableTypeTypeParameter(destination);
1522-
if (sourceIsPossiblyNullableTypeParameter && !destinationIsPossiblyNullableTypeParameter)
1520+
if (source.IsPossiblyNullableTypeTypeParameter() && !destination.IsPossiblyNullableTypeTypeParameter())
15231521
{
15241522
return destination.NullableAnnotation.IsAnnotated();
15251523
}
15261524

1527-
if (destinationIsPossiblyNullableTypeParameter && !sourceIsPossiblyNullableTypeParameter)
1525+
if (destination.IsPossiblyNullableTypeTypeParameter() && !source.IsPossiblyNullableTypeTypeParameter())
15281526
{
15291527
return source.NullableAnnotation.IsAnnotated();
15301528
}
@@ -1549,21 +1547,14 @@ internal bool HasTopLevelNullabilityImplicitConversion(TypeWithAnnotations sourc
15491547
return true;
15501548
}
15511549

1552-
if (IsPossiblyNullableTypeTypeParameter(source) && !IsPossiblyNullableTypeTypeParameter(destination))
1550+
if (source.IsPossiblyNullableTypeTypeParameter() && !destination.IsPossiblyNullableTypeTypeParameter())
15531551
{
15541552
return false;
15551553
}
15561554

15571555
return !source.NullableAnnotation.IsAnnotated();
15581556
}
15591557

1560-
private static bool IsPossiblyNullableTypeTypeParameter(in TypeWithAnnotations typeWithAnnotations)
1561-
{
1562-
var type = typeWithAnnotations.Type;
1563-
return type is object &&
1564-
(type.IsPossiblyNullableReferenceTypeTypeParameter() || type.IsNullableTypeOrTypeParameter());
1565-
}
1566-
15671558
/// <summary>
15681559
/// Returns false if the source does not have an implicit conversion to the destination
15691560
/// because of either incompatible top level or nested nullability.

src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1541,9 +1541,9 @@ private bool ExactOrBoundsNullableInference(ExactOrBoundsKind kind, TypeWithAnno
15411541

15421542
return false;
15431543

1544-
// True if the type is nullable.
1544+
// True if the type is nullable but not an unconstrained type parameter.
15451545
bool isNullableOnly(TypeWithAnnotations type)
1546-
=> type.NullableAnnotation.IsAnnotated();
1546+
=> type.NullableAnnotation.IsAnnotated() && !type.Type.IsTypeParameterDisallowingAnnotation();
15471547
}
15481548

15491549
private bool ExactNullableInference(TypeWithAnnotations source, TypeWithAnnotations target, ref HashSet<DiagnosticInfo> useSiteDiagnostics)

src/Compilers/CSharp/Portable/CSharpResources.resx

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1363,7 +1363,7 @@
13631363
<value>The return type for ++ or -- operator must match the parameter type or be derived from the parameter type</value>
13641364
</data>
13651365
<data name="ERR_TypeConstraintsMustBeUniqueAndFirst" xml:space="preserve">
1366-
<value>The 'class', 'struct', 'unmanaged', 'notnull', and 'default' constraints cannot be combined or duplicated, and must be specified first in the constraints list.</value>
1366+
<value>The 'class', 'struct', 'unmanaged', and 'notnull' constraints cannot be combined or duplicated, and must be specified first in the constraints list.</value>
13671367
</data>
13681368
<data name="ERR_RefValBoundWithClass" xml:space="preserve">
13691369
<value>'{0}': cannot specify both a constraint class and the 'class' or 'struct' constraint</value>
@@ -5608,7 +5608,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
56085608
<value>Explicit application of 'System.Runtime.CompilerServices.NullableAttribute' is not allowed.</value>
56095609
</data>
56105610
<data name="ERR_NullableUnconstrainedTypeParameter" xml:space="preserve">
5611-
<value>A nullable type parameter must be known to be a value type or non-nullable reference type unless language version '{0}' or greater is used. Consider changing the language version or adding a 'class', 'struct', or type constraint.</value>
5611+
<value>A nullable type parameter must be known to be a value type or non-nullable reference type. Consider adding a 'class', 'struct', or type constraint.</value>
56125612
</data>
56135613
<data name="ERR_NullableOptionNotAvailable" xml:space="preserve">
56145614
<value>Invalid '{0}' value: '{1}' for C# {2}. Please use language version '{3}' or greater.</value>
@@ -5736,9 +5736,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
57365736
<data name="IDS_FeatureNullPointerConstantPattern" xml:space="preserve">
57375737
<value>null pointer constant pattern</value>
57385738
</data>
5739-
<data name="IDS_FeatureDefaultTypeParameterConstraint" xml:space="preserve">
5740-
<value>default type parameter constraints</value>
5741-
</data>
57425739
<data name="ERR_WrongNumberOfSubpatterns" xml:space="preserve">
57435740
<value>Matching the tuple type '{0}' requires '{1}' subpatterns, but '{2}' subpatterns are present.</value>
57445741
</data>
@@ -6024,12 +6021,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
60246021
<data name="ERR_OverrideValConstraintNotSatisfied" xml:space="preserve">
60256022
<value>Method '{0}' specifies a 'struct' constraint for type parameter '{1}', but corresponding type parameter '{2}' of overridden or explicitly implemented method '{3}' is not a non-nullable value type.</value>
60266023
</data>
6027-
<data name="ERR_OverrideDefaultConstraintNotSatisfied" xml:space="preserve">
6028-
<value>Method '{0}' specifies a 'default' constraint for type parameter '{1}', but corresponding type parameter '{2}' of overridden or explicitly implemented method '{3}' is constrained to a reference type or a value type.</value>
6029-
</data>
6030-
<data name="ERR_DefaultConstraintOverrideOnly" xml:space="preserve">
6031-
<value>The 'default' constraint is valid on override and explicit interface implementation methods only.</value>
6032-
</data>
60336024
<data name="IDS_OverrideWithConstraints" xml:space="preserve">
60346025
<value>constraints for override and explicit interface implementation methods</value>
60356026
</data>

src/Compilers/CSharp/Portable/Errors/ErrorCode.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1831,8 +1831,6 @@ internal enum ErrorCode
18311831

18321832
ERR_StaticAnonymousFunctionCannotCaptureVariable = 8820,
18331833
ERR_StaticAnonymousFunctionCannotCaptureThis = 8821,
1834-
ERR_OverrideDefaultConstraintNotSatisfied = 8822,
1835-
ERR_DefaultConstraintOverrideOnly = 8823,
18361834

18371835
ERR_BadWarningVersion = 8848,
18381836
ERR_ExpressionTreeContainsWithExpression = 8849,

src/Compilers/CSharp/Portable/Errors/LazyDiagnosticInfo.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,13 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5-
#nullable enable
6-
75
using System.Threading;
86

97
namespace Microsoft.CodeAnalysis.CSharp
108
{
119
internal abstract class LazyDiagnosticInfo : DiagnosticInfo
1210
{
13-
private DiagnosticInfo? _lazyInfo;
11+
private DiagnosticInfo _lazyInfo;
1412

1513
protected LazyDiagnosticInfo()
1614
: base(CSharp.MessageProvider.Instance, (int)ErrorCode.Unknown)
@@ -27,6 +25,6 @@ internal sealed override DiagnosticInfo GetResolvedInfo()
2725
return _lazyInfo;
2826
}
2927

30-
protected abstract DiagnosticInfo? ResolveInfo();
28+
protected abstract DiagnosticInfo ResolveInfo();
3129
}
3230
}

src/Compilers/CSharp/Portable/Errors/LazyUseSiteDiagnosticsInfoForNullableType.cs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,31 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5-
#nullable enable
6-
75
using Microsoft.CodeAnalysis.CSharp.Symbols;
86

97
namespace Microsoft.CodeAnalysis.CSharp
108
{
119
internal sealed class LazyUseSiteDiagnosticsInfoForNullableType : LazyDiagnosticInfo
1210
{
13-
private readonly LanguageVersion _languageVersion;
1411
private readonly TypeWithAnnotations _possiblyNullableTypeSymbol;
1512

16-
internal LazyUseSiteDiagnosticsInfoForNullableType(LanguageVersion languageVersion, TypeWithAnnotations possiblyNullableTypeSymbol)
13+
internal LazyUseSiteDiagnosticsInfoForNullableType(TypeWithAnnotations possiblyNullableTypeSymbol)
1714
{
18-
_languageVersion = languageVersion;
1915
_possiblyNullableTypeSymbol = possiblyNullableTypeSymbol;
2016
}
2117

22-
protected override DiagnosticInfo? ResolveInfo()
18+
protected override DiagnosticInfo ResolveInfo()
2319
{
2420
if (_possiblyNullableTypeSymbol.IsNullableType())
2521
{
2622
return _possiblyNullableTypeSymbol.Type.OriginalDefinition.GetUseSiteDiagnostic();
2723
}
28-
return Binder.GetNullableUnconstrainedTypeParameterDiagnosticIfNecessary(_languageVersion, _possiblyNullableTypeSymbol);
24+
else if (_possiblyNullableTypeSymbol.Type.IsTypeParameterDisallowingAnnotation())
25+
{
26+
return new CSDiagnosticInfo(ErrorCode.ERR_NullableUnconstrainedTypeParameter);
27+
}
28+
29+
return null;
2930
}
3031
}
3132
}

0 commit comments

Comments
 (0)