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.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.