Skip to content

Commit 762d254

Browse files
authored
Rollup merge of #105339 - BoxyUwU:wf_ct_kind_expr, r=TaKO8Ki
support `ConstKind::Expr` in `is_const_evaluatable` and `WfPredicates::compute` Fixes #105205 Currently we haven't implemented a way to evaluate `ConstKind::Expr(Expr::Binop(Add, 1, 2))` so I just left that with a `FIXME` and a `delay_span_bug` since I have no idea how to do that and it would make this a much larger (and more complicated) PR :P
2 parents e29a510 + c9bab74 commit 762d254

File tree

4 files changed

+99
-20
lines changed

4 files changed

+99
-20
lines changed

compiler/rustc_trait_selection/src/traits/const_evaluatable.rs

+40-18
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,13 @@ use crate::traits::ObligationCtxt;
2525
#[instrument(skip(infcx), level = "debug")]
2626
pub fn is_const_evaluatable<'tcx>(
2727
infcx: &InferCtxt<'tcx>,
28-
ct: ty::Const<'tcx>,
28+
unexpanded_ct: ty::Const<'tcx>,
2929
param_env: ty::ParamEnv<'tcx>,
3030
span: Span,
3131
) -> Result<(), NotConstEvaluatable> {
3232
let tcx = infcx.tcx;
33-
let uv = match ct.kind() {
34-
ty::ConstKind::Unevaluated(uv) => uv,
35-
// FIXME(generic_const_exprs): this seems wrong but I couldn't find a way to get this to trigger
36-
ty::ConstKind::Expr(_) => bug!("unexpected expr in `is_const_evaluatable: {ct:?}"),
33+
match unexpanded_ct.kind() {
34+
ty::ConstKind::Unevaluated(_) | ty::ConstKind::Expr(_) => (),
3735
ty::ConstKind::Param(_)
3836
| ty::ConstKind::Bound(_, _)
3937
| ty::ConstKind::Placeholder(_)
@@ -43,7 +41,7 @@ pub fn is_const_evaluatable<'tcx>(
4341
};
4442

4543
if tcx.features().generic_const_exprs {
46-
let ct = tcx.expand_abstract_consts(ct);
44+
let ct = tcx.expand_abstract_consts(unexpanded_ct);
4745

4846
let is_anon_ct = if let ty::ConstKind::Unevaluated(uv) = ct.kind() {
4947
tcx.def_kind(uv.def.did) == DefKind::AnonConst
@@ -62,18 +60,40 @@ pub fn is_const_evaluatable<'tcx>(
6260
}
6361
}
6462

65-
let concrete = infcx.const_eval_resolve(param_env, uv, Some(span));
66-
match concrete {
67-
Err(ErrorHandled::TooGeneric) => Err(NotConstEvaluatable::Error(
68-
infcx
69-
.tcx
70-
.sess
71-
.delay_span_bug(span, "Missing value for constant, but no error reported?"),
72-
)),
73-
Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
74-
Ok(_) => Ok(()),
63+
match unexpanded_ct.kind() {
64+
ty::ConstKind::Expr(_) => {
65+
// FIXME(generic_const_exprs): we have a `ConstKind::Expr` which is fully concrete, but
66+
// currently it is not possible to evaluate `ConstKind::Expr` so we are unable to tell if it
67+
// is evaluatable or not. For now we just ICE until this is implemented this.
68+
Err(NotConstEvaluatable::Error(tcx.sess.delay_span_bug(
69+
span,
70+
"evaluating `ConstKind::Expr` is not currently supported",
71+
)))
72+
}
73+
ty::ConstKind::Unevaluated(uv) => {
74+
let concrete = infcx.const_eval_resolve(param_env, uv, Some(span));
75+
match concrete {
76+
Err(ErrorHandled::TooGeneric) => {
77+
Err(NotConstEvaluatable::Error(infcx.tcx.sess.delay_span_bug(
78+
span,
79+
"Missing value for constant, but no error reported?",
80+
)))
81+
}
82+
Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
83+
Ok(_) => Ok(()),
84+
}
85+
}
86+
_ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"),
7587
}
7688
} else {
89+
let uv = match unexpanded_ct.kind() {
90+
ty::ConstKind::Unevaluated(uv) => uv,
91+
ty::ConstKind::Expr(_) => {
92+
bug!("`ConstKind::Expr` without `feature(generic_const_exprs)` enabled")
93+
}
94+
_ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"),
95+
};
96+
7797
// FIXME: We should only try to evaluate a given constant here if it is fully concrete
7898
// as we don't want to allow things like `[u8; std::mem::size_of::<*mut T>()]`.
7999
//
@@ -92,7 +112,7 @@ pub fn is_const_evaluatable<'tcx>(
92112
&& satisfied_from_param_env(
93113
tcx,
94114
infcx,
95-
tcx.expand_abstract_consts(ct),
115+
tcx.expand_abstract_consts(unexpanded_ct),
96116
param_env,
97117
) =>
98118
{
@@ -152,6 +172,7 @@ fn satisfied_from_param_env<'tcx>(
152172
impl<'a, 'tcx> TypeVisitor<'tcx> for Visitor<'a, 'tcx> {
153173
type BreakTy = ();
154174
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
175+
debug!("is_const_evaluatable: candidate={:?}", c);
155176
if let Ok(()) = self.infcx.commit_if_ok(|_| {
156177
let ocx = ObligationCtxt::new_in_snapshot(self.infcx);
157178
if let Ok(()) = ocx.eq(&ObligationCause::dummy(), self.param_env, c.ty(), self.ct.ty())
@@ -187,13 +208,14 @@ fn satisfied_from_param_env<'tcx>(
187208
let result = b_ct.visit_with(&mut v);
188209

189210
if let ControlFlow::Break(()) = result {
190-
debug!("is_const_evaluatable: abstract_const ~~> ok");
211+
debug!("is_const_evaluatable: yes");
191212
return true;
192213
}
193214
}
194215
_ => {} // don't care
195216
}
196217
}
197218

219+
debug!("is_const_evaluatable: no");
198220
false
199221
}

compiler/rustc_trait_selection/src/traits/wf.rs

+17-2
Original file line numberDiff line numberDiff line change
@@ -476,9 +476,24 @@ impl<'tcx> WfPredicates<'tcx> {
476476
ty::Binder::dummy(ty::PredicateKind::WellFormed(ct.into())),
477477
));
478478
}
479-
// FIXME(generic_const_exprs): This seems wrong but I could not find a way to get this to trigger
480479
ty::ConstKind::Expr(_) => {
481-
bug!("checking wfness of `ConstKind::Expr` is unsupported")
480+
// FIXME(generic_const_exprs): this doesnt verify that given `Expr(N + 1)` the
481+
// trait bound `typeof(N): Add<typeof(1)>` holds. This is currently unnecessary
482+
// as `ConstKind::Expr` is only produced via normalization of `ConstKind::Unevaluated`
483+
// which means that the `DefId` would have been typeck'd elsewhere. However in
484+
// the future we may allow directly lowering to `ConstKind::Expr` in which case
485+
// we would not be proving bounds we should.
486+
487+
let predicate =
488+
ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct));
489+
let cause = self.cause(traits::WellFormed(None));
490+
self.out.push(traits::Obligation::with_depth(
491+
self.tcx(),
492+
cause,
493+
self.recursion_depth,
494+
self.param_env,
495+
predicate,
496+
));
482497
}
483498

484499
ty::ConstKind::Error(_)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#![feature(generic_const_exprs, generic_arg_infer)]
2+
#![allow(incomplete_features)]
3+
4+
// minimized repro for #105205
5+
//
6+
// the `foo::<_, L>` call results in a `WellFormed(_)` obligation and a
7+
// `ConstEvaluatable(Unevaluated(_ + 1 + L))` obligation. Attempting to fulfill the latter
8+
// unifies the `_` with `Expr(L - 1)` from the paramenv which turns the `WellFormed`
9+
// obligation into `WellFormed(Expr(L - 1))`
10+
11+
fn foo<const N: usize, const M: usize>(_: [(); N + 1 + M]) {}
12+
13+
fn ice<const L: usize>()
14+
where
15+
[(); (L - 1) + 1 + L]:,
16+
{
17+
foo::<_, L>([(); L + 1 + L]);
18+
//~^ ERROR: mismatched types
19+
//~^^ ERROR: unconstrained generic constant
20+
}
21+
22+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/wf_obligation.rs:17:17
3+
|
4+
LL | foo::<_, L>([(); L + 1 + L]);
5+
| ^^^^^^^^^^^^^^^ expected `N + 1 + M`, found `L + 1 + L`
6+
|
7+
= note: expected constant `N + 1 + M`
8+
found constant `L + 1 + L`
9+
10+
error: unconstrained generic constant
11+
--> $DIR/wf_obligation.rs:17:22
12+
|
13+
LL | foo::<_, L>([(); L + 1 + L]);
14+
| ^^^^^^^^^
15+
|
16+
= help: try adding a `where` bound using this expression: `where [(); L + 1 + L]:`
17+
18+
error: aborting due to 2 previous errors
19+
20+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)