Add support for ~const item bounds

This commit is contained in:
Michael Goulet 2024-10-22 00:00:50 +00:00
parent 1d4a7670d4
commit 3bad5014c9
11 changed files with 191 additions and 25 deletions

View File

@ -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<I, Self>,
alias_ty: ty::AliasTy<I>,
) -> Vec<Candidate<I>>;
fn consider_impl_candidate(
ecx: &mut EvalCtxt<'_, D>,
goal: Goal<I, Self>,
@ -594,6 +603,8 @@ where
));
}
candidates.extend(G::consider_additional_alias_assumptions(self, goal, alias_ty));
if kind != ty::Projection {
return;
}

View File

@ -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<I, Self>,
alias_ty: ty::AliasTy<I>,
) -> Vec<Candidate<I>> {
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<I, Self>,

View File

@ -193,6 +193,14 @@ where
}
}
fn consider_additional_alias_assumptions(
_ecx: &mut EvalCtxt<'_, D>,
_goal: Goal<I, Self>,
_alias_ty: ty::AliasTy<I>,
) -> Vec<Candidate<I>> {
vec![]
}
fn consider_impl_candidate(
ecx: &mut EvalCtxt<'_, D>,
goal: Goal<I, NormalizesTo<I>>,

View File

@ -39,6 +39,14 @@ where
self.def_id()
}
fn consider_additional_alias_assumptions(
_ecx: &mut EvalCtxt<'_, D>,
_goal: Goal<I, Self>,
_alias_ty: ty::AliasTy<I>,
) -> Vec<Candidate<I>> {
vec![]
}
fn consider_impl_candidate(
ecx: &mut EvalCtxt<'_, D>,
goal: Goal<I, TraitPredicate<I>>,

View File

@ -1,5 +1,5 @@
//@ compile-flags: -Znext-solver
//@ known-bug: unknown
//@ check-pass
#![allow(incomplete_features)]
#![feature(const_trait_impl, effects)]

View File

@ -1,15 +0,0 @@
error[E0271]: type mismatch resolving `<T as Trait>::Assoc == T`
--> $DIR/assoc-type-const-bound-usage-0.rs:14:5
|
LL | T::Assoc::func()
| ^^^^^^^^^^^^^^^^ types differ
error[E0271]: type mismatch resolving `<T as Trait>::Assoc == T`
--> $DIR/assoc-type-const-bound-usage-0.rs:18:5
|
LL | <T as Trait>::Assoc::func()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0271`.

View File

@ -6,18 +6,30 @@ LL | #![feature(const_trait_impl, effects, generic_const_exprs)]
|
= help: remove one of these features
error[E0271]: type mismatch resolving `<T as Trait>::Assoc == T`
--> $DIR/assoc-type-const-bound-usage-1.rs:15:44
error[E0284]: type annotations needed: cannot normalize `unqualified<T>::{constant#0}`
--> $DIR/assoc-type-const-bound-usage-1.rs:15:37
|
LL | fn unqualified<T: const Trait>() -> Type<{ T::Assoc::func() }> {
| ^^^^^^^^^^^^^^^^ types differ
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `unqualified<T>::{constant#0}`
error[E0271]: type mismatch resolving `<T as Trait>::Assoc == T`
--> $DIR/assoc-type-const-bound-usage-1.rs:19:42
error[E0284]: type annotations needed: cannot normalize `qualified<T>::{constant#0}`
--> $DIR/assoc-type-const-bound-usage-1.rs:19:35
|
LL | fn qualified<T: const Trait>() -> Type<{ <T as Trait>::Assoc::func() }> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `qualified<T>::{constant#0}`
error: aborting due to 3 previous errors
error[E0284]: type annotations needed: cannot normalize `unqualified<T>::{constant#0}`
--> $DIR/assoc-type-const-bound-usage-1.rs:16:5
|
LL | Type
| ^^^^ cannot normalize `unqualified<T>::{constant#0}`
For more information about this error, try `rustc --explain E0271`.
error[E0284]: type annotations needed: cannot normalize `qualified<T>::{constant#0}`
--> $DIR/assoc-type-const-bound-usage-1.rs:20:5
|
LL | Type
| ^^^^ cannot normalize `qualified<T>::{constant#0}`
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0284`.

View File

@ -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<U>: ~const Trait
where
U: ~const Other;
fn func();
}
#[const_trait]
trait Other {}
const fn fails<T: ~const Trait, U: Other>() {
T::Assoc::<U>::func();
//~^ ERROR the trait bound `<T as Trait>::Assoc<U>: ~const Trait` is not satisfied
<T as Trait>::Assoc::<U>::func();
//~^ ERROR the trait bound `<T as Trait>::Assoc<U>: ~const Trait` is not satisfied
}
const fn works<T: ~const Trait, U: ~const Other>() {
T::Assoc::<U>::func();
<T as Trait>::Assoc::<U>::func();
}
fn main() {}

View File

@ -0,0 +1,15 @@
error[E0277]: the trait bound `<T as Trait>::Assoc<U>: ~const Trait` is not satisfied
--> $DIR/assoc-type-const-bound-usage-fail-2.rs:24:5
|
LL | T::Assoc::<U>::func();
| ^^^^^^^^^^^^^^^^^^^^^
error[E0277]: the trait bound `<T as Trait>::Assoc<U>: ~const Trait` is not satisfied
--> $DIR/assoc-type-const-bound-usage-fail-2.rs:26:5
|
LL | <T as Trait>::Assoc::<U>::func();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@ -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: Trait>() {
T::Assoc::func();
//~^ ERROR the trait bound `T: ~const Trait` is not satisfied
<T as Trait>::Assoc::func();
//~^ ERROR the trait bound `T: ~const Trait` is not satisfied
}
const fn works<T: ~const Trait>() {
T::Assoc::func();
<T as Trait>::Assoc::func();
}
fn main() {}

View File

@ -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 | <T as Trait>::Assoc::func();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.