Populate pattern bindings/ascriptions while building MatchPairTree
This commit is contained in:
parent
281455add7
commit
ef44273838
3 changed files with 100 additions and 46 deletions
|
@ -6,7 +6,7 @@ use rustc_middle::ty::{self, Ty, TypeVisitableExt};
|
||||||
|
|
||||||
use crate::builder::Builder;
|
use crate::builder::Builder;
|
||||||
use crate::builder::expr::as_place::{PlaceBase, PlaceBuilder};
|
use crate::builder::expr::as_place::{PlaceBase, PlaceBuilder};
|
||||||
use crate::builder::matches::{FlatPat, MatchPairTree, TestCase};
|
use crate::builder::matches::{FlatPat, MatchPairTree, PatternExtraData, TestCase};
|
||||||
|
|
||||||
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
/// Builds and pushes [`MatchPairTree`] subtrees, one for each pattern in
|
/// Builds and pushes [`MatchPairTree`] subtrees, one for each pattern in
|
||||||
|
@ -17,12 +17,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
fn field_match_pairs(
|
fn field_match_pairs(
|
||||||
&mut self,
|
&mut self,
|
||||||
match_pairs: &mut Vec<MatchPairTree<'tcx>>,
|
match_pairs: &mut Vec<MatchPairTree<'tcx>>,
|
||||||
|
extra_data: &mut PatternExtraData<'tcx>,
|
||||||
place: PlaceBuilder<'tcx>,
|
place: PlaceBuilder<'tcx>,
|
||||||
subpatterns: &[FieldPat<'tcx>],
|
subpatterns: &[FieldPat<'tcx>],
|
||||||
) {
|
) {
|
||||||
for fieldpat in subpatterns {
|
for fieldpat in subpatterns {
|
||||||
let place = place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty));
|
let place = place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty));
|
||||||
MatchPairTree::for_pattern(place, &fieldpat.pattern, self, match_pairs);
|
MatchPairTree::for_pattern(place, &fieldpat.pattern, self, match_pairs, extra_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +34,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
fn prefix_slice_suffix(
|
fn prefix_slice_suffix(
|
||||||
&mut self,
|
&mut self,
|
||||||
match_pairs: &mut Vec<MatchPairTree<'tcx>>,
|
match_pairs: &mut Vec<MatchPairTree<'tcx>>,
|
||||||
|
extra_data: &mut PatternExtraData<'tcx>,
|
||||||
place: &PlaceBuilder<'tcx>,
|
place: &PlaceBuilder<'tcx>,
|
||||||
prefix: &[Pat<'tcx>],
|
prefix: &[Pat<'tcx>],
|
||||||
opt_slice: &Option<Box<Pat<'tcx>>>,
|
opt_slice: &Option<Box<Pat<'tcx>>>,
|
||||||
|
@ -57,7 +59,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
let elem =
|
let elem =
|
||||||
ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false };
|
ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false };
|
||||||
let place = place.clone_project(elem);
|
let place = place.clone_project(elem);
|
||||||
MatchPairTree::for_pattern(place, subpattern, self, match_pairs);
|
MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(subslice_pat) = opt_slice {
|
if let Some(subslice_pat) = opt_slice {
|
||||||
|
@ -67,7 +69,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
to: if exact_size { min_length - suffix_len } else { suffix_len },
|
to: if exact_size { min_length - suffix_len } else { suffix_len },
|
||||||
from_end: !exact_size,
|
from_end: !exact_size,
|
||||||
});
|
});
|
||||||
MatchPairTree::for_pattern(subslice, subslice_pat, self, match_pairs);
|
MatchPairTree::for_pattern(subslice, subslice_pat, self, match_pairs, extra_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (idx, subpattern) in suffix.iter().rev().enumerate() {
|
for (idx, subpattern) in suffix.iter().rev().enumerate() {
|
||||||
|
@ -78,7 +80,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
from_end: !exact_size,
|
from_end: !exact_size,
|
||||||
};
|
};
|
||||||
let place = place.clone_project(elem);
|
let place = place.clone_project(elem);
|
||||||
MatchPairTree::for_pattern(place, subpattern, self, match_pairs);
|
MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,11 +88,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
impl<'tcx> MatchPairTree<'tcx> {
|
impl<'tcx> MatchPairTree<'tcx> {
|
||||||
/// Recursively builds a match pair tree for the given pattern and its
|
/// Recursively builds a match pair tree for the given pattern and its
|
||||||
/// subpatterns.
|
/// subpatterns.
|
||||||
pub(in crate::builder) fn for_pattern(
|
pub(super) fn for_pattern(
|
||||||
mut place_builder: PlaceBuilder<'tcx>,
|
mut place_builder: PlaceBuilder<'tcx>,
|
||||||
pattern: &Pat<'tcx>,
|
pattern: &Pat<'tcx>,
|
||||||
cx: &mut Builder<'_, 'tcx>,
|
cx: &mut Builder<'_, 'tcx>,
|
||||||
match_pairs: &mut Vec<Self>, // Newly-created nodes are added to this vector
|
match_pairs: &mut Vec<Self>, // Newly-created nodes are added to this vector
|
||||||
|
extra_data: &mut PatternExtraData<'tcx>, // Bindings/ascriptions are added here
|
||||||
) {
|
) {
|
||||||
// Force the place type to the pattern's type.
|
// Force the place type to the pattern's type.
|
||||||
// FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
|
// FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
|
||||||
|
@ -113,7 +116,7 @@ impl<'tcx> MatchPairTree<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let place = place_builder.try_to_place(cx);
|
let place = place_builder.try_to_place(cx);
|
||||||
let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None };
|
let default_irrefutable = || TestCase::Irrefutable {};
|
||||||
let mut subpairs = Vec::new();
|
let mut subpairs = Vec::new();
|
||||||
let test_case = match pattern.kind {
|
let test_case = match pattern.kind {
|
||||||
PatKind::Wild | PatKind::Error(_) => default_irrefutable(),
|
PatKind::Wild | PatKind::Error(_) => default_irrefutable(),
|
||||||
|
@ -137,39 +140,77 @@ impl<'tcx> MatchPairTree<'tcx> {
|
||||||
ref subpattern,
|
ref subpattern,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
// Apply the type ascription to the value at `match_pair.place`
|
MatchPairTree::for_pattern(
|
||||||
let ascription = place.map(|source| super::Ascription {
|
place_builder,
|
||||||
annotation: annotation.clone(),
|
subpattern,
|
||||||
source,
|
cx,
|
||||||
variance,
|
&mut subpairs,
|
||||||
});
|
extra_data,
|
||||||
|
);
|
||||||
|
|
||||||
MatchPairTree::for_pattern(place_builder, subpattern, cx, &mut subpairs);
|
// Apply the type ascription to the value at `match_pair.place`
|
||||||
TestCase::Irrefutable { ascription, binding: None }
|
if let Some(source) = place {
|
||||||
|
let annotation = annotation.clone();
|
||||||
|
extra_data.ascriptions.push(super::Ascription { source, annotation, variance });
|
||||||
|
}
|
||||||
|
|
||||||
|
default_irrefutable()
|
||||||
}
|
}
|
||||||
|
|
||||||
PatKind::Binding { mode, var, ref subpattern, .. } => {
|
PatKind::Binding { mode, var, ref subpattern, .. } => {
|
||||||
let binding = place.map(|source| super::Binding {
|
// In order to please the borrow checker, when lowering a pattern
|
||||||
span: pattern.span,
|
// like `x @ subpat` we must establish any bindings in `subpat`
|
||||||
source,
|
// before establishing the binding for `x`.
|
||||||
var_id: var,
|
//
|
||||||
binding_mode: mode,
|
// For example (from #69971):
|
||||||
});
|
//
|
||||||
|
// ```ignore (illustrative)
|
||||||
|
// struct NonCopyStruct {
|
||||||
|
// copy_field: u32,
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fn foo1(x: NonCopyStruct) {
|
||||||
|
// let y @ NonCopyStruct { copy_field: z } = x;
|
||||||
|
// // the above should turn into
|
||||||
|
// let z = x.copy_field;
|
||||||
|
// let y = x;
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
|
||||||
|
// First, recurse into the subpattern, if any.
|
||||||
if let Some(subpattern) = subpattern.as_ref() {
|
if let Some(subpattern) = subpattern.as_ref() {
|
||||||
// this is the `x @ P` case; have to keep matching against `P` now
|
// this is the `x @ P` case; have to keep matching against `P` now
|
||||||
MatchPairTree::for_pattern(place_builder, subpattern, cx, &mut subpairs);
|
MatchPairTree::for_pattern(
|
||||||
|
place_builder,
|
||||||
|
subpattern,
|
||||||
|
cx,
|
||||||
|
&mut subpairs,
|
||||||
|
extra_data,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
TestCase::Irrefutable { ascription: None, binding }
|
|
||||||
|
// Then push this binding, after any bindings in the subpattern.
|
||||||
|
if let Some(source) = place {
|
||||||
|
extra_data.bindings.push(super::Binding {
|
||||||
|
span: pattern.span,
|
||||||
|
source,
|
||||||
|
var_id: var,
|
||||||
|
binding_mode: mode,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
default_irrefutable()
|
||||||
}
|
}
|
||||||
|
|
||||||
PatKind::ExpandedConstant { subpattern: ref pattern, def_id: _, is_inline: false } => {
|
PatKind::ExpandedConstant { subpattern: ref pattern, def_id: _, is_inline: false } => {
|
||||||
MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs);
|
MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs, extra_data);
|
||||||
default_irrefutable()
|
default_irrefutable()
|
||||||
}
|
}
|
||||||
PatKind::ExpandedConstant { subpattern: ref pattern, def_id, is_inline: true } => {
|
PatKind::ExpandedConstant { subpattern: ref pattern, def_id, is_inline: true } => {
|
||||||
|
MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs, extra_data);
|
||||||
|
|
||||||
// Apply a type ascription for the inline constant to the value at `match_pair.place`
|
// Apply a type ascription for the inline constant to the value at `match_pair.place`
|
||||||
let ascription = place.map(|source| {
|
if let Some(source) = place {
|
||||||
let span = pattern.span;
|
let span = pattern.span;
|
||||||
let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id());
|
let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id());
|
||||||
let args = ty::InlineConstArgs::new(
|
let args = ty::InlineConstArgs::new(
|
||||||
|
@ -188,19 +229,33 @@ impl<'tcx> MatchPairTree<'tcx> {
|
||||||
span,
|
span,
|
||||||
user_ty: Box::new(user_ty),
|
user_ty: Box::new(user_ty),
|
||||||
};
|
};
|
||||||
super::Ascription { annotation, source, variance: ty::Contravariant }
|
let variance = ty::Contravariant;
|
||||||
});
|
extra_data.ascriptions.push(super::Ascription { annotation, source, variance });
|
||||||
|
}
|
||||||
|
|
||||||
MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs);
|
default_irrefutable()
|
||||||
TestCase::Irrefutable { ascription, binding: None }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PatKind::Array { ref prefix, ref slice, ref suffix } => {
|
PatKind::Array { ref prefix, ref slice, ref suffix } => {
|
||||||
cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
|
cx.prefix_slice_suffix(
|
||||||
|
&mut subpairs,
|
||||||
|
extra_data,
|
||||||
|
&place_builder,
|
||||||
|
prefix,
|
||||||
|
slice,
|
||||||
|
suffix,
|
||||||
|
);
|
||||||
default_irrefutable()
|
default_irrefutable()
|
||||||
}
|
}
|
||||||
PatKind::Slice { ref prefix, ref slice, ref suffix } => {
|
PatKind::Slice { ref prefix, ref slice, ref suffix } => {
|
||||||
cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
|
cx.prefix_slice_suffix(
|
||||||
|
&mut subpairs,
|
||||||
|
extra_data,
|
||||||
|
&place_builder,
|
||||||
|
prefix,
|
||||||
|
slice,
|
||||||
|
suffix,
|
||||||
|
);
|
||||||
|
|
||||||
if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
|
if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
|
||||||
default_irrefutable()
|
default_irrefutable()
|
||||||
|
@ -214,7 +269,7 @@ impl<'tcx> MatchPairTree<'tcx> {
|
||||||
|
|
||||||
PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => {
|
PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => {
|
||||||
let downcast_place = place_builder.downcast(adt_def, variant_index); // `(x as Variant)`
|
let downcast_place = place_builder.downcast(adt_def, variant_index); // `(x as Variant)`
|
||||||
cx.field_match_pairs(&mut subpairs, downcast_place, subpatterns);
|
cx.field_match_pairs(&mut subpairs, extra_data, downcast_place, subpatterns);
|
||||||
|
|
||||||
let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
|
let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
|
||||||
i == variant_index
|
i == variant_index
|
||||||
|
@ -232,12 +287,18 @@ impl<'tcx> MatchPairTree<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
PatKind::Leaf { ref subpatterns } => {
|
PatKind::Leaf { ref subpatterns } => {
|
||||||
cx.field_match_pairs(&mut subpairs, place_builder, subpatterns);
|
cx.field_match_pairs(&mut subpairs, extra_data, place_builder, subpatterns);
|
||||||
default_irrefutable()
|
default_irrefutable()
|
||||||
}
|
}
|
||||||
|
|
||||||
PatKind::Deref { ref subpattern } => {
|
PatKind::Deref { ref subpattern } => {
|
||||||
MatchPairTree::for_pattern(place_builder.deref(), subpattern, cx, &mut subpairs);
|
MatchPairTree::for_pattern(
|
||||||
|
place_builder.deref(),
|
||||||
|
subpattern,
|
||||||
|
cx,
|
||||||
|
&mut subpairs,
|
||||||
|
extra_data,
|
||||||
|
);
|
||||||
default_irrefutable()
|
default_irrefutable()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,6 +314,7 @@ impl<'tcx> MatchPairTree<'tcx> {
|
||||||
subpattern,
|
subpattern,
|
||||||
cx,
|
cx,
|
||||||
&mut subpairs,
|
&mut subpairs,
|
||||||
|
extra_data,
|
||||||
);
|
);
|
||||||
TestCase::Deref { temp, mutability }
|
TestCase::Deref { temp, mutability }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1008,17 +1008,15 @@ impl<'tcx> FlatPat<'tcx> {
|
||||||
/// Creates a `FlatPat` containing a simplified [`MatchPairTree`] list/forest
|
/// Creates a `FlatPat` containing a simplified [`MatchPairTree`] list/forest
|
||||||
/// for the given pattern.
|
/// for the given pattern.
|
||||||
fn new(place: PlaceBuilder<'tcx>, pattern: &Pat<'tcx>, cx: &mut Builder<'_, 'tcx>) -> Self {
|
fn new(place: PlaceBuilder<'tcx>, pattern: &Pat<'tcx>, cx: &mut Builder<'_, 'tcx>) -> Self {
|
||||||
// First, recursively build a tree of match pairs for the given pattern.
|
// Recursively build a tree of match pairs for the given pattern.
|
||||||
let mut match_pairs = vec![];
|
let mut match_pairs = vec![];
|
||||||
MatchPairTree::for_pattern(place, pattern, cx, &mut match_pairs);
|
|
||||||
let mut extra_data = PatternExtraData {
|
let mut extra_data = PatternExtraData {
|
||||||
span: pattern.span,
|
span: pattern.span,
|
||||||
bindings: Vec::new(),
|
bindings: Vec::new(),
|
||||||
ascriptions: Vec::new(),
|
ascriptions: Vec::new(),
|
||||||
is_never: pattern.is_never_pattern(),
|
is_never: pattern.is_never_pattern(),
|
||||||
};
|
};
|
||||||
// Recursively remove irrefutable match pairs, while recording their
|
MatchPairTree::for_pattern(place, pattern, cx, &mut match_pairs, &mut extra_data);
|
||||||
// bindings/ascriptions, and sort or-patterns after other match pairs.
|
|
||||||
cx.simplify_match_pairs(&mut match_pairs, &mut extra_data);
|
cx.simplify_match_pairs(&mut match_pairs, &mut extra_data);
|
||||||
|
|
||||||
Self { match_pairs, extra_data }
|
Self { match_pairs, extra_data }
|
||||||
|
@ -1238,7 +1236,7 @@ struct Ascription<'tcx> {
|
||||||
/// - See [`Builder::expand_and_match_or_candidates`].
|
/// - See [`Builder::expand_and_match_or_candidates`].
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
enum TestCase<'tcx> {
|
enum TestCase<'tcx> {
|
||||||
Irrefutable { binding: Option<Binding<'tcx>>, ascription: Option<Ascription<'tcx>> },
|
Irrefutable {},
|
||||||
Variant { adt_def: ty::AdtDef<'tcx>, variant_index: VariantIdx },
|
Variant { adt_def: ty::AdtDef<'tcx>, variant_index: VariantIdx },
|
||||||
Constant { value: mir::Const<'tcx> },
|
Constant { value: mir::Const<'tcx> },
|
||||||
Range(Arc<PatRange<'tcx>>),
|
Range(Arc<PatRange<'tcx>>),
|
||||||
|
|
|
@ -47,13 +47,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
// match lowering forces us to lower bindings inside or-patterns last.
|
// match lowering forces us to lower bindings inside or-patterns last.
|
||||||
for mut match_pair in mem::take(match_pairs) {
|
for mut match_pair in mem::take(match_pairs) {
|
||||||
self.simplify_match_pairs(&mut match_pair.subpairs, extra_data);
|
self.simplify_match_pairs(&mut match_pair.subpairs, extra_data);
|
||||||
if let TestCase::Irrefutable { binding, ascription } = match_pair.test_case {
|
if let TestCase::Irrefutable {} = match_pair.test_case {
|
||||||
if let Some(binding) = binding {
|
|
||||||
extra_data.bindings.push(binding);
|
|
||||||
}
|
|
||||||
if let Some(ascription) = ascription {
|
|
||||||
extra_data.ascriptions.push(ascription);
|
|
||||||
}
|
|
||||||
// Simplifiable pattern; we replace it with its already simplified subpairs.
|
// Simplifiable pattern; we replace it with its already simplified subpairs.
|
||||||
match_pairs.append(&mut match_pair.subpairs);
|
match_pairs.append(&mut match_pair.subpairs);
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue