-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Treat unconstrained type parameters declared in #nullable disable
context as having an unknown nullability in case they are substituted with a reference type.
#34797
Changes from 7 commits
080d432
baca72a
b84946f
3d4d0c5
4fc7699
822f080
5c62a66
0e3794d
cda3fd2
8d2048e
c30c856
159f7cc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -352,21 +352,29 @@ internal static ImmutableArray<TypeParameterConstraintClause> MakeTypeParameterC | |
this Symbol containingSymbol, | ||
Binder binder, | ||
ImmutableArray<TypeParameterSymbol> typeParameters, | ||
TypeParameterListSyntax typeParameterList, | ||
SyntaxList<TypeParameterConstraintClauseSyntax> constraintClauses, | ||
Location location, | ||
DiagnosticBag diagnostics) | ||
{ | ||
if (typeParameters.Length == 0 || constraintClauses.Count == 0) | ||
if (typeParameters.Length == 0) | ||
{ | ||
return ImmutableArray<TypeParameterConstraintClause>.Empty; | ||
} | ||
|
||
if (constraintClauses.Count == 0) | ||
{ | ||
ImmutableArray<TypeParameterConstraintClause> defaultClauses = binder.GetDefaultTypeParameterConstraintClauses(typeParameterList); | ||
|
||
return defaultClauses.ContainsOnlyEmptyConstraintClauses() ? ImmutableArray<TypeParameterConstraintClause>.Empty : defaultClauses; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Should There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Some consumers do not want this optimization. In reply to: 273625867 [](ancestors = 273625867) |
||
} | ||
|
||
// Wrap binder from factory in a generic constraints specific binder | ||
// to avoid checking constraints when binding type names. | ||
Debug.Assert(!binder.Flags.Includes(BinderFlags.GenericConstraintsClause)); | ||
binder = binder.WithAdditionalFlags(BinderFlags.GenericConstraintsClause | BinderFlags.SuppressConstraintChecks); | ||
|
||
return binder.BindTypeParameterConstraintClauses(containingSymbol, typeParameters, constraintClauses, diagnostics); | ||
return binder.BindTypeParameterConstraintClauses(containingSymbol, typeParameters, typeParameterList, constraintClauses, diagnostics); | ||
} | ||
|
||
/// <summary> | ||
|
@@ -394,32 +402,37 @@ private static TypeParameterConstraintClause MakeTypeParameterConstraintsLate( | |
TypeParameterConstraintClause constraintClause, | ||
DiagnosticBag diagnostics) | ||
{ | ||
Symbol containingSymbol = typeParameter.ContainingSymbol; | ||
|
||
var constraintTypeBuilder = ArrayBuilder<TypeWithAnnotations>.GetInstance(); | ||
var constraintTypes = constraintClause.ConstraintTypes; | ||
int n = constraintTypes.Length; | ||
for (int i = 0; i < n; i++) | ||
|
||
if (!constraintClause.TypeConstraintsSyntax.IsDefault) | ||
{ | ||
var constraintType = constraintTypes[i]; | ||
var syntax = constraintClause.TypeConstraintsSyntax[i]; | ||
// Only valid constraint types are included in ConstraintTypes | ||
// since, in general, it may be difficult to support all invalid types. | ||
// In the future, we may want to include some invalid types | ||
// though so the public binding API has the most information. | ||
if (Binder.IsValidConstraint(typeParameter.Name, syntax, constraintType, constraintClause.Constraints, constraintTypeBuilder, diagnostics)) | ||
Symbol containingSymbol = typeParameter.ContainingSymbol; | ||
|
||
var constraintTypeBuilder = ArrayBuilder<TypeWithAnnotations>.GetInstance(); | ||
int n = constraintTypes.Length; | ||
|
||
for (int i = 0; i < n; i++) | ||
{ | ||
containingSymbol.CheckConstraintTypeVisibility(syntax.Location, constraintType, diagnostics); | ||
constraintTypeBuilder.Add(constraintType); | ||
var constraintType = constraintTypes[i]; | ||
var syntax = constraintClause.TypeConstraintsSyntax[i]; | ||
// Only valid constraint types are included in ConstraintTypes | ||
// since, in general, it may be difficult to support all invalid types. | ||
// In the future, we may want to include some invalid types | ||
// though so the public binding API has the most information. | ||
if (Binder.IsValidConstraint(typeParameter.Name, syntax, constraintType, constraintClause.Constraints, constraintTypeBuilder, diagnostics)) | ||
{ | ||
containingSymbol.CheckConstraintTypeVisibility(syntax.Location, constraintType, diagnostics); | ||
constraintTypeBuilder.Add(constraintType); | ||
} | ||
} | ||
} | ||
|
||
if (constraintTypeBuilder.Count < n) | ||
{ | ||
constraintTypes = constraintTypeBuilder.ToImmutable(); | ||
} | ||
if (constraintTypeBuilder.Count < n) | ||
{ | ||
constraintTypes = constraintTypeBuilder.ToImmutable(); | ||
} | ||
|
||
constraintTypeBuilder.Free(); | ||
constraintTypeBuilder.Free(); | ||
} | ||
|
||
// Verify constraints on any other partial declarations. | ||
foreach (var otherClause in constraintClause.OtherPartialDeclarations) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be useful to have some comments somewhere about the strategy here: we add constraints to represent the default oblivious constraint
where T: object~
, which causes us to suppress the IL emission of the default nullable constraint to imitate the behavior of pre-nullable compilers. When reading an assembly, the absence of a constraint causes us to create the default oblivious constraint.where T: object~
, whereas reading the default nullable constraintwhere T: object?
causes us to drop it on the floor, as that is the new default. Adjusted to correct any misunderstanding I may have. #Resolved