rewrite the method-receiver matching code
the old code was *so terrible*.
This commit is contained in:
parent
2ced149925
commit
efc45758fd
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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))
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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(); }
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user