Rewrote check_method_receiver and ExplicitSelf, got a borrow checker error
Rewrote ExplicitSelf, adding a new `Other` variant for arbitrary self types. It’s a bit more sophisticated now, and checks for type equality, so you have to pass the type context and param env as arguments. There’s a borrow-checker error here that I have to fix Rewrote check_method_receiver, so it acts as if arbitrary self types are allowed, and then checks for ExplicitSelf::Other at the end and disallows it unless the feature is present.
This commit is contained in:
parent
497397ab4b
commit
7dff08de57
|
@ -1407,7 +1407,8 @@ impl<'a, 'gcx, 'tcx> Bounds<'tcx> {
|
|||
pub enum ExplicitSelf<'tcx> {
|
||||
ByValue,
|
||||
ByReference(ty::Region<'tcx>, hir::Mutability),
|
||||
ByBox
|
||||
ByBox,
|
||||
Other
|
||||
}
|
||||
|
||||
impl<'tcx> ExplicitSelf<'tcx> {
|
||||
|
@ -1431,36 +1432,27 @@ impl<'tcx> ExplicitSelf<'tcx> {
|
|||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// To do the check we just count the number of "modifiers"
|
||||
/// on each type and compare them. If they are the same or
|
||||
/// the impl has more, we call it "by value". Otherwise, we
|
||||
/// look at the outermost modifier on the method decl and
|
||||
/// call it by-ref, by-box as appropriate. For method1, for
|
||||
/// example, the impl type has one modifier, but the method
|
||||
/// type has two, so we end up with
|
||||
/// ExplicitSelf::ByReference.
|
||||
pub fn determine(untransformed_self_ty: Ty<'tcx>,
|
||||
self_arg_ty: Ty<'tcx>)
|
||||
-> ExplicitSelf<'tcx> {
|
||||
fn count_modifiers(ty: Ty) -> usize {
|
||||
match ty.sty {
|
||||
ty::TyRef(_, mt) => count_modifiers(mt.ty) + 1,
|
||||
ty::TyAdt(def, _) if def.is_box() => count_modifiers(ty.boxed_ty()) + 1,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
pub fn determine<'a, 'gcx>(
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
self_ty: Ty<'a>,
|
||||
self_arg_ty: Ty<'a>
|
||||
) -> ExplicitSelf<'tcx>
|
||||
{
|
||||
use self::ExplicitSelf::*;
|
||||
|
||||
let impl_modifiers = count_modifiers(untransformed_self_ty);
|
||||
let method_modifiers = count_modifiers(self_arg_ty);
|
||||
tcx.infer_ctxt().enter(|infcx| {
|
||||
let can_eq = |expected, actual| {
|
||||
let cause = traits::ObligationCause::dummy();
|
||||
infcx.at(&cause, param_env).eq(expected, actual).is_ok()
|
||||
};
|
||||
|
||||
if impl_modifiers >= method_modifiers {
|
||||
ExplicitSelf::ByValue
|
||||
} else {
|
||||
match self_arg_ty.sty {
|
||||
ty::TyRef(r, mt) => ExplicitSelf::ByReference(r, mt.mutbl),
|
||||
ty::TyAdt(def, _) if def.is_box() => ExplicitSelf::ByBox,
|
||||
_ => ExplicitSelf::ByValue,
|
||||
_ if can_eq(self_arg_ty, self_ty) => ByValue,
|
||||
ty::TyRef(region, ty::TypeAndMut { ty, mutbl}) if can_eq(ty, self_ty) => ByReference(region, mutbl),
|
||||
ty::TyAdt(def, _) if def.is_box() && can_eq(self_arg_ty.boxed_ty(), self_ty) => ByBox,
|
||||
_ => Other
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -503,7 +503,9 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
ty::TraitContainer(_) => tcx.mk_self_type()
|
||||
};
|
||||
let self_arg_ty = *tcx.fn_sig(method.def_id).input(0).skip_binder();
|
||||
match ExplicitSelf::determine(untransformed_self_ty, self_arg_ty) {
|
||||
let param_env = ty::ParamEnv::empty(Reveal::All);
|
||||
|
||||
match ExplicitSelf::determine(tcx, param_env, untransformed_self_ty, self_arg_ty) {
|
||||
ExplicitSelf::ByValue => "self".to_string(),
|
||||
ExplicitSelf::ByReference(_, hir::MutImmutable) => "&self".to_string(),
|
||||
ExplicitSelf::ByReference(_, hir::MutMutable) => "&mut self".to_string(),
|
||||
|
|
|
@ -13,6 +13,7 @@ use check::{Inherited, FnCtxt};
|
|||
use constrained_type_params::{identify_constrained_type_params, Parameter};
|
||||
|
||||
use hir::def_id::DefId;
|
||||
use rustc::infer::InferOk;
|
||||
use rustc::traits::{self, ObligationCauseCode};
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc::util::nodemap::{FxHashSet, FxHashMap};
|
||||
|
@ -451,8 +452,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
|
|||
method: &ty::AssociatedItem,
|
||||
self_ty: Ty<'tcx>)
|
||||
{
|
||||
// check that the type of the method's receiver matches the
|
||||
// method's first parameter.
|
||||
// check that the method has a valid receiver type, given the type `Self`
|
||||
debug!("check_method_receiver({:?}, self_ty={:?})",
|
||||
method, self_ty);
|
||||
|
||||
|
@ -470,47 +470,29 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
|
|||
|
||||
let self_arg_ty = sig.inputs()[0];
|
||||
|
||||
if fcx.tcx.sess.features.borrow().arbitrary_self_types {
|
||||
let cause = fcx.cause(span, ObligationCauseCode::MethodReceiver);
|
||||
let cause = fcx.cause(span, ObligationCauseCode::MethodReceiver);
|
||||
let at = fcx.at(&cause, fcx.param_env);
|
||||
let mut autoderef = fcx.autoderef(span, self_arg_ty);
|
||||
|
||||
let mut autoderef = fcx.autoderef(span, self_arg_ty);
|
||||
while let Some((potential_self_ty, _)) = autoderef.next() {
|
||||
loop {
|
||||
if let Some((potential_self_ty, _)) = autoderef.next() {
|
||||
debug!("check_method_receiver: potential self type `{:?}` to match `{:?}`", potential_self_ty, self_ty);
|
||||
|
||||
// there's gotta be a more idiomatic way of checking if types are equal than this
|
||||
if let Some(mut err) = fcx.demand_eqtype_with_origin(&cause, self_ty, potential_self_ty) {
|
||||
err.cancel();
|
||||
continue;
|
||||
} else {
|
||||
// we found a type that matches `self_ty`
|
||||
if let Ok(InferOk { obligations, value: () }) = at.eq(self_ty, potential_self_ty) {
|
||||
fcx.register_predicates(obligations);
|
||||
autoderef.finalize();
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
span_err!(fcx.tcx.sess, span, E0307, "invalid `self` type: {:?}", self_arg_ty);
|
||||
return;
|
||||
} else {
|
||||
span_err!(fcx.tcx.sess, span, E0307, "invalid self type: {:?}", self_arg_ty);
|
||||
}
|
||||
}
|
||||
|
||||
let rcvr_ty = match ExplicitSelf::determine(self_ty, self_arg_ty) {
|
||||
ExplicitSelf::ByValue => self_ty,
|
||||
ExplicitSelf::ByReference(region, mutbl) => {
|
||||
fcx.tcx.mk_ref(region, ty::TypeAndMut {
|
||||
ty: self_ty,
|
||||
mutbl,
|
||||
})
|
||||
if let ExplicitSelf::Other = ExplicitSelf::determine(fcx.tcx, fcx.param_env, self_ty, self_arg_ty) {
|
||||
if !fcx.tcx.sess.features.borrow().arbitrary_self_types {
|
||||
fcx.tcx.sess.span_err(span, "Arbitrary `self` types are experimental");
|
||||
}
|
||||
ExplicitSelf::ByBox => fcx.tcx.mk_box(self_ty)
|
||||
};
|
||||
let rcvr_ty = fcx.normalize_associated_types_in(span, &rcvr_ty);
|
||||
let rcvr_ty = fcx.liberate_late_bound_regions(method.def_id,
|
||||
&ty::Binder(rcvr_ty));
|
||||
|
||||
debug!("check_method_receiver: receiver ty = {:?}", rcvr_ty);
|
||||
|
||||
let cause = fcx.cause(span, ObligationCauseCode::MethodReceiver);
|
||||
if let Some(mut err) = fcx.demand_eqtype_with_origin(&cause, rcvr_ty, self_arg_ty) {
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue