-
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
Support unmanaged constraint #24817
Support unmanaged constraint #24817
Changes from all commits
0e6d4ce
fb7e482
45bd5af
7bb24dc
53f3977
3c47bf4
97d0909
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 |
---|---|---|
|
@@ -92,7 +92,6 @@ private TypeParameterConstraintClause BindTypeParameterConstraints( | |
{ | ||
var constraints = TypeParameterConstraintKind.None; | ||
var constraintTypes = ArrayBuilder<TypeSymbol>.GetInstance(); | ||
var isStruct = false; | ||
|
||
for (int i = 0, n = constraintsSyntax.Count; i < n; i++) | ||
{ | ||
|
@@ -113,14 +112,17 @@ private TypeParameterConstraintClause BindTypeParameterConstraints( | |
diagnostics.Add(ErrorCode.ERR_RefValBoundMustBeFirst, syntax.GetFirstToken().GetLocation()); | ||
} | ||
|
||
isStruct = true; | ||
constraints |= TypeParameterConstraintKind.ValueType; | ||
continue; | ||
case SyntaxKind.ConstructorConstraint: | ||
if (isStruct) | ||
if ((constraints & TypeParameterConstraintKind.ValueType) != 0) | ||
{ | ||
diagnostics.Add(ErrorCode.ERR_NewBoundWithVal, syntax.GetFirstToken().GetLocation()); | ||
} | ||
if ((constraints & TypeParameterConstraintKind.Unmanaged) != 0) | ||
{ | ||
diagnostics.Add(ErrorCode.ERR_NewBoundWithUnmanaged, syntax.GetFirstToken().GetLocation()); | ||
} | ||
|
||
if (i != n - 1) | ||
{ | ||
|
@@ -133,55 +135,80 @@ private TypeParameterConstraintClause BindTypeParameterConstraints( | |
{ | ||
var typeConstraintSyntax = (TypeConstraintSyntax)syntax; | ||
var typeSyntax = typeConstraintSyntax.Type; | ||
if (typeSyntax.Kind() != SyntaxKind.PredefinedType && !SyntaxFacts.IsName(typeSyntax.Kind())) | ||
var typeSyntaxKind = typeSyntax.Kind(); | ||
if (typeSyntaxKind != SyntaxKind.PredefinedType && typeSyntaxKind != SyntaxKind.PointerType && !SyntaxFacts.IsName(typeSyntax.Kind())) | ||
{ | ||
diagnostics.Add(ErrorCode.ERR_BadConstraintType, typeSyntax.GetLocation()); | ||
} | ||
|
||
var type = this.BindType(typeSyntax, diagnostics); | ||
var type = BindTypeOrUnmanagedKeyword(typeSyntax, diagnostics, out var isUnmanaged); | ||
|
||
// 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 (!IsValidConstraintType(typeConstraintSyntax, type, diagnostics)) | ||
if (isUnmanaged) | ||
{ | ||
continue; | ||
} | ||
if (constraints != 0 || constraintTypes.Any()) | ||
{ | ||
diagnostics.Add(ErrorCode.ERR_UnmanagedConstraintMustBeAlone, typeSyntax.GetLocation()); | ||
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.
Why can't it be combined with an interface? #Closed 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. It should be able to combine with interfaces. I think we discussed this on the tesplan review as a potential hole/followup issue. In reply to: 172416658 [](ancestors = 172416658) 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. |
||
continue; | ||
} | ||
|
||
if (constraintTypes.Contains(type)) | ||
{ | ||
// "Duplicate constraint '{0}' for type parameter '{1}'" | ||
Error(diagnostics, ErrorCode.ERR_DuplicateBound, syntax, type, name); | ||
// This should produce diagnostics if the types are missing | ||
GetWellKnownType(WellKnownType.System_Runtime_InteropServices_UnmanagedType, diagnostics, typeSyntax); | ||
GetSpecialType(SpecialType.System_ValueType, diagnostics, typeSyntax); | ||
|
||
constraints |= TypeParameterConstraintKind.Unmanaged; | ||
continue; | ||
} | ||
|
||
if (type.TypeKind == TypeKind.Class) | ||
else | ||
{ | ||
// If there is already a struct or class constraint (class constraint could be | ||
// 'class' or explicit type), report an error and drop this class. If we don't | ||
// drop this additional class, we may end up with conflicting class constraints. | ||
// 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 (!IsValidConstraintType(typeConstraintSyntax, type, diagnostics)) | ||
{ | ||
continue; | ||
} | ||
|
||
if (constraintTypes.Contains(type)) | ||
{ | ||
// "Duplicate constraint '{0}' for type parameter '{1}'" | ||
Error(diagnostics, ErrorCode.ERR_DuplicateBound, syntax, type, name); | ||
continue; | ||
} | ||
|
||
if (constraintTypes.Count > 0) | ||
if ((constraints & TypeParameterConstraintKind.Unmanaged) != 0) | ||
{ | ||
// "The class type constraint '{0}' must come before any other constraints" | ||
Error(diagnostics, ErrorCode.ERR_ClassBoundNotFirst, syntax, type); | ||
diagnostics.Add(ErrorCode.ERR_UnmanagedConstraintMustBeAlone, typeSyntax.GetLocation()); | ||
continue; | ||
} | ||
|
||
if ((constraints & (TypeParameterConstraintKind.ReferenceType | TypeParameterConstraintKind.ValueType)) != 0) | ||
if (type.TypeKind == TypeKind.Class) | ||
{ | ||
switch (type.SpecialType) | ||
// If there is already a struct or class constraint (class constraint could be | ||
// 'class' or explicit type), report an error and drop this class. If we don't | ||
// drop this additional class, we may end up with conflicting class constraints. | ||
|
||
if (constraintTypes.Count > 0) | ||
{ | ||
// "The class type constraint '{0}' must come before any other constraints" | ||
Error(diagnostics, ErrorCode.ERR_ClassBoundNotFirst, syntax, type); | ||
continue; | ||
} | ||
|
||
if ((constraints & (TypeParameterConstraintKind.ReferenceType | TypeParameterConstraintKind.ValueType)) != 0) | ||
{ | ||
case SpecialType.System_Enum: | ||
case SpecialType.System_Delegate: | ||
case SpecialType.System_MulticastDelegate: | ||
break; | ||
|
||
default: | ||
// "'{0}': cannot specify both a constraint class and the 'class' or 'struct' constraint" | ||
Error(diagnostics, ErrorCode.ERR_RefValBoundWithClass, syntax, type); | ||
continue; | ||
switch (type.SpecialType) | ||
{ | ||
case SpecialType.System_Enum: | ||
case SpecialType.System_Delegate: | ||
case SpecialType.System_MulticastDelegate: | ||
break; | ||
|
||
default: | ||
// "'{0}': cannot specify both a constraint class and the 'class' or 'struct' constraint" | ||
Error(diagnostics, ErrorCode.ERR_RefValBoundWithClass, syntax, type); | ||
continue; | ||
} | ||
} | ||
} | ||
} | ||
|
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 is not obvious why we are no longer reporting this error for pointers. Could you elaborate? #Closed
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.
Added a comment. This error is reported for pointers during binding typeSyntax (to prevent cycles). So we don't need a duplicate error here.
In reply to: 172416549 [](ancestors = 172416549)