Skip to content

Commit 2c1473c

Browse files
Normalize anon consts in new solver
1 parent 4fbb43e commit 2c1473c

File tree

7 files changed

+115
-42
lines changed

7 files changed

+115
-42
lines changed

compiler/rustc_infer/src/infer/combine.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ impl<'tcx> InferCtxt<'tcx> {
227227
return self.unify_const_variable(vid, a, relation.param_env());
228228
}
229229
(ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..))
230-
if self.tcx.features().generic_const_exprs =>
230+
if self.tcx.features().generic_const_exprs || self.tcx.trait_solver_next() =>
231231
{
232232
relation.register_const_equate_obligation(a, b);
233233
return Ok(b);

compiler/rustc_trait_selection/src/solve/eval_ctxt.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -772,4 +772,21 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
772772
}
773773
values
774774
}
775+
776+
// Try to evaluate a const, or return `None` if the const is too generic.
777+
// This doesn't mean the const isn't evaluatable, though, and should be treated
778+
// as an ambiguity rather than no-solution.
779+
pub(super) fn try_const_eval_resolve(
780+
&self,
781+
param_env: ty::ParamEnv<'tcx>,
782+
unevaluated: ty::UnevaluatedConst<'tcx>,
783+
ty: Ty<'tcx>,
784+
) -> Option<ty::Const<'tcx>> {
785+
use rustc_middle::mir::interpret::ErrorHandled;
786+
match self.infcx.try_const_eval_resolve(param_env, unevaluated, ty, None) {
787+
Ok(ct) => Some(ct),
788+
Err(ErrorHandled::Reported(e)) => Some(self.tcx().const_error(ty, e.into())),
789+
Err(ErrorHandled::TooGeneric) => None,
790+
}
791+
}
775792
}

compiler/rustc_trait_selection/src/solve/project_goals.rs

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,55 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
2222
&mut self,
2323
goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
2424
) -> QueryResult<'tcx> {
25-
match goal.predicate.projection_ty.kind(self.tcx()) {
26-
ty::AliasKind::Projection => {
27-
// To only compute normalization once for each projection we only
28-
// normalize if the expected term is an unconstrained inference variable.
29-
//
30-
// E.g. for `<T as Trait>::Assoc == u32` we recursively compute the goal
31-
// `exists<U> <T as Trait>::Assoc == U` and then take the resulting type for
32-
// `U` and equate it with `u32`. This means that we don't need a separate
33-
// projection cache in the solver.
34-
if self.term_is_fully_unconstrained(goal) {
35-
let candidates = self.assemble_and_evaluate_candidates(goal);
36-
self.merge_candidates(candidates)
37-
} else {
38-
self.set_normalizes_to_hack_goal(goal);
39-
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
25+
let def_id = goal.predicate.def_id();
26+
match self.tcx().def_kind(def_id) {
27+
DefKind::AssocTy | DefKind::AssocConst => {
28+
match self.tcx().associated_item(def_id).container {
29+
ty::AssocItemContainer::TraitContainer => {
30+
// To only compute normalization once for each projection we only
31+
// normalize if the expected term is an unconstrained inference variable.
32+
//
33+
// E.g. for `<T as Trait>::Assoc == u32` we recursively compute the goal
34+
// `exists<U> <T as Trait>::Assoc == U` and then take the resulting type for
35+
// `U` and equate it with `u32`. This means that we don't need a separate
36+
// projection cache in the solver.
37+
if self.term_is_fully_unconstrained(goal) {
38+
let candidates = self.assemble_and_evaluate_candidates(goal);
39+
self.merge_candidates(candidates)
40+
} else {
41+
self.set_normalizes_to_hack_goal(goal);
42+
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
43+
}
44+
}
45+
ty::AssocItemContainer::ImplContainer => bug!("IATs not supported here yet"),
4046
}
4147
}
42-
ty::AliasKind::Opaque => self.normalize_opaque_type(goal),
43-
ty::AliasKind::Inherent => bug!("IATs not supported here yet"),
48+
DefKind::AnonConst => self.normalize_anon_const(goal),
49+
DefKind::OpaqueTy => self.normalize_opaque_type(goal),
50+
kind => bug!("uknown DefKind {} in projection goal: {goal:#?}", kind.descr(def_id)),
51+
}
52+
}
53+
54+
#[instrument(level = "debug", skip(self), ret)]
55+
fn normalize_anon_const(
56+
&mut self,
57+
goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>,
58+
) -> QueryResult<'tcx> {
59+
if let Some(normalized_const) = self.try_const_eval_resolve(
60+
goal.param_env,
61+
ty::UnevaluatedConst::new(
62+
goal.predicate.projection_ty.def_id,
63+
goal.predicate.projection_ty.substs,
64+
),
65+
self.tcx()
66+
.type_of(goal.predicate.projection_ty.def_id)
67+
.no_bound_vars()
68+
.expect("const ty should not rely on other generics"),
69+
) {
70+
self.eq(goal.param_env, normalized_const, goal.predicate.term.ct().unwrap())?;
71+
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
72+
} else {
73+
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
4474
}
4575
}
4676
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// compile-flags: -Ztrait-solver=next
2+
// check-pass
3+
4+
fn has_default<const N: usize>() where [(); N]: Default {}
5+
6+
fn main() {
7+
has_default::<1>();
8+
}
Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,13 @@
11
// compile-flags: -Ztrait-solver=next
22
// check-pass
33

4+
#[derive(Default)]
45
struct Foo {
56
x: i32,
67
}
78

8-
impl MyDefault for Foo {
9-
fn my_default() -> Self {
10-
Self {
11-
x: 0,
12-
}
13-
}
14-
}
15-
16-
trait MyDefault {
17-
fn my_default() -> Self;
18-
}
19-
20-
impl MyDefault for [Foo; 0] {
21-
fn my_default() -> Self {
22-
[]
23-
}
24-
}
25-
impl MyDefault for [Foo; 1] {
26-
fn my_default() -> Self {
27-
[Foo::my_default(); 1]
28-
}
29-
}
30-
319
fn main() {
32-
let mut xs = <[Foo; 1]>::my_default();
10+
let mut xs = <[Foo; 1]>::default();
3311
xs[0].x = 1;
3412
(&mut xs[0]).x = 2;
3513
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error[E0277]: the trait bound `(): Trait<1>` is not satisfied
2+
--> $DIR/unevaluated-const-impl-trait-ref.rs:20:13
3+
|
4+
LL | needs::<1>();
5+
| ^ the trait `Trait<1>` is not implemented for `()`
6+
|
7+
= help: the following other types implement trait `Trait<N>`:
8+
<() as Trait<0>>
9+
<() as Trait<2>>
10+
note: required by a bound in `needs`
11+
--> $DIR/unevaluated-const-impl-trait-ref.rs:10:38
12+
|
13+
LL | fn needs<const N: usize>() where (): Trait<N> {}
14+
| ^^^^^^^^ required by this bound in `needs`
15+
16+
error: aborting due to previous error
17+
18+
For more information about this error, try `rustc --explain E0277`.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// compile-flags: -Ztrait-solver=next
2+
// revisions: works fails
3+
//[works] check-pass
4+
5+
trait Trait<const N: usize> {}
6+
7+
impl Trait<{ 1 - 1 }> for () {}
8+
impl Trait<{ 1 + 1 }> for () {}
9+
10+
fn needs<const N: usize>() where (): Trait<N> {}
11+
12+
#[cfg(works)]
13+
fn main() {
14+
needs::<0>();
15+
needs::<2>();
16+
}
17+
18+
#[cfg(fails)]
19+
fn main() {
20+
needs::<1>();
21+
//[fails]~^ ERROR the trait bound `(): Trait<1>` is not satisfied
22+
}

0 commit comments

Comments
 (0)