← board

Copy as a generic overloaded intrinsic (string + dynarray families)

Why the lib cannot finish this

lib/rtl/strutils.pas provides Copy(s: AnsiString; index, count): AnsiString — good enough for the demos that copy substrings, and soon to be SetLength-optimized (build the result once, no char-by-char append). But the full FPC Copy is a generic intrinsic overloaded over a type family, which a single non-generic RTL function cannot express:

  1. dynamic-array Copy(arr, index, count) → sub-array of array of T. The real blocker: element-type-aware, generic over T. Not writable as one concrete RTL routine. Needs generics or a compiler intrinsic.
  2. 2-arg form Copy(s, index) = from index to the end (count defaults to the rest). Overload resolution on arity.
  3. string-family overloads: ShortString, UnicodeString / WideString (if/when those types exist).
  4. call-site resolution by argument type: pick the string vs dynarray meaning of Copy from the actual argument type.

Scope

Track B note (2026-06-25)

The interim AnsiString Copy (lib/rtl/sysutils.pas) is now SetLength+single Move, not char-by-char append — the optimization this ticket anticipated. Behaviour unchanged (make lib-test green). Does not affect the Track A intrinsic scope above (still needs generics / call-site overload for the dynarray family).

Siblings (same reasoning — mention so they aren't re-discovered)

Delete(s/arr, index, count), Insert(src, dst, index), and Concat(...) are also intrinsics overloaded over the same string + dynarray families. They will hit the identical "can't be one non-generic RTL function" wall. Fold them into this work (or spin a sibling ticket) rather than re-filing each from a demo.

Log

Progress (2026-06-19) — dynamic-array Copy DONE

The real blocker (generic dynamic-array Copy(arr, index, count) → fresh array of T, element-type-aware) is implemented, plus the 2-arg Copy(arr, index) form and call-site resolution by argument type:

Validated x86-64 (test-core, test/test_dynarray_copy.pas) + arm32 cross suite; self-host + cross-bootstrap byte-identical. NOTE: a raw byte copy, so an array of a managed element type (AnsiString / managed record) is shallow — deep element copy is a later extension.

Landmines recorded: a bare runtime-helper call whose result is unused is NOT emitted (only statement-linked nodes are) — store the result into a temp; and the result must be tagged so the assignment stores the full 8-byte handle.

Remaining: string-family overloads beyond the RTL Copy (ShortString / UnicodeString), and the dynarray Delete/Insert/Concat variants. On i386/aarch64 b := Copy(...) is additionally blocked by a separate pre-existing whole-dynamic-array assignment gap (bug-dynarray-whole-var-assign-cross).

Progress (2026-06-20) — string Delete / Insert / Concat in sysutils

The AnsiString Delete, Insert, and Concat siblings are now in lib/rtl/sysutils.pas as pure-Pascal library functions (not compiler intrinsics). Design decision: Copy stays compiler-owned (it has intercept entanglements with Str); Delete/Insert/Concat are library-side since the compiler doesn't depend on them internally.

All three tested in test/lib_sysutils.pas with golden-output verification (make lib-test). Remaining scope under this ticket: the dynarray variants of Delete/Insert/Concat (these need compiler intrinsics, same as dynarray Copy), and string-family overloads for ShortString/UnicodeString.

TRIAGE (2026-06-30, multi-agent verify)

SOLVED. Probed: Copy(dynarr,1,2)->len2 [10,20]; Copy(s,1,5)->'hello'; 2-arg Copy(s,7)->'world' all work. Remaining scope is covered elsewhere: dynarray Delete/Insert = [[feature-dynarray-insert-delete]]; ShortString/UnicodeString overloads need types that do not exist yet. The Copy intrinsic itself is complete -> done.