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

Support basic end-to-end scenarios for converting string constants to UTF8 byte representation. #58849

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions docs/features/utf8-string-literals.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Proposal - https://github.com/dotnet/csharplang/blob/main/proposals/utf8-string-literals.md
Test plan - https://github.com/dotnet/roslyn/issues/58848
9 changes: 7 additions & 2 deletions src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,11 @@ BoundExpression createConversion(
.WithSuppression(source.IsSuppressed);
}

if (conversion.IsUtf8StringLiteral)
{
CheckFeatureAvailability(syntax, MessageID.IDS_FeatureUTF8StringLiterals, diagnostics);
}

reportUseSiteDiagnosticsForUnderlyingConversions(conversion);

return new BoundConversion(
Expand Down Expand Up @@ -547,7 +552,7 @@ private BoundExpression CreateUserDefinedConversion(
convertedOperand = CreateConversion(
syntax: syntax,
source: convertedOperand,
conversion: Conversions.ClassifyStandardConversion(null, convertedOperand.Type, conversionParameterType, ref useSiteInfo),
conversion: Conversions.ClassifyStandardConversion(convertedOperand.Type, conversionParameterType, ref useSiteInfo),
isCast: false,
conversionGroupOpt: conversionGroup,
wasCompilerGenerated: true,
Expand Down Expand Up @@ -591,7 +596,7 @@ private BoundExpression CreateUserDefinedConversion(
userDefinedConversion = CreateConversion(
syntax: syntax,
source: userDefinedConversion,
conversion: Conversions.ClassifyStandardConversion(null, conversionReturnType, conversionToType, ref useSiteInfo),
conversion: Conversions.ClassifyStandardConversion(conversionReturnType, conversionToType, ref useSiteInfo),
isCast: false,
conversionGroupOpt: conversionGroup,
wasCompilerGenerated: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ public static NullableFlowState GetNullableState(ArrayBuilder<TypeWithState> typ
public static TypeSymbol? InferBestTypeForConditionalOperator(
BoundExpression expr1,
BoundExpression expr2,
ConversionsBase conversions,
Conversions conversions,
out bool hadMultipleCandidates,
ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ private static void AssertTrivialConversion(ConversionKind kind)
case ConversionKind.NoConversion:
case ConversionKind.Identity:
case ConversionKind.ImplicitConstant:
case ConversionKind.ImplicitUtf8StringLiteral:
case ConversionKind.ImplicitNumeric:
case ConversionKind.ImplicitReference:
case ConversionKind.ImplicitEnumeration:
Expand Down Expand Up @@ -226,6 +227,7 @@ internal static Conversion GetTrivialConversion(ConversionKind kind)
internal static Conversion NoConversion => new Conversion(ConversionKind.NoConversion);
internal static Conversion Identity => new Conversion(ConversionKind.Identity);
internal static Conversion ImplicitConstant => new Conversion(ConversionKind.ImplicitConstant);
internal static Conversion ImplicitUtf8StringLiteral => new Conversion(ConversionKind.ImplicitUtf8StringLiteral);
internal static Conversion ImplicitNumeric => new Conversion(ConversionKind.ImplicitNumeric);
internal static Conversion ImplicitReference => new Conversion(ConversionKind.ImplicitReference);
internal static Conversion ImplicitEnumeration => new Conversion(ConversionKind.ImplicitEnumeration);
Expand Down Expand Up @@ -825,6 +827,17 @@ public bool IsConstantExpression
}
}

/// <summary>
/// Returns true if the conversion is an implicit Utf8 strings literal conversion.
Copy link
Contributor

@RikkiGibson RikkiGibson Jan 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like string was meant to be used here instead of strings #Closed

/// </summary>
public bool IsUtf8StringLiteral
{
get
{
return Kind == ConversionKind.ImplicitUtf8StringLiteral;
}
}

/// <summary>
/// Returns true if the conversion is an implicit anonymous function conversion.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ internal enum ConversionKind : byte
ImplicitDynamic,
ExplicitDynamic,
ImplicitConstant,
ImplicitUtf8StringLiteral,
ImplicitUserDefined,
AnonymousFunction,
MethodGroup,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public static bool IsImplicitConversion(this ConversionKind conversionKind)
case Boxing:
case ImplicitDynamic:
case ImplicitConstant:
case ImplicitUtf8StringLiteral:
case ImplicitUserDefined:
case AnonymousFunction:
case ConversionKind.MethodGroup:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -367,5 +367,44 @@ public override Conversion GetStackAllocConversion(BoundStackAllocArrayCreation

return Conversion.NoConversion;
}

/// <summary>
RikkiGibson marked this conversation as resolved.
Show resolved Hide resolved
/// Returns this instance if includeNullability is correct, and returns a
/// cached clone of this instance with distinct IncludeNullability otherwise.
/// </summary>
internal new Conversions WithNullability(bool includeNullability)
{
return (Conversions)base.WithNullability(includeNullability);
}

/// <summary>
/// Determines if the source expression is convertible to the destination type via
/// any built-in or user-defined implicit conversion.
/// </summary>
public Conversion ClassifyImplicitConversionFromExpression(BoundExpression sourceExpression, TypeSymbol destination, ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo)
{
return ClassifyImplicitConversionFromExpression(sourceExpression, Compilation, destination, ref useSiteInfo);
}

/// <summary>
/// Determines if the source expression is convertible to the destination type via
/// any conversion: implicit, explicit, user-defined or built-in.
/// </summary>
/// <remarks>
/// It is rare but possible for a source expression to be convertible to a destination type
/// by both an implicit user-defined conversion and a built-in explicit conversion.
/// In that circumstance, this method classifies the conversion as the implicit conversion or explicit depending on "forCast"
/// </remarks>
public Conversion ClassifyConversionFromExpression(BoundExpression sourceExpression, TypeSymbol destination, ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo, bool forCast = false)
{
return ClassifyConversionFromExpression(sourceExpression, Compilation, destination, ref useSiteInfo, forCast);
}

// Spec 7.6.5.2: "An extension method ... is eligible if ... [an] implicit identity, reference,
// or boxing conversion exists from expr to the type of the first parameter"
public Conversion ClassifyImplicitExtensionMethodThisArgConversion(BoundExpression sourceExpressionOpt, TypeSymbol sourceType, TypeSymbol destination, ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo)
{
return ClassifyImplicitExtensionMethodThisArgConversion(sourceExpressionOpt, Compilation, sourceType, destination, ref useSiteInfo);
}
}
}
Loading