Warn when invoking polymorphic functions with non copyable types. Closes #2466.

This commit is contained in:
Michael Sullivan 2012-05-29 16:22:22 -07:00
parent 5a4e53487f
commit 4d5d43beae
3 changed files with 45 additions and 15 deletions

View File

@ -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<node_id, ()>;
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<ctx>) {
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<ctx>) {
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<ctx>) {
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<ctx>) {
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) + "`)");
}
}
}

View File

@ -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})
];

View File

@ -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()); }