Repository navigation
Conversation
limitlessprojects#1399) TypeShape::Atomic was sendable-by-type (model.rs) and const-copyable (shape_is_const_sendable), so every by-value copy of a scalar sync/atomic value passed `hyb check --deny-managed` with 0 diagnostics: decl copies (`other := hits`), whole-value assignments (`hits = z`), compound read-modify-writes (`hits += 1` / `hits++`), by-value task/spawn/send operands, and `move` of a container holding one. The Go types embed sync/atomic.noCopy, so `go vet` (copylocks) rejects every copy, and a copy racing a `&hits` task is a real data race (go run -race, exit 66). The rule is one-directional: an atomic VALUE never copies by value; the pointer route (`&hits`, OQ6) and atomic methods stay legal. - model.rs::is_sendable_by_type: Atomic removed from the by-type class; Pointer(Atomic) kept (OQ6). - sendability.rs: Atomic removed from shape_is_const_sendable; new explicit Atomic reject arm in classify_move_ident; Atomic joins the unmovable leaves in shape_holds_unmovable_leaf (holder structs). - emit_guard.rs: new HYB-E2011 statement-level guard on decl-copy and assign values, plus compound/inc-dec targets; registered in diagnostics.json (category ownership-sendability, rule O4, A1c). Pinned by hy-check/tests/atomic_value_copy.rs (9 tests: 3 statement forms, 3 boundary forms, 3 legal-route controls) and the corpus fixture atomic-value-copy-reject (REJECT A1c, first diagnostic HYB-E2011); census 126 -> 127 (ACCEPT 38 / AM 2 / REJECT 87). Verified: harness 127/127, differential accept 40/40 + reject 87/87, negative flip 126/127 restored, cargo test hy-check / hy-syntax green, corpus limitlessprojects#17 (the `&hits` positive control) unchanged.
|
Intake triage — queued for deep verification, not landed this round. The fix direction is correct: atomic values ARE copy-locked in Go (sync/atomic wrappers are noCopy-adjacent and by-value copies are vet-flagged), and moving them from "sendable by value" to "reference-only" in the O4.6 deep-sendability table is the right call per #1399. What holds the landing here is scale + shared surfaces: 14 files including Verification plan (next round): (1) repro #1399's by-value atomic copy on current main, (2) your probe matrix on the PR tree, (3) over-reach controls — Nothing blocking from a design standpoint — this is process honesty about the surface size, not a quality concern. Thanks @Ljunqiang. |
…nd comparisons (fixes limitlessprojects#922) Root cause: check_binary_operands compared numeric FAMILIES, not concrete kinds — for `< <= > >=` and `+` the mismatch term was `lk.is_numeric() != rk.is_numeric()` (int and float64 are both numeric, so never mismatched), and `- * /` only checked kind membership. `x + f`, `x - f`, `x * f`, `x / f`, `x < f`, `f <= x` checked clean while go build refused each with `mismatched types int and float64` (GUARANTEES Row 13). Fix: a new Collector::numeric_adapt_conflict routes cross-kind operand pairs through Go's only implicit numeric conversion — untyped-constant adaptation — and emits HYB-E1002 when it cannot bridge them: - `1 + 2.5` (both untyped) and `f + 1` / `1 + f` (int const -> float64) keep building, including untyped `const` identifiers (`f + k`); - `x + f`, `f + x`, `x - f`, `x < f`, `f <= x`, and the untyped float const against a typed int (`x + 2.5`) are rejected; - `Define.untyped_const` (from LocalDecl.ty) distinguishes `const k = 1` (untyped) from `const k int = 1` (typed like a variable) for fn-local consts — the annotation was recorded but never consulted. Validation: new hy-check/tests/binop_operand_types_issue_922.rs 24/24 (15 reject faces + 9 accept controls); corpus pin binop-mismatched-numeric-reject.hy (REJECT BUILDABLE + HYB-E1002), census 126 -> 127 on all 7 surfaces; harness 127/127, tripwire not fired; negative flip: baseline upstream accepts the pin (126/127, pin FAILs) and restores to 127/127; differential 40/40 accept + 87/87 reject; cargo test --workspace green except the pre-existing local-CRLF spec_t3_strings failure (reproduces on clean HEAD). Harvest credit: stale companion rickymulya PR limitlessprojects#923 (bot:stale-base + bot:conflict) proposed the same family of rules with literal-only helpers; this take supersedes it with const-ident support and the untyped_const annotation check. Coordination: limitlessprojects#1428, limitlessprojects#1430 and limitlessprojects#1447 also bump census 126 -> 127 — the PR that lands last rebases the count to 128+. The numeric_adapt_conflict doc carries a dedupe NOTE against limitlessprojects#1447's is_untyped_constant (the kinds_conflict / PR limitlessprojects#620 duplicate-helper precedent) for whoever lands second.
|
Queue-reset sweep: this repo now runs a rolling conveyor, and open PRs This is not a verdict on the work. If this change still matters:
Wildcard holds (verdict window 2026-11-01) and Pareto land candidates are |
…nd comparisons (fixes limitlessprojects#922) Root cause: check_binary_operands compared numeric FAMILIES, not concrete kinds — for `< <= > >=` and `+` the mismatch term was `lk.is_numeric() != rk.is_numeric()` (int and float64 are both numeric, so never mismatched), and `- * /` only checked kind membership. `x + f`, `x - f`, `x * f`, `x / f`, `x < f`, `f <= x` checked clean while go build refused each with `mismatched types int and float64` (GUARANTEES Row 13). Fix: a new Collector::numeric_adapt_conflict routes cross-kind operand pairs through Go's only implicit numeric conversion — untyped-constant adaptation — and emits HYB-E1002 when it cannot bridge them: - `1 + 2.5` (both untyped) and `f + 1` / `1 + f` (int const -> float64) keep building, including untyped `const` identifiers (`f + k`); - `x + f`, `f + x`, `x - f`, `x < f`, `f <= x`, and the untyped float const against a typed int (`x + 2.5`) are rejected; - `Define.untyped_const` (from LocalDecl.ty) distinguishes `const k = 1` (untyped) from `const k int = 1` (typed like a variable) for fn-local consts — the annotation was recorded but never consulted. Validation: new hy-check/tests/binop_operand_types_issue_922.rs 24/24 (15 reject faces + 9 accept controls); corpus pin binop-mismatched-numeric-reject.hy (REJECT BUILDABLE + HYB-E1002), census 126 -> 127 on all 7 surfaces; harness 127/127, tripwire not fired; negative flip: baseline upstream accepts the pin (126/127, pin FAILs) and restores to 127/127; differential 40/40 accept + 87/87 reject; cargo test --workspace green except the pre-existing local-CRLF spec_t3_strings failure (reproduces on clean HEAD). Harvest credit: stale companion rickymulya PR limitlessprojects#923 (bot:stale-base + bot:conflict) proposed the same family of rules with literal-only helpers; this take supersedes it with const-ident support and the untyped_const annotation check. Coordination: limitlessprojects#1428, limitlessprojects#1430 and limitlessprojects#1447 also bump census 126 -> 127 — the PR that lands last rebases the count to 128+. The numeric_adapt_conflict doc carries a dedupe NOTE against limitlessprojects#1447's is_untyped_constant (the kinds_conflict / PR limitlessprojects#620 duplicate-helper precedent) for whoever lands second.
Fixes #1399.
Bug
TypeShape::Atomic(atomic.bool,atomic.int32,atomic.int64,atomic.uint32,atomic.uint64,atomic.uintptr) was sendable-by-type (model.rs::is_sendable_by_type) and const-copyable (shape_is_const_sendable), so every by-value copy passedhyb check --deny-managedwith 0 diagnostics:other := hits), whole-value assignments (hits = z), compound RMWs (hits += 1/hits++) — statement level;ch <- hits, andmoveof a container holding one — boundary level.On the Go side these types embed
sync/atomic.noCopy:go vet(copylocks) rejects every one of them, and a copy taken while another task mutates through&hitsis an unsynchronized data race (go run -race, exit 66 — both races in the issue).Fix (one-directional: VALUES never copy; the pointer route stays)
model.rs::is_sendable_by_type:Atomicremoved from the by-type class;Pointer(Atomic)kept (the OQ6 mediated route —task worker(&hits, ...)still accepts, corpus fix(hy-check):new(T)returns a pointer*T, not a primitive — fixes #16 #17 unchanged).sendability.rs:Atomicremoved fromshape_is_const_sendable; new explicitAtomicreject arm inclassify_move_ident(baremove);Atomicjoins the unmovable leaves inshape_holds_unmovable_leaf(somoveof a holder struct rejects too).emit_guard.rs: new statement-level guardcheck_atomic_value_copyon decl-copy/assign values and compound/inc-dec targets — emits the new HYB-E2011 (registered indiagnostics.json: categoryownership-sendability, rule O4, tier0 A1c).ch <- hits→ HYB-E3002,move→ HYB-E3001.Legal routes pinned as controls:
&hitsspawn,hits.add(1)/hits.load(), pointer copies (q := pon*atomic.int64).Regression pins
hy-check/tests/atomic_value_copy.rs: 9 tests (3 statement forms, 3 boundary forms, 3 legal-route controls).tests/checker-corpus/atomic-value-copy-reject.hy(REJECT A1c, first diagnosticHYB-E2011); census 126 → 127 (ACCEPT 38 · AM 2 · REJECT 87); VERDICTS.md + README registration appended.Verification
cargo test -p hy-check/-p hy-syntax: green (incl. the 9 new tests,parse_allasserts 127).tools/corpus_harness.py: 127/127, tripwire not fired (corpus fix(hy-check):new(T)returns a pointer*T, not a primitive — fixes #16 #17&hitspositive control still ACCEPT).tools/differential_loop.py: accept-side 40/40 (build+run), reject-side 87/87.repro_atomic_val_race.hy→ HYB-E3001; local-copy repro → HYB-E2011 ×2 + HYB-E3002; holdermoverepro → HYB-E3001.Note: sibling PR #1428 (issue #1398, slot-loan flush) also moves the census numbers (126 → 127 with an ACCEPT pin). Whichever lands second rebases and renumbers to 128.