From 544a5a3e0e6d4c69d62b8e331732c896fe3376d0 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 21 Jul 2025 13:57:44 +0000 Subject: [PATCH] Make const trait aliases work in next solver --- .../src/collect/predicates_of.rs | 22 +++++++------ .../src/solve/effect_goals.rs | 31 +++++++++++++++++-- tests/ui/consts/trait_alias.fail.stderr | 18 ++--------- tests/ui/consts/trait_alias.pass.stderr | 17 ---------- tests/ui/consts/trait_alias.rs | 3 +- 5 files changed, 45 insertions(+), 46 deletions(-) delete mode 100644 tests/ui/consts/trait_alias.pass.stderr diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 88deed1be683..2eefe1eb3e92 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -1031,9 +1031,11 @@ pub(super) fn const_conditions<'tcx>( Node::Item(item) => match item.kind { hir::ItemKind::Impl(impl_) => (impl_.generics, None, false), hir::ItemKind::Fn { generics, .. } => (generics, None, false), - hir::ItemKind::TraitAlias(_, _, generics, supertraits) - | hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => { - (generics, Some((item.owner_id.def_id, supertraits)), false) + hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => { + (generics, Some((Some(item.owner_id.def_id), supertraits)), false) + } + hir::ItemKind::TraitAlias(_, _, generics, supertraits) => { + (generics, Some((None, supertraits)), false) } _ => bug!("const_conditions called on wrong item: {def_id:?}"), }, @@ -1090,12 +1092,14 @@ pub(super) fn const_conditions<'tcx>( } if let Some((def_id, supertraits)) = trait_def_id_and_supertraits { - // We've checked above that the trait is conditionally const. - bounds.push(( - ty::Binder::dummy(ty::TraitRef::identity(tcx, def_id.to_def_id())) - .to_host_effect_clause(tcx, ty::BoundConstness::Maybe), - DUMMY_SP, - )); + if let Some(def_id) = def_id { + // We've checked above that the trait is conditionally const. + bounds.push(( + ty::Binder::dummy(ty::TraitRef::identity(tcx, def_id.to_def_id())) + .to_host_effect_clause(tcx, ty::BoundConstness::Maybe), + DUMMY_SP, + )); + } icx.lowerer().lower_bounds( tcx.types.self_param, diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 48bd0963c874..c18f22ca0fb1 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -196,10 +196,35 @@ where } fn consider_trait_alias_candidate( - _ecx: &mut EvalCtxt<'_, D>, - _goal: Goal, + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, ) -> Result, NoSolution> { - unreachable!("trait aliases are never const") + let cx = ecx.cx(); + + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { + let where_clause_bounds = cx + .predicates_of(goal.predicate.def_id().into()) + .iter_instantiated(cx, goal.predicate.trait_ref.args) + .map(|p| goal.with(cx, p)); + + let const_conditions = cx + .const_conditions(goal.predicate.def_id().into()) + .iter_instantiated(cx, goal.predicate.trait_ref.args) + .map(|bound_trait_ref| { + goal.with( + cx, + bound_trait_ref.to_host_effect_clause(cx, goal.predicate.constness), + ) + }); + // While you could think of trait aliases to have a single builtin impl + // which uses its implied trait bounds as where-clauses, using + // `GoalSource::ImplWhereClause` here would be incorrect, as we also + // impl them, which means we're "stepping out of the impl constructor" + // again. To handle this, we treat these cycles as ambiguous for now. + ecx.add_goals(GoalSource::Misc, where_clause_bounds); + ecx.add_goals(GoalSource::Misc, const_conditions); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) } fn consider_builtin_sizedness_candidates( diff --git a/tests/ui/consts/trait_alias.fail.stderr b/tests/ui/consts/trait_alias.fail.stderr index e9148f0bfece..bb0a4e22efcf 100644 --- a/tests/ui/consts/trait_alias.fail.stderr +++ b/tests/ui/consts/trait_alias.fail.stderr @@ -1,23 +1,9 @@ error[E0277]: the trait bound `T: [const] Baz` is not satisfied - --> $DIR/trait_alias.rs:20:11 + --> $DIR/trait_alias.rs:22:11 | LL | x.baz(); | ^^^ -error[E0277]: the trait bound `(): const Foo` is not satisfied - --> $DIR/trait_alias.rs:25:19 - | -LL | const _: () = foo(&()); - | --- ^^^ - | | - | required by a bound introduced by this call - | -note: required by a bound in `foo` - --> $DIR/trait_alias.rs:16:17 - | -LL | const fn foo(x: &T) { - | ^^^^^^^^^^^ required by this bound in `foo` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/trait_alias.pass.stderr b/tests/ui/consts/trait_alias.pass.stderr deleted file mode 100644 index d107ddbf8e45..000000000000 --- a/tests/ui/consts/trait_alias.pass.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0277]: the trait bound `(): const Foo` is not satisfied - --> $DIR/trait_alias.rs:25:19 - | -LL | const _: () = foo(&()); - | --- ^^^ - | | - | required by a bound introduced by this call - | -note: required by a bound in `foo` - --> $DIR/trait_alias.rs:16:17 - | -LL | const fn foo(x: &T) { - | ^^^^^^^^^^^ required by this bound in `foo` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/trait_alias.rs b/tests/ui/consts/trait_alias.rs index 0755c1126b06..2496ef609865 100644 --- a/tests/ui/consts/trait_alias.rs +++ b/tests/ui/consts/trait_alias.rs @@ -1,5 +1,7 @@ #![feature(trait_alias, const_trait_impl)] //@ revisions: pass fail +//@ compile-flags: -Znext-solver +//@[pass] check-pass const trait Bar { fn bar(&self) {} @@ -23,6 +25,5 @@ const fn foo(x: &T) { } const _: () = foo(&()); -//~^ ERROR: `(): const Foo` is not satisfied fn main() {}