De-@ typeck::check::method.

This commit is contained in:
Eduard Burtescu 2014-03-14 10:44:03 +02:00
parent da842c6278
commit a1e24c7f22

View File

@ -95,7 +95,6 @@ use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
use util::common::indenter;
use util::ppaux::Repr;
use std::cell::RefCell;
use collections::HashSet;
use std::result;
use std::vec_ng::Vec;
@ -132,15 +131,15 @@ pub fn lookup<'a>(
check_traits: CheckTraitsFlag, // Whether we check traits only.
autoderef_receiver: AutoderefReceiverFlag)
-> Option<MethodCallee> {
let lcx = LookupContext {
let mut lcx = LookupContext {
fcx: fcx,
span: expr.span,
self_expr: Some(self_expr),
m_name: m_name,
supplied_tps: supplied_tps,
impl_dups: @RefCell::new(HashSet::new()),
inherent_candidates: @RefCell::new(Vec::new()),
extension_candidates: @RefCell::new(Vec::new()),
impl_dups: HashSet::new(),
inherent_candidates: Vec::new(),
extension_candidates: Vec::new(),
deref_args: deref_args,
check_traits: check_traits,
autoderef_receiver: autoderef_receiver,
@ -161,7 +160,7 @@ pub fn lookup<'a>(
lcx.reset_candidates();
lcx.push_bound_candidates(self_ty, None);
lcx.push_extension_candidates(expr.id);
return lcx.search(self_ty);
lcx.search(self_ty)
}
pub fn lookup_in_trait<'a>(
@ -176,15 +175,15 @@ pub fn lookup_in_trait<'a>(
supplied_tps: &'a [ty::t], // The list of types X, Y, ... .
autoderef_receiver: AutoderefReceiverFlag)
-> Option<MethodCallee> {
let lcx = LookupContext {
let mut lcx = LookupContext {
fcx: fcx,
span: span,
self_expr: self_expr,
m_name: m_name,
supplied_tps: supplied_tps,
impl_dups: @RefCell::new(HashSet::new()),
inherent_candidates: @RefCell::new(Vec::new()),
extension_candidates: @RefCell::new(Vec::new()),
impl_dups: HashSet::new(),
inherent_candidates: Vec::new(),
extension_candidates: Vec::new(),
deref_args: check::DoDerefArgs,
check_traits: CheckTraitsOnly,
autoderef_receiver: autoderef_receiver,
@ -198,6 +197,91 @@ pub fn lookup_in_trait<'a>(
lcx.search(self_ty)
}
// Determine the index of a method in the list of all methods belonging
// to a trait and its supertraits.
fn get_method_index(tcx: &ty::ctxt,
trait_ref: &TraitRef,
subtrait: @TraitRef,
n_method: uint) -> uint {
// We need to figure the "real index" of the method in a
// listing of all the methods of an object. We do this by
// iterating down the supertraits of the object's trait until
// we find the trait the method came from, counting up the
// methods from them.
let mut method_count = 0;
ty::each_bound_trait_and_supertraits(tcx, &[subtrait], |bound_ref| {
if bound_ref.def_id == trait_ref.def_id { false }
else {
method_count += ty::trait_methods(tcx, bound_ref.def_id).len();
true
}
});
method_count + n_method
}
fn construct_transformed_self_ty_for_object(
tcx: &ty::ctxt,
span: Span,
trait_def_id: ast::DefId,
rcvr_substs: &ty::substs,
method_ty: &ty::Method)
-> 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
*
* trait Foo {
* fn r_method<'a>(&'a self);
* fn u_method(~self);
* }
*
* Now, assuming that `r_method` is being called, we want the
* result to be `&'a Foo`. Assuming that `u_method` is being
* called, we want the result to be `~Foo`. Of course,
* this transformation has already been done as part of
* `method_ty.fty.sig.inputs[0]`, but there the type
* is expressed in terms of `Self` (i.e., `&'a Self`, `~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: rcvr_substs.regions.clone(),
self_ty: None,
tps: rcvr_substs.tps.clone()};
match method_ty.explicit_self {
ast::SelfStatic => {
tcx.sess.span_bug(span, "static method for object type receiver");
}
ast::SelfValue => {
ty::mk_err() // error reported in `enforce_object_limitations()`
}
ast::SelfRegion(..) | ast::SelfUniq => {
let transformed_self_ty = *method_ty.fty.sig.inputs.get(0);
match ty::get(transformed_self_ty).sty {
ty::ty_rptr(r, mt) => { // must be SelfRegion
ty::mk_trait(tcx, trait_def_id, substs,
RegionTraitStore(r), mt.mutbl,
ty::EmptyBuiltinBounds())
}
ty::ty_uniq(_) => { // must be SelfUniq
ty::mk_trait(tcx, trait_def_id, substs,
UniqTraitStore, ast::MutImmutable,
ty::EmptyBuiltinBounds())
}
_ => {
tcx.sess.span_bug(span,
format!("'impossible' transformed_self_ty: {}",
transformed_self_ty.repr(tcx)));
}
}
}
}
}
struct LookupContext<'a> {
fcx: &'a FnCtxt<'a>,
span: Span,
@ -210,9 +294,9 @@ struct LookupContext<'a> {
m_name: ast::Name,
supplied_tps: &'a [ty::t],
impl_dups: @RefCell<HashSet<DefId>>,
inherent_candidates: @RefCell<Vec<Candidate> >,
extension_candidates: @RefCell<Vec<Candidate> >,
impl_dups: HashSet<DefId>,
inherent_candidates: Vec<Candidate>,
extension_candidates: Vec<Candidate>,
deref_args: check::DerefArgs,
check_traits: CheckTraitsFlag,
autoderef_receiver: AutoderefReceiverFlag,
@ -315,12 +399,12 @@ impl<'a> LookupContext<'a> {
// ______________________________________________________________________
// Candidate collection (see comment at start of file)
fn reset_candidates(&self) {
self.inherent_candidates.set(Vec::new());
self.extension_candidates.set(Vec::new());
fn reset_candidates(&mut self) {
self.inherent_candidates = Vec::new();
self.extension_candidates = Vec::new();
}
fn push_inherent_candidates(&self, self_ty: ty::t) {
fn push_inherent_candidates(&mut self, self_ty: ty::t) {
/*!
* Collect all inherent candidates into
* `self.inherent_candidates`. See comment at the start of
@ -354,7 +438,7 @@ impl<'a> LookupContext<'a> {
});
}
fn push_bound_candidates(&self, self_ty: ty::t, restrict_to: Option<DefId>) {
fn push_bound_candidates(&mut self, self_ty: ty::t, restrict_to: Option<DefId>) {
let span = self.self_expr.map_or(self.span, |e| e.span);
check::autoderef(self.fcx, span, self_ty, None, PreferMutLvalue, |self_ty, _| {
match get(self_ty).sty {
@ -378,20 +462,18 @@ impl<'a> LookupContext<'a> {
});
}
fn push_extension_candidate(&self, trait_did: DefId) {
fn push_extension_candidate(&mut self, trait_did: DefId) {
ty::populate_implementations_for_trait_if_necessary(self.tcx(), trait_did);
// Look for explicit implementations.
let trait_impls = self.tcx().trait_impls.borrow();
for impl_infos in trait_impls.get().find(&trait_did).iter() {
for impl_infos in self.tcx().trait_impls.borrow().get().find(&trait_did).iter() {
for impl_info in impl_infos.borrow().get().iter() {
self.push_candidates_from_impl(
self.extension_candidates.borrow_mut().get(), *impl_info);
self.push_candidates_from_impl(*impl_info, true);
}
}
}
fn push_extension_candidates(&self, expr_id: ast::NodeId) {
fn push_extension_candidates(&mut self, expr_id: ast::NodeId) {
// If the method being called is associated with a trait, then
// find all the impls of that trait. Each of those are
// candidates.
@ -403,38 +485,15 @@ impl<'a> LookupContext<'a> {
}
}
// Determine the index of a method in the list of all methods belonging
// to a trait and its supertraits.
fn get_method_index(&self,
trait_ref: @TraitRef,
subtrait: @TraitRef,
n_method: uint) -> uint {
let tcx = self.tcx();
// We need to figure the "real index" of the method in a
// listing of all the methods of an object. We do this by
// iterating down the supertraits of the object's trait until
// we find the trait the method came from, counting up the
// methods from them.
let mut method_count = 0;
ty::each_bound_trait_and_supertraits(tcx, &[subtrait], |bound_ref| {
if bound_ref.def_id == trait_ref.def_id { false }
else {
method_count += ty::trait_methods(tcx, bound_ref.def_id).len();
true
}
});
return method_count + n_method;
}
fn push_inherent_candidates_from_object(&self,
fn push_inherent_candidates_from_object(&mut self,
did: DefId,
substs: &ty::substs) {
debug!("push_inherent_candidates_from_object(did={}, substs={})",
self.did_to_str(did),
substs.repr(self.tcx()));
let _indenter = indenter();
let tcx = self.tcx();
let span = self.span;
// It is illegal to invoke a method on a trait instance that
// refers to the `self` type. An error will be reported by
@ -452,13 +511,13 @@ impl<'a> LookupContext<'a> {
self.push_inherent_candidates_from_bounds_inner(&[trait_ref],
|new_trait_ref, m, method_num, _bound_num| {
let vtable_index =
self.get_method_index(new_trait_ref, trait_ref, method_num);
let vtable_index = get_method_index(tcx, new_trait_ref,
trait_ref, method_num);
let mut m = (*m).clone();
// We need to fix up the transformed self type.
*m.fty.sig.inputs.get_mut(0) =
self.construct_transformed_self_ty_for_object(
did, &rcvr_substs, &m);
construct_transformed_self_ty_for_object(
tcx, span, did, &rcvr_substs, &m);
Some(Candidate {
rcvr_match_condition: RcvrMatchesIfObject(did),
@ -474,7 +533,7 @@ impl<'a> LookupContext<'a> {
});
}
fn push_inherent_candidates_from_param(&self,
fn push_inherent_candidates_from_param(&mut self,
rcvr_ty: ty::t,
restrict_to: Option<DefId>,
param_ty: param_ty) {
@ -494,7 +553,7 @@ impl<'a> LookupContext<'a> {
}
fn push_inherent_candidates_from_self(&self,
fn push_inherent_candidates_from_self(&mut self,
rcvr_ty: ty::t,
restrict_to: Option<DefId>) {
debug!("push_inherent_candidates_from_self()");
@ -505,7 +564,7 @@ impl<'a> LookupContext<'a> {
param_self)
}
fn push_inherent_candidates_from_bounds(&self,
fn push_inherent_candidates_from_bounds(&mut self,
self_ty: ty::t,
bounds: &[@TraitRef],
restrict_to: Option<DefId>,
@ -536,7 +595,7 @@ impl<'a> LookupContext<'a> {
// Do a search through a list of bounds, using a callback to actually
// create the candidates.
fn push_inherent_candidates_from_bounds_inner(&self,
fn push_inherent_candidates_from_bounds_inner(&mut self,
bounds: &[@TraitRef],
mk_cand: |tr: @TraitRef,
m: @ty::Method,
@ -561,7 +620,7 @@ impl<'a> LookupContext<'a> {
Some(cand) => {
debug!("pushing inherent candidate for param: {}",
cand.repr(self.tcx()));
self.inherent_candidates.borrow_mut().get().push(cand);
self.inherent_candidates.push(cand);
}
None => {}
}
@ -577,32 +636,23 @@ impl<'a> LookupContext<'a> {
}
fn push_inherent_impl_candidates_for_type(&self, did: DefId) {
fn push_inherent_impl_candidates_for_type(&mut self, did: DefId) {
// Read the inherent implementation candidates for this type from the
// metadata if necessary.
ty::populate_implementations_for_type_if_necessary(self.tcx(), did);
let inherent_impls = self.tcx().inherent_impls.borrow();
let opt_impl_infos = inherent_impls.get().find(&did);
for impl_infos in opt_impl_infos.iter() {
let impl_infos = impl_infos.borrow();
for impl_info in impl_infos.get().iter() {
let mut inherent_candidates = self.inherent_candidates
.borrow_mut();
self.push_candidates_from_impl(inherent_candidates.get(),
*impl_info);
for impl_infos in self.tcx().inherent_impls.borrow().get().find(&did).iter() {
for impl_info in impl_infos.borrow().get().iter() {
self.push_candidates_from_impl(*impl_info, false);
}
}
}
fn push_candidates_from_impl(&self,
candidates: &mut Vec<Candidate>,
impl_info: &ty::Impl) {
{
let mut impl_dups = self.impl_dups.borrow_mut();
if !impl_dups.get().insert(impl_info.did) {
return; // already visited
}
fn push_candidates_from_impl(&mut self,
impl_info: &ty::Impl,
is_extension: bool) {
if !self.impl_dups.insert(impl_info.did) {
return; // already visited
}
debug!("push_candidates_from_impl: {} {} {}",
@ -631,6 +681,12 @@ impl<'a> LookupContext<'a> {
ty: impl_ty
} = impl_self_ty(&vcx, span, impl_info.did);
let candidates = if is_extension {
&mut self.extension_candidates
} else {
&mut self.inherent_candidates
};
candidates.push(Candidate {
rcvr_match_condition: RcvrMatchesIfSubtype(impl_ty),
rcvr_substs: impl_substs,
@ -913,8 +969,7 @@ impl<'a> LookupContext<'a> {
// existing code.
debug!("searching inherent candidates");
let mut inherent_candidates = self.inherent_candidates.borrow_mut();
match self.consider_candidates(rcvr_ty, inherent_candidates.get()) {
match self.consider_candidates(rcvr_ty, self.inherent_candidates.as_slice()) {
None => {}
Some(mme) => {
return Some(mme);
@ -922,19 +977,11 @@ impl<'a> LookupContext<'a> {
}
debug!("searching extension candidates");
let mut extension_candidates = self.extension_candidates.borrow_mut();
match self.consider_candidates(rcvr_ty, extension_candidates.get()) {
None => {
return None;
}
Some(mme) => {
return Some(mme);
}
}
self.consider_candidates(rcvr_ty, self.extension_candidates.as_slice())
}
fn consider_candidates(&self, rcvr_ty: ty::t,
candidates: &mut Vec<Candidate>)
candidates: &[Candidate])
-> Option<MethodCallee> {
// FIXME(pcwalton): Do we need to clone here?
let relevant_candidates: Vec<Candidate> =
@ -1140,66 +1187,6 @@ impl<'a> LookupContext<'a> {
}
}
fn construct_transformed_self_ty_for_object(
&self,
trait_def_id: ast::DefId,
rcvr_substs: &ty::substs,
method_ty: &ty::Method)
-> 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
*
* trait Foo {
* fn r_method<'a>(&'a self);
* fn u_method(~self);
* }
*
* Now, assuming that `r_method` is being called, we want the
* result to be `&'a Foo`. Assuming that `u_method` is being
* called, we want the result to be `~Foo`. Of course,
* this transformation has already been done as part of
* `method_ty.fty.sig.inputs[0]`, but there the type
* is expressed in terms of `Self` (i.e., `&'a Self`, `~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: rcvr_substs.regions.clone(),
self_ty: None,
tps: rcvr_substs.tps.clone()};
match method_ty.explicit_self {
ast::SelfStatic => {
self.bug("static method for object type receiver");
}
ast::SelfValue => {
ty::mk_err() // error reported in `enforce_object_limitations()`
}
ast::SelfRegion(..) | ast::SelfUniq => {
let transformed_self_ty = *method_ty.fty.sig.inputs.get(0);
match ty::get(transformed_self_ty).sty {
ty::ty_rptr(r, mt) => { // must be SelfRegion
ty::mk_trait(self.tcx(), trait_def_id,
substs, RegionTraitStore(r), mt.mutbl,
ty::EmptyBuiltinBounds())
}
ty::ty_uniq(_) => { // must be SelfUniq
ty::mk_trait(self.tcx(), trait_def_id,
substs, UniqTraitStore, ast::MutImmutable,
ty::EmptyBuiltinBounds())
}
_ => {
self.bug(
format!("'impossible' transformed_self_ty: {}",
transformed_self_ty.repr(self.tcx())));
}
}
}
}
}
fn enforce_object_limitations(&self, candidate: &Candidate) {
/*!
* There are some limitations to calling functions through an
@ -1426,7 +1413,7 @@ impl<'a> LookupContext<'a> {
&self.fcx.inh.infcx
}
fn tcx(&'a self) -> &'a ty::ctxt {
fn tcx(&self) -> &'a ty::ctxt {
self.fcx.tcx()
}
@ -1439,8 +1426,7 @@ impl<'a> LookupContext<'a> {
}
fn bug(&self, s: &str) -> ! {
let span = self.self_expr.map_or(self.span, |e| e.span);
self.tcx().sess.span_bug(span, s)
self.tcx().sess.span_bug(self.span, s)
}
}