rust-lang/rust-analyzer · error
Parameter type differs from impl block type
Error message
Parameter type differs from impl block type
What it means
When renaming the first parameter to `self`, rust-analyzer checks that the parameter's type matches the `Self` type of the containing impl block (after stripping/adding references per the impl's self type). If the stripped parameter type differs from `impl_.self_ty()`, the resulting `self` receiver would be ill-typed, so the rename is rejected.
Source
Thrown at crates/ide/src/rename.rs:547
let impl_ = match assoc_item.container(sema.db) {
hir::AssocItemContainer::Trait(_) => {
bail!("Cannot rename parameter to self for trait functions");
}
hir::AssocItemContainer::Impl(impl_) => impl_,
};
let first_param_ty = first_param.ty();
let impl_ty = impl_.self_ty(sema.db);
let (ty, self_param) = if impl_ty.is_reference() {
// if the impl is a ref to the type we can just match the `&T` with self directly
(first_param_ty.clone(), "self")
} else {
first_param_ty.as_reference_inner().map_or((first_param_ty.clone(), "self"), |ty| {
(ty, if first_param_ty.is_mutable_reference() { "&mut self" } else { "&self" })
})
};
if ty != impl_ty {
bail!("Parameter type differs from impl block type");
}
let InFile { file_id, value: param_source } = sema
.source(first_param.clone())
.ok_or_else(|| format_err!("No source for parameter found"))?;
let def = Definition::Local(local);
let usages = def.usages(sema).all();
let mut source_change = SourceChange::default();
source_change.extend(usages.iter().map(|(file_id, references)| {
(
file_id.file_id(sema.db),
source_edit_from_references(
sema.db,
references,
def,
&Name::new_symbol_root(sym::self_),
file_id.edition(sema.db),View on GitHub (pinned to e8f7e90aa3)
Solutions
- Change the parameter's type to the impl's self type (e.g. `&Self` or `&Foo` matching the `impl Foo` block) before renaming to `self`.
- Rename to `self` only when the signature is like `fn f(x: Foo)` / `fn f(x: &Foo)` inside `impl Foo`.
- If the parameter intentionally has another type, keep it as a normal named parameter and update the body/call sites instead.
Example fix
// before
impl Foo {
fn f(x: &Bar) {}
}
// after
impl Foo {
fn f(&self) {}
} Defensive patterns
Strategy: validation
Validate before calling
fn can_rename_to_self(param_ty: &str, impl_ty: &str) -> bool {
let stripped = param_ty
.trim_start_matches("&mut ")
.trim_start_matches('&');
stripped == impl_ty || param_ty == format!("&{impl_ty}") || param_ty == format!("&mut {impl_ty}")
}
// call before rename: ensure can_rename_to_self("&Foo", "Foo") Prevention
- Ensure the first parameter type matches the impl's self type (optionally by reference).
- Prefer writing `&self`/`self` directly instead of a typed first parameter.
- Check for type aliases obscuring the real type.
When it happens
Trigger: Calling rename_to_self on a first parameter whose type is not the impl's self type (optionally behind a reference), e.g. in `impl Foo { fn f(x: &Bar) }` where `Bar != Foo`.
Common situations: Accidentally renaming a helper's parameter in a large impl block; copy-pasted method whose parameter type points to a different struct; type aliases or generics making the types subtly differ.
Related errors
- AstIdMap node mismatch with node `{ptr:?}`
- Cannot rename builtin type
- Cannot rename a builtin attr.
- Cannot rename `Self`
- Invalid name `{0}`: cannot rename module to {0}
AI-assisted analysis of rust-lang/rust-analyzer@e8f7e90aa3 (2026-09-03).
Data as JSON: /api/errors/ce0ab2e4307b81ee.
Report an issue: GitHub.