Skip to content

librustc: Implement overloading for the call operator behind a feature #14590

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

Closed
wants to merge 1 commit into from
Closed
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
21 changes: 21 additions & 0 deletions src/libcore/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,27 @@ pub trait DerefMut<Result>: Deref<Result> {
fn deref_mut<'a>(&'a mut self) -> &'a mut Result;
}

/// A version of the call operator that takes an immutable receiver.
#[lang="fn"]
pub trait Fn<Args,Result> {
/// This is called when the call operator is used.
fn call(&self, args: Args) -> Result;
}

/// A version of the call operator that takes a mutable receiver.
#[lang="fn_mut"]
pub trait FnMut<Args,Result> {
/// This is called when the call operator is used.
fn call_mut(&mut self, args: Args) -> Result;
}

/// A version of the call operator that takes a by-value receiver.
#[lang="fn_once"]
pub trait FnOnce<Args,Result> {
/// This is called when the call operator is used.
fn call_once(self, args: Args) -> Result;
}

#[cfg(test)]
mod bench {
extern crate test;
Expand Down
4 changes: 4 additions & 0 deletions src/librustc/front/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
("quote", Active),
("linkage", Active),
("struct_inherit", Active),
("overloaded_calls", Active),

("quad_precision_float", Active),

Expand Down Expand Up @@ -86,6 +87,7 @@ pub struct Features {
pub default_type_params: Cell<bool>,
pub quad_precision_float: Cell<bool>,
pub issue_5723_bootstrap: Cell<bool>,
pub overloaded_calls: Cell<bool>,
}

impl Features {
Expand All @@ -94,6 +96,7 @@ impl Features {
default_type_params: Cell::new(false),
quad_precision_float: Cell::new(false),
issue_5723_bootstrap: Cell::new(false),
overloaded_calls: Cell::new(false),
}
}
}
Expand Down Expand Up @@ -376,4 +379,5 @@ pub fn check_crate(sess: &Session, krate: &ast::Crate) {
sess.features.default_type_params.set(cx.has_feature("default_type_params"));
sess.features.quad_precision_float.set(cx.has_feature("quad_precision_float"));
sess.features.issue_5723_bootstrap.set(cx.has_feature("issue_5723_bootstrap"));
sess.features.overloaded_calls.set(cx.has_feature("overloaded_calls"));
}
19 changes: 15 additions & 4 deletions src/librustc/middle/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use middle::def;
use middle::freevars;
use middle::pat_util;
use middle::ty;
use middle::typeck::MethodCall;
use middle::typeck;
use syntax::ast;
use syntax::codemap::{Span};
Expand Down Expand Up @@ -427,10 +428,20 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> {
}
}
_ => {
self.tcx().sess.span_bug(
callee.span,
format!("unxpected callee type {}",
callee_ty.repr(self.tcx())).as_slice());
match self.tcx()
Copy link
Member

Choose a reason for hiding this comment

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

Could you add a comment here saying what we're looking for? It is not obvious from the code.

.method_map
.borrow()
.find(&MethodCall::expr(call.id)) {
Some(_) => {
// FIXME(#14774, pcwalton): Implement this.
}
None => {
self.tcx().sess.span_bug(
callee.span,
format!("unxpected callee type {}",
callee_ty.repr(self.tcx())).as_slice());
}
}
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/librustc/middle/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,10 @@ lets_do_this! {
DerefTraitLangItem, "deref", deref_trait;
DerefMutTraitLangItem, "deref_mut", deref_mut_trait;

FnTraitLangItem, "fn", fn_trait;
FnMutTraitLangItem, "fn_mut", fn_mut_trait;
FnOnceTraitLangItem, "fn_once", fn_once_trait;

EqTraitLangItem, "eq", eq_trait;
OrdTraitLangItem, "ord", ord_trait;

Expand Down
13 changes: 10 additions & 3 deletions src/librustc/middle/liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
use middle::def::*;
use middle::freevars;
use middle::lint::{UnusedVariable, DeadAssignment};
use middle::mem_categorization::Typer;
use middle::pat_util;
use middle::ty;
use util::nodemap::NodeMap;
Expand Down Expand Up @@ -1146,9 +1147,15 @@ impl<'a> Liveness<'a> {
ExprCall(f, ref args) => {
// calling a fn with bot return type means that the fn
// will fail, and hence the successors can be ignored
let t_ret = ty::ty_fn_ret(ty::expr_ty(self.ir.tcx, f));
let succ = if ty::type_is_bot(t_ret) {self.s.exit_ln}
else {succ};
let is_bot = !self.ir.tcx.is_method_call(expr.id) && {
let t_ret = ty::ty_fn_ret(ty::expr_ty(self.ir.tcx, f));
ty::type_is_bot(t_ret)
};
let succ = if is_bot {
self.s.exit_ln
} else {
succ
};
let succ = self.propagate_through_exprs(args.as_slice(), succ);
self.propagate_through_expr(f, succ)
}
Expand Down
87 changes: 86 additions & 1 deletion src/librustc/middle/trans/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use lib;
use metadata::csearch;
use middle::def;
use middle::lang_items::MallocFnLangItem;
use middle::mem_categorization::Typer;
use middle::trans::_match;
use middle::trans::adt;
use middle::trans::asm;
Expand All @@ -65,6 +66,7 @@ use middle::ty::{AutoBorrowObj, AutoDerefRef, AutoAddEnv, AutoObject, AutoUnsafe
use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef};
use middle::ty;
use middle::typeck::MethodCall;
use middle::typeck;
use util::common::indenter;
use util::ppaux::Repr;
use util::nodemap::NodeMap;
Expand Down Expand Up @@ -713,7 +715,20 @@ fn trans_rvalue_dps_unadjusted<'a>(bcx: &'a Block<'a>,
closure::trans_expr_fn(bcx, store, decl, body, expr.id, dest)
}
ast::ExprCall(f, ref args) => {
callee::trans_call(bcx, expr, f, callee::ArgExprs(args.as_slice()), dest)
if bcx.tcx().is_method_call(expr.id) {
let callee_datum = unpack_datum!(bcx, trans(bcx, f));
trans_overloaded_call(bcx,
expr,
callee_datum,
args.as_slice(),
Some(dest))
} else {
callee::trans_call(bcx,
expr,
f,
callee::ArgExprs(args.as_slice()),
dest)
}
}
ast::ExprMethodCall(_, _, ref args) => {
callee::trans_method_call(bcx,
Expand Down Expand Up @@ -1461,6 +1476,76 @@ fn trans_overloaded_op<'a, 'b>(
dest)
}

fn trans_overloaded_call<'a>(
mut bcx: &'a Block<'a>,
expr: &ast::Expr,
callee: Datum<Expr>,
args: &[@ast::Expr],
dest: Option<Dest>)
-> &'a Block<'a> {
// Evaluate and tuple the arguments.
let tuple_type = ty::mk_tup(bcx.tcx(),
args.iter()
.map(|e| expr_ty(bcx, *e))
.collect());
let repr = adt::represent_type(bcx.ccx(), tuple_type);
let numbered_fields: Vec<(uint, @ast::Expr)> =
args.iter().enumerate().map(|(i, arg)| (i, *arg)).collect();
let argument_scope = bcx.fcx.push_custom_cleanup_scope();
let tuple_datum =
unpack_datum!(bcx,
lvalue_scratch_datum(bcx,
tuple_type,
"tupled_arguments",
false,
cleanup::CustomScope(
argument_scope),
(),
|(), bcx, addr| {
trans_adt(bcx,
&*repr,
0,
numbered_fields.as_slice(),
None,
SaveIn(addr))
}));

let method_call = typeck::MethodCall::expr(expr.id);
let method_type = bcx.tcx()
.method_map
.borrow()
.get(&method_call)
.ty;
let callee_rvalue = unpack_datum!(bcx,
callee.to_rvalue_datum(bcx, "callee"));
let tuple_datum = tuple_datum.to_expr_datum();
let tuple_rvalue = unpack_datum!(bcx,
tuple_datum.to_rvalue_datum(bcx,
"tuple"));
let argument_values = [
callee_rvalue.add_clean(bcx.fcx,
cleanup::CustomScope(argument_scope)),
tuple_rvalue.add_clean(bcx.fcx, cleanup::CustomScope(argument_scope))
];
unpack_result!(bcx,
callee::trans_call_inner(bcx,
Some(expr_info(expr)),
monomorphize_type(bcx,
method_type),
|bcx, arg_cleanup_scope| {
meth::trans_method_callee(
bcx,
method_call,
None,
arg_cleanup_scope)
},
callee::ArgVals(argument_values),
dest));

bcx.fcx.pop_custom_cleanup_scope(argument_scope);
bcx
}

fn int_cast(bcx: &Block,
lldsttype: Type,
llsrctype: Type,
Expand Down
Loading