Rework Fields internals.

Now `Fields` is just a `Vec` of patterns, with some extra info on the
side to reconstruct patterns when needed. This emphasizes that this
extra info is not central to the algorithm.
This commit is contained in:
Nadrieril 2021-09-22 18:16:07 +01:00
parent 87a0a25b38
commit 3175409682
3 changed files with 196 additions and 241 deletions

View File

@ -56,7 +56,7 @@
use rustc_middle::mir::Field;
use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange};
use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::{self, Const, Ty, TyCtxt};
use rustc_middle::ty::{self, Const, Ty, TyCtxt, VariantDef};
use rustc_session::lint;
use rustc_span::{Span, DUMMY_SP};
use rustc_target::abi::{Integer, Size, VariantIdx};
@ -1073,120 +1073,103 @@ pub(super) fn iter_missing<'a, 'p>(
}
}
/// Some fields need to be explicitly hidden away in certain cases; see the comment above the
/// `Fields` struct. This struct represents such a potentially-hidden field.
#[derive(Debug, Copy, Clone)]
pub(super) enum FilteredField<'p, 'tcx> {
Kept(&'p Pat<'tcx>),
Hidden,
}
impl<'p, 'tcx> FilteredField<'p, 'tcx> {
fn kept(self) -> Option<&'p Pat<'tcx>> {
match self {
FilteredField::Kept(p) => Some(p),
FilteredField::Hidden => None,
}
}
}
/// A value can be decomposed into a constructor applied to some fields. This struct represents
/// those fields, generalized to allow patterns in each field. See also `Constructor`.
/// This is constructed from a constructor using [`Fields::wildcards()`].
///
/// If a private or `non_exhaustive` field is uninhabited, the code mustn't observe that it is
/// uninhabited. For that, we filter these fields out of the matrix. This is handled automatically
/// in `Fields`. This filtering is uncommon in practice, because uninhabited fields are rarely used,
/// so we avoid it when possible to preserve performance.
/// This is constructed for a constructor using [`Fields::wildcards()`]. The idea is that
/// [`Fields::wildcards()`] constructs a list of fields where all entries are wildcards, and then
/// given a pattern we fill some of the fields with its subpatterns.
/// In the following example `Fields::wildcards` returns `[_, _, _, _]`. Then in
/// `extract_pattern_arguments` we fill some of the entries, and the result is
/// `[Some(0), _, _, _]`.
/// ```rust
/// let x: [Option<u8>; 4] = foo();
/// match x {
/// [Some(0), ..] => {}
/// }
/// ```
///
/// Note that the number of fields of a constructor may not match the fields declared in the
/// original struct/variant. This happens if a private or `non_exhaustive` field is uninhabited,
/// because the code mustn't observe that it is uninhabited. In that case that field is not
/// included in `fields`. For that reason, when you have a `mir::Field` you must use
/// `index_with_declared_idx`.
#[derive(Debug, Clone)]
pub(super) enum Fields<'p, 'tcx> {
/// Lists of patterns that don't contain any filtered fields.
/// `Slice` and `Vec` behave the same; the difference is only to avoid allocating and
/// triple-dereferences when possible. Frankly this is premature optimization, I (Nadrieril)
/// have not measured if it really made a difference.
Slice(&'p [Pat<'tcx>]),
Vec(SmallVec<[&'p Pat<'tcx>; 2]>),
/// Patterns where some of the fields need to be hidden. For all intents and purposes we only
/// care about the non-hidden fields. We need to keep the real field index for those fields;
/// we're morally storing a `Vec<(usize, &Pat)>` but what we do is more convenient.
/// `len` counts the number of non-hidden fields
Filtered {
fields: SmallVec<[FilteredField<'p, 'tcx>; 2]>,
len: usize,
},
pub(super) struct Fields<'p, 'tcx> {
fields: SmallVec<[&'p Pat<'tcx>; 2]>,
}
impl<'p, 'tcx> Fields<'p, 'tcx> {
/// Internal use. Use `Fields::wildcards()` instead.
/// Must not be used if the pattern is a field of a struct/tuple/variant.
fn from_single_pattern(pat: &'p Pat<'tcx>) -> Self {
Fields::Slice(std::slice::from_ref(pat))
fn empty() -> Self {
Fields { fields: SmallVec::new() }
}
fn from_iter(
cx: &MatchCheckCtxt<'p, 'tcx>,
fields: impl IntoIterator<Item = Pat<'tcx>>,
) -> Self {
let fields: &_ = cx.pattern_arena.alloc_from_iter(fields);
Fields { fields: fields.iter().collect() }
}
/// Convenience; internal use.
fn wildcards_from_tys(
cx: &MatchCheckCtxt<'p, 'tcx>,
tys: impl IntoIterator<Item = Ty<'tcx>>,
) -> Self {
let wilds = tys.into_iter().map(Pat::wildcard_from_ty);
let pats = cx.pattern_arena.alloc_from_iter(wilds);
Fields::Slice(pats)
Fields::from_iter(cx, tys.into_iter().map(Pat::wildcard_from_ty))
}
// In the cases of either a `#[non_exhaustive]` field list or a non-public field, we hide
// uninhabited fields in order not to reveal the uninhabitedness of the whole variant.
// This lists the fields we keep along with their types.
fn list_variant_nonhidden_fields<'a>(
cx: &'a MatchCheckCtxt<'p, 'tcx>,
ty: Ty<'tcx>,
variant: &'a VariantDef,
) -> impl Iterator<Item = (Field, Ty<'tcx>)> + Captures<'a> + Captures<'p> {
let (adt, substs) = match ty.kind() {
ty::Adt(adt, substs) => (adt, substs),
_ => bug!(),
};
// Whether we must not match the fields of this variant exhaustively.
let is_non_exhaustive = variant.is_field_list_non_exhaustive() && !adt.did.is_local();
variant.fields.iter().enumerate().filter_map(move |(i, field)| {
let ty = field.ty(cx.tcx, substs);
let is_visible = adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx);
let is_uninhabited = cx.is_uninhabited(ty);
if is_uninhabited && (!is_visible || is_non_exhaustive) {
None
} else {
Some((Field::new(i), ty))
}
})
}
/// Creates a new list of wildcard fields for a given constructor.
pub(super) fn wildcards(pcx: PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'tcx>) -> Self {
let ty = pcx.ty;
let cx = pcx.cx;
let wildcard_from_ty = |ty| &*cx.pattern_arena.alloc(Pat::wildcard_from_ty(ty));
pub(super) fn wildcards(
cx: &MatchCheckCtxt<'p, 'tcx>,
ty: Ty<'tcx>,
constructor: &Constructor<'tcx>,
) -> Self {
let ret = match constructor {
Single | Variant(_) => match ty.kind() {
ty::Tuple(ref fs) => {
Fields::wildcards_from_tys(cx, fs.into_iter().map(|ty| ty.expect_ty()))
}
ty::Ref(_, rty, _) => Fields::from_single_pattern(wildcard_from_ty(rty)),
ty::Ref(_, rty, _) => Fields::wildcards_from_tys(cx, once(*rty)),
ty::Adt(adt, substs) => {
if adt.is_box() {
// Use T as the sub pattern type of Box<T>.
Fields::from_single_pattern(wildcard_from_ty(substs.type_at(0)))
// FIXME(Nadrieril): This is to make box-patterns work even though `Box` is
// actually a struct with 2 private fields. Hacky.
Fields::wildcards_from_tys(cx, once(substs.type_at(0)))
} else {
let variant = &adt.variants[constructor.variant_index_for_adt(adt)];
// Whether we must not match the fields of this variant exhaustively.
let is_non_exhaustive =
variant.is_field_list_non_exhaustive() && !adt.did.is_local();
let field_tys = variant.fields.iter().map(|field| field.ty(cx.tcx, substs));
// In the following cases, we don't need to filter out any fields. This is
// the vast majority of real cases, since uninhabited fields are uncommon.
let has_no_hidden_fields = (adt.is_enum() && !is_non_exhaustive)
|| !field_tys.clone().any(|ty| cx.is_uninhabited(ty));
if has_no_hidden_fields {
Fields::wildcards_from_tys(cx, field_tys)
} else {
let mut len = 0;
let fields = variant
.fields
.iter()
.map(|field| {
let ty = field.ty(cx.tcx, substs);
let is_visible = adt.is_enum()
|| field.vis.is_accessible_from(cx.module, cx.tcx);
let is_uninhabited = cx.is_uninhabited(ty);
// In the cases of either a `#[non_exhaustive]` field list
// or a non-public field, we hide uninhabited fields in
// order not to reveal the uninhabitedness of the whole
// variant.
if is_uninhabited && (!is_visible || is_non_exhaustive) {
FilteredField::Hidden
} else {
len += 1;
FilteredField::Kept(wildcard_from_ty(ty))
}
})
.collect();
Fields::Filtered { fields, len }
}
let tys = Fields::list_variant_nonhidden_fields(cx, ty, variant)
.map(|(_, ty)| ty);
Fields::wildcards_from_tys(cx, tys)
}
}
_ => bug!("Unexpected type for `Single` constructor: {:?}", ty),
@ -1204,12 +1187,25 @@ pub(super) fn wildcards(pcx: PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'t
| NonExhaustive
| Opaque
| Missing { .. }
| Wildcard => Fields::Slice(&[]),
| Wildcard => Fields::empty(),
};
debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret);
ret
}
/// Returns the number of patterns. This is the same as the arity of the constructor used to
/// construct `self`.
pub(super) fn len(&self) -> usize {
self.fields.len()
}
/// Returns the list of patterns.
pub(super) fn iter_patterns<'a>(
&'a self,
) -> impl Iterator<Item = &'p Pat<'tcx>> + Captures<'a> {
self.fields.iter().copied()
}
/// Apply a constructor to a list of patterns, yielding a new pattern. `self`
/// must have as many elements as this constructor's arity.
///
@ -1229,28 +1225,37 @@ pub(super) fn wildcards(pcx: PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'t
/// returns `Some(false)`
/// ```
pub(super) fn apply(self, pcx: PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>) -> Pat<'tcx> {
let subpatterns_and_indices = self.patterns_and_indices();
let mut subpatterns = subpatterns_and_indices.iter().map(|&(_, p)| p).cloned();
let mut subpatterns = self.iter_patterns().cloned();
let pat = match ctor {
Single | Variant(_) => match pcx.ty.kind() {
ty::Adt(..) | ty::Tuple(..) => {
// We want the real indices here.
let subpatterns = subpatterns_and_indices
.iter()
.map(|&(field, p)| FieldPat { field, pattern: p.clone() })
.collect();
ty::Tuple(..) => PatKind::Leaf {
subpatterns: subpatterns
.enumerate()
.map(|(i, p)| FieldPat { field: Field::new(i), pattern: p })
.collect(),
},
ty::Adt(adt_def, _) if adt_def.is_box() => {
// Without `box_patterns`, the only legal pattern of type `Box` is `_` (outside
// of `std`). So this branch is only reachable when the feature is enabled and
// the pattern is a box pattern.
PatKind::Deref { subpattern: subpatterns.next().unwrap() }
}
ty::Adt(adt, substs) => {
let variant_index = ctor.variant_index_for_adt(adt);
let variant = &adt.variants[variant_index];
let subpatterns =
Fields::list_variant_nonhidden_fields(pcx.cx, pcx.ty, variant)
.zip(subpatterns)
.map(|((field, _ty), pattern)| FieldPat { field, pattern })
.collect();
if let ty::Adt(adt, substs) = pcx.ty.kind() {
if adt.is_enum() {
PatKind::Variant {
adt_def: adt,
substs,
variant_index: ctor.variant_index_for_adt(adt),
subpatterns,
}
} else {
PatKind::Leaf { subpatterns }
if adt.is_enum() {
PatKind::Variant {
adt_def: adt,
substs,
variant_index: ctor.variant_index_for_adt(adt),
subpatterns,
}
} else {
PatKind::Leaf { subpatterns }
@ -1261,8 +1266,7 @@ pub(super) fn apply(self, pcx: PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>)
// literal pattern will never be reported as a non-exhaustiveness witness, so we
// can ignore this issue.
ty::Ref(..) => PatKind::Deref { subpattern: subpatterns.next().unwrap() },
ty::Slice(_) | ty::Array(..) => bug!("bad slice pattern {:?} {:?}", ctor, pcx.ty),
_ => PatKind::Wild,
_ => bug!("unexpected ctor for type {:?} {:?}", ctor, pcx.ty),
},
Slice(slice) => match slice.kind {
FixedLen(_) => {
@ -1303,138 +1307,77 @@ pub(super) fn apply(self, pcx: PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>)
Pat { ty: pcx.ty, span: DUMMY_SP, kind: Box::new(pat) }
}
/// Returns the number of patterns. This is the same as the arity of the constructor used to
/// construct `self`.
pub(super) fn len(&self) -> usize {
match self {
Fields::Slice(pats) => pats.len(),
Fields::Vec(pats) => pats.len(),
Fields::Filtered { len, .. } => *len,
}
}
/// Returns the list of patterns along with the corresponding field indices.
fn patterns_and_indices(&self) -> SmallVec<[(Field, &'p Pat<'tcx>); 2]> {
match self {
Fields::Slice(pats) => {
pats.iter().enumerate().map(|(i, p)| (Field::new(i), p)).collect()
}
Fields::Vec(pats) => {
pats.iter().copied().enumerate().map(|(i, p)| (Field::new(i), p)).collect()
}
Fields::Filtered { fields, .. } => {
// Indices must be relative to the full list of patterns
fields
.iter()
.enumerate()
.filter_map(|(i, p)| Some((Field::new(i), p.kept()?)))
.collect()
}
}
}
/// Returns the list of patterns.
pub(super) fn into_patterns(self) -> SmallVec<[&'p Pat<'tcx>; 2]> {
match self {
Fields::Slice(pats) => pats.iter().collect(),
Fields::Vec(pats) => pats,
Fields::Filtered { fields, .. } => fields.iter().filter_map(|p| p.kept()).collect(),
}
}
/// Overrides some of the fields with the provided patterns. Exactly like
/// `replace_fields_indexed`, except that it takes `FieldPat`s as input.
fn replace_with_fieldpats(
&self,
new_pats: impl IntoIterator<Item = &'p FieldPat<'tcx>>,
) -> Self {
self.replace_fields_indexed(
new_pats.into_iter().map(|pat| (pat.field.index(), &pat.pattern)),
)
}
/// Overrides some of the fields with the provided patterns. This is used when a pattern
/// defines some fields but not all, for example `Foo { field1: Some(_), .. }`: here we start
/// with a `Fields` that is just one wildcard per field of the `Foo` struct, and override the
/// entry corresponding to `field1` with the pattern `Some(_)`. This is also used for slice
/// patterns for the same reason.
fn replace_fields_indexed(
&self,
new_pats: impl IntoIterator<Item = (usize, &'p Pat<'tcx>)>,
) -> Self {
let mut fields = self.clone();
if let Fields::Slice(pats) = fields {
fields = Fields::Vec(pats.iter().collect());
}
match &mut fields {
Fields::Vec(pats) => {
for (i, pat) in new_pats {
if let Some(p) = pats.get_mut(i) {
*p = pat;
}
}
}
Fields::Filtered { fields, .. } => {
for (i, pat) in new_pats {
if let FilteredField::Kept(p) = &mut fields[i] {
*p = pat
}
}
}
Fields::Slice(_) => unreachable!(),
}
fields
}
/// Replaces contained fields with the given list of patterns. There must be `len()` patterns
/// in `pats`.
pub(super) fn replace_fields(
&self,
self,
cx: &MatchCheckCtxt<'p, 'tcx>,
pats: impl IntoIterator<Item = Pat<'tcx>>,
) -> Self {
let pats: &[_] = cx.pattern_arena.alloc_from_iter(pats);
match self {
Fields::Filtered { fields, len } => {
let mut pats = pats.iter();
let mut fields = fields.clone();
for f in &mut fields {
if let FilteredField::Kept(p) = f {
// We take one input pattern for each `Kept` field, in order.
*p = pats.next().unwrap();
}
}
Fields::Filtered { fields, len: *len }
}
_ => Fields::Slice(pats),
}
Self::from_iter(cx, pats)
}
/// Replaces contained fields with the arguments of the given pattern. Only use on a pattern
/// that is compatible with the constructor used to build `self`.
/// This is meant to be used on the result of `Fields::wildcards()`. The idea is that
/// `wildcards` constructs a list of fields where all entries are wildcards, and the pattern
/// provided to this function fills some of the fields with non-wildcards.
/// In the following example `Fields::wildcards` would return `[_, _, _, _]`. If we call
/// `replace_with_pattern_arguments` on it with the pattern, the result will be `[Some(0), _,
/// _, _]`.
/// ```rust
/// let x: [Option<u8>; 4] = foo();
/// match x {
/// [Some(0), ..] => {}
/// }
/// ```
/// This is meant to be used on the result of `Fields::wildcards()`. See the comment above
/// `Fields` for details
/// This is guaranteed to preserve the number of patterns in `self`.
pub(super) fn replace_with_pattern_arguments(&self, pat: &'p Pat<'tcx>) -> Self {
pub(super) fn extract_pattern_arguments(
mut self,
cx: &MatchCheckCtxt<'p, 'tcx>,
pat: &'p Pat<'tcx>,
) -> Self {
match pat.kind.as_ref() {
PatKind::Deref { subpattern } => {
assert_eq!(self.len(), 1);
Fields::from_single_pattern(subpattern)
self.fields[0] = subpattern;
}
PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => {
self.replace_with_fieldpats(subpatterns)
match pat.ty.kind() {
ty::Adt(adt, _) if adt.is_box() => {
// FIXME(Nadrieril): A `Box` can in theory be matched either with `Box(_,
// _)` or a box pattern. As a hack to avoid an ICE with the former, we
// ignore other fields than the first one. This will trigger an error later
// anyway.
// See https://github.com/rust-lang/rust/issues/82772 ,
// explanation: https://github.com/rust-lang/rust/pull/82789#issuecomment-796921977
// The problem is that we can't know from the type whether we'll match
// normally or through box-patterns. We'll have to figure out a proper
// solution when we introduce generalized deref patterns. Also need to
// prevent mixing of those two options.
assert_eq!(self.len(), 1);
let pat = subpatterns.into_iter().find(|pat| pat.field.index() == 0);
if let Some(pat) = pat {
self.fields[0] = &pat.pattern;
}
}
ty::Adt(adt, _) => {
let variant_index = match pat.kind.as_ref() {
PatKind::Leaf { .. } => VariantIdx::new(0),
PatKind::Variant { variant_index, .. } => *variant_index,
_ => bug!(),
};
let variant = &adt.variants[variant_index];
// For each field in the variant, we store the relevant index into `self.fields` if any.
let mut field_id_to_id: Vec<Option<usize>> =
(0..variant.fields.len()).map(|_| None).collect();
for (i, (field, _ty)) in
Fields::list_variant_nonhidden_fields(cx, pat.ty, variant).enumerate()
{
field_id_to_id[field.index()] = Some(i);
}
for pat in subpatterns {
if let Some(i) = field_id_to_id[pat.field.index()] {
self.fields[i] = &pat.pattern;
}
}
}
_ => {
for pat in subpatterns {
self.fields[pat.field.index()] = &pat.pattern;
}
}
}
}
PatKind::Array { prefix, suffix, .. } | PatKind::Slice { prefix, suffix, .. } => {
// Number of subpatterns for the constructor
@ -1445,9 +1388,13 @@ pub(super) fn replace_with_pattern_arguments(&self, pat: &'p Pat<'tcx>) -> Self
let prefix = prefix.iter().enumerate();
let suffix =
suffix.iter().enumerate().map(|(i, p)| (ctor_arity - suffix.len() + i, p));
self.replace_fields_indexed(prefix.chain(suffix))
for (i, pat) in prefix.chain(suffix) {
self.fields[i] = pat
}
}
_ => self.clone(),
}
_ => {}
};
self
}
}

View File

@ -467,11 +467,18 @@ fn expand_or_pat<'a>(&'a self) -> impl Iterator<Item = PatStack<'p, 'tcx>> + Cap
/// fields filled with wild patterns.
///
/// This is roughly the inverse of `Constructor::apply`.
fn pop_head_constructor(&self, ctor_wild_subpatterns: &Fields<'p, 'tcx>) -> PatStack<'p, 'tcx> {
fn pop_head_constructor(
&self,
cx: &MatchCheckCtxt<'p, 'tcx>,
ctor_wild_subpatterns: &Fields<'p, 'tcx>,
) -> PatStack<'p, 'tcx> {
// We pop the head pattern and push the new fields extracted from the arguments of
// `self.head()`.
let mut new_fields =
ctor_wild_subpatterns.replace_with_pattern_arguments(self.head()).into_patterns();
let mut new_fields: SmallVec<[_; 2]> = ctor_wild_subpatterns
.clone()
.extract_pattern_arguments(cx, self.head())
.iter_patterns()
.collect();
new_fields.extend_from_slice(&self.pats[1..]);
PatStack::from_vec(new_fields)
}
@ -559,7 +566,7 @@ fn specialize_constructor(
let mut matrix = Matrix::empty();
for row in &self.patterns {
if ctor.is_covered_by(pcx, row.head_ctor(pcx.cx)) {
let new_row = row.pop_head_constructor(ctor_wild_subpatterns);
let new_row = row.pop_head_constructor(pcx.cx, ctor_wild_subpatterns);
matrix.push(new_row);
}
}
@ -923,7 +930,7 @@ fn apply_constructor(
// Here we don't want the user to try to list all variants, we want them to add
// a wildcard, so we only suggest that.
vec![
Fields::wildcards(pcx, &Constructor::NonExhaustive)
Fields::wildcards(pcx.cx, pcx.ty, &Constructor::NonExhaustive)
.apply(pcx, &Constructor::NonExhaustive),
]
} else {
@ -936,7 +943,8 @@ fn apply_constructor(
split_wildcard
.iter_missing(pcx)
.map(|missing_ctor| {
Fields::wildcards(pcx, missing_ctor).apply(pcx, missing_ctor)
Fields::wildcards(pcx.cx, pcx.ty, missing_ctor)
.apply(pcx, missing_ctor)
})
.collect()
};
@ -1036,7 +1044,7 @@ fn apply_constructor<'p>(
let len = self.0.len();
let arity = ctor_wild_subpatterns.len();
let pats = self.0.drain((len - arity)..).rev();
ctor_wild_subpatterns.replace_fields(pcx.cx, pats).apply(pcx, ctor)
ctor_wild_subpatterns.clone().replace_fields(pcx.cx, pats).apply(pcx, ctor)
};
self.0.push(pat);
@ -1172,10 +1180,10 @@ fn is_useful<'p, 'tcx>(
for ctor in split_ctors {
debug!("specialize({:?})", ctor);
// We cache the result of `Fields::wildcards` because it is used a lot.
let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor);
let ctor_wild_subpatterns = Fields::wildcards(pcx.cx, pcx.ty, &ctor);
let spec_matrix =
start_matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns);
let v = v.pop_head_constructor(&ctor_wild_subpatterns);
let v = v.pop_head_constructor(pcx.cx, &ctor_wild_subpatterns);
let usefulness =
is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false);
let usefulness =
@ -1207,7 +1215,7 @@ fn is_useful<'p, 'tcx>(
// to our lint
.filter(|c| !c.is_non_exhaustive())
.map(|missing_ctor| {
Fields::wildcards(pcx, missing_ctor).apply(pcx, missing_ctor)
Fields::wildcards(pcx.cx, pcx.ty, missing_ctor).apply(pcx, missing_ctor)
})
.collect::<Vec<_>>()
};

View File

@ -1,8 +1,8 @@
error[E0004]: non-exhaustive patterns: `Box(_, _)` not covered
error[E0004]: non-exhaustive patterns: `box _` not covered
--> $DIR/issue-3601.rs:30:44
|
LL | box NodeKind::Element(ed) => match ed.kind {
| ^^^^^^^ pattern `Box(_, _)` not covered
| ^^^^^^^ pattern `box _` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `Box<ElementKind>`