From 3bad5014c92686bc0e9914b03eb00e4855e48d99 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 22 Oct 2024 00:00:50 +0000 Subject: [PATCH] Add support for ~const item bounds --- .../src/solve/assembly/mod.rs | 11 ++++ .../src/solve/effect_goals.rs | 51 ++++++++++++++++++- .../src/solve/normalizes_to/mod.rs | 8 +++ .../src/solve/trait_goals.rs | 8 +++ .../assoc-type-const-bound-usage-0.rs | 2 +- .../assoc-type-const-bound-usage-0.stderr | 15 ------ .../assoc-type-const-bound-usage-1.stderr | 28 +++++++--- .../assoc-type-const-bound-usage-fail-2.rs | 35 +++++++++++++ ...assoc-type-const-bound-usage-fail-2.stderr | 15 ++++++ .../assoc-type-const-bound-usage-fail.rs | 28 ++++++++++ .../assoc-type-const-bound-usage-fail.stderr | 15 ++++++ 11 files changed, 191 insertions(+), 25 deletions(-) delete mode 100644 tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.stderr create mode 100644 tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs create mode 100644 tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.stderr create mode 100644 tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs create mode 100644 tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.stderr diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 5e604a5d74f58..f6a5f20a639ec 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -100,6 +100,15 @@ where }) } + /// Assemble additional assumptions for an alias that are not included + /// in the item bounds of the alias. For now, this is limited to the + /// `implied_const_bounds` for an associated type. + fn consider_additional_alias_assumptions( + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, + alias_ty: ty::AliasTy, + ) -> Vec>; + fn consider_impl_candidate( ecx: &mut EvalCtxt<'_, D>, goal: Goal, @@ -594,6 +603,8 @@ where )); } + candidates.extend(G::consider_additional_alias_assumptions(self, goal, alias_ty)); + if kind != ty::Projection { return; } 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 62b4bb0004cad..8d57ad8f2551b 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -3,7 +3,7 @@ use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; -use rustc_type_ir::{self as ty, Interner}; +use rustc_type_ir::{self as ty, Interner, elaborate}; use tracing::instrument; use super::assembly::Candidate; @@ -70,6 +70,55 @@ where } } + /// Register additional assumptions for aliases corresponding to `~const` item bounds. + /// + /// Unlike item bounds, they are not simply implied by the well-formedness of the alias. + /// Instead, they only hold if the const conditons on the alias also hold. This is why + /// we also register the const conditions of the alias after matching the goal against + /// the assumption. + fn consider_additional_alias_assumptions( + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, + alias_ty: ty::AliasTy, + ) -> Vec> { + let cx = ecx.cx(); + let mut candidates = vec![]; + + // FIXME(effects): We elaborate here because the implied const bounds + // aren't necessarily elaborated. We probably should prefix this query + // with `explicit_`... + for clause in elaborate::elaborate( + cx, + cx.implied_const_bounds(alias_ty.def_id) + .iter_instantiated(cx, alias_ty.args) + .map(|trait_ref| trait_ref.to_host_effect_clause(cx, goal.predicate.host)), + ) { + candidates.extend(Self::probe_and_match_goal_against_assumption( + ecx, + CandidateSource::AliasBound, + goal, + clause, + |ecx| { + // Const conditions must hold for the implied const bound to hold. + ecx.add_goals( + GoalSource::Misc, + cx.const_conditions(alias_ty.def_id) + .iter_instantiated(cx, alias_ty.args) + .map(|trait_ref| { + goal.with( + cx, + trait_ref.to_host_effect_clause(cx, goal.predicate.host), + ) + }), + ); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }, + )); + } + + candidates + } + fn consider_impl_candidate( ecx: &mut EvalCtxt<'_, D>, goal: Goal, diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index c98fd85355142..7287cdf74bf45 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -193,6 +193,14 @@ where } } + fn consider_additional_alias_assumptions( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + _alias_ty: ty::AliasTy, + ) -> Vec> { + vec![] + } + fn consider_impl_candidate( ecx: &mut EvalCtxt<'_, D>, goal: Goal>, diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 6b26f960286f6..08cc89d950e22 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -39,6 +39,14 @@ where self.def_id() } + fn consider_additional_alias_assumptions( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + _alias_ty: ty::AliasTy, + ) -> Vec> { + vec![] + } + fn consider_impl_candidate( ecx: &mut EvalCtxt<'_, D>, goal: Goal>, diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.rs b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.rs index 5a54e8eec91f2..bbf8891790516 100644 --- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.rs +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.rs @@ -1,5 +1,5 @@ //@ compile-flags: -Znext-solver -//@ known-bug: unknown +//@ check-pass #![allow(incomplete_features)] #![feature(const_trait_impl, effects)] diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.stderr deleted file mode 100644 index 35069a5a52fc3..0000000000000 --- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0271]: type mismatch resolving `::Assoc == T` - --> $DIR/assoc-type-const-bound-usage-0.rs:14:5 - | -LL | T::Assoc::func() - | ^^^^^^^^^^^^^^^^ types differ - -error[E0271]: type mismatch resolving `::Assoc == T` - --> $DIR/assoc-type-const-bound-usage-0.rs:18:5 - | -LL | ::Assoc::func() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.stderr index ed9182c733423..b8768bd5541c9 100644 --- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.stderr +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.stderr @@ -6,18 +6,30 @@ LL | #![feature(const_trait_impl, effects, generic_const_exprs)] | = help: remove one of these features -error[E0271]: type mismatch resolving `::Assoc == T` - --> $DIR/assoc-type-const-bound-usage-1.rs:15:44 +error[E0284]: type annotations needed: cannot normalize `unqualified::{constant#0}` + --> $DIR/assoc-type-const-bound-usage-1.rs:15:37 | LL | fn unqualified() -> Type<{ T::Assoc::func() }> { - | ^^^^^^^^^^^^^^^^ types differ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `unqualified::{constant#0}` -error[E0271]: type mismatch resolving `::Assoc == T` - --> $DIR/assoc-type-const-bound-usage-1.rs:19:42 +error[E0284]: type annotations needed: cannot normalize `qualified::{constant#0}` + --> $DIR/assoc-type-const-bound-usage-1.rs:19:35 | LL | fn qualified() -> Type<{ ::Assoc::func() }> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `qualified::{constant#0}` -error: aborting due to 3 previous errors +error[E0284]: type annotations needed: cannot normalize `unqualified::{constant#0}` + --> $DIR/assoc-type-const-bound-usage-1.rs:16:5 + | +LL | Type + | ^^^^ cannot normalize `unqualified::{constant#0}` + +error[E0284]: type annotations needed: cannot normalize `qualified::{constant#0}` + --> $DIR/assoc-type-const-bound-usage-1.rs:20:5 + | +LL | Type + | ^^^^ cannot normalize `qualified::{constant#0}` + +error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs new file mode 100644 index 0000000000000..5e873082781be --- /dev/null +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs @@ -0,0 +1,35 @@ +//@ compile-flags: -Znext-solver + +// Check that `~const` item bounds only hold if the where clauses on the +// associated type are also const. +// i.e. check that we validate the const conditions for the associated type +// when considering one of implied const bounds. + +#![allow(incomplete_features)] +#![feature(const_trait_impl, effects)] + +#[const_trait] +trait Trait { + type Assoc: ~const Trait + where + U: ~const Other; + + fn func(); +} + +#[const_trait] +trait Other {} + +const fn fails() { + T::Assoc::::func(); + //~^ ERROR the trait bound `::Assoc: ~const Trait` is not satisfied + ::Assoc::::func(); + //~^ ERROR the trait bound `::Assoc: ~const Trait` is not satisfied +} + +const fn works() { + T::Assoc::::func(); + ::Assoc::::func(); +} + +fn main() {} diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.stderr new file mode 100644 index 0000000000000..1f6532c7a570e --- /dev/null +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `::Assoc: ~const Trait` is not satisfied + --> $DIR/assoc-type-const-bound-usage-fail-2.rs:24:5 + | +LL | T::Assoc::::func(); + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `::Assoc: ~const Trait` is not satisfied + --> $DIR/assoc-type-const-bound-usage-fail-2.rs:26:5 + | +LL | ::Assoc::::func(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs new file mode 100644 index 0000000000000..73b3d142f7c84 --- /dev/null +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs @@ -0,0 +1,28 @@ +//@ compile-flags: -Znext-solver + +// Check that `~const` item bounds only hold if the parent trait is `~const`. +// i.e. check that we validate the const conditions for the associated type +// when considering one of implied const bounds. + +#![allow(incomplete_features)] +#![feature(const_trait_impl, effects)] + +#[const_trait] +trait Trait { + type Assoc: ~const Trait; + fn func(); +} + +const fn unqualified() { + T::Assoc::func(); + //~^ ERROR the trait bound `T: ~const Trait` is not satisfied + ::Assoc::func(); + //~^ ERROR the trait bound `T: ~const Trait` is not satisfied +} + +const fn works() { + T::Assoc::func(); + ::Assoc::func(); +} + +fn main() {} diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.stderr new file mode 100644 index 0000000000000..fb08e74eb7f41 --- /dev/null +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `T: ~const Trait` is not satisfied + --> $DIR/assoc-type-const-bound-usage-fail.rs:17:5 + | +LL | T::Assoc::func(); + | ^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `T: ~const Trait` is not satisfied + --> $DIR/assoc-type-const-bound-usage-fail.rs:19:5 + | +LL | ::Assoc::func(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`.