Skip to content

Commit

Permalink
rollup merge of rust-lang#20751: nikomatsakis/issue-20232
Browse files Browse the repository at this point in the history
Issue rust-lang#20232. Fun.

r? @eddyb you prob know this system best
  • Loading branch information
alexcrichton committed Jan 8, 2015
2 parents 6a09aa2 + ba87b54 commit 8ed88c1
Show file tree
Hide file tree
Showing 28 changed files with 263 additions and 111 deletions.
136 changes: 97 additions & 39 deletions src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ use middle::def;
use middle::region;
use middle::ty::{self, Ty};
use util::nodemap::{NodeMap};
use util::ppaux::{Repr};
use util::ppaux::{Repr, UserString};

use syntax::ast::{MutImmutable, MutMutable};
use syntax::ast;
Expand Down Expand Up @@ -113,10 +113,17 @@ pub struct Upvar {
// different kinds of pointers:
#[derive(Clone, Copy, PartialEq, Eq, Hash, Show)]
pub enum PointerKind {
/// `Box<T>`
Unique,

/// `&T`
BorrowedPtr(ty::BorrowKind, ty::Region),
Implicit(ty::BorrowKind, ty::Region), // Implicit deref of a borrowed ptr.
UnsafePtr(ast::Mutability)

/// `*T`
UnsafePtr(ast::Mutability),

/// Implicit deref of the `&T` that results from an overloaded index `[]`.
Implicit(ty::BorrowKind, ty::Region),
}

// We use the term "interior" to mean "something reachable from the
Expand Down Expand Up @@ -453,7 +460,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
autoderefs,
cmt.repr(self.tcx()));
for deref in range(1u, autoderefs + 1) {
cmt = try!(self.cat_deref(expr, cmt, deref, false));
cmt = try!(self.cat_deref(expr, cmt, deref));
}
return Ok(cmt);
}
Expand All @@ -465,7 +472,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
match expr.node {
ast::ExprUnary(ast::UnDeref, ref e_base) => {
let base_cmt = try!(self.cat_expr(&**e_base));
self.cat_deref(expr, base_cmt, 0, false)
self.cat_deref(expr, base_cmt, 0)
}

ast::ExprField(ref base, f_name) => {
Expand All @@ -489,10 +496,23 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
// If this is an index implemented by a method call, then it
// will include an implicit deref of the result.
let ret_ty = self.overloaded_method_return_ty(method_ty);
self.cat_deref(expr,
self.cat_rvalue_node(expr.id(),
expr.span(),
ret_ty), 1, true)

// The index method always returns an `&T`, so
// dereference it to find the result type.
let elem_ty = match ret_ty.sty {
ty::ty_rptr(_, mt) => mt.ty,
_ => {
debug!("cat_expr_unadjusted: return type of overloaded index is {}?",
ret_ty.repr(self.tcx()));
return Err(());
}
};

// The call to index() returns a `&T` value, which
// is an rvalue. That is what we will be
// dereferencing.
let base_cmt = self.cat_rvalue_node(expr.id(), expr.span(), ret_ty);
self.cat_deref_common(expr, base_cmt, 1, elem_ty, true)
}
None => {
self.cat_index(expr, try!(self.cat_expr(&**base)))
Expand Down Expand Up @@ -837,8 +857,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
fn cat_deref<N:ast_node>(&self,
node: &N,
base_cmt: cmt<'tcx>,
deref_cnt: uint,
implicit: bool)
deref_cnt: uint)
-> McResult<cmt<'tcx>> {
let adjustment = match self.typer.adjustments().borrow().get(&node.id()) {
Some(adj) if ty::adjust_is_object(adj) => ty::AutoObject,
Expand Down Expand Up @@ -866,7 +885,8 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
};
let base_cmt_ty = base_cmt.ty;
match ty::deref(base_cmt_ty, true) {
Some(mt) => self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty, implicit),
Some(mt) => self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty,
/* implicit: */ false),
None => {
debug!("Explicit deref of non-derefable type: {}",
base_cmt_ty.repr(self.tcx()));
Expand Down Expand Up @@ -1236,7 +1256,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
// box p1, &p1, &mut p1. we can ignore the mutability of
// PatRegion since that information is already contained
// in the type.
let subcmt = try!(self.cat_deref(pat, cmt, 0, false));
let subcmt = try!(self.cat_deref(pat, cmt, 0));
try!(self.cat_pattern_(subcmt, &**subpat, op));
}

Expand Down Expand Up @@ -1392,22 +1412,6 @@ impl<'tcx> cmt_<'tcx> {


pub fn descriptive_string(&self, tcx: &ty::ctxt) -> String {
fn upvar_to_string(upvar: &Upvar, is_copy: bool) -> String {
if upvar.is_unboxed {
let kind = match upvar.kind {
ty::FnUnboxedClosureKind => "Fn",
ty::FnMutUnboxedClosureKind => "FnMut",
ty::FnOnceUnboxedClosureKind => "FnOnce"
};
format!("captured outer variable in an `{}` closure", kind)
} else {
(match (upvar.kind, is_copy) {
(ty::FnOnceUnboxedClosureKind, true) => "captured outer variable in a proc",
_ => "captured outer variable"
}).to_string()
}
}

match self.cat {
cat_static_item => {
"static item".to_string()
Expand All @@ -1427,16 +1431,23 @@ impl<'tcx> cmt_<'tcx> {
let upvar = self.upvar();
match upvar.as_ref().map(|i| &i.cat) {
Some(&cat_upvar(ref var)) => {
upvar_to_string(var, false)
var.user_string(tcx)
}
Some(_) => unreachable!(),
None => {
match pk {
Implicit(..) => {
"dereference (dereference is implicit, due to indexing)".to_string()
format!("indexed content")
}
Unique => {
format!("`Box` content")
}
UnsafePtr(..) => {
format!("dereference of unsafe pointer")
}
BorrowedPtr(..) => {
format!("borrowed content")
}
Unique => format!("dereference of `{}`", ptr_sigil(pk)),
_ => format!("dereference of `{}`-pointer", ptr_sigil(pk))
}
}
}
Expand All @@ -1447,14 +1458,12 @@ impl<'tcx> cmt_<'tcx> {
cat_interior(_, InteriorField(PositionalField(_))) => {
"anonymous field".to_string()
}
cat_interior(_, InteriorElement(VecElement)) => {
"vec content".to_string()
}
cat_interior(_, InteriorElement(VecElement)) |
cat_interior(_, InteriorElement(OtherElement)) => {
"indexed content".to_string()
}
cat_upvar(ref var) => {
upvar_to_string(var, true)
var.user_string(tcx)
}
cat_downcast(ref cmt, _) => {
cmt.descriptive_string(tcx)
Expand Down Expand Up @@ -1483,7 +1492,7 @@ impl<'tcx> Repr<'tcx> for categorization<'tcx> {
format!("{:?}", *self)
}
cat_deref(ref cmt, derefs, ptr) => {
format!("{}-{}{}->", cmt.cat.repr(tcx), ptr_sigil(ptr), derefs)
format!("{}-{}{}->", cmt.cat.repr(tcx), ptr.repr(tcx), derefs)
}
cat_interior(ref cmt, interior) => {
format!("{}.{}", cmt.cat.repr(tcx), interior.repr(tcx))
Expand All @@ -1504,7 +1513,32 @@ pub fn ptr_sigil(ptr: PointerKind) -> &'static str {
Implicit(ty::MutBorrow, _) => "&mut",
BorrowedPtr(ty::UniqueImmBorrow, _) |
Implicit(ty::UniqueImmBorrow, _) => "&unique",
UnsafePtr(_) => "*"
UnsafePtr(_) => "*",
}
}

impl<'tcx> Repr<'tcx> for PointerKind {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
match *self {
Unique => {
format!("Box")
}
BorrowedPtr(ty::ImmBorrow, ref r) |
Implicit(ty::ImmBorrow, ref r) => {
format!("&{}", r.repr(tcx))
}
BorrowedPtr(ty::MutBorrow, ref r) |
Implicit(ty::MutBorrow, ref r) => {
format!("&{} mut", r.repr(tcx))
}
BorrowedPtr(ty::UniqueImmBorrow, ref r) |
Implicit(ty::UniqueImmBorrow, ref r) => {
format!("&{} uniq", r.repr(tcx))
}
UnsafePtr(_) => {
format!("*")
}
}
}
}

Expand All @@ -1531,3 +1565,27 @@ fn element_kind(t: Ty) -> ElementKind {
_ => OtherElement
}
}

impl<'tcx> Repr<'tcx> for ty::UnboxedClosureKind {
fn repr(&self, _: &ty::ctxt) -> String {
format!("Upvar({:?})", self)
}
}

impl<'tcx> Repr<'tcx> for Upvar {
fn repr(&self, tcx: &ty::ctxt) -> String {
format!("Upvar({})", self.kind.repr(tcx))
}
}

impl<'tcx> UserString<'tcx> for Upvar {
fn user_string(&self, _: &ty::ctxt) -> String {
let kind = match self.kind {
ty::FnUnboxedClosureKind => "Fn",
ty::FnMutUnboxedClosureKind => "FnMut",
ty::FnOnceUnboxedClosureKind => "FnOnce",
};
format!("captured outer variable in an `{}` closure", kind)
}
}

20 changes: 11 additions & 9 deletions src/librustc_borrowck/borrowck/gather_loans/move_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,29 +115,31 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
match move_from.cat {
mc::cat_deref(_, _, mc::BorrowedPtr(..)) |
mc::cat_deref(_, _, mc::Implicit(..)) |
mc::cat_deref(_, _, mc::UnsafePtr(..)) |
mc::cat_static_item => {
bccx.span_err(
move_from.span,
&format!("cannot move out of {}",
bccx.cmt_to_string(&*move_from))[]);
bccx.span_err(move_from.span,
&format!("cannot move out of {}",
move_from.descriptive_string(bccx.tcx))[]);
}

mc::cat_downcast(ref b, _) |
mc::cat_interior(ref b, _) => {
match b.ty.sty {
ty::ty_struct(did, _)
| ty::ty_enum(did, _) if ty::has_dtor(bccx.tcx, did) => {
ty::ty_struct(did, _) |
ty::ty_enum(did, _) if ty::has_dtor(bccx.tcx, did) => {
bccx.span_err(
move_from.span,
&format!("cannot move out of type `{}`, \
which defines the `Drop` trait",
b.ty.user_string(bccx.tcx))[]);
},
_ => panic!("this path should not cause illegal move")
_ => {
bccx.span_bug(move_from.span, "this path should not cause illegal move")
}
}
}
_ => panic!("this path should not cause illegal move")
_ => {
bccx.span_bug(move_from.span, "this path should not cause illegal move")
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/librustc_borrowck/borrowck/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
self.tcx.sess.span_err(s, m);
}

pub fn span_bug(&self, s: Span, m: &str) {
self.tcx.sess.span_bug(s, m);
}

pub fn span_note(&self, s: Span, m: &str) {
self.tcx.sess.span_note(s, m);
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/check/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
autoderef(fcx,
callee_expr.span,
original_callee_ty,
Some(callee_expr.id),
Some(callee_expr),
LvaluePreference::NoPreference,
|adj_ty, idx| {
let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None };
Expand Down
12 changes: 6 additions & 6 deletions src/librustc_typeck/check/method/confirm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
// time writing the results into the various tables.
let (autoderefd_ty, n, result) =
check::autoderef(
self.fcx, self.span, unadjusted_self_ty, Some(self.self_expr.id), NoPreference,
self.fcx, self.span, unadjusted_self_ty, Some(self.self_expr), NoPreference,
|_, n| if n == auto_deref_ref.autoderefs { Some(()) } else { None });
assert_eq!(n, auto_deref_ref.autoderefs);
assert_eq!(result, Some(()));
Expand Down Expand Up @@ -492,7 +492,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
exprs.repr(self.tcx()));

// Fix up autoderefs and derefs.
for (i, expr) in exprs.iter().rev().enumerate() {
for (i, &expr) in exprs.iter().rev().enumerate() {
// Count autoderefs.
let autoderef_count = match self.fcx
.inh
Expand All @@ -512,8 +512,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
if autoderef_count > 0 {
check::autoderef(self.fcx,
expr.span,
self.fcx.expr_ty(*expr),
Some(expr.id),
self.fcx.expr_ty(expr),
Some(expr),
PreferMutLvalue,
|_, autoderefs| {
if autoderefs == autoderef_count + 1 {
Expand Down Expand Up @@ -567,7 +567,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
let result = check::try_index_step(
self.fcx,
MethodCall::expr(expr.id),
*expr,
expr,
&**base_expr,
adjusted_base_ty,
base_adjustment,
Expand All @@ -577,7 +577,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
if let Some((input_ty, return_ty)) = result {
demand::suptype(self.fcx, index_expr.span, input_ty, index_expr_ty);

let expr_ty = self.fcx.expr_ty(&**expr);
let expr_ty = self.fcx.expr_ty(&*expr);
demand::suptype(self.fcx, expr.span, expr_ty, return_ty);
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/librustc_typeck/check/method/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,9 @@ pub fn lookup<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
Ok(confirm::confirm(fcx, span, self_expr, call_expr, self_ty, pick, supplied_method_types))
}

pub fn lookup_in_trait<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
pub fn lookup_in_trait<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
span: Span,
self_expr: Option<&'a ast::Expr>,
self_expr: Option<&ast::Expr>,
m_name: ast::Name,
trait_def_id: DefId,
self_ty: Ty<'tcx>,
Expand All @@ -125,9 +125,9 @@ pub fn lookup_in_trait<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
/// method-lookup code. In particular, autoderef on index is basically identical to autoderef with
/// normal probes, except that the test also looks for built-in indexing. Also, the second half of
/// this method is basically the same as confirmation.
pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
span: Span,
self_expr: Option<&'a ast::Expr>,
self_expr: Option<&ast::Expr>,
m_name: ast::Name,
trait_def_id: DefId,
autoderefref: ty::AutoDerefRef<'tcx>,
Expand Down
Loading

0 comments on commit 8ed88c1

Please sign in to comment.