typeck: Modify method resolution to use new object adjustments, and
to favor inherent methods over extension methods. The reason to favor inherent methods is that otherwise an impl like impl Foo for @Foo { fn method(&self) { self.method() } } causes infinite recursion. The current change to favor inherent methods is rather hacky; the method resolution code is in need of a refactoring.
This commit is contained in:
parent
006c6b6be4
commit
1bceb98084
@ -586,8 +586,8 @@ impl tr for method_origin {
|
||||
}
|
||||
)
|
||||
}
|
||||
typeck::method_trait(did, m, vstore) => {
|
||||
typeck::method_trait(did.tr(xcx), m, vstore)
|
||||
typeck::method_trait(did, m) => {
|
||||
typeck::method_trait(did.tr(xcx), m)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -290,7 +290,7 @@ pub fn check_crate<'mm>(tcx: ty::ctxt,
|
||||
method_num: method_num,
|
||||
_
|
||||
}) |
|
||||
method_trait(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, _)) => {
|
||||
|
@ -3131,7 +3131,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_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.
|
||||
|
@ -94,6 +94,7 @@ 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;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
use std::hashmap::HashSet;
|
||||
use std::result;
|
||||
@ -147,9 +148,24 @@ pub fn lookup(
|
||||
check_traits: check_traits,
|
||||
autoderef_receiver: autoderef_receiver,
|
||||
};
|
||||
let mme = lcx.do_lookup(self_ty);
|
||||
debug!("method lookup for %s yielded %?", expr.repr(fcx.tcx()), mme);
|
||||
return mme;
|
||||
|
||||
let self_ty = structurally_resolved_type(fcx, self_expr.span, self_ty);
|
||||
debug!("method lookup(self_ty=%s, expr=%s, self_expr=%s)",
|
||||
self_ty.repr(fcx.tcx()), expr.repr(fcx.tcx()),
|
||||
self_expr.repr(fcx.tcx()));
|
||||
|
||||
debug!("searching inherent candidates");
|
||||
lcx.push_inherent_candidates(self_ty);
|
||||
let mme = lcx.search(self_ty);
|
||||
if mme.is_some() {
|
||||
return mme;
|
||||
}
|
||||
|
||||
debug!("searching extension candidates");
|
||||
lcx.reset_candidates();
|
||||
lcx.push_bound_candidates(self_ty);
|
||||
lcx.push_extension_candidates();
|
||||
return lcx.search(self_ty);
|
||||
}
|
||||
|
||||
pub struct LookupContext<'self> {
|
||||
@ -173,27 +189,28 @@ pub struct LookupContext<'self> {
|
||||
*/
|
||||
#[deriving(Clone)]
|
||||
pub struct Candidate {
|
||||
rcvr_ty: ty::t,
|
||||
rcvr_match_condition: RcvrMatchCondition,
|
||||
rcvr_substs: ty::substs,
|
||||
method_ty: @ty::Method,
|
||||
origin: method_origin,
|
||||
}
|
||||
|
||||
/// This type represents the conditions under which the receiver is
|
||||
/// considered to "match" a given method candidate. Typically the test
|
||||
/// is whether the receiver is of a particular type. However, this
|
||||
/// type is the type of the receiver *after accounting for the
|
||||
/// method's self type* (e.g., if the method is an `@self` method, we
|
||||
/// have *already verified* that the receiver is of some type `@T` and
|
||||
/// now we must check that the type `T` is correct). Unfortunately,
|
||||
/// because traits are not types, this is a pain to do.
|
||||
#[deriving(Clone)]
|
||||
enum RcvrMatchCondition {
|
||||
RcvrMatchesIfObject(ast::def_id),
|
||||
RcvrMatchesIfSubtype(ty::t)
|
||||
}
|
||||
|
||||
impl<'self> LookupContext<'self> {
|
||||
pub fn do_lookup(&self, self_ty: ty::t) -> Option<method_map_entry> {
|
||||
let self_ty = structurally_resolved_type(self.fcx,
|
||||
self.self_expr.span,
|
||||
self_ty);
|
||||
|
||||
debug!("do_lookup(self_ty=%s, expr=%s, self_expr=%s)",
|
||||
self.ty_to_str(self_ty),
|
||||
self.expr.repr(self.tcx()),
|
||||
self.self_expr.repr(self.tcx()));
|
||||
|
||||
// Prepare the list of candidates
|
||||
self.push_inherent_candidates(self_ty);
|
||||
self.push_extension_candidates();
|
||||
|
||||
fn search(&self, self_ty: ty::t) -> Option<method_map_entry> {
|
||||
let mut self_ty = self_ty;
|
||||
let mut autoderefs = 0;
|
||||
loop {
|
||||
@ -280,20 +297,10 @@ impl<'self> LookupContext<'self> {
|
||||
let mut self_ty = self_ty;
|
||||
loop {
|
||||
match get(self_ty).sty {
|
||||
ty_param(p) => {
|
||||
self.push_inherent_candidates_from_param(self_ty, p);
|
||||
}
|
||||
ty_trait(did, ref substs, store, _, _) => {
|
||||
self.push_inherent_candidates_from_trait(
|
||||
self_ty, did, substs, store);
|
||||
ty_trait(did, ref substs, _, _, _) => {
|
||||
self.push_inherent_candidates_from_trait(did, substs);
|
||||
self.push_inherent_impl_candidates_for_type(did);
|
||||
}
|
||||
ty_self(self_did) => {
|
||||
// Call is of the form "self.foo()" and appears in one
|
||||
// of a trait's default method implementations.
|
||||
self.push_inherent_candidates_from_self(
|
||||
self_ty, self_did);
|
||||
}
|
||||
ty_enum(did, _) | ty_struct(did, _) => {
|
||||
if self.check_traits == CheckTraitsAndInherentMethods {
|
||||
self.push_inherent_impl_candidates_for_type(did);
|
||||
@ -312,7 +319,30 @@ impl<'self> LookupContext<'self> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_extension_candidates(&self) {
|
||||
fn push_bound_candidates(&self, self_ty: ty::t) {
|
||||
let mut self_ty = self_ty;
|
||||
loop {
|
||||
match get(self_ty).sty {
|
||||
ty_param(p) => {
|
||||
self.push_inherent_candidates_from_param(self_ty, p);
|
||||
}
|
||||
ty_self(self_did) => {
|
||||
// Call is of the form "self.foo()" and appears in one
|
||||
// of a trait's default method implementations.
|
||||
self.push_inherent_candidates_from_self(
|
||||
self_ty, self_did);
|
||||
}
|
||||
_ => { /* No bound methods in these types */ }
|
||||
}
|
||||
|
||||
self_ty = match self.deref(self_ty) {
|
||||
None => { return; }
|
||||
Some(ty) => { ty }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn push_extension_candidates(&self) {
|
||||
// If the method being called is associated with a trait, then
|
||||
// find all the impls of that trait. Each of those are
|
||||
// candidates.
|
||||
@ -333,11 +363,9 @@ impl<'self> LookupContext<'self> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_inherent_candidates_from_trait(&self,
|
||||
self_ty: ty::t,
|
||||
fn push_inherent_candidates_from_trait(&self,
|
||||
did: def_id,
|
||||
substs: &ty::substs,
|
||||
store: ty::TraitStore) {
|
||||
substs: &ty::substs) {
|
||||
debug!("push_inherent_candidates_from_trait(did=%s, substs=%s)",
|
||||
self.did_to_str(did),
|
||||
substs_to_str(self.tcx(), substs));
|
||||
@ -351,41 +379,35 @@ impl<'self> LookupContext<'self> {
|
||||
};
|
||||
let method = ms[index];
|
||||
|
||||
/* FIXME(#5762) we should transform the vstore in accordance
|
||||
with the self type
|
||||
|
||||
match method.self_type {
|
||||
ast::sty_region(_) => {
|
||||
return; // inapplicable
|
||||
match method.explicit_self {
|
||||
ast::sty_static => {
|
||||
return; // not a method we can call with dot notation
|
||||
}
|
||||
ast::sty_region(_) => vstore_slice(r)
|
||||
ast::sty_box(_) => vstore_box, // NDM mutability, as per #5762
|
||||
ast::sty_uniq(_) => vstore_uniq
|
||||
_ => {}
|
||||
}
|
||||
*/
|
||||
|
||||
// It is illegal to invoke a method on a trait instance that
|
||||
// refers to the `self` type. Nonetheless, we substitute
|
||||
// `trait_ty` for `self` here, because it allows the compiler
|
||||
// to soldier on. An error will be reported should this
|
||||
// candidate be selected if the method refers to `self`.
|
||||
// refers to the `self` type. An error will be reported by
|
||||
// `enforce_object_limitations()` if the method refers
|
||||
// to the `Self` type. Substituting ty_err here allows
|
||||
// compiler to soldier on.
|
||||
//
|
||||
// NB: `confirm_candidate()` also relies upon this substitution
|
||||
// for Self.
|
||||
// NOTE: `confirm_candidate()` also relies upon this substitution
|
||||
// for Self. (fix)
|
||||
let rcvr_substs = substs {
|
||||
self_ty: Some(self_ty),
|
||||
self_ty: Some(ty::mk_err()),
|
||||
..(*substs).clone()
|
||||
};
|
||||
|
||||
self.inherent_candidates.push(Candidate {
|
||||
rcvr_ty: self_ty,
|
||||
rcvr_match_condition: RcvrMatchesIfObject(did),
|
||||
rcvr_substs: rcvr_substs,
|
||||
method_ty: method,
|
||||
origin: method_trait(did, index, store)
|
||||
origin: method_trait(did, index)
|
||||
});
|
||||
}
|
||||
|
||||
pub fn push_inherent_candidates_from_param(&self,
|
||||
fn push_inherent_candidates_from_param(&self,
|
||||
rcvr_ty: ty::t,
|
||||
param_ty: param_ty) {
|
||||
debug!("push_inherent_candidates_from_param(param_ty=%?)",
|
||||
@ -438,11 +460,11 @@ impl<'self> LookupContext<'self> {
|
||||
let method = trait_methods[pos];
|
||||
|
||||
let cand = Candidate {
|
||||
rcvr_ty: self_ty,
|
||||
rcvr_match_condition: RcvrMatchesIfSubtype(self_ty),
|
||||
rcvr_substs: bound_trait_ref.substs.clone(),
|
||||
method_ty: method,
|
||||
origin: method_param(
|
||||
method_param {
|
||||
method_param {
|
||||
trait_id: bound_trait_ref.def_id,
|
||||
method_num: pos,
|
||||
param_num: param,
|
||||
@ -507,7 +529,7 @@ impl<'self> LookupContext<'self> {
|
||||
} = impl_self_ty(&vcx, location_info, impl_info.did);
|
||||
|
||||
candidates.push(Candidate {
|
||||
rcvr_ty: impl_ty,
|
||||
rcvr_match_condition: RcvrMatchesIfSubtype(impl_ty),
|
||||
rcvr_substs: impl_substs,
|
||||
method_ty: method,
|
||||
origin: method_static(method.def_id)
|
||||
@ -583,6 +605,17 @@ impl<'self> LookupContext<'self> {
|
||||
autoderefs: autoderefs,
|
||||
autoref: Some(ty::AutoBorrowVec(region, self_mt.mutbl))}))
|
||||
}
|
||||
ty_trait(did, ref substs, ty::RegionTraitStore(_), mutbl, bounds) => {
|
||||
let region =
|
||||
self.infcx().next_region_var(
|
||||
infer::Autoref(self.expr.span));
|
||||
(ty::mk_trait(tcx, did, substs.clone(),
|
||||
ty::RegionTraitStore(region),
|
||||
mutbl, bounds),
|
||||
ty::AutoDerefRef(ty::AutoDerefRef {
|
||||
autoderefs: autoderefs,
|
||||
autoref: Some(ty::AutoBorrowObj(region, mutbl))}))
|
||||
}
|
||||
_ => {
|
||||
(self_ty,
|
||||
ty::AutoDerefRef(ty::AutoDerefRef {
|
||||
@ -612,7 +645,8 @@ impl<'self> LookupContext<'self> {
|
||||
* `~[]` to `&[]`. */
|
||||
|
||||
let tcx = self.tcx();
|
||||
match ty::get(self_ty).sty {
|
||||
let sty = ty::get(self_ty).sty.clone();
|
||||
match sty {
|
||||
ty_evec(mt, vstore_box) |
|
||||
ty_evec(mt, vstore_uniq) |
|
||||
ty_evec(mt, vstore_slice(_)) | // NDM(#3148)
|
||||
@ -659,8 +693,20 @@ impl<'self> LookupContext<'self> {
|
||||
})
|
||||
}
|
||||
|
||||
ty_trait(*) | ty_closure(*) => {
|
||||
// NDM---eventually these should be some variant of autoref
|
||||
ty_trait(trt_did, trt_substs, _, _, b) => {
|
||||
// Coerce ~/@/&Trait instances to &Trait.
|
||||
|
||||
self.search_for_some_kind_of_autorefd_method(
|
||||
AutoBorrowObj, autoderefs, [m_const, m_imm, m_mutbl],
|
||||
|trt_mut, reg| {
|
||||
ty::mk_trait(tcx, trt_did, trt_substs.clone(),
|
||||
RegionTraitStore(reg), trt_mut, b)
|
||||
})
|
||||
}
|
||||
|
||||
ty_closure(*) => {
|
||||
// This case should probably be handled similarly to
|
||||
// Trait instances.
|
||||
None
|
||||
}
|
||||
|
||||
@ -840,31 +886,16 @@ impl<'self> LookupContext<'self> {
|
||||
self.cand_to_str(candidate),
|
||||
self.ty_to_str(fty));
|
||||
|
||||
self.enforce_trait_instance_limitations(fty, candidate);
|
||||
self.enforce_object_limitations(fty, candidate);
|
||||
self.enforce_drop_trait_limitations(candidate);
|
||||
|
||||
// static methods should never have gotten this far:
|
||||
assert!(candidate.method_ty.explicit_self != sty_static);
|
||||
|
||||
let transformed_self_ty = match candidate.origin {
|
||||
method_trait(*) => {
|
||||
match candidate.method_ty.explicit_self {
|
||||
sty_region(*) => {
|
||||
// FIXME(#5762) again, preserving existing
|
||||
// behavior here which (for &self) desires
|
||||
// &@Trait where @Trait is the type of the
|
||||
// receiver. Here we fetch the method's
|
||||
// transformed_self_ty which will be something
|
||||
// like &'a Self. We then perform a
|
||||
// substitution which will replace Self with
|
||||
// @Trait.
|
||||
let t = candidate.method_ty.transformed_self_ty.unwrap();
|
||||
ty::subst(tcx, &candidate.rcvr_substs, t)
|
||||
}
|
||||
_ => {
|
||||
candidate.rcvr_ty
|
||||
}
|
||||
}
|
||||
method_trait(trait_def_id, _) => {
|
||||
self.construct_transformed_self_ty_for_object(
|
||||
trait_def_id, candidate)
|
||||
}
|
||||
_ => {
|
||||
let t = candidate.method_ty.transformed_self_ty.unwrap();
|
||||
@ -954,23 +985,88 @@ impl<'self> LookupContext<'self> {
|
||||
self.fcx.write_ty(self.callee_id, fty);
|
||||
self.fcx.write_substs(self.callee_id, all_substs);
|
||||
method_map_entry {
|
||||
self_ty: rcvr_ty,
|
||||
self_ty: transformed_self_ty,
|
||||
self_mode: self_mode,
|
||||
explicit_self: candidate.method_ty.explicit_self,
|
||||
origin: candidate.origin,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enforce_trait_instance_limitations(&self,
|
||||
method_fty: ty::t,
|
||||
candidate: &Candidate) {
|
||||
fn construct_transformed_self_ty_for_object(&self,
|
||||
trait_def_id: ast::def_id,
|
||||
candidate: &Candidate) -> ty::t
|
||||
{
|
||||
/*!
|
||||
* This is a bit tricky. We have a match against a trait method
|
||||
* being invoked on an object, and we want to generate the
|
||||
* self-type. As an example, consider a trait
|
||||
*
|
||||
* There are some limitations to calling functions through a
|
||||
* trait instance, because (a) the self type is not known
|
||||
* trait Foo {
|
||||
* fn r_method<'a>(&'a self);
|
||||
* fn m_method(@mut self);
|
||||
* }
|
||||
*
|
||||
* Now, assuming that `r_method` is being called, we want the
|
||||
* result to be `&'a Foo`. Assuming that `m_method` is being
|
||||
* called, we want the result to be `@mut Foo`. Of course,
|
||||
* this transformation has already been done as part of
|
||||
* `candidate.method_ty.transformed_self_ty`, but there the
|
||||
* type is expressed in terms of `Self` (i.e., `&'a Self`, `@mut Self`).
|
||||
* Because objects are not standalone types, we can't just substitute
|
||||
* `s/Self/Foo/`, so we must instead perform this kind of hokey
|
||||
* match below.
|
||||
*/
|
||||
|
||||
let substs = ty::substs {regions: candidate.rcvr_substs.regions.clone(),
|
||||
self_ty: None,
|
||||
tps: candidate.rcvr_substs.tps.clone()};
|
||||
match candidate.method_ty.explicit_self {
|
||||
ast::sty_static => {
|
||||
self.bug(~"static method for object type receiver");
|
||||
}
|
||||
ast::sty_value => {
|
||||
ty::mk_err() // error reported in `enforce_object_limitations()`
|
||||
}
|
||||
ast::sty_region(*) | ast::sty_box(*) | ast::sty_uniq(*) => {
|
||||
let transformed_self_ty =
|
||||
candidate.method_ty.transformed_self_ty.clone().unwrap();
|
||||
match ty::get(transformed_self_ty).sty {
|
||||
ty::ty_rptr(r, mt) => { // must be sty_region
|
||||
ty::mk_trait(self.tcx(), trait_def_id,
|
||||
substs, RegionTraitStore(r), mt.mutbl,
|
||||
ty::EmptyBuiltinBounds())
|
||||
}
|
||||
ty::ty_box(mt) => { // must be sty_box
|
||||
ty::mk_trait(self.tcx(), trait_def_id,
|
||||
substs, BoxTraitStore, mt.mutbl,
|
||||
ty::EmptyBuiltinBounds())
|
||||
}
|
||||
ty::ty_uniq(mt) => { // must be sty_uniq
|
||||
ty::mk_trait(self.tcx(), trait_def_id,
|
||||
substs, UniqTraitStore, mt.mutbl,
|
||||
ty::EmptyBuiltinBounds())
|
||||
}
|
||||
_ => {
|
||||
self.bug(
|
||||
fmt!("'impossible' transformed_self_ty: %s",
|
||||
transformed_self_ty.repr(self.tcx())));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn enforce_object_limitations(&self,
|
||||
method_fty: ty::t,
|
||||
candidate: &Candidate)
|
||||
{
|
||||
/*!
|
||||
* There are some limitations to calling functions through an
|
||||
* object, 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. */
|
||||
* vtable and hence cannot be monomorphized.
|
||||
*/
|
||||
|
||||
match candidate.origin {
|
||||
method_static(*) | method_param(*) => {
|
||||
@ -979,21 +1075,39 @@ impl<'self> LookupContext<'self> {
|
||||
method_trait(*) => {}
|
||||
}
|
||||
|
||||
if ty::type_has_self(method_fty) {
|
||||
match candidate.method_ty.explicit_self {
|
||||
ast::sty_static => { // reason (a) above
|
||||
self.tcx().sess.span_err(
|
||||
self.expr.span,
|
||||
"cannot call a method without a receiver \
|
||||
through an object");
|
||||
}
|
||||
|
||||
ast::sty_value => { // reason (a) above
|
||||
self.tcx().sess.span_err(
|
||||
self.expr.span,
|
||||
"cannot call a method with a by-value receiver \
|
||||
through an object");
|
||||
}
|
||||
|
||||
ast::sty_region(*) | ast::sty_box(*) | ast::sty_uniq(*) => {}
|
||||
}
|
||||
|
||||
if ty::type_has_self(method_fty) { // reason (a) above
|
||||
self.tcx().sess.span_err(
|
||||
self.expr.span,
|
||||
"cannot call a method whose type contains a \
|
||||
self-type through a boxed trait");
|
||||
self-type through an object");
|
||||
}
|
||||
|
||||
if candidate.method_ty.generics.has_type_params() {
|
||||
if candidate.method_ty.generics.has_type_params() { // reason (b) above
|
||||
self.tcx().sess.span_err(
|
||||
self.expr.span,
|
||||
"cannot call a generic method through a boxed trait");
|
||||
"cannot call a generic method through an object");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enforce_drop_trait_limitations(&self, candidate: &Candidate) {
|
||||
fn enforce_drop_trait_limitations(&self, candidate: &Candidate) {
|
||||
// No code can call the finalize method explicitly.
|
||||
let bad;
|
||||
match candidate.origin {
|
||||
@ -1003,7 +1117,7 @@ impl<'self> LookupContext<'self> {
|
||||
// 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, _, _) => {
|
||||
method_trait(trait_id, _) => {
|
||||
bad = self.tcx().destructor_for_type.contains_key(&trait_id);
|
||||
}
|
||||
}
|
||||
@ -1016,43 +1130,18 @@ impl<'self> LookupContext<'self> {
|
||||
|
||||
// `rcvr_ty` is the type of the expression. It may be a subtype of a
|
||||
// candidate method's `self_ty`.
|
||||
pub fn is_relevant(&self, rcvr_ty: ty::t, candidate: &Candidate) -> bool {
|
||||
fn is_relevant(&self, rcvr_ty: ty::t, candidate: &Candidate) -> bool {
|
||||
debug!("is_relevant(rcvr_ty=%s, candidate=%s)",
|
||||
self.ty_to_str(rcvr_ty), self.cand_to_str(candidate));
|
||||
|
||||
// Check for calls to object methods. We resolve these differently.
|
||||
//
|
||||
// FIXME(#5762)---we don't check that an @self method is only called
|
||||
// on an @Trait object here and so forth
|
||||
match candidate.origin {
|
||||
method_trait(*) => {
|
||||
match candidate.method_ty.explicit_self {
|
||||
sty_static | sty_value => {
|
||||
return false;
|
||||
}
|
||||
sty_region(*) => {
|
||||
// just echoing current behavior here, which treats
|
||||
// an &self method on an @Trait object as requiring
|
||||
// an &@Trait receiver (wacky)
|
||||
}
|
||||
sty_box(*) | sty_uniq(*) => {
|
||||
return self.fcx.can_mk_subty(rcvr_ty,
|
||||
candidate.rcvr_ty).is_ok();
|
||||
}
|
||||
};
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let result = match candidate.method_ty.explicit_self {
|
||||
return match candidate.method_ty.explicit_self {
|
||||
sty_static => {
|
||||
debug!("(is relevant?) explicit self is static");
|
||||
false
|
||||
}
|
||||
|
||||
sty_value => {
|
||||
debug!("(is relevant?) explicit self is by-value");
|
||||
self.fcx.can_mk_subty(rcvr_ty, candidate.rcvr_ty).is_ok()
|
||||
rcvr_matches_ty(self.fcx, rcvr_ty, candidate)
|
||||
}
|
||||
|
||||
sty_region(_, m) => {
|
||||
@ -1060,7 +1149,12 @@ impl<'self> LookupContext<'self> {
|
||||
match ty::get(rcvr_ty).sty {
|
||||
ty::ty_rptr(_, mt) => {
|
||||
mutability_matches(mt.mutbl, m) &&
|
||||
self.fcx.can_mk_subty(mt.ty, candidate.rcvr_ty).is_ok()
|
||||
rcvr_matches_ty(self.fcx, mt.ty, candidate)
|
||||
}
|
||||
|
||||
ty::ty_trait(self_did, _, RegionTraitStore(_), self_m, _) => {
|
||||
mutability_matches(self_m, m) &&
|
||||
rcvr_matches_object(self_did, candidate)
|
||||
}
|
||||
|
||||
_ => false
|
||||
@ -1072,7 +1166,12 @@ impl<'self> LookupContext<'self> {
|
||||
match ty::get(rcvr_ty).sty {
|
||||
ty::ty_box(mt) => {
|
||||
mutability_matches(mt.mutbl, m) &&
|
||||
self.fcx.can_mk_subty(mt.ty, candidate.rcvr_ty).is_ok()
|
||||
rcvr_matches_ty(self.fcx, mt.ty, candidate)
|
||||
}
|
||||
|
||||
ty::ty_trait(self_did, _, BoxTraitStore, self_m, _) => {
|
||||
mutability_matches(self_m, m) &&
|
||||
rcvr_matches_object(self_did, candidate)
|
||||
}
|
||||
|
||||
_ => false
|
||||
@ -1083,8 +1182,11 @@ impl<'self> LookupContext<'self> {
|
||||
debug!("(is relevant?) explicit self is a unique pointer");
|
||||
match ty::get(rcvr_ty).sty {
|
||||
ty::ty_uniq(mt) => {
|
||||
mutability_matches(mt.mutbl, ast::m_imm) &&
|
||||
self.fcx.can_mk_subty(mt.ty, candidate.rcvr_ty).is_ok()
|
||||
rcvr_matches_ty(self.fcx, mt.ty, candidate)
|
||||
}
|
||||
|
||||
ty::ty_trait(self_did, _, UniqTraitStore, _, _) => {
|
||||
rcvr_matches_object(self_did, candidate)
|
||||
}
|
||||
|
||||
_ => false
|
||||
@ -1092,9 +1194,30 @@ impl<'self> LookupContext<'self> {
|
||||
}
|
||||
};
|
||||
|
||||
debug!("(is relevant?) %s", if result { "yes" } else { "no" });
|
||||
fn rcvr_matches_object(self_did: ast::def_id,
|
||||
candidate: &Candidate) -> bool {
|
||||
match candidate.rcvr_match_condition {
|
||||
RcvrMatchesIfObject(desired_did) => {
|
||||
self_did == desired_did
|
||||
}
|
||||
RcvrMatchesIfSubtype(_) => {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
fn rcvr_matches_ty(fcx: @mut FnCtxt,
|
||||
rcvr_ty: ty::t,
|
||||
candidate: &Candidate) -> bool {
|
||||
match candidate.rcvr_match_condition {
|
||||
RcvrMatchesIfObject(_) => {
|
||||
false
|
||||
}
|
||||
RcvrMatchesIfSubtype(of_type) => {
|
||||
fcx.can_mk_subty(rcvr_ty, of_type).is_ok()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn mutability_matches(self_mutbl: ast::mutability,
|
||||
candidate_mutbl: ast::mutability) -> bool {
|
||||
@ -1120,7 +1243,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_trait(did, idx) => {
|
||||
type_of_trait_method(self.tcx(), did, idx)
|
||||
}
|
||||
};
|
||||
@ -1141,7 +1264,7 @@ impl<'self> LookupContext<'self> {
|
||||
method_param(ref mp) => {
|
||||
self.report_param_candidate(idx, (*mp).trait_id)
|
||||
}
|
||||
method_trait(trait_did, _, _) => {
|
||||
method_trait(trait_did, _) => {
|
||||
self.report_trait_candidate(idx, trait_did)
|
||||
}
|
||||
}
|
||||
@ -1214,3 +1337,16 @@ pub fn get_mode_from_explicit_self(explicit_self: ast::explicit_self_) -> SelfMo
|
||||
_ => ty::ByCopy,
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for RcvrMatchCondition {
|
||||
fn repr(&self, tcx: ty::ctxt) -> ~str {
|
||||
match *self {
|
||||
RcvrMatchesIfObject(d) => {
|
||||
fmt!("RcvrMatchesIfObject(%s)", d.repr(tcx))
|
||||
}
|
||||
RcvrMatchesIfSubtype(t) => {
|
||||
fmt!("RcvrMatchesIfSubtype(%s)", t.repr(tcx))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -863,7 +863,8 @@ pub mod guarantor {
|
||||
|
||||
ty::AutoBorrowVec(r, _) |
|
||||
ty::AutoBorrowVecRef(r, _) |
|
||||
ty::AutoBorrowFn(r) => {
|
||||
ty::AutoBorrowFn(r) |
|
||||
ty::AutoBorrowObj(r, _) => {
|
||||
// In each of these cases, what is being borrowed is
|
||||
// not the (autoderef'd) expr itself but rather the
|
||||
// contents of the autoderef'd expression (i.e., what
|
||||
@ -1072,7 +1073,8 @@ pub mod guarantor {
|
||||
Some(ty::AutoPtr(r, _)) |
|
||||
Some(ty::AutoBorrowVec(r, _)) |
|
||||
Some(ty::AutoBorrowVecRef(r, _)) |
|
||||
Some(ty::AutoBorrowFn(r)) => {
|
||||
Some(ty::AutoBorrowFn(r)) |
|
||||
Some(ty::AutoBorrowObj(r, _)) => {
|
||||
// If there is an autoref, then the result of this
|
||||
// expression will be some sort of borrowed pointer.
|
||||
expr_ct.cat.guarantor = None;
|
||||
|
@ -65,7 +65,7 @@ we may want to adjust precisely when coercions occur.
|
||||
*/
|
||||
|
||||
|
||||
use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowFn};
|
||||
use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowFn, AutoBorrowObj};
|
||||
use middle::ty::{AutoDerefRef};
|
||||
use middle::ty::{vstore_slice, vstore_box, vstore_uniq};
|
||||
use middle::ty::{mt};
|
||||
@ -121,6 +121,12 @@ impl Coerce {
|
||||
};
|
||||
}
|
||||
|
||||
ty::ty_trait(_, _, ty::RegionTraitStore(*), _, _) => {
|
||||
return do self.unpack_actual_value(a) |sty_a| {
|
||||
self.coerce_borrowed_object(a, sty_a, b)
|
||||
};
|
||||
}
|
||||
|
||||
ty::ty_ptr(mt_b) => {
|
||||
return do self.unpack_actual_value(a) |sty_a| {
|
||||
self.coerce_unsafe_ptr(a, sty_a, b, mt_b)
|
||||
@ -265,6 +271,40 @@ impl Coerce {
|
||||
})))
|
||||
}
|
||||
|
||||
fn coerce_borrowed_object(&self,
|
||||
a: ty::t,
|
||||
sty_a: &ty::sty,
|
||||
b: ty::t) -> CoerceResult
|
||||
{
|
||||
debug!("coerce_borrowed_object(a=%s, sty_a=%?, b=%s)",
|
||||
a.inf_str(self.infcx), sty_a,
|
||||
b.inf_str(self.infcx));
|
||||
|
||||
let tcx = self.infcx.tcx;
|
||||
let r_a = self.infcx.next_region_var(Coercion(self.trace));
|
||||
let trt_mut;
|
||||
|
||||
let a_borrowed = match *sty_a {
|
||||
ty::ty_trait(_, _, ty::RegionTraitStore(_), _, _) => {
|
||||
return self.subtype(a, b);
|
||||
}
|
||||
ty::ty_trait(did, ref substs, _, m, b) => {
|
||||
trt_mut = m;
|
||||
ty::mk_trait(tcx, did, substs.clone(),
|
||||
ty::RegionTraitStore(r_a), m, b)
|
||||
}
|
||||
_ => {
|
||||
return self.subtype(a, b);
|
||||
}
|
||||
};
|
||||
|
||||
if_ok!(self.tys(a_borrowed, b));
|
||||
Ok(Some(@AutoDerefRef(AutoDerefRef {
|
||||
autoderefs: 0,
|
||||
autoref: Some(AutoBorrowObj(r_a, trt_mut))
|
||||
})))
|
||||
}
|
||||
|
||||
pub fn coerce_borrowed_fn(&self,
|
||||
a: ty::t,
|
||||
sty_a: &ty::sty,
|
||||
|
@ -88,7 +88,7 @@ pub enum method_origin {
|
||||
method_param(method_param),
|
||||
|
||||
// method invoked on a trait instance
|
||||
method_trait(ast::def_id, uint, ty::TraitStore),
|
||||
method_trait(ast::def_id, uint),
|
||||
|
||||
}
|
||||
|
||||
|
@ -747,9 +747,8 @@ impl Repr for typeck::method_origin {
|
||||
&typeck::method_param(ref p) => {
|
||||
p.repr(tcx)
|
||||
}
|
||||
&typeck::method_trait(def_id, n, st) => {
|
||||
fmt!("method_trait(%s, %?, %s)", def_id.repr(tcx), n,
|
||||
st.repr(tcx))
|
||||
&typeck::method_trait(def_id, n) => {
|
||||
fmt!("method_trait(%s, %?)", def_id.repr(tcx), n)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user