PatKind: store constants as valtrees
This commit is contained in:
parent
2c1ac85679
commit
3f1e99dca4
11 changed files with 68 additions and 78 deletions
|
|
@ -832,17 +832,20 @@ pub enum PatKind<'tcx> {
|
|||
},
|
||||
|
||||
/// One of the following:
|
||||
/// * `&str` (represented as a valtree), which will be handled as a string pattern and thus
|
||||
/// * `&str`, which will be handled as a string pattern and thus
|
||||
/// exhaustiveness checking will detect if you use the same string twice in different
|
||||
/// patterns.
|
||||
/// * integer, bool, char or float (represented as a valtree), which will be handled by
|
||||
/// * integer, bool, char or float, which will be handled by
|
||||
/// exhaustiveness to cover exactly its own value, similar to `&str`, but these values are
|
||||
/// much simpler.
|
||||
/// * raw pointers derived from integers, other raw pointers will have already resulted in an
|
||||
// error.
|
||||
/// * `String`, if `string_deref_patterns` is enabled.
|
||||
Constant {
|
||||
value: mir::Const<'tcx>,
|
||||
// Not using `ty::Value` since this is conceptually not a type-level constant. In
|
||||
// particular, it can have raw pointers.
|
||||
ty: Ty<'tcx>,
|
||||
value: ty::ValTree<'tcx>,
|
||||
},
|
||||
|
||||
/// Pattern obtained by converting a constant (inline or named) to its pattern
|
||||
|
|
|
|||
|
|
@ -265,7 +265,7 @@ pub(crate) fn for_each_immediate_subpat<'a, 'tcx>(
|
|||
PatKind::Missing
|
||||
| PatKind::Wild
|
||||
| PatKind::Binding { subpattern: None, .. }
|
||||
| PatKind::Constant { value: _ }
|
||||
| PatKind::Constant { .. }
|
||||
| PatKind::Range(_)
|
||||
| PatKind::Never
|
||||
| PatKind::Error(_) => {}
|
||||
|
|
|
|||
|
|
@ -146,9 +146,9 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
|
|||
for arm in rest {
|
||||
let arm = &self.thir[*arm];
|
||||
let value = match arm.pattern.kind {
|
||||
PatKind::Constant { value } => value,
|
||||
PatKind::Constant { value, .. } => value,
|
||||
PatKind::ExpandedConstant { ref subpattern, def_id: _ }
|
||||
if let PatKind::Constant { value } = subpattern.kind =>
|
||||
if let PatKind::Constant { value, .. } = subpattern.kind =>
|
||||
{
|
||||
value
|
||||
}
|
||||
|
|
@ -160,7 +160,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
|
|||
});
|
||||
}
|
||||
};
|
||||
values.push(value.eval_bits(self.tcx, self.typing_env));
|
||||
values.push(value.unwrap_leaf().to_bits_unchecked());
|
||||
targets.push(self.parse_block(arm.body)?);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -146,7 +146,11 @@ impl<'tcx> MatchPairTree<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
PatKind::Constant { value } => Some(TestCase::Constant { value }),
|
||||
PatKind::Constant { ty: value_ty, value } => {
|
||||
// FIXME: `TestCase::Constant` should probably represent that it is always a `ValTree`.
|
||||
let value = Const::Ty(value_ty, ty::Const::new_value(cx.tcx, value, value_ty));
|
||||
Some(TestCase::Constant { value })
|
||||
}
|
||||
|
||||
PatKind::AscribeUserType {
|
||||
ascription: Ascription { ref annotation, variance },
|
||||
|
|
|
|||
|
|
@ -1321,7 +1321,7 @@ enum TestKind<'tcx> {
|
|||
value: Const<'tcx>,
|
||||
// Integer types are handled by `SwitchInt`, and constants with ADT
|
||||
// types and `&[T]` types are converted back into patterns, so this can
|
||||
// only be `&str`, `f32` or `f64`.
|
||||
// only be `&str` or `f*`.
|
||||
ty: Ty<'tcx>,
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -11,11 +11,11 @@ use rustc_index::Idx;
|
|||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_infer::traits::Obligation;
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::thir::{FieldPat, Pat, PatKind};
|
||||
use rustc_middle::ty::{
|
||||
self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitableExt, TypeVisitor, ValTree,
|
||||
};
|
||||
use rustc_middle::{mir, span_bug};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
use rustc_trait_selection::traits::ObligationCause;
|
||||
|
|
@ -288,16 +288,12 @@ impl<'tcx> ConstToPat<'tcx> {
|
|||
// when lowering to MIR in `Builder::perform_test`, treat the constant as a `&str`.
|
||||
// This works because `str` and `&str` have the same valtree representation.
|
||||
let ref_str_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty);
|
||||
PatKind::Constant {
|
||||
value: mir::Const::Ty(ref_str_ty, ty::Const::new_value(tcx, cv, ref_str_ty)),
|
||||
}
|
||||
PatKind::Constant { ty: ref_str_ty, value: cv }
|
||||
}
|
||||
ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() {
|
||||
// `&str` is represented as a valtree, let's keep using this
|
||||
// optimization for now.
|
||||
ty::Str => PatKind::Constant {
|
||||
value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)),
|
||||
},
|
||||
ty::Str => PatKind::Constant { ty, value: cv },
|
||||
// All other references are converted into deref patterns and then recursively
|
||||
// convert the dereferenced constant to a pattern that is the sub-pattern of the
|
||||
// deref pattern.
|
||||
|
|
@ -326,15 +322,13 @@ impl<'tcx> ConstToPat<'tcx> {
|
|||
// Also see <https://github.com/rust-lang/rfcs/pull/3535>.
|
||||
return self.mk_err(tcx.dcx().create_err(NaNPattern { span }), ty);
|
||||
} else {
|
||||
PatKind::Constant {
|
||||
value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)),
|
||||
}
|
||||
PatKind::Constant { ty, value: cv }
|
||||
}
|
||||
}
|
||||
ty::Pat(..) | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => {
|
||||
// The raw pointers we see here have been "vetted" by valtree construction to be
|
||||
// just integers, so we simply allow them.
|
||||
PatKind::Constant { value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)) }
|
||||
PatKind::Constant { ty, value: cv }
|
||||
}
|
||||
ty::FnPtr(..) => {
|
||||
unreachable!(
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ use rustc_middle::thir::{
|
|||
use rustc_middle::ty::adjustment::{PatAdjust, PatAdjustment};
|
||||
use rustc_middle::ty::layout::IntegerExt;
|
||||
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, TypingMode};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_middle::{bug, mir, span_bug};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::{ErrorGuaranteed, Span};
|
||||
use tracing::{debug, instrument};
|
||||
|
|
@ -156,12 +156,15 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
// The unpeeled kind should now be a constant, giving us the endpoint value.
|
||||
let PatKind::Constant { value } = kind else {
|
||||
let PatKind::Constant { ty, value } = kind else {
|
||||
let msg =
|
||||
format!("found bad range pattern endpoint `{expr:?}` outside of error recovery");
|
||||
return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg));
|
||||
};
|
||||
|
||||
// FIXME: `Finite` should probably take a `ValTree` or even a `ScalarInt`
|
||||
// (but it should also be the same type as what `TestCase::Constant` uses, or at least
|
||||
// easy to convert).
|
||||
let value = mir::Const::Ty(ty, ty::Const::new_value(self.tcx, value, ty));
|
||||
Ok(Some(PatRangeBoundary::Finite(value)))
|
||||
}
|
||||
|
||||
|
|
@ -244,7 +247,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
(RangeEnd::Included, Some(Ordering::Less)) => {}
|
||||
// `x..=y` where `x == y` and `x` and `y` are finite.
|
||||
(RangeEnd::Included, Some(Ordering::Equal)) if lo.is_finite() && hi.is_finite() => {
|
||||
kind = PatKind::Constant { value: lo.as_finite().unwrap() };
|
||||
// FIXME: silly conversion because not all pattern stuff uses valtrees yet.
|
||||
let mir::Const::Ty(ty, val) = lo.as_finite().unwrap() else { unreachable!() };
|
||||
kind = PatKind::Constant { ty, value: val.to_value().valtree };
|
||||
}
|
||||
// `..=x` where `x == ty::MIN`.
|
||||
(RangeEnd::Included, Some(Ordering::Equal)) if !lo.is_finite() => {}
|
||||
|
|
|
|||
|
|
@ -761,7 +761,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
|
|||
self.print_pat(subpattern, depth_lvl + 2);
|
||||
print_indented!(self, "}", depth_lvl + 1);
|
||||
}
|
||||
PatKind::Constant { value } => {
|
||||
PatKind::Constant { value, ty: _ } => {
|
||||
print_indented!(self, "Constant {", depth_lvl + 1);
|
||||
print_indented!(self, format!("value: {:?}", value), depth_lvl + 2);
|
||||
print_indented!(self, "}", depth_lvl + 1);
|
||||
|
|
|
|||
|
|
@ -517,78 +517,57 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
|
|||
),
|
||||
}
|
||||
}
|
||||
PatKind::Constant { value } => {
|
||||
PatKind::Constant { ty: value_ty, value } => {
|
||||
match ty.kind() {
|
||||
ty::Bool => {
|
||||
ctor = match value.try_eval_bool(cx.tcx, cx.typing_env) {
|
||||
Some(b) => Bool(b),
|
||||
None => Opaque(OpaqueId::new()),
|
||||
};
|
||||
ctor = Bool(value.unwrap_leaf().try_to_bool().unwrap());
|
||||
fields = vec![];
|
||||
arity = 0;
|
||||
}
|
||||
ty::Char | ty::Int(_) | ty::Uint(_) => {
|
||||
ctor = match value.try_eval_bits(cx.tcx, cx.typing_env) {
|
||||
Some(bits) => {
|
||||
let x = match *ty.kind() {
|
||||
ty::Int(ity) => {
|
||||
let size = Integer::from_int_ty(&cx.tcx, ity).size().bits();
|
||||
MaybeInfiniteInt::new_finite_int(bits, size)
|
||||
}
|
||||
_ => MaybeInfiniteInt::new_finite_uint(bits),
|
||||
};
|
||||
IntRange(IntRange::from_singleton(x))
|
||||
}
|
||||
None => Opaque(OpaqueId::new()),
|
||||
ctor = {
|
||||
let bits = value.unwrap_leaf().to_bits_unchecked();
|
||||
let x = match *ty.kind() {
|
||||
ty::Int(ity) => {
|
||||
let size = Integer::from_int_ty(&cx.tcx, ity).size().bits();
|
||||
MaybeInfiniteInt::new_finite_int(bits, size)
|
||||
}
|
||||
_ => MaybeInfiniteInt::new_finite_uint(bits),
|
||||
};
|
||||
IntRange(IntRange::from_singleton(x))
|
||||
};
|
||||
fields = vec![];
|
||||
arity = 0;
|
||||
}
|
||||
ty::Float(ty::FloatTy::F16) => {
|
||||
ctor = match value.try_eval_bits(cx.tcx, cx.typing_env) {
|
||||
Some(bits) => {
|
||||
use rustc_apfloat::Float;
|
||||
let value = rustc_apfloat::ieee::Half::from_bits(bits);
|
||||
F16Range(value, value, RangeEnd::Included)
|
||||
}
|
||||
None => Opaque(OpaqueId::new()),
|
||||
};
|
||||
use rustc_apfloat::Float;
|
||||
let bits = value.unwrap_leaf().to_u16();
|
||||
let value = rustc_apfloat::ieee::Half::from_bits(bits.into());
|
||||
ctor = F16Range(value, value, RangeEnd::Included);
|
||||
fields = vec![];
|
||||
arity = 0;
|
||||
}
|
||||
ty::Float(ty::FloatTy::F32) => {
|
||||
ctor = match value.try_eval_bits(cx.tcx, cx.typing_env) {
|
||||
Some(bits) => {
|
||||
use rustc_apfloat::Float;
|
||||
let value = rustc_apfloat::ieee::Single::from_bits(bits);
|
||||
F32Range(value, value, RangeEnd::Included)
|
||||
}
|
||||
None => Opaque(OpaqueId::new()),
|
||||
};
|
||||
use rustc_apfloat::Float;
|
||||
let bits = value.unwrap_leaf().to_u32();
|
||||
let value = rustc_apfloat::ieee::Single::from_bits(bits.into());
|
||||
ctor = F32Range(value, value, RangeEnd::Included);
|
||||
fields = vec![];
|
||||
arity = 0;
|
||||
}
|
||||
ty::Float(ty::FloatTy::F64) => {
|
||||
ctor = match value.try_eval_bits(cx.tcx, cx.typing_env) {
|
||||
Some(bits) => {
|
||||
use rustc_apfloat::Float;
|
||||
let value = rustc_apfloat::ieee::Double::from_bits(bits);
|
||||
F64Range(value, value, RangeEnd::Included)
|
||||
}
|
||||
None => Opaque(OpaqueId::new()),
|
||||
};
|
||||
use rustc_apfloat::Float;
|
||||
let bits = value.unwrap_leaf().to_u64();
|
||||
let value = rustc_apfloat::ieee::Double::from_bits(bits.into());
|
||||
ctor = F64Range(value, value, RangeEnd::Included);
|
||||
fields = vec![];
|
||||
arity = 0;
|
||||
}
|
||||
ty::Float(ty::FloatTy::F128) => {
|
||||
ctor = match value.try_eval_bits(cx.tcx, cx.typing_env) {
|
||||
Some(bits) => {
|
||||
use rustc_apfloat::Float;
|
||||
let value = rustc_apfloat::ieee::Quad::from_bits(bits);
|
||||
F128Range(value, value, RangeEnd::Included)
|
||||
}
|
||||
None => Opaque(OpaqueId::new()),
|
||||
};
|
||||
use rustc_apfloat::Float;
|
||||
let bits = value.unwrap_leaf().to_u128();
|
||||
let value = rustc_apfloat::ieee::Quad::from_bits(bits);
|
||||
ctor = F128Range(value, value, RangeEnd::Included);
|
||||
fields = vec![];
|
||||
arity = 0;
|
||||
}
|
||||
|
|
@ -601,7 +580,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
|
|||
// subfields.
|
||||
// Note: `t` is `str`, not `&str`.
|
||||
let ty = self.reveal_opaque_ty(*t);
|
||||
let subpattern = DeconstructedPat::new(Str(*value), Vec::new(), 0, ty, pat);
|
||||
// FIXME: why does `Str` need a `mir::Value`?
|
||||
let val = mir::Const::Ty(
|
||||
*value_ty,
|
||||
ty::Const::new_value(self.tcx, *value, *value_ty),
|
||||
);
|
||||
let subpattern = DeconstructedPat::new(Str(val), Vec::new(), 0, ty, pat);
|
||||
ctor = Ref;
|
||||
fields = vec![subpattern.at_index(0)];
|
||||
arity = 1;
|
||||
|
|
|
|||
|
|
@ -375,7 +375,7 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> {
|
|||
}
|
||||
|
||||
match pat.kind {
|
||||
thir::PatKind::Constant { value } => value.has_non_region_param(),
|
||||
thir::PatKind::Constant { value, .. } => value.has_non_region_param(),
|
||||
thir::PatKind::Range(ref range) => {
|
||||
let &thir::PatRange { lo, hi, .. } = range.as_ref();
|
||||
lo.has_non_region_param() || hi.has_non_region_param()
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ body:
|
|||
span: $DIR/thir-tree-loop-match.rs:12:17: 12:21 (#0)
|
||||
kind: PatKind {
|
||||
Constant {
|
||||
value: Ty(bool, true)
|
||||
value: Leaf(0x01)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -219,7 +219,7 @@ body:
|
|||
span: $DIR/thir-tree-loop-match.rs:16:17: 16:22 (#0)
|
||||
kind: PatKind {
|
||||
Constant {
|
||||
value: Ty(bool, false)
|
||||
value: Leaf(0x00)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue