rust-lang / rust-lang/rust

Bug: chained where T: trait multiple applicable items

Open
#140,892 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-inference A-method-lookup C-bug T-compiler
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.