Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 39 additions & 46 deletions compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ 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::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitableExt, TypeVisitor};
use rustc_span::def_id::DefId;
use rustc_span::{DUMMY_SP, Span};
use rustc_trait_selection::traits::ObligationCause;
Expand Down Expand Up @@ -48,7 +46,7 @@ impl<'tcx> PatCtxt<'tcx> {

match c.kind() {
ty::ConstKind::Unevaluated(uv) => convert.unevaluated_to_pat(uv, ty),
ty::ConstKind::Value(cv) => convert.valtree_to_pat(cv.valtree, cv.ty),
ty::ConstKind::Value(value) => convert.valtree_to_pat(value),
_ => span_bug!(span, "Invalid `ConstKind` for `const_to_pat`: {:?}", c),
}
}
Expand Down Expand Up @@ -175,7 +173,7 @@ impl<'tcx> ConstToPat<'tcx> {
};

// Lower the valtree to a THIR pattern.
let mut thir_pat = self.valtree_to_pat(valtree, ty);
let mut thir_pat = self.valtree_to_pat(ty::Value { ty, valtree });

if !thir_pat.references_error() {
// Always check for `PartialEq` if we had no other errors yet.
Expand All @@ -192,31 +190,32 @@ impl<'tcx> ConstToPat<'tcx> {
thir_pat
}

fn field_pats(
fn lower_field_values_to_fieldpats(
&self,
vals: impl Iterator<Item = (ValTree<'tcx>, Ty<'tcx>)>,
values: impl Iterator<Item = ty::Value<'tcx>>,
) -> Vec<FieldPat<'tcx>> {
vals.enumerate()
.map(|(idx, (val, ty))| {
let field = FieldIdx::new(idx);
// Patterns can only use monomorphic types.
let ty = self.tcx.normalize_erasing_regions(self.typing_env, ty);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I simply delete this normalize_erasing_regions and run the ui test suite with no other changes, I get a bunch of failures.

But if I remove the normalization in conjunction with using types from the valtree, everything appears to work. That suggests to me that using the types from the valtree makes the normalization step redundant.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah the types stored in the valtree will come directly from CTFE and are fully normalized (though contain erased regions, but this is fine for THIR building)

FieldPat { field, pattern: *self.valtree_to_pat(val, ty) }
values
.enumerate()
.map(|(index, value)| FieldPat {
field: FieldIdx::new(index),
pattern: *self.valtree_to_pat(value),
})
.collect()
}

// Recursive helper for `to_pat`; invoke that (instead of calling this directly).
// FIXME(valtrees): Accept `ty::Value` instead of `Ty` and `ty::ValTree` separately.
#[instrument(skip(self), level = "debug")]
fn valtree_to_pat(&self, cv: ValTree<'tcx>, ty: Ty<'tcx>) -> Box<Pat<'tcx>> {
fn valtree_to_pat(&self, value: ty::Value<'tcx>) -> Box<Pat<'tcx>> {
let span = self.span;
let tcx = self.tcx;
let ty::Value { ty, valtree } = value;

let kind = match ty.kind() {
// Extremely important check for all ADTs!
// Make sure they are eligible to be used in patterns, and if not, emit an error.
ty::Adt(adt_def, _) if !self.type_marked_structural(ty) => {
// Extremely important check for all ADTs! Make sure they opted-in to be used in
// patterns.
debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty);
// This ADT cannot be used as a constant in patterns.
debug!(?adt_def, ?value.ty, "ADT type in pattern is not `type_marked_structural`");
let PartialEqImplStatus {
is_derived, structural_partial_eq, non_blanket_impl, ..
} = type_has_partial_eq_impl(self.tcx, self.typing_env, ty);
Expand All @@ -239,51 +238,43 @@ impl<'tcx> ConstToPat<'tcx> {
return self.mk_err(tcx.dcx().create_err(err), ty);
}
ty::Adt(adt_def, args) if adt_def.is_enum() => {
let (&variant_index, fields) = cv.to_branch().split_first().unwrap();
let (&variant_index, fields) = valtree.to_branch().split_first().unwrap();
let variant_index = VariantIdx::from_u32(variant_index.to_leaf().to_u32());
PatKind::Variant {
adt_def: *adt_def,
args,
variant_index,
subpatterns: self.field_pats(
fields.iter().map(|ct| ct.to_value().valtree).zip(
adt_def.variants()[variant_index]
.fields
.iter()
.map(|field| field.ty(tcx, args)),
),
),
subpatterns: self
.lower_field_values_to_fieldpats(fields.iter().map(|ct| ct.to_value())),
}
}
ty::Adt(def, args) => {
ty::Adt(def, _) => {
assert!(!def.is_union()); // Valtree construction would never succeed for unions.
PatKind::Leaf {
subpatterns: self.field_pats(
cv.to_branch().iter().map(|ct| ct.to_value().valtree).zip(
def.non_enum_variant().fields.iter().map(|field| field.ty(tcx, args)),
),
subpatterns: self.lower_field_values_to_fieldpats(
valtree.to_branch().iter().map(|ct| ct.to_value()),
),
}
}
ty::Tuple(fields) => PatKind::Leaf {
subpatterns: self.field_pats(
cv.to_branch().iter().map(|ct| ct.to_value().valtree).zip(fields.iter()),
ty::Tuple(_) => PatKind::Leaf {
subpatterns: self.lower_field_values_to_fieldpats(
valtree.to_branch().iter().map(|ct| ct.to_value()),
),
},
ty::Slice(elem_ty) => PatKind::Slice {
prefix: cv
ty::Slice(_) => PatKind::Slice {
prefix: valtree
.to_branch()
.iter()
.map(|val| *self.valtree_to_pat(val.to_value().valtree, *elem_ty))
.map(|val| *self.valtree_to_pat(val.to_value()))
.collect(),
slice: None,
suffix: Box::new([]),
},
ty::Array(elem_ty, _) => PatKind::Array {
prefix: cv
ty::Array(_, _) => PatKind::Array {
prefix: valtree
.to_branch()
.iter()
.map(|val| *self.valtree_to_pat(val.to_value().valtree, *elem_ty))
.map(|val| *self.valtree_to_pat(val.to_value()))
.collect(),
slice: None,
suffix: Box::new([]),
Expand All @@ -296,15 +287,17 @@ impl<'tcx> ConstToPat<'tcx> {
// Under `feature(deref_patterns)`, string literal patterns can also
// have type `str` directly, without the `&`, in order to allow things
// like `deref!("...")` to work when the scrutinee is `String`.
PatKind::Constant { value: ty::Value { ty, valtree: cv } }
PatKind::Constant { value }
}
ty::Ref(_, pointee_ty, ..) => {
if pointee_ty.is_str()
|| pointee_ty.is_slice()
|| pointee_ty.is_sized(tcx, self.typing_env)
{
// References have the same valtree representation as their pointee.
PatKind::Deref { subpattern: self.valtree_to_pat(cv, *pointee_ty) }
PatKind::Deref {
subpattern: self.valtree_to_pat(ty::Value { ty: *pointee_ty, valtree }),
}
} else {
return self.mk_err(
tcx.dcx().create_err(UnsizedPattern { span, non_sm_ty: *pointee_ty }),
Expand All @@ -313,7 +306,7 @@ impl<'tcx> ConstToPat<'tcx> {
}
}
ty::Float(flt) => {
let v = cv.to_leaf();
let v = valtree.to_leaf();
let is_nan = match flt {
ty::FloatTy::F16 => v.to_f16().is_nan(),
ty::FloatTy::F32 => v.to_f32().is_nan(),
Expand All @@ -325,13 +318,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: ty::Value { ty, valtree: cv } }
PatKind::Constant { value }
}
}
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: ty::Value { ty, valtree: cv } }
PatKind::Constant { value }
}
ty::FnPtr(..) => {
unreachable!(
Expand Down
Loading