Rustc fails to infer type for trait associated function

For the following code,

trait SomeTrait {                                                                  
    type T;                                                                        
    fn hello(a: Self::T);                                                          
}                                                                                  
                                                                                   
struct A;                                                                          
                                                                                   
impl SomeTrait for A {                                                             
    type T = i32;                                                                  
    fn hello(a: i32) {                                                             
        println!("{}", a);                                                         
    }                                                                              
}                                                                                  
                                                                                   
impl A {                                                                           
    fn foo(&self) { 
        let a: i32 = 10;                                                              
        SomeTrait::hello(a);                                                      
    }                                                                              
}                                                                                  
                                                                                   
fn main() {                                                                        
    let a = A;                                                                     
    a.foo();                                                                       
}

I got compile error

error[E0283]: type annotations needed
  --> main.rs:23:9
   |
23 |         SomeTrait::hello(10);
   |         ^^^^^^^^^^^^^^^^ cannot infer type
   |
   = note: cannot satisfy `_: SomeTrait`

Why cannot the Rust compiler infer that the call to SomeTrait::hello() is the one defined for struct A? To my understanding, there is no ambiguity here because there is only one hello() method that takes an i32 parameter.

I know this problem can be solved by changing the call to Self::hello(a) or <A as SomeTrait>::hello(a). But I saw some crate that has code pattern like above. So I'd like to know why the compile fails here.

Many other types could implement the trait with the same T = i32 associated type. If this inference were allowed, then implementing the trait in this way for another type would become ambiguous, so it would be a breaking change. (Worse yet, even importing such a type would then break compilation!)

1 Like

Thanks for the explanation. But I'm still confused: For my example, both trait SomeTrait and struct A are private, so the compiler should know that there is only one definition for SomeTrait::hello(T = i32), correct? Can you be more specific (an example would be great) about how my example could be broken?

I think it's just a matter of trait resolution being based on the inputs of an impl

  • The trait and its parameters
  • The implementing type and its parameters

and not considering the outputs of the impl

  • Such as associated types

and as you note, visibility scopes don't alter this.

I suspect the use-case of "I have a private trait with exactly one implementer (and I expect it to stay that way)" is too niche to break consistency. (Why not just use inherent functions/methods?)

You could still break it by adding another, public type – even from a 3rd-party, downstream crate.

But they can't, since the trait is private and can't be implemented anywhere else. I guess that's the source of confusion.

@quinedot @H2CO3 Could you have a look at this example for why it can compile without ambiguity.

In the git2 crate, trait Binding has one method from_raw: git2-rs/util.rs at e6aa6666b9f0f9110adf5bad56ea1d1dfa119d1c · rust-lang/git2-rs · GitHub. Many different struct implement Binding and from_raw, such as struct Repository: git2-rs/repo.rs at e6aa6666b9f0f9110adf5bad56ea1d1dfa119d1c · rust-lang/git2-rs · GitHub. And in the implementation of these struct, they directly call from_raw by Binding::from_raw, e.g., git2-rs/repo.rs at e6aa6666b9f0f9110adf5bad56ea1d1dfa119d1c · rust-lang/git2-rs · GitHub.

My small example seems to have the same code pattern as the git2 example, so I'm confused why git2 can directly call by Trait::method().

from_raw returns Self (an input to Binding). The call is in a context where Self can be inferred to be Repository.

Here's your example, adjusted.

1 Like

But still, should the mere visibility of the trait change whether it compiles? Worse yet, should it break when it changes to public? That would be pretty bad.