Skip to content

Rust Error E0530: Match Bindings Cannot Shadow Tuple Variants

E0530 means: a name in your pattern is already taken. You wrote a plain name, like Circle, where Rust would normally create a new variable. But Circle already means something else in this scope: a tuple variant, a tuple struct, or a static. Rust refuses to quietly hide it behind a new variable, because that would almost never be what you meant. The classic case is a match arm Circle => after use Shape::*;, and the fix is usually two characters: Circle(..). (This page is part of Rust compiler errors explained.)

error[E0530]: match bindings cannot shadow tuple variants
--> src/main.rs:10:9
|
6 | use Shape::*;
| -------- the tuple variant `Circle` is imported here
...
10 | Circle => "circle", // ❌ `Circle` holds a value
| ^^^^^^
| |
| cannot be named the same as a tuple variant
| help: try specify the pattern arguments: `Circle(..)`

This is the program that produces it:

enum Shape {
Circle(f64),
Square(f64),
}
use Shape::*;
fn name(shape: &Shape) -> &'static str {
match shape {
Circle => "circle", // ❌ `Circle` holds a value
Square(_) => "square",
}
}
fn main() {
println!("{}", name(&Circle(1.0)));
}

The ^^^ points at Circle on line 10, and the --- on line 6 shows where that name comes from: use Shape::*; brought the variant Shape::Circle into scope.

In a pattern, a plain lowercase-looking name like x or other creates a new variable that matches anything. So Circle => could mean two things:

  • “match the variant Circle”, but Circle holds an f64, so a correct pattern needs parentheses: Circle(_) or Circle(..).
  • “match anything and call it Circle”, a new variable that would hide the variant.

Rust won’t guess. The headline tells you what kind of name you collided with, and the first word tells you where:

  • match bindings cannot shadow ...: in a match arm
  • let bindings cannot shadow ...: in let or if let
  • function parameters cannot shadow ...: in a function’s parameter list

and it ends in tuple variants, tuple structs or statics.

It’s like naming your dog “Doctor”. Every time someone shouts “Doctor!” in the waiting room, nobody knows who’s meant.

Without this rule, Circle => would be a new variable named Circle. It would match every value, and every arm after it would be dead code. Your program would compile, then print “circle” for squares too. That’s a nasty bug that hides behind code that looks right.

So Rust makes it an error whenever a new variable would take the name of a tuple variant, a tuple struct or a static. You either say what you mean with parentheses, or pick another name. Unit variants like None and constants (const) are different: those are valid patterns on their own, so Rust reads them as “match this value”. See Pattern matching and Enums.

Fix 1: Add (..) or (_) to match the variant

Section titled “Fix 1: Add (..) or (_) to match the variant”

Choose this when the message says tuple variants or tuple structs, which is the most common case. You meant the variant, so give it its parentheses, as rustc’s help suggests. Writing the full path, Shape::Circle(_), is even clearer:

enum Shape {
Circle(f64),
Square(f64),
}
use Shape::*;
fn name(shape: &Shape) -> &'static str {
match shape {
Circle(..) => "circle", // ✅ the variant, any value inside
Square(_) => "square",
}
}
fn area(shape: &Shape) -> f64 {
match shape {
Shape::Circle(r) => 3.14 * r * r, // ✅ full path, and use the value
Shape::Square(side) => side * side,
}
}
fn main() {
let shapes = [Circle(1.0), Square(2.0)];
for shape in &shapes {
println!("{}: {:.2}", name(shape), area(shape));
}
}

Output:

circle: 3.14
square: 4.00
▶ Try it Yourself

.. means “whatever is inside”, and it keeps working if the variant gets more values later. See Ignoring parts with _ and ...

Choose this when you really wanted a new variable, and its name just happens to match a type. That often happens with let and function parameters, when you name a variable after its type:

error[E0530]: let bindings cannot shadow tuple structs
--> src/main.rs:4:9
|
1 | struct Meters(f64);
| ------------------- the tuple struct `Meters` is defined here
...
4 | let Meters = 5.0; // ❌ `Meters` is a tuple struct
| ^^^^^^ cannot be named the same as a tuple struct

The program behind it:

struct Meters(f64);
fn main() {
let Meters = 5.0; // ❌ `Meters` is a tuple struct
println!("{}", Meters);
}

Rust’s naming style solves this for you: types and variants are CamelCase, variables are snake_case. Use a lowercase name and the clash is gone:

struct Meters(f64);
fn total(meters: &[Meters]) -> f64 {
meters.iter().map(|m| m.0).sum()
}
fn main() {
let meters = 5.0; // ✅ a lowercase variable name
println!("{} m", meters);
let Meters(height) = Meters(1.8); // ✅ or destructure the tuple struct
println!("height: {} m", height);
println!("total: {} m", total(&[Meters(2.0), Meters(3.5)]));
}

Output:

5 m
height: 1.8 m
total: 5.5 m
▶ Try it Yourself

The same goes for a parameter: fn show(Point: i32) gives function parameters cannot shadow tuple structs, and fn show(point: i32) fixes it. See Naming rules.

Fix 3: Use a const (or a match guard) instead of a static

Section titled “Fix 3: Use a const (or a match guard) instead of a static”

Choose this when the message says statics. You probably wanted to compare against a fixed value. A static can’t be used as a pattern, but a const can:

error[E0530]: match bindings cannot shadow statics
--> src/main.rs:5:9
|
1 | static LIMIT: u32 = 100;
| ------------------------ the static `LIMIT` is defined here
...
5 | LIMIT => "full", // ❌ a static can't be a pattern
| ^^^^^ cannot be named the same as a static

The program behind it:

static LIMIT: u32 = 100;
fn status(users: u32) -> &'static str {
match users {
LIMIT => "full", // ❌ a static can't be a pattern
_ => "open",
}
}
fn main() {
println!("{}", status(100));
}

Change static to const. If it has to stay a static (for example, because other code takes its address), bind the value to a name and compare in a match guard:

const LIMIT: u32 = 100; // ✅ a const works as a pattern
static MAX_USERS: u32 = 500; // a static stays a static
fn status(users: u32) -> &'static str {
match users {
LIMIT => "full",
_ => "open",
}
}
fn premium_status(users: u32) -> &'static str {
match users {
n if n >= MAX_USERS => "full", // ✅ compare a static in a guard
_ => "open",
}
}
fn main() {
println!("{}", status(100));
println!("{}", status(42));
println!("{}", premium_status(500));
}

Output:

full
open
full
▶ Try it Yourself

For a plain number you’d rarely need static at all. const is the usual choice; see Constants.

Ok => or Some => without parentheses. Ok, Err and Some are tuple variants from the prelude, so match result { Ok => ... } gives E0530 with the help try specify the pattern arguments: `Ok(..)` . Fix: Ok(_) => or Ok(value) =>.

Inside if let. if let Some(Some) = x tries to call the inner value Some and gives let bindings cannot shadow tuple variants. Fix: a lowercase name, if let Some(inner) = x.

With the full path, it’s E0532 instead. Shape::Circle => can’t be a new variable (a variable name has no ::), so rustc reports E0532, expected unit struct, unit variant or constant, found tuple variant. Same fix: add (_) or (..).

A let with the name of a unit struct is E0308. With struct Guest;, the line let Guest = "Ana"; doesn’t create a variable at all: rustc reads Guest as the unit struct and reports E0308 (mismatched types), saying `Guest` is interpreted as a unit struct, not a new binding. Fix: rename the variable, let guest = "Ana";.

Quick check

1. After use Shape::*;, where Circle(f64) is a variant, which match arm compiles?

2. rustc says "let bindings cannot shadow tuple structs" for let Meters = 5.0;. What's the simplest fix?

3. static LIMIT: u32 = 100; can't be used as a match pattern. What can?

Score: 0 / 3