Skip to content

Commit 101ddf8

Browse files
Add support for constant slices of InlineArrays
1 parent 667036c commit 101ddf8

File tree

5 files changed

+56
-9
lines changed

5 files changed

+56
-9
lines changed

ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineArrayTests.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,23 @@ public byte GenericByteN(Generic16<byte> array, byte value)
7777
return array[GetIndex()] = value;
7878
}
7979

80+
public void Slice(Byte16 array)
81+
{
82+
Receiver(array[..8]);
83+
Receiver((ReadOnlySpan<byte>)array[..8]);
84+
ReceiverSpan(array[..8]);
85+
ReceiverReadOnlySpan(array[..8]);
86+
}
87+
88+
// TODO
89+
//public void Slice(Byte16 array, int end)
90+
//{
91+
// Receiver(array[..end]);
92+
// Receiver((ReadOnlySpan<byte>)array[..end]);
93+
// ReceiverSpan(array[..end]);
94+
// ReceiverReadOnlySpan(array[..end]);
95+
//}
96+
8097
public byte VariableSplitting(Byte16 array, byte value)
8198
{
8299
return array[GetIndex()] = (array[GetIndex() + 1] = value);

ICSharpCode.Decompiler/CSharp/CallBuilder.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,16 +468,35 @@ public ExpressionWithResolveResult Build(OpCode callOpCode, IMethod method,
468468
&& argumentList.Length == 2)
469469
{
470470
argumentList.CheckNoNamedOrOptionalArguments();
471+
var arrayType = method.TypeArguments[0];
472+
var arrayLength = arrayType.GetInlineArrayLength();
473+
var arrayElementType = arrayType.GetInlineArrayElementType();
471474
var argument = argumentList.Arguments[0];
475+
var spanLengthExpr = argumentList.Arguments[1];
472476
var targetType = method.ReturnType;
477+
var spanType = typeSystem.FindType(KnownTypeCode.SpanOfT);
473478
if (argument.Expression is DirectionExpression { FieldDirection: FieldDirection.In or FieldDirection.Ref, Expression: var lvalueExpr })
474479
{
475480
// `(TargetType)(in arg)` is invalid syntax.
476481
// Also, `f(in arg)` is invalid when there's an implicit conversion involved.
477482
argument = argument.UnwrapChild(lvalueExpr);
478483
}
479-
return new CastExpression(expressionBuilder.ConvertType(targetType), argument.Expression)
484+
if (spanLengthExpr.ResolveResult.ConstantValue is int spanLength && spanLength <= arrayLength)
485+
{
486+
if (spanLength < arrayLength)
487+
{
488+
argument = new IndexerExpression(argument.Expression, new BinaryOperatorExpression {
489+
Operator = BinaryOperatorType.Range,
490+
Right = spanLengthExpr.Expression
491+
}).WithRR(new ResolveResult(new ParameterizedType(spanType, arrayElementType))).WithoutILInstruction();
492+
if (targetType.IsKnownType(KnownTypeCode.SpanOfT))
493+
{
494+
return argument;
495+
}
496+
}
497+
return new CastExpression(expressionBuilder.ConvertType(targetType), argument.Expression)
480498
.WithRR(new ConversionResolveResult(targetType, argument.ResolveResult, Conversion.InlineArrayConversion));
499+
}
481500
}
482501

483502
if (settings.LiftNullables && method.Name == "GetValueOrDefault"

ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3138,18 +3138,13 @@ protected internal override TranslatedExpression VisitLdElemaInlineArray(LdElema
31383138
memberStatic: false,
31393139
memberDeclaringType: inst.Type
31403140
);
3141-
var inlineArrayElementType = GetInlineArrayElementType(inst.Type);
3141+
var inlineArrayElementType = inst.Type.GetInlineArrayElementType();
31423142
IndexerExpression indexerExpr = new IndexerExpression(
31433143
arrayExpr, inst.Indices.Select(i => TranslateArrayIndex(i).Expression)
31443144
);
31453145
TranslatedExpression expr = indexerExpr.WithILInstruction(inst).WithRR(new ResolveResult(inlineArrayElementType));
31463146
return new DirectionExpression(FieldDirection.Ref, expr)
31473147
.WithoutILInstruction().WithRR(new ByReferenceResolveResult(expr.ResolveResult, ReferenceKind.Ref));
3148-
3149-
IType GetInlineArrayElementType(IType arrayType)
3150-
{
3151-
return arrayType?.GetFields(f => !f.IsStatic).SingleOrDefault()?.Type ?? SpecialType.UnknownType;
3152-
}
31533148
}
31543149

31553150
TranslatedExpression TranslateArrayIndex(ILInstruction i)

ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,9 +233,9 @@ Conversion StandardImplicitConversion(IType fromType, IType toType, bool allowTu
233233
if ((toType.IsKnownType(KnownTypeCode.SpanOfT) || toType.IsKnownType(KnownTypeCode.ReadOnlySpanOfT))
234234
&& fromType.IsInlineArrayType())
235235
{
236-
var @field = fromType.GetFields(f => !f.IsStatic, GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault();
236+
var elementType = fromType.GetInlineArrayElementType();
237237
var spanElementType = toType.TypeArguments[0];
238-
if (field != null && IdentityConversion(field.ReturnType, spanElementType))
238+
if (IdentityConversion(elementType, spanElementType))
239239
return Conversion.InlineArrayConversion;
240240
}
241241
return Conversion.None;

ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,22 @@ public static bool IsInlineArrayType(this IType type)
316316
return td.HasAttribute(KnownAttribute.InlineArray);
317317
}
318318

319+
public static int? GetInlineArrayLength(this IType type)
320+
{
321+
if (type.Kind != TypeKind.Struct)
322+
return null;
323+
var td = type.GetDefinition();
324+
if (td == null)
325+
return null;
326+
var attr = td.GetAttribute(KnownAttribute.InlineArray);
327+
return attr?.FixedArguments.FirstOrDefault().Value as int?;
328+
}
329+
330+
public static IType GetInlineArrayElementType(this IType arrayType)
331+
{
332+
return arrayType?.GetFields(f => !f.IsStatic).SingleOrDefault()?.Type ?? SpecialType.UnknownType;
333+
}
334+
319335
/// <summary>
320336
/// Gets whether the type is the specified known type.
321337
/// For generic known types, this returns true for any parameterization of the type (and also for the definition itself).

0 commit comments

Comments
 (0)