1
Fork 0

Rollup merge of #136435 - Zalathar:thir-pat-stuff, r=Nadrieril

Simplify some code for lowering THIR patterns

I've been playing around with some radically different ways of storing THIR patterns, and while those experiments haven't yet produced a clear win, I have noticed various smaller things in the existing code that can be made a bit nicer.

Some of the more significant changes:
- With a little bit of extra effort (and thoughtful use of Arc), we can completely remove an entire layer of `'pat` lifetimes from the intermediate data structures used for match lowering.
- In several places, lists of THIR patterns were being double-boxed for no apparent reason.
This commit is contained in:
Matthias Krüger 2025-02-06 13:10:00 +01:00 committed by GitHub
commit c9635e51b5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 148 additions and 148 deletions

View file

@ -11,6 +11,7 @@
use std::cmp::Ordering; use std::cmp::Ordering;
use std::fmt; use std::fmt;
use std::ops::Index; use std::ops::Index;
use std::sync::Arc;
use rustc_abi::{FieldIdx, Integer, Size, VariantIdx}; use rustc_abi::{FieldIdx, Integer, Size, VariantIdx};
use rustc_ast::{AsmMacro, InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_ast::{AsmMacro, InlineAsmOptions, InlineAsmTemplatePiece};
@ -618,7 +619,7 @@ pub enum InlineAsmOperand<'tcx> {
#[derive(Debug, HashStable, TypeVisitable)] #[derive(Debug, HashStable, TypeVisitable)]
pub struct FieldPat<'tcx> { pub struct FieldPat<'tcx> {
pub field: FieldIdx, pub field: FieldIdx,
pub pattern: Box<Pat<'tcx>>, pub pattern: Pat<'tcx>,
} }
#[derive(Debug, HashStable, TypeVisitable)] #[derive(Debug, HashStable, TypeVisitable)]
@ -679,7 +680,7 @@ impl<'tcx> Pat<'tcx> {
Or { pats } => pats.iter().for_each(|p| p.walk_(it)), Or { pats } => pats.iter().for_each(|p| p.walk_(it)),
Array { box ref prefix, ref slice, box ref suffix } Array { box ref prefix, ref slice, box ref suffix }
| Slice { box ref prefix, ref slice, box ref suffix } => { | Slice { box ref prefix, ref slice, box ref suffix } => {
prefix.iter().chain(slice.iter()).chain(suffix.iter()).for_each(|p| p.walk_(it)) prefix.iter().chain(slice.as_deref()).chain(suffix.iter()).for_each(|p| p.walk_(it))
} }
} }
} }
@ -836,28 +837,28 @@ pub enum PatKind<'tcx> {
subpattern: Box<Pat<'tcx>>, subpattern: Box<Pat<'tcx>>,
}, },
Range(Box<PatRange<'tcx>>), Range(Arc<PatRange<'tcx>>),
/// Matches against a slice, checking the length and extracting elements. /// Matches against a slice, checking the length and extracting elements.
/// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty. /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty.
/// e.g., `&[ref xs @ ..]`. /// e.g., `&[ref xs @ ..]`.
Slice { Slice {
prefix: Box<[Box<Pat<'tcx>>]>, prefix: Box<[Pat<'tcx>]>,
slice: Option<Box<Pat<'tcx>>>, slice: Option<Box<Pat<'tcx>>>,
suffix: Box<[Box<Pat<'tcx>>]>, suffix: Box<[Pat<'tcx>]>,
}, },
/// Fixed match against an array; irrefutable. /// Fixed match against an array; irrefutable.
Array { Array {
prefix: Box<[Box<Pat<'tcx>>]>, prefix: Box<[Pat<'tcx>]>,
slice: Option<Box<Pat<'tcx>>>, slice: Option<Box<Pat<'tcx>>>,
suffix: Box<[Box<Pat<'tcx>>]>, suffix: Box<[Pat<'tcx>]>,
}, },
/// An or-pattern, e.g. `p | q`. /// An or-pattern, e.g. `p | q`.
/// Invariant: `pats.len() >= 2`. /// Invariant: `pats.len() >= 2`.
Or { Or {
pats: Box<[Box<Pat<'tcx>>]>, pats: Box<[Pat<'tcx>]>,
}, },
/// A never pattern `!`. /// A never pattern `!`.

View file

@ -1,3 +1,5 @@
use std::sync::Arc;
use rustc_middle::mir::*; use rustc_middle::mir::*;
use rustc_middle::thir::{self, *}; use rustc_middle::thir::{self, *};
use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_middle::ty::{self, Ty, TypeVisitableExt};
@ -12,11 +14,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// [`PatKind::Leaf`]. /// [`PatKind::Leaf`].
/// ///
/// Used internally by [`MatchPairTree::for_pattern`]. /// Used internally by [`MatchPairTree::for_pattern`].
fn field_match_pairs<'pat>( fn field_match_pairs(
&mut self, &mut self,
place: PlaceBuilder<'tcx>, place: PlaceBuilder<'tcx>,
subpatterns: &'pat [FieldPat<'tcx>], subpatterns: &[FieldPat<'tcx>],
) -> Vec<MatchPairTree<'pat, 'tcx>> { ) -> Vec<MatchPairTree<'tcx>> {
subpatterns subpatterns
.iter() .iter()
.map(|fieldpat| { .map(|fieldpat| {
@ -31,13 +33,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// array pattern or slice pattern, and adds those trees to `match_pairs`. /// array pattern or slice pattern, and adds those trees to `match_pairs`.
/// ///
/// Used internally by [`MatchPairTree::for_pattern`]. /// Used internally by [`MatchPairTree::for_pattern`].
fn prefix_slice_suffix<'pat>( fn prefix_slice_suffix(
&mut self, &mut self,
match_pairs: &mut Vec<MatchPairTree<'pat, 'tcx>>, match_pairs: &mut Vec<MatchPairTree<'tcx>>,
place: &PlaceBuilder<'tcx>, place: &PlaceBuilder<'tcx>,
prefix: &'pat [Box<Pat<'tcx>>], prefix: &[Pat<'tcx>],
opt_slice: &'pat Option<Box<Pat<'tcx>>>, opt_slice: &Option<Box<Pat<'tcx>>>,
suffix: &'pat [Box<Pat<'tcx>>], suffix: &[Pat<'tcx>],
) { ) {
let tcx = self.tcx; let tcx = self.tcx;
let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) { let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) {
@ -83,14 +85,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} }
} }
impl<'pat, 'tcx> MatchPairTree<'pat, '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(in crate::builder) fn for_pattern(
mut place_builder: PlaceBuilder<'tcx>, mut place_builder: PlaceBuilder<'tcx>,
pattern: &'pat Pat<'tcx>, pattern: &Pat<'tcx>,
cx: &mut Builder<'_, 'tcx>, cx: &mut Builder<'_, 'tcx>,
) -> MatchPairTree<'pat, 'tcx> { ) -> MatchPairTree<'tcx> {
// 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?
if let Some(resolved) = place_builder.resolve_upvar(cx) { if let Some(resolved) = place_builder.resolve_upvar(cx) {
@ -125,7 +127,7 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
if range.is_full_range(cx.tcx) == Some(true) { if range.is_full_range(cx.tcx) == Some(true) {
default_irrefutable() default_irrefutable()
} else { } else {
TestCase::Range(range) TestCase::Range(Arc::clone(range))
} }
} }
@ -255,6 +257,12 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
PatKind::Never => TestCase::Never, PatKind::Never => TestCase::Never,
}; };
MatchPairTree { place, test_case, subpairs, pattern } MatchPairTree {
place,
test_case,
subpairs,
pattern_ty: pattern.ty,
pattern_span: pattern.span,
}
} }
} }

View file

@ -33,6 +33,7 @@ mod util;
use std::assert_matches::assert_matches; use std::assert_matches::assert_matches;
use std::borrow::Borrow; use std::borrow::Borrow;
use std::mem; use std::mem;
use std::sync::Arc;
/// Arguments to [`Builder::then_else_break_inner`] that are usually forwarded /// Arguments to [`Builder::then_else_break_inner`] that are usually forwarded
/// to recursive invocations. /// to recursive invocations.
@ -361,11 +362,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let scrutinee_place = let scrutinee_place =
unpack!(block = self.lower_scrutinee(block, scrutinee_id, scrutinee_span)); unpack!(block = self.lower_scrutinee(block, scrutinee_id, scrutinee_span));
let arms = arms.iter().map(|arm| &self.thir[*arm]);
let match_start_span = span.shrink_to_lo().to(scrutinee_span); let match_start_span = span.shrink_to_lo().to(scrutinee_span);
let patterns = arms let patterns = arms
.clone() .iter()
.map(|arm| { .map(|&arm| {
let arm = &self.thir[arm];
let has_match_guard = let has_match_guard =
if arm.guard.is_some() { HasMatchGuard::Yes } else { HasMatchGuard::No }; if arm.guard.is_some() { HasMatchGuard::Yes } else { HasMatchGuard::No };
(&*arm.pattern, has_match_guard) (&*arm.pattern, has_match_guard)
@ -412,20 +413,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// (by [Builder::lower_match_tree]). /// (by [Builder::lower_match_tree]).
/// ///
/// `outer_source_info` is the SourceInfo for the whole match. /// `outer_source_info` is the SourceInfo for the whole match.
fn lower_match_arms<'pat>( fn lower_match_arms(
&mut self, &mut self,
destination: Place<'tcx>, destination: Place<'tcx>,
scrutinee_place_builder: PlaceBuilder<'tcx>, scrutinee_place_builder: PlaceBuilder<'tcx>,
scrutinee_span: Span, scrutinee_span: Span,
arms: impl IntoIterator<Item = &'pat Arm<'tcx>>, arms: &[ArmId],
built_match_tree: BuiltMatchTree<'tcx>, built_match_tree: BuiltMatchTree<'tcx>,
outer_source_info: SourceInfo, outer_source_info: SourceInfo,
) -> BlockAnd<()> ) -> BlockAnd<()> {
where
'tcx: 'pat,
{
let arm_end_blocks: Vec<BasicBlock> = arms let arm_end_blocks: Vec<BasicBlock> = arms
.into_iter() .iter()
.map(|&arm| &self.thir[arm])
.zip(built_match_tree.branches) .zip(built_match_tree.branches)
.map(|(arm, branch)| { .map(|(arm, branch)| {
debug!("lowering arm {:?}\ncorresponding branch = {:?}", arm, branch); debug!("lowering arm {:?}\ncorresponding branch = {:?}", arm, branch);
@ -604,19 +603,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// Optimize the case of `let x: T = ...` to write directly // Optimize the case of `let x: T = ...` to write directly
// into `x` and then require that `T == typeof(x)`. // into `x` and then require that `T == typeof(x)`.
PatKind::AscribeUserType { PatKind::AscribeUserType {
subpattern: ref subpattern,
box Pat {
kind:
PatKind::Binding {
mode: BindingMode(ByRef::No, _),
var,
subpattern: None,
..
},
..
},
ascription: thir::Ascription { ref annotation, variance: _ }, ascription: thir::Ascription { ref annotation, variance: _ },
} => { } if let PatKind::Binding {
mode: BindingMode(ByRef::No, _),
var,
subpattern: None,
..
} = subpattern.kind =>
{
let place = self.storage_live_binding( let place = self.storage_live_binding(
block, block,
var, var,
@ -989,23 +984,19 @@ impl<'tcx> PatternExtraData<'tcx> {
/// ///
/// Will typically be incorporated into a [`Candidate`]. /// Will typically be incorporated into a [`Candidate`].
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct FlatPat<'pat, 'tcx> { struct FlatPat<'tcx> {
/// To match the pattern, all of these must be satisfied... /// To match the pattern, all of these must be satisfied...
// Invariant: all the match pairs are recursively simplified. // Invariant: all the match pairs are recursively simplified.
// Invariant: or-patterns must be sorted to the end. // Invariant: or-patterns must be sorted to the end.
match_pairs: Vec<MatchPairTree<'pat, 'tcx>>, match_pairs: Vec<MatchPairTree<'tcx>>,
extra_data: PatternExtraData<'tcx>, extra_data: PatternExtraData<'tcx>,
} }
impl<'tcx, 'pat> FlatPat<'pat, 'tcx> { 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( fn new(place: PlaceBuilder<'tcx>, pattern: &Pat<'tcx>, cx: &mut Builder<'_, 'tcx>) -> Self {
place: PlaceBuilder<'tcx>,
pattern: &'pat Pat<'tcx>,
cx: &mut Builder<'_, 'tcx>,
) -> Self {
// First, recursively build a tree of match pairs for the given pattern. // First, recursively build a tree of match pairs for the given pattern.
let mut match_pairs = vec![MatchPairTree::for_pattern(place, pattern, cx)]; let mut match_pairs = vec![MatchPairTree::for_pattern(place, pattern, cx)];
let mut extra_data = PatternExtraData { let mut extra_data = PatternExtraData {
@ -1033,7 +1024,7 @@ impl<'tcx, 'pat> FlatPat<'pat, 'tcx> {
/// of candidates, where each "leaf" candidate represents one of the ways for /// of candidates, where each "leaf" candidate represents one of the ways for
/// the arm pattern to successfully match. /// the arm pattern to successfully match.
#[derive(Debug)] #[derive(Debug)]
struct Candidate<'pat, 'tcx> { struct Candidate<'tcx> {
/// For the candidate to match, all of these must be satisfied... /// For the candidate to match, all of these must be satisfied...
/// ///
/// --- /// ---
@ -1055,7 +1046,7 @@ struct Candidate<'pat, 'tcx> {
/// Invariants: /// Invariants:
/// - All [`TestCase::Irrefutable`] patterns have been removed by simplification. /// - All [`TestCase::Irrefutable`] patterns have been removed by simplification.
/// - All or-patterns ([`TestCase::Or`]) have been sorted to the end. /// - All or-patterns ([`TestCase::Or`]) have been sorted to the end.
match_pairs: Vec<MatchPairTree<'pat, 'tcx>>, match_pairs: Vec<MatchPairTree<'tcx>>,
/// ...and if this is non-empty, one of these subcandidates also has to match... /// ...and if this is non-empty, one of these subcandidates also has to match...
/// ///
@ -1072,7 +1063,7 @@ struct Candidate<'pat, 'tcx> {
/// Invariant: at the end of match tree lowering, this must not contain an /// Invariant: at the end of match tree lowering, this must not contain an
/// `is_never` candidate, because that would break binding consistency. /// `is_never` candidate, because that would break binding consistency.
/// - See [`Builder::remove_never_subcandidates`]. /// - See [`Builder::remove_never_subcandidates`].
subcandidates: Vec<Candidate<'pat, 'tcx>>, subcandidates: Vec<Candidate<'tcx>>,
/// ...and if there is a guard it must be evaluated; if it's `false` then branch to `otherwise_block`. /// ...and if there is a guard it must be evaluated; if it's `false` then branch to `otherwise_block`.
/// ///
@ -1107,10 +1098,10 @@ struct Candidate<'pat, 'tcx> {
false_edge_start_block: Option<BasicBlock>, false_edge_start_block: Option<BasicBlock>,
} }
impl<'tcx, 'pat> Candidate<'pat, 'tcx> { impl<'tcx> Candidate<'tcx> {
fn new( fn new(
place: PlaceBuilder<'tcx>, place: PlaceBuilder<'tcx>,
pattern: &'pat Pat<'tcx>, pattern: &Pat<'tcx>,
has_guard: HasMatchGuard, has_guard: HasMatchGuard,
cx: &mut Builder<'_, 'tcx>, cx: &mut Builder<'_, 'tcx>,
) -> Self { ) -> Self {
@ -1123,7 +1114,7 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
} }
/// Incorporates an already-simplified [`FlatPat`] into a new candidate. /// Incorporates an already-simplified [`FlatPat`] into a new candidate.
fn from_flat_pat(flat_pat: FlatPat<'pat, 'tcx>, has_guard: bool) -> Self { fn from_flat_pat(flat_pat: FlatPat<'tcx>, has_guard: bool) -> Self {
Candidate { Candidate {
match_pairs: flat_pat.match_pairs, match_pairs: flat_pat.match_pairs,
extra_data: flat_pat.extra_data, extra_data: flat_pat.extra_data,
@ -1172,7 +1163,7 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
/// reference or by value, and to allow a mutable "context" to be shared by the /// reference or by value, and to allow a mutable "context" to be shared by the
/// traversal callbacks. Most traversals can use the simpler /// traversal callbacks. Most traversals can use the simpler
/// [`Candidate::visit_leaves`] wrapper instead. /// [`Candidate::visit_leaves`] wrapper instead.
fn traverse_candidate<'pat, 'tcx: 'pat, C, T, I>( fn traverse_candidate<'tcx, C, T, I>(
candidate: C, candidate: C,
context: &mut T, context: &mut T,
// Called when visiting a "leaf" candidate (with no subcandidates). // Called when visiting a "leaf" candidate (with no subcandidates).
@ -1184,7 +1175,7 @@ fn traverse_candidate<'pat, 'tcx: 'pat, C, T, I>(
// Called after visiting a "node" candidate's children. // Called after visiting a "node" candidate's children.
complete_children: impl Copy + Fn(&mut T), complete_children: impl Copy + Fn(&mut T),
) where ) where
C: Borrow<Candidate<'pat, 'tcx>>, // Typically `Candidate` or `&mut Candidate` C: Borrow<Candidate<'tcx>>, // Typically `Candidate` or `&mut Candidate`
I: Iterator<Item = C>, I: Iterator<Item = C>,
{ {
if candidate.borrow().subcandidates.is_empty() { if candidate.borrow().subcandidates.is_empty() {
@ -1234,20 +1225,20 @@ struct Ascription<'tcx> {
/// participate in or-pattern expansion, where they are transformed into subcandidates. /// participate in or-pattern expansion, where they are transformed into subcandidates.
/// - See [`Builder::expand_and_match_or_candidates`]. /// - See [`Builder::expand_and_match_or_candidates`].
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
enum TestCase<'pat, 'tcx> { enum TestCase<'tcx> {
Irrefutable { binding: Option<Binding<'tcx>>, ascription: Option<Ascription<'tcx>> }, Irrefutable { binding: Option<Binding<'tcx>>, ascription: Option<Ascription<'tcx>> },
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(&'pat PatRange<'tcx>), Range(Arc<PatRange<'tcx>>),
Slice { len: usize, variable_length: bool }, Slice { len: usize, variable_length: bool },
Deref { temp: Place<'tcx>, mutability: Mutability }, Deref { temp: Place<'tcx>, mutability: Mutability },
Never, Never,
Or { pats: Box<[FlatPat<'pat, 'tcx>]> }, Or { pats: Box<[FlatPat<'tcx>]> },
} }
impl<'pat, 'tcx> TestCase<'pat, 'tcx> { impl<'tcx> TestCase<'tcx> {
fn as_range(&self) -> Option<&'pat PatRange<'tcx>> { fn as_range(&self) -> Option<&PatRange<'tcx>> {
if let Self::Range(v) = self { Some(*v) } else { None } if let Self::Range(v) = self { Some(v.as_ref()) } else { None }
} }
} }
@ -1257,7 +1248,7 @@ impl<'pat, 'tcx> TestCase<'pat, 'tcx> {
/// Each node also has a list of subpairs (possibly empty) that must also match, /// Each node also has a list of subpairs (possibly empty) that must also match,
/// and a reference to the THIR pattern it represents. /// and a reference to the THIR pattern it represents.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct MatchPairTree<'pat, 'tcx> { pub(crate) struct MatchPairTree<'tcx> {
/// This place... /// This place...
/// ///
/// --- /// ---
@ -1272,7 +1263,7 @@ pub(crate) struct MatchPairTree<'pat, 'tcx> {
/// --- /// ---
/// Invariant: after creation and simplification in [`FlatPat::new`], /// Invariant: after creation and simplification in [`FlatPat::new`],
/// this must not be [`TestCase::Irrefutable`]. /// this must not be [`TestCase::Irrefutable`].
test_case: TestCase<'pat, 'tcx>, test_case: TestCase<'tcx>,
/// ... and these subpairs must match. /// ... and these subpairs must match.
/// ///
@ -1283,8 +1274,10 @@ pub(crate) struct MatchPairTree<'pat, 'tcx> {
/// that tests its field for the value `3`. /// that tests its field for the value `3`.
subpairs: Vec<Self>, subpairs: Vec<Self>,
/// The pattern this was created from. /// Type field of the pattern this node was created from.
pattern: &'pat Pat<'tcx>, pattern_ty: Ty<'tcx>,
/// Span field of the pattern this node was created from.
pattern_span: Span,
} }
/// See [`Test`] for more. /// See [`Test`] for more.
@ -1320,7 +1313,7 @@ enum TestKind<'tcx> {
}, },
/// Test whether the value falls within an inclusive or exclusive range. /// Test whether the value falls within an inclusive or exclusive range.
Range(Box<PatRange<'tcx>>), Range(Arc<PatRange<'tcx>>),
/// Test that the length of the slice is `== len` or `>= len`. /// Test that the length of the slice is `== len` or `>= len`.
Len { len: u64, op: BinOp }, Len { len: u64, op: BinOp },
@ -1423,7 +1416,7 @@ struct BuiltMatchTree<'tcx> {
impl<'tcx> MatchTreeSubBranch<'tcx> { impl<'tcx> MatchTreeSubBranch<'tcx> {
fn from_sub_candidate( fn from_sub_candidate(
candidate: Candidate<'_, 'tcx>, candidate: Candidate<'tcx>,
parent_data: &Vec<PatternExtraData<'tcx>>, parent_data: &Vec<PatternExtraData<'tcx>>,
) -> Self { ) -> Self {
debug_assert!(candidate.match_pairs.is_empty()); debug_assert!(candidate.match_pairs.is_empty());
@ -1449,12 +1442,12 @@ impl<'tcx> MatchTreeSubBranch<'tcx> {
} }
impl<'tcx> MatchTreeBranch<'tcx> { impl<'tcx> MatchTreeBranch<'tcx> {
fn from_candidate(candidate: Candidate<'_, 'tcx>) -> Self { fn from_candidate(candidate: Candidate<'tcx>) -> Self {
let mut sub_branches = Vec::new(); let mut sub_branches = Vec::new();
traverse_candidate( traverse_candidate(
candidate, candidate,
&mut Vec::new(), &mut Vec::new(),
&mut |candidate: Candidate<'_, '_>, parent_data: &mut Vec<PatternExtraData<'_>>| { &mut |candidate: Candidate<'_>, parent_data: &mut Vec<PatternExtraData<'_>>| {
sub_branches.push(MatchTreeSubBranch::from_sub_candidate(candidate, parent_data)); sub_branches.push(MatchTreeSubBranch::from_sub_candidate(candidate, parent_data));
}, },
|inner_candidate, parent_data| { |inner_candidate, parent_data| {
@ -1485,23 +1478,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// `refutable` indicates whether the candidate list is refutable (for `if let` and `let else`) /// `refutable` indicates whether the candidate list is refutable (for `if let` and `let else`)
/// or not (for `let` and `match`). In the refutable case we return the block to which we branch /// or not (for `let` and `match`). In the refutable case we return the block to which we branch
/// on failure. /// on failure.
fn lower_match_tree<'pat>( fn lower_match_tree(
&mut self, &mut self,
block: BasicBlock, block: BasicBlock,
scrutinee_span: Span, scrutinee_span: Span,
scrutinee_place_builder: &PlaceBuilder<'tcx>, scrutinee_place_builder: &PlaceBuilder<'tcx>,
match_start_span: Span, match_start_span: Span,
patterns: Vec<(&'pat Pat<'tcx>, HasMatchGuard)>, patterns: Vec<(&Pat<'tcx>, HasMatchGuard)>,
refutable: bool, refutable: bool,
) -> BuiltMatchTree<'tcx> ) -> BuiltMatchTree<'tcx> {
where
'tcx: 'pat,
{
// Assemble the initial list of candidates. These top-level candidates are 1:1 with the // Assemble the initial list of candidates. These top-level candidates are 1:1 with the
// input patterns, but other parts of match lowering also introduce subcandidates (for // input patterns, but other parts of match lowering also introduce subcandidates (for
// sub-or-patterns). So inside the algorithm, the candidates list may not correspond to // sub-or-patterns). So inside the algorithm, the candidates list may not correspond to
// match arms directly. // match arms directly.
let mut candidates: Vec<Candidate<'_, '_>> = patterns let mut candidates: Vec<Candidate<'_>> = patterns
.into_iter() .into_iter()
.map(|(pat, has_guard)| { .map(|(pat, has_guard)| {
Candidate::new(scrutinee_place_builder.clone(), pat, has_guard, self) Candidate::new(scrutinee_place_builder.clone(), pat, has_guard, self)
@ -1664,7 +1654,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
span: Span, span: Span,
scrutinee_span: Span, scrutinee_span: Span,
start_block: BasicBlock, start_block: BasicBlock,
candidates: &mut [&mut Candidate<'_, 'tcx>], candidates: &mut [&mut Candidate<'tcx>],
) -> BasicBlock { ) -> BasicBlock {
ensure_sufficient_stack(|| { ensure_sufficient_stack(|| {
self.match_candidates_inner(span, scrutinee_span, start_block, candidates) self.match_candidates_inner(span, scrutinee_span, start_block, candidates)
@ -1678,7 +1668,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
span: Span, span: Span,
scrutinee_span: Span, scrutinee_span: Span,
mut start_block: BasicBlock, mut start_block: BasicBlock,
candidates: &mut [&mut Candidate<'_, 'tcx>], candidates: &mut [&mut Candidate<'tcx>],
) -> BasicBlock { ) -> BasicBlock {
if let [first, ..] = candidates { if let [first, ..] = candidates {
if first.false_edge_start_block.is_none() { if first.false_edge_start_block.is_none() {
@ -1747,7 +1737,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// [otherwise block]: Candidate::otherwise_block /// [otherwise block]: Candidate::otherwise_block
fn select_matched_candidate( fn select_matched_candidate(
&mut self, &mut self,
candidate: &mut Candidate<'_, 'tcx>, candidate: &mut Candidate<'tcx>,
start_block: BasicBlock, start_block: BasicBlock,
) -> BasicBlock { ) -> BasicBlock {
assert!(candidate.otherwise_block.is_none()); assert!(candidate.otherwise_block.is_none());
@ -1765,13 +1755,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Takes a list of candidates such that some of the candidates' first match pairs are /// Takes a list of candidates such that some of the candidates' first match pairs are
/// or-patterns. This expands as many or-patterns as possible and processes the resulting /// or-patterns. This expands as many or-patterns as possible and processes the resulting
/// candidates. Returns the unprocessed candidates if any. /// candidates. Returns the unprocessed candidates if any.
fn expand_and_match_or_candidates<'pat, 'b, 'c>( fn expand_and_match_or_candidates<'b, 'c>(
&mut self, &mut self,
span: Span, span: Span,
scrutinee_span: Span, scrutinee_span: Span,
start_block: BasicBlock, start_block: BasicBlock,
candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>], candidates: &'b mut [&'c mut Candidate<'tcx>],
) -> BlockAnd<&'b mut [&'c mut Candidate<'pat, 'tcx>]> { ) -> BlockAnd<&'b mut [&'c mut Candidate<'tcx>]> {
// We can't expand or-patterns freely. The rule is: // We can't expand or-patterns freely. The rule is:
// - If a candidate doesn't start with an or-pattern, we include it in // - If a candidate doesn't start with an or-pattern, we include it in
// the expansion list as-is (i.e. it "expands" to itself). // the expansion list as-is (i.e. it "expands" to itself).
@ -1865,14 +1855,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Given a match-pair that corresponds to an or-pattern, expand each subpattern into a new /// Given a match-pair that corresponds to an or-pattern, expand each subpattern into a new
/// subcandidate. Any candidate that has been expanded this way should also be postprocessed /// subcandidate. Any candidate that has been expanded this way should also be postprocessed
/// at the end of [`Self::expand_and_match_or_candidates`]. /// at the end of [`Self::expand_and_match_or_candidates`].
fn create_or_subcandidates<'pat>( fn create_or_subcandidates(
&mut self, &mut self,
candidate: &mut Candidate<'pat, 'tcx>, candidate: &mut Candidate<'tcx>,
match_pair: MatchPairTree<'pat, 'tcx>, match_pair: MatchPairTree<'tcx>,
) { ) {
let TestCase::Or { pats } = match_pair.test_case else { bug!() }; let TestCase::Or { pats } = match_pair.test_case else { bug!() };
debug!("expanding or-pattern: candidate={:#?}\npats={:#?}", candidate, pats); debug!("expanding or-pattern: candidate={:#?}\npats={:#?}", candidate, pats);
candidate.or_span = Some(match_pair.pattern.span); candidate.or_span = Some(match_pair.pattern_span);
candidate.subcandidates = pats candidate.subcandidates = pats
.into_vec() .into_vec()
.into_iter() .into_iter()
@ -1938,7 +1928,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// ///
/// Note that this takes place _after_ the subcandidates have participated /// Note that this takes place _after_ the subcandidates have participated
/// in match tree lowering. /// in match tree lowering.
fn merge_trivial_subcandidates(&mut self, candidate: &mut Candidate<'_, 'tcx>) { fn merge_trivial_subcandidates(&mut self, candidate: &mut Candidate<'tcx>) {
assert!(!candidate.subcandidates.is_empty()); assert!(!candidate.subcandidates.is_empty());
if candidate.has_guard { if candidate.has_guard {
// FIXME(or_patterns; matthewjasper) Don't give up if we have a guard. // FIXME(or_patterns; matthewjasper) Don't give up if we have a guard.
@ -1981,7 +1971,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Never subcandidates may have a set of bindings inconsistent with their siblings, /// Never subcandidates may have a set of bindings inconsistent with their siblings,
/// which would break later code. So we filter them out. Note that we can't filter out /// which would break later code. So we filter them out. Note that we can't filter out
/// top-level candidates this way. /// top-level candidates this way.
fn remove_never_subcandidates(&mut self, candidate: &mut Candidate<'_, 'tcx>) { fn remove_never_subcandidates(&mut self, candidate: &mut Candidate<'tcx>) {
if candidate.subcandidates.is_empty() { if candidate.subcandidates.is_empty() {
return; return;
} }
@ -2020,7 +2010,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
&mut self, &mut self,
span: Span, span: Span,
scrutinee_span: Span, scrutinee_span: Span,
candidate: &mut Candidate<'_, 'tcx>, candidate: &mut Candidate<'tcx>,
) { ) {
if candidate.match_pairs.is_empty() { if candidate.match_pairs.is_empty() {
return; return;
@ -2086,7 +2076,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// [`Switch`]: TestKind::Switch /// [`Switch`]: TestKind::Switch
/// [`SwitchInt`]: TestKind::SwitchInt /// [`SwitchInt`]: TestKind::SwitchInt
/// [`Range`]: TestKind::Range /// [`Range`]: TestKind::Range
fn pick_test(&mut self, candidates: &[&mut Candidate<'_, 'tcx>]) -> (Place<'tcx>, Test<'tcx>) { fn pick_test(&mut self, candidates: &[&mut Candidate<'tcx>]) -> (Place<'tcx>, Test<'tcx>) {
// Extract the match-pair from the highest priority candidate // Extract the match-pair from the highest priority candidate
let match_pair = &candidates[0].match_pairs[0]; let match_pair = &candidates[0].match_pairs[0];
let test = self.pick_test_for_match_pair(match_pair); let test = self.pick_test_for_match_pair(match_pair);
@ -2137,18 +2127,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// The sorted candidates are mutated to remove entailed match pairs: /// The sorted candidates are mutated to remove entailed match pairs:
/// - candidate 0 becomes `[z @ true]` since we know that `x` was `true`; /// - candidate 0 becomes `[z @ true]` since we know that `x` was `true`;
/// - candidate 1 becomes `[y @ false]` since we know that `x` was `false`. /// - candidate 1 becomes `[y @ false]` since we know that `x` was `false`.
fn sort_candidates<'b, 'c, 'pat>( fn sort_candidates<'b, 'c>(
&mut self, &mut self,
match_place: Place<'tcx>, match_place: Place<'tcx>,
test: &Test<'tcx>, test: &Test<'tcx>,
mut candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>], mut candidates: &'b mut [&'c mut Candidate<'tcx>],
) -> ( ) -> (
&'b mut [&'c mut Candidate<'pat, 'tcx>], &'b mut [&'c mut Candidate<'tcx>],
FxIndexMap<TestBranch<'tcx>, Vec<&'b mut Candidate<'pat, 'tcx>>>, FxIndexMap<TestBranch<'tcx>, Vec<&'b mut Candidate<'tcx>>>,
) { ) {
// For each of the possible outcomes, collect vector of candidates that apply if the test // For each of the possible outcomes, collect vector of candidates that apply if the test
// has that particular outcome. // has that particular outcome.
let mut target_candidates: FxIndexMap<_, Vec<&mut Candidate<'_, '_>>> = Default::default(); let mut target_candidates: FxIndexMap<_, Vec<&mut Candidate<'_>>> = Default::default();
let total_candidate_count = candidates.len(); let total_candidate_count = candidates.len();
@ -2274,13 +2264,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// ``` /// ```
/// ///
/// We return the unprocessed candidates. /// We return the unprocessed candidates.
fn test_candidates<'pat, 'b, 'c>( fn test_candidates<'b, 'c>(
&mut self, &mut self,
span: Span, span: Span,
scrutinee_span: Span, scrutinee_span: Span,
candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>], candidates: &'b mut [&'c mut Candidate<'tcx>],
start_block: BasicBlock, start_block: BasicBlock,
) -> BlockAnd<&'b mut [&'c mut Candidate<'pat, 'tcx>]> { ) -> BlockAnd<&'b mut [&'c mut Candidate<'tcx>]> {
// Choose a match pair from the first candidate, and use it to determine a // Choose a match pair from the first candidate, and use it to determine a
// test to perform that will confirm or refute that match pair. // test to perform that will confirm or refute that match pair.
let (match_place, test) = self.pick_test(candidates); let (match_place, test) = self.pick_test(candidates);

View file

@ -23,9 +23,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Simplify a list of match pairs so they all require a test. Stores relevant bindings and /// Simplify a list of match pairs so they all require a test. Stores relevant bindings and
/// ascriptions in `extra_data`. /// ascriptions in `extra_data`.
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
pub(super) fn simplify_match_pairs<'pat>( pub(super) fn simplify_match_pairs(
&mut self, &mut self,
match_pairs: &mut Vec<MatchPairTree<'pat, 'tcx>>, match_pairs: &mut Vec<MatchPairTree<'tcx>>,
extra_data: &mut PatternExtraData<'tcx>, extra_data: &mut PatternExtraData<'tcx>,
) { ) {
// In order to please the borrow checker, in a pattern like `x @ pat` we must lower the // In order to please the borrow checker, in a pattern like `x @ pat` we must lower the

View file

@ -6,6 +6,7 @@
// the candidates based on the result. // the candidates based on the result.
use std::cmp::Ordering; use std::cmp::Ordering;
use std::sync::Arc;
use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::fx::FxIndexMap;
use rustc_hir::{LangItem, RangeEnd}; use rustc_hir::{LangItem, RangeEnd};
@ -26,20 +27,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Identifies what test is needed to decide if `match_pair` is applicable. /// Identifies what test is needed to decide if `match_pair` is applicable.
/// ///
/// It is a bug to call this with a not-fully-simplified pattern. /// It is a bug to call this with a not-fully-simplified pattern.
pub(super) fn pick_test_for_match_pair<'pat>( pub(super) fn pick_test_for_match_pair(
&mut self, &mut self,
match_pair: &MatchPairTree<'pat, 'tcx>, match_pair: &MatchPairTree<'tcx>,
) -> Test<'tcx> { ) -> Test<'tcx> {
let kind = match match_pair.test_case { let kind = match match_pair.test_case {
TestCase::Variant { adt_def, variant_index: _ } => TestKind::Switch { adt_def }, TestCase::Variant { adt_def, variant_index: _ } => TestKind::Switch { adt_def },
TestCase::Constant { .. } if match_pair.pattern.ty.is_bool() => TestKind::If, TestCase::Constant { .. } if match_pair.pattern_ty.is_bool() => TestKind::If,
TestCase::Constant { .. } if is_switch_ty(match_pair.pattern.ty) => TestKind::SwitchInt, TestCase::Constant { .. } if is_switch_ty(match_pair.pattern_ty) => TestKind::SwitchInt,
TestCase::Constant { value } => TestKind::Eq { value, ty: match_pair.pattern.ty }, TestCase::Constant { value } => TestKind::Eq { value, ty: match_pair.pattern_ty },
TestCase::Range(range) => { TestCase::Range(ref range) => {
assert_eq!(range.ty, match_pair.pattern.ty); assert_eq!(range.ty, match_pair.pattern_ty);
TestKind::Range(Box::new(range.clone())) TestKind::Range(Arc::clone(range))
} }
TestCase::Slice { len, variable_length } => { TestCase::Slice { len, variable_length } => {
@ -56,13 +57,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
TestCase::Or { .. } => bug!("or-patterns should have already been handled"), TestCase::Or { .. } => bug!("or-patterns should have already been handled"),
TestCase::Irrefutable { .. } => span_bug!( TestCase::Irrefutable { .. } => span_bug!(
match_pair.pattern.span, match_pair.pattern_span,
"simplifiable pattern found: {:?}", "simplifiable pattern found: {:?}",
match_pair.pattern match_pair.pattern_span
), ),
}; };
Test { span: match_pair.pattern.span, kind } Test { span: match_pair.pattern_span, kind }
} }
#[instrument(skip(self, target_blocks, place), level = "debug")] #[instrument(skip(self, target_blocks, place), level = "debug")]
@ -521,8 +522,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
&mut self, &mut self,
test_place: Place<'tcx>, test_place: Place<'tcx>,
test: &Test<'tcx>, test: &Test<'tcx>,
candidate: &mut Candidate<'_, 'tcx>, candidate: &mut Candidate<'tcx>,
sorted_candidates: &FxIndexMap<TestBranch<'tcx>, Vec<&mut Candidate<'_, 'tcx>>>, sorted_candidates: &FxIndexMap<TestBranch<'tcx>, Vec<&mut Candidate<'tcx>>>,
) -> Option<TestBranch<'tcx>> { ) -> Option<TestBranch<'tcx>> {
// Find the match_pair for this place (if any). At present, // Find the match_pair for this place (if any). At present,
// afaik, there can be at most one. (In the future, if we // afaik, there can be at most one. (In the future, if we
@ -558,14 +559,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// FIXME(#29623) we could use PatKind::Range to rule // FIXME(#29623) we could use PatKind::Range to rule
// things out here, in some cases. // things out here, in some cases.
(TestKind::SwitchInt, &TestCase::Constant { value }) (TestKind::SwitchInt, &TestCase::Constant { value })
if is_switch_ty(match_pair.pattern.ty) => if is_switch_ty(match_pair.pattern_ty) =>
{ {
// An important invariant of candidate sorting is that a candidate // An important invariant of candidate sorting is that a candidate
// must not match in multiple branches. For `SwitchInt` tests, adding // must not match in multiple branches. For `SwitchInt` tests, adding
// a new value might invalidate that property for range patterns that // a new value might invalidate that property for range patterns that
// have already been sorted into the failure arm, so we must take care // have already been sorted into the failure arm, so we must take care
// not to add such values here. // not to add such values here.
let is_covering_range = |test_case: &TestCase<'_, 'tcx>| { let is_covering_range = |test_case: &TestCase<'tcx>| {
test_case.as_range().is_some_and(|range| { test_case.as_range().is_some_and(|range| {
matches!( matches!(
range.contains(value, self.tcx, self.typing_env()), range.contains(value, self.tcx, self.typing_env()),
@ -573,7 +574,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
) )
}) })
}; };
let is_conflicting_candidate = |candidate: &&mut Candidate<'_, 'tcx>| { let is_conflicting_candidate = |candidate: &&mut Candidate<'tcx>| {
candidate candidate
.match_pairs .match_pairs
.iter() .iter()
@ -685,8 +686,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} }
} }
(TestKind::Range(test), &TestCase::Range(pat)) => { (TestKind::Range(test), TestCase::Range(pat)) => {
if test.as_ref() == pat { if test == pat {
fully_matched = true; fully_matched = true;
Some(TestBranch::Success) Some(TestBranch::Success)
} else { } else {

View file

@ -67,7 +67,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// a MIR pass run after borrow checking. /// a MIR pass run after borrow checking.
pub(super) fn collect_fake_borrows<'tcx>( pub(super) fn collect_fake_borrows<'tcx>(
cx: &mut Builder<'_, 'tcx>, cx: &mut Builder<'_, 'tcx>,
candidates: &[Candidate<'_, 'tcx>], candidates: &[Candidate<'tcx>],
temp_span: Span, temp_span: Span,
scrutinee_base: PlaceBase, scrutinee_base: PlaceBase,
) -> Vec<(Place<'tcx>, Local, FakeBorrowKind)> { ) -> Vec<(Place<'tcx>, Local, FakeBorrowKind)> {
@ -135,7 +135,7 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
} }
} }
fn visit_candidate(&mut self, candidate: &Candidate<'_, 'tcx>) { fn visit_candidate(&mut self, candidate: &Candidate<'tcx>) {
for binding in &candidate.extra_data.bindings { for binding in &candidate.extra_data.bindings {
self.visit_binding(binding); self.visit_binding(binding);
} }
@ -144,7 +144,7 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
} }
} }
fn visit_flat_pat(&mut self, flat_pat: &FlatPat<'_, 'tcx>) { fn visit_flat_pat(&mut self, flat_pat: &FlatPat<'tcx>) {
for binding in &flat_pat.extra_data.bindings { for binding in &flat_pat.extra_data.bindings {
self.visit_binding(binding); self.visit_binding(binding);
} }
@ -153,7 +153,7 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
} }
} }
fn visit_match_pair(&mut self, match_pair: &MatchPairTree<'_, 'tcx>) { fn visit_match_pair(&mut self, match_pair: &MatchPairTree<'tcx>) {
if let TestCase::Or { pats, .. } = &match_pair.test_case { if let TestCase::Or { pats, .. } = &match_pair.test_case {
for flat_pat in pats.iter() { for flat_pat in pats.iter() {
self.visit_flat_pat(flat_pat) self.visit_flat_pat(flat_pat)

View file

@ -676,12 +676,14 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
let mut interpreted_as_const = None; let mut interpreted_as_const = None;
let mut interpreted_as_const_sugg = None; let mut interpreted_as_const_sugg = None;
if let PatKind::ExpandedConstant { def_id, is_inline: false, .. } // These next few matches want to peek through `AscribeUserType` to see
| PatKind::AscribeUserType { // the underlying pattern.
subpattern: let mut unpeeled_pat = pat;
box Pat { kind: PatKind::ExpandedConstant { def_id, is_inline: false, .. }, .. }, while let PatKind::AscribeUserType { ref subpattern, .. } = unpeeled_pat.kind {
.. unpeeled_pat = subpattern;
} = pat.kind }
if let PatKind::ExpandedConstant { def_id, is_inline: false, .. } = unpeeled_pat.kind
&& let DefKind::Const = self.tcx.def_kind(def_id) && let DefKind::Const = self.tcx.def_kind(def_id)
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span) && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span)
// We filter out paths with multiple path::segments. // We filter out paths with multiple path::segments.
@ -692,11 +694,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
// When we encounter a constant as the binding name, point at the `const` definition. // When we encounter a constant as the binding name, point at the `const` definition.
interpreted_as_const = Some(span); interpreted_as_const = Some(span);
interpreted_as_const_sugg = Some(InterpretedAsConst { span: pat.span, variable }); interpreted_as_const_sugg = Some(InterpretedAsConst { span: pat.span, variable });
} else if let PatKind::Constant { .. } } else if let PatKind::Constant { .. } = unpeeled_pat.kind
| PatKind::AscribeUserType {
subpattern: box Pat { kind: PatKind::Constant { .. }, .. },
..
} = pat.kind
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span) && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span)
{ {
// If the pattern to match is an integer literal: // If the pattern to match is an integer literal:

View file

@ -208,7 +208,7 @@ impl<'tcx> ConstToPat<'tcx> {
let field = FieldIdx::new(idx); let field = FieldIdx::new(idx);
// Patterns can only use monomorphic types. // Patterns can only use monomorphic types.
let ty = self.tcx.normalize_erasing_regions(self.typing_env, ty); let ty = self.tcx.normalize_erasing_regions(self.typing_env, ty);
FieldPat { field, pattern: self.valtree_to_pat(val, ty) } FieldPat { field, pattern: *self.valtree_to_pat(val, ty) }
}) })
.collect() .collect()
} }
@ -277,7 +277,7 @@ impl<'tcx> ConstToPat<'tcx> {
prefix: cv prefix: cv
.unwrap_branch() .unwrap_branch()
.iter() .iter()
.map(|val| self.valtree_to_pat(*val, *elem_ty)) .map(|val| *self.valtree_to_pat(*val, *elem_ty))
.collect(), .collect(),
slice: None, slice: None,
suffix: Box::new([]), suffix: Box::new([]),
@ -286,7 +286,7 @@ impl<'tcx> ConstToPat<'tcx> {
prefix: cv prefix: cv
.unwrap_branch() .unwrap_branch()
.iter() .iter()
.map(|val| self.valtree_to_pat(*val, *elem_ty)) .map(|val| *self.valtree_to_pat(*val, *elem_ty))
.collect(), .collect(),
slice: None, slice: None,
suffix: Box::new([]), suffix: Box::new([]),

View file

@ -4,6 +4,7 @@ mod check_match;
mod const_to_pat; mod const_to_pat;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::sync::Arc;
use rustc_abi::{FieldIdx, Integer}; use rustc_abi::{FieldIdx, Integer};
use rustc_errors::MultiSpan; use rustc_errors::MultiSpan;
@ -262,7 +263,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
let hi = lower_endpoint(hi_expr)?.unwrap_or(PatRangeBoundary::PosInfinity); let hi = lower_endpoint(hi_expr)?.unwrap_or(PatRangeBoundary::PosInfinity);
let cmp = lo.compare_with(hi, ty, self.tcx, self.typing_env); let cmp = lo.compare_with(hi, ty, self.tcx, self.typing_env);
let mut kind = PatKind::Range(Box::new(PatRange { lo, hi, end, ty })); let mut kind = PatKind::Range(Arc::new(PatRange { lo, hi, end, ty }));
match (end, cmp) { match (end, cmp) {
// `x..y` where `x < y`. // `x..y` where `x < y`.
(RangeEnd::Excluded, Some(Ordering::Less)) => {} (RangeEnd::Excluded, Some(Ordering::Less)) => {}
@ -418,7 +419,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
.iter() .iter()
.map(|field| FieldPat { .map(|field| FieldPat {
field: self.typeck_results.field_index(field.hir_id), field: self.typeck_results.field_index(field.hir_id),
pattern: self.lower_pattern(field.pat), pattern: *self.lower_pattern(field.pat),
}) })
.collect(); .collect();
@ -446,13 +447,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
.enumerate_and_adjust(expected_len, gap_pos) .enumerate_and_adjust(expected_len, gap_pos)
.map(|(i, subpattern)| FieldPat { .map(|(i, subpattern)| FieldPat {
field: FieldIdx::new(i), field: FieldIdx::new(i),
pattern: self.lower_pattern(subpattern), pattern: *self.lower_pattern(subpattern),
}) })
.collect() .collect()
} }
fn lower_patterns(&mut self, pats: &'tcx [hir::Pat<'tcx>]) -> Box<[Box<Pat<'tcx>>]> { fn lower_patterns(&mut self, pats: &'tcx [hir::Pat<'tcx>]) -> Box<[Pat<'tcx>]> {
pats.iter().map(|p| self.lower_pattern(p)).collect() pats.iter().map(|p| *self.lower_pattern(p)).collect()
} }
fn lower_opt_pattern(&mut self, pat: Option<&'tcx hir::Pat<'tcx>>) -> Option<Box<Pat<'tcx>>> { fn lower_opt_pattern(&mut self, pat: Option<&'tcx hir::Pat<'tcx>>) -> Option<Box<Pat<'tcx>>> {

View file

@ -643,8 +643,8 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
print_indented!(self, "}", depth_lvl); print_indented!(self, "}", depth_lvl);
} }
fn print_pat(&mut self, pat: &Box<Pat<'tcx>>, depth_lvl: usize) { fn print_pat(&mut self, pat: &Pat<'tcx>, depth_lvl: usize) {
let Pat { ty, span, kind } = &**pat; let &Pat { ty, span, ref kind } = pat;
print_indented!(self, "Pat: {", depth_lvl); print_indented!(self, "Pat: {", depth_lvl);
print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1); print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1);

View file

@ -373,7 +373,8 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> {
match pat.kind { match pat.kind {
thir::PatKind::Constant { value } => value.has_non_region_param(), thir::PatKind::Constant { value } => value.has_non_region_param(),
thir::PatKind::Range(box thir::PatRange { lo, hi, .. }) => { thir::PatKind::Range(ref range) => {
let &thir::PatRange { lo, hi, .. } = range.as_ref();
lo.has_non_region_param() || hi.has_non_region_param() lo.has_non_region_param() || hi.has_non_region_param()
} }
_ => false, _ => false,