mir: Match against slices by calling PartialEq::eq.
This commit is contained in:
parent
d9277b163c
commit
41499f4563
@ -174,33 +174,78 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
targets
|
||||
}
|
||||
|
||||
TestKind::Eq { ref value, ty } => {
|
||||
// If we're matching against &[u8] with b"...", we need to insert
|
||||
// an unsizing coercion, as the byte string has type &[u8; N].
|
||||
let expect = match *value {
|
||||
ConstVal::ByteStr(ref bytes) if ty.is_slice() => {
|
||||
let tcx = self.hir.tcx();
|
||||
let array_ty = tcx.mk_array(tcx.types.u8, bytes.len());
|
||||
let ref_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), array_ty);
|
||||
let array = self.literal_operand(test.span, ref_ty, Literal::Value {
|
||||
value: value.clone()
|
||||
});
|
||||
TestKind::Eq { ref value, mut ty } => {
|
||||
let mut val = Operand::Consume(lvalue.clone());
|
||||
|
||||
let sliced = self.temp(ty);
|
||||
self.cfg.push_assign(block, test.span, &sliced,
|
||||
Rvalue::Cast(CastKind::Unsize, array, ty));
|
||||
Operand::Consume(sliced)
|
||||
}
|
||||
_ => {
|
||||
self.literal_operand(test.span, ty, Literal::Value {
|
||||
value: value.clone()
|
||||
})
|
||||
// If we're using b"..." as a pattern, we need to insert an
|
||||
// unsizing coercion, as the byte string has the type &[u8; N].
|
||||
let expect = if let ConstVal::ByteStr(ref bytes) = *value {
|
||||
let tcx = self.hir.tcx();
|
||||
|
||||
// Unsize the lvalue to &[u8], too, if necessary.
|
||||
if let ty::TyRef(region, mt) = ty.sty {
|
||||
if let ty::TyArray(_, _) = mt.ty.sty {
|
||||
ty = tcx.mk_imm_ref(region, tcx.mk_slice(tcx.types.u8));
|
||||
let val_slice = self.temp(ty);
|
||||
self.cfg.push_assign(block, test.span, &val_slice,
|
||||
Rvalue::Cast(CastKind::Unsize, val, ty));
|
||||
val = Operand::Consume(val_slice);
|
||||
}
|
||||
}
|
||||
|
||||
assert!(ty.is_slice());
|
||||
|
||||
let array_ty = tcx.mk_array(tcx.types.u8, bytes.len());
|
||||
let array_ref = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), array_ty);
|
||||
let array = self.literal_operand(test.span, array_ref, Literal::Value {
|
||||
value: value.clone()
|
||||
});
|
||||
|
||||
let slice = self.temp(ty);
|
||||
self.cfg.push_assign(block, test.span, &slice,
|
||||
Rvalue::Cast(CastKind::Unsize, array, ty));
|
||||
Operand::Consume(slice)
|
||||
} else {
|
||||
self.literal_operand(test.span, ty, Literal::Value {
|
||||
value: value.clone()
|
||||
})
|
||||
};
|
||||
let val = Operand::Consume(lvalue.clone());
|
||||
|
||||
// Use PartialEq::eq for &str and &[u8] slices, instead of BinOp::Eq.
|
||||
let fail = self.cfg.start_new_block();
|
||||
let block = self.compare(block, fail, test.span, BinOp::Eq, expect, val.clone());
|
||||
vec![block, fail]
|
||||
if let ty::TyRef(_, mt) = ty.sty {
|
||||
assert!(ty.is_slice());
|
||||
let eq_def_id = self.hir.tcx().lang_items.eq_trait().unwrap();
|
||||
let ty = mt.ty;
|
||||
let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, vec![ty]);
|
||||
|
||||
let bool_ty = self.hir.bool_ty();
|
||||
let eq_result = self.temp(bool_ty);
|
||||
let eq_block = self.cfg.start_new_block();
|
||||
let cleanup = self.diverge_cleanup();
|
||||
self.cfg.terminate(block, Terminator::Call {
|
||||
func: Operand::Constant(Constant {
|
||||
span: test.span,
|
||||
ty: mty,
|
||||
literal: method
|
||||
}),
|
||||
args: vec![val, expect],
|
||||
destination: Some((eq_result.clone(), eq_block)),
|
||||
cleanup: cleanup,
|
||||
});
|
||||
|
||||
// check the result
|
||||
let block = self.cfg.start_new_block();
|
||||
self.cfg.terminate(eq_block, Terminator::If {
|
||||
cond: Operand::Consume(eq_result),
|
||||
targets: (block, fail),
|
||||
});
|
||||
|
||||
vec![block, fail]
|
||||
} else {
|
||||
let block = self.compare(block, fail, test.span, BinOp::Eq, expect, val);
|
||||
vec![block, fail]
|
||||
}
|
||||
}
|
||||
|
||||
TestKind::Range { ref lo, ref hi, ty } => {
|
||||
|
@ -19,7 +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, TyCtxt};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::parse::token;
|
||||
@ -96,6 +98,34 @@ impl<'a,'tcx:'a> Cx<'a, 'tcx> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn trait_method(&mut self,
|
||||
trait_def_id: DefId,
|
||||
method_name: &str,
|
||||
self_ty: Ty<'tcx>,
|
||||
params: Vec<Ty<'tcx>>)
|
||||
-> (Ty<'tcx>, Literal<'tcx>) {
|
||||
let method_name = token::intern(method_name);
|
||||
let substs = Substs::new_trait(params, vec![], self_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 (method_ty, Literal::Item {
|
||||
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));
|
||||
}
|
||||
|
||||
pub fn num_variants(&mut self, adt_def: ty::AdtDef<'tcx>) -> usize {
|
||||
adt_def.variants.len()
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user