{"id":"6cc706b81fc6b83f","repo":"rust-lang/rust","slug":"expected-projection-found-kind","errorCode":null,"errorMessage":"expected projection, found {kind:?}","messagePattern":"expected projection, found (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs","lineNumber":315,"sourceCode":"            // See <https://github.com/rust-lang/trait-system-refactor-initiative/issues/185>.\n            ecx.try_evaluate_added_goals()?;\n\n            // Add GAT where clauses from the trait's definition. This is necessary\n            // for soundness until we properly handle implied bounds on binders,\n            // see tests/ui/generic-associated-types/must-prove-where-clauses-on-norm.rs.\n            ecx.add_goals(\n                GoalSource::AliasWellFormed,\n                cx.own_clauses_of(alias_def_id.into())\n                    .iter_instantiated(cx, goal.predicate.alias.args)\n                    .map(Unnormalized::skip_norm_wip)\n                    .map(|clause| goal.with(cx, clause)),\n            )?;\n\n            let error_response = |ecx: &mut EvalCtxt<'_, D>, guar| {\n                let error_term = match goal.predicate.alias.kind {\n                    ty::AliasTermKind::ProjectionTy { .. } => Ty::new_error(cx, guar).into(),\n                    ty::AliasTermKind::ProjectionConst { .. } => Const::new_error(cx, guar).into(),\n                    kind => panic!(\"expected projection, found {kind:?}\"),\n                };\n                ecx.instantiate_normalizes_to_term(goal, error_term)?;\n                ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)\n            };\n\n            let target_item_def_id =\n                match ecx.fetch_eligible_assoc_item(goal_trait_ref, alias_def_id, impl_def_id) {\n                    FetchEligibleAssocItemResponse::Found(target_item_def_id) => target_item_def_id,\n                    FetchEligibleAssocItemResponse::NotFound(tm) => {\n                        match tm {\n                            // In case the associated item is hidden due to specialization,\n                            // normalizing this associated item is always ambiguous. Treating\n                            // the associated item as rigid would be incomplete and allow for\n                            // overlapping impls, see #105782.\n                            //\n                            // As this ambiguity is unavoidable we emit a nested ambiguous\n                            // goal instead of using `Certainty::AMBIGUOUS`. This allows us to\n                            // return the nested goals to the parent `AliasRelate` goal. This","sourceCodeStart":297,"sourceCodeEnd":333,"githubUrl":"https://github.com/rust-lang/rust/blob/22057b88b091743bc0fd8d592a9264f0a6951403/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs#L297-L333","documentation":"A `panic!` inside the `error_response` closure of `consider_impl_candidate`, which builds an error term (`Ty::new_error` / `Const::new_error`) when projection fails. The match expects `AliasTermKind::ProjectionTy` or `ProjectionConst`; any other alias kind (inherent, weak, or a future kind) reaching here means the goal was not actually a projection alias — the dispatch logic that routed it to an impl candidate is inconsistent with the alias kind it carries.","triggerScenarios":"A `NormalizesTo` goal whose `alias.kind` is not a projection (e.g. an inherent associated type `T::Assoc` or a weak alias) reaches the impl-candidate error path during projection in the new solver. Typically an internal dispatch mistake rather than user code.","commonSituations":"Nightly features that introduce new `AliasTermKind` variants, or refactors of how inherent/weak aliases are assembled. Users see it as an ICE when normalizing an inherent associated type under `-Znext-solver`.","solutions":["Confirm the goal's `alias` is genuinely a `ProjectionTy`/`ProjectionConst` before it is handed to `consider_impl_candidate`; inherent/weak aliases should be dispatched elsewhere.","Reduce to a minimal inherent-associated-type or weak-alias test and file under `A-traits` / `F-inherent-associates`.","Run without `-Znext-solver` as a workaround."],"exampleFix":"// before — inherent associated type normalized under new solver\nimpl Foo for () { type Assoc = i32; }  // inherent alias T::Assoc\n// after — route inherent aliases through their own candidate, or use stable solver\n","handlingStrategy":"type-guard","validationCode":"// normalizes_to expects an alias (projection) term. Reject anything\n// else before calling.\nuse rustc_middle::ty::{TermKind, AliasTyKind};\nfn term_is_projection(term: Term<'_>) -> bool {\n    matches!(\n        term.kind(),\n        TermKind::Ty(ty) if matches!(ty.kind(), ty::Alias(AliasTyKind::Projection, _))\n    )\n}\nif !term_is_projection(term) { return Err(\"term is not a projection\"); }","typeGuard":"// Narrows a Term to a projection alias suitable for normalizes_to.\nfn as_projection<'tcx>(term: Term<'tcx>) -> Option<ty::AliasTy<'tcx>> {\n    match term.kind() {\n        TermKind::Ty(ty::TyKind::Alias(ty::AliasTyKind::Projection, p)) => Some(*p),\n        _ => None,\n    }\n}","tryCatchPattern":"use std::panic;\nlet r = panic::catch_unwind(panic::AssertUnwindSafe(|| solver.normalizes_to(goal)));\nmatch r {\n    Ok(v) => v,\n    Err(_) => Err(\"normalizes_to only accepts projection terms; caller passed a non-alias\"),\n}","preventionTips":["Only call normalizes_to on terms whose kind is an `Alias(Projection, ..)`.","Add an assertion or guard at the boundary where you produce terms to feed the solver.","Distinguish inherent types and opaque types from projections before normalizing.","Prefer `tcx.normalize_erasing_regions` after confirming the term is a projection."],"tags":["rustc","trait-solver","alias-normalization","compiler-internal","ice"],"analyzedSha":"22057b88b091743bc0fd8d592a9264f0a6951403","analyzedAt":"2026-08-03T08:09:25.915Z","schemaVersion":2}