From 172ea83adc1e97d1f2fbe72326d1381bf80760bd Mon Sep 17 00:00:00 2001 From: Michael Sullivan Date: Mon, 22 Jul 2013 13:26:47 -0700 Subject: [PATCH 01/12] Get rid of an unused variable warning. --- src/librustc/middle/trans/_match.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 2ff0c39476fe..843aa2b749cf 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -1279,8 +1279,6 @@ pub fn compile_submatch(bcx: @mut Block, assert!((m.len() > 0u || chk.is_some())); let _icx = push_ctxt("match::compile_submatch"); let mut bcx = bcx; - let tcx = bcx.tcx(); - let dm = tcx.def_map; if m.len() == 0u { Br(bcx, chk.get()()); return; From 89c4af0ea959dd911eb4a2fe18b9f1e95ef77b8c Mon Sep 17 00:00:00 2001 From: Michael Sullivan Date: Mon, 22 Jul 2013 17:41:07 -0700 Subject: [PATCH 02/12] Fix a default method polymorphism bug. --- src/librustc/middle/trans/callee.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index 5f76981c7946..3e34f80b1446 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -343,7 +343,7 @@ pub fn trans_fn_ref_with_vtables( let vtables = resolve_default_method_vtables(bcx, impl_id, - method, &new_substs, vtables); + method, &substs, vtables); debug!("trans_fn_with_vtables - default method: \ substs = %s, trait_subst = %s, \ From 4b9759e20fc8a23b3d87765ebb8943adc357ce33 Mon Sep 17 00:00:00 2001 From: Michael Sullivan Date: Fri, 19 Jul 2013 17:21:28 -0700 Subject: [PATCH 03/12] Add a to_owned_vec method to IteratorUtil. --- src/libstd/iterator.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index 198e63f83c60..1aca34894b4f 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -333,6 +333,18 @@ pub trait IteratorUtil { /// ~~~ fn collect>(&mut self) -> B; + /// Loops through the entire iterator, collecting all of the elements into + /// a unique vector. This is simply collect() specialized for vectors. + /// + /// # Example + /// + /// ~~~ {.rust} + /// let a = [1, 2, 3, 4, 5]; + /// let b: ~[int] = a.iter().transform(|&x| x).to_owned_vec(); + /// assert!(a == b); + /// ~~~ + fn to_owned_vec(&mut self) -> ~[A]; + /// Loops through `n` iterations, returning the `n`th element of the /// iterator. /// @@ -529,6 +541,11 @@ impl> IteratorUtil for T { FromIterator::from_iterator(self) } + #[inline] + fn to_owned_vec(&mut self) -> ~[A] { + self.collect() + } + /// Return the `n`th item yielded by an iterator. #[inline] fn nth(&mut self, mut n: uint) -> Option { From fbbbc98ea4aaa59c7266ab4b60f18050a046634e Mon Sep 17 00:00:00 2001 From: Michael Sullivan Date: Thu, 18 Jul 2013 17:20:58 -0700 Subject: [PATCH 04/12] Refactor a bunch of lookup_vtable to reduce rightward drift and clean things up. --- src/librustc/middle/trans/common.rs | 4 +- src/librustc/middle/typeck/check/vtable.rs | 461 +++++++++++---------- src/librustc/middle/typeck/infer/mod.rs | 5 + 3 files changed, 245 insertions(+), 225 deletions(-) diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index fef6607bbed8..e3a661b4b00c 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -1109,7 +1109,9 @@ pub fn find_vtable(tcx: ty::ctxt, debug!("find_vtable(n_param=%u, n_bound=%u, ps=%s)", n_param, n_bound, ps.repr(tcx)); - ps.vtables.get()[n_param][n_bound].clone() + let tables = ps.vtables.expect("vtables missing where they are needed"); + let param_bounds = tables[n_param]; + param_bounds[n_bound].clone() } pub fn dummy_substs(tps: ~[ty::t]) -> ty::substs { diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index da09f79d0312..0052629cd2df 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -16,11 +16,10 @@ 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_res}; +use middle::typeck::{CrateCtxt, vtable_origin, vtable_res, vtable_param_res}; use middle::typeck::{vtable_static, vtable_param, vtable_self}; use middle::subst::Subst; use util::common::indenter; -use util::ppaux::tys_to_str; use util::ppaux; use std::hashmap::HashSet; @@ -84,41 +83,10 @@ fn lookup_vtables(vcx: &VtableContext, substs.repr(vcx.tcx())); let _i = indenter(); - let tcx = vcx.tcx(); let mut result = ~[]; - 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| - { - // ...and here trait_ref is each bound that was declared on A, - // expressed in terms of the type parameters. - - debug!("about to subst: %s, %s", trait_ref.repr(tcx), substs.repr(tcx)); - - // Substitute the values of the type parameters that may - // appear in the bound. - let trait_ref = trait_ref.subst(tcx, substs); - - debug!("after subst: %s", trait_ref.repr(tcx)); - - match lookup_vtable(vcx, location_info, *ty, trait_ref, is_early) { - Some(vtable) => param_result.push(vtable), - None => { - vcx.tcx().sess.span_fatal( - location_info.span, - fmt!("failed to find an implementation of \ - trait %s for %s", - vcx.infcx.trait_ref_to_str(trait_ref), - vcx.infcx.ty_to_str(*ty))); - } - } - } - result.push(@param_result); - i += 1u; + for substs.tps.iter().zip(type_param_defs.iter()).advance |(ty, def)| { + result.push(lookup_vtables_for_param(vcx, location_info, Some(substs), + &*def.bounds, *ty, is_early)); } debug!("lookup_vtables result(\ location_info=%?, \ @@ -132,25 +100,58 @@ fn lookup_vtables(vcx: &VtableContext, @result } -fn fixup_substs(vcx: &VtableContext, - location_info: &LocationInfo, - id: ast::def_id, - substs: ty::substs, - is_early: bool) - -> Option { +fn lookup_vtables_for_param(vcx: &VtableContext, + location_info: &LocationInfo, + // None for substs means the identity + substs: Option<&ty::substs>, + type_param_bounds: &ty::ParamBounds, + ty: ty::t, + is_early: bool) -> vtable_param_res { let tcx = vcx.tcx(); - // use a dummy type just to package up the substs that need fixing up - let t = ty::mk_trait(tcx, - id, substs, - ty::RegionTraitStore(ty::re_static), - ast::m_imm, - ty::EmptyBuiltinBounds()); - do fixup_ty(vcx, location_info, t, is_early).map |t_f| { - match ty::get(*t_f).sty { - ty::ty_trait(_, ref substs_f, _, _, _) => (*substs_f).clone(), - _ => fail!("t_f should be a trait") + + // ty is the value supplied for the type parameter A... + let mut param_result = ~[]; + + for ty::each_bound_trait_and_supertraits( + tcx, type_param_bounds) |trait_ref| + { + // ...and here trait_ref is each bound that was declared on A, + // expressed in terms of the type parameters. + + // Substitute the values of the type parameters that may + // appear in the bound. + let trait_ref = substs.map_default(trait_ref, |substs| { + debug!("about to subst: %s, %s", + trait_ref.repr(tcx), substs.repr(tcx)); + trait_ref.subst(tcx, *substs) + }); + + debug!("after subst: %s", trait_ref.repr(tcx)); + + match lookup_vtable(vcx, location_info, ty, trait_ref, is_early) { + Some(vtable) => param_result.push(vtable), + None => { + vcx.tcx().sess.span_fatal( + location_info.span, + fmt!("failed to find an implementation of \ + trait %s for %s", + vcx.infcx.trait_ref_to_str(trait_ref), + vcx.infcx.ty_to_str(ty))); + } } } + + debug!("lookup_vtables_for_param result(\ + location_info=%?, \ + type_param_bounds=%s, \ + ty=%s, \ + result=%s)", + location_info, + type_param_bounds.repr(vcx.tcx()), + ty.repr(vcx.tcx()), + param_result.repr(vcx.tcx())); + + return @param_result; } fn relate_trait_refs(vcx: &VtableContext, @@ -173,10 +174,15 @@ fn relate_trait_refs(vcx: &VtableContext, { result::Ok(()) => {} // Ok. result::Err(ref err) => { + // There is an error, but we need to do some work to make + // the message good. + // Resolve any type vars in the trait refs let r_act_trait_ref = vcx.infcx.resolve_type_vars_in_trait_ref_if_possible(act_trait_ref); let r_exp_trait_ref = vcx.infcx.resolve_type_vars_in_trait_ref_if_possible(exp_trait_ref); + // Only print the message if there aren't any previous type errors + // inside the types. if !ty::trait_ref_contains_error(&r_act_trait_ref) && !ty::trait_ref_contains_error(&r_exp_trait_ref) { @@ -256,182 +262,186 @@ fn lookup_vtable(vcx: &VtableContext, } _ => { - let mut found = ~[]; - - let mut impls_seen = HashSet::new(); - - match tcx.trait_impls.find(&trait_ref.def_id) { - None => { - // Nothing found. Continue. - } - Some(implementations) => { - // implementations is the list of all impls in scope for - // trait_ref. (Usually, there's just one.) - for implementations.iter().advance |im| { - // im is one specific impl of trait_ref. - - // First, ensure we haven't processed this impl yet. - if impls_seen.contains(&im.did) { - loop; - } - impls_seen.insert(im.did); - - // ty::impl_traits gives us the trait im implements, - // if there is one (there's either zero or one). - // - // If foo implements a trait t, and if t is the - // same trait as trait_ref, we need to - // unify it with trait_ref in order to get all - // the ty vars sorted out. - let r = ty::impl_trait_ref(tcx, im.did); - for r.iter().advance |&of_trait_ref| { - if of_trait_ref.def_id != trait_ref.def_id { loop; } - - // At this point, we know that of_trait_ref is - // the same trait as trait_ref, but - // possibly applied to different substs. - // - // Next, we check whether the "for" ty in - // the impl is compatible with the type - // that we're casting to a trait. That is, - // if im is: - // - // impl self_ty: some_trait { ... } - // - // we check whether self_ty is the type - // of the thing that we're trying to cast - // to some_trait. If not, then we try the next - // impl. - // - // FIXME(#5781) this should be mk_eqty not mk_subty - let ty::ty_param_substs_and_ty { - substs: substs, - ty: for_ty - } = impl_self_ty(vcx, location_info, im.did); - match infer::mk_subty(vcx.infcx, - false, - infer::RelateSelfType( - location_info.span), - ty, - for_ty) { - result::Err(_) => loop, - result::Ok(()) => () - } - - // Now, in the previous example, for_ty is - // bound to the type self_ty, and substs - // is bound to [T]. - debug!("The self ty is %s and its substs are %s", - vcx.infcx.ty_to_str(for_ty), - tys_to_str(vcx.tcx(), substs.tps)); - - // Next, we unify trait_ref -- the type - // that we want to cast to -- with of_trait_ref - // -- the trait that im implements. At - // this point, we require that they be - // unifiable with each other -- that's - // what relate_trait_refs does. - // - // For example, in the above example, - // of_trait_ref would be some_trait, so we - // would be unifying trait_ref (for some - // value of U) with some_trait. This - // would fail if T and U weren't - // compatible. - - debug!("(checking vtable) @2 relating trait \ - ty %s to of_trait_ref %s", - vcx.infcx.trait_ref_to_str(trait_ref), - vcx.infcx.trait_ref_to_str(of_trait_ref)); - - let of_trait_ref = of_trait_ref.subst(tcx, &substs); - relate_trait_refs( - vcx, location_info, - of_trait_ref, trait_ref); - - // Recall that trait_ref -- the trait type - // we're casting to -- is the trait with - // id trait_ref.def_id applied to the substs - // trait_ref.substs. Now we extract out the - // types themselves from trait_ref.substs. - - // Recall that substs is the impl self - // type's list of substitutions. That is, - // if this is an impl of some trait for - // foo, then substs is [T, - // U]. substs might contain type - // variables, so we call fixup_substs to - // resolve them. - - let substs_f = match fixup_substs(vcx, - location_info, - trait_ref.def_id, - substs, - is_early) { - Some(ref substs) => (*substs).clone(), - None => { - assert!(is_early); - // Bail out with a bogus answer - return Some(vtable_param(0, 0)); - } - }; - - debug!("The fixed-up substs are %s - \ - they will be unified with the bounds for \ - the target ty, %s", - tys_to_str(vcx.tcx(), substs_f.tps), - vcx.infcx.trait_ref_to_str(trait_ref)); - - // Next, we unify the fixed-up - // substitutions for the impl self ty with - // the substitutions from the trait type - // that we're trying to cast - // to. connect_trait_tps requires these - // lists of types to unify pairwise. - - let im_generics = - ty::lookup_item_type(tcx, im.did).generics; - connect_trait_tps(vcx, - location_info, - &substs_f, - trait_ref, - im.did); - let subres = lookup_vtables( - vcx, location_info, - *im_generics.type_param_defs, &substs_f, - is_early); - - // Finally, we register that we found a - // matching impl, and record the def ID of - // the impl as well as the resolved list - // of type substitutions for the target - // trait. - found.push(vtable_static(im.did, - substs_f.tps.clone(), - subres)); - } - } - } - } - - match found.len() { - 0 => { /* fallthrough */ } - 1 => return Some(found[0].clone()), - _ => { - if !is_early { - vcx.tcx().sess.span_err( - location_info.span, - "multiple applicable methods in scope"); - } - return Some(found[0].clone()); - } - } + return search_for_vtable(vcx, location_info, + ty, trait_ref, is_early) } } return None; } +fn search_for_vtable(vcx: &VtableContext, + location_info: &LocationInfo, + ty: ty::t, + trait_ref: @ty::TraitRef, + is_early: bool) + -> Option +{ + let tcx = vcx.tcx(); + + let mut found = ~[]; + let mut impls_seen = HashSet::new(); + + // XXX: this is a bad way to do this, since we do + // pointless allocations. + let impls = tcx.trait_impls.find(&trait_ref.def_id) + .map_default(@mut ~[], |x| **x); + // impls is the list of all impls in scope for trait_ref. + for impls.iter().advance |im| { + // im is one specific impl of trait_ref. + + // First, ensure we haven't processed this impl yet. + if impls_seen.contains(&im.did) { + loop; + } + impls_seen.insert(im.did); + + // ty::impl_traits gives us the trait im implements. + // + // If foo implements a trait t, and if t is the same trait as + // trait_ref, we need to unify it with trait_ref in order to + // get all the ty vars sorted out. + let r = ty::impl_trait_ref(tcx, im.did); + let of_trait_ref = r.expect("trait_ref missing on trait impl"); + if of_trait_ref.def_id != trait_ref.def_id { loop; } + + // At this point, we know that of_trait_ref is the same trait + // as trait_ref, but possibly applied to different substs. + // + // Next, we check whether the "for" ty in the impl is + // compatible with the type that we're casting to a + // trait. That is, if im is: + // + // impl some_trait for self_ty { ... } + // + // we check whether self_ty is the type of the thing that + // we're trying to cast to some_trait. If not, then we try + // the next impl. + // + // XXX: document a bit more what this means + // + // FIXME(#5781) this should be mk_eqty not mk_subty + let ty::ty_param_substs_and_ty { + substs: substs, + ty: for_ty + } = impl_self_ty(vcx, location_info, im.did); + match infer::mk_subty(vcx.infcx, + false, + infer::RelateSelfType( + location_info.span), + ty, + for_ty) { + result::Err(_) => loop, + result::Ok(()) => () + } + + // Now, in the previous example, for_ty is bound to + // the type self_ty, and substs is bound to [T]. + debug!("The self ty is %s and its substs are %s", + vcx.infcx.ty_to_str(for_ty), + vcx.infcx.tys_to_str(substs.tps)); + + // Next, we unify trait_ref -- the type that we want to cast + // to -- with of_trait_ref -- the trait that im implements. At + // this point, we require that they be unifiable with each + // other -- that's what relate_trait_refs does. + // + // For example, in the above example, of_trait_ref would be + // some_trait, so we would be unifying trait_ref (for + // some value of U) with some_trait. This would fail if T + // and U weren't compatible. + + debug!("(checking vtable) @2 relating trait \ + ty %s to of_trait_ref %s", + vcx.infcx.trait_ref_to_str(trait_ref), + vcx.infcx.trait_ref_to_str(of_trait_ref)); + + let of_trait_ref = of_trait_ref.subst(tcx, &substs); + relate_trait_refs(vcx, location_info, of_trait_ref, trait_ref); + + // Recall that trait_ref -- the trait type we're casting to -- + // is the trait with id trait_ref.def_id applied to the substs + // trait_ref.substs. Now we extract out the types themselves + // from trait_ref.substs. + + // Recall that substs is the impl self type's list of + // substitutions. That is, if this is an impl of some trait + // for foo, then substs is [T, U]. substs might contain + // type variables, so we call fixup_substs to resolve them. + + let substs_f = match fixup_substs(vcx, + location_info, + trait_ref.def_id, + substs, + is_early) { + Some(ref substs) => (*substs).clone(), + None => { + assert!(is_early); + // Bail out with a bogus answer + return Some(vtable_param(0, 0)); + } + }; + + debug!("The fixed-up substs are %s - \ + they will be unified with the bounds for \ + the target ty, %s", + vcx.infcx.tys_to_str(substs_f.tps), + vcx.infcx.trait_ref_to_str(trait_ref)); + + // Next, we unify the fixed-up substitutions for the impl self + // ty with the substitutions from the trait type that we're + // trying to cast to. connect_trait_tps requires these lists + // of types to unify pairwise. + + let im_generics = + ty::lookup_item_type(tcx, im.did).generics; + connect_trait_tps(vcx, location_info, &substs_f, trait_ref, im.did); + let subres = lookup_vtables(vcx, location_info, + *im_generics.type_param_defs, &substs_f, + is_early); + + // Finally, we register that we found a matching impl, and + // record the def ID of the impl as well as the resolved list + // of type substitutions for the target trait. + found.push(vtable_static(im.did, substs_f.tps.clone(), subres)); + } + + match found.len() { + 0 => { return None } + 1 => return Some(found[0].clone()), + _ => { + if !is_early { + vcx.tcx().sess.span_err( + location_info.span, + "multiple applicable methods in scope"); + } + return Some(found[0].clone()); + } + } +} + + +fn fixup_substs(vcx: &VtableContext, + location_info: &LocationInfo, + id: ast::def_id, + substs: ty::substs, + is_early: bool) + -> Option { + let tcx = vcx.tcx(); + // use a dummy type just to package up the substs that need fixing up + let t = ty::mk_trait(tcx, + id, substs, + ty::RegionTraitStore(ty::re_static), + ast::m_imm, + ty::EmptyBuiltinBounds()); + do fixup_ty(vcx, location_info, t, is_early).map |t_f| { + match ty::get(*t_f).sty { + ty::ty_trait(_, ref substs_f, _, _, _) => (*substs_f).clone(), + _ => fail!("t_f should be a trait") + } + } +} + fn fixup_ty(vcx: &VtableContext, location_info: &LocationInfo, ty: ty::t, @@ -682,10 +692,13 @@ pub fn resolve_impl(ccx: @mut CrateCtxt, impl_item: @ast::item) { 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 loc_info = location_info_for_item(impl_item); + // First, check that the impl implements any trait bounds + // on the trait. + let trait_def = ty::lookup_trait_def(ccx.tcx, trait_ref.def_id); let vtbls = lookup_vtables(&vcx, - &location_info_for_item(impl_item), + &loc_info, *trait_def.generics.type_param_defs, &trait_ref.substs, false); diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index 1f0fb1357628..eb32f4e59f00 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -653,6 +653,11 @@ impl InferCtxt { self.resolve_type_vars_if_possible(t)) } + pub fn tys_to_str(@mut self, ts: &[ty::t]) -> ~str { + let tstrs = ts.map(|t| self.ty_to_str(*t)); + fmt!("(%s)", tstrs.connect(", ")) + } + pub fn trait_ref_to_str(@mut self, t: &ty::TraitRef) -> ~str { let t = self.resolve_type_vars_in_trait_ref_if_possible(t); trait_ref_to_str(self.tcx, &t) From e75ec8015701d4a43ec2644dbbc4a2e051c4f515 Mon Sep 17 00:00:00 2001 From: Michael Sullivan Date: Tue, 23 Jul 2013 17:01:43 -0700 Subject: [PATCH 05/12] Improve vtable resolution. Improve vtable resolution in a handful of ways. First, if we don't find a vtable for a self/param type, do a regular vtable search. This could find impls of the form "impl for A". Second, we don't require that types be fully resolved before looking up subtables, and we process tables in reverse order. This allows us to gain more information about early type parameters based on how they are used by the impls used to resolve later params. Closes #6967, I believe. --- src/librustc/middle/typeck/check/vtable.rs | 70 ++++++++++++++-------- 1 file changed, 46 insertions(+), 24 deletions(-) diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 0052629cd2df..9143563a68fd 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -45,6 +45,16 @@ use syntax::visit; // *fully* resolved. (We could be less restrictive than that, but it // would require much more care, and this seems to work decently in // practice.) +// +// While resolution on a single type requires the type to be fully +// resolved, when resolving a substitution against a list of bounds, +// we do not require all of the types to be resolved in advance. +// Furthermore, we process substitutions in reverse order, which +// allows resolution on later parameters to give information on +// earlier params referenced by the typeclass bounds. +// It may be better to do something more clever, like processing fully +// resolved types first. + /// Location info records the span and ID of the expression or item that is /// responsible for this vtable instantiation. (This may not be an expression @@ -83,11 +93,19 @@ fn lookup_vtables(vcx: &VtableContext, substs.repr(vcx.tcx())); let _i = indenter(); - let mut result = ~[]; - for substs.tps.iter().zip(type_param_defs.iter()).advance |(ty, def)| { - result.push(lookup_vtables_for_param(vcx, location_info, Some(substs), - &*def.bounds, *ty, is_early)); - } + + // We do this backwards for reasons discussed above. + assert_eq!(substs.tps.len(), type_param_defs.len()); + let mut result = + substs.tps.rev_iter() + .zip(type_param_defs.rev_iter()) + .transform(|(ty, def)| + lookup_vtables_for_param(vcx, location_info, Some(substs), + &*def.bounds, *ty, is_early)) + .to_owned_vec(); + result.reverse(); + + assert_eq!(substs.tps.len(), result.len()); debug!("lookup_vtables result(\ location_info=%?, \ type_param_defs=%s, \ @@ -198,8 +216,7 @@ fn relate_trait_refs(vcx: &VtableContext, } } -// Look up the vtable to use when treating an item of type `t` as if it has -// type `trait_ty` +// Look up the vtable implementing the trait `trait_ref` at type `t` fn lookup_vtable(vcx: &VtableContext, location_info: &LocationInfo, ty: ty::t, @@ -261,13 +278,14 @@ fn lookup_vtable(vcx: &VtableContext, } } - _ => { - return search_for_vtable(vcx, location_info, - ty, trait_ref, is_early) - } + // Default case just falls through + _ => { } } - return None; + // If we aren't a self type or param, or it was, but we didn't find it, + // do a search. + return search_for_vtable(vcx, location_info, + ty, trait_ref, is_early) } fn search_for_vtable(vcx: &VtableContext, @@ -359,16 +377,23 @@ fn search_for_vtable(vcx: &VtableContext, let of_trait_ref = of_trait_ref.subst(tcx, &substs); relate_trait_refs(vcx, location_info, of_trait_ref, trait_ref); + // Recall that trait_ref -- the trait type we're casting to -- // is the trait with id trait_ref.def_id applied to the substs - // trait_ref.substs. Now we extract out the types themselves - // from trait_ref.substs. + // trait_ref.substs. - // Recall that substs is the impl self type's list of - // substitutions. That is, if this is an impl of some trait - // for foo, then substs is [T, U]. substs might contain - // type variables, so we call fixup_substs to resolve them. + // Resolve any sub bounds. Note that there still may be free + // type variables in substs. This might still be OK: the + // process of looking up bounds might constrain some of them. + let im_generics = + ty::lookup_item_type(tcx, im.did).generics; + let subres = lookup_vtables(vcx, location_info, + *im_generics.type_param_defs, &substs, + is_early); + + // substs might contain type variables, so we call + // fixup_substs to resolve them. let substs_f = match fixup_substs(vcx, location_info, trait_ref.def_id, @@ -392,13 +417,10 @@ fn search_for_vtable(vcx: &VtableContext, // ty with the substitutions from the trait type that we're // trying to cast to. connect_trait_tps requires these lists // of types to unify pairwise. - - let im_generics = - ty::lookup_item_type(tcx, im.did).generics; + // I am a little confused about this, since it seems to be + // very similar to the relate_trait_refs we already do, + // but problems crop up if it is removed, so... -sully connect_trait_tps(vcx, location_info, &substs_f, trait_ref, im.did); - let subres = lookup_vtables(vcx, location_info, - *im_generics.type_param_defs, &substs_f, - is_early); // Finally, we register that we found a matching impl, and // record the def ID of the impl as well as the resolved list From a0f8540c9571dadb9af542799156cc8a96263c41 Mon Sep 17 00:00:00 2001 From: Michael Sullivan Date: Fri, 19 Jul 2013 15:21:52 -0700 Subject: [PATCH 06/12] Fix some impls such that all supertraits are actually implemented. --- src/libextra/num/bigint.rs | 5 +++++ src/libextra/num/rational.rs | 19 +++++++++++++++++++ src/libstd/cmp.rs | 6 ++++++ src/libstd/iterator.rs | 2 +- 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/libextra/num/bigint.rs b/src/libextra/num/bigint.rs index d940b6d6667f..46a744572749 100644 --- a/src/libextra/num/bigint.rs +++ b/src/libextra/num/bigint.rs @@ -732,6 +732,11 @@ impl Ord for Sign { } } +impl TotalEq for Sign { + fn equals(&self, other: &Sign) -> bool { + *self == *other + } +} impl TotalOrd for Sign { fn cmp(&self, other: &Sign) -> Ordering { diff --git a/src/libextra/num/rational.rs b/src/libextra/num/rational.rs index 6733599d1ea2..ff14009e5561 100644 --- a/src/libextra/num/rational.rs +++ b/src/libextra/num/rational.rs @@ -110,6 +110,25 @@ cmp_impl!(impl TotalEq, equals) cmp_impl!(impl Ord, lt, gt, le, ge) cmp_impl!(impl TotalOrd, cmp -> cmp::Ordering) +impl Orderable for Ratio { + #[inline] + fn min(&self, other: &Ratio) -> Ratio { + if *self < *other { self.clone() } else { other.clone() } + } + + #[inline] + fn max(&self, other: &Ratio) -> Ratio { + if *self > *other { self.clone() } else { other.clone() } + } + + #[inline] + fn clamp(&self, mn: &Ratio, mx: &Ratio) -> Ratio { + if *self > *mx { mx.clone()} else + if *self < *mn { mn.clone() } else { self.clone() } + } +} + + /* Arithmetic */ // a/b * c/d = (a*c)/(b*d) impl diff --git a/src/libstd/cmp.rs b/src/libstd/cmp.rs index 8a13cab28c3b..eee786524f57 100644 --- a/src/libstd/cmp.rs +++ b/src/libstd/cmp.rs @@ -86,6 +86,12 @@ pub trait TotalOrd: TotalEq { fn cmp(&self, other: &Self) -> Ordering; } +impl TotalEq for Ordering { + #[inline] + fn equals(&self, other: &Ordering) -> bool { + *self == *other + } +} impl TotalOrd for Ordering { #[inline] fn cmp(&self, other: &Ordering) -> Ordering { diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index 1aca34894b4f..d7edf746f90d 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -86,7 +86,7 @@ impl> Iterator for InvertIterator { fn size_hint(&self) -> (uint, Option) { self.iter.size_hint() } } -impl> DoubleEndedIterator for InvertIterator { +impl> DoubleEndedIterator for InvertIterator { #[inline] fn next_back(&mut self) -> Option { self.iter.next() } } From 304a5f07867cff4cb6a558d320efafd7c6da56c3 Mon Sep 17 00:00:00 2001 From: Michael Sullivan Date: Fri, 19 Jul 2013 17:19:04 -0700 Subject: [PATCH 07/12] Have vtable resolution check for supertrait bounds. Closes #4055. --- src/librustc/middle/typeck/check/vtable.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 9143563a68fd..6ab6af2baeec 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -727,6 +727,23 @@ pub fn resolve_impl(ccx: @mut CrateCtxt, impl_item: @ast::item) { // FIXME(#7450): Doesn't work cross crate ccx.vtable_map.insert(impl_item.id, vtbls); + + // Now, locate the vtable for the impl itself. The real + // purpose of this is to check for supertrait impls, + // but that falls out of doing this. + let param_bounds = ty::ParamBounds { + builtin_bounds: ty::EmptyBuiltinBounds(), + trait_bounds: ~[trait_ref] + }; + let t = ty::node_id_to_type(ccx.tcx, impl_item.id); + debug!("=== Doing a self lookup now."); + // Right now, we don't have any place to store this. + // We will need to make one so we can use this information + // for compiling default methods that refer to supertraits. + let _self_vtable_res = + lookup_vtables_for_param(&vcx, &loc_info, None, + ¶m_bounds, t, false); + } } } From 79f8a7fee5c82d6b5d108f9930d9445fb0e6c94a Mon Sep 17 00:00:00 2001 From: Michael Sullivan Date: Mon, 22 Jul 2013 16:40:31 -0700 Subject: [PATCH 08/12] Properly track and export information about vtables for impls in metadata. Partially rework how vtables are handled in default method calls. Closes #7460. --- src/librustc/metadata/common.rs | 1 + src/librustc/metadata/csearch.rs | 9 +++ src/librustc/metadata/decoder.rs | 18 +++++ src/librustc/metadata/encoder.rs | 13 ++++ src/librustc/middle/astencode.rs | 91 +++++++++++++++++----- src/librustc/middle/trans/callee.rs | 58 +++++--------- src/librustc/middle/trans/common.rs | 29 ++++--- src/librustc/middle/trans/meth.rs | 7 +- src/librustc/middle/trans/monomorphize.rs | 9 +-- src/librustc/middle/ty.rs | 12 +++ src/librustc/middle/typeck/check/vtable.rs | 13 ++-- src/librustc/middle/typeck/mod.rs | 22 ++++++ 12 files changed, 202 insertions(+), 80 deletions(-) diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 645188ce5a4d..1c5d202d4d95 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -180,6 +180,7 @@ pub static tag_misc_info: uint = 0x7f; pub static tag_misc_info_crate_items: uint = 0x80; pub static tag_item_method_provided_source: uint = 0x81; +pub static tag_item_impl_vtables: uint = 0x82; pub struct LinkMeta { name: @str, diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 97344ee91adb..6f7feae4479b 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -16,6 +16,7 @@ use metadata::cstore; use metadata::decoder; use metadata; use middle::ty; +use middle::typeck; use std::vec; use reader = extra::ebml::reader; @@ -216,6 +217,14 @@ pub fn get_impl_trait(tcx: ty::ctxt, decoder::get_impl_trait(cdata, def.node, tcx) } +// Given a def_id for an impl, return information about its vtables +pub fn get_impl_vtables(tcx: ty::ctxt, + def: ast::def_id) -> typeck::impl_res { + let cstore = tcx.cstore; + let cdata = cstore::get_crate_data(cstore, def.crate); + decoder::get_impl_vtables(cdata, def.node, tcx) +} + pub fn get_impl_method(cstore: @mut cstore::CStore, def: ast::def_id, mname: ast::ident) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 6e166cfbfc85..0f6a912b917a 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -21,6 +21,9 @@ use metadata::tydecode::{parse_ty_data, parse_def_id, parse_type_param_def_data, parse_bare_fn_ty_data, parse_trait_ref_data}; use middle::ty; +use middle::typeck; +use middle::astencode::vtable_decoder_helpers; + use std::hash::HashUtil; use std::int; @@ -410,6 +413,21 @@ pub fn get_impl_trait(cdata: cmd, } } +pub fn get_impl_vtables(cdata: cmd, + id: ast::node_id, + tcx: ty::ctxt) -> typeck::impl_res +{ + let item_doc = lookup_item(id, cdata.data); + let vtables_doc = reader::get_doc(item_doc, tag_item_impl_vtables); + let mut decoder = reader::Decoder(vtables_doc); + + typeck::impl_res { + trait_vtables: decoder.read_vtable_res(tcx, cdata), + self_vtables: decoder.read_vtable_param_res(tcx, cdata) + } +} + + pub fn get_impl_method(intr: @ident_interner, cdata: cmd, id: ast::node_id, name: ast::ident) -> Option { let items = reader::get_doc(reader::Doc(cdata.data), tag_items); diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 3c02609def11..2af8e84cd3e9 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -17,6 +17,8 @@ use metadata::decoder; use metadata::tyencode; use middle::ty::{node_id_to_type, lookup_item_type}; use middle::ty; +use middle::typeck; +use middle::astencode; use middle; use std::hash::HashUtil; @@ -162,6 +164,15 @@ fn encode_trait_ref(ebml_w: &mut writer::Encoder, ebml_w.end_tag(); } +fn encode_impl_vtables(ebml_w: &mut writer::Encoder, + ecx: &EncodeContext, + vtables: &typeck::impl_res) { + ebml_w.start_tag(tag_item_impl_vtables); + astencode::encode_vtable_res(ecx, ebml_w, vtables.trait_vtables); + astencode::encode_vtable_param_res(ecx, ebml_w, vtables.self_vtables); + ebml_w.end_tag(); +} + // Item info table encoding fn encode_family(ebml_w: &mut writer::Encoder, c: char) { ebml_w.start_tag(tag_items_data_item_family); @@ -1009,6 +1020,8 @@ fn encode_info_for_item(ecx: &EncodeContext, let trait_ref = ty::node_id_to_trait_ref( tcx, ast_trait_ref.ref_id); encode_trait_ref(ebml_w, ecx, trait_ref, tag_item_trait_ref); + let impl_vtables = ty::lookup_impl_vtables(tcx, def_id); + encode_impl_vtables(ebml_w, ecx, &impl_vtables); } encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); ebml_w.end_tag(); diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index f3e0779475cc..447f7315f94c 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -250,6 +250,8 @@ impl def_id_encoder_helpers for S { trait def_id_decoder_helpers { fn read_def_id(&mut self, xcx: @ExtendedDecodeContext) -> ast::def_id; + fn read_def_id_noxcx(&mut self, + cdata: @cstore::crate_metadata) -> ast::def_id; } impl def_id_decoder_helpers for D { @@ -257,6 +259,12 @@ impl def_id_decoder_helpers for D { let did: ast::def_id = Decodable::decode(self); did.tr(xcx) } + + fn read_def_id_noxcx(&mut self, + cdata: @cstore::crate_metadata) -> ast::def_id { + let did: ast::def_id = Decodable::decode(self); + decoder::translate_def_id(cdata, did) + } } // ______________________________________________________________________ @@ -595,7 +603,7 @@ impl tr for method_origin { // ______________________________________________________________________ // Encoding and decoding vtable_res -fn encode_vtable_res(ecx: &e::EncodeContext, +pub fn encode_vtable_res(ecx: &e::EncodeContext, ebml_w: &mut writer::Encoder, dr: typeck::vtable_res) { // can't autogenerate this code because automatic code of @@ -603,13 +611,20 @@ fn encode_vtable_res(ecx: &e::EncodeContext, // hand-written encoding routines combine with auto-generated // ones. perhaps we should fix this. 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) - } + encode_vtable_param_res(ecx, ebml_w, *param_tables); } } -fn encode_vtable_origin(ecx: &e::EncodeContext, +pub fn encode_vtable_param_res(ecx: &e::EncodeContext, + ebml_w: &mut writer::Encoder, + param_tables: typeck::vtable_param_res) { + do ebml_w.emit_from_vec(*param_tables) |ebml_w, vtable_origin| { + encode_vtable_origin(ecx, ebml_w, vtable_origin) + } +} + + +pub fn encode_vtable_origin(ecx: &e::EncodeContext, ebml_w: &mut writer::Encoder, vtable_origin: &typeck::vtable_origin) { do ebml_w.emit_enum("vtable_origin") |ebml_w| { @@ -648,22 +663,35 @@ fn encode_vtable_origin(ecx: &e::EncodeContext, } } -trait vtable_decoder_helpers { - fn read_vtable_res(&mut self, xcx: @ExtendedDecodeContext) +pub trait vtable_decoder_helpers { + fn read_vtable_res(&mut self, + tcx: ty::ctxt, cdata: @cstore::crate_metadata) -> typeck::vtable_res; - fn read_vtable_origin(&mut self, xcx: @ExtendedDecodeContext) + fn read_vtable_param_res(&mut self, + tcx: ty::ctxt, cdata: @cstore::crate_metadata) + -> typeck::vtable_param_res; + fn read_vtable_origin(&mut self, + tcx: ty::ctxt, cdata: @cstore::crate_metadata) -> typeck::vtable_origin; } impl vtable_decoder_helpers for reader::Decoder { - fn read_vtable_res(&mut self, xcx: @ExtendedDecodeContext) + fn read_vtable_res(&mut self, + tcx: ty::ctxt, cdata: @cstore::crate_metadata) -> typeck::vtable_res { @self.read_to_vec(|this| - @this.read_to_vec(|this| - this.read_vtable_origin(xcx))) + this.read_vtable_param_res(tcx, cdata)) } - fn read_vtable_origin(&mut self, xcx: @ExtendedDecodeContext) + fn read_vtable_param_res(&mut self, + tcx: ty::ctxt, cdata: @cstore::crate_metadata) + -> typeck::vtable_param_res { + @self.read_to_vec(|this| + this.read_vtable_origin(tcx, cdata)) + } + + fn read_vtable_origin(&mut self, + tcx: ty::ctxt, cdata: @cstore::crate_metadata) -> typeck::vtable_origin { do self.read_enum("vtable_origin") |this| { do this.read_enum_variant(["vtable_static", @@ -674,13 +702,13 @@ impl vtable_decoder_helpers for reader::Decoder { 0 => { typeck::vtable_static( do this.read_enum_variant_arg(0u) |this| { - this.read_def_id(xcx) + this.read_def_id_noxcx(cdata) }, do this.read_enum_variant_arg(1u) |this| { - this.read_tys(xcx) + this.read_tys_noxcx(tcx, cdata) }, do this.read_enum_variant_arg(2u) |this| { - this.read_vtable_res(xcx) + this.read_vtable_res(tcx, cdata) } ) } @@ -697,7 +725,7 @@ impl vtable_decoder_helpers for reader::Decoder { 2 => { typeck::vtable_self( do this.read_enum_variant_arg(0u) |this| { - this.read_def_id(xcx) + this.read_def_id_noxcx(cdata) } ) } @@ -995,9 +1023,35 @@ trait ebml_decoder_decoder_helpers { source: DefIdSource, did: ast::def_id) -> ast::def_id; + + // Versions of the type reading functions that don't need the full + // ExtendedDecodeContext. + fn read_ty_noxcx(&mut self, + tcx: ty::ctxt, cdata: @cstore::crate_metadata) -> ty::t; + fn read_tys_noxcx(&mut self, + tcx: ty::ctxt, + cdata: @cstore::crate_metadata) -> ~[ty::t]; } impl ebml_decoder_decoder_helpers for reader::Decoder { + fn read_ty_noxcx(&mut self, + tcx: ty::ctxt, cdata: @cstore::crate_metadata) -> ty::t { + do self.read_opaque |_, doc| { + tydecode::parse_ty_data( + *doc.data, + cdata.cnum, + doc.start, + tcx, + |_, id| decoder::translate_def_id(cdata, id)) + } + } + + fn read_tys_noxcx(&mut self, + tcx: ty::ctxt, + cdata: @cstore::crate_metadata) -> ~[ty::t] { + self.read_to_vec(|this| this.read_ty_noxcx(tcx, cdata) ) + } + fn read_ty(&mut self, xcx: @ExtendedDecodeContext) -> ty::t { // Note: regions types embed local node ids. In principle, we // should translate these node ids into the new decode @@ -1160,8 +1214,9 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext, val_dsr.read_method_map_entry(xcx)); } c::tag_table_vtable_map => { - dcx.maps.vtable_map.insert(id, - val_dsr.read_vtable_res(xcx)); + dcx.maps.vtable_map.insert( + id, + val_dsr.read_vtable_res(xcx.dcx.tcx, xcx.dcx.cdata)); } c::tag_table_adjustments => { let adj: @ty::AutoAdjustment = @Decodable::decode(val_dsr); diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index 3e34f80b1446..858294a9ffad 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -193,30 +193,15 @@ pub fn trans_fn_ref_with_vtables_to_callee( type_params, vtables))} } -fn get_impl_resolutions(bcx: @mut Block, - impl_id: ast::def_id) - -> typeck::vtable_res { - if impl_id.crate == ast::local_crate { - bcx.ccx().maps.vtable_map.get_copy(&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: @mut Block, impl_id: ast::def_id, method: &ty::Method, substs: &ty::substs, impl_vtables: Option) - -> typeck::vtable_res { + -> (typeck::vtable_res, typeck::vtable_param_res) { // Get the vtables that the impl implements the trait at - let trait_vtables = get_impl_resolutions(bcx, impl_id); + let impl_res = ty::lookup_impl_vtables(bcx.tcx(), impl_id); // Build up a param_substs that we are going to resolve the // trait_vtables under. @@ -224,11 +209,11 @@ fn resolve_default_method_vtables(bcx: @mut Block, tys: substs.tps.clone(), self_ty: substs.self_ty, vtables: impl_vtables, - self_vtable: None + self_vtables: None }); let trait_vtables_fixed = resolve_vtables_under_param_substs( - bcx.tcx(), param_substs, trait_vtables); + bcx.tcx(), param_substs, impl_res.trait_vtables); // Now we pull any vtables for parameters on the actual method. let num_method_vtables = method.generics.type_param_defs.len(); @@ -241,7 +226,12 @@ fn resolve_default_method_vtables(bcx: @mut Block, None => vec::from_elem(num_method_vtables, @~[]) }; - @(*trait_vtables_fixed + method_vtables) + let param_vtables = @(*trait_vtables_fixed + method_vtables); + + let self_vtables = resolve_param_vtables_under_param_substs( + bcx.tcx(), param_substs, impl_res.self_vtables); + + (param_vtables, self_vtables) } @@ -296,7 +286,7 @@ pub fn trans_fn_ref_with_vtables( // 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 (is_default, def_id, substs, self_vtable, vtables) = + let (is_default, def_id, substs, self_vtables, vtables) = match ty::provided_source(tcx, def_id) { None => (false, def_id, substs, None, vtables), Some(source_id) => { @@ -319,20 +309,6 @@ pub fn trans_fn_ref_with_vtables( .expect("could not find trait_ref for impl with \ default methods"); - // 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(impl_id, receiver_substs, - receiver_vtables); // Compute the first substitution let first_subst = make_substs_for_receiver_types( tcx, impl_id, trait_ref, method); @@ -341,20 +317,22 @@ pub fn trans_fn_ref_with_vtables( let new_substs = first_subst.subst(tcx, &substs); - let vtables = + let (param_vtables, self_vtables) = resolve_default_method_vtables(bcx, impl_id, method, &substs, vtables); debug!("trans_fn_with_vtables - default method: \ substs = %s, trait_subst = %s, \ first_subst = %s, new_subst = %s, \ - self_vtable = %s, vtables = %s", + vtables = %s, \ + self_vtable = %s, param_vtables = %s", substs.repr(tcx), trait_ref.substs.repr(tcx), first_subst.repr(tcx), new_substs.repr(tcx), - self_vtable.repr(tcx), vtables.repr(tcx)); + vtables.repr(tcx), + self_vtables.repr(tcx), param_vtables.repr(tcx)); (true, source_id, - new_substs, Some(self_vtable), Some(vtables)) + new_substs, Some(self_vtables), Some(param_vtables)) } }; @@ -400,7 +378,7 @@ pub fn trans_fn_ref_with_vtables( let (val, must_cast) = monomorphize::monomorphic_fn(ccx, def_id, &substs, - vtables, self_vtable, + vtables, self_vtables, Some(ref_id)); let mut val = val; if must_cast && ref_id != 0 { diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index e3a661b4b00c..5d9c44b85e18 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -133,7 +133,7 @@ pub struct param_substs { tys: ~[ty::t], self_ty: Option, vtables: Option, - self_vtable: Option + self_vtables: Option } impl param_substs { @@ -1037,14 +1037,25 @@ pub fn resolve_vtables_under_param_substs(tcx: ty::ctxt, vts: typeck::vtable_res) -> typeck::vtable_res { @vts.iter().transform(|ds| - @ds.iter().transform( - |d| resolve_vtable_under_param_substs(tcx, - param_substs, - d)) - .collect::<~[typeck::vtable_origin]>()) - .collect::<~[typeck::vtable_param_res]>() + resolve_param_vtables_under_param_substs(tcx, + param_substs, + *ds)) + .collect() } +pub fn resolve_param_vtables_under_param_substs( + tcx: ty::ctxt, + param_substs: Option<@param_substs>, + ds: typeck::vtable_param_res) + -> typeck::vtable_param_res { + @ds.iter().transform( + |d| resolve_vtable_under_param_substs(tcx, + param_substs, + d)) + .collect() +} + + // Apply the typaram substitutions in the FunctionContext to a vtable. This should // eliminate any vtable_params. @@ -1088,8 +1099,8 @@ pub fn resolve_vtable_under_param_substs(tcx: ty::ctxt, typeck::vtable_self(_trait_id) => { match param_substs { Some(@param_substs - {self_vtable: Some(ref self_vtable), _}) => { - (*self_vtable).clone() + {self_vtables: Some(self_vtables), _}) => { + self_vtables[0].clone() } _ => { tcx.sess.bug(fmt!( diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index a65999ff2aa1..1ee4cd5d2cbb 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -222,14 +222,15 @@ pub fn trans_method_callee(bcx: @mut Block, typeck::method_self(trait_id, method_index) => { match bcx.fcx.param_substs { Some(@param_substs - {self_vtable: Some(ref vtbl), _}) => { + {self_vtables: Some(vtbls), _}) => { + let vtbl = vtbls[0].clone(); trans_monomorphized_callee(bcx, callee_id, this, mentry, trait_id, method_index, - (*vtbl).clone()) + vtbl) } _ => { fail!("trans_method_callee: missing self_vtable") @@ -611,7 +612,7 @@ pub fn vtable_id(ccx: @mut CrateContext, tys: (*substs).clone(), vtables: Some(sub_vtables), self_ty: None, - self_vtable: None + self_vtables: None }; monomorphize::make_mono_id( diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index 789532abc611..9852e6b09b76 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -41,7 +41,7 @@ pub fn monomorphic_fn(ccx: @mut CrateContext, fn_id: ast::def_id, real_substs: &ty::substs, vtables: Option, - self_vtable: Option, + self_vtables: Option, ref_id: Option) -> (ValueRef, bool) { @@ -54,7 +54,7 @@ pub fn monomorphic_fn(ccx: @mut CrateContext, fn_id.repr(ccx.tcx), real_substs.repr(ccx.tcx), vtables.repr(ccx.tcx), - self_vtable.repr(ccx.tcx), + self_vtables.repr(ccx.tcx), ref_id); assert!(real_substs.tps.iter().all(|t| !ty::type_needs_infer(*t))); @@ -72,7 +72,7 @@ pub fn monomorphic_fn(ccx: @mut CrateContext, tys: real_substs.tps.map(|x| do_normalize(x)), vtables: vtables, self_ty: real_substs.self_ty.map(|x| do_normalize(x)), - self_vtable: self_vtable + self_vtables: self_vtables }; for real_substs.tps.iter().advance |s| { assert!(!ty::type_has_params(*s)); } @@ -371,8 +371,7 @@ pub fn make_mono_id(ccx: @mut CrateContext, Some(vts) => { debug!("make_mono_id vtables=%s substs=%s", vts.repr(ccx.tcx), substs.tys.repr(ccx.tcx)); - let self_vtables = substs.self_vtable.map(|vtbl| @~[(*vtbl).clone()]); - let vts_iter = self_vtables.iter().chain_(vts.iter()); + let vts_iter = substs.self_vtables.iter().chain_(vts.iter()); vts_iter.zip(substs_iter).transform(|(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/ty.rs b/src/librustc/middle/ty.rs index cd9d744c2403..3e0b7552ba04 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -317,6 +317,9 @@ struct ctxt_ { // some point. Local variable definitions not in this set can be warned // about. used_mut_nodes: @mut HashSet, + + // vtable resolution information for impl declarations + impl_vtables: typeck::impl_vtable_map } pub enum tbox_flag { @@ -911,6 +914,7 @@ pub fn mk_ctxt(s: session::Session, impls: @mut HashMap::new(), used_unsafe: @mut HashSet::new(), used_mut_nodes: @mut HashSet::new(), + impl_vtables: @mut HashMap::new(), } } @@ -3955,6 +3959,14 @@ pub fn lookup_item_type(cx: ctxt, || csearch::get_type(cx, did)) } +pub fn lookup_impl_vtables(cx: ctxt, + did: ast::def_id) + -> typeck::impl_res { + lookup_locally_or_in_crate_store( + "impl_vtables", did, cx.impl_vtables, + || csearch::get_impl_vtables(cx, did) ) +} + /// Given the did of a trait, returns its canonical trait ref. pub fn lookup_trait_def(cx: ctxt, did: ast::def_id) -> @ty::TraitDef { match cx.trait_defs.find(&did) { diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 6ab6af2baeec..406e4f5b30da 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -17,7 +17,7 @@ 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_res, vtable_param_res}; -use middle::typeck::{vtable_static, vtable_param, vtable_self}; +use middle::typeck::{vtable_static, vtable_param, vtable_self, impl_res}; use middle::subst::Subst; use util::common::indenter; use util::ppaux; @@ -725,9 +725,6 @@ pub fn resolve_impl(ccx: @mut CrateCtxt, impl_item: @ast::item) { &trait_ref.substs, false); - // FIXME(#7450): Doesn't work cross crate - ccx.vtable_map.insert(impl_item.id, vtbls); - // Now, locate the vtable for the impl itself. The real // purpose of this is to check for supertrait impls, // but that falls out of doing this. @@ -740,10 +737,16 @@ pub fn resolve_impl(ccx: @mut CrateCtxt, impl_item: @ast::item) { // Right now, we don't have any place to store this. // We will need to make one so we can use this information // for compiling default methods that refer to supertraits. - let _self_vtable_res = + let self_vtable_res = lookup_vtables_for_param(&vcx, &loc_info, None, ¶m_bounds, t, false); + + let res = impl_res { + trait_vtables: vtbls, + self_vtables: self_vtable_res + }; + ccx.tcx.impl_vtables.insert(def_id, res); } } } diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index 81b18e746b23..261f26671146 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -187,6 +187,28 @@ impl Repr for vtable_origin { pub type vtable_map = @mut HashMap; + +// Information about the vtable resolutions for for a trait impl. +// Mostly the information is important for implementing default +// methods. +#[deriving(Clone)] +pub struct impl_res { + // resolutions for any bounded params on the trait definition + trait_vtables: vtable_res, + // resolutions for the trait /itself/ (and for supertraits) + self_vtables: vtable_param_res +} + +impl Repr for impl_res { + fn repr(&self, tcx: ty::ctxt) -> ~str { + fmt!("impl_res {trait_vtables=%s, self_vtables=%s}", + self.trait_vtables.repr(tcx), + self.self_vtables.repr(tcx)) + } +} + +pub type impl_vtable_map = @mut HashMap; + pub struct CrateCtxt { // A mapping from method call sites to traits that have that method. trait_map: resolve::TraitMap, From ffc879c2e46c8ffd7dc35b9d3169286fca609bc3 Mon Sep 17 00:00:00 2001 From: Michael Sullivan Date: Mon, 22 Jul 2013 17:42:45 -0700 Subject: [PATCH 09/12] Major rework of how calls to self and super methods work. Eliminates method_super, method_self, and vtable_self, merging all of them into the param cases. Cloes #4396. Closes #7301. --- src/librustc/middle/astencode.rs | 24 +- src/librustc/middle/privacy.rs | 7 +- src/librustc/middle/trans/common.rs | 27 +-- src/librustc/middle/trans/meth.rs | 63 +----- src/librustc/middle/trans/type_use.rs | 5 +- src/librustc/middle/ty.rs | 29 +-- src/librustc/middle/typeck/check/method.rs | 207 +++++++----------- src/librustc/middle/typeck/check/vtable.rs | 11 +- src/librustc/middle/typeck/check/writeback.rs | 5 +- src/librustc/middle/typeck/mod.rs | 29 +-- src/librustc/util/ppaux.rs | 7 - 11 files changed, 121 insertions(+), 293 deletions(-) diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 447f7315f94c..bf39be407c52 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -590,12 +590,6 @@ impl tr for method_origin { typeck::method_trait(did, m, vstore) => { typeck::method_trait(did.tr(xcx), m, vstore) } - typeck::method_self(did, m) => { - typeck::method_self(did.tr(xcx), m) - } - typeck::method_super(trait_did, m) => { - typeck::method_super(trait_did.tr(xcx), m) - } } } } @@ -645,20 +639,13 @@ pub fn encode_vtable_origin(ecx: &e::EncodeContext, typeck::vtable_param(pn, bn) => { do ebml_w.emit_enum_variant("vtable_param", 1u, 2u) |ebml_w| { do ebml_w.emit_enum_variant_arg(0u) |ebml_w| { - ebml_w.emit_uint(pn); + pn.encode(ebml_w); } do ebml_w.emit_enum_variant_arg(1u) |ebml_w| { ebml_w.emit_uint(bn); } } } - 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) - } - } - } } } } @@ -715,20 +702,13 @@ impl vtable_decoder_helpers for reader::Decoder { 1 => { typeck::vtable_param( do this.read_enum_variant_arg(0u) |this| { - this.read_uint() + Decodable::decode(this) }, do this.read_enum_variant_arg(1u) |this| { this.read_uint() } ) } - 2 => { - typeck::vtable_self( - do this.read_enum_variant_arg(0u) |this| { - this.read_def_id_noxcx(cdata) - } - ) - } // hard to avoid - user input _ => fail!("bad enum variant") } diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 1ea32b3f4046..e768a6d687c2 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -15,8 +15,7 @@ use metadata::csearch; use middle::ty::{ty_struct, ty_enum}; use middle::ty; -use middle::typeck::{method_map, method_origin, method_param, method_self}; -use middle::typeck::{method_super}; +use middle::typeck::{method_map, method_origin, method_param}; use middle::typeck::{method_static, method_trait}; use std::util::ignore; @@ -291,9 +290,7 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, method_num: method_num, _ }) | - method_trait(trait_id, method_num, _) | - method_self(trait_id, method_num) | - method_super(trait_id, method_num) => { + method_trait(trait_id, method_num, _) => { if trait_id.crate == local_crate { match tcx.items.find(&trait_id.node) { Some(&node_item(item, _)) => { diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 5d9c44b85e18..40c476321884 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -1096,32 +1096,25 @@ pub fn resolve_vtable_under_param_substs(tcx: ty::ctxt, } } } - typeck::vtable_self(_trait_id) => { - match param_substs { - Some(@param_substs - {self_vtables: Some(self_vtables), _}) => { - self_vtables[0].clone() - } - _ => { - tcx.sess.bug(fmt!( - "resolve_vtable_in_fn_ctxt: asked to lookup but \ - no self_vtable in the fn_ctxt!")) - } - } - } } } pub fn find_vtable(tcx: ty::ctxt, ps: ¶m_substs, - n_param: uint, + n_param: typeck::param_index, n_bound: uint) -> typeck::vtable_origin { - debug!("find_vtable(n_param=%u, n_bound=%u, ps=%s)", + debug!("find_vtable(n_param=%?, n_bound=%u, ps=%s)", n_param, n_bound, ps.repr(tcx)); - let tables = ps.vtables.expect("vtables missing where they are needed"); - let param_bounds = tables[n_param]; + let param_bounds = match n_param { + typeck::param_self => ps.self_vtables.expect("self vtables missing"), + typeck::param_numbered(n) => { + let tables = ps.vtables + .expect("vtables missing where they are needed"); + tables[n] + } + }; param_bounds[n_bound].clone() } diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index 1ee4cd5d2cbb..9228f20513bb 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -147,46 +147,13 @@ pub fn trans_method_callee(bcx: @mut Block, mentry: typeck::method_map_entry) -> Callee { let _icx = push_ctxt("impl::trans_method_callee"); - let tcx = bcx.tcx(); debug!("trans_method_callee(callee_id=%?, this=%s, mentry=%s)", callee_id, bcx.expr_to_str(this), mentry.repr(bcx.tcx())); - // Replace method_self with method_static here. - let mut origin = mentry.origin; - match origin { - typeck::method_super(trait_id, method_index) => { - // is the self type for this method call - let self_ty = node_id_type(bcx, this.id); - // is the ID of the implementation of - // trait for type - let impl_id = ty::bogus_get_impl_id_from_ty(tcx, trait_id, self_ty); - // Get the supertrait's methods - let supertrait_method_def_ids = ty::trait_method_def_ids(tcx, trait_id); - // Make sure to fail with a readable error message if - // there's some internal error here - if !(method_index < supertrait_method_def_ids.len()) { - tcx.sess.bug("trans_method_callee: supertrait method \ - index is out of bounds"); - } - // Get the method name using the method index in the origin - let method_name = - ty::method(tcx, supertrait_method_def_ids[method_index]).ident; - // Now that we know the impl ID, we can look up the method - // ID from its name - origin = typeck::method_static( - method_with_name(bcx.ccx(), impl_id, method_name)); - } - typeck::method_self(*) | - typeck::method_static(*) | typeck::method_param(*) | - typeck::method_trait(*) => {} - } - - debug!("origin=%?", origin); - - match origin { + match mentry.origin { typeck::method_static(did) => { let callee_fn = callee::trans_fn_ref(bcx, did, callee_id); let mut temp_cleanups = ~[]; @@ -210,7 +177,8 @@ pub fn trans_method_callee(bcx: @mut Block, }) => { match bcx.fcx.param_substs { Some(substs) => { - let vtbl = find_vtable(bcx.tcx(), substs, p, b); + let vtbl = find_vtable(bcx.tcx(), substs, + p, b); trans_monomorphized_callee(bcx, callee_id, this, mentry, trait_id, off, vtbl) } @@ -219,25 +187,6 @@ pub fn trans_method_callee(bcx: @mut Block, } } - typeck::method_self(trait_id, method_index) => { - match bcx.fcx.param_substs { - Some(@param_substs - {self_vtables: Some(vtbls), _}) => { - let vtbl = vtbls[0].clone(); - trans_monomorphized_callee(bcx, - callee_id, - this, - mentry, - trait_id, - method_index, - vtbl) - } - _ => { - fail!("trans_method_callee: missing self_vtable") - } - } - } - typeck::method_trait(_, off, store) => { trans_trait_callee(bcx, callee_id, @@ -246,9 +195,6 @@ pub fn trans_method_callee(bcx: @mut Block, store, mentry.explicit_self) } - typeck::method_super(*) => { - fail!("method_super should have been handled above") - } } } @@ -403,9 +349,6 @@ pub fn trans_monomorphized_callee(bcx: @mut 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"); - } }; } diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs index 4d5d597d382f..aa19af01893c 100644 --- a/src/librustc/middle/trans/type_use.rs +++ b/src/librustc/middle/trans/type_use.rs @@ -274,13 +274,12 @@ pub fn mark_for_method_call(cx: &Context, e_id: node_id, callee_id: node_id) { opt_static_did = Some(did); } typeck::method_param(typeck::method_param { - param_num: param, + param_num: typeck::param_numbered(param), _ }) => { cx.uses[param] |= use_tydesc; } - typeck::method_trait(*) | typeck::method_self(*) - | typeck::method_super(*) => (), + _ => (), } } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 3e0b7552ba04..2381cb069e59 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -3065,9 +3065,7 @@ pub fn method_call_type_param_defs(tcx: ctxt, typeck::method_param(typeck::method_param { trait_id: trt_id, method_num: n_mth, _}) | - typeck::method_trait(trt_id, n_mth, _) | - typeck::method_self(trt_id, n_mth) | - typeck::method_super(trt_id, n_mth) => { + typeck::method_trait(trt_id, n_mth, _) => { // ...trait methods bounds, in contrast, include only the // method bounds, so we must preprend the tps from the // trait itself. This ought to be harmonized. @@ -4401,31 +4399,6 @@ pub fn count_traits_and_supertraits(tcx: ctxt, return total; } -// Given a trait and a type, returns the impl of that type. -// This is broken, of course, by parametric impls. This used to use -// a table specifically for this mapping, but I removed that table. -// This is only used when calling a supertrait method from a default method, -// and should go away once I fix how that works. -sully -pub fn bogus_get_impl_id_from_ty(tcx: ctxt, - trait_id: def_id, self_ty: t) -> def_id { - match tcx.trait_impls.find(&trait_id) { - Some(ty_to_impl) => { - for ty_to_impl.iter().advance |imp| { - let impl_ty = tcx.tcache.get_copy(&imp.did); - if impl_ty.ty == self_ty { return imp.did; } - } - // try autoderef! - match deref(tcx, self_ty, false) { - Some(some_ty) => - bogus_get_impl_id_from_ty(tcx, trait_id, some_ty.ty), - None => tcx.sess.bug("get_impl_id: no impl of trait for \ - this type") - } - }, - None => tcx.sess.bug("get_impl_id: trait isn't in trait_impls") - } -} - pub fn get_tydesc_ty(tcx: ctxt) -> Result { do tcx.lang_items.require(TyDescStructLangItem).map |tydesc_lang_item| { tcx.intrinsic_defs.find_copy(tydesc_lang_item) diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 4a32e8bf952c..545a16a7993c 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -90,7 +90,8 @@ use middle::typeck::check::vtable; use middle::typeck::check; use middle::typeck::infer; use middle::typeck::{method_map_entry, method_origin, method_param}; -use middle::typeck::{method_self, method_static, method_trait, method_super}; +use middle::typeck::{method_static, method_trait}; +use middle::typeck::{param_numbered, param_self, param_index}; use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig; use util::common::indenter; @@ -342,64 +343,6 @@ impl<'self> LookupContext<'self> { } } - pub fn push_inherent_candidates_from_param(&self, - rcvr_ty: ty::t, - param_ty: param_ty) { - debug!("push_inherent_candidates_from_param(param_ty=%?)", - param_ty); - let _indenter = indenter(); - - let tcx = self.tcx(); - let mut next_bound_idx = 0; // count only trait bounds - let type_param_def = match tcx.ty_param_defs.find(¶m_ty.def_id.node) { - Some(t) => t, - None => { - tcx.sess.span_bug( - self.expr.span, - fmt!("No param def for %?", param_ty)); - } - }; - - for ty::each_bound_trait_and_supertraits(tcx, type_param_def.bounds) - |bound_trait_ref| - { - let this_bound_idx = next_bound_idx; - next_bound_idx += 1; - - let trait_methods = ty::trait_methods(tcx, bound_trait_ref.def_id); - let pos = { - match trait_methods.iter().position(|m| { - m.explicit_self != ast::sty_static && - m.ident == self.m_name }) - { - Some(pos) => pos, - None => { - debug!("trait doesn't contain method: %?", - bound_trait_ref.def_id); - loop; // check next trait or bound - } - } - }; - let method = trait_methods[pos]; - - let cand = Candidate { - rcvr_ty: rcvr_ty, - rcvr_substs: bound_trait_ref.substs.clone(), - method_ty: method, - origin: method_param( - method_param { - trait_id: bound_trait_ref.def_id, - method_num: pos, - param_num: param_ty.idx, - bound_num: this_bound_idx, - }) - }; - - debug!("pushing inherent candidate for param: %?", cand); - self.inherent_candidates.push(cand); - } - } - pub fn push_inherent_candidates_from_trait(&self, self_ty: ty::t, did: def_id, @@ -452,69 +395,91 @@ impl<'self> LookupContext<'self> { }); } + pub fn push_inherent_candidates_from_param(&self, + rcvr_ty: ty::t, + param_ty: param_ty) { + debug!("push_inherent_candidates_from_param(param_ty=%?)", + param_ty); + let _indenter = indenter(); + + let tcx = self.tcx(); + let type_param_def = match tcx.ty_param_defs.find(¶m_ty.def_id.node) { + Some(t) => t, + None => { + tcx.sess.span_bug( + self.expr.span, + fmt!("No param def for %?", param_ty)); + } + }; + + self.push_inherent_candidates_from_bounds( + rcvr_ty, &*type_param_def.bounds, param_numbered(param_ty.idx)); + } + + pub fn push_inherent_candidates_from_self(&self, self_ty: ty::t, did: def_id) { - struct MethodInfo { - method_ty: @ty::Method, - trait_def_id: ast::def_id, - index: uint, - trait_ref: @ty::TraitRef - } - let tcx = self.tcx(); - // First, try self methods - let mut method_info: Option = None; - let methods = ty::trait_methods(tcx, did); - match methods.iter().position(|m| m.ident == self.m_name) { - Some(i) => { - method_info = Some(MethodInfo { - method_ty: methods[i], - index: i, - trait_def_id: did, - trait_ref: ty::lookup_trait_def(tcx, did).trait_ref - }); - } - None => () - } - // No method found yet? Check each supertrait - if method_info.is_none() { - for ty::trait_supertraits(tcx, did).iter().advance |trait_ref| { - let supertrait_methods = - ty::trait_methods(tcx, trait_ref.def_id); - match supertrait_methods.iter().position(|m| m.ident == self.m_name) { - Some(i) => { - method_info = Some(MethodInfo { - method_ty: supertrait_methods[i], - index: i, - trait_def_id: trait_ref.def_id, - trait_ref: *trait_ref - }); - break; + + let trait_ref = ty::lookup_trait_def(tcx, did).trait_ref; + let bounds = ParamBounds { + builtin_bounds: EmptyBuiltinBounds(), + trait_bounds: ~[trait_ref] + }; + + self.push_inherent_candidates_from_bounds( + self_ty, &bounds, param_self); + } + + pub fn push_inherent_candidates_from_bounds(&self, + self_ty: ty::t, + bounds: &ParamBounds, + param: param_index) { + let tcx = self.tcx(); + let mut next_bound_idx = 0; // count only trait bounds + + for ty::each_bound_trait_and_supertraits(tcx, bounds) + |bound_trait_ref| + { + let this_bound_idx = next_bound_idx; + next_bound_idx += 1; + + let trait_methods = ty::trait_methods(tcx, bound_trait_ref.def_id); + let pos = { + match trait_methods.iter().position(|m| { + m.explicit_self != ast::sty_static && + m.ident == self.m_name }) + { + Some(pos) => pos, + None => { + debug!("trait doesn't contain method: %?", + bound_trait_ref.def_id); + loop; // check next trait or bound } - None => () } - } - } - match method_info { - Some(ref info) => { - // We've found a method -- return it - let origin = if did == info.trait_def_id { - method_self(info.trait_def_id, info.index) - } else { - method_super(info.trait_def_id, info.index) - }; - self.inherent_candidates.push(Candidate { - rcvr_ty: self_ty, - rcvr_substs: info.trait_ref.substs.clone(), - method_ty: info.method_ty, - origin: origin - }); - } - _ => return + }; + let method = trait_methods[pos]; + + let cand = Candidate { + rcvr_ty: self_ty, + rcvr_substs: bound_trait_ref.substs.clone(), + method_ty: method, + origin: method_param( + method_param { + trait_id: bound_trait_ref.def_id, + method_num: pos, + param_num: param, + bound_num: this_bound_idx, + }) + }; + + debug!("pushing inherent candidate for param: %?", cand); + self.inherent_candidates.push(cand); } } + pub fn push_inherent_impl_candidates_for_type(&self, did: def_id) { let opt_impl_infos = self.tcx().inherent_impls.find(&did); for opt_impl_infos.iter().advance |impl_infos| { @@ -1019,14 +984,13 @@ impl<'self> LookupContext<'self> { /*! * * There are some limitations to calling functions through a - * traint instance, because (a) the self type is not known + * trait instance, because (a) the self type is not known * (that's the whole point of a trait instance, after all, to * obscure the self type) and (b) the call must go through a * vtable and hence cannot be monomorphized. */ match candidate.origin { - method_static(*) | method_param(*) | - method_self(*) | method_super(*) => { + method_static(*) | method_param(*) => { return; // not a call to a trait instance } method_trait(*) => {} @@ -1050,10 +1014,11 @@ impl<'self> LookupContext<'self> { // No code can call the finalize method explicitly. let bad; match candidate.origin { - method_static(method_id) | method_self(method_id, _) - | method_super(method_id, _) => { + method_static(method_id) => { bad = self.tcx().destructors.contains(&method_id); } + // XXX: does this properly enforce this on everything now + // that self has been merged in? -sully method_param(method_param { trait_id: trait_id, _ }) | method_trait(trait_id, _, _) => { bad = self.tcx().destructor_for_type.contains_key(&trait_id); @@ -1172,8 +1137,7 @@ impl<'self> LookupContext<'self> { method_param(ref mp) => { type_of_trait_method(self.tcx(), mp.trait_id, mp.method_num) } - method_trait(did, idx, _) | method_self(did, idx) | - method_super(did, idx) => { + method_trait(did, idx, _) => { type_of_trait_method(self.tcx(), did, idx) } }; @@ -1194,8 +1158,7 @@ impl<'self> LookupContext<'self> { method_param(ref mp) => { self.report_param_candidate(idx, (*mp).trait_id) } - method_trait(trait_did, _, _) | method_self(trait_did, _) - | method_super(trait_did, _) => { + method_trait(trait_did, _, _) => { self.report_trait_candidate(idx, trait_did) } } diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 406e4f5b30da..056b330e9c52 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -17,7 +17,8 @@ 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_res, vtable_param_res}; -use middle::typeck::{vtable_static, vtable_param, vtable_self, impl_res}; +use middle::typeck::{vtable_static, vtable_param, impl_res}; +use middle::typeck::{param_numbered, param_self}; use middle::subst::Subst; use util::common::indenter; use util::ppaux; @@ -239,7 +240,7 @@ fn lookup_vtable(vcx: &VtableContext, // The type has unconstrained type variables in it, so we can't // do early resolution on it. Return some completely bogus vtable // information: we aren't storing it anyways. - return Some(vtable_param(0, 0)); + return Some(vtable_param(param_self, 0)); } }; @@ -257,7 +258,7 @@ fn lookup_vtable(vcx: &VtableContext, location_info, bound_trait_ref, trait_ref); - let vtable = vtable_param(n, n_bound); + let vtable = vtable_param(param_numbered(n), n_bound); debug!("found param vtable: %?", vtable); return Some(vtable); @@ -272,7 +273,7 @@ fn lookup_vtable(vcx: &VtableContext, trait_ref.def_id, trait_id); if trait_id == trait_ref.def_id { - let vtable = vtable_self(trait_id); + let vtable = vtable_param(param_self, 0); debug!("found self vtable: %?", vtable); return Some(vtable); } @@ -403,7 +404,7 @@ fn search_for_vtable(vcx: &VtableContext, None => { assert!(is_early); // Bail out with a bogus answer - return Some(vtable_param(0, 0)); + return Some(vtable_param(param_self, 0)); } }; diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index 4d437d83f2ab..a7319d4b0081 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -20,7 +20,7 @@ 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, vtable_self}; +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; @@ -109,9 +109,6 @@ fn resolve_vtable_map_entry(fcx: @mut FnCtxt, sp: span, id: ast::node_id) { &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 261f26671146..0ea00e15863d 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -75,14 +75,14 @@ pub mod infer; pub mod collect; pub mod coherence; +#[deriving(Clone, Encodable, Decodable, Eq, Ord)] +pub enum param_index { + param_numbered(uint), + param_self +} + #[deriving(Clone, Encodable, Decodable)] pub enum method_origin { - // supertrait method invoked on "self" inside a default method - // first field is supertrait ID; - // second field is method index (relative to the *supertrait* - // method list) - method_super(ast::def_id, uint), - // fully statically resolved method method_static(ast::def_id), @@ -92,9 +92,6 @@ pub enum method_origin { // method invoked on a trait instance method_trait(ast::def_id, uint, ty::TraitStore), - // method invoked on "self" inside a default method - method_self(ast::def_id, uint) - } // details for a method invoked with a receiver whose type is a type parameter @@ -109,7 +106,7 @@ pub struct method_param { // index of the type parameter (from those that are in scope) that is // the type of the receiver - param_num: uint, + param_num: param_index, // index of the bound for this type parameter which specifies the trait bound_num: uint, @@ -153,15 +150,10 @@ pub enum vtable_origin { fn foo(a: T) -- a's vtable would have a vtable_param origin - The first uint is the param number (identifying T in the example), + The first argument is the param index (identifying T in the example), and the second is the bound number (identifying baz) */ - vtable_param(uint, uint), - - /* - Dynamic vtable, comes from self. - */ - vtable_self(ast::def_id) + vtable_param(param_index, uint), } impl Repr for vtable_origin { @@ -178,9 +170,6 @@ 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/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 32ac5e72928e..932648d4f9b9 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -715,10 +715,6 @@ impl Repr for typeck::method_map_entry { impl Repr for typeck::method_origin { fn repr(&self, tcx: ctxt) -> ~str { match self { - &typeck::method_super(def_id, n) => { - fmt!("method_super(%s, %?)", - def_id.repr(tcx), n) - } &typeck::method_static(def_id) => { fmt!("method_static(%s)", def_id.repr(tcx)) } @@ -729,9 +725,6 @@ impl Repr for typeck::method_origin { fmt!("method_trait(%s, %?, %s)", def_id.repr(tcx), n, st.repr(tcx)) } - &typeck::method_self(def_id, n) => { - fmt!("method_self(%s, %?)", def_id.repr(tcx), n) - } } } } From 387df4e1277ed09002bb050caac5a86d126a1339 Mon Sep 17 00:00:00 2001 From: Michael Sullivan Date: Tue, 23 Jul 2013 13:46:51 -0700 Subject: [PATCH 10/12] Fix the issue-3979 tests and add a new test. --- src/test/auxiliary/issue_3979_traits.rs | 7 ++-- src/test/run-pass/issue-3979-2.rs | 2 - src/test/run-pass/issue-3979-generics.rs | 12 +++--- src/test/run-pass/issue-3979-xcrate.rs | 2 +- src/test/run-pass/issue-3979.rs | 2 - .../run-pass/supertrait-default-generics.rs | 42 +++++++++++++++++++ 6 files changed, 53 insertions(+), 14 deletions(-) create mode 100644 src/test/run-pass/supertrait-default-generics.rs diff --git a/src/test/auxiliary/issue_3979_traits.rs b/src/test/auxiliary/issue_3979_traits.rs index 1e56dab1559c..eb10553f19c2 100644 --- a/src/test/auxiliary/issue_3979_traits.rs +++ b/src/test/auxiliary/issue_3979_traits.rs @@ -14,12 +14,13 @@ #[crate_type = "lib"]; trait Positioned { - fn SetX(&self, int); + fn SetX(&mut self, int); fn X(&self) -> int; } trait Movable: Positioned { - fn translate(&self, dx: int) { - self.SetX(self.X() + dx); + fn translate(&mut self, dx: int) { + let x = self.X() + dx; + self.SetX(x); } } diff --git a/src/test/run-pass/issue-3979-2.rs b/src/test/run-pass/issue-3979-2.rs index 9a8b90db185b..39e9f5dcd2d8 100644 --- a/src/test/run-pass/issue-3979-2.rs +++ b/src/test/run-pass/issue-3979-2.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test - trait A { fn a_method(&self); } diff --git a/src/test/run-pass/issue-3979-generics.rs b/src/test/run-pass/issue-3979-generics.rs index 2a1ded96827d..867301121dae 100644 --- a/src/test/run-pass/issue-3979-generics.rs +++ b/src/test/run-pass/issue-3979-generics.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test FIXME #5946 trait Positioned { fn SetX(&mut self, S); fn X(&self) -> S; } -trait Movable: Positioned { - fn translate(&self, dx: T) { - self.SetX(self.X() + dx); +trait Movable>: Positioned { + fn translate(&mut self, dx: S) { + let x = self.X() + dx; + self.SetX(x); } } @@ -31,10 +31,10 @@ impl Positioned for Point { } } -impl Movable for Point; +impl Movable for Point; pub fn main() { - let p = Point{ x: 1, y: 2}; + let mut p = Point{ x: 1, y: 2}; p.translate(3); assert_eq!(p.X(), 4); } diff --git a/src/test/run-pass/issue-3979-xcrate.rs b/src/test/run-pass/issue-3979-xcrate.rs index 4bde414c4acf..caf6d2023169 100644 --- a/src/test/run-pass/issue-3979-xcrate.rs +++ b/src/test/run-pass/issue-3979-xcrate.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test // tjc: ??? +// xfail-fast // aux-build:issue_3979_traits.rs extern mod issue_3979_traits; use issue_3979_traits::*; diff --git a/src/test/run-pass/issue-3979.rs b/src/test/run-pass/issue-3979.rs index fe10dd5af53d..2e53fb5d3f92 100644 --- a/src/test/run-pass/issue-3979.rs +++ b/src/test/run-pass/issue-3979.rs @@ -1,5 +1,3 @@ -// xfail-test -// Reason: ICE with explicit self // Copyright 2012 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at diff --git a/src/test/run-pass/supertrait-default-generics.rs b/src/test/run-pass/supertrait-default-generics.rs new file mode 100644 index 000000000000..ae7e18d532b7 --- /dev/null +++ b/src/test/run-pass/supertrait-default-generics.rs @@ -0,0 +1,42 @@ +// Copyright 2012 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. + +// There is some other borrowck bug, so we make the stuff not mut. + +trait Positioned { + fn SetX(&mut self, S); + fn X(&self) -> S; +} + +trait Movable>: Positioned { + fn translate(&mut self, dx: S) { + let x = self.X() + dx; + self.SetX(x); + } +} + +struct Point { x: S, y: S } + +impl Positioned for Point { + fn SetX(&mut self, x: S) { + self.x = x; + } + fn X(&self) -> S { + self.x.clone() + } +} + +impl> Movable for Point; + +pub fn main() { + let mut p = Point{ x: 1, y: 2}; + p.translate(3); + assert_eq!(p.X(), 4); +} From 17e30d6b4ef5c6fb4d6257323903cba1213cae8f Mon Sep 17 00:00:00 2001 From: Michael Sullivan Date: Tue, 23 Jul 2013 14:54:53 -0700 Subject: [PATCH 11/12] Change each_bound_trait_and_supertraits to take a vec of TraitRefs. --- src/librustc/middle/ty.rs | 7 ++++--- src/librustc/middle/typeck/check/method.rs | 12 ++++-------- src/librustc/middle/typeck/check/vtable.rs | 4 ++-- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 2381cb069e59..6a75c845f161 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -4348,9 +4348,9 @@ pub fn determine_inherited_purity(parent: (ast::purity, ast::node_id), // relation on the supertraits from each bounded trait's constraint // list. pub fn each_bound_trait_and_supertraits(tcx: ctxt, - bounds: &ParamBounds, + bounds: &[@TraitRef], f: &fn(@TraitRef) -> bool) -> bool { - for bounds.trait_bounds.iter().advance |&bound_trait_ref| { + for bounds.iter().advance |&bound_trait_ref| { let mut supertrait_set = HashMap::new(); let mut trait_refs = ~[]; let mut i = 0; @@ -4392,7 +4392,8 @@ pub fn count_traits_and_supertraits(tcx: ctxt, type_param_defs: &[TypeParameterDef]) -> uint { let mut total = 0; for type_param_defs.iter().advance |type_param_def| { - for each_bound_trait_and_supertraits(tcx, type_param_def.bounds) |_| { + for each_bound_trait_and_supertraits( + tcx, type_param_def.bounds.trait_bounds) |_| { total += 1; } } diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 545a16a7993c..5e2fff3b25df 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -413,7 +413,8 @@ impl<'self> LookupContext<'self> { }; self.push_inherent_candidates_from_bounds( - rcvr_ty, &*type_param_def.bounds, param_numbered(param_ty.idx)); + rcvr_ty, type_param_def.bounds.trait_bounds, + param_numbered(param_ty.idx)); } @@ -423,18 +424,13 @@ impl<'self> LookupContext<'self> { let tcx = self.tcx(); let trait_ref = ty::lookup_trait_def(tcx, did).trait_ref; - let bounds = ParamBounds { - builtin_bounds: EmptyBuiltinBounds(), - trait_bounds: ~[trait_ref] - }; - self.push_inherent_candidates_from_bounds( - self_ty, &bounds, param_self); + self_ty, &[trait_ref], param_self); } pub fn push_inherent_candidates_from_bounds(&self, self_ty: ty::t, - bounds: &ParamBounds, + bounds: &[@TraitRef], param: param_index) { let tcx = self.tcx(); let mut next_bound_idx = 0; // count only trait bounds diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 056b330e9c52..07f82a5ef205 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -132,7 +132,7 @@ fn lookup_vtables_for_param(vcx: &VtableContext, let mut param_result = ~[]; for ty::each_bound_trait_and_supertraits( - tcx, type_param_bounds) |trait_ref| + tcx, type_param_bounds.trait_bounds) |trait_ref| { // ...and here trait_ref is each bound that was declared on A, // expressed in terms of the type parameters. @@ -249,7 +249,7 @@ fn lookup_vtable(vcx: &VtableContext, let mut n_bound = 0; let type_param_def = tcx.ty_param_defs.get(&did.node); for ty::each_bound_trait_and_supertraits( - tcx, type_param_def.bounds) |bound_trait_ref| + tcx, type_param_def.bounds.trait_bounds) |bound_trait_ref| { debug!("checking bounds trait %s", bound_trait_ref.repr(vcx.tcx())); From f37c7cd30651e6514c6ac03a081940e28a53292c Mon Sep 17 00:00:00 2001 From: Michael Sullivan Date: Tue, 23 Jul 2013 16:28:53 -0700 Subject: [PATCH 12/12] Fix vtable resolution for self to search supertraits. Closes #7661. --- src/librustc/middle/typeck/check/vtable.rs | 80 ++++++++++++------- .../default-method-supertrait-vtable.rs | 36 +++++++++ 2 files changed, 85 insertions(+), 31 deletions(-) create mode 100644 src/test/run-pass/default-method-supertrait-vtable.rs diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 07f82a5ef205..50f7f18b0a6d 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -18,7 +18,7 @@ use middle::typeck::infer::{resolve_and_force_all_but_regions, resolve_type}; use middle::typeck::infer; use middle::typeck::{CrateCtxt, vtable_origin, vtable_res, vtable_param_res}; use middle::typeck::{vtable_static, vtable_param, impl_res}; -use middle::typeck::{param_numbered, param_self}; +use middle::typeck::{param_numbered, param_self, param_index}; use middle::subst::Subst; use util::common::indenter; use util::ppaux; @@ -244,44 +244,30 @@ fn lookup_vtable(vcx: &VtableContext, } }; - match ty::get(ty).sty { + // If the type is self or a param, we look at the trait/supertrait + // bounds to see if they include the trait we are looking for. + let vtable_opt = match ty::get(ty).sty { ty::ty_param(param_ty {idx: n, def_id: did}) => { - let mut n_bound = 0; let type_param_def = tcx.ty_param_defs.get(&did.node); - for ty::each_bound_trait_and_supertraits( - tcx, type_param_def.bounds.trait_bounds) |bound_trait_ref| - { - debug!("checking bounds trait %s", bound_trait_ref.repr(vcx.tcx())); - - if bound_trait_ref.def_id == trait_ref.def_id { - relate_trait_refs(vcx, - location_info, - bound_trait_ref, - trait_ref); - let vtable = vtable_param(param_numbered(n), n_bound); - debug!("found param vtable: %?", - vtable); - return Some(vtable); - } - - n_bound += 1; - } + lookup_vtable_from_bounds(vcx, location_info, + type_param_def.bounds.trait_bounds, + param_numbered(n), + trait_ref) } 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_param(param_self, 0); - debug!("found self vtable: %?", vtable); - return Some(vtable); - } + let self_trait_ref = ty::lookup_trait_def(tcx, trait_id).trait_ref; + lookup_vtable_from_bounds(vcx, location_info, + &[self_trait_ref], + param_self, + trait_ref) } // Default case just falls through - _ => { } - } + _ => None + }; + + if vtable_opt.is_some() { return vtable_opt; } // If we aren't a self type or param, or it was, but we didn't find it, // do a search. @@ -289,6 +275,38 @@ fn lookup_vtable(vcx: &VtableContext, ty, trait_ref, is_early) } +// Given a list of bounds on a type, search those bounds to see if any +// of them are the vtable we are looking for. +fn lookup_vtable_from_bounds(vcx: &VtableContext, + location_info: &LocationInfo, + bounds: &[@ty::TraitRef], + param: param_index, + trait_ref: @ty::TraitRef) + -> Option { + let tcx = vcx.tcx(); + + let mut n_bound = 0; + for ty::each_bound_trait_and_supertraits(tcx, bounds) |bound_trait_ref| { + debug!("checking bounds trait %s", + bound_trait_ref.repr(vcx.tcx())); + + if bound_trait_ref.def_id == trait_ref.def_id { + relate_trait_refs(vcx, + location_info, + bound_trait_ref, + trait_ref); + let vtable = vtable_param(param, n_bound); + debug!("found param vtable: %?", + vtable); + return Some(vtable); + } + + n_bound += 1; + } + + return None; +} + fn search_for_vtable(vcx: &VtableContext, location_info: &LocationInfo, ty: ty::t, diff --git a/src/test/run-pass/default-method-supertrait-vtable.rs b/src/test/run-pass/default-method-supertrait-vtable.rs new file mode 100644 index 000000000000..90a2b9140212 --- /dev/null +++ b/src/test/run-pass/default-method-supertrait-vtable.rs @@ -0,0 +1,36 @@ +// 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. + + +// Tests that we can call a function bounded over a supertrait from +// a default method + +fn require_y(x: T) -> int { x.y() } + +trait Y { + fn y(self) -> int; +} + + +trait Z: Y { + fn x(self) -> int { + require_y(self) + } +} + +impl Y for int { + fn y(self) -> int { self } +} + +impl Z for int; + +fn main() { + assert_eq!(12.x(), 12); +}