← board

Builtin TObject class — var o: TObject + TObject.Create + root methods

Symptom

TObject works as a PARAMETER type (tyPointer/elem tyClass, landed bug-tobject-param-truncated-32bit) and as an implicit class PARENT (class(TObject) — parent resolution special-cases it). But there is no real TObject class ROW, so:

var o: TObject;
begin
  o := TObject.Create;   { undefined variable (TObject) }
  writeln(o.GetHashCode);
end.

fails. Blocks tobject5, tclassinfo1 (also needs RTTI ClassInfo), and any real-world code using a bare TObject instance (very common — Pascal Script, Synapse hooks, LCL).

Fix shape

Mirror RegisterBuiltinTGuid (a builtin record minted at ParseProgram start), but as a CLASS: a zero-field TObject with a VMT, a Create constructor (GetMem instance + stamp VMT + return), and Free/Destroy (the obj.Free desugar already exists). FPC's TObject also has Equals/GetHashCode/ClassName/ UnitName/InstanceSize — add the simple ones (GetHashCode = PtrInt(self), Equals = pointer compare); ClassName/UnitName/ClassInfo need RTTI (defer / separate ticket).

The tricky part vs TGuid: a class needs a VMT slot table + a constructor proc with a synthesized body. Look at how metaclass New / GenMakeFreeObject build instances for the allocation shape.

Slice 1 landed (2026-07-12, opus-p)

Instantiation works: var o: TObject; o := TObject.Create; o.Free, and a child instance assigns to a TObject ref. RegisterBuiltinTObject mints the root row (fieldless, VMT slot); the class(TObject) parent guard forces the implicit-root model so no VMT relocates (an early real-parent version RED'd test-core + cross ARC — fixed). Test: test_builtin_tobject.

Remaining: RTTI-backed root methods — GetHashCode (= PtrInt(self)), Equals (pointer compare), ClassName / UnitName / InstanceSize / ClassInfo — for tobject5/tclassinfo1. Needs the RTTI-on-IR surface; separate slice.

Gate

make test + self-host byte-identical; a compile-run test (var o: TObject; o := TObject.Create; o.Free); unskip tobject5 (partial — the RTTI-free assertions).