rewrite the method-receiver matching code

the old code was *so terrible*.
This commit is contained in:
Ariel Ben-Yehuda 2015-12-27 22:09:33 +02:00
parent 2ced149925
commit efc45758fd
14 changed files with 163 additions and 358 deletions

View File

@ -633,7 +633,6 @@ pub struct RegionParameterDef {
impl RegionParameterDef {
pub fn to_early_bound_region(&self) -> ty::Region {
ty::ReEarlyBound(ty::EarlyBoundRegion {
def_id: self.def_id,
space: self.space,
index: self.index,
name: self.name,

View File

@ -695,7 +695,6 @@ pub enum Region {
#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
pub struct EarlyBoundRegion {
pub def_id: DefId,
pub space: subst::ParamSpace,
pub index: u32,
pub name: Name,

View File

@ -462,8 +462,7 @@ impl fmt::Debug for ty::Region {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ty::ReEarlyBound(ref data) => {
write!(f, "ReEarlyBound({:?}, {:?}, {}, {})",
data.def_id,
write!(f, "ReEarlyBound({:?}, {}, {})",
data.space,
data.index,
data.name)

View File

@ -289,7 +289,6 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
-> ty::Region {
let name = token::intern(name);
ty::ReEarlyBound(ty::EarlyBoundRegion {
def_id: self.infcx.tcx.map.local_def_id(ast::DUMMY_NODE_ID),
space: space,
index: index,
name: name,

View File

@ -192,14 +192,12 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
}
'B' => {
assert_eq!(self.next(), '[');
let def_id = self.parse_def();
let space = self.parse_param_space();
assert_eq!(self.next(), '|');
let index = self.parse_u32();
assert_eq!(self.next(), '|');
let name = token::intern(&self.parse_str(']'));
ty::ReEarlyBound(ty::EarlyBoundRegion {
def_id: def_id,
space: space,
index: index,
name: name

View File

@ -253,8 +253,7 @@ pub fn enc_region(w: &mut Encoder, cx: &ctxt, r: ty::Region) {
mywrite!(w, "]");
}
ty::ReEarlyBound(ref data) => {
mywrite!(w, "B[{}|{}|{}|{}]",
(cx.ds)(data.def_id),
mywrite!(w, "B[{}|{}|{}]",
data.space.to_uint(),
data.index,
data.name);

View File

@ -57,7 +57,7 @@ use middle::resolve_lifetime as rl;
use middle::privacy::{AllPublic, LastMod};
use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs, ParamSpace};
use middle::traits;
use middle::ty::{self, RegionEscape, Ty, ToPredicate, HasTypeFlags};
use middle::ty::{self, Ty, ToPredicate, HasTypeFlags};
use middle::ty::wf::object_region_bounds;
use require_c_abi_if_variadic;
use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
@ -169,10 +169,8 @@ pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &hir::Lifetime)
ty::ReLateBound(debruijn, ty::BrNamed(tcx.map.local_def_id(id), lifetime.name))
}
Some(&rl::DefEarlyBoundRegion(space, index, id)) => {
let def_id = tcx.map.local_def_id(id);
Some(&rl::DefEarlyBoundRegion(space, index, _)) => {
ty::ReEarlyBound(ty::EarlyBoundRegion {
def_id: def_id,
space: space,
index: index,
name: lifetime.name
@ -1797,75 +1795,31 @@ fn ty_of_method_or_bare_fn<'a, 'tcx>(this: &AstConv<'tcx>,
// lifetime elision, we can determine it in two ways. First (determined
// here), if self is by-reference, then the implied output region is the
// region of the self parameter.
let mut explicit_self_category_result = None;
let (self_ty, implied_output_region) = match opt_self_info {
let (self_ty, explicit_self_category) = match opt_self_info {
None => (None, None),
Some(self_info) => {
// This type comes from an impl or trait; no late-bound
// regions should be present.
assert!(!self_info.untransformed_self_ty.has_escaping_regions());
// Figure out and record the explicit self category.
let explicit_self_category =
determine_explicit_self_category(this, &rb, &self_info);
explicit_self_category_result = Some(explicit_self_category);
match explicit_self_category {
ty::StaticExplicitSelfCategory => {
(None, None)
}
ty::ByValueExplicitSelfCategory => {
(Some(self_info.untransformed_self_ty), None)
}
ty::ByReferenceExplicitSelfCategory(region, mutability) => {
(Some(this.tcx().mk_ref(
this.tcx().mk_region(region),
ty::TypeAndMut {
ty: self_info.untransformed_self_ty,
mutbl: mutability
})),
Some(region))
}
ty::ByBoxExplicitSelfCategory => {
(Some(this.tcx().mk_box(self_info.untransformed_self_ty)), None)
}
}
}
Some(self_info) => determine_self_type(this, &rb, self_info)
};
// HACK(eddyb) replace the fake self type in the AST with the actual type.
let input_params = if self_ty.is_some() {
let arg_params = if self_ty.is_some() {
&decl.inputs[1..]
} else {
&decl.inputs[..]
};
let input_tys = input_params.iter().map(|a| ty_of_arg(this, &rb, a, None));
let input_pats: Vec<String> = input_params.iter()
.map(|a| pprust::pat_to_string(&*a.pat))
.collect();
let self_and_input_tys: Vec<Ty> =
self_ty.into_iter().chain(input_tys).collect();
let arg_tys: Vec<Ty> =
arg_params.iter().map(|a| ty_of_arg(this, &rb, a, None)).collect();
let arg_pats: Vec<String> =
arg_params.iter().map(|a| pprust::pat_to_string(&*a.pat)).collect();
// Second, if there was exactly one lifetime (either a substitution or a
// reference) in the arguments, then any anonymous regions in the output
// have that lifetime.
let implied_output_region = match implied_output_region {
Some(r) => Ok(r),
None => {
let input_tys = if self_ty.is_some() {
// Skip the first argument if `self` is present.
&self_and_input_tys[1..]
} else {
&self_and_input_tys[..]
};
find_implied_output_region(this.tcx(), input_tys, input_pats)
}
let implied_output_region = match explicit_self_category {
Some(ty::ByReferenceExplicitSelfCategory(region, _)) => Ok(region),
_ => find_implied_output_region(this.tcx(), &arg_tys, arg_pats)
};
let output_ty = match decl.output {
hir::Return(ref output) if output.node == hir::TyInfer =>
ty::FnConverging(this.ty_infer(None, None, None, output.span)),
hir::Return(ref output) =>
ty::FnConverging(convert_ty_with_lifetime_elision(this,
implied_output_region,
@ -1878,28 +1832,37 @@ fn ty_of_method_or_bare_fn<'a, 'tcx>(this: &AstConv<'tcx>,
unsafety: unsafety,
abi: abi,
sig: ty::Binder(ty::FnSig {
inputs: self_and_input_tys,
inputs: self_ty.into_iter().chain(arg_tys).collect(),
output: output_ty,
variadic: decl.variadic
}),
}, explicit_self_category_result)
}, explicit_self_category)
}
fn determine_explicit_self_category<'a, 'tcx>(this: &AstConv<'tcx>,
rscope: &RegionScope,
self_info: &SelfInfo<'a, 'tcx>)
-> ty::ExplicitSelfCategory
fn determine_self_type<'a, 'tcx>(this: &AstConv<'tcx>,
rscope: &RegionScope,
self_info: SelfInfo<'a, 'tcx>)
-> (Option<Ty<'tcx>>, Option<ty::ExplicitSelfCategory>)
{
let self_ty = self_info.untransformed_self_ty;
return match self_info.explicit_self.node {
hir::SelfStatic => ty::StaticExplicitSelfCategory,
hir::SelfValue(_) => ty::ByValueExplicitSelfCategory,
hir::SelfStatic => (None, Some(ty::StaticExplicitSelfCategory)),
hir::SelfValue(_) => {
(Some(self_ty), Some(ty::ByValueExplicitSelfCategory))
}
hir::SelfRegion(ref lifetime, mutability, _) => {
let region =
opt_ast_region_to_region(this,
rscope,
self_info.explicit_self.span,
lifetime);
ty::ByReferenceExplicitSelfCategory(region, mutability)
(Some(this.tcx().mk_ref(
this.tcx().mk_region(region),
ty::TypeAndMut {
ty: self_ty,
mutbl: mutability
})),
Some(ty::ByReferenceExplicitSelfCategory(region, mutability)))
}
hir::SelfExplicit(ref ast_type, _) => {
let explicit_type = ast_ty_to_ty(this, rscope, &**ast_type);
@ -1944,7 +1907,7 @@ fn determine_explicit_self_category<'a, 'tcx>(this: &AstConv<'tcx>,
impl_modifiers,
method_modifiers);
if impl_modifiers >= method_modifiers {
let category = if impl_modifiers >= method_modifiers {
ty::ByValueExplicitSelfCategory
} else {
match explicit_type.sty {
@ -1952,7 +1915,9 @@ fn determine_explicit_self_category<'a, 'tcx>(this: &AstConv<'tcx>,
ty::TyBox(_) => ty::ByBoxExplicitSelfCategory,
_ => ty::ByValueExplicitSelfCategory,
}
}
};
(Some(explicit_type), Some(category))
}
};

View File

@ -136,9 +136,10 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
let item = fcx.tcx().impl_or_trait_item(fcx.tcx().map.local_def_id(item_id));
let mut implied_bounds = match item.container() {
ty::TraitContainer(_) => vec![],
ty::ImplContainer(def_id) => impl_implied_bounds(fcx, def_id, span)
let (mut implied_bounds, self_ty) = match item.container() {
ty::TraitContainer(_) => (vec![], fcx.tcx().mk_self_type()),
ty::ImplContainer(def_id) => (impl_implied_bounds(fcx, def_id, span),
fcx.tcx().lookup_item_type(def_id).ty)
};
match item {
@ -152,6 +153,8 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
let predicates = fcx.instantiate_bounds(span, free_substs, &method.predicates);
this.check_fn_or_method(fcx, span, &method_ty, &predicates,
free_id_outlive, &mut implied_bounds);
this.check_method_receiver(fcx, span, &method,
free_id_outlive, self_ty);
}
ty::TypeTraitItem(assoc_type) => {
if let Some(ref ty) = assoc_type.ty {
@ -377,6 +380,47 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
self.check_where_clauses(fcx, span, predicates);
}
fn check_method_receiver<'fcx>(&mut self,
fcx: &FnCtxt<'fcx,'tcx>,
span: Span,
method: &ty::Method<'tcx>,
free_id_outlive: CodeExtent,
self_ty: ty::Ty<'tcx>)
{
// check that the type of the method's receiver matches the
// method's first parameter.
let free_substs = &fcx.inh.infcx.parameter_environment.free_substs;
let fty = fcx.instantiate_type_scheme(span, free_substs, &method.fty);
let sig = fcx.tcx().liberate_late_bound_regions(free_id_outlive, &fty.sig);
debug!("check_method_receiver({:?},cat={:?},self_ty={:?},sig={:?})",
method.name, method.explicit_self, self_ty, sig);
let rcvr_ty = match method.explicit_self {
ty::StaticExplicitSelfCategory => return,
ty::ByValueExplicitSelfCategory => self_ty,
ty::ByReferenceExplicitSelfCategory(region, mutability) => {
fcx.tcx().mk_ref(fcx.tcx().mk_region(region), ty::TypeAndMut {
ty: self_ty,
mutbl: mutability
})
}
ty::ByBoxExplicitSelfCategory => fcx.tcx().mk_box(self_ty)
};
let rcvr_ty = fcx.instantiate_type_scheme(span, free_substs, &rcvr_ty);
let rcvr_ty = fcx.tcx().liberate_late_bound_regions(free_id_outlive,
&ty::Binder(rcvr_ty));
debug!("check_method_receiver: receiver ty = {:?}", rcvr_ty);
let _ = ::require_same_types(
fcx.tcx(), Some(fcx.infcx()), false, span,
sig.inputs[0], rcvr_ty,
|| "mismatched method receiver".to_owned()
);
}
fn check_variances_for_type_defn(&self,
item: &hir::Item,
ast_generics: &hir::Generics)

View File

@ -69,18 +69,15 @@ use middle::def;
use middle::def_id::DefId;
use constrained_type_params as ctp;
use middle::lang_items::SizedTraitLangItem;
use middle::free_region::FreeRegionMap;
use middle::region;
use middle::resolve_lifetime;
use middle::const_eval::{self, ConstVal};
use middle::const_eval::EvalHint::UncheckedExprHint;
use middle::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace};
use middle::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer};
use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty, TypeScheme};
use middle::ty::{self, ToPolyTraitRef, Ty, TypeScheme};
use middle::ty::{VariantKind};
use middle::ty::fold::{TypeFolder, TypeFoldable};
use middle::ty::fold::{TypeFolder};
use middle::ty::util::IntTypeExt;
use middle::infer;
use rscope::*;
use rustc::front::map as hir_map;
use util::common::{ErrorReported, memoized};
@ -195,16 +192,6 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> {
ItemCtxt { ccx: self, param_bounds: param_bounds }
}
fn method_ty(&self, method_id: ast::NodeId) -> Rc<ty::Method<'tcx>> {
let def_id = self.tcx.map.local_def_id(method_id);
match *self.tcx.impl_or_trait_items.borrow().get(&def_id).unwrap() {
ty::MethodTraitItem(ref mty) => mty.clone(),
_ => {
self.tcx.sess.bug(&format!("method with id {} has the wrong type", method_id));
}
}
}
fn cycle_check<F,R>(&self,
span: Span,
request: AstConvRequest,
@ -573,10 +560,10 @@ fn is_param<'tcx>(tcx: &ty::ctxt<'tcx>,
fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
container: ImplOrTraitItemContainer,
sig: &hir::MethodSig,
id: ast::NodeId,
name: ast::Name,
id: ast::NodeId,
vis: hir::Visibility,
sig: &hir::MethodSig,
untransformed_rcvr_ty: Ty<'tcx>,
rcvr_ty_generics: &ty::Generics<'tcx>,
rcvr_ty_predicates: &ty::GenericPredicates<'tcx>) {
@ -681,33 +668,6 @@ fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
.insert(ccx.tcx.map.local_def_id(id), ty::TypeTraitItem(associated_type));
}
fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>,
container: ImplOrTraitItemContainer,
methods: I,
untransformed_rcvr_ty: Ty<'tcx>,
rcvr_ty_generics: &ty::Generics<'tcx>,
rcvr_ty_predicates: &ty::GenericPredicates<'tcx>)
where I: Iterator<Item=(&'i hir::MethodSig, ast::NodeId, ast::Name, hir::Visibility, Span)>
{
debug!("convert_methods(untransformed_rcvr_ty={:?}, rcvr_ty_generics={:?}, \
rcvr_ty_predicates={:?})",
untransformed_rcvr_ty,
rcvr_ty_generics,
rcvr_ty_predicates);
for (sig, id, name, vis, _span) in methods {
convert_method(ccx,
container,
sig,
id,
name,
vis,
untransformed_rcvr_ty,
rcvr_ty_generics,
rcvr_ty_predicates);
}
}
fn ensure_no_ty_param_bounds(ccx: &CrateCtxt,
span: Span,
generics: &hir::Generics,
@ -867,36 +827,17 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
}
}
let methods = impl_items.iter().filter_map(|ii| {
if let hir::ImplItemKind::Method(ref sig, _) = ii.node {
for impl_item in impl_items {
if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node {
// if the method specifies a visibility, use that, otherwise
// inherit the visibility from the impl (so `foo` in `pub impl
// { fn foo(); }` is public, but private in `impl { fn
// foo(); }`).
let method_vis = ii.vis.inherit_from(parent_visibility);
Some((sig, ii.id, ii.name, method_vis, ii.span))
} else {
None
}
});
convert_methods(ccx,
ImplContainer(def_id),
methods,
selfty,
&ty_generics,
&ty_predicates);
let method_vis = impl_item.vis.inherit_from(parent_visibility);
for impl_item in impl_items {
if let hir::ImplItemKind::Method(ref sig, ref body) = impl_item.node {
let body_id = body.id;
let body_scope = ccx.tcx.region_maps.call_site_extent(impl_item.id, body_id);
check_method_self_type(ccx,
&BindingRscope::new(),
ccx.method_ty(impl_item.id),
selfty,
&sig.explicit_self,
body_scope,
body_id);
convert_method(ccx, ImplContainer(def_id),
impl_item.name, impl_item.id, method_vis,
sig, selfty, &ty_generics, &ty_predicates);
}
}
@ -904,112 +845,80 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
},
hir::ItemTrait(_, _, _, ref trait_items) => {
let trait_def = trait_def_of_item(ccx, it);
let def_id = trait_def.trait_ref.def_id;
let _: Result<(), ErrorReported> = // any error is already reported, can ignore
ccx.ensure_super_predicates(it.span, ccx.tcx.map.local_def_id(it.id));
ccx.ensure_super_predicates(it.span, def_id);
convert_trait_predicates(ccx, it);
let trait_predicates = tcx.lookup_predicates(ccx.tcx.map.local_def_id(it.id));
let trait_predicates = tcx.lookup_predicates(def_id);
debug!("convert: trait_bounds={:?}", trait_predicates);
// Convert all the associated types.
// FIXME: is the ordering here important? I think it is.
let container = TraitContainer(def_id);
// Convert all the associated constants.
for trait_item in trait_items {
match trait_item.node {
hir::ConstTraitItem(ref ty, ref default) => {
let ty = ccx.icx(&trait_predicates)
.to_ty(&ExplicitRscope, ty);
tcx.register_item_type(ccx.tcx.map.local_def_id(trait_item.id),
TypeScheme {
generics: trait_def.generics.clone(),
ty: ty,
});
convert_associated_const(ccx,
TraitContainer(ccx.tcx.map.local_def_id(it.id)),
trait_item.name,
trait_item.id,
hir::Public,
ty,
default.is_some())
}
_ => {}
if let hir::ConstTraitItem(ref ty, ref default) = trait_item.node {
let ty = ccx.icx(&trait_predicates)
.to_ty(&ExplicitRscope, ty);
tcx.register_item_type(ccx.tcx.map.local_def_id(trait_item.id),
TypeScheme {
generics: trait_def.generics.clone(),
ty: ty,
});
convert_associated_const(ccx,
container,
trait_item.name,
trait_item.id,
hir::Public,
ty,
default.is_some())
}
};
}
// Convert all the associated types.
for trait_item in trait_items {
match trait_item.node {
hir::TypeTraitItem(_, ref opt_ty) => {
let typ = opt_ty.as_ref().map({
|ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty)
});
if let hir::TypeTraitItem(_, ref opt_ty) = trait_item.node {
let typ = opt_ty.as_ref().map({
|ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty)
});
convert_associated_type(ccx,
TraitContainer(ccx.tcx.map.local_def_id(it.id)),
trait_item.name,
trait_item.id,
hir::Public,
typ);
}
_ => {}
convert_associated_type(ccx,
container,
trait_item.name,
trait_item.id,
hir::Public,
typ);
}
};
}
let methods = trait_items.iter().filter_map(|ti| {
let sig = match ti.node {
hir::MethodTraitItem(ref sig, _) => sig,
_ => return None,
};
Some((sig, ti.id, ti.name, hir::Inherited, ti.span))
});
// Convert all the methods
for trait_item in trait_items {
if let hir::MethodTraitItem(ref sig, _) = trait_item.node {
convert_method(ccx,
container,
trait_item.name,
trait_item.id,
hir::Inherited,
sig,
tcx.mk_self_type(),
&trait_def.generics,
&trait_predicates);
// Run convert_methods on the trait methods.
convert_methods(ccx,
TraitContainer(ccx.tcx.map.local_def_id(it.id)),
methods,
tcx.mk_self_type(),
&trait_def.generics,
&trait_predicates);
}
}
// Add an entry mapping
let trait_item_def_ids = Rc::new(trait_items.iter().map(|trait_item| {
let def_id = ccx.tcx.map.local_def_id(trait_item.id);
match trait_item.node {
hir::ConstTraitItem(..) => {
ty::ConstTraitItemId(def_id)
}
hir::MethodTraitItem(..) => {
ty::MethodTraitItemId(def_id)
}
hir::TypeTraitItem(..) => {
ty::TypeTraitItemId(def_id)
}
hir::ConstTraitItem(..) => ty::ConstTraitItemId(def_id),
hir::MethodTraitItem(..) => ty::MethodTraitItemId(def_id),
hir::TypeTraitItem(..) => ty::TypeTraitItemId(def_id)
}
}).collect());
tcx.trait_item_def_ids.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id),
trait_item_def_ids);
// This must be done after `collect_trait_methods` so that
// we have a method type stored for every method.
for trait_item in trait_items {
let (sig, the_scope, the_id) = match trait_item.node {
hir::MethodTraitItem(ref sig, Some(ref body)) => {
let body_scope =
ccx.tcx.region_maps.call_site_extent(trait_item.id, body.id);
(sig, body_scope, body.id)
}
hir::MethodTraitItem(ref sig, None) => {
let item_scope = ccx.tcx.region_maps.item_extent(trait_item.id);
(sig, item_scope, it.id)
}
_ => continue
};
check_method_self_type(ccx,
&BindingRscope::new(),
ccx.method_ty(trait_item.id),
tcx.mk_self_type(),
&sig.explicit_self,
the_scope,
the_id)
}
},
hir::ItemStruct(ref struct_def, _) => {
let (scheme, predicates) = convert_typed_item(ccx, it);
@ -1395,7 +1304,6 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
.iter()
.enumerate()
.map(|(i, def)| ty::ReEarlyBound(ty::EarlyBoundRegion {
def_id: tcx.map.local_def_id(def.lifetime.id),
space: TypeSpace,
index: i as u32,
name: def.lifetime.name
@ -1870,10 +1778,8 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
let early_lifetimes = early_bound_lifetimes_from_generics(space, ast_generics);
for (index, param) in early_lifetimes.iter().enumerate() {
let index = index as u32;
let def_id = tcx.map.local_def_id(param.lifetime.id);
let region =
ty::ReEarlyBound(ty::EarlyBoundRegion {
def_id: def_id,
space: space,
index: index,
name: param.lifetime.name
@ -2281,106 +2187,6 @@ fn mk_item_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
Substs::new(types, regions)
}
/// Verifies that the explicit self type of a method matches the impl
/// or trait. This is a bit weird but basically because right now we
/// don't handle the general case, but instead map it to one of
/// several pre-defined options using various heuristics, this method
/// comes back to check after the fact that explicit type the user
/// wrote actually matches what the pre-defined option said.
fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
ccx: &CrateCtxt<'a, 'tcx>,
rs: &RS,
method_type: Rc<ty::Method<'tcx>>,
required_type: Ty<'tcx>,
explicit_self: &hir::ExplicitSelf,
body_scope: region::CodeExtent,
body_id: ast::NodeId)
{
let tcx = ccx.tcx;
if let hir::SelfExplicit(ref ast_type, _) = explicit_self.node {
let typ = ccx.icx(&method_type.predicates).to_ty(rs, &**ast_type);
let base_type = match typ.sty {
ty::TyRef(_, tm) => tm.ty,
ty::TyBox(typ) => typ,
_ => typ,
};
// "Required type" comes from the trait definition. It may
// contain late-bound regions from the method, but not the
// trait (since traits only have early-bound region
// parameters).
assert!(!base_type.has_regions_escaping_depth(1));
let required_type_free =
liberate_early_bound_regions(
tcx, body_scope,
&tcx.liberate_late_bound_regions(body_scope, &ty::Binder(required_type)));
// The "base type" comes from the impl. It too may have late-bound
// regions from the method.
assert!(!base_type.has_regions_escaping_depth(1));
let base_type_free =
liberate_early_bound_regions(
tcx, body_scope,
&tcx.liberate_late_bound_regions(body_scope, &ty::Binder(base_type)));
debug!("required_type={:?} required_type_free={:?} \
base_type={:?} base_type_free={:?}",
required_type,
required_type_free,
base_type,
base_type_free);
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, false);
drop(::require_same_types(tcx,
Some(&infcx),
false,
explicit_self.span,
base_type_free,
required_type_free,
|| {
format!("mismatched self type: expected `{}`",
required_type)
}));
// We could conceviably add more free-region relations here,
// but since this code is just concerned with checking that
// the `&Self` types etc match up, it's not really necessary.
// It would just allow people to be more approximate in some
// cases. In any case, we can do it later as we feel the need;
// I'd like this function to go away eventually.
let free_regions = FreeRegionMap::new();
infcx.resolve_regions_and_report_errors(&free_regions, body_id);
}
fn liberate_early_bound_regions<'tcx,T>(
tcx: &ty::ctxt<'tcx>,
scope: region::CodeExtent,
value: &T)
-> T
where T : TypeFoldable<'tcx>
{
/*!
* Convert early-bound regions into free regions; normally this is done by
* applying the `free_substs` from the `ParameterEnvironment`, but this particular
* method-self-type check is kind of hacky and done very early in the process,
* before we really have a `ParameterEnvironment` to check.
*/
tcx.fold_regions(value, &mut false, |region, _| {
match region {
ty::ReEarlyBound(data) => {
ty::ReFree(ty::FreeRegion {
scope: scope,
bound_region: ty::BrNamed(data.def_id, data.name)
})
}
_ => region
}
})
}
}
/// Checks that all the type parameters on an impl
fn enforce_impl_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>,
ast_generics: &hir::Generics,
@ -2450,9 +2256,7 @@ fn enforce_impl_lifetimes_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>,
.collect();
for (index, lifetime_def) in ast_generics.lifetimes.iter().enumerate() {
let def_id = tcx.map.local_def_id(lifetime_def.lifetime.id);
let region = ty::EarlyBoundRegion { def_id: def_id,
space: TypeSpace,
let region = ty::EarlyBoundRegion { space: TypeSpace,
index: index as u32,
name: lifetime_def.lifetime.name };
if

View File

@ -1002,12 +1002,14 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
/// Adds constraints appropriate for a region appearing in a
/// context with ambient variance `variance`
fn add_constraints_from_region(&mut self,
_generics: &ty::Generics<'tcx>,
generics: &ty::Generics<'tcx>,
region: ty::Region,
variance: VarianceTermPtr<'a>) {
match region {
ty::ReEarlyBound(ref data) => {
let node_id = self.tcx().map.as_local_node_id(data.def_id).unwrap();
let def_id =
generics.regions.get(data.space, data.index as usize).def_id;
let node_id = self.tcx().map.as_local_node_id(def_id).unwrap();
if self.is_to_be_inferred(node_id) {
let index = self.inferred_index(node_id);
self.add_constraint(index, variance);

View File

@ -15,12 +15,12 @@ struct Foo<'a> {
impl <'a> Foo<'a>{
fn bar(self: &mut Foo) {
//~^ mismatched types
//~| expected `Foo<'a>`
//~| found `Foo<'_>`
//~| expected `&mut Foo<'a>`
//~| found `&mut Foo<'_>`
//~| lifetime mismatch
//~| mismatched types
//~| expected `Foo<'a>`
//~| found `Foo<'_>`
//~| expected `&mut Foo<'a>`
//~| found `&mut Foo<'_>`
//~| lifetime mismatch
}
}

View File

@ -16,10 +16,6 @@ impl Pair<
isize
> {
fn say(self: &Pair<&str, isize>) {
//~^ ERROR mismatched types
//~| expected `Pair<&'static str, isize>`
//~| found `Pair<&str, isize>`
//~| lifetime mismatch
println!("{}", self);
}
}

View File

@ -12,7 +12,7 @@ struct S(String);
impl S {
fn f(self: *mut S) -> String { self.0 }
//~^ ERROR mismatched self type
//~^ ERROR mismatched method receiver
}
fn main() { S("".to_owned()).f(); }

View File

@ -15,7 +15,7 @@ struct Foo {
}
impl Foo {
fn foo(self: isize, x: isize) -> isize { //~ ERROR mismatched self type
fn foo(self: isize, x: isize) -> isize { //~ ERROR mismatched method receiver
self.f + x
}
}
@ -25,10 +25,10 @@ struct Bar<T> {
}
impl<T> Bar<T> {
fn foo(self: Bar<isize>, x: isize) -> isize { //~ ERROR mismatched self type
fn foo(self: Bar<isize>, x: isize) -> isize { //~ ERROR mismatched method receiver
x
}
fn bar(self: &Bar<usize>, x: isize) -> isize { //~ ERROR mismatched self type
fn bar(self: &Bar<usize>, x: isize) -> isize { //~ ERROR mismatched method receiver
x
}
}
@ -41,15 +41,16 @@ trait SomeTrait {
impl<'a, T> SomeTrait for &'a Bar<T> {
fn dummy1(self: &&'a Bar<T>) { }
fn dummy2(self: &Bar<T>) {} //~ ERROR mismatched self type
fn dummy2(self: &Bar<T>) {} //~ ERROR mismatched types
//~^ ERROR mismatched types
fn dummy3(self: &&Bar<T>) {}
//~^ ERROR mismatched types
//~| expected `&'a Bar<T>`
//~| found `&Bar<T>`
//~| expected `&&'a Bar<T>`
//~| found `&&Bar<T>`
//~| lifetime mismatch
//~| ERROR mismatched types
//~| expected `&'a Bar<T>`
//~| found `&Bar<T>`
//~| expected `&&'a Bar<T>`
//~| found `&&Bar<T>`
//~| lifetime mismatch
}