From ea7d729589259c52808d3e1d77f99f880f188147 Mon Sep 17 00:00:00 2001 From: Nicolas Maman Date: Tue, 20 Oct 2026 19:10:47 -0300 Subject: [PATCH] Aether 0.836.0: the accessors into their argument declare it @into 0.836.0 checks aether#2990: a function that returns a pointer made from a borrowed `ptr` parameter is E0902 unless the parameter is `@into`, which says the argument reaches the result and nowhere else. 13 accessors hand back a pointer into the block they are given (state_at, sim_at, the constraint, block, stage and spec accessors, the wide solver's state_or_identity, resolve_contact_body_sim, native.scratch), and now declare it. No caller stores a result past its argument, so no call site changed. player_step_frame lost the return after its `while true`, which never completes: 0.836.0 warns (W1002), and scripts/test.sh fails a warning. CI and the README pin 0.836.0. The suite and the golden trace pass on it. --- .github/workflows/test.yaml | 13 +++++++------ README.md | 10 +++++----- aephysics/contact_solver/module.ae | 8 ++++---- aephysics/contact_solver_wide/module.ae | 4 ++-- aephysics/dynamics/module.ae | 2 +- aephysics/human/module.ae | 2 +- aephysics/native/module.ae | 2 +- aephysics/recording/module.ae | 1 - aephysics/solver/module.ae | 10 +++++----- 9 files changed, 26 insertions(+), 26 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 51d50f6..f443910 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -7,13 +7,14 @@ on: - main pull_request: -# Pin: 0.835.0, the latest release: its lane moves (aether#2550), bit -# casts and reductions (#2603) and `@target("avx2") import` (#2607) are -# what the wide gather, the wide separating axis test and the run-time -# width are written with. A reproducible bootstrap version: the floor -# this code needs, verified by every job below. +# Pin: 0.836.0, the latest release. The accessors that hand back a +# pointer into their argument declare it `@into` (aether#2990), which +# 0.836.0 checks; the lane moves (aether#2550), bit casts and reductions +# (#2603) and `@target("avx2") import` (#2607) are 0.835.0's. A +# reproducible bootstrap version: the floor this code needs, verified by +# every job below. env: - AE_PIN: 0.835.0 + AE_PIN: 0.836.0 AEB_REF: v0.328 jobs: diff --git a/README.md b/README.md index c4bdf11..cf6a7d5 100644 --- a/README.md +++ b/README.md @@ -84,15 +84,15 @@ Install the released toolchain with the shared, version-pinned installer ```sh curl -fsSL https://raw.githubusercontent.com/aether-lang-dev/aeb/main/get.sh \ - | AE_PIN=0.835.0 AEB_REF=v0.328 sh + | AE_PIN=0.836.0 AEB_REF=v0.328 sh export PATH="$HOME/.local/bin:$PATH" ``` -This installs `ae` 0.835.0, the release CI pins, and `aeb` v0.328 under +This installs `ae` 0.836.0, the release CI pins, and `aeb` v0.328 under `~/.local` (`PREFIX` overrides it), using release binaries where available. -CI verifies only the pinned release; older ones are not tested (the lane -moves and `@target("avx2")` imports this code is written with arrived in -0.835.0). +CI verifies only the pinned release; older ones are not tested (the +`@into` parameters this code declares arrived in 0.836.0, the lane moves +and `@target("avx2")` imports in 0.835.0). ``` scripts/test.sh # builds and runs every tests/test_*.ae with ae; what CI runs diff --git a/aephysics/contact_solver/module.ae b/aephysics/contact_solver/module.ae index e1d890f..14603fc 100644 --- a/aephysics/contact_solver/module.ae +++ b/aephysics/contact_solver/module.ae @@ -131,14 +131,14 @@ struct ContactConstraint { manifold_count: int } -contact_constraint_at(base: ptr, index: int) -> *ContactConstraint { return (base + index * sizeof(ContactConstraint)) as *ContactConstraint } -manifold_constraint_at(base: ptr, index: int) -> *ManifoldConstraint { return (base + index * sizeof(ManifoldConstraint)) as *ManifoldConstraint } +contact_constraint_at(base: @into ptr, index: int) -> *ContactConstraint { return (base + index * sizeof(ContactConstraint)) as *ContactConstraint } +manifold_constraint_at(base: @into ptr, index: int) -> *ManifoldConstraint { return (base + index * sizeof(ManifoldConstraint)) as *ManifoldConstraint } constraint_point_at(m: *ManifoldConstraint, index: int) -> *ManifoldConstraintPoint { return ((m as ptr) + index * sizeof(ManifoldConstraintPoint)) as *ManifoldConstraintPoint } -state_at(base: ptr, index: int) -> *BodyState { return (base + index * sizeof(BodyState)) as *BodyState } -sim_at(base: ptr, index: int) -> *BodySim { return (base + index * sizeof(BodySim)) as *BodySim } +state_at(base: @into ptr, index: int) -> *BodyState { return (base + index * sizeof(BodyState)) as *BodyState } +sim_at(base: @into ptr, index: int) -> *BodySim { return (base + index * sizeof(BodySim)) as *BodySim } var g_dummy: ptr = null // BodyState: a static body's, identity, never written diff --git a/aephysics/contact_solver_wide/module.ae b/aephysics/contact_solver_wide/module.ae index 11bd9bb..f2dd3fb 100644 --- a/aephysics/contact_solver_wide/module.ae +++ b/aephysics/contact_solver_wide/module.ae @@ -226,7 +226,7 @@ struct WideConstraint { point3: WideConstraintPoint } -wide_constraint_at(base: ptr, index: int) -> *WideConstraint { return (base + index * sizeof(WideConstraint)) as *WideConstraint } +wide_constraint_at(base: @into ptr, index: int) -> *WideConstraint { return (base + index * sizeof(WideConstraint)) as *WideConstraint } wide_point_at(c: *WideConstraint, index: int) -> *WideConstraintPoint { return ((&c.point0) as ptr + index * sizeof(WideConstraintPoint)) as *WideConstraintPoint } @@ -261,7 +261,7 @@ struct BodyStateW { dq: QuatW } -state_or_identity(states: ptr, index1: int) -> *BodyState { +state_or_identity(states: @into ptr, index1: int) -> *BodyState { if index1 == 0 { return contact_solver.dummy_state() } return (states + (index1 - 1) * sizeof(BodyState)) as *BodyState } diff --git a/aephysics/dynamics/module.ae b/aephysics/dynamics/module.ae index 8a3ced6..365faf2 100644 --- a/aephysics/dynamics/module.ae +++ b/aephysics/dynamics/module.ae @@ -1908,7 +1908,7 @@ sleep_body_sim_index(encoded: int) -> int { // A contact's body sim from its encoding, through the body when the body // is neither awake nor static (b3ResolveContactBodySim). -resolve_contact_body_sim(w: *World, awake_sims: ptr, static_sims: ptr, encoded: int, body_id: int) -> *BodySim { +resolve_contact_body_sim(w: *World, awake_sims: @into ptr, static_sims: @into ptr, encoded: int, body_id: int) -> *BodySim { if encoded >= 0 { return (awake_sims + encoded * sizeof(BodySim)) as *BodySim } if encoded < NULL_INDEX { return (static_sims + (0 - encoded - 2) * sizeof(BodySim)) as *BodySim } return get_body_sim(w, body_at(w, body_id)) diff --git a/aephysics/human/module.ae b/aephysics/human/module.ae index dabd495..7a483cd 100644 --- a/aephysics/human/module.ae +++ b/aephysics/human/module.ae @@ -175,7 +175,7 @@ struct BoneSpec { // allocator: the reference's from human_reference_shape, a rig's once // human_fit_shape has fitted it, and create_human_shaped builds either. // The caller frees it with destroy_shape. -spec_at(shape: ptr, index: int) -> *BoneSpec { return (shape + index * sizeof(BoneSpec)) as *BoneSpec } +spec_at(shape: @into ptr, index: int) -> *BoneSpec { return (shape + index * sizeof(BoneSpec)) as *BoneSpec } set_spec(shape: ptr, index: int, spec: BoneSpec) { (shape as BoneSpec[])[index] = spec } no_foot() -> Capsule { return manifold.capsule(math.vec3(0.0, 0.0, 0.0), math.vec3(0.0, 0.0, 0.0), 0.0) } diff --git a/aephysics/native/module.ae b/aephysics/native/module.ae index 1a3abb5..f08d3a7 100644 --- a/aephysics/native/module.ae +++ b/aephysics/native/module.ae @@ -120,4 +120,4 @@ semaphore_signal(s: ptr, count: int) { aephysics_semaphore_signal(s, count) } // MAX_WORKERS blocks of `bytes`: what the reference keeps on the stack // of each thread, kept here as one block per worker since Aether has // neither stack arrays nor thread-local variables. -scratch(blocks: ptr, bytes: int) -> ptr { return blocks + aephysics_worker_index() * bytes } +scratch(blocks: @into ptr, bytes: int) -> ptr { return blocks + aephysics_worker_index() * bytes } diff --git a/aephysics/recording/module.ae b/aephysics/recording/module.ae index a6a553e..e404992 100644 --- a/aephysics/recording/module.ae +++ b/aephysics/recording/module.ae @@ -703,7 +703,6 @@ player_step_frame(p: *Player) -> bool { stepped = true } } - return stepped } // The next frame played in two calls when it makes a body diff --git a/aephysics/solver/module.ae b/aephysics/solver/module.ae index abc88d2..a0f885a 100644 --- a/aephysics/solver/module.ae +++ b/aephysics/solver/module.ae @@ -130,8 +130,8 @@ set_wide_contacts(enabled: bool) { g_wide_contacts = enabled } wide_contacts_enabled() -> bool { return g_wide_contacts } const MAX_CONTINUOUS_SENSOR_HITS = 8 -state_at(base: ptr, index: int) -> *BodyState { return (base + index * sizeof(BodyState)) as *BodyState } -sim_at(base: ptr, index: int) -> *BodySim { return (base + index * sizeof(BodySim)) as *BodySim } +state_at(base: @into ptr, index: int) -> *BodyState { return (base + index * sizeof(BodyState)) as *BodyState } +sim_at(base: @into ptr, index: int) -> *BodySim { return (base + index * sizeof(BodySim)) as *BodySim } // --- the body stages ------------------------------------------------------------------------------------------- @@ -816,9 +816,9 @@ block_dim(item_count: int, min_size: int, max_block_count: int) -> BlockDim { return BlockDim { size: size, count: (item_count + size - 1) / size } } -block_at(blocks: ptr, index: int) -> *SolverBlock { return (blocks + index * sizeof(SolverBlock)) as *SolverBlock } -stage_at(stages: ptr, index: int) -> *SolverStage { return (stages + index * sizeof(SolverStage)) as *SolverStage } -color_blocks_at(base: ptr, index: int) -> *ColorBlocks { return (base + index * sizeof(ColorBlocks)) as *ColorBlocks } +block_at(blocks: @into ptr, index: int) -> *SolverBlock { return (blocks + index * sizeof(SolverBlock)) as *SolverBlock } +stage_at(stages: @into ptr, index: int) -> *SolverStage { return (stages + index * sizeof(SolverStage)) as *SolverStage } +color_blocks_at(base: @into ptr, index: int) -> *ColorBlocks { return (base + index * sizeof(ColorBlocks)) as *ColorBlocks } // The blocks of one item range, the last one short; claims at zero so // the first stage over them swaps 0 for 1.