Skip to content

Commit 194fe69

Browse files
committed
rustc: decompose Adjustment into a vector of adjustment steps.
1 parent 91d603a commit 194fe69

File tree

19 files changed

+676
-850
lines changed

19 files changed

+676
-850
lines changed

src/librustc/ich/impls_ty.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,16 +99,20 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::adjustment::Ad
9999
ty::adjustment::Adjust::ReifyFnPointer |
100100
ty::adjustment::Adjust::UnsafeFnPointer |
101101
ty::adjustment::Adjust::ClosureFnPointer |
102-
ty::adjustment::Adjust::MutToConstPointer => {}
103-
ty::adjustment::Adjust::Deref(ref autoderefs) => {
104-
autoderefs.hash_stable(hcx, hasher);
102+
ty::adjustment::Adjust::MutToConstPointer |
103+
ty::adjustment::Adjust::Unsize => {}
104+
ty::adjustment::Adjust::Deref(ref overloaded) => {
105+
overloaded.hash_stable(hcx, hasher);
106+
}
107+
ty::adjustment::Adjust::Borrow(ref autoref) => {
108+
autoref.hash_stable(hcx, hasher);
105109
}
106110
}
107111
}
108112
}
109113

110-
impl_stable_hash_for!(struct ty::adjustment::Adjustment<'tcx> { kind, autoref, unsize, target });
111-
impl_stable_hash_for!(struct ty::adjustment::OverloadedDeref<'tcx> { region, mutbl, target });
114+
impl_stable_hash_for!(struct ty::adjustment::Adjustment<'tcx> { kind, target });
115+
impl_stable_hash_for!(struct ty::adjustment::OverloadedDeref<'tcx> { region, mutbl });
112116
impl_stable_hash_for!(struct ty::UpvarId { var_id, closure_expr_id });
113117
impl_stable_hash_for!(struct ty::UpvarBorrow<'tcx> { kind, region });
114118

src/librustc/middle/expr_use_visitor.rs

Lines changed: 27 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -704,89 +704,55 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
704704
// consumed or borrowed as part of the automatic adjustment
705705
// process.
706706
fn walk_adjustment(&mut self, expr: &hir::Expr) {
707-
let infcx = self.mc.infcx;
708707
//NOTE(@jroesch): mixed RefCell borrow causes crash
709-
let adj = infcx.tables.borrow().adjustments.get(&expr.id).cloned();
708+
let adjustments = self.mc.infcx.tables.borrow().expr_adjustments(expr).to_vec();
710709
let mut cmt = return_if_err!(self.mc.cat_expr_unadjusted(expr));
711-
if let Some(adjustment) = adj {
710+
for adjustment in adjustments {
712711
debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
713712
match adjustment.kind {
714713
adjustment::Adjust::NeverToAny |
715714
adjustment::Adjust::ReifyFnPointer |
716715
adjustment::Adjust::UnsafeFnPointer |
717716
adjustment::Adjust::ClosureFnPointer |
718-
adjustment::Adjust::MutToConstPointer => {
717+
adjustment::Adjust::MutToConstPointer |
718+
adjustment::Adjust::Unsize => {
719719
// Creating a closure/fn-pointer or unsizing consumes
720720
// the input and stores it into the resulting rvalue.
721-
self.delegate_consume(expr.id, expr.span, cmt);
722-
assert!(adjustment.autoref.is_none() && !adjustment.unsize);
723-
return;
724-
}
725-
adjustment::Adjust::Deref(ref autoderefs) => {
726-
cmt = return_if_err!(self.walk_autoderefs(expr, cmt, autoderefs));
721+
self.delegate_consume(expr.id, expr.span, cmt.clone());
727722
}
728-
}
729723

730-
cmt = self.walk_autoref(expr, cmt, adjustment.autoref);
731-
732-
if adjustment.unsize {
733-
// Unsizing consumes the thin pointer and produces a fat one.
734-
self.delegate_consume(expr.id, expr.span, cmt);
735-
}
736-
}
737-
}
724+
adjustment::Adjust::Deref(None) => {}
725+
726+
// Autoderefs for overloaded Deref calls in fact reference
727+
// their receiver. That is, if we have `(*x)` where `x`
728+
// is of type `Rc<T>`, then this in fact is equivalent to
729+
// `x.deref()`. Since `deref()` is declared with `&self`,
730+
// this is an autoref of `x`.
731+
adjustment::Adjust::Deref(Some(ref deref)) => {
732+
let bk = ty::BorrowKind::from_mutbl(deref.mutbl);
733+
self.delegate.borrow(expr.id, expr.span, cmt.clone(),
734+
deref.region, bk, AutoRef);
735+
}
738736

739-
/// Autoderefs for overloaded Deref calls in fact reference their receiver. That is, if we have
740-
/// `(*x)` where `x` is of type `Rc<T>`, then this in fact is equivalent to `x.deref()`. Since
741-
/// `deref()` is declared with `&self`, this is an autoref of `x`.
742-
fn walk_autoderefs(&mut self,
743-
expr: &hir::Expr,
744-
mut cmt: mc::cmt<'tcx>,
745-
autoderefs: &[Option<adjustment::OverloadedDeref<'tcx>>])
746-
-> mc::McResult<mc::cmt<'tcx>> {
747-
debug!("walk_autoderefs expr={:?} autoderefs={:?}", expr, autoderefs);
748-
749-
for &overloaded in autoderefs {
750-
if let Some(deref) = overloaded {
751-
let bk = ty::BorrowKind::from_mutbl(deref.mutbl);
752-
self.delegate.borrow(expr.id, expr.span, cmt.clone(),
753-
deref.region, bk, AutoRef);
754-
cmt = self.mc.cat_overloaded_autoderef(expr, deref)?;
755-
} else {
756-
cmt = self.mc.cat_deref(expr, cmt, false)?;
737+
adjustment::Adjust::Borrow(ref autoref) => {
738+
self.walk_autoref(expr, cmt.clone(), autoref);
739+
}
757740
}
741+
cmt = return_if_err!(self.mc.cat_expr_adjusted(expr, cmt, &adjustment));
758742
}
759-
Ok(cmt)
760743
}
761744

762-
/// Walks the autoref `opt_autoref` applied to the autoderef'd
763-
/// `expr`. `cmt_derefd` is the mem-categorized form of `expr`
764-
/// after all relevant autoderefs have occurred. Because AutoRefs
765-
/// can be recursive, this function is recursive: it first walks
766-
/// deeply all the way down the autoref chain, and then processes
767-
/// the autorefs on the way out. At each point, it returns the
768-
/// `cmt` for the rvalue that will be produced by introduced an
769-
/// autoref.
745+
/// Walks the autoref `autoref` applied to the autoderef'd
746+
/// `expr`. `cmt_base` is the mem-categorized form of `expr`
747+
/// after all relevant autoderefs have occurred.
770748
fn walk_autoref(&mut self,
771749
expr: &hir::Expr,
772750
cmt_base: mc::cmt<'tcx>,
773-
opt_autoref: Option<adjustment::AutoBorrow<'tcx>>)
774-
-> mc::cmt<'tcx>
775-
{
776-
debug!("walk_autoref(expr.id={} cmt_derefd={:?} opt_autoref={:?})",
751+
autoref: &adjustment::AutoBorrow<'tcx>) {
752+
debug!("walk_autoref(expr.id={} cmt_base={:?} autoref={:?})",
777753
expr.id,
778754
cmt_base,
779-
opt_autoref);
780-
781-
let cmt_base_ty = cmt_base.ty;
782-
783-
let autoref = match opt_autoref {
784-
Some(ref autoref) => autoref,
785-
None => {
786-
// No AutoRef.
787-
return cmt_base;
788-
}
789-
};
755+
autoref);
790756

791757
match *autoref {
792758
adjustment::AutoBorrow::Ref(r, m) => {
@@ -816,14 +782,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
816782
AutoUnsafe);
817783
}
818784
}
819-
820-
// Construct the categorization for the result of the autoref.
821-
// This is always an rvalue, since we are producing a new
822-
// (temporary) indirection.
823-
824-
let adj_ty = cmt_base_ty.adjust_for_autoref(self.tcx(), opt_autoref);
825-
826-
self.mc.cat_rvalue_node(expr.id, expr.span, adj_ty)
827785
}
828786

829787

src/librustc/middle/mem_categorization.rs

Lines changed: 53 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -466,42 +466,62 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
466466
}
467467

468468
pub fn cat_expr(&self, expr: &hir::Expr) -> McResult<cmt<'tcx>> {
469-
match self.infcx.tables.borrow().adjustments.get(&expr.id) {
470-
None => {
471-
// No adjustments.
472-
self.cat_expr_unadjusted(expr)
469+
// This recursion helper avoids going through *too many*
470+
// adjustments, since *only* non-overloaded deref recurses.
471+
fn helper<'a, 'gcx, 'tcx>(mc: &MemCategorizationContext<'a, 'gcx, 'tcx>,
472+
expr: &hir::Expr,
473+
adjustments: &[adjustment::Adjustment<'tcx>])
474+
-> McResult<cmt<'tcx>> {
475+
match adjustments.split_last() {
476+
None => mc.cat_expr_unadjusted(expr),
477+
Some((adjustment, previous)) => {
478+
mc.cat_expr_adjusted_with(expr, || helper(mc, expr, previous), adjustment)
479+
}
473480
}
481+
}
474482

475-
Some(adjustment) => {
476-
debug!("cat_expr({:?}): {:?}", adjustment, expr);
477-
match adjustment.kind {
478-
adjustment::Adjust::Deref(ref autoderefs)
479-
if adjustment.autoref.is_none() && !adjustment.unsize => {
480-
// Equivalent to *expr or something similar.
481-
let mut cmt = self.cat_expr_unadjusted(expr)?;
482-
debug!("cat_expr: autoderefs={:?}, cmt={:?}",
483-
autoderefs, cmt);
484-
for &overloaded in autoderefs {
485-
if let Some(deref) = overloaded {
486-
cmt = self.cat_overloaded_autoderef(expr, deref)?;
487-
} else {
488-
cmt = self.cat_deref(expr, cmt, false)?;
489-
}
490-
}
491-
return Ok(cmt);
492-
}
483+
helper(self, expr, self.infcx.tables.borrow().expr_adjustments(expr))
484+
}
493485

494-
adjustment::Adjust::NeverToAny |
495-
adjustment::Adjust::ReifyFnPointer |
496-
adjustment::Adjust::UnsafeFnPointer |
497-
adjustment::Adjust::ClosureFnPointer |
498-
adjustment::Adjust::MutToConstPointer |
499-
adjustment::Adjust::Deref(_) => {
500-
// Result is an rvalue.
501-
let expr_ty = self.expr_ty_adjusted(expr)?;
502-
Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
503-
}
504-
}
486+
pub fn cat_expr_adjusted(&self, expr: &hir::Expr,
487+
previous: cmt<'tcx>,
488+
adjustment: &adjustment::Adjustment<'tcx>)
489+
-> McResult<cmt<'tcx>> {
490+
self.cat_expr_adjusted_with(expr, || Ok(previous), adjustment)
491+
}
492+
493+
fn cat_expr_adjusted_with<F>(&self, expr: &hir::Expr,
494+
previous: F,
495+
adjustment: &adjustment::Adjustment<'tcx>)
496+
-> McResult<cmt<'tcx>>
497+
where F: FnOnce() -> McResult<cmt<'tcx>>
498+
{
499+
debug!("cat_expr_adjusted_with({:?}): {:?}", adjustment, expr);
500+
let target = self.infcx.resolve_type_vars_if_possible(&adjustment.target);
501+
match adjustment.kind {
502+
adjustment::Adjust::Deref(overloaded) => {
503+
// Equivalent to *expr or something similar.
504+
let base = if let Some(deref) = overloaded {
505+
let ref_ty = self.tcx().mk_ref(deref.region, ty::TypeAndMut {
506+
ty: target,
507+
mutbl: deref.mutbl,
508+
});
509+
self.cat_rvalue_node(expr.id, expr.span, ref_ty)
510+
} else {
511+
previous()?
512+
};
513+
self.cat_deref(expr, base, false)
514+
}
515+
516+
adjustment::Adjust::NeverToAny |
517+
adjustment::Adjust::ReifyFnPointer |
518+
adjustment::Adjust::UnsafeFnPointer |
519+
adjustment::Adjust::ClosureFnPointer |
520+
adjustment::Adjust::MutToConstPointer |
521+
adjustment::Adjust::Borrow(_) |
522+
adjustment::Adjust::Unsize => {
523+
// Result is an rvalue.
524+
Ok(self.cat_rvalue_node(expr.id, expr.span, target))
505525
}
506526
}
507527
}
@@ -931,21 +951,6 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
931951
self.cat_deref(expr, base_cmt, implicit)
932952
}
933953

934-
pub fn cat_overloaded_autoderef(&self,
935-
expr: &hir::Expr,
936-
deref: adjustment::OverloadedDeref<'tcx>)
937-
-> McResult<cmt<'tcx>> {
938-
debug!("cat_overloaded_autoderef: deref={:?}", deref);
939-
940-
let target = self.infcx.resolve_type_vars_if_possible(&deref.target);
941-
let ref_ty = self.tcx().mk_ref(deref.region, ty::TypeAndMut {
942-
ty: target,
943-
mutbl: deref.mutbl,
944-
});
945-
let base_cmt = self.cat_rvalue_node(expr.id, expr.span, ref_ty);
946-
self.cat_deref(expr, base_cmt, false)
947-
}
948-
949954
pub fn cat_deref<N:ast_node>(&self,
950955
node: &N,
951956
base_cmt: cmt<'tcx>,

0 commit comments

Comments
 (0)