Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
1859153
docs(frontend): add GdCompilerType design risk analysis and plan
Iridium-Zero Jun 29, 2026
b32ecb9
feat(type): implement phase 1 of GdCompilerType plan — GdccForRangeIt…
Iridium-Zero Jun 29, 2026
4f7e10d
feat(lir): restrict compiler-only type to function local variables
Iridium-Zero Jun 29, 2026
0f18d08
feat(frontend): fail-fast guards preventing compiler-only type leaks …
Iridium-Zero Jun 29, 2026
5309498
docs(frontend/type): add GdCompilerType abstraction phase and sync fa…
Iridium-Zero Jun 29, 2026
7cc045f
feat(type): add compiler-only type abstraction layer
Iridium-Zero Jun 29, 2026
20ee201
test(frontend): add comprehensive tests for compiler-only type leak g…
Iridium-Zero Jun 29, 2026
9cae1ae
feat(lir): add pre-codegen validator for compiler-only type leaks on …
Iridium-Zero Jun 30, 2026
51432a4
feat(backend): implement compiler-only storage init intrinsic and pre…
Iridium-Zero Jun 30, 2026
f2909f7
feat(backend): implement compiler-only for-range-iterator intrinsics …
Iridium-Zero Jun 30, 2026
be8b549
feat(backend): seal compiler-only type leaks in ordinary codegen path…
Iridium-Zero Jun 30, 2026
68bc7fd
feat(backend): seal compiler-only type leaks on remaining codegen pat…
Iridium-Zero Jun 30, 2026
e493ded
feat(backend): elevate compiler-only C storage contracts from implici…
Iridium-Zero Jun 30, 2026
00f2c0c
refactor(test,doc): decouple intrinsic tests from C header internals
Iridium-Zero Jul 2, 2026
7f3ca28
docs(frontend/type): promote implementation doc as long-term fact source
Iridium-Zero Jul 3, 2026
733c4a1
fix(backend): remove duplicate wildcard imports in CGenHelper
Iridium-Zero Jul 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
467 changes: 467 additions & 0 deletions doc/analysis/gdcompiler_type_design_risk_analysis.md

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions doc/gdcc_c_backend.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ already exists, otherwise use the project's own `compiler-cache` directory.
`REAL_T_IS_DOUBLE` and 32-bit Godot builds are outside the supported target matrix.
- Any Object, including engine object and GDCC objects, are always passed as pointers, and the pointers are passed as values, usually we do not use pointers to pointers.
- There are 3 types: built-in types, engine types, and GDCC types, see [gdcc_type_system.md](gdcc_type_system.md) for more details.
- Compiler-only storage types are backend-owned `GdType` implementations that do not belong to the source-facing type namespace. They are rendered with explicit `gdcc_*` storage/helper names and must never fall back to the default `godot_*` naming path.
- Engine types and GDCC types are all Objects, built-in types are not Objects.
- Only `godot_bool`, `godot_int` and `godot_float` can be used directly as C primitive types, they are always passed by value.
- Variable `ref` semantics in generated C (mandatory):
Expand Down Expand Up @@ -93,6 +94,7 @@ already exists, otherwise use the project's own `compiler-cache` directory.
- If we can 100% sure that an object is ref-counted, we can use `own_object` and `release_object` directly, these 2 functions are faster.
- For type mapping between compiler types and C types:
- GDCC types are directly used as C types, e.g., `MyCustomGdClass` is used as `MyCustomGdClass*`.
- Compiler-only types are mapped to their own explicit C storage names and helper names, not to generated `godot_*` ABI symbols.
- Other types are mapped with a `godot_` prefix, e.g., `int` is mapped to `godot_int`, `String` is mapped to `godot_String`.
- Always remember GDExtension API does not receive GDCC object ptrs, convert them to `godot_Object*` using generated per-class helper functions first.
- When receiving `godot_Object*` from GDExtension API that is actually a GDCC object, convert it to the correct GDCC type using `gdcc_object_from_godot_object_ptr(GDExtensionObjectPtr ptr)` if necessary.
Expand Down
135 changes: 135 additions & 0 deletions doc/gdcc_lir_intrinsic.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,141 @@ $target = godot_new_Vector4_with_Vector4i(&$source);

- `doc/module_impl/backend/implicit_conversion_implementation.md`

### `gdcc.for_range_iter.init`

状态:Implemented

形态:

```text
$<iter_result> = call_intrinsic "gdcc.for_range_iter.init" $<start> $<end> $<step>;
```

合同:

- result 必须存在。
- result 必须是非 `ref` 的 `compiler::GdccForRangeIter` slot。
- exactly three arguments。
- arguments 必须依次是 `int`、`int`、`int` slot,分别表示已归一化的 `start`、`end`、`step`。

C backend 语义:

```c
$target = gdcc_for_range_iter_from_bounds($start, $end, $step);
```

`step == 0` 策略:

- `gdcc_for_range_iter_from_bounds(...)` 显式调用 runtime error helper(`godot_print_error(...)`)并返回不可无限循环的 fallback state。
- 前端未来 lowering 仍应避免生成零步长;手写 LIR 不会静默获得无限循环语义。

Lifecycle / ownership:

- `compiler::GdccForRangeIter` 是 destroyable non-object value。
- helper 返回按值 iterator state;slot 写入仍通过 `CBodyBuilder.callAssign(...)` 处理旧值 destroy 与 direct struct assignment。
- 不产生 Godot object ownership,也不参与 Variant pack / unpack。

长期事实源:

- `doc/module_impl/frontend/frontend_gdcompiler_type_implementation.md`

### `gdcc.for_range_iter.should_continue`

状态:Implemented

形态:

```text
$<bool_result> = call_intrinsic "gdcc.for_range_iter.should_continue" $<iter>;
```

合同:

- result 必须存在。
- result 必须是非 `ref` 的 `bool` slot。
- exactly one argument。
- argument 必须是 `compiler::GdccForRangeIter` slot。

C backend 语义:

```c
$target = gdcc_for_range_iter_should_continue(&$iter);
```

Lifecycle / ownership:

- 只读 iterator state,不销毁或转移 iterator ownership。
- 正步长使用 `current < end`,负步长使用 `current > end`,end 为排他边界。

长期事实源:

- `doc/module_impl/frontend/frontend_gdcompiler_type_implementation.md`

### `gdcc.for_range_iter.next`

状态:Implemented

形态:

```text
$<next_iter_result> = call_intrinsic "gdcc.for_range_iter.next" $<iter>;
```

合同:

- result 必须存在。
- result 必须是非 `ref` 的 `compiler::GdccForRangeIter` slot。
- exactly one argument。
- argument 必须是 `compiler::GdccForRangeIter` slot。

C backend 语义:

```c
$target = gdcc_for_range_iter_next(&$iter);
```

Lifecycle / ownership:

- 输入 iterator 只读。
- helper 返回新的按值 iterator state,语义为 `current + step`,保留原 `end` 与 `step`。
- slot 写入仍通过 `CBodyBuilder.callAssign(...)` 处理旧值 destroy 与 direct struct assignment。

长期事实源:

- `doc/module_impl/frontend/frontend_gdcompiler_type_implementation.md`

### `gdcc.for_range_iter.get`

状态:Implemented

形态:

```text
$<int_result> = call_intrinsic "gdcc.for_range_iter.get" $<iter>;
```

合同:

- result 必须存在。
- result 必须是非 `ref` 的 `int` slot。
- exactly one argument。
- argument 必须是 `compiler::GdccForRangeIter` slot。

C backend 语义:

```c
$target = gdcc_for_range_iter_get(&$iter);
```

Lifecycle / ownership:

- 只读 iterator state,不销毁或转移 iterator ownership。
- 返回当前迭代值,不推进 state。

长期事实源:

- `doc/module_impl/frontend/frontend_gdcompiler_type_implementation.md`

## 新增 Intrinsic Checklist

新增 intrinsic 时按以下顺序维护:
Expand Down
15 changes: 15 additions & 0 deletions doc/gdcc_low_ir.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,20 @@ manipulate variables.

See [Types](gdcc_type_system.md) for details on the type system used in Low IR.

Low IR can also carry backend-owned compiler-only types. They use the `compiler::<Name>` textual grammar and are only valid on function-local `<variables>` storage unless a dedicated validator explicitly allows a wider surface.

Current MVP contract:

- Compiler-only type text is LIR-only and does not reuse source-facing declared-type parsing.
- `compiler::<Name>` is accepted only for function `<variables>`.
- Compiler-only types must not appear on:
- function `<parameters>`
- function `<return_type>`
- class `<properties>`
- signal parameters
- lambda captures
- The first concrete grammar instance is `compiler::GdccForRangeIter`.

## Instructions

Each instruction has an optional return value, a string id, and a list of operands:
Expand Down Expand Up @@ -86,6 +100,7 @@ Current assignability rules in backend codegen are:
- `Array[SubClass]` to `Array[SuperClass]`.
- `Dictionary[K, V]` to `Dictionary` / `Dictionary[Variant, Variant]`.
- `Dictionary[K1, V1]` to `Dictionary[K2, V2]` when `K1` is assignable to `K2` and `V1` is assignable to `V2`.
- Compiler-only types are not widened into ordinary ABI-facing assignability. They stay on backend-owned local/intrinsic paths.
```
$<result_id> = assign $<source_id>
```
Expand Down
14 changes: 13 additions & 1 deletion doc/gdcc_runtime_lib.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,19 @@ extend the runtime-provided `godot_*` surface.
- `gdcc_intrinsic.h`: wrapper-only inbound materialization helpers for accepted Variant payloads whose
runtime type differs from the published method metadata. It owns vector narrow-payload helpers
and string-family `String` / `StringName` cross-case helpers; scalar `int -> float` inbound
materialization remains directly emitted by the generated wrapper code.
materialization remains directly emitted by the generated wrapper code. The same header also owns
compiler-only range-iterator runtime storage helpers:
- `gdcc_for_range_iter` is the backend-owned C storage struct for `compiler::GdccForRangeIter`
- `gdcc_for_range_iter_init()` is the prepare-block default initializer
- `gdcc_for_range_iter_destroy()` is the matching destroy hook; it is intentionally a no-op today
- `gdcc_for_range_iter_from_bounds()` materializes normalized `start/end/step` bounds and reports
`step == 0` through `godot_print_error(...)` before returning an always-terminating fallback state with
`step=1`. A zero-step argument is a programming error; frontend lowering and generated code must not
emit zero-step range iterators under any normal path.
- `gdcc_for_range_iter_should_continue()`, `gdcc_for_range_iter_next()` and
`gdcc_for_range_iter_get()` implement the range intrinsic family
- these helpers are GDCC-owned runtime support and must keep the `gdcc_*` namespace instead of
pretending to be generated `godot_*` wrappers
- `gdcc_helper.h`: the aggregate helper header included by generated entry code. It provides
runtime error printing, Object property get/set helpers, RefCounted ownership helpers, GDCC
wrapper pointer conversion helpers, compatibility constructors, UTF-8 formatting helpers,
Expand Down
18 changes: 15 additions & 3 deletions doc/gdcc_type_system.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,19 @@
- Primitive types: `GdPrimitiveType` and subclasses (`GdIntType`, `GdFloatType`, `GdBoolType`, `GdStringType`, ...).
- Vector/geometry types: `GdVectorType`, `GdFloatVectorType`, `GdQuaternionType`, `GdTransform3DType`, etc.
- Container types: `GdArrayType`, `GdDictionaryType`, and `GdPacked*` variants.
- Object/reference types: `GdObjectType`, `GdNodePathType`, `GdRidType`, `GdSignalType`, `GdCallableType`.
- Meta/extension types: `GdMetaType`, `GdExtensionTypeEnum` for annotations and extension points.
- Object/reference types: `GdObjectType`, `GdNodePathType`, `GdRidType`, `GdSignalType`, `GdCallableType`.
- Meta/extension types: `GdMetaType`, `GdExtensionTypeEnum` for annotations and extension points.
- Compiler-only types: `GdCompilerType` as the shared abstraction for backend-only storage types, with `GdccForRangeIterType` as the first concrete example.

## Compiler-only Types

- `GdCompilerType` models GDCC-owned runtime storage that only exists inside compiler / lowering / LIR / backend pipelines.
- Compiler-only types are not part of the GDScript source-facing type set:
- declared type parsers must not resolve them
- type-meta and outward ABI metadata must not publish them
- ordinary user-facing semantic facts such as `expressionTypes()` and ordinary slot typing must not expose them
- `GdccForRangeIterType` is the first concrete `GdCompilerType`. It represents backend-owned range-iterator state storage, not a user-declarable `range(...)` result type.
- Compiler-only types may participate in LIR/backend-local assignment and intrinsic contracts, but they are outside the ordinary frontend assignment/conversion matrix.

## Major Types (Summary)
- `GdPrimitiveType`: atomic values.
Expand Down Expand Up @@ -60,7 +71,8 @@
- `Array[SubClass]` -> `Array[SuperClass]`
- `Dictionary[K, V]` -> `Dictionary` / `Dictionary[Variant, Variant]`
- `Dictionary[K1, V1]` -> `Dictionary[K2, V2]` when both key/value directions are assignable.
- Other implicit promotions (for example numeric promotion) are not part of generic assignment compatibility and must be handled by dedicated lowering/instruction semantics.
- Other implicit promotions (for example numeric promotion) are not part of generic assignment compatibility and must be handled by dedicated lowering/instruction semantics.
- Compiler-only types are not part of the ordinary assignment-compatibility matrix; they are handled by LIR/backend-specific contracts and must not be treated as source-facing declared types.
- For "TypeType", which is a type representing another type:
- e.g. `var N = Node` where `N` is a "TypeType" representing the `Node` type.
- We do not explicitly model "TypeType" in the type system; instead, we use a `StringName` to represent the type name as the implementation detail.
Expand Down
Loading