Merge pull request #4101 from brson/bound-default-methods

Call default methods on bound typarams more correctly
This commit is contained in:
Brian Anderson 2012-12-07 15:10:57 -08:00
commit e71081ec03
10 changed files with 156 additions and 36 deletions

View File

@ -309,8 +309,8 @@ fn trans_static_method_callee(bcx: block,
}
fn method_from_methods(ms: ~[@ast::method], name: ast::ident)
-> ast::def_id {
local_def(option::get(vec::find(ms, |m| m.ident == name)).id)
-> Option<ast::def_id> {
ms.find(|m| m.ident == name).map(|m| local_def(m.id))
}
fn method_with_name(ccx: @crate_ctxt, impl_id: ast::def_id,
@ -318,11 +318,43 @@ fn method_with_name(ccx: @crate_ctxt, impl_id: ast::def_id,
if impl_id.crate == ast::local_crate {
match ccx.tcx.items.get(impl_id.node) {
ast_map::node_item(@{node: ast::item_impl(_, _, _, ms), _}, _) => {
method_from_methods(ms, name)
method_from_methods(ms, name).get()
}
ast_map::node_item(@{node:
ast::item_class(struct_def, _), _}, _) => {
method_from_methods(struct_def.methods, name)
method_from_methods(struct_def.methods, name).get()
}
_ => fail ~"method_with_name"
}
} else {
csearch::get_impl_method(ccx.sess.cstore, impl_id, name)
}
}
fn method_with_name_or_default(ccx: @crate_ctxt, impl_id: ast::def_id,
name: ast::ident) -> ast::def_id {
if impl_id.crate == ast::local_crate {
match ccx.tcx.items.get(impl_id.node) {
ast_map::node_item(@{node: ast::item_impl(_, _, _, ms), _}, _) => {
let did = method_from_methods(ms, name);
if did.is_some() {
return did.get();
} else {
// Look for a default method
let pmm = ccx.tcx.provided_methods;
match pmm.find(impl_id) {
Some(pmis) => {
for pmis.each |pmi| {
if pmi.method_info.ident == name {
debug!("XXX %?", pmi.method_info.did);
return pmi.method_info.did;
}
}
fail
}
None => fail
}
}
}
_ => fail ~"method_with_name"
}
@ -333,10 +365,22 @@ fn method_with_name(ccx: @crate_ctxt, impl_id: ast::def_id,
fn method_ty_param_count(ccx: @crate_ctxt, m_id: ast::def_id,
i_id: ast::def_id) -> uint {
debug!("mythod_ty_param_count: m_id: %?, i_id: %?", m_id, i_id);
if m_id.crate == ast::local_crate {
match ccx.tcx.items.get(m_id.node) {
ast_map::node_method(m, _, _) => vec::len(m.tps),
_ => fail ~"method_ty_param_count"
match ccx.tcx.items.find(m_id.node) {
Some(ast_map::node_method(m, _, _)) => m.tps.len(),
None => {
match ccx.tcx.provided_method_sources.find(m_id) {
Some(source) => {
method_ty_param_count(ccx, source.method_id, source.impl_id)
}
None => fail
}
}
Some(ast_map::node_trait_method(@ast::provided(@m), _, _)) => {
m.tps.len()
}
e => fail fmt!("method_ty_param_count %?", e)
}
} else {
csearch::get_type_param_count(ccx.sess.cstore, m_id) -
@ -358,7 +402,8 @@ fn trans_monomorphized_callee(bcx: block,
typeck::vtable_static(impl_did, rcvr_substs, rcvr_origins) => {
let ccx = bcx.ccx();
let mname = ty::trait_methods(ccx.tcx, trait_id)[n_method].ident;
let mth_id = method_with_name(bcx.ccx(), impl_did, mname);
let mth_id = method_with_name_or_default(
bcx.ccx(), impl_did, mname);
// obtain the `self` value:
let Result {bcx, val: llself_val} =

View File

@ -10,6 +10,7 @@
#[warn(deprecated_pattern)];
use core::dvec::DVec;
use std::{map, smallintmap};
use result::Result;
use std::map::HashMap;
@ -27,8 +28,11 @@ use middle::lint::{get_lint_level, allow};
use syntax::ast::*;
use syntax::print::pprust::*;
use util::ppaux::{ty_to_str, proto_ty_to_str, tys_to_str};
use middle::resolve::{Impl, MethodInfo};
export ProvidedMethodSource;
export ProvidedMethodInfo;
export ProvidedMethodsMap;
export InstantiatedTraitRef;
export TyVid, IntVid, FloatVid, FnVid, RegionVid, vid;
export br_hashmap;
@ -352,6 +356,21 @@ enum AutoRefKind {
AutoBorrowFn,
}
// Stores information about provided methods (a.k.a. default methods) in
// implementations.
//
// This is a map from ID of each implementation to the method info and trait
// method ID of each of the default methods belonging to the trait that that
// implementation implements.
type ProvidedMethodsMap = HashMap<def_id,@DVec<@ProvidedMethodInfo>>;
// Stores the method info and definition ID of the associated trait method for
// each instantiation of each provided method.
struct ProvidedMethodInfo {
method_info: @MethodInfo,
trait_method_def_id: def_id
}
struct ProvidedMethodSource {
method_id: ast::def_id,
impl_id: ast::def_id
@ -416,6 +435,10 @@ type ctxt =
normalized_cache: HashMap<t, t>,
lang_items: middle::lang_items::LanguageItems,
legacy_boxed_traits: HashMap<node_id, ()>,
// A mapping from an implementation ID to the method info and trait method
// ID of the provided (a.k.a. default) methods in the traits that that
// implementation implements.
provided_methods: ProvidedMethodsMap,
provided_method_sources: HashMap<ast::def_id, ProvidedMethodSource>,
supertraits: HashMap<ast::def_id, @~[InstantiatedTraitRef]>,
deriving_struct_methods: HashMap<ast::def_id, @~[DerivedFieldInfo]>,
@ -975,6 +998,7 @@ fn mk_ctxt(s: session::Session,
normalized_cache: new_ty_hash(),
lang_items: move lang_items,
legacy_boxed_traits: HashMap(),
provided_methods: HashMap(),
provided_method_sources: HashMap(),
supertraits: HashMap(),
deriving_struct_methods: HashMap(),

View File

@ -79,7 +79,7 @@ obtained the type `Foo`, we would never match this method.
*/
use coherence::{ProvidedMethodInfo, get_base_type_def_id};
use coherence::get_base_type_def_id;
use middle::resolve::{Impl, MethodInfo};
use middle::ty::*;
use syntax::ast::{def_id, sty_by_ref, sty_value, sty_region, sty_box,
@ -313,7 +313,7 @@ impl LookupContext {
}
// Look for default methods.
match coherence_info.provided_methods.find(*trait_did) {
match self.tcx().provided_methods.find(*trait_did) {
Some(methods) => {
self.push_candidates_from_provided_methods(
&self.extension_candidates, self_ty, *trait_did,

View File

@ -19,7 +19,7 @@ use metadata::csearch::{get_impls_for_mod};
use metadata::cstore::{CStore, iter_crate_data};
use metadata::decoder::{dl_def, dl_field, dl_impl};
use middle::resolve::{Impl, MethodInfo};
use middle::ty::{DerivedMethodInfo, ProvidedMethodSource, get};
use middle::ty::{DerivedMethodInfo, ProvidedMethodSource, ProvidedMethodInfo, get};
use middle::ty::{lookup_item_type, subst, t, ty_bot, ty_box, ty_class};
use middle::ty::{ty_bool, ty_enum, ty_int, ty_nil, ty_ptr, ty_rptr, ty_uint};
use middle::ty::{ty_float, ty_estr, ty_evec, ty_rec, ty_uniq};
@ -130,21 +130,6 @@ fn method_to_MethodInfo(ast_method: @method) -> @MethodInfo {
}
}
// Stores the method info and definition ID of the associated trait method for
// each instantiation of each provided method.
struct ProvidedMethodInfo {
method_info: @MethodInfo,
trait_method_def_id: def_id
}
// Stores information about provided methods (a.k.a. default methods) in
// implementations.
//
// This is a map from ID of each implementation to the method info and trait
// method ID of each of the default methods belonging to the trait that that
// implementation implements.
type ProvidedMethodsMap = HashMap<def_id,@DVec<@ProvidedMethodInfo>>;
struct CoherenceInfo {
// Contains implementations of methods that are inherent to a type.
// Methods in these implementations don't need to be exported.
@ -154,17 +139,12 @@ struct CoherenceInfo {
// the associated trait must be imported at the call site.
extension_methods: HashMap<def_id,@DVec<@Impl>>,
// A mapping from an implementation ID to the method info and trait method
// ID of the provided (a.k.a. default) methods in the traits that that
// implementation implements.
provided_methods: ProvidedMethodsMap,
}
fn CoherenceInfo() -> CoherenceInfo {
CoherenceInfo {
inherent_methods: HashMap(),
extension_methods: HashMap(),
provided_methods: HashMap(),
}
}
@ -350,7 +330,7 @@ impl CoherenceChecker {
trait_method_def_id: trait_method.def_id
};
let pmm = self.crate_context.coherence_info.provided_methods;
let pmm = self.crate_context.tcx.provided_methods;
match pmm.find(local_def(impl_id)) {
Some(mis) => {
// If the trait already has an entry in the
@ -765,8 +745,7 @@ impl CoherenceChecker {
let trait_did =
self.trait_ref_to_trait_def_id(*trait_ref);
match self.crate_context
.coherence_info
match self.crate_context.tcx
.provided_methods
.find(local_def(item.id)) {
None => {
@ -925,7 +904,7 @@ impl CoherenceChecker {
fn add_default_methods_for_external_trait(trait_def_id: ast::def_id) {
let tcx = self.crate_context.tcx;
let pmm = self.crate_context.coherence_info.provided_methods;
let pmm = tcx.provided_methods;
if pmm.contains_key(trait_def_id) { return; }

View File

@ -88,6 +88,7 @@ export vtable_origin;
export method_static, method_param, method_trait, method_self;
export vtable_static, vtable_param, vtable_trait;
export provided_methods_map;
export coherence;
#[legacy_exports]
#[path = "check/mod.rs"]
@ -380,7 +381,7 @@ fn check_for_main_fn(ccx: @crate_ctxt) {
fn check_crate(tcx: ty::ctxt,
trait_map: resolve::TraitMap,
crate: @ast::crate)
-> (method_map, vtable_map) {
-> (method_map, vtable_map) {
let ccx = @crate_ctxt_({trait_map: trait_map,
method_map: std::map::HashMap(),

View File

@ -0,0 +1,15 @@
// xfail-test
trait A<T> {
fn g<U>(x: T, y: U) -> (T, U) { (move x, move y) }
}
impl int: A<int> { }
fn f<T, U, V: A<T>>(i: V, j: T, k: U) -> (T, U) {
i.g(move j, move k)
}
fn main () {
assert f(0, 1, 2) == (1, 2);
}

View File

@ -0,0 +1,15 @@
// xfail-test
trait A<T> {
fn g(x: T) -> T { move x }
}
impl int: A<int> { }
fn f<T, V: A<T>>(i: V, j: T) -> T {
i.g(move j)
}
fn main () {
assert f(0, 2) == 2;
}

View File

@ -0,0 +1,14 @@
trait A {
fn g<T>(x: T, y: T) -> (T, T) { (move x, move y) }
}
impl int: A { }
fn f<T, V: A>(i: V, j: T, k: T) -> (T, T) {
i.g(move j, move k)
}
fn main () {
assert f(0, 1, 2) == (1, 2);
assert f(0, 1u8, 2u8) == (1u8, 2u8);
}

View File

@ -0,0 +1,14 @@
trait A<T> {
fn g(x: uint) -> uint { move x }
}
impl<T> int: A<T> { }
fn f<T, V: A<T>>(i: V, j: uint) -> uint {
i.g(move j)
}
fn main () {
assert f::<float, int>(0, 2u) == 2u;
assert f::<uint, int>(0, 2u) == 2u;
}

View File

@ -0,0 +1,13 @@
trait A {
fn g() -> int { 10 }
}
impl int: A { }
fn f<T: A>(i: T) {
assert i.g() == 10;
}
fn main () {
f(0);
}