Skip to content

Commit

Permalink
Call str::eq and <[T]>::eq for match comparisons
Browse files Browse the repository at this point in the history
We used to call the less efficient `<&str>::eq` and `<&[T]>::eq`.
  • Loading branch information
matthewjasper committed Jun 13, 2019
1 parent da22793 commit ef1fc86
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 47 deletions.
66 changes: 21 additions & 45 deletions src/librustc_mir/build/matches/test.rs
Expand Up @@ -15,7 +15,9 @@ use rustc::ty::{self, Ty, adjustment::{PointerCast}};
use rustc::ty::util::IntTypeExt;
use rustc::ty::layout::VariantIdx;
use rustc::mir::*;
use rustc::hir::{RangeEnd, Mutability};
use rustc::hir::RangeEnd;
use syntax_pos::symbol::sym;

use std::cmp::Ordering;

impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
Expand Down Expand Up @@ -252,10 +254,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
}

TestKind::Eq { value, ty } => {
// Use `PartialEq::eq` instead of `BinOp::Eq`
// (the binop can only handle primitives)
if let [success, fail] = *target_blocks {
if !ty.is_scalar() {
// Use `PartialEq::eq` instead of `BinOp::Eq`
// (the binop can only handle primitives)
self.non_scalar_compare(
block,
success,
Expand Down Expand Up @@ -368,7 +370,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
);
}

/// Compare using `std::compare::PartialEq::eq`
/// Compare two `&T` values using `<T as std::compare::PartialEq>::eq`
fn non_scalar_compare(
&mut self,
block: BasicBlock,
Expand All @@ -381,8 +383,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
) {
use rustc::middle::lang_items::EqTraitLangItem;

let mut expect = self.literal_operand(source_info.span, ty, value);
let val = Operand::Copy(place.clone());
let mut expect = self.literal_operand(source_info.span, value.ty, value);
let mut val = Operand::Copy(place.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]`.
Expand All @@ -399,7 +401,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
};
let opt_ref_ty = unsize(ty);
let opt_ref_test_ty = unsize(value.ty);
let mut place = place.clone();
match (opt_ref_ty, opt_ref_test_ty) {
// nothing to do, neither is an array
(None, None) => {},
Expand All @@ -409,56 +410,33 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// make both a slice
ty = tcx.mk_imm_ref(region, tcx.mk_slice(elem_ty));
if opt_ref_ty.is_some() {
place = self.temp(ty, source_info.span);
let temp = self.temp(ty, source_info.span);
self.cfg.push_assign(
block, source_info, &place, Rvalue::Cast(
block, source_info, &temp, Rvalue::Cast(
CastKind::Pointer(PointerCast::Unsize), val, ty
)
);
val = Operand::Move(temp);
}
if opt_ref_test_ty.is_some() {
let array = self.literal_operand(
source_info.span,
value.ty,
value,
);

let slice = self.temp(ty, source_info.span);
self.cfg.push_assign(
block, source_info, &slice, Rvalue::Cast(
CastKind::Pointer(PointerCast::Unsize), array, ty
CastKind::Pointer(PointerCast::Unsize), expect, ty
)
);
expect = Operand::Move(slice);
}
},
}
let eq_def_id = self.hir.tcx().require_lang_item(EqTraitLangItem);
let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty.into()]);

let re_erased = self.hir.tcx().lifetimes.re_erased;
// take the argument by reference
let tam = ty::TypeAndMut {
ty,
mutbl: Mutability::MutImmutable,
let deref_ty = match ty.sty {
ty::Ref(_, deref_ty, _) => deref_ty,
_ => bug!("non_scalar_compare called on non-reference type: {}", ty),
};
let ref_ty = self.hir.tcx().mk_ref(re_erased, tam);

// let lhs_ref_place = &lhs;
let ref_rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, place);
let lhs_ref_place = self.temp(ref_ty, source_info.span);
self.cfg.push_assign(block, source_info, &lhs_ref_place, ref_rvalue);
let val = Operand::Move(lhs_ref_place);

// let rhs_place = rhs;
let rhs_place = self.temp(ty, source_info.span);
self.cfg.push_assign(block, source_info, &rhs_place, Rvalue::Use(expect));

// let rhs_ref_place = &rhs_place;
let ref_rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, rhs_place);
let rhs_ref_place = self.temp(ref_ty, source_info.span);
self.cfg.push_assign(block, source_info, &rhs_ref_place, ref_rvalue);
let expect = Operand::Move(rhs_ref_place);
let eq_def_id = self.hir.tcx().require_lang_item(EqTraitLangItem);
let (mty, method) = self.hir.trait_method(eq_def_id, sym::eq, deref_ty, &[deref_ty.into()]);

let bool_ty = self.hir.bool_ty();
let eq_result = self.temp(bool_ty, source_info.span);
Expand All @@ -469,12 +447,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
span: source_info.span,
ty: mty,

// FIXME(#54571): This constant comes from user
// input (a constant in a pattern). Are
// there forms where users can add type
// annotations here? For example, an
// associated constant? Need to
// experiment.
// FIXME(#54571): This constant comes from user input (a
// constant in a pattern). Are there forms where users can add
// type annotations here? For example, an associated constant?
// Need to experiment.
user_ty: None,

literal: method,
Expand Down
3 changes: 1 addition & 2 deletions src/librustc_mir/hair/cx/mod.rs
Expand Up @@ -168,11 +168,10 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {

pub fn trait_method(&mut self,
trait_def_id: DefId,
method_name: &str,
method_name: Symbol,
self_ty: Ty<'tcx>,
params: &[Kind<'tcx>])
-> (Ty<'tcx>, &'tcx ty::Const<'tcx>) {
let method_name = Symbol::intern(method_name);
let substs = self.tcx.mk_substs_trait(self_ty, params);
for item in self.tcx.associated_items(trait_def_id) {
if item.kind == ty::AssocKind::Method && item.ident.name == method_name {
Expand Down
1 change: 1 addition & 0 deletions src/libsyntax_pos/symbol.rs
Expand Up @@ -247,6 +247,7 @@ symbols! {
eh_personality,
eh_unwind_resume,
enable,
eq,
err,
Err,
Equal,
Expand Down

0 comments on commit ef1fc86

Please sign in to comment.