{"id":"4c4c12d3ffe86ddb","repo":"rust-lang/rust","slug":"params-should-have-been-canonicalized-to-placehold","errorCode":null,"errorMessage":"Params should have been canonicalized to placeholders","messagePattern":"Params should have been canonicalized to placeholders","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"compiler/rustc_next_trait_solver/src/solve/eval_ctxt/solver_region_constraints.rs","lineNumber":185,"sourceCode":"        components: &[Component<I>],\n        r: Region<I>,\n    ) -> RegionConstraint<I> {\n        RegionConstraint::And(\n            components.into_iter().map(|c| self.destructure_component(c, r)).collect(),\n        )\n    }\n\n    fn destructure_component(&mut self, c: &Component<I>, r: Region<I>) -> RegionConstraint<I> {\n        use Component::*;\n        match c {\n            Region(c_r) => RegionConstraint::RegionOutlives(*c_r, r),\n            Placeholder(p) => {\n                RegionConstraint::PlaceholderTyOutlives(Ty::new_placeholder(self.cx(), *p), r)\n            }\n            // The alias is either rigid or ambiguous in which case we'll return with ambiguity.\n            Alias(_, alias) => self.destructure_alias_outlives(*alias, r),\n            UnresolvedInferenceVariable(_) => RegionConstraint::Ambiguity,\n            Param(_) => panic!(\"Params should have been canonicalized to placeholders\"),\n            EscapingAlias(components) => self.destructure_components(components, r),\n        }\n    }\n\n    /// Convert an alias outlives constraint into an OR constraint of any number of three\n    /// separate classes of candidates:\n    /// 1. component outlives. we turn `Alias<T, 'a>: 'b` into `T: 'b, 'a: 'b`.\n    /// 2. item bounds. we turn `Alias<T, 'a>: 'b` into `'c: 'b` if `Alias` is\n    ///     defined as `type Alias<T, 'a>: 'c`\n    /// 3. env assumptions. we defer handling `Alias<T, 'a>: 'b` via where clauses until\n    ///     when exiting the current binder. See [`RegionConstraint::AliasTyOutlivesViaEnv`].\n    #[instrument(level = \"debug\", skip(self), ret)]\n    fn destructure_alias_outlives(\n        &mut self,\n        alias: AliasTy<I>,\n        r: Region<I>,\n    ) -> RegionConstraint<I> {\n        let item_bounds =","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/rust-lang/rust/blob/22057b88b091743bc0fd8d592a9264f0a6951403/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/solver_region_constraints.rs#L167-L203","documentation":"In the solver's region-constraint destructor, a Component::Param(_) is treated as a hard error because canonicalization is supposed to have rewritten every early-bound region param into a Placeholder before region constraints are processed. Encountering a Param here means the canonicalization step that should have run before evaluating the goal was skipped or is incomplete.","triggerScenarios":"Triggered when SolverRegionConstraints::destructure_component (compiler/rustc_next_trait_solver/src/solve/eval_ctxt/solver_region_constraints.rs:175) matches Component::Param(_) — i.e. an outlives constraint over a still-parametric region reached the region-constraint collector without first being canonicalized to a placeholder.","commonSituations":"ICE during region-outlives / alias-outlives solving under -Znext-solver. Usually a regression in how the search graph or EvalCtxt canonicalizes goals before invoking the region constraint machinery.","solutions":["Report the ICE to rustc with the offending crate and the backtrace.","Verify the goal was canonicalized (params -> placeholders) before reaching region constraint collection; the bug is the missing canonicalization.","Disable -Znext-solver to unblock.","Bisect changes to canonicalization / placeholder instantiation in the new solver."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Region constraints must see placeholders, not Params. Ensure generic params are\n// canonicalized before being passed into region solving (this is the compiler's job,\n// but you can avoid triggering it by not hand-rolling region-parameterized generics).\nfn uses_explicit_lifetime_params(src: &str) -> bool {\n    src.contains(\"<'\") && src.contains(\">\")\n}\n#[test]\nfn flag_region_param_heavy_crates() {\n    if uses_explicit_lifetime_params(include_str!(\"lib.rs\")) {\n        eprintln!(\"warning: explicit lifetime params may trigger solver canonicalization bug\");\n    }\n}","typeGuard":"trait CanonicalLifetime: 'static {}\n// force callers to bind lifetimes to 'static-or-equivalent placeholders, never raw Params\nfn requires_canonical<'a, T: CanonicalLifetime>(_x: &'a T) {}","tryCatchPattern":"use std::panic::{catch_unwind, AssertUnwindSafe};\nlet ok = catch_unwind(AssertUnwindSafe(|| solve_region_constraints(&regions)));\nif ok.is_err() { fall_back_to_legacy_solver_for_regions(); }","preventionTips":["Prefer `'_` elision and lifetime inference over explicit named lifetime params; the canonicalizer handles inferred lifetimes more reliably.","Avoid HRTB over multiple lifetimes (`for<'a,'b>`) in public API signatures.","If you must use explicit lifetimes, write a small `cargo check` gate in CI and treat any region-related ICE as a release blocker."],"tags":["rust","rustc","trait-solver","ice","next-solver","regions","canonicalization","lifetimes"],"analyzedSha":"22057b88b091743bc0fd8d592a9264f0a6951403","analyzedAt":"2026-08-03T08:09:25.915Z","schemaVersion":2}