diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index d7f33dcf0d0..41349d9c085 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -2149,18 +2149,24 @@ impl TypeNames { self.named_types.find_equiv(&s).map_consume(|x| Type::from_ref(*x)) } - pub fn type_to_str(&self, ty: Type) -> ~str { + // We have a depth count, because we seem to make infinite types. + pub fn type_to_str_depth(&self, ty: Type, depth: int) -> ~str { match self.find_name(&ty) { option::Some(name) => return name.to_owned(), None => () } + if depth == 0 { + return ~"###"; + } + unsafe { let kind = ty.kind(); match kind { Void => ~"Void", Half => ~"Half", + Float => ~"Float", Double => ~"Double", X86_FP80 => ~"X86_FP80", FP128 => ~"FP128", @@ -2175,24 +2181,25 @@ impl TypeNames { Function => { let out_ty = ty.return_type(); let args = ty.func_params(); - let args = args.map(|&ty| self.type_to_str(ty)).connect(", "); - let out_ty = self.type_to_str(out_ty); + let args = + args.map(|&ty| self.type_to_str_depth(ty, depth-1)).connect(", "); + let out_ty = self.type_to_str_depth(out_ty, depth-1); fmt!("fn(%s) -> %s", args, out_ty) } Struct => { let tys = ty.field_types(); - let tys = tys.map(|&ty| self.type_to_str(ty)).connect(", "); + let tys = tys.map(|&ty| self.type_to_str_depth(ty, depth-1)).connect(", "); fmt!("{%s}", tys) } Array => { let el_ty = ty.element_type(); - let el_ty = self.type_to_str(el_ty); + let el_ty = self.type_to_str_depth(el_ty, depth-1); let len = ty.array_length(); fmt!("[%s x %u]", el_ty, len) } Pointer => { let el_ty = ty.element_type(); - let el_ty = self.type_to_str(el_ty); + let el_ty = self.type_to_str_depth(el_ty, depth-1); fmt!("*%s", el_ty) } _ => fail!("Unknown Type Kind (%u)", kind as uint) @@ -2200,6 +2207,10 @@ impl TypeNames { } } + pub fn type_to_str(&self, ty: Type) -> ~str { + self.type_to_str_depth(ty, 30) + } + pub fn val_to_str(&self, val: ValueRef) -> ~str { unsafe { let ty = Type::from_ref(llvm::LLVMTypeOf(val)); diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 70e94844319..16e3bd34cdd 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -599,8 +599,10 @@ fn encode_vtable_res(ecx: &e::EncodeContext, // ty::t doesn't work, and there is no way (atm) to have // hand-written encoding routines combine with auto-generated // ones. perhaps we should fix this. - do ebml_w.emit_from_vec(*dr) |ebml_w, vtable_origin| { - encode_vtable_origin(ecx, ebml_w, vtable_origin) + do ebml_w.emit_from_vec(*dr) |ebml_w, param_tables| { + do ebml_w.emit_from_vec(**param_tables) |ebml_w, vtable_origin| { + encode_vtable_origin(ecx, ebml_w, vtable_origin) + } } } @@ -632,6 +634,13 @@ fn encode_vtable_origin(ecx: &e::EncodeContext, } } } + typeck::vtable_self(def_id) => { + do ebml_w.emit_enum_variant("vtable_self", 2u, 1u) |ebml_w| { + do ebml_w.emit_enum_variant_arg(0u) |ebml_w| { + ebml_w.emit_def_id(def_id) + } + } + } } } } @@ -646,13 +655,17 @@ trait vtable_decoder_helpers { impl vtable_decoder_helpers for reader::Decoder { fn read_vtable_res(&mut self, xcx: @ExtendedDecodeContext) -> typeck::vtable_res { - @self.read_to_vec(|this| this.read_vtable_origin(xcx)) + @self.read_to_vec(|this| + @this.read_to_vec(|this| + this.read_vtable_origin(xcx))) } fn read_vtable_origin(&mut self, xcx: @ExtendedDecodeContext) -> typeck::vtable_origin { do self.read_enum("vtable_origin") |this| { - do this.read_enum_variant(["vtable_static", "vtable_param"]) + do this.read_enum_variant(["vtable_static", + "vtable_param", + "vtable_self"]) |this, i| { match i { 0 => { @@ -678,6 +691,13 @@ impl vtable_decoder_helpers for reader::Decoder { } ) } + 2 => { + typeck::vtable_self( + do this.read_enum_variant_arg(0u) |this| { + this.read_def_id(xcx) + } + ) + } // hard to avoid - user input _ => fail!("bad enum variant") } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index df7f73a5243..efa69ab5e62 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -461,6 +461,7 @@ pub fn get_res_dtor(ccx: @mut CrateContext, &tsubsts, None, None, + None, None); val @@ -1544,17 +1545,15 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext, llfndecl: ValueRef, id: ast::node_id, output_type: ty::t, - impl_id: Option, param_substs: Option<@param_substs>, sp: Option) -> fn_ctxt { for param_substs.iter().advance |p| { p.validate(); } - debug!("new_fn_ctxt_w_id(path=%s, id=%?, impl_id=%?, \ + debug!("new_fn_ctxt_w_id(path=%s, id=%?, \ param_substs=%s)", path_str(ccx.sess, path), id, - impl_id, param_substs.repr(ccx.tcx)); let llbbs = mk_standard_basic_blocks(llfndecl); @@ -1583,7 +1582,6 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext, lllocals: @mut HashMap::new(), llupvars: @mut HashMap::new(), id: id, - impl_id: impl_id, param_substs: param_substs, span: sp, path: path, @@ -1604,7 +1602,7 @@ pub fn new_fn_ctxt(ccx: @mut CrateContext, output_type: ty::t, sp: Option) -> fn_ctxt { - new_fn_ctxt_w_id(ccx, path, llfndecl, -1, output_type, None, None, sp) + new_fn_ctxt_w_id(ccx, path, llfndecl, -1, output_type, None, sp) } // NB: must keep 4 fns in sync: @@ -1773,7 +1771,6 @@ pub fn trans_closure(ccx: @mut CrateContext, self_arg: self_arg, param_substs: Option<@param_substs>, id: ast::node_id, - impl_id: Option, attributes: &[ast::attribute], output_type: ty::t, maybe_load_env: &fn(fn_ctxt), @@ -1791,7 +1788,6 @@ pub fn trans_closure(ccx: @mut CrateContext, llfndecl, id, output_type, - impl_id, param_substs, Some(body.span)); let raw_llargs = create_llargs_for_fn_args(fcx, self_arg, decl.inputs); @@ -1850,7 +1846,6 @@ pub fn trans_fn(ccx: @mut CrateContext, self_arg: self_arg, param_substs: Option<@param_substs>, id: ast::node_id, - impl_id: Option, attrs: &[ast::attribute]) { let do_time = ccx.sess.trans_stats(); let start = if do_time { time::get_time() } @@ -1870,7 +1865,6 @@ pub fn trans_fn(ccx: @mut CrateContext, self_arg, param_substs, id, - impl_id, attrs, output_type, |fcx| { @@ -1920,7 +1914,6 @@ pub fn trans_enum_variant(ccx: @mut CrateContext, llfndecl, variant.node.id, enum_ty, - None, param_substs, None); @@ -2000,7 +1993,6 @@ pub fn trans_tuple_struct(ccx: @mut CrateContext, llfndecl, ctor_id, tup_ty, - None, param_substs, None); @@ -2080,7 +2072,6 @@ pub fn trans_item(ccx: @mut CrateContext, item: &ast::item) { no_self, None, item.id, - None, item.attrs); } else { for body.node.stmts.iter().advance |stmt| { diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index 3405db8e52f..4c07f88f16e 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -17,6 +17,7 @@ // closure. use core::prelude::*; +use core::vec; use back::abi; use driver::session; @@ -194,6 +195,58 @@ pub fn trans_fn_ref_with_vtables_to_callee( type_params, vtables))} } +fn get_impl_resolutions(bcx: block, + impl_id: ast::def_id) + -> typeck::vtable_res { + if impl_id.crate == ast::local_crate { + *bcx.ccx().maps.vtable_map.get(&impl_id.node) + } else { + // XXX: This is a temporary hack to work around not properly + // exporting information about resolutions for impls. + // This doesn't actually work if the trait has param bounds, + // but it does allow us to survive the case when it does not. + let trait_ref = ty::impl_trait_ref(bcx.tcx(), impl_id).get(); + @vec::from_elem(trait_ref.substs.tps.len(), @~[]) + } +} + +fn resolve_default_method_vtables(bcx: block, + impl_id: ast::def_id, + method: &ty::Method, + substs: &ty::substs, + impl_vtables: Option) + -> typeck::vtable_res { + + // Get the vtables that the impl implements the trait at + let trait_vtables = get_impl_resolutions(bcx, impl_id); + + // Build up a param_substs that we are going to resolve the + // trait_vtables under. + let param_substs = Some(@param_substs { + tys: copy substs.tps, + self_ty: substs.self_ty, + vtables: impl_vtables, + self_vtable: None + }); + + let trait_vtables_fixed = resolve_vtables_under_param_substs( + bcx.tcx(), param_substs, trait_vtables); + + // Now we pull any vtables for parameters on the actual method. + let num_method_vtables = method.generics.type_param_defs.len(); + let method_vtables = match impl_vtables { + Some(vtables) => { + let num_impl_type_parameters = + vtables.len() - num_method_vtables; + vtables.tailn(num_impl_type_parameters).to_owned() + }, + None => vec::from_elem(num_method_vtables, @~[]) + }; + + @(*trait_vtables_fixed + method_vtables) +} + + pub fn trans_fn_ref_with_vtables( bcx: block, // def_id: ast::def_id, // def id of fn @@ -233,15 +286,21 @@ pub fn trans_fn_ref_with_vtables( // Polytype of the function item (may have type params) let fn_tpt = ty::lookup_item_type(tcx, def_id); - let substs = ty::substs { self_r: None, self_ty: None, + // For simplicity, we want to use the Subst trait when composing + // substitutions for default methods. The subst trait does + // substitutions with regions, though, so we put a dummy self + // region parameter in to keep it from failing. This is a hack. + let substs = ty::substs { self_r: Some(ty::re_empty), + self_ty: None, tps: /*bad*/ type_params.to_owned() }; // We need to do a bunch of special handling for default methods. // We need to modify the def_id and our substs in order to monomorphize // the function. - let (def_id, opt_impl_did, substs) = match tcx.provided_method_sources.find(&def_id) { - None => (def_id, None, substs), + let (def_id, opt_impl_did, substs, self_vtable, vtables) = + match tcx.provided_method_sources.find(&def_id) { + None => (def_id, None, substs, None, vtables), Some(source) => { // There are two relevant substitutions when compiling // default methods. First, there is the substitution for @@ -261,20 +320,42 @@ pub fn trans_fn_ref_with_vtables( default methods"); let method = ty::method(tcx, source.method_id); + // Get all of the type params for the receiver + let param_defs = method.generics.type_param_defs; + let receiver_substs = + type_params.initn(param_defs.len()).to_owned(); + let receiver_vtables = match vtables { + None => @~[], + Some(call_vtables) => { + @call_vtables.initn(param_defs.len()).to_owned() + } + }; + + let self_vtable = + typeck::vtable_static(source.impl_id, receiver_substs, + receiver_vtables); // Compute the first substitution let first_subst = make_substs_for_receiver_types( tcx, source.impl_id, trait_ref, method); // And compose them let new_substs = first_subst.subst(tcx, &substs); + + + let vtables = + resolve_default_method_vtables(bcx, source.impl_id, + method, &new_substs, vtables); + debug!("trans_fn_with_vtables - default method: \ substs = %s, trait_subst = %s, \ - first_subst = %s, new_subst = %s", + first_subst = %s, new_subst = %s, \ + self_vtable = %s, vtables = %s", substs.repr(tcx), trait_ref.substs.repr(tcx), - first_subst.repr(tcx), new_substs.repr(tcx)); + first_subst.repr(tcx), new_substs.repr(tcx), + self_vtable.repr(tcx), vtables.repr(tcx)); - - (source.method_id, Some(source.impl_id), new_substs) + (source.method_id, Some(source.impl_id), + new_substs, Some(self_vtable), Some(vtables)) } }; @@ -321,7 +402,8 @@ pub fn trans_fn_ref_with_vtables( let (val, must_cast) = monomorphize::monomorphic_fn(ccx, def_id, &substs, - vtables, opt_impl_did, Some(ref_id)); + vtables, self_vtable, + opt_impl_did, Some(ref_id)); let mut val = val; if must_cast && ref_id != 0 { // Monotype of the REFERENCE to the function (type params diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs index 3ce52a63171..ad68ffb402e 100644 --- a/src/librustc/middle/trans/closure.rs +++ b/src/librustc/middle/trans/closure.rs @@ -444,7 +444,6 @@ pub fn trans_expr_fn(bcx: block, no_self, /*bad*/ copy bcx.fcx.param_substs, user_id, - None, [], real_return_type, |fcx| load_environment(fcx, cdata_ty, cap_vars, diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index a7ffa8e13b0..7624fb13903 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -130,9 +130,9 @@ pub struct ValSelfData { // will only be set in the case of default methods. pub struct param_substs { tys: ~[ty::t], + self_ty: Option, vtables: Option, - type_param_defs: @~[ty::TypeParameterDef], - self_ty: Option + self_vtable: Option } impl param_substs { @@ -143,10 +143,9 @@ impl param_substs { } fn param_substs_to_str(this: ¶m_substs, tcx: ty::ctxt) -> ~str { - fmt!("param_substs {tys:%s, vtables:%s, type_param_defs:%s}", + fmt!("param_substs {tys:%s, vtables:%s}", this.tys.repr(tcx), - this.vtables.repr(tcx), - this.type_param_defs.repr(tcx)) + this.vtables.repr(tcx)) } impl Repr for param_substs { @@ -223,9 +222,6 @@ pub struct fn_ctxt_ { // a user-defined function. id: ast::node_id, - // The def_id of the impl we're inside, or None if we aren't inside one. - impl_id: Option, - // If this function is being monomorphized, this contains the type // substitutions used. param_substs: Option<@param_substs>, @@ -981,7 +977,11 @@ pub fn monomorphize_type(bcx: block, t: ty::t) -> ty::t { Some(substs) => { ty::subst_tps(bcx.tcx(), substs.tys, substs.self_ty, t) } - _ => { assert!(!ty::type_has_params(t)); t } + _ => { + assert!(!ty::type_has_params(t)); + assert!(!ty::type_has_self(t)); + t + } } } @@ -1030,17 +1030,37 @@ pub fn node_vtables(bcx: block, id: ast::node_id) pub fn resolve_vtables_in_fn_ctxt(fcx: fn_ctxt, vts: typeck::vtable_res) -> typeck::vtable_res { - @vec::map(*vts, |d| resolve_vtable_in_fn_ctxt(fcx, copy *d)) + resolve_vtables_under_param_substs(fcx.ccx.tcx, + fcx.param_substs, + vts) } +pub fn resolve_vtables_under_param_substs(tcx: ty::ctxt, + param_substs: Option<@param_substs>, + vts: typeck::vtable_res) + -> typeck::vtable_res { + @vec::map(*vts, |ds| + @vec::map(**ds, |d| + resolve_vtable_under_param_substs(tcx, param_substs, copy *d))) +} + + // Apply the typaram substitutions in the fn_ctxt to a vtable. This should // eliminate any vtable_params. pub fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, vt: typeck::vtable_origin) -> typeck::vtable_origin { - let tcx = fcx.ccx.tcx; + resolve_vtable_under_param_substs(fcx.ccx.tcx, + fcx.param_substs, + vt) +} + +pub fn resolve_vtable_under_param_substs(tcx: ty::ctxt, + param_substs: Option<@param_substs>, + vt: typeck::vtable_origin) + -> typeck::vtable_origin { match vt { typeck::vtable_static(trait_id, tys, sub) => { - let tys = match fcx.param_substs { + let tys = match param_substs { Some(substs) => { do vec::map(tys) |t| { ty::subst_tps(tcx, substs.tys, substs.self_ty, *t) @@ -1048,11 +1068,12 @@ pub fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, vt: typeck::vtable_origin) } _ => tys }; - typeck::vtable_static(trait_id, tys, - resolve_vtables_in_fn_ctxt(fcx, sub)) + typeck::vtable_static( + trait_id, tys, + resolve_vtables_under_param_substs(tcx, param_substs, sub)) } typeck::vtable_param(n_param, n_bound) => { - match fcx.param_substs { + match param_substs { Some(substs) => { find_vtable(tcx, substs, n_param, n_bound) } @@ -1063,6 +1084,19 @@ pub fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, vt: typeck::vtable_origin) } } } + typeck::vtable_self(_trait_id) => { + match param_substs { + Some(@param_substs + {self_vtable: Some(ref self_vtable), _}) => { + copy *self_vtable + } + _ => { + tcx.sess.bug(fmt!( + "resolve_vtable_in_fn_ctxt: asked to lookup but \ + no self_vtable in the fn_ctxt!")) + } + } + } } } @@ -1072,13 +1106,7 @@ pub fn find_vtable(tcx: ty::ctxt, ps: ¶m_substs, debug!("find_vtable(n_param=%u, n_bound=%u, ps=%s)", n_param, n_bound, ps.repr(tcx)); - // Vtables are stored in a flat array, finding the right one is - // somewhat awkward - let first_n_type_param_defs = ps.type_param_defs.slice(0, n_param); - let vtables_to_skip = - ty::count_traits_and_supertraits(tcx, first_n_type_param_defs); - let vtable_off = vtables_to_skip + n_bound; - /*bad*/ copy ps.vtables.get()[vtable_off] + /*bad*/ copy ps.vtables.get()[n_param][n_bound] } pub fn dummy_substs(tps: ~[ty::t]) -> ty::substs { diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 6263ffb318e..7672f3b615d 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -555,7 +555,6 @@ pub fn trans_intrinsic(ccx: @mut CrateContext, decl, item.id, output_type, - None, Some(substs), Some(item.span)); @@ -1183,7 +1182,6 @@ pub fn trans_foreign_fn(ccx: @mut CrateContext, no_self, None, id, - None, []); return llfndecl; } diff --git a/src/librustc/middle/trans/inline.rs b/src/librustc/middle/trans/inline.rs index 01849ac6e8f..11c02f165b6 100644 --- a/src/librustc/middle/trans/inline.rs +++ b/src/librustc/middle/trans/inline.rs @@ -127,7 +127,6 @@ pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::def_id, self_kind, None, mth.id, - Some(impl_did), []); } local_def(mth.id) diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index fc0c9c06c45..f145f83f13c 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -68,8 +68,7 @@ pub fn trans_impl(ccx: @mut CrateContext, path, *method, None, - llfn, - ast_util::local_def(id)); + llfn); } } } @@ -90,8 +89,7 @@ pub fn trans_method(ccx: @mut CrateContext, path: path, method: &ast::method, param_substs: Option<@param_substs>, - llfn: ValueRef, - impl_id: ast::def_id) { + llfn: ValueRef) { // figure out how self is being passed let self_arg = match method.explicit_self.node { ast::sty_static => { @@ -127,7 +125,6 @@ pub fn trans_method(ccx: @mut CrateContext, self_arg, param_substs, method.id, - Some(impl_id), []); } @@ -139,7 +136,6 @@ pub fn trans_self_arg(bcx: block, // Compute the type of self. let self_ty = monomorphize_type(bcx, mentry.self_ty); - let result = trans_arg_expr(bcx, self_ty, mentry.self_mode, @@ -174,21 +170,6 @@ pub fn trans_method_callee(bcx: block, // Replace method_self with method_static here. let mut origin = mentry.origin; match origin { - typeck::method_self(trait_id, method_index) => { - // Get the ID of the impl we're inside. - let impl_def_id = bcx.fcx.impl_id.get(); - - debug!("impl_def_id is %?", impl_def_id); - - // Get the ID of the method we're calling. - let method_name = - ty::trait_method(tcx, trait_id, method_index).ident; - let method_id = - method_with_name_or_default(bcx.ccx(), - impl_def_id, - method_name); - origin = typeck::method_static(method_id); - } typeck::method_super(trait_id, method_index) => { // is the self type for this method call let self_ty = node_id_type(bcx, this.id); @@ -213,6 +194,7 @@ pub fn trans_method_callee(bcx: block, impl_id, method_name)); } + typeck::method_self(*) | typeck::method_static(*) | typeck::method_param(*) | typeck::method_trait(*) => {} } @@ -250,6 +232,21 @@ pub fn trans_method_callee(bcx: block, None => fail!("trans_method_callee: missing param_substs") } } + + typeck::method_self(trait_id, method_index) => { + match bcx.fcx.param_substs { + Some(@param_substs + {self_vtable: Some(ref vtbl), _}) => { + trans_monomorphized_callee(bcx, callee_id, this, mentry, + trait_id, method_index, + copy *vtbl) + } + _ => { + fail!("trans_method_callee: missing self_vtable") + } + } + } + typeck::method_trait(_, off, store) => { trans_trait_callee(bcx, callee_id, @@ -258,9 +255,9 @@ pub fn trans_method_callee(bcx: block, store, mentry.explicit_self) } - typeck::method_self(*) | typeck::method_super(*) => { - fail!("method_self or method_super should have been handled \ - above") + typeck::method_super(*) => { + fail!("method_super should have been handled \ + above") } } } @@ -292,15 +289,9 @@ pub fn trans_static_method_callee(bcx: block, // // So when we see a call to this function foo, we have to figure // out which impl the `Trait` bound on the type `self` was - // bound to. Due to the fact that we use a flattened list of - // impls, one per bound, this means we have to total up the bounds - // found on the type parametesr T1...Tn to find the index of the - // one we are interested in. - let bound_index = { - let trait_def = ty::lookup_trait_def(bcx.tcx(), trait_id); - ty::count_traits_and_supertraits( - bcx.tcx(), *trait_def.generics.type_param_defs) - }; + // bound to. + let bound_index = ty::lookup_trait_def(bcx.tcx(), trait_id). + generics.type_param_defs.len(); let mname = if method_id.crate == ast::local_crate { match bcx.tcx().items.get_copy(&method_id.node) { @@ -322,17 +313,17 @@ pub fn trans_static_method_callee(bcx: block, let vtbls = resolve_vtables_in_fn_ctxt( bcx.fcx, ccx.maps.vtable_map.get_copy(&callee_id)); - match vtbls[bound_index] { + match vtbls[bound_index][0] { typeck::vtable_static(impl_did, ref rcvr_substs, rcvr_origins) => { assert!(rcvr_substs.iter().all(|t| !ty::type_needs_infer(*t))); let mth_id = method_with_name_or_default(bcx.ccx(), impl_did, mname); - let callee_substs = combine_impl_and_methods_tps( - bcx, mth_id, impl_did, callee_id, *rcvr_substs); - let callee_origins = combine_impl_and_methods_origins( - bcx, mth_id, impl_did, callee_id, rcvr_origins); + let (callee_substs, callee_origins) = + combine_impl_and_methods_tps( + bcx, mth_id, impl_did, callee_id, + *rcvr_substs, rcvr_origins); let FnData {llfn: lval} = trans_fn_ref_with_vtables(bcx, @@ -428,10 +419,10 @@ pub fn trans_monomorphized_callee(bcx: block, // create a concatenated set of substitutions which includes // those from the impl and those from the method: - let callee_substs = combine_impl_and_methods_tps( - bcx, mth_id, impl_did, callee_id, *rcvr_substs); - let callee_origins = combine_impl_and_methods_origins( - bcx, mth_id, impl_did, callee_id, rcvr_origins); + let (callee_substs, callee_origins) = + combine_impl_and_methods_tps( + bcx, mth_id, impl_did, callee_id, + *rcvr_substs, rcvr_origins); // translate the function let callee = trans_fn_ref_with_vtables(bcx, @@ -460,6 +451,9 @@ pub fn trans_monomorphized_callee(bcx: block, typeck::vtable_param(*) => { fail!("vtable_param left in monomorphized function's vtable substs"); } + typeck::vtable_self(*) => { + fail!("vtable_self left in monomorphized function's vtable substs"); + } }; } @@ -468,8 +462,9 @@ pub fn combine_impl_and_methods_tps(bcx: block, mth_did: ast::def_id, impl_did: ast::def_id, callee_id: ast::node_id, - rcvr_substs: &[ty::t]) - -> ~[ty::t] { + rcvr_substs: &[ty::t], + rcvr_origins: typeck::vtable_res) + -> (~[ty::t], typeck::vtable_res) { /*! * * Creates a concatenated set of substitutions which includes @@ -498,52 +493,18 @@ pub fn combine_impl_and_methods_tps(bcx: block, debug!("node_substs=%?", node_substs.map(|t| bcx.ty_to_str(*t))); debug!("ty_substs=%?", ty_substs.map(|t| bcx.ty_to_str(*t))); - return ty_substs; -} -pub fn combine_impl_and_methods_origins(bcx: block, - mth_did: ast::def_id, - impl_did: ast::def_id, - callee_id: ast::node_id, - rcvr_origins: typeck::vtable_res) - -> typeck::vtable_res { - /*! - * - * Similar to `combine_impl_and_methods_tps`, but for vtables. - * This is much messier because of the flattened layout we are - * currently using (for some reason that I fail to understand). - * The proper fix is described in #3446. - */ - - - // Find the bounds for the method, which are the tail of the - // bounds found in the item type, as the item type combines the - // rcvr + method bounds. - let ccx = bcx.ccx(); - let tcx = bcx.tcx(); - let n_m_tps = method_ty_param_count(ccx, mth_did, impl_did); - let ty::ty_param_bounds_and_ty { - generics: r_m_generics, - _ - } = ty::lookup_item_type(tcx, mth_did); - let n_r_m_tps = r_m_generics.type_param_defs.len(); // rcvr + method tps - let m_type_param_defs = - r_m_generics.type_param_defs.slice(n_r_m_tps - n_m_tps, n_r_m_tps); - - // Flatten out to find the number of vtables the method expects. - let m_vtables = ty::count_traits_and_supertraits(tcx, m_type_param_defs); - - // Find the vtables we computed at type check time and monomorphize them + // Now, do the same work for the vtables. The vtables might not + // exist, in which case we need to make them. let r_m_origins = match node_vtables(bcx, callee_id) { Some(vt) => vt, - None => @~[] + None => @vec::from_elem(node_substs.len(), @~[]) }; + let vtables + = @vec::append(rcvr_origins.to_owned(), + r_m_origins.tailn(r_m_origins.len() - n_m_tps)); - // Extract those that belong to method: - let m_origins = r_m_origins.tailn(r_m_origins.len() - m_vtables); - - // Combine rcvr + method to find the final result: - @vec::append(/*bad*/copy *rcvr_origins, m_origins) + return (ty_substs, vtables); } @@ -842,7 +803,7 @@ pub fn trans_trait_cast(bcx: block, bcx = expr::trans_into(bcx, val, SaveIn(llboxdest)); // Store the vtable into the pair or triple. - let orig = /*bad*/copy ccx.maps.vtable_map.get(&id)[0]; + let orig = /*bad*/copy ccx.maps.vtable_map.get(&id)[0][0]; let orig = resolve_vtable_in_fn_ctxt(bcx.fcx, orig); let vtable = get_vtable(bcx, v_ty, orig); Store(bcx, vtable, PointerCast(bcx, diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index 586dfd7e98a..92d8192aee6 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -43,6 +43,7 @@ pub fn monomorphic_fn(ccx: @mut CrateContext, fn_id: ast::def_id, real_substs: &ty::substs, vtables: Option, + self_vtable: Option, impl_did_opt: Option, ref_id: Option) -> (ValueRef, bool) @@ -165,6 +166,7 @@ pub fn monomorphic_fn(ccx: @mut CrateContext, let mut pt = /* bad */copy (*pt); pt.push(elt); let s = mangle_exported_name(ccx, /*bad*/copy pt, mono_ty); + debug!("monomorphize_fn mangled to %s", s); let mk_lldecl = || { let lldecl = decl_internal_cdecl_fn(ccx.llmod, /*bad*/copy s, llfty); @@ -175,8 +177,8 @@ pub fn monomorphic_fn(ccx: @mut CrateContext, let psubsts = Some(@param_substs { tys: substs, vtables: vtables, - type_param_defs: tpt.generics.type_param_defs, - self_ty: real_substs.self_ty + self_ty: real_substs.self_ty, + self_vtable: self_vtable }); let lldecl = match map_node { @@ -194,7 +196,6 @@ pub fn monomorphic_fn(ccx: @mut CrateContext, no_self, psubsts, fn_id.node, - None, []); d } @@ -222,27 +223,17 @@ pub fn monomorphic_fn(ccx: @mut CrateContext, } d } - ast_map::node_method(mth, supplied_impl_did, _) => { + ast_map::node_method(mth, _, _) => { // XXX: What should the self type be here? let d = mk_lldecl(); set_inline_hint_if_appr(/*bad*/copy mth.attrs, d); - - // Override the impl def ID if necessary. - let impl_did; - match impl_did_opt { - None => impl_did = supplied_impl_did, - Some(override_impl_did) => impl_did = override_impl_did - } - - meth::trans_method(ccx, pt, mth, psubsts, d, impl_did); + meth::trans_method(ccx, pt, mth, psubsts, d); d } ast_map::node_trait_method(@ast::provided(mth), _, pt) => { let d = mk_lldecl(); set_inline_hint_if_appr(/*bad*/copy mth.attrs, d); - debug!("monomorphic_fn impl_did_opt is %?", impl_did_opt); - meth::trans_method(ccx, /*bad*/copy *pt, mth, psubsts, d, - impl_did_opt.get()); + meth::trans_method(ccx, /*bad*/copy *pt, mth, psubsts, d); d } ast_map::node_struct_ctor(struct_def, _, _) => { @@ -337,14 +328,10 @@ pub fn make_mono_id(ccx: @mut CrateContext, param_uses: Option<@~[type_use::type_uses]>) -> mono_id { let precise_param_ids = match vtables { Some(vts) => { - let item_ty = ty::lookup_item_type(ccx.tcx, item); - let mut i = 0; - vec::map_zip(*item_ty.generics.type_param_defs, substs, |type_param_def, subst| { - let mut v = ~[]; - for type_param_def.bounds.trait_bounds.iter().advance |_bound| { - v.push(meth::vtable_id(ccx, &vts[i])); - i += 1; - } + debug!("make_mono_id vtables=%s substs=%s", + vts.repr(ccx.tcx), substs.repr(ccx.tcx)); + vec::map_zip(*vts, substs, |vtable, subst| { + let v = vtable.map(|vt| meth::vtable_id(ccx, vt)); (*subst, if !v.is_empty() { Some(@v) } else { None }) }) } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 4c1c8e5c2c8..23266767124 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -609,6 +609,7 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) { for ms.iter().advance |m| { check_method(ccx, *m); } + vtable::resolve_impl(ccx, it); } ast::item_trait(_, _, ref trait_methods) => { for (*trait_methods).iter().advance |trait_method| { diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index bd78e9cc5fb..0bf20f9fbcb 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -17,8 +17,8 @@ use middle::typeck::check::{structurally_resolved_type}; use middle::typeck::infer::fixup_err_to_str; use middle::typeck::infer::{resolve_and_force_all_but_regions, resolve_type}; use middle::typeck::infer; -use middle::typeck::{CrateCtxt, vtable_origin, vtable_param, vtable_res}; -use middle::typeck::vtable_static; +use middle::typeck::{CrateCtxt, vtable_origin, vtable_res}; +use middle::typeck::{vtable_static, vtable_param, vtable_self}; use middle::subst::Subst; use util::common::indenter; use util::ppaux::tys_to_str; @@ -90,6 +90,7 @@ fn lookup_vtables(vcx: &VtableContext, let mut i = 0u; for substs.tps.iter().advance |ty| { // ty is the value supplied for the type parameter A... + let mut param_result = ~[]; for ty::each_bound_trait_and_supertraits( tcx, type_param_defs[i].bounds) |trait_ref| @@ -106,7 +107,7 @@ fn lookup_vtables(vcx: &VtableContext, debug!("after subst: %s", trait_ref.repr(tcx)); match lookup_vtable(vcx, location_info, *ty, &trait_ref, is_early) { - Some(vtable) => result.push(vtable), + Some(vtable) => param_result.push(vtable), None => { vcx.tcx().sess.span_fatal( location_info.span, @@ -117,6 +118,7 @@ fn lookup_vtables(vcx: &VtableContext, } } } + result.push(@param_result); i += 1u; } debug!("lookup_vtables result(\ @@ -237,6 +239,17 @@ fn lookup_vtable(vcx: &VtableContext, } } + ty::ty_self(trait_id) => { + debug!("trying to find %? vtable for type %?", + trait_ref.def_id, trait_id); + + if trait_id == trait_ref.def_id { + let vtable = vtable_self(trait_id); + debug!("found self vtable: %?", vtable); + return Some(vtable); + } + } + _ => { let mut found = ~[]; @@ -467,6 +480,12 @@ pub fn location_info_for_expr(expr: @ast::expr) -> LocationInfo { id: expr.id } } +pub fn location_info_for_item(item: @ast::item) -> LocationInfo { + LocationInfo { + span: item.span, + id: item.id + } +} pub fn early_resolve_expr(ex: @ast::expr, fcx: @mut FnCtxt, @@ -583,7 +602,8 @@ pub fn early_resolve_expr(ex: @ast::expr, // vtable (that is: "ex has vtable // ") if !is_early { - insert_vtables(fcx, ex.id, @~[vtable]); + insert_vtables(fcx, ex.id, + @~[@~[vtable]]); } } None => { @@ -650,6 +670,27 @@ fn resolve_expr(ex: @ast::expr, visit::visit_expr(ex, (fcx, v)); } +pub fn resolve_impl(ccx: @mut CrateCtxt, impl_item: @ast::item) { + let def_id = ast_util::local_def(impl_item.id); + match ty::impl_trait_ref(ccx.tcx, def_id) { + None => {}, + Some(trait_ref) => { + let infcx = infer::new_infer_ctxt(ccx.tcx); + let vcx = VtableContext { ccx: ccx, infcx: infcx }; + let trait_def = ty::lookup_trait_def(ccx.tcx, trait_ref.def_id); + + let vtbls = lookup_vtables(&vcx, + &location_info_for_item(impl_item), + *trait_def.generics.type_param_defs, + &trait_ref.substs, + false); + + // FIXME(#7450): Doesn't work cross crate + ccx.vtable_map.insert(impl_item.id, vtbls); + } + } +} + // Detect points where a trait-bounded type parameter is // instantiated, resolve the impls for the parameters. pub fn resolve_in_block(fcx: @mut FnCtxt, bl: &ast::blk) { diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index dd9d68beb1f..e2efdc51fca 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -20,7 +20,8 @@ use middle::typeck::check::{FnCtxt, SelfInfo}; use middle::typeck::infer::{force_all, resolve_all, resolve_region}; use middle::typeck::infer::resolve_type; use middle::typeck::infer; -use middle::typeck::{vtable_origin, vtable_static, vtable_param}; +use middle::typeck::{vtable_res, vtable_origin}; +use middle::typeck::{vtable_static, vtable_param, vtable_self}; use middle::typeck::method_map_entry; use middle::typeck::write_substs_to_tcx; use middle::typeck::write_ty_to_tcx; @@ -84,7 +85,7 @@ fn resolve_vtable_map_entry(fcx: @mut FnCtxt, sp: span, id: ast::node_id) { match fcx.inh.vtable_map.find(&id) { None => {} Some(origins) => { - let r_origins = @origins.map(|o| resolve_origin(fcx, sp, o)); + let r_origins = resolve_origins(fcx, sp, *origins); let vtable_map = fcx.ccx.vtable_map; vtable_map.insert(id, r_origins); debug!("writeback::resolve_vtable_map_entry(id=%d, vtables=%?)", @@ -92,18 +93,26 @@ fn resolve_vtable_map_entry(fcx: @mut FnCtxt, sp: span, id: ast::node_id) { } } + fn resolve_origins(fcx: @mut FnCtxt, sp: span, + vtbls: vtable_res) -> vtable_res { + @vtbls.map(|os| @os.map(|o| resolve_origin(fcx, sp, o))) + } + fn resolve_origin(fcx: @mut FnCtxt, sp: span, origin: &vtable_origin) -> vtable_origin { match origin { &vtable_static(def_id, ref tys, origins) => { let r_tys = resolve_type_vars_in_types(fcx, sp, *tys); - let r_origins = @origins.map(|o| resolve_origin(fcx, sp, o)); + let r_origins = resolve_origins(fcx, sp, origins); vtable_static(def_id, r_tys, r_origins) } &vtable_param(n, b) => { vtable_param(n, b) } + &vtable_self(def_id) => { + vtable_self(def_id) + } } } } diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index d834998d4ee..98f7af4bfd4 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -135,8 +135,9 @@ pub struct method_map_entry { // of the method to be invoked pub type method_map = @mut HashMap; +pub type vtable_param_res = @~[vtable_origin]; // Resolutions for bounds of all parameters, left to right, for a given path. -pub type vtable_res = @~[vtable_origin]; +pub type vtable_res = @~[vtable_param_res]; pub enum vtable_origin { /* @@ -154,7 +155,12 @@ pub enum vtable_origin { The first uint is the param number (identifying T in the example), and the second is the bound number (identifying baz) */ - vtable_param(uint, uint) + vtable_param(uint, uint), + + /* + Dynamic vtable, comes from self. + */ + vtable_self(ast::def_id) } impl Repr for vtable_origin { @@ -171,6 +177,9 @@ impl Repr for vtable_origin { vtable_param(x, y) => { fmt!("vtable_param(%?, %?)", x, y) } + vtable_self(def_id) => { + fmt!("vtable_self(%?)", def_id) + } } } } diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index aa4d632a482..8555d99255d 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -2346,6 +2346,7 @@ impl FromIter for ~[T]{ } } +#[cfg(stage0)] impl> FromIterator for ~[A] { pub fn from_iterator(iterator: &mut T) -> ~[A] { let mut xs = ~[]; @@ -2356,7 +2357,8 @@ impl> FromIterator for ~[A] { } } -/* FIXME: #7341 - ICE + +#[cfg(not(stage0))] impl> FromIterator for ~[A] { pub fn from_iterator(iterator: &mut T) -> ~[A] { let (lower, _) = iterator.size_hint(); @@ -2367,7 +2369,7 @@ impl> FromIterator for ~[A] { xs } } -*/ + #[cfg(test)] mod tests { diff --git a/src/test/compile-fail/impl-bounds-checking.rs b/src/test/compile-fail/impl-bounds-checking.rs new file mode 100644 index 00000000000..00c415a860d --- /dev/null +++ b/src/test/compile-fail/impl-bounds-checking.rs @@ -0,0 +1,24 @@ +// Copyright 2013 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub trait Clone2 { + fn clone(&self) -> Self; +} + + +trait Getter { + fn get(&self) -> T; +} + +impl Getter for int { //~ ERROR failed to find an implementation of trait Clone2 for int + fn get(&self) -> int { *self } +} + +fn main() { } diff --git a/src/test/run-pass/bug-7183-generics.rs b/src/test/run-pass/bug-7183-generics.rs new file mode 100644 index 00000000000..4fc5587e7f3 --- /dev/null +++ b/src/test/run-pass/bug-7183-generics.rs @@ -0,0 +1,45 @@ +// Copyright 2013 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[allow(default_methods)] +trait Speak { + fn say(&self, s:&str) -> ~str; + fn hi(&self) -> ~str { hello(self) } +} + +fn hello(s:&S) -> ~str{ + s.say("hello") +} + +impl Speak for int { + fn say(&self, s:&str) -> ~str { + fmt!("%s: %d", s, *self) + } +} + +impl Speak for Option { + fn say(&self, s:&str) -> ~str { + match *self { + None => fmt!("%s - none", s), + Some(ref x) => { ~"something!" + x.say(s) } + } + } +} + + +fn main() { + assert_eq!(3.hi(), ~"hello: 3"); + assert_eq!(Some(Some(3)).hi(), ~"something!something!hello: 3"); + assert_eq!(None::.hi(), ~"hello - none"); + + // These fail because of a bug in monomorphization's ID generation. + //assert_eq!(Some(None::).hi(), ~"something!hello - none"); + //assert_eq!(Some(3).hi(), ~"something!hello: 3"); +} diff --git a/src/test/run-pass/trait-with-bounds-default.rs b/src/test/run-pass/trait-with-bounds-default.rs new file mode 100644 index 00000000000..b3ddbbb9dc1 --- /dev/null +++ b/src/test/run-pass/trait-with-bounds-default.rs @@ -0,0 +1,41 @@ +// Copyright 2013 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub trait Clone2 { + /// Returns a copy of the value. The contents of owned pointers + /// are copied to maintain uniqueness, while the contents of + /// managed pointers are not copied. + fn clone(&self) -> Self; +} + +#[allow(default_methods)] +trait Getter { + fn do_get(&self) -> T; + + fn do_get2(&self) -> (T, T) { + let x = self.do_get(); + (x.clone(), x.clone()) + } + +} + +impl Getter for int { + fn do_get(&self) -> int { *self } +} + +impl Getter for Option { + fn do_get(&self) -> T { self.get_ref().clone() } +} + + +fn main() { + assert_eq!(3.do_get2(), (3, 3)); + assert_eq!(Some(~"hi").do_get2(), (~"hi", ~"hi")); +}