Skip to content

Commit e4a6b24

Browse files
Rollup merge of #112183 - compiler-errors:new-solver-anon-ct, r=BoxyUwU
Normalize anon consts in new solver We don't do any of that `expand_abstract_consts` stuff so this isn't sufficient to make GCE work, but it does allow, e.g. `[(); 1]: Default`, to solve. r? `@BoxyUwU`
2 parents 5460f92 + 84196f3 commit e4a6b24

File tree

13 files changed

+134
-70
lines changed

13 files changed

+134
-70
lines changed

compiler/rustc_hir_analysis/src/collect/generics_of.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
5050
// We do not allow generic parameters in anon consts if we are inside
5151
// of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
5252
None
53-
} else if tcx.lazy_normalization() {
53+
} else if tcx.features().generic_const_exprs {
5454
let parent_node = tcx.hir().get_parent(hir_id);
5555
if let Node::Variant(Variant { disr_expr: Some(constant), .. }) = parent_node
5656
&& constant.hir_id == hir_id

compiler/rustc_hir_analysis/src/collect/predicates_of.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ pub(super) fn explicit_predicates_of<'tcx>(
463463
}
464464
}
465465
} else {
466-
if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() {
466+
if matches!(def_kind, DefKind::AnonConst) && tcx.features().generic_const_exprs {
467467
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
468468
let parent_def_id = tcx.hir().get_parent_item(hir_id);
469469

compiler/rustc_hir_analysis/src/outlives/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ pub fn provide(providers: &mut Providers) {
2020
fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clause<'_>, Span)] {
2121
let id = tcx.hir().local_def_id_to_hir_id(item_def_id);
2222

23-
if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst) && tcx.lazy_normalization()
23+
if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst)
24+
&& tcx.features().generic_const_exprs
2425
{
2526
if tcx.hir().opt_const_param_default_param_def_id(id).is_some() {
2627
// In `generics_of` we set the generics' parent to be our parent's parent which means that

compiler/rustc_infer/src/infer/combine.rs

+1-1
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.lazy_normalization() =>
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_middle/src/ty/context.rs

-9
Original file line numberDiff line numberDiff line change
@@ -1015,15 +1015,6 @@ impl<'tcx> TyCtxt<'tcx> {
10151015
self.query_system.on_disk_cache.as_ref().map_or(Ok(0), |c| c.serialize(self, encoder))
10161016
}
10171017

1018-
/// If `true`, we should use lazy normalization for constants, otherwise
1019-
/// we still evaluate them eagerly.
1020-
#[inline]
1021-
pub fn lazy_normalization(self) -> bool {
1022-
let features = self.features();
1023-
// Note: We only use lazy normalization for generic const expressions.
1024-
features.generic_const_exprs
1025-
}
1026-
10271018
#[inline]
10281019
pub fn local_crate_exports_generics(self) -> bool {
10291020
debug_assert!(self.sess.opts.share_generics());

compiler/rustc_trait_selection/src/solve/eval_ctxt.rs

+22-2
Original file line numberDiff line numberDiff line change
@@ -322,10 +322,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
322322
ty::PredicateKind::Ambiguous => {
323323
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
324324
}
325-
// FIXME: implement these predicates :)
326-
ty::PredicateKind::ConstEvaluatable(_) | ty::PredicateKind::ConstEquate(_, _) => {
325+
// FIXME: implement this predicate :)
326+
ty::PredicateKind::ConstEvaluatable(_) => {
327327
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
328328
}
329+
ty::PredicateKind::ConstEquate(_, _) => {
330+
bug!("ConstEquate should not be emitted when `-Ztrait-solver=next` is active")
331+
}
329332
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
330333
bug!("TypeWellFormedFromEnv is only used for Chalk")
331334
}
@@ -772,4 +775,21 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
772775
}
773776
values
774777
}
778+
779+
// Try to evaluate a const, or return `None` if the const is too generic.
780+
// This doesn't mean the const isn't evaluatable, though, and should be treated
781+
// as an ambiguity rather than no-solution.
782+
pub(super) fn try_const_eval_resolve(
783+
&self,
784+
param_env: ty::ParamEnv<'tcx>,
785+
unevaluated: ty::UnevaluatedConst<'tcx>,
786+
ty: Ty<'tcx>,
787+
) -> Option<ty::Const<'tcx>> {
788+
use rustc_middle::mir::interpret::ErrorHandled;
789+
match self.infcx.try_const_eval_resolve(param_env, unevaluated, ty, None) {
790+
Ok(ct) => Some(ct),
791+
Err(ErrorHandled::Reported(e)) => Some(self.tcx().const_error(ty, e.into())),
792+
Err(ErrorHandled::TooGeneric) => None,
793+
}
794+
}
775795
}

compiler/rustc_trait_selection/src/solve/fulfill.rs

+2-11
Original file line numberDiff line numberDiff line change
@@ -118,16 +118,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
118118
TypeError::Sorts(expected_found),
119119
)
120120
}
121-
ty::PredicateKind::ConstEquate(a, b) => {
122-
let (a, b) = infcx.instantiate_binder_with_placeholders(
123-
goal.predicate.kind().rebind((a, b)),
124-
);
125-
let expected_found = ExpectedFound::new(true, a, b);
126-
FulfillmentErrorCode::CodeConstEquateError(
127-
expected_found,
128-
TypeError::ConstMismatch(expected_found),
129-
)
130-
}
131121
ty::PredicateKind::Clause(_)
132122
| ty::PredicateKind::WellFormed(_)
133123
| ty::PredicateKind::ObjectSafe(_)
@@ -138,7 +128,8 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
138128
SelectionError::Unimplemented,
139129
)
140130
}
141-
ty::PredicateKind::TypeWellFormedFromEnv(_) => {
131+
ty::PredicateKind::ConstEquate(..)
132+
| ty::PredicateKind::TypeWellFormedFromEnv(_) => {
142133
bug!("unexpected goal: {goal:?}")
143134
}
144135
},

compiler/rustc_trait_selection/src/solve/project_goals.rs

+52-19
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,65 @@ 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 => {
25+
let def_id = goal.predicate.def_id();
26+
match self.tcx().def_kind(def_id) {
27+
DefKind::AssocTy | DefKind::AssocConst => {
2728
// To only compute normalization once for each projection we only
28-
// normalize if the expected term is an unconstrained inference variable.
29+
// assemble normalization candidates if the expected term is an
30+
// unconstrained inference variable.
31+
//
32+
// Why: For better cache hits, since if we have an unconstrained RHS then
33+
// there are only as many cache keys as there are (canonicalized) alias
34+
// types in each normalizes-to goal. This also weakens inference in a
35+
// forwards-compatible way so we don't use the value of the RHS term to
36+
// affect candidate assembly for projections.
2937
//
3038
// E.g. for `<T as Trait>::Assoc == u32` we recursively compute the goal
3139
// `exists<U> <T as Trait>::Assoc == U` and then take the resulting type for
3240
// `U` and equate it with `u32`. This means that we don't need a separate
33-
// projection cache in the solver.
41+
// projection cache in the solver, since we're piggybacking off of regular
42+
// goal caching.
3443
if self.term_is_fully_unconstrained(goal) {
35-
let candidates = self.assemble_and_evaluate_candidates(goal);
36-
self.merge_candidates(candidates)
44+
match self.tcx().associated_item(def_id).container {
45+
ty::AssocItemContainer::TraitContainer => {
46+
let candidates = self.assemble_and_evaluate_candidates(goal);
47+
self.merge_candidates(candidates)
48+
}
49+
ty::AssocItemContainer::ImplContainer => {
50+
bug!("IATs not supported here yet")
51+
}
52+
}
3753
} else {
3854
self.set_normalizes_to_hack_goal(goal);
3955
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
4056
}
4157
}
42-
ty::AliasKind::Opaque => self.normalize_opaque_type(goal),
43-
ty::AliasKind::Inherent => bug!("IATs not supported here yet"),
58+
DefKind::AnonConst => self.normalize_anon_const(goal),
59+
DefKind::OpaqueTy => self.normalize_opaque_type(goal),
60+
kind => bug!("unknown DefKind {} in projection goal: {goal:#?}", kind.descr(def_id)),
61+
}
62+
}
63+
64+
#[instrument(level = "debug", skip(self), ret)]
65+
fn normalize_anon_const(
66+
&mut self,
67+
goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>,
68+
) -> QueryResult<'tcx> {
69+
if let Some(normalized_const) = self.try_const_eval_resolve(
70+
goal.param_env,
71+
ty::UnevaluatedConst::new(
72+
goal.predicate.projection_ty.def_id,
73+
goal.predicate.projection_ty.substs,
74+
),
75+
self.tcx()
76+
.type_of(goal.predicate.projection_ty.def_id)
77+
.no_bound_vars()
78+
.expect("const ty should not rely on other generics"),
79+
) {
80+
self.eq(goal.param_env, normalized_const, goal.predicate.term.ct().unwrap())?;
81+
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
82+
} else {
83+
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
4484
}
4585
}
4686
}
@@ -173,17 +213,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
173213
);
174214

175215
// Finally we construct the actual value of the associated type.
176-
let is_const = matches!(tcx.def_kind(assoc_def.item.def_id), DefKind::AssocConst);
177-
let ty = tcx.type_of(assoc_def.item.def_id);
178-
let term: ty::EarlyBinder<ty::Term<'tcx>> = if is_const {
179-
let identity_substs =
180-
ty::InternalSubsts::identity_for_item(tcx, assoc_def.item.def_id);
181-
let did = assoc_def.item.def_id;
182-
let kind =
183-
ty::ConstKind::Unevaluated(ty::UnevaluatedConst::new(did, identity_substs));
184-
ty.map_bound(|ty| tcx.mk_const(kind, ty).into())
185-
} else {
186-
ty.map_bound(|ty| ty.into())
216+
let term = match assoc_def.item.kind {
217+
ty::AssocKind::Type => tcx.type_of(assoc_def.item.def_id).map_bound(|ty| ty.into()),
218+
ty::AssocKind::Const => bug!("associated const projection is not supported yet"),
219+
ty::AssocKind::Fn => unreachable!("we should never project to a fn"),
187220
};
188221

189222
ecx.eq(goal.param_env, goal.predicate.term, term.subst(tcx, substs))

compiler/rustc_trait_selection/src/traits/project.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,9 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
672672
#[instrument(skip(self), level = "debug")]
673673
fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> {
674674
let tcx = self.selcx.tcx();
675-
if tcx.lazy_normalization() || !needs_normalization(&constant, self.param_env.reveal()) {
675+
if tcx.features().generic_const_exprs
676+
|| !needs_normalization(&constant, self.param_env.reveal())
677+
{
676678
constant
677679
} else {
678680
let constant = constant.super_fold_with(self);
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+
}
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
}
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`.
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)