From 8b6bfc96cba80dd59c244acbb27487e28ef8280f Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Thu, 24 May 2012 14:24:09 -0700 Subject: [PATCH] Const kind checking. The rules are almost certainly incomplete and unsound... --- src/rustc/middle/kind.rs | 27 +++--- src/rustc/middle/ty.rs | 85 +++++++++++++++---- .../compile-fail/bad-method-typaram-kind.rs | 3 +- src/test/compile-fail/non-const.rs | 19 +++++ src/test/compile-fail/unique-unique-kind.rs | 8 +- src/test/run-pass/const-bound.rs | 2 + 6 files changed, 110 insertions(+), 34 deletions(-) create mode 100644 src/test/compile-fail/non-const.rs diff --git a/src/rustc/middle/kind.rs b/src/rustc/middle/kind.rs index b350d34781a..e6facc2f7fd 100644 --- a/src/rustc/middle/kind.rs +++ b/src/rustc/middle/kind.rs @@ -1,7 +1,8 @@ import syntax::{visit, ast_util}; import syntax::ast::*; import syntax::codemap::span; -import ty::{kind, kind_sendable, kind_copyable, kind_noncopyable }; +import ty::{kind, kind_sendable, kind_copyable, kind_noncopyable, kind_const, + operators}; import driver::session::session; import std::map::hashmap; import util::ppaux::{ty_to_str, tys_to_str}; @@ -24,12 +25,17 @@ import freevars::freevar_entry; // types. fn kind_to_str(k: kind) -> str { - alt (ty::kind_can_be_copied(k), ty::kind_can_be_sent(k)) { - (false, false) { "noncopyable" } - (false, true) { "sendable" } - (true, false) { "copyable" } - (true, true) { "copy-sendable" } + let mut kinds = []; + if ty::kind_lteq(k, kind_const()) { + kinds += ["const"]; } + if ty::kind_can_be_copied(k) { + kinds += ["copy"]; + } + if ty::kind_can_be_sent(k) { + kinds += ["send"]; + } + str::connect(kinds, " ") } type rval_map = std::map::hashmap; @@ -320,10 +326,11 @@ fn check_bounds(cx: ctx, 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 " + - kind_to_str(p_kind) + - " type parameter with a " - + kind_to_str(kind) + " type"); + 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/ty.rs b/src/rustc/middle/ty.rs index f1371b42598..25780dcd29f 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -110,8 +110,9 @@ export ty_var_id; export ty_to_def_id; export ty_fn_args; export type_constr; -export kind, kind_sendable, kind_copyable, kind_noncopyable; +export kind, kind_sendable, kind_copyable, kind_noncopyable, kind_const; export kind_can_be_copied, kind_can_be_sent, proto_kind, kind_lteq, type_kind; +export operators; export type_err, terr_vstore_kind; export type_err_to_str; export type_needs_drop; @@ -431,7 +432,8 @@ fn param_bounds_to_kind(bounds: param_bounds) -> kind { kind = raise_kind(kind, kind_copyable()); } bound_send { kind = raise_kind(kind, kind_send_only()); } - _ {} + bound_const { kind = raise_kind(kind, kind_const()); } + bound_iface(_) {} } } kind @@ -1266,8 +1268,9 @@ fn type_needs_unwind_cleanup_(cx: ctxt, ty: t, enum kind { kind_(u32) } -const KIND_MASK_COPY : u32 = 0b00000000000000000000000000000001u32; -const KIND_MASK_SEND : u32 = 0b00000000000000000000000000000010u32; +const KIND_MASK_COPY : u32 = 0b00000000000000000000000000000001u32; +const KIND_MASK_SEND : u32 = 0b00000000000000000000000000000010u32; +const KIND_MASK_CONST : u32 = 0b00000000000000000000000000000100u32; fn kind_noncopyable() -> kind { kind_(0u32) @@ -1285,10 +1288,37 @@ fn kind_send_only() -> kind { kind_(KIND_MASK_SEND) } +fn kind_const() -> kind { + kind_(KIND_MASK_CONST) +} + fn kind_top() -> kind { kind_(0xffffffffu32) } +fn remove_const(k: kind, tm: mt) -> kind { + if tm.mutbl == ast::m_mutbl { + k - kind_const() + } + else { + k + } +} + +impl operators for kind { + fn &(other: kind) -> kind { + lower_kind(self, other) + } + + fn |(other: kind) -> kind { + raise_kind(self, other) + } + + fn -(other: kind) -> kind { + kind_(*self & !*other) + } +} + // Using these query functons is preferable to direct comparison or matching // against the kind constants, as we may modify the kind hierarchy in the // future. @@ -1306,7 +1336,7 @@ fn proto_kind(p: proto) -> kind { ast::proto_block { kind_noncopyable() } ast::proto_box { kind_copyable() } ast::proto_uniq { kind_sendable() } - ast::proto_bare { kind_sendable() } + ast::proto_bare { kind_sendable() | kind_const() } } } @@ -1345,7 +1375,7 @@ fn type_kind(cx: ctxt, ty: t) -> kind { let result = alt get(ty).struct { // Scalar and unique types are sendable ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | - ty_ptr(_) | ty_str { kind_sendable() } + ty_ptr(_) | ty_str { kind_sendable() | kind_const() } ty_type { kind_copyable() } ty_fn(f) { proto_kind(f.proto) } @@ -1356,30 +1386,50 @@ fn type_kind(cx: ctxt, ty: t) -> kind { // Those with refcounts raise noncopyable to copyable, // lower sendable to copyable. Therefore just set result to copyable. - ty_box(_) | ty_iface(_, _) | ty_opaque_box { kind_copyable() } + ty_box(tm) { + if tm.mutbl == ast::m_mutbl { + kind_copyable() + } + else { + let k = type_kind(cx, tm.ty); + if kind_lteq(kind_const(), k) { + kind_copyable() | kind_const() + } + else { kind_copyable() } + } + } + ty_iface(_, _) | ty_opaque_box { kind_copyable() } ty_rptr(_, _) { kind_copyable() } // Unique boxes and vecs have the kind of their contained type. - ty_vec(tm) | ty_uniq(tm) { type_kind(cx, tm.ty) } + ty_vec(tm) | ty_uniq(tm) { remove_const(type_kind(cx, tm.ty), tm) } // Slice and refcounted evecs are copyable; uniques and interiors // depend on the their contained type. - ty_evec(_, vstore_box) | - ty_evec(_, vstore_slice(_)) { kind_copyable() } + ty_evec(tm, vstore_box) | + ty_evec(tm, vstore_slice(_)) { + if kind_lteq(kind_const(), type_kind(cx, tm.ty)) { + kind_copyable() | kind_const() + } + else { + kind_const() + } + } ty_evec(tm, vstore_uniq) | - ty_evec(tm, vstore_fixed(_)) { type_kind(cx, tm.ty) } + ty_evec(tm, vstore_fixed(_)) { remove_const(type_kind(cx, tm.ty), tm) } // All estrs are copyable; uniques and interiors are sendable. ty_estr(vstore_box) | - ty_estr(vstore_slice(_)) { kind_copyable() } + ty_estr(vstore_slice(_)) { kind_copyable() | kind_const() } ty_estr(vstore_uniq) | - ty_estr(vstore_fixed(_)) { kind_sendable() } + ty_estr(vstore_fixed(_)) { kind_sendable() | kind_const() } // Records lower to the lowest of their members. ty_rec(flds) { - let mut lowest = kind_sendable(); + let mut lowest = kind_top(); for flds.each {|f| lowest = lower_kind(lowest, type_kind(cx, f.mt.ty)); + lowest = remove_const(lowest, f.mt); } lowest } @@ -1387,7 +1437,7 @@ fn type_kind(cx: ctxt, ty: t) -> kind { // sendable, but I'm just treating them like records (#1726) ty_class(did, substs) { // also factor out this code, copied from the records case - let mut lowest = kind_sendable(); + let mut lowest = kind_top(); let flds = class_items_as_fields(cx, did, substs); for flds.each {|f| lowest = lower_kind(lowest, type_kind(cx, f.mt.ty)); @@ -1396,13 +1446,13 @@ fn type_kind(cx: ctxt, ty: t) -> kind { } // Tuples lower to the lowest of their members. ty_tup(tys) { - let mut lowest = kind_sendable(); + let mut lowest = kind_top(); for tys.each {|ty| lowest = lower_kind(lowest, type_kind(cx, ty)); } lowest } // Enums lower to the lowest of their variants. ty_enum(did, substs) { - let mut lowest = kind_sendable(); + let mut lowest = kind_top(); let variants = enum_variants(cx, did); if vec::len(*variants) == 0u { lowest = kind_noncopyable(); @@ -1423,6 +1473,7 @@ fn type_kind(cx: ctxt, ty: t) -> kind { param_bounds_to_kind(cx.ty_param_bounds.get(did.node)) } ty_constr(t, _) { type_kind(cx, t) } + // FIXME: is self ever const? ty_self { kind_noncopyable() } ty_var(_) { cx.sess.bug("Asked to compute kind of a type variable"); } diff --git a/src/test/compile-fail/bad-method-typaram-kind.rs b/src/test/compile-fail/bad-method-typaram-kind.rs index a5070ac5698..55b259daf1e 100644 --- a/src/test/compile-fail/bad-method-typaram-kind.rs +++ b/src/test/compile-fail/bad-method-typaram-kind.rs @@ -1,6 +1,5 @@ -// error-pattern:instantiating a copyable type parameter with a noncopyable fn foo() { - 1u.bar::(); + 1u.bar::(); //! ERROR: missing `copy` } impl methods for uint { diff --git a/src/test/compile-fail/non-const.rs b/src/test/compile-fail/non-const.rs new file mode 100644 index 00000000000..193fdb4a16b --- /dev/null +++ b/src/test/compile-fail/non-const.rs @@ -0,0 +1,19 @@ +// Test that various non const things are rejected. + +fn foo(_x: T) { } + +resource r(_x: int) {} + +fn main() { + foo({f: 3}); + foo({mut f: 3}); //! ERROR missing `const` + foo([1]); + foo([mut 1]); //! ERROR missing `const` + foo(~1); + foo(~mut 1); //! ERROR missing `const` + foo(@1); + foo(@mut 1); //! ERROR missing `const` + foo(r(1)); //! ERROR missing `const` + foo("123"); + foo({f: {mut f: 1}}); //! ERROR missing `const` +} diff --git a/src/test/compile-fail/unique-unique-kind.rs b/src/test/compile-fail/unique-unique-kind.rs index 8845e15721f..9373ae70230 100644 --- a/src/test/compile-fail/unique-unique-kind.rs +++ b/src/test/compile-fail/unique-unique-kind.rs @@ -1,9 +1,7 @@ -// error-pattern: instantiating a sendable type parameter with a copyable type - -fn f(i: T) { +fn f(_i: T) { } fn main() { let i = ~@100; - f(i); -} \ No newline at end of file + f(i); //! ERROR missing `send` +} diff --git a/src/test/run-pass/const-bound.rs b/src/test/run-pass/const-bound.rs index 7b7b188c67e..ac532ea0569 100644 --- a/src/test/run-pass/const-bound.rs +++ b/src/test/run-pass/const-bound.rs @@ -10,4 +10,6 @@ fn main() { foo([1, 2, 3]); foo({field: 42}); foo((1, 2u)); + foo(@1); + foo(~1); }