Skip to content

Commit

Permalink
Specially handle more scenarios for type parameters with 'allows ref …
Browse files Browse the repository at this point in the history
…struct' constraint (#73059)
  • Loading branch information
AlekseyTs authored Apr 19, 2024
1 parent e3b4e37 commit 1841565
Show file tree
Hide file tree
Showing 13 changed files with 557 additions and 21 deletions.
2 changes: 1 addition & 1 deletion src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs
Original file line number Diff line number Diff line change
Expand Up @@ -894,7 +894,7 @@ private BoundExpression BindDeconstructionVariable(
}

if (declTypeWithAnnotations.HasType &&
localSymbol.Scope == ScopedKind.ScopedValue && !declTypeWithAnnotations.Type.IsErrorTypeOrIsRefLikeTypeOrAllowByRefLike())
localSymbol.Scope == ScopedKind.ScopedValue && !declTypeWithAnnotations.Type.IsErrorTypeOrIsRefLikeTypeOrAllowsByRefLike())
{
diagnostics.Add(ErrorCode.ERR_ScopedRefAndRefStructOnly, typeSyntax.Location);
}
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 @@ -3126,7 +3126,7 @@ private BoundExpression BindOutVariableDeclarationArgument(

CheckRestrictedTypeInAsyncMethod(this.ContainingMemberOrLambda, declType.Type, diagnostics, typeSyntax);

if (localSymbol.Scope == ScopedKind.ScopedValue && !declType.Type.IsErrorTypeOrIsRefLikeTypeOrAllowByRefLike())
if (localSymbol.Scope == ScopedKind.ScopedValue && !declType.Type.IsErrorTypeOrIsRefLikeTypeOrAllowsByRefLike())
{
diagnostics.Add(ErrorCode.ERR_ScopedRefAndRefStructOnly, typeSyntax.Location);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1101,7 +1101,7 @@ protected BoundLocalDeclaration BindVariableDeclaration(

CheckRestrictedTypeInAsyncMethod(this.ContainingMemberOrLambda, declTypeOpt.Type, localDiagnostics, typeSyntax);

if (localSymbol.Scope == ScopedKind.ScopedValue && !declTypeOpt.Type.IsErrorTypeOrIsRefLikeTypeOrAllowByRefLike())
if (localSymbol.Scope == ScopedKind.ScopedValue && !declTypeOpt.Type.IsErrorTypeOrIsRefLikeTypeOrAllowsByRefLike())
{
localDiagnostics.Add(ErrorCode.ERR_ScopedRefAndRefStructOnly, typeSyntax.Location);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ private BoundForEachStatement BindForEachPartsWorker(BindingDiagnosticBag diagno

CheckRestrictedTypeInAsyncMethod(this.ContainingMemberOrLambda, declType.Type, diagnostics, typeSyntax);

if (local.Scope == ScopedKind.ScopedValue && !declType.Type.IsErrorTypeOrIsRefLikeTypeOrAllowByRefLike())
if (local.Scope == ScopedKind.ScopedValue && !declType.Type.IsErrorTypeOrIsRefLikeTypeOrAllowsByRefLike())
{
diagnostics.Add(ErrorCode.ERR_ScopedRefAndRefStructOnly, typeSyntax.Location);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ internal BoundExpression SetInferredTypeWithAnnotations(TypeWithAnnotations type

Binder.CheckRestrictedTypeInAsyncMethod(localSymbol.ContainingSymbol, type.Type, diagnosticsOpt, typeOrDesignationSyntax);

if (localSymbol.Scope == ScopedKind.ScopedValue && !type.Type.IsErrorTypeOrIsRefLikeTypeOrAllowByRefLike())
if (localSymbol.Scope == ScopedKind.ScopedValue && !type.Type.IsErrorTypeOrIsRefLikeTypeOrAllowsByRefLike())
{
diagnosticsOpt.Add(ErrorCode.ERR_ScopedRefAndRefStructOnly,
(typeOrDesignationSyntax is TypeSyntax typeSyntax ? typeSyntax.SkipScoped(out _).SkipRef() : typeOrDesignationSyntax).Location);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,9 @@ private NamedTypeSymbol ConstructAnonymousDelegateImplementationSymbol(Anonymous
// If all parameter types and return type are valid type arguments, construct
// the delegate type from a generic template. Otherwise, use a non-generic template.
bool useUpdatedEscapeRules = Compilation.SourceModule.UseUpdatedEscapeRules;
if (allValidTypeArguments(useUpdatedEscapeRules, typeDescr, out var needsIndexedName))
bool runtimeSupportsByRefLikeGenerics = Compilation.SourceAssembly.RuntimeSupportsByRefLikeGenerics;

if (allValidTypeArguments(useUpdatedEscapeRules, runtimeSupportsByRefLikeGenerics, typeDescr, out var needsIndexedName))
{
var fields = typeDescr.Fields;
Debug.Assert(fields.All(f => hasDefaultScope(useUpdatedEscapeRules, f)));
Expand Down Expand Up @@ -294,20 +296,20 @@ private NamedTypeSymbol ConstructAnonymousDelegateImplementationSymbol(Anonymous
template.Construct(typeParameters);
}

static bool allValidTypeArguments(bool useUpdatedEscapeRules, AnonymousTypeDescriptor typeDescr, out bool needsIndexedName)
static bool allValidTypeArguments(bool useUpdatedEscapeRules, bool runtimeSupportsByRefLikeGenerics, AnonymousTypeDescriptor typeDescr, out bool needsIndexedName)
{
needsIndexedName = false;
var fields = typeDescr.Fields;
int n = fields.Length;
for (int i = 0; i < n - 1; i++)
{
if (!isValidTypeArgument(useUpdatedEscapeRules, fields[i], ref needsIndexedName))
if (!isValidTypeArgument(useUpdatedEscapeRules, runtimeSupportsByRefLikeGenerics, fields[i], ref needsIndexedName))
{
return false;
}
}
var returnParameter = fields[n - 1];
return returnParameter.Type.IsVoidType() || isValidTypeArgument(useUpdatedEscapeRules, returnParameter, ref needsIndexedName);
return returnParameter.Type.IsVoidType() || isValidTypeArgument(useUpdatedEscapeRules, runtimeSupportsByRefLikeGenerics, returnParameter, ref needsIndexedName);
}

static bool hasDefaultScope(bool useUpdatedEscapeRules, AnonymousTypeField field)
Expand All @@ -324,13 +326,13 @@ static bool hasDefaultScope(bool useUpdatedEscapeRules, AnonymousTypeField field
};
}

static bool isValidTypeArgument(bool useUpdatedEscapeRules, AnonymousTypeField field, ref bool needsIndexedName)
static bool isValidTypeArgument(bool useUpdatedEscapeRules, bool runtimeSupportsByRefLikeGenerics, AnonymousTypeField field, ref bool needsIndexedName)
{
needsIndexedName = needsIndexedName || field.IsParams || field.DefaultValue is not null;
return hasDefaultScope(useUpdatedEscapeRules, field) &&
field.Type is { } type &&
!type.IsPointerOrFunctionPointer() &&
!type.IsRestrictedType() && // PROTOTYPE(RefStructInterfaces): Is this doing the right thing for 'allows ref struct' type parameters?
(type.IsTypeParameter() || !type.IsRestrictedType(ignoreSpanLikeTypes: runtimeSupportsByRefLikeGenerics)) &&
(!field.IsParams || field.Type.IsSZArray()); // [params T collection] is not recognized as a valid params parameter definition
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ internal sealed partial class AnonymousTypeManager
/// </summary>
internal sealed class AnonymousTypeParameterSymbol : TypeParameterSymbol
{
private readonly Symbol _container;
private readonly AnonymousTypeOrDelegateTemplateSymbol _container;
private readonly int _ordinal;
private readonly string _name;

public AnonymousTypeParameterSymbol(Symbol container, int ordinal, string name)
public AnonymousTypeParameterSymbol(AnonymousTypeOrDelegateTemplateSymbol container, int ordinal, string name)
{
Debug.Assert((object)container != null);
Debug.Assert(!string.IsNullOrEmpty(name));
Expand Down Expand Up @@ -93,7 +93,10 @@ public override bool HasValueTypeConstraint

public override bool AllowByRefLike
{
get { return false; }
get
{
return _container.IsDelegateType() && _container.Manager.Compilation.SourceAssembly.RuntimeSupportsByRefLikeGenerics;
}
}

public override bool IsValueTypeFromConstraintTypes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1538,7 +1538,7 @@ private void DoMiscValidation()
validateParamsType(diagnostics);
}

if (DeclaredScope == ScopedKind.ScopedValue && !Type.IsErrorTypeOrIsRefLikeTypeOrAllowByRefLike())
if (DeclaredScope == ScopedKind.ScopedValue && !Type.IsErrorTypeOrIsRefLikeTypeOrAllowsByRefLike())
{
Debug.Assert(ParameterSyntax is not null);
diagnostics.Add(ErrorCode.ERR_ScopedRefAndRefStructOnly, ParameterSyntax);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.

using System.Collections.Immutable;
using System.Diagnostics;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.Symbols
Expand All @@ -13,6 +14,7 @@ internal sealed class SynthesizedReadOnlyListTypeParameterSymbol : TypeParameter

internal SynthesizedReadOnlyListTypeParameterSymbol(SynthesizedReadOnlyListTypeSymbol containingType)
{
Debug.Assert(containingType.IsClassType());
_containingType = containingType;
}

Expand All @@ -32,7 +34,7 @@ internal SynthesizedReadOnlyListTypeParameterSymbol(SynthesizedReadOnlyListTypeS

public override bool HasValueTypeConstraint => false;

public override bool AllowByRefLike => false; // PROTOTYPE(RefStructInterfaces): That should probably match constraints on implemented interface(s).
public override bool AllowByRefLike => false; // The list is a class type and cannot store ref structs as elements.

public override bool IsValueTypeFromConstraintTypes => false;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ internal override void GenerateMethodBody(TypeCompilationState compilationState,
diagnostics.Add(ErrorCode.ERR_BadFieldTypeInRecord, f.GetFirstLocationOrNone(), parameterType);
foundBadField = true;
}
else if (parameterType.IsRestrictedType()) // PROTOTYPE(RefStructInterfaces): Is this doing the right thing for 'allows ref struct' type parameters?
else if (parameterType.IsRestrictedType())
{
// We'll have reported a diagnostic elsewhere (SourceMemberFieldSymbol.TypeChecks)
foundBadField = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,9 @@ internal override void GenerateMethodBody(TypeCompilationState compilationState,
F.WellKnownMethod(WellKnownMember.System_Text_StringBuilder__AppendString),
F.Call(value, F.SpecialMethod(SpecialMember.System_Object__ToString)))));
}
else
else if (!value.Type.IsRestrictedType())
{
// Otherwise, an error has been reported elsewhere (SourceMemberFieldSymbol.TypeChecks)
block.Add(F.ExpressionStatement(
F.Call(receiver: builder,
F.WellKnownMethod(WellKnownMember.System_Text_StringBuilder__AppendObject),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ public static bool IsPossibleArrayGenericInterface(this TypeSymbol type)
return false;
}

internal static bool IsErrorTypeOrIsRefLikeTypeOrAllowByRefLike(this TypeSymbol type)
internal static bool IsErrorTypeOrIsRefLikeTypeOrAllowsByRefLike(this TypeSymbol type)
{
return type.IsErrorType() || type.IsRefLikeTypeOrAllowsByRefLike();
}
Expand Down
Loading

0 comments on commit 1841565

Please sign in to comment.