Use only the appropriate trait when looking up operator overloads.
This commit is contained in:
parent
818203e9d2
commit
d096eefd80
|
@ -134,7 +134,6 @@ pub fn lookup(
|
|||
check_traits: CheckTraitsFlag, // Whether we check traits only.
|
||||
autoderef_receiver: AutoderefReceiverFlag)
|
||||
-> Option<method_origin> {
|
||||
let impl_dups = @RefCell::new(HashSet::new());
|
||||
let lcx = LookupContext {
|
||||
fcx: fcx,
|
||||
expr: expr,
|
||||
|
@ -142,7 +141,7 @@ pub fn lookup(
|
|||
callee_id: callee_id,
|
||||
m_name: m_name,
|
||||
supplied_tps: supplied_tps,
|
||||
impl_dups: impl_dups,
|
||||
impl_dups: @RefCell::new(HashSet::new()),
|
||||
inherent_candidates: @RefCell::new(~[]),
|
||||
extension_candidates: @RefCell::new(~[]),
|
||||
deref_args: deref_args,
|
||||
|
@ -164,11 +163,50 @@ pub fn lookup(
|
|||
|
||||
debug!("searching extension candidates");
|
||||
lcx.reset_candidates();
|
||||
lcx.push_bound_candidates(self_ty);
|
||||
lcx.push_bound_candidates(self_ty, None);
|
||||
lcx.push_extension_candidates();
|
||||
return lcx.search(self_ty);
|
||||
}
|
||||
|
||||
pub fn lookup_in_trait(
|
||||
fcx: @FnCtxt,
|
||||
|
||||
// In a call `a.b::<X, Y, ...>(...)`:
|
||||
expr: &ast::Expr, // The expression `a.b(...)`.
|
||||
self_expr: &ast::Expr, // The expression `a`.
|
||||
callee_id: NodeId, /* Where to store `a.b`'s type,
|
||||
* also the scope of the call */
|
||||
m_name: ast::Name, // The name `b`.
|
||||
trait_did: DefId, // The trait to limit the lookup to.
|
||||
self_ty: ty::t, // The type of `a`.
|
||||
supplied_tps: &[ty::t], // The list of types X, Y, ... .
|
||||
autoderef_receiver: AutoderefReceiverFlag)
|
||||
-> Option<method_origin> {
|
||||
let lcx = LookupContext {
|
||||
fcx: fcx,
|
||||
expr: expr,
|
||||
self_expr: self_expr,
|
||||
callee_id: callee_id,
|
||||
m_name: m_name,
|
||||
supplied_tps: supplied_tps,
|
||||
impl_dups: @RefCell::new(HashSet::new()),
|
||||
inherent_candidates: @RefCell::new(~[]),
|
||||
extension_candidates: @RefCell::new(~[]),
|
||||
deref_args: check::DoDerefArgs,
|
||||
check_traits: CheckTraitsOnly,
|
||||
autoderef_receiver: autoderef_receiver,
|
||||
};
|
||||
|
||||
let self_ty = structurally_resolved_type(fcx, self_expr.span, self_ty);
|
||||
debug!("method lookup_in_trait(self_ty={}, expr={}, self_expr={})",
|
||||
self_ty.repr(fcx.tcx()), expr.repr(fcx.tcx()),
|
||||
self_expr.repr(fcx.tcx()));
|
||||
|
||||
lcx.push_bound_candidates(self_ty, Some(trait_did));
|
||||
lcx.push_extension_candidate(trait_did);
|
||||
lcx.search(self_ty)
|
||||
}
|
||||
|
||||
pub struct LookupContext<'a> {
|
||||
fcx: @FnCtxt,
|
||||
expr: &'a ast::Expr,
|
||||
|
@ -319,17 +357,17 @@ impl<'a> LookupContext<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn push_bound_candidates(&self, self_ty: ty::t) {
|
||||
fn push_bound_candidates(&self, self_ty: ty::t, restrict_to: Option<DefId>) {
|
||||
let mut self_ty = self_ty;
|
||||
loop {
|
||||
match get(self_ty).sty {
|
||||
ty_param(p) => {
|
||||
self.push_inherent_candidates_from_param(self_ty, p);
|
||||
self.push_inherent_candidates_from_param(self_ty, restrict_to, p);
|
||||
}
|
||||
ty_self(..) => {
|
||||
// Call is of the form "self.foo()" and appears in one
|
||||
// of a trait's default method implementations.
|
||||
self.push_inherent_candidates_from_self(self_ty);
|
||||
self.push_inherent_candidates_from_self(self_ty, restrict_to);
|
||||
}
|
||||
_ => { /* No bound methods in these types */ }
|
||||
}
|
||||
|
@ -341,6 +379,19 @@ impl<'a> LookupContext<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn push_extension_candidate(&self, trait_did: DefId) {
|
||||
ty::populate_implementations_for_trait_if_necessary(self.tcx(), trait_did);
|
||||
|
||||
// Look for explicit implementations.
|
||||
let trait_impls = self.tcx().trait_impls.borrow();
|
||||
for impl_infos in trait_impls.get().find(&trait_did).iter() {
|
||||
for impl_info in impl_infos.borrow().get().iter() {
|
||||
self.push_candidates_from_impl(
|
||||
self.extension_candidates.borrow_mut().get(), *impl_info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn push_extension_candidates(&self) {
|
||||
// If the method being called is associated with a trait, then
|
||||
// find all the impls of that trait. Each of those are
|
||||
|
@ -428,7 +479,7 @@ impl<'a> LookupContext<'a> {
|
|||
self.construct_transformed_self_ty_for_object(
|
||||
did, &rcvr_substs, &m);
|
||||
|
||||
Candidate {
|
||||
Some(Candidate {
|
||||
rcvr_match_condition: RcvrMatchesIfObject(did),
|
||||
rcvr_substs: new_trait_ref.substs.clone(),
|
||||
method_ty: @m,
|
||||
|
@ -438,49 +489,61 @@ impl<'a> LookupContext<'a> {
|
|||
method_num: method_num,
|
||||
real_index: vtable_index
|
||||
})
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn push_inherent_candidates_from_param(&self,
|
||||
rcvr_ty: ty::t,
|
||||
restrict_to: Option<DefId>,
|
||||
param_ty: param_ty) {
|
||||
debug!("push_inherent_candidates_from_param(param_ty={:?})",
|
||||
param_ty);
|
||||
self.push_inherent_candidates_from_bounds(
|
||||
rcvr_ty,
|
||||
self.fcx.inh.param_env.type_param_bounds[param_ty.idx].trait_bounds,
|
||||
restrict_to,
|
||||
param_numbered(param_ty.idx));
|
||||
}
|
||||
|
||||
|
||||
fn push_inherent_candidates_from_self(&self,
|
||||
rcvr_ty: ty::t) {
|
||||
rcvr_ty: ty::t,
|
||||
restrict_to: Option<DefId>) {
|
||||
debug!("push_inherent_candidates_from_self()");
|
||||
self.push_inherent_candidates_from_bounds(
|
||||
rcvr_ty,
|
||||
[self.fcx.inh.param_env.self_param_bound.unwrap()],
|
||||
restrict_to,
|
||||
param_self)
|
||||
}
|
||||
|
||||
fn push_inherent_candidates_from_bounds(&self,
|
||||
self_ty: ty::t,
|
||||
bounds: &[@TraitRef],
|
||||
restrict_to: Option<DefId>,
|
||||
param: param_index) {
|
||||
self.push_inherent_candidates_from_bounds_inner(bounds,
|
||||
|trait_ref, m, method_num, bound_num| {
|
||||
Candidate {
|
||||
rcvr_match_condition: RcvrMatchesIfSubtype(self_ty),
|
||||
rcvr_substs: trait_ref.substs.clone(),
|
||||
method_ty: m,
|
||||
origin: method_param(
|
||||
method_param {
|
||||
match restrict_to {
|
||||
Some(trait_did) => {
|
||||
if trait_did != trait_ref.def_id {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Some(Candidate {
|
||||
rcvr_match_condition: RcvrMatchesIfSubtype(self_ty),
|
||||
rcvr_substs: trait_ref.substs.clone(),
|
||||
method_ty: m,
|
||||
origin: method_param(method_param {
|
||||
trait_id: trait_ref.def_id,
|
||||
method_num: method_num,
|
||||
param_num: param,
|
||||
bound_num: bound_num,
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -492,7 +555,7 @@ impl<'a> LookupContext<'a> {
|
|||
m: @ty::Method,
|
||||
method_num: uint,
|
||||
bound_num: uint|
|
||||
-> Candidate) {
|
||||
-> Option<Candidate>) {
|
||||
let tcx = self.tcx();
|
||||
let mut next_bound_idx = 0; // count only trait bounds
|
||||
|
||||
|
@ -508,17 +571,17 @@ impl<'a> LookupContext<'a> {
|
|||
Some(pos) => {
|
||||
let method = trait_methods[pos];
|
||||
|
||||
let cand = mk_cand(bound_trait_ref, method,
|
||||
pos, this_bound_idx);
|
||||
|
||||
debug!("pushing inherent candidate for param: {:?}", cand);
|
||||
let mut inherent_candidates = self.inherent_candidates
|
||||
.borrow_mut();
|
||||
inherent_candidates.get().push(cand);
|
||||
match mk_cand(bound_trait_ref, method, pos, this_bound_idx) {
|
||||
Some(cand) => {
|
||||
debug!("pushing inherent candidate for param: {:?}", cand);
|
||||
self.inherent_candidates.borrow_mut().get().push(cand);
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
debug!("trait doesn't contain method: {:?}",
|
||||
bound_trait_ref.def_id);
|
||||
bound_trait_ref.def_id);
|
||||
// check next trait or bound
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@ use middle::typeck::check::_match::pat_ctxt;
|
|||
use middle::typeck::check::method::{AutoderefReceiver};
|
||||
use middle::typeck::check::method::{AutoderefReceiverFlag};
|
||||
use middle::typeck::check::method::{CheckTraitsAndInherentMethods};
|
||||
use middle::typeck::check::method::{CheckTraitsOnly, DontAutoderefReceiver};
|
||||
use middle::typeck::check::method::{DontAutoderefReceiver};
|
||||
use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig;
|
||||
use middle::typeck::check::regionmanip::relate_free_regions;
|
||||
use middle::typeck::check::vtable::{LocationInfo, VtableContext};
|
||||
|
@ -1936,35 +1936,34 @@ pub fn check_expr_with_unifier(fcx: @FnCtxt,
|
|||
op_ex: &ast::Expr,
|
||||
self_t: ty::t,
|
||||
opname: ast::Name,
|
||||
trait_did: Option<ast::DefId>,
|
||||
args: &[@ast::Expr],
|
||||
deref_args: DerefArgs,
|
||||
autoderef_receiver: AutoderefReceiverFlag,
|
||||
unbound_method: ||,
|
||||
_expected_result: Option<ty::t>
|
||||
)
|
||||
-> ty::t {
|
||||
match method::lookup(fcx, op_ex, args[0],
|
||||
callee_id, opname, self_t, [],
|
||||
deref_args, CheckTraitsOnly, autoderef_receiver) {
|
||||
Some(ref origin) => {
|
||||
unbound_method: ||) -> ty::t {
|
||||
let origin = match trait_did {
|
||||
Some(trait_did) => {
|
||||
method::lookup_in_trait(fcx, op_ex, args[0], callee_id, opname,
|
||||
trait_did, self_t, [], autoderef_receiver)
|
||||
}
|
||||
None => None
|
||||
};
|
||||
match origin {
|
||||
Some(origin) => {
|
||||
let method_ty = fcx.node_ty(callee_id);
|
||||
let method_map = fcx.inh.method_map;
|
||||
{
|
||||
let mut method_map = method_map.borrow_mut();
|
||||
method_map.get().insert(op_ex.id, *origin);
|
||||
}
|
||||
method_map.borrow_mut().get().insert(op_ex.id, origin);
|
||||
check_method_argument_types(fcx, op_ex.span,
|
||||
method_ty, op_ex,
|
||||
args, deref_args)
|
||||
args, DoDerefArgs)
|
||||
}
|
||||
_ => {
|
||||
None => {
|
||||
unbound_method();
|
||||
// Check the args anyway
|
||||
// so we get all the error messages
|
||||
let expected_ty = ty::mk_err();
|
||||
check_method_argument_types(fcx, op_ex.span,
|
||||
expected_ty, op_ex,
|
||||
args, deref_args);
|
||||
args, DoDerefArgs);
|
||||
ty::mk_err()
|
||||
}
|
||||
}
|
||||
|
@ -1977,10 +1976,7 @@ pub fn check_expr_with_unifier(fcx: @FnCtxt,
|
|||
op: ast::BinOp,
|
||||
lhs: @ast::Expr,
|
||||
rhs: @ast::Expr,
|
||||
// Used only in the error case
|
||||
expected_result: Option<ty::t>,
|
||||
is_binop_assignment: IsBinopAssignment
|
||||
) {
|
||||
is_binop_assignment: IsBinopAssignment) {
|
||||
let tcx = fcx.ccx.tcx;
|
||||
|
||||
check_expr(fcx, lhs);
|
||||
|
@ -2004,12 +2000,8 @@ pub fn check_expr_with_unifier(fcx: @FnCtxt,
|
|||
|
||||
let result_t = match op {
|
||||
ast::BiEq | ast::BiNe | ast::BiLt | ast::BiLe | ast::BiGe |
|
||||
ast::BiGt => {
|
||||
ty::mk_bool()
|
||||
}
|
||||
_ => {
|
||||
lhs_t
|
||||
}
|
||||
ast::BiGt => ty::mk_bool(),
|
||||
_ => lhs_t
|
||||
};
|
||||
|
||||
fcx.write_ty(expr.id, result_t);
|
||||
|
@ -2030,16 +2022,8 @@ pub fn check_expr_with_unifier(fcx: @FnCtxt,
|
|||
}
|
||||
|
||||
// Check for overloaded operators if not an assignment.
|
||||
let result_t;
|
||||
if is_binop_assignment == SimpleBinop {
|
||||
result_t = check_user_binop(fcx,
|
||||
callee_id,
|
||||
expr,
|
||||
lhs,
|
||||
lhs_t,
|
||||
op,
|
||||
rhs,
|
||||
expected_result);
|
||||
let result_t = if is_binop_assignment == SimpleBinop {
|
||||
check_user_binop(fcx, callee_id, expr, lhs, lhs_t, op, rhs)
|
||||
} else {
|
||||
fcx.type_error_message(expr.span,
|
||||
|actual| {
|
||||
|
@ -2051,8 +2035,8 @@ pub fn check_expr_with_unifier(fcx: @FnCtxt,
|
|||
lhs_t,
|
||||
None);
|
||||
check_expr(fcx, rhs);
|
||||
result_t = ty::mk_err();
|
||||
}
|
||||
ty::mk_err()
|
||||
};
|
||||
|
||||
fcx.write_ty(expr.id, result_t);
|
||||
if ty::type_is_error(result_t) {
|
||||
|
@ -2066,48 +2050,54 @@ pub fn check_expr_with_unifier(fcx: @FnCtxt,
|
|||
lhs_expr: @ast::Expr,
|
||||
lhs_resolved_t: ty::t,
|
||||
op: ast::BinOp,
|
||||
rhs: @ast::Expr,
|
||||
expected_result: Option<ty::t>) -> ty::t {
|
||||
rhs: @ast::Expr) -> ty::t {
|
||||
let tcx = fcx.ccx.tcx;
|
||||
match ast_util::binop_to_method_name(op) {
|
||||
Some(ref name) => {
|
||||
let if_op_unbound = || {
|
||||
fcx.type_error_message(ex.span, |actual| {
|
||||
format!("binary operation `{}` cannot be applied \
|
||||
to type `{}`",
|
||||
ast_util::binop_to_str(op), actual)},
|
||||
lhs_resolved_t, None)
|
||||
};
|
||||
return lookup_op_method(fcx, callee_id, ex, lhs_resolved_t,
|
||||
token::intern(*name), [lhs_expr, rhs],
|
||||
DoDerefArgs,DontAutoderefReceiver,
|
||||
if_op_unbound, expected_result);
|
||||
let lang = tcx.lang_items;
|
||||
let (name, trait_did) = match op {
|
||||
ast::BiAdd => ("add", lang.add_trait()),
|
||||
ast::BiSub => ("sub", lang.sub_trait()),
|
||||
ast::BiMul => ("mul", lang.mul_trait()),
|
||||
ast::BiDiv => ("div", lang.div_trait()),
|
||||
ast::BiRem => ("rem", lang.rem_trait()),
|
||||
ast::BiBitXor => ("bitxor", lang.bitxor_trait()),
|
||||
ast::BiBitAnd => ("bitand", lang.bitand_trait()),
|
||||
ast::BiBitOr => ("bitor", lang.bitor_trait()),
|
||||
ast::BiShl => ("shl", lang.shl_trait()),
|
||||
ast::BiShr => ("shr", lang.shr_trait()),
|
||||
ast::BiLt => ("lt", lang.ord_trait()),
|
||||
ast::BiLe => ("le", lang.ord_trait()),
|
||||
ast::BiGe => ("ge", lang.ord_trait()),
|
||||
ast::BiGt => ("gt", lang.ord_trait()),
|
||||
ast::BiEq => ("eq", lang.eq_trait()),
|
||||
ast::BiNe => ("ne", lang.eq_trait()),
|
||||
ast::BiAnd | ast::BiOr => {
|
||||
check_expr(fcx, rhs);
|
||||
return ty::mk_err();
|
||||
}
|
||||
None => ()
|
||||
};
|
||||
check_expr(fcx, rhs);
|
||||
|
||||
ty::mk_err()
|
||||
lookup_op_method(fcx, callee_id, ex, lhs_resolved_t, token::intern(name),
|
||||
trait_did, [lhs_expr, rhs], DontAutoderefReceiver, || {
|
||||
fcx.type_error_message(ex.span, |actual| {
|
||||
format!("binary operation `{}` cannot be applied to type `{}`",
|
||||
ast_util::binop_to_str(op), actual)
|
||||
}, lhs_resolved_t, None)
|
||||
})
|
||||
}
|
||||
|
||||
fn check_user_unop(fcx: @FnCtxt,
|
||||
callee_id: ast::NodeId,
|
||||
op_str: &str,
|
||||
mname: &str,
|
||||
trait_did: Option<ast::DefId>,
|
||||
ex: &ast::Expr,
|
||||
rhs_expr: @ast::Expr,
|
||||
rhs_t: ty::t,
|
||||
expected_t: Option<ty::t>)
|
||||
-> ty::t {
|
||||
lookup_op_method(
|
||||
fcx, callee_id, ex, rhs_t, token::intern(mname),
|
||||
[rhs_expr], DoDerefArgs, DontAutoderefReceiver,
|
||||
|| {
|
||||
fcx.type_error_message(ex.span, |actual| {
|
||||
format!("cannot apply unary operator `{}` to type `{}`",
|
||||
op_str, actual)
|
||||
}, rhs_t, None);
|
||||
}, expected_t)
|
||||
rhs_t: ty::t) -> ty::t {
|
||||
lookup_op_method(fcx, callee_id, ex, rhs_t, token::intern(mname),
|
||||
trait_did, [rhs_expr], DontAutoderefReceiver, || {
|
||||
fcx.type_error_message(ex.span, |actual| {
|
||||
format!("cannot apply unary operator `{}` to type `{}`", op_str, actual)
|
||||
}, rhs_t, None);
|
||||
})
|
||||
}
|
||||
|
||||
// Resolves `expected` by a single level if it is a variable and passes it
|
||||
|
@ -2631,14 +2621,7 @@ pub fn check_expr_with_unifier(fcx: @FnCtxt,
|
|||
fcx.write_ty(id, typ);
|
||||
}
|
||||
ast::ExprBinary(callee_id, op, lhs, rhs) => {
|
||||
check_binop(fcx,
|
||||
callee_id,
|
||||
expr,
|
||||
op,
|
||||
lhs,
|
||||
rhs,
|
||||
expected,
|
||||
SimpleBinop);
|
||||
check_binop(fcx, callee_id, expr, op, lhs, rhs, SimpleBinop);
|
||||
|
||||
let lhs_ty = fcx.expr_ty(lhs);
|
||||
let rhs_ty = fcx.expr_ty(rhs);
|
||||
|
@ -2652,14 +2635,7 @@ pub fn check_expr_with_unifier(fcx: @FnCtxt,
|
|||
}
|
||||
}
|
||||
ast::ExprAssignOp(callee_id, op, lhs, rhs) => {
|
||||
check_binop(fcx,
|
||||
callee_id,
|
||||
expr,
|
||||
op,
|
||||
lhs,
|
||||
rhs,
|
||||
expected,
|
||||
BinopAssignment);
|
||||
check_binop(fcx, callee_id, expr, op, lhs, rhs, BinopAssignment);
|
||||
|
||||
let lhs_t = fcx.expr_ty(lhs);
|
||||
let result_t = fcx.expr_ty(expr);
|
||||
|
@ -2734,9 +2710,9 @@ pub fn check_expr_with_unifier(fcx: @FnCtxt,
|
|||
oprnd_t);
|
||||
if !(ty::type_is_integral(oprnd_t) ||
|
||||
ty::get(oprnd_t).sty == ty::ty_bool) {
|
||||
oprnd_t = check_user_unop(fcx, callee_id,
|
||||
"!", "not", expr, oprnd, oprnd_t,
|
||||
expected);
|
||||
oprnd_t = check_user_unop(fcx, callee_id, "!", "not",
|
||||
tcx.lang_items.not_trait(),
|
||||
expr, oprnd, oprnd_t);
|
||||
}
|
||||
}
|
||||
ast::UnNeg => {
|
||||
|
@ -2744,8 +2720,9 @@ pub fn check_expr_with_unifier(fcx: @FnCtxt,
|
|||
oprnd_t);
|
||||
if !(ty::type_is_integral(oprnd_t) ||
|
||||
ty::type_is_fp(oprnd_t)) {
|
||||
oprnd_t = check_user_unop(fcx, callee_id,
|
||||
"-", "neg", expr, oprnd, oprnd_t, expected);
|
||||
oprnd_t = check_user_unop(fcx, callee_id, "-", "neg",
|
||||
tcx.lang_items.neg_trait(),
|
||||
expr, oprnd, oprnd_t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3160,11 +3137,10 @@ pub fn check_expr_with_unifier(fcx: @FnCtxt,
|
|||
expr,
|
||||
resolved,
|
||||
token::intern("index"),
|
||||
tcx.lang_items.index_trait(),
|
||||
[base, idx],
|
||||
DoDerefArgs,
|
||||
AutoderefReceiver,
|
||||
error_message,
|
||||
expected);
|
||||
error_message);
|
||||
fcx.write_ty(id, ret_ty);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,48 +79,26 @@ pub fn def_id_of_def(d: Def) -> DefId {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn binop_to_str(op: BinOp) -> ~str {
|
||||
pub fn binop_to_str(op: BinOp) -> &'static str {
|
||||
match op {
|
||||
BiAdd => return ~"+",
|
||||
BiSub => return ~"-",
|
||||
BiMul => return ~"*",
|
||||
BiDiv => return ~"/",
|
||||
BiRem => return ~"%",
|
||||
BiAnd => return ~"&&",
|
||||
BiOr => return ~"||",
|
||||
BiBitXor => return ~"^",
|
||||
BiBitAnd => return ~"&",
|
||||
BiBitOr => return ~"|",
|
||||
BiShl => return ~"<<",
|
||||
BiShr => return ~">>",
|
||||
BiEq => return ~"==",
|
||||
BiLt => return ~"<",
|
||||
BiLe => return ~"<=",
|
||||
BiNe => return ~"!=",
|
||||
BiGe => return ~">=",
|
||||
BiGt => return ~">"
|
||||
}
|
||||
}
|
||||
|
||||
pub fn binop_to_method_name(op: BinOp) -> Option<~str> {
|
||||
match op {
|
||||
BiAdd => return Some(~"add"),
|
||||
BiSub => return Some(~"sub"),
|
||||
BiMul => return Some(~"mul"),
|
||||
BiDiv => return Some(~"div"),
|
||||
BiRem => return Some(~"rem"),
|
||||
BiBitXor => return Some(~"bitxor"),
|
||||
BiBitAnd => return Some(~"bitand"),
|
||||
BiBitOr => return Some(~"bitor"),
|
||||
BiShl => return Some(~"shl"),
|
||||
BiShr => return Some(~"shr"),
|
||||
BiLt => return Some(~"lt"),
|
||||
BiLe => return Some(~"le"),
|
||||
BiGe => return Some(~"ge"),
|
||||
BiGt => return Some(~"gt"),
|
||||
BiEq => return Some(~"eq"),
|
||||
BiNe => return Some(~"ne"),
|
||||
BiAnd | BiOr => return None
|
||||
BiAdd => "+",
|
||||
BiSub => "-",
|
||||
BiMul => "*",
|
||||
BiDiv => "/",
|
||||
BiRem => "%",
|
||||
BiAnd => "&&",
|
||||
BiOr => "||",
|
||||
BiBitXor => "^",
|
||||
BiBitAnd => "&",
|
||||
BiBitOr => "|",
|
||||
BiShl => "<<",
|
||||
BiShr => ">>",
|
||||
BiEq => "==",
|
||||
BiLt => "<",
|
||||
BiLe => "<=",
|
||||
BiNe => "!=",
|
||||
BiGe => ">=",
|
||||
BiGt => ">"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// #12402 Operator overloading only considers the method name, not which trait is implemented
|
||||
|
||||
trait MyMul<Rhs, Res> {
|
||||
fn mul(&self, rhs: &Rhs) -> Res;
|
||||
}
|
||||
|
||||
fn foo<T: MyMul<f64, f64>>(a: &T, b: f64) -> f64 {
|
||||
a * b //~ ERROR binary operation `*` cannot be applied to type `&T`
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
Reference in New Issue