Skip to content

Commit 2e10ea5

Browse files
committed
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
1 parent d4fd30c commit 2e10ea5

11 files changed

+144
-47
lines changed

src/librustc/middle/borrowck/gather_loans.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,11 +591,53 @@ impl gather_loan_ctxt {
591591
}
592592
}
593593

594+
ast::pat_vec(_, Some(tail_pat)) => {
595+
// The `tail_pat` here creates a slice into the
596+
// original vector. This is effectively a borrow of
597+
// the elements of the vector being matched.
598+
599+
let tail_ty = self.tcx().ty(tail_pat);
600+
let (tail_mutbl, tail_r) =
601+
self.vec_slice_info(tail_pat, tail_ty);
602+
let mcx = self.bccx.mc_ctxt();
603+
let cmt_index = mcx.cat_index(tail_pat, cmt);
604+
self.guarantee_valid(cmt_index, tail_mutbl, tail_r);
605+
}
606+
594607
_ => {}
595608
}
596609
}
597610
}
598611

612+
fn vec_slice_info(&self,
613+
pat: @ast::pat,
614+
tail_ty: ty::t) -> (ast::mutability, ty::Region)
615+
{
616+
/*!
617+
*
618+
* In a pattern like [a, b, ..c], normally `c` has slice type,
619+
* but if you have [a, b, ..ref c], then the type of `ref c`
620+
* will be `&&[]`, so to extract the slice details we have
621+
* to recurse through rptrs.
622+
*/
623+
624+
match ty::get(tail_ty).sty {
625+
ty::ty_evec(tail_mt, ty::vstore_slice(tail_r)) => {
626+
(tail_mt.mutbl, tail_r)
627+
}
628+
629+
ty::ty_rptr(_, ref mt) => {
630+
self.vec_slice_info(pat, mt.ty)
631+
}
632+
633+
_ => {
634+
self.tcx().sess.span_bug(
635+
pat.span,
636+
fmt!("Type of tail pattern is not a slice"));
637+
}
638+
}
639+
}
640+
599641
fn pat_is_variant_or_struct(&self, pat: @ast::pat) -> bool {
600642
pat_util::pat_is_variant_or_struct(self.bccx.tcx.def_map, pat)
601643
}

src/librustc/middle/borrowck/mod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -504,9 +504,13 @@ impl borrowck_ctxt {
504504
return @{cat:cat_discr(cmt, match_id),.. *cmt};
505505
}
506506

507+
fn mc_ctxt() -> mem_categorization_ctxt {
508+
mem_categorization_ctxt {tcx: self.tcx,
509+
method_map: self.method_map}
510+
}
511+
507512
fn cat_pattern(cmt: cmt, pat: @ast::pat, op: fn(cmt, @ast::pat)) {
508-
let mc = &mem_categorization_ctxt {tcx: self.tcx,
509-
method_map: self.method_map};
513+
let mc = self.mc_ctxt();
510514
mc.cat_pattern(cmt, pat, op);
511515
}
512516

src/librustc/middle/mem_categorization.rs

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -521,8 +521,8 @@ impl &mem_categorization_ctxt {
521521
ty: self.tcx.ty(arg)}
522522
}
523523

524-
fn cat_rvalue(expr: @ast::expr, expr_ty: ty::t) -> cmt {
525-
@{id:expr.id, span:expr.span,
524+
fn cat_rvalue<N: ast_node>(elt: N, expr_ty: ty::t) -> cmt {
525+
@{id:elt.id(), span:elt.span(),
526526
cat:cat_rvalue, lp:None,
527527
mutbl:m_imm, ty:expr_ty}
528528
}
@@ -643,12 +643,12 @@ impl &mem_categorization_ctxt {
643643
}
644644
}
645645

646-
fn cat_index(expr: @ast::expr, base_cmt: cmt) -> cmt {
646+
fn cat_index<N: ast_node>(elt: N, base_cmt: cmt) -> cmt {
647647
let mt = match ty::index(self.tcx, base_cmt.ty) {
648648
Some(mt) => mt,
649649
None => {
650650
self.tcx.sess.span_bug(
651-
expr.span,
651+
elt.span(),
652652
fmt!("Explicit index of non-index type `%s`",
653653
ty_to_str(self.tcx, base_cmt.ty)));
654654
}
@@ -675,25 +675,27 @@ impl &mem_categorization_ctxt {
675675
};
676676

677677
// (c) the deref is explicit in the resulting cmt
678-
let deref_cmt = @{id:expr.id, span:expr.span,
678+
let deref_cmt = @{id:elt.id(), span:elt.span(),
679679
cat:cat_deref(base_cmt, 0u, ptr), lp:deref_lp,
680680
mutbl:m, ty:mt.ty};
681681

682-
comp(expr, deref_cmt, base_cmt.ty, m, mt.ty)
682+
comp(elt, deref_cmt, base_cmt.ty, m, mt.ty)
683683
}
684684

685685
deref_comp(_) => {
686686
// fixed-length vectors have no deref
687687
let m = self.inherited_mutability(base_cmt.mutbl, mt.mutbl);
688-
comp(expr, base_cmt, base_cmt.ty, m, mt.ty)
688+
comp(elt, base_cmt, base_cmt.ty, m, mt.ty)
689689
}
690690
};
691691

692-
fn comp(expr: @ast::expr, of_cmt: cmt,
693-
vect: ty::t, mutbl: ast::mutability, ty: ty::t) -> cmt {
692+
fn comp<N: ast_node>(elt: N, of_cmt: cmt,
693+
vect: ty::t, mutbl: ast::mutability,
694+
ty: ty::t) -> cmt
695+
{
694696
let comp = comp_index(vect, mutbl);
695697
let index_lp = of_cmt.lp.map(|lp| @lp_comp(*lp, comp) );
696-
@{id:expr.id, span:expr.span,
698+
@{id:elt.id(), span:elt.span(),
697699
cat:cat_comp(of_cmt, comp), lp:index_lp,
698700
mutbl:mutbl, ty:ty}
699701
}
@@ -723,8 +725,6 @@ impl &mem_categorization_ctxt {
723725

724726
fn cat_pattern(cmt: cmt, pat: @ast::pat, op: fn(cmt, @ast::pat)) {
725727

726-
op(cmt, pat);
727-
728728
// Here, `cmt` is the categorization for the value being
729729
// matched and pat is the pattern it is being matched against.
730730
//
@@ -759,21 +759,23 @@ impl &mem_categorization_ctxt {
759759
// and the id of `local(x)->@->@` is the id of the `y` pattern.
760760

761761

762-
let _i = indenter();
763762
let tcx = self.tcx;
764763
debug!("cat_pattern: id=%d pat=%s cmt=%s",
765764
pat.id, pprust::pat_to_str(pat, tcx.sess.intr()),
766765
self.cmt_to_repr(cmt));
766+
let _i = indenter();
767767

768-
match /*bad*/copy pat.node {
768+
op(cmt, pat);
769+
770+
match pat.node {
769771
ast::pat_wild => {
770772
// _
771773
}
772774

773775
ast::pat_enum(_, None) => {
774776
// variant(*)
775777
}
776-
ast::pat_enum(_, Some(subpats)) => {
778+
ast::pat_enum(_, Some(ref subpats)) => {
777779
match self.tcx.def_map.find(pat.id) {
778780
Some(ast::def_variant(enum_did, _)) => {
779781
// variant(x, y, z)
@@ -805,23 +807,16 @@ impl &mem_categorization_ctxt {
805807
// nullary variant or identifier: ignore
806808
}
807809

808-
ast::pat_rec(field_pats, _) => {
810+
ast::pat_rec(ref field_pats, _) |
811+
ast::pat_struct(_, ref field_pats, _) => {
809812
// {f1: p1, ..., fN: pN}
810813
for field_pats.each |fp| {
811814
let cmt_field = self.cat_field(fp.pat, cmt, fp.ident, pat.id);
812815
self.cat_pattern(cmt_field, fp.pat, op);
813816
}
814817
}
815818

816-
ast::pat_struct(_, field_pats, _) => {
817-
// {f1: p1, ..., fN: pN}
818-
for field_pats.each |fp| {
819-
let cmt_field = self.cat_field(fp.pat, cmt, fp.ident, pat.id);
820-
self.cat_pattern(cmt_field, fp.pat, op);
821-
}
822-
}
823-
824-
ast::pat_tup(subpats) => {
819+
ast::pat_tup(ref subpats) => {
825820
// (p1, ..., pN)
826821
for subpats.each |subpat| {
827822
let subcmt = self.cat_tuple_elt(*subpat, cmt);
@@ -836,7 +831,20 @@ impl &mem_categorization_ctxt {
836831
self.cat_pattern(subcmt, subpat, op);
837832
}
838833

839-
ast::pat_vec(*) | ast::pat_lit(_) | ast::pat_range(_, _) => {
834+
ast::pat_vec(ref pats, opt_tail_pat) => {
835+
for pats.each |pat| {
836+
let elt_cmt = self.cat_index(*pat, cmt);
837+
self.cat_pattern(elt_cmt, *pat, op);
838+
}
839+
840+
for opt_tail_pat.each |tail_pat| {
841+
let tail_ty = self.tcx.ty(*tail_pat);
842+
let tail_cmt = self.cat_rvalue(*tail_pat, tail_ty);
843+
self.cat_pattern(tail_cmt, *tail_pat, op);
844+
}
845+
}
846+
847+
ast::pat_lit(_) | ast::pat_range(_, _) => {
840848
/*always ok*/
841849
}
842850
}

src/librustc/middle/ty.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3017,7 +3017,9 @@ pure fn ty_vstore(ty: t) -> vstore {
30173017
fn ty_region(ty: t) -> Region {
30183018
match get(ty).sty {
30193019
ty_rptr(r, _) => r,
3020-
ref s => fail fmt!("ty_region() invoked on non-rptr: %?", (*s))
3020+
ty_evec(_, vstore_slice(r)) => r,
3021+
ty_estr(vstore_slice(r)) => r,
3022+
ref s => fail fmt!("ty_region() invoked on in appropriate ty: %?", (*s))
30213023
}
30223024
}
30233025

src/librustc/middle/typeck/check/regionck.rs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,13 @@ mod guarantor {
530530
* but more special purpose.
531531
*/
532532

533+
use core::prelude::*;
534+
use middle::typeck::check::regionck::{rcx, infallibly_mk_subr};
535+
use middle::ty;
536+
use syntax::ast;
537+
use syntax::codemap::span;
538+
use util::ppaux::{ty_to_str};
539+
533540
pub fn for_addr_of(rcx: @rcx, expr: @ast::expr, base: @ast::expr) {
534541
/*!
535542
*
@@ -726,17 +733,17 @@ mod guarantor {
726733

727734
fn pointer_categorize(ty: ty::t) -> PointerCat {
728735
match ty::get(ty).sty {
729-
ty::ty_rptr(r, _) | ty::ty_evec(_, vstore_slice(r)) |
730-
ty::ty_estr(vstore_slice(r)) => {
736+
ty::ty_rptr(r, _) | ty::ty_evec(_, ty::vstore_slice(r)) |
737+
ty::ty_estr(ty::vstore_slice(r)) => {
731738
BorrowedPointer(r)
732739
}
733-
ty::ty_uniq(*) | ty::ty_estr(vstore_uniq) |
734-
ty::ty_evec(_, vstore_uniq) => {
740+
ty::ty_uniq(*) | ty::ty_estr(ty::vstore_uniq) |
741+
ty::ty_evec(_, ty::vstore_uniq) => {
735742
OwnedPointer
736743
}
737744
ty::ty_box(*) | ty::ty_ptr(*) |
738-
ty::ty_evec(_, vstore_box) |
739-
ty::ty_estr(vstore_box) => {
745+
ty::ty_evec(_, ty::vstore_box) |
746+
ty::ty_estr(ty::vstore_box) => {
740747
OtherPointer
741748
}
742749
_ => {
@@ -828,9 +835,9 @@ mod guarantor {
828835
for rcx.resolve_node_type(pat.id).each |vec_ty| {
829836
let vstore = ty::ty_vstore(*vec_ty);
830837
let guarantor1 = match vstore {
831-
vstore_fixed(_) | vstore_uniq => guarantor,
832-
vstore_slice(r) => Some(r),
833-
vstore_box => None
838+
ty::vstore_fixed(_) | ty::vstore_uniq => guarantor,
839+
ty::vstore_slice(r) => Some(r),
840+
ty::vstore_box => None
834841
};
835842

836843
link_ref_bindings_in_pats(rcx, ps, guarantor1);
@@ -844,8 +851,8 @@ mod guarantor {
844851
}
845852

846853
fn link_ref_bindings_in_pats(rcx: @rcx,
847-
pats: &~[@ast::pat],
848-
guarantor: Option<ty::Region>)
854+
pats: &~[@ast::pat],
855+
guarantor: Option<ty::Region>)
849856
{
850857
for pats.each |pat| {
851858
link_ref_bindings_in_pat(rcx, *pat, guarantor);

src/test/compile-fail/alt-vec-illegal-tail-loan.rs renamed to src/test/compile-fail/borrowck-vec-pattern-element-loan.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
// xfail-test
2-
31
fn a() -> &[int] {
42
let vec = [1, 2, 3, 4];
5-
let tail = match vec {
6-
[_a, ..tail] => tail, //~ ERROR illegal borrow
3+
let tail = match vec { //~ ERROR illegal borrow
4+
[_a, ..tail] => tail,
75
_ => fail ~"foo"
86
};
97
move tail
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
fn a() {
2+
let mut v = ~[1, 2, 3];
3+
match v {
4+
[_a, ..tail] => {
5+
v.push(tail[0] + tail[1]); //~ ERROR conflicts with prior loan
6+
}
7+
_ => {}
8+
};
9+
}
10+
11+
fn main() {}
12+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
fn a() {
2+
let mut vec = [~1, ~2, ~3];
3+
match vec {
4+
[~ref _a] => {
5+
vec[0] = ~4; //~ ERROR prohibited due to outstanding loan
6+
}
7+
_ => fail ~"foo"
8+
}
9+
}
10+
11+
fn b() {
12+
let mut vec = [~1, ~2, ~3];
13+
match vec {
14+
[.._b] => {
15+
vec[0] = ~4; //~ ERROR prohibited due to outstanding loan
16+
}
17+
}
18+
}
19+
20+
fn main() {}
21+

src/test/compile-fail/alt-vec-illegal-tail-element-loan.rs renamed to src/test/compile-fail/borrowck-vec-pattern-tail-element-loan.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
fn a() -> &int {
22
let vec = [1, 2, 3, 4];
3-
let tail = match vec {
4-
[_a, ..tail] => &tail[0], //~ ERROR illegal borrow
3+
let tail = match vec { //~ ERROR illegal borrow
4+
[_a, ..tail] => &tail[0],
55
_ => fail ~"foo"
66
};
77
move tail

src/test/run-pass/region-dependent-addr-of.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,7 @@ fn main() {
109109

110110
let p = get_v6_c(&a, 1);
111111
assert *p == a.value.v6.get().f;
112+
113+
let p = get_v5_ref(&a, 1);
114+
assert *p == a.value.v5.f;
112115
}

src/test/run-pass/vec-matching-legal-tail-element-borrow.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ fn main() {
22
let x = &[1, 2, 3, 4, 5];
33
if !x.is_empty() {
44
let el = match x {
5-
[1, ..ref tail] => &tail[0],
5+
[1, ..ref tail] => &tail[0],
66
_ => ::core::util::unreachable()
77
};
88
io::println(fmt!("%d", *el));

0 commit comments

Comments
 (0)