Type inference of generic parameters
⚓ Rust 📅 2026-04-16 👤 surdeus 👁️ 3I'm currently working on a simple implementation of grep to get to know the language. However, when introducing some generics, the compiler throws an error about it not being able to infer the type of a generic parameter. Here's a minimum working example without any of the real functionality:
use ignore::WalkBuilder;
use std::path::{Path, PathBuf};
use std::io;
use std::fs::File;
use clap::Parser;
mod parser {
use super::*;
#[derive(Parser)]
#[command(name = "grep", version, about, long_about = None)]
pub struct Grep {
/// Path/paths to search for expression
pub path: PathBuf,
/// Search recursively in current directory
#[arg(short, long, default_value_t = false)]
pub recursive: bool,
}
}
fn main() -> io::Result<()> {
let args = parser::Grep::parse();
find_matches(args.recursive, &args.path, &args, find_match_in_file)?;
Ok(())
}
fn find_matches<F, P, S>(recursive: bool, path: P, args: &parser::Grep, cb: F) -> io::Result<()>
where P: AsRef<Path>,
F: Fn(S, &parser::Grep) -> io::Result<()>,
S: AsRef<Path>,
{
let walker = if recursive {
WalkBuilder::new(path).max_depth(None).build()
} else {
WalkBuilder::new(path).max_depth(Some(1)).build()
};
for entry in walker {
let entry = match entry {
Ok(entry) => entry,
Err(_error) => {
eprintln!("Skipping path");
continue;
}
};
let p = entry.path();
if p.is_file() {
println!("Scanning file: {}", p.to_str().unwrap_or("Unknown file"));
match cb(p, args) {
Ok(()) => { /* Do nothing */ },
Err(error) => eprintln!("Couldn't search file: {:?}", error),
}
}
}
Ok(())
}
fn find_match_in_file<S>(path: S, _args: &parser::Grep) -> io::Result<()>
where S: AsRef<Path>,
{
let _file = File::open(path)?;
Ok(())
}
I get the following error when compiling:
error[E0283]: type annotations needed
--> src/bin/test-clap.rs:24:53
|
24 | find_matches(args.recursive, &args.path, &args, find_match_in_file)?;
| ^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `S` declared on the function `find_match_in_file`
|
= note: multiple `impl`s satisfying `_: AsRef<Path>` found in the following crates: `clap_builder`, `std`:
- impl AsRef<Path> for OsString;
- impl AsRef<Path> for Path;
- impl AsRef<Path> for Str;
- impl AsRef<Path> for clap::builder::OsStr;
- impl AsRef<Path> for std::ffi::OsStr;
- impl AsRef<Path> for std::path::PathBuf;
- impl AsRef<Path> for std::string::String;
- impl AsRef<Path> for str;
note: required by a bound in `find_matches`
--> src/bin/test-clap.rs:31:10
|
28 | fn find_matches<F, P, S>(recursive: bool, path: P, args: &parser::Grep, cb: F) -> io::Result<()>
| ------------ required by a bound in this function
...
31 | S: AsRef<Path>,
| ^^^^^^^^^^^ required by this bound in `find_matches`
help: consider specifying the generic argument
|
24 | find_matches(args.recursive, &args.path, &args, find_match_in_file::<S>)?;
| +++++ +++++
According to the docs for the ignore crate, and it's structs, iterating over ignore::Walk should yield ignore::DirEntry, and calling .path() on those should return &Path. So why can't rust infer that the type parameter S is &Path?
3 posts - 2 participants
🏷️ Rust_feed