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
- Confirm `FnPtr` is never the trait of a projection goal; it is a marker, not a projection source.
- Reduce and report as a rustc ICE with `-Znext-solver`.
- 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
- Use `Fn`/`FnMut`/`FnOnce` (which do define `Output`) rather than the `FnPtr` trait.
- Do not confuse the `FnPtr` trait with the `fn` type or the `Fn` family.
- Project `Output` only via the closure traits, never via `FnPtr`.
- Lint against `<T as FnPtr>::` in user code.
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
- `Sized`/`MetaSized` does not have an associated type: {:?}
- `Copy`/`Clone` does not have an associated type: {:?}
- reservation impl for trait with assoc item: {:?}
- trait aliases do not have associated types: {:?}
- `ConstKind::Param` should have been canonicalized to `Placeh
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/cf1fba6625fb1c30.json.
Report an issue: GitHub.