Skip to content
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

Merge from Features/constraints to dev15.7.x #25454

Merged
merged 21 commits into from
Mar 14, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 81 additions & 30 deletions src/Compilers/CSharp/Portable/Binder/Binder_Constraints.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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++)
{
Expand All @@ -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)
{
Expand All @@ -133,48 +135,91 @@ 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_UnmanagedConstraintMustBeFirst, typeSyntax.GetLocation());
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.

if (constraintTypes.Count > 0)
// 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))
{
// "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)
if (constraintTypes.Contains(type))
{
// "'{0}': cannot specify both a constraint class and the 'class' or 'struct' constraint"
Error(diagnostics, ErrorCode.ERR_RefValBoundWithClass, syntax, type);
// "Duplicate constraint '{0}' for type parameter '{1}'"
Error(diagnostics, ErrorCode.ERR_DuplicateBound, syntax, type, name);
continue;
}

if (type.TypeKind == TypeKind.Class)
{
// 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)) != 0)
{
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;
}
}
else if (type.SpecialType != SpecialType.System_Enum)
{
if ((constraints & TypeParameterConstraintKind.ValueType) != 0)
{
// "'{0}': cannot specify both a constraint class and the 'class' or 'struct' constraint"
Error(diagnostics, ErrorCode.ERR_RefValBoundWithClass, syntax, type);
continue;
}
else if ((constraints & TypeParameterConstraintKind.Unmanaged) != 0)
{
// "'{0}': cannot specify both a constraint class and the 'unmanaged' constraint"
Error(diagnostics, ErrorCode.ERR_UnmanagedBoundWithClass, syntax, type);
continue;
}
}
}
}

constraintTypes.Add(type);
Expand All @@ -196,11 +241,17 @@ private static bool IsValidConstraintType(TypeConstraintSyntax syntax, TypeSymbo
{
switch (type.SpecialType)
{
case SpecialType.System_Object:
case SpecialType.System_ValueType:
case SpecialType.System_Enum:
CheckFeatureAvailability(syntax, MessageID.IDS_FeatureEnumGenericTypeConstraint, diagnostics);
break;

case SpecialType.System_Delegate:
case SpecialType.System_MulticastDelegate:
CheckFeatureAvailability(syntax, MessageID.IDS_FeatureDelegateGenericTypeConstraint, diagnostics);
break;

case SpecialType.System_Object:
case SpecialType.System_ValueType:
case SpecialType.System_Array:
// "Constraint cannot be special class '{0}'"
Error(diagnostics, ErrorCode.ERR_SpecialTypeAsBound, syntax, type);
Expand Down
2 changes: 1 addition & 1 deletion src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2342,7 +2342,7 @@ private BoundExpression BindOutVariableDeclarationArgument(
if (typeSyntax.IsVar)
{
var ignored = DiagnosticBag.GetInstance();
BindTypeOrAlias(typeSyntax, ignored, out isVar);
BindTypeOrAliasOrVarKeyword(typeSyntax, ignored, out isVar);
ignored.Free();

if (isVar)
Expand Down
2 changes: 1 addition & 1 deletion src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ private BoundPattern BindDeclarationPattern(

bool isVar;
AliasSymbol aliasOpt;
TypeSymbol declType = BindType(typeSyntax, diagnostics, out isVar, out aliasOpt);
TypeSymbol declType = BindTypeOrVarKeyword(typeSyntax, diagnostics, out isVar, out aliasOpt);
if (isVar)
{
declType = operandType;
Expand Down
4 changes: 2 additions & 2 deletions src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,7 @@ declarationNode is VariableDesignationSyntax ||
// or it might not; if it is not then we do not want to report an error. If it is, then
// we want to treat the declaration as an explicitly typed declaration.

TypeSymbol declType = BindType(typeSyntax.SkipRef(out _), diagnostics, out isVar, out alias);
TypeSymbol declType = BindTypeOrVarKeyword(typeSyntax.SkipRef(out _), diagnostics, out isVar, out alias);
Debug.Assert((object)declType != null || isVar);

if (isVar)
Expand Down Expand Up @@ -2209,7 +2209,7 @@ internal BoundStatement BindForOrUsingOrFixedDeclarations(VariableDeclarationSyn

AliasSymbol alias;
bool isVar;
TypeSymbol declType = BindType(typeSyntax, diagnostics, out isVar, out alias);
TypeSymbol declType = BindTypeOrVarKeyword(typeSyntax, diagnostics, out isVar, out alias);

Debug.Assert((object)declType != null || isVar);

Expand Down
Loading