Skip to content

Commit 7dff08d

Browse files
committed
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.
1 parent 497397a commit 7dff08d

File tree

3 files changed

+39
-63
lines changed

3 files changed

+39
-63
lines changed

src/librustc_typeck/astconv.rs

Lines changed: 20 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1407,7 +1407,8 @@ impl<'a, 'gcx, 'tcx> Bounds<'tcx> {
14071407
pub enum ExplicitSelf<'tcx> {
14081408
ByValue,
14091409
ByReference(ty::Region<'tcx>, hir::Mutability),
1410-
ByBox
1410+
ByBox,
1411+
Other
14111412
}
14121413

14131414
impl<'tcx> ExplicitSelf<'tcx> {
@@ -1431,36 +1432,27 @@ impl<'tcx> ExplicitSelf<'tcx> {
14311432
/// }
14321433
/// ```
14331434
///
1434-
/// To do the check we just count the number of "modifiers"
1435-
/// on each type and compare them. If they are the same or
1436-
/// the impl has more, we call it "by value". Otherwise, we
1437-
/// look at the outermost modifier on the method decl and
1438-
/// call it by-ref, by-box as appropriate. For method1, for
1439-
/// example, the impl type has one modifier, but the method
1440-
/// type has two, so we end up with
1441-
/// ExplicitSelf::ByReference.
1442-
pub fn determine(untransformed_self_ty: Ty<'tcx>,
1443-
self_arg_ty: Ty<'tcx>)
1444-
-> ExplicitSelf<'tcx> {
1445-
fn count_modifiers(ty: Ty) -> usize {
1446-
match ty.sty {
1447-
ty::TyRef(_, mt) => count_modifiers(mt.ty) + 1,
1448-
ty::TyAdt(def, _) if def.is_box() => count_modifiers(ty.boxed_ty()) + 1,
1449-
_ => 0,
1450-
}
1451-
}
1435+
pub fn determine<'a, 'gcx>(
1436+
tcx: TyCtxt<'a, 'gcx, 'tcx>,
1437+
param_env: ty::ParamEnv<'tcx>,
1438+
self_ty: Ty<'a>,
1439+
self_arg_ty: Ty<'a>
1440+
) -> ExplicitSelf<'tcx>
1441+
{
1442+
use self::ExplicitSelf::*;
14521443

1453-
let impl_modifiers = count_modifiers(untransformed_self_ty);
1454-
let method_modifiers = count_modifiers(self_arg_ty);
1444+
tcx.infer_ctxt().enter(|infcx| {
1445+
let can_eq = |expected, actual| {
1446+
let cause = traits::ObligationCause::dummy();
1447+
infcx.at(&cause, param_env).eq(expected, actual).is_ok()
1448+
};
14551449

1456-
if impl_modifiers >= method_modifiers {
1457-
ExplicitSelf::ByValue
1458-
} else {
14591450
match self_arg_ty.sty {
1460-
ty::TyRef(r, mt) => ExplicitSelf::ByReference(r, mt.mutbl),
1461-
ty::TyAdt(def, _) if def.is_box() => ExplicitSelf::ByBox,
1462-
_ => ExplicitSelf::ByValue,
1451+
_ if can_eq(self_arg_ty, self_ty) => ByValue,
1452+
ty::TyRef(region, ty::TypeAndMut { ty, mutbl}) if can_eq(ty, self_ty) => ByReference(region, mutbl),
1453+
ty::TyAdt(def, _) if def.is_box() && can_eq(self_arg_ty.boxed_ty(), self_ty) => ByBox,
1454+
_ => Other
14631455
}
1464-
}
1456+
})
14651457
}
14661458
}

src/librustc_typeck/check/compare_method.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,9 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
503503
ty::TraitContainer(_) => tcx.mk_self_type()
504504
};
505505
let self_arg_ty = *tcx.fn_sig(method.def_id).input(0).skip_binder();
506-
match ExplicitSelf::determine(untransformed_self_ty, self_arg_ty) {
506+
let param_env = ty::ParamEnv::empty(Reveal::All);
507+
508+
match ExplicitSelf::determine(tcx, param_env, untransformed_self_ty, self_arg_ty) {
507509
ExplicitSelf::ByValue => "self".to_string(),
508510
ExplicitSelf::ByReference(_, hir::MutImmutable) => "&self".to_string(),
509511
ExplicitSelf::ByReference(_, hir::MutMutable) => "&mut self".to_string(),

src/librustc_typeck/check/wfcheck.rs

Lines changed: 16 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use check::{Inherited, FnCtxt};
1313
use constrained_type_params::{identify_constrained_type_params, Parameter};
1414

1515
use hir::def_id::DefId;
16+
use rustc::infer::InferOk;
1617
use rustc::traits::{self, ObligationCauseCode};
1718
use rustc::ty::{self, Ty, TyCtxt};
1819
use rustc::util::nodemap::{FxHashSet, FxHashMap};
@@ -451,8 +452,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
451452
method: &ty::AssociatedItem,
452453
self_ty: Ty<'tcx>)
453454
{
454-
// check that the type of the method's receiver matches the
455-
// method's first parameter.
455+
// check that the method has a valid receiver type, given the type `Self`
456456
debug!("check_method_receiver({:?}, self_ty={:?})",
457457
method, self_ty);
458458

@@ -470,47 +470,29 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
470470

471471
let self_arg_ty = sig.inputs()[0];
472472

473-
if fcx.tcx.sess.features.borrow().arbitrary_self_types {
474-
let cause = fcx.cause(span, ObligationCauseCode::MethodReceiver);
473+
let cause = fcx.cause(span, ObligationCauseCode::MethodReceiver);
474+
let at = fcx.at(&cause, fcx.param_env);
475+
let mut autoderef = fcx.autoderef(span, self_arg_ty);
475476

476-
let mut autoderef = fcx.autoderef(span, self_arg_ty);
477-
while let Some((potential_self_ty, _)) = autoderef.next() {
477+
loop {
478+
if let Some((potential_self_ty, _)) = autoderef.next() {
478479
debug!("check_method_receiver: potential self type `{:?}` to match `{:?}`", potential_self_ty, self_ty);
479480

480-
// there's gotta be a more idiomatic way of checking if types are equal than this
481-
if let Some(mut err) = fcx.demand_eqtype_with_origin(&cause, self_ty, potential_self_ty) {
482-
err.cancel();
483-
continue;
484-
} else {
485-
// we found a type that matches `self_ty`
481+
if let Ok(InferOk { obligations, value: () }) = at.eq(self_ty, potential_self_ty) {
482+
fcx.register_predicates(obligations);
486483
autoderef.finalize();
487-
return;
484+
break;
488485
}
489-
}
490486

491-
span_err!(fcx.tcx.sess, span, E0307, "invalid `self` type: {:?}", self_arg_ty);
492-
return;
487+
} else {
488+
span_err!(fcx.tcx.sess, span, E0307, "invalid self type: {:?}", self_arg_ty);
489+
}
493490
}
494491

495-
let rcvr_ty = match ExplicitSelf::determine(self_ty, self_arg_ty) {
496-
ExplicitSelf::ByValue => self_ty,
497-
ExplicitSelf::ByReference(region, mutbl) => {
498-
fcx.tcx.mk_ref(region, ty::TypeAndMut {
499-
ty: self_ty,
500-
mutbl,
501-
})
492+
if let ExplicitSelf::Other = ExplicitSelf::determine(fcx.tcx, fcx.param_env, self_ty, self_arg_ty) {
493+
if !fcx.tcx.sess.features.borrow().arbitrary_self_types {
494+
fcx.tcx.sess.span_err(span, "Arbitrary `self` types are experimental");
502495
}
503-
ExplicitSelf::ByBox => fcx.tcx.mk_box(self_ty)
504-
};
505-
let rcvr_ty = fcx.normalize_associated_types_in(span, &rcvr_ty);
506-
let rcvr_ty = fcx.liberate_late_bound_regions(method.def_id,
507-
&ty::Binder(rcvr_ty));
508-
509-
debug!("check_method_receiver: receiver ty = {:?}", rcvr_ty);
510-
511-
let cause = fcx.cause(span, ObligationCauseCode::MethodReceiver);
512-
if let Some(mut err) = fcx.demand_eqtype_with_origin(&cause, rcvr_ty, self_arg_ty) {
513-
err.emit();
514496
}
515497
}
516498

0 commit comments

Comments
 (0)