From 4d5d43beaee01fbec830365b12d893ac3ca6b7ad Mon Sep 17 00:00:00 2001 From: Michael Sullivan Date: Tue, 29 May 2012 16:22:22 -0700 Subject: [PATCH] Warn when invoking polymorphic functions with non copyable types. Closes #2466. --- src/rustc/middle/kind.rs | 48 +++++++++++++++++++++++++++++----------- src/rustc/middle/lint.rs | 7 ++++++ src/rustc/middle/ty.rs | 5 +++-- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/src/rustc/middle/kind.rs b/src/rustc/middle/kind.rs index fef2a0ad28e..10f095bba34 100644 --- a/src/rustc/middle/kind.rs +++ b/src/rustc/middle/kind.rs @@ -9,6 +9,7 @@ import util::ppaux::{ty_to_str, tys_to_str}; import syntax::print::pprust::expr_to_str; import freevars::freevar_entry; import dvec::extensions; +import lint::non_implicitly_copyable_typarams; // Kind analysis pass. // @@ -56,19 +57,26 @@ type rval_map = std::map::hashmap; type ctx = {tcx: ty::ctxt, method_map: typeck::method_map, - last_use_map: liveness::last_use_map}; + last_use_map: liveness::last_use_map, + current_item: node_id}; -fn check_crate(tcx: ty::ctxt, method_map: typeck::method_map, - last_use_map: liveness::last_use_map, crate: @crate) { +fn check_crate(tcx: ty::ctxt, + method_map: typeck::method_map, + last_use_map: liveness::last_use_map, + crate: @crate) { let ctx = {tcx: tcx, method_map: method_map, - last_use_map: last_use_map}; + last_use_map: last_use_map, + current_item: -1}; let visit = visit::mk_vt(@{ visit_expr: check_expr, visit_stmt: check_stmt, visit_block: check_block, visit_fn: check_fn, - visit_ty: check_ty + visit_ty: check_ty, + visit_item: fn@(i: @item, cx: ctx, v: visit::vt) { + visit::visit_item(i, {current_item: i.id with cx}, v); + } with *visit::default_visitor() }); visit::visit_crate(*crate, ctx, visit); @@ -280,7 +288,7 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt) { tys_to_str(cx.tcx, ts), ts.len(), *bounds, (*bounds).len()); } vec::iter2(ts, *bounds) {|ty, bound| - check_bounds(cx, e.span, ty, bound) + check_bounds(cx, e.id, e.span, ty, bound) } } } @@ -311,7 +319,7 @@ fn check_ty(aty: @ty, cx: ctx, v: visit::vt) { let did = ast_util::def_id_of_def(cx.tcx.def_map.get(id)); let bounds = ty::lookup_item_type(cx.tcx, did).bounds; vec::iter2(ts, *bounds) {|ty, bound| - check_bounds(cx, aty.span, ty, bound) + check_bounds(cx, aty.id, aty.span, ty, bound) } } } @@ -320,15 +328,29 @@ fn check_ty(aty: @ty, cx: ctx, v: visit::vt) { visit::visit_ty(aty, cx, v); } -fn check_bounds(cx: ctx, sp: span, ty: ty::t, bounds: ty::param_bounds) { +fn check_bounds(cx: ctx, id: node_id, sp: span, + ty: ty::t, bounds: ty::param_bounds) { let kind = ty::type_kind(cx.tcx, ty); let p_kind = ty::param_bounds_to_kind(bounds); if !ty::kind_lteq(p_kind, kind) { - cx.tcx.sess.span_err( - sp, "instantiating a type parameter with an incompatible type " + - "(needs `" + kind_to_str(p_kind) + - "`, got `" + kind_to_str(kind) + - "`, missing `" + kind_to_str(p_kind - kind) + "`)"); + // If the only reason the kind check fails is because the + // argument type isn't implicitly copyable, consult the warning + // settings to figure out what to do. + let implicit = ty::kind_implicitly_copyable() - ty::kind_copyable(); + if ty::kind_lteq(p_kind, kind | implicit) { + cx.tcx.sess.span_lint( + non_implicitly_copyable_typarams, + id, cx.current_item, sp, + "instantiating copy type parameter with a \ + not implicitly copyable type"); + } else { + cx.tcx.sess.span_err( + sp, + "instantiating a type parameter with an incompatible type " + + "(needs `" + kind_to_str(p_kind) + + "`, got `" + kind_to_str(kind) + + "`, missing `" + kind_to_str(p_kind - kind) + "`)"); + } } } diff --git a/src/rustc/middle/lint.rs b/src/rustc/middle/lint.rs index dc31c75733e..a3ef8615982 100644 --- a/src/rustc/middle/lint.rs +++ b/src/rustc/middle/lint.rs @@ -44,6 +44,7 @@ enum lint { path_statement, old_vecs, unrecognized_warning, + non_implicitly_copyable_typarams, } // This is pretty unfortunate. We really want some sort of "deriving Enum" @@ -56,6 +57,7 @@ fn int_to_lint(i: int) -> lint { 3 { path_statement } 4 { old_vecs } 5 { unrecognized_warning } + 6 { non_implicitly_copyable_typarams } } } @@ -103,6 +105,11 @@ fn get_lint_dict() -> lint_dict { ("unrecognized_warning", @{lint: unrecognized_warning, desc: "unrecognized warning attribute", + default: warn}), + + ("non_implicitly_copyable_typarams", + @{lint: non_implicitly_copyable_typarams, + desc: "passing non implicitly copyable types as copy type params", default: warn}) ]; diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index c608a83319c..84d541731df 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -112,7 +112,8 @@ export ty_var_id; export ty_to_def_id; export ty_fn_args; export type_constr; -export kind, kind_sendable, kind_copyable, kind_noncopyable, kind_const; +export kind, kind_implicitly_copyable, kind_sendable, kind_copyable; +export kind_noncopyable, kind_const; export kind_can_be_copied, kind_can_be_sent, kind_can_be_implicitly_copied; export proto_kind, kind_lteq, type_kind; export operators; @@ -455,7 +456,7 @@ fn param_bounds_to_kind(bounds: param_bounds) -> kind { for vec::each(*bounds) {|bound| alt bound { bound_copy { - kind = raise_kind(kind, kind_copyable()); + kind = raise_kind(kind, kind_implicitly_copyable()); } bound_send { kind = raise_kind(kind, kind_send_only()); } bound_const { kind = raise_kind(kind, kind_const()); }