platform: SDL3 backend (desktop + WASM) + two bug repros
- library/modules/platform/sdl3.sx: SdlPlatform impl wrapping SDL3 init,
GL context, event pump, swap. run_frame_loop owns the loop: while loop
on desktop, emscripten_set_main_loop on WASM. Registers an event-watch
that re-invokes the frame closure during macOS modal resize-drag so
content keeps rendering at the new size. safe_insets / keyboard /
show_keyboard / hide_keyboard are no-ops (these targets have no soft
keyboard).
Two compiler bug repros uncovered during the refactor:
- examples/issue-0020.sx: global `Foo = .{}` zero-initializes, ignoring
struct field defaults. Local `Foo = .{}` correctly applies defaults.
Workaround: set fields explicitly in an init method or heap-allocate
the value.
- examples/issue-0021.sx: an enclosing function's return type bleeds
into `xx`'s target type inside an `if-then-else` expression on the
RHS of a struct-field assignment. The same expression in a `-> void`
function produces the right value; in a `-> bool` function it
silently produces 0. Bit the SX Chess game's dpi_scale calc inside
`SdlPlatform.init` (returns bool), making all text labels render
invisibly on retina. Workaround: hoist each `xx` cast into its own
f32 local.
Regression gate: 50/50 examples pass, macOS chess game runs at ~2700fps
(close to the pre-refactor 2900 baseline), WASM build still emits a
working .html/.js/.wasm/.data quad.
This commit is contained in:
54
examples/issue-0020.sx
Normal file
54
examples/issue-0020.sx
Normal file
@@ -0,0 +1,54 @@
|
||||
// issue-0020: Global `Foo = .{}` zero-initializes, ignoring field defaults
|
||||
//
|
||||
// Struct field defaults declared via `field: T = expr;` are honored when the
|
||||
// struct is constructed at function-local scope, but are silently dropped
|
||||
// when the struct is declared at module scope with `= .{}`.
|
||||
//
|
||||
// Repro:
|
||||
//
|
||||
// Foo :: struct {
|
||||
// running: bool = true; // default
|
||||
// }
|
||||
//
|
||||
// g_foo : Foo = .{}; // global → g_foo.running == false (BUG)
|
||||
//
|
||||
// main :: () {
|
||||
// l_foo : Foo = .{}; // local → l_foo.running == true (correct)
|
||||
// }
|
||||
//
|
||||
// Surface bites:
|
||||
//
|
||||
// - In the SX Chess game, the SDL3 platform backend stores a `running: bool
|
||||
// = true` field on `SdlPlatform`. With `g_plat : SdlPlatform = .{};` the
|
||||
// main loop's `while self.running { ... }` exits immediately because
|
||||
// `running` was zero-initialized despite the field default.
|
||||
// - Workaround: assign defaults explicitly in the type's `init` method, or
|
||||
// spell every field out at the global construction site:
|
||||
// g_plat : SdlPlatform = .{ running = true };
|
||||
//
|
||||
// Likely cause: the globals path emits an LLVM ConstantAggregateZero (or
|
||||
// memset-to-zero) for the initializer, skipping the per-field default-expr
|
||||
// lowering used for local declarations.
|
||||
//
|
||||
// This file is a runnable repro: locals print "running=true", globals print
|
||||
// "running=false".
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
Foo :: struct {
|
||||
running: bool = true;
|
||||
x: s32 = 42;
|
||||
}
|
||||
|
||||
g_foo : Foo = .{};
|
||||
|
||||
main :: () -> void {
|
||||
out("global running=");
|
||||
out(if g_foo.running then "true" else "false");
|
||||
out("\n");
|
||||
|
||||
l_foo : Foo = .{};
|
||||
out("local running=");
|
||||
out(if l_foo.running then "true" else "false");
|
||||
out("\n");
|
||||
}
|
||||
Reference in New Issue
Block a user