From 05e51e6f7f4f70ede2164e8da325f60c64f79616 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 2 Dec 2012 18:29:22 -0800 Subject: [PATCH] Call default methods on bound typarams more correctly --- src/librustc/middle/trans/meth.rs | 61 ++++++++++++++++--- src/librustc/middle/ty.rs | 24 ++++++++ src/librustc/middle/typeck/check/method.rs | 4 +- src/librustc/middle/typeck/coherence.rs | 29 ++------- src/librustc/middle/typeck/mod.rs | 3 +- .../trait-default-method-bound-subst.rs | 15 +++++ .../trait-default-method-bound-subst2.rs | 15 +++++ .../trait-default-method-bound-subst3.rs | 14 +++++ .../trait-default-method-bound-subst4.rs | 14 +++++ .../run-pass/trait-default-method-bound.rs | 13 ++++ 10 files changed, 156 insertions(+), 36 deletions(-) create mode 100644 src/test/run-pass/trait-default-method-bound-subst.rs create mode 100644 src/test/run-pass/trait-default-method-bound-subst2.rs create mode 100644 src/test/run-pass/trait-default-method-bound-subst3.rs create mode 100644 src/test/run-pass/trait-default-method-bound-subst4.rs create mode 100644 src/test/run-pass/trait-default-method-bound.rs diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index ba6ec2a44c9..1943bbfc4ae 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -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 { + 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} = diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index cd70f7b1958..725d3bc37f5 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -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>; + +// 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, lang_items: middle::lang_items::LanguageItems, legacy_boxed_traits: HashMap, + // 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, supertraits: HashMap, deriving_struct_methods: HashMap, @@ -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(), diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index b4f5441c981..ff0128e34b7 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -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, diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index d441f11959d..227fe245baa 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -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>; - 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>, - // 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; } diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index eb82b95389d..044b0418847 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -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(), diff --git a/src/test/run-pass/trait-default-method-bound-subst.rs b/src/test/run-pass/trait-default-method-bound-subst.rs new file mode 100644 index 00000000000..9fbb3562a7b --- /dev/null +++ b/src/test/run-pass/trait-default-method-bound-subst.rs @@ -0,0 +1,15 @@ +// xfail-test + +trait A { + fn g(x: T, y: U) -> (T, U) { (move x, move y) } +} + +impl int: A { } + +fn f>(i: V, j: T, k: U) -> (T, U) { + i.g(move j, move k) +} + +fn main () { + assert f(0, 1, 2) == (1, 2); +} diff --git a/src/test/run-pass/trait-default-method-bound-subst2.rs b/src/test/run-pass/trait-default-method-bound-subst2.rs new file mode 100644 index 00000000000..1cc35b85340 --- /dev/null +++ b/src/test/run-pass/trait-default-method-bound-subst2.rs @@ -0,0 +1,15 @@ +// xfail-test + +trait A { + fn g(x: T) -> T { move x } +} + +impl int: A { } + +fn f>(i: V, j: T) -> T { + i.g(move j) +} + +fn main () { + assert f(0, 2) == 2; +} diff --git a/src/test/run-pass/trait-default-method-bound-subst3.rs b/src/test/run-pass/trait-default-method-bound-subst3.rs new file mode 100644 index 00000000000..dafee149a2e --- /dev/null +++ b/src/test/run-pass/trait-default-method-bound-subst3.rs @@ -0,0 +1,14 @@ +trait A { + fn g(x: T, y: T) -> (T, T) { (move x, move y) } +} + +impl int: A { } + +fn f(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); +} diff --git a/src/test/run-pass/trait-default-method-bound-subst4.rs b/src/test/run-pass/trait-default-method-bound-subst4.rs new file mode 100644 index 00000000000..eeeefd041af --- /dev/null +++ b/src/test/run-pass/trait-default-method-bound-subst4.rs @@ -0,0 +1,14 @@ +trait A { + fn g(x: uint) -> uint { move x } +} + +impl int: A { } + +fn f>(i: V, j: uint) -> uint { + i.g(move j) +} + +fn main () { + assert f::(0, 2u) == 2u; + assert f::(0, 2u) == 2u; +} diff --git a/src/test/run-pass/trait-default-method-bound.rs b/src/test/run-pass/trait-default-method-bound.rs new file mode 100644 index 00000000000..3d22a3fdd66 --- /dev/null +++ b/src/test/run-pass/trait-default-method-bound.rs @@ -0,0 +1,13 @@ +trait A { + fn g() -> int { 10 } +} + +impl int: A { } + +fn f(i: T) { + assert i.g() == 10; +} + +fn main () { + f(0); +}