Stop inferring bot/static when types/regions are unconstrained.
Also, some other changes that came up along the way: - add a 'blk' region for the current block. - detect unused type/region variables.
This commit is contained in:
parent
079c3b02a8
commit
2db4259b35
@ -14,7 +14,7 @@ native mod rustrt {
|
||||
fn rust_task_unweaken(ch: rust_port_id);
|
||||
}
|
||||
|
||||
type global_ptr<T: send> = *libc::uintptr_t;
|
||||
type global_ptr = *libc::uintptr_t;
|
||||
|
||||
#[doc = "
|
||||
Atomically gets a channel from a pointer to a pointer-sized memory location
|
||||
@ -22,7 +22,7 @@ or, if no channel exists creates and installs a new channel and sets up a new
|
||||
task to receive from it.
|
||||
"]
|
||||
unsafe fn chan_from_global_ptr<T: send>(
|
||||
global: global_ptr<T>,
|
||||
global: global_ptr,
|
||||
builder: fn() -> task::builder,
|
||||
f: fn~(comm::port<T>)
|
||||
) -> comm::chan<T> {
|
||||
|
@ -1168,7 +1168,9 @@ mod unsafe {
|
||||
#[inline(always)]
|
||||
unsafe fn form_slice<T,U>(p: *T, len: uint, f: fn([T]/&) -> U) -> U {
|
||||
let pair = (p, len * sys::size_of::<T>());
|
||||
let v : *([T]/&) = ::unsafe::reinterpret_cast(ptr::addr_of(pair));
|
||||
// FIXME: should use &blk not &static here, but a snapshot is req'd
|
||||
let v : *([T]/&static) =
|
||||
::unsafe::reinterpret_cast(ptr::addr_of(pair));
|
||||
f(*v)
|
||||
}
|
||||
}
|
||||
|
@ -452,11 +452,7 @@ enum prim_ty {
|
||||
type region = {id: node_id, node: region_};
|
||||
|
||||
#[auto_serialize]
|
||||
enum region_ {
|
||||
re_anon,
|
||||
re_named(ident),
|
||||
re_static
|
||||
}
|
||||
enum region_ { re_anon, re_named(ident) }
|
||||
|
||||
#[auto_serialize]
|
||||
enum ty_ {
|
||||
|
@ -250,16 +250,7 @@ fn parse_ret_ty(p: parser) -> (ast::ret_style, @ast::ty) {
|
||||
|
||||
fn region_from_name(p: parser, s: option<str>) -> @ast::region {
|
||||
let r = alt s {
|
||||
some (string) {
|
||||
// FIXME: To be consistent with our type resolution, the
|
||||
// static region should probably be resolved during type
|
||||
// checking, not in the parser. (Issue #2256)
|
||||
if string == "static" {
|
||||
ast::re_static
|
||||
} else {
|
||||
ast::re_named(string)
|
||||
}
|
||||
}
|
||||
some (string) { ast::re_named(string) }
|
||||
none { ast::re_anon }
|
||||
};
|
||||
|
||||
|
@ -329,7 +329,6 @@ fn print_native_mod(s: ps, nmod: ast::native_mod, attrs: [ast::attribute]) {
|
||||
fn print_region(s: ps, region: @ast::region) {
|
||||
alt region.node {
|
||||
ast::re_anon { word_space(s, "&"); }
|
||||
ast::re_static { word_space(s, "&static"); }
|
||||
ast::re_named(name) {
|
||||
word(s.s, "&");
|
||||
word_space(s, name);
|
||||
|
@ -251,23 +251,23 @@ fn find_library_crate_aux(sess: session::session,
|
||||
if !(str::starts_with(f, prefix) && str::ends_with(f, suffix)) {
|
||||
#debug("skipping %s, doesn't look like %s*%s", path, prefix,
|
||||
suffix);
|
||||
option::none
|
||||
option::none::<()>
|
||||
} else {
|
||||
#debug("%s is a candidate", path);
|
||||
alt get_metadata_section(sess, path) {
|
||||
option::some(cvec) {
|
||||
if !crate_matches(cvec, metas, hash) {
|
||||
#debug("skipping %s, metadata doesn't match", path);
|
||||
option::none
|
||||
option::none::<()>
|
||||
} else {
|
||||
#debug("found %s with matching metadata", path);
|
||||
matches += [{ident: path, data: cvec}];
|
||||
option::none
|
||||
option::none::<()>
|
||||
}
|
||||
}
|
||||
_ {
|
||||
#debug("could not load metadata for %s", path);
|
||||
option::none
|
||||
option::none::<()>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -579,11 +579,8 @@ impl unify_methods for infer_ctxt {
|
||||
// [B]. Deep resolution, on the other hand, would yield [int].
|
||||
//
|
||||
// But there is one more knob: the force_vars variable controls the
|
||||
// behavior in the face of unconstrained variables. If we have A, B
|
||||
// and only the constraint that A <: B, then the result is [_|_] if
|
||||
// force_vars is true and [B] otherwise. We use force_vars == true
|
||||
// when resolving types after typeck, but false otherwise (for
|
||||
// example, when pretty-printing them for errors).
|
||||
// behavior in the face of unconstrained variables. If it is true,
|
||||
// then unconstrained variables result in an error.
|
||||
|
||||
type resolve_state = @{
|
||||
infcx: infer_ctxt,
|
||||
@ -673,8 +670,12 @@ impl methods for resolve_state {
|
||||
let r1 = alt bounds {
|
||||
{ ub:_, lb:some(t) } { self.resolve_region(t) }
|
||||
{ ub:some(t), lb:_ } { self.resolve_region(t) }
|
||||
{ ub:none, lb:none } if self.force_vars { ty::re_static }
|
||||
{ ub:none, lb:none } { ty::re_var(rid) }
|
||||
{ ub:none, lb:none } {
|
||||
if self.force_vars {
|
||||
self.err = some(unresolved_region(rid));
|
||||
}
|
||||
ty::re_var(rid)
|
||||
}
|
||||
};
|
||||
vec::pop(self.r_seen);
|
||||
ret r1;
|
||||
@ -700,8 +701,12 @@ impl methods for resolve_state {
|
||||
{ ub:_, lb:some(t) } if !type_is_bot(t) { self.resolve1(t) }
|
||||
{ ub:some(t), lb:_ } { self.resolve1(t) }
|
||||
{ ub:_, lb:some(t) } { self.resolve1(t) }
|
||||
{ ub:none, lb:none } if self.force_vars { ty::mk_bot(tcx) }
|
||||
{ ub:none, lb:none } { ty::mk_var(tcx, vid) }
|
||||
{ ub:none, lb:none } {
|
||||
if self.force_vars {
|
||||
self.err = some(unresolved_ty(vid));
|
||||
}
|
||||
ty::mk_var(tcx, vid)
|
||||
}
|
||||
};
|
||||
vec::pop(self.v_seen);
|
||||
ret t1;
|
||||
|
@ -4,6 +4,7 @@ import syntax::codemap::span;
|
||||
import ty::{kind, kind_copyable, kind_sendable, kind_noncopyable};
|
||||
import driver::session::session;
|
||||
import std::map::hashmap;
|
||||
import syntax::print::pprust::expr_to_str;
|
||||
|
||||
// Kind analysis pass. There are three kinds:
|
||||
//
|
||||
@ -138,6 +139,7 @@ fn check_block(b: blk, cx: ctx, v: visit::vt<ctx>) {
|
||||
}
|
||||
|
||||
fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
|
||||
#debug["kind::check_expr(%s)", expr_to_str(e)];
|
||||
alt e.node {
|
||||
expr_assign(_, ex) | expr_assign_op(_, _, ex) |
|
||||
expr_unary(box(_), ex) | expr_unary(uniq(_), ex) |
|
||||
|
@ -37,7 +37,7 @@ export expr_ty_params_and_ty;
|
||||
export expr_is_lval;
|
||||
export field_ty;
|
||||
export fold_ty, fold_sty_to_ty, fold_region, fold_regions, fold_ty_var;
|
||||
export fold_regions_and_ty;
|
||||
export fold_regions_and_ty, walk_regions_and_ty;
|
||||
export field;
|
||||
export field_idx;
|
||||
export get_field;
|
||||
@ -97,7 +97,7 @@ export ty_tup, mk_tup;
|
||||
export ty_type, mk_type;
|
||||
export ty_uint, mk_uint, mk_mach_uint;
|
||||
export ty_uniq, mk_uniq, mk_imm_uniq, type_is_unique_box;
|
||||
export ty_var, mk_var;
|
||||
export ty_var, mk_var, type_is_var;
|
||||
export ty_self, mk_self;
|
||||
export region, bound_region;
|
||||
export get, type_has_params, type_has_vars, type_has_regions;
|
||||
@ -818,6 +818,21 @@ fn fold_ty_var(cx: ctxt, t0: t, fldop: fn(ty_vid) -> t) -> t {
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_regions_and_ty(
|
||||
cx: ctxt,
|
||||
ty: t,
|
||||
walkr: fn(r: region),
|
||||
walkt: fn(t: t) -> bool) {
|
||||
|
||||
if (walkt(ty)) {
|
||||
fold_regions_and_ty(
|
||||
cx, ty,
|
||||
{ |r| walkr(r); r },
|
||||
{ |t| walkt(t); walk_regions_and_ty(cx, t, walkr, walkt); t },
|
||||
{ |t| walkt(t); walk_regions_and_ty(cx, t, walkr, walkt); t });
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_regions_and_ty(
|
||||
cx: ctxt,
|
||||
ty: t,
|
||||
@ -1000,6 +1015,13 @@ fn type_is_nil(ty: t) -> bool { get(ty).struct == ty_nil }
|
||||
|
||||
fn type_is_bot(ty: t) -> bool { get(ty).struct == ty_bot }
|
||||
|
||||
fn type_is_var(ty: t) -> bool {
|
||||
alt get(ty).struct {
|
||||
ty_var(_) { true }
|
||||
_ { false }
|
||||
}
|
||||
}
|
||||
|
||||
fn type_is_bool(ty: t) -> bool { get(ty).struct == ty_bool }
|
||||
|
||||
fn type_is_structural(ty: t) -> bool {
|
||||
|
@ -105,6 +105,7 @@ type fn_ctxt =
|
||||
ty_var_counter: @mut uint,
|
||||
region_var_counter: @mut uint,
|
||||
|
||||
mut blocks: [ast::node_id], // stack of blocks in scope, may be empty
|
||||
in_scope_regions: isr_alist,
|
||||
|
||||
// While type checking a function, the intermediate types for the
|
||||
@ -276,10 +277,8 @@ fn instantiate_path(fcx: @fn_ctxt,
|
||||
|
||||
// Type tests
|
||||
fn structurally_resolved_type(fcx: @fn_ctxt, sp: span, tp: ty::t) -> ty::t {
|
||||
alt infer::resolve_shallow(fcx.infcx, tp, true) {
|
||||
// note: the bot type doesn't count as resolved; it's what we use when
|
||||
// there is no information about a variable.
|
||||
result::ok(t_s) if !ty::type_is_bot(t_s) { ret t_s; }
|
||||
alt infer::resolve_shallow(fcx.infcx, tp, false) {
|
||||
result::ok(t_s) if !ty::type_is_var(t_s) { ret t_s; }
|
||||
_ {
|
||||
fcx.ccx.tcx.sess.span_fatal
|
||||
(sp, "the type of this value must be known in this context");
|
||||
@ -322,7 +321,16 @@ fn ast_expr_vstore_to_vstore(fcx: @fn_ctxt, e: @ast::expr, n: uint,
|
||||
ast::vstore_uniq { ty::vstore_uniq }
|
||||
ast::vstore_box { ty::vstore_box }
|
||||
ast::vstore_slice(r) {
|
||||
ty::vstore_slice(ast_region_to_region(fcx, fcx, e.span, r))
|
||||
alt fcx.block_region() {
|
||||
result::ok(b_r) {
|
||||
let rscope = in_anon_rscope(fcx, b_r);
|
||||
ty::vstore_slice(ast_region_to_region(fcx, rscope, e.span, r))
|
||||
}
|
||||
result::err(msg) {
|
||||
fcx.ccx.tcx.sess.span_err(e.span, msg);
|
||||
ty::vstore_slice(ty::re_static)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -386,8 +394,9 @@ impl of region_scope for empty_rscope {
|
||||
fn anon_region() -> result<ty::region, str> {
|
||||
result::err("region types are not allowed here")
|
||||
}
|
||||
fn named_region(_id: str) -> result<ty::region, str> {
|
||||
result::err("region types are not allowed here")
|
||||
fn named_region(id: str) -> result<ty::region, str> {
|
||||
if id == "static" { result::ok(ty::re_static) }
|
||||
else { result::err("only the static region is allowed here") }
|
||||
}
|
||||
}
|
||||
|
||||
@ -395,9 +404,7 @@ enum type_rscope = ast::region_param;
|
||||
impl of region_scope for type_rscope {
|
||||
fn anon_region() -> result<ty::region, str> {
|
||||
alt *self {
|
||||
ast::rp_self {
|
||||
result::ok(ty::re_bound(ty::br_self))
|
||||
}
|
||||
ast::rp_self { result::ok(ty::re_bound(ty::br_self)) }
|
||||
ast::rp_none {
|
||||
result::err("to use region types here, the containing type \
|
||||
must be declared with a region bound")
|
||||
@ -405,11 +412,12 @@ impl of region_scope for type_rscope {
|
||||
}
|
||||
}
|
||||
fn named_region(id: str) -> result<ty::region, str> {
|
||||
if id == "self" {
|
||||
self.anon_region()
|
||||
} else {
|
||||
result::err("named regions other than `self` are not \
|
||||
allowed as part of a type declaration")
|
||||
empty_rscope.named_region(id).chain_err { |_e|
|
||||
if id == "self" { self.anon_region() }
|
||||
else {
|
||||
result::err("named regions other than `self` are not \
|
||||
allowed as part of a type declaration")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -419,11 +427,14 @@ impl of region_scope for @fn_ctxt {
|
||||
result::ok(self.next_region_var())
|
||||
}
|
||||
fn named_region(id: str) -> result<ty::region, str> {
|
||||
alt self.in_scope_regions.find(ty::br_named(id)) {
|
||||
some(r) { result::ok(r) }
|
||||
none {
|
||||
result::err(#fmt["named region `%s` not in scope here", id])
|
||||
}
|
||||
empty_rscope.named_region(id).chain_err { |_e|
|
||||
alt self.in_scope_regions.find(ty::br_named(id)) {
|
||||
some(r) { result::ok(r) }
|
||||
none if id == "blk" { self.block_region() }
|
||||
none {
|
||||
result::err(#fmt["named region `%s` not in scope here", id])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -477,7 +488,6 @@ fn ast_region_to_region<AC: ast_conv, RS: region_scope>(
|
||||
let res = alt a_r.node {
|
||||
ast::re_anon { rscope.anon_region() }
|
||||
ast::re_named(id) { rscope.named_region(id) }
|
||||
ast::re_static { result::ok(ty::re_static) }
|
||||
};
|
||||
|
||||
get_region_reporting_err(self.tcx(), span, res)
|
||||
@ -772,6 +782,49 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy>(
|
||||
ret typ;
|
||||
}
|
||||
|
||||
fn check_bounds_are_used(ccx: @crate_ctxt,
|
||||
span: span,
|
||||
tps: [ast::ty_param],
|
||||
rp: ast::region_param,
|
||||
ty: ty::t) {
|
||||
let mut r_used = alt rp {
|
||||
ast::rp_self { false }
|
||||
ast::rp_none { true }
|
||||
};
|
||||
|
||||
if tps.len() == 0u && r_used { ret; }
|
||||
let tps_used = vec::to_mut(vec::from_elem(tps.len(), false));
|
||||
|
||||
ty::walk_regions_and_ty(
|
||||
ccx.tcx, ty,
|
||||
{ |r|
|
||||
alt r {
|
||||
ty::re_bound(_) { r_used = true; }
|
||||
_ { }
|
||||
}
|
||||
},
|
||||
{ |t|
|
||||
alt ty::get(t).struct {
|
||||
ty::ty_param(idx, _) { tps_used[idx] = true; }
|
||||
_ { }
|
||||
}
|
||||
true
|
||||
});
|
||||
|
||||
if !r_used {
|
||||
ccx.tcx.sess.span_err(
|
||||
span, "lifetime `self` unused inside \
|
||||
reference-parameterized type.");
|
||||
}
|
||||
|
||||
for tps_used.eachi { |i, b|
|
||||
if !b {
|
||||
ccx.tcx.sess.span_err(
|
||||
span, #fmt["Type parameter %s is unused.", tps[i].ident]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn ty_of_item(ccx: @crate_ctxt, it: @ast::item)
|
||||
-> ty::ty_param_bounds_and_ty {
|
||||
|
||||
@ -816,6 +869,9 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item)
|
||||
};
|
||||
{bounds: ty_param_bounds(ccx, tps), rp: rp, ty: ty}
|
||||
};
|
||||
|
||||
check_bounds_are_used(ccx, t.span, tps, rp, tpt.ty);
|
||||
|
||||
tcx.tcache.insert(local_def(it.id), tpt);
|
||||
ret tpt;
|
||||
}
|
||||
@ -1125,6 +1181,12 @@ impl methods for @fn_ctxt {
|
||||
fn ty_to_str(t: ty::t) -> str {
|
||||
ty_to_str(self.ccx.tcx, resolve_type_vars_if_possible(self, t))
|
||||
}
|
||||
fn block_region() -> result<ty::region, str> {
|
||||
alt vec::last_opt(self.blocks) {
|
||||
some(bid) { result::ok(ty::re_scope(bid)) }
|
||||
none { result::err("no block is in scope here") }
|
||||
}
|
||||
}
|
||||
fn write_ty(node_id: ast::node_id, ty: ty::t) {
|
||||
#debug["write_ty(%d, %s) in fcx %s",
|
||||
node_id, ty_to_str(self.tcx(), ty), self.tag()];
|
||||
@ -3144,7 +3206,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
||||
-> option<O> {
|
||||
alt expected {
|
||||
some(t) {
|
||||
alt infer::resolve_shallow(fcx.infcx, t, true) {
|
||||
alt infer::resolve_shallow(fcx.infcx, t, false) {
|
||||
result::ok(t) { unpack(ty::get(t).struct) }
|
||||
_ { none }
|
||||
}
|
||||
@ -3913,6 +3975,7 @@ fn check_block(fcx0: @fn_ctxt, blk: ast::blk) -> bool {
|
||||
ast::unsafe_blk { @{purity: ast::unsafe_fn with *fcx0} }
|
||||
ast::default_blk { fcx0 }
|
||||
};
|
||||
vec::push(fcx.blocks, blk.node.id);
|
||||
let mut bot = false;
|
||||
let mut warned = false;
|
||||
for blk.node.stmts.each {|s|
|
||||
@ -3943,6 +4006,7 @@ fn check_block(fcx0: @fn_ctxt, blk: ast::blk) -> bool {
|
||||
if bot {
|
||||
fcx.write_bot(blk.node.id);
|
||||
}
|
||||
vec::pop(fcx.blocks);
|
||||
ret bot;
|
||||
}
|
||||
|
||||
@ -3960,6 +4024,7 @@ fn check_const(ccx: @crate_ctxt, _sp: span, e: @ast::expr, id: ast::node_id) {
|
||||
locals: int_hash(),
|
||||
ty_var_counter: @mut 0u,
|
||||
region_var_counter: @mut 0u,
|
||||
mut blocks: [],
|
||||
in_scope_regions: @nil,
|
||||
node_types: smallintmap::mk(),
|
||||
node_type_substs: map::int_hash(),
|
||||
@ -4000,6 +4065,7 @@ fn check_enum_variants(ccx: @crate_ctxt,
|
||||
locals: int_hash(),
|
||||
ty_var_counter: @mut 0u,
|
||||
region_var_counter: @mut 0u,
|
||||
mut blocks: [],
|
||||
in_scope_regions: @nil,
|
||||
node_types: smallintmap::mk(),
|
||||
node_type_substs: map::int_hash(),
|
||||
@ -4262,6 +4328,7 @@ fn check_fn(ccx: @crate_ctxt,
|
||||
locals: locals,
|
||||
ty_var_counter: tvc,
|
||||
region_var_counter: rvc,
|
||||
mut blocks: [],
|
||||
in_scope_regions: isr,
|
||||
node_types: node_types,
|
||||
node_type_substs: node_type_substs,
|
||||
@ -4350,21 +4417,27 @@ fn check_fn(ccx: @crate_ctxt,
|
||||
visit::visit_pat(p, e, v);
|
||||
};
|
||||
|
||||
let visit_block = fn@(b: ast::blk, &&e: (), v: visit::vt<()>) {
|
||||
vec::push(fcx.blocks, b.node.id);
|
||||
visit::visit_block(b, e, v);
|
||||
vec::pop(fcx.blocks);
|
||||
};
|
||||
|
||||
// Don't descend into fns and items
|
||||
fn visit_fn<T>(_fk: visit::fn_kind, _decl: ast::fn_decl,
|
||||
_body: ast::blk, _sp: span,
|
||||
_id: ast::node_id, _t: T, _v: visit::vt<T>) {
|
||||
fn visit_fn(_fk: visit::fn_kind, _decl: ast::fn_decl,
|
||||
_body: ast::blk, _sp: span,
|
||||
_id: ast::node_id, &&_t: (), _v: visit::vt<()>) {
|
||||
}
|
||||
fn visit_item<E>(_i: @ast::item, _e: E, _v: visit::vt<E>) { }
|
||||
fn visit_item(_i: @ast::item, &&_e: (), _v: visit::vt<()>) { }
|
||||
|
||||
let visit =
|
||||
@{visit_local: visit_local,
|
||||
visit_pat: visit_pat,
|
||||
visit_fn: bind visit_fn(_, _, _, _, _, _, _),
|
||||
visit_item: bind visit_item(_, _, _)
|
||||
with *visit::default_visitor()};
|
||||
let visit = visit::mk_vt(@{visit_local: visit_local,
|
||||
visit_pat: visit_pat,
|
||||
visit_fn: visit_fn,
|
||||
visit_item: visit_item,
|
||||
visit_block: visit_block
|
||||
with *visit::default_visitor()});
|
||||
|
||||
visit::visit_block(body, (), visit::mk_vt(visit));
|
||||
visit.visit_block(body, (), visit);
|
||||
}
|
||||
}
|
||||
|
||||
|
7
src/test/compile-fail/issue-1763.rs
Normal file
7
src/test/compile-fail/issue-1763.rs
Normal file
@ -0,0 +1,7 @@
|
||||
// Issue #1763 - infer types correctly
|
||||
|
||||
type actor<T> = { //! ERROR Type parameter T is unused.
|
||||
unused: bool
|
||||
};
|
||||
|
||||
fn main() {}
|
@ -1,5 +1,5 @@
|
||||
fn main(s: [str]) {
|
||||
let a = [];
|
||||
let a: [int] = [];
|
||||
vec::each(a) { |x| //! ERROR in function `anon`, not all control paths
|
||||
} //! ERROR see function return type of `bool`
|
||||
}
|
||||
|
3
src/test/compile-fail/region-unused.rs
Normal file
3
src/test/compile-fail/region-unused.rs
Normal file
@ -0,0 +1,3 @@
|
||||
type foo/& = {f: int}; //! ERROR lifetime `self` unused
|
||||
|
||||
fn main() {}
|
15
src/test/compile-fail/regions-blk.rs
Normal file
15
src/test/compile-fail/regions-blk.rs
Normal file
@ -0,0 +1,15 @@
|
||||
fn foo(cond: bool) {
|
||||
let x = 5;
|
||||
let mut y: &blk.int = &x;
|
||||
|
||||
let mut z: &blk.int;
|
||||
if cond {
|
||||
z = &x;
|
||||
} else {
|
||||
let w: &blk.int = &x;
|
||||
z = w; //! ERROR mismatched types
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
7
src/test/compile-fail/regions-in-consts.rs
Normal file
7
src/test/compile-fail/regions-in-consts.rs
Normal file
@ -0,0 +1,7 @@
|
||||
// xfail-test
|
||||
|
||||
const c_x: &blk.int = 22; //! ERROR only the static region is allowed here
|
||||
const c_y: &static.int = &22; //! ERROR only the static region is allowed here
|
||||
|
||||
fn main() {
|
||||
}
|
@ -18,7 +18,7 @@ type item_ty_yes1/& = {
|
||||
x: &self.uint
|
||||
};
|
||||
|
||||
type item_ty_yes2/& = {
|
||||
type item_ty_yes2/& = { //! ERROR lifetime `self` unused inside reference-parameterized type
|
||||
x: &foo.uint //! ERROR named regions other than `self` are not allowed as part of a type declaration
|
||||
};
|
||||
|
||||
|
13
src/test/compile-fail/regions-out-of-scope-slice.rs
Normal file
13
src/test/compile-fail/regions-out-of-scope-slice.rs
Normal file
@ -0,0 +1,13 @@
|
||||
// xfail-test
|
||||
|
||||
fn foo(cond: bool) {
|
||||
// Here we will infer a type that uses the
|
||||
// region of the if stmt then block, but in the scope:
|
||||
let mut x; //! ERROR foo
|
||||
|
||||
if cond {
|
||||
x = [1,2,3]/&blk;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
13
src/test/compile-fail/regions-var-type-out-of-scope.rs
Normal file
13
src/test/compile-fail/regions-var-type-out-of-scope.rs
Normal file
@ -0,0 +1,13 @@
|
||||
// xfail-test
|
||||
|
||||
fn foo(cond: bool) {
|
||||
// Here we will infer a type that uses the
|
||||
// region of the if stmt then block:
|
||||
let mut x; //! ERROR foo
|
||||
|
||||
if cond {
|
||||
x = &3;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -4,7 +4,8 @@ fn send<T: send>(ch: _chan<T>, -data: T) {
|
||||
log(debug, data);
|
||||
fail;
|
||||
}
|
||||
type _chan<T> = int;
|
||||
|
||||
enum _chan<T> = int;
|
||||
|
||||
// Tests that "log(debug, message);" is flagged as using
|
||||
// message after the send deinitializes it
|
||||
|
3
src/test/compile-fail/vector-no-ann.rs
Normal file
3
src/test/compile-fail/vector-no-ann.rs
Normal file
@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
let _foo = []; //! ERROR unconstrained type
|
||||
}
|
@ -4,7 +4,7 @@ fn test00_start(ch: chan_t<int>, message: int) { send(ch, copy message); }
|
||||
type task_id = int;
|
||||
type port_id = int;
|
||||
|
||||
type chan_t<T: send> = {task: task_id, port: port_id};
|
||||
enum chan_t<T: send> = {task: task_id, port: port_id};
|
||||
|
||||
fn send<T: send>(ch: chan_t<T>, -data: T) { fail; }
|
||||
|
||||
|
@ -1,14 +0,0 @@
|
||||
// Issue #1763 - infer types correctly
|
||||
// error-pattern:explicit failure
|
||||
|
||||
type actor<T> = {
|
||||
unused: bool
|
||||
};
|
||||
|
||||
fn act2<T>() -> actor<T> {
|
||||
fail;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let a: actor<int> = act2();
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
// error-pattern:get called on error result: "kitty"
|
||||
fn main() {
|
||||
log(error, result::get(result::err("kitty")));
|
||||
log(error, result::get(result::err::<int,str>("kitty")));
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
// xfail-test
|
||||
|
||||
// xfail-fast
|
||||
// aux-build:cci_class_6.rs
|
||||
use cci_class_6;
|
||||
|
@ -1,7 +1,8 @@
|
||||
fn main() {
|
||||
assert [1u, 3u].to_vec() == [1u, 3u];
|
||||
assert [].to_vec() == [];
|
||||
assert none.to_vec() == [];
|
||||
let e: [uint] = [];
|
||||
assert e.to_vec() == [];
|
||||
assert none::<uint>.to_vec() == [];
|
||||
assert some(1u).to_vec() == [1u];
|
||||
assert some(2u).to_vec() == [2u];
|
||||
}
|
@ -16,7 +16,7 @@ type ccx = {
|
||||
};
|
||||
|
||||
fn alloc(_bcx : &a.arena) -> &a.bcx unsafe {
|
||||
ret unsafe::reinterpret_cast(libc::malloc(sys::size_of::<bcx>()));
|
||||
ret unsafe::reinterpret_cast(libc::malloc(sys::size_of::<bcx/&blk>()));
|
||||
}
|
||||
|
||||
fn h(bcx : &a.bcx) -> &a.bcx {
|
||||
|
@ -8,7 +8,6 @@ fn call_id() {
|
||||
}
|
||||
|
||||
fn call_id_3() { id(ret) && id(ret); }
|
||||
//!^ ERROR the type of this value must be known
|
||||
|
||||
fn main() {
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
// xfail-pretty
|
||||
|
||||
fn id(x: bool) -> bool { x }
|
||||
|
||||
fn call_id() {
|
||||
let c <- fail;
|
||||
id(c);
|
||||
}
|
||||
|
||||
fn call_id_2() { id(true) && id(ret); }
|
||||
|
||||
fn call_id_4() { while id(ret) { } }
|
||||
|
||||
fn bind_id_1() { bind id(fail); }
|
||||
|
||||
fn bind_id_2() { bind id(ret); }
|
||||
|
||||
fn fail_fail() { fail fail; }
|
||||
|
||||
fn log_fail() { log(error, fail); }
|
||||
|
||||
fn log_ret() { log(error, ret); }
|
||||
|
||||
fn log_break() { loop { log(error, break); } }
|
||||
|
||||
fn log_cont() { do { log(error, cont); } while false }
|
||||
|
||||
fn ret_ret() -> int { ret 3 + (ret 2); }
|
||||
|
||||
fn ret_guard() {
|
||||
alt check 2 {
|
||||
x if (ret) { x; }
|
||||
}
|
||||
}
|
||||
|
||||
fn rec_ret() { let _r: {c: int} = {c: ret}; }
|
||||
|
||||
fn vec_ret() { let _v: [int] = [1, 2, ret, 4]; }
|
||||
|
||||
fn fail_then_concat() {
|
||||
let mut x = [], y = [3];
|
||||
fail;
|
||||
x += y;
|
||||
"good" + "bye";
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Call the functions that don't fail.
|
||||
rec_ret();
|
||||
vec_ret();
|
||||
ret_ret();
|
||||
log_ret();
|
||||
call_id_2();
|
||||
call_id_4();
|
||||
bind_id_2();
|
||||
ret_guard();
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
fn main() {
|
||||
// We will infer this to have the type vec[bot]
|
||||
let _foo = [];
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
// Just a grab bag of stuff that you wouldn't want to actually write.
|
||||
|
||||
fn strange() -> bool { let _x = ret true; }
|
||||
fn strange() -> bool { let _x: bool = ret true; }
|
||||
|
||||
fn funny() {
|
||||
fn f(_x: ()) { }
|
||||
@ -20,13 +20,14 @@ fn zombiejesus() {
|
||||
while (ret) {
|
||||
if (ret) {
|
||||
alt (ret) {
|
||||
_ {
|
||||
1 {
|
||||
if (ret) {
|
||||
ret
|
||||
} else {
|
||||
ret
|
||||
}
|
||||
}
|
||||
_ { ret }
|
||||
};
|
||||
} else if (ret) {
|
||||
ret;
|
||||
@ -51,7 +52,7 @@ fn canttouchthis() -> uint {
|
||||
pure fn p() -> bool { true }
|
||||
let _a = (assert (true)) == (check (p()));
|
||||
let _c = (check (p())) == ();
|
||||
let _b = (log(debug, 0) == (ret 0u));
|
||||
let _b: bool = (log(debug, 0) == (ret 0u));
|
||||
}
|
||||
|
||||
fn angrydome() {
|
||||
|
Loading…
Reference in New Issue
Block a user