Skip to content

Commit

Permalink
rustc: replace autoderefs' use of MethodCallee with OverloadedDeref.
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyb committed Jun 1, 2017
1 parent c0e8fff commit 4a754f2
Show file tree
Hide file tree
Showing 15 changed files with 261 additions and 164 deletions.
2 changes: 1 addition & 1 deletion src/librustc/ich/impls_ty.rs
Expand Up @@ -110,7 +110,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::adjustment::Ad
}

impl_stable_hash_for!(struct ty::adjustment::Adjustment<'tcx> { kind, target });
impl_stable_hash_for!(struct ty::MethodCallee<'tcx> { def_id, substs, sig });
impl_stable_hash_for!(struct ty::adjustment::OverloadedDeref<'tcx> { region, mutbl, target });
impl_stable_hash_for!(struct ty::UpvarId { var_id, closure_expr_id });
impl_stable_hash_for!(struct ty::UpvarBorrow<'tcx> { kind, region });

Expand Down
17 changes: 5 additions & 12 deletions src/librustc/middle/expr_use_visitor.rs
Expand Up @@ -745,23 +745,16 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
fn walk_autoderefs(&mut self,
expr: &hir::Expr,
mut cmt: mc::cmt<'tcx>,
autoderefs: &[Option<ty::MethodCallee<'tcx>>])
autoderefs: &[Option<adjustment::OverloadedDeref<'tcx>>])
-> mc::McResult<mc::cmt<'tcx>> {
debug!("walk_autoderefs expr={:?} autoderefs={:?}", expr, autoderefs);

for &overloaded in autoderefs {
if let Some(method) = overloaded {
let self_ty = method.sig.inputs()[0];
let self_ty = self.mc.infcx.resolve_type_vars_if_possible(&self_ty);

let (m, r) = match self_ty.sty {
ty::TyRef(r, ref m) => (m.mutbl, r),
_ => span_bug!(expr.span, "bad overloaded deref type {:?}", self_ty)
};
let bk = ty::BorrowKind::from_mutbl(m);
if let Some(deref) = overloaded {
let bk = ty::BorrowKind::from_mutbl(deref.mutbl);
self.delegate.borrow(expr.id, expr.span, cmt.clone(),
r, bk, AutoRef);
cmt = self.mc.cat_overloaded_autoderef(expr, method)?;
deref.region, bk, AutoRef);
cmt = self.mc.cat_overloaded_autoderef(expr, deref)?;
} else {
cmt = self.mc.cat_deref(expr, cmt, false)?;
}
Expand Down
15 changes: 9 additions & 6 deletions src/librustc/middle/mem_categorization.rs
Expand Up @@ -485,8 +485,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
debug!("cat_expr: autoderefs={:?}, cmt={:?}",
autoderefs, cmt);
for &overloaded in autoderefs {
if let Some(method) = overloaded {
cmt = self.cat_overloaded_autoderef(expr, method)?;
if let Some(deref) = overloaded {
cmt = self.cat_overloaded_autoderef(expr, deref)?;
} else {
cmt = self.cat_deref(expr, cmt, false)?;
}
Expand Down Expand Up @@ -936,12 +936,15 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {

pub fn cat_overloaded_autoderef(&self,
expr: &hir::Expr,
method: ty::MethodCallee<'tcx>)
deref: adjustment::OverloadedDeref<'tcx>)
-> McResult<cmt<'tcx>> {
debug!("cat_overloaded_autoderef: method={:?}", method);
debug!("cat_overloaded_autoderef: deref={:?}", deref);

let ref_ty = method.sig.output();
let ref_ty = self.infcx.resolve_type_vars_if_possible(&ref_ty);
let target = self.infcx.resolve_type_vars_if_possible(&deref.target);
let ref_ty = self.tcx().mk_ref(deref.region, ty::TypeAndMut {
ty: target,
mutbl: deref.mutbl,
});
let base_cmt = self.cat_rvalue_node(expr.id, expr.span, ref_ty);
self.cat_deref(expr, base_cmt, false)
}
Expand Down
31 changes: 28 additions & 3 deletions src/librustc/ty/adjustment.rs
Expand Up @@ -8,9 +8,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use ty::{self, Ty, TyCtxt, TypeAndMut};

use hir;
use hir::def_id::DefId;
use ty::{self, Ty, TyCtxt, TypeAndMut};
use ty::subst::Substs;

#[derive(Clone, RustcEncodable, RustcDecodable)]
pub struct Adjustment<'tcx> {
Expand Down Expand Up @@ -105,7 +106,7 @@ pub enum Adjust<'tcx> {
/// ```
DerefRef {
/// Step 1. Apply a number of dereferences, producing an lvalue.
autoderefs: Vec<Option<ty::MethodCallee<'tcx>>>,
autoderefs: Vec<Option<OverloadedDeref<'tcx>>>,

/// Step 2. Optionally produce a pointer/reference from the value.
autoref: Option<AutoBorrow<'tcx>>,
Expand Down Expand Up @@ -136,6 +137,30 @@ impl<'tcx> Adjustment<'tcx> {
}
}

/// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)`
/// call, with the signature `&'a T -> &'a U` or `&'a mut T -> &'a mut U`.
/// The target type is `U` in both cases, with the region and mutability
/// being those shared by both the receiver and the returned reference.
#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
pub struct OverloadedDeref<'tcx> {
pub region: ty::Region<'tcx>,
pub mutbl: hir::Mutability,
pub target: Ty<'tcx>,
}

impl<'a, 'gcx, 'tcx> OverloadedDeref<'tcx> {
pub fn method_call(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, source: Ty<'tcx>)
-> (DefId, &'tcx Substs<'tcx>) {
let trait_def_id = match self.mutbl {
hir::MutImmutable => tcx.lang_items.deref_trait(),
hir::MutMutable => tcx.lang_items.deref_mut_trait()
};
let method_def_id = tcx.associated_items(trait_def_id.unwrap())
.find(|m| m.kind == ty::AssociatedKind::Method).unwrap().def_id;
(method_def_id, tcx.mk_substs_trait(source, &[]))
}
}

#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
pub enum AutoBorrow<'tcx> {
/// Convert from T to &T.
Expand Down
12 changes: 0 additions & 12 deletions src/librustc/ty/mod.rs
Expand Up @@ -390,18 +390,6 @@ impl Variance {
}
}

#[derive(Clone, Copy, Debug, RustcDecodable, RustcEncodable)]
pub struct MethodCallee<'tcx> {
/// Impl method ID, for inherent methods, or trait method ID, otherwise.
pub def_id: DefId,
pub substs: &'tcx Substs<'tcx>,

/// Instantiated method signature, i.e. it has been substituted,
/// normalized, and has had late-bound lifetimes replaced
/// (with inference variables, during type-checking).
pub sig: FnSig<'tcx>,
}

// Contains information needed to resolve types and (in the future) look up
// the types of AST nodes.
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
Expand Down
108 changes: 108 additions & 0 deletions src/librustc/ty/structural_impls.rs
Expand Up @@ -220,6 +220,55 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ClosureSubsts<'a> {
}
}

impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjustment<'a> {
type Lifted = ty::adjustment::Adjustment<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
tcx.lift(&self.kind).and_then(|kind| {
tcx.lift(&self.target).map(|target| {
ty::adjustment::Adjustment { kind, target }
})
})
}
}

impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjust<'a> {
type Lifted = ty::adjustment::Adjust<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
match *self {
ty::adjustment::Adjust::NeverToAny =>
Some(ty::adjustment::Adjust::NeverToAny),
ty::adjustment::Adjust::ReifyFnPointer =>
Some(ty::adjustment::Adjust::ReifyFnPointer),
ty::adjustment::Adjust::UnsafeFnPointer =>
Some(ty::adjustment::Adjust::UnsafeFnPointer),
ty::adjustment::Adjust::ClosureFnPointer =>
Some(ty::adjustment::Adjust::ClosureFnPointer),
ty::adjustment::Adjust::MutToConstPointer =>
Some(ty::adjustment::Adjust::MutToConstPointer),
ty::adjustment::Adjust::DerefRef { ref autoderefs, ref autoref, unsize } => {
tcx.lift(autoderefs).and_then(|autoderefs| {
tcx.lift(autoref).map(|autoref| {
ty::adjustment::Adjust::DerefRef { autoderefs, autoref, unsize }
})
})
}
}
}
}

impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::OverloadedDeref<'a> {
type Lifted = ty::adjustment::OverloadedDeref<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
tcx.lift(&(self.region, self.target)).map(|(region, target)| {
ty::adjustment::OverloadedDeref {
region,
mutbl: self.mutbl,
target,
}
})
}
}

impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::AutoBorrow<'a> {
type Lifted = ty::adjustment::AutoBorrow<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
Expand Down Expand Up @@ -631,6 +680,65 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> {
}
}

impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::Adjustment<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
ty::adjustment::Adjustment {
kind: self.kind.fold_with(folder),
target: self.target.fold_with(folder),
}
}

fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.kind.visit_with(visitor) || self.target.visit_with(visitor)
}
}

impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::Adjust<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
match *self {
ty::adjustment::Adjust::NeverToAny |
ty::adjustment::Adjust::ReifyFnPointer |
ty::adjustment::Adjust::UnsafeFnPointer |
ty::adjustment::Adjust::ClosureFnPointer |
ty::adjustment::Adjust::MutToConstPointer => self.clone(),
ty::adjustment::Adjust::DerefRef { ref autoderefs, ref autoref, unsize } => {
ty::adjustment::Adjust::DerefRef {
autoderefs: autoderefs.fold_with(folder),
autoref: autoref.fold_with(folder),
unsize,
}
}
}
}

fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
match *self {
ty::adjustment::Adjust::NeverToAny |
ty::adjustment::Adjust::ReifyFnPointer |
ty::adjustment::Adjust::UnsafeFnPointer |
ty::adjustment::Adjust::ClosureFnPointer |
ty::adjustment::Adjust::MutToConstPointer => false,
ty::adjustment::Adjust::DerefRef { ref autoderefs, ref autoref, unsize: _ } => {
autoderefs.visit_with(visitor) || autoref.visit_with(visitor)
}
}
}
}

impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::OverloadedDeref<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
ty::adjustment::OverloadedDeref {
region: self.region.fold_with(folder),
mutbl: self.mutbl,
target: self.target.fold_with(folder),
}
}

fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.region.visit_with(visitor) || self.target.visit_with(visitor)
}
}

impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoBorrow<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
match *self {
Expand Down
10 changes: 8 additions & 2 deletions src/librustc_lint/builtin.rs
Expand Up @@ -892,11 +892,17 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
if let Some(&Adjustment {
kind: Adjust::DerefRef { ref autoderefs, .. }, ..
}) = cx.tables.adjustments.get(&id) {
let mut source = cx.tables.expr_ty(expr);
for &overloaded in autoderefs {
if let Some(m) = overloaded {
if method_call_refers_to_method(cx.tcx, method, m.def_id, m.substs, id) {
if let Some(deref) = overloaded {
let (def_id, substs) = deref.method_call(cx.tcx, source);
if method_call_refers_to_method(cx.tcx, method, def_id, substs, id) {
return true;
}
source = deref.target;
} else {
source = source.builtin_deref(true,
ty::LvaluePreference::NoPreference).unwrap().ty;
}
}
}
Expand Down

0 comments on commit 4a754f2

Please sign in to comment.