|
1 |
| -import std::option::some; |
| 1 | +import std::option::{some, none}; |
2 | 2 | import syntax::{visit, ast_util};
|
3 | 3 | import syntax::ast::*;
|
4 | 4 | import syntax::codemap::span;
|
@@ -50,12 +50,33 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
|
50 | 50 | expr_bind(_, args) {
|
51 | 51 | for a in args { alt a { some(ex) { maybe_copy(cx, ex); } _ {} } }
|
52 | 52 | }
|
53 |
| - // FIXME check for by-copy args |
54 |
| - expr_call(_f, _args, _) { |
55 |
| - |
| 53 | + expr_call(f, args, _) { |
| 54 | + let i = 0u; |
| 55 | + for arg_t in ty::ty_fn_args(cx.tcx, ty::expr_ty(cx.tcx, f)) { |
| 56 | + alt arg_t.mode { by_copy. { maybe_copy(cx, args[i]); } _ {} } |
| 57 | + i += 1u; |
| 58 | + } |
| 59 | + } |
| 60 | + expr_path(_) { |
| 61 | + let substs = ty::node_id_to_ty_param_substs_opt_and_ty(cx.tcx, e.id); |
| 62 | + alt substs.substs { |
| 63 | + some(ts) { |
| 64 | + let did = ast_util::def_id_of_def(cx.tcx.def_map.get(e.id)); |
| 65 | + let kinds = ty::lookup_item_type(cx.tcx, did).kinds, i = 0u; |
| 66 | + for ty in ts { |
| 67 | + let kind = ty::type_kind(cx.tcx, ty); |
| 68 | + if !ty::kind_lteq(kinds[i], kind) { |
| 69 | + cx.tcx.sess.span_err(e.span, "instantiating a " + |
| 70 | + kind_to_str(kinds[i]) + |
| 71 | + " type parameter with a " |
| 72 | + + kind_to_str(kind) + " type"); |
| 73 | + } |
| 74 | + i += 1u; |
| 75 | + } |
| 76 | + } |
| 77 | + none. {} |
| 78 | + } |
56 | 79 | }
|
57 |
| - // FIXME: generic instantiation |
58 |
| - expr_path(_) {} |
59 | 80 | expr_fn({proto: proto_shared(_), _}) {
|
60 | 81 | for free in *freevars::get_freevars(cx.tcx, e.id) {
|
61 | 82 | let id = ast_util::def_id_of_def(free).node;
|
@@ -114,284 +135,6 @@ fn check_copy(cx: ctx, ty: ty::t, sp: span) {
|
114 | 135 | }
|
115 | 136 | }
|
116 | 137 |
|
117 |
| - |
118 |
| -/* |
119 |
| -* Kinds are types of type. |
120 |
| -* |
121 |
| -* Every type has a kind. Every type parameter has a set of kind-capabilities |
122 |
| -* saying which kind of type may be passed as the parameter. |
123 |
| -* |
124 |
| -* The kinds are based on two capabilities: move and send. These may each be |
125 |
| -* present or absent, though only three of the four combinations can actually |
126 |
| -* occur: |
127 |
| -* |
128 |
| -* |
129 |
| -* |
130 |
| -* MOVE + SEND = "Unique": no shared substructures or pins, only |
131 |
| -* interiors and ~ boxes. |
132 |
| -* |
133 |
| -* MOVE + NOSEND = "Shared": structures containing @, fixed to the local |
134 |
| -* task heap/pool; or ~ structures pointing to |
135 |
| -* pinned values. |
136 |
| -* |
137 |
| -* NOMOVE + NOSEND = "Pinned": structures directly containing resources, or |
138 |
| -* by-alias closures as interior or |
139 |
| -* uniquely-boxed members. |
140 |
| -* |
141 |
| -* NOMOVE + SEND = -- : no types are like this. |
142 |
| -* |
143 |
| -* |
144 |
| -* Since this forms a lattice, we denote the capabilites in terms of a |
145 |
| -* worst-case requirement. That is, if your function needs to move-and-send (or |
146 |
| -* copy) your T, you write fn<uniq T>(...). If you need to move but not send, |
147 |
| -* you write fn<T>(...). And if you need neither -- can work with any sort of |
148 |
| -* pinned data at all -- then you write fn<pin T>(...). |
149 |
| -* |
150 |
| -* Most types are unique or shared. Other possible name combinations for these |
151 |
| -* two: (tree, graph; pruned, pooled; message, local; owned, common) are |
152 |
| -* plausible but nothing stands out as completely pithy-and-obvious. |
153 |
| -* |
154 |
| -* Pinned values arise in 2 contexts: resources and &-closures (blocks). The |
155 |
| -* latter absolutely must not be moved, since they could escape to the heap; |
156 |
| -* the former must not be copied, since they'd then be multiply-destructed. |
157 |
| -* We achieve the no-copy restriction by recycling the no-move restriction |
158 |
| -* in place on pinned kinds for &-closures; and as a benefit we can guarantee |
159 |
| -* that a resource passed by reference to C will never move during its life, |
160 |
| -* occasionally useful for FFI-code. |
161 |
| -* |
162 |
| -* Resources cannot be sent because we don't want to oblige the communication |
163 |
| -* system to run destructors in some weird limbo context of |
164 |
| -* messages-in-transit. It should always be ok to just free messages it's |
165 |
| -* dropping. Even if you wanted to send them, you'd need a new sigil for the |
166 |
| -* NOMOVE + SEND combination, and you couldn't use the move-mode library |
167 |
| -* interface to chan.send in that case (NOMOVE after all), so the whole thing |
168 |
| -* wouldn't really work as minimally as the encoding we have here. |
169 |
| -* |
170 |
| -* Note that obj~ and fn~ -- those that capture a unique environment -- can be |
171 |
| -* sent, so satisfy ~T. So can plain obj and fn. They can all also be copied. |
172 |
| -* |
173 |
| -* Further notes on copying and moving; sending is accomplished by calling a |
174 |
| -* move-in operator on something constrained to a unique type ~T. |
175 |
| -* |
176 |
| -* |
177 |
| -* COPYING: |
178 |
| -* -------- |
179 |
| -* |
180 |
| -* A copy is made any time you pass-by-value or execute the = operator in a |
181 |
| -* non-init expression. Copying requires discriminating on type constructor. |
182 |
| -* |
183 |
| -* @-boxes copy shallow, copying is always legal. |
184 |
| -* |
185 |
| -* ~-boxes copy deep, copying is only legal if pointee is unique-kind. |
186 |
| -* |
187 |
| -* Pinned-kind values (resources, &-closures) can't be copied. All other |
188 |
| -* unique-kind (eg. interior) values can be copied, and copy shallow. |
189 |
| -* |
190 |
| -* Note: If you have no type constructor -- only an opaque typaram -- then |
191 |
| -* you can only copy if the typaram is constrained to ~T; this is because @T |
192 |
| -* might be a "~resource" box, and making a copy would cause a deep |
193 |
| -* resource-copy. |
194 |
| -* |
195 |
| -* |
196 |
| -* MOVING: |
197 |
| -* ------- |
198 |
| -* |
199 |
| -* A move is made any time you pass-by-move (that is, with move mode '-') or |
200 |
| -* execute the move ('<-') or swap ('<->') operators. |
201 |
| -* |
202 |
| -*/ |
203 |
| - |
204 |
| -/* |
205 |
| -fn type_and_kind(tcx: ty::ctxt, e: @ast::expr) -> |
206 |
| - {ty: ty::t, kind: ast::kind} { |
207 |
| - let t = ty::expr_ty(tcx, e); |
208 |
| - let k = ty::type_kind(tcx, t); |
209 |
| - {ty: t, kind: k} |
210 |
| -} |
211 |
| -
|
212 |
| -fn need_expr_kind(tcx: ty::ctxt, e: @ast::expr, k_need: ast::kind, |
213 |
| - descr: str) { |
214 |
| - let tk = type_and_kind(tcx, e); |
215 |
| - log #fmt["for %s: want %s type, got %s type %s", descr, |
216 |
| - kind_to_str(k_need), kind_to_str(tk.kind), |
217 |
| - util::ppaux::ty_to_str(tcx, tk.ty)]; |
218 |
| -
|
219 |
| - demand_kind(tcx, e.span, tk.ty, k_need, descr); |
220 |
| -} |
221 |
| -
|
222 |
| -fn demand_kind(tcx: ty::ctxt, sp: codemap::span, t: ty::t, |
223 |
| - k_need: ast::kind, descr: str) { |
224 |
| - let k = ty::type_kind(tcx, t); |
225 |
| - if !kind_lteq(k_need, k) { |
226 |
| - let s = |
227 |
| - #fmt["mismatched kinds for %s: needed %s type, got %s type %s", |
228 |
| - descr, kind_to_str(k_need), kind_to_str(k), |
229 |
| - util::ppaux::ty_to_str(tcx, t)]; |
230 |
| - tcx.sess.span_err(sp, s); |
231 |
| - } |
232 |
| -} |
233 |
| -
|
234 |
| -fn need_shared_lhs_rhs(tcx: ty::ctxt, a: @ast::expr, b: @ast::expr, op: str) { |
235 |
| - need_expr_kind(tcx, a, ast::kind_copyable, op + " lhs"); |
236 |
| - need_expr_kind(tcx, b, ast::kind_copyable, op + " rhs"); |
237 |
| -} |
238 |
| -
|
239 |
| -/* |
240 |
| -This ... is a hack (I find myself writing that too often *sadface*). |
241 |
| -
|
242 |
| -We need to be able to put pinned kinds into other types but such operations |
243 |
| -are conceptually copies, and pinned kinds can't do that, e.g. |
244 |
| -
|
245 |
| -let a = my_resource(x); |
246 |
| -let b = @a; // no-go |
247 |
| -
|
248 |
| -So this function attempts to make a loophole where resources can be put into |
249 |
| -other types as long as it's done in a safe way, specifically like |
250 |
| -
|
251 |
| -let b = @my_resource(x); |
252 |
| -*/ |
253 |
| -fn need_shared_or_pinned_ctor(tcx: ty::ctxt, a: @ast::expr, descr: str) { |
254 |
| - let tk = type_and_kind(tcx, a); |
255 |
| - if tk.kind == ast::kind_pinned && !pinned_ctor(a) { |
256 |
| - let err = |
257 |
| - #fmt["mismatched kinds for %s: cannot copy pinned type %s", |
258 |
| - descr, util::ppaux::ty_to_str(tcx, tk.ty)]; |
259 |
| - tcx.sess.span_err(a.span, err); |
260 |
| - let note = |
261 |
| - #fmt["try constructing %s directly into %s", |
262 |
| - util::ppaux::ty_to_str(tcx, tk.ty), descr]; |
263 |
| - tcx.sess.span_note(a.span, note); |
264 |
| - } else if tk.kind != ast::kind_pinned { |
265 |
| - need_expr_kind(tcx, a, ast::kind_shared, descr); |
266 |
| - } |
267 |
| -
|
268 |
| - fn pinned_ctor(a: @ast::expr) -> bool { |
269 |
| - // FIXME: Technically a lambda block is also a pinned ctor |
270 |
| - alt a.node { |
271 |
| - ast::expr_call(cexpr, _, _) { |
272 |
| - // Assuming that if it's a call that it's safe to move in, mostly |
273 |
| - // because I don't know offhand how to ensure that it's a call |
274 |
| - // specifically to a resource constructor |
275 |
| - true |
276 |
| - } |
277 |
| - ast::expr_rec(_, _) { |
278 |
| - true |
279 |
| - } |
280 |
| - ast::expr_unary(ast::uniq(_), _) { |
281 |
| - true |
282 |
| - } |
283 |
| - ast::expr_tup(_) { |
284 |
| - true |
285 |
| - } |
286 |
| - ast::expr_vec(exprs, _) { |
287 |
| - true |
288 |
| - } |
289 |
| - _ { false } |
290 |
| - } |
291 |
| - } |
292 |
| -} |
293 |
| -
|
294 |
| -fn check_expr(tcx: ty::ctxt, e: @ast::expr) { |
295 |
| - alt e.node { |
296 |
| -
|
297 |
| - // FIXME: These rules do not fully implement the copy type-constructor |
298 |
| - // discrimination described by the block comment at the top of this |
299 |
| - // file. This code is wrong; it lets you copy anything shared-kind. |
300 |
| -
|
301 |
| - ast::expr_move(a, b) { need_shared_lhs_rhs(tcx, a, b, "<-"); } |
302 |
| - ast::expr_assign(a, b) { |
303 |
| - need_shared_lhs_rhs(tcx, a, b, "="); |
304 |
| - } |
305 |
| - ast::expr_assign_op(_, a, b) { |
306 |
| - need_shared_lhs_rhs(tcx, a, b, "op="); |
307 |
| - } |
308 |
| - ast::expr_swap(a, b) { need_shared_lhs_rhs(tcx, a, b, "<->"); } |
309 |
| - ast::expr_copy(a) { |
310 |
| - need_expr_kind(tcx, a, ast::kind_shared, "'copy' operand"); |
311 |
| - } |
312 |
| - ast::expr_ret(option::some(a)) { |
313 |
| - need_expr_kind(tcx, a, ast::kind_shared, "'ret' operand"); |
314 |
| - } |
315 |
| - ast::expr_be(a) { |
316 |
| - need_expr_kind(tcx, a, ast::kind_shared, "'be' operand"); |
317 |
| - } |
318 |
| - ast::expr_fail(option::some(a)) { |
319 |
| - need_expr_kind(tcx, a, ast::kind_shared, "'fail' operand"); |
320 |
| - } |
321 |
| - ast::expr_call(callee, _, _) { |
322 |
| - let tpt = ty::expr_ty_params_and_ty(tcx, callee); |
323 |
| -
|
324 |
| - // If we have typarams, we're calling an item; we need to check |
325 |
| - // that all the types we're supplying as typarams conform to the |
326 |
| - // typaram kind constraints on that item. |
327 |
| - if vec::len(tpt.params) != 0u { |
328 |
| - let callee_def = |
329 |
| - ast_util::def_id_of_def(tcx.def_map.get(callee.id)); |
330 |
| - let item_tk = ty::lookup_item_type(tcx, callee_def); |
331 |
| - let i = 0; |
332 |
| - assert (vec::len(item_tk.kinds) == vec::len(tpt.params)); |
333 |
| - for k_need: ast::kind in item_tk.kinds { |
334 |
| - let t = tpt.params[i]; |
335 |
| - demand_kind(tcx, e.span, t, k_need, |
336 |
| - #fmt("typaram %d", i)); |
337 |
| - i += 1; |
338 |
| - } |
339 |
| - } |
340 |
| - } |
341 |
| - ast::expr_unary(op, a) { |
342 |
| - alt op { |
343 |
| - ast::box(_) { |
344 |
| - need_shared_or_pinned_ctor(tcx, a, "'@' operand"); |
345 |
| - } |
346 |
| - ast::uniq(_) { |
347 |
| - need_shared_or_pinned_ctor(tcx, a, "'~' operand"); |
348 |
| - } |
349 |
| - _ { /* fall through */ } |
350 |
| - } |
351 |
| - } |
352 |
| - ast::expr_rec(fields, _) { |
353 |
| - for field in fields { |
354 |
| - need_shared_or_pinned_ctor(tcx, field.node.expr, "record field"); |
355 |
| - } |
356 |
| - } |
357 |
| - ast::expr_tup(exprs) { |
358 |
| - for expr in exprs { |
359 |
| - need_shared_or_pinned_ctor(tcx, expr, "tuple parameter"); |
360 |
| - } |
361 |
| - } |
362 |
| - ast::expr_vec(exprs, _) { |
363 |
| - // Putting pinned things into vectors is pretty useless since vector |
364 |
| - // addition can't work (it's a copy) |
365 |
| - for expr in exprs { |
366 |
| - need_expr_kind(tcx, expr, ast::kind_shared, "vector element"); |
367 |
| - } |
368 |
| - } |
369 |
| - _ { } |
370 |
| - } |
371 |
| -} |
372 |
| -
|
373 |
| -fn check_stmt(tcx: ty::ctxt, stmt: @ast::stmt) { |
374 |
| - alt stmt.node { |
375 |
| - ast::stmt_decl(@{node: ast::decl_local(locals), _}, _) { |
376 |
| - for (let_style, local) in locals { |
377 |
| - alt local.node.init { |
378 |
| - option::some({op: ast::init_assign., expr}) { |
379 |
| - need_shared_or_pinned_ctor(tcx, expr, |
380 |
| - "local initializer"); |
381 |
| - } |
382 |
| - option::some({op: ast::init_move., expr}) { |
383 |
| - need_shared_or_pinned_ctor(tcx, expr, |
384 |
| - "local initializer"); |
385 |
| - } |
386 |
| - option::none. { /* fall through */ } |
387 |
| - } |
388 |
| - } |
389 |
| - } |
390 |
| - _ { /* fall through */ } |
391 |
| - } |
392 |
| -} |
393 |
| -*/ |
394 |
| - |
395 | 138 | //
|
396 | 139 | // Local Variables:
|
397 | 140 | // mode: rust
|
|
0 commit comments