Skip to content

Commit a11bb40

Browse files
committed
Further refinement to kind system lattice and type-kind rules; first successful caught kind error (prohibits copying a pinned resource, though trans already caught it later).
1 parent 7073ee4 commit a11bb40

File tree

2 files changed

+62
-27
lines changed

2 files changed

+62
-27
lines changed

src/comp/middle/kind.rs

+54-20
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,25 @@
1010
*
1111
*
1212
*
13-
* COPY + SEND = "Unique": no shared substructures or pins, only
13+
* MOVE + SEND = "Unique": no shared substructures or pins, only
1414
* interiors and ~ boxes.
1515
*
16-
* COPY + NOSEND = "Shared": structures containing @, fixed to the local
17-
* task heap/pool.
16+
* MOVE + NOSEND = "Shared": structures containing @, fixed to the local
17+
* task heap/pool; or ~ structures pointing to
18+
* pinned values.
1819
*
19-
* NOCOPY + NOSEND = "Pinned": structures containing resources or
20+
* NOMOVE + NOSEND = "Pinned": structures directly containing resources, or
2021
* by-alias closures as interior or
2122
* uniquely-boxed members.
2223
*
23-
* NOCOPY + SEND = -- : no types are like this.
24+
* NOMOVE + SEND = -- : no types are like this.
2425
*
2526
*
2627
* Since this forms a lattice, we denote the capabilites in terms of a
27-
* worst-case requirement. That is, if your function needs to copy-and-send
28-
* your T, you write fn<~T>(...). If you need to copy but not send, you write
29-
* fn<@T>(...). And if you need neither -- can work with any sort of pinned
30-
* data at all -- then you write fn<T>(...).
28+
* worst-case requirement. That is, if your function needs to move-and-send
29+
* (or copy) your T, you write fn<~T>(...). If you need to copy but not send,
30+
* you write fn<@T>(...). And if you need neither -- can work with any sort of
31+
* pinned data at all -- then you write fn<T>(...).
3132
*
3233
*
3334
* Most types are unique or shared. Other possible name combinations for these
@@ -54,22 +55,19 @@
5455
* A copy is made any time you pass-by-value or execute the = operator in a
5556
* non-init expression.
5657
*
57-
* ~ copies deep
58-
* @ copies shallow
58+
* @ copies shallow, is always legal
59+
* ~ copies deep, is only legal if pointee is unique.
5960
* pinned values (pinned resources, alias-closures) can't be copied
60-
* all other interiors copy shallow
61+
* all other unique (eg. interior) values copy shallow
62+
*
63+
* Note this means that only type parameters constrained to ~T can be copied.
6164
*
6265
* MOVING:
6366
* -------
6467
*
6568
* A move is made any time you pass-by-move (that is, with 'move' mode) or
6669
* execute the <- operator.
6770
*
68-
* Anything you can copy, you can move. Move is (semantically) just
69-
* shallow-copy + deinit. Note that: ~ moves shallow even though it copies
70-
* deep. Move is the operator that lets ~ copy shallow: by pairing it with a
71-
* deinit.
72-
*
7371
*/
7472

7573

@@ -101,11 +99,47 @@ fn kind_to_str(k: kind) -> str {
10199
}
102100
}
103101

104-
fn check_expr(tcx: &ty::ctxt, e: &@ast::expr) {
102+
fn type_and_kind(tcx: &ty::ctxt, e: &@ast::expr)
103+
-> {ty: ty::t, kind: ast::kind} {
105104
let t = ty::expr_ty(tcx, e);
106105
let k = ty::type_kind(tcx, t);
107-
log #fmt("%s type: %s", kind_to_str(k),
108-
util::ppaux::ty_to_str(tcx, t));
106+
{ty: t, kind: k}
107+
}
108+
109+
fn need_expr_kind(tcx: &ty::ctxt, e: &@ast::expr,
110+
k_need: ast::kind, descr: &str) {
111+
let tk = type_and_kind(tcx, e);
112+
log #fmt("for %s: want %s type, got %s type %s",
113+
descr,
114+
kind_to_str(k_need),
115+
kind_to_str(tk.kind),
116+
util::ppaux::ty_to_str(tcx, tk.ty));
117+
118+
if ! kind_lteq(k_need, tk.kind) {
119+
let s =
120+
#fmt("mismatched kinds for %s: needed %s type, got %s type %s",
121+
descr,
122+
kind_to_str(k_need),
123+
kind_to_str(tk.kind),
124+
util::ppaux::ty_to_str(tcx, tk.ty));
125+
tcx.sess.span_err(e.span, s);
126+
}
127+
}
128+
129+
fn need_shared_lhs_rhs(tcx: &ty::ctxt,
130+
a: &@ast::expr, b: &@ast::expr,
131+
op: &str) {
132+
need_expr_kind(tcx, a, ast::kind_shared, op + " lhs");
133+
need_expr_kind(tcx, b, ast::kind_shared, op + " rhs");
134+
}
135+
136+
fn check_expr(tcx: &ty::ctxt, e: &@ast::expr) {
137+
alt e.node {
138+
ast::expr_move(a, b) { need_shared_lhs_rhs(tcx, a, b, "<-"); }
139+
ast::expr_assign(a, b) { need_shared_lhs_rhs(tcx, a, b, "="); }
140+
ast::expr_swap(a, b) { need_shared_lhs_rhs(tcx, a, b, "<->"); }
141+
_ { }
142+
}
109143
}
110144

111145
fn check_crate(tcx: &ty::ctxt, crate: &@ast::crate) {

src/comp/middle/ty.rs

+8-7
Original file line numberDiff line numberDiff line change
@@ -1058,12 +1058,10 @@ fn type_kind(cx: &ctxt, ty: &t) -> ast::kind {
10581058
}
10591059
}
10601060

1061-
// Those with refcounts-to-inner are the lower of their
1062-
// inner and shared.
1061+
// Those with refcounts-to-inner raise pinned to shared,
1062+
// lower unique to shared. Therefore just set result to shared.
10631063
ty_box(mt) | ty_vec(mt) {
1064-
result = kind::lower_kind(ast::kind_shared,
1065-
type_kind(cx, mt.ty));
1066-
1064+
result = ast::kind_shared;
10671065
}
10681066

10691067
// FIXME: remove ports. Ports currently contribute 'shared'
@@ -1078,9 +1076,12 @@ fn type_kind(cx: &ctxt, ty: &t) -> ast::kind {
10781076
result = type_kind(cx, t);
10791077
}
10801078

1081-
// Pointers and unique boxes / vecs lower to whatever they point to.
1079+
// Pointers and unique boxes / vecs raise pinned to shared,
1080+
// otherwise pass through their pointee kind.
10821081
ty_ptr(tm) | ty_ivec(tm) {
1083-
result = type_kind(cx, tm.ty);
1082+
let k = type_kind(cx, tm.ty);
1083+
if k == ast::kind_pinned { k = ast::kind_shared }
1084+
result = kind::lower_kind(result, k);
10841085
}
10851086

10861087
// Records lower to the lowest of their members.

0 commit comments

Comments
 (0)