Skip to content

Commit 673d0d8

Browse files
committed
Less confusing error message when copying into heap closures (close #2942)
1 parent d320848 commit 673d0d8

File tree

1 file changed

+40
-21
lines changed

1 file changed

+40
-21
lines changed

src/rustc/middle/kind.rs

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,13 @@ fn with_appropriate_checker(cx: ctx, id: node_id, b: fn(check_fn)) {
103103
104104
// copied in data must be copyable, but moved in data can be anything
105105
let is_implicit = fv.is_some();
106-
if !is_move { check_copy(cx, id, var_t, sp, is_implicit); }
106+
if !is_move {
107+
check_copy(cx, id, var_t, sp, is_implicit,
108+
some(("non-copyable value cannot be copied into a \
109+
~fn closure",
110+
"to copy values into a ~fn closure, use a \
111+
capture clause: `fn~(copy x)` or `|copy x|`")));
112+
}
107113

108114
// check that only immutable variables are implicitly copied in
109115
for fv.each |fv| {
@@ -118,7 +124,13 @@ fn with_appropriate_checker(cx: ctx, id: node_id, b: fn(check_fn)) {
118124

119125
// copied in data must be copyable, but moved in data can be anything
120126
let is_implicit = fv.is_some();
121-
if !is_move { check_copy(cx, id, var_t, sp, is_implicit); }
127+
if !is_move {
128+
check_copy(cx, id, var_t, sp, is_implicit,
129+
some(("non-copyable value cannot be copied into a \
130+
@fn closure",
131+
"to copy values into a @fn closure, use a \
132+
capture clause: `fn~(copy x)` or `|copy x|`")));
133+
}
122134

123135
// check that only immutable variables are implicitly copied in
124136
for fv.each |fv| {
@@ -207,7 +219,7 @@ fn check_fn(fk: visit::fn_kind, decl: fn_decl, body: blk, sp: span,
207219

208220
fn check_block(b: blk, cx: ctx, v: visit::vt<ctx>) {
209221
match b.node.expr {
210-
some(ex) => maybe_copy(cx, ex),
222+
some(ex) => maybe_copy(cx, ex, none),
211223
_ => ()
212224
}
213225
visit::visit_block(b, cx, v);
@@ -247,21 +259,21 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
247259
expr_assign(_, ex) |
248260
expr_unary(box(_), ex) | expr_unary(uniq(_), ex) |
249261
expr_ret(some(ex)) => {
250-
maybe_copy(cx, ex);
262+
maybe_copy(cx, ex, none);
251263
}
252264
expr_cast(source, _) => {
253-
maybe_copy(cx, source);
265+
maybe_copy(cx, source, none);
254266
check_cast_for_escaping_regions(cx, source, e);
255267
}
256-
expr_copy(expr) => check_copy_ex(cx, expr, false),
268+
expr_copy(expr) => check_copy_ex(cx, expr, false, none),
257269
// Vector add copies, but not "implicitly"
258-
expr_assign_op(_, _, ex) => check_copy_ex(cx, ex, false),
270+
expr_assign_op(_, _, ex) => check_copy_ex(cx, ex, false, none),
259271
expr_binary(add, ls, rs) => {
260-
check_copy_ex(cx, ls, false);
261-
check_copy_ex(cx, rs, false);
272+
check_copy_ex(cx, ls, false, none);
273+
check_copy_ex(cx, rs, false, none);
262274
}
263275
expr_rec(fields, def) => {
264-
for fields.each |field| { maybe_copy(cx, field.node.expr); }
276+
for fields.each |field| { maybe_copy(cx, field.node.expr, none); }
265277
match def {
266278
some(ex) => {
267279
// All noncopyable fields must be overridden
@@ -282,13 +294,13 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
282294
}
283295
}
284296
expr_tup(exprs) | expr_vec(exprs, _) => {
285-
for exprs.each |expr| { maybe_copy(cx, expr); }
297+
for exprs.each |expr| { maybe_copy(cx, expr, none); }
286298
}
287299
expr_call(f, args, _) => {
288300
let mut i = 0u;
289301
for ty::ty_fn_args(ty::expr_ty(cx.tcx, f)).each |arg_t| {
290302
match ty::arg_mode(cx.tcx, arg_t) {
291-
by_copy => maybe_copy(cx, args[i]),
303+
by_copy => maybe_copy(cx, args[i], none),
292304
by_ref | by_val | by_mutbl_ref | by_move => ()
293305
}
294306
i += 1u;
@@ -298,17 +310,17 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
298310
// If this is a method call with a by-val argument, we need
299311
// to check the copy
300312
match cx.method_map.find(e.id) {
301-
some({self_mode: by_copy, _}) => maybe_copy(cx, lhs),
313+
some({self_mode: by_copy, _}) => maybe_copy(cx, lhs, none),
302314
_ => ()
303315
}
304316
}
305317
expr_repeat(element, count_expr, _) => {
306318
let count = ty::eval_repeat_count(cx.tcx, count_expr, e.span);
307319
if count == 1 {
308-
maybe_copy(cx, element);
320+
maybe_copy(cx, element, none);
309321
} else {
310322
let element_ty = ty::expr_ty(cx.tcx, element);
311-
check_copy(cx, element.id, element_ty, element.span, true);
323+
check_copy(cx, element.id, element_ty, element.span, true, none);
312324
}
313325
}
314326
_ => { }
@@ -321,7 +333,7 @@ fn check_stmt(stmt: @stmt, cx: ctx, v: visit::vt<ctx>) {
321333
stmt_decl(@{node: decl_local(locals), _}, _) => {
322334
for locals.each |local| {
323335
match local.node.init {
324-
some({op: init_assign, expr}) => maybe_copy(cx, expr),
336+
some({op: init_assign, expr}) => maybe_copy(cx, expr, none),
325337
_ => {}
326338
}
327339
}
@@ -373,8 +385,8 @@ fn check_bounds(cx: ctx, id: node_id, sp: span,
373385
}
374386
}
375387

376-
fn maybe_copy(cx: ctx, ex: @expr) {
377-
check_copy_ex(cx, ex, true);
388+
fn maybe_copy(cx: ctx, ex: @expr, why: option<(&str,&str)>) {
389+
check_copy_ex(cx, ex, true, why);
378390
}
379391

380392
fn is_nullary_variant(cx: ctx, ex: @expr) -> bool {
@@ -391,7 +403,8 @@ fn is_nullary_variant(cx: ctx, ex: @expr) -> bool {
391403
}
392404
}
393405

394-
fn check_copy_ex(cx: ctx, ex: @expr, implicit_copy: bool) {
406+
fn check_copy_ex(cx: ctx, ex: @expr, implicit_copy: bool,
407+
why: option<(&str,&str)>) {
395408
if ty::expr_is_lval(cx.method_map, ex) &&
396409

397410
// this is a move
@@ -405,7 +418,7 @@ fn check_copy_ex(cx: ctx, ex: @expr, implicit_copy: bool) {
405418
!cx.tcx.borrowings.contains_key(ex.id)
406419
{
407420
let ty = ty::expr_ty(cx.tcx, ex);
408-
check_copy(cx, ex.id, ty, ex.span, implicit_copy);
421+
check_copy(cx, ex.id, ty, ex.span, implicit_copy, why);
409422
}
410423
}
411424

@@ -439,15 +452,21 @@ fn check_imm_free_var(cx: ctx, def: def, sp: span) {
439452
}
440453

441454
fn check_copy(cx: ctx, id: node_id, ty: ty::t, sp: span,
442-
implicit_copy: bool) {
455+
implicit_copy: bool, why: option<(&str,&str)>) {
443456
let k = ty::type_kind(cx.tcx, ty);
444457
if !ty::kind_can_be_copied(k) {
445458
cx.tcx.sess.span_err(sp, ~"copying a noncopyable value");
459+
do why.map |reason| {
460+
cx.tcx.sess.span_note(sp, fmt!("%s", reason.first()));
461+
};
446462
} else if implicit_copy && !ty::kind_can_be_implicitly_copied(k) {
447463
cx.tcx.sess.span_lint(
448464
implicit_copies, id, cx.current_item,
449465
sp,
450466
~"implicitly copying a non-implicitly-copyable value");
467+
do why.map |reason| {
468+
cx.tcx.sess.span_note(sp, fmt!("%s", reason.second()));
469+
};
451470
}
452471
}
453472

0 commit comments

Comments
 (0)