Issue #982: Defect triage 2026-10-29: fix in moved Nikaia, defer the rest to its move

Open and answer this issue on GitHub.

note · opened 2026-10-29 · updated 2026-10-29 · 0 comments

Owner’s direction (2026-10-29): a compiler defect is fixed now when its code has already moved to Nikaia completely (crates/nikaia-std/src/tools/*.nika, lowered). A defect whose fix lands in Rust that is still to move waits for that move, so the work is not done twice. Self-hosting goes on.

The probes were re-run with target/fast/nikaia at de0bb82 (0.0.1296), each fix site was found by grepping tools/*.nika against crates/nikaia/src, and the issues were sorted.

Counts

Class Meaning Count Issues
A the fix lands in moved Nikaia: fix now 35 the lanes below
B the fix lands in Rust still to move: waits 5 #935, #939, #587, #972, #690
C fixed already, or a duplicate: closed by hand 6 #713, #914, #916, #946, #976, #977
D a decision, not a defect: relabelled decision 1 #625

A: three lanes, separate by file

The order inside each lane puts self-hosting blockers first (docs/priorities.md): a workaround in tools/*.nika or in the converter that the fix lets us undo, then a false refusal a move meets, then a rustc error reaching users, then message text.

Lane T: text tiers and keeps (text_tiers.nika, keeps.nika, view_changes.nika)

  1. #958: tuple with a literal into Vec[(i64, String)] (the bounds_walk.nika ~2293 workaround, NK1106)
  2. #980: a nested list’s element is not linked to the mut parameter (source_of/place_of lack Expr::Index)
  3. #967: a list element’s text field changed in place (v[0].name += "!")
  4. #981: a change in place through a m[k] ?? jump view
  5. #882: the remaining String? half (classify keeps a String? read through ??/match)
  6. #971: NK2305 help names self, not the list

Lane E: lowering (emit_*.nika)

  1. #908: split_once(..) ?? ("", owned) (three converter workarounds)
  2. #915: a pushed mut String read through .trim() becomes a view (converter workaround rs2nika_text)
  3. #907: [..].contains(view) over literals (converter writes around it)
  4. #910: == between a view and an owned String
  5. #947: (xs.get(k) ?? return false) == "a" (&str vs str; same comparison code as #910)
  6. #911: text = f(text, k) with an EitherText result
  7. #925: != against an EitherText result (same root as #911)
  8. #913: ref Bytes? opened with .as_ref(), ?.clone() gives Vec<u8> (P3b wrote around it)
  9. #930: arm => if c { set.insert(v) } (E0317, met in check_core_method.nika)
  10. #970: (*x) for a for mut element (removes the unused_parens cover in nikaia-std/src/lib.rs)
  11. #937: f-string parts borrowed across a ref mut self call
  12. #938: for n in xs hands &i64 to an i64 parameter
  13. #940: a match over a match that reads its binding’s field
  14. #899: a mut argument read by another argument; mismatched_lifetime_syntaxes
  15. #918: the else after a complete match error lowered as _
  16. #896: the open steps only: the filter_map closure without Some (step 1 is fixed, the probe prints one 3). Its std gaps (BTreeSet::iter/clear, Seq::chain) go with #950 and #924
  17. #627: two view-struct programs that rustc refuses (from 0.0.969; re-probe first)

Lane C: checker (check_*.nika, ty.nika)

  1. #900: let mut c = a.clone() typed as a view (blocks the rs2nika_convert par_iter split)
  2. #898: x != null does not narrow a ref T? (converter R205)
  3. #936: n.starts_with(self.p) refused NK1131 outside main.nika. Trace first: the refusal is Nikaia’s, but if the per-file cause is the ledger that contracts/mod.rs builds, it moves to B (C1)
  4. #909: a lent loop element moved into a tuple literal (E0308)
  5. #927: a list element moved out by index (needs a new NK code from the supervisor)
  6. #917: an integer local takes its type from contains
  7. #931: [1, 2, 3] stays Vec[?] for sum/max
  8. #968: for mut x in grid[i] refused NK1139 (also touches emit_stmt.nika, so it runs after lane E has finished that file, or in agreement with it)
  9. #677: NK2203, step 1 only (a door opened directly inside a door: check_doors.nika has the refusal, but the walk never reaches it). The chain-of-calls half reads touches_a_lock from contracts/locks.rs and waits for the contracts move
  10. #591: a HashMap/HashSet key that cannot be hashed (beside NK1247 in check_collect.nika)
  11. #919: rustc’s dead-code warning in Rust’s words (needs an NK code)

Converter (the lane that already exists, not these three): #895, a const slice item that rs2nika --file drops (crates/rs2nika/convert/src/*.nika).

Collisions to watch: lane T’s #882 and lane C’s #936 can both touch keeps.nika. Every lane regenerates its own tools/lowered/*.rs files only.

B: waits for its move

Issue Where the fix lands Move
#935 emit/mod.rs:826 computes pausing_reach from one parsed file’s items, so a cycle that crosses files is missed (emit_reach.nika is ready for the package’s items) rest of emit/mod.rs: E11 / E13 (with_contracts’ analyses)
#939 parser/mod.rs grammar! (the guard rule) parser R rows, after #903 and #557
#587 parser/mod.rs grammar! (exponential backtracking, stack depth) parser R rows, after #903 and #557
#972 project.rs project_for_file / packages_of_file (which file check FILE reports) P5b
#690 project.rs drive_to decides when own_copy runs (2544-2547). With CARGO_TARGET_DIR set, the build at de0bb82 still leaves no target/nikaia/bin P5c

C: closed by hand

D

Not triaged here

Umbrellas #585 and #586 (per-item lists, older than the moves), #650 (prover, prover_*.nika, A if it is briefed), #741 (flaky runtime tests in nikaia-std/src/rt, not compiler code), #868 (a bench script).


Generated by Claude Code

Back to Open Issues