Call default methods on bound typarams more correctly
This commit is contained in:
parent
bde2dcc8d5
commit
05e51e6f7f
@ -294,8 +294,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,
|
||||
@ -303,11 +303,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"
|
||||
}
|
||||
@ -318,10 +350,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) -
|
||||
@ -343,7 +387,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} =
|
||||
|
@ -1,5 +1,6 @@
|
||||
#[warn(deprecated_pattern)];
|
||||
|
||||
use core::dvec::DVec;
|
||||
use std::{map, smallintmap};
|
||||
use result::Result;
|
||||
use std::map::HashMap;
|
||||
@ -17,8 +18,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;
|
||||
@ -331,6 +335,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
|
||||
@ -395,6 +414,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]>,
|
||||
@ -951,6 +974,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(),
|
||||
|
@ -69,7 +69,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,
|
||||
@ -293,7 +293,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,
|
||||
|
@ -9,7 +9,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};
|
||||
@ -120,21 +120,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.
|
||||
@ -144,17 +129,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(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -340,7 +320,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
|
||||
@ -755,8 +735,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 => {
|
||||
@ -915,7 +894,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; }
|
||||
|
||||
|
@ -78,6 +78,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"]
|
||||
@ -367,7 +368,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(),
|
||||
|
15
src/test/run-pass/trait-default-method-bound-subst.rs
Normal file
15
src/test/run-pass/trait-default-method-bound-subst.rs
Normal 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);
|
||||
}
|
15
src/test/run-pass/trait-default-method-bound-subst2.rs
Normal file
15
src/test/run-pass/trait-default-method-bound-subst2.rs
Normal 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;
|
||||
}
|
14
src/test/run-pass/trait-default-method-bound-subst3.rs
Normal file
14
src/test/run-pass/trait-default-method-bound-subst3.rs
Normal 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);
|
||||
}
|
14
src/test/run-pass/trait-default-method-bound-subst4.rs
Normal file
14
src/test/run-pass/trait-default-method-bound-subst4.rs
Normal 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;
|
||||
}
|
13
src/test/run-pass/trait-default-method-bound.rs
Normal file
13
src/test/run-pass/trait-default-method-bound.rs
Normal 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);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user