fix(native): class-level const array element access (T.Arr[I])
A class-level const array (const Days: array[0..6] of string = (...)) read via an instance, T.Days[I], returned an empty string on native. The semantic pass folds the subscript into the field-access node — IsConstant=True with ConstArraySymbol (the global data label), ConstArrayType (the static-array type) and PropIndexExpr (the index) — but native's EmitExprToEax IsConstant branch only handled scalar string/int consts and fell through to an empty string literal. Added the class-const-array element path: compute base + (idx - LowBound) * ElemSize and load the element by type (float / string pointer / narrowed integer), plus a bare-reference case returning the label address. Mirrors the QBE EmitExpr ConstArraySymbol path. The range- and enum-indexed class-const-array e2e tests are converted to AssertRunsOnAll. (Static-array-of-interface element store/read/dispatch remains a separate, larger follow-up — tracked in bugs.txt; that test stays QBE-only meanwhile.) All three fixpoints green; 3481 tests pass.
This commit is contained in:
parent
5c1293f268
commit
28a4093244
|
|
@ -4830,6 +4830,7 @@ var
|
|||
SuppOut: string;
|
||||
LSuppNo: string;
|
||||
LSuppEnd: string;
|
||||
SCAT: TStaticArrayTypeDesc;
|
||||
begin
|
||||
if AExpr is TNilLiteral then
|
||||
begin
|
||||
|
|
@ -6477,6 +6478,41 @@ begin
|
|||
if (AExpr is TFieldAccessExpr) and TFieldAccessExpr(AExpr).IsConstant then
|
||||
begin
|
||||
FAE := TFieldAccessExpr(AExpr);
|
||||
{ Class-level const ARRAY element access (T.Days[I]): semantic folds the
|
||||
subscript into the field-access node, setting ConstArraySymbol (the global
|
||||
data label), ConstArrayType (the static-array type) and PropIndexExpr (the
|
||||
index). Compute base + (idx - LowBound)*ElemSize and load — mirrors the
|
||||
QBE EmitSupportsExpr/IsConstant ConstArraySymbol path. Without this the
|
||||
access fell through to the scalar-string branch and read an empty literal. }
|
||||
if (FAE.ConstArraySymbol <> '') and (FAE.PropIndexExpr <> nil) and
|
||||
(FAE.ConstArrayType <> nil) then
|
||||
begin
|
||||
SCAT := TStaticArrayTypeDesc(FAE.ConstArrayType);
|
||||
Self.EmitExprToEax(FAE.PropIndexExpr); { index -> %rax }
|
||||
if SCAT.LowBound <> 0 then
|
||||
Self.Emit(Format(#9'subq $%d, %%rax', [SCAT.LowBound]));
|
||||
Self.Emit(Format(#9'imulq $%d, %%rax', [SCAT.ElementType.RawSize()]));
|
||||
Self.Emit(Format(#9'leaq %s(%%rip), %%rcx',
|
||||
[NativeMangle(FAE.ConstArraySymbol)]));
|
||||
Self.Emit(#9'addq %rcx, %rax');
|
||||
if (SCAT.ElementType <> nil) and IsFloatFamily(SCAT.ElementType) then
|
||||
Self.EmitLoadFloat('(%rax)', SCAT.ElementType)
|
||||
else if (SCAT.ElementType <> nil) and SCAT.ElementType.IsString() then
|
||||
Self.Emit(#9'movq (%rax), %rax')
|
||||
else
|
||||
begin
|
||||
Self.Emit(#9'movq (%rax), %rax');
|
||||
Self.EmitNarrowToType(SCAT.ElementType);
|
||||
end;
|
||||
Exit;
|
||||
end;
|
||||
{ Bare class-const array reference (no subscript): the data label address. }
|
||||
if FAE.ConstArraySymbol <> '' then
|
||||
begin
|
||||
Self.Emit(Format(#9'leaq %s(%%rip), %%rax',
|
||||
[NativeMangle(FAE.ConstArraySymbol)]));
|
||||
Exit;
|
||||
end;
|
||||
if (FAE.ResolvedType <> nil) and FAE.ResolvedType.IsString() then
|
||||
Self.EmitStrLitAddr(FAE.ConstString)
|
||||
else
|
||||
|
|
|
|||
|
|
@ -418,19 +418,10 @@ const
|
|||
T.Free()
|
||||
end.
|
||||
''';
|
||||
var Output: string; RCode: Integer;
|
||||
Lines: TStringList;
|
||||
begin
|
||||
if not ToolchainAvailable() then begin Fail('<toolchain-missing>'); Exit end;
|
||||
AssertTrue('compile+run', CompileAndRun(Src, Output, RCode));
|
||||
AssertEquals('exit 0', 0, RCode);
|
||||
Lines := TStringList.Create();
|
||||
try
|
||||
Lines.Text := Trim(Output);
|
||||
AssertEquals('Days[0]', 'Sun', Lines.Strings[0]);
|
||||
AssertEquals('Days[1]', 'Mon', Lines.Strings[1]);
|
||||
AssertEquals('Days[5]', 'Fri', Lines.Strings[2]);
|
||||
finally Lines.Free() end
|
||||
AssertRunsOnAll(Src,
|
||||
'Sun' + Chr(10) + 'Mon' + Chr(10) + 'Fri' + Chr(10), 0);
|
||||
end;
|
||||
|
||||
procedure TE2EStaticArrayTests.TestRun_ClassConstArray_EnumIndexed;
|
||||
|
|
@ -452,18 +443,9 @@ const
|
|||
P2.Free()
|
||||
end.
|
||||
''';
|
||||
var Output: string; RCode: Integer;
|
||||
Lines: TStringList;
|
||||
begin
|
||||
if not ToolchainAvailable() then begin Fail('<toolchain-missing>'); Exit end;
|
||||
AssertTrue('compile+run', CompileAndRun(Src, Output, RCode));
|
||||
AssertEquals('exit 0', 0, RCode);
|
||||
Lines := TStringList.Create();
|
||||
try
|
||||
Lines.Text := Trim(Output);
|
||||
AssertEquals('Names[0]', 'Red', Lines.Strings[0]);
|
||||
AssertEquals('Names[2]', 'Blue', Lines.Strings[1]);
|
||||
finally Lines.Free() end
|
||||
AssertRunsOnAll(Src, 'Red' + Chr(10) + 'Blue' + Chr(10), 0);
|
||||
end;
|
||||
|
||||
procedure TE2EStaticArrayTests.TestRun_DynArray_High_ReturnsLengthMinusOne;
|
||||
|
|
|
|||
Loading…
Reference in a new issue