Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Translate tuple struct constructors #3856

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/libsyntax/ast_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ enum ast_node {
// Destructor for a class
node_dtor(~[ty_param], @class_dtor, def_id, @path),
node_block(blk),
node_struct_ctor(@struct_def, @item, @path)
node_struct_ctor(@struct_def, @item, @path),
}

type map = std::map::HashMap<node_id, ast_node>;
Expand Down
43 changes: 42 additions & 1 deletion src/rustc/middle/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ use util::ppaux;
use util::ppaux::{ty_to_str, ty_to_short_str};
use syntax::diagnostic::expect;
use util::common::indenter;
use ty::DerivedMethodInfo;

use build::*;
use shape::*;
Expand Down Expand Up @@ -1843,7 +1844,7 @@ fn trans_item(ccx: @crate_ctxt, item: ast::item) {
match ms_opt {
None => {
deriving::trans_deriving_impl(ccx, *path, item.ident, tps,
None, item.id);
item.id);
}
Some(ms) => {
meth::trans_impl(ccx, *path, item.ident, ms, tps, None,
Expand Down Expand Up @@ -2079,6 +2080,20 @@ fn get_item_val(ccx: @crate_ctxt, id: ast::node_id) -> ValueRef {
match ccx.item_vals.find(id) {
Some(v) => v,
None => {
// First, check whether we need to automatically generate a method
// via the deriving mechanism.
match ccx.tcx.automatically_derived_methods.find(local_def(id)) {
None => {} // Continue.
Some(ref derived_method_info) => {
// XXX: Mark as internal if necessary.
let llfn = register_deriving_method(
ccx, id, derived_method_info);
ccx.item_vals.insert(id, llfn);
return llfn;
}
}

// Failing that, look for an item.
let mut exprt = false;
let val = match ccx.tcx.items.get(id) {
ast_map::node_item(i, pth) => {
Expand Down Expand Up @@ -2226,6 +2241,32 @@ fn register_method(ccx: @crate_ctxt, id: ast::node_id, pth: @ast_map::path,
llfn
}

fn register_deriving_method(ccx: @crate_ctxt,
id: ast::node_id,
derived_method_info: &DerivedMethodInfo) ->
ValueRef {
// Find the path of the item.
let path, span;
match ccx.tcx.items.get(derived_method_info.containing_impl.node) {
ast_map::node_item(item, found_path) => {
path = found_path;
span = item.span;
}
_ => {
ccx.tcx.sess.bug(~"derived method info containing impl didn't \
refer to an item");
}
}

let path = vec::append(*path, ~[
ast_map::path_name(derived_method_info.method_info.ident)
]);
let mty = ty::lookup_item_type(ccx.tcx, local_def(id)).ty;
let llfn = register_fn_full(ccx, span, path, id, mty);
// XXX: Inline hint.
llfn
}

// The constant translation pass.
fn trans_constant(ccx: @crate_ctxt, it: @ast::item) {
let _icx = ccx.insn_ctxt("trans_constant");
Expand Down
46 changes: 31 additions & 15 deletions src/rustc/middle/trans/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,23 +210,30 @@ fn trans_fn_ref_with_vtables(
// intrinsic, or is a default method. In particular, if we see an
// intrinsic that is inlined from a different crate, we want to reemit the
// intrinsic instead of trying to call it in the other crate.
let must_monomorphise = type_params.len() > 0 ||
opt_impl_did.is_some() || {
if def_id.crate == ast::local_crate {
let map_node = session::expect(
ccx.sess,
ccx.tcx.items.find(def_id.node),
|| fmt!("local item should be in ast map"));

match map_node {
ast_map::node_foreign_item(
_, ast::foreign_abi_rust_intrinsic, _) => true,
_ => false
let must_monomorphise;
if type_params.len() > 0 || opt_impl_did.is_some() {
must_monomorphise = true;
} else if ccx.tcx.automatically_derived_methods.contains_key(def_id) {
must_monomorphise = false;
} else if def_id.crate == ast::local_crate {
let map_node = session::expect(
ccx.sess,
ccx.tcx.items.find(def_id.node),
|| fmt!("local item should be in ast map"));

match map_node {
ast_map::node_foreign_item(_,
ast::foreign_abi_rust_intrinsic,
_) => {
must_monomorphise = true;
}
_ => {
must_monomorphise = false;
}
} else {
false
}
};
} else {
must_monomorphise = false;
}

// Create a monomorphic verison of generic functions
if must_monomorphise {
Expand Down Expand Up @@ -434,6 +441,15 @@ fn trans_call_inner(
_ => {}
}

// Uncomment this to debug calls.
/*
io::println(fmt!("calling: %s", bcx.val_str(llfn)));
for llargs.each |llarg| {
io::println(fmt!("arg: %s", bcx.val_str(*llarg)));
}
io::println("---");
*/

// If the block is terminated, then one or more of the args
// has type _|_. Since that means it diverges, the code for
// the call itself is unreachable.
Expand Down
117 changes: 111 additions & 6 deletions src/rustc/middle/trans/deriving.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,126 @@
// Translation of automatically-derived trait implementations. This handles
// enums and structs only; other types cannot be automatically derived.

use middle::trans::base::get_insn_ctxt;
use middle::trans::common::crate_ctxt;
use syntax::ast::{ident, node_id, ty_param};
use lib::llvm::llvm;
use middle::trans::base::{finish_fn, get_insn_ctxt, get_item_val};
use middle::trans::base::{new_fn_ctxt, sub_block, top_scope_block};
use middle::trans::build::{Br, CondBr, GEPi, Load, PointerCast, Store};
use middle::trans::build::{ValueRef};
use middle::trans::callee;
use middle::trans::callee::{ArgVals, Callee, DontAutorefArg, Method};
use middle::trans::callee::{MethodData};
use middle::trans::common;
use middle::trans::common::{C_bool, T_ptr, block, crate_ctxt};
use middle::trans::expr::SaveIn;
use middle::trans::type_of::type_of;
use middle::typeck::method_static;
use syntax::ast;
use syntax::ast::{def_id, ident, node_id, ty_param};
use syntax::ast_map::path;
use syntax::ast_util;
use syntax::ast_util::local_def;

/// The main "translation" pass for automatically-derived impls. Generates
/// code for monomorphic methods only. Other methods will be generated when
/// they are invoked with specific type parameters; see
/// `trans::base::lval_static_fn()` or `trans::base::monomorphic_fn()`.
pub fn trans_deriving_impl(ccx: @crate_ctxt, _path: path, _name: ident,
tps: ~[ty_param], _self_ty: Option<ty::t>,
_id: node_id) {
tps: ~[ty_param], id: node_id) {
let _icx = ccx.insn_ctxt("deriving::trans_deriving_impl");
if tps.len() > 0 { return; }

// XXX: Unimplemented.
let impl_def_id = local_def(id);
let self_ty = ty::lookup_item_type(ccx.tcx, impl_def_id);
let method_dids = ccx.tcx.automatically_derived_methods_for_impl.get(
impl_def_id);

for method_dids.each |method_did| {
let llfn = get_item_val(ccx, method_did.node);
match ty::get(self_ty.ty).sty {
ty::ty_class(*) => {
trans_deriving_struct_method(ccx, llfn, impl_def_id,
self_ty.ty);
}
_ => {
ccx.tcx.sess.unimpl(~"translation of non-struct deriving \
method");
}
}
}
}

fn trans_deriving_struct_method(ccx: @crate_ctxt, llfn: ValueRef,
impl_did: def_id, self_ty: ty::t) {
let _icx = ccx.insn_ctxt("trans_deriving_struct_method");
let fcx = new_fn_ctxt(ccx, ~[], llfn, None);
let top_bcx = top_scope_block(fcx, None);
let lltop = top_bcx.llbb;
let mut bcx = top_bcx;

let llselfty = type_of(ccx, self_ty);
let llselfval = PointerCast(bcx, fcx.llenv, T_ptr(llselfty));
let llotherval = llvm::LLVMGetParam(llfn, 2);

let struct_field_tys;
match ty::get(self_ty).sty {
ty::ty_class(struct_id, ref struct_substs) => {
struct_field_tys = ty::class_items_as_fields(
ccx.tcx, struct_id, struct_substs);
}
_ => {
ccx.tcx.sess.bug(~"passed non-struct to \
trans_deriving_struct_method");
}
}

// Iterate over every element of the struct.
for ccx.tcx.deriving_struct_methods.get(impl_did).eachi
|i, derived_method_info| {
let target_method_def_id;
match *derived_method_info {
method_static(did) => target_method_def_id = did,
_ => fail ~"derived method didn't resolve to a static method"
}

let fn_expr_ty =
ty::lookup_item_type(ccx.tcx, target_method_def_id).ty;

let llselfval = GEPi(bcx, llselfval, [0, 0, i]);
let llotherval = GEPi(bcx, llotherval, [0, 0, i]);

// XXX: Cross-crate won't work!
let llfn = get_item_val(ccx, target_method_def_id.node);
let cb: &fn(block) -> Callee = |block| {
Callee {
bcx: block,
data: Method(MethodData {
llfn: llfn,
llself: llselfval,
self_ty: struct_field_tys[i].mt.ty,
self_mode: ast::by_copy
})
}
};

bcx = callee::trans_call_inner(bcx,
None,
fn_expr_ty,
ty::mk_bool(ccx.tcx),
cb,
ArgVals(~[llotherval]),
SaveIn(fcx.llretptr),
DontAutorefArg);

// Return immediately if the call returned false.
let next_block = sub_block(top_bcx, ~"next");
let llcond = Load(bcx, fcx.llretptr);
CondBr(bcx, llcond, next_block.llbb, fcx.llreturn);
bcx = next_block;
}

Store(bcx, C_bool(true), fcx.llretptr);
Br(bcx, fcx.llreturn);

finish_fn(fcx, lltop);
}

22 changes: 20 additions & 2 deletions src/rustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ export provided_trait_methods;
export trait_supertraits;
export AutoAdjustment;
export AutoRef, AutoRefKind, AutoSlice, AutoPtr;
export DerivedMethodInfo;

// Data types

Expand Down Expand Up @@ -333,6 +334,11 @@ struct InstantiatedTraitRef {
tpt: ty_param_substs_and_ty
}

struct DerivedMethodInfo {
method_info: @middle::resolve::MethodInfo,
containing_impl: ast::def_id
}

type ctxt =
@{diag: syntax::diagnostic::span_handler,
interner: HashMap<intern_key, t_box>,
Expand Down Expand Up @@ -379,7 +385,17 @@ type ctxt =
provided_method_sources: HashMap<ast::def_id, ProvidedMethodSource>,
supertraits: HashMap<ast::def_id, @~[InstantiatedTraitRef]>,
deriving_struct_methods: HashMap<ast::def_id,
@~[typeck::method_origin]>};
@~[typeck::method_origin]>,

// A mapping from the def ID of a method that was automatically derived
// to information about it.
automatically_derived_methods: HashMap<ast::def_id, DerivedMethodInfo>,

// A mapping from the def ID of an impl to the IDs of the derived
// methods within it.
automatically_derived_methods_for_impl:
HashMap<ast::def_id, @~[ast::def_id]>
};

enum tbox_flag {
has_params = 1,
Expand Down Expand Up @@ -942,7 +958,9 @@ fn mk_ctxt(s: session::Session,
legacy_boxed_traits: HashMap(),
provided_method_sources: HashMap(),
supertraits: HashMap(),
deriving_struct_methods: HashMap()}
deriving_struct_methods: HashMap(),
automatically_derived_methods: HashMap(),
automatically_derived_methods_for_impl: HashMap()}
}


Expand Down
37 changes: 29 additions & 8 deletions src/rustc/middle/typeck/coherence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ use metadata::csearch::{get_impls_for_mod};
use metadata::cstore::{CStore, iter_crate_data};
use metadata::decoder::{dl_def, dl_field, dl_impl};
use middle::resolve::{Impl, MethodInfo};
use middle::ty::{ProvidedMethodSource, get, lookup_item_type, subst, t};
use middle::ty::{ty_box, ty_uniq, ty_ptr, ty_rptr, ty_enum};
use middle::ty::{ty_class, ty_nil, ty_bot, ty_bool, ty_int, ty_uint};
use middle::ty::{ty_float, ty_estr, ty_evec, ty_rec};
use middle::ty::{DerivedMethodInfo, ProvidedMethodSource, get};
use middle::ty::{lookup_item_type, subst, t, ty_bot, ty_box, ty_class};
use middle::ty::{ty_bool, ty_enum, ty_int, ty_nil, ty_ptr, ty_rptr, ty_uint};
use middle::ty::{ty_float, ty_estr, ty_evec, ty_rec, ty_uniq};
use middle::ty::{ty_fn, ty_trait, ty_tup, ty_infer};
use middle::ty::{ty_param, ty_self, ty_type, ty_opaque_box};
use middle::ty::{ty_opaque_closure_ptr, ty_unboxed_vec, type_is_ty_var};
Expand Down Expand Up @@ -592,17 +592,33 @@ impl CoherenceChecker {
}

fn add_automatically_derived_methods_from_trait(
all_methods: &mut ~[@MethodInfo], trait_did: def_id, self_ty: ty::t) {
all_methods: &mut ~[@MethodInfo],
trait_did: def_id,
self_ty: ty::t,
impl_did: def_id) {
let tcx = self.crate_context.tcx;
let new_method_dids = dvec::DVec();
for (*ty::trait_methods(tcx, trait_did)).each |method| {
// Generate a def ID for each node.
let new_def_id = local_def(tcx.sess.next_node_id());
all_methods.push(@{
let method_info = @{
did: new_def_id,
n_tps: method.tps.len(),
ident: method.ident,
self_type: method.self_ty
});
};
all_methods.push(method_info);

// Note that this method was automatically derived so that trans
// can handle it differently.
let derived_method_info = DerivedMethodInfo {
method_info: method_info,
containing_impl: impl_did
};
tcx.automatically_derived_methods.insert(new_def_id,
derived_method_info);

new_method_dids.push(new_def_id);

// Additionally, generate the type for the derived method and add
// it to the type cache.
Expand All @@ -615,6 +631,10 @@ impl CoherenceChecker {
ty: ty::subst(tcx, &substs, ty::mk_fn(tcx, method.fty))
});
}

let new_method_dids = @dvec::unwrap(move new_method_dids);
tcx.automatically_derived_methods_for_impl.insert(impl_did,
new_method_dids);
}

// Converts an implementation in the AST to an Impl structure.
Expand Down Expand Up @@ -651,7 +671,8 @@ impl CoherenceChecker {
let trait_did =
self.trait_ref_to_trait_def_id(*trait_ref);
self.add_automatically_derived_methods_from_trait(
&mut methods, trait_did, self_ty.ty);
&mut methods, trait_did, self_ty.ty,
local_def(item.id));
}
}
}
Expand Down
Loading