Skip to content

A bunch of default method fixes/improvements, and some other cleanups #7725

New issue

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

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

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
Closed
19 changes: 7 additions & 12 deletions src/librustc/metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -791,7 +791,7 @@ fn encode_info_for_method(ecx: &EncodeContext,
if len > 0u || should_inline {
(ecx.encode_inlined_item)(
ecx, ebml_w, impl_path,
ii_method(local_def(parent_id), m));
ii_method(local_def(parent_id), false, m));
} else {
encode_symbol(ecx, ebml_w, m.id);
}
Expand Down Expand Up @@ -1123,21 +1123,16 @@ fn encode_info_for_item(ecx: &EncodeContext,
}

provided(m) => {
// This is obviously a bogus assert but I don't think this
// ever worked before anyhow...near as I can tell, before
// we would emit two items.
if method_ty.explicit_self == sty_static {
tcx.sess.span_unimpl(
item.span,
fmt!("Method %s is both provided and static",
token::ident_to_str(&method_ty.ident)));
// If this is a static method, we've already encoded
// this.
if method_ty.explicit_self != sty_static {
encode_type_param_bounds(ebml_w, ecx,
&m.generics.ty_params);
}
encode_type_param_bounds(ebml_w, ecx,
&m.generics.ty_params);
encode_method_sort(ebml_w, 'p');
(ecx.encode_inlined_item)(
ecx, ebml_w, path,
ii_method(local_def(item.id), m));
ii_method(local_def(item.id), true, m));
}
}

Expand Down
6 changes: 4 additions & 2 deletions src/librustc/middle/astencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,8 @@ fn simplify_ast(ii: &ast::inlined_item) -> ast::inlined_item {
match *ii {
//hack: we're not dropping items
ast::ii_item(i) => ast::ii_item(fld.fold_item(i).get()),
ast::ii_method(d, m) => ast::ii_method(d, fld.fold_method(m)),
ast::ii_method(d, is_provided, m) =>
ast::ii_method(d, is_provided, fld.fold_method(m)),
ast::ii_foreign(i) => ast::ii_foreign(fld.fold_foreign_item(i))
}
}
Expand All @@ -340,7 +341,8 @@ fn renumber_ast(xcx: @ExtendedDecodeContext, ii: ast::inlined_item)

match ii {
ast::ii_item(i) => ast::ii_item(fld.fold_item(i).get()),
ast::ii_method(d, m) => ast::ii_method(xcx.tr_def_id(d), fld.fold_method(m)),
ast::ii_method(d, is_provided, m) =>
ast::ii_method(xcx.tr_def_id(d), is_provided, fld.fold_method(m)),
ast::ii_foreign(i) => ast::ii_foreign(fld.fold_foreign_item(i)),
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[
LintSpec {
lint: default_methods,
desc: "allow default methods",
default: deny
default: allow
}),

("unused_unsafe",
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1185,7 +1185,7 @@ impl cmt_ {
}
}

impl Repr for cmt {
impl Repr for cmt_ {
fn repr(&self, tcx: ty::ctxt) -> ~str {
fmt!("{%s id:%d m:%? ty:%s}",
self.cat.repr(tcx),
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ pub fn get_res_dtor(ccx: @mut CrateContext,
let _icx = push_ctxt("trans_res_dtor");
if !substs.is_empty() {
let did = if did.crate != ast::local_crate {
inline::maybe_instantiate_inline(ccx, did, true)
inline::maybe_instantiate_inline(ccx, did)
} else {
did
};
Expand Down
5 changes: 2 additions & 3 deletions src/librustc/middle/trans/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ pub fn trans_fn_ref_with_vtables(
def_id: ast::def_id, // def id of fn
ref_id: ast::node_id, // 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: Option<typeck::vtable_res>) // vtables for the call
-> FnData {
//!
//
Expand Down Expand Up @@ -361,8 +361,7 @@ pub fn trans_fn_ref_with_vtables(
// def_id to the local id of the inlined copy.
let def_id = {
if def_id.crate != ast::local_crate {
let may_translate = opt_impl_did.is_none();
inline::maybe_instantiate_inline(ccx, def_id, may_translate)
inline::maybe_instantiate_inline(ccx, def_id)
} else {
def_id
}
Expand Down
6 changes: 0 additions & 6 deletions src/librustc/middle/trans/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,6 @@ impl Repr for param_substs {
}
}

impl Repr for @param_substs {
fn repr(&self, tcx: ty::ctxt) -> ~str {
param_substs_to_str(*self, tcx)
}
}

// Function context. Every LLVM function we create will have one of
// these.
pub struct fn_ctxt_ {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/trans/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ pub fn get_const_val(cx: @mut CrateContext, mut def_id: ast::def_id) -> ValueRef
let contains_key = cx.const_values.contains_key(&def_id.node);
if !ast_util::is_local(def_id) || !contains_key {
if !ast_util::is_local(def_id) {
def_id = inline::maybe_instantiate_inline(cx, def_id, true);
def_id = inline::maybe_instantiate_inline(cx, def_id);
}
match cx.tcx.items.get_copy(&def_id.node) {
ast_map::node_item(@ast::item {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/trans/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -956,7 +956,7 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
fn get_did(ccx: @mut CrateContext, did: ast::def_id)
-> ast::def_id {
if did.crate != ast::local_crate {
inline::maybe_instantiate_inline(ccx, did, true)
inline::maybe_instantiate_inline(ccx, did)
} else {
did
}
Expand Down
14 changes: 5 additions & 9 deletions src/librustc/middle/trans/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,7 @@ use syntax::ast;
use syntax::ast_map::path_name;
use syntax::ast_util::local_def;

// `translate` will be true if this function is allowed to translate the
// item and false otherwise. Currently, this parameter is set to false when
// translating default methods.
pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::def_id,
translate: bool)
pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::def_id)
-> ast::def_id {
let _icx = push_ctxt("maybe_instantiate_inline");
match ccx.external.find(&fn_id) {
Expand Down Expand Up @@ -59,7 +55,7 @@ pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::def_id,
csearch::found(ast::ii_item(item)) => {
ccx.external.insert(fn_id, Some(item.id));
ccx.stats.n_inlines += 1;
if translate { trans_item(ccx, item); }
trans_item(ccx, item);
local_def(item.id)
}
csearch::found(ast::ii_foreign(item)) => {
Expand All @@ -81,19 +77,19 @@ pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::def_id,
_ => ccx.sess.bug("maybe_instantiate_inline: item has a \
non-enum parent")
}
if translate { trans_item(ccx, item); }
trans_item(ccx, item);
local_def(my_id)
}
csearch::found_parent(_, _) => {
ccx.sess.bug("maybe_get_item_ast returned a found_parent \
with a non-item parent");
}
csearch::found(ast::ii_method(impl_did, mth)) => {
csearch::found(ast::ii_method(impl_did, is_provided, mth)) => {
ccx.stats.n_inlines += 1;
ccx.external.insert(fn_id, Some(mth.id));
// If this is a default method, we can't look up the
// impl type. But we aren't going to translate anyways, so don't.
if !translate { return local_def(mth.id); }
if is_provided { return local_def(mth.id); }

let impl_tpt = ty::lookup_item_type(ccx.tcx, impl_did);
let num_type_params =
Expand Down
60 changes: 50 additions & 10 deletions src/librustc/middle/trans/monomorphize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,24 +63,26 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
assert!(real_substs.tps.iter().all(|t| !ty::type_needs_infer(*t)));
let _icx = push_ctxt("monomorphic_fn");
let mut must_cast = false;
let substs = real_substs.tps.iter().transform(|t| {

let do_normalize = |t: &ty::t| {
match normalize_for_monomorphization(ccx.tcx, *t) {
Some(t) => { must_cast = true; t }
None => *t
}
}).collect::<~[ty::t]>();

for real_substs.tps.iter().advance |s| { assert!(!ty::type_has_params(*s)); }
for substs.iter().advance |s| { assert!(!ty::type_has_params(*s)); }
let param_uses = type_use::type_uses_for(ccx, fn_id, substs.len());
};

let psubsts = @param_substs {
tys: substs,
tys: real_substs.tps.map(|x| do_normalize(x)),
vtables: vtables,
self_ty: real_substs.self_ty,
self_ty: real_substs.self_ty.map(|x| do_normalize(x)),
self_vtable: self_vtable
};

for real_substs.tps.iter().advance |s| { assert!(!ty::type_has_params(*s)); }
for psubsts.tys.iter().advance |s| { assert!(!ty::type_has_params(*s)); }
let param_uses = type_use::type_uses_for(ccx, fn_id, psubsts.tys.len());


let hash_id = make_mono_id(ccx, fn_id, impl_did_opt,
&*psubsts,
Some(param_uses));
Expand Down Expand Up @@ -109,6 +111,10 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
let tpt = ty::lookup_item_type(ccx.tcx, fn_id);
let llitem_ty = tpt.ty;

// We need to do special handling of the substitutions if we are
// calling a static provided method. This is sort of unfortunate.
let mut is_static_provided = None;

let map_node = session::expect(
ccx.sess,
ccx.tcx.items.find_copy(&fn_id.node),
Expand All @@ -127,6 +133,12 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
return (get_item_val(ccx, fn_id.node), true);
}
ast_map::node_trait_method(@ast::provided(m), _, pt) => {
// If this is a static provided method, indicate that
// and stash the number of params on the method.
if m.explicit_self.node == ast::sty_static {
is_static_provided = Some(m.generics.ty_params.len());
}

(pt, m.ident, m.span)
}
ast_map::node_trait_method(@ast::required(_), _, _) => {
Expand All @@ -151,8 +163,36 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
ast_map::node_struct_ctor(_, i, pt) => (pt, i.ident, i.span)
};

let mono_ty = ty::subst_tps(ccx.tcx, psubsts.tys,
psubsts.self_ty, llitem_ty);
debug!("monomorphic_fn about to subst into %s", llitem_ty.repr(ccx.tcx));
let mono_ty = match is_static_provided {
None => ty::subst_tps(ccx.tcx, psubsts.tys,
psubsts.self_ty, llitem_ty),
Some(num_method_ty_params) => {
// Static default methods are a little unfortunate, in
// that the "internal" and "external" type of them differ.
// Internally, the method body can refer to Self, but the
// externally visable type of the method has a type param
// inserted in between the trait type params and the
// method type params. The substs that we are given are
// the proper substs *internally* to the method body, so
// we have to use those when compiling it.
//
// In order to get the proper substitution to use on the
// type of the method, we pull apart the substitution and
// stick a substitution for the self type in.
// This is a bit unfortunate.
Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, it is.


let idx = psubsts.tys.len() - num_method_ty_params;
let substs =
(psubsts.tys.slice(0, idx) +
&[psubsts.self_ty.get()] +
psubsts.tys.tailn(idx));
debug!("static default: changed substitution to %s",
substs.repr(ccx.tcx));

ty::subst_tps(ccx.tcx, substs, None, llitem_ty)
}
};
let llfty = type_of_fn_from_ty(ccx, mono_ty);

ccx.stats.n_monos += 1;
Expand Down
61 changes: 40 additions & 21 deletions src/librustc/middle/trans/type_use.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ pub type type_uses = uint; // Bitmask
pub static use_repr: uint = 1; /* Dependency on size/alignment/mode and
take/drop glue */
pub static use_tydesc: uint = 2; /* Takes the tydesc, or compares */
pub static use_all: uint = use_repr|use_tydesc;


pub struct Context {
ccx: @mut CrateContext,
Expand All @@ -57,6 +59,14 @@ pub struct Context {

pub fn type_uses_for(ccx: @mut CrateContext, fn_id: def_id, n_tps: uint)
-> @~[type_uses] {

fn store_type_uses(cx: Context, fn_id: def_id) -> @~[type_uses] {
let Context { uses, ccx } = cx;
let uses = @copy *uses; // freeze
ccx.type_use_cache.insert(fn_id, uses);
uses
}

match ccx.type_use_cache.find(&fn_id) {
Some(uses) => return *uses,
None => ()
Expand All @@ -65,32 +75,29 @@ pub fn type_uses_for(ccx: @mut CrateContext, fn_id: def_id, n_tps: uint)
let fn_id_loc = if fn_id.crate == local_crate {
fn_id
} else {
inline::maybe_instantiate_inline(ccx, fn_id, true)
inline::maybe_instantiate_inline(ccx, fn_id)
};

// Conservatively assume full use for recursive loops
ccx.type_use_cache.insert(fn_id, @vec::from_elem(n_tps, 3u));
ccx.type_use_cache.insert(fn_id, @vec::from_elem(n_tps, use_all));

let cx = Context {
ccx: ccx,
uses: @mut vec::from_elem(n_tps, 0)
};
match ty::get(ty::lookup_item_type(cx.ccx.tcx, fn_id).ty).sty {
ty::ty_bare_fn(ty::BareFnTy {sig: ref sig, _}) |
ty::ty_closure(ty::ClosureTy {sig: ref sig, _}) => {
for sig.inputs.iter().advance |arg| {
type_needs(&cx, use_repr, *arg);
}
}
_ => ()
}

if fn_id_loc.crate != local_crate {
let Context { uses, _ } = cx;
let uses = @copy *uses; // freeze
ccx.type_use_cache.insert(fn_id, uses);
return uses;
// If the method is a default method, we mark all of the types as
// used. This is imprecise, but simple. Getting it right is
// tricky because the substs on the call and the substs on the
// default method differ, because of substs on the trait/impl.
let is_default = ccx.tcx.provided_method_sources.contains_key(&fn_id_loc);
// We also mark all of the params as used if it is an extern thing
// that we haven't been able to inline yet.
if is_default || fn_id_loc.crate != local_crate {
for uint::range(0u, n_tps) |n| { cx.uses[n] |= use_all; }
return store_type_uses(cx, fn_id);
}

let map_node = match ccx.tcx.items.find(&fn_id_loc.node) {
Some(x) => (/*bad*/copy *x),
None => ccx.sess.bug(fmt!("type_uses_for: unbound item ID %?",
Expand All @@ -106,7 +113,10 @@ pub fn type_uses_for(ccx: @mut CrateContext, fn_id: def_id, n_tps: uint)
// This will be a static trait method. For now, we just assume
// it fully depends on all of the type information. (Doing
// otherwise would require finding the actual implementation).
for uint::range(0u, n_tps) |n| { cx.uses[n] |= use_repr|use_tydesc;}
for uint::range(0u, n_tps) |n| { cx.uses[n] |= use_all;}
// We need to return early, before the arguments are processed,
// because of difficulties in the handling of Self.
return store_type_uses(cx, fn_id);
}
ast_map::node_variant(_, _, _) => {
for uint::range(0u, n_tps) |n| { cx.uses[n] |= use_repr;}
Expand Down Expand Up @@ -171,10 +181,19 @@ pub fn type_uses_for(ccx: @mut CrateContext, fn_id: def_id, n_tps: uint)
token::get_ident_interner())));
}
}
let Context { uses, _ } = cx;
let uses = @copy *uses; // freeze
ccx.type_use_cache.insert(fn_id, uses);
uses

// Now handle arguments
match ty::get(ty::lookup_item_type(cx.ccx.tcx, fn_id).ty).sty {
ty::ty_bare_fn(ty::BareFnTy {sig: ref sig, _}) |
ty::ty_closure(ty::ClosureTy {sig: ref sig, _}) => {
for sig.inputs.iter().advance |arg| {
type_needs(&cx, use_repr, *arg);
}
}
_ => ()
}

store_type_uses(cx, fn_id)
}

pub fn type_needs(cx: &Context, use_: uint, ty: ty::t) {
Expand Down
Loading