1
Fork 0

Borrow checking for overloaded indexing

Closes #15525
This commit is contained in:
Nick Cameron 2014-07-14 19:43:21 +12:00
parent 996263a015
commit 2bc6547a5a
9 changed files with 96 additions and 23 deletions

View file

@ -734,7 +734,8 @@ impl<'a> CheckLoanCtxt<'a> {
mc::cat_static_item | mc::cat_static_item |
mc::cat_copied_upvar(..) | mc::cat_copied_upvar(..) |
mc::cat_deref(_, _, mc::UnsafePtr(..)) | mc::cat_deref(_, _, mc::UnsafePtr(..)) |
mc::cat_deref(_, _, mc::BorrowedPtr(..)) => { mc::cat_deref(_, _, mc::BorrowedPtr(..)) |
mc::cat_deref(_, _, mc::Implicit(..)) => {
assert_eq!(cmt.mutbl, mc::McDeclared); assert_eq!(cmt.mutbl, mc::McDeclared);
return; return;
} }

View file

@ -131,6 +131,7 @@ fn check_and_get_illegal_move_origin(bccx: &BorrowckCtxt,
cmt: &mc::cmt) -> Option<mc::cmt> { cmt: &mc::cmt) -> Option<mc::cmt> {
match cmt.cat { match cmt.cat {
mc::cat_deref(_, _, mc::BorrowedPtr(..)) | mc::cat_deref(_, _, mc::BorrowedPtr(..)) |
mc::cat_deref(_, _, mc::Implicit(..)) |
mc::cat_deref(_, _, mc::GcPtr) | mc::cat_deref(_, _, mc::GcPtr) |
mc::cat_deref(_, _, mc::UnsafePtr(..)) | mc::cat_deref(_, _, mc::UnsafePtr(..)) |
mc::cat_upvar(..) | mc::cat_static_item | mc::cat_upvar(..) | mc::cat_static_item |

View file

@ -72,6 +72,7 @@ impl<'a> GuaranteeLifetimeContext<'a> {
mc::cat_arg(..) | // L-Local mc::cat_arg(..) | // L-Local
mc::cat_upvar(..) | mc::cat_upvar(..) |
mc::cat_deref(_, _, mc::BorrowedPtr(..)) | // L-Deref-Borrowed mc::cat_deref(_, _, mc::BorrowedPtr(..)) | // L-Deref-Borrowed
mc::cat_deref(_, _, mc::Implicit(..)) |
mc::cat_deref(_, _, mc::UnsafePtr(..)) => { mc::cat_deref(_, _, mc::UnsafePtr(..)) => {
self.check_scope(self.scope(cmt)) self.check_scope(self.scope(cmt))
} }
@ -180,7 +181,8 @@ impl<'a> GuaranteeLifetimeContext<'a> {
mc::cat_deref(_, _, mc::UnsafePtr(..)) => { mc::cat_deref(_, _, mc::UnsafePtr(..)) => {
ty::ReStatic ty::ReStatic
} }
mc::cat_deref(_, _, mc::BorrowedPtr(_, r)) => { mc::cat_deref(_, _, mc::BorrowedPtr(_, r)) |
mc::cat_deref(_, _, mc::Implicit(_, r)) => {
r r
} }
mc::cat_downcast(ref cmt) | mc::cat_downcast(ref cmt) |

View file

@ -113,6 +113,7 @@ fn group_errors_with_same_origin(errors: &Vec<MoveError>)
fn report_cannot_move_out_of(bccx: &BorrowckCtxt, move_from: mc::cmt) { fn report_cannot_move_out_of(bccx: &BorrowckCtxt, move_from: mc::cmt) {
match move_from.cat { match move_from.cat {
mc::cat_deref(_, _, mc::BorrowedPtr(..)) | mc::cat_deref(_, _, mc::BorrowedPtr(..)) |
mc::cat_deref(_, _, mc::Implicit(..)) |
mc::cat_deref(_, _, mc::GcPtr) | mc::cat_deref(_, _, mc::GcPtr) |
mc::cat_deref(_, _, mc::UnsafePtr(..)) | mc::cat_deref(_, _, mc::UnsafePtr(..)) |
mc::cat_upvar(..) | mc::cat_static_item | mc::cat_upvar(..) | mc::cat_static_item |

View file

@ -122,7 +122,9 @@ impl<'a> RestrictionsContext<'a> {
} }
mc::cat_deref(cmt_base, _, mc::BorrowedPtr(ty::ImmBorrow, lt)) | mc::cat_deref(cmt_base, _, mc::BorrowedPtr(ty::ImmBorrow, lt)) |
mc::cat_deref(cmt_base, _, mc::BorrowedPtr(ty::UniqueImmBorrow, lt)) => { mc::cat_deref(cmt_base, _, mc::BorrowedPtr(ty::UniqueImmBorrow, lt)) |
mc::cat_deref(cmt_base, _, mc::Implicit(ty::ImmBorrow, lt)) |
mc::cat_deref(cmt_base, _, mc::Implicit(ty::UniqueImmBorrow, lt)) => {
// R-Deref-Imm-Borrowed // R-Deref-Imm-Borrowed
if !self.bccx.is_subregion_of(self.loan_region, lt) { if !self.bccx.is_subregion_of(self.loan_region, lt) {
self.bccx.report( self.bccx.report(
@ -137,7 +139,8 @@ impl<'a> RestrictionsContext<'a> {
Safe Safe
} }
mc::cat_deref(cmt_base, _, pk @ mc::BorrowedPtr(ty::MutBorrow, lt)) => { mc::cat_deref(cmt_base, _, pk @ mc::BorrowedPtr(ty::MutBorrow, lt)) |
mc::cat_deref(cmt_base, _, pk @ mc::Implicit(ty::MutBorrow, lt)) => {
// R-Deref-Mut-Borrowed // R-Deref-Mut-Borrowed
if !self.bccx.is_subregion_of(self.loan_region, lt) { if !self.bccx.is_subregion_of(self.loan_region, lt) {
self.bccx.report( self.bccx.report(

View file

@ -106,7 +106,8 @@ pub enum PointerKind {
OwnedPtr, OwnedPtr,
GcPtr, GcPtr,
BorrowedPtr(ty::BorrowKind, ty::Region), BorrowedPtr(ty::BorrowKind, ty::Region),
UnsafePtr(ast::Mutability), Implicit(ty::BorrowKind, ty::Region), // Implicit deref of a borrowed ptr.
UnsafePtr(ast::Mutability)
} }
// We use the term "interior" to mean "something reachable from the // We use the term "interior" to mean "something reachable from the
@ -293,7 +294,7 @@ impl MutabilityCategory {
OwnedPtr => { OwnedPtr => {
base_mutbl.inherit() base_mutbl.inherit()
} }
BorrowedPtr(borrow_kind, _) => { BorrowedPtr(borrow_kind, _) | Implicit(borrow_kind, _) => {
MutabilityCategory::from_borrow_kind(borrow_kind) MutabilityCategory::from_borrow_kind(borrow_kind)
} }
GcPtr => { GcPtr => {
@ -422,7 +423,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
-> McResult<cmt> { -> McResult<cmt> {
let mut cmt = if_ok!(self.cat_expr_unadjusted(expr)); let mut cmt = if_ok!(self.cat_expr_unadjusted(expr));
for deref in range(1u, autoderefs + 1) { for deref in range(1u, autoderefs + 1) {
cmt = self.cat_deref(expr, cmt, deref); cmt = self.cat_deref(expr, cmt, deref, false);
} }
return Ok(cmt); return Ok(cmt);
} }
@ -434,7 +435,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
match expr.node { match expr.node {
ast::ExprUnary(ast::UnDeref, ref e_base) => { ast::ExprUnary(ast::UnDeref, ref e_base) => {
let base_cmt = if_ok!(self.cat_expr(&**e_base)); let base_cmt = if_ok!(self.cat_expr(&**e_base));
Ok(self.cat_deref(expr, base_cmt, 0)) Ok(self.cat_deref(expr, base_cmt, 0, false))
} }
ast::ExprField(ref base, f_name, _) => { ast::ExprField(ref base, f_name, _) => {
@ -443,8 +444,22 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
} }
ast::ExprIndex(ref base, _) => { ast::ExprIndex(ref base, _) => {
let base_cmt = if_ok!(self.cat_expr(&**base)); let method_call = typeck::MethodCall::expr(expr.id());
Ok(self.cat_index(expr, base_cmt, 0)) match self.typer.node_method_ty(method_call) {
Some(method_ty) => {
// If this is an index implemented by a method call, then it will
// include an implicit deref of the result.
let ret_ty = ty::ty_fn_ret(method_ty);
Ok(self.cat_deref(expr,
self.cat_rvalue_node(expr.id(),
expr.span(),
ret_ty), 1, true))
}
None => {
let base_cmt = if_ok!(self.cat_expr(&**base));
Ok(self.cat_index(expr, base_cmt, 0))
}
}
} }
ast::ExprPath(_) => { ast::ExprPath(_) => {
@ -687,13 +702,14 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
} }
pub fn cat_deref_obj<N:ast_node>(&self, node: &N, base_cmt: cmt) -> cmt { pub fn cat_deref_obj<N:ast_node>(&self, node: &N, base_cmt: cmt) -> cmt {
self.cat_deref_common(node, base_cmt, 0, ty::mk_nil()) self.cat_deref_common(node, base_cmt, 0, ty::mk_nil(), false)
} }
fn cat_deref<N:ast_node>(&self, fn cat_deref<N:ast_node>(&self,
node: &N, node: &N,
base_cmt: cmt, base_cmt: cmt,
deref_cnt: uint) deref_cnt: uint,
implicit: bool)
-> cmt { -> cmt {
let adjustment = match self.typer.adjustments().borrow().find(&node.id()) { let adjustment = match self.typer.adjustments().borrow().find(&node.id()) {
Some(&ty::AutoObject(..)) => typeck::AutoObject, Some(&ty::AutoObject(..)) => typeck::AutoObject,
@ -717,7 +733,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
None => base_cmt None => base_cmt
}; };
match ty::deref(base_cmt.ty, true) { match ty::deref(base_cmt.ty, true) {
Some(mt) => self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty), Some(mt) => self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty, implicit),
None => { None => {
self.tcx().sess.span_bug( self.tcx().sess.span_bug(
node.span(), node.span(),
@ -731,10 +747,20 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
node: &N, node: &N,
base_cmt: cmt, base_cmt: cmt,
deref_cnt: uint, deref_cnt: uint,
deref_ty: ty::t) deref_ty: ty::t,
implicit: bool)
-> cmt { -> cmt {
let (m, cat) = match deref_kind(self.tcx(), base_cmt.ty) { let (m, cat) = match deref_kind(self.tcx(), base_cmt.ty) {
deref_ptr(ptr) => { deref_ptr(ptr) => {
let ptr = if implicit {
match ptr {
BorrowedPtr(bk, r) => Implicit(bk, r),
_ => self.tcx().sess.span_bug(node.span(),
"Implicit deref of non-borrowed pointer")
}
} else {
ptr
};
// for unique ptrs, we inherit mutability from the // for unique ptrs, we inherit mutability from the
// owning reference. // owning reference.
(MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr), (MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr),
@ -1073,7 +1099,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
ast::PatBox(ref subpat) | ast::PatRegion(ref subpat) => { ast::PatBox(ref subpat) | ast::PatRegion(ref subpat) => {
// @p1, ~p1 // @p1, ~p1
let subcmt = self.cat_deref(pat, cmt, 0); let subcmt = self.cat_deref(pat, cmt, 0, false);
if_ok!(self.cat_pattern(subcmt, &**subpat, op)); if_ok!(self.cat_pattern(subcmt, &**subpat, op));
} }
@ -1129,6 +1155,9 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
} }
_ => { _ => {
match pk { match pk {
Implicit(..) => {
"dereference (dereference is implicit, due to indexing)".to_string()
}
OwnedPtr | GcPtr => format!("dereference of `{}`", ptr_sigil(pk)), OwnedPtr | GcPtr => format!("dereference of `{}`", ptr_sigil(pk)),
_ => format!("dereference of `{}`-pointer", ptr_sigil(pk)) _ => format!("dereference of `{}`-pointer", ptr_sigil(pk))
} }
@ -1188,6 +1217,7 @@ impl cmt_ {
cat_deref(_, _, UnsafePtr(..)) | cat_deref(_, _, UnsafePtr(..)) |
cat_deref(_, _, GcPtr(..)) | cat_deref(_, _, GcPtr(..)) |
cat_deref(_, _, BorrowedPtr(..)) | cat_deref(_, _, BorrowedPtr(..)) |
cat_deref(_, _, Implicit(..)) |
cat_upvar(..) => { cat_upvar(..) => {
Rc::new((*self).clone()) Rc::new((*self).clone())
} }
@ -1212,7 +1242,9 @@ impl cmt_ {
match self.cat { match self.cat {
cat_deref(ref b, _, BorrowedPtr(ty::MutBorrow, _)) | cat_deref(ref b, _, BorrowedPtr(ty::MutBorrow, _)) |
cat_deref(ref b, _, Implicit(ty::MutBorrow, _)) |
cat_deref(ref b, _, BorrowedPtr(ty::UniqueImmBorrow, _)) | cat_deref(ref b, _, BorrowedPtr(ty::UniqueImmBorrow, _)) |
cat_deref(ref b, _, Implicit(ty::UniqueImmBorrow, _)) |
cat_downcast(ref b) | cat_downcast(ref b) |
cat_deref(ref b, _, OwnedPtr) | cat_deref(ref b, _, OwnedPtr) |
cat_interior(ref b, _) | cat_interior(ref b, _) |
@ -1252,7 +1284,8 @@ impl cmt_ {
Some(AliasableManaged) Some(AliasableManaged)
} }
cat_deref(_, _, BorrowedPtr(ty::ImmBorrow, _)) => { cat_deref(_, _, BorrowedPtr(ty::ImmBorrow, _)) |
cat_deref(_, _, Implicit(ty::ImmBorrow, _)) => {
Some(AliasableBorrowed) Some(AliasableBorrowed)
} }
} }
@ -1300,9 +1333,12 @@ pub fn ptr_sigil(ptr: PointerKind) -> &'static str {
match ptr { match ptr {
OwnedPtr => "Box", OwnedPtr => "Box",
GcPtr => "Gc", GcPtr => "Gc",
BorrowedPtr(ty::ImmBorrow, _) => "&", BorrowedPtr(ty::ImmBorrow, _) |
BorrowedPtr(ty::MutBorrow, _) => "&mut", Implicit(ty::ImmBorrow, _) => "&",
BorrowedPtr(ty::UniqueImmBorrow, _) => "&unique", BorrowedPtr(ty::MutBorrow, _) |
Implicit(ty::MutBorrow, _) => "&mut",
BorrowedPtr(ty::UniqueImmBorrow, _) |
Implicit(ty::UniqueImmBorrow, _) => "&unique",
UnsafePtr(_) => "*" UnsafePtr(_) => "*"
} }
} }

View file

@ -1219,7 +1219,8 @@ fn link_region(rcx: &Rcx,
kind.repr(rcx.tcx()), kind.repr(rcx.tcx()),
cmt_borrowed.repr(rcx.tcx())); cmt_borrowed.repr(rcx.tcx()));
match cmt_borrowed.cat.clone() { match cmt_borrowed.cat.clone() {
mc::cat_deref(base, _, mc::BorrowedPtr(_, r_borrowed)) => { mc::cat_deref(base, _, mc::BorrowedPtr(_, r_borrowed)) |
mc::cat_deref(base, _, mc::Implicit(_, r_borrowed)) => {
// References to an upvar `x` are translated to // References to an upvar `x` are translated to
// `*x`, since that is what happens in the // `*x`, since that is what happens in the
// underlying machine. We detect such references // underlying machine. We detect such references
@ -1340,7 +1341,8 @@ fn adjust_upvar_borrow_kind_for_mut(rcx: &Rcx,
continue; continue;
} }
mc::cat_deref(base, _, mc::BorrowedPtr(..)) => { mc::cat_deref(base, _, mc::BorrowedPtr(..)) |
mc::cat_deref(base, _, mc::Implicit(..)) => {
match base.cat { match base.cat {
mc::cat_upvar(ref upvar_id, _) => { mc::cat_upvar(ref upvar_id, _) => {
// if this is an implicit deref of an // if this is an implicit deref of an
@ -1394,7 +1396,8 @@ fn adjust_upvar_borrow_kind_for_unique(rcx: &Rcx, cmt: mc::cmt) {
continue; continue;
} }
mc::cat_deref(base, _, mc::BorrowedPtr(..)) => { mc::cat_deref(base, _, mc::BorrowedPtr(..)) |
mc::cat_deref(base, _, mc::Implicit(..)) => {
match base.cat { match base.cat {
mc::cat_upvar(ref upvar_id, _) => { mc::cat_upvar(ref upvar_id, _) => {
// if this is an implicit deref of an // if this is an implicit deref of an

View file

@ -0,0 +1,26 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
struct MyVec<T> {
data: Vec<T>,
}
impl<T> Index<uint, T> for MyVec<T> {
fn index<'a>(&'a self, &i: &uint) -> &'a T {
self.data.get(i)
}
}
fn main() {
let v = MyVec { data: vec!(box 1i, box 2, box 3) };
let good = &v[0]; // Shouldn't fail here
let bad = v[0];
//~^ ERROR cannot move out of dereference (dereference is implicit, due to indexing)
}

View file

@ -58,7 +58,7 @@ fn main() {
x: 1, x: 1,
}; };
s[2] = 20; s[2] = 20;
//~^ ERROR cannot assign to immutable indexed content //~^ ERROR cannot assign to immutable dereference (dereference is implicit, due to indexing)
} }