Skip to content

Autofix failure for clippy map_unwrap_or lint #16901

@lmmx

Description

@lmmx

Summary

Hi Clippy team 📎 I got this message:

warning: failed to automatically apply fixes suggested by rustc to crate nave_pen

This likely indicates a bug in either rustc or cargo itself,
and we would appreciate a bug report! You're likely to see
a number of compiler warnings after this message which cargo
attempted to fix but failed. If you could open an issue at
https://github.com/rust-lang/rust-clippy/issues
quoting the full output of this command we'd be very appreciative!
Note that you may be able to make some more progress in the near-term
fixing code with the --broken-code flag

I think it means that the fix produced code that won't check (previously it did check and build ok)

The full error:

    Checking nave_pen v0.0.4 (/home/louis/dev/nave/crates/nave_pen)
warning: failed to automatically apply fixes suggested by rustc to crate `nave_pen`

after fixes were automatically applied the compiler reported errors within these files:

  * crates/nave_pen/src/create.rs

This likely indicates a bug in either rustc or cargo itself,
and we would appreciate a bug report! You're likely to see
a number of compiler warnings after this message which cargo
attempted to fix but failed. If you could open an issue at
https://github.com/rust-lang/rust-clippy/issues
quoting the full output of this command we'd be very appreciative!
Note that you may be able to make some more progress in the near-term
fixing code with the `--broken-code` flag

The following errors were reported:
error[E0308]: mismatched types
  --> crates/nave_pen/src/create.rs:94:65
   |
94 |     let after_scope = raw.split_once(':').map_or(&raw, |(_, v)| v);
   |                                                                 ^ expected `&String`, found `&str`
   |
   = note: expected reference `&std::string::String`
              found reference `&str`

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0308`.
Original diagnostics will follow.

warning: called `map(<f>).unwrap_or(<a>)` on an `Option` value
  --> crates/nave_pen/src/create.rs:94:23
   |
94 |     let after_scope = raw.split_once(':').map(|(_, v)| v).unwrap_or(&raw);
   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.95.0/index.html#map_unwrap_or
   = note: `-W clippy::map-unwrap-or` implied by `-W clippy::pedantic`
   = help: to override `-W clippy::pedantic` add `#[allow(clippy::map_unwrap_or)]`
help: use `map_or(<a>, <f>)` instead
   |
94 -     let after_scope = raw.split_once(':').map(|(_, v)| v).unwrap_or(&raw);
94 +     let after_scope = raw.split_once(':').map_or(&raw, |(_, v)| v);
   |

warning: `nave_pen` (lib) generated 1 warning (run `cargo clippy --fix --lib -p nave_pen -- --no-deps` to apply 1 suggestion)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.28s

The commit that caused it was e368c0c9a44bca64cfb65110802a00bef8963983 and I put it in a PR here which should make it accessible at lmmx/nave@e368c0c

The full content of the file that caused it:

//! Materialise a pen: run the filter, clone matching repos, write pen.toml.

use std::path::Path;

use anyhow::{Context, Result, anyhow, bail};
use time::OffsetDateTime;
use tokio::process::Command;
use tracing::{debug, info};

use nave_config::cache::read_repo_meta;
use nave_config::{NaveConfig, Term, cache_root};
use nave_search::{SearchOptions, run_search};

use crate::storage::{
    Pen, PenFilter, PenRepo, pen_dir, pen_repo_clone_dir, resolve_pen_root, write_pen,
};

pub struct CreateOptions {
    pub name: Option<String>,
    pub terms: Vec<String>,
    pub ignore_case: bool,
}

pub async fn create_pen(cfg: &NaveConfig, opts: CreateOptions) -> Result<Pen> {
    if opts.terms.is_empty() {
        bail!("pen create requires at least one filter term");
    }
    let root = resolve_pen_root(&cfg.pen)?;
    std::fs::create_dir_all(&root)?;

    let cache = cache_root()?;
    let parsed_terms: Vec<Term> = opts
        .terms
        .iter()
        .map(|s| Term::parse(s).with_context(|| format!("parsing term {s:?}")))
        .collect::<Result<_>>()?;

    let search_opts = SearchOptions {
        terms: parsed_terms,
        ignore_case: opts.ignore_case,
        enrich_holes: false,
    };
    let report = run_search(&cache, cfg, &search_opts)?;

    if report.repos.is_empty() {
        bail!("filter matched no repos");
    }

    let name = opts
        .name
        .clone()
        .unwrap_or_else(|| derive_name(&opts.terms));
    let name = ensure_name_unique(&root, &name)?;
    let branch = name.clone();

    info!(pen = %name, count = report.repos.len(), "creating pen");

    let mut pen_repos = Vec::with_capacity(report.repos.len());
    for repo_match in &report.repos {
        let owner = &repo_match.owner;
        let name_r = &repo_match.repo;
        let meta = read_repo_meta(&cache, owner, name_r)?
            .ok_or_else(|| anyhow!("no cached meta for {owner}/{name_r}; run `nave scan` first"))?;

        let dest = pen_repo_clone_dir(&root, &name, owner, name_r);
        if dest.exists() {
            debug!(path = %dest.display(), "clone dir exists, skipping");
        } else {
            clone_and_branch(&meta.clone_url, &meta.default_branch, &branch, &dest).await?;
        }

        pen_repos.push(PenRepo {
            owner: owner.clone(),
            name: name_r.clone(),
            default_branch: meta.default_branch.clone(),
            clone_url: meta.clone_url.clone(),
        });
    }

    let pen = Pen {
        name: name.clone(),
        created_at: OffsetDateTime::now_utc(),
        branch,
        filter: PenFilter { terms: opts.terms },
        repos: pen_repos,
    };
    write_pen(&root, &pen)?;
    Ok(pen)
}

fn derive_name(terms: &[String]) -> String {
    let raw = terms.first().cloned().unwrap_or_else(|| "pen".to_string());
    // Strip any scope prefix (e.g. "workflow:maturin" -> "maturin").
    let after_scope = raw.split_once(':').map(|(_, v)| v).unwrap_or(&raw);
    let slug = slugify(after_scope);
    let truncated: String = slug.chars().take(20).collect();
    format!("nave/{truncated}")
}

fn slugify(s: &str) -> String {
    let mut out = String::with_capacity(s.len());
    let mut prev_hyphen = false;
    for ch in s.chars() {
        if ch.is_ascii_alphanumeric() {
            out.push(ch.to_ascii_lowercase());
            prev_hyphen = false;
        } else if !prev_hyphen && !out.is_empty() {
            out.push('-');
            prev_hyphen = true;
        }
    }
    while out.ends_with('-') {
        out.pop();
    }
    if out.is_empty() {
        "pen".to_string()
    } else {
        out
    }
}

fn ensure_name_unique(root: &Path, name: &str) -> Result<String> {
    if !pen_dir(root, name).exists() {
        return Ok(name.to_string());
    }
    for n in 2..1000 {
        let candidate = format!("{name}-{n}");
        if !pen_dir(root, &candidate).exists() {
            return Ok(candidate);
        }
    }
    bail!("could not find a unique name for pen {name}")
}

async fn clone_and_branch(
    clone_url: &str,
    default_branch: &str,
    pen_branch: &str,
    dest: &Path,
) -> Result<()> {
    if let Some(parent) = dest.parent() {
        std::fs::create_dir_all(parent)?;
    }
    // Full (non-sparse) but depth=1 shallow clone.
    let out = Command::new("git")
        .args(["clone", "--depth=1"])
        .arg(clone_url)
        .arg(dest)
        .output()
        .await?;
    if !out.status.success() {
        bail!(
            "git clone failed: {}",
            String::from_utf8_lossy(&out.stderr).trim()
        );
    }
    let out = Command::new("git")
        .arg("-C")
        .arg(dest)
        .args(["checkout", "-b", pen_branch, default_branch])
        .output()
        .await?;
    if !out.status.success() {
        // Branch already exists — just check it out.
        let out2 = Command::new("git")
            .arg("-C")
            .arg(dest)
            .args(["checkout", pen_branch])
            .output()
            .await?;
        if !out2.status.success() {
            bail!(
                "git checkout {pen_branch} failed: {}",
                String::from_utf8_lossy(&out2.stderr).trim()
            );
        }
    }
    Ok(())
}

Version

rustc 1.95.0 (59807616e 2026-04-14)
binary: rustc
commit-hash: 59807616e1fa2540724bfbac14d7976d7e4a3860
commit-date: 2026-04-14
host: x86_64-unknown-linux-gnu
release: 1.95.0
LLVM version: 22.1.2

Error output

Backtrace

RUST_BACKTRACE=1 cargo clippy --fix -p nave_pen --allow-dirty
  Checking nave_pen v0.0.4 (/home/louis/dev/nave/crates/nave_pen)
warning: failed to automatically apply fixes suggested by rustc to crate `nave_pen`

after fixes were automatically applied the compiler reported errors within these files:

* crates/nave_pen/src/create.rs

This likely indicates a bug in either rustc or cargo itself,
and we would appreciate a bug report! You're likely to see
a number of compiler warnings after this message which cargo
attempted to fix but failed. If you could open an issue at
https://github.com/rust-lang/rust-clippy/issues
quoting the full output of this command we'd be very appreciative!
Note that you may be able to make some more progress in the near-term
fixing code with the `--broken-code` flag

The following errors were reported:
error[E0308]: mismatched types
--> crates/nave_pen/src/create.rs:94:65
 |
94 |     let after_scope = raw.split_once(':').map_or(&raw, |(_, v)| v);
 |                                                                 ^ expected `&String`, found `&str`
 |
 = note: expected reference `&std::string::String`
            found reference `&str`

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0308`.
Original diagnostics will follow.

warning: called `map(<f>).unwrap_or(<a>)` on an `Option` value
--> crates/nave_pen/src/create.rs:94:23
 |
94 |     let after_scope = raw.split_once(':').map(|(_, v)| v).unwrap_or(&raw);
 |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 |
 = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.95.0/index.html#map_unwrap_or
 = note: `-W clippy::map-unwrap-or` implied by `-W clippy::pedantic`
 = help: to override `-W clippy::pedantic` add `#[allow(clippy::map_unwrap_or)]`
help: use `map_or(<a>, <f>)` instead
 |
94 -     let after_scope = raw.split_once(':').map(|(_, v)| v).unwrap_or(&raw);
94 +     let after_scope = raw.split_once(':').map_or(&raw, |(_, v)| v);
 |

warning: `nave_pen` (lib) generated 1 warning (run `cargo clippy --fix --lib -p nave_pen -- --no-deps` to apply 1 suggestion)
  Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.29s

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: Clippy is not doing the correct thingI-ICEIssue: Clippy panicked, giving an Internal Compilation Error (ICE) ❄️

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions