Skip to content

[MIR] Fix equality checks in matching code #30651

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 1 commit into from
Jan 4, 2016
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
2 changes: 1 addition & 1 deletion src/librustc_mir/build/matches/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ enum TestKind<'tcx> {

// test for equality
Eq {
value: Literal<'tcx>,
value: ConstVal,
ty: Ty<'tcx>,
},

Expand Down
55 changes: 11 additions & 44 deletions src/librustc_mir/build/matches/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
}
}

PatternKind::Constant { value: Literal::Value { .. } }
PatternKind::Constant { .. }
if is_switch_ty(match_pair.pattern.ty) => {
// for integers, we use a SwitchInt match, which allows
// us to handle more cases
Expand All @@ -55,12 +55,11 @@ impl<'a,'tcx> Builder<'a,'tcx> {
}

PatternKind::Constant { ref value } => {
// for other types, we use an equality comparison
Test {
span: match_pair.pattern.span,
kind: TestKind::Eq {
value: value.clone(),
ty: match_pair.pattern.ty.clone(),
ty: match_pair.pattern.ty.clone()
}
}
}
Expand Down Expand Up @@ -113,7 +112,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
};

match *match_pair.pattern.kind {
PatternKind::Constant { value: Literal::Value { ref value } } => {
PatternKind::Constant { ref value } => {
// if the lvalues match, the type should match
assert_eq!(match_pair.pattern.ty, switch_ty);

Expand All @@ -126,7 +125,6 @@ impl<'a,'tcx> Builder<'a,'tcx> {
}

PatternKind::Range { .. } |
PatternKind::Constant { .. } |
PatternKind::Variant { .. } |
PatternKind::Slice { .. } |
PatternKind::Array { .. } |
Expand Down Expand Up @@ -177,11 +175,13 @@ impl<'a,'tcx> Builder<'a,'tcx> {
}

TestKind::Eq { ref value, ty } => {
// call PartialEq::eq(discrim, constant)
let constant = self.literal_operand(test.span, ty.clone(), value.clone());
let item_ref = self.hir.partial_eq(ty);
self.call_comparison_fn(block, test.span, item_ref,
Operand::Consume(lvalue.clone()), constant)
let expect = self.literal_operand(test.span, ty.clone(), Literal::Value {
value: value.clone()
});
let val = Operand::Consume(lvalue.clone());
let fail = self.cfg.start_new_block();
let block = self.compare(block, fail, test.span, BinOp::Eq, expect, val.clone());
vec![block, fail]
}

TestKind::Range { ref lo, ref hi, ty } => {
Expand Down Expand Up @@ -251,39 +251,6 @@ impl<'a,'tcx> Builder<'a,'tcx> {
target_block
}

fn call_comparison_fn(&mut self,
block: BasicBlock,
span: Span,
item_ref: ItemRef<'tcx>,
lvalue1: Operand<'tcx>,
lvalue2: Operand<'tcx>)
-> Vec<BasicBlock> {
let target_blocks = vec![self.cfg.start_new_block(), self.cfg.start_new_block()];

let bool_ty = self.hir.bool_ty();
let eq_result = self.temp(bool_ty);
let func = self.item_ref_operand(span, item_ref);
let call_blocks = (self.cfg.start_new_block(), self.diverge_cleanup());
self.cfg.terminate(block,
Terminator::Call {
data: CallData {
destination: eq_result.clone(),
func: func,
args: vec![lvalue1, lvalue2],
},
targets: call_blocks,
});

// check the result
self.cfg.terminate(call_blocks.0,
Terminator::If {
cond: Operand::Consume(eq_result),
targets: (target_blocks[0], target_blocks[1]),
});

target_blocks
}

/// Given that we are performing `test` against `test_lvalue`,
/// this job sorts out what the status of `candidate` will be
/// after the test. The `resulting_candidates` vector stores, for
Expand Down Expand Up @@ -368,7 +335,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
// things out here, in some cases.
TestKind::SwitchInt { switch_ty: _, options: _, ref indices } => {
match *match_pair.pattern.kind {
PatternKind::Constant { value: Literal::Value { ref value } }
PatternKind::Constant { ref value }
if is_switch_ty(match_pair.pattern.ty) => {
let index = indices[value];
let new_candidate = self.candidate_without_match_pair(match_pair_index,
Expand Down
37 changes: 0 additions & 37 deletions src/librustc_mir/hair/cx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,9 @@ use hair::*;
use rustc::mir::repr::*;

use rustc::middle::const_eval::{self, ConstVal};
use rustc::middle::def_id::DefId;
use rustc::middle::infer::InferCtxt;
use rustc::middle::subst::{Subst, Substs};
use rustc::middle::ty::{self, Ty};
use syntax::codemap::Span;
use syntax::parse::token;
use rustc_front::hir;

#[derive(Copy, Clone)]
Expand Down Expand Up @@ -83,11 +80,6 @@ impl<'a,'tcx:'a> Cx<'a, 'tcx> {
.map(|v| Literal::Value { value: v })
}

pub fn partial_eq(&mut self, ty: Ty<'tcx>) -> ItemRef<'tcx> {
let eq_def_id = self.tcx.lang_items.eq_trait().unwrap();
self.cmp_method_ref(eq_def_id, "eq", ty)
}

pub fn num_variants(&mut self, adt_def: ty::AdtDef<'tcx>) -> usize {
adt_def.variants.len()
}
Expand Down Expand Up @@ -118,35 +110,6 @@ impl<'a,'tcx:'a> Cx<'a, 'tcx> {
pub fn tcx(&self) -> &'a ty::ctxt<'tcx> {
self.tcx
}

fn cmp_method_ref(&mut self,
trait_def_id: DefId,
method_name: &str,
arg_ty: Ty<'tcx>)
-> ItemRef<'tcx> {
let method_name = token::intern(method_name);
let substs = Substs::new_trait(vec![arg_ty], vec![], arg_ty);
for trait_item in self.tcx.trait_items(trait_def_id).iter() {
match *trait_item {
ty::ImplOrTraitItem::MethodTraitItem(ref method) => {
if method.name == method_name {
let method_ty = self.tcx.lookup_item_type(method.def_id);
let method_ty = method_ty.ty.subst(self.tcx, &substs);
return ItemRef {
ty: method_ty,
kind: ItemKind::Method,
def_id: method.def_id,
substs: self.tcx.mk_substs(substs),
};
}
}
ty::ImplOrTraitItem::ConstTraitItem(..) |
ty::ImplOrTraitItem::TypeTraitItem(..) => {}
}
}

self.tcx.sess.bug(&format!("found no method `{}` in `{:?}`", method_name, trait_def_id));
}
}

mod block;
Expand Down
78 changes: 32 additions & 46 deletions src/librustc_mir/hair/cx/pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ use rustc_data_structures::fnv::FnvHashMap;
use rustc::middle::const_eval;
use rustc::middle::def;
use rustc::middle::pat_util::{pat_is_resolved_const, pat_is_binding};
use rustc::middle::subst::Substs;
use rustc::middle::ty::{self, Ty};
use rustc::mir::repr::*;
use rustc_front::hir;
use syntax::ast;
use syntax::codemap::Span;
use syntax::ptr::P;

/// When there are multiple patterns in a single arm, each one has its
Expand All @@ -40,15 +40,15 @@ struct PatCx<'patcx, 'cx: 'patcx, 'tcx: 'cx> {
}

impl<'cx, 'tcx> Cx<'cx, 'tcx> {
pub fn irrefutable_pat(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> {
PatCx::new(self, None).to_pat(pat)
pub fn irrefutable_pat(&mut self, pat: &hir::Pat) -> Pattern<'tcx> {
PatCx::new(self, None).to_pattern(pat)
}

pub fn refutable_pat(&mut self,
binding_map: Option<&FnvHashMap<ast::Name, ast::NodeId>>,
pat: &'tcx hir::Pat)
pat: &hir::Pat)
-> Pattern<'tcx> {
PatCx::new(self, binding_map).to_pat(pat)
PatCx::new(self, binding_map).to_pattern(pat)
}
}

Expand All @@ -62,13 +62,12 @@ impl<'patcx, 'cx, 'tcx> PatCx<'patcx, 'cx, 'tcx> {
}
}

fn to_pat(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> {
fn to_pattern(&mut self, pat: &hir::Pat) -> Pattern<'tcx> {
let kind = match pat.node {
hir::PatWild => PatternKind::Wild,

hir::PatLit(ref value) => {
let value = const_eval::eval_const_expr(self.cx.tcx, value);
let value = Literal::Value { value: value };
PatternKind::Constant { value: value }
}

Expand All @@ -88,22 +87,9 @@ impl<'patcx, 'cx, 'tcx> PatCx<'patcx, 'cx, 'tcx> {
def::DefConst(def_id) | def::DefAssociatedConst(def_id) =>
match const_eval::lookup_const_by_id(self.cx.tcx, def_id, Some(pat.id)) {
Some(const_expr) => {
let opt_value =
const_eval::eval_const_expr_partial(
self.cx.tcx, const_expr,
const_eval::EvalHint::ExprTypeChecked,
None);
let literal = if let Ok(value) = opt_value {
Literal::Value { value: value }
} else {
let substs = self.cx.tcx.mk_substs(Substs::empty());
Literal::Item {
def_id: def_id,
kind: ItemKind::Constant,
substs: substs
}
};
PatternKind::Constant { value: literal }
let pat = const_eval::const_expr_to_pat(self.cx.tcx, const_expr,
pat.span);
Copy link
Member

Choose a reason for hiding this comment

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

Would be nice if we can use HAIR to avoid allocating here.

Copy link
Member

Choose a reason for hiding this comment

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

Nevermind, that would overcomplicate too many things.

return self.to_pattern(&*pat);
}
None => {
self.cx.tcx.sess.span_bug(
Expand All @@ -120,7 +106,7 @@ impl<'patcx, 'cx, 'tcx> PatCx<'patcx, 'cx, 'tcx> {

hir::PatRegion(ref subpattern, _) |
hir::PatBox(ref subpattern) => {
PatternKind::Deref { subpattern: self.to_pat(subpattern) }
PatternKind::Deref { subpattern: self.to_pattern(subpattern) }
}

hir::PatVec(ref prefix, ref slice, ref suffix) => {
Expand All @@ -131,14 +117,14 @@ impl<'patcx, 'cx, 'tcx> PatCx<'patcx, 'cx, 'tcx> {
subpattern: Pattern {
ty: mt.ty,
span: pat.span,
kind: Box::new(self.slice_or_array_pattern(pat, mt.ty, prefix,
kind: Box::new(self.slice_or_array_pattern(pat.span, mt.ty, prefix,
slice, suffix)),
},
},

ty::TySlice(..) |
ty::TyArray(..) =>
self.slice_or_array_pattern(pat, ty, prefix, slice, suffix),
self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix),

ref sty =>
self.cx.tcx.sess.span_bug(
Expand All @@ -153,7 +139,7 @@ impl<'patcx, 'cx, 'tcx> PatCx<'patcx, 'cx, 'tcx> {
.enumerate()
.map(|(i, subpattern)| FieldPattern {
field: Field::new(i),
pattern: self.to_pat(subpattern),
pattern: self.to_pattern(subpattern),
})
.collect();

Expand Down Expand Up @@ -188,7 +174,7 @@ impl<'patcx, 'cx, 'tcx> PatCx<'patcx, 'cx, 'tcx> {
name: ident.node.name,
var: id,
ty: var_ty,
subpattern: self.to_opt_pat(sub),
subpattern: self.to_opt_pattern(sub),
}
}

Expand All @@ -203,7 +189,7 @@ impl<'patcx, 'cx, 'tcx> PatCx<'patcx, 'cx, 'tcx> {
.enumerate()
.map(|(i, field)| FieldPattern {
field: Field::new(i),
pattern: self.to_pat(field),
pattern: self.to_pattern(field),
})
.collect();
self.variant_or_leaf(pat, subpatterns)
Expand Down Expand Up @@ -234,7 +220,7 @@ impl<'patcx, 'cx, 'tcx> PatCx<'patcx, 'cx, 'tcx> {
});
FieldPattern {
field: Field::new(index),
pattern: self.to_pat(&field.node.pat),
pattern: self.to_pattern(&field.node.pat),
}
})
.collect();
Expand All @@ -256,49 +242,49 @@ impl<'patcx, 'cx, 'tcx> PatCx<'patcx, 'cx, 'tcx> {
}
}

fn to_pats(&mut self, pats: &'tcx [P<hir::Pat>]) -> Vec<Pattern<'tcx>> {
pats.iter().map(|p| self.to_pat(p)).collect()
fn to_patterns(&mut self, pats: &[P<hir::Pat>]) -> Vec<Pattern<'tcx>> {
pats.iter().map(|p| self.to_pattern(p)).collect()
}

fn to_opt_pat(&mut self, pat: &'tcx Option<P<hir::Pat>>) -> Option<Pattern<'tcx>> {
pat.as_ref().map(|p| self.to_pat(p))
fn to_opt_pattern(&mut self, pat: &Option<P<hir::Pat>>) -> Option<Pattern<'tcx>> {
pat.as_ref().map(|p| self.to_pattern(p))
}

fn slice_or_array_pattern(&mut self,
pat: &'tcx hir::Pat,
span: Span,
ty: Ty<'tcx>,
prefix: &'tcx [P<hir::Pat>],
slice: &'tcx Option<P<hir::Pat>>,
suffix: &'tcx [P<hir::Pat>])
prefix: &[P<hir::Pat>],
slice: &Option<P<hir::Pat>>,
suffix: &[P<hir::Pat>])
-> PatternKind<'tcx> {
match ty.sty {
ty::TySlice(..) => {
// matching a slice or fixed-length array
PatternKind::Slice {
prefix: self.to_pats(prefix),
slice: self.to_opt_pat(slice),
suffix: self.to_pats(suffix),
prefix: self.to_patterns(prefix),
slice: self.to_opt_pattern(slice),
suffix: self.to_patterns(suffix),
}
}

ty::TyArray(_, len) => {
// fixed-length array
assert!(len >= prefix.len() + suffix.len());
PatternKind::Array {
prefix: self.to_pats(prefix),
slice: self.to_opt_pat(slice),
suffix: self.to_pats(suffix),
prefix: self.to_patterns(prefix),
slice: self.to_opt_pattern(slice),
suffix: self.to_patterns(suffix),
}
}

_ => {
self.cx.tcx.sess.span_bug(pat.span, "unexpanded macro or bad constant etc");
self.cx.tcx.sess.span_bug(span, "unexpanded macro or bad constant etc");
}
}
}

fn variant_or_leaf(&mut self,
pat: &'tcx hir::Pat,
pat: &hir::Pat,
subpatterns: Vec<FieldPattern<'tcx>>)
-> PatternKind<'tcx> {
let def = self.cx.tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_mir/hair/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
//! structures.

use rustc::mir::repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp, ItemKind};
use rustc::middle::const_eval::ConstVal;
use rustc::middle::def_id::DefId;
use rustc::middle::region::CodeExtent;
use rustc::middle::subst::Substs;
Expand Down Expand Up @@ -305,7 +306,7 @@ pub enum PatternKind<'tcx> {
}, // box P, &P, &mut P, etc

Constant {
value: Literal<'tcx>,
value: ConstVal,
},

Range {
Expand Down
Loading