Skip to content

Commit

Permalink
Give 'typeof'-like errors in attribute type arguments (#54956)
Browse files Browse the repository at this point in the history
  • Loading branch information
RikkiGibson authored Jul 21, 2021
1 parent 2c4059c commit f260ccb
Show file tree
Hide file tree
Showing 28 changed files with 501 additions and 97 deletions.
26 changes: 26 additions & 0 deletions src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1313,10 +1313,36 @@ private BoundExpression BindTypeOf(TypeOfExpressionSyntax node, BindingDiagnosti
hasError = true;
}

if (!hasError)
{
CheckDisallowedAttributeDependentType(typeWithAnnotations, isError: false, node.Location, diagnostics);
}

BoundTypeExpression boundType = new BoundTypeExpression(typeSyntax, alias, typeWithAnnotations, type.IsErrorType());
return new BoundTypeOfOperator(node, boundType, null, this.GetWellKnownType(WellKnownType.System_Type, diagnostics, node), hasError);
}

/// <summary>Called when an "attribute-dependent" type such as 'dynamic', 'string?', etc. is not permitted.</summary>
private void CheckDisallowedAttributeDependentType(TypeWithAnnotations typeArgument, bool isError, Location errorLocation, BindingDiagnosticBag diagnostics)
{
var diagnosticId = isError ? ErrorCode.ERR_AttrDependentTypeNotAllowed : ErrorCode.WRN_AttrDependentTypeNotAllowed;
typeArgument.VisitType(type: null, static (typeWithAnnotations, arg, _) =>
{
var (topLevelType, diagnosticId, errorLocation, diagnostics) = arg;
var type = typeWithAnnotations.Type;
if (type.IsDynamic()
|| (typeWithAnnotations.NullableAnnotation.IsAnnotated() && !type.IsValueType)
|| type.IsNativeIntegerType
|| (type.IsTupleType && !type.TupleElementNames.IsDefault))
{
diagnostics.Add(diagnosticId, errorLocation, topLevelType.ToDisplayString(SymbolDisplayFormat.CSharpShortErrorMessageFormat));
return true;
}

return false;
}, typePredicate: null, arg: (typeArgument, diagnosticId, errorLocation, diagnostics));
}

private BoundExpression BindSizeOf(SizeOfExpressionSyntax node, BindingDiagnosticBag diagnostics)
{
ExpressionSyntax typeSyntax = node.Type;
Expand Down
17 changes: 14 additions & 3 deletions src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1175,11 +1175,22 @@ private TypeWithAnnotations BindGenericSimpleNamespaceOrTypeOrAliasSymbol(
{
var boundTypeArguments = BindTypeArguments(typeArguments, diagnostics, basesBeingResolved);
if (unconstructedType.IsGenericType
&& options.IsAttributeTypeLookup()
&& boundTypeArguments.FirstOrDefault(bta => bta.Type.IsUnboundGenericType() || bta.Type.ContainsTypeParameter()) is { HasType: true } badAttributeArgument)
&& options.IsAttributeTypeLookup())
{
diagnostics.Add(ErrorCode.ERR_AttrTypeArgCannotBeTypeVar, node.Location, badAttributeArgument.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat));
foreach (var typeArgument in boundTypeArguments)
{
var type = typeArgument.Type;
if (type.IsUnboundGenericType() || type.ContainsTypeParameter())
{
diagnostics.Add(ErrorCode.ERR_AttrTypeArgCannotBeTypeVar, node.Location, type.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat));
}
else
{
CheckDisallowedAttributeDependentType(typeArgument, isError: true, node.Location, diagnostics);
}
}
}

// It's not an unbound type expression, so we must have type arguments, and we have a
// generic type of the correct arity in hand (possibly an error type). Bind the type
// arguments and construct the final result.
Expand Down
9 changes: 9 additions & 0 deletions src/Compilers/CSharp/Portable/CSharpResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1308,6 +1308,15 @@
<data name="ERR_AttrTypeArgCannotBeTypeVar" xml:space="preserve">
<value>'{0}': an attribute type argument cannot use type parameters</value>
</data>
<data name="WRN_AttrDependentTypeNotAllowed" xml:space="preserve">
<value>Type '{0}' cannot be used in this context because it cannot be represented in metadata.</value>
</data>
<data name="WRN_AttrDependentTypeNotAllowed_Title" xml:space="preserve">
<value>Type cannot be used in this context because it cannot be represented in metadata.</value>
</data>
<data name="ERR_AttrDependentTypeNotAllowed" xml:space="preserve">
<value>Type '{0}' cannot be used in this context because it cannot be represented in metadata.</value>
</data>
<data name="ERR_NewTyvarWithArgs" xml:space="preserve">
<value>'{0}': cannot provide arguments when creating an instance of a variable type</value>
</data>
Expand Down
2 changes: 2 additions & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1982,6 +1982,8 @@ internal enum ErrorCode
ERR_FileScopedNamespaceNotBeforeAllMembers = 8956,
ERR_NoImplicitConvTargetTypedConditional = 8957,
ERR_AttrTypeArgCannotBeTypeVar = 8958,
WRN_AttrDependentTypeNotAllowed = 8959,
ERR_AttrDependentTypeNotAllowed = 8960

#endregion

Expand Down
1 change: 1 addition & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ internal static int GetWarningLevel(ErrorCode code)
switch (code)
{
case ErrorCode.WRN_PartialMethodTypeDifference:
case ErrorCode.WRN_AttrDependentTypeNotAllowed:
// Warning level 6 is exclusively for warnings introduced in the compiler
// shipped with dotnet 6 (C# 10) and that can be reported for pre-existing code.
return 6;
Expand Down

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

17 changes: 16 additions & 1 deletion src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf

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

17 changes: 16 additions & 1 deletion src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf

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

17 changes: 16 additions & 1 deletion src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf

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

17 changes: 16 additions & 1 deletion src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf

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

17 changes: 16 additions & 1 deletion src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf

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

Loading

0 comments on commit f260ccb

Please sign in to comment.