rust-lang/rust · critical

`FnPtr` does not have an associated type: {:?}

Error message

`FnPtr` does not have an associated type: {:?}

What it means

A `panic!` in `consider_builtin_fn_ptr_trait_candidate`. The built-in `FnPtr` trait (the marker trait for fn pointers, distinct from the `Fn`/`FnMut`/`FnOnce` function-call traits) has no associated types, so a `NormalizesTo` goal against it should not reach this candidate. It indicates a dispatch mistake routing a projection goal into the fn-pointer candidate assembly.

Source

Thrown at compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs:515

        _ecx: &mut EvalCtxt<'_, D>,
        goal: Goal<I, Self>,
        _sizedness: SizedTraitKind,
    ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
        panic!("`Sized`/`MetaSized` does not have an associated type: {:?}", goal);
    }

    fn consider_builtin_copy_clone_candidate(
        _ecx: &mut EvalCtxt<'_, D>,
        goal: Goal<I, Self>,
    ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
        panic!("`Copy`/`Clone` does not have an associated type: {:?}", goal);
    }

    fn consider_builtin_fn_ptr_trait_candidate(
        _ecx: &mut EvalCtxt<'_, D>,
        goal: Goal<I, Self>,
    ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
        panic!("`FnPtr` does not have an associated type: {:?}", goal);
    }

    fn consider_builtin_fn_trait_candidates(
        ecx: &mut EvalCtxt<'_, D>,
        goal: Goal<I, Self>,
        goal_kind: ty::ClosureKind,
    ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
        let cx = ecx.cx();
        let Some(tupled_inputs_and_output) =
            structural_traits::extract_tupled_inputs_and_output_from_callable(
                cx,
                goal.predicate.self_ty(),
                goal_kind,
            )?
        else {
            return ecx.forced_ambiguity(MaybeInfo::AMBIGUOUS);
        };
        let (inputs, output) = ecx.instantiate_binder_with_infer(tupled_inputs_and_output);

View on GitHub (pinned to 22057b88b0)

Solutions

  1. Confirm `FnPtr` is never the trait of a projection goal; it is a marker, not a projection source.
  2. Reduce and report as a rustc ICE with `-Znext-solver`.
  3. Work around on the stable solver.

Example fix

// before — projecting on the FnPtr marker trait (invalid)
fn f<T: FnPtr>() -> <T as FnPtr>::Ret { todo!() }
// after — use the Fn/FnOnce call trait for return-type projection
fn f<F: FnOnce() -> i32>() -> F::Output { todo!() }
Defensive patterns

Strategy: validation

Validate before calling

// FnPtr (the unboxed function-pointer marker) has no associated type.
fn is_fnptr_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
    tcx.lang_items().fn_ptr_trait() == Some(trait_def_id)
}
if is_fnptr_trait(tcx, did) {
    return Err("FnPtr has no associated type");
}

Type guard

fn projection_target_is_not_fnptr(tcx: TyCtxt<'_>, did: DefId) -> bool {
    tcx.lang_items().fn_ptr_trait() != Some(did)
}

Try / catch

use std::panic;
match panic::catch_unwind(panic::AssertUnwindSafe(|| solver.normalizes_to(goal))) {
    Ok(v) => v,
    Err(_) => Err("do not project an associated type off FnPtr; use Fn/FnMut/FnOnce instead"),
}

Prevention

When it happens

Trigger: A `NormalizesTo` goal whose trait is `FnPtr` is dispatched to `consider_builtin_fn_ptr_trait_candidate` under the new solver. Reachable via IR that names an associated item on `FnPtr`.

Common situations: Nightly features around `FnPtr` (e.g. `fn_ptr_trait`); macro or compiler code that builds `<T as FnPtr>::Item`; regressions in how the solver filters candidates for marker-style builtin traits.

Related errors


AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03). Data as JSON: /data/errors/cf1fba6625fb1c30.json. Report an issue: GitHub.