Pin toolchain to 1.95.0 + mechanical clippy/rustc fixes

CI was red on every recent main commit (pre-existing, not from the
V0.2/audit work): the workflow installs rolling `stable`, which on
the runners is ~1 year newer than the local toolchain that validated
the code. Under `RUSTFLAGS: -D warnings` + `clippy -- -D warnings`,
new rustc/clippy lints across pre-existing code became hard failures.
Confirmed identical on the 4 commits before v1.0-rc (e.g. the
`rope.rs:1076` unused_parens compile error is byte-identical there).

Resolution:

- `rust-toolchain.toml` pins channel 1.95.0 (the validated version).
  The repo directory override makes every cargo invocation use it
  regardless of what the CI action installs, eliminating the
  local/CI toolchain-drift class permanently. Bump deliberately.
- Mechanical lint fixes (~17 sites, all the trivial/auto-fixable
  class — no logic change): `cargo clippy --fix` + `cargo fix`
  applied the machine-applicable set; hand-fixed the residuals:
  daemon.rs (duplicated #[allow]), completion_framework.rs
  (sort_by -> sort_by_key/Reverse), attach.rs (map().unwrap_or ->
  map_or, crdt), buffer.rs (is_some+expect -> match, crdt),
  m10_11_acceptance.rs (if -> match guard x2, crdt).
- `cargo fmt --all` (clippy --fix left overlay_paint.rs unformatted).

Verified clean under 1.95.0, all lanes: fmt 0 diffs; clippy
--all-targets -D warnings clean for luajit, lua54, AND crdt;
-D warnings build clean luajit+lua54; doc tests pass; lib 1223/0;
autofix-modified tests (m7_5, m8_1 incl. the Finding-2 fs_watch fix)
pass.

Scope: this clears CI red class #1 (toolchain-gap lints) only.
Independent and still triage-pending: #2 macOS F9 nix
PeerCredentials portability (Test (macos-*)), #3 M1/M4/M6 perf/fuzz
gates. Per plan, those are triaged after CI confirms #1 green.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Levi Neuwirth 2026-05-18 11:38:57 -04:00
parent c50db222d3
commit 7171282b57
14 changed files with 51 additions and 50 deletions

10
rust-toolchain.toml Normal file
View File

@ -0,0 +1,10 @@
[toolchain]
# Pinned so local == CI permanently. The CI workflow installs the
# `stable` channel via dtolnay/rust-toolchain; this directory override
# makes every cargo invocation in the repo use the validated version
# regardless, eliminating the local/CI toolchain-drift class that
# silently red-lined CI under newer rolling-stable lints. Bump
# deliberately (its own validated cycle), never implicitly.
channel = "1.95.0"
components = ["clippy", "rustfmt"]
profile = "minimal"

View File

@ -803,8 +803,7 @@ pub(crate) fn run_attach_pair(
if matches!(k.kind, KeyEventKind::Press | KeyEventKind::Repeat) { if matches!(k.kind, KeyEventKind::Press | KeyEventKind::Repeat) {
let timestamp_ns = std::time::SystemTime::now() let timestamp_ns = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH) .duration_since(std::time::UNIX_EPOCH)
.map(|d| u64::try_from(d.as_nanos()).unwrap_or(0)) .map_or(0, |d| u64::try_from(d.as_nanos()).unwrap_or(0));
.unwrap_or(0);
let pmacs_key = key_from_crossterm(k, assigned_id, timestamp_ns); let pmacs_key = key_from_crossterm(k, assigned_id, timestamp_ns);
// T M10.10 Day 3 step 5 Path β — determine // T M10.10 Day 3 step 5 Path β — determine
@ -985,8 +984,7 @@ fn forward_event<W: Write>(
let _ = KeyModifiers::empty(); // import touch: keeps lint happy if unused let _ = KeyModifiers::empty(); // import touch: keeps lint happy if unused
let timestamp_ns = std::time::SystemTime::now() let timestamp_ns = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH) .duration_since(std::time::UNIX_EPOCH)
.map(|d| u64::try_from(d.as_nanos()).unwrap_or(0)) .map_or(0, |d| u64::try_from(d.as_nanos()).unwrap_or(0));
.unwrap_or(0);
let pmacs_key = key_from_crossterm(k, assigned_id, timestamp_ns); let pmacs_key = key_from_crossterm(k, assigned_id, timestamp_ns);
write_message(writer, &FrontendEvent::Key(pmacs_key))?; write_message(writer, &FrontendEvent::Key(pmacs_key))?;
} }

View File

@ -322,11 +322,11 @@ mod tests {
let mut s = BackoffSchedule::new(); let mut s = BackoffSchedule::new();
let expected = [ let expected = [
Duration::from_millis(500), Duration::from_millis(500),
Duration::from_millis(1000), Duration::from_secs(1),
Duration::from_millis(2000), Duration::from_secs(2),
Duration::from_millis(4000), Duration::from_secs(4),
Duration::from_millis(8000), Duration::from_secs(8),
Duration::from_millis(16000), Duration::from_secs(16),
Duration::from_secs(30), Duration::from_secs(30),
]; ];
for (i, &want) in expected.iter().enumerate() { for (i, &want) in expected.iter().enumerate() {
@ -366,7 +366,7 @@ mod tests {
s.reset(); s.reset();
assert_eq!(s.next_delay(), Duration::from_millis(500)); assert_eq!(s.next_delay(), Duration::from_millis(500));
assert_eq!(s.next_delay(), Duration::from_millis(1000)); assert_eq!(s.next_delay(), Duration::from_secs(1));
} }
#[test] #[test]

View File

@ -1050,10 +1050,9 @@ impl Buffer {
let (lossy_owned, captured_crdt_op): ( let (lossy_owned, captured_crdt_op): (
Option<Vec<u8>>, Option<Vec<u8>>,
Option<Box<crate::rope::CrdtOp>>, Option<Box<crate::rope::CrdtOp>>,
) = if self.crdt.is_some() && !is_no_op_edit(current) { ) = match (&self.crdt, is_no_op_edit(current)) {
Self::apply_to_crdt_then_normalize_bytes(self.crdt.as_ref().expect("checked"), current)? (Some(crdt), false) => Self::apply_to_crdt_then_normalize_bytes(crdt, current)?,
} else { _ => (None, None),
(None, None)
}; };
// Stage 2: rope edit. In CRDT mode, the EditOp's byte payload // Stage 2: rope edit. In CRDT mode, the EditOp's byte payload

View File

@ -295,7 +295,7 @@ impl CompletionRegistry {
// the highest-priority hit. // the highest-priority hit.
let mut order: Vec<&RegisteredProvider> = let mut order: Vec<&RegisteredProvider> =
self.providers.iter().filter(|p| p.enabled).collect(); self.providers.iter().filter(|p| p.enabled).collect();
order.sort_by(|a, b| b.priority.cmp(&a.priority)); order.sort_by_key(|p| std::cmp::Reverse(p.priority));
let mut by_key: HashMap<(String, String), usize> = HashMap::new(); let mut by_key: HashMap<(String, String), usize> = HashMap::new();
let mut out: Vec<CompletionCandidate> = Vec::new(); let mut out: Vec<CompletionCandidate> = Vec::new();

View File

@ -798,7 +798,6 @@ fn per_attach_thread(
clippy::needless_pass_by_value, clippy::needless_pass_by_value,
clippy::too_many_lines clippy::too_many_lines
)] )]
#[allow(clippy::needless_pass_by_value)]
fn dispatcher_loop( fn dispatcher_loop(
dispatcher_rx: mpsc::Receiver<DispatcherEvent>, dispatcher_rx: mpsc::Receiver<DispatcherEvent>,
editor: &mut EditorState, editor: &mut EditorState,

View File

@ -939,7 +939,7 @@ mod tests {
let msg = format!("{err}"); let msg = format!("{err}");
assert!(msg.contains("/usr/local/bin/pmacs")); assert!(msg.contains("/usr/local/bin/pmacs"));
assert!(msg.contains("permission denied")); assert!(msg.contains("permission denied"));
assert!(msg.contains("PATH"), "should hint at PATH check: {msg}",); assert!(msg.contains("PATH"), "should hint at PATH check: {msg}");
} }
/// F8 reproduction (M10.11 acceptance criterion 1, SSH transport). /// F8 reproduction (M10.11 acceptance criterion 1, SSH transport).
@ -1017,7 +1017,7 @@ mod tests {
.set_read_timeout(Some(Duration::from_secs(3))) .set_read_timeout(Some(Duration::from_secs(3)))
.unwrap(); .unwrap();
match output_reader.read_exact(&mut received) { match output_reader.read_exact(&mut received) {
Ok(()) => assert_eq!(received, HELLO_FRAME, "Hello bytes corrupted in transit",), Ok(()) => assert_eq!(received, HELLO_FRAME, "Hello bytes corrupted in transit"),
Err(e) => panic!( Err(e) => panic!(
"F8 reproduced: Hello never reached local output ({e}) — \ "F8 reproduced: Hello never reached local output ({e}) — \
the bridge dropped the daemonclient direction on \ the bridge dropped the daemonclient direction on \

View File

@ -323,7 +323,7 @@ impl EditorCore {
#[must_use] #[must_use]
pub fn active_buffer_len(&self) -> u64 { pub fn active_buffer_len(&self) -> u64 {
let id = self.active_buffer_id(); let id = self.active_buffer_id();
self.registry.borrow().get(id).map(Buffer::len).unwrap_or(0) self.registry.borrow().get(id).map_or(0, Buffer::len)
} }
/// Active buffer's name. Returns an owned String to release the /// Active buffer's name. Returns an owned String to release the

View File

@ -169,8 +169,7 @@ fn temp_sibling(target: &Path) -> PathBuf {
// and `create_new` would error if hit. // and `create_new` would error if hit.
let nanos = SystemTime::now() let nanos = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH) .duration_since(SystemTime::UNIX_EPOCH)
.map(|d| d.subsec_nanos()) .map_or(0, |d| d.subsec_nanos());
.unwrap_or(0);
name.push(format!("{nanos:x}")); name.push(format!("{nanos:x}"));
parent.join(name) parent.join(name)
} }

View File

@ -249,21 +249,19 @@ fn paint_selection_in_window(
break; break;
}; };
match (disp.row as usize).checked_sub(window.view_top) { match (disp.row as usize).checked_sub(window.view_top) {
Some(r) if r < inner_rows as usize => { Some(r) if r < inner_rows as usize && disp.col < rect.size.cols => {
if disp.col < rect.size.cols { let grid_row = rect.origin.row + r as u32;
let grid_row = rect.origin.row + r as u32; let grid_col = rect.origin.col + disp.col;
let grid_col = rect.origin.col + disp.col; if grid_row < grid.size.rows && grid_col < grid.size.cols {
if grid_row < grid.size.rows && grid_col < grid.size.cols { let cell = grid.at(CellCoord::new(grid_row, grid_col));
let cell = grid.at(CellCoord::new(grid_row, grid_col)); cell.style.underline = UnderlineStyle::Single;
cell.style.underline = UnderlineStyle::Single; // Use the source's color for the underline; if
// Use the source's color for the underline; if // the cell already has a foreground style, the
// the cell already has a foreground style, the // underline color comes from the fg. We don't
// underline color comes from the fg. We don't // override fg to preserve the cell's existing
// override fg to preserve the cell's existing // glyph appearance.
// glyph appearance. if cell.style.fg == Color::Default {
if cell.style.fg == Color::Default { cell.style.fg = color;
cell.style.fg = color;
}
} }
} }
} }

View File

@ -1073,7 +1073,7 @@ mod tests {
let pos = (rng() as usize) % (len + 1); let pos = (rng() as usize) % (len + 1);
let n = (rng() % 64 + 1) as usize; let n = (rng() % 64 + 1) as usize;
let bytes: Vec<u8> = (0..n) let bytes: Vec<u8> = (0..n)
.map(|i| ((rng() as u8).wrapping_add(i as u8))) .map(|i| (rng() as u8).wrapping_add(i as u8))
.collect(); .collect();
rope = rope.insert(pos as u64, &bytes).unwrap().new_rope; rope = rope.insert(pos as u64, &bytes).unwrap().new_rope;
reference.splice(pos..pos, bytes); reference.splice(pos..pos, bytes);

View File

@ -252,17 +252,15 @@ impl Observer {
InstanceMessage::BufferSnapshot { InstanceMessage::BufferSnapshot {
buffer_id, buffer_id,
crdt_snapshot, crdt_snapshot,
} => { } if !self.replicas.contains_key(&buffer_id) => {
// Bootstrap each buffer's replica on first // Bootstrap each buffer's replica on first
// BufferSnapshot for that BufferId. Later snapshots // BufferSnapshot for that BufferId. Later snapshots
// for the same buffer are ignored — the established // for the same buffer are ignored — the established
// replica catches up via CrdtOps. // replica catches up via CrdtOps.
if !self.replicas.contains_key(&buffer_id) { let r = CrdtState::new(self.frontend_id.0).expect("observer CrdtState::new");
let r = CrdtState::new(self.frontend_id.0).expect("observer CrdtState::new"); r.import_snapshot(&crdt_snapshot)
r.import_snapshot(&crdt_snapshot) .expect("observer import_snapshot");
.expect("observer import_snapshot"); self.replicas.insert(buffer_id, r);
self.replicas.insert(buffer_id, r);
}
} }
InstanceMessage::CrdtOp { buffer_id, op } => { InstanceMessage::CrdtOp { buffer_id, op } => {
// If we received a CrdtOp for a buffer whose snapshot // If we received a CrdtOp for a buffer whose snapshot
@ -279,10 +277,10 @@ impl Observer {
} }
} }
} }
InstanceMessage::PresenceUpdate { frontend_id, .. } => { InstanceMessage::PresenceUpdate { frontend_id, .. }
if frontend_id != self.frontend_id { if frontend_id != self.frontend_id =>
self.other_frontends.insert(frontend_id); {
} self.other_frontends.insert(frontend_id);
} }
_ => {} _ => {}
} }

View File

@ -246,7 +246,7 @@ fn make_branched_package(name: &str) -> (TempDir, PathBuf, String) {
]); ]);
std::fs::write( std::fs::write(
work.join("init.lua"), work.join("init.lua"),
format!("return {{ name = '{name}', version = '1.0.0', flavor = 'feature' }}\n",), format!("return {{ name = '{name}', version = '1.0.0', flavor = 'feature' }}\n"),
) )
.expect("write init.lua feature"); .expect("write init.lua feature");
run_git(&[ run_git(&[

View File

@ -121,7 +121,7 @@ fn read_dir_returns_one_entry_per_child_with_lstat_metadata() {
if let Ok(err) = entries.get::<String>("error") { if let Ok(err) = entries.get::<String>("error") {
panic!("read_dir errored: {err}"); panic!("read_dir errored: {err}");
} }
let len: usize = entries.len().map(|n| n as usize).unwrap_or(0); let len: usize = entries.len().map_or(0, |n| n as usize);
assert_eq!(len, 3, "expected 3 entries, got {len}"); assert_eq!(len, 3, "expected 3 entries, got {len}");
// Names are filesystem-iteration-ordered; gather and sort. // Names are filesystem-iteration-ordered; gather and sort.