Skip to content

Commit e613bc9

Browse files
committedJul 18, 2024
const_to_pat: cleanup leftovers from when we had to deal with non-structural constants
1 parent fa74a9e commit e613bc9

16 files changed

+174
-460
lines changed
 

‎Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4411,6 +4411,7 @@ dependencies = [
44114411
name = "rustc_mir_build"
44124412
version = "0.0.0"
44134413
dependencies = [
4414+
"either",
44144415
"itertools",
44154416
"rustc_apfloat",
44164417
"rustc_arena",

‎compiler/rustc_middle/src/ty/consts.rs

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::middle::resolve_bound_vars as rbv;
22
use crate::mir::interpret::{ErrorHandled, LitToConstInput, Scalar};
33
use crate::ty::{self, GenericArgs, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
4+
use either::Either;
45
use rustc_data_structures::intern::Interned;
56
use rustc_error_messages::MultiSpan;
67
use rustc_hir as hir;
@@ -312,14 +313,16 @@ impl<'tcx> Const<'tcx> {
312313
Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize))
313314
}
314315

315-
/// Returns the evaluated constant
316+
/// Returns the evaluated constant as a valtree;
317+
/// if that fails due to a valtree-incompatible type, indicate which type that is
318+
/// by returning `Err(Left(bad_type))`.
316319
#[inline]
317-
pub fn eval(
320+
pub fn eval_valtree(
318321
self,
319322
tcx: TyCtxt<'tcx>,
320323
param_env: ParamEnv<'tcx>,
321324
span: Span,
322-
) -> Result<(Ty<'tcx>, ValTree<'tcx>), ErrorHandled> {
325+
) -> Result<(Ty<'tcx>, ValTree<'tcx>), Either<Ty<'tcx>, ErrorHandled>> {
323326
assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}");
324327
match self.kind() {
325328
ConstKind::Unevaluated(unevaluated) => {
@@ -328,26 +331,47 @@ impl<'tcx> Const<'tcx> {
328331
let (param_env, unevaluated) = unevaluated.prepare_for_eval(tcx, param_env);
329332
// try to resolve e.g. associated constants to their definition on an impl, and then
330333
// evaluate the const.
331-
let Ok(c) = tcx.const_eval_resolve_for_typeck(param_env, unevaluated, span)? else {
332-
// This can happen when we run on ill-typed code.
333-
let e = tcx.dcx().span_delayed_bug(
334-
span,
335-
"`ty::Const::eval` called on a non-valtree-compatible type",
336-
);
337-
return Err(e.into());
338-
};
339-
Ok((tcx.type_of(unevaluated.def).instantiate(tcx, unevaluated.args), c))
334+
match tcx.const_eval_resolve_for_typeck(param_env, unevaluated, span) {
335+
Ok(Ok(c)) => {
336+
Ok((tcx.type_of(unevaluated.def).instantiate(tcx, unevaluated.args), c))
337+
}
338+
Ok(Err(bad_ty)) => Err(Either::Left(bad_ty)),
339+
Err(err) => Err(Either::Right(err.into())),
340+
}
340341
}
341342
ConstKind::Value(ty, val) => Ok((ty, val)),
342-
ConstKind::Error(g) => Err(g.into()),
343+
ConstKind::Error(g) => Err(Either::Right(g.into())),
343344
ConstKind::Param(_)
344345
| ConstKind::Infer(_)
345346
| ConstKind::Bound(_, _)
346347
| ConstKind::Placeholder(_)
347-
| ConstKind::Expr(_) => Err(ErrorHandled::TooGeneric(span)),
348+
| ConstKind::Expr(_) => Err(Either::Right(ErrorHandled::TooGeneric(span))),
348349
}
349350
}
350351

352+
/// Returns the evaluated constant
353+
#[inline]
354+
pub fn eval(
355+
self,
356+
tcx: TyCtxt<'tcx>,
357+
param_env: ParamEnv<'tcx>,
358+
span: Span,
359+
) -> Result<(Ty<'tcx>, ValTree<'tcx>), ErrorHandled> {
360+
self.eval_valtree(tcx, param_env, span).map_err(|err| {
361+
match err {
362+
Either::Right(err) => err,
363+
Either::Left(_bad_ty) => {
364+
// This can happen when we run on ill-typed code.
365+
let e = tcx.dcx().span_delayed_bug(
366+
span,
367+
"`ty::Const::eval` called on a non-valtree-compatible type",
368+
);
369+
e.into()
370+
}
371+
}
372+
})
373+
}
374+
351375
/// Normalizes the constant to a value or an error if possible.
352376
#[inline]
353377
pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {

‎compiler/rustc_mir_build/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ edition = "2021"
55

66
[dependencies]
77
# tidy-alphabetical-start
8+
either = "1.5.0"
89
itertools = "0.12"
910
rustc_apfloat = "0.2.0"
1011
rustc_arena = { path = "../rustc_arena" }

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

Lines changed: 70 additions & 141 deletions
Large diffs are not rendered by default.

‎compiler/rustc_mir_build/src/thir/pattern/mod.rs

Lines changed: 37 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ use rustc_hir::pat_util::EnumerateAndAdjustIterator;
1414
use rustc_hir::{self as hir, ByRef, Mutability, RangeEnd};
1515
use rustc_index::Idx;
1616
use rustc_lint as lint;
17-
use rustc_middle::mir::interpret::{ErrorHandled, GlobalId, LitToConstError, LitToConstInput};
18-
use rustc_middle::mir::{self, Const};
17+
use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
1918
use rustc_middle::thir::{
2019
Ascription, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary,
2120
};
@@ -575,63 +574,39 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
575574
}
576575
};
577576

578-
let cid = GlobalId { instance, promoted: None };
579-
// Prefer valtrees over opaque constants.
580-
let const_value = self
581-
.tcx
582-
.const_eval_global_id_for_typeck(param_env_reveal_all, cid, span)
583-
.map(|val| match val {
584-
Ok(valtree) => mir::Const::Ty(ty, ty::Const::new_value(self.tcx, valtree, ty)),
585-
Err(_) => mir::Const::Val(
586-
self.tcx
587-
.const_eval_global_id(param_env_reveal_all, cid, span)
588-
.expect("const_eval_global_id_for_typeck should have already failed"),
589-
ty,
590-
),
591-
});
592-
593-
match const_value {
594-
Ok(const_) => {
595-
let pattern = self.const_to_pat(const_, id, span);
596-
597-
if !is_associated_const {
598-
return pattern;
599-
}
577+
let c = ty::Const::new_unevaluated(
578+
self.tcx,
579+
ty::UnevaluatedConst { def: instance.def_id(), args: instance.args },
580+
);
600581

601-
let user_provided_types = self.typeck_results().user_provided_types();
602-
if let Some(&user_ty) = user_provided_types.get(id) {
603-
let annotation = CanonicalUserTypeAnnotation {
604-
user_ty: Box::new(user_ty),
605-
span,
606-
inferred_ty: self.typeck_results().node_type(id),
607-
};
608-
Box::new(Pat {
609-
span,
610-
kind: PatKind::AscribeUserType {
611-
subpattern: pattern,
612-
ascription: Ascription {
613-
annotation,
614-
// Note that use `Contravariant` here. See the
615-
// `variance` field documentation for details.
616-
variance: ty::Contravariant,
617-
},
618-
},
619-
ty: const_.ty(),
620-
})
621-
} else {
622-
pattern
623-
}
624-
}
625-
Err(ErrorHandled::TooGeneric(_)) => {
626-
// While `Reported | Linted` cases will have diagnostics emitted already
627-
// it is not true for TooGeneric case, so we need to give user more information.
628-
let e = self.tcx.dcx().emit_err(ConstPatternDependsOnGenericParameter { span });
629-
pat_from_kind(PatKind::Error(e))
630-
}
631-
Err(_) => {
632-
let e = self.tcx.dcx().emit_err(CouldNotEvalConstPattern { span });
633-
pat_from_kind(PatKind::Error(e))
634-
}
582+
let pattern = self.const_to_pat(c, ty, id, span);
583+
584+
if !is_associated_const {
585+
return pattern;
586+
}
587+
588+
let user_provided_types = self.typeck_results().user_provided_types();
589+
if let Some(&user_ty) = user_provided_types.get(id) {
590+
let annotation = CanonicalUserTypeAnnotation {
591+
user_ty: Box::new(user_ty),
592+
span,
593+
inferred_ty: self.typeck_results().node_type(id),
594+
};
595+
Box::new(Pat {
596+
span,
597+
kind: PatKind::AscribeUserType {
598+
subpattern: pattern,
599+
ascription: Ascription {
600+
annotation,
601+
// Note that use `Contravariant` here. See the
602+
// `variance` field documentation for details.
603+
variance: ty::Contravariant,
604+
},
605+
},
606+
ty,
607+
})
608+
} else {
609+
pattern
635610
}
636611
}
637612

@@ -662,7 +637,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
662637
};
663638
if let Some(lit_input) = lit_input {
664639
match tcx.at(expr.span).lit_to_const(lit_input) {
665-
Ok(c) => return self.const_to_pat(Const::Ty(ty, c), id, span).kind,
640+
Ok(c) => return self.const_to_pat(c, ty, id, span).kind,
666641
// If an error occurred, ignore that it's a literal
667642
// and leave reporting the error up to const eval of
668643
// the unevaluated constant below.
@@ -675,32 +650,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
675650
tcx.erase_regions(ty::GenericArgs::identity_for_item(tcx, typeck_root_def_id));
676651
let args = ty::InlineConstArgs::new(tcx, ty::InlineConstArgsParts { parent_args, ty }).args;
677652

678-
let uneval = mir::UnevaluatedConst { def: def_id.to_def_id(), args, promoted: None };
679653
debug_assert!(!args.has_free_regions());
680654

681655
let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args };
682-
// First try using a valtree in order to destructure the constant into a pattern.
683-
// FIXME: replace "try to do a thing, then fall back to another thing"
684-
// but something more principled, like a trait query checking whether this can be turned into a valtree.
685-
if let Ok(Ok(valtree)) = self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, span) {
686-
let subpattern = self.const_to_pat(
687-
Const::Ty(ty, ty::Const::new_value(self.tcx, valtree, ty)),
688-
id,
689-
span,
690-
);
691-
PatKind::InlineConstant { subpattern, def: def_id }
692-
} else {
693-
// If that fails, convert it to an opaque constant pattern.
694-
match tcx.const_eval_resolve(self.param_env, uneval, span) {
695-
Ok(val) => self.const_to_pat(mir::Const::Val(val, ty), id, span).kind,
696-
Err(ErrorHandled::TooGeneric(_)) => {
697-
// If we land here it means the const can't be evaluated because it's `TooGeneric`.
698-
let e = self.tcx.dcx().emit_err(ConstPatternDependsOnGenericParameter { span });
699-
PatKind::Error(e)
700-
}
701-
Err(ErrorHandled::Reported(err, ..)) => PatKind::Error(err.into()),
702-
}
703-
}
656+
let subpattern = self.const_to_pat(ty::Const::new_unevaluated(self.tcx, ct), ty, id, span);
657+
PatKind::InlineConstant { subpattern, def: def_id }
704658
}
705659

706660
/// Converts literals, paths and negation of literals to patterns.
@@ -728,9 +682,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
728682
let ct_ty = self.typeck_results.expr_ty(expr);
729683
let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg };
730684
match self.tcx.at(expr.span).lit_to_const(lit_input) {
731-
Ok(constant) => {
732-
self.const_to_pat(Const::Ty(ct_ty, constant), expr.hir_id, lit.span).kind
733-
}
685+
Ok(constant) => self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind,
734686
Err(LitToConstError::Reported(e)) => PatKind::Error(e),
735687
Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"),
736688
}

‎compiler/rustc_trait_selection/src/traits/mod.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ pub mod query;
1616
#[allow(hidden_glob_reexports)]
1717
mod select;
1818
mod specialize;
19-
mod structural_match;
2019
mod structural_normalize;
2120
#[allow(hidden_glob_reexports)]
2221
mod util;
@@ -60,7 +59,6 @@ pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind;
6059
pub use self::specialize::{
6160
specialization_graph, translate_args, translate_args_with_cause, OverlapError,
6261
};
63-
pub use self::structural_match::search_for_structural_match_violation;
6462
pub use self::structural_normalize::StructurallyNormalizeExt;
6563
pub use self::util::elaborate;
6664
pub use self::util::{expand_trait_aliases, TraitAliasExpander, TraitAliasExpansionInfo};

‎compiler/rustc_trait_selection/src/traits/structural_match.rs

Lines changed: 0 additions & 173 deletions
This file was deleted.

‎tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,20 @@ const BAR_BAZ: Foo = if 42 == 42 {
2323
Foo::Qux(CustomEq) // dead arm
2424
};
2525

26+
const EMPTY: &[CustomEq] = &[];
27+
2628
fn main() {
29+
// BAR_BAZ itself is fine but the enum has other variants
30+
// that are non-structural. Still, this should be accepted.
2731
match Foo::Qux(CustomEq) {
2832
BAR_BAZ => panic!(),
2933
_ => {}
3034
}
35+
36+
// Similarly, an empty slice of a type that is non-structural
37+
// is accepted.
38+
match &[CustomEq] as &[CustomEq] {
39+
EMPTY => panic!(),
40+
_ => {},
41+
}
3142
}

‎tests/ui/consts/const_in_pattern/reject_non_partial_eq.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ fn main() {
2626

2727
match None {
2828
NO_PARTIAL_EQ_NONE => println!("NO_PARTIAL_EQ_NONE"),
29-
//~^ ERROR must be annotated with `#[derive(PartialEq)]`
29+
//~^ ERROR must implement `PartialEq`
3030
_ => panic!("whoops"),
3131
}
3232
}
Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1-
error: to use a constant of type `NoPartialEq` in a pattern, `NoPartialEq` must be annotated with `#[derive(PartialEq)]`
1+
error: to use a constant of type `Option<NoPartialEq>` in a pattern, the type must implement `PartialEq`
22
--> $DIR/reject_non_partial_eq.rs:28:9
33
|
44
LL | NO_PARTIAL_EQ_NONE => println!("NO_PARTIAL_EQ_NONE"),
55
| ^^^^^^^^^^^^^^^^^^
6-
|
7-
= note: the traits must be derived, manual `impl`s are not sufficient
8-
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
96

107
error: aborting due to 1 previous error
118

‎tests/ui/consts/invalid-inline-const-in-match-arm.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ fn main() {
44
match () {
55
const { (|| {})() } => {}
66
//~^ ERROR cannot call non-const closure in constants
7+
//~| ERROR could not evaluate constant pattern
78
}
89
}

‎tests/ui/consts/invalid-inline-const-in-match-arm.stderr

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
1111
LL + #![feature(const_trait_impl)]
1212
|
1313

14-
error: aborting due to 1 previous error
14+
error: could not evaluate constant pattern
15+
--> $DIR/invalid-inline-const-in-match-arm.rs:5:9
16+
|
17+
LL | const { (|| {})() } => {}
18+
| ^^^^^^^^^^^^^^^^^^^
19+
20+
error: aborting due to 2 previous errors
1521

1622
For more information about this error, try `rustc --explain E0015`.

‎tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const A: &[B] = &[];
1313
pub fn main() {
1414
match &[][..] {
1515
A => (),
16-
//~^ ERROR must be annotated with `#[derive(PartialEq)]`
16+
//~^ ERROR must implement `PartialEq`
1717
_ => (),
1818
}
1919
}
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1-
error: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq)]`
1+
error: to use a constant of type `&[B]` in a pattern, the type must implement `PartialEq`
22
--> $DIR/issue-61188-match-slice-forbidden-without-eq.rs:15:9
33
|
44
LL | A => (),
55
| ^
6-
|
7-
= note: the traits must be derived, manual `impl`s are not sufficient
8-
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
96

107
error: aborting due to 1 previous error
118

‎tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,9 @@ fn main() {
2828
// Also cover range patterns
2929
match x {
3030
NAN..=1.0 => {}, //~ ERROR cannot use NaN in patterns
31-
//~^ ERROR lower range bound must be less than or equal to upper
3231
-1.0..=NAN => {}, //~ ERROR cannot use NaN in patterns
33-
//~^ ERROR lower range bound must be less than or equal to upper
3432
NAN.. => {}, //~ ERROR cannot use NaN in patterns
35-
//~^ ERROR lower range bound must be less than or equal to upper
3633
..NAN => {}, //~ ERROR cannot use NaN in patterns
37-
//~^ ERROR lower range bound must be less than upper
3834
_ => {},
3935
};
4036
}

‎tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.stderr

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -34,58 +34,32 @@ LL | NAN..=1.0 => {},
3434
= note: NaNs compare inequal to everything, even themselves, so this pattern would never match
3535
= help: try using the `is_nan` method instead
3636

37-
error[E0030]: lower range bound must be less than or equal to upper
38-
--> $DIR/issue-6804-nan-match.rs:30:9
39-
|
40-
LL | NAN..=1.0 => {},
41-
| ^^^^^^^^^ lower bound larger than upper bound
42-
4337
error: cannot use NaN in patterns
44-
--> $DIR/issue-6804-nan-match.rs:32:16
38+
--> $DIR/issue-6804-nan-match.rs:31:16
4539
|
4640
LL | -1.0..=NAN => {},
4741
| ^^^
4842
|
4943
= note: NaNs compare inequal to everything, even themselves, so this pattern would never match
5044
= help: try using the `is_nan` method instead
5145

52-
error[E0030]: lower range bound must be less than or equal to upper
53-
--> $DIR/issue-6804-nan-match.rs:32:9
54-
|
55-
LL | -1.0..=NAN => {},
56-
| ^^^^^^^^^^ lower bound larger than upper bound
57-
5846
error: cannot use NaN in patterns
59-
--> $DIR/issue-6804-nan-match.rs:34:9
47+
--> $DIR/issue-6804-nan-match.rs:32:9
6048
|
6149
LL | NAN.. => {},
6250
| ^^^
6351
|
6452
= note: NaNs compare inequal to everything, even themselves, so this pattern would never match
6553
= help: try using the `is_nan` method instead
6654

67-
error[E0030]: lower range bound must be less than or equal to upper
68-
--> $DIR/issue-6804-nan-match.rs:34:9
69-
|
70-
LL | NAN.. => {},
71-
| ^^^^^ lower bound larger than upper bound
72-
7355
error: cannot use NaN in patterns
74-
--> $DIR/issue-6804-nan-match.rs:36:11
56+
--> $DIR/issue-6804-nan-match.rs:33:11
7557
|
7658
LL | ..NAN => {},
7759
| ^^^
7860
|
7961
= note: NaNs compare inequal to everything, even themselves, so this pattern would never match
8062
= help: try using the `is_nan` method instead
8163

82-
error[E0579]: lower range bound must be less than upper
83-
--> $DIR/issue-6804-nan-match.rs:36:9
84-
|
85-
LL | ..NAN => {},
86-
| ^^^^^
87-
88-
error: aborting due to 11 previous errors
64+
error: aborting due to 7 previous errors
8965

90-
Some errors have detailed explanations: E0030, E0579.
91-
For more information about an error, try `rustc --explain E0030`.

0 commit comments

Comments
 (0)
Please sign in to comment.