rust-lang/rust · error
if we had an explicit self, we wouldn't be here
Error message
if we had an explicit self, we wouldn't be here
What it means
This `unreachable!` is fired by `SelfKind::to_ref_suggestion` when the receiver is a `SelfKind::Value` (`self` / `mut self`) or `SelfKind::Explicit` (`self: TYPE`). The method only knows how to render a *reference* suggestion string (e.g. `&self`, `&pin mut self`); value/explicit selves have no reference prefix to suggest, so reaching this arm means the caller violated that contract. It is an internal rustc invariant, not a user-visible diagnostic.
Source
Thrown at compiler/rustc_ast/src/ast.rs:2952
/// `self`, `mut self`
Value(Mutability),
/// `&'lt self`, `&'lt mut self`
Region(Option<Lifetime>, Mutability),
/// `&'lt pin const self`, `&'lt pin mut self`
Pinned(Option<Lifetime>, Mutability),
/// `self: TYPE`, `mut self: TYPE`
Explicit(Box<Ty>, Mutability),
}
impl SelfKind {
pub fn to_ref_suggestion(&self) -> String {
match self {
SelfKind::Region(None, mutbl) => mutbl.ref_prefix_str().to_string(),
SelfKind::Region(Some(lt), mutbl) => format!("&{lt} {}", mutbl.prefix_str()),
SelfKind::Pinned(None, mutbl) => format!("&pin {}", mutbl.ptr_str()),
SelfKind::Pinned(Some(lt), mutbl) => format!("&{lt} pin {}", mutbl.ptr_str()),
SelfKind::Value(_) | SelfKind::Explicit(_, _) => {
unreachable!("if we had an explicit self, we wouldn't be here")
}
}
}
}
pub type ExplicitSelf = Spanned<SelfKind>;
impl Param {
/// Attempts to cast parameter to `ExplicitSelf`.
pub fn to_self(&self) -> Option<ExplicitSelf> {
if let PatKind::Ident(BindingMode(ByRef::No, mutbl), ident, _) = self.pat.kind {
if ident.name == kw::SelfLower {
return match self.ty.kind {
TyKind::ImplicitSelf => Some(respan(self.pat.span, SelfKind::Value(mutbl))),
TyKind::Ref(lt, MutTy { ref ty, mutbl }) if ty.kind.is_implicit_self() => {
Some(respan(self.pat.span, SelfKind::Region(lt, mutbl)))
}
TyKind::PinnedRef(lt, MutTy { ref ty, mutbl })View on GitHub (pinned to 22057b88b0)
Solutions
- Match only `SelfKind::Region` and `SelfKind::Pinned` before calling `to_ref_suggestion`, and handle `Value`/`Explicit` separately.
- If you need a suggestion for value/explicit self, return the original receiver text or use `Mutability::prefix_str()` directly instead of this method.
- Add a regression test that exercises the lint/suggestion path with `self`, `mut self`, and `self: Box<Self>` receivers.
Example fix
// before
let s = self_kind.to_ref_suggestion();
// after
let s = match &self_kind {
SelfKind::Region(..) | SelfKind::Pinned(..) => self_kind.to_ref_suggestion(),
SelfKind::Value(mutbl) => mutbl.prefix_str().to_string(),
SelfKind::Explicit(_, mutbl) => mutbl.prefix_str().to_string(),
}; Defensive patterns
Strategy: type-guard
Validate before calling
// Before calling to_ref_suggestion, confirm the SelfKind is a reference form.
let kind: &SelfKind = /* ... */;
let is_ref = matches!(
kind,
SelfKind::Region(_, _) | SelfKind::Pinned(_, _)
);
if !is_ref {
// skip suggestion; kind is Value/Explicit and has no ref form
} Type guard
fn is_ref_self_kind(kind: &SelfKind) -> bool {
matches!(kind, SelfKind::Region(_, _) | SelfKind::Pinned(_, _))
} Prevention
- Never call `to_ref_suggestion()` on `SelfKind::Value` or `SelfKind::Explicit`; the function documents it only handles reference receivers.
- Pattern-match on `SelfKind` first and only fall into the reference arm.
- Treat `to_ref_suggestion` as a refinement helper, not a total function over the enum.
When it happens
Trigger: A rustc internals caller invokes `SelfKind::to_ref_suggestion()` (or a downstream helper that calls it) on a `SelfKind::Value(..)` or `SelfKind::Explicit(..)` variant — for example, code that builds a `&self`-style suggestion without first excluding value/explicit self kinds. Reachable via lints, suggestions, or HIR lowering paths that ask every `SelfKind` for a reference prefix.
Common situations: Custom rustc patches or new lints that want to emit a borrow-receiver suggestion and route all `SelfKind` variants through `to_ref_suggestion` instead of matching only `Region`/`Pinned`. Also surfaces during refactors that change how method receivers are classified.
Related errors
- empty prefix in a simple import
- `UseTree::ident` can only be used on a simple import
- attribute is missing tokens: {self:?}
- Should be `AttrTokenTree::Delimited`, not delim tokens: {:?}
- cloning statement `NodeId`s is prohibited by default, the vi
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/0fb94d40baf8acc1.json.
Report an issue: GitHub.