I am struggling to get this code to compile:
struct Marker;
struct Input;
struct Output;
trait Coerce<T, U> {
fn coerce(val: T) -> U;
}
impl<T> Coerce<T, Output> for Marker {
fn coerce(_val: T) -> Output {
Output
}
}
fn test_coerce1<T>(x: T) -> Output
where
Marker: Coerce<T, Output>,
{
Marker::coerce(x)
}
fn test_coerce2<U>(x: U) -> Output
// where
// Marker: Coerce<U, Output>,
{
test_coerce1(Input)
}
fn test_coerce3<V>(x: V) -> Output
where
Marker: Coerce<V, Output>,
{
test_coerce1(Input) // error[E0308]: mismatched types
}
test_coerce2() compiles successfully, so I imagine test_coerce3() should compile as well!
It seems that adding the bound Marker: Coerce<V, Output> bound somehow prevents the compiler from noticing that there already exists a more general implementation: impl<T> Coerce<T, Output> for Marker.
It is trying to substitute V for T, but it SHOULD be substituting Input for T.
Is this a known bug? Is there any way to work around this, other than manually specifying a fully-qualified path? I really would like to avoid using a fully-qualified path since the full type might be extremely complicated (e.g. potentially involving async), or possibly even opaque.
jofas
October 4, 2025, 7:58pm
2
This looks like an edge case of Rust's type inference to me. I can't point you to a specific issue on GitHub for this, but my guess would be that this is already known. Not sure if you mean this by manually using a fully-qualified path, but explicitly setting T of the test_coerce1(Input) call makes test_coerce3 compile:
fn test_coerce3<V>(x: V) -> Output
where
Marker: Coerce<V, Output>,
{
test_coerce1::<Input>(Input)
}
Playground.
You know what, I just came up with a profoundly dumb way to solve this:
fn test_coerce3<V>(x: V) -> Output
where
Marker: Coerce<V, Output>,
{
fn inner<V>(_x: V) -> Output {
test_coerce1(Input)
}
inner(x)
}
Yes that occurred to me but I am trying to work with opaque types here. Are you aware of a specific GitHub issue tracking this? Or should I just open a separate issue at risk of it being a duplicate?
jofas
October 4, 2025, 8:04pm
4
From a glance, this looks like a similar report to me:
opened 11:00PM - 11 Oct 22 UTC
A-inference
C-bug
T-types
I tried this code ([Playground](https://play.rust-lang.org/?version=stable&mode=… debug&edition=2021&gist=6af5347fc4b86cc9e41551719382814e)):
```rust
pub struct Type {}
pub struct Unrelated<T>(T);
impl From<Unrelated<Type>> for Unrelated<()> {
fn from(_: Unrelated<Type>) -> Self {
todo!()
}
}
fn type_ok<T>() {
let _: Type = type_constraint(Type {});
}
fn type_wrong_type_parameter<T>()
where
Unrelated<T>: Into<Unrelated<()>>,
{
let _: Type = type_constraint(Type {});
//. --------------- ^^^^^^^ expected type parameter `T`, found struct `Type`
// |
// arguments to this function are incorrect
}
fn type_constraint<Q>(_: Q) -> Q
where
Unrelated<Q>: Into<Unrelated<()>>,
{
unimplemented!()
}
```
Another example with the same problem caused associated types: [Example 2 Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e6d824a679932452a78e31f03402dd88).
I expected to see this happen: The example should compile and the ignored variables `_` on the left hand side has type `Type` in the examples.
Instead, this happened: Only the unbounded function compiles. The functions with the added trait bounds causes a compile time error. The three simplest ways of resolving the problem are:
1. Removing the trait bounds from either `type_wrong_type_parameter` or `type_constraint`. Might not be possible.
2. Replacing `Unrelated<T>` with `T` in the trait bounds. This is usually not a solution either.
3. Adding an explicit type to the function call `type_constraint::<Type>`. This allows the problem to in most cases be side-stepped.
If the problem is that the function want's to resolve `T` to a known type, the relation between the unused generic variable `T` and the function call is still not obvious.
### Meta
Tested on both the stable and nightly compiler:
```
rustc 1.64.0 (a55dd71d5 2022-09-19)
binary: rustc
commit-hash: a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52
commit-date: 2022-09-19
host: x86_64-apple-darwin
release: 1.64.0
LLVM version: 14.0.6
```
```
rustc 1.66.0-nightly (a6b7274a4 2022-10-10)
binary: rustc
commit-hash: a6b7274a462829f8ef08a1ddcdcec7ac80dbf3e1
commit-date: 2022-10-10
host: x86_64-apple-darwin
release: 1.66.0-nightly
LLVM version: 15.0.2
```
### Error output
```
Compiling playground v0.0.1 (/playground)
error[[E0308]](https://doc.rust-lang.org/stable/error-index.html#E0308): mismatched types
--> src/lib.rs:18:35
|
14 | fn type_wrong_type_parameter<T>()
| - this type parameter
...
18 | let _: Type = type_constraint(Type {});
| --------------- ^^^^^^^ expected type parameter `T`, found struct `Type`
| |
| arguments to this function are incorrect
|
= note: expected type parameter `T`
found struct `Type`
note: function defined here
--> src/lib.rs:24:4
|
24 | fn type_constraint<Q>(_: Q) -> Q
| ^^^^^^^^^^^^^^^ ----
error[[E0308]](https://doc.rust-lang.org/stable/error-index.html#E0308): mismatched types
--> src/lib.rs:18:19
|
14 | fn type_wrong_type_parameter<T>()
| - this type parameter
...
18 | let _: Type = type_constraint(Type {});
| ---- ^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Type`, found type parameter `T`
| |
| expected due to this
|
= note: expected struct `Type`
found type parameter `T`
For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` due to 2 previous errors
```
A longer standing issue:
opened 01:52PM - 04 Apr 15 UTC
A-trait-system
T-compiler
C-bug
T-types
MVCE:
```rust
trait Trait<T> {
fn call_me(&self, x: T) {}
}
impl<T> Trait<u3… 2> for T {}
impl<T> Trait<i32> for T {}
fn bug<T: Trait<U>, U>(x: T) {
x.call_me(1u32);
//~^ ERROR mismatched types
}
```
This is due to the fact that we prefer where-bounds over impls, even if the where-bounds have unnecessary inference constraints.
---
I stumbled upon this trying to write a function that generically takes a range (or something else with which `str` can be indexed), and slices a str with that range. I got that to work, this bug comes into play when the str is produced by slicing another string with a `RangeFrom` or another concrete type (in the same function).
Here's a simpler (no lifetimes, no associated types) and self-contained example ([playpen](http://is.gd/f5auhw)):
``` rust
trait Frobnicate<I> {
fn frob(&self, i: I) -> Self;
}
struct Thing;
struct IA;
struct IB;
impl Frobnicate<IA> for Thing {
fn frob(&self, _i: IA) -> Thing {
Thing
}
}
impl Frobnicate<IB> for Thing {
fn frob(&self, _i: IB) -> Thing {
Thing
}
}
fn delegate_frob<I>(t: Thing, i: I) -> Thing
where
Thing: Frobnicate<I>,
{
let t2: Thing = t.frob(IA);
t2.frob(i)
}
```
This seems innocent enough. There's a `impl Frobnicate<IA> for Thing`, so the `.frob(IA)` call should work, and it's known to return `Thing` again, so via the `where` clause the `.frob(i)` call is good as well. However, I get this error message:
```
error[E0308]: mismatched types
--> src/main.rs:26:28
|
22 | fn delegate_frob<I>(t: Thing, i: I) -> Thing
| - expected this type parameter
...
26 | let t2: Thing = t.frob(IA);
| ---- ^^ expected type parameter `I`, found `IA`
| |
| arguments to this method are incorrect
|
= note: expected type parameter `I`
found struct `IA`
note: method defined here
--> src/main.rs:2:8
|
2 | fn frob(&self, i: I) -> Self;
| ^^^^ -
```
It appears that the where clause makes the compiler forget that there are other impls.
Adding a `Thing : Frobnicate<IA>` bound only makes the compiler (rightly) complain that that's not a bound at all, since it doesn't involve any type parameters.
UFCS makes it compile, though:
``` rust
let t2: Thing = <Thing as Frobnicate<IA>>::frob(&t, IA);
```
Edit: Besides playpen, I can also reproduce this locally:
```
rustc 1.0.0-beta (9854143cb 2015-04-02) (built 2015-04-02)
binary: rustc
commit-hash: 9854143cba679834bc4ef932858cd5303f015a0e
commit-date: 2015-04-02
build-date: 2015-04-02
host: x86_64-pc-windows-gnu
release: 1.0.0-beta
```
But I already noticed it a couple of weeks ago, so it can't be a recent regression.
A recent conversation about it on this forum:
Hey folks,
I was thinking a while about issue #24066 the initial post of the issue mentions the following example:
trait Trait<T> {
fn call_me(&self, x: T) {}
}
impl<T> Trait<u32> for T {}
impl<T> Trait<i32> for T {}
fn bug<T: Trait<U>, U>(x: T) {
x.call_me(1u32);
//~^ ERROR mismatched types
}
My personal gut feeling tells me that it's perfectly fine how it works today, because otherwise the body could further restrict the constraints from the function signature which would proba…
You can't leave the bound off ala test_coerce2?
1 Like
Side note: I've also found this comment which is linked from the original issue. That's maybe the reason for the confusing compiler errors this bug often causes à la "expected type parameter V, found Input" like in the initial example of this topic.
1 Like