rust-lang/rust-analyzer · error

Cannot rename parameter to self for trait functions

Error message

Cannot rename parameter to self for trait functions

What it means

rust-analyzer's rename_to_self refuses to convert the first parameter of a trait function into a `self` parameter. A trait's method signature declares its receiver abstractly (e.g. `fn foo(x: &Self)`) and rewriting it to `self` would change the trait contract for every implementor, not just the local function body, so the IDE bails out instead of producing an unsafe edit.

Solutions

  1. Rename the trait method's parameter to a normal identifier instead of `self`.
  2. If a method receiver is wanted, convert a concrete `impl` method's first parameter to `self` rather than the trait declaration's, or edit the trait signature manually (e.g. `fn foo(self)` / `fn foo(&self)`).
  3. Implement the method in an `impl Trait for Type` block and rename that impl's first parameter to `self` there.

Example fix

// before
trait Speaker {
    fn speak(me: &Self);
}
// after
trait Speaker {
    fn speak(&self);
}
Defensive patterns

Strategy: try-catch

Try / catch

match rust_analyzer.rename(new_name == "self") {
    Ok(edit) => apply(edit),
    Err(e) if e.contains("trait functions") => {
        // edit the trait signature manually or target an impl method instead
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling rename with new name "self" on the first parameter of a function defined inside a `trait` block, where `fn_def.as_assoc_item()` resolves and `assoc_item.container()` is `AssocItemContainer::Trait(_)`.

Common situations: Selecting a parameter like `x: &Self` in a trait default method and invoking rename-to-self (IDE shortcut / `rust-analyzer.rename` from an editor LSP client).

Related errors


AI-assisted analysis of rust-lang/rust-analyzer@e8f7e90aa3 (2026-09-03). Data as JSON: /api/errors/6aef099348315fac. Report an issue: GitHub.

Appendix: source

Thrown at crates/ide/src/rename.rs:531

    let params = fn_def.assoc_fn_params(sema.db);
    let first_param = params
        .first()
        .ok_or_else(|| format_err!("Cannot rename local to self unless it is a parameter"))?;
    match first_param.as_local(sema.db) {
        Some(plocal) => {
            if plocal != local {
                bail!("Only the first parameter may be renamed to self");
            }
        }
        None => bail!("rename_to_self invoked on destructuring parameter"),
    }

    let assoc_item = fn_def
        .as_assoc_item(sema.db)
        .ok_or_else(|| format_err!("Cannot rename parameter to self for free function"))?;
    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");
    }

View on GitHub (pinned to e8f7e90aa3)