Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/arena.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ macro_rules! arena_types {
[] tys: rustc_type_ir::WithCachedTypeInfo<rustc_middle::ty::TyKind<'tcx>>,
[] predicates: rustc_type_ir::WithCachedTypeInfo<rustc_middle::ty::PredicateKind<'tcx>>,
[] consts: rustc_middle::ty::ConstData<'tcx>,
[] pats: rustc_middle::thir::Pat<'tcx>,

// Note that this deliberately duplicates items in the `rustc_hir::arena`,
// since we need to allocate this type on both the `rustc_hir` arena
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use super::sty::ConstKind;
/// Use this rather than `ConstData`, whenever possible.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
#[rustc_pass_by_value]
pub struct Const<'tcx>(pub(super) Interned<'tcx, ConstData<'tcx>>);
pub struct Const<'tcx>(pub Interned<'tcx, ConstData<'tcx>>);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this has still not been addressed


/// Typed constant value.
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, TyEncodable, TyDecodable)]
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_middle/src/ty/consts/valtree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ impl<'tcx> ValTree<'tcx> {
Self::Branch(interned)
}

pub fn from_scalars<'a>(tcx: TyCtxt<'tcx>, scalars: &'a [ScalarInt]) -> Self {
Comment thread
john-h-k marked this conversation as resolved.
Outdated
let interned = tcx.arena.alloc_from_iter(scalars.iter().map(|&s| Self::Leaf(s)));

Self::Branch(interned)
}

pub fn from_scalar_int(i: ScalarInt) -> Self {
Self::Leaf(i)
}
Expand Down
114 changes: 97 additions & 17 deletions compiler/rustc_mir_build/src/build/matches/simplify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@
use crate::build::expr::as_place::PlaceBuilder;
use crate::build::matches::{Ascription, Binding, Candidate, MatchPair};
use crate::build::Builder;
use rustc_data_structures::intern::Interned;
use rustc_hir::RangeEnd;
use rustc_middle::mir::ConstantKind;
use rustc_middle::thir::{self, *};
use rustc_middle::ty;
use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::Const;
use rustc_middle::ty::{self, Ty, ValTree};
use rustc_target::abi::{Integer, Size};

use std::mem;
Expand Down Expand Up @@ -120,6 +123,38 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}

fn try_build_valtree(&self, elements: &Box<[Box<Pat<'tcx>>]>) -> Option<ValTree<'tcx>> {
if elements.iter().all(|p| {
matches!(
p.kind,
PatKind::Constant {
value: ConstantKind::Ty(ty::Const(Interned(
ty::ConstData { kind: ty::ConstKind::Value(ty::ValTree::Leaf(_)), .. },
_
)))
}
)
}) {
// This ValTree represents the content of the simple array.
// We then create a new pattern that matches against this ValTree.
// This reduces a match against `[1, 2, 3, 4]` from 4 basic-blocks in the MIR to just 1
Some(ValTree::from_scalars(
self.tcx,
&elements
.iter()
.map(|p| match p.kind {
PatKind::Constant { value: ConstantKind::Ty(c) } => {
c.to_valtree().unwrap_leaf()
}
_ => unreachable!(),
})
.collect::<Vec<_>>(),
))
} else {
None
}
}

/// Given `candidate` that has a single or-pattern for its match-pairs,
/// creates a fresh candidate for each of its input subpatterns passed via
/// `pats`.
Expand Down Expand Up @@ -243,22 +278,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Err(match_pair)
}

PatKind::Slice { ref prefix, ref slice, ref suffix } => {
if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
// irrefutable
self.prefix_slice_suffix(
&mut candidate.match_pairs,
&match_pair.place,
prefix,
slice,
suffix,
);
Ok(())
} else {
Err(match_pair)
}
}

PatKind::Variant { adt_def, args, variant_index, ref subpatterns } => {
let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
i == variant_index || {
Expand All @@ -281,6 +300,51 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}

// Looks for simple array patterns such as `[1, 2, 3]`
// They cannot have slices (e.g `[1, .., 3, 4]` is not simple), and
// all the elements of the array must be leaf constants (so no strings!)
PatKind::Array { ref prefix, slice: None, ref suffix }
| PatKind::Slice { ref prefix, slice: None, ref suffix }
if let Some(_val) = self.try_build_valtree(prefix)
&& !prefix.is_empty()
&& suffix.is_empty() =>
{
// This ValTree represents the content of the simple array.
// We then create a new pattern that matches against this ValTree.
// This reduces a match against `[1, 2, 3, 4]` from 4 basic-blocks in the MIR to just 1
let val = self.try_build_valtree(prefix).unwrap(); // FIXME: false positive

let el_ty = prefix.iter().next().unwrap().ty;
let (place, cnst_ty, pat_ty) =
if match_pair.pattern.ty.is_slice() {
(
PlaceBuilder::from(match_pair.place.base()),
Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, Ty::new_array(tcx, el_ty, prefix.len() as u64)),
Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, Ty::new_slice(tcx, el_ty))
)
} else {
let arr_ty = Ty::new_array(tcx, el_ty, prefix.len() as u64);
(
match_pair.place,
arr_ty,
arr_ty
)
};

let cnst = Const::new(tcx, ty::ConstKind::Value(val), cnst_ty);
let new_pat = Pat {
ty: pat_ty,
span: match_pair.pattern.span,
kind: PatKind::Constant { value: ConstantKind::Ty(cnst) },
};

let pat = tcx.arena.alloc(new_pat);

candidate.match_pairs.push(MatchPair::new(place, pat, self));

Ok(())
}

PatKind::Array { ref prefix, ref slice, ref suffix } => {
self.prefix_slice_suffix(
&mut candidate.match_pairs,
Expand All @@ -292,6 +356,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Ok(())
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should this special case be moved to prefix_slice_suffix? Once for the prefix and once for the suffix?


PatKind::Slice { ref prefix, ref slice, ref suffix } => {
if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
// irrefutable
self.prefix_slice_suffix(
&mut candidate.match_pairs,
&match_pair.place,
prefix,
slice,
suffix,
);
Ok(())
} else {
Err(match_pair)
}
}

PatKind::Leaf { ref subpatterns } => {
// tuple struct, match subpats (if any)
candidate.match_pairs.extend(self.field_match_pairs(match_pair.place, subpatterns));
Expand Down
7 changes: 5 additions & 2 deletions compiler/rustc_mir_build/src/build/matches/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
};

match match_pair.pattern.kind {
PatKind::Constant { value } => {
PatKind::Constant {
value
} if let Some(result) = value.try_eval_bits(self.tcx, self.param_env, switch_ty) => {
options
.entry(value)
.or_insert_with(|| value.eval_bits(self.tcx, self.param_env, switch_ty));
.or_insert(result);
true
}
PatKind::Variant { .. } => {
Expand All @@ -108,6 +110,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.values_not_contained_in_range(&*range, options).unwrap_or(false)
}
PatKind::Slice { .. }
| PatKind::Constant { .. }
| PatKind::Array { .. }
| PatKind::Wild
| PatKind::Or { .. }
Expand Down