From 7dff08de57cebfff792948eabf72809565a007e2 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Sun, 5 Nov 2017 06:43:29 -0500 Subject: [PATCH] Rewrote check_method_receiver and ExplicitSelf, got a borrow checker error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- src/librustc_typeck/astconv.rs | 48 +++++++++----------- src/librustc_typeck/check/compare_method.rs | 4 +- src/librustc_typeck/check/wfcheck.rs | 50 +++++++-------------- 3 files changed, 39 insertions(+), 63 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1471e235156..58269737784 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1407,7 +1407,8 @@ pub fn predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, param_ty: Ty<'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 } - } + }) } } diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 554a858bcc1..a008d73238d 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -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(), diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 9f3fd33260e..2e87f41c7dc 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -13,6 +13,7 @@ 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 @@ fn check_method_receiver<'fcx, 'tcx>(&mut self, 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 @@ fn check_method_receiver<'fcx, 'tcx>(&mut self, 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(); } } -- GitLab