Skip to content

Commit

Permalink
Use built-in comparisons for range matching in MIR.
Browse files Browse the repository at this point in the history
The previous version using `PartialOrd::le` was broken since it passed `T`
arguments where `&T` was expected.

It makes sense to use primitive comparisons since range patterns can only be
used with chars and numeric types.
  • Loading branch information
solson committed Dec 30, 2015
1 parent 6e2a64b commit 8a83409
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 23 deletions.
47 changes: 29 additions & 18 deletions src/librustc_mir/build/matches/test.rs
Expand Up @@ -185,28 +185,16 @@ impl<'a,'tcx> Builder<'a,'tcx> {
}

TestKind::Range { ref lo, ref hi, ty } => {
// Test `v` by computing `PartialOrd::le(lo, v) && PartialOrd::le(v, hi)`.
// Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons.
let lo = self.literal_operand(test.span, ty.clone(), lo.clone());
let hi = self.literal_operand(test.span, ty.clone(), hi.clone());
let item_ref = self.hir.partial_le(ty);
let val = Operand::Consume(lvalue.clone());

let lo_blocks = self.call_comparison_fn(block,
test.span,
item_ref.clone(),
lo,
Operand::Consume(lvalue.clone()));
let fail = self.cfg.start_new_block();
let block = self.compare(block, fail, test.span, BinOp::Le, lo, val.clone());
let block = self.compare(block, fail, test.span, BinOp::Le, val, hi);

let hi_blocks = self.call_comparison_fn(lo_blocks[0],
test.span,
item_ref,
Operand::Consume(lvalue.clone()),
hi);

let failure = self.cfg.start_new_block();
self.cfg.terminate(lo_blocks[1], Terminator::Goto { target: failure });
self.cfg.terminate(hi_blocks[1], Terminator::Goto { target: failure });

vec![hi_blocks[0], failure]
vec![block, fail]
}

TestKind::Len { len, op } => {
Expand Down Expand Up @@ -240,6 +228,29 @@ impl<'a,'tcx> Builder<'a,'tcx> {
}
}

fn compare(&mut self,
block: BasicBlock,
fail_block: BasicBlock,
span: Span,
op: BinOp,
left: Operand<'tcx>,
right: Operand<'tcx>) -> BasicBlock {
let bool_ty = self.hir.bool_ty();
let result = self.temp(bool_ty);

// result = op(left, right)
self.cfg.push_assign(block, span, &result, Rvalue::BinaryOp(op, left, right));

// branch based on result
let target_block = self.cfg.start_new_block();
self.cfg.terminate(block, Terminator::If {
cond: Operand::Consume(result),
targets: (target_block, fail_block)
});

target_block
}

fn call_comparison_fn(&mut self,
block: BasicBlock,
span: Span,
Expand Down
5 changes: 0 additions & 5 deletions src/librustc_mir/hair/cx/mod.rs
Expand Up @@ -88,11 +88,6 @@ impl<'a,'tcx:'a> Cx<'a, 'tcx> {
self.cmp_method_ref(eq_def_id, "eq", ty)
}

pub fn partial_le(&mut self, ty: Ty<'tcx>) -> ItemRef<'tcx> {
let ord_def_id = self.tcx.lang_items.ord_trait().unwrap();
self.cmp_method_ref(ord_def_id, "le", ty)
}

pub fn num_variants(&mut self, adt_def: ty::AdtDef<'tcx>) -> usize {
adt_def.variants.len()
}
Expand Down

0 comments on commit 8a83409

Please sign in to comment.