{"id":"9180bec71880a161","repo":"rust-lang/rust","slug":"no-such-thing-as-an-opaque-const","errorCode":null,"errorMessage":"no such thing as an opaque const","messagePattern":"no such thing as an opaque const","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs","lineNumber":23,"sourceCode":"use rustc_type_ir::solve::{GoalSource, QueryResultOrRerunNonErased, RerunReason};\nuse rustc_type_ir::{self as ty, Interner, MayBeErased, TypingMode, fold_regions};\n\nuse crate::delegate::SolverDelegate;\nuse crate::solve::{Certainty, EvalCtxt, Goal};\n\nimpl<D, I> EvalCtxt<'_, D>\nwhere\n    D: SolverDelegate<Interner = I>,\n    I: Interner,\n{\n    #[tracing::instrument(skip(self))]\n    pub(super) fn normalize_opaque_type(\n        &mut self,\n        goal: Goal<I, ty::ProjectionPredicate<I>>,\n    ) -> QueryResultOrRerunNonErased<I> {\n        let cx = self.cx();\n        let opaque_ty = goal.predicate.projection_term;\n        let expected = goal.predicate.term.as_type().expect(\"no such thing as an opaque const\");\n        let def_id = opaque_ty.expect_opaque_ty_def_id();\n\n        match self.typing_mode() {\n            TypingMode::Coherence => {\n                // An impossible opaque type bound is the only way this goal will fail\n                // e.g. assigning `impl Copy := NotCopy`\n                self.add_item_bounds_for_hidden_type(\n                    def_id,\n                    opaque_ty.args,\n                    goal.param_env,\n                    expected,\n                )?;\n                // Trying to normalize an opaque type during coherence is always ambiguous.\n                // We add a nested ambiguous goal here instead of using `Certainty::AMBIGUOUS`.\n                // This allows us to return the nested goals to the parent `AliasRelate` goal.\n                // This can then allow nested goals to fail after we've constrained the `term`.\n                self.add_goal(GoalSource::Misc, goal.with(cx, ty::PredicateKind::Ambiguous))?;\n                self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/rust-lang/rust/blob/22057b88b091743bc0fd8d592a9264f0a6951403/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs#L5-L41","documentation":"Opaque types (`impl Trait`, async-fn returns, RPIT, TAIT) are always types, never constants. In `normalize_opaque_type` (opaque_types.rs:23), `goal.predicate.term.as_type().expect(\"no such thing as an opaque const\")` fires if the term on the RHS of the projection goal is a const term. An opaque-type projection goal with a const RHS is meaningless, so reaching the `expect` means the solver constructed a malformed opaque-type goal — a compiler bug.","triggerScenarios":"An opaque-type projection goal is built whose `term` is a const (not a type), e.g. when an opaque appears in an associated-const position or const-eval context, under `-Znext-solver`.","commonSituations":"Nightly users putting `impl Trait` / async-fn opaque returns into associated-const or const-generic positions, or after a rustc update that mishandles opaque terms across the type/const boundary.","solutions":["Report at https://github.com/rust-lang/rust/issues with the panic `no such thing as an opaque const` and a minimal `impl Trait` / async repro.","Move the opaque type out of const positions (don't use `impl Trait` as/for an associated const).","Disable `-Znext-solver`.","`rustup update nightly`."],"exampleFix":"// before — opaque in a const-ish position\nconst C: impl Trait = async {}.await; // nonsensical, leaks const term\n// after — opaque as a type only\nasync fn f() -> impl Trait { /* ... */ }","handlingStrategy":"type-guard","validationCode":"// There is no such thing as an 'opaque const' — opaque types (impl Trait)\n// are only valid in type position, not in const-value position.\n// BAD:  const X: = impl Trait;  (nonsensical)\n// GOOD: const X: i32 = 5;\n//       type O = impl Trait;   (opaque in type position)\nfn ensure_not_opaque_const<T>() -> bool { false }","typeGuard":"// Reject any construction that places `impl Trait` in a const/value slot.\n// Only use `impl Trait` as a return type, argument type, or type alias:\ntrait Trait {}\nfn returns_opaque() -> impl Trait { struct Z; impl Trait for Z {} Z }\n// const OPAQUE: impl Trait = ...; // <- never valid, would panic solver","tryCatchPattern":null,"preventionTips":["Never use `impl Trait` (or `type ... = impl Trait;`) in a const definition or const-expression position.","Opaque types live only in type position; const values must have a concrete type annotation.","If a macro generates opaque types, audit its output to ensure none land in const contexts."],"tags":["rustc","trait-solver","next-solver","ice","opaque-types","impl-trait"],"analyzedSha":"22057b88b091743bc0fd8d592a9264f0a6951403","analyzedAt":"2026-08-03T08:09:25.915Z","schemaVersion":2}