Skip to content

Commit

Permalink
Widen RefKindVector to hold RefReadonlyParameter (#69034)
Browse files Browse the repository at this point in the history
* Widen `RefKindVector` to hold `RefReadonlyParameter`

* Assert that argument ref kind is not `ref readonly` in dynamic call

* Test dynamic invocations with `ref readonly` parameters
  • Loading branch information
jjonescz authored Jul 19, 2023
1 parent 0bed80f commit 60de847
Show file tree
Hide file tree
Showing 14 changed files with 364 additions and 262 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,6 @@ internal FieldSymbol DefineCallSiteStorageSymbol(NamedTypeSymbol containerDefini
}
}

// PROTOTYPE: RefKindVector does not support RefReadOnlyParameter.
RefKindVector byRefs;
if (hasByRefs)
{
Expand Down Expand Up @@ -804,7 +803,11 @@ internal FieldSymbol DefineCallSiteStorageSymbol(NamedTypeSymbol containerDefini
return synthesizedType.Construct(delegateSignature);

// The distinction between by-ref kinds is ignored for dynamic call-sites.
static RefKind getRefKind(RefKind refKind) => refKind == RefKind.None ? RefKind.None : RefKind.Ref;
static RefKind getRefKind(RefKind refKind)
{
Debug.Assert(refKind != RefKind.RefReadOnlyParameter);
return refKind == RefKind.None ? RefKind.None : RefKind.Ref;
}
}

private BoundExpression GetArgumentInfo(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,8 +323,7 @@ static bool hasDefaultScope(bool useUpdatedEscapeRules, AnonymousTypeField field

static bool isValidTypeArgument(bool useUpdatedEscapeRules, AnonymousTypeField field, ref bool needsIndexedName)
{
// PROTOTYPE: Instead of using indexed name for delegates with `ref readonly` parameters, expand RefKindVector to use more bits?
needsIndexedName = needsIndexedName || field.IsParams || field.DefaultValue is not null || field.RefKind == RefKind.RefReadOnlyParameter;
needsIndexedName = needsIndexedName || field.IsParams || field.DefaultValue is not null;
return hasDefaultScope(useUpdatedEscapeRules, field) &&
field.Type is { } type &&
!type.IsPointerOrFunctionPointer() &&
Expand Down
34 changes: 19 additions & 15 deletions src/Compilers/CSharp/Portable/Symbols/Synthesized/RefKindVector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
internal struct RefKindVector : IEquatable<RefKindVector>
{
private const int BitsPerRefKind = 3;
private BitVector _bits;

internal static RefKindVector Create(int capacity)
Expand All @@ -21,7 +22,7 @@ internal static RefKindVector Create(int capacity)

private RefKindVector(int capacity)
{
_bits = BitVector.Create(capacity * 2);
_bits = BitVector.Create(capacity * BitsPerRefKind);
}

private RefKindVector(BitVector bits)
Expand All @@ -31,32 +32,35 @@ private RefKindVector(BitVector bits)

internal bool IsNull => _bits.IsNull;

internal int Capacity => _bits.Capacity / 2;
internal int Capacity => _bits.Capacity / BitsPerRefKind;

internal IEnumerable<ulong> Words() => _bits.Words();

internal RefKind this[int index]
{
get
{
index *= 2;
return (_bits[index + 1], _bits[index]) switch
index *= BitsPerRefKind;
return (_bits[index + 2], _bits[index + 1], _bits[index]) switch
{
(false, false) => RefKind.None,
(false, true) => RefKind.Ref,
(true, false) => RefKind.Out,
(true, true) => RefKind.RefReadOnly,
(false, false, false) => RefKind.None,
(false, false, true) => RefKind.Ref,
(false, true, false) => RefKind.Out,
(false, true, true) => RefKind.RefReadOnly,
(true, false, false) => RefKind.RefReadOnlyParameter,
var bits => throw ExceptionUtilities.UnexpectedValue(bits)
};
}
set
{
index *= 2;
(_bits[index + 1], _bits[index]) = value switch
index *= BitsPerRefKind;
(_bits[index + 2], _bits[index + 1], _bits[index]) = value switch
{
RefKind.None => (false, false),
RefKind.Ref => (false, true),
RefKind.Out => (true, false),
RefKind.RefReadOnly => (true, true),
RefKind.None => (false, false, false),
RefKind.Ref => (false, false, true),
RefKind.Out => (false, true, false),
RefKind.RefReadOnly => (false, true, true),
RefKind.RefReadOnlyParameter => (true, false, false),
_ => throw ExceptionUtilities.UnexpectedValue(value)
};
}
Expand Down Expand Up @@ -132,7 +136,7 @@ public static bool TryParse(string refKindString, int capacity, out RefKindVecto

Debug.Assert(firstWord is not null);

var bitVector = BitVector.FromWords(firstWord.Value, otherWords?.ToArrayAndFree() ?? Array.Empty<ulong>(), capacity * 2);
var bitVector = BitVector.FromWords(firstWord.Value, otherWords?.ToArrayAndFree() ?? Array.Empty<ulong>(), capacity * BitsPerRefKind);
result = new RefKindVector(bitVector);
return true;
}
Expand Down
Loading

0 comments on commit 60de847

Please sign in to comment.