- 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.
82 lines
3.2 KiB
Plaintext
82 lines
3.2 KiB
Plaintext
// issue-0021: 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
|
|
//
|
|
// ── Repro ──────────────────────────────────────────────────────────────────
|
|
//
|
|
// Foo :: struct { pixel_w: s32; dpi: f32; }
|
|
//
|
|
// calc_void :: (self: *Foo, wf: f32) {
|
|
// self.dpi = if wf > 0.0 then xx self.pixel_w / wf else 1.0;
|
|
// }
|
|
//
|
|
// calc_bool :: (self: *Foo, wf: f32) -> bool {
|
|
// self.dpi = if wf > 0.0 then xx self.pixel_w / wf else 1.0;
|
|
// true;
|
|
// }
|
|
//
|
|
// With `f.pixel_w = 2880` and `wf = 1440.0`:
|
|
// - `calc_void` produces `f.dpi = 2.0` (correct).
|
|
// - `calc_bool` produces `f.dpi = 0.0` (wrong).
|
|
//
|
|
// Only difference: the enclosing function's declared return type. The `xx`
|
|
// cast appears to take its target type from the enclosing function's return
|
|
// type rather than from the assignment LHS (which is `f32`). When the return
|
|
// type is `bool`, the divide is lowered against a non-numeric/zero-valued
|
|
// operand.
|
|
//
|
|
// ── Related, possibly same root cause ───────────────────────────────────────
|
|
//
|
|
// In a struct-returning function, this form makes LLVM verification fail with
|
|
// `udiv { float, float, i32, i32, float, float }` — the divide is lowered as
|
|
// integer division over the function's return-struct shape:
|
|
//
|
|
// FC :: struct { a: f32; b: f32; c: s32; d: s32; e: f32; f: f32; }
|
|
// begin :: (self: *Foo) -> FC {
|
|
// if self.last_perf > 0 {
|
|
// self.delta_time = xx (current - self.last_perf) / xx freq;
|
|
// }
|
|
// FC.{ ... };
|
|
// }
|
|
//
|
|
// ── Workaround ─────────────────────────────────────────────────────────────
|
|
//
|
|
// Hoist the `xx` cast into its own variable so the divide sees two
|
|
// already-typed f32 values:
|
|
//
|
|
// pw : f32 = xx self.pixel_w;
|
|
// self.dpi = if wf > 0.0 then pw / wf else 1.0;
|
|
//
|
|
// ── Real-world impact ──────────────────────────────────────────────────────
|
|
//
|
|
// The SX Chess game's dpi_scale calculation took this form inside
|
|
// `SdlPlatform.init` (which returns `bool`). On a retina display the
|
|
// dpi_scale silently became 0, so the glyph cache rasterized at scale=0 and
|
|
// every text label rendered invisibly.
|
|
|
|
#import "modules/std.sx";
|
|
|
|
Foo :: struct { pixel_w: s32; dpi: f32; }
|
|
|
|
calc_void :: (self: *Foo, wf: f32) {
|
|
self.dpi = if wf > 0.0 then xx self.pixel_w / wf else 1.0;
|
|
}
|
|
|
|
calc_bool :: (self: *Foo, wf: f32) -> bool {
|
|
self.dpi = if wf > 0.0 then xx self.pixel_w / wf else 1.0;
|
|
true;
|
|
}
|
|
|
|
main :: () -> void {
|
|
f : *Foo = xx malloc(size_of(Foo));
|
|
f.pixel_w = 2880;
|
|
|
|
f.dpi = 0.0;
|
|
calc_void(f, 1440.0);
|
|
out("void-return (expect 200): "); out(int_to_string(xx (f.dpi * 100.0))); out("\n");
|
|
|
|
f.dpi = 0.0;
|
|
calc_bool(f, 1440.0);
|
|
out("bool-return (expect 200): "); out(int_to_string(xx (f.dpi * 100.0))); out("\n");
|
|
}
|