Bug: chained where T: trait multiple applicable items
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
use core::hash::BuildHasher;
use std::{collections::HashSet, hash::DefaultHasher};
/// no Default trait
struct DummyBuildHasher;
impl BuildHasher for DummyBuildHasher {
type Hasher = DefaultHasher;
fn build_hasher(&self) -> Self::Hasher {
unreachable!();
}
}
/// requires Default trait
trait RealHasher: Sized + BuildHasher + Default {}
impl<T: BuildHasher + Default> RealHasher for T {}
struct Builder<H: BuildHasher> {
languages: Option<HashSet<usize, H>>,
}
impl Builder<DummyBuildHasher> {
fn new() -> Self {
Self { languages: None }
}
// candidate 1
fn build(self) -> Builder<std::hash::RandomState> {
self.languages([].into_iter().collect())
}
}
impl<H: RealHasher> Builder<H> {
// candidate 2
fn build(self) -> Builder<H> {
self
}
}
impl<H: BuildHasher> Builder<H> {
fn languages<H2: RealHasher>(self, languages: HashSet<usize, H2>) -> Builder<H2> {
Builder {
languages: Some(languages),
}
}
fn all_languages<H2: RealHasher>(self) -> Builder<H2> {
self.languages([].into_iter().collect())
}
}
fn main() {
// works
let builder: Builder<std::hash::RandomState> = Builder::new().build();
let builder = Builder::new().languages(HashSet::new()).build();
let builder = Builder::new()
.all_languages::<std::hash::RandomState>()
.build();
// does not compile
let builder: Builder<std::hash::RandomState> = Builder::new().all_languages().build();
}
I expected that all_languages() filters type by Builder<impl RealHasher>, and so there would be only one candidate of build() (second), because hasher of the first one does not implement RealHasher (because DummyBuildHasher does not implement Default), so it would compile.
Instead, it ignores that all_languages() limits hasher type with trait RealHasher, and thinks that there are two candidates of build().
Ideas
I still don't understand why it enables the second candidate of build(), but does not disable the first one. Because without all_languages() there is only one candidate. Maybe it correctly adds the trait RealHasher, but forgets to remove the first candidate of build() from a list of all possible candidates?
Also given that .all_languages::<std::hash::RandomState>().build() works, but not .all_languages().build::<std::hash::RandomState>(), maybe there is a problem with type determination (passing) in chained calls?
Meta
rustc --version --verbose:
rustc 1.88.0-nightly (e9f8103f9 2025-05-07)
binary: rustc
commit-hash: e9f8103f93f8ce2fa2c15c0c6796ec821f8ae15d
commit-date: 2025-05-07
host: x86_64-unknown-linux-gnu
release: 1.88.0-nightly
LLVM version: 20.1.4
Backtrace
error[E0034]: multiple applicable items in scope
--> src/main.rs:62:83
|
62 | let builder: Builder<std::hash::RandomState> = Builder::new().all_languages().build();
| ^^^^^ multiple `build` found
|
note: candidate #1 is defined in an impl for the type `Builder<DummyBuildHasher>`
--> src/main.rs:27:5
|
27 | fn build(self) -> Builder<std::hash::RandomState> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: candidate #2 is defined in an impl for the type `Builder<H>`
--> src/main.rs:34:5
|
34 | fn build(self) -> Builder<H> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the diagnostic with the standalone example in src/main.rs using the reported rustc nightly version. Start by examining method resolution for the chained all_languages().build() call and compare it with the explicitly typed variants; done means the compiler consistently selects only the applicable build method or provides a justified diagnostic.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100