Skip to content

Commit

Permalink
Nullable annotation is no longer part of array rank specifier (#32431)
Browse files Browse the repository at this point in the history
Fixes #32290 
Fixes #32169 
Fixes #32141 
Fixes #32025
  • Loading branch information
Neal Gafter committed Jan 25, 2019
1 parent f75f501 commit 0bee025
Show file tree
Hide file tree
Showing 50 changed files with 1,891 additions and 944 deletions.
33 changes: 28 additions & 5 deletions src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
Expand Up @@ -2794,7 +2794,7 @@ private BoundExpression BindArrayCreationExpression(ArrayCreationExpressionSynta
//
// SPEC ends

var type = (ArrayTypeSymbol)BindType(node.Type, diagnostics).TypeSymbol;
var type = (ArrayTypeSymbol)BindArrayType(node.Type, diagnostics, permitDimensions: true, basesBeingResolved: null).TypeSymbol;

// CONSIDER:
//
Expand All @@ -2810,7 +2810,8 @@ private BoundExpression BindArrayCreationExpression(ArrayCreationExpressionSynta
// error has already been reported) so that "go to definition" works.

ArrayBuilder<BoundExpression> sizes = ArrayBuilder<BoundExpression>.GetInstance();
foreach (var arg in node.Type.RankSpecifiers[0].Sizes)
ArrayRankSpecifierSyntax firstRankSpecifier = node.Type.RankSpecifiers[0];
foreach (var arg in firstRankSpecifier.Sizes)
{
// These make the parse tree nicer, but they shouldn't actually appear in the bound tree.
if (arg.Kind() != SyntaxKind.OmittedArraySizeExpression)
Expand All @@ -2827,6 +2828,27 @@ private BoundExpression BindArrayCreationExpression(ArrayCreationExpressionSynta

sizes.Add(size);
}
else if (node.Initializer is null && arg == firstRankSpecifier.Sizes[0])
{
Error(diagnostics, ErrorCode.ERR_MissingArraySize, firstRankSpecifier);
}
}

// produce errors for additional sizes in the ranks
for (int additionalRankIndex = 1; additionalRankIndex < node.Type.RankSpecifiers.Count; additionalRankIndex++)
{
var rank = node.Type.RankSpecifiers[additionalRankIndex];
var dimension = rank.Sizes;
foreach (var arg in dimension)
{
if (arg.Kind() != SyntaxKind.OmittedArraySizeExpression)
{
var size = BindValue(arg, diagnostics, BindValueKind.RValue);
Error(diagnostics, ErrorCode.ERR_InvalidArray, dimension[0]);
// Capture the invalid sizes for `SemanticModel` and `IOperation`
sizes.Add(size);
}
}
}

ImmutableArray<BoundExpression> arraySizes = sizes.ToImmutableAndFree();
Expand Down Expand Up @@ -3231,8 +3253,9 @@ private void BindArrayInitializerExpressions(InitializerExpressionSyntax initial
}

ArrayTypeSyntax arrayTypeSyntax = (ArrayTypeSyntax)typeSyntax;
TypeSyntax elementTypeSyntax = arrayTypeSyntax.ElementType;
var elementType = BindType(elementTypeSyntax, diagnostics);
var elementTypeSyntax = arrayTypeSyntax.ElementType;
var arrayType = (ArrayTypeSymbol)BindArrayType(arrayTypeSyntax, diagnostics, permitDimensions: true, basesBeingResolved: null).TypeSymbol;
var elementType = arrayType.ElementType;

TypeSymbol type = GetStackAllocType(node, elementType, diagnostics, out bool hasErrors);
if (!elementType.IsErrorType() && elementType.IsManagedType)
Expand Down Expand Up @@ -3290,7 +3313,7 @@ private void BindArrayInitializerExpressions(InitializerExpressionSyntax initial
}
else if (node.Initializer == null)
{
// ERR_MissingArraySize is already reported
Error(diagnostics, ErrorCode.ERR_MissingArraySize, rankSpecifiers[0]);
count = BadExpression(countSyntax);
hasErrors = true;
}
Expand Down
25 changes: 18 additions & 7 deletions src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs
Expand Up @@ -2724,7 +2724,8 @@ private BoundExpression BindIsOperator(BinaryExpressionSyntax node, DiagnosticBa
// try binding as a type, but back off to binding as an expression if that does not work.
AliasSymbol alias;
var isTypeDiagnostics = DiagnosticBag.GetInstance();
TypeSymbol targetType = BindType(node.Right, isTypeDiagnostics, out alias).TypeSymbol;
TypeSymbolWithAnnotations targetTypeWithAnnotations = BindType(node.Right, isTypeDiagnostics, out alias);
TypeSymbol targetType = targetTypeWithAnnotations.TypeSymbol;

bool wasUnderscore = node.Right is IdentifierNameSyntax name && name.Identifier.ContextualKind() == SyntaxKind.UnderscoreToken;
if (!wasUnderscore && targetType?.IsErrorType() == true && isTypeDiagnostics.HasAnyResolvedErrors() &&
Expand Down Expand Up @@ -2757,6 +2758,12 @@ private BoundExpression BindIsOperator(BinaryExpressionSyntax node, DiagnosticBa
}

diagnostics.AddRangeAndFree(isTypeDiagnostics);
if (targetType.IsReferenceType && targetTypeWithAnnotations.NullableAnnotation == NullableAnnotation.Annotated)
{
Error(diagnostics, ErrorCode.ERR_IsNullableType, node.Right, targetType);
operandHasErrors = true;
}

var typeExpression = new BoundTypeExpression(node.Right, alias, targetType);
var targetTypeKind = targetType.TypeKind;
if (operandHasErrors || IsOperatorErrors(node, operand.Type, typeExpression, diagnostics))
Expand Down Expand Up @@ -3123,7 +3130,8 @@ private BoundExpression BindAsOperator(BinaryExpressionSyntax node, DiagnosticBa
{
var operand = BindValue(node.Left, diagnostics, BindValueKind.RValue);
AliasSymbol alias;
var targetType = BindType(node.Right, diagnostics, out alias).TypeSymbol;
TypeSymbolWithAnnotations targetTypeWithAnnotations = BindType(node.Right, diagnostics, out alias);
TypeSymbol targetType = targetTypeWithAnnotations.TypeSymbol;
var typeExpression = new BoundTypeExpression(node.Right, alias, targetType);
var targetTypeKind = targetType.TypeKind;
var resultType = targetType;
Expand Down Expand Up @@ -3163,13 +3171,16 @@ private BoundExpression BindAsOperator(BinaryExpressionSyntax node, DiagnosticBa
return new BoundAsOperator(node, operand, typeExpression, Conversion.NoConversion, resultType, hasErrors: true);
}

// SPEC: In an operation of the form E as T, E must be an expression and T must be a
// SPEC: reference type, a type parameter known to be a reference type, or a nullable type.
if (targetType.IsReferenceType && targetTypeWithAnnotations.NullableAnnotation == NullableAnnotation.Annotated)
{
Error(diagnostics, ErrorCode.ERR_AsNullableType, node.Right, targetType);

if (!targetType.IsReferenceType && !targetType.IsNullableType())
return new BoundAsOperator(node, operand, typeExpression, Conversion.NoConversion, resultType, hasErrors: true);
}
else if (!targetType.IsReferenceType && !targetType.IsNullableType())
{
// target type for an as expression cannot be a non-nullable value type.
// generate appropriate error
// SPEC: In an operation of the form E as T, E must be an expression and T must be a
// SPEC: reference type, a type parameter known to be a reference type, or a nullable type.
if (targetTypeKind == TypeKind.TypeParameter)
{
Error(diagnostics, ErrorCode.ERR_AsWithTypeVar, node, targetType);
Expand Down
1 change: 1 addition & 0 deletions src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs
Expand Up @@ -378,6 +378,7 @@ private BoundPattern BindDiscardPattern(DiscardPatternSyntax node, TypeSymbol in
Debug.Assert(!typeSyntax.IsVar); // if the syntax had `var`, it would have been parsed as a var pattern.
TypeSymbolWithAnnotations declType = BindType(typeSyntax, diagnostics, out AliasSymbol aliasOpt);
Debug.Assert(!declType.IsNull);
Debug.Assert(typeSyntax.Kind() != SyntaxKind.NullableType); // the syntax does not permit nullable annotations
BoundTypeExpression boundDeclType = new BoundTypeExpression(typeSyntax, aliasOpt, inferredType: false, type: declType.TypeSymbol);
hasErrors |= CheckValidPatternType(typeSyntax, inputType, declType.TypeSymbol, patternTypeWasInSource: true, diagnostics: diagnostics);
return boundDeclType;
Expand Down
83 changes: 45 additions & 38 deletions src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs
Expand Up @@ -413,44 +413,7 @@ internal NamespaceOrTypeOrAliasSymbolWithAnnotations BindNamespaceOrTypeOrAliasS

case SyntaxKind.ArrayType:
{
var node = (ArrayTypeSyntax)syntax;
TypeSymbolWithAnnotations type = BindType(node.ElementType, diagnostics, basesBeingResolved);
if (type.IsStatic)
{
// CS0719: '{0}': array elements cannot be of static type
Error(diagnostics, ErrorCode.ERR_ArrayOfStaticClass, node.ElementType, type.TypeSymbol);
}

if (ShouldCheckConstraints)
{
if (type.IsRestrictedType())
{
// CS0611: Array elements cannot be of type '{0}'
Error(diagnostics, ErrorCode.ERR_ArrayElementCantBeRefAny, node.ElementType, type.TypeSymbol);
}
}
else
{
diagnostics.Add(new LazyArrayElementCantBeRefAnyDiagnosticInfo(type), node.ElementType.GetLocation());
}

for (int i = node.RankSpecifiers.Count - 1; i >= 0; i--)
{
var a = node.RankSpecifiers[i];
var array = ArrayTypeSymbol.CreateCSharpArray(this.Compilation.Assembly, type, a.Rank);

if (a.QuestionToken.IsKind(SyntaxKind.QuestionToken))
{
type = TypeSymbolWithAnnotations.Create(array, NullableAnnotation.Annotated);
reportNullableReferenceTypesIfNeeded(a.QuestionToken);
}
else
{
type = TypeSymbolWithAnnotations.Create(IsNullableEnabled(a.CloseBracketToken), array);
}
}

return type;
return BindArrayType((ArrayTypeSyntax)syntax, diagnostics, permitDimensions: false, basesBeingResolved);
}

case SyntaxKind.PointerType:
Expand Down Expand Up @@ -523,6 +486,50 @@ void reportNullableReferenceTypesIfNeeded(SyntaxToken questionToken, TypeSymbolW
}
}

private TypeSymbolWithAnnotations BindArrayType(
ArrayTypeSyntax node,
DiagnosticBag diagnostics,
bool permitDimensions,
ConsList<TypeSymbol> basesBeingResolved)
{
TypeSymbolWithAnnotations type = BindType(node.ElementType, diagnostics, basesBeingResolved);
if (type.IsStatic)
{
// CS0719: '{0}': array elements cannot be of static type
Error(diagnostics, ErrorCode.ERR_ArrayOfStaticClass, node.ElementType, type.TypeSymbol);
}

if (ShouldCheckConstraints)
{
if (type.IsRestrictedType())
{
// CS0611: Array elements cannot be of type '{0}'
Error(diagnostics, ErrorCode.ERR_ArrayElementCantBeRefAny, node.ElementType, type.TypeSymbol);
}
}
else
{
diagnostics.Add(new LazyArrayElementCantBeRefAnyDiagnosticInfo(type), node.ElementType.GetLocation());
}

for (int i = node.RankSpecifiers.Count - 1; i >= 0; i--)
{
var rankSpecifier = node.RankSpecifiers[i];
var dimension = rankSpecifier.Sizes;
if (!permitDimensions && dimension.Count != 0 && dimension[0].Kind() != SyntaxKind.OmittedArraySizeExpression)
{
// https://github.com/dotnet/roslyn/issues/32464
// Should capture invalid dimensions for use in `SemanticModel` and `IOperation`.
Error(diagnostics, ErrorCode.ERR_ArraySizeInDeclaration, rankSpecifier);
}

var array = ArrayTypeSymbol.CreateCSharpArray(this.Compilation.Assembly, type, rankSpecifier.Rank);
type = TypeSymbolWithAnnotations.Create(IsNullableEnabled(rankSpecifier.CloseBracketToken), array);
}

return type;
}

private TypeSymbol BindTupleType(TupleTypeSyntax syntax, DiagnosticBag diagnostics)
{
int numElements = syntax.Elements.Count;
Expand Down
18 changes: 18 additions & 0 deletions src/Compilers/CSharp/Portable/CSharpResources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions src/Compilers/CSharp/Portable/CSharpResources.resx
Expand Up @@ -5037,6 +5037,12 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_PatternNullableType" xml:space="preserve">
<value>It is not legal to use nullable type '{0}' in a pattern; use the underlying type '{1}' instead.</value>
</data>
<data name="ERR_IsNullableType" xml:space="preserve">
<value>It is not legal to use nullable reference type '{0}?' in an is-type expression; use the underlying type '{0}' instead.</value>
</data>
<data name="ERR_AsNullableType" xml:space="preserve">
<value>It is not legal to use nullable reference type '{0}?' in an as expression; use the underlying type '{0}' instead.</value>
</data>
<data name="ERR_BadPatternExpression" xml:space="preserve">
<value>Invalid operand for pattern match; value required, but found '{0}'.</value>
</data>
Expand Down
3 changes: 3 additions & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
Expand Up @@ -1676,6 +1676,9 @@ internal enum ErrorCode
ERR_UsingVarInSwitchCase = 8647,
ERR_GoToForwardJumpOverUsingVar = 8648,
ERR_GoToBackwardJumpOverUsingVar = 8649,
ERR_IsNullableType = 8650,
ERR_AsNullableType = 8651,

#endregion diagnostics introduced for C# 8.0

// Note: you will need to re-generate compiler code after adding warnings (eng\generate-compiler-code.cmd)
Expand Down

0 comments on commit 0bee025

Please sign in to comment.