Integrate vec patterns into borrow checker.
The tail portion of the pattern effectively borrows a vector, but the borrow checker knew nothing about this. r=catamorphism
This commit is contained in:
parent
d4fd30c6ac
commit
2e10ea58c3
@ -591,11 +591,53 @@ impl gather_loan_ctxt {
|
||||
}
|
||||
}
|
||||
|
||||
ast::pat_vec(_, Some(tail_pat)) => {
|
||||
// The `tail_pat` here creates a slice into the
|
||||
// original vector. This is effectively a borrow of
|
||||
// the elements of the vector being matched.
|
||||
|
||||
let tail_ty = self.tcx().ty(tail_pat);
|
||||
let (tail_mutbl, tail_r) =
|
||||
self.vec_slice_info(tail_pat, tail_ty);
|
||||
let mcx = self.bccx.mc_ctxt();
|
||||
let cmt_index = mcx.cat_index(tail_pat, cmt);
|
||||
self.guarantee_valid(cmt_index, tail_mutbl, tail_r);
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn vec_slice_info(&self,
|
||||
pat: @ast::pat,
|
||||
tail_ty: ty::t) -> (ast::mutability, ty::Region)
|
||||
{
|
||||
/*!
|
||||
*
|
||||
* In a pattern like [a, b, ..c], normally `c` has slice type,
|
||||
* but if you have [a, b, ..ref c], then the type of `ref c`
|
||||
* will be `&&[]`, so to extract the slice details we have
|
||||
* to recurse through rptrs.
|
||||
*/
|
||||
|
||||
match ty::get(tail_ty).sty {
|
||||
ty::ty_evec(tail_mt, ty::vstore_slice(tail_r)) => {
|
||||
(tail_mt.mutbl, tail_r)
|
||||
}
|
||||
|
||||
ty::ty_rptr(_, ref mt) => {
|
||||
self.vec_slice_info(pat, mt.ty)
|
||||
}
|
||||
|
||||
_ => {
|
||||
self.tcx().sess.span_bug(
|
||||
pat.span,
|
||||
fmt!("Type of tail pattern is not a slice"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn pat_is_variant_or_struct(&self, pat: @ast::pat) -> bool {
|
||||
pat_util::pat_is_variant_or_struct(self.bccx.tcx.def_map, pat)
|
||||
}
|
||||
|
@ -504,9 +504,13 @@ impl borrowck_ctxt {
|
||||
return @{cat:cat_discr(cmt, match_id),.. *cmt};
|
||||
}
|
||||
|
||||
fn mc_ctxt() -> mem_categorization_ctxt {
|
||||
mem_categorization_ctxt {tcx: self.tcx,
|
||||
method_map: self.method_map}
|
||||
}
|
||||
|
||||
fn cat_pattern(cmt: cmt, pat: @ast::pat, op: fn(cmt, @ast::pat)) {
|
||||
let mc = &mem_categorization_ctxt {tcx: self.tcx,
|
||||
method_map: self.method_map};
|
||||
let mc = self.mc_ctxt();
|
||||
mc.cat_pattern(cmt, pat, op);
|
||||
}
|
||||
|
||||
|
@ -521,8 +521,8 @@ impl &mem_categorization_ctxt {
|
||||
ty: self.tcx.ty(arg)}
|
||||
}
|
||||
|
||||
fn cat_rvalue(expr: @ast::expr, expr_ty: ty::t) -> cmt {
|
||||
@{id:expr.id, span:expr.span,
|
||||
fn cat_rvalue<N: ast_node>(elt: N, expr_ty: ty::t) -> cmt {
|
||||
@{id:elt.id(), span:elt.span(),
|
||||
cat:cat_rvalue, lp:None,
|
||||
mutbl:m_imm, ty:expr_ty}
|
||||
}
|
||||
@ -643,12 +643,12 @@ impl &mem_categorization_ctxt {
|
||||
}
|
||||
}
|
||||
|
||||
fn cat_index(expr: @ast::expr, base_cmt: cmt) -> cmt {
|
||||
fn cat_index<N: ast_node>(elt: N, base_cmt: cmt) -> cmt {
|
||||
let mt = match ty::index(self.tcx, base_cmt.ty) {
|
||||
Some(mt) => mt,
|
||||
None => {
|
||||
self.tcx.sess.span_bug(
|
||||
expr.span,
|
||||
elt.span(),
|
||||
fmt!("Explicit index of non-index type `%s`",
|
||||
ty_to_str(self.tcx, base_cmt.ty)));
|
||||
}
|
||||
@ -675,25 +675,27 @@ impl &mem_categorization_ctxt {
|
||||
};
|
||||
|
||||
// (c) the deref is explicit in the resulting cmt
|
||||
let deref_cmt = @{id:expr.id, span:expr.span,
|
||||
let deref_cmt = @{id:elt.id(), span:elt.span(),
|
||||
cat:cat_deref(base_cmt, 0u, ptr), lp:deref_lp,
|
||||
mutbl:m, ty:mt.ty};
|
||||
|
||||
comp(expr, deref_cmt, base_cmt.ty, m, mt.ty)
|
||||
comp(elt, deref_cmt, base_cmt.ty, m, mt.ty)
|
||||
}
|
||||
|
||||
deref_comp(_) => {
|
||||
// fixed-length vectors have no deref
|
||||
let m = self.inherited_mutability(base_cmt.mutbl, mt.mutbl);
|
||||
comp(expr, base_cmt, base_cmt.ty, m, mt.ty)
|
||||
comp(elt, base_cmt, base_cmt.ty, m, mt.ty)
|
||||
}
|
||||
};
|
||||
|
||||
fn comp(expr: @ast::expr, of_cmt: cmt,
|
||||
vect: ty::t, mutbl: ast::mutability, ty: ty::t) -> cmt {
|
||||
fn comp<N: ast_node>(elt: N, of_cmt: cmt,
|
||||
vect: ty::t, mutbl: ast::mutability,
|
||||
ty: ty::t) -> cmt
|
||||
{
|
||||
let comp = comp_index(vect, mutbl);
|
||||
let index_lp = of_cmt.lp.map(|lp| @lp_comp(*lp, comp) );
|
||||
@{id:expr.id, span:expr.span,
|
||||
@{id:elt.id(), span:elt.span(),
|
||||
cat:cat_comp(of_cmt, comp), lp:index_lp,
|
||||
mutbl:mutbl, ty:ty}
|
||||
}
|
||||
@ -723,8 +725,6 @@ impl &mem_categorization_ctxt {
|
||||
|
||||
fn cat_pattern(cmt: cmt, pat: @ast::pat, op: fn(cmt, @ast::pat)) {
|
||||
|
||||
op(cmt, pat);
|
||||
|
||||
// Here, `cmt` is the categorization for the value being
|
||||
// matched and pat is the pattern it is being matched against.
|
||||
//
|
||||
@ -759,13 +759,15 @@ impl &mem_categorization_ctxt {
|
||||
// and the id of `local(x)->@->@` is the id of the `y` pattern.
|
||||
|
||||
|
||||
let _i = indenter();
|
||||
let tcx = self.tcx;
|
||||
debug!("cat_pattern: id=%d pat=%s cmt=%s",
|
||||
pat.id, pprust::pat_to_str(pat, tcx.sess.intr()),
|
||||
self.cmt_to_repr(cmt));
|
||||
let _i = indenter();
|
||||
|
||||
match /*bad*/copy pat.node {
|
||||
op(cmt, pat);
|
||||
|
||||
match pat.node {
|
||||
ast::pat_wild => {
|
||||
// _
|
||||
}
|
||||
@ -773,7 +775,7 @@ impl &mem_categorization_ctxt {
|
||||
ast::pat_enum(_, None) => {
|
||||
// variant(*)
|
||||
}
|
||||
ast::pat_enum(_, Some(subpats)) => {
|
||||
ast::pat_enum(_, Some(ref subpats)) => {
|
||||
match self.tcx.def_map.find(pat.id) {
|
||||
Some(ast::def_variant(enum_did, _)) => {
|
||||
// variant(x, y, z)
|
||||
@ -805,7 +807,8 @@ impl &mem_categorization_ctxt {
|
||||
// nullary variant or identifier: ignore
|
||||
}
|
||||
|
||||
ast::pat_rec(field_pats, _) => {
|
||||
ast::pat_rec(ref field_pats, _) |
|
||||
ast::pat_struct(_, ref field_pats, _) => {
|
||||
// {f1: p1, ..., fN: pN}
|
||||
for field_pats.each |fp| {
|
||||
let cmt_field = self.cat_field(fp.pat, cmt, fp.ident, pat.id);
|
||||
@ -813,15 +816,7 @@ impl &mem_categorization_ctxt {
|
||||
}
|
||||
}
|
||||
|
||||
ast::pat_struct(_, field_pats, _) => {
|
||||
// {f1: p1, ..., fN: pN}
|
||||
for field_pats.each |fp| {
|
||||
let cmt_field = self.cat_field(fp.pat, cmt, fp.ident, pat.id);
|
||||
self.cat_pattern(cmt_field, fp.pat, op);
|
||||
}
|
||||
}
|
||||
|
||||
ast::pat_tup(subpats) => {
|
||||
ast::pat_tup(ref subpats) => {
|
||||
// (p1, ..., pN)
|
||||
for subpats.each |subpat| {
|
||||
let subcmt = self.cat_tuple_elt(*subpat, cmt);
|
||||
@ -836,7 +831,20 @@ impl &mem_categorization_ctxt {
|
||||
self.cat_pattern(subcmt, subpat, op);
|
||||
}
|
||||
|
||||
ast::pat_vec(*) | ast::pat_lit(_) | ast::pat_range(_, _) => {
|
||||
ast::pat_vec(ref pats, opt_tail_pat) => {
|
||||
for pats.each |pat| {
|
||||
let elt_cmt = self.cat_index(*pat, cmt);
|
||||
self.cat_pattern(elt_cmt, *pat, op);
|
||||
}
|
||||
|
||||
for opt_tail_pat.each |tail_pat| {
|
||||
let tail_ty = self.tcx.ty(*tail_pat);
|
||||
let tail_cmt = self.cat_rvalue(*tail_pat, tail_ty);
|
||||
self.cat_pattern(tail_cmt, *tail_pat, op);
|
||||
}
|
||||
}
|
||||
|
||||
ast::pat_lit(_) | ast::pat_range(_, _) => {
|
||||
/*always ok*/
|
||||
}
|
||||
}
|
||||
|
@ -3017,7 +3017,9 @@ pure fn ty_vstore(ty: t) -> vstore {
|
||||
fn ty_region(ty: t) -> Region {
|
||||
match get(ty).sty {
|
||||
ty_rptr(r, _) => r,
|
||||
ref s => fail fmt!("ty_region() invoked on non-rptr: %?", (*s))
|
||||
ty_evec(_, vstore_slice(r)) => r,
|
||||
ty_estr(vstore_slice(r)) => r,
|
||||
ref s => fail fmt!("ty_region() invoked on in appropriate ty: %?", (*s))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -530,6 +530,13 @@ mod guarantor {
|
||||
* but more special purpose.
|
||||
*/
|
||||
|
||||
use core::prelude::*;
|
||||
use middle::typeck::check::regionck::{rcx, infallibly_mk_subr};
|
||||
use middle::ty;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::span;
|
||||
use util::ppaux::{ty_to_str};
|
||||
|
||||
pub fn for_addr_of(rcx: @rcx, expr: @ast::expr, base: @ast::expr) {
|
||||
/*!
|
||||
*
|
||||
@ -726,17 +733,17 @@ mod guarantor {
|
||||
|
||||
fn pointer_categorize(ty: ty::t) -> PointerCat {
|
||||
match ty::get(ty).sty {
|
||||
ty::ty_rptr(r, _) | ty::ty_evec(_, vstore_slice(r)) |
|
||||
ty::ty_estr(vstore_slice(r)) => {
|
||||
ty::ty_rptr(r, _) | ty::ty_evec(_, ty::vstore_slice(r)) |
|
||||
ty::ty_estr(ty::vstore_slice(r)) => {
|
||||
BorrowedPointer(r)
|
||||
}
|
||||
ty::ty_uniq(*) | ty::ty_estr(vstore_uniq) |
|
||||
ty::ty_evec(_, vstore_uniq) => {
|
||||
ty::ty_uniq(*) | ty::ty_estr(ty::vstore_uniq) |
|
||||
ty::ty_evec(_, ty::vstore_uniq) => {
|
||||
OwnedPointer
|
||||
}
|
||||
ty::ty_box(*) | ty::ty_ptr(*) |
|
||||
ty::ty_evec(_, vstore_box) |
|
||||
ty::ty_estr(vstore_box) => {
|
||||
ty::ty_evec(_, ty::vstore_box) |
|
||||
ty::ty_estr(ty::vstore_box) => {
|
||||
OtherPointer
|
||||
}
|
||||
_ => {
|
||||
@ -828,9 +835,9 @@ mod guarantor {
|
||||
for rcx.resolve_node_type(pat.id).each |vec_ty| {
|
||||
let vstore = ty::ty_vstore(*vec_ty);
|
||||
let guarantor1 = match vstore {
|
||||
vstore_fixed(_) | vstore_uniq => guarantor,
|
||||
vstore_slice(r) => Some(r),
|
||||
vstore_box => None
|
||||
ty::vstore_fixed(_) | ty::vstore_uniq => guarantor,
|
||||
ty::vstore_slice(r) => Some(r),
|
||||
ty::vstore_box => None
|
||||
};
|
||||
|
||||
link_ref_bindings_in_pats(rcx, ps, guarantor1);
|
||||
@ -844,8 +851,8 @@ mod guarantor {
|
||||
}
|
||||
|
||||
fn link_ref_bindings_in_pats(rcx: @rcx,
|
||||
pats: &~[@ast::pat],
|
||||
guarantor: Option<ty::Region>)
|
||||
pats: &~[@ast::pat],
|
||||
guarantor: Option<ty::Region>)
|
||||
{
|
||||
for pats.each |pat| {
|
||||
link_ref_bindings_in_pat(rcx, *pat, guarantor);
|
||||
|
@ -1,9 +1,7 @@
|
||||
// xfail-test
|
||||
|
||||
fn a() -> &[int] {
|
||||
let vec = [1, 2, 3, 4];
|
||||
let tail = match vec {
|
||||
[_a, ..tail] => tail, //~ ERROR illegal borrow
|
||||
let tail = match vec { //~ ERROR illegal borrow
|
||||
[_a, ..tail] => tail,
|
||||
_ => fail ~"foo"
|
||||
};
|
||||
move tail
|
12
src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs
Normal file
12
src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs
Normal file
@ -0,0 +1,12 @@
|
||||
fn a() {
|
||||
let mut v = ~[1, 2, 3];
|
||||
match v {
|
||||
[_a, ..tail] => {
|
||||
v.push(tail[0] + tail[1]); //~ ERROR conflicts with prior loan
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
21
src/test/compile-fail/borrowck-vec-pattern-nesting.rs
Normal file
21
src/test/compile-fail/borrowck-vec-pattern-nesting.rs
Normal file
@ -0,0 +1,21 @@
|
||||
fn a() {
|
||||
let mut vec = [~1, ~2, ~3];
|
||||
match vec {
|
||||
[~ref _a] => {
|
||||
vec[0] = ~4; //~ ERROR prohibited due to outstanding loan
|
||||
}
|
||||
_ => fail ~"foo"
|
||||
}
|
||||
}
|
||||
|
||||
fn b() {
|
||||
let mut vec = [~1, ~2, ~3];
|
||||
match vec {
|
||||
[.._b] => {
|
||||
vec[0] = ~4; //~ ERROR prohibited due to outstanding loan
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,7 +1,7 @@
|
||||
fn a() -> &int {
|
||||
let vec = [1, 2, 3, 4];
|
||||
let tail = match vec {
|
||||
[_a, ..tail] => &tail[0], //~ ERROR illegal borrow
|
||||
let tail = match vec { //~ ERROR illegal borrow
|
||||
[_a, ..tail] => &tail[0],
|
||||
_ => fail ~"foo"
|
||||
};
|
||||
move tail
|
@ -109,4 +109,7 @@ fn main() {
|
||||
|
||||
let p = get_v6_c(&a, 1);
|
||||
assert *p == a.value.v6.get().f;
|
||||
|
||||
let p = get_v5_ref(&a, 1);
|
||||
assert *p == a.value.v5.f;
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ fn main() {
|
||||
let x = &[1, 2, 3, 4, 5];
|
||||
if !x.is_empty() {
|
||||
let el = match x {
|
||||
[1, ..ref tail] => &tail[0],
|
||||
[1, ..ref tail] => &tail[0],
|
||||
_ => ::core::util::unreachable()
|
||||
};
|
||||
io::println(fmt!("%d", *el));
|
||||
|
Loading…
x
Reference in New Issue
Block a user