blaise/tools/bif-coverage/bif-coverage.status

313 lines
8.9 KiB
Plaintext
Raw Permalink Normal View History

# bif-coverage status - one line per public AST field.
# Format: <TClass>.<Field> <serialise|safe>
# serialise must appear in EncodeStmt/EncodeExpr AND ReadStmt/ReadExpr
# safe intentionally not serialised (set by semantic etc.)
# Regenerate from scratch with: bif-coverage --reset
# TIntLiteral (uAST.pas:36)
TIntLiteral.Value serialise
TIntLiteral.IsUInt64 safe
# TFloatLiteral (uAST.pas:44)
TFloatLiteral.Value serialise
# TStringLiteral (uAST.pas:49)
TStringLiteral.Value serialise
TStringLiteral.IsCharCoerce safe
TStringLiteral.CharOrdValue safe
# TStringSubscriptExpr (uAST.pas:56)
TStringSubscriptExpr.StrExpr serialise
TStringSubscriptExpr.IndexExpr serialise
# TArrayLiteralExpr (uAST.pas:63)
TArrayLiteralExpr.Elements serialise
feat(params): array of const (heterogeneous variadic parameters) A parameter declared 'array of const' accepts a single call-site bracket list of mixed-type values, boxed into an array of the intrinsic record TVarRec and passed via the existing open-array ABI: procedure Log(args: array of const); ... Log([42, 'hi', 3.5, True]); This is the one loosely-typed-passing mechanism Blaise adopts (see the rationale section); untyped params, varargs, and Variant remain omitted. - RTL/builtins: TVarRec is registered as a compiler-intrinsic record { VType: Byte; VValue: Pointer } (16-byte layout, mirroring TMethod), with vt* discriminant constants - all available with no uses clause, matching Delphi's auto-available System.TVarRec. Blaise has no record variant parts, so the callee reads each element by reinterpret-casting the single VValue slot (Integer(v.VValue), string(PChar(v.VValue)), PDouble(v.VValue)^, ...). - Parser: 'array of const' parses as an open array whose element is TVarRec. - Semantic: a heterogeneous bracket literal is typed 'array of TVarRec' rather than rejected; overload resolution binds it (and homogeneous / empty literals) to an array-of-const formal; retyping runs for proc, func, and method calls. - Codegen (both backends): EmitConstArrayLiteral builds one 16-byte TVarRec per element, tagging by inferred type. Borrow semantics (FPC) - strings and objects are stored without AddRef. Doubles are heap-boxed via _BlaiseGetMem (vtExtended holds a PDouble) since a double does not fit the pointer slot. - Native: also fixes a pre-existing gap - reading a float through a pointer deref (PDouble^) in EmitExprToXmm0 - needed for vtExtended read-back. Tests: cp.test.arrayofconst (parser/semantic/IR) and cp.test.e2e.arrayofconst (compile + run on both backends, including value read-back, empty/homogeneous lists, and string-variable borrow). Grammar and language rationale documented.
2026-06-13 19:37:59 +03:00
TArrayLiteralExpr.IsConstArray safe
feat(sets): range syntax in set literals — [lo..hi] (#105) A set literal element may now be a constant range: e := [Red..Blue]; { {Red, Green, Blue} } e := [m0, m2..m4, m7]; { ranges mix with single members } The parser builds a transient TSetRangeExpr for each lo..hi element; the semantic pass (AnalyseSetLiteralExpr) expands it into the individual member idents before any other consumer runs, so overload resolution, the bitmask folder, the jumbo-set path, and both code generators see an ordinary member list and need no range-specific logic. Both bounds must be compile-time constants of the set's base type. A reversed constant range [Blue..Red] is a compile-time error rather than a silently empty set — matching Blaise's preference for rejecting confusing-but-legal constructs over FPC's empty-set-with-warning behaviour. Variable bounds [lo..hi] are rejected ("set range bound must be a constant"); runtime-variable ranges are deferred. TSetRangeExpr is wired into the .bif serialiser and the AST cloner so a generic template body containing an unexpanded range round-trips through separate compilation (verified by hand: a generic returning [m1..m3] compiled to .o, then instantiated from the .bif with source hidden). Set base types remain enumerations; the issue's set-of-byte example needs ordinal-base set types, tracked separately in docs/future-improvements.adoc. Range expansion is base-type-agnostic, so ranges will work for those automatically once they land. Docs: grammar.ebnf SetElement rule; language-rationale.adoc decision + alternatives. bif-coverage.status regenerated for the new node. FIXPOINT_OK + NATIVE_FIXPOINT_OK; full suite OK (3201 tests, 11 new).
2026-06-15 19:14:05 +03:00
# TSetRangeExpr (uAST.pas:80)
TSetRangeExpr.LowExpr serialise
TSetRangeExpr.HighExpr serialise
feat(sets): range syntax in set literals — [lo..hi] (#105) A set literal element may now be a constant range: e := [Red..Blue]; { {Red, Green, Blue} } e := [m0, m2..m4, m7]; { ranges mix with single members } The parser builds a transient TSetRangeExpr for each lo..hi element; the semantic pass (AnalyseSetLiteralExpr) expands it into the individual member idents before any other consumer runs, so overload resolution, the bitmask folder, the jumbo-set path, and both code generators see an ordinary member list and need no range-specific logic. Both bounds must be compile-time constants of the set's base type. A reversed constant range [Blue..Red] is a compile-time error rather than a silently empty set — matching Blaise's preference for rejecting confusing-but-legal constructs over FPC's empty-set-with-warning behaviour. Variable bounds [lo..hi] are rejected ("set range bound must be a constant"); runtime-variable ranges are deferred. TSetRangeExpr is wired into the .bif serialiser and the AST cloner so a generic template body containing an unexpanded range round-trips through separate compilation (verified by hand: a generic returning [m1..m3] compiled to .o, then instantiated from the .bif with source hidden). Set base types remain enumerations; the issue's set-of-byte example needs ordinal-base set types, tracked separately in docs/future-improvements.adoc. Range expansion is base-type-agnostic, so ranges will work for those automatically once they land. Docs: grammar.ebnf SetElement rule; language-rationale.adoc decision + alternatives. bif-coverage.status regenerated for the new node. FIXPOINT_OK + NATIVE_FIXPOINT_OK; full suite OK (3201 tests, 11 new).
2026-06-15 19:14:05 +03:00
# TNilLiteral (uAST.pas:87)
# TIdentExpr (uAST.pas:97)
TIdentExpr.Name serialise
TIdentExpr.ParamMode safe
TIdentExpr.IsConstant safe
TIdentExpr.ConstValue safe
TIdentExpr.ConstString safe
TIdentExpr.IsGlobal safe
TIdentExpr.IsThreadVar safe
TIdentExpr.IsImplicitSelf safe
TIdentExpr.IsImplicitSelfMethod safe
TIdentExpr.IsMetaclassRef safe
TIdentExpr.ConstArraySymbol safe
feat(sets): range syntax in set literals — [lo..hi] (#105) A set literal element may now be a constant range: e := [Red..Blue]; { {Red, Green, Blue} } e := [m0, m2..m4, m7]; { ranges mix with single members } The parser builds a transient TSetRangeExpr for each lo..hi element; the semantic pass (AnalyseSetLiteralExpr) expands it into the individual member idents before any other consumer runs, so overload resolution, the bitmask folder, the jumbo-set path, and both code generators see an ordinary member list and need no range-specific logic. Both bounds must be compile-time constants of the set's base type. A reversed constant range [Blue..Red] is a compile-time error rather than a silently empty set — matching Blaise's preference for rejecting confusing-but-legal constructs over FPC's empty-set-with-warning behaviour. Variable bounds [lo..hi] are rejected ("set range bound must be a constant"); runtime-variable ranges are deferred. TSetRangeExpr is wired into the .bif serialiser and the AST cloner so a generic template body containing an unexpanded range round-trips through separate compilation (verified by hand: a generic returning [m1..m3] compiled to .o, then instantiated from the .bif with source hidden). Set base types remain enumerations; the issue's set-of-byte example needs ordinal-base set types, tracked separately in docs/future-improvements.adoc. Range expansion is base-type-agnostic, so ranges will work for those automatically once they land. Docs: grammar.ebnf SetElement rule; language-rationale.adoc decision + alternatives. bif-coverage.status regenerated for the new node. FIXPOINT_OK + NATIVE_FIXPOINT_OK; full suite OK (3201 tests, 11 new).
2026-06-15 19:14:05 +03:00
# TFieldAccessExpr (uAST.pas:118)
TFieldAccessExpr.RecordName serialise
TFieldAccessExpr.FieldName serialise
TFieldAccessExpr.Base serialise
TFieldAccessExpr.FieldInfo safe
TFieldAccessExpr.IsConstant safe
TFieldAccessExpr.ConstValue safe
TFieldAccessExpr.ConstString safe
TFieldAccessExpr.ConstArraySymbol safe
TFieldAccessExpr.IsConstructorCall safe
TFieldAccessExpr.IsClassAccess safe
TFieldAccessExpr.PropRead safe
TFieldAccessExpr.PropOwnerType safe
fix(codegen): virtual-dispatch property accessors through the vtable A property whose getter or setter is declared `virtual` did not dispatch through the vtable: reading or writing the property through a base-typed variable holding a derived instance called the BASE accessor, not the override. A direct b.GetVal() call dispatched correctly, but b.Val (the property over the same virtual getter) did not. TBase = class function GetVal: Integer; virtual; begin Result := 1; end; property Val: Integer read GetVal; end; TDerived = class(TBase) function GetVal: Integer; override; begin Result := 99; end; end; b: TBase := TDerived.Create; WriteLn(b.Val); // was 1, now 99 The property read/write lowering always emitted a static call to the accessor's declaring class. Now the semantic pass records the accessor's vtable slot on the AST node (PropAccessorVSlot, -1 when the accessor is not virtual), and codegen dispatches through the vtable when the slot is >= 0, exactly as a direct method call does. QBE: PropAccessorTarget computes the call target — emitting the vptr+slot loads and returning the function-pointer temp for a virtual accessor, or the static mangled symbol otherwise — and each call site emits its own `call <target>(...)`. (A single emit-and-return helper was tried first but tripped a latent native-backend miscompile on the self-compile; see bugs.txt. The target-string shape avoids it.) Native: EmitPropAccessorCallNative dispatches through the vtable or statically. Covers getter and setter, on both backends. Adds TE2EInheritTests.TestRun_VirtualProperty{Getter,Setter}_Dispatches (dual-backend). The two new AST fields are marked `safe` in bif-coverage.status (semantic-set, not serialised).
2026-06-16 14:59:46 +03:00
TFieldAccessExpr.PropAccessorVSlot safe
TFieldAccessExpr.IsImplicitSelf safe
TFieldAccessExpr.IsMethodCall safe
TFieldAccessExpr.IsInterfaceCall safe
TFieldAccessExpr.IsGlobal safe
TFieldAccessExpr.IsClassNameAccess safe
TFieldAccessExpr.IsClassTypeAccess safe
TFieldAccessExpr.IsBuiltinToString safe
TFieldAccessExpr.IsVarParam safe
TFieldAccessExpr.PropIndexExpr serialise
TFieldAccessExpr.IsCharAccess safe
TFieldAccessExpr.IsArrayAccess safe
# TIsExpr (uAST.pas:151)
TIsExpr.Obj serialise
TIsExpr.TypeName serialise
# TAsExpr (uAST.pas:159)
TAsExpr.Obj serialise
TAsExpr.TypeName serialise
# TSupportsExpr (uAST.pas:168)
TSupportsExpr.Obj serialise
TSupportsExpr.IntfTypeName serialise
TSupportsExpr.OutVarName serialise
TSupportsExpr.OutVarIsGlobal safe
# TInheritedCallExpr (uAST.pas:182)
TInheritedCallExpr.Name serialise
TInheritedCallExpr.Args serialise
# TBinaryExpr (uAST.pas:199)
TBinaryExpr.Op serialise
TBinaryExpr.Left serialise
TBinaryExpr.Right serialise
# TNotExpr (uAST.pas:207)
TNotExpr.Expr serialise
# TAssignment (uAST.pas:219)
TAssignment.Name serialise
TAssignment.Expr serialise
TAssignment.IsVarParam safe
TAssignment.IsGlobal safe
TAssignment.IsThreadVar safe
TAssignment.IsWeakLhs safe
TAssignment.ImplicitSelfField safe
# TIfStmt (uAST.pas:235)
TIfStmt.Condition serialise
TIfStmt.ThenStmt serialise
TIfStmt.ElseStmt serialise
# TCompoundStmt (uAST.pas:243)
TCompoundStmt.Stmts serialise
# TWhileStmt (uAST.pas:250)
TWhileStmt.Condition serialise
TWhileStmt.Body serialise
# TRepeatStmt (uAST.pas:257)
TRepeatStmt.Body serialise
TRepeatStmt.Condition serialise
# TForStmt (uAST.pas:264)
TForStmt.VarName serialise
TForStmt.IsGlobal safe
TForStmt.StartExpr serialise
TForStmt.EndExpr serialise
TForStmt.IsDownTo serialise
TForStmt.Body serialise
# TForInStmt (uAST.pas:275)
TForInStmt.VarName serialise
TForInStmt.VarIsGlobal safe
TForInStmt.CollExpr serialise
TForInStmt.Body serialise
TForInStmt.IsArrayIter safe
TForInStmt.EnumVarName safe
TForInStmt.ResolvedEnumTypeName safe
TForInStmt.IdxVarName safe
TForInStmt.ArrayLow safe
TForInStmt.ArrayHigh safe
TForInStmt.IsDynArrayIter safe
TForInStmt.IsStringIter safe
TForInStmt.IsCodePointIter safe
TForInStmt.AdvVarName safe
TForInStmt.IsSetIter safe
TForInStmt.SetBitCount safe
TForInStmt.SetMaskVarName safe
feat(sets): jumbo sets — set of enum up to 256 members Extend set of <enum> from a 64-member cap to 256, Java-EnumSet style. Sets of 64 members or fewer keep the existing single-register bitmask (QBE w/l); sets of 65..256 members ('jumbo') become an inline byte-array bitmap of ceil(N/8) bytes, treated as a value aggregate (passed by reference, returned via sret, memset/memcpy), with operations performed by new RTL helpers. Representation (uSymbolTable): TSetTypeDesc.IsJumbo (BitCount > 64) and RawByteSize; RawSize/ByteSize/AllocAlign sized accordingly. TSymbol gains ConstSetBytes/ConstSetQbe for jumbo constants (can't fit an Int64 mask). RTL: new runtime/src/main/pascal/blaise_set.pas — _SetIn/_SetInclude/ _SetExclude/_SetUnion/_SetInter/_SetDiff/_SetEqual/_SetCopy over byte-array bitmaps (overlap-safe). Wired into runtime/Makefile. Semantic: the four >64 caps become >256. AnalyseSetConstDecl folds a jumbo const to a byte array. The anonymous set for 'X in [a,b,c]' is sized to the largest listed ordinal (when constant), not the full enum — keeping the common low-ordinal membership test (incl. the compiler's own TokenKind tests) on the fast register path. This also fixes a latent miscompile: the old fixed-l representation silently dropped any listed ordinal >= 64. Codegen (both backends): jumbo branches for literal, in, +/-/*, =/<>, Include/Exclude, for-in, assignment, params (pmJumboSetValue ABI), and sret returns. The register 'in' gained a range guard for literal-sized sets. Native reserves two 32-byte scratch slots per frame (and .bss in main) for set-op/literal result buffers. QBE adds IsAggregateAddrType so jumbo sets ride the record/static-array address paths and are never promoted. OPDF: no format change — recSet SizeInBytes (1 byte) already covers <=32. Verified: FIXPOINT_OK and NATIVE_FIXPOINT_OK; full suite (3172 tests) green built by the stage-2 binary, the QBE fixpoint binary, and the native fixpoint binary; bif-coverage OK. Tests: cp.test.jumboset (12 IR) and cp.test.e2e.jumboset (6 e2e, both backends via AssertRunsOnAll); the >256-member rejection test in cp.test.sets updated. Docs: grammar.ebnf and language-rationale set-type sections updated for the 256 cap and literal sizing. Closes the design discussion behind #81.
2026-06-15 01:23:19 +03:00
TForInStmt.SetIsJumbo safe
# TTryFinallyStmt (uAST.pas:312)
TTryFinallyStmt.TryBody serialise
TTryFinallyStmt.FinallyBody serialise
# TTryExceptStmt (uAST.pas:329)
TTryExceptStmt.TryBody serialise
TTryExceptStmt.Handlers serialise
TTryExceptStmt.ElseBody serialise
TTryExceptStmt.ExceptBody serialise
# TRaiseStmt (uAST.pas:342)
TRaiseStmt.Expr serialise
# TExitStmt (uAST.pas:353)
TExitStmt.Value serialise
TExitStmt.ResultAssign safe
# TBreakStmt (uAST.pas:361)
# TContinueStmt (uAST.pas:364)
# TCaseStmt (uAST.pas:375)
TCaseStmt.Selector serialise
TCaseStmt.Branches serialise
TCaseStmt.ElseStmt serialise
TCaseStmt.IsStringCase safe
# TFieldAssignment (uAST.pas:386)
TFieldAssignment.RecordName serialise
TFieldAssignment.FieldName serialise
TFieldAssignment.Expr serialise
TFieldAssignment.ObjExpr serialise
TFieldAssignment.FieldInfo safe
TFieldAssignment.IsClassAccess safe
TFieldAssignment.IsImplicitSelf safe
TFieldAssignment.IsGlobal safe
TFieldAssignment.IsVarParam safe
TFieldAssignment.PropIndexExpr serialise
TFieldAssignment.PropOwnerType safe
fix(codegen): virtual-dispatch property accessors through the vtable A property whose getter or setter is declared `virtual` did not dispatch through the vtable: reading or writing the property through a base-typed variable holding a derived instance called the BASE accessor, not the override. A direct b.GetVal() call dispatched correctly, but b.Val (the property over the same virtual getter) did not. TBase = class function GetVal: Integer; virtual; begin Result := 1; end; property Val: Integer read GetVal; end; TDerived = class(TBase) function GetVal: Integer; override; begin Result := 99; end; end; b: TBase := TDerived.Create; WriteLn(b.Val); // was 1, now 99 The property read/write lowering always emitted a static call to the accessor's declaring class. Now the semantic pass records the accessor's vtable slot on the AST node (PropAccessorVSlot, -1 when the accessor is not virtual), and codegen dispatches through the vtable when the slot is >= 0, exactly as a direct method call does. QBE: PropAccessorTarget computes the call target — emitting the vptr+slot loads and returning the function-pointer temp for a virtual accessor, or the static mangled symbol otherwise — and each call site emits its own `call <target>(...)`. (A single emit-and-return helper was tried first but tripped a latent native-backend miscompile on the self-compile; see bugs.txt. The target-string shape avoids it.) Native: EmitPropAccessorCallNative dispatches through the vtable or statically. Covers getter and setter, on both backends. Adds TE2EInheritTests.TestRun_VirtualProperty{Getter,Setter}_Dispatches (dual-backend). The two new AST fields are marked `safe` in bif-coverage.status (semantic-set, not serialised).
2026-06-16 14:59:46 +03:00
TFieldAssignment.PropAccessorVSlot safe
fix: element access through array-typed fields — r.A[i], c.N.A[i], SetLength(r.A) Array-typed FIELDS were second-class citizens for element access; this lands the full variation family on both backends: - Semantic: r.A[i] := v dropped the subscript from the LHS type — the parser stores it in TFieldAssignment.PropIndexExpr (the indexed- property slot) and semantic ignored it for real fields, demanding the whole array type on the RHS. A subscript on a real dyn/static-array field is now an ELEMENT write (new semantic-set IsElemWrite flag); both backends emit the element store with the standard ARC and record-copy rules. - Parser: c.N.A[i] := v failed with "Expected 'end' but got '['" — the chained L-value walker now accepts a terminating Field[idx] :=, and the subscript-chain path accepts arr[i].A[j] := v (subscript directly over another subscript stays a clear parse error). - Bare implicit-Self: A[i] := v inside a method raised "Undeclared variable 'A'" — TStaticSubscriptAssign now resolves array-typed fields of Self (IsImplicitSelf + ImplicitFieldInfo). - SetLength(r.A, n): QBE refused ("first argument must be a variable"); native silently emitted NO code for field receivers and mis-stored through var-param receivers. QBE routes through EmitLValueAddr; native gains EmitLValueSlotAddr covering field, var-param and implicit-Self receivers for dyn-array and string SetLength. - Read side: c.A[i] through a class variable computed the element base as if c were an inline record (missing object-pointer load) and segfaulted; implicit-Self bases had the same gap; native missed chained reads (c.N.A[i]) entirely. All base shapes are handled in the IsArrayAccess read paths of both backends now. bif-coverage.status regenerated for the new semantic-set AST fields (safe). Tests: 4 IR tests (cp.test.dynarray) + 6 e2e tests on both backends (cp.test.e2e.records) covering record/class/implicit-Self receivers, nested chains, static-array fields and string-element ARC. Suite: 2922 OK on working and fixpoint binaries; FIXPOINT_OK (single round); NATIVE_FIXPOINT_OK.
2026-06-11 11:19:35 +03:00
TFieldAssignment.IsElemWrite safe
# TStaticSubscriptAssign (uAST.pas:414)
TStaticSubscriptAssign.ArrayName serialise
TStaticSubscriptAssign.IndexExpr serialise
TStaticSubscriptAssign.ValueExpr serialise
feat(arrays): support multi-dimensional static arrays Add multi-dimensional static array syntax, both the comma form (array[0..1, 0..2] of Integer; A[i, j]) and the equivalent nested/chained form (array[0..1] of array[0..2] of Integer; A[i][j]). The comma forms are syntactic sugar: the parser desugars array[a, b] of T into the nested array[a] of array[b] of T, and A[i, j] into chained subscripts A[i][j], so the two notations are fully interchangeable in every position. Layers: - uParser: comma loops in ParseTypeName and subscript reads; the statement LHS now lowers A[i, j] := v and A[i][j] := v to a TStaticSubscriptAssign carrying a new BaseExpr (the inner-array address expression). The previous "chained base not yet supported" rejection is removed. - uAST: TStaticSubscriptAssign.BaseExpr (owned); wired into CloneStmt and the .bif encoder/decoder (uUnitInterfaceIO); bif-coverage status updated. - uSemantic: BaseExpr branch resolves the inner static-array type and checks the index and value element type. - Codegen (both backends): a nested static-array element now evaluates to its inline address (mirroring record/interface elements) so a further subscript indexes into it; the static-subscript store reads its base from BaseExpr when set. Nested arrays are a flat row-major contiguous block. - OPDF: no new record needed - each dimension emits one recArray whose element points at the next inner recArray; pdr follows the chain and renders the value as a true multi-dimensional structure. Tests: IR unit tests (cp.test.staticarray), e2e tests on both backends via AssertRunsOnAll (cp.test.e2e.staticarray), and a nested-recArray OPDF test (cp.test.opdf). Grammar and language rationale documented.
2026-06-13 13:56:38 +03:00
TStaticSubscriptAssign.BaseExpr serialise
TStaticSubscriptAssign.IsGlobal safe
fix: var parameters of dynamic-array, static-array, PChar and interface types Diagnosis credit: Andrew Haines (issue #89) correctly identified that the subscript-assign path loads through a var/out parameter's slot only once — the slot holds the ADDRESS of the caller's variable, so element writes landed in the wrong memory and corrupted the heap. His patch covered the QBE dyn-array and class cases; the class half had already landed independently (248dccf). This implements the remaining cases across BOTH backends in the current tree. Subscript writes through var/out params (TStaticSubscriptAssign gains IsVarParam, set by the semantic pass; bif-coverage status updated): - dynamic arrays: one extra dereference to reach the data pointer (writes were lost and stray stores corrupted the heap; SetLength and element reads already worked), - static arrays: load the array address from the slot instead of offsetting the slot itself (QBE wrote into the parameter slot region; the native ident READ also produced garbage — pmVar now treated like the other by-ref param modes), - PChar: extra dereference before the byte store (writes were lost). Interface var/out parameters (previously did not even compile: QBE emitted loads from a non-existent %_var_G_obj; native mis-spilled the single incoming pointer as a two-register fat pointer): - interface variables now occupy ONE contiguous 16-byte fat-pointer block (obj at +0, itab at +8). QBE locals: a single alloc8 16 with the _itab name derived at +8; QBE globals: a single 16-byte data item $Name_obj with the itab half addressed as $Name_obj + 8 (the separate $Name_itab item could not be guaranteed adjacent). Native locals and globals were already contiguous. - new IntfObjAddr/IntfItabAddr helpers route every QBE obj/itab access (assignment variants incl. weak, dispatch, expr-pair reads, as-out binding); var/out params dereference the slot first. - native: var-param-aware receiver load in EmitInterfaceCall, var-param LHS in EmitInterfaceAssign (shares the sret-Result pointer path), interface globals usable as var args (leaq Name_obj), and the call slot counter treats a var interface arg as ONE pointer slot (it was counted as two, desynchronising the argument register pops). IR assertions updated for the new global fat-pointer layout. New e2e tests: TestRun_VarParamDynArray_WriteAndGrow, TestRun_VarParamStaticArray_PChar, TestRun_VarParamInterface_DispatchAndReassign. Closes #89.
2026-06-11 20:50:50 +03:00
TStaticSubscriptAssign.IsVarParam safe
fix: element access through array-typed fields — r.A[i], c.N.A[i], SetLength(r.A) Array-typed FIELDS were second-class citizens for element access; this lands the full variation family on both backends: - Semantic: r.A[i] := v dropped the subscript from the LHS type — the parser stores it in TFieldAssignment.PropIndexExpr (the indexed- property slot) and semantic ignored it for real fields, demanding the whole array type on the RHS. A subscript on a real dyn/static-array field is now an ELEMENT write (new semantic-set IsElemWrite flag); both backends emit the element store with the standard ARC and record-copy rules. - Parser: c.N.A[i] := v failed with "Expected 'end' but got '['" — the chained L-value walker now accepts a terminating Field[idx] :=, and the subscript-chain path accepts arr[i].A[j] := v (subscript directly over another subscript stays a clear parse error). - Bare implicit-Self: A[i] := v inside a method raised "Undeclared variable 'A'" — TStaticSubscriptAssign now resolves array-typed fields of Self (IsImplicitSelf + ImplicitFieldInfo). - SetLength(r.A, n): QBE refused ("first argument must be a variable"); native silently emitted NO code for field receivers and mis-stored through var-param receivers. QBE routes through EmitLValueAddr; native gains EmitLValueSlotAddr covering field, var-param and implicit-Self receivers for dyn-array and string SetLength. - Read side: c.A[i] through a class variable computed the element base as if c were an inline record (missing object-pointer load) and segfaulted; implicit-Self bases had the same gap; native missed chained reads (c.N.A[i]) entirely. All base shapes are handled in the IsArrayAccess read paths of both backends now. bif-coverage.status regenerated for the new semantic-set AST fields (safe). Tests: 4 IR tests (cp.test.dynarray) + 6 e2e tests on both backends (cp.test.e2e.records) covering record/class/implicit-Self receivers, nested chains, static-array fields and string-element ARC. Suite: 2922 OK on working and fixpoint binaries; FIXPOINT_OK (single round); NATIVE_FIXPOINT_OK.
2026-06-11 11:19:35 +03:00
TStaticSubscriptAssign.IsImplicitSelf safe
feat(properties): default array property — Obj[I] sugar Adds the `default` directive on an indexed property, enabling subscript sugar on the object itself: property Items[I: Integer]: T read Get write Put; default; ... V[0] := 10; // lowers to V.Put(0, 10) WriteLn(V[0]); // lowers to V.Get(0) This is the mechanism behind the familiar List[i] syntax and was a real foundational gap (the directive did not even parse — "Expected ':'"). Implementation: - Parser: accept the trailing `default;` directive after a property declaration; set TPropertyDecl.IsDefault. - AST / symbol table: IsDefault on TPropertyDecl and TPropertyInfo; TRecordTypeDesc.FindDefaultProperty walks the inheritance chain. - Semantic: Obj[I] read (AnalyseStringSubscriptExpr) synthesises the default property's field access and reuses the indexed-property read path; Obj[I] := V write (AnalyseStaticSubscriptAssign) records the setter on the TStaticSubscriptAssign node. - Codegen (both backends): the write path emits the setter call via the existing PropAccessorTarget / EmitPropAccessorCallNative helpers, so it honours virtual/override on the accessor; the read path delegates the TStringSubscriptExpr to its folded property-read field access. - Cross-unit: IsDefault is serialised in the .bif interface so a default property declared in one unit keeps its subscript sugar elsewhere. Verified read, write, string-element, inherited, and cross-unit cases on both backends. Adds IR tests (TPropertyTests.TestCodegen_DefaultProperty_ {Read,Write}) and dual-backend e2e tests (TE2EPropertyTests.TestRun_ DefaultProperty_{ReadWrite,StringElement,Inherited}). Grammar and language-rationale updated; the two new TStaticSubscriptAssign fields are marked safe in bif-coverage.status.
2026-06-16 16:48:38 +03:00
TStaticSubscriptAssign.PropOwnerType safe
TStaticSubscriptAssign.PropAccessorVSlot safe
# TPointerWriteStmt (uAST.pas:444)
TPointerWriteStmt.PtrExpr serialise
TPointerWriteStmt.ValExpr serialise
# TProcCall (uAST.pas:452)
TProcCall.Name serialise
TProcCall.Args serialise
TProcCall.IsImplicitSelfMethod safe
TProcCall.IsIndirectCall safe
TProcCall.IndirectCallIsGlobal safe
# TFuncCallExpr (uAST.pas:465)
TFuncCallExpr.Name serialise
TFuncCallExpr.Args serialise
TFuncCallExpr.IsImplicitSelfMethod safe
TFuncCallExpr.IsIndirectCall safe
TFuncCallExpr.IndirectCallIsGlobal safe
TFuncCallExpr.IsBuiltinHasClassAttr safe
TFuncCallExpr.HasClassAttrClass safe
TFuncCallExpr.HasClassAttrAttr safe
# TIndirectFuncCallExpr (uAST.pas:491)
TIndirectFuncCallExpr.CalleeExpr serialise
TIndirectFuncCallExpr.Args serialise
# TDerefExpr (uAST.pas:501)
TDerefExpr.Expr serialise
# TAddrOfExpr (uAST.pas:508)
TAddrOfExpr.Expr serialise
TAddrOfExpr.ResolvedFreeRoutine safe
# TMethodCallStmt (uAST.pas:520)
TMethodCallStmt.ObjectName serialise
TMethodCallStmt.Name serialise
TMethodCallStmt.Args serialise
TMethodCallStmt.ObjExpr serialise
TMethodCallStmt.IsImplicitSelf safe
TMethodCallStmt.IsGlobal safe
TMethodCallStmt.IsVarParam safe
TMethodCallStmt.IsBuiltinToString safe
TMethodCallStmt.IsConstructorCall safe
TMethodCallStmt.IsMetaclassDispatch safe
TMethodCallStmt.IsProcFieldCall safe
# TInheritedCallStmt (uAST.pas:554)
TInheritedCallStmt.Name serialise
TInheritedCallStmt.Args serialise
# TMethodCallExpr (uAST.pas:835)
TMethodCallExpr.ObjectName serialise
TMethodCallExpr.Name serialise
TMethodCallExpr.Args serialise
TMethodCallExpr.ObjExpr serialise
TMethodCallExpr.IsConstructorCall safe
TMethodCallExpr.IsMetaclassDispatch safe
TMethodCallExpr.IsGlobal safe
TMethodCallExpr.IsVarParam safe
TMethodCallExpr.IsBuiltinToString safe
TMethodCallExpr.IsBuiltinInheritsFrom safe
TMethodCallExpr.IsProcFieldCall safe
# === Interface-container types (uUnitInterface.pas + TMethodParam) ===
# serialise must appear in the encoder AND decoder of uUnitInterfaceIO.pas
# TRoutineSig (uUnitInterface.pas:64)
TRoutineSig.Name serialise
TRoutineSig.IsFunction serialise
TRoutineSig.Params serialise
TRoutineSig.ReturnType serialise
TRoutineSig.IsInline safe
TRoutineSig.IsPublished safe
TRoutineSig.IsExternal safe
TRoutineSig.ExternalName safe
TRoutineSig.CallingConv serialise
TRoutineSig.VTableSlot serialise
TRoutineSig.ResolvedQbeName serialise
TRoutineSig.IsVirtual serialise
TRoutineSig.IsOverride serialise
# TConstEntry (uUnitInterface.pas:97)
TConstEntry.Decl serialise
TConstEntry.TypeRef serialise
# TVarEntry (uUnitInterface.pas:105)
TVarEntry.Name serialise
TVarEntry.TypeRef serialise
TVarEntry.IsThreadVar serialise
# TUnitInterface (uUnitInterface.pas:169)
TUnitInterface.Name serialise
TUnitInterface.SourceFile serialise
TUnitInterface.SourceHash serialise
TUnitInterface.SourceModTime serialise
TUnitInterface.CompilerId serialise
TUnitInterface.UsedUnits serialise
TUnitInterface.ImplUsedUnits serialise
TUnitInterface.HasInitialization serialise
# TMethodParam (uAST.pas:764)
TMethodParam.ParamName serialise
TMethodParam.TypeName serialise
TMethodParam.IsVarParam serialise
TMethodParam.IsConstParam serialise
TMethodParam.IsOutParam serialise
TMethodParam.IsOpenArray serialise
TMethodParam.DefaultValue serialise
TMethodParam.HasDefault serialise