Skip to content

Stop creating fake HIR pattern nodes. #38766

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 2, 2017
Merged
Show file tree
Hide file tree
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
145 changes: 62 additions & 83 deletions src/librustc_const_eval/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,12 @@ use rustc_data_structures::indexed_vec::Idx;
use pattern::{FieldPattern, Pattern, PatternKind};
use pattern::{PatternFoldable, PatternFolder};

use rustc::hir::def::Def;
use rustc::hir::def_id::DefId;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};

use rustc::hir;
use rustc::hir::def::CtorKind;
use rustc::hir::{Pat, PatKind};
use rustc::mir::Field;
use rustc::util::common::ErrorReported;

use syntax::ast::{self, DUMMY_NODE_ID};
use syntax::codemap::Spanned;
use syntax::ptr::P;
use syntax_pos::{Span, DUMMY_SP};

use arena::TypedArena;
Expand Down Expand Up @@ -74,12 +68,6 @@ impl<'tcx> PatternFolder<'tcx> for LiteralExpander {
}
}

pub const DUMMY_WILD_PAT: &'static Pat = &Pat {
id: DUMMY_NODE_ID,
node: PatKind::Wild,
span: DUMMY_SP
};

impl<'tcx> Pattern<'tcx> {
fn is_wildcard(&self) -> bool {
match *self.kind {
Expand Down Expand Up @@ -224,25 +212,34 @@ pub enum Constructor {
}

impl<'tcx> Constructor {
fn variant_for_adt(&self, adt: &'tcx ty::AdtDef) -> &'tcx ty::VariantDef {
fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> usize {
match self {
&Variant(vid) => adt.variant_with_id(vid),
&Variant(vid) => adt.variant_index_with_id(vid),
&Single => {
assert_eq!(adt.variants.len(), 1);
&adt.variants[0]
0
}
_ => bug!("bad constructor {:?} for adt {:?}", self, adt)
}
}
}

#[derive(Clone, PartialEq)]
pub enum Usefulness {
#[derive(Clone)]
pub enum Usefulness<'tcx> {
Useful,
UsefulWithWitness(Vec<Witness>),
UsefulWithWitness(Vec<Witness<'tcx>>),
NotUseful
}

impl<'tcx> Usefulness<'tcx> {
fn is_useful(&self) -> bool {
match *self {
NotUseful => false,
_ => true
}
}
}

#[derive(Copy, Clone)]
pub enum WitnessPreference {
ConstructWitness,
Expand All @@ -255,39 +252,25 @@ struct PatternContext<'tcx> {
max_slice_length: usize,
}


fn const_val_to_expr(value: &ConstVal) -> P<hir::Expr> {
let node = match value {
&ConstVal::Bool(b) => ast::LitKind::Bool(b),
_ => bug!()
};
P(hir::Expr {
id: DUMMY_NODE_ID,
node: hir::ExprLit(P(Spanned { node: node, span: DUMMY_SP })),
span: DUMMY_SP,
attrs: ast::ThinVec::new(),
})
}

/// A stack of patterns in reverse order of construction
#[derive(Clone, PartialEq, Eq)]
pub struct Witness(Vec<P<Pat>>);
#[derive(Clone)]
pub struct Witness<'tcx>(Vec<Pattern<'tcx>>);

impl Witness {
pub fn single_pattern(&self) -> &Pat {
impl<'tcx> Witness<'tcx> {
pub fn single_pattern(&self) -> &Pattern<'tcx> {
assert_eq!(self.0.len(), 1);
&self.0[0]
}

fn push_wild_constructor<'a, 'tcx>(
fn push_wild_constructor<'a>(
mut self,
cx: &MatchCheckCtxt<'a, 'tcx>,
ctor: &Constructor,
ty: Ty<'tcx>)
-> Self
{
let arity = constructor_arity(cx, ctor, ty);
self.0.extend(repeat(DUMMY_WILD_PAT).take(arity).map(|p| P(p.clone())));
self.0.extend(repeat(cx.wild_pattern).take(arity).cloned());
self.apply_constructor(cx, ctor, ty)
}

Expand All @@ -305,7 +288,7 @@ impl Witness {
///
/// left_ty: struct X { a: (bool, &'static str), b: usize}
/// pats: [(false, "foo"), 42] => X { a: (false, "foo"), b: 42 }
fn apply_constructor<'a, 'tcx>(
fn apply_constructor<'a>(
mut self,
cx: &MatchCheckCtxt<'a,'tcx>,
ctor: &Constructor,
Expand All @@ -318,60 +301,56 @@ impl Witness {
let mut pats = self.0.drain(len-arity..).rev();

match ty.sty {
ty::TyTuple(..) => PatKind::Tuple(pats.collect(), None),

ty::TyAdt(adt, _) => {
let v = ctor.variant_for_adt(adt);
let qpath = hir::QPath::Resolved(None, P(hir::Path {
span: DUMMY_SP,
def: Def::Err,
segments: vec![hir::PathSegment::from_name(v.name)].into(),
}));
match v.ctor_kind {
CtorKind::Fictive => {
let field_pats: hir::HirVec<_> = v.fields.iter()
.zip(pats)
.filter(|&(_, ref pat)| pat.node != PatKind::Wild)
.map(|(field, pat)| Spanned {
span: DUMMY_SP,
node: hir::FieldPat {
name: field.name,
pat: pat,
is_shorthand: false,
}
}).collect();
let has_more_fields = field_pats.len() < arity;
PatKind::Struct(qpath, field_pats, has_more_fields)
ty::TyAdt(..) |
ty::TyTuple(..) => {
let pats = pats.enumerate().map(|(i, p)| {
FieldPattern {
field: Field::new(i),
pattern: p
}
CtorKind::Fn => {
PatKind::TupleStruct(qpath, pats.collect(), None)
}).collect();

if let ty::TyAdt(adt, _) = ty.sty {
if adt.variants.len() > 1 {
PatternKind::Variant {
adt_def: adt,
variant_index: ctor.variant_index_for_adt(adt),
subpatterns: pats
}
} else {
PatternKind::Leaf { subpatterns: pats }
}
CtorKind::Const => PatKind::Path(qpath)
} else {
PatternKind::Leaf { subpatterns: pats }
}
}

ty::TyRef(_, ty::TypeAndMut { mutbl, .. }) => {
PatKind::Ref(pats.nth(0).unwrap(), mutbl)
ty::TyRef(..) => {
PatternKind::Deref { subpattern: pats.nth(0).unwrap() }
}

ty::TySlice(_) | ty::TyArray(..) => {
PatKind::Slice(pats.collect(), None, hir::HirVec::new())
PatternKind::Slice {
prefix: pats.collect(),
slice: None,
suffix: vec![]
}
}

_ => {
match *ctor {
ConstantValue(ref v) => PatKind::Lit(const_val_to_expr(v)),
_ => PatKind::Wild,
ConstantValue(ref v) => PatternKind::Constant { value: v.clone() },
_ => PatternKind::Wild,
}
}
}
};

self.0.push(P(hir::Pat {
id: DUMMY_NODE_ID,
node: pat,
span: DUMMY_SP
}));
self.0.push(Pattern {
ty: ty,
span: DUMMY_SP,
kind: Box::new(pat),
});

self
}
Expand Down Expand Up @@ -528,13 +507,13 @@ pub fn is_useful<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
matrix: &Matrix<'a, 'tcx>,
v: &[&'a Pattern<'tcx>],
witness: WitnessPreference)
-> Usefulness {
-> Usefulness<'tcx> {
let &Matrix(ref rows) = matrix;
debug!("is_useful({:?}, {:?})", matrix, v);
if rows.is_empty() {
return match witness {
ConstructWitness => UsefulWithWitness(vec![Witness(
repeat(DUMMY_WILD_PAT).take(v.len()).map(|p| P(p.clone())).collect()
repeat(cx.wild_pattern).take(v.len()).cloned().collect()
)]),
LeaveOutWitness => Useful
};
Expand All @@ -559,15 +538,15 @@ pub fn is_useful<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
debug!("is_useful - expanding constructors: {:?}", constructors);
constructors.into_iter().map(|c|
is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness)
).find(|result| result != &NotUseful).unwrap_or(NotUseful)
).find(|result| result.is_useful()).unwrap_or(NotUseful)
} else {
debug!("is_useful - expanding wildcard");
let constructors = missing_constructors(cx, matrix, pcx);
debug!("is_useful - missing_constructors = {:?}", constructors);
if constructors.is_empty() {
all_constructors(cx, pcx).into_iter().map(|c| {
is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness)
}).find(|result| result != &NotUseful).unwrap_or(NotUseful)
}).find(|result| result.is_useful()).unwrap_or(NotUseful)
} else {
let matrix = rows.iter().filter_map(|r| {
if r[0].is_wildcard() {
Expand Down Expand Up @@ -597,7 +576,7 @@ fn is_useful_specialized<'a, 'tcx>(
v: &[&'a Pattern<'tcx>],
ctor: Constructor,
lty: Ty<'tcx>,
witness: WitnessPreference) -> Usefulness
witness: WitnessPreference) -> Usefulness<'tcx>
{
let arity = constructor_arity(cx, &ctor, lty);
let matrix = Matrix(m.iter().flat_map(|r| {
Expand Down Expand Up @@ -672,7 +651,7 @@ fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> usize
},
ty::TyRef(..) => 1,
ty::TyAdt(adt, _) => {
ctor.variant_for_adt(adt).fields.len()
adt.variants[ctor.variant_index_for_adt(adt)].fields.len()
}
_ => 0
}
Expand Down
43 changes: 15 additions & 28 deletions src/librustc_const_eval/check_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@
// except according to those terms.

use _match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful};
use _match::{DUMMY_WILD_PAT};
use _match::Usefulness::*;
use _match::WitnessPreference::*;

use pattern::{Pattern, PatternContext, PatternError};
use pattern::{Pattern, PatternContext, PatternError, PatternKind};

use eval::report_const_eval_err;

Expand Down Expand Up @@ -117,13 +116,6 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
fn report_inlining_errors(&self, patcx: PatternContext, pat_span: Span) {
for error in patcx.errors {
match error {
PatternError::BadConstInPattern(span, def_id) => {
self.tcx.sess.span_err(
span,
&format!("constants of the type `{}` \
cannot be used in patterns",
self.tcx.item_path_str(def_id)));
}
PatternError::StaticInPattern(span) => {
span_err!(self.tcx.sess, span, E0158,
"statics cannot be referenced in patterns");
Expand Down Expand Up @@ -230,9 +222,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
Useful => bug!()
};

let pattern_string = hir::print::to_string(&self.tcx.map, |s| {
s.print_pat(witness[0].single_pattern())
});
let pattern_string = witness[0].single_pattern().to_string();
let mut diag = struct_span_err!(
self.tcx.sess, pat.span, E0005,
"refutable pattern in {}: `{}` not covered",
Expand Down Expand Up @@ -369,23 +359,21 @@ fn check_exhaustive<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
match is_useful(cx, matrix, &[cx.wild_pattern], ConstructWitness) {
UsefulWithWitness(pats) => {
let witnesses = if pats.is_empty() {
vec![DUMMY_WILD_PAT]
vec![cx.wild_pattern]
} else {
pats.iter().map(|w| w.single_pattern()).collect()
};
match source {
hir::MatchSource::ForLoopDesugar => {
// `witnesses[0]` has the form `Some(<head>)`, peel off the `Some`
let witness = match witnesses[0].node {
PatKind::TupleStruct(_, ref pats, _) => match &pats[..] {
&[ref pat] => &**pat,
let witness = match *witnesses[0].kind {
PatternKind::Variant { ref subpatterns, .. } => match &subpatterns[..] {
&[ref pat] => &pat.pattern,
_ => bug!(),
},
_ => bug!(),
};
let pattern_string = hir::print::to_string(&cx.tcx.map, |s| {
s.print_pat(witness)
});
let pattern_string = witness.to_string();
struct_span_err!(cx.tcx.sess, sp, E0297,
"refutable pattern in `for` loop binding: \
`{}` not covered",
Expand All @@ -394,24 +382,23 @@ fn check_exhaustive<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
.emit();
},
_ => {
let pattern_strings: Vec<_> = witnesses.iter().map(|w| {
hir::print::to_string(&cx.tcx.map, |s| s.print_pat(w))
}).collect();
const LIMIT: usize = 3;
let joined_patterns = match pattern_strings.len() {
let joined_patterns = match witnesses.len() {
0 => bug!(),
1 => format!("`{}`", pattern_strings[0]),
1 => format!("`{}`", witnesses[0]),
2...LIMIT => {
let (tail, head) = pattern_strings.split_last().unwrap();
format!("`{}`", head.join("`, `") + "` and `" + tail)
let (tail, head) = witnesses.split_last().unwrap();
let head: Vec<_> = head.iter().map(|w| w.to_string()).collect();
format!("`{}` and `{}`", head.join("`, `"), tail)
},
_ => {
let (head, tail) = pattern_strings.split_at(LIMIT);
let (head, tail) = witnesses.split_at(LIMIT);
let head: Vec<_> = head.iter().map(|w| w.to_string()).collect();
format!("`{}` and {} more", head.join("`, `"), tail.len())
}
};

let label_text = match pattern_strings.len(){
let label_text = match witnesses.len() {
1 => format!("pattern {} not covered", joined_patterns),
_ => format!("patterns {} not covered", joined_patterns)
};
Expand Down
Loading