Skip to content

Bug: chained where T: trait multiple applicable items #140892

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
RoDmitry opened this issue May 10, 2025 · 0 comments
Open

Bug: chained where T: trait multiple applicable items #140892

RoDmitry opened this issue May 10, 2025 · 0 comments
Labels
C-bug Category: This is a bug. needs-triage This issue may need triage. Remove it if it has been sufficiently triaged.

Comments

@RoDmitry
Copy link

RoDmitry commented May 10, 2025

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(), 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> {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

@RoDmitry RoDmitry added the C-bug Category: This is a bug. label May 10, 2025
@rustbot rustbot added needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels May 10, 2025
@RoDmitry RoDmitry changed the title Bug: chained where T: trait ignored Bug: chained where T: trait multiple applicable items May 10, 2025
@jieyouxu jieyouxu removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label May 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug. needs-triage This issue may need triage. Remove it if it has been sufficiently triaged.
Projects
None yet
Development

No branches or pull requests

3 participants