Normalize anon consts in new solver
This commit is contained in:
parent
4fbb43e70f
commit
2c1473ca70
@ -227,7 +227,7 @@ pub fn super_combine_consts<R>(
|
|||||||
return self.unify_const_variable(vid, a, relation.param_env());
|
return self.unify_const_variable(vid, a, relation.param_env());
|
||||||
}
|
}
|
||||||
(ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..))
|
(ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..))
|
||||||
if self.tcx.features().generic_const_exprs =>
|
if self.tcx.features().generic_const_exprs || self.tcx.trait_solver_next() =>
|
||||||
{
|
{
|
||||||
relation.register_const_equate_obligation(a, b);
|
relation.register_const_equate_obligation(a, b);
|
||||||
return Ok(b);
|
return Ok(b);
|
||||||
|
@ -772,4 +772,21 @@ pub(super) fn unify_existing_opaque_tys(
|
|||||||
}
|
}
|
||||||
values
|
values
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try to evaluate a const, or return `None` if the const is too generic.
|
||||||
|
// This doesn't mean the const isn't evaluatable, though, and should be treated
|
||||||
|
// as an ambiguity rather than no-solution.
|
||||||
|
pub(super) fn try_const_eval_resolve(
|
||||||
|
&self,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
unevaluated: ty::UnevaluatedConst<'tcx>,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
) -> Option<ty::Const<'tcx>> {
|
||||||
|
use rustc_middle::mir::interpret::ErrorHandled;
|
||||||
|
match self.infcx.try_const_eval_resolve(param_env, unevaluated, ty, None) {
|
||||||
|
Ok(ct) => Some(ct),
|
||||||
|
Err(ErrorHandled::Reported(e)) => Some(self.tcx().const_error(ty, e.into())),
|
||||||
|
Err(ErrorHandled::TooGeneric) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,8 +22,11 @@ pub(super) fn compute_projection_goal(
|
|||||||
&mut self,
|
&mut self,
|
||||||
goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
|
goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> QueryResult<'tcx> {
|
||||||
match goal.predicate.projection_ty.kind(self.tcx()) {
|
let def_id = goal.predicate.def_id();
|
||||||
ty::AliasKind::Projection => {
|
match self.tcx().def_kind(def_id) {
|
||||||
|
DefKind::AssocTy | DefKind::AssocConst => {
|
||||||
|
match self.tcx().associated_item(def_id).container {
|
||||||
|
ty::AssocItemContainer::TraitContainer => {
|
||||||
// To only compute normalization once for each projection we only
|
// To only compute normalization once for each projection we only
|
||||||
// normalize if the expected term is an unconstrained inference variable.
|
// normalize if the expected term is an unconstrained inference variable.
|
||||||
//
|
//
|
||||||
@ -39,8 +42,35 @@ pub(super) fn compute_projection_goal(
|
|||||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::AliasKind::Opaque => self.normalize_opaque_type(goal),
|
ty::AssocItemContainer::ImplContainer => bug!("IATs not supported here yet"),
|
||||||
ty::AliasKind::Inherent => bug!("IATs not supported here yet"),
|
}
|
||||||
|
}
|
||||||
|
DefKind::AnonConst => self.normalize_anon_const(goal),
|
||||||
|
DefKind::OpaqueTy => self.normalize_opaque_type(goal),
|
||||||
|
kind => bug!("uknown DefKind {} in projection goal: {goal:#?}", kind.descr(def_id)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip(self), ret)]
|
||||||
|
fn normalize_anon_const(
|
||||||
|
&mut self,
|
||||||
|
goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>,
|
||||||
|
) -> QueryResult<'tcx> {
|
||||||
|
if let Some(normalized_const) = self.try_const_eval_resolve(
|
||||||
|
goal.param_env,
|
||||||
|
ty::UnevaluatedConst::new(
|
||||||
|
goal.predicate.projection_ty.def_id,
|
||||||
|
goal.predicate.projection_ty.substs,
|
||||||
|
),
|
||||||
|
self.tcx()
|
||||||
|
.type_of(goal.predicate.projection_ty.def_id)
|
||||||
|
.no_bound_vars()
|
||||||
|
.expect("const ty should not rely on other generics"),
|
||||||
|
) {
|
||||||
|
self.eq(goal.param_env, normalized_const, goal.predicate.term.ct().unwrap())?;
|
||||||
|
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
|
} else {
|
||||||
|
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
8
tests/ui/traits/new-solver/array-default.rs
Normal file
8
tests/ui/traits/new-solver/array-default.rs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// compile-flags: -Ztrait-solver=next
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
fn has_default<const N: usize>() where [(); N]: Default {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
has_default::<1>();
|
||||||
|
}
|
@ -1,35 +1,13 @@
|
|||||||
// compile-flags: -Ztrait-solver=next
|
// compile-flags: -Ztrait-solver=next
|
||||||
// check-pass
|
// check-pass
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
struct Foo {
|
struct Foo {
|
||||||
x: i32,
|
x: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MyDefault for Foo {
|
|
||||||
fn my_default() -> Self {
|
|
||||||
Self {
|
|
||||||
x: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trait MyDefault {
|
|
||||||
fn my_default() -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MyDefault for [Foo; 0] {
|
|
||||||
fn my_default() -> Self {
|
|
||||||
[]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl MyDefault for [Foo; 1] {
|
|
||||||
fn my_default() -> Self {
|
|
||||||
[Foo::my_default(); 1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut xs = <[Foo; 1]>::my_default();
|
let mut xs = <[Foo; 1]>::default();
|
||||||
xs[0].x = 1;
|
xs[0].x = 1;
|
||||||
(&mut xs[0]).x = 2;
|
(&mut xs[0]).x = 2;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
error[E0277]: the trait bound `(): Trait<1>` is not satisfied
|
||||||
|
--> $DIR/unevaluated-const-impl-trait-ref.rs:20:13
|
||||||
|
|
|
||||||
|
LL | needs::<1>();
|
||||||
|
| ^ the trait `Trait<1>` is not implemented for `()`
|
||||||
|
|
|
||||||
|
= help: the following other types implement trait `Trait<N>`:
|
||||||
|
<() as Trait<0>>
|
||||||
|
<() as Trait<2>>
|
||||||
|
note: required by a bound in `needs`
|
||||||
|
--> $DIR/unevaluated-const-impl-trait-ref.rs:10:38
|
||||||
|
|
|
||||||
|
LL | fn needs<const N: usize>() where (): Trait<N> {}
|
||||||
|
| ^^^^^^^^ required by this bound in `needs`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
@ -0,0 +1,22 @@
|
|||||||
|
// compile-flags: -Ztrait-solver=next
|
||||||
|
// revisions: works fails
|
||||||
|
//[works] check-pass
|
||||||
|
|
||||||
|
trait Trait<const N: usize> {}
|
||||||
|
|
||||||
|
impl Trait<{ 1 - 1 }> for () {}
|
||||||
|
impl Trait<{ 1 + 1 }> for () {}
|
||||||
|
|
||||||
|
fn needs<const N: usize>() where (): Trait<N> {}
|
||||||
|
|
||||||
|
#[cfg(works)]
|
||||||
|
fn main() {
|
||||||
|
needs::<0>();
|
||||||
|
needs::<2>();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(fails)]
|
||||||
|
fn main() {
|
||||||
|
needs::<1>();
|
||||||
|
//[fails]~^ ERROR the trait bound `(): Trait<1>` is not satisfied
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user