Fixes #10667 and closes #10259.
return;
}
StaticBenchFn(benchfn) => {
- let bs = ::test::bench::benchmark(benchfn);
+ let bs = ::test::bench::benchmark(|harness| benchfn(harness));
monitor_ch.send((desc, TrBench(bs)));
return;
}
pub static tag_item_method_tps: uint = 0x7b;
pub static tag_item_method_fty: uint = 0x7c;
-pub static tag_item_method_transformed_self_ty: uint = 0x7d;
-pub static tag_mod_child: uint = 0x7e;
-pub static tag_misc_info: uint = 0x7f;
-pub static tag_misc_info_crate_items: uint = 0x80;
+pub static tag_mod_child: uint = 0x7d;
+pub static tag_misc_info: uint = 0x7e;
+pub static tag_misc_info_crate_items: uint = 0x7f;
-pub static tag_item_method_provided_source: uint = 0x81;
-pub static tag_item_impl_vtables: uint = 0x82;
+pub static tag_item_method_provided_source: uint = 0x80;
+pub static tag_item_impl_vtables: uint = 0x81;
-pub static tag_impls: uint = 0x83;
-pub static tag_impls_impl: uint = 0x84;
+pub static tag_impls: uint = 0x82;
+pub static tag_impls_impl: uint = 0x83;
-pub static tag_items_data_item_inherent_impl: uint = 0x85;
-pub static tag_items_data_item_extension_impl: uint = 0x86;
+pub static tag_items_data_item_inherent_impl: uint = 0x84;
+pub static tag_items_data_item_extension_impl: uint = 0x85;
-pub static tag_path_elem_pretty_name: uint = 0x87;
-pub static tag_path_elem_pretty_name_ident: uint = 0x88;
-pub static tag_path_elem_pretty_name_extra: uint = 0x89;
+pub static tag_path_elem_pretty_name: uint = 0x86;
+pub static tag_path_elem_pretty_name_ident: uint = 0x87;
+pub static tag_path_elem_pretty_name_extra: uint = 0x88;
pub static tag_region_param_def: uint = 0x100;
pub static tag_region_param_def_ident: uint = 0x101;
|_, did| translate_def_id(cdata, did))
}
-fn doc_transformed_self_ty(doc: ebml::Doc,
- tcx: ty::ctxt,
- cdata: Cmd) -> Option<ty::t>
-{
- reader::maybe_get_doc(doc, tag_item_method_transformed_self_ty).map(|tp| {
- parse_ty_data(tp.data, cdata.cnum, tp.start, tcx,
- |_, did| translate_def_id(cdata, did))
- })
-}
-
pub fn item_type(_item_id: ast::DefId, item: ebml::Doc,
tcx: ty::ctxt, cdata: Cmd) -> ty::t {
doc_type(item, tcx, cdata)
let explicit_self_kind = string[0];
match explicit_self_kind as char {
's' => ast::SelfStatic,
- 'v' => ast::SelfValue(get_mutability(string[1])),
+ 'v' => ast::SelfValue,
'@' => ast::SelfBox,
- '~' => ast::SelfUniq(get_mutability(string[1])),
+ '~' => ast::SelfUniq,
// FIXME(#4846) expl. region
'&' => ast::SelfRegion(None, get_mutability(string[1])),
_ => fail!("unknown self type code: `{}`", explicit_self_kind as char)
let type_param_defs = item_ty_param_defs(method_doc, tcx, cdata,
tag_item_method_tps);
let rp_defs = item_region_param_defs(method_doc, tcx, cdata);
- let transformed_self_ty = doc_transformed_self_ty(method_doc, tcx, cdata);
let fty = doc_method_fty(method_doc, tcx, cdata);
let vis = item_visibility(method_doc);
let explicit_self = get_explicit_self(method_doc);
type_param_defs: type_param_defs,
region_param_defs: rp_defs,
},
- transformed_self_ty,
fty,
explicit_self,
vis,
ebml_w.end_tag();
}
-fn encode_transformed_self_ty(ecx: &EncodeContext,
- ebml_w: &mut writer::Encoder,
- opt_typ: Option<ty::t>) {
- for &typ in opt_typ.iter() {
- ebml_w.start_tag(tag_item_method_transformed_self_ty);
- write_type(ecx, ebml_w, typ);
- ebml_w.end_tag();
- }
-}
-
fn encode_method_fty(ecx: &EncodeContext,
ebml_w: &mut writer::Encoder,
typ: &ty::BareFnTy) {
// Encode the base self type.
match explicit_self {
- SelfStatic => {
- ebml_w.writer.write(&[ 's' as u8 ]);
- }
- SelfValue(m) => {
- ebml_w.writer.write(&[ 'v' as u8 ]);
- encode_mutability(ebml_w, m);
- }
+ SelfStatic => ebml_w.writer.write(&[ 's' as u8 ]),
+ SelfValue => ebml_w.writer.write(&[ 'v' as u8 ]),
+ SelfBox => ebml_w.writer.write(&[ '@' as u8 ]),
+ SelfUniq => ebml_w.writer.write(&[ '~' as u8 ]),
SelfRegion(_, m) => {
// FIXME(#4846) encode custom lifetime
- ebml_w.writer.write(&[ '&' as u8 ]);
- encode_mutability(ebml_w, m);
- }
- SelfBox => {
- ebml_w.writer.write(&[ '@' as u8 ]);
- }
- SelfUniq(m) => {
- ebml_w.writer.write(&[ '~' as u8 ]);
+ ebml_w.writer.write(&['&' as u8]);
encode_mutability(ebml_w, m);
}
}
encode_ty_type_param_defs(ebml_w, ecx,
method_ty.generics.type_param_defs,
tag_item_method_tps);
- encode_transformed_self_ty(ecx, ebml_w, method_ty.transformed_self_ty);
encode_method_fty(ecx, ebml_w, &method_ty.fty);
encode_visibility(ebml_w, method_ty.vis);
encode_explicit_self(ebml_w, method_ty.explicit_self);
return ty::mk_bare_fn(st.tcx, parse_bare_fn_ty(st, |x,y| conv(x,y)));
}
'Y' => return ty::mk_type(st.tcx),
- 'C' => {
- let sigil = parse_sigil(st);
- return ty::mk_opaque_closure_ptr(st.tcx, sigil);
- }
'#' => {
let pos = parse_hex(st);
assert_eq!(next(st), ':');
mywrite!(w, "s{}|", (cx.ds)(did));
}
ty::ty_type => mywrite!(w, "Y"),
- ty::ty_opaque_closure_ptr(p) => {
- mywrite!(w, "C&");
- enc_sigil(w, p);
- }
ty::ty_struct(def, ref substs) => {
mywrite!(w, "a[{}|", (cx.ds)(def));
enc_substs(w, cx, substs);
ast::DefMethod(did0.tr(xcx), did1.map(|did1| did1.tr(xcx)))
}
ast::DefSelfTy(nid) => { ast::DefSelfTy(xcx.tr_id(nid)) }
- ast::DefSelf(nid, m) => { ast::DefSelf(xcx.tr_id(nid), m) }
ast::DefMod(did) => { ast::DefMod(did.tr(xcx)) }
ast::DefForeignMod(did) => { ast::DefForeignMod(did.tr(xcx)) }
ast::DefStatic(did, m) => { ast::DefStatic(did.tr(xcx), m) }
-> method_map_entry;
}
-fn encode_method_map_entry(ecx: &e::EncodeContext,
- ebml_w: &mut writer::Encoder,
- mme: method_map_entry) {
+fn encode_method_map_entry(ebml_w: &mut writer::Encoder, mme: method_map_entry) {
ebml_w.emit_struct("method_map_entry", 3, |ebml_w| {
- ebml_w.emit_struct_field("self_ty", 0u, |ebml_w| {
- ebml_w.emit_ty(ecx, mme.self_ty);
- });
- ebml_w.emit_struct_field("explicit_self", 2u, |ebml_w| {
- mme.explicit_self.encode(ebml_w);
- });
ebml_w.emit_struct_field("origin", 1u, |ebml_w| {
mme.origin.encode(ebml_w);
});
-> method_map_entry {
self.read_struct("method_map_entry", 3, |this| {
method_map_entry {
- self_ty: this.read_struct_field("self_ty", 0u, |this| {
- this.read_ty(xcx)
- }),
- explicit_self: this.read_struct_field("explicit_self",
- 2,
- |this| {
- let explicit_self: ast::ExplicitSelf_ = Decodable::decode(this);
- explicit_self
- }),
origin: this.read_struct_field("origin", 1, |this| {
let method_origin: method_origin =
Decodable::decode(this);
ebml_w.tag(c::tag_table_method_map, |ebml_w| {
ebml_w.id(id);
ebml_w.tag(c::tag_table_val, |ebml_w| {
- encode_method_map_entry(ecx, ebml_w, *mme)
+ encode_method_map_entry(ebml_w, *mme)
})
})
}
debug!("mark_writes_through_upvars_as_used_mut(cmt={})",
cmt.repr(this.tcx()));
match cmt.cat {
- mc::cat_local(id) |
- mc::cat_arg(id) |
- mc::cat_self(id) => {
+ mc::cat_local(id) | mc::cat_arg(id) => {
let mut used_mut_nodes = this.tcx()
.used_mut_nodes
.borrow_mut();
mc::cat_rvalue(..) |
mc::cat_local(..) |
mc::cat_arg(_) |
- mc::cat_self(..) |
mc::cat_deref(_, _, mc::unsafe_ptr(..)) |
mc::cat_static_item(..) |
mc::cat_deref(_, _, mc::gc_ptr) |
let method_map = this.bccx.method_map.borrow();
match expr.node {
- ast::ExprSelf |
ast::ExprPath(..) => {
if !this.move_data.is_assignee(expr.id) {
let cmt = this.bccx.cat_expr_unadjusted(expr);
ast::ExprCall(f, ref args, _) => {
this.check_call(expr, Some(f), f.id, f.span, *args);
}
- ast::ExprMethodCall(callee_id, _, _, _, ref args, _) => {
+ ast::ExprMethodCall(callee_id, _, _, ref args, _) => {
this.check_call(expr, None, callee_id, expr.span, *args);
}
ast::ExprIndex(callee_id, _, rval) |
ast::ExprBinary(callee_id, _, _, rval)
if method_map.get().contains_key(&expr.id) => {
- this.check_call(expr,
- None,
- callee_id,
- expr.span,
- [rval]);
+ this.check_call(expr, None, callee_id, expr.span, [rval]);
}
ast::ExprUnary(callee_id, _, _) | ast::ExprIndex(callee_id, _, _)
if method_map.get().contains_key(&expr.id) => {
- this.check_call(expr,
- None,
- callee_id,
- expr.span,
- []);
+ this.check_call(expr, None, callee_id, expr.span, []);
}
ast::ExprInlineAsm(ref ia) => {
for &(_, out) in ia.outputs.iter() {
this.check_assignment(out);
}
}
- _ => { }
+ _ => {}
}
}
mc::cat_rvalue(..) |
mc::cat_local(..) |
- mc::cat_arg(..) |
- mc::cat_self(..) => {
+ mc::cat_arg(..) => {
true
}
mc::cat_copied_upvar(..) | // L-Local
mc::cat_local(..) | // L-Local
mc::cat_arg(..) | // L-Local
- mc::cat_self(..) | // L-Local
mc::cat_deref(_, _, mc::region_ptr(..)) | // L-Deref-Borrowed
mc::cat_deref(_, _, mc::unsafe_ptr(..)) => {
let scope = self.scope(cmt);
match cmt.guarantor().cat {
mc::cat_local(id) |
- mc::cat_self(id) |
mc::cat_arg(id) => {
let moved_variables_set = self.bccx
.moved_variables_set
ty::ReStatic
}
mc::cat_local(local_id) |
- mc::cat_arg(local_id) |
- mc::cat_self(local_id) => {
+ mc::cat_arg(local_id) => {
ty::ReScope(self.bccx.tcx.region_maps.var_scope(local_id))
}
mc::cat_deref(_, _, mc::unsafe_ptr(..)) => {
}
mc::cat_local(local_id) |
- mc::cat_arg(local_id) |
- mc::cat_self(local_id) => {
+ mc::cat_arg(local_id) => {
// R-Variable
let lp = @LpVar(local_id);
SafeIf(lp, ~[Restriction {loan_path: lp,
use std::result::{Result};
use syntax::ast;
use syntax::ast_map;
+use syntax::ast_util;
use syntax::codemap::Span;
use syntax::parse::token;
use syntax::visit;
None
}
- mc::cat_local(id) |
- mc::cat_arg(id) |
- mc::cat_self(id) => {
+ mc::cat_local(id) | mc::cat_arg(id) => {
Some(@LpVar(id))
}
match *loan_path {
LpVar(id) => {
match self.tcx.items.find(id) {
- Some(ast_map::NodeLocal(ref ident, _)) => {
- out.push_str(token::ident_to_str(ident));
+ Some(ast_map::NodeLocal(pat)) => {
+ match pat.node {
+ ast::PatIdent(_, ref path, _) => {
+ let ident = ast_util::path_to_ident(path);
+ out.push_str(token::ident_to_str(&ident));
+ }
+ _ => {
+ self.tcx.sess.bug(
+ format!("Loan path LpVar({:?}) maps to {:?}, not local",
+ id, pat));
+ }
+ }
}
r => {
self.tcx.sess.bug(
self.call(expr, pred, func, *args)
}
- ast::ExprMethodCall(_, rcvr, _, _, ref args, _) => {
- self.call(expr, pred, rcvr, *args)
+ ast::ExprMethodCall(_, _, _, ref args, _) => {
+ self.call(expr, pred, args[0], args.slice_from(1))
}
ast::ExprIndex(_, l, r) |
ast::ExprLogLevel |
ast::ExprMac(..) |
ast::ExprInlineAsm(..) |
- ast::ExprSelf |
ast::ExprFnBlock(..) |
ast::ExprProc(..) |
ast::ExprLit(..) |
}
ast::ExprCall(f, ref args, _) => {
- self.walk_call(f.id, expr.id,
- f, *args, in_out, loop_scopes);
+ self.walk_expr(f, in_out, loop_scopes);
+ self.walk_call(f.id, expr.id, *args, in_out, loop_scopes);
}
- ast::ExprMethodCall(callee_id, rcvr, _, _, ref args, _) => {
- self.walk_call(callee_id, expr.id,
- rcvr, *args, in_out, loop_scopes);
+ ast::ExprMethodCall(callee_id, _, _, ref args, _) => {
+ self.walk_call(callee_id, expr.id, *args, in_out, loop_scopes);
}
ast::ExprIndex(callee_id, l, r) |
ast::ExprBinary(callee_id, _, l, r) if self.is_method_call(expr) => {
- self.walk_call(callee_id, expr.id,
- l, [r], in_out, loop_scopes);
+ self.walk_call(callee_id, expr.id, [l, r], in_out, loop_scopes);
}
ast::ExprUnary(callee_id, _, e) if self.is_method_call(expr) => {
- self.walk_call(callee_id, expr.id,
- e, [], in_out, loop_scopes);
+ self.walk_call(callee_id, expr.id, [e], in_out, loop_scopes);
}
ast::ExprTup(ref exprs) => {
ast::ExprLogLevel |
ast::ExprLit(..) |
- ast::ExprPath(..) |
- ast::ExprSelf => {
- }
+ ast::ExprPath(..) => {}
ast::ExprAddrOf(_, e) |
ast::ExprDoBody(e) |
fn walk_call(&mut self,
_callee_id: ast::NodeId,
call_id: ast::NodeId,
- arg0: &ast::Expr,
args: &[@ast::Expr],
in_out: &mut [uint],
loop_scopes: &mut ~[LoopScope]) {
- self.walk_expr(arg0, in_out, loop_scopes);
self.walk_exprs(args, in_out, loop_scopes);
// FIXME(#6268) nested method calls
fn visit_expr(&mut self, expr: &ast::Expr, _:()) {
match expr.node {
- ast::ExprMethodCall(callee_id, _, _, _, _, _) => {
+ ast::ExprMethodCall(callee_id, _, _, _, _) => {
let base_type = ty::node_id_to_type(self.tcx, callee_id);
debug!("effect: method call case, base type is {}",
ppaux::ty_to_str(self.tcx, base_type));
ast::ExprFnBlock(..) | ast::ExprProc(..) => {
visit::walk_expr(self, expr, depth + 1)
}
- ast::ExprPath(..) | ast::ExprSelf => {
+ ast::ExprPath(..) => {
let mut i = 0;
let def_map = self.def_map.borrow();
match def_map.get().find(&expr.id) {
sp,
"mutable variables cannot be implicitly captured");
}
- DefLocal(..) | DefArg(..) => { /* ok */ }
+ DefLocal(..) | DefArg(..) | DefBinding(..) => { /* ok */ }
DefUpvar(_, def1, _, _) => { check_imm_free_var(cx, *def1, sp); }
- DefBinding(..) | DefSelf(..) => { /*ok*/ }
_ => {
cx.tcx.sess.span_bug(
sp,
})
};
- // Add `this`, whether explicit or implicit.
- match *fk {
- visit::FkMethod(_, _, method) => {
- match method.explicit_self.node {
- SelfValue(_) | SelfRegion(..) | SelfBox | SelfUniq(_) => {
- fn_maps.add_variable(Arg(method.self_id,
- special_idents::self_));
- }
- SelfStatic => {}
- }
- }
- visit::FkItemFn(..) | visit::FkFnBlock(..) => {}
- }
-
// gather up the various local variables, significant expressions,
// and so forth:
visit::walk_fn(v, fk, decl, body, sp, id, fn_maps);
fn visit_expr(v: &mut LivenessVisitor, expr: &Expr, this: @IrMaps) {
match expr.node {
// live nodes required for uses or definitions of variables:
- ExprPath(_) | ExprSelf => {
+ ExprPath(_) => {
let def_map = this.tcx.def_map.borrow();
let def = def_map.get().get_copy(&expr.id);
debug!("expr {}: path that leads to {:?}", expr.id, def);
match expr.node {
// Interesting cases with control flow or which gen/kill
- ExprPath(_) | ExprSelf => {
+ ExprPath(_) => {
self.access_path(expr, succ, ACC_READ | ACC_USE)
}
self.propagate_through_expr(f, succ)
}
- ExprMethodCall(callee_id, rcvr, _, _, ref args, _) => {
+ ExprMethodCall(callee_id, _, _, ref args, _) => {
// calling a method with bot return type means that the method
// will fail, and hence the successors can be ignored
let t_ret = ty::ty_fn_ret(ty::node_id_to_type(self.tcx, callee_id));
let succ = if ty::type_is_bot(t_ret) {self.s.exit_ln}
else {succ};
- let succ = self.propagate_through_exprs(*args, succ);
- self.propagate_through_expr(rcvr, succ)
+ self.propagate_through_exprs(*args, succ)
}
ExprTup(ref exprs) => {
ExprAgain(..) | ExprLit(_) | ExprBlock(..) |
ExprMac(..) | ExprAddrOf(..) | ExprStruct(..) | ExprRepeat(..) |
ExprParen(..) | ExprFnBlock(..) | ExprProc(..) | ExprPath(..) |
- ExprSelf(..) | ExprBox(..) => {
+ ExprBox(..) => {
visit::walk_expr(this, expr, ());
}
ExprForLoop(..) => fail!("non-desugared expr_for_loop")
for arg in decl.inputs.iter() {
pat_util::pat_bindings(self.tcx.def_map,
arg.pat,
- |_bm, p_id, sp, _n| {
+ |_bm, p_id, sp, path| {
let var = self.variable(p_id, sp);
- self.warn_about_unused(sp, p_id, entry_ln, var);
+ // Ignore unused self.
+ let ident = ast_util::path_to_ident(path);
+ if ident.name != special_idents::self_.name {
+ self.warn_about_unused(sp, p_id, entry_ln, var);
+ }
})
}
}
cat_interior(cmt, InteriorKind), // something interior: field, tuple, etc
cat_downcast(cmt), // selects a particular enum variant (..)
cat_discr(cmt, ast::NodeId), // match discriminant (see preserve())
- cat_self(ast::NodeId), // explicit `self`
// (..) downcast is only required if the enum has more than one variant
}
self.cat_index(expr, base_cmt, 0)
}
- ast::ExprPath(_) | ast::ExprSelf => {
+ ast::ExprPath(_) => {
let def_map = self.tcx.def_map.borrow();
let def = def_map.get().get_copy(&expr.id);
self.cat_def(expr.id, expr.span, expr_ty, def)
}
}
- ast::DefSelf(self_id, mutbl) => {
- @cmt_ {
- id:id,
- span:span,
- cat:cat_self(self_id),
- mutbl: if mutbl { McDeclared } else { McImmutable },
- ty:expr_ty
- }
- }
-
ast::DefUpvar(upvar_id, inner, fn_node_id, _) => {
let ty = ty::node_id_to_type(self.tcx, fn_node_id);
match ty::get(ty).sty {
cat_local(_) => {
~"local variable"
}
- cat_self(_) => {
- ~"self value"
- }
cat_arg(..) => {
~"argument"
}
cat_static_item |
cat_copied_upvar(..) |
cat_local(..) |
- cat_self(..) |
cat_arg(..) |
cat_deref(_, _, unsafe_ptr(..)) |
cat_deref(_, _, gc_ptr) |
cat_rvalue(..) |
cat_local(..) |
cat_arg(_) |
- cat_self(..) |
cat_deref(_, _, unsafe_ptr(..)) | // of course it is aliasable, but...
cat_deref(_, _, region_ptr(MutMutable, _)) => {
None
cat_rvalue(..) |
cat_copied_upvar(..) |
cat_local(..) |
- cat_self(..) |
cat_arg(..) => {
format!("{:?}", *self)
}
pub fn moved_variable_node_id_from_def(def: Def) -> Option<NodeId> {
match def {
- DefBinding(nid, _) |
- DefArg(nid, _) |
- DefLocal(nid, _) |
- DefSelf(nid, _) => Some(nid),
+ DefBinding(nid, _) |
+ DefArg(nid, _) |
+ DefLocal(nid, _) => Some(nid),
_ => None
}
debug!("comp_mode = {:?}", comp_mode);
match expr.node {
- ExprPath(..) | ExprSelf => {
+ ExprPath(..) => {
match comp_mode {
Move => {
let def_map = self.tcx.def_map.borrow();
self.use_fn_args(callee.id, *args);
}
- ExprMethodCall(callee_id, rcvr, _, _, ref args, _) => { // callee.m(args)
- // Implicit self is equivalent to & mode, but every
- // other kind should be + mode.
- self.use_receiver(rcvr);
+ ExprMethodCall(callee_id, _, _, ref args, _) => { // callee.m(args)
self.use_fn_args(callee_id, *args);
}
return false;
}
- self.use_receiver(receiver_expr);
+ self.use_fn_arg(receiver_expr);
// for overloaded operatrs, we are always passing in a
// reference, so it's always read mode:
})
}
- pub fn use_receiver(&mut self,
- receiver_expr: @Expr) {
- self.use_fn_arg(receiver_expr);
- }
-
pub fn use_fn_args(&mut self,
_: NodeId,
arg_exprs: &[@Expr]) {
_ => {}
}
}
- ast::ExprMethodCall(_, base, ident, _, _, _) => {
+ ast::ExprMethodCall(_, ident, _, ref args, _) => {
// see above
- let t = ty::type_autoderef(ty::expr_ty(self.tcx, base));
+ let t = ty::type_autoderef(ty::expr_ty(self.tcx, args[0]));
match ty::get(t).sty {
ty::ty_enum(_, _) | ty::ty_struct(_, _) => {
let method_map = self.method_map.borrow();
// The arguments and `self` are parented to the body of the fn.
let decl_cx = Context {parent: Some(body.id),
var_parent: Some(body.id)};
- match *fk {
- visit::FkMethod(_, _, method) => {
- visitor.region_maps.record_var_scope(method.self_id, body.id);
- }
- _ => {}
- }
visit::walk_fn_decl(visitor, decl, decl_cx);
// The body of the fn itself is either a root scope (top-level fn)
ImportNameDefinition(Def, LastPrivate) //< The name identifies an import.
}
-enum SelfBinding {
- NoSelfBinding,
- HasSelfBinding(NodeId, ExplicitSelf)
-}
-
impl Visitor<()> for Resolver {
fn visit_item(&mut self, item: &Item, _: ()) {
self.resolve_item(item);
PrefixFound(@Module, uint)
}
-#[deriving(Eq)]
-enum AllowCapturingSelfFlag {
- AllowCapturingSelf, //< The "self" definition can be captured.
- DontAllowCapturingSelf, //< The "self" definition cannot be captured.
-}
-
#[deriving(Eq)]
enum NameSearchType {
/// We're doing a name search in order to resolve a `use` directive.
/// One local scope.
struct Rib {
bindings: RefCell<HashMap<Name, DefLike>>,
- self_binding: RefCell<Option<DefLike>>,
kind: RibKind,
}
fn new(kind: RibKind) -> Rib {
Rib {
bindings: RefCell::new(HashMap::new()),
- self_binding: RefCell::new(None),
kind: kind
}
}
ignoring {:?}", def);
// Ignored; handled elsewhere.
}
- DefSelf(..) | DefArg(..) | DefLocal(..) |
- DefPrimTy(..) | DefTyParam(..) | DefBinding(..) |
+ DefArg(..) | DefLocal(..) | DefPrimTy(..) |
+ DefTyParam(..) | DefBinding(..) |
DefUse(..) | DefUpvar(..) | DefRegion(..) |
DefTyParamBinder(..) | DefLabel(..) | DefSelfTy(..) => {
fail!("didn't expect `{:?}`", def);
ribs: &mut ~[@Rib],
rib_index: uint,
def_like: DefLike,
- span: Span,
- allow_capturing_self: AllowCapturingSelfFlag)
+ span: Span)
-> Option<DefLike> {
let mut def;
let is_ty_param;
def = d;
is_ty_param = true;
}
- DlDef(d @ DefSelf(..))
- if allow_capturing_self == DontAllowCapturingSelf => {
- def = d;
- is_ty_param = false;
- }
_ => {
return Some(def_like);
}
fn search_ribs(&mut self,
ribs: &mut ~[@Rib],
name: Name,
- span: Span,
- allow_capturing_self: AllowCapturingSelfFlag)
+ span: Span)
-> Option<DefLike> {
// FIXME #4950: This should not use a while loop.
// FIXME #4950: Try caching?
};
match binding_opt {
Some(def_like) => {
- return self.upvarify(ribs, i, def_like, span,
- allow_capturing_self);
+ return self.upvarify(ribs, i, def_like, span);
}
None => {
// Continue.
item.id,
0,
OpaqueFunctionRibKind),
- block,
- NoSelfBinding);
+ block);
}
ItemStatic(..) => {
}
fn resolve_function(&mut self,
- rib_kind: RibKind,
- optional_declaration: Option<P<FnDecl>>,
- type_parameters: TypeParameters,
- block: P<Block>,
- self_binding: SelfBinding) {
+ rib_kind: RibKind,
+ optional_declaration: Option<P<FnDecl>>,
+ type_parameters: TypeParameters,
+ block: P<Block>) {
// Create a value rib for the function.
let function_value_rib = @Rib::new(rib_kind);
{
}
}
- // Add self to the rib, if necessary.
- match self_binding {
- NoSelfBinding => {
- // Nothing to do.
- }
- HasSelfBinding(self_node_id, explicit_self) => {
- let mutable = match explicit_self.node {
- SelfUniq(m) | SelfValue(m) if m == MutMutable => true,
- _ => false
- };
- let def_like = DlDef(DefSelf(self_node_id, mutable));
- function_value_rib.self_binding.set(Some(def_like));
- }
- }
-
// Add each argument to the rib.
match optional_declaration {
None => {
// Does this really need to take a RibKind or is it always going
// to be NormalRibKind?
fn resolve_method(&mut self,
- rib_kind: RibKind,
- method: @Method,
- outer_type_parameter_count: uint) {
+ rib_kind: RibKind,
+ method: @Method,
+ outer_type_parameter_count: uint) {
let method_generics = &method.generics;
let type_parameters =
HasTypeParameters(method_generics,
method.id,
outer_type_parameter_count,
rib_kind);
- // we only have self ty if it is a non static method
- let self_binding = match method.explicit_self.node {
- SelfStatic => NoSelfBinding,
- _ => HasSelfBinding(method.self_id, method.explicit_self)
- };
- self.resolve_function(rib_kind,
- Some(method.decl),
- type_parameters,
- method.body,
- self_binding);
+ self.resolve_function(rib_kind, Some(method.decl), type_parameters, method.body);
}
fn resolve_implementation(&mut self,
method.id,
outer_type_parameter_count,
NormalRibKind),
- method.body,
- HasSelfBinding(method.self_id),
- visitor);
+ method.body);
*/
}
let mut value_ribs = self.value_ribs.borrow_mut();
search_result = self.search_ribs(value_ribs.get(),
renamed,
- span,
- DontAllowCapturingSelf);
+ span);
}
TypeNS => {
let name = ident.name;
let mut type_ribs = self.type_ribs.borrow_mut();
search_result = self.search_ribs(type_ribs.get(),
name,
- span,
- AllowCapturingSelf);
+ span);
}
}
}
}
- fn resolve_self_value_in_local_ribs(&mut self, span: Span)
- -> Option<Def> {
- // FIXME #4950: This should not use a while loop.
- let mut i = {
- let value_ribs = self.value_ribs.borrow();
- value_ribs.get().len()
- };
- while i != 0 {
- i -= 1;
- let self_binding_opt = {
- let value_ribs = self.value_ribs.borrow();
- value_ribs.get()[i].self_binding.get()
- };
- match self_binding_opt {
- Some(def_like) => {
- let mut value_ribs = self.value_ribs.borrow_mut();
- match self.upvarify(value_ribs.get(),
- i,
- def_like,
- span,
- DontAllowCapturingSelf) {
- Some(DlDef(def)) => return Some(def),
- _ => {
- if self.session.has_errors() {
- // May happen inside a nested fn item, cf #6642.
- return None;
- } else {
- self.session.span_bug(span,
- "self wasn't mapped to a def?!")
- }
- }
- }
- }
- None => {}
- }
- }
-
- None
- }
-
fn resolve_item_by_identifier_in_lexical_scope(&mut self,
ident: Ident,
namespace: Namespace)
ExprFnBlock(fn_decl, block) |
ExprProc(fn_decl, block) => {
self.resolve_function(FunctionRibKind(expr.id, block.id),
- Some(fn_decl),
- NoTypeParameters,
- block,
- NoSelfBinding);
+ Some(fn_decl), NoTypeParameters,
+ block);
}
ExprStruct(ref path, _, _) => {
ExprBreak(Some(label)) | ExprAgain(Some(label)) => {
let mut label_ribs = self.label_ribs.borrow_mut();
- match self.search_ribs(label_ribs.get(), label, expr.span,
- DontAllowCapturingSelf) {
+ match self.search_ribs(label_ribs.get(), label, expr.span) {
None =>
self.resolve_error(expr.span,
format!("use of undeclared label \
}
}
- ExprSelf => {
- match self.resolve_self_value_in_local_ribs(expr.span) {
- None => {
- self.resolve_error(expr.span,
- "`self` is not allowed in \
- this context")
- }
- Some(def) => self.record_def(expr.id, (def, AllPublic)),
- }
- }
-
_ => {
visit::walk_expr(self, expr, ());
}
let traits = self.search_for_traits_containing_method(ident);
self.trait_map.insert(expr.id, @RefCell::new(traits));
}
- ExprMethodCall(_, _, ident, _, _, _) => {
+ ExprMethodCall(_, ident, _, _, _) => {
debug!("(recording candidate traits for expr) recording \
traits for {}",
expr.id);
return adt::trans_case(bcx, repr, disr_val);
}
range(l1, l2) => {
- let (l1, _) = consts::const_expr(ccx, l1);
- let (l2, _) = consts::const_expr(ccx, l2);
+ let (l1, _) = consts::const_expr(ccx, l1, true);
+ let (l2, _) = consts::const_expr(ccx, l2, true);
return range_result(rslt(bcx, l1), rslt(bcx, l2));
}
vec_len(n, vec_len_eq, _) => {
}
}
- let f = decl_rust_fn(ccx, None, inputs, output, name);
+ let f = decl_rust_fn(ccx, false, inputs, output, name);
csearch::get_item_attrs(ccx.tcx.cstore, did, |meta_items| {
set_llvm_fn_attrs(meta_items.iter().map(|&x| attr::mk_attr(x)).to_owned_vec(), f)
});
f
}
-fn decl_rust_fn(ccx: &CrateContext,
- self_ty: Option<ty::t>,
- inputs: &[ty::t],
- output: ty::t,
- name: &str) -> ValueRef {
- let llfty = type_of_rust_fn(ccx, self_ty, inputs, output);
+pub fn decl_rust_fn(ccx: &CrateContext, has_env: bool,
+ inputs: &[ty::t], output: ty::t,
+ name: &str) -> ValueRef {
+ let llfty = type_of_rust_fn(ccx, has_env, inputs, output);
let llfn = decl_cdecl_fn(ccx.llmod, name, llfty, output);
let uses_outptr = type_of::return_uses_outptr(ccx, output);
- let offset = if uses_outptr { 2 } else { 1 };
+ let offset = if uses_outptr { 1 } else { 0 };
+ let offset = if has_env { offset + 1 } else { offset };
for (i, &arg_ty) in inputs.iter().enumerate() {
let llarg = unsafe { llvm::LLVMGetParam(llfn, (offset + i) as c_uint) };
llfn
}
-pub fn decl_internal_rust_fn(ccx: &CrateContext,
- self_ty: Option<ty::t>, inputs: &[ty::t],
- output: ty::t, name: &str) -> ValueRef {
- let llfn = decl_rust_fn(ccx, self_ty, inputs, output, name);
+pub fn decl_internal_rust_fn(ccx: &CrateContext, has_env: bool,
+ inputs: &[ty::t], output: ty::t,
+ name: &str) -> ValueRef {
+ let llfn = decl_rust_fn(ccx, has_env, inputs, output, name);
lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
llfn
}
// Returns a pointer to the body for the box. The box may be an opaque
// box. The result will be casted to the type of body_t, if it is statically
// known.
-//
-// The runtime equivalent is box_body() in "rust_internal.h".
-pub fn opaque_box_body(bcx: &Block, body_t: ty::t, boxptr: ValueRef)
- -> ValueRef {
- let _icx = push_ctxt("opaque_box_body");
+pub fn at_box_body(bcx: &Block, body_t: ty::t, boxptr: ValueRef) -> ValueRef {
+ let _icx = push_ctxt("at_box_body");
let ccx = bcx.ccx();
- let ty = type_of(ccx, body_t);
- let ty = Type::smart_ptr(ccx, &ty);
+ let ty = Type::at_box(ccx, type_of(ccx, body_t));
let boxptr = PointerCast(bcx, boxptr, ty.ptr_to());
GEPi(bcx, boxptr, [0u, abi::box_field_body])
}
})
}
-pub fn null_env_ptr(ccx: &CrateContext) -> ValueRef {
- C_null(Type::opaque_box(ccx).ptr_to())
-}
-
pub fn trans_external_path(ccx: &CrateContext, did: ast::DefId, t: ty::t) -> ValueRef {
let name = csearch::get_symbol(ccx.sess.cstore, did);
match ty::get(t).sty {
Some(..) | None => {
let c = foreign::llvm_calling_convention(ccx, fn_ty.abis);
let cconv = c.unwrap_or(lib::llvm::CCallConv);
- let llty = type_of_fn_from_ty(ccx, None, t);
+ let llty = type_of_fn_from_ty(ccx, t);
let mut externs = ccx.externs.borrow_mut();
get_extern_fn(externs.get(), ccx.llmod, name,
cconv, llty, fn_ty.sig.output)
path: ast_map::Path,
llfndecl: ValueRef,
id: ast::NodeId,
+ has_env: bool,
output_type: ty::t,
param_substs: Option<@param_substs>,
sp: Option<Span>)
let uses_outptr = type_of::return_uses_outptr(ccx, substd_output_type);
let debug_context = debuginfo::create_function_debug_context(ccx, id, param_substs, llfndecl);
- let fcx = FunctionContext {
- llfn: llfndecl,
- llenv: unsafe {
- Cell::new(llvm::LLVMGetUndef(Type::i8p().to_ref()))
- },
- llretptr: Cell::new(None),
- entry_bcx: RefCell::new(None),
- alloca_insert_pt: Cell::new(None),
- llreturn: Cell::new(None),
- llself: Cell::new(None),
- personality: Cell::new(None),
- caller_expects_out_pointer: uses_outptr,
- llargs: RefCell::new(HashMap::new()),
- lllocals: RefCell::new(HashMap::new()),
- llupvars: RefCell::new(HashMap::new()),
- id: id,
- param_substs: param_substs,
- span: sp,
- path: path,
- block_arena: TypedArena::new(),
- ccx: ccx,
- debug_context: debug_context,
- scopes: RefCell::new(~[])
+ let mut fcx = FunctionContext {
+ llfn: llfndecl,
+ llenv: None,
+ llretptr: Cell::new(None),
+ entry_bcx: RefCell::new(None),
+ alloca_insert_pt: Cell::new(None),
+ llreturn: Cell::new(None),
+ personality: Cell::new(None),
+ caller_expects_out_pointer: uses_outptr,
+ llargs: RefCell::new(HashMap::new()),
+ lllocals: RefCell::new(HashMap::new()),
+ llupvars: RefCell::new(HashMap::new()),
+ id: id,
+ param_substs: param_substs,
+ span: sp,
+ path: path,
+ block_arena: TypedArena::new(),
+ ccx: ccx,
+ debug_context: debug_context,
+ scopes: RefCell::new(~[])
};
- fcx.llenv.set(unsafe {
- llvm::LLVMGetParam(llfndecl, fcx.env_arg_pos() as c_uint)
- });
+
+ if has_env {
+ fcx.llenv = Some(unsafe {
+ llvm::LLVMGetParam(fcx.llfn, fcx.env_arg_pos() as c_uint)
+ });
+ }
fcx
}
skip_retptr: bool,
output_type: ty::t,
param_substs: Option<@param_substs>) {
- unsafe {
- let entry_bcx = fcx.new_temp_block("entry-block");
- Load(entry_bcx, C_null(Type::i8p()));
+ let entry_bcx = fcx.new_temp_block("entry-block");
- fcx.entry_bcx.set(Some(entry_bcx));
- fcx.alloca_insert_pt.set(Some(
- llvm::LLVMGetFirstInstruction(entry_bcx.llbb)));
- }
+ fcx.entry_bcx.set(Some(entry_bcx));
+
+ // Use a dummy instruction as the insertion point for all allocas.
+ // This is later removed in FunctionContext::cleanup.
+ fcx.alloca_insert_pt.set(Some(unsafe {
+ Load(entry_bcx, C_null(Type::i8p()));
+ llvm::LLVMGetFirstInstruction(entry_bcx.llbb)
+ }));
let substd_output_type = match param_substs {
None => output_type,
// Otherwise, we normally allocate the llretptr, unless we
// have been instructed to skip it for immediate return
// values.
- fcx.llretptr.set(Some(make_return_pointer(fcx,
- substd_output_type)));
+ fcx.llretptr.set(Some(make_return_pointer(fcx, substd_output_type)));
}
}
}
pub fn new_fn_ctxt(ccx: @CrateContext,
path: ast_map::Path,
llfndecl: ValueRef,
+ has_env: bool,
output_type: ty::t,
sp: Option<Span>)
-> FunctionContext {
// FIXME(#11385): Do not call `init_function` here; it will typecheck
// but segfault.
- new_fn_ctxt_detailed(ccx, path, llfndecl, -1, output_type, None, sp)
+ new_fn_ctxt_detailed(ccx, path, llfndecl, -1, has_env, output_type, None, sp)
}
// NB: must keep 4 fns in sync:
type RvalueDatum = datum::Datum<datum::Rvalue>;
type LvalueDatum = datum::Datum<datum::Lvalue>;
-// create_datums_for_fn_args: creates rvalue datums for `self` and each of the
+// create_datums_for_fn_args: creates rvalue datums for each of the
// incoming function arguments. These will later be stored into
// appropriate lvalue datums.
-fn create_datums_for_fn_args(cx: &FunctionContext,
- self_arg: Option<ty::t>,
- arg_tys: &[ty::t])
- -> (Option<RvalueDatum>, ~[RvalueDatum]) {
+pub fn create_datums_for_fn_args(fcx: &FunctionContext,
+ arg_tys: &[ty::t])
+ -> ~[RvalueDatum] {
let _icx = push_ctxt("create_datums_for_fn_args");
- let self_datum = self_arg.map(
- |t| datum::Datum(cx.llenv.get(), t, arg_kind(cx, t)));
-
// Return an array wrapping the ValueRefs that we get from
// llvm::LLVMGetParam for each argument into datums.
- let arg_datums = arg_tys.iter().enumerate().map(|(i, &arg_ty)| {
- let llarg = unsafe {
- llvm::LLVMGetParam(cx.llfn, cx.arg_pos(i) as c_uint)
- };
- datum::Datum(llarg, arg_ty, arg_kind(cx, arg_ty))
- }).collect();
-
- (self_datum, arg_datums)
+ arg_tys.iter().enumerate().map(|(i, &arg_ty)| {
+ let llarg = unsafe {
+ llvm::LLVMGetParam(fcx.llfn, fcx.arg_pos(i) as c_uint)
+ };
+ datum::Datum(llarg, arg_ty, arg_kind(fcx, arg_ty))
+ }).collect()
}
fn copy_args_to_allocas<'a>(fcx: &FunctionContext<'a>,
arg_scope: cleanup::CustomScopeIndex,
bcx: &'a Block<'a>,
args: &[ast::Arg],
- self_datum: Option<RvalueDatum>,
arg_datums: ~[RvalueDatum])
-> &'a Block<'a> {
debug!("copy_args_to_allocas");
let mut bcx = bcx;
let arg_scope_id = cleanup::CustomScope(arg_scope);
- match self_datum {
- Some(slf_rv) => {
- let slf = unpack_datum!(
- bcx, slf_rv.to_lvalue_datum_in_scope(bcx, "__self",
- arg_scope_id));
- fcx.llself.set(Some(slf));
- if fcx.ccx.sess.opts.extra_debuginfo {
- debuginfo::create_self_argument_metadata(bcx, slf.ty, slf.val);
- }
- }
- _ => {}
- }
for (i, arg_datum) in arg_datums.move_iter().enumerate() {
// For certain mode/type combinations, the raw llarg values are passed
}
}
- return bcx;
+ bcx
}
// Ties up the llstaticallocas -> llloadenv -> lltop edges,
decl: &ast::FnDecl,
body: &ast::Block,
llfndecl: ValueRef,
- self_arg: Option<ty::t>,
param_substs: Option<@param_substs>,
id: ast::NodeId,
_attributes: &[ast::Attribute],
debug!("trans_closure(..., param_substs={})",
param_substs.repr(ccx.tcx));
- let fcx = new_fn_ctxt_detailed(ccx,
- path,
- llfndecl,
- id,
- output_type,
- param_substs,
- Some(body.span));
+ let has_env = match ty::get(ty::node_id_to_type(ccx.tcx, id)).sty {
+ ty::ty_closure(_) => true,
+ _ => false
+ };
+
+ let fcx = new_fn_ctxt_detailed(ccx, path, llfndecl, id, has_env, output_type,
+ param_substs, Some(body.span));
init_function(&fcx, false, output_type, param_substs);
// cleanup scope for the incoming arguments
// Set up arguments to the function.
let arg_tys = ty::ty_fn_args(node_id_type(bcx, id));
- let (self_datum, arg_datums) =
- create_datums_for_fn_args(&fcx, self_arg, arg_tys);
+ let arg_datums = create_datums_for_fn_args(&fcx, arg_tys);
- bcx = copy_args_to_allocas(&fcx, arg_scope, bcx,
- decl.inputs, self_datum, arg_datums);
+ bcx = copy_args_to_allocas(&fcx, arg_scope, bcx, decl.inputs, arg_datums);
maybe_load_env(&fcx);
decl: &ast::FnDecl,
body: &ast::Block,
llfndecl: ValueRef,
- self_arg: Option<ty::t>,
param_substs: Option<@param_substs>,
id: ast::NodeId,
attrs: &[ast::Attribute]) {
let the_path_str = path_str(ccx.sess, path);
let _s = StatRecorder::new(ccx, the_path_str);
- debug!("trans_fn(self_arg={:?}, param_substs={})",
- self_arg,
- param_substs.repr(ccx.tcx));
+ debug!("trans_fn(param_substs={})", param_substs.repr(ccx.tcx));
let _icx = push_ctxt("trans_fn");
let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx, id));
trans_closure(ccx,
decl,
body,
llfndecl,
- self_arg,
param_substs,
id,
attrs,
ty_to_str(ccx.tcx, ctor_ty)))
};
- let fcx = new_fn_ctxt_detailed(ccx,
- ~[],
- llfndecl,
- ctor_id,
- result_ty,
- param_substs,
- None);
+ let fcx = new_fn_ctxt_detailed(ccx, ~[], llfndecl, ctor_id, false,
+ result_ty, param_substs, None);
init_function(&fcx, false, result_ty, param_substs);
let arg_tys = ty::ty_fn_args(ctor_ty);
- let (_, arg_datums) = create_datums_for_fn_args(&fcx, None, arg_tys);
+ let arg_datums = create_datums_for_fn_args(&fcx, arg_tys);
let bcx = fcx.entry_bcx.get().unwrap();
llfndecl,
item.id);
} else if !generics.is_type_parameterized() {
- let llfndecl = get_item_val(ccx, item.id);
- trans_fn(ccx,
- vec::append_one((*path).clone(), PathName(item.ident)),
- decl,
- body,
- llfndecl,
- None,
- None,
- item.id,
- item.attrs);
+ let path = vec::append_one((*path).clone(), PathName(item.ident));
+ let llfn = get_item_val(ccx, item.id);
+ trans_fn(ccx, path, decl, body, llfn, None, item.id, item.attrs);
} else {
// Be sure to travel more than just one layer deep to catch nested
// items in blocks and such.
sp: Span,
sym: ~str,
node_id: ast::NodeId,
- node_type: ty::t,
- self_ty: Option<ty::t>)
+ node_type: ty::t)
-> ValueRef {
let f = match ty::get(node_type).sty {
ty::ty_bare_fn(ref f) => {
_ => fail!("expected bare rust fn or an intrinsic")
};
- let llfn = decl_rust_fn(ccx, self_ty, f.sig.inputs, f.sig.output, sym);
+ let llfn = decl_rust_fn(ccx, false, f.sig.inputs, f.sig.output, sym);
finish_register_fn(ccx, sp, sym, node_id, llfn);
llfn
}
});
~[
- C_null(Type::opaque_box(ccx).ptr_to()),
opaque_rust_main,
llvm::LLVMGetParam(llfn, 0),
llvm::LLVMGetParam(llfn, 1)
} else {
debug!("using user-defined start fn");
let args = ~[
- C_null(Type::opaque_box(ccx).ptr_to()),
llvm::LLVMGetParam(llfn, 0 as c_uint),
llvm::LLVMGetParam(llfn, 1 as c_uint)
];
}
}
-pub fn fill_fn_pair(bcx: &Block,
- pair: ValueRef,
- llfn: ValueRef,
- llenvptr: ValueRef) {
- let ccx = bcx.ccx();
- let code_cell = GEPi(bcx, pair, [0u, abi::fn_field_code]);
- Store(bcx, llfn, code_cell);
- let env_cell = GEPi(bcx, pair, [0u, abi::fn_field_box]);
- let llenvblobptr = PointerCast(bcx, llenvptr, Type::opaque_box(ccx).ptr_to());
- Store(bcx, llenvblobptr, env_cell);
-}
-
pub fn item_path(ccx: &CrateContext, id: &ast::NodeId) -> ast_map::Path {
ty::item_path(ccx.tcx, ast_util::local_def(*id))
}
// using the current crate's name/version
// information in the hash of the symbol
debug!("making {}", sym);
- let sym = {
+ let (sym, is_local) = {
let external_srcs = ccx.external_srcs
.borrow();
match external_srcs.get().find(&i.id) {
Some(&did) => {
debug!("but found in other crate...");
- csearch::get_symbol(ccx.sess.cstore,
- did)
+ (csearch::get_symbol(ccx.sess.cstore,
+ did), false)
}
- None => sym
+ None => (sym, true)
}
};
// We need the translated value here, because for enums the
// LLVM type is not fully determined by the Rust type.
- let (v, inlineable) = consts::const_expr(ccx, expr);
+ let (v, inlineable) = consts::const_expr(ccx, expr, is_local);
{
let mut const_values = ccx.const_values
.borrow_mut();
ast::ItemFn(_, purity, _, _, _) => {
let llfn = if purity != ast::ExternFn {
- register_fn(ccx, i.span, sym, i.id, ty, None)
+ register_fn(ccx, i.span, sym, i.id, ty)
} else {
foreign::register_rust_fn_with_foreign_abi(ccx,
i.span,
llfn = match enm.node {
ast::ItemEnum(_, _) => {
- register_fn(ccx, (*v).span, sym, id, ty, None)
+ register_fn(ccx, (*v).span, sym, id, ty)
}
_ => fail!("NodeVariant, shouldn't happen")
};
let sym = exported_name(ccx, (*struct_path).clone(), ty,
struct_item.attrs);
let llfn = register_fn(ccx, struct_item.span,
- sym, ctor_id, ty, None);
+ sym, ctor_id, ty);
set_inline_hint(llfn);
llfn
}
let sym = exported_name(ccx, path, mty, m.attrs);
- let self_ty = match m.explicit_self.node {
- ast::SelfStatic => None,
- _ => Some(ty::node_id_to_type(ccx.tcx, m.self_id))
- };
- let llfn = register_fn(ccx, m.span, sym, id, mty, self_ty);
+ let llfn = register_fn(ccx, m.span, sym, id, mty);
set_llvm_fn_attrs(m.attrs, llfn);
llfn
}
pub fn call(&self, llfn: ValueRef, args: &[ValueRef],
attributes: &[(uint, lib::llvm::Attribute)]) -> ValueRef {
self.count_insn("call");
+
+ debug!("Call {} with args ({})",
+ self.ccx.tn.val_to_str(llfn),
+ args.map(|&v| self.ccx.tn.val_to_str(v)).connect(", "));
+
unsafe {
let v = llvm::LLVMBuildCall(self.llbuilder, llfn, args.as_ptr(),
args.len() as c_uint, noname());
use syntax::abi::AbiSet;
use syntax::ast_map;
-// Represents a (possibly monomorphized) top-level fn item or method
-// item. Note that this is just the fn-ptr and is not a Rust closure
-// value (which is a pair).
-pub struct FnData {
- llfn: ValueRef,
-}
-
pub struct MethodData {
llfn: ValueRef,
llself: ValueRef,
pub enum CalleeData {
Closure(Datum<Lvalue>),
- Fn(FnData),
- Method(MethodData)
+
+ // Represents a (possibly monomorphized) top-level fn item or method
+ // item. Note that this is just the fn-ptr and is not a Rust closure
+ // value (which is a pair).
+ Fn(/* llfn */ ValueRef),
+
+ TraitMethod(MethodData)
}
pub struct Callee<'a> {
match ty::get(datum.ty).sty {
ty::ty_bare_fn(..) => {
let llval = datum.to_llscalarish(bcx);
- return Callee {bcx: bcx, data: Fn(FnData {llfn: llval})};
+ return Callee {bcx: bcx, data: Fn(llval)};
}
ty::ty_closure(..) => {
let datum = unpack_datum!(
}
}
- fn fn_callee<'a>(bcx: &'a Block<'a>, fd: FnData) -> Callee<'a> {
- return Callee {bcx: bcx, data: Fn(fd)};
+ fn fn_callee<'a>(bcx: &'a Block<'a>, llfn: ValueRef) -> Callee<'a> {
+ return Callee {bcx: bcx, data: Fn(llfn)};
}
fn trans_def<'a>(bcx: &'a Block<'a>, def: ast::Def, ref_expr: &ast::Expr)
ast::DefArg(..) |
ast::DefLocal(..) |
ast::DefBinding(..) |
- ast::DefUpvar(..) |
- ast::DefSelf(..) => {
+ ast::DefUpvar(..) => {
datum_callee(bcx, ref_expr)
}
ast::DefMod(..) | ast::DefForeignMod(..) | ast::DefTrait(..) |
}
pub fn trans_fn_ref(bcx: &Block, def_id: ast::DefId, ref_id: ast::NodeId)
- -> FnData {
+ -> ValueRef {
/*!
*
* Translates a reference (with id `ref_id`) to the fn/method
ref_id: ast::NodeId, // node id of use of fn; may be zero if N/A
type_params: &[ty::t], // values for fn's ty params
vtables: Option<typeck::vtable_res>) // vtables for the call
- -> FnData {
+ -> ValueRef {
/*!
* Translates a reference to a fn/method item, monomorphizing and
* inlining as it goes.
let ref_ty = common::node_id_type(bcx, ref_id);
val = PointerCast(
- bcx, val, type_of::type_of_fn_from_ty(ccx, None, ref_ty).ptr_to());
+ bcx, val, type_of::type_of_fn_from_ty(ccx, ref_ty).ptr_to());
}
- return FnData {llfn: val};
+ return val;
}
// Find the actual function pointer.
// This can occur on either a crate-local or crate-external
// reference. It also occurs when testing libcore and in some
// other weird situations. Annoying.
- let llty = type_of::type_of_fn_from_ty(ccx, None, fn_tpt.ty);
+ let llty = type_of::type_of_fn_from_ty(ccx, fn_tpt.ty);
let llptrty = llty.ptr_to();
if val_ty(val) != llptrty {
val = BitCast(bcx, val, llptrty);
}
- return FnData {llfn: val};
+ val
}
// ______________________________________________________________________
node_id_type(in_cx, id),
|cx, _| trans(cx, f),
args,
- Some(dest),
- DontAutorefArg).bcx
+ Some(dest)).bcx
}
pub fn trans_method_call<'a>(
dest: expr::Dest)
-> &'a Block<'a> {
let _icx = push_ctxt("trans_method_call");
- debug!("trans_method_call(call_ex={}, rcvr={})",
- call_ex.repr(in_cx.tcx()),
- rcvr.repr(in_cx.tcx()));
+ debug!("trans_method_call(call_ex={})", call_ex.repr(in_cx.tcx()));
trans_call_inner(
in_cx,
Some(common::expr_info(call_ex)),
}
},
args,
- Some(dest),
- DontAutorefArg).bcx
+ Some(dest)).bcx
}
pub fn trans_lang_call<'a>(
None)
},
ArgVals(args),
- dest,
- DontAutorefArg)
+ dest)
}
pub fn trans_lang_call_with_type_params<'a>(
let new_llval;
match callee.data {
- Fn(fn_data) => {
+ Fn(llfn) => {
let substituted = ty::subst_tps(callee.bcx.tcx(),
type_params,
None,
fty);
let llfnty = type_of::type_of(callee.bcx.ccx(),
substituted);
- new_llval = PointerCast(callee.bcx, fn_data.llfn, llfnty);
+ new_llval = PointerCast(callee.bcx, llfn, llfnty);
}
_ => fail!()
}
- Callee { bcx: callee.bcx, data: Fn(FnData { llfn: new_llval }) }
+ Callee { bcx: callee.bcx, data: Fn(new_llval) }
},
- ArgVals(args), Some(dest), DontAutorefArg).bcx;
+ ArgVals(args), Some(dest)).bcx;
}
pub fn trans_call_inner<'a>(
arg_cleanup_scope: cleanup::ScopeId|
-> Callee<'a>,
args: CallArgs,
- dest: Option<expr::Dest>,
- autoref_arg: AutorefArg)
+ dest: Option<expr::Dest>)
-> Result<'a> {
/*!
* This behemoth of a function translates function calls.
let callee = get_callee(bcx, cleanup::CustomScope(arg_cleanup_scope));
let mut bcx = callee.bcx;
- let (llfn, llenv) = unsafe {
- match callee.data {
- Fn(d) => {
- (d.llfn, llvm::LLVMGetUndef(Type::opaque_box(ccx).ptr_to().to_ref()))
- }
- Method(d) => {
- // Weird but true: we pass self in the *environment* slot!
- (d.llfn, d.llself)
- }
- Closure(d) => {
- // Closures are represented as (llfn, llclosure) pair:
- // load the requisite values out.
- let pair = d.to_llref();
- let llfn = GEPi(bcx, pair, [0u, abi::fn_field_code]);
- let llfn = Load(bcx, llfn);
- let llenv = GEPi(bcx, pair, [0u, abi::fn_field_box]);
- let llenv = Load(bcx, llenv);
- (llfn, llenv)
- }
+ let (llfn, llenv, llself) = match callee.data {
+ Fn(llfn) => {
+ (llfn, None, None)
+ }
+ TraitMethod(d) => {
+ (d.llfn, None, Some(d.llself))
+ }
+ Closure(d) => {
+ // Closures are represented as (llfn, llclosure) pair:
+ // load the requisite values out.
+ let pair = d.to_llref();
+ let llfn = GEPi(bcx, pair, [0u, abi::fn_field_code]);
+ let llfn = Load(bcx, llfn);
+ let llenv = GEPi(bcx, pair, [0u, abi::fn_field_box]);
+ let llenv = Load(bcx, llenv);
+ (llfn, Some(llenv), None)
}
};
llargs.push(opt_llretslot.unwrap());
}
- // Push the environment.
- llargs.push(llenv);
+ // Push the environment (or a trait object's self).
+ match (llenv, llself) {
+ (Some(llenv), None) => llargs.push(llenv),
+ (None, Some(llself)) => llargs.push(llself),
+ _ => {}
+ }
// Push the arguments.
- bcx = trans_args(bcx, args, callee_ty,
- autoref_arg, &mut llargs,
- cleanup::CustomScope(arg_cleanup_scope));
+ bcx = trans_args(bcx, args, callee_ty, &mut llargs,
+ cleanup::CustomScope(arg_cleanup_scope),
+ llself.is_some());
fcx.pop_custom_cleanup_scope(arg_cleanup_scope);
match ty::get(ret_ty).sty {
// `~` pointer return values never alias because ownership
// is transferred
- ty::ty_uniq(..) |
- ty::ty_vec(_, ty::vstore_uniq) => {
+ ty::ty_uniq(..) | ty::ty_vec(_, ty::vstore_uniq) => {
attrs.push((0, NoAliasAttribute));
}
- _ => ()
+ _ => {}
}
// Invoke the actual rust fn and update bcx/llresult.
assert!(dest.is_some());
let mut llargs = ~[];
- bcx = trans_args(bcx, args, callee_ty,
- autoref_arg, &mut llargs,
- cleanup::CustomScope(arg_cleanup_scope));
+ bcx = trans_args(bcx, args, callee_ty, &mut llargs,
+ cleanup::CustomScope(arg_cleanup_scope), false);
fcx.pop_custom_cleanup_scope(arg_cleanup_scope);
let arg_tys = match args {
ArgExprs(a) => a.iter().map(|x| expr_ty(bcx, *x)).collect(),
- ArgVals(_) => fail!("expected arg exprs.")
+ _ => fail!("expected arg exprs.")
};
bcx = foreign::trans_native_call(bcx, callee_ty,
llfn, opt_llretslot.unwrap(), llargs, arg_tys);
pub enum CallArgs<'a> {
ArgExprs(&'a [@ast::Expr]),
+ // HACK used only by trans_overloaded_op.
+ ArgAutorefSecond(&'a ast::Expr, Option<&'a ast::Expr>),
ArgVals(&'a [ValueRef])
}
-pub fn trans_args<'a>(
- cx: &'a Block<'a>,
+fn trans_args<'a>(cx: &'a Block<'a>,
args: CallArgs,
fn_ty: ty::t,
- autoref_arg: AutorefArg,
llargs: &mut ~[ValueRef],
- arg_cleanup_scope: cleanup::ScopeId)
- -> &'a Block<'a>
-{
+ arg_cleanup_scope: cleanup::ScopeId,
+ ignore_self: bool)
+ -> &'a Block<'a> {
let _icx = push_ctxt("trans_args");
let arg_tys = ty::ty_fn_args(fn_ty);
let variadic = ty::fn_is_variadic(fn_ty);
// This will be needed if this is a generic call, because the callee has
// to cast her view of the arguments to the caller's view.
match args {
- ArgExprs(arg_exprs) => {
- let num_formal_args = arg_tys.len();
- for (i, arg_expr) in arg_exprs.iter().enumerate() {
- let arg_ty = if i >= num_formal_args {
- assert!(variadic);
- expr_ty_adjusted(cx, *arg_expr)
- } else {
- arg_tys[i]
- };
- let arg_val = unpack_result!(bcx, {
- trans_arg_expr(bcx,
- arg_ty,
- *arg_expr,
+ ArgExprs(arg_exprs) => {
+ let num_formal_args = arg_tys.len();
+ for (i, arg_expr) in arg_exprs.iter().enumerate() {
+ if i == 0 && ignore_self {
+ continue;
+ }
+ let arg_ty = if i >= num_formal_args {
+ assert!(variadic);
+ expr_ty_adjusted(cx, *arg_expr)
+ } else {
+ arg_tys[i]
+ };
+ llargs.push(unpack_result!(bcx, {
+ trans_arg_expr(bcx, arg_ty, *arg_expr,
+ arg_cleanup_scope,
+ DontAutorefArg)
+ }));
+ }
+ }
+ ArgAutorefSecond(arg_expr, arg2) => {
+ assert!(!variadic);
+
+ llargs.push(unpack_result!(bcx, {
+ trans_arg_expr(bcx, arg_tys[0], arg_expr,
arg_cleanup_scope,
- autoref_arg)
- });
- llargs.push(arg_val);
+ DontAutorefArg)
+ }));
+
+ match arg2 {
+ Some(arg2_expr) => {
+ assert_eq!(arg_tys.len(), 2);
+
+ llargs.push(unpack_result!(bcx, {
+ trans_arg_expr(bcx, arg_tys[1], arg2_expr,
+ arg_cleanup_scope,
+ DoAutorefArg)
+ }));
+ }
+ None => assert_eq!(arg_tys.len(), 1)
+ }
+ }
+ ArgVals(vs) => {
+ llargs.push_all(vs);
}
- }
- ArgVals(vs) => {
- llargs.push_all(vs);
- }
}
bcx
// The exception handling personality function.
let def_id = common::langcall(pad_bcx, None, "", EhPersonalityLangItem);
- let llpersonality = callee::trans_fn_ref(pad_bcx, def_id, 0).llfn;
+ let llpersonality = callee::trans_fn_ref(pad_bcx, def_id, 0);
// The only landing pad clause will be 'cleanup'
let llretval = build::LandingPad(pad_bcx, llretty, llpersonality, 1u);
use back::abi;
-use back::link::{mangle_internal_name_by_path_and_seq};
+use back::link::mangle_internal_name_by_path_and_seq;
use lib::llvm::ValueRef;
use middle::moves;
use middle::trans::base::*;
use middle::trans::build::*;
use middle::trans::common::*;
-use middle::trans::datum::{Datum, Lvalue};
+use middle::trans::datum::{Datum, DatumBlock, Expr, Lvalue, rvalue_scratch_datum};
use middle::trans::debuginfo;
use middle::trans::expr;
-use middle::trans::glue;
use middle::trans::type_of::*;
+use middle::trans::type_::Type;
use middle::ty;
+use util::ppaux::Repr;
use util::ppaux::ty_to_str;
use std::vec;
// closure".
//
// Typically an opaque closure suffices because we only manipulate it
-// by ptr. The routine Type::opaque_box().ptr_to() returns an
-// appropriate type for such an opaque closure; it allows access to
-// the box fields, but not the closure_data itself.
+// by ptr. The routine Type::at_box().ptr_to() returns an appropriate
+// type for such an opaque closure; it allows access to the box fields,
+// but not the closure_data itself.
//
// But sometimes, such as when cloning or freeing a closure, we need
// to know the full information. That is where the type descriptor
// Given a context and a list of upvars, build a closure. This just
// collects the upvars and packages them up for store_environment.
-pub fn build_closure<'a>(
- bcx0: &'a Block<'a>,
+fn build_closure<'a>(bcx0: &'a Block<'a>,
cap_vars: &[moves::CaptureVar],
sigil: ast::Sigil)
-> ClosureResult<'a> {
// Given an enclosing block context, a new function context, a closure type,
// and a list of upvars, generate code to load and populate the environment
// with the upvars and type descriptors.
-pub fn load_environment(fcx: &FunctionContext,
- cdata_ty: ty::t,
- cap_vars: &[moves::CaptureVar],
- sigil: ast::Sigil) {
+fn load_environment(fcx: &FunctionContext, cdata_ty: ty::t,
+ cap_vars: &[moves::CaptureVar], sigil: ast::Sigil) {
let _icx = push_ctxt("closure::load_environment");
// Don't bother to create the block if there's nothing to load
let bcx = fcx.entry_bcx.get().unwrap();
// Load a pointer to the closure data, skipping over the box header:
- let llcdata = opaque_box_body(bcx, cdata_ty, fcx.llenv.get());
+ let llcdata = at_box_body(bcx, cdata_ty, fcx.llenv.unwrap());
// Store the pointer to closure data in an alloca for debug info because that's what the
// llvm.dbg.declare intrinsic expects
}
}
+fn fill_fn_pair(bcx: &Block, pair: ValueRef, llfn: ValueRef, llenvptr: ValueRef) {
+ Store(bcx, llfn, GEPi(bcx, pair, [0u, abi::fn_field_code]));
+ let llenvptr = PointerCast(bcx, llenvptr, Type::i8p());
+ Store(bcx, llenvptr, GEPi(bcx, pair, [0u, abi::fn_field_box]));
+}
+
pub fn trans_expr_fn<'a>(
bcx: &'a Block<'a>,
sigil: ast::Sigil,
let s = mangle_internal_name_by_path_and_seq(ccx,
sub_path.clone(),
"expr_fn");
- let llfn = decl_internal_rust_fn(ccx, None, f.sig.inputs, f.sig.output, s);
+ let llfn = decl_internal_rust_fn(ccx, true, f.sig.inputs, f.sig.output, s);
// set an inline hint for all closures
set_inline_hint(llfn);
- let Result {bcx: bcx, val: closure} = match sigil {
- ast::BorrowedSigil | ast::ManagedSigil | ast::OwnedSigil => {
- let cap_vars = {
- let capture_map = ccx.maps.capture_map.borrow();
- capture_map.get().get_copy(&user_id)
- };
- let ClosureResult {llbox, cdata_ty, bcx}
- = build_closure(bcx, cap_vars, sigil);
- trans_closure(ccx,
- sub_path,
- decl,
- body,
- llfn,
- None,
- bcx.fcx.param_substs,
- user_id,
- [],
- ty::ty_fn_ret(fty),
- |fcx| load_environment(fcx, cdata_ty, cap_vars, sigil));
- rslt(bcx, llbox)
- }
+ let cap_vars = {
+ let capture_map = ccx.maps.capture_map.borrow();
+ capture_map.get().get_copy(&user_id)
};
- fill_fn_pair(bcx, dest_addr, llfn, closure);
-
- return bcx;
+ let ClosureResult {llbox, cdata_ty, bcx} = build_closure(bcx, cap_vars, sigil);
+ trans_closure(ccx, sub_path, decl, body, llfn,
+ bcx.fcx.param_substs, user_id,
+ [], ty::ty_fn_ret(fty),
+ |fcx| load_environment(fcx, cdata_ty, cap_vars, sigil));
+ fill_fn_pair(bcx, dest_addr, llfn, llbox);
+
+ bcx
}
-pub fn make_closure_glue<'a>(
- cx: &'a Block<'a>,
- v: ValueRef,
- t: ty::t,
- glue_fn: |&'a Block<'a>, v: ValueRef, t: ty::t|
- -> &'a Block<'a>)
- -> &'a Block<'a> {
- let _icx = push_ctxt("closure::make_closure_glue");
- let bcx = cx;
- let tcx = cx.tcx();
-
- let sigil = ty::ty_closure_sigil(t);
- match sigil {
- ast::BorrowedSigil => bcx,
- ast::OwnedSigil | ast::ManagedSigil => {
- let box_cell_v = GEPi(cx, v, [0u, abi::fn_field_box]);
- let box_ptr_v = Load(cx, box_cell_v);
- with_cond(cx, IsNotNull(cx, box_ptr_v), |bcx| {
- let closure_ty = ty::mk_opaque_closure_ptr(tcx, sigil);
- glue_fn(bcx, box_cell_v, closure_ty)
- })
+pub fn get_wrapper_for_bare_fn(ccx: @CrateContext,
+ closure_ty: ty::t,
+ def: ast::Def,
+ fn_ptr: ValueRef,
+ is_local: bool) -> ValueRef {
+
+ let def_id = match def {
+ ast::DefFn(did, _) | ast::DefStaticMethod(did, _, _) |
+ ast::DefVariant(_, did, _) | ast::DefStruct(did) => did,
+ _ => {
+ ccx.sess.bug(format!("get_wrapper_for_bare_fn: \
+ expected a statically resolved fn, got {:?}",
+ def));
}
- }
-}
+ };
-pub fn make_opaque_cbox_drop_glue<'a>(
- bcx: &'a Block<'a>,
- sigil: ast::Sigil,
- cboxptr: ValueRef) // opaque closure ptr
- -> &'a Block<'a> {
- let _icx = push_ctxt("closure::make_opaque_cbox_drop_glue");
- match sigil {
- ast::BorrowedSigil => bcx,
- ast::ManagedSigil => {
- bcx.tcx().sess.bug("trying to trans drop glue of @fn")
- }
- ast::OwnedSigil => {
- glue::make_free_glue(
- bcx, cboxptr,
- ty::mk_opaque_closure_ptr(bcx.tcx(), sigil))
+ {
+ let cache = ccx.closure_bare_wrapper_cache.borrow();
+ match cache.get().find(&fn_ptr) {
+ Some(&llval) => return llval,
+ None => {}
}
}
-}
-/// `cbox` is a pointer to a pointer to an opaque closure.
-pub fn make_opaque_cbox_free_glue<'a>(
- bcx: &'a Block<'a>,
- sigil: ast::Sigil,
- cbox: ValueRef)
- -> &'a Block<'a> {
- let _icx = push_ctxt("closure::make_opaque_cbox_free_glue");
- match sigil {
- ast::BorrowedSigil => {
- return bcx;
+ let tcx = ccx.tcx;
+
+ debug!("get_wrapper_for_bare_fn(closure_ty={})", closure_ty.repr(tcx));
+
+ let f = match ty::get(closure_ty).sty {
+ ty::ty_closure(ref f) => f,
+ _ => {
+ ccx.sess.bug(format!("get_wrapper_for_bare_fn: \
+ expected a closure ty, got {}",
+ closure_ty.repr(tcx)));
}
- ast::ManagedSigil | ast::OwnedSigil => {
- /* hard cases: fallthrough to code below */
+ };
+
+ let path = ty::item_path(tcx, def_id);
+ let name = mangle_internal_name_by_path_and_seq(ccx, path, "as_closure");
+ let llfn = if is_local {
+ decl_internal_rust_fn(ccx, true, f.sig.inputs, f.sig.output, name)
+ } else {
+ decl_rust_fn(ccx, true, f.sig.inputs, f.sig.output, name)
+ };
+
+ {
+ let mut cache = ccx.closure_bare_wrapper_cache.borrow_mut();
+ cache.get().insert(fn_ptr, llfn);
+ }
+
+ // This is only used by statics inlined from a different crate.
+ if !is_local {
+ // Don't regenerate the wrapper, just reuse the original one.
+ return llfn;
+ }
+
+ let _icx = push_ctxt("closure::get_wrapper_for_bare_fn");
+
+ let fcx = new_fn_ctxt(ccx, ~[], llfn, true, f.sig.output, None);
+ init_function(&fcx, true, f.sig.output, None);
+ let bcx = fcx.entry_bcx.get().unwrap();
+
+ let args = create_datums_for_fn_args(&fcx, ty::ty_fn_args(closure_ty));
+ let mut llargs = ~[];
+ match fcx.llretptr.get() {
+ Some(llretptr) => {
+ llargs.push(llretptr);
}
+ None => {}
}
+ llargs.extend(&mut args.iter().map(|arg| arg.val));
- let ccx = bcx.ccx();
- with_cond(bcx, IsNotNull(bcx, cbox), |bcx| {
- // Load the type descr found in the cbox
- let lltydescty = ccx.tydesc_type.ptr_to();
- let cbox = Load(bcx, cbox);
- let tydescptr = GEPi(bcx, cbox, [0u, abi::box_field_tydesc]);
- let tydesc = Load(bcx, tydescptr);
- let tydesc = PointerCast(bcx, tydesc, lltydescty);
-
- // Drop the tuple data then free the descriptor
- let cdata = GEPi(bcx, cbox, [0u, abi::box_field_body]);
- glue::call_tydesc_glue_full(bcx, cdata, tydesc,
- abi::tydesc_field_drop_glue, None);
-
- // Free the ty descr (if necc) and the box itself
- glue::trans_exchange_free(bcx, cbox);
-
- bcx
- })
+ let retval = Call(bcx, fn_ptr, llargs, []);
+ if type_is_zero_size(ccx, f.sig.output) || fcx.llretptr.get().is_some() {
+ RetVoid(bcx);
+ } else {
+ Ret(bcx, retval);
+ }
+
+ // HACK(eddyb) finish_fn cannot be used here, we returned directly.
+ debuginfo::clear_source_location(&fcx);
+ fcx.cleanup();
+
+ llfn
+}
+
+pub fn make_closure_from_bare_fn<'a>(bcx: &'a Block<'a>,
+ closure_ty: ty::t,
+ def: ast::Def,
+ fn_ptr: ValueRef)
+ -> DatumBlock<'a, Expr> {
+ let scratch = rvalue_scratch_datum(bcx, closure_ty, "__adjust");
+ let wrapper = get_wrapper_for_bare_fn(bcx.ccx(), closure_ty, def, fn_ptr, true);
+ fill_fn_pair(bcx, scratch.val, wrapper, C_null(Type::i8p()));
+
+ DatumBlock(bcx, scratch.to_expr_datum())
}
// section of the executable we're generating.
llfn: ValueRef,
- // The implicit environment argument that arrives in the function we're
- // creating.
- llenv: Cell<ValueRef>,
+ // The environment argument in a closure.
+ llenv: Option<ValueRef>,
// The place to store the return value. If the return type is immediate,
// this is an alloca in the function. Otherwise, it's the hidden first
alloca_insert_pt: Cell<Option<ValueRef>>,
llreturn: Cell<Option<BasicBlockRef>>,
- // The 'self' value currently in use in this function, if there
- // is one.
- //
- // NB: This is the type of the self *variable*, not the self *type*. The
- // self type is set only for default methods, while the self variable is
- // set for all methods.
- llself: Cell<Option<LvalueDatum>>,
-
// The a value alloca'd for calls to upcalls.rust_personality. Used when
// outputting the resume instruction.
personality: Cell<Option<ValueRef>>,
impl<'a> FunctionContext<'a> {
pub fn arg_pos(&self, arg: uint) -> uint {
- if self.caller_expects_out_pointer {
- arg + 2u
+ let arg = self.env_arg_pos() + arg;
+ if self.llenv.is_some() {
+ arg + 1
} else {
- arg + 1u
+ arg
}
}
use middle::trans::adt;
use middle::trans::base;
use middle::trans::base::push_ctxt;
+use middle::trans::closure;
use middle::trans::common::*;
use middle::trans::consts;
use middle::trans::expr;
}
}
-fn const_vec(cx: @CrateContext, e: &ast::Expr, es: &[@ast::Expr]) -> (ValueRef, Type, bool) {
+fn const_vec(cx: @CrateContext, e: &ast::Expr,
+ es: &[@ast::Expr], is_local: bool) -> (ValueRef, Type, bool) {
let vec_ty = ty::expr_ty(cx.tcx, e);
let unit_ty = ty::sequence_element_type(cx.tcx, vec_ty);
let llunitty = type_of::type_of(cx, unit_ty);
- let (vs, inlineable) = vec::unzip(es.iter().map(|e| const_expr(cx, *e)));
+ let (vs, inlineable) = vec::unzip(es.iter().map(|e| const_expr(cx, *e, is_local)));
// If the vector contains enums, an LLVM array won't work.
let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
C_struct(vs, false)
!non_inlineable_statics.get().contains(&def_id.node))
}
-pub fn const_expr(cx: @CrateContext, e: &ast::Expr) -> (ValueRef, bool) {
- let (llconst, inlineable) = const_expr_unadjusted(cx, e);
+pub fn const_expr(cx: @CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef, bool) {
+ let (llconst, inlineable) = const_expr_unadjusted(cx, e, is_local);
let mut llconst = llconst;
let mut inlineable = inlineable;
let ety = ty::expr_ty(cx.tcx, e);
+ let ety_adjusted = ty::expr_ty_adjusted(cx.tcx, e);
let adjustment = {
let adjustments = cx.tcx.adjustments.borrow();
adjustments.get().find_copy(&e.id)
Some(adj) => {
match *adj {
ty::AutoAddEnv(ty::ReStatic, ast::BorrowedSigil) => {
- llconst = C_struct([
- llconst,
- C_null(Type::opaque_box(cx).ptr_to())
- ], false)
+ let def = ty::resolve_expr(cx.tcx, e);
+ let wrapper = closure::get_wrapper_for_bare_fn(cx,
+ ety_adjusted,
+ def,
+ llconst,
+ is_local);
+ llconst = C_struct([wrapper, C_null(Type::i8p())], false)
}
ty::AutoAddEnv(ref r, ref s) => {
cx.sess
}
}
- let ety_adjusted = ty::expr_ty_adjusted(cx.tcx, e);
let llty = type_of::sizing_type_of(cx, ety_adjusted);
let csize = machine::llsize_of_alloc(cx, val_ty(llconst));
let tsize = machine::llsize_of_alloc(cx, llty);
// the bool returned is whether this expression can be inlined into other crates
// if it's assigned to a static.
-fn const_expr_unadjusted(cx: @CrateContext,
- e: &ast::Expr) -> (ValueRef, bool) {
- fn map_list(cx: @CrateContext,
- exprs: &[@ast::Expr]) -> (~[ValueRef], bool) {
- exprs.iter().map(|&e| const_expr(cx, e))
+fn const_expr_unadjusted(cx: @CrateContext, e: &ast::Expr,
+ is_local: bool) -> (ValueRef, bool) {
+ let map_list = |exprs: &[@ast::Expr]| {
+ exprs.iter().map(|&e| const_expr(cx, e, is_local))
.fold((~[], true), |(L, all_inlineable), (val, inlineable)| {
- (vec::append_one(L, val), all_inlineable && inlineable)
+ (vec::append_one(L, val), all_inlineable && inlineable)
})
- }
+ };
unsafe {
let _icx = push_ctxt("const_expr");
return match e.node {
ast::ExprLit(lit) => (consts::const_lit(cx, e, *lit), true),
ast::ExprBinary(_, b, e1, e2) => {
- let (te1, _) = const_expr(cx, e1);
- let (te2, _) = const_expr(cx, e2);
+ let (te1, _) = const_expr(cx, e1, is_local);
+ let (te2, _) = const_expr(cx, e2, is_local);
let te2 = base::cast_shift_const_rhs(b, te1, te2);
}, true)
},
ast::ExprUnary(_, u, e) => {
- let (te, _) = const_expr(cx, e);
+ let (te, _) = const_expr(cx, e, is_local);
let ty = ty::expr_ty(cx.tcx, e);
let is_float = ty::type_is_fp(ty);
return (match u {
ast::ExprField(base, field, _) => {
let bt = ty::expr_ty_adjusted(cx.tcx, base);
let brepr = adt::represent_type(cx, bt);
- let (bv, inlineable) = const_expr(cx, base);
+ let (bv, inlineable) = const_expr(cx, base, is_local);
expr::with_field_tys(cx.tcx, bt, None, |discr, field_tys| {
let ix = ty::field_idx_strict(cx.tcx, field.name, field_tys);
(adt::const_get_field(cx, brepr, bv, discr, ix), inlineable)
ast::ExprIndex(_, base, index) => {
let bt = ty::expr_ty_adjusted(cx.tcx, base);
- let (bv, inlineable) = const_expr(cx, base);
+ let (bv, inlineable) = const_expr(cx, base, is_local);
let iv = match const_eval::eval_const_expr(cx.tcx, index) {
const_eval::const_int(i) => i as u64,
const_eval::const_uint(u) => u,
let ety = ty::expr_ty(cx.tcx, e);
let llty = type_of::type_of(cx, ety);
let basety = ty::expr_ty(cx.tcx, base);
- let (v, inlineable) = const_expr(cx, base);
+ let (v, inlineable) = const_expr(cx, base, is_local);
return (match (expr::cast_type_kind(basety),
expr::cast_type_kind(ety)) {
}, inlineable)
}
ast::ExprAddrOf(ast::MutImmutable, sub) => {
- let (e, _) = const_expr(cx, sub);
+ let (e, _) = const_expr(cx, sub, is_local);
(const_addr_of(cx, e), false)
}
ast::ExprTup(ref es) => {
let ety = ty::expr_ty(cx.tcx, e);
let repr = adt::represent_type(cx, ety);
- let (vals, inlineable) = map_list(cx, *es);
+ let (vals, inlineable) = map_list(*es);
(adt::trans_const(cx, repr, 0, vals), inlineable)
}
ast::ExprStruct(_, ref fs, ref base_opt) => {
let tcx = cx.tcx;
let base_val = match *base_opt {
- Some(base) => Some(const_expr(cx, base)),
+ Some(base) => Some(const_expr(cx, base, is_local)),
None => None
};
let cs = field_tys.iter().enumerate()
.map(|(ix, &field_ty)| {
match fs.iter().find(|f| field_ty.ident.name == f.ident.node.name) {
- Some(f) => const_expr(cx, (*f).expr),
+ Some(f) => const_expr(cx, (*f).expr, is_local),
None => {
match base_val {
Some((bv, inlineable)) => {
})
}
ast::ExprVec(ref es, ast::MutImmutable) => {
- let (v, _, inlineable) = const_vec(cx, e, *es);
+ let (v, _, inlineable) = const_vec(cx, e, *es, is_local);
(v, inlineable)
}
ast::ExprVstore(sub, ast::ExprVstoreSlice) => {
match sub.node {
ast::ExprLit(ref lit) => {
match lit.node {
- ast::LitStr(..) => { const_expr(cx, sub) }
+ ast::LitStr(..) => { const_expr(cx, sub, is_local) }
_ => { cx.sess.span_bug(e.span, "bad const-slice lit") }
}
}
ast::ExprVec(ref es, ast::MutImmutable) => {
- let (cv, llunitty, _) = const_vec(cx, e, *es);
+ let (cv, llunitty, _) = const_vec(cx, e, *es, is_local);
let llty = val_ty(cv);
let gv = "const".with_c_str(|name| {
llvm::LLVMAddGlobal(cx.llmod, llty.to_ref(), name)
const_eval::const_uint(i) => i as uint,
_ => cx.sess.span_bug(count.span, "count must be integral const expression.")
};
- let vs = vec::from_elem(n, const_expr(cx, elem).first());
+ let vs = vec::from_elem(n, const_expr(cx, elem, is_local).first());
let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
C_struct(vs, false)
} else {
Some(ast::DefStruct(_)) => {
let ety = ty::expr_ty(cx.tcx, e);
let repr = adt::represent_type(cx, ety);
- let (arg_vals, inlineable) = map_list(cx, *args);
+ let (arg_vals, inlineable) = map_list(*args);
(adt::trans_const(cx, repr, 0, arg_vals), inlineable)
}
Some(ast::DefVariant(enum_did, variant_did, _)) => {
let vinfo = ty::enum_variant_with_id(cx.tcx,
enum_did,
variant_did);
- let (arg_vals, inlineable) = map_list(cx, *args);
+ let (arg_vals, inlineable) = map_list(*args);
(adt::trans_const(cx, repr, vinfo.disr_val, arg_vals),
inlineable)
}
_ => cx.sess.span_bug(e.span, "expected a struct or variant def")
}
}
- ast::ExprParen(e) => { const_expr(cx, e) }
+ ast::ExprParen(e) => { const_expr(cx, e, is_local) }
_ => cx.sess.span_bug(e.span,
"bad constant expression type in consts::const_expr")
};
impl_method_cache: RefCell<HashMap<(ast::DefId, ast::Name), ast::DefId>>,
+ // Cache of closure wrappers for bare fn's.
+ closure_bare_wrapper_cache: RefCell<HashMap<ValueRef, ValueRef>>,
+
module_data: RefCell<HashMap<~str, ValueRef>>,
lltypes: RefCell<HashMap<ty::t, Type>>,
llsizingtypes: RefCell<HashMap<ty::t, Type>>,
const_values: RefCell::new(HashMap::new()),
extern_const_values: RefCell::new(HashMap::new()),
impl_method_cache: RefCell::new(HashMap::new()),
+ closure_bare_wrapper_cache: RefCell::new(HashMap::new()),
module_data: RefCell::new(HashMap::new()),
lltypes: RefCell::new(HashMap::new()),
llsizingtypes: RefCell::new(HashMap::new()),
Some(x) => {
bcx = expr::trans_into(bcx, x, dest);
}
- _ => ()
+ _ => {}
}
let cleanup_llbb = fcx.return_exit_block();
Br(bcx, cleanup_llbb);
use lib::llvm::{ModuleRef, ContextRef, ValueRef};
use lib::llvm::debuginfo::*;
use middle::trans::adt;
-use middle::trans::base;
-use middle::trans::build;
use middle::trans::common::*;
use middle::trans::datum::{Datum, Lvalue};
use middle::trans::machine;
None => {
cx.sess.span_bug(span, "debuginfo::create_captured_var_metadata() - NodeId not found");
}
- Some(ast_map::NodeLocal(ident, _)) => ident,
- Some(ast_map::NodeArg(pat)) => {
+ Some(ast_map::NodeLocal(pat)) | Some(ast_map::NodeArg(pat)) => {
match pat.node {
ast::PatIdent(_, ref path, _) => {
ast_util::path_to_ident(path)
span);
}
-/// Creates debug information for the self argument of a method.
-///
-/// Adds the created metadata nodes directly to the crate's IR.
-pub fn create_self_argument_metadata(bcx: &Block,
- type_of_self: ty::t,
- llptr: ValueRef) {
- if fn_should_be_ignored(bcx.fcx) {
- return;
- }
-
- // Extract the span of the self argument from the method's AST
- let fnitem = bcx.ccx().tcx.items.get(bcx.fcx.id);
- let span = match fnitem {
- ast_map::NodeMethod(method, _, _) => {
- method.explicit_self.span
- }
- ast_map::NodeTraitMethod(trait_method, _, _) => {
- match *trait_method {
- ast::Provided(method) => method.explicit_self.span,
- _ => {
- bcx.ccx()
- .sess
- .bug(format!("create_self_argument_metadata: \
- unexpected sort of node: {:?}",
- fnitem))
- }
- }
- }
- _ => bcx.ccx().sess.bug(
- format!("create_self_argument_metadata: unexpected sort of node: {:?}", fnitem))
- };
-
- let scope_metadata = bcx.fcx.debug_context.get_ref(bcx.ccx(), span).fn_metadata;
-
- let argument_index = {
- let counter = &bcx.fcx.debug_context.get_ref(bcx.ccx(), span).argument_counter;
- let argument_index = counter.get();
- counter.set(argument_index + 1);
- argument_index
- };
-
- let address_operations = &[unsafe { llvm::LLVMDIBuilderCreateOpDeref(Type::i64().to_ref()) }];
-
- // The self argument comes in one of two forms:
- // (1) For `&self`, `~self`, and `@self` it is an alloca containing a pointer to the data. That
- // is the `{&~@}self` pointer is contained by value in the alloca, and `type_of_self` will
- // be `{&~@}Self`
- // (2) For by-value `self`, `llptr` will not be an alloca, but a pointer to the self-value. That
- // is by-value `self` is always implicitly passed by reference (sic!). So we have a couple
- // of problems here:
- // (a) There is no alloca to give to `llvm.dbg.declare` and
- // (b) `type_of_self` is `Self`, but `llptr` is of type `*Self`
- // In order to solve this problem, the else branch below creates a helper alloca which
- // contains a copy of `llptr`. We then describe the `self` parameter by pointing
- // `llvm.dbg.declare` to this helper alloca and tell it that the pointer there needs to be
- // dereferenced once to get to the actual data (similar to non-immediate by-value args).
- let variable_access = if unsafe { llvm::LLVMIsAAllocaInst(llptr) } != ptr::null() {
- DirectVariable { alloca: llptr }
- } else {
- // Create a helper alloca that allows us to track the self-argument properly. The alloca
- // contains a pointer to the self-value.
- let ptr_type = ty::mk_mut_ptr(bcx.tcx(), type_of_self);
- let helper_alloca = base::alloc_ty(bcx, ptr_type, "__self");
- build::Store(bcx, llptr, helper_alloca);
-
- IndirectVariable { alloca: helper_alloca, address_operations: address_operations }
- };
-
- declare_local(bcx,
- special_idents::self_,
- type_of_self,
- scope_metadata,
- variable_access,
- ArgumentVariable(argument_index),
- span);
-}
-
/// Creates debug information for the given function argument.
///
/// Adds the created metadata nodes directly to the crate's IR.
None => ~"BoxedType"
};
- let box_llvm_type = Type::smart_ptr(cx, &content_llvm_type);
+ let box_llvm_type = Type::at_box(cx, content_llvm_type);
let member_llvm_types = box_llvm_type.field_types();
assert!(box_layout_is_correct(cx, member_llvm_types, content_llvm_type));
match exp.node {
ast::ExprLogLevel |
- ast::ExprSelf |
ast::ExprLit(_) |
ast::ExprBreak(_) |
ast::ExprAgain(_) |
- ast::ExprPath(_) => (),
+ ast::ExprPath(_) => {}
ast::ExprVstore(sub_exp, _) |
ast::ExprCast(sub_exp, _) |
})
}
- // ast::expr_loop_body(inner_exp) |
- ast::ExprDoBody(inner_exp) => {
+ ast::ExprDoBody(inner_exp) => {
let inner_expr_is_expr_fn_block = match *inner_exp {
ast::Expr { node: ast::ExprFnBlock(..), .. } => true,
_ => false
}
}
- ast::ExprMethodCall(node_id, receiver_exp, _, _, ref args, _) => {
+ ast::ExprMethodCall(node_id, _, _, ref args, _) => {
scope_map.insert(node_id, scope_stack.last().unwrap().scope_metadata);
- walk_expr(cx, receiver_exp, scope_stack, scope_map);
for arg_exp in args.iter() {
walk_expr(cx, *arg_exp, scope_stack, scope_map);
use middle::trans::base::*;
use middle::trans::base;
use middle::trans::build::*;
-use middle::trans::callee::DoAutorefArg;
use middle::trans::callee;
use middle::trans::cleanup;
use middle::trans::cleanup::CleanupMethods;
// code and keep it DRY that accommodates that use case at the
// moment.
- let tcx = bcx.tcx();
let closure_ty = expr_ty_adjusted(bcx, expr);
- debug!("add_env(closure_ty={})", closure_ty.repr(tcx));
- let scratch = rvalue_scratch_datum(bcx, closure_ty, "__adjust");
- let llfn = GEPi(bcx, scratch.val, [0u, abi::fn_field_code]);
- let llval = datum.to_llscalarish(bcx);
- Store(bcx, llval, llfn);
- let llenv = GEPi(bcx, scratch.val, [0u, abi::fn_field_box]);
- Store(bcx, base::null_env_ptr(bcx.ccx()), llenv);
- DatumBlock(bcx, scratch.to_expr_datum())
+ let fn_ptr = datum.to_llscalarish(bcx);
+ let def = ty::resolve_expr(bcx.tcx(), expr);
+ closure::make_closure_from_bare_fn(bcx, closure_ty, def, fn_ptr)
}
fn auto_slice_and_ref<'a>(
ast::ExprParen(e) => {
trans(bcx, e)
}
- ast::ExprPath(_) | ast::ExprSelf => {
+ ast::ExprPath(_) => {
trans_def(bcx, expr, bcx.def(expr.id))
}
ast::ExprField(base, ident, _) => {
let _icx = push_ctxt("trans_def_lvalue");
match def {
- ast::DefFn(..) | ast::DefStaticMethod(..) => {
+ ast::DefFn(..) | ast::DefStaticMethod(..) |
+ ast::DefStruct(_) | ast::DefVariant(..) => {
trans_def_fn_unadjusted(bcx, ref_expr, def)
}
ast::DefStatic(did, _) => {
match expr.node {
ast::ExprParen(e) => {
- return trans_into(bcx, e, dest);
+ trans_into(bcx, e, dest)
}
- ast::ExprPath(_) | ast::ExprSelf => {
- return trans_def_dps_unadjusted(bcx, expr,
- bcx.def(expr.id), dest);
+ ast::ExprPath(_) => {
+ trans_def_dps_unadjusted(bcx, expr, bcx.def(expr.id), dest)
}
ast::ExprIf(cond, thn, els) => {
- return controlflow::trans_if(bcx, expr.id, cond, thn, els, dest);
+ controlflow::trans_if(bcx, expr.id, cond, thn, els, dest)
}
ast::ExprMatch(discr, ref arms) => {
- return _match::trans_match(bcx, expr, discr, *arms, dest);
+ _match::trans_match(bcx, expr, discr, *arms, dest)
}
ast::ExprBlock(blk) => {
controlflow::trans_block(bcx, blk, dest)
}
ast::ExprStruct(_, ref fields, base) => {
- return trans_rec_or_struct(bcx, (*fields), base, expr.span, expr.id, dest);
+ trans_rec_or_struct(bcx, (*fields), base, expr.span, expr.id, dest)
}
ast::ExprTup(ref args) => {
let repr = adt::represent_type(bcx.ccx(), expr_ty(bcx, expr));
let numbered_fields: ~[(uint, @ast::Expr)] =
args.iter().enumerate().map(|(i, arg)| (i, *arg)).collect();
- return trans_adt(bcx, repr, 0, numbered_fields, None, dest);
+ trans_adt(bcx, repr, 0, numbered_fields, None, dest)
}
ast::ExprLit(lit) => {
match lit.node {
ast::LitStr(s, _) => {
- return tvec::trans_lit_str(bcx, expr, s, dest);
+ tvec::trans_lit_str(bcx, expr, s, dest)
}
_ => {
bcx.tcx()
ast::ExprVstore(contents, ast::ExprVstoreMutSlice) => {
fcx.push_ast_cleanup_scope(contents.id);
bcx = tvec::trans_slice_vstore(bcx, expr, contents, dest);
- return fcx.pop_and_trans_ast_cleanup_scope(bcx, contents.id);
+ fcx.pop_and_trans_ast_cleanup_scope(bcx, contents.id)
}
ast::ExprVec(..) | ast::ExprRepeat(..) => {
- return tvec::trans_fixed_vstore(bcx, expr, expr, dest);
+ tvec::trans_fixed_vstore(bcx, expr, expr, dest)
}
ast::ExprFnBlock(decl, body) |
ast::ExprProc(decl, body) => {
debug!("translating block function {} with type {}",
expr_to_str(expr, tcx.sess.intr()),
expr_ty.repr(tcx));
- return closure::trans_expr_fn(bcx, sigil, decl, body,
- expr.id, expr.id, dest);
+ closure::trans_expr_fn(bcx, sigil, decl, body,
+ expr.id, expr.id, dest)
}
ast::ExprDoBody(blk) => {
- return trans_into(bcx, blk, dest);
+ trans_into(bcx, blk, dest)
}
ast::ExprCall(f, ref args, _) => {
- return callee::trans_call(
- bcx, expr, f, callee::ArgExprs(*args), expr.id, dest);
+ callee::trans_call(bcx, expr, f,
+ callee::ArgExprs(*args), expr.id, dest)
}
- ast::ExprMethodCall(callee_id, rcvr, _, _, ref args, _) => {
- return callee::trans_method_call(bcx,
- expr,
- callee_id,
- rcvr,
- callee::ArgExprs(*args),
- dest);
+ ast::ExprMethodCall(callee_id, _, _, ref args, _) => {
+ callee::trans_method_call(bcx, expr, callee_id, args[0],
+ callee::ArgExprs(*args), dest)
}
ast::ExprBinary(callee_id, _, lhs, rhs) => {
// if not overloaded, would be RvalueDatumExpr
- return trans_overloaded_op(bcx,
- expr,
- callee_id,
- lhs,
- ~[rhs],
- expr_ty(bcx, expr),
- dest);
+ trans_overloaded_op(bcx, expr, callee_id, lhs,
+ Some(&*rhs), expr_ty(bcx, expr), dest)
}
ast::ExprUnary(callee_id, _, subexpr) => {
// if not overloaded, would be RvalueDatumExpr
- return trans_overloaded_op(bcx,
- expr,
- callee_id,
- subexpr,
- ~[],
- expr_ty(bcx, expr),
- dest);
+ trans_overloaded_op(bcx, expr, callee_id, subexpr,
+ None, expr_ty(bcx, expr), dest)
}
ast::ExprIndex(callee_id, base, idx) => {
// if not overloaded, would be RvalueDatumExpr
- return trans_overloaded_op(bcx,
- expr,
- callee_id,
- base,
- ~[idx],
- expr_ty(bcx, expr),
- dest);
+ trans_overloaded_op(bcx, expr, callee_id, base,
+ Some(&*idx), expr_ty(bcx, expr), dest)
}
ast::ExprCast(val, _) => {
// DPS output mode means this is a trait cast:
match ty::get(node_id_type(bcx, expr.id)).sty {
ty::ty_trait(..) => {
let datum = unpack_datum!(bcx, trans(bcx, val));
- return meth::trans_trait_cast(bcx, datum, expr.id, dest);
+ meth::trans_trait_cast(bcx, datum, expr.id, dest)
}
_ => {
bcx.tcx().sess.span_bug(expr.span,
}
}
ast::ExprAssignOp(callee_id, op, dst, src) => {
- return trans_assign_op(bcx, expr, callee_id, op, dst, src);
+ trans_assign_op(bcx, expr, callee_id, op, dst, src)
}
ast::ExprBox(_, contents) => {
// Special case for `Gc<T>` for now. The other case, for unique
// pointers, is handled in `trans_rvalue_datum_unadjusted`.
- return trans_gc(bcx, expr, contents, dest)
+ trans_gc(bcx, expr, contents, dest)
}
_ => {
bcx.tcx().sess.span_bug(
let variant_info = ty::enum_variant_with_id(ccx.tcx, tid, vid);
if variant_info.args.len() > 0u {
// N-ary variant.
- let fn_data = callee::trans_fn_ref(bcx, vid, ref_expr.id);
- Store(bcx, fn_data.llfn, lldest);
+ let llfn = callee::trans_fn_ref(bcx, vid, ref_expr.id);
+ Store(bcx, llfn, lldest);
return bcx;
} else {
// Nullary variant.
return bcx;
}
}
- ast::DefStruct(def_id) => {
+ ast::DefStruct(_) => {
let ty = expr_ty(bcx, ref_expr);
match ty::get(ty).sty {
ty::ty_struct(did, _) if ty::has_dtor(ccx.tcx, did) => {
let repr = adt::represent_type(ccx, ty);
adt::trans_start_init(bcx, repr, lldest, 0);
}
- ty::ty_bare_fn(..) => {
- let fn_data = callee::trans_fn_ref(bcx, def_id, ref_expr.id);
- Store(bcx, fn_data.llfn, lldest);
- }
- _ => ()
+ _ => {}
}
- return bcx;
+ bcx
}
_ => {
bcx.tcx().sess.span_bug(ref_expr.span, format!(
{
let _icx = push_ctxt("trans_def_datum_unadjusted");
- let fn_data = match def {
+ let llfn = match def {
ast::DefFn(did, _) |
+ ast::DefStruct(did) | ast::DefVariant(_, did, _) |
ast::DefStaticMethod(did, ast::FromImpl(_), _) => {
callee::trans_fn_ref(bcx, did, ref_expr.id)
}
ast::DefStaticMethod(impl_did, ast::FromTrait(trait_did), _) => {
- meth::trans_static_method_callee(bcx,
- impl_did,
- trait_did,
- ref_expr.id)
+ meth::trans_static_method_callee(bcx, impl_did,
+ trait_did, ref_expr.id)
}
_ => {
bcx.tcx().sess.span_bug(ref_expr.span, format!(
};
let fn_ty = expr_ty(bcx, ref_expr);
- DatumBlock(bcx, Datum(fn_data.llfn, fn_ty, RvalueExpr(Rvalue(ByValue))))
+ DatumBlock(bcx, Datum(llfn, fn_ty, RvalueExpr(Rvalue(ByValue))))
}
pub fn trans_local_var<'a>(bcx: &'a Block<'a>,
let lllocals = bcx.fcx.lllocals.borrow();
take_local(bcx, lllocals.get(), nid)
}
- ast::DefSelf(nid, _) => {
- let self_info = match bcx.fcx.llself.get() {
- Some(self_info) => self_info,
- None => {
- bcx.sess().bug(format!(
- "trans_local_var: reference to self \
- out of context with id {:?}", nid));
- }
- };
-
- debug!("def_self() reference, self_info.ty={}",
- self_info.ty.repr(bcx.tcx()));
-
- self_info
- }
_ => {
bcx.sess().unimpl(format!(
"unsupported def type in trans_local_var: {:?}", def));
}
}
-fn trans_overloaded_op<'a>(
+fn trans_overloaded_op<'a, 'b>(
bcx: &'a Block<'a>,
expr: &ast::Expr,
callee_id: ast::NodeId,
- rcvr: &ast::Expr,
- args: ~[@ast::Expr],
+ rcvr: &'b ast::Expr,
+ arg: Option<&'b ast::Expr>,
ret_ty: ty::t,
dest: Dest)
-> &'a Block<'a> {
origin,
arg_cleanup_scope)
},
- callee::ArgExprs(args),
- Some(dest),
- DoAutorefArg).bcx
+ callee::ArgAutorefSecond(rcvr, arg),
+ Some(dest)).bcx
}
fn int_cast(bcx: &Block,
id,
t.repr(tcx));
- let llfndecl = base::decl_internal_rust_fn(ccx, None, f.sig.inputs, f.sig.output, ps);
- base::set_llvm_fn_attrs(attrs, llfndecl);
- base::trans_fn(ccx,
- (*path).clone(),
- decl,
- body,
- llfndecl,
- None,
- None,
- id,
- []);
- return llfndecl;
+ let llfn = base::decl_internal_rust_fn(ccx, false, f.sig.inputs, f.sig.output, ps);
+ base::set_llvm_fn_attrs(attrs, llfn);
+ base::trans_fn(ccx, (*path).clone(), decl, body, llfn, None, id, []);
+ llfn
}
unsafe fn build_wrap_fn(ccx: @CrateContext,
return_alloca = None;
};
- // Push an (null) env pointer
- let env_pointer = base::null_env_ptr(ccx);
- debug!("env pointer={}", ccx.tn.val_to_str(env_pointer));
- llrust_args.push(env_pointer);
-
// Build up the arguments to the call to the rust function.
// Careful to adapt for cases where the native convention uses
// a pointer and Rust does not or vice versa.
use middle::trans::callee;
use middle::trans::cleanup;
use middle::trans::cleanup::CleanupMethods;
-use middle::trans::closure;
use middle::trans::common::*;
use middle::trans::build::*;
use middle::trans::expr;
}
// See [Note-arg-mode]
-pub fn call_tydesc_glue_full(bcx: &Block,
- v: ValueRef,
- tydesc: ValueRef,
- field: uint,
- static_ti: Option<@tydesc_info>) {
+pub fn call_tydesc_glue_full(bcx: &Block, v: ValueRef, tydesc: ValueRef,
+ field: uint, static_ti: Option<@tydesc_info>) {
let _icx = push_ctxt("call_tydesc_glue_full");
let ccx = bcx.ccx();
// NB: Don't short-circuit even if this block is unreachable because
if bcx.unreachable.get() && !ccx.sess.no_landing_pads() { return; }
let static_glue_fn = match static_ti {
- None => None,
- Some(sti) => {
- lazily_emit_tydesc_glue(ccx, field, sti);
- if field == abi::tydesc_field_take_glue {
- sti.take_glue.get()
- } else if field == abi::tydesc_field_drop_glue {
- sti.drop_glue.get()
- } else if field == abi::tydesc_field_visit_glue {
- sti.visit_glue.get()
- } else {
- None
+ None => None,
+ Some(sti) => {
+ lazily_emit_tydesc_glue(ccx, field, sti);
+ if field == abi::tydesc_field_take_glue {
+ sti.take_glue.get()
+ } else if field == abi::tydesc_field_drop_glue {
+ sti.drop_glue.get()
+ } else if field == abi::tydesc_field_visit_glue {
+ sti.visit_glue.get()
+ } else {
+ None
+ }
}
- }
};
// When static type info is available, avoid casting parameter unless the
// glue is using a simplified type, because the function already has the
// right type. Otherwise cast to generic pointer.
- let llrawptr = if static_ti.is_none() || static_glue_fn.is_none() {
+ let llrawptr = if static_glue_fn.is_none() {
PointerCast(bcx, v, Type::i8p())
} else {
let ty = static_ti.unwrap().ty;
let llfn = {
match static_glue_fn {
- None => {
- // Select out the glue function to call from the tydesc
- let llfnptr = GEPi(bcx, tydesc, [0u, field]);
- Load(bcx, llfnptr)
- }
- Some(sgf) => sgf
+ None => {
+ // Select out the glue function to call from the tydesc
+ let llfnptr = GEPi(bcx, tydesc, [0u, field]);
+ Load(bcx, llfnptr)
+ }
+ Some(sgf) => sgf
}
};
- Call(bcx, llfn, [C_null(Type::nil().ptr_to()), llrawptr], []);
+ Call(bcx, llfn, [llrawptr], []);
}
// See [Note-arg-mode]
bcx
}
-pub fn make_free_glue<'a>(bcx: &'a Block<'a>,
- v: ValueRef,
- t: ty::t)
- -> &'a Block<'a> {
- // NB: v0 is an *alias* of type t here, not a direct value.
- let _icx = push_ctxt("make_free_glue");
- match ty::get(t).sty {
- ty::ty_box(body_ty) => {
- let v = Load(bcx, v);
- let body = GEPi(bcx, v, [0u, abi::box_field_body]);
- let bcx = drop_ty(bcx, body, body_ty);
- trans_free(bcx, v)
- }
- ty::ty_uniq(content_ty) => {
- let llbox = Load(bcx, v);
- let not_null = IsNotNull(bcx, llbox);
- with_cond(bcx, not_null, |bcx| {
- let bcx = drop_ty(bcx, llbox, content_ty);
- trans_exchange_free(bcx, llbox)
- })
- }
- ty::ty_vec(_, ty::vstore_uniq) | ty::ty_str(ty::vstore_uniq) |
- ty::ty_vec(_, ty::vstore_box) | ty::ty_str(ty::vstore_box) => {
- make_free_glue(bcx, v, tvec::expand_boxed_vec_ty(bcx.tcx(), t))
- }
- ty::ty_closure(_) => {
- closure::make_closure_glue(bcx, v, t, make_free_glue)
- }
- ty::ty_opaque_closure_ptr(ck) => {
- closure::make_opaque_cbox_free_glue(bcx, ck, v)
- }
- _ => bcx
- }
-}
-
-pub fn trans_struct_drop_flag<'a>(
- bcx: &'a Block<'a>,
+fn trans_struct_drop_flag<'a>(bcx: &'a Block<'a>,
t: ty::t,
v0: ValueRef,
dtor_did: ast::DefId,
})
}
-pub fn trans_struct_drop<'a>(
- bcx: &'a Block<'a>,
+fn trans_struct_drop<'a>(bcx: &'a Block<'a>,
t: ty::t,
v0: ValueRef,
dtor_did: ast::DefId,
bcx.fcx.pop_and_trans_custom_cleanup_scope(bcx, field_scope)
}
-pub fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t)
- -> &'a Block<'a> {
+fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<'a> {
// NB: v0 is an *alias* of type t here, not a direct value.
let _icx = push_ctxt("make_drop_glue");
let ccx = bcx.ccx();
match ty::get(t).sty {
- ty::ty_box(_) |
- ty::ty_str(ty::vstore_box) | ty::ty_vec(_, ty::vstore_box) => {
- decr_refcnt_maybe_free(bcx, v0, Some(t))
- }
- ty::ty_uniq(_) |
- ty::ty_vec(_, ty::vstore_uniq) | ty::ty_str(ty::vstore_uniq) => {
- make_free_glue(bcx, v0, t)
- }
- ty::ty_unboxed_vec(_) => {
- tvec::make_drop_glue_unboxed(bcx, v0, t)
- }
- ty::ty_struct(did, ref substs) => {
- let tcx = bcx.tcx();
- match ty::ty_dtor(tcx, did) {
- ty::TraitDtor(dtor, true) => {
- trans_struct_drop_flag(bcx, t, v0, dtor, did, substs)
- }
- ty::TraitDtor(dtor, false) => {
- trans_struct_drop(bcx, t, v0, dtor, did, substs)
- }
- ty::NoDtor => {
- // No dtor? Just the default case
- iter_structural_ty(bcx, v0, t, drop_ty)
- }
+ ty::ty_box(body_ty) => {
+ decr_refcnt_maybe_free(bcx, v0, Some(body_ty))
+ }
+ ty::ty_str(ty::vstore_box) | ty::ty_vec(_, ty::vstore_box) => {
+ let unit_ty = ty::sequence_element_type(ccx.tcx, t);
+ let unboxed_vec_ty = ty::mk_mut_unboxed_vec(ccx.tcx, unit_ty);
+ decr_refcnt_maybe_free(bcx, v0, Some(unboxed_vec_ty))
+ }
+ ty::ty_uniq(content_ty) => {
+ let llbox = Load(bcx, v0);
+ let not_null = IsNotNull(bcx, llbox);
+ with_cond(bcx, not_null, |bcx| {
+ let bcx = drop_ty(bcx, llbox, content_ty);
+ trans_exchange_free(bcx, llbox)
+ })
+ }
+ ty::ty_vec(_, ty::vstore_uniq) | ty::ty_str(ty::vstore_uniq) => {
+ make_drop_glue(bcx, v0, tvec::expand_boxed_vec_ty(bcx.tcx(), t))
+ }
+ ty::ty_unboxed_vec(_) => {
+ tvec::make_drop_glue_unboxed(bcx, v0, t)
+ }
+ ty::ty_struct(did, ref substs) => {
+ let tcx = bcx.tcx();
+ match ty::ty_dtor(tcx, did) {
+ ty::TraitDtor(dtor, true) => {
+ trans_struct_drop_flag(bcx, t, v0, dtor, did, substs)
+ }
+ ty::TraitDtor(dtor, false) => {
+ trans_struct_drop(bcx, t, v0, dtor, did, substs)
+ }
+ ty::NoDtor => {
+ // No dtor? Just the default case
+ iter_structural_ty(bcx, v0, t, drop_ty)
+ }
+ }
+ }
+ ty::ty_trait(_, _, ty::BoxTraitStore, _, _) => {
+ let llbox_ptr = GEPi(bcx, v0, [0u, abi::trt_field_box]);
+ decr_refcnt_maybe_free(bcx, llbox_ptr, None)
+ }
+ ty::ty_trait(_, _, ty::UniqTraitStore, _, _) => {
+ let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]);
+ // Only drop the value when it is non-null
+ with_cond(bcx, IsNotNull(bcx, Load(bcx, lluniquevalue)), |bcx| {
+ let llvtable = Load(bcx, GEPi(bcx, v0, [0, abi::trt_field_vtable]));
+
+ // Cast the vtable to a pointer to a pointer to a tydesc.
+ let llvtable = PointerCast(bcx, llvtable,
+ ccx.tydesc_type.ptr_to().ptr_to());
+ let lltydesc = Load(bcx, llvtable);
+ call_tydesc_glue_full(bcx,
+ lluniquevalue,
+ lltydesc,
+ abi::tydesc_field_drop_glue,
+ None);
+ bcx
+ })
+ }
+ ty::ty_closure(ref f) if f.sigil == ast::OwnedSigil => {
+ let box_cell_v = GEPi(bcx, v0, [0u, abi::fn_field_box]);
+ let env = Load(bcx, box_cell_v);
+ let env_ptr_ty = Type::at_box(ccx, Type::i8()).ptr_to();
+ let env = PointerCast(bcx, env, env_ptr_ty);
+ with_cond(bcx, IsNotNull(bcx, env), |bcx| {
+ // Load the type descr found in the env
+ let lltydescty = ccx.tydesc_type.ptr_to();
+ let tydescptr = GEPi(bcx, env, [0u, abi::box_field_tydesc]);
+ let tydesc = Load(bcx, tydescptr);
+ let tydesc = PointerCast(bcx, tydesc, lltydescty);
+
+ // Drop the tuple data then free the descriptor
+ let cdata = GEPi(bcx, env, [0u, abi::box_field_body]);
+ call_tydesc_glue_full(bcx, cdata, tydesc,
+ abi::tydesc_field_drop_glue, None);
+
+ // Free the ty descr (if necc) and the env itself
+ trans_exchange_free(bcx, env)
+ })
+ }
+ _ => {
+ if ty::type_needs_drop(ccx.tcx, t) &&
+ ty::type_is_structural(t) {
+ iter_structural_ty(bcx, v0, t, drop_ty)
+ } else {
+ bcx
+ }
}
- }
- ty::ty_closure(_) => {
- closure::make_closure_glue(bcx, v0, t, drop_ty)
- }
- ty::ty_trait(_, _, ty::BoxTraitStore, _, _) => {
- let llbox_ptr = GEPi(bcx, v0, [0u, abi::trt_field_box]);
- decr_refcnt_maybe_free(bcx, llbox_ptr, None)
- }
- ty::ty_trait(_, _, ty::UniqTraitStore, _, _) => {
- let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]);
- // Only drop the value when it is non-null
- with_cond(bcx, IsNotNull(bcx, Load(bcx, lluniquevalue)), |bcx| {
- let llvtable = Load(bcx, GEPi(bcx, v0, [0, abi::trt_field_vtable]));
-
- // Cast the vtable to a pointer to a pointer to a tydesc.
- let llvtable = PointerCast(bcx, llvtable,
- ccx.tydesc_type.ptr_to().ptr_to());
- let lltydesc = Load(bcx, llvtable);
- call_tydesc_glue_full(bcx,
- lluniquevalue,
- lltydesc,
- abi::tydesc_field_drop_glue,
- None);
- bcx
- })
- }
- ty::ty_opaque_closure_ptr(ck) => {
- closure::make_opaque_cbox_drop_glue(bcx, ck, v0)
- }
- _ => {
- if ty::type_needs_drop(ccx.tcx, t) &&
- ty::type_is_structural(t) {
- iter_structural_ty(bcx, v0, t, drop_ty)
- } else { bcx }
- }
}
}
Store(decr_bcx, rc, rc_ptr);
CondBr(decr_bcx, IsNull(decr_bcx, rc), free_bcx.llbb, next_bcx.llbb);
+ let v = Load(free_bcx, box_ptr_ptr);
+ let body = GEPi(free_bcx, v, [0u, abi::box_field_body]);
let free_bcx = match t {
- Some(t) => make_free_glue(free_bcx, box_ptr_ptr, t),
+ Some(t) => drop_ty(free_bcx, body, t),
None => {
- let v = Load(free_bcx, box_ptr_ptr);
- let td = Load(free_bcx, GEPi(free_bcx, v, [0u, abi::box_field_tydesc]));
- let valptr = GEPi(free_bcx, v, [0u, abi::box_field_body]);
// Generate code that, dynamically, indexes into the
// tydesc and calls the drop glue that got set dynamically
- call_tydesc_glue_full(free_bcx, valptr, td, abi::tydesc_field_drop_glue, None);
- trans_free(free_bcx, v)
+ let td = Load(free_bcx, GEPi(free_bcx, v, [0u, abi::box_field_tydesc]));
+ call_tydesc_glue_full(free_bcx, body, td, abi::tydesc_field_drop_glue, None);
+ free_bcx
}
};
+ let free_bcx = trans_free(free_bcx, v);
Br(free_bcx, next_bcx.llbb);
next_bcx
let _icx = push_ctxt("make_take_glue");
// NB: v is a *pointer* to type t here, not a direct value.
match ty::get(t).sty {
- ty::ty_box(_) |
- ty::ty_vec(_, ty::vstore_box) | ty::ty_str(ty::vstore_box) => {
- incr_refcnt_of_boxed(bcx, Load(bcx, v)); bcx
- }
- ty::ty_vec(_, ty::vstore_slice(_))
- | ty::ty_str(ty::vstore_slice(_)) => {
- bcx
- }
- ty::ty_closure(_) => bcx,
- ty::ty_trait(_, _, ty::BoxTraitStore, _, _) => {
- let llbox = Load(bcx, GEPi(bcx, v, [0u, abi::trt_field_box]));
- incr_refcnt_of_boxed(bcx, llbox);
- bcx
- }
- ty::ty_trait(_, _, ty::UniqTraitStore, _, _) => {
- let lluniquevalue = GEPi(bcx, v, [0, abi::trt_field_box]);
- let llvtable = Load(bcx, GEPi(bcx, v, [0, abi::trt_field_vtable]));
-
- // Cast the vtable to a pointer to a pointer to a tydesc.
- let llvtable = PointerCast(bcx, llvtable,
- bcx.ccx().tydesc_type.ptr_to().ptr_to());
- let lltydesc = Load(bcx, llvtable);
- call_tydesc_glue_full(bcx,
- lluniquevalue,
- lltydesc,
- abi::tydesc_field_take_glue,
- None);
- bcx
- }
- ty::ty_opaque_closure_ptr(_) => bcx,
- _ if ty::type_is_structural(t) => {
- iter_structural_ty(bcx, v, t, take_ty)
- }
- _ => bcx
+ ty::ty_box(_) |
+ ty::ty_vec(_, ty::vstore_box) | ty::ty_str(ty::vstore_box) => {
+ incr_refcnt_of_boxed(bcx, Load(bcx, v)); bcx
+ }
+ ty::ty_vec(_, ty::vstore_slice(_))
+ | ty::ty_str(ty::vstore_slice(_)) => {
+ bcx
+ }
+ ty::ty_closure(_) => bcx,
+ ty::ty_trait(_, _, ty::BoxTraitStore, _, _) => {
+ let llbox = Load(bcx, GEPi(bcx, v, [0u, abi::trt_field_box]));
+ incr_refcnt_of_boxed(bcx, llbox);
+ bcx
+ }
+ ty::ty_trait(_, _, ty::UniqTraitStore, _, _) => {
+ let lluniquevalue = GEPi(bcx, v, [0, abi::trt_field_box]);
+ let llvtable = Load(bcx, GEPi(bcx, v, [0, abi::trt_field_vtable]));
+
+ // Cast the vtable to a pointer to a pointer to a tydesc.
+ let llvtable = PointerCast(bcx, llvtable,
+ bcx.ccx().tydesc_type.ptr_to().ptr_to());
+ let lltydesc = Load(bcx, llvtable);
+ call_tydesc_glue_full(bcx,
+ lluniquevalue,
+ lltydesc,
+ abi::tydesc_field_take_glue,
+ None);
+ bcx
+ }
+ _ if ty::type_is_structural(t) => {
+ iter_structural_ty(bcx, v, t, take_ty)
+ }
+ _ => bcx
}
}
let glue_name = format!("glue {} {}", name, ty_to_short_str(ccx.tcx, t));
let _s = StatRecorder::new(ccx, glue_name);
- let fcx = new_fn_ctxt(ccx, ~[], llfn, ty::mk_nil(), None);
+ let fcx = new_fn_ctxt(ccx, ~[], llfn, false, ty::mk_nil(), None);
init_function(&fcx, false, ty::mk_nil(), None);
lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
use middle::trans::base::{push_ctxt, trans_item, get_item_val, trans_fn};
use middle::trans::common::*;
use middle::ty;
-use util::ppaux::ty_to_str;
use std::vec;
use syntax::ast;
let llfn = get_item_val(ccx, mth.id);
let path = vec::append_one(
ty::item_path(ccx.tcx, impl_did), PathName(mth.ident));
- let self_kind = match mth.explicit_self.node {
- ast::SelfStatic => None,
- _ => {
- let self_ty = ty::node_id_to_type(ccx.tcx,
- mth.self_id);
- debug!("calling inline trans_fn with self_ty {}",
- ty_to_str(ccx.tcx, self_ty));
- Some(self_ty)
- }
- };
- trans_fn(ccx,
- path,
- mth.decl,
- mth.body,
- llfn,
- self_kind,
- None,
- mth.id,
- []);
+ trans_fn(ccx, path, mth.decl, mth.body, llfn, None, mth.id, []);
}
local_def(mth.id)
}
let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx, item.id));
- let fcx = new_fn_ctxt_detailed(ccx,
- path,
- decl,
- item.id,
- output_type,
- Some(substs),
- Some(item.span));
+ let fcx = new_fn_ctxt_detailed(ccx, path, decl, item.id, false, output_type,
+ Some(substs), Some(item.span));
init_function(&fcx, true, output_type, Some(substs));
set_always_inline(fcx.llfn);
// FIXME This is a hack to grab the address of this particular
// native function. There should be a general in-language
// way to do this
- let llfty = type_of_rust_fn(bcx.ccx(), None, [], ty::mk_nil());
+ let llfty = type_of_rust_fn(bcx.ccx(), false, [], ty::mk_nil());
let morestack_addr = decl_cdecl_fn(bcx.ccx().llmod, "__morestack",
llfty, ty::mk_nil());
let morestack_addr = PointerCast(bcx, morestack_addr,
methods: &[@ast::Method],
generics: &ast::Generics,
id: ast::NodeId) {
- let _icx = push_ctxt("impl::trans_impl");
+ let _icx = push_ctxt("meth::trans_impl");
let tcx = ccx.tcx;
debug!("trans_impl(path={}, name={}, id={:?})",
let path = vec::append_one(sub_path.clone(),
PathName(method.ident));
- trans_method(ccx,
- path,
- *method,
- None,
- |_| llfn);
+ trans_fn(ccx, path, method.decl, method.body,
+ llfn, None, method.id, []);
} else {
let mut v = TransItemVisitor{ ccx: ccx };
visit::walk_method_helper(&mut v, *method, ());
/// * `path`: the path to the method
/// * `method`: the AST node for the method
/// * `param_substs`: if this is a generic method, the current values for
-/// type parameters and so forth, else none
-/// * `llfn`: a closure returning the LLVM ValueRef for the method
-/// * `impl_id`: the node ID of the impl this method is inside
+/// type parameters and so forth, else None
+/// * `llfn`: the LLVM ValueRef for the method
///
/// FIXME(pcwalton) Can we take `path` by reference?
-pub fn trans_method(ccx: @CrateContext,
- path: Path,
- method: &ast::Method,
+pub fn trans_method(ccx: @CrateContext, path: Path, method: &ast::Method,
param_substs: Option<@param_substs>,
- llfn_with_self: |Option<ty::t>| -> ValueRef) -> ValueRef {
- // figure out how self is being passed
- let self_ty = match method.explicit_self.node {
- ast::SelfStatic => None,
- _ => {
- // determine the (monomorphized) type that `self` maps to for
- // this method
- let self_ty = ty::node_id_to_type(ccx.tcx, method.self_id);
- let self_ty = match param_substs {
- None => self_ty,
- Some(param_substs) => {
- ty::subst_tps(ccx.tcx,
- param_substs.tys,
- param_substs.self_ty,
- self_ty)
- }
- };
- debug!("calling trans_fn with self_ty {}", self_ty.repr(ccx.tcx));
- Some(self_ty)
- }
- };
-
- let llfn = llfn_with_self(self_ty);
-
- // generate the actual code
- trans_fn(ccx,
- path,
- method.decl,
- method.body,
- llfn,
- self_ty,
- param_substs,
- method.id,
- []);
+ llfn: ValueRef) -> ValueRef {
+ trans_fn(ccx, path, method.decl, method.body,
+ llfn, param_substs, method.id, []);
llfn
}
mentry: typeck::method_map_entry,
arg_cleanup_scope: cleanup::ScopeId)
-> Callee<'a> {
- let _icx = push_ctxt("impl::trans_method_callee");
+ let _icx = push_ctxt("meth::trans_method_callee");
- debug!("trans_method_callee(callee_id={:?}, this={}, mentry={})",
+ debug!("trans_method_callee(callee_id={:?}, mentry={})",
callee_id,
- bcx.expr_to_str(this),
mentry.repr(bcx.tcx()));
match mentry.origin {
typeck::method_static(did) => {
- let self_ty = monomorphize_type(bcx, mentry.self_ty);
- let Result {bcx, val} = trans_arg_expr(bcx, self_ty, this,
- arg_cleanup_scope,
- DontAutorefArg);
- // HACK should not need the pointer cast, eventually trans_fn_ref
- // should return a function type with the right type for self.
- let callee_fn = callee::trans_fn_ref(bcx, did, callee_id);
- let fn_ty = node_id_type(bcx, callee_id);
- let llfn_ty = type_of_fn_from_ty(bcx.ccx(), Some(self_ty), fn_ty).ptr_to();
- let llfn_val = PointerCast(bcx, callee_fn.llfn, llfn_ty);
Callee {
bcx: bcx,
- data: Method(MethodData {
- llfn: llfn_val,
- llself: val,
- })
+ data: Fn(callee::trans_fn_ref(bcx, did, callee_id))
}
}
typeck::method_param(typeck::method_param {
trait_id);
let vtbl = find_vtable(bcx.tcx(), substs, p, b);
- trans_monomorphized_callee(bcx, callee_id, this, mentry,
- trait_id, off, vtbl,
- arg_cleanup_scope)
+ trans_monomorphized_callee(bcx, callee_id,
+ trait_id, off, vtbl)
}
// how to get rid of this?
None => fail!("trans_method_callee: missing param_substs")
method_id: ast::DefId,
trait_id: ast::DefId,
callee_id: ast::NodeId)
- -> FnData {
- let _icx = push_ctxt("impl::trans_static_method_callee");
+ -> ValueRef {
+ let _icx = push_ctxt("meth::trans_static_method_callee");
let ccx = bcx.ccx();
debug!("trans_static_method_callee(method_id={:?}, trait_id={}, \
bcx, mth_id, callee_id,
*rcvr_substs, rcvr_origins);
- let FnData {llfn: lval} =
- trans_fn_ref_with_vtables(bcx,
- mth_id,
- callee_id,
- callee_substs,
- Some(callee_origins));
+ let llfn = trans_fn_ref_with_vtables(bcx, mth_id, callee_id,
+ callee_substs,
+ Some(callee_origins));
let callee_ty = node_id_type(bcx, callee_id);
- let llty = type_of_fn_from_ty(ccx, None, callee_ty).ptr_to();
- FnData {llfn: PointerCast(bcx, lval, llty)}
+ let llty = type_of_fn_from_ty(ccx, callee_ty).ptr_to();
+ PointerCast(bcx, llfn, llty)
}
_ => {
fail!("vtable_param left in monomorphized \
meth.def_id
}
-pub fn trans_monomorphized_callee<'a>(
- bcx: &'a Block<'a>,
+fn trans_monomorphized_callee<'a>(bcx: &'a Block<'a>,
callee_id: ast::NodeId,
- base: &ast::Expr,
- mentry: typeck::method_map_entry,
trait_id: ast::DefId,
n_method: uint,
- vtbl: typeck::vtable_origin,
- arg_cleanup_scope: cleanup::ScopeId)
+ vtbl: typeck::vtable_origin)
-> Callee<'a> {
- let _icx = push_ctxt("impl::trans_monomorphized_callee");
+ let _icx = push_ctxt("meth::trans_monomorphized_callee");
return match vtbl {
typeck::vtable_static(impl_did, ref rcvr_substs, rcvr_origins) => {
let ccx = bcx.ccx();
let mname = ty::trait_method(ccx.tcx, trait_id, n_method).ident;
let mth_id = method_with_name(bcx.ccx(), impl_did, mname.name);
- // obtain the `self` value:
- let self_ty = monomorphize_type(bcx, mentry.self_ty);
- let Result {bcx, val} = trans_arg_expr(bcx, self_ty, base,
- arg_cleanup_scope,
- DontAutorefArg);
-
// create a concatenated set of substitutions which includes
// those from the impl and those from the method:
let (callee_substs, callee_origins) =
*rcvr_substs, rcvr_origins);
// translate the function
- let callee = trans_fn_ref_with_vtables(bcx,
- mth_id,
- callee_id,
- callee_substs,
- Some(callee_origins));
+ let llfn = trans_fn_ref_with_vtables(bcx,
+ mth_id,
+ callee_id,
+ callee_substs,
+ Some(callee_origins));
- // create a llvalue that represents the fn ptr
- // HACK should not need the pointer cast (add self in trans_fn_ref_with_vtables).
- let fn_ty = node_id_type(bcx, callee_id);
- let llfn_ty = type_of_fn_from_ty(ccx, Some(self_ty), fn_ty).ptr_to();
- let llfn_val = PointerCast(bcx, callee.llfn, llfn_ty);
-
- // combine the self environment with the rest
- Callee {
- bcx: bcx,
- data: Method(MethodData {
- llfn: llfn_val,
- llself: val,
- })
- }
+ Callee { bcx: bcx, data: Fn(llfn) }
}
typeck::vtable_param(..) => {
fail!("vtable_param left in monomorphized function's vtable substs");
return (ty_substs, vtables);
}
-pub fn trans_trait_callee<'a>(
- bcx: &'a Block<'a>,
+fn trans_trait_callee<'a>(bcx: &'a Block<'a>,
callee_id: ast::NodeId,
n_method: uint,
self_expr: &ast::Expr,
* pair.
*/
- let _icx = push_ctxt("impl::trans_trait_callee");
+ let _icx = push_ctxt("meth::trans_trait_callee");
let mut bcx = bcx;
// Translate self_datum and take ownership of the value by
* a by-ref pointer to the object pair.
*/
- let _icx = push_ctxt("impl::trans_trait_callee");
+ let _icx = push_ctxt("meth::trans_trait_callee");
let ccx = bcx.ccx();
// Load the data pointer from the object.
debug!("(translating trait callee) loading second index from pair");
let llboxptr = GEPi(bcx, llpair, [0u, abi::trt_field_box]);
let llbox = Load(bcx, llboxptr);
- let llself = PointerCast(bcx, llbox, Type::opaque_box(ccx).ptr_to());
+ let llself = PointerCast(bcx, llbox, Type::i8p());
// Load the function from the vtable and cast it to the expected type.
debug!("(translating trait callee) loading method");
- let llcallee_ty = type_of_fn_from_ty(ccx, None, callee_ty);
+ // Replace the self type (&Self or ~Self) with an opaque pointer.
+ let llcallee_ty = match ty::get(callee_ty).sty {
+ ty::ty_bare_fn(ref f) if f.abis.is_rust() => {
+ type_of_rust_fn(ccx, true, f.sig.inputs.slice_from(1), f.sig.output)
+ }
+ _ => {
+ ccx.sess.bug("meth::trans_trait_callee given non-bare-rust-fn");
+ }
+ };
let llvtable = Load(bcx,
PointerCast(bcx,
GEPi(bcx, llpair,
return Callee {
bcx: bcx,
- data: Method(MethodData {
+ data: TraitMethod(MethodData {
llfn: mptr,
llself: llself,
})
origins: typeck::vtable_param_res)
-> ValueRef {
let ccx = bcx.ccx();
- let _icx = push_ctxt("impl::get_vtable");
+ let _icx = push_ctxt("meth::get_vtable");
// Check the cache.
let hash_id = (self_ty, vtable_id(ccx, &origins[0]));
ptrs: &[ValueRef])
-> ValueRef {
unsafe {
- let _icx = push_ctxt("impl::make_vtable");
+ let _icx = push_ctxt("meth::make_vtable");
let mut components = ~[ tydesc.tydesc ];
for &ptr in ptrs.iter() {
tcx.sess.str_of(ident));
C_null(Type::nil().ptr_to())
} else {
- trans_fn_ref_with_vtables(bcx, m_id, 0,
- substs, Some(vtables)).llfn
+ trans_fn_ref_with_vtables(bcx, m_id, 0, substs, Some(vtables))
}
})
}
*/
let mut bcx = bcx;
- let _icx = push_ctxt("impl::trans_cast");
+ let _icx = push_ctxt("meth::trans_cast");
let lldest = match dest {
Ignore => {
let s = mangle_exported_name(ccx, pt.clone(), mono_ty);
debug!("monomorphize_fn mangled to {}", s);
- let mk_lldecl = |self_ty| {
- let lldecl = decl_internal_rust_fn(ccx, self_ty, f.sig.inputs, f.sig.output, s);
+ let mk_lldecl = || {
+ let lldecl = decl_internal_rust_fn(ccx, false,
+ f.sig.inputs,
+ f.sig.output, s);
let mut monomorphized = ccx.monomorphized.borrow_mut();
monomorphized.get().insert(hash_id, lldecl);
lldecl
node: ast::ItemFn(decl, _, _, _, body),
..
} => {
- let d = mk_lldecl(None);
+ let d = mk_lldecl();
set_llvm_fn_attrs(i.attrs, d);
- trans_fn(ccx,
- pt,
- decl,
- body,
- d,
- None,
- Some(psubsts),
- fn_id.node,
- []);
+ trans_fn(ccx, pt, decl, body, d, Some(psubsts), fn_id.node, []);
d
}
_ => {
}
}
ast_map::NodeForeignItem(i, _, _, _) => {
- let d = mk_lldecl(None);
+ let d = mk_lldecl();
intrinsic::trans_intrinsic(ccx, d, i, pt, psubsts, i.attrs,
ref_id);
d
ast_map::NodeVariant(v, enum_item, _) => {
let tvs = ty::enum_variants(ccx.tcx, local_def(enum_item.id));
let this_tv = *tvs.iter().find(|tv| { tv.id.node == fn_id.node}).unwrap();
- let d = mk_lldecl(None);
+ let d = mk_lldecl();
set_inline_hint(d);
match v.node.kind {
ast::TupleVariantKind(ref args) => {
d
}
ast_map::NodeMethod(mth, _, _) => {
- meth::trans_method(ccx, pt, mth, Some(psubsts), |self_ty| {
- let d = mk_lldecl(self_ty);
- set_llvm_fn_attrs(mth.attrs, d);
- d
- })
+ let d = mk_lldecl();
+ set_llvm_fn_attrs(mth.attrs, d);
+ trans_fn(ccx, pt, mth.decl, mth.body, d, Some(psubsts), mth.id, []);
+ d
}
ast_map::NodeTraitMethod(method, _, pt) => {
match *method {
ast::Provided(mth) => {
- meth::trans_method(ccx,
- (*pt).clone(),
- mth,
- Some(psubsts),
- |self_ty| {
- let d = mk_lldecl(self_ty);
- set_llvm_fn_attrs(mth.attrs, d);
- d
- })
+ let d = mk_lldecl();
+ set_llvm_fn_attrs(mth.attrs, d);
+ trans_fn(ccx, (*pt).clone(), mth.decl, mth.body,
+ d, Some(psubsts), mth.id, []);
+ d
}
_ => {
ccx.tcx.sess.bug(format!("Can't monomorphize a {:?}",
}
}
ast_map::NodeStructCtor(struct_def, _, _) => {
- let d = mk_lldecl(None);
+ let d = mk_lldecl();
set_inline_hint(d);
base::trans_tuple_struct(ccx,
struct_def.fields,
use middle::trans::adt;
use middle::trans::base::*;
use middle::trans::build::*;
-use middle::trans::callee::{ArgVals, DontAutorefArg};
+use middle::trans::callee::ArgVals;
use middle::trans::callee;
use middle::trans::common::*;
use middle::trans::datum::*;
mth_ty,
mth_idx,
v),
- ArgVals(args), None, DontAutorefArg));
+ ArgVals(args), None));
let result = bool_to_i1(bcx, result);
let next_bcx = fcx.new_temp_block("next");
CondBr(bcx, result, next_bcx.llbb, self.final_bcx.llbb);
sub_path,
"get_disr");
- let llfdecl = decl_internal_rust_fn(ccx, None, [opaqueptrty], ty::mk_u64(), sym);
- let fcx = new_fn_ctxt(ccx,
- ~[],
- llfdecl,
- ty::mk_u64(),
- None);
+ let llfdecl = decl_internal_rust_fn(ccx, false,
+ [opaqueptrty],
+ ty::mk_u64(), sym);
+ let fcx = new_fn_ctxt(ccx, ~[], llfdecl, false, ty::mk_u64(), None);
init_function(&fcx, false, ty::mk_u64(), None);
let arg = unsafe {
self.visit("param", extra)
}
ty::ty_self(..) => self.leaf("self"),
- ty::ty_type => self.leaf("type"),
- ty::ty_opaque_closure_ptr(ck) => {
- let ckval = ast_sigil_constant(ck);
- let extra = ~[self.c_uint(ckval)];
- self.visit("closure_ptr", extra)
- }
+ ty::ty_type => self.leaf("type")
}
}
args.len() as c_uint, True))
}
- pub fn func_pair(cx: &CrateContext, fn_ty: &Type) -> Type {
- Type::struct_([fn_ty.ptr_to(), Type::opaque_cbox_ptr(cx)], false)
- }
-
pub fn ptr(ty: Type) -> Type {
ty!(llvm::LLVMPointerType(ty.to_ref(), 0 as c_uint))
}
}
pub fn glue_fn(t: Type) -> Type {
- Type::func([ Type::nil().ptr_to(), t ],
- &Type::void())
+ Type::func([t], &Type::void())
}
pub fn tydesc(arch: Architecture) -> Type {
// Must mirror:
//
// std::unstable::intrinsics::TyDesc
- // type_desc in rt
let elems = [int_ty, // size
int_ty, // align
Type::vec(arch, &Type::i8())
}
- #[inline]
- pub fn box_header_fields(ctx: &CrateContext) -> ~[Type] {
- ~[
+ // The box pointed to by @T.
+ pub fn at_box(ctx: &CrateContext, ty: Type) -> Type {
+ Type::struct_([
ctx.int_type, ctx.tydesc_type.ptr_to(),
- Type::i8().ptr_to(), Type::i8().ptr_to()
- ]
- }
-
- pub fn box_header(ctx: &CrateContext) -> Type {
- Type::struct_(Type::box_header_fields(ctx), false)
- }
-
- pub fn smart_ptr(ctx: &CrateContext, ty: &Type) -> Type {
- Type::struct_(Type::box_header_fields(ctx) + &[*ty], false)
- }
-
- pub fn opaque() -> Type {
- Type::i8()
- }
-
- pub fn opaque_box(ctx: &CrateContext) -> Type {
- Type::smart_ptr(ctx, &Type::opaque())
- }
-
- pub fn opaque_cbox_ptr(cx: &CrateContext) -> Type {
- Type::opaque_box(cx).ptr_to()
+ Type::i8p(), Type::i8p(), ty
+ ], false)
}
pub fn opaque_trait(ctx: &CrateContext, store: ty::TraitStore) -> Type {
let tydesc_ptr = ctx.tydesc_type.ptr_to();
let box_ty = match store {
- ty::BoxTraitStore => Type::opaque_box(ctx),
+ ty::BoxTraitStore => Type::at_box(ctx, Type::i8()),
ty::UniqTraitStore => Type::i8(),
ty::RegionTraitStore(..) => Type::i8()
};
}
}
-pub fn type_of_explicit_args(ccx: &CrateContext,
- inputs: &[ty::t]) -> ~[Type] {
- inputs.map(|&arg_ty| type_of_explicit_arg(ccx, arg_ty))
-}
-
-pub fn type_of_rust_fn(cx: &CrateContext,
- self_ty: Option<ty::t>,
- inputs: &[ty::t],
- output: ty::t) -> Type {
+pub fn type_of_rust_fn(cx: &CrateContext, has_env: bool,
+ inputs: &[ty::t], output: ty::t) -> Type {
let mut atys: ~[Type] = ~[];
// Arg 0: Output pointer.
}
// Arg 1: Environment
- let env = match self_ty {
- Some(t) => type_of_explicit_arg(cx, t),
- None => Type::opaque_box(cx).ptr_to()
- };
- atys.push(env);
+ if has_env {
+ atys.push(Type::i8p());
+ }
// ... then explicit args.
- atys.push_all(type_of_explicit_args(cx, inputs));
+ let mut input_tys = inputs.iter().map(|&arg_ty| type_of_explicit_arg(cx, arg_ty));
+ atys.extend(&mut input_tys);
// Use the output as the actual return value if it's immediate.
if use_out_pointer || return_type_is_void(cx, output) {
}
// Given a function type and a count of ty params, construct an llvm type
-pub fn type_of_fn_from_ty(cx: &CrateContext, self_ty: Option<ty::t>, fty: ty::t) -> Type {
- return match ty::get(fty).sty {
+pub fn type_of_fn_from_ty(cx: &CrateContext, fty: ty::t) -> Type {
+ match ty::get(fty).sty {
ty::ty_closure(ref f) => {
- type_of_rust_fn(cx, None, f.sig.inputs, f.sig.output)
+ type_of_rust_fn(cx, true, f.sig.inputs, f.sig.output)
}
ty::ty_bare_fn(ref f) => {
if f.abis.is_rust() || f.abis.is_intrinsic() {
- type_of_rust_fn(cx, self_ty, f.sig.inputs, f.sig.output)
+ type_of_rust_fn(cx, false, f.sig.inputs, f.sig.output)
} else {
foreign::lltype_for_foreign_fn(cx, fty)
}
_ => {
cx.sess.bug("type_of_fn_from_ty given non-closure, non-bare-fn")
}
- };
+ }
}
// A "sizing type" is an LLVM type, the size and alignment of which are
ty::ty_uniq(..) |
ty::ty_ptr(..) |
ty::ty_rptr(..) |
- ty::ty_type |
- ty::ty_opaque_closure_ptr(..) => Type::i8p(),
+ ty::ty_type => Type::i8p(),
ty::ty_str(ty::vstore_slice(..)) |
ty::ty_vec(_, ty::vstore_slice(..)) => {
adt::incomplete_type_of(cx, repr, name)
}
ty::ty_str(ty::vstore_box) => {
- Type::smart_ptr(cx,
- &Type::vec(cx.sess.targ_cfg.arch,
- &Type::i8())).ptr_to()
+ Type::at_box(cx, Type::vec(cx.sess.targ_cfg.arch, &Type::i8())).ptr_to()
}
ty::ty_vec(ref mt, ty::vstore_box) => {
let e_ty = type_of(cx, mt.ty);
- let v_ty = Type::vec(cx.sess.targ_cfg.arch, &e_ty);
- Type::smart_ptr(cx, &v_ty).ptr_to()
+ Type::at_box(cx, Type::vec(cx.sess.targ_cfg.arch, &e_ty)).ptr_to()
}
ty::ty_box(typ) => {
- let ty = type_of(cx, typ);
- Type::smart_ptr(cx, &ty).ptr_to()
+ Type::at_box(cx, type_of(cx, typ)).ptr_to()
}
ty::ty_uniq(typ) => {
type_of(cx, typ).ptr_to()
}
ty::ty_bare_fn(_) => {
- type_of_fn_from_ty(cx, None, t).ptr_to()
+ type_of_fn_from_ty(cx, t).ptr_to()
}
ty::ty_closure(_) => {
- let ty = type_of_fn_from_ty(cx, None, t);
- Type::func_pair(cx, &ty)
+ let fn_ty = type_of_fn_from_ty(cx, t).ptr_to();
+ Type::struct_([fn_ty, Type::i8p()], false)
}
ty::ty_trait(_, _, store, _, _) => Type::opaque_trait(cx, store),
ty::ty_type => cx.tydesc_type.ptr_to(),
let repr = adt::represent_type(cx, t);
adt::type_of(cx, repr)
}
- ty::ty_opaque_closure_ptr(_) => Type::opaque_box(cx).ptr_to(),
ty::ty_struct(did, ref substs) => {
if ty::type_is_simd(cx.tcx, t) {
let et = ty::simd_type(cx.tcx, t);
pub struct Method {
ident: ast::Ident,
generics: ty::Generics,
- transformed_self_ty: Option<ty::t>,
fty: BareFnTy,
explicit_self: ast::ExplicitSelf_,
vis: ast::Visibility,
impl Method {
pub fn new(ident: ast::Ident,
generics: ty::Generics,
- transformed_self_ty: Option<ty::t>,
fty: BareFnTy,
explicit_self: ast::ExplicitSelf_,
vis: ast::Visibility,
container: MethodContainer,
provided_source: Option<ast::DefId>)
-> Method {
- // Check the invariants.
- if explicit_self == ast::SelfStatic {
- assert!(transformed_self_ty.is_none());
- } else {
- assert!(transformed_self_ty.is_some());
- }
-
Method {
ident: ident,
generics: generics,
- transformed_self_ty: transformed_self_ty,
fty: fty,
explicit_self: explicit_self,
vis: vis,
// "Fake" types, used for trans purposes
ty_type, // type_desc*
- ty_opaque_closure_ptr(Sigil), // ptr to env for || and proc
ty_unboxed_vec(mt),
}
flags |= get(mt.ty).flags;
}
&ty_nil | &ty_bool | &ty_char | &ty_int(_) | &ty_float(_) | &ty_uint(_) |
- &ty_str(_) | &ty_type | &ty_opaque_closure_ptr(_) => {}
+ &ty_str(_) | &ty_type => {}
// You might think that we could just return ty_err for
// any type containing ty_err as a component, and get
// rid of the has_ty_err flag -- likewise for ty_bot (with
pub fn mk_type(cx: ctxt) -> t { mk_t(cx, ty_type) }
-pub fn mk_opaque_closure_ptr(cx: ctxt, sigil: ast::Sigil) -> t {
- mk_t(cx, ty_opaque_closure_ptr(sigil))
-}
-
pub fn walk_ty(ty: t, f: |t|) {
maybe_walk_ty(ty, |t| { f(t); true });
}
return;
}
match get(ty).sty {
- ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) | ty_uint(_) | ty_float(_) |
- ty_str(_) | ty_type | ty_self(_) |
- ty_opaque_closure_ptr(_) | ty_infer(_) | ty_param(_) | ty_err => {}
- ty_box(ty) | ty_uniq(ty) => maybe_walk_ty(ty, f),
- ty_vec(ref tm, _) | ty_unboxed_vec(ref tm) | ty_ptr(ref tm) |
- ty_rptr(_, ref tm) => {
- maybe_walk_ty(tm.ty, f);
- }
- ty_enum(_, ref substs) | ty_struct(_, ref substs) |
- ty_trait(_, ref substs, _, _, _) => {
- for subty in (*substs).tps.iter() { maybe_walk_ty(*subty, |x| f(x)); }
- }
- ty_tup(ref ts) => { for tt in ts.iter() { maybe_walk_ty(*tt, |x| f(x)); } }
- ty_bare_fn(ref ft) => {
- for a in ft.sig.inputs.iter() { maybe_walk_ty(*a, |x| f(x)); }
- maybe_walk_ty(ft.sig.output, f);
- }
- ty_closure(ref ft) => {
- for a in ft.sig.inputs.iter() { maybe_walk_ty(*a, |x| f(x)); }
- maybe_walk_ty(ft.sig.output, f);
- }
+ ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) | ty_uint(_) | ty_float(_) |
+ ty_str(_) | ty_type | ty_self(_) |
+ ty_infer(_) | ty_param(_) | ty_err => {}
+ ty_box(ty) | ty_uniq(ty) => maybe_walk_ty(ty, f),
+ ty_vec(ref tm, _) | ty_unboxed_vec(ref tm) | ty_ptr(ref tm) |
+ ty_rptr(_, ref tm) => {
+ maybe_walk_ty(tm.ty, f);
+ }
+ ty_enum(_, ref substs) | ty_struct(_, ref substs) |
+ ty_trait(_, ref substs, _, _, _) => {
+ for subty in (*substs).tps.iter() { maybe_walk_ty(*subty, |x| f(x)); }
+ }
+ ty_tup(ref ts) => { for tt in ts.iter() { maybe_walk_ty(*tt, |x| f(x)); } }
+ ty_bare_fn(ref ft) => {
+ for a in ft.sig.inputs.iter() { maybe_walk_ty(*a, |x| f(x)); }
+ maybe_walk_ty(ft.sig.output, f);
+ }
+ ty_closure(ref ft) => {
+ for a in ft.sig.inputs.iter() { maybe_walk_ty(*a, |x| f(x)); }
+ maybe_walk_ty(ft.sig.output, f);
+ }
}
}
pub fn type_is_unique(ty: t) -> bool {
match get(ty).sty {
- ty_uniq(_) |
- ty_vec(_, vstore_uniq) |
- ty_str(vstore_uniq) |
- ty_opaque_closure_ptr(ast::OwnedSigil) => true,
- _ => return false
+ ty_uniq(_) | ty_vec(_, vstore_uniq) | ty_str(vstore_uniq) => true,
+ _ => false
}
}
TC::All
}
ty_unboxed_vec(mt) => TC::InteriorUnsized | tc_mt(cx, mt, cache),
- ty_opaque_closure_ptr(sigil) => {
- match sigil {
- ast::BorrowedSigil => TC::ReachesBorrowed,
- ast::ManagedSigil => TC::Managed,
- ast::OwnedSigil => TC::OwnsOwned,
- }
- }
ty_type => TC::None,
ty_param(_) |
ty_self(_) |
ty_type |
- ty_opaque_closure_ptr(_) |
ty_vec(_, _) |
ty_unboxed_vec(_) => {
false
result = type_is_pod(cx, mt.ty);
}
ty_param(_) => result = false,
- ty_opaque_closure_ptr(_) => result = true,
ty_struct(did, ref substs) => {
let fields = lookup_struct_fields(cx, did);
result = fields.iter().all(|f| {
}
match expr.node {
- ast::ExprPath(..) | ast::ExprSelf => {
+ ast::ExprPath(..) => {
match resolve_expr(tcx, expr) {
- ast::DefVariant(..) | ast::DefStruct(..) => RvalueDpsExpr,
+ ast::DefVariant(tid, vid, _) => {
+ let variant_info = enum_variant_with_id(tcx, tid, vid);
+ if variant_info.args.len() > 0u {
+ // N-ary variant.
+ RvalueDatumExpr
+ } else {
+ // Nullary variant.
+ RvalueDpsExpr
+ }
+ }
+
+ ast::DefStruct(_) => {
+ match get(expr_ty(tcx, expr)).sty {
+ ty_bare_fn(..) => RvalueDatumExpr,
+ _ => RvalueDpsExpr
+ }
+ }
// Fn pointers are just scalar values.
ast::DefFn(..) | ast::DefStaticMethod(..) => RvalueDatumExpr,
// Note: there is actually a good case to be made that
- // def_args, particularly those of immediate type, ought to
+ // DefArg's, particularly those of immediate type, ought to
// considered rvalues.
ast::DefStatic(..) |
ast::DefBinding(..) |
ast::DefUpvar(..) |
ast::DefArg(..) |
- ast::DefLocal(..) |
- ast::DefSelf(..) => LvalueExpr,
+ ast::DefLocal(..) => LvalueExpr,
def => {
tcx.sess.span_bug(expr.span, format!(
pub fn ty_sort_str(cx: ctxt, t: t) -> ~str {
match get(t).sty {
- ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) |
- ty_uint(_) | ty_float(_) | ty_str(_) |
- ty_type | ty_opaque_closure_ptr(_) => {
- ::util::ppaux::ty_to_str(cx, t)
- }
-
- ty_enum(id, _) => format!("enum {}", item_path_str(cx, id)),
- ty_box(_) => ~"@-ptr",
- ty_uniq(_) => ~"~-ptr",
- ty_vec(_, _) => ~"vector",
- ty_unboxed_vec(_) => ~"unboxed vector",
- ty_ptr(_) => ~"*-ptr",
- ty_rptr(_, _) => ~"&-ptr",
- ty_bare_fn(_) => ~"extern fn",
- ty_closure(_) => ~"fn",
- ty_trait(id, _, _, _, _) => format!("trait {}", item_path_str(cx, id)),
- ty_struct(id, _) => format!("struct {}", item_path_str(cx, id)),
- ty_tup(_) => ~"tuple",
- ty_infer(TyVar(_)) => ~"inferred type",
- ty_infer(IntVar(_)) => ~"integral variable",
- ty_infer(FloatVar(_)) => ~"floating-point variable",
- ty_param(_) => ~"type parameter",
- ty_self(_) => ~"self",
- ty_err => ~"type error"
+ ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) |
+ ty_uint(_) | ty_float(_) | ty_str(_) | ty_type => {
+ ::util::ppaux::ty_to_str(cx, t)
+ }
+
+ ty_enum(id, _) => format!("enum {}", item_path_str(cx, id)),
+ ty_box(_) => ~"@-ptr",
+ ty_uniq(_) => ~"~-ptr",
+ ty_vec(_, _) => ~"vector",
+ ty_unboxed_vec(_) => ~"unboxed vector",
+ ty_ptr(_) => ~"*-ptr",
+ ty_rptr(_, _) => ~"&-ptr",
+ ty_bare_fn(_) => ~"extern fn",
+ ty_closure(_) => ~"fn",
+ ty_trait(id, _, _, _, _) => format!("trait {}", item_path_str(cx, id)),
+ ty_struct(id, _) => format!("struct {}", item_path_str(cx, id)),
+ ty_tup(_) => ~"tuple",
+ ty_infer(TyVar(_)) => ~"inferred type",
+ ty_infer(IntVar(_)) => ~"integral variable",
+ ty_infer(FloatVar(_)) => ~"floating-point variable",
+ ty_param(_) => ~"type parameter",
+ ty_self(_) => ~"self",
+ ty_err => ~"type error"
}
}
ty_infer(_) => unreachable!(),
ty_err => hash.input([23]),
ty_type => hash.input([24]),
- ty_opaque_closure_ptr(s) => {
- hash.input([25]);
- iter(&mut hash, &s);
- }
ty_unboxed_vec(m) => {
- hash.input([26]);
+ hash.input([25]);
mt(&mut hash, m);
}
}
ty::ty_nil | ty::ty_bot | ty::ty_bool | ty::ty_char |
ty::ty_int(_) | ty::ty_uint(_) |
ty::ty_float(_) | ty::ty_type |
- ty::ty_opaque_closure_ptr(_) |
ty::ty_err | ty::ty_infer(_) |
ty::ty_param(..) | ty::ty_self(_) => {
(*sty).clone()
return typ;
}
-pub fn ty_of_arg<AC:AstConv,
- RS:RegionScope>(
- this: &AC,
- rscope: &RS,
- a: &ast::Arg,
- expected_ty: Option<ty::t>)
- -> ty::t {
+pub fn ty_of_arg<AC: AstConv, RS: RegionScope>(this: &AC, rscope: &RS, a: &ast::Arg,
+ expected_ty: Option<ty::t>) -> ty::t {
match a.ty.node {
ast::TyInfer if expected_ty.is_some() => expected_ty.unwrap(),
ast::TyInfer => this.ty_infer(a.ty.span),
purity: ast::Purity,
untransformed_self_ty: ty::t,
explicit_self: ast::ExplicitSelf,
- decl: &ast::FnDecl) -> (Option<ty::t>, ty::BareFnTy)
-{
- let self_info = SelfInfo {
+ decl: &ast::FnDecl) -> ty::BareFnTy {
+ ty_of_method_or_bare_fn(this, id, purity, AbiSet::Rust(), Some(SelfInfo {
untransformed_self_ty: untransformed_self_ty,
explicit_self: explicit_self
- };
- let (a, b) = ty_of_method_or_bare_fn(
- this, id, purity, AbiSet::Rust(), Some(&self_info), decl);
- (a.unwrap(), b)
+ }), decl)
}
-pub fn ty_of_bare_fn<AC:AstConv>(
- this: &AC,
- id: ast::NodeId,
- purity: ast::Purity,
- abi: AbiSet,
- decl: &ast::FnDecl) -> ty::BareFnTy
-{
- let (_, b) = ty_of_method_or_bare_fn(this, id, purity,
- abi, None, decl);
- b
+pub fn ty_of_bare_fn<AC:AstConv>(this: &AC, id: ast::NodeId,
+ purity: ast::Purity, abi: AbiSet,
+ decl: &ast::FnDecl) -> ty::BareFnTy {
+ ty_of_method_or_bare_fn(this, id, purity, abi, None, decl)
}
-fn ty_of_method_or_bare_fn<AC:AstConv>(
- this: &AC,
- id: ast::NodeId,
- purity: ast::Purity,
- abi: AbiSet,
- opt_self_info: Option<&SelfInfo>,
- decl: &ast::FnDecl) -> (Option<Option<ty::t>>, ty::BareFnTy)
-{
+fn ty_of_method_or_bare_fn<AC:AstConv>(this: &AC, id: ast::NodeId,
+ purity: ast::Purity, abi: AbiSet,
+ opt_self_info: Option<SelfInfo>,
+ decl: &ast::FnDecl) -> ty::BareFnTy {
debug!("ty_of_method_or_bare_fn");
// new region names that appear inside of the fn decl are bound to
// that function type
let rb = rscope::BindingRscope::new(id);
- let opt_transformed_self_ty = opt_self_info.map(|self_info| {
- transform_self_ty(this, &rb, self_info)
- });
-
- let input_tys = decl.inputs.map(|a| ty_of_arg(this, &rb, a, None));
-
- let output_ty = match decl.output.node {
- ast::TyInfer => this.ty_infer(decl.output.span),
- _ => ast_ty_to_ty(this, &rb, decl.output)
- };
-
- return (opt_transformed_self_ty,
- ty::BareFnTy {
- purity: purity,
- abis: abi,
- sig: ty::FnSig {binder_id: id,
- inputs: input_tys,
- output: output_ty,
- variadic: decl.variadic}
- });
-
- fn transform_self_ty<AC:AstConv,RS:RegionScope>(
- this: &AC,
- rscope: &RS,
- self_info: &SelfInfo) -> Option<ty::t>
- {
+ let self_ty = opt_self_info.and_then(|self_info| {
match self_info.explicit_self.node {
ast::SelfStatic => None,
- ast::SelfValue(_) => {
+ ast::SelfValue => {
Some(self_info.untransformed_self_ty)
}
ast::SelfRegion(ref lifetime, mutability) => {
let region =
- opt_ast_region_to_region(this, rscope,
+ opt_ast_region_to_region(this, &rb,
self_info.explicit_self.span,
lifetime);
Some(ty::mk_rptr(this.tcx(), region,
ast::SelfBox => {
Some(ty::mk_box(this.tcx(), self_info.untransformed_self_ty))
}
- ast::SelfUniq(_) => {
+ ast::SelfUniq => {
Some(ty::mk_uniq(this.tcx(), self_info.untransformed_self_ty))
}
}
- }
+ });
+
+ // HACK(eddyb) replace the fake self type in the AST with the actual type.
+ let input_tys = if self_ty.is_some() {
+ decl.inputs.slice_from(1)
+ } else {
+ decl.inputs.as_slice()
+ };
+ let input_tys = input_tys.iter().map(|a| ty_of_arg(this, &rb, a, None));
+
+ let self_and_input_tys = self_ty.move_iter().chain(input_tys).collect();
+
+ let output_ty = match decl.output.node {
+ ast::TyInfer => this.ty_infer(decl.output.span),
+ _ => ast_ty_to_ty(this, &rb, decl.output)
+ };
+
+ return ty::BareFnTy {
+ purity: purity,
+ abis: abi,
+ sig: ty::FnSig {
+ binder_id: id,
+ inputs: self_and_input_tys,
+ output: output_ty,
+ variadic: decl.variadic
+ }
+ };
}
pub fn ty_of_closure<AC:AstConv,RS:RegionScope>(
*/
+use middle::subst::Subst;
use middle::resolve;
use middle::ty::*;
use middle::ty;
|new_trait_ref, m, method_num, _bound_num| {
let vtable_index =
self.get_method_index(new_trait_ref, trait_ref, method_num);
+ let mut m = (*m).clone();
// We need to fix up the transformed self type.
- let transformed_self_ty =
+ m.fty.sig.inputs[0] =
self.construct_transformed_self_ty_for_object(
- did, &rcvr_substs, m);
- let m = @Method {
- transformed_self_ty: Some(transformed_self_ty),
- .. (*m).clone()
- };
+ did, &rcvr_substs, &m);
Candidate {
rcvr_match_condition: RcvrMatchesIfObject(did),
rcvr_substs: new_trait_ref.substs.clone(),
- method_ty: m,
+ method_ty: @m,
origin: method_object(method_object {
trait_id: new_trait_ref.def_id,
object_trait_id: did,
ty_err => None,
- ty_opaque_closure_ptr(_) | ty_unboxed_vec(_) |
- ty_type | ty_infer(TyVar(_)) => {
+ ty_unboxed_vec(_) | ty_type | ty_infer(TyVar(_)) => {
self.bug(format!("Unexpected type: {}",
self.ty_to_str(self_ty)));
}
fn confirm_candidate(&self, rcvr_ty: ty::t, candidate: &Candidate)
-> method_map_entry {
+ // This method performs two sets of substitutions, one after the other:
+ // 1. Substitute values for any type/lifetime parameters from the impl and
+ // method declaration into the method type. This is the function type
+ // before it is called; it may still include late bound region variables.
+ // 2. Instantiate any late bound lifetime parameters in the method itself
+ // with fresh region variables.
+
let tcx = self.tcx();
- let fty = ty::mk_bare_fn(tcx, candidate.method_ty.fty.clone());
- debug!("confirm_candidate(expr={}, candidate={}, fty={})",
+ debug!("confirm_candidate(expr={}, candidate={})",
self.expr.repr(tcx),
- self.cand_to_str(candidate),
- self.ty_to_str(fty));
+ self.cand_to_str(candidate));
- self.enforce_object_limitations(fty, candidate);
+ self.enforce_object_limitations(candidate);
self.enforce_drop_trait_limitations(candidate);
// static methods should never have gotten this far:
assert!(candidate.method_ty.explicit_self != SelfStatic);
- let transformed_self_ty = match candidate.origin {
- method_object(..) => {
- // For annoying reasons, we've already handled the
- // substitution for object calls.
- candidate.method_ty.transformed_self_ty.unwrap()
- }
- _ => {
- ty::subst(tcx, &candidate.rcvr_substs,
- candidate.method_ty.transformed_self_ty.unwrap())
- }
- };
-
// Determine the values for the type parameters of the method.
// If they were not explicitly supplied, just construct fresh
// type variables.
self_ty: candidate.rcvr_substs.self_ty,
};
+ let ref bare_fn_ty = candidate.method_ty.fty;
+
// Compute the method type with type parameters substituted
debug!("fty={} all_substs={}",
- self.ty_to_str(fty),
+ bare_fn_ty.repr(tcx),
ty::substs_to_str(tcx, &all_substs));
- let fty = ty::subst(tcx, &all_substs, fty);
- debug!("after subst, fty={}", self.ty_to_str(fty));
- // Replace any bound regions that appear in the function
- // signature with region variables
- let bare_fn_ty = match ty::get(fty).sty {
- ty::ty_bare_fn(ref f) => f,
- ref s => {
- tcx.sess.span_bug(
- self.expr.span,
- format!("Invoking method with non-bare-fn ty: {:?}", s));
+ let fn_sig = &bare_fn_ty.sig;
+ let inputs = match candidate.origin {
+ method_object(..) => {
+ // For annoying reasons, we've already handled the
+ // substitution of self for object calls.
+ let args = fn_sig.inputs.slice_from(1).iter().map(|t| {
+ t.subst(tcx, &all_substs)
+ });
+ Some(fn_sig.inputs[0]).move_iter().chain(args).collect()
}
+ _ => fn_sig.inputs.subst(tcx, &all_substs)
};
- let (_, opt_transformed_self_ty, fn_sig) =
- replace_bound_regions_in_fn_sig(
- tcx, Some(transformed_self_ty), &bare_fn_ty.sig,
- |br| self.fcx.infcx().next_region_var(
- infer::BoundRegionInFnCall(self.expr.span, br)));
- let transformed_self_ty = opt_transformed_self_ty.unwrap();
+ let fn_sig = ty::FnSig {
+ binder_id: fn_sig.binder_id,
+ inputs: inputs,
+ output: fn_sig.output.subst(tcx, &all_substs),
+ variadic: fn_sig.variadic
+ };
+
+ debug!("after subst, fty={}", fn_sig.repr(tcx));
+
+ // Replace any bound regions that appear in the function
+ // signature with region variables
+ let (_, fn_sig) = replace_bound_regions_in_fn_sig( tcx, &fn_sig, |br| {
+ self.fcx.infcx().next_region_var(
+ infer::BoundRegionInFnCall(self.expr.span, br))
+ });
+ let transformed_self_ty = fn_sig.inputs[0];
let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {
sig: fn_sig,
purity: bare_fn_ty.purity,
// should never fail.
match self.fcx.mk_subty(false, infer::Misc(self.self_expr.span),
rcvr_ty, transformed_self_ty) {
- result::Ok(_) => (),
+ result::Ok(_) => {}
result::Err(_) => {
self.bug(format!("{} was a subtype of {} but now is not?",
self.ty_to_str(rcvr_ty),
self.fcx.write_ty(self.callee_id, fty);
self.fcx.write_substs(self.callee_id, all_substs);
method_map_entry {
- self_ty: transformed_self_ty,
- explicit_self: candidate.method_ty.explicit_self,
- origin: candidate.origin,
+ origin: candidate.origin
}
}
* result to be `&'a Foo`. Assuming that `u_method` is being
* called, we want the result to be `~Foo`. Of course,
* this transformation has already been done as part of
- * `method_ty.transformed_self_ty`, but there the type
+ * `method_ty.fty.sig.inputs[0]`, but there the type
* is expressed in terms of `Self` (i.e., `&'a Self`, `~Self`).
* Because objects are not standalone types, we can't just substitute
* `s/Self/Foo/`, so we must instead perform this kind of hokey
ast::SelfStatic => {
self.bug(~"static method for object type receiver");
}
- ast::SelfValue(_) => {
+ ast::SelfValue => {
ty::mk_err() // error reported in `enforce_object_limitations()`
}
- ast::SelfRegion(..) | ast::SelfBox | ast::SelfUniq(..) => {
- let transformed_self_ty =
- method_ty.transformed_self_ty.clone().unwrap();
+ ast::SelfRegion(..) | ast::SelfBox | ast::SelfUniq => {
+ let transformed_self_ty = method_ty.fty.sig.inputs[0];
match ty::get(transformed_self_ty).sty {
ty::ty_rptr(r, mt) => { // must be SelfRegion
ty::mk_trait(self.tcx(), trait_def_id,
}
}
- fn enforce_object_limitations(&self,
- method_fty: ty::t,
- candidate: &Candidate)
- {
+ fn enforce_object_limitations(&self, candidate: &Candidate) {
/*!
* There are some limitations to calling functions through an
* object, because (a) the self type is not known
through an object");
}
- ast::SelfValue(_) => { // reason (a) above
+ ast::SelfValue => { // reason (a) above
self.tcx().sess.span_err(
self.expr.span,
"cannot call a method with a by-value receiver \
through an object");
}
- ast::SelfRegion(..) | ast::SelfBox | ast::SelfUniq(..) => {}
+ ast::SelfRegion(..) | ast::SelfBox | ast::SelfUniq => {}
}
- if ty::type_has_self(method_fty) { // reason (a) above
- self.tcx().sess.span_err(
- self.expr.span,
- "cannot call a method whose type contains a \
- self-type through an object");
+ // reason (a) above
+ let check_for_self_ty = |ty| {
+ if ty::type_has_self(ty) {
+ self.tcx().sess.span_err(
+ self.expr.span,
+ "cannot call a method whose type contains a \
+ self-type through an object");
+ true
+ } else {
+ false
+ }
+ };
+ let ref sig = candidate.method_ty.fty.sig;
+ let mut found_self_ty = false;
+ for &input_ty in sig.inputs.iter() {
+ if check_for_self_ty(input_ty) {
+ found_self_ty = true;
+ break;
+ }
+ }
+ if !found_self_ty {
+ check_for_self_ty(sig.output);
}
if candidate.method_ty.generics.has_type_params() { // reason (b) above
false
}
- SelfValue(_) => {
+ SelfValue => {
rcvr_matches_ty(self.fcx, rcvr_ty, candidate)
}
}
}
- SelfUniq(_) => {
+ SelfUniq => {
debug!("(is relevant?) explicit self is a unique pointer");
match ty::get(rcvr_ty).sty {
ty::ty_uniq(typ) => {
pub mod demand;
pub mod method;
-pub struct SelfInfo {
- self_ty: ty::t,
- self_id: ast::NodeId,
- span: Span
-}
-
/// Fields that are part of a `FnCtxt` which are inherited by
/// closures defined within the function. For example:
///
visit::walk_crate(&mut visit, crate, ());
}
-pub fn check_bare_fn(ccx: @CrateCtxt,
- decl: &ast::FnDecl,
- body: &ast::Block,
- id: ast::NodeId,
- self_info: Option<SelfInfo>,
- fty: ty::t,
- param_env: ty::ParameterEnvironment) {
+fn check_bare_fn(ccx: @CrateCtxt,
+ decl: &ast::FnDecl,
+ body: &ast::Block,
+ id: ast::NodeId,
+ fty: ty::t,
+ param_env: ty::ParameterEnvironment) {
match ty::get(fty).sty {
ty::ty_bare_fn(ref fn_ty) => {
let fcx =
- check_fn(ccx, self_info, fn_ty.purity,
- &fn_ty.sig, decl, id, body, Vanilla,
- @Inherited::new(ccx.tcx, param_env));
+ check_fn(ccx, fn_ty.purity, &fn_ty.sig, decl, id, body,
+ Vanilla, @Inherited::new(ccx.tcx, param_env));
vtable::resolve_in_block(fcx, body);
regionck::regionck_fn(fcx, body);
- writeback::resolve_type_vars_in_fn(fcx, decl, body, self_info);
+ writeback::resolve_type_vars_in_fn(fcx, decl, body);
}
_ => ccx.tcx.sess.impossible_case(body.span,
"check_bare_fn: function type expected")
}
-pub fn check_fn(ccx: @CrateCtxt,
- opt_self_info: Option<SelfInfo>,
- purity: ast::Purity,
- fn_sig: &ty::FnSig,
- decl: &ast::FnDecl,
- id: ast::NodeId,
- body: &ast::Block,
- fn_kind: FnKind,
- inherited: @Inherited) -> @FnCtxt
+fn check_fn(ccx: @CrateCtxt,
+ purity: ast::Purity,
+ fn_sig: &ty::FnSig,
+ decl: &ast::FnDecl,
+ id: ast::NodeId,
+ body: &ast::Block,
+ fn_kind: FnKind,
+ inherited: @Inherited) -> @FnCtxt
{
/*!
* Helper used by check_bare_fn and check_expr_fn. Does the
let tcx = ccx.tcx;
let err_count_on_creation = tcx.sess.err_count();
- // First, we have to replace any bound regions in the fn and self
- // types with free ones. The free region references will be bound
- // the node_id of the body block.
- let (opt_self_info, fn_sig) = {
- let opt_self_ty = opt_self_info.map(|i| i.self_ty);
- let (_, opt_self_ty, fn_sig) =
- replace_bound_regions_in_fn_sig(
- tcx, opt_self_ty, fn_sig,
- |br| ty::ReFree(ty::FreeRegion {scope_id: body.id,
- bound_region: br}));
- let opt_self_info =
- opt_self_info.map(
- |si| SelfInfo {self_ty: opt_self_ty.unwrap(), .. si});
- (opt_self_info, fn_sig)
- };
+ // First, we have to replace any bound regions in the fn type with free ones.
+ // The free region references will be bound the node_id of the body block.
+ let (_, fn_sig) = replace_bound_regions_in_fn_sig(tcx, fn_sig, |br| {
+ ty::ReFree(ty::FreeRegion {scope_id: body.id, bound_region: br})
+ });
- relate_free_regions(tcx, opt_self_info.map(|s| s.self_ty), &fn_sig);
+ relate_free_regions(tcx, &fn_sig);
- let arg_tys = fn_sig.inputs.map(|a| *a);
+ let arg_tys = fn_sig.inputs.as_slice();
let ret_ty = fn_sig.output;
- debug!("check_fn(arg_tys={:?}, ret_ty={:?}, opt_self_ty={:?})",
+ debug!("check_fn(arg_tys={:?}, ret_ty={:?})",
arg_tys.map(|&a| ppaux::ty_to_str(tcx, a)),
- ppaux::ty_to_str(tcx, ret_ty),
- opt_self_info.map(|si| ppaux::ty_to_str(tcx, si.self_ty)));
+ ppaux::ty_to_str(tcx, ret_ty));
// Create the function context. This is either derived from scratch or,
// in the case of function expressions, based on the outer context.
- let fcx: @FnCtxt = {
- @FnCtxt {
- err_count_on_creation: err_count_on_creation,
- ret_ty: ret_ty,
- ps: RefCell::new(PurityState::function(purity, id)),
- region_lb: Cell::new(body.id),
- fn_kind: fn_kind,
- inh: inherited,
- ccx: ccx
- }
+ let fcx = @FnCtxt {
+ err_count_on_creation: err_count_on_creation,
+ ret_ty: ret_ty,
+ ps: RefCell::new(PurityState::function(purity, id)),
+ region_lb: Cell::new(body.id),
+ fn_kind: fn_kind,
+ inh: inherited,
+ ccx: ccx
};
- gather_locals(fcx, decl, body, arg_tys, opt_self_info);
- check_block_with_expected(fcx, body, Some(ret_ty));
-
- // We unify the tail expr's type with the
- // function result type, if there is a tail expr.
- match body.expr {
- Some(tail_expr) => {
- let tail_expr_ty = fcx.expr_ty(tail_expr);
- // Special case: we print a special error if there appears
- // to be do-block/for-loop confusion
- demand::suptype_with_fn(fcx, tail_expr.span, false,
- fcx.ret_ty, tail_expr_ty,
- |sp, e, a, s| {
- fcx.report_mismatched_return_types(sp, e, a, s) });
- }
- None => ()
- }
-
- for self_info in opt_self_info.iter() {
- fcx.write_ty(self_info.self_id, self_info.self_ty);
- }
- for (input, arg) in decl.inputs.iter().zip(arg_tys.iter()) {
- fcx.write_ty(input.id, *arg);
- }
-
- return fcx;
-
- fn gather_locals(fcx: @FnCtxt,
- decl: &ast::FnDecl,
- body: &ast::Block,
- arg_tys: &[ty::t],
- opt_self_info: Option<SelfInfo>) {
- let tcx = fcx.ccx.tcx;
+ {
let mut visit = GatherLocalsVisitor { fcx: fcx, tcx: tcx, };
-
- // Add the self parameter
- for self_info in opt_self_info.iter() {
- visit.assign(self_info.self_id, Some(self_info.self_ty));
- let locals = fcx.inh.locals.borrow();
- debug!("self is assigned to {}",
- fcx.infcx().ty_to_str(
- locals.get().get_copy(&self_info.self_id)));
- }
-
// Add formal parameters.
for (arg_ty, input) in arg_tys.iter().zip(decl.inputs.iter()) {
// Create type variables for each argument.
pat_util::pat_bindings(tcx.def_map,
input.pat,
|_bm, pat_id, _sp, _path| {
- visit.assign(pat_id, None);
- });
+ visit.assign(pat_id, None);
+ });
// Check the pattern.
let pcx = pat_ctxt {
visit.visit_block(body, ());
}
+
+ check_block_with_expected(fcx, body, Some(ret_ty));
+
+ // We unify the tail expr's type with the
+ // function result type, if there is a tail expr.
+ match body.expr {
+ Some(tail_expr) => {
+ // Special case: we print a special error if there appears
+ // to be do-block/for-loop confusion
+ demand::suptype_with_fn(fcx, tail_expr.span, false,
+ fcx.ret_ty, fcx.expr_ty(tail_expr),
+ |sp, e, a, s| {
+ fcx.report_mismatched_return_types(sp, e, a, s);
+ });
+ }
+ None => {}
+ }
+
+ for (input, arg) in decl.inputs.iter().zip(arg_tys.iter()) {
+ fcx.write_ty(input.id, *arg);
+ }
+
+ fcx
}
pub fn check_no_duplicate_fields(tcx: ty::ctxt,
[],
body.id);
- check_bare_fn(ccx, decl, body, it.id, None, fn_tpt.ty, param_env);
+ check_bare_fn(ccx, decl, body, it.id, fn_tpt.ty, param_env);
}
ast::ItemImpl(_, ref opt_trait_ref, _, ref ms) => {
debug!("ItemImpl {} with id {}", ccx.tcx.sess.str_of(it.ident), it.id);
item_generics.region_param_defs,
method.body.id);
- // Compute the self type and fty from point of view of inside fn
- let opt_self_info = method_ty.transformed_self_ty.map(|ty| {
- SelfInfo {self_ty: ty.subst(ccx.tcx, ¶m_env.free_substs),
- self_id: method.self_id,
- span: method.explicit_self.span}
- });
+ // Compute the fty from point of view of inside fn
let fty = ty::node_id_to_type(ccx.tcx, method.id);
let fty = fty.subst(ccx.tcx, ¶m_env.free_substs);
- check_bare_fn(
- ccx,
- method.decl,
- method.body,
- method.id,
- opt_self_info,
- fty,
- param_env);
+ check_bare_fn(ccx, method.decl, method.body, method.id, fty, param_env);
}
fn check_impl_methods_against_trait(ccx: @CrateCtxt,
* - trait_m: the method in the trait
* - trait_substs: the substitutions used on the type of the trait
*/
-pub fn compare_impl_method(tcx: ty::ctxt,
- impl_generics: &ty::Generics,
- impl_m: @ty::Method,
- impl_m_span: Span,
- impl_m_body_id: ast::NodeId,
- trait_m: &ty::Method,
- trait_substs: &ty::substs) {
+fn compare_impl_method(tcx: ty::ctxt,
+ impl_generics: &ty::Generics,
+ impl_m: @ty::Method,
+ impl_m_span: Span,
+ impl_m_body_id: ast::NodeId,
+ trait_m: &ty::Method,
+ trait_substs: &ty::substs) {
debug!("compare_impl_method()");
let infcx = infer::new_infer_ctxt(tcx);
regions: ty::NonerasedRegions(dummy_impl_regions),
self_ty: None };
- // We are going to create a synthetic fn type that includes
- // both the method's self argument and its normal arguments.
- // So a method like `fn(&self, a: uint)` would be converted
- // into a function `fn(self: &T, a: uint)`.
- let mut trait_fn_args = ~[];
- let mut impl_fn_args = ~[];
-
- // For both the trait and the impl, create an argument to
- // represent the self argument (unless this is a static method).
- // This argument will have the *transformed* self type.
- for &t in trait_m.transformed_self_ty.iter() {
- trait_fn_args.push(t);
- }
- for &t in impl_m.transformed_self_ty.iter() {
- impl_fn_args.push(t);
- }
-
- // Add in the normal arguments.
- trait_fn_args.push_all(trait_m.fty.sig.inputs);
- impl_fn_args.push_all(impl_m.fty.sig.inputs);
-
- // Create a bare fn type for trait/impl that includes self argument
- let trait_fty =
- ty::mk_bare_fn(tcx,
- ty::BareFnTy {
- purity: trait_m.fty.purity,
- abis: trait_m.fty.abis,
- sig: ty::FnSig {
- binder_id: trait_m.fty.sig.binder_id,
- inputs: trait_fn_args,
- output: trait_m.fty.sig.output,
- variadic: false
- }
- });
- let impl_fty =
- ty::mk_bare_fn(tcx,
- ty::BareFnTy {
- purity: impl_m.fty.purity,
- abis: impl_m.fty.abis,
- sig: ty::FnSig {
- binder_id: impl_m.fty.sig.binder_id,
- inputs: impl_fn_args,
- output: impl_m.fty.sig.output,
- variadic: false
- }
- });
+ // Create a bare fn type for trait/impl
+ // It'd be nice to refactor so as to provide the bare fn types instead.
+ let trait_fty = ty::mk_bare_fn(tcx, trait_m.fty.clone());
+ let impl_fty = ty::mk_bare_fn(tcx, impl_m.fty.clone());
// Perform substitutions so that the trait/impl methods are expressed
// in terms of the same set of type/region parameters:
sugar: ast::CallSugar,
deref_args: DerefArgs) -> ty::t
{
+ // HACK(eddyb) ignore provided self (it has special typeck rules).
+ let args = args.slice_from(1);
if ty::type_is_error(method_fn_ty) {
let err_inputs = err_args(args.len());
check_argument_types(fcx, sp, err_inputs, callee_expr,
} else {
match ty::get(method_fn_ty).sty {
ty::ty_bare_fn(ref fty) => {
- check_argument_types(fcx, sp, fty.sig.inputs, callee_expr,
- args, sugar, deref_args, fty.sig.variadic);
+ // HACK(eddyb) ignore self in the definition (see above).
+ check_argument_types(fcx, sp, fty.sig.inputs.slice_from(1),
+ callee_expr, args, sugar, deref_args,
+ fty.sig.variadic);
fty.sig.output
}
_ => {
// Replace any bound regions that appear in the function
// signature with region variables
- let (_, _, fn_sig) =
- replace_bound_regions_in_fn_sig(fcx.tcx(),
- None,
- fn_sig,
- |br| fcx.infcx()
- .next_region_var(
- infer::BoundRegionInFnCall(call_expr.span, br)));
+ let (_, fn_sig) = replace_bound_regions_in_fn_sig(fcx.tcx(), fn_sig, |br| {
+ fcx.infcx()
+ .next_region_var(infer::BoundRegionInFnCall(call_expr.span, br))
+ });
// Call the generic checker.
check_argument_types(fcx, call_expr.span, fn_sig.inputs, f,
fn check_method_call(fcx: @FnCtxt,
callee_id: ast::NodeId,
expr: &ast::Expr,
- rcvr: &ast::Expr,
method_name: ast::Ident,
args: &[@ast::Expr],
tps: &[ast::P<ast::Ty>],
sugar: ast::CallSugar) {
+ let rcvr = args[0];
check_expr(fcx, rcvr);
// no need to check for bot/err -- callee does that
fn lookup_op_method(fcx: @FnCtxt,
callee_id: ast::NodeId,
op_ex: &ast::Expr,
- self_ex: &ast::Expr,
self_t: ty::t,
opname: ast::Name,
args: &[@ast::Expr],
_expected_result: Option<ty::t>
)
-> ty::t {
- match method::lookup(fcx, op_ex, self_ex,
+ match method::lookup(fcx, op_ex, args[0],
callee_id, opname, self_t, [],
deref_args, CheckTraitsOnly, autoderef_receiver) {
Some(ref origin) => {
callee_id: ast::NodeId,
expr: &ast::Expr,
op: ast::BinOp,
- lhs: &ast::Expr,
+ lhs: @ast::Expr,
rhs: @ast::Expr,
// Used only in the error case
expected_result: Option<ty::t>,
fn check_user_binop(fcx: @FnCtxt,
callee_id: ast::NodeId,
ex: &ast::Expr,
- lhs_expr: &ast::Expr,
+ lhs_expr: @ast::Expr,
lhs_resolved_t: ty::t,
op: ast::BinOp,
rhs: @ast::Expr,
ast_util::binop_to_str(op), actual)},
lhs_resolved_t, None)
};
- return lookup_op_method(fcx, callee_id, ex, lhs_expr, lhs_resolved_t,
- token::intern(*name),
- &[rhs], DoDerefArgs, DontAutoderefReceiver, if_op_unbound,
- expected_result);
+ return lookup_op_method(fcx, callee_id, ex, lhs_resolved_t,
+ token::intern(*name), [lhs_expr, rhs],
+ DoDerefArgs,DontAutoderefReceiver,
+ if_op_unbound, expected_result);
}
None => ()
};
op_str: &str,
mname: &str,
ex: &ast::Expr,
- rhs_expr: &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_expr, rhs_t,
- token::intern(mname), &[],
- DoDerefArgs, DontAutoderefReceiver,
+ 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 `{}`",
expected_bounds) = {
match expected_sty {
Some(ty::ty_closure(ref cenv)) => {
- let (_, _, sig) =
+ let (_, sig) =
replace_bound_regions_in_fn_sig(
- tcx, None, &cenv.sig,
+ tcx, &cenv.sig,
|_| fcx.inh.infcx.fresh_bound_region(expr.id));
(Some(sig), cenv.purity, cenv.sigil,
cenv.onceness, cenv.bounds)
(purity, expr.id),
sigil);
- check_fn(fcx.ccx, None, inherited_purity, &fty_sig,
+ check_fn(fcx.ccx, inherited_purity, &fty_sig,
decl, id, body, fn_kind, fcx.inh);
}
let tpt = ty_param_bounds_and_ty_for_def(fcx, expr.span, defn);
instantiate_path(fcx, pth, tpt, defn, expr.span, expr.id);
}
- ast::ExprSelf => {
- let definition = lookup_def(fcx, expr.span, id);
- let ty_param_bounds_and_ty =
- ty_param_bounds_and_ty_for_def(fcx, expr.span, definition);
- fcx.write_ty(id, ty_param_bounds_and_ty.ty);
- }
ast::ExprInlineAsm(ref ia) => {
for &(_, input) in ia.inputs.iter() {
check_expr(fcx, input);
fcx.write_bot(id);
}
}
- ast::ExprMethodCall(callee_id, rcvr, ident, ref tps, ref args, sugar) => {
- check_method_call(fcx, callee_id, expr, rcvr, ident, *args, *tps, sugar);
- let f_ty = fcx.expr_ty(rcvr);
+ ast::ExprMethodCall(callee_id, ident, ref tps, ref args, sugar) => {
+ check_method_call(fcx, callee_id, expr, ident, *args, *tps, sugar);
let arg_tys = args.map(|a| fcx.expr_ty(*a));
let (args_bot, args_err) = arg_tys.iter().fold((false, false),
|(rest_bot, rest_err), a| {
(rest_bot || ty::type_is_bot(*a),
rest_err || ty::type_is_error(*a))});
- if ty::type_is_error(f_ty) || args_err {
+ if args_err {
fcx.write_error(id);
- }
- else if ty::type_is_bot(f_ty) || args_bot {
+ } else if args_bot {
fcx.write_bot(id);
}
}
let ret_ty = lookup_op_method(fcx,
callee_id,
expr,
- base,
resolved,
index_ident.name,
- &[idx],
+ [base, idx],
DoDerefArgs,
AutoderefReceiver,
error_message,
defn: ast::Def)
-> ty_param_bounds_and_ty {
match defn {
- ast::DefArg(nid, _) | ast::DefLocal(nid, _) | ast::DefSelf(nid, _) |
+ ast::DefArg(nid, _) | ast::DefLocal(nid, _) |
ast::DefBinding(nid, _) => {
let typ = fcx.local_ty(sp, nid);
return no_params(typ);
use util::ppaux::{ty_to_str, region_to_str, Repr};
use syntax::ast::{ManagedSigil, OwnedSigil, BorrowedSigil};
-use syntax::ast::{DefArg, DefBinding, DefLocal, DefSelf, DefUpvar};
+use syntax::ast::{DefArg, DefBinding, DefLocal, DefUpvar};
use syntax::ast;
use syntax::codemap::Span;
use syntax::visit;
let tcx = fcx.tcx();
match def {
DefLocal(node_id, _) | DefArg(node_id, _) |
- DefSelf(node_id, _) | DefBinding(node_id, _) => {
+ DefBinding(node_id, _) => {
tcx.region_maps.var_region(node_id)
}
DefUpvar(_, subdef, closure_id, body_id) => {
visit::walk_expr(rcx, expr, ());
}
- ast::ExprMethodCall(callee_id, arg0, _, _, ref args, _) => {
- constrain_call(rcx, callee_id, expr, Some(arg0), *args, false);
+ ast::ExprMethodCall(callee_id, _, _, ref args, _) => {
+ constrain_call(rcx, callee_id, expr, Some(args[0]),
+ args.slice_from(1), false);
visit::walk_expr(rcx, expr, ());
}
guarantor(rcx, e)
}
- ast::ExprPath(..) | ast::ExprSelf => {
- // Either a variable or constant and hence resides
- // in constant memory or on the stack frame. Either way,
- // not guaranteed by a region pointer.
- None
- }
+ // Either a variable or constant and hence resides
+ // in constant memory or on the stack frame. Either way,
+ // not guaranteed by a region pointer.
+ ast::ExprPath(..) => None,
// All of these expressions are rvalues and hence their
// value is not guaranteed by a region pointer.
pub fn replace_bound_regions_in_fn_sig(
tcx: ty::ctxt,
- opt_self_ty: Option<ty::t>,
fn_sig: &ty::FnSig,
mapf: |ty::BoundRegion| -> ty::Region)
- -> (HashMap<ty::BoundRegion,ty::Region>, Option<ty::t>, ty::FnSig) {
- debug!("replace_bound_regions_in_fn_sig(self_ty={}, fn_sig={})",
- opt_self_ty.repr(tcx),
- fn_sig.repr(tcx));
+ -> (HashMap<ty::BoundRegion,ty::Region>, ty::FnSig) {
+ debug!("replace_bound_regions_in_fn_sig({})", fn_sig.repr(tcx));
let mut map = HashMap::new();
- let (fn_sig, opt_self_ty) = {
+ let fn_sig = {
let mut f = ty_fold::RegionFolder::regions(tcx, |r| {
- debug!("region r={}", r.to_str());
- match r {
+ debug!("region r={}", r.to_str());
+ match r {
ty::ReLateBound(s, br) if s == fn_sig.binder_id => {
*map.find_or_insert_with(br, |_| mapf(br))
}
_ => r
- }});
- (ty_fold::super_fold_sig(&mut f, fn_sig),
- ty_fold::fold_opt_ty(&mut f, opt_self_ty))
+ }
+ });
+ ty_fold::super_fold_sig(&mut f, fn_sig)
};
debug!("resulting map: {}", map.to_str());
- (map, opt_self_ty, fn_sig)
+ (map, fn_sig)
}
pub fn relate_nested_regions(tcx: ty::ctxt,
}
}
-pub fn relate_free_regions(
- tcx: ty::ctxt,
- self_ty: Option<ty::t>,
- fn_sig: &ty::FnSig)
-{
+pub fn relate_free_regions(tcx: ty::ctxt, fn_sig: &ty::FnSig) {
/*!
* This function populates the region map's `free_region_map`.
* It walks over the transformed self type and argument types
for arg in fn_sig.inputs.iter() {
all_tys.push(*arg);
}
- for &t in self_ty.iter() {
- all_tys.push(t);
- }
for &t in all_tys.iter() {
debug!("relate_free_regions(t={})", ppaux::ty_to_str(tcx, t));
ast::ExprUnary(callee_id, _, _) |
ast::ExprAssignOp(callee_id, _, _, _) |
ast::ExprIndex(callee_id, _, _) |
- ast::ExprMethodCall(callee_id, _, _, _, _, _) => {
+ ast::ExprMethodCall(callee_id, _, _, _, _) => {
match ty::method_call_type_param_defs(cx.tcx, fcx.inh.method_map, ex.id) {
Some(type_param_defs) => {
debug!("vtable resolution on parameter bounds for method call {}",
use middle::pat_util;
use middle::ty;
use middle::typeck::astconv::AstConv;
-use middle::typeck::check::{FnCtxt, SelfInfo};
+use middle::typeck::check::FnCtxt;
use middle::typeck::infer::{force_all, resolve_all, resolve_region};
use middle::typeck::infer::resolve_type;
use middle::typeck::infer;
use middle::typeck::{vtable_res, vtable_origin};
use middle::typeck::{vtable_static, vtable_param};
-use middle::typeck::method_map_entry;
use middle::typeck::write_substs_to_tcx;
use middle::typeck::write_ty_to_tcx;
use util::ppaux;
})
}
-fn resolve_method_map_entry(fcx: @FnCtxt, sp: Span, id: ast::NodeId) {
+fn resolve_method_map_entry(fcx: @FnCtxt, id: ast::NodeId) {
// Resolve any method map entry
let method_map_entry_opt = {
let method_map = fcx.inh.method_map.borrow();
match method_map_entry_opt {
None => {}
Some(mme) => {
- {
- let r = resolve_type_vars_in_type(fcx, sp, mme.self_ty);
- for t in r.iter() {
- let method_map = fcx.ccx.method_map;
- let new_entry = method_map_entry { self_ty: *t, ..mme };
- debug!("writeback::resolve_method_map_entry(id={:?}, \
- new_entry={:?})",
- id, new_entry);
- let mut method_map = method_map.borrow_mut();
- method_map.get().insert(id, new_entry);
- }
- }
+ debug!("writeback::resolve_method_map_entry(id={:?}, entry={:?})", id, mme);
+ let mut method_map = fcx.ccx.method_map.borrow_mut();
+ method_map.get().insert(id, mme);
}
}
}
resolve_all | force_all) {
Err(e) => {
// This should not, I think, happen:
- fcx.ccx.tcx.sess.span_err(
+ tcx.sess.span_err(
sp,
format!("cannot resolve bound for closure: \
{}",
infer::fixup_err_to_str(e)));
}
Ok(r1) => {
+ // FIXME(eddyb) #2190 Allow only statically resolved
+ // bare functions to coerce to a closure to avoid
+ // constructing (slower) indirect call wrappers.
+ {
+ let def_map = tcx.def_map.borrow();
+ match def_map.get().find(&id) {
+ Some(&ast::DefFn(..)) |
+ Some(&ast::DefStaticMethod(..)) |
+ Some(&ast::DefVariant(..)) |
+ Some(&ast::DefStruct(_)) => {}
+ _ => tcx.sess.span_err(sp,
+ "cannot coerce non-statically resolved bare fn")
+ }
+ }
+
let resolved_adj = @ty::AutoAddEnv(r1, s);
debug!("Adjustments for node {}: {:?}",
id,
resolved_adj);
- let mut adjustments = fcx.tcx()
- .adjustments
+ let mut adjustments = tcx.adjustments
.borrow_mut();
adjustments.get().insert(id, resolved_adj);
}
Ok(r1) => r1,
Err(e) => {
// This should not, I think, happen.
- fcx.ccx.tcx.sess.span_err(
+ tcx.sess.span_err(
sp,
format!("cannot resolve scope of borrow: \
{}",
autoref: resolved_autoref,
});
debug!("Adjustments for node {}: {:?}", id, resolved_adj);
- let mut adjustments = fcx.tcx().adjustments.borrow_mut();
+ let mut adjustments = tcx.adjustments.borrow_mut();
adjustments.get().insert(id, resolved_adj);
}
ty::AutoObject(..) => {
debug!("Adjustments for node {}: {:?}", id, adjustment);
- let mut adjustments = fcx.tcx().adjustments.borrow_mut();
+ let mut adjustments = tcx.adjustments.borrow_mut();
adjustments.get().insert(id, adjustment);
}
}
resolve_type_vars_for_node(wbcx, e.span, e.id);
- resolve_method_map_entry(wbcx.fcx, e.span, e.id);
+ resolve_method_map_entry(wbcx.fcx, e.id);
{
let r = e.get_callee_id();
for callee_id in r.iter() {
- resolve_method_map_entry(wbcx.fcx, e.span, *callee_id);
+ resolve_method_map_entry(wbcx.fcx, *callee_id);
}
}
maybe_resolve_type_vars_for_node(wbcx, e.span, callee_id);
}
- ast::ExprMethodCall(callee_id, _, _, _, _, _) => {
+ ast::ExprMethodCall(callee_id, _, _, _, _) => {
// We must always have written in a callee ID type for these.
resolve_type_vars_for_node(wbcx, e.span, callee_id);
}
return wbcx.success;
}
-pub fn resolve_type_vars_in_fn(fcx: @FnCtxt,
- decl: &ast::FnDecl,
- blk: &ast::Block,
- self_info: Option<SelfInfo>) -> bool {
+pub fn resolve_type_vars_in_fn(fcx: @FnCtxt, decl: &ast::FnDecl,
+ blk: &ast::Block) -> bool {
let mut wbcx = WbCtxt { fcx: fcx, success: true };
let wbcx = &mut wbcx;
wbcx.visit_block(blk, ());
- for self_info in self_info.iter() {
- resolve_type_vars_for_node(wbcx,
- self_info.span,
- self_info.self_id);
- }
for arg in decl.inputs.iter() {
wbcx.visit_pat(arg.pat, ());
// Privacy needs the type for the whole pattern, not just each binding
use middle::ty::{ty_param, ty_param_bounds_and_ty, ty_ptr};
use middle::ty::{ty_rptr, ty_self, ty_struct, ty_trait, ty_tup};
use middle::ty::{ty_type, ty_uint, ty_uniq, ty_bare_fn, ty_closure};
-use middle::ty::{ty_opaque_closure_ptr, ty_unboxed_vec};
-use middle::ty::{type_is_ty_var};
+use middle::ty::{ty_unboxed_vec, type_is_ty_var};
use middle::subst::Subst;
use middle::ty;
use middle::ty::{Impl, Method};
ty_nil | ty_bot | ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) |
ty_str(..) | ty_vec(..) | ty_bare_fn(..) | ty_closure(..) | ty_tup(..) |
ty_infer(..) | ty_param(..) | ty_self(..) | ty_type |
- ty_opaque_closure_ptr(..) | ty_unboxed_vec(..) | ty_err | ty_box(_) |
+ ty_unboxed_vec(..) | ty_err | ty_box(_) |
ty_uniq(_) | ty_ptr(_) | ty_rptr(_, _) => {
debug!("(getting base type) no base type; found {:?}",
get(original_type).sty);
// method types *can* appear in the generic bounds
method.generics.subst(tcx, &combined_substs),
- // method tps cannot appear in the self_ty, so use `substs` from trait ref
- method.transformed_self_ty.subst(tcx, &trait_ref.substs),
-
// method types *can* appear in the fty
method.fty.subst(tcx, &combined_substs),
m_decl: &ast::FnDecl) -> ty::Method
{
let trait_self_ty = ty::mk_self(this.tcx, local_def(trait_id));
- let (transformed_self_ty, fty) =
- astconv::ty_of_method(this, *m_id, *m_purity,
- trait_self_ty, *m_explicit_self, m_decl);
+ let fty = astconv::ty_of_method(this, *m_id, *m_purity, trait_self_ty,
+ *m_explicit_self, m_decl);
let num_trait_type_params = trait_generics.type_param_defs.len();
ty::Method::new(
*m_ident,
// FIXME(#5121) -- distinguish early vs late lifetime params
ty_generics(this, m_generics, num_trait_type_params),
- transformed_self_ty,
fty,
m_explicit_self.node,
// assume public, because this is only invoked on trait methods
rcvr_generics: &ast::Generics,
rcvr_visibility: ast::Visibility) -> ty::Method
{
- let (transformed_self_ty, fty) =
- astconv::ty_of_method(ccx, m.id, m.purity,
- untransformed_rcvr_ty,
- m.explicit_self, m.decl);
+ let fty = astconv::ty_of_method(ccx, m.id, m.purity,
+ untransformed_rcvr_ty,
+ m.explicit_self, m.decl);
// if the method specifies a visibility, use that, otherwise
// inherit the visibility from the impl (so `foo` in `pub impl
m.ident,
// FIXME(#5121) -- distinguish early vs late lifetime params
ty_generics(ccx, &m.generics, num_rcvr_type_params),
- transformed_self_ty,
fty,
m.explicit_self.node,
method_vis,
})))
}
- pub fn coerce_from_bare_fn(&self,
- a: ty::t,
- fn_ty_a: &ty::BareFnTy,
- b: ty::t)
- -> CoerceResult {
- self.unpack_actual_value(b, |sty_b| {
- self.coerce_from_bare_fn_post_unpack(a, fn_ty_a, b, sty_b)
- })
- }
-
- pub fn coerce_from_bare_fn_post_unpack(&self,
- a: ty::t,
- fn_ty_a: &ty::BareFnTy,
- b: ty::t,
- sty_b: &ty::sty)
- -> CoerceResult {
+ fn coerce_from_bare_fn(&self, a: ty::t, fn_ty_a: &ty::BareFnTy, b: ty::t)
+ -> CoerceResult {
/*!
*
* Attempts to coerce from a bare Rust function (`extern
- * "rust" fn`) into a closure.
+ * "Rust" fn`) into a closure or a `proc`.
*/
- debug!("coerce_from_bare_fn(a={}, b={})",
- a.inf_str(self.get_ref().infcx), b.inf_str(self.get_ref().infcx));
+ self.unpack_actual_value(b, |sty_b| {
- if !fn_ty_a.abis.is_rust() || fn_ty_a.purity != ast::ImpureFn {
- return self.subtype(a, b);
- }
+ debug!("coerce_from_bare_fn(a={}, b={})",
+ a.inf_str(self.get_ref().infcx), b.inf_str(self.get_ref().infcx));
- let fn_ty_b = match *sty_b {
- ty::ty_closure(ref f) => (*f).clone(),
- _ => return self.subtype(a, b),
- };
+ if !fn_ty_a.abis.is_rust() || fn_ty_a.purity != ast::ImpureFn {
+ return self.subtype(a, b);
+ }
- let adj = @ty::AutoAddEnv(fn_ty_b.region, fn_ty_b.sigil);
- let a_closure = ty::mk_closure(self.get_ref().infcx.tcx,
- ty::ClosureTy {
- sig: fn_ty_a.sig.clone(),
- ..fn_ty_b
- });
- if_ok!(self.subtype(a_closure, b));
- Ok(Some(adj))
+ let fn_ty_b = match *sty_b {
+ ty::ty_closure(ref f) => (*f).clone(),
+ _ => return self.subtype(a, b)
+ };
+
+ let adj = @ty::AutoAddEnv(fn_ty_b.region, fn_ty_b.sigil);
+ let a_closure = ty::mk_closure(self.get_ref().infcx.tcx,
+ ty::ClosureTy {
+ sig: fn_ty_a.sig.clone(),
+ ..fn_ty_b
+ });
+ if_ok!(self.subtype(a_closure, b));
+ Ok(Some(adj))
+ })
}
pub fn coerce_unsafe_ptr(&self,
use middle::ty;
use middle::ty_fold;
use middle::ty_fold::TypeFolder;
-use middle::typeck::check::regionmanip::{replace_bound_regions_in_fn_sig};
+use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig;
use middle::typeck::infer::coercion::Coerce;
use middle::typeck::infer::combine::{Combine, CombineFields, eq_tys};
use middle::typeck::infer::region_inference::{RegionVarBindings};
-> (ty::FnSig,
HashMap<ty::BoundRegion,
ty::Region>) {
- let (map, _, fn_sig) =
- replace_bound_regions_in_fn_sig(self.tcx, None, fsig, |br| {
+ let (map, fn_sig) =
+ replace_bound_regions_in_fn_sig(self.tcx, fsig, |br| {
let rvar = self.next_region_var(
BoundRegionInFnType(trace.origin.span(), br));
debug!("Bound region {} maps to {:?}",
// Second, we instantiate each bound region in the supertype with a
// fresh concrete region.
- let (skol_map, _, b_sig) = {
- replace_bound_regions_in_fn_sig(self.get_ref().infcx.tcx, None, b, |br| {
+ let (skol_map, b_sig) = {
+ replace_bound_regions_in_fn_sig(self.get_ref().infcx.tcx, b, |br| {
let skol = self.get_ref().infcx.region_vars.new_skolemized(br);
debug!("Bound region {} skolemized to {:?}",
bound_region_to_str(self.get_ref().infcx.tcx, "", false, br),
#[deriving(Clone)]
pub struct method_map_entry {
- // the type of the self parameter, which is not reflected in the fn type
- // (FIXME #3446)
- self_ty: ty::t,
-
- // the type of explicit self on the method
- explicit_self: ast::ExplicitSelf_,
-
// method details being invoked
origin: method_origin,
}
pub fn lookup_def_tcx(tcx: ty::ctxt, sp: Span, id: ast::NodeId) -> ast::Def {
let def_map = tcx.def_map.borrow();
match def_map.get().find(&id) {
- Some(&x) => x,
- _ => {
- tcx.sess.span_fatal(sp, "internal error looking up a definition")
- }
+ Some(&x) => x,
+ _ => {
+ tcx.sess.span_fatal(sp, "internal error looking up a definition")
+ }
}
}
ast::ItemTrait(..) => {
let methods = ty::trait_methods(tcx, did);
for method in methods.iter() {
- match method.transformed_self_ty {
- Some(self_ty) => {
- // The implicit self parameter is basically
- // equivalent to a normal parameter declared
- // like:
- //
- // self : self_ty
- //
- // where self_ty is `&Self` or `&mut Self`
- // or whatever.
- self.add_constraints_from_ty(
- self_ty, self.contravariant);
- }
- None => {}
- }
-
self.add_constraints_from_sig(
&method.fty.sig, self.covariant);
}
self.add_constraints_from_sig(sig, variance);
}
- ty::ty_infer(..) | ty::ty_err | ty::ty_type |
- ty::ty_opaque_closure_ptr(..) | ty::ty_unboxed_vec(..) => {
+ ty::ty_infer(..) | ty::ty_err |
+ ty::ty_type | ty::ty_unboxed_vec(..) => {
self.tcx().sess.bug(
format!("Unexpected type encountered in \
variance inference: {}",
ReEmpty};
use middle::ty::{ty_bool, ty_char, ty_bot, ty_box, ty_struct, ty_enum};
use middle::ty::{ty_err, ty_str, ty_vec, ty_float, ty_bare_fn, ty_closure};
-use middle::ty::{ty_nil, ty_opaque_closure_ptr, ty_param};
-use middle::ty::{ty_ptr, ty_rptr, ty_self, ty_tup, ty_type, ty_uniq};
-use middle::ty::{ty_trait, ty_int};
-use middle::ty::{ty_uint, ty_unboxed_vec, ty_infer};
+use middle::ty::{ty_nil, ty_param, ty_ptr, ty_rptr, ty_self, ty_tup, ty_type};
+use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_unboxed_vec, ty_infer};
use middle::ty;
use middle::typeck;
use syntax::abi::AbiSet;
ty_vec(ref mt, vs) => {
vstore_ty_to_str(cx, mt, vs)
}
- ty_str(vs) => format!("{}{}", vstore_to_str(cx, vs), "str"),
- ty_opaque_closure_ptr(ast::BorrowedSigil) => ~"&closure",
- ty_opaque_closure_ptr(ast::ManagedSigil) => ~"@closure",
- ty_opaque_closure_ptr(ast::OwnedSigil) => ~"~closure",
+ ty_str(vs) => format!("{}{}", vstore_to_str(cx, vs), "str")
}
}
impl Repr for ty::Method {
fn repr(&self, tcx: ctxt) -> ~str {
- format!("method(ident: {}, generics: {}, transformed_self_ty: {}, \
- fty: {}, explicit_self: {}, vis: {}, def_id: {})",
+ format!("method(ident: {}, generics: {}, fty: {}, \
+ explicit_self: {}, vis: {}, def_id: {})",
self.ident.repr(tcx),
self.generics.repr(tcx),
- self.transformed_self_ty.repr(tcx),
self.fty.repr(tcx),
self.explicit_self.repr(tcx),
self.vis.repr(tcx),
impl Repr for typeck::method_map_entry {
fn repr(&self, tcx: ctxt) -> ~str {
- format!("method_map_entry \\{self_arg: {}, \
- explicit_self: {}, \
- origin: {}\\}",
- self.self_ty.repr(tcx),
- self.explicit_self.repr(tcx),
- self.origin.repr(tcx))
+ format!("method_map_entry \\{origin: {}\\}", self.origin.repr(tcx))
}
}
impl Clean<Item> for ast::Method {
fn clean(&self) -> Item {
+ let inputs = match self.explicit_self.node {
+ ast::SelfStatic => self.decl.inputs.as_slice(),
+ _ => self.decl.inputs.slice_from(1)
+ };
+ let decl = FnDecl {
+ inputs: inputs.iter().map(|x| x.clean()).collect(),
+ output: (self.decl.output.clean()),
+ cf: self.decl.cf.clean(),
+ attrs: ~[]
+ };
Item {
name: Some(self.ident.clean()),
attrs: self.attrs.clean(),
generics: self.generics.clean(),
self_: self.explicit_self.clean(),
purity: self.purity.clone(),
- decl: self.decl.clean(),
+ decl: decl,
}),
}
}
impl Clean<Item> for ast::TypeMethod {
fn clean(&self) -> Item {
+ let inputs = match self.explicit_self.node {
+ ast::SelfStatic => self.decl.inputs.as_slice(),
+ _ => self.decl.inputs.slice_from(1)
+ };
+ let decl = FnDecl {
+ inputs: inputs.iter().map(|x| x.clean()).collect(),
+ output: (self.decl.output.clean()),
+ cf: self.decl.cf.clean(),
+ attrs: ~[]
+ };
Item {
name: Some(self.ident.clean()),
attrs: self.attrs.clean(),
visibility: None,
inner: TyMethodItem(TyMethod {
purity: self.purity.clone(),
- decl: self.decl.clean(),
+ decl: decl,
self_: self.explicit_self.clean(),
generics: self.generics.clean(),
}),
fn clean(&self) -> SelfTy {
match self.node {
ast::SelfStatic => SelfStatic,
- ast::SelfValue(_) => SelfValue,
- ast::SelfUniq(_) => SelfOwned,
+ ast::SelfValue => SelfValue,
+ ast::SelfUniq => SelfOwned,
ast::SelfRegion(lt, mt) => SelfBorrowed(lt.clean(), mt.clean()),
ast::SelfBox => SelfManaged,
}
let (def_id, kind) = match *d {
ast::DefFn(i, _) => (i, TypeFunction),
- ast::DefSelf(i, _) | ast::DefSelfTy(i) => return Self(i),
+ ast::DefSelfTy(i) => return Self(i),
ast::DefTy(i) => (i, TypeEnum),
ast::DefTrait(i) => {
debug!("saw DefTrait in def_to_id");
///
/// This currently isn't parallelized, but it'd be pretty easy to add
/// parallelization to this function.
- fn crate(mut self, mut crate: clean::Crate, cache: Cache) {
+ fn crate(self, mut crate: clean::Crate, cache: Cache) {
let mut item = match crate.module.take() {
Some(i) => i,
None => return
}
impl rtio::RtioTcpListener for TcpListener {
- fn listen(mut ~self) -> Result<~rtio::RtioTcpAcceptor, IoError> {
+ fn listen(~self) -> Result<~rtio::RtioTcpAcceptor, IoError> {
// create the acceptor object from ourselves
let mut acceptor = ~TcpAcceptor { listener: self };
}
impl RtioUnixListener for PipeListener {
- fn listen(mut ~self) -> Result<~RtioUnixAcceptor, IoError> {
+ fn listen(~self) -> Result<~RtioUnixAcceptor, IoError> {
// create the acceptor object from ourselves
let mut acceptor = ~PipeAcceptor { listener: self };
/// Unwraps this buffer, returning the underlying writer.
///
/// The internal buffer is flushed before returning the writer.
- pub fn unwrap(mut self) -> W { self.inner.unwrap() }
+ pub fn unwrap(self) -> W { self.inner.unwrap() }
}
impl<W: Writer> Writer for LineBufferedWriter<W> {
true
}
- fn visit_opaque_box(&mut self) -> bool {
- self.align_to::<@u8>();
- if ! self.inner.visit_opaque_box() { return false; }
- self.bump_past::<@u8>();
- true
- }
-
+ // NOTE remove after next snapshot
+ #[cfg(stage0)]
fn visit_closure_ptr(&mut self, ck: uint) -> bool {
self.align_to::<proc()>();
if ! self.inner.visit_closure_ptr(ck) {
fn visit_self(&mut self) -> bool { true }
fn visit_type(&mut self) -> bool { true }
- fn visit_opaque_box(&mut self) -> bool {
- self.writer.write(['@' as u8]);
- self.get::<&raw::Box<()>>(|this, b| {
- let p = ptr::to_unsafe_ptr(&b.data) as *u8;
- this.visit_ptr_inner(p, b.type_desc);
- })
- }
-
+ // NOTE remove after next snapshot
+ #[cfg(stage0)]
fn visit_closure_ptr(&mut self, _ck: uint) -> bool { true }
}
fn visit_param(&mut self, i: uint) -> bool;
fn visit_self(&mut self) -> bool;
fn visit_type(&mut self) -> bool;
- fn visit_opaque_box(&mut self) -> bool;
+
+ // NOTE remove after next snapshot
+ #[cfg(stage0)]
fn visit_closure_ptr(&mut self, ck: uint) -> bool;
}
// The Rust abstract syntax tree.
-use codemap::{Span, Spanned};
+use codemap::{Span, Spanned, DUMMY_SP};
use abi::AbiSet;
+use ast_util;
use opt_vec::OptVec;
-use parse::token::{interner_get, str_to_ident};
+use parse::token::{interner_get, str_to_ident, special_idents};
use std::cell::RefCell;
use std::hashmap::HashMap;
pub enum Def {
DefFn(DefId, Purity),
DefStaticMethod(/* method */ DefId, MethodProvenance, Purity),
- DefSelf(NodeId, bool /* is_mutbl */),
DefSelfTy(/* trait id */ NodeId),
DefMod(DefId),
DefForeignMod(DefId),
pub enum Pat_ {
PatWild,
PatWildMulti,
- // A pat_ident may either be a new bound variable,
+ // A PatIdent may either be a new bound variable,
// or a nullary enum (in which case the second field
// is None).
// In the nullary enum case, the parser can't determine
// set (of "pat_idents that refer to nullary enums")
PatIdent(BindingMode, Path, Option<@Pat>),
PatEnum(Path, Option<~[@Pat]>), /* "none" means a * pattern where
- * we don't bind the fields to names */
+ * we don't bind the fields to names */
PatStruct(Path, ~[FieldPat], bool),
PatTup(~[@Pat]),
PatUniq(@Pat),
PatLit(@Expr),
PatRange(@Expr, @Expr),
// [a, b, ..i, y, z] is represented as
- // pat_vec(~[a, b], Some(i), ~[y, z])
+ // PatVec(~[a, b], Some(i), ~[y, z])
PatVec(~[@Pat], Option<@Pat>, ~[@Pat])
}
impl Expr {
pub fn get_callee_id(&self) -> Option<NodeId> {
match self.node {
- ExprMethodCall(callee_id, _, _, _, _, _) |
+ ExprMethodCall(callee_id, _, _, _, _) |
ExprIndex(callee_id, _, _) |
ExprBinary(callee_id, _, _, _) |
ExprAssignOp(callee_id, _, _, _) |
ExprBox(@Expr, @Expr),
ExprVec(~[@Expr], Mutability),
ExprCall(@Expr, ~[@Expr], CallSugar),
- ExprMethodCall(NodeId, @Expr, Ident, ~[P<Ty>], ~[@Expr], CallSugar),
+ ExprMethodCall(NodeId, Ident, ~[P<Ty>], ~[@Expr], CallSugar),
ExprTup(~[@Expr]),
ExprBinary(NodeId, BinOp, @Expr, @Expr),
ExprUnary(NodeId, UnOp, @Expr),
/// of a function call.
ExprPath(Path),
- /// The special identifier `self`.
- ExprSelf,
ExprAddrOf(Mutability, @Expr),
ExprBreak(Option<Name>),
ExprAgain(Option<Name>),
impl ToStr for IntTy {
fn to_str(&self) -> ~str {
- ::ast_util::int_ty_to_str(*self)
+ ast_util::int_ty_to_str(*self)
}
}
impl ToStr for UintTy {
fn to_str(&self) -> ~str {
- ::ast_util::uint_ty_to_str(*self)
+ ast_util::uint_ty_to_str(*self)
}
}
impl ToStr for FloatTy {
fn to_str(&self) -> ~str {
- ::ast_util::float_ty_to_str(*self)
+ ast_util::float_ty_to_str(*self)
}
}
TyTup(~[P<Ty>]),
TyPath(Path, Option<OptVec<TyParamBound>>, NodeId), // for #7264; see above
TyTypeof(@Expr),
- // ty_infer means the type should be inferred instead of it having been
+ // TyInfer means the type should be inferred instead of it having been
// specified. This should only appear at the "top level" of a type and not
// nested in one.
TyInfer,
id: NodeId,
}
+impl Arg {
+ pub fn new_self(span: Span, mutability: Mutability) -> Arg {
+ let path = ast_util::ident_to_path(span, special_idents::self_);
+ Arg {
+ // HACK(eddyb) fake type for the self argument.
+ ty: P(Ty {
+ id: DUMMY_NODE_ID,
+ node: TyInfer,
+ span: DUMMY_SP,
+ }),
+ pat: @Pat {
+ id: DUMMY_NODE_ID,
+ node: PatIdent(BindByValue(mutability), path, None),
+ span: span
+ },
+ id: DUMMY_NODE_ID
+ }
+ }
+}
+
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub struct FnDecl {
inputs: ~[Arg],
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub enum ExplicitSelf_ {
SelfStatic, // no self
- SelfValue(Mutability), // `self`, `mut self`
+ SelfValue, // `self`
SelfRegion(Option<Lifetime>, Mutability), // `&'lt self`, `&'lt mut self`
SelfBox, // `@self`
- SelfUniq(Mutability) // `~self`, `mut ~self`
+ SelfUniq // `~self`
}
pub type ExplicitSelf = Spanned<ExplicitSelf_>;
body: P<Block>,
id: NodeId,
span: Span,
- self_id: NodeId,
vis: Visibility,
}
use fold::Folder;
use fold;
use parse::token::{get_ident_interner, IdentInterner};
-use parse::token::special_idents;
use print::pprust;
use util::small_vector::SmallVector;
NodeExpr(@Expr),
NodeStmt(@Stmt),
NodeArg(@Pat),
- // HACK(eddyb) should always be a pattern, but `self` is not, and thus it
- // is identified only by an ident and no span is available. In all other
- // cases, node_span will return the proper span (required by borrowck).
- NodeLocal(Ident, Option<@Pat>),
+ NodeLocal(@Pat),
NodeBlock(P<Block>),
/// NodeStructCtor represents a tuple struct.
let mut map = self.map.map.borrow_mut();
map.get().insert(id as uint, node);
}
-
- fn map_self(&self, m: @Method) {
- self.insert(m.self_id, NodeLocal(special_idents::self_, None));
- }
}
impl<F: FoldOps> Folder for Ctx<F> {
let impl_did = ast_util::local_def(i.id);
for &m in ms.iter() {
self.insert(m.id, NodeMethod(m, impl_did, p));
- self.map_self(m);
}
}
}
Provided(m) => {
self.insert(m.id, NodeTraitMethod(@Provided(m), d_id, p));
- self.map_self(m);
}
}
}
fn fold_pat(&mut self, pat: @Pat) -> @Pat {
let pat = fold::noop_fold_pat(pat, self);
match pat.node {
- PatIdent(_, ref path, _) => {
+ PatIdent(..) => {
// Note: this is at least *potentially* a pattern...
- self.insert(pat.id, NodeLocal(ast_util::path_to_ident(path), Some(pat)));
+ self.insert(pat.id, NodeLocal(pat));
}
_ => {}
}
NodeMethod(m, impl_did, @path)
};
cx.insert(m.id, entry);
- cx.map_self(m);
}
}
Some(NodeArg(pat)) => {
format!("arg {} (id={})", pprust::pat_to_str(pat, itr), id)
}
- Some(NodeLocal(ident, _)) => {
- format!("local (id={}, name={})", id, itr.get(ident.name))
+ Some(NodeLocal(pat)) => {
+ format!("local {} (id={})", pprust::pat_to_str(pat, itr), id)
}
Some(NodeBlock(block)) => {
format!("block {} (id={})", pprust::block_to_str(block, itr), id)
Some(NodeVariant(variant, _, _)) => variant.span,
Some(NodeExpr(expr)) => expr.span,
Some(NodeStmt(stmt)) => stmt.span,
- Some(NodeArg(pat)) => pat.span,
- Some(NodeLocal(_, pat)) => match pat {
- Some(pat) => pat.span,
- None => fail!("node_span: cannot get span from NodeLocal (likely `self`)")
- },
+ Some(NodeArg(pat)) | Some(NodeLocal(pat)) => pat.span,
Some(NodeBlock(block)) => block.span,
Some(NodeStructCtor(_, item, _)) => item.span,
Some(NodeCalleeScope(expr)) => expr.span,
pub fn def_id_of_def(d: Def) -> DefId {
match d {
- DefFn(id, _) | DefStaticMethod(id, _, _) | DefMod(id) |
- DefForeignMod(id) | DefStatic(id, _) |
- DefVariant(_, id, _) | DefTy(id) | DefTyParam(id, _) |
- DefUse(id) | DefStruct(id) | DefTrait(id) | DefMethod(id, _) => {
- id
- }
- DefArg(id, _) | DefLocal(id, _) | DefSelf(id, _) | DefSelfTy(id)
- | DefUpvar(id, _, _, _) | DefBinding(id, _) | DefRegion(id)
- | DefTyParamBinder(id) | DefLabel(id) => {
- local_def(id)
- }
+ DefFn(id, _) | DefStaticMethod(id, _, _) | DefMod(id) |
+ DefForeignMod(id) | DefStatic(id, _) |
+ DefVariant(_, id, _) | DefTy(id) | DefTyParam(id, _) |
+ DefUse(id) | DefStruct(id) | DefTrait(id) | DefMethod(id, _) => {
+ id
+ }
+ DefArg(id, _) | DefLocal(id, _) | DefSelfTy(id)
+ | DefUpvar(id, _, _, _) | DefBinding(id, _) | DefRegion(id)
+ | DefTyParamBinder(id) | DefLabel(id) => {
+ local_def(id)
+ }
- DefPrimTy(_) => fail!()
+ DefPrimTy(_) => fail!()
}
}
}
}
-/* True if d is either a def_self, or a chain of def_upvars
- referring to a def_self */
-pub fn is_self(d: ast::Def) -> bool {
- match d {
- DefSelf(..) => true,
- DefUpvar(_, d, _, _) => is_self(*d),
- _ => false
- }
-}
-
/// Maps a binary operator to its precedence
pub fn operator_prec(op: ast::BinOp) -> uint {
match op {
self.operation.visit_id(node_id);
match *function_kind {
- visit::FkItemFn(_, generics, _, _) => {
- self.visit_generics_helper(generics)
- }
- visit::FkMethod(_, generics, method) => {
- self.operation.visit_id(method.self_id);
+ visit::FkItemFn(_, generics, _, _) |
+ visit::FkMethod(_, generics, _) => {
self.visit_generics_helper(generics)
}
visit::FkFnBlock => {}
use fold::Folder;
use opt_vec;
use opt_vec::OptVec;
+use parse::token::special_idents;
pub struct Field {
ident: ast::Ident,
self.expr_path(self.path_ident(span, id))
}
fn expr_self(&self, span: Span) -> @ast::Expr {
- self.expr(span, ast::ExprSelf)
+ self.expr_ident(span, special_idents::self_)
}
fn expr_binary(&self, sp: Span, op: ast::BinOp,
fn expr_method_call(&self, span: Span,
expr: @ast::Expr,
ident: ast::Ident,
- args: ~[@ast::Expr]) -> @ast::Expr {
- self.expr(span,
- ast::ExprMethodCall(ast::DUMMY_NODE_ID, expr, ident, ~[], args, ast::NoSugar))
+ mut args: ~[@ast::Expr]) -> @ast::Expr {
+ args.unshift(expr);
+ self.expr(span, ast::ExprMethodCall(ast::DUMMY_NODE_ID, ident, ~[], args, ast::NoSugar))
}
fn expr_block(&self, b: P<ast::Block>) -> @ast::Expr {
self.expr(b.span, ast::ExprBlock(b))
// create the generics that aren't for Self
let fn_generics = self.generics.to_generics(trait_.cx, trait_.span, type_ident, generics);
+ let self_arg = match explicit_self.node {
+ ast::SelfStatic => None,
+ _ => Some(ast::Arg::new_self(trait_.span, ast::MutImmutable))
+ };
let args = arg_types.move_iter().map(|(name, ty)| {
trait_.cx.arg(trait_.span, name, ty)
- }).collect();
+ });
+ let args = self_arg.move_iter().chain(args).collect();
let ret_type = self.get_ret_ty(trait_, generics, type_ident);
body: body_block,
id: ast::DUMMY_NODE_ID,
span: trait_.span,
- self_id: ast::DUMMY_NODE_ID,
vis: ast::Inherited,
}
}
let self_path = cx.expr_self(span);
match *self_ptr {
None => {
- (self_path, respan(span, ast::SelfValue(ast::MutImmutable)))
+ (self_path, respan(span, ast::SelfValue))
}
Some(ref ptr) => {
let self_ty = respan(
span,
match *ptr {
- Send => ast::SelfUniq(ast::MutImmutable),
+ Send => ast::SelfUniq,
Managed => ast::SelfBox,
Borrowed(ref lt, mutbl) => {
let lt = lt.map(|s| cx.lifetime(span, cx.ident_of(s)));
fn fold_explicit_self_(&mut self, es: &ExplicitSelf_) -> ExplicitSelf_ {
match *es {
- SelfStatic | SelfValue(_) | SelfUniq(_) | SelfBox => {
- *es
- }
+ SelfStatic | SelfValue | SelfUniq | SelfBox => *es,
SelfRegion(ref lifetime, m) => {
SelfRegion(fold_opt_lifetime(lifetime, self), m)
}
body: folder.fold_block(m.body),
id: folder.new_id(m.id),
span: folder.new_span(m.span),
- self_id: folder.new_id(m.self_id),
vis: m.vis
}
}
args.map(|&x| folder.fold_expr(x)),
blk)
}
- ExprMethodCall(callee_id, f, i, ref tps, ref args, blk) => {
+ ExprMethodCall(callee_id, i, ref tps, ref args, blk) => {
ExprMethodCall(
folder.new_id(callee_id),
- folder.fold_expr(f),
folder.fold_ident(i),
tps.map(|&x| folder.fold_ty(x)),
args.map(|&x| folder.fold_expr(x)),
folder.fold_expr(er))
}
ExprPath(ref pth) => ExprPath(folder.fold_path(pth)),
- ExprSelf => ExprSelf,
ExprLogLevel => ExprLogLevel,
ExprBreak(opt_ident) => ExprBreak(opt_ident),
ExprAgain(opt_ident) => ExprAgain(opt_ident),
| ast::ExprForLoop(..)
| ast::ExprCall(_, _, ast::DoSugar)
| ast::ExprCall(_, _, ast::ForSugar)
- | ast::ExprMethodCall(_, _, _, _, _, ast::DoSugar)
- | ast::ExprMethodCall(_, _, _, _, _, ast::ForSugar) => false,
+ | ast::ExprMethodCall(_, _, _, _, ast::DoSugar)
+ | ast::ExprMethodCall(_, _, _, _, ast::ForSugar) => false,
_ => true
}
}
use ast::{ExprBreak, ExprCall, ExprCast, ExprDoBody};
use ast::{ExprField, ExprFnBlock, ExprIf, ExprIndex};
use ast::{ExprLit, ExprLogLevel, ExprLoop, ExprMac};
-use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc, ExprRepeat};
-use ast::{ExprRet, ExprSelf, ExprStruct, ExprTup, ExprUnary};
+use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc};
+use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary};
use ast::{ExprVec, ExprVstore, ExprVstoreSlice, ExprVstoreBox};
use ast::{ExprVstoreMutSlice, ExprWhile, ExprForLoop, ExternFn, Field, FnDecl};
use ast::{ExprVstoreUniq, Onceness, Once, Many};
body: body,
id: ast::DUMMY_NODE_ID,
span: mk_sp(lo, hi),
- self_id: ast::DUMMY_NODE_ID,
vis: vis,
})
}
ExprCall(f, args, sugar)
}
- pub fn mk_method_call(&mut self,
- rcvr: @Expr,
- ident: Ident,
- tps: ~[P<Ty>],
- args: ~[@Expr],
+ fn mk_method_call(&mut self, ident: Ident, tps: ~[P<Ty>], args: ~[@Expr],
sugar: CallSugar) -> ast::Expr_ {
- ExprMethodCall(ast::DUMMY_NODE_ID, rcvr, ident, tps, args, sugar)
+ ExprMethodCall(ast::DUMMY_NODE_ID, ident, tps, args, sugar)
}
pub fn mk_index(&mut self, expr: @Expr, idx: @Expr) -> ast::Expr_ {
return self.mk_expr(lo, body.span.hi, ExprProc(decl, fakeblock));
} else if self.eat_keyword(keywords::Self) {
- ex = ExprSelf;
+ let path = ast_util::ident_to_path(mk_sp(lo, hi), special_idents::self_);
+ ex = ExprPath(path);
hi = self.span.hi;
} else if self.eat_keyword(keywords::If) {
return self.parse_if_expr();
// expr.f() method call
match self.token {
token::LPAREN => {
- let es = self.parse_unspanned_seq(
+ let mut es = self.parse_unspanned_seq(
&token::LPAREN,
&token::RPAREN,
seq_sep_trailing_disallowed(token::COMMA),
);
hi = self.span.hi;
- let nd = self.mk_method_call(e, i, tys, es, NoSugar);
+ es.unshift(e);
+ let nd = self.mk_method_call(i, tys, es, NoSugar);
e = self.mk_expr(lo, hi, nd);
}
_ => {
let block = self.parse_lambda_block_expr();
let last_arg = self.mk_expr(block.span.lo, block.span.hi,
ctor(block));
- let args = vec::append((*args).clone(), [last_arg]);
+ let args = vec::append_one((*args).clone(), last_arg);
self.mk_expr(lo, block.span.hi, ExprCall(f, args, sugar))
}
- ExprMethodCall(_, f, i, ref tps, ref args, NoSugar) => {
+ ExprMethodCall(_, i, ref tps, ref args, NoSugar) => {
let block = self.parse_lambda_block_expr();
let last_arg = self.mk_expr(block.span.lo, block.span.hi,
ctor(block));
- let args = vec::append((*args).clone(), [last_arg]);
- let method_call = self.mk_method_call(f,
- i,
+ let args = vec::append_one((*args).clone(), last_arg);
+ let method_call = self.mk_method_call(i,
(*tps).clone(),
args,
sugar);
let block = self.parse_lambda_block_expr();
let last_arg = self.mk_expr(block.span.lo, block.span.hi,
ctor(block));
- let method_call = self.mk_method_call(f,
- i,
+ let method_call = self.mk_method_call(i,
(*tps).clone(),
- ~[last_arg],
+ ~[f, last_arg],
sugar);
self.mk_expr(lo, block.span.hi, method_call)
}
// A bit of complexity and lookahead is needed here in order to be
// backwards compatible.
let lo = self.span.lo;
+ let mut mutbl_self = MutImmutable;
let explicit_self = match self.token {
token::BINOP(token::AND) => {
maybe_parse_borrowed_explicit_self(self)
maybe_parse_explicit_self(SelfBox, self)
}
token::TILDE => {
- maybe_parse_explicit_self(SelfUniq(MutImmutable), self)
+ maybe_parse_explicit_self(SelfUniq, self)
}
token::IDENT(..) if self.is_self_ident() => {
self.bump();
- SelfValue(MutImmutable)
+ SelfValue
}
token::BINOP(token::STAR) => {
// Possibly "*self" or "*mut self" -- not supported. Try to avoid
// emitting cryptic "unexpected token" errors.
self.bump();
- let mutability = if Parser::token_is_mutability(&self.token) {
+ let _mutability = if Parser::token_is_mutability(&self.token) {
self.parse_mutability()
} else { MutImmutable };
if self.is_self_ident() {
self.span_err(self.span, "cannot pass self by unsafe pointer");
self.bump();
}
- SelfValue(mutability)
+ SelfValue
}
_ if Parser::token_is_mutability(&self.token) &&
self.look_ahead(1, |t| token::is_keyword(keywords::Self, t)) => {
- let mutability = self.parse_mutability();
+ mutbl_self = self.parse_mutability();
self.expect_self_ident();
- SelfValue(mutability)
+ SelfValue
}
_ if Parser::token_is_mutability(&self.token) &&
self.look_ahead(1, |t| *t == token::TILDE) &&
self.look_ahead(2, |t| token::is_keyword(keywords::Self, t)) => {
- let mutability = self.parse_mutability();
+ mutbl_self = self.parse_mutability();
self.bump();
self.expect_self_ident();
- SelfUniq(mutability)
+ SelfUniq
}
_ => SelfStatic
};
+ let explicit_self_sp = mk_sp(lo, self.span.hi);
+
// If we parsed a self type, expect a comma before the argument list.
- let fn_inputs;
- if explicit_self != SelfStatic {
+ let fn_inputs = if explicit_self != SelfStatic {
match self.token {
token::COMMA => {
self.bump();
let sep = seq_sep_trailing_disallowed(token::COMMA);
- fn_inputs = self.parse_seq_to_before_end(
+ let mut fn_inputs = self.parse_seq_to_before_end(
&token::RPAREN,
sep,
parse_arg_fn
);
+ fn_inputs.unshift(Arg::new_self(explicit_self_sp, mutbl_self));
+ fn_inputs
}
token::RPAREN => {
- fn_inputs = ~[];
+ ~[Arg::new_self(explicit_self_sp, mutbl_self)]
}
_ => {
let token_str = self.this_token_to_str();
}
} else {
let sep = seq_sep_trailing_disallowed(token::COMMA);
- fn_inputs = self.parse_seq_to_before_end(&token::RPAREN,
- sep,
- parse_arg_fn);
- }
+ self.parse_seq_to_before_end(&token::RPAREN, sep, parse_arg_fn)
+ };
self.expect(&token::RPAREN);
body: body,
id: ast::DUMMY_NODE_ID,
span: mk_sp(lo, hi),
- self_id: ast::DUMMY_NODE_ID,
vis: visa,
}
}
print_expr(s, func);
print_call_post(s, sugar, &blk, &mut base_args);
}
- ast::ExprMethodCall(_, func, ident, ref tys, ref args, sugar) => {
- let mut base_args = (*args).clone();
+ ast::ExprMethodCall(_, ident, ref tys, ref args, sugar) => {
+ let mut base_args = args.slice_from(1).to_owned();
let blk = print_call_pre(s, sugar, &mut base_args);
- print_expr(s, func);
+ print_expr(s, args[0]);
word(&mut s.s, ".");
print_ident(s, ident);
if tys.len() > 0u {
word(&mut s.s, "]");
}
ast::ExprPath(ref path) => print_path(s, path, true),
- ast::ExprSelf => word(&mut s.s, "self"),
ast::ExprBreak(opt_ident) => {
word(&mut s.s, "break");
space(&mut s.s);
}
pub fn explicit_self_to_str(explicit_self: &ast::ExplicitSelf_, intr: @IdentInterner) -> ~str {
- to_str(explicit_self, |a, &b| { print_explicit_self(a, b); () }, intr)
+ to_str(explicit_self, |a, &b| { print_explicit_self(a, b, ast::MutImmutable); () }, intr)
}
// Returns whether it printed anything
-pub fn print_explicit_self(s: &mut State, explicit_self: ast::ExplicitSelf_) -> bool {
+fn print_explicit_self(s: &mut State,
+ explicit_self: ast::ExplicitSelf_,
+ mutbl: ast::Mutability) -> bool {
+ print_mutability(s, mutbl);
match explicit_self {
ast::SelfStatic => { return false; }
- ast::SelfValue(m) => {
- print_mutability(s, m);
+ ast::SelfValue => {
word(&mut s.s, "self");
}
- ast::SelfUniq(m) => {
- print_mutability(s, m);
+ ast::SelfUniq => {
word(&mut s.s, "~self");
}
ast::SelfRegion(ref lt, m) => {
// self type and the args all in the same box.
rbox(s, 0u, Inconsistent);
let mut first = true;
- for explicit_self in opt_explicit_self.iter() {
- first = !print_explicit_self(s, *explicit_self);
+ for &explicit_self in opt_explicit_self.iter() {
+ let m = match explicit_self {
+ ast::SelfStatic => ast::MutImmutable,
+ _ => match decl.inputs[0].pat.node {
+ ast::PatIdent(ast::BindByValue(m), _, _) => m,
+ _ => ast::MutImmutable
+ }
+ };
+ first = !print_explicit_self(s, explicit_self, m);
}
- for arg in decl.inputs.iter() {
+ // HACK(eddyb) ignore the separately printed self argument.
+ let args = if first {
+ decl.inputs.as_slice()
+ } else {
+ decl.inputs.slice_from(1)
+ };
+
+ for arg in args.iter() {
if first { first = false; } else { word_space(s, ","); }
print_arg(s, arg);
}
popen(s);
}
- // It is unfortunate to duplicate the commasep logic, but we want the
- // self type and the args all in the same box.
- rbox(s, 0u, Inconsistent);
- let mut first = true;
- for explicit_self in opt_explicit_self.iter() {
- first = !print_explicit_self(s, *explicit_self);
- }
- for arg in decl.inputs.iter() {
- if first { first = false; } else { word_space(s, ","); }
- print_arg(s, arg);
- }
- end(s);
+ print_fn_args(s, decl, opt_explicit_self);
if opt_sigil == Some(ast::BorrowedSigil) {
word(&mut s.s, "|");
explicit_self: &ExplicitSelf,
env: E) {
match explicit_self.node {
- SelfStatic | SelfValue(_) | SelfBox | SelfUniq(_) => {}
+ SelfStatic | SelfValue | SelfBox | SelfUniq => {}
SelfRegion(ref lifetime, _) => {
visitor.visit_opt_lifetime_ref(explicit_self.span, lifetime, env)
}
}
visitor.visit_expr(callee_expression, env.clone())
}
- ExprMethodCall(_, callee, _, ref types, ref arguments, _) => {
+ ExprMethodCall(_, _, ref types, ref arguments, _) => {
walk_exprs(visitor, *arguments, env.clone());
for &typ in types.iter() {
visitor.visit_ty(typ, env.clone())
}
- visitor.visit_expr(callee, env.clone())
}
ExprBinary(_, _, left_expression, right_expression) => {
visitor.visit_expr(left_expression, env.clone());
ExprPath(ref path) => {
visitor.visit_path(path, expression.id, env.clone())
}
- ExprSelf | ExprBreak(_) | ExprAgain(_) => {}
+ ExprBreak(_) | ExprAgain(_) => {}
ExprRet(optional_expression) => {
walk_expr_opt(visitor, optional_expression, env.clone())
}
--- /dev/null
+// 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.
+
+fn foo() {}
+
+fn main() {
+ let f = foo;
+ let f_closure: || = f;
+ //~^ ERROR: cannot coerce non-statically resolved bare fn
+ let f_proc: proc() = f;
+ //~^ ERROR: cannot coerce non-statically resolved bare fn
+}
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
struct A;
impl A {
fn m(&self) {
- fn x() {
- self.m()
- //~^ ERROR can't capture dynamic environment in a fn item
- //~^^ ERROR `self` is not allowed in this context
- }
+ fn x() {
+ self.m() //~ ERROR can't capture dynamic environment in a fn item
+ //~^ ERROR unresolved name `self`
+ }
}
}
fn main() {}
--- /dev/null
+// 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.
+
+#[allow(dead_assignment)];
+#[allow(unused_variable)];
+#[allow(dead_code)];
+#[deny(unused_mut)];
+
+struct Foo;
+impl Foo {
+ fn foo(mut self) {} //~ ERROR: variable does not need to be mutable
+ fn bar(mut ~self) {} //~ ERROR: variable does not need to be mutable
+}
+
+fn main() {}
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
}
impl foo for int {
fn bar(&self) -> int {
- //~^ ERROR method `bar` has 0 parameters but the declaration in trait `foo::bar` has 1
+ //~^ ERROR method `bar` has 1 parameter but the declaration in trait `foo::bar` has 2
*self
}
}
--- /dev/null
+// 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.
+
+fn id<T>(x: T) -> T {
+ x
+}
+
+#[deriving(Eq)]
+struct Foo<T>(T);
+
+#[deriving(Eq)]
+enum Bar<T> {
+ Bar(T)
+}
+
+pub fn main() {
+ let f: |int| -> int = id;
+ assert_eq!(f(5), 5);
+
+ let f: proc(int) -> int = id;
+ assert_eq!(f(5), 5);
+
+ let f: |int| -> Foo<int> = Foo;
+ assert_eq!(f(5), Foo(5));
+
+ let f: proc(int) -> Foo<int> = Foo;
+ assert_eq!(f(5), Foo(5));
+
+ let f: |int| -> Bar<int> = Bar;
+ assert_eq!(f(5), Bar(5));
+
+ let f: proc(int) -> Bar<int> = Bar;
+ assert_eq!(f(5), Bar(5));
+
+ let f: |int| -> Option<int> = Some;
+ assert_eq!(f(5), Some(5));
+
+ let f: proc(int) -> Option<int> = Some;
+ assert_eq!(f(5), Some(5));
+}
fn test_fn() {
type t = 'static || -> int;
fn ten() -> int { return 10; }
- let rs: t = { ten };
+ let rs: t = ten;
assert!((rs() == 10));
}
if ! self.inner().visit_type() { return false; }
true
}
-
- fn visit_opaque_box(&mut self) -> bool {
- self.align_to::<@u8>();
- if ! self.inner().visit_opaque_box() { return false; }
- self.bump_past::<@u8>();
- true
- }
-
- fn visit_closure_ptr(&mut self, ck: uint) -> bool {
- self.align_to::<(uint,uint)>();
- if ! self.inner().visit_closure_ptr(ck) { return false; }
- self.bump_past::<(uint,uint)>();
- true
- }
}
struct my_visitor(@RefCell<Stuff>);
fn visit_param(&mut self, _i: uint) -> bool { true }
fn visit_self(&mut self) -> bool { true }
fn visit_type(&mut self) -> bool { true }
- fn visit_opaque_box(&mut self) -> bool { true }
- fn visit_closure_ptr(&mut self, _ck: uint) -> bool { true }
}
fn get_tydesc_for<T>(_t: T) -> *TyDesc {
fn visit_param(&mut self, _i: uint) -> bool { true }
fn visit_self(&mut self) -> bool { true }
fn visit_type(&mut self) -> bool { true }
- fn visit_opaque_box(&mut self) -> bool { true }
- fn visit_closure_ptr(&mut self, _ck: uint) -> bool { true }
}
fn visit_ty<T>(v: &mut MyVisitor) {