Common Generic Errors
Working with generics in Rust surfaces a well-defined set of compile-time diagnostics when trait bounds are missing, type parameters cannot be inferred, or caller and callee perspectives on a type parameter are confused.
Reference Table of Common Compiler Diagnostics
| Error Code | Summary | Typical Cause |
|---|---|---|
E0277 |
Trait bound not satisfied | Using an operator, format specifier, or method on T without declaring the required trait bound |
E0282 |
Type annotations needed | Calling a generic function or constructing a variant (None, Ok) without enough context to fix T |
E0308 |
Mismatched types (caller vs. callee T) |
Returning a concrete type (i32) where a caller-chosen type parameter T was declared |
E0392 |
Type parameter is never used | Declaring <T> on a struct or enum without referencing T in any field or variant |
E0401 |
Can't use generic parameters from outer item | Referencing an enclosing impl<T> or fn<T> type parameter inside a nested fn or struct |
E0507 |
Cannot move out of [T] / &T |
Indexing a generic slice slice[0] by value without T: Copy or T: Clone |
Confusing Caller-Chosen T with Callee-Chosen Return Types (E0308)
A type parameter fn make_value<T>() -> T means the caller chooses T, and the function body must be able to produce whatever T the caller requests. Returning a fixed concrete type such as 42_i32 inside fn make_value<T>() -> T fails with E0308 because the caller might ask for make_value::<String>():
// ❌ does not compile
fn make_default<T>() -> T {
0
}
fn main() {
let _x: i32 = make_default();
}
error[E0308]: mismatched types
--> src/main.rs:3:5
|
2 | fn make_default<T>() -> T {
| - - expected `T` because of return type
| |
| expected this type parameter
3 | 0
| ^ expected type parameter `T`, found integer
|
= note: expected type parameter `T`
found type `{integer}`
Fix this in one of two ways depending on intent:
- If the caller chooses
T, constrainTwith a trait capable of constructingT, such asT: Default, and returnT::default(). - If the callee chooses a single concrete hidden type, return
impl Trait(fn make_default() -> impl Display) instead of<T>.
Moving Out of a Generic Slice or Reference (E0507)
With concrete primitives like &[i32], writing let first = slice[0]; works because i32 implements Copy. With an unconstrained generic slice &[T], T is not known to implement Copy, so slice[0] attempts to move ownership out of a borrowed slice:
// ❌ does not compile
fn first_owned<T>(slice: &[T]) -> T {
slice[0]
}
fn main() {}
error[E0507]: cannot move out of `slice[_]` which is behind a shared reference
--> src/main.rs:3:5
|
3 | slice[0]
| ^^^^^^^^ move occurs because `slice[_]` has type `T`, which does not implement the `Copy` trait
|
help: consider borrowing here
|
3 | &slice[0]
| +
You have three ways to resolve E0507 on generic references:
- Return a reference (
&T) instead of an ownedT:fn first_ref<T>(slice: &[T]) -> Option<&T> { slice.first() }. - Require
T: Cloneand callslice[0].clone(). - Require
T: Copyif the function is intended only for trivially copyable types.
Using Outer Generic Parameters in Inner Items (E0401)
A nested fn or struct defined inside a generic function does not automatically inherit the outer function's type parameters:
// ❌ does not compile
fn process<T: Copy>(item: T) -> (T, T) {
fn duplicate(x: T) -> (T, T) {
(x, x)
}
duplicate(item)
}
fn main() {}
error[E0401]: can't use generic parameters from outer item
--> src/main.rs:3:21
|
2 | fn process<T: Copy>(item: T) -> (T, T) {
| - type parameter from outer item
3 | fn duplicate(x: T) -> (T, T) {
| - ^ use of generic parameter from outer item
| |
| help: try introducing a local generic parameter here: `<T>`
Declare the type parameter explicitly on the inner function (fn duplicate<U: Copy>(x: U) -> (U, U)) or use a closure (let duplicate = |x: T| (x, x);), which shares the enclosing function's generic scope:
fn process<T: Copy>(item: T) -> (T, T) {
let duplicate = |x: T| (x, x);
duplicate(item)
}
fn main() {
println!("{:?}", process("ok"));
}
("ok", "ok")