Skip to content

Commit

Permalink
Support u8 type suffix for UTF8 string literals. (#58991)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlekseyTs committed Jan 25, 2022
1 parent 36def1e commit d681e4e
Show file tree
Hide file tree
Showing 27 changed files with 1,492 additions and 44 deletions.
20 changes: 20 additions & 0 deletions src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,13 @@ private BoundExpression BindExpressionInternal(ExpressionSyntax node, BindingDia
case SyntaxKind.NullLiteralExpression:
return BindLiteralConstant((LiteralExpressionSyntax)node, diagnostics);

case SyntaxKind.UTF8StringLiteralExpression:
// PROTOTYPE(UTF8StringLiterals) : In the raw-string-work we decided to not have a special expression type.
// It's just a string-literal that consumer can check the token kind on.
// Once that feature makes it into this branch, evaluate if we can/want
// to do the same for this feature.
return BindUTF8StringLiteral((LiteralExpressionSyntax)node, diagnostics);

case SyntaxKind.DefaultLiteralExpression:
return new BoundDefaultLiteral(node);

Expand Down Expand Up @@ -5897,6 +5904,19 @@ private BoundLiteral BindLiteralConstant(LiteralExpressionSyntax node, BindingDi
return new BoundLiteral(node, cv, type);
}

private BoundUTF8String BindUTF8StringLiteral(LiteralExpressionSyntax node, BindingDiagnosticBag diagnostics)
{
Debug.Assert(node.Kind() == SyntaxKind.UTF8StringLiteralExpression);

CheckFeatureAvailability(node, MessageID.IDS_FeatureUTF8StringLiterals, diagnostics);

var value = (string)node.Token.Value;
var type = ArrayTypeSymbol.CreateSZArray(Compilation.Assembly, TypeWithAnnotations.Create(GetSpecialType(SpecialType.System_Byte, diagnostics, node)));

// PROTOTYPE(UTF8StringLiterals) : The result type is a deviation from the proposal, but I think it simplifies language rules. Will bring this for discussion to LDM.
return new BoundUTF8String(node, value, type);
}

private BoundExpression BindCheckedExpression(CheckedExpressionSyntax node, BindingDiagnosticBag diagnostics)
{
// the binder is not cached since we only cache statement level binders
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ internal static bool CanBeValidAttributeArgument(ExpressionSyntax node, Binder t
// Literals (including the null literal).
case SyntaxKind.NumericLiteralExpression:
case SyntaxKind.StringLiteralExpression:
case SyntaxKind.UTF8StringLiteralExpression:
case SyntaxKind.CharacterLiteralExpression:
case SyntaxKind.TrueLiteralExpression:
case SyntaxKind.FalseLiteralExpression:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -828,7 +828,7 @@ public bool IsConstantExpression
}

/// <summary>
/// Returns true if the conversion is an implicit Utf8 strings literal conversion.
/// Returns true if the conversion is an implicit Utf8 string literal conversion.
/// </summary>
public bool IsUtf8StringLiteral
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1110,10 +1110,10 @@ private Conversion ClassifyImplicitUtf8StringLiteralConversion(BoundExpression s
if (constantValue?.IsString == true && // PROTOTYPE(UTF8StringLiterals) : confirm if we actually want it to work with 'null' constant value.
sourceExpression.Type?.SpecialType == SpecialType.System_String &&
(destination is ArrayTypeSymbol { IsSZArray: true, ElementType.SpecialType: SpecialType.System_Byte } || // byte[]
((destinationOriginalDefinition.Equals(compilation.GetWellKnownType(WellKnownType.System_Span_T), TypeCompareKind.AllIgnoreOptions) || // Span<T>
(destinationOriginalDefinition.TypeKind == TypeKind.Struct && destinationOriginalDefinition.IsRefLikeType &&
(destinationOriginalDefinition.Equals(compilation.GetWellKnownType(WellKnownType.System_Span_T), TypeCompareKind.AllIgnoreOptions) || // Span<T>
destinationOriginalDefinition.Equals(compilation.GetWellKnownType(WellKnownType.System_ReadOnlySpan_T), TypeCompareKind.AllIgnoreOptions)) && // ReadOnlySpan<T>
destinationOriginalDefinition.TypeKind == TypeKind.Struct && destinationOriginalDefinition.IsRefLikeType &&
((NamedTypeSymbol)destination).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.Single().SpecialType == SpecialType.System_Byte))) // T is byte
((NamedTypeSymbol)destination).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.Single().SpecialType == SpecialType.System_Byte))) // T is byte
{
return Conversion.ImplicitUtf8StringLiteral;
}
Expand Down Expand Up @@ -1638,7 +1638,7 @@ internal Conversion GetCallerLineNumberConversion(TypeSymbol destination, ref Co
TypeSymbol expectedAttributeType = corLibrary.GetSpecialType(SpecialType.System_Int32);
BoundLiteral intMaxValueLiteral = new BoundLiteral(syntaxNode, ConstantValue.Create(int.MaxValue), expectedAttributeType);

// Below is a dupliucation of relevant parts of ClassifyStandardImplicitConversion method.
// Below is a duplication of relevant parts of ClassifyStandardImplicitConversion method.
// It needs a compilation instance, but we don't have it and the relevant parts actually do not depend on
// a compilation.
if (HasImplicitEnumerationConversion(intMaxValueLiteral, destination))
Expand Down
6 changes: 6 additions & 0 deletions src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1288,6 +1288,12 @@
<Field Name="ConstantValueOpt" Type="ConstantValue?"/>
</Node>

<Node Name="BoundUTF8String" Base="BoundExpression">
<!-- Non-null type is required for this node kind -->
<Field Name="Type" Type="TypeSymbol" Override="true" Null="disallow"/>
<Field Name="Value" Type="string" Null="disallow"/>
</Node>

<Node Name="BoundThisReference" Base="BoundExpression">
<!-- Non-null type is required for this node kind -->
<Field Name="Type" Type="TypeSymbol" Override="true" Null="disallow"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1543,6 +1543,11 @@ public override BoundNode VisitLiteral(BoundLiteral node)
return null;
}

public override BoundNode VisitUTF8String(BoundUTF8String node)
{
return null;
}

protected void SplitIfBooleanConstant(BoundExpression node)
{
if (node.ConstantValue is { IsBoolean: true, BooleanValue: bool booleanValue })
Expand Down
8 changes: 8 additions & 0 deletions src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10357,6 +10357,14 @@ private TypeWithState InferResultNullabilityOfBinaryLogicalOperator(BoundExpress
return result;
}

public override BoundNode? VisitUTF8String(BoundUTF8String node)
{
Debug.Assert(!IsConditionalState);
var result = base.VisitUTF8String(node);
SetNotNullResult(node);
return result;
}

public override BoundNode? VisitPreviousSubmissionReference(BoundPreviousSubmissionReference node)
{
var result = base.VisitPreviousSubmissionReference(node);
Expand Down

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

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4

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

Original file line number Diff line number Diff line change
Expand Up @@ -36270,6 +36270,7 @@ public LiteralExpressionSyntax LiteralExpression(SyntaxKind kind, SyntaxToken to
case SyntaxKind.ArgListExpression:
case SyntaxKind.NumericLiteralExpression:
case SyntaxKind.StringLiteralExpression:
case SyntaxKind.UTF8StringLiteralExpression:
case SyntaxKind.CharacterLiteralExpression:
case SyntaxKind.TrueLiteralExpression:
case SyntaxKind.FalseLiteralExpression:
Expand All @@ -36284,6 +36285,7 @@ public LiteralExpressionSyntax LiteralExpression(SyntaxKind kind, SyntaxToken to
case SyntaxKind.ArgListKeyword:
case SyntaxKind.NumericLiteralToken:
case SyntaxKind.StringLiteralToken:
case SyntaxKind.UTF8StringLiteralToken:
case SyntaxKind.CharacterLiteralToken:
case SyntaxKind.TrueKeyword:
case SyntaxKind.FalseKeyword:
Expand Down Expand Up @@ -41284,6 +41286,7 @@ public static LiteralExpressionSyntax LiteralExpression(SyntaxKind kind, SyntaxT
case SyntaxKind.ArgListExpression:
case SyntaxKind.NumericLiteralExpression:
case SyntaxKind.StringLiteralExpression:
case SyntaxKind.UTF8StringLiteralExpression:
case SyntaxKind.CharacterLiteralExpression:
case SyntaxKind.TrueLiteralExpression:
case SyntaxKind.FalseLiteralExpression:
Expand All @@ -41298,6 +41301,7 @@ public static LiteralExpressionSyntax LiteralExpression(SyntaxKind kind, SyntaxT
case SyntaxKind.ArgListKeyword:
case SyntaxKind.NumericLiteralToken:
case SyntaxKind.StringLiteralToken:
case SyntaxKind.UTF8StringLiteralToken:
case SyntaxKind.CharacterLiteralToken:
case SyntaxKind.TrueKeyword:
case SyntaxKind.FalseKeyword:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2836,6 +2836,7 @@ public static LiteralExpressionSyntax LiteralExpression(SyntaxKind kind, SyntaxT
case SyntaxKind.ArgListExpression:
case SyntaxKind.NumericLiteralExpression:
case SyntaxKind.StringLiteralExpression:
case SyntaxKind.UTF8StringLiteralExpression:
case SyntaxKind.CharacterLiteralExpression:
case SyntaxKind.TrueLiteralExpression:
case SyntaxKind.FalseLiteralExpression:
Expand All @@ -2848,6 +2849,7 @@ public static LiteralExpressionSyntax LiteralExpression(SyntaxKind kind, SyntaxT
case SyntaxKind.ArgListKeyword:
case SyntaxKind.NumericLiteralToken:
case SyntaxKind.StringLiteralToken:
case SyntaxKind.UTF8StringLiteralToken:
case SyntaxKind.CharacterLiteralToken:
case SyntaxKind.TrueKeyword:
case SyntaxKind.FalseKeyword:
Expand All @@ -2868,6 +2870,7 @@ private static SyntaxKind GetLiteralExpressionTokenKind(SyntaxKind kind)
SyntaxKind.ArgListExpression => SyntaxKind.ArgListKeyword,
SyntaxKind.NumericLiteralExpression => SyntaxKind.NumericLiteralToken,
SyntaxKind.StringLiteralExpression => SyntaxKind.StringLiteralToken,
SyntaxKind.UTF8StringLiteralExpression => SyntaxKind.UTF8StringLiteralToken,
SyntaxKind.CharacterLiteralExpression => SyntaxKind.CharacterLiteralToken,
SyntaxKind.TrueLiteralExpression => SyntaxKind.TrueKeyword,
SyntaxKind.FalseLiteralExpression => SyntaxKind.FalseKeyword,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1947,6 +1947,7 @@ public BaseExpressionSyntax Update(SyntaxToken token)
/// <item><description><see cref="SyntaxKind.ArgListExpression"/></description></item>
/// <item><description><see cref="SyntaxKind.NumericLiteralExpression"/></description></item>
/// <item><description><see cref="SyntaxKind.StringLiteralExpression"/></description></item>
/// <item><description><see cref="SyntaxKind.UTF8StringLiteralExpression"/></description></item>
/// <item><description><see cref="SyntaxKind.CharacterLiteralExpression"/></description></item>
/// <item><description><see cref="SyntaxKind.TrueLiteralExpression"/></description></item>
/// <item><description><see cref="SyntaxKind.FalseLiteralExpression"/></description></item>
Expand Down
Loading

0 comments on commit d681e4e

Please sign in to comment.