Skip to content

Commit 2ad3bd4

Browse files
authored
Rollup merge of #157660 - Shourya742:2026-06-08-add-type-const-evaluation, r=BoxyUwU
normalize instead of evaluating type const patterns closes: #156409 Fixes: rust-lang/project-const-generics#116 r? @BoxyUwU
2 parents fcfdcb8 + d1fadce commit 2ad3bd4

4 files changed

Lines changed: 141 additions & 60 deletions

File tree

compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs

Lines changed: 82 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ use rustc_infer::traits::Obligation;
1212
use rustc_middle::mir::interpret::ErrorHandled;
1313
use rustc_middle::span_bug;
1414
use rustc_middle::thir::{FieldPat, Pat, PatKind};
15-
use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitableExt, TypeVisitor};
15+
use rustc_middle::ty::{
16+
self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitableExt, TypeVisitor, Unnormalized,
17+
};
1618
use rustc_span::def_id::DefId;
1719
use rustc_span::{DUMMY_SP, Span};
1820
use rustc_trait_selection::traits::ObligationCause;
@@ -106,72 +108,92 @@ impl<'tcx> ConstToPat<'tcx> {
106108
self.tcx.erase_and_anonymize_regions(self.typing_env).with_codegen_normalized(self.tcx);
107109
let uv = self.tcx.erase_and_anonymize_regions(uv);
108110

109-
// try to resolve e.g. associated constants to their definition on an impl, and then
110-
// evaluate the const.
111-
let valtree = match self.tcx.const_eval_resolve_for_typeck(typing_env, uv, self.span) {
112-
Ok(Ok(c)) => c,
113-
Err(ErrorHandled::Reported(_, _)) => {
114-
// Let's tell the use where this failing const occurs.
115-
let mut err =
116-
self.tcx.dcx().create_err(CouldNotEvalConstPattern { span: self.span });
117-
// We've emitted an error on the original const, it would be redundant to complain
118-
// on its use as well.
119-
if let ty::ConstKind::Unevaluated(uv) = self.c.kind()
120-
&& let ty::UnevaluatedConstKind::Projection { .. }
121-
| ty::UnevaluatedConstKind::Inherent { .. }
122-
| ty::UnevaluatedConstKind::Free { .. } = uv.kind
123-
{
124-
err.downgrade_to_delayed_bug();
125-
}
111+
// FIXME(gca): This will become insufficient once associated constants can be
112+
// implemented as `type` consts (project-const-generics#76). At that point it'll
113+
// become necessary to just use type system normalization for all const patterns
114+
// but that's not yet possible.
115+
let mut thir_pat = if uv.kind.is_type_const(self.tcx) {
116+
let Ok(normalize) = self
117+
.tcx
118+
.try_normalize_erasing_regions(self.typing_env, Unnormalized::new_wip(self.c))
119+
else {
120+
let err = self.tcx.dcx().create_err(CouldNotEvalConstPattern { span: self.span });
126121
return self.mk_err(err, ty);
127-
}
128-
Err(ErrorHandled::TooGeneric(_)) => {
129-
let mut e = self
130-
.tcx
131-
.dcx()
132-
.create_err(ConstPatternDependsOnGenericParameter { span: self.span });
133-
for arg in uv.args {
134-
if let ty::GenericArgKind::Type(ty) = arg.kind()
135-
&& let ty::Param(param_ty) = ty.kind()
122+
};
123+
124+
let ty::ConstKind::Value(value) = normalize.kind() else {
125+
let err = self.tcx.dcx().create_err(CouldNotEvalConstPattern { span: self.span });
126+
return self.mk_err(err, ty);
127+
};
128+
self.valtree_to_pat(value)
129+
} else {
130+
// try to resolve e.g. associated constants to their definition on an impl, and then
131+
// evaluate the const.
132+
let valtree = match self.tcx.const_eval_resolve_for_typeck(typing_env, uv, self.span) {
133+
Ok(Ok(c)) => c,
134+
Err(ErrorHandled::Reported(_, _)) => {
135+
// Let's tell the use where this failing const occurs.
136+
let mut err =
137+
self.tcx.dcx().create_err(CouldNotEvalConstPattern { span: self.span });
138+
// We've emitted an error on the original const, it would be redundant to complain
139+
// on its use as well.
140+
if let ty::ConstKind::Unevaluated(uv) = self.c.kind()
141+
&& let ty::UnevaluatedConstKind::Projection { .. }
142+
| ty::UnevaluatedConstKind::Inherent { .. }
143+
| ty::UnevaluatedConstKind::Free { .. } = uv.kind
136144
{
137-
let def_id = self.tcx.hir_enclosing_body_owner(self.id);
138-
let generics = self.tcx.generics_of(def_id);
139-
let param = generics.type_param(*param_ty, self.tcx);
140-
let span = self.tcx.def_span(param.def_id);
141-
e.span_label(span, "constant depends on this generic parameter");
142-
if let Some(ident) = self.tcx.def_ident_span(def_id)
143-
&& self.tcx.sess.source_map().is_multiline(ident.between(span))
145+
err.downgrade_to_delayed_bug();
146+
}
147+
return self.mk_err(err, ty);
148+
}
149+
Err(ErrorHandled::TooGeneric(_)) => {
150+
let mut e = self
151+
.tcx
152+
.dcx()
153+
.create_err(ConstPatternDependsOnGenericParameter { span: self.span });
154+
for arg in uv.args {
155+
if let ty::GenericArgKind::Type(ty) = arg.kind()
156+
&& let ty::Param(param_ty) = ty.kind()
144157
{
145-
// Display the `fn` name as well in the diagnostic, as the generic isn't
146-
// in the same line and it could be confusing otherwise.
147-
e.span_label(ident, "");
158+
let def_id = self.tcx.hir_enclosing_body_owner(self.id);
159+
let generics = self.tcx.generics_of(def_id);
160+
let param = generics.type_param(*param_ty, self.tcx);
161+
let span = self.tcx.def_span(param.def_id);
162+
e.span_label(span, "constant depends on this generic parameter");
163+
if let Some(ident) = self.tcx.def_ident_span(def_id)
164+
&& self.tcx.sess.source_map().is_multiline(ident.between(span))
165+
{
166+
// Display the `fn` name as well in the diagnostic, as the generic isn't
167+
// in the same line and it could be confusing otherwise.
168+
e.span_label(ident, "");
169+
}
148170
}
149171
}
172+
return self.mk_err(e, ty);
150173
}
151-
return self.mk_err(e, ty);
152-
}
153-
Ok(Err(bad_ty)) => {
154-
// The pattern cannot be turned into a valtree.
155-
let e = match bad_ty.kind() {
156-
ty::Adt(def, ..) => {
157-
assert!(def.is_union());
158-
self.tcx.dcx().create_err(UnionPattern { span: self.span })
159-
}
160-
ty::FnPtr(..) | ty::RawPtr(..) => {
161-
self.tcx.dcx().create_err(PointerPattern { span: self.span })
162-
}
163-
_ => self.tcx.dcx().create_err(InvalidPattern {
164-
span: self.span,
165-
non_sm_ty: bad_ty,
166-
prefix: bad_ty.prefix_string(self.tcx).to_string(),
167-
}),
168-
};
169-
return self.mk_err(e, ty);
170-
}
171-
};
174+
Ok(Err(bad_ty)) => {
175+
// The pattern cannot be turned into a valtree.
176+
let e = match bad_ty.kind() {
177+
ty::Adt(def, ..) => {
178+
assert!(def.is_union());
179+
self.tcx.dcx().create_err(UnionPattern { span: self.span })
180+
}
181+
ty::FnPtr(..) | ty::RawPtr(..) => {
182+
self.tcx.dcx().create_err(PointerPattern { span: self.span })
183+
}
184+
_ => self.tcx.dcx().create_err(InvalidPattern {
185+
span: self.span,
186+
non_sm_ty: bad_ty,
187+
prefix: bad_ty.prefix_string(self.tcx).to_string(),
188+
}),
189+
};
190+
return self.mk_err(e, ty);
191+
}
192+
};
172193

173-
// Lower the valtree to a THIR pattern.
174-
let mut thir_pat = self.valtree_to_pat(ty::Value { ty, valtree });
194+
// Lower the valtree to a THIR pattern.
195+
self.valtree_to_pat(ty::Value { ty, valtree })
196+
};
175197

176198
if !thir_pat.references_error() {
177199
// Always check for `PartialEq` if we had no other errors yet.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//@ check-pass
2+
#![feature(min_generic_const_args)]
3+
#![expect(incomplete_features)]
4+
#![allow(irrefutable_let_patterns)]
5+
6+
type const CONST: usize = 1_usize;
7+
8+
struct Inherent;
9+
10+
impl Inherent {
11+
type const BAR: usize = 1_usize;
12+
}
13+
14+
trait Trait {
15+
type const BAZ: usize;
16+
}
17+
18+
struct Assoc;
19+
20+
impl Trait for Assoc {
21+
type const BAZ: usize = 1_usize;
22+
}
23+
24+
fn main() {
25+
if let CONST = 1 {}
26+
if let Inherent::BAR = 1 {}
27+
if let <Assoc as Trait>::BAZ = 1 {}
28+
29+
match CONST {
30+
CONST => 0,
31+
_ => 1,
32+
};
33+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#![feature(min_generic_const_args)]
2+
#![expect(incomplete_features)]
3+
4+
trait Trait {
5+
type const ASSOC: usize;
6+
}
7+
8+
fn test<T: Trait>() {
9+
if let <T as Trait>::ASSOC = 1 {}
10+
//~^ ERROR could not evaluate constant pattern
11+
}
12+
13+
fn main() {}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error: could not evaluate constant pattern
2+
--> $DIR/type_const_in_pattern_too_generic.rs:9:12
3+
|
4+
LL | trait Trait {
5+
| -----------
6+
LL | type const ASSOC: usize;
7+
| ----------------------- constant defined here
8+
...
9+
LL | if let <T as Trait>::ASSOC = 1 {}
10+
| ^^^^^^^^^^^^^^^^^^^ could not evaluate constant
11+
12+
error: aborting due to 1 previous error
13+

0 commit comments

Comments
 (0)