提交 c2ce2741 编写于 作者: N Niko Matsakis

allow mutable vectors and so forth to be used as immutable slices

上级 0470abe1
...@@ -562,6 +562,17 @@ fn tr(xcx: extended_decode_ctxt) -> method_origin { ...@@ -562,6 +562,17 @@ fn tr(xcx: extended_decode_ctxt) -> method_origin {
} }
} }
// ______________________________________________________________________
// Encoding and decoding of borrow
impl helper for ebml::ebml_deserializer {
fn read_borrow(xcx: extended_decode_ctxt) -> ty::borrow {
let borrow = ty::deserialize_borrow(self);
{scope_id: xcx.tr_id(borrow.scope_id),
mutbl: borrow.mutbl}
}
}
// ______________________________________________________________________ // ______________________________________________________________________
// Encoding and decoding vtable_res // Encoding and decoding vtable_res
...@@ -866,10 +877,12 @@ fn encode_side_tables_for_id(ecx: @e::encode_ctxt, ...@@ -866,10 +877,12 @@ fn encode_side_tables_for_id(ecx: @e::encode_ctxt,
} }
} }
option::iter(tcx.borrowings.find(id)) {|s| option::iter(tcx.borrowings.find(id)) {|borrow|
ebml_w.tag(c::tag_table_borrowings) {|| ebml_w.tag(c::tag_table_borrowings) {||
ebml_w.id(id); ebml_w.id(id);
ebml_w.wr_tagged_i64(c::tag_table_val as uint, s as i64); ebml_w.tag(c::tag_table_val) {||
ty::serialize_borrow(ebml_w, borrow)
}
} }
} }
} }
...@@ -979,8 +992,8 @@ fn decode_side_tables(xcx: extended_decode_ctxt, ...@@ -979,8 +992,8 @@ fn decode_side_tables(xcx: extended_decode_ctxt,
dcx.maps.vtable_map.insert(id, dcx.maps.vtable_map.insert(id,
val_dsr.read_vtable_res(xcx)); val_dsr.read_vtable_res(xcx));
} else if tag == (c::tag_table_borrowings as uint) { } else if tag == (c::tag_table_borrowings as uint) {
let scope_id = ebml::doc_as_i64(val_doc) as int; let borrow = val_dsr.read_borrow(xcx);
dcx.tcx.borrowings.insert(id, scope_id); dcx.tcx.borrowings.insert(id, borrow);
} else { } else {
xcx.dcx.tcx.sess.bug( xcx.dcx.tcx.sess.bug(
#fmt["unknown tag found in side tables: %x", tag]); #fmt["unknown tag found in side tables: %x", tag]);
......
...@@ -190,10 +190,10 @@ fn req_loans_in_expr(ex: @ast::expr, ...@@ -190,10 +190,10 @@ fn req_loans_in_expr(ex: @ast::expr,
let tcx = bccx.tcx; let tcx = bccx.tcx;
// If this expression is borrowed, have to ensure it remains valid: // If this expression is borrowed, have to ensure it remains valid:
for tcx.borrowings.find(ex.id).each { |scope_id| for tcx.borrowings.find(ex.id).each { |borrow|
let cmt = self.bccx.cat_borrow_of_expr(ex); let cmt = self.bccx.cat_borrow_of_expr(ex);
let scope_r = ty::re_scope(scope_id); let scope_r = ty::re_scope(borrow.scope_id);
self.guarantee_valid(cmt, m_const, scope_r); self.guarantee_valid(cmt, borrow.mutbl, scope_r);
} }
// Special checks for various kinds of expressions: // Special checks for various kinds of expressions:
......
...@@ -158,6 +158,7 @@ ...@@ -158,6 +158,7 @@
export ty_sort_str; export ty_sort_str;
export normalize_ty; export normalize_ty;
export to_str; export to_str;
export borrow, serialize_borrow, deserialize_borrow;
// Data types // Data types
...@@ -204,6 +205,12 @@ enum ast_ty_to_ty_cache_entry { ...@@ -204,6 +205,12 @@ enum ast_ty_to_ty_cache_entry {
atttce_resolved(t) /* resolved to a type, irrespective of region */ atttce_resolved(t) /* resolved to a type, irrespective of region */
} }
#[auto_serialize]
type borrow = {
scope_id: ast::node_id,
mutbl: ast::mutability
};
type ctxt = type ctxt =
@{diag: syntax::diagnostic::span_handler, @{diag: syntax::diagnostic::span_handler,
interner: hashmap<intern_key, t_box>, interner: hashmap<intern_key, t_box>,
...@@ -239,7 +246,7 @@ enum ast_ty_to_ty_cache_entry { ...@@ -239,7 +246,7 @@ enum ast_ty_to_ty_cache_entry {
ty_param_bounds: hashmap<ast::node_id, param_bounds>, ty_param_bounds: hashmap<ast::node_id, param_bounds>,
inferred_modes: hashmap<ast::node_id, ast::mode>, inferred_modes: hashmap<ast::node_id, ast::mode>,
// maps the id of borrowed expr to scope of borrowed ptr // maps the id of borrowed expr to scope of borrowed ptr
borrowings: hashmap<ast::node_id, ast::node_id>, borrowings: hashmap<ast::node_id, borrow>,
normalized_cache: hashmap<t, t>}; normalized_cache: hashmap<t, t>};
enum tbox_flag { enum tbox_flag {
......
...@@ -157,6 +157,7 @@ fn bar() { ...@@ -157,6 +157,7 @@ fn bar() {
import driver::session::session; import driver::session::session;
import util::common::{indent, indenter}; import util::common::{indent, indenter};
import ast::{unsafe_fn, impure_fn, pure_fn, crust_fn}; import ast::{unsafe_fn, impure_fn, pure_fn, crust_fn};
import ast::{m_const, m_imm, m_mutbl};
export infer_ctxt; export infer_ctxt;
export new_infer_ctxt; export new_infer_ctxt;
...@@ -961,24 +962,27 @@ fn resolve_ty_var(vid: ty_vid) -> ty::t { ...@@ -961,24 +962,27 @@ fn resolve_ty_var(vid: ty_vid) -> ty::t {
// we just fall back to requiring that a <: b. // we just fall back to requiring that a <: b.
// //
// Assuming we have a bound from both sides, we will then examine // Assuming we have a bound from both sides, we will then examine
// these bounds and see if they have the form (@MT_a, &rb.MT_b) // these bounds and see if they have the form (@M_a T_a, &rb.M_b T_b)
// (resp. ~MT_a). If they do not, we fall back to subtyping. // (resp. ~M_a T_a, [M_a T_a], etc). If they do not, we fall back to
// subtyping.
// //
// If they *do*, then we know that the two types could never be // If they *do*, then we know that the two types could never be
// subtypes of one another. We will then construct a type @MT_b and // subtypes of one another. We will then construct a type @const T_b
// ensure that type a is a subtype of that. This allows for the // and ensure that type a is a subtype of that. This allows for the
// possibility of assigning from a type like (say) @[mut T1] to a type // possibility of assigning from a type like (say) @[mut T1] to a type
// &[const T2] where T1 <: T2. Basically we would require that @[mut // &[T2] where T1 <: T2. This might seem surprising, since the `@`
// T1] <: @[const T2]. Next we require that the region for the // points at mutable memory but the `&` points at immutable memory.
// enclosing scope be a superregion of the region r. These two checks // This would in fact be unsound, except for the borrowck, which comes
// together guarantee that the type A would be a subtype of the type B // later and guarantees that such mutability conversions are safe.
// if the @ were converted to a region r. // See borrowck for more details. Next we require that the region for
// the enclosing scope be a superregion of the region r.
// //
// You might wonder why we don't just make the type &e.MT_a where e is // You might wonder why we don't make the type &e.const T_a where e is
// the enclosing region and check that &e.MT_a <: B. The reason is // the enclosing region and check that &e.const T_a <: B. The reason
// that the type @MT_a is (generally) just a *lower-bound*, so this // is that the type of A is (generally) just a *lower-bound*, so this
// would be imposing @MT_a also as the upper-bound on type A. But // would be imposing that lower-bound also as the upper-bound on type
// this upper-bound might be stricter than what is truly needed. // A. But this upper-bound might be stricter than what is truly
// needed.
impl assignment for infer_ctxt { impl assignment for infer_ctxt {
fn assign_tys(anmnt: assignment, a: ty::t, b: ty::t) -> ures { fn assign_tys(anmnt: assignment, a: ty::t, b: ty::t) -> ures {
...@@ -1051,35 +1055,39 @@ fn is_borrowable(v: ty::vstore) -> bool { ...@@ -1051,35 +1055,39 @@ fn is_borrowable(v: ty::vstore) -> bool {
(some(a_bnd), some(b_bnd)) { (some(a_bnd), some(b_bnd)) {
alt (ty::get(a_bnd).struct, ty::get(b_bnd).struct) { alt (ty::get(a_bnd).struct, ty::get(b_bnd).struct) {
(ty::ty_box(mt_a), ty::ty_rptr(r_b, mt_b)) { (ty::ty_box(mt_a), ty::ty_rptr(r_b, mt_b)) {
let nr_b = ty::mk_box(self.tcx, mt_b); let nr_b = ty::mk_box(self.tcx, {ty: mt_b.ty,
self.crosspollinate(anmnt, a, nr_b, r_b) mutbl: m_const});
self.crosspollinate(anmnt, a, nr_b, mt_b.mutbl, r_b)
} }
(ty::ty_uniq(mt_a), ty::ty_rptr(r_b, mt_b)) { (ty::ty_uniq(mt_a), ty::ty_rptr(r_b, mt_b)) {
let nr_b = ty::mk_uniq(self.tcx, mt_b); let nr_b = ty::mk_uniq(self.tcx, {ty: mt_b.ty,
self.crosspollinate(anmnt, a, nr_b, r_b) mutbl: m_const});
self.crosspollinate(anmnt, a, nr_b, mt_b.mutbl, r_b)
} }
(ty::ty_estr(vs_a), (ty::ty_estr(vs_a),
ty::ty_estr(ty::vstore_slice(r_b))) ty::ty_estr(ty::vstore_slice(r_b)))
if is_borrowable(vs_a) { if is_borrowable(vs_a) {
let nr_b = ty::mk_estr(self.tcx, vs_a); let nr_b = ty::mk_estr(self.tcx, vs_a);
self.crosspollinate(anmnt, a, nr_b, r_b) self.crosspollinate(anmnt, a, nr_b, m_imm, r_b)
} }
(ty::ty_str, (ty::ty_str,
ty::ty_estr(ty::vstore_slice(r_b))) { ty::ty_estr(ty::vstore_slice(r_b))) {
let nr_b = ty::mk_str(self.tcx); let nr_b = ty::mk_str(self.tcx);
self.crosspollinate(anmnt, a, nr_b, r_b) self.crosspollinate(anmnt, a, nr_b, m_imm, r_b)
} }
(ty::ty_evec(mt_a, vs_a), (ty::ty_evec(mt_a, vs_a),
ty::ty_evec(mt_b, ty::vstore_slice(r_b))) ty::ty_evec(mt_b, ty::vstore_slice(r_b)))
if is_borrowable(vs_a) { if is_borrowable(vs_a) {
let nr_b = ty::mk_evec(self.tcx, mt_b, vs_a); let nr_b = ty::mk_evec(self.tcx, {ty: mt_b.ty,
self.crosspollinate(anmnt, a, nr_b, r_b) mutbl: m_const}, vs_a);
self.crosspollinate(anmnt, a, nr_b, mt_b.mutbl, r_b)
} }
(ty::ty_vec(mt_a), (ty::ty_vec(mt_a),
ty::ty_evec(mt_b, ty::vstore_slice(r_b))) { ty::ty_evec(mt_b, ty::vstore_slice(r_b))) {
let nr_b = ty::mk_vec(self.tcx, mt_b); let nr_b = ty::mk_vec(self.tcx, {ty: mt_b.ty,
self.crosspollinate(anmnt, a, nr_b, r_b) mutbl: m_const});
self.crosspollinate(anmnt, a, nr_b, mt_b.mutbl, r_b)
} }
_ { _ {
self.sub_tys(a, b) self.sub_tys(a, b)
...@@ -1093,9 +1101,10 @@ fn is_borrowable(v: ty::vstore) -> bool { ...@@ -1093,9 +1101,10 @@ fn is_borrowable(v: ty::vstore) -> bool {
} }
fn crosspollinate(anmnt: assignment, fn crosspollinate(anmnt: assignment,
a: ty::t, a: ty::t,
nr_b: ty::t, nr_b: ty::t,
r_b: ty::region) -> ures { m: ast::mutability,
r_b: ty::region) -> ures {
#debug["crosspollinate(anmnt=%?, a=%s, nr_b=%s, r_b=%s)", #debug["crosspollinate(anmnt=%?, a=%s, nr_b=%s, r_b=%s)",
anmnt, a.to_str(self), nr_b.to_str(self), anmnt, a.to_str(self), nr_b.to_str(self),
...@@ -1109,8 +1118,9 @@ fn crosspollinate(anmnt: assignment, ...@@ -1109,8 +1118,9 @@ fn crosspollinate(anmnt: assignment,
// if successful, add an entry indicating that // if successful, add an entry indicating that
// borrowing occurred // borrowing occurred
#debug["borrowing expression #%?", anmnt]; #debug["borrowing expression #%?", anmnt];
self.tcx.borrowings.insert(anmnt.expr_id, let borrow = {scope_id: anmnt.borrow_scope,
anmnt.borrow_scope); mutbl: m};
self.tcx.borrowings.insert(anmnt.expr_id, borrow);
uok() uok()
} }
} }
...@@ -1561,17 +1571,17 @@ fn regions(a: ty::region, b: ty::region) -> cres<ty::region> { ...@@ -1561,17 +1571,17 @@ fn regions(a: ty::region, b: ty::region) -> cres<ty::region> {
fn mts(a: ty::mt, b: ty::mt) -> cres<ty::mt> { fn mts(a: ty::mt, b: ty::mt) -> cres<ty::mt> {
#debug("mts(%s <: %s)", a.to_str(*self), b.to_str(*self)); #debug("mts(%s <: %s)", a.to_str(*self), b.to_str(*self));
if a.mutbl != b.mutbl && b.mutbl != ast::m_const { if a.mutbl != b.mutbl && b.mutbl != m_const {
ret err(ty::terr_mutability); ret err(ty::terr_mutability);
} }
alt b.mutbl { alt b.mutbl {
ast::m_mutbl { m_mutbl {
// If supertype is mut, subtype must match exactly // If supertype is mut, subtype must match exactly
// (i.e., invariant if mut): // (i.e., invariant if mut):
self.infcx().eq_tys(a.ty, b.ty).then {|| ok(a) } self.infcx().eq_tys(a.ty, b.ty).then {|| ok(a) }
} }
ast::m_imm | ast::m_const { m_imm | m_const {
// Otherwise we can be covariant: // Otherwise we can be covariant:
self.tys(a.ty, b.ty).chain {|_t| ok(a) } self.tys(a.ty, b.ty).chain {|_t| ok(a) }
} }
...@@ -1710,24 +1720,24 @@ fn mts(a: ty::mt, b: ty::mt) -> cres<ty::mt> { ...@@ -1710,24 +1720,24 @@ fn mts(a: ty::mt, b: ty::mt) -> cres<ty::mt> {
let m = if a.mutbl == b.mutbl { let m = if a.mutbl == b.mutbl {
a.mutbl a.mutbl
} else { } else {
ast::m_const m_const
}; };
alt m { alt m {
ast::m_imm | ast::m_const { m_imm | m_const {
self.tys(a.ty, b.ty).chain {|t| self.tys(a.ty, b.ty).chain {|t|
ok({ty: t, mutbl: m}) ok({ty: t, mutbl: m})
} }
} }
ast::m_mutbl { m_mutbl {
self.infcx().try {|| self.infcx().try {||
self.infcx().eq_tys(a.ty, b.ty).then {|| self.infcx().eq_tys(a.ty, b.ty).then {||
ok({ty: a.ty, mutbl: m}) ok({ty: a.ty, mutbl: m})
} }
}.chain_err {|_e| }.chain_err {|_e|
self.tys(a.ty, b.ty).chain {|t| self.tys(a.ty, b.ty).chain {|t|
ok({ty: t, mutbl: ast::m_const}) ok({ty: t, mutbl: m_const})
} }
} }
} }
...@@ -1893,43 +1903,43 @@ fn mts(a: ty::mt, b: ty::mt) -> cres<ty::mt> { ...@@ -1893,43 +1903,43 @@ fn mts(a: ty::mt, b: ty::mt) -> cres<ty::mt> {
alt (a.mutbl, b.mutbl) { alt (a.mutbl, b.mutbl) {
// If one side or both is mut, then the GLB must use // If one side or both is mut, then the GLB must use
// the precise type from the mut side. // the precise type from the mut side.
(ast::m_mutbl, ast::m_const) { (m_mutbl, m_const) {
sub(*self).tys(a.ty, b.ty).chain {|_t| sub(*self).tys(a.ty, b.ty).chain {|_t|
ok({ty: a.ty, mutbl: ast::m_mutbl}) ok({ty: a.ty, mutbl: m_mutbl})
} }
} }
(ast::m_const, ast::m_mutbl) { (m_const, m_mutbl) {
sub(*self).tys(b.ty, a.ty).chain {|_t| sub(*self).tys(b.ty, a.ty).chain {|_t|
ok({ty: b.ty, mutbl: ast::m_mutbl}) ok({ty: b.ty, mutbl: m_mutbl})
} }
} }
(ast::m_mutbl, ast::m_mutbl) { (m_mutbl, m_mutbl) {
self.infcx().eq_tys(a.ty, b.ty).then {|| self.infcx().eq_tys(a.ty, b.ty).then {||
ok({ty: a.ty, mutbl: ast::m_mutbl}) ok({ty: a.ty, mutbl: m_mutbl})
} }
} }
// If one side or both is immutable, we can use the GLB of // If one side or both is immutable, we can use the GLB of
// both sides but mutbl must be `m_imm`. // both sides but mutbl must be `m_imm`.
(ast::m_imm, ast::m_const) | (m_imm, m_const) |
(ast::m_const, ast::m_imm) | (m_const, m_imm) |
(ast::m_imm, ast::m_imm) { (m_imm, m_imm) {
self.tys(a.ty, b.ty).chain {|t| self.tys(a.ty, b.ty).chain {|t|
ok({ty: t, mutbl: ast::m_imm}) ok({ty: t, mutbl: m_imm})
} }
} }
// If both sides are const, then we can use GLB of both // If both sides are const, then we can use GLB of both
// sides and mutbl of only `m_const`. // sides and mutbl of only `m_const`.
(ast::m_const, ast::m_const) { (m_const, m_const) {
self.tys(a.ty, b.ty).chain {|t| self.tys(a.ty, b.ty).chain {|t|
ok({ty: t, mutbl: ast::m_const}) ok({ty: t, mutbl: m_const})
} }
} }
// There is no mutual subtype of these combinations. // There is no mutual subtype of these combinations.
(ast::m_mutbl, ast::m_imm) | (m_mutbl, m_imm) |
(ast::m_imm, ast::m_mutbl) { (m_imm, m_mutbl) {
err(ty::terr_mutability) err(ty::terr_mutability)
} }
} }
......
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
fn want_slice(v: [int]/&) -> int {
let mut sum = 0;
for vec::each(v) { |i| sum += i; }
ret sum;
}
fn has_mut_vec(+v: @[mut int]) -> int {
want_slice(*v) //! ERROR illegal borrow unless pure: creating immutable alias to aliasable, mutable memory
//!^ NOTE impure due to access to impure function
}
fn main() {
assert has_mut_vec(@[mut 1, 2, 3]) == 6;
}
\ No newline at end of file
// xfail-fast (compile-flags unsupported on windows)
// compile-flags:--borrowck=err
fn want_slice(v: [int]/&) -> int {
let mut sum = 0;
for vec::each(v) { |i| sum += i; }
ret sum;
}
fn has_mut_vec(+v: [mut int]) -> int {
want_slice(v)
}
fn main() {
assert has_mut_vec([mut 1, 2, 3]) == 6;
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册