fix(semantic): accept empty open-array literal [] as an open-array argument
An empty bracket literal [] passed to a plain open-array parameter (`array of T`) failed overload resolution with "No matching overload" on both backends. A non-empty literal works because AnalyseArrayLiteralExpr infers the element type and types it `array of <elem>`; an empty [] has nothing to infer from and was left untyped (nil), so it matched neither the open-array param (nil arg type) nor the existing set / array-of-const special cases. Two changes in uSemantic: * ArgMatchScore now scores an empty TArrayLiteralExpr as an exact (2) match against any tyOpenArray parameter — an empty open array is valid for any element type — placed before the nil-arg bail so overload selection accepts it. * RetypeSetLiteralArgs pins the empty []'s ResolvedType to the chosen formal's open-array type, so codegen emits a zero-length open array (data=nil, high=-1) of the right element type. Overload disambiguation is preserved ([] picks the open-array overload; a scalar argument still picks the scalar overload), and two equally-matching open-array overloads still raise a clean "ambiguous overload" error. Works for `array of string`, `array of Integer`, and `array of const`. This was the last open item in native-testrunner-investigation.txt; the native TestRunner now passes the full suite unfiltered. Adds dual-backend e2e tests. All three fixpoints green; 3501 tests pass.
This commit is contained in:
parent
937146a3ac
commit
1ef226369d
|
|
@ -8000,6 +8000,15 @@ begin
|
|||
TArrayLiteralExpr(Arg).IsConstArray := True;
|
||||
Arg.ResolvedType := Par.ResolvedType;
|
||||
end;
|
||||
{ Empty bracket literal [] bound to a plain open-array formal: pin its type
|
||||
to the formal so codegen emits a zero-length open array (data=nil, high=-1)
|
||||
of the right element type. The untyped [] would otherwise reach codegen
|
||||
with no ResolvedType. }
|
||||
if (Par.ResolvedType <> nil) and (Par.ResolvedType.Kind = tyOpenArray) and
|
||||
(Arg is TArrayLiteralExpr) and
|
||||
(TArrayLiteralExpr(Arg).Elements.Count = 0) and
|
||||
(Arg.ResolvedType = nil) then
|
||||
Arg.ResolvedType := Par.ResolvedType;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
|
@ -8073,6 +8082,17 @@ begin
|
|||
Result := 2;
|
||||
Exit;
|
||||
end;
|
||||
{ An EMPTY bracket literal [] passed to a plain open-array parameter (array of
|
||||
T) is a valid empty open array of any element type — it has no elements to
|
||||
infer a type from, so AnalyseArrayLiteralExpr left it untyped (nil). Match
|
||||
it here, before the nil-arg bail; AnalyseProcCall re-types it to the formal's
|
||||
open-array type so codegen emits a zero-length (data=nil, high=-1) array. }
|
||||
if (AParam.Kind = tyOpenArray) and (AArgExpr is TArrayLiteralExpr) and
|
||||
(TArrayLiteralExpr(AArgExpr).Elements.Count = 0) then
|
||||
begin
|
||||
Result := 2;
|
||||
Exit;
|
||||
end;
|
||||
if AArg = nil then Exit;
|
||||
{ Integer literal (untyped constant) matches any integer type exactly —
|
||||
mirrors Pascal's treatment of untyped integer constants. Floating-point
|
||||
|
|
|
|||
|
|
@ -52,6 +52,10 @@ type
|
|||
procedure TestRun_DynToOpen_Empty;
|
||||
procedure TestRun_DynToOpen_OfString;
|
||||
procedure TestRun_DynToOpen_PassToNested;
|
||||
|
||||
{ Empty bracket literal [] as an open-array argument }
|
||||
procedure TestRun_EmptyLiteral_ToOpenArray;
|
||||
procedure TestRun_EmptyLiteral_OverloadDisambiguation;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
|
@ -484,6 +488,54 @@ begin
|
|||
AssertRunsOnAll(SrcDynNested, '100' + #10, 0);
|
||||
end;
|
||||
|
||||
procedure TE2EOpenArrayTests.TestRun_EmptyLiteral_ToOpenArray;
|
||||
{ An empty bracket literal [] passed to a plain open-array parameter — both for a
|
||||
string and an integer open array — is a valid zero-length open array. This
|
||||
previously failed overload resolution ("No matching overload"). }
|
||||
const Src = '''
|
||||
program P;
|
||||
procedure ShowS(const A: array of string);
|
||||
begin WriteLn(Length(A)) end;
|
||||
procedure ShowI(const A: array of Integer);
|
||||
var i, s: Integer;
|
||||
begin
|
||||
s := 0;
|
||||
for i := 0 to Length(A) - 1 do s := s + A[i];
|
||||
WriteLn(Length(A), ' ', s)
|
||||
end;
|
||||
begin
|
||||
ShowS([]);
|
||||
ShowS(['a', 'b']);
|
||||
ShowI([]);
|
||||
ShowI([10, 20, 30])
|
||||
end.
|
||||
''';
|
||||
begin
|
||||
if not ToolchainAvailable() then begin Ignore('toolchain unavailable'); Exit; end;
|
||||
AssertRunsOnAll(Src,
|
||||
'0' + #10 + '2' + #10 + '0 0' + #10 + '3 60' + #10, 0);
|
||||
end;
|
||||
|
||||
procedure TE2EOpenArrayTests.TestRun_EmptyLiteral_OverloadDisambiguation;
|
||||
{ [] selects the open-array overload over a non-array one; a non-bracket
|
||||
argument still picks the scalar overload. }
|
||||
const Src = '''
|
||||
program P;
|
||||
procedure F(X: Integer); overload;
|
||||
begin WriteLn('int') end;
|
||||
procedure F(const A: array of string); overload;
|
||||
begin WriteLn('oa ', Length(A)) end;
|
||||
begin
|
||||
F([]);
|
||||
F(['x']);
|
||||
F(5)
|
||||
end.
|
||||
''';
|
||||
begin
|
||||
if not ToolchainAvailable() then begin Ignore('toolchain unavailable'); Exit; end;
|
||||
AssertRunsOnAll(Src, 'oa 0' + #10 + 'oa 1' + #10 + 'int' + #10, 0);
|
||||
end;
|
||||
|
||||
initialization
|
||||
RegisterTest(TE2EOpenArrayTests);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue