new cap clause syntax
This commit is contained in:
parent
8affc78e8a
commit
50ec6bd2c3
31 changed files with 447 additions and 360 deletions
|
@ -154,11 +154,11 @@ fn steal(crate: ast::crate, tm: test_mode) -> stolen_stuff {
|
||||||
fn safe_to_replace_expr(e: ast::expr_, _tm: test_mode) -> bool {
|
fn safe_to_replace_expr(e: ast::expr_, _tm: test_mode) -> bool {
|
||||||
alt e {
|
alt e {
|
||||||
// https://github.com/mozilla/rust/issues/652
|
// https://github.com/mozilla/rust/issues/652
|
||||||
ast::expr_if(_, _, _) { false }
|
ast::expr_if(*) { false }
|
||||||
ast::expr_block(_) { false }
|
ast::expr_block(_) { false }
|
||||||
|
|
||||||
// expr_call is also missing a constraint
|
// expr_call is also missing a constraint
|
||||||
ast::expr_fn_block(_, _) { false }
|
ast::expr_fn_block(*) { false }
|
||||||
|
|
||||||
_ { true }
|
_ { true }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1096,6 +1096,14 @@ impl extensions<T> for [T] {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn map<U>(f: fn(T) -> U) -> [U] { map(self, f) }
|
fn map<U>(f: fn(T) -> U) -> [U] { map(self, f) }
|
||||||
#[doc = "
|
#[doc = "
|
||||||
|
Apply a function to the index and value of each element in the vector
|
||||||
|
and return the results
|
||||||
|
"]
|
||||||
|
fn mapi<U>(f: fn(uint, T) -> U) -> [U] {
|
||||||
|
let mut i = 0u;
|
||||||
|
self.map { |e| i += 1u; f(i - 1u, e) }
|
||||||
|
}
|
||||||
|
#[doc = "
|
||||||
Apply a function to each element of a vector and return a concatenation
|
Apply a function to each element of a vector and return a concatenation
|
||||||
of each result vector
|
of each result vector
|
||||||
"]
|
"]
|
||||||
|
|
|
@ -311,8 +311,8 @@ enum expr_ {
|
||||||
(implicit) condition is always true. */
|
(implicit) condition is always true. */
|
||||||
expr_loop(blk),
|
expr_loop(blk),
|
||||||
expr_alt(@expr, [arm], alt_mode),
|
expr_alt(@expr, [arm], alt_mode),
|
||||||
expr_fn(proto, fn_decl, blk, @capture_clause),
|
expr_fn(proto, fn_decl, blk, capture_clause),
|
||||||
expr_fn_block(fn_decl, blk),
|
expr_fn_block(fn_decl, blk, capture_clause),
|
||||||
// Inner expr is always an expr_fn_block. We need the wrapping node to
|
// Inner expr is always an expr_fn_block. We need the wrapping node to
|
||||||
// sanely type this (a function returning nil on the inside but bool on
|
// sanely type this (a function returning nil on the inside but bool on
|
||||||
// the outside).
|
// the outside).
|
||||||
|
@ -356,15 +356,13 @@ enum expr_ {
|
||||||
#[auto_serialize]
|
#[auto_serialize]
|
||||||
type capture_item = {
|
type capture_item = {
|
||||||
id: int,
|
id: int,
|
||||||
|
is_move: bool,
|
||||||
name: ident, // Currently, can only capture a local var.
|
name: ident, // Currently, can only capture a local var.
|
||||||
span: span
|
span: span
|
||||||
};
|
};
|
||||||
|
|
||||||
#[auto_serialize]
|
#[auto_serialize]
|
||||||
type capture_clause = {
|
type capture_clause = [capture_item];
|
||||||
copies: [@capture_item],
|
|
||||||
moves: [@capture_item]
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// Says whether this is a block the user marked as
|
// Says whether this is a block the user marked as
|
||||||
|
|
|
@ -456,8 +456,9 @@ fn noop_fold_expr(e: expr_, fld: ast_fold) -> expr_ {
|
||||||
expr_fn(proto, fold_fn_decl(decl, fld),
|
expr_fn(proto, fold_fn_decl(decl, fld),
|
||||||
fld.fold_block(body), captures)
|
fld.fold_block(body), captures)
|
||||||
}
|
}
|
||||||
expr_fn_block(decl, body) {
|
expr_fn_block(decl, body, captures) {
|
||||||
expr_fn_block(fold_fn_decl(decl, fld), fld.fold_block(body))
|
expr_fn_block(fold_fn_decl(decl, fld), fld.fold_block(body),
|
||||||
|
captures)
|
||||||
}
|
}
|
||||||
expr_block(blk) { expr_block(fld.fold_block(blk)) }
|
expr_block(blk) { expr_block(fld.fold_block(blk)) }
|
||||||
expr_move(el, er) {
|
expr_move(el, er) {
|
||||||
|
|
|
@ -398,15 +398,40 @@ fn parse_arg_mode(p: parser) -> ast::mode {
|
||||||
} else { ast::infer(p.get_id()) }
|
} else { ast::infer(p.get_id()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_arg(p: parser) -> ast::arg {
|
fn parse_capture_item_or(
|
||||||
|
p: parser,
|
||||||
|
parse_arg_fn: fn() -> arg_or_capture_item) -> arg_or_capture_item {
|
||||||
|
|
||||||
|
fn parse_capture_item(p: parser, is_move: bool) -> ast::capture_item {
|
||||||
|
let id = p.get_id();
|
||||||
|
let sp = mk_sp(p.span.lo, p.span.hi);
|
||||||
|
let ident = parse_ident(p);
|
||||||
|
{id: id, is_move: is_move, name: ident, span: sp}
|
||||||
|
}
|
||||||
|
|
||||||
|
if eat_keyword(p, "move") {
|
||||||
|
either::right(parse_capture_item(p, true))
|
||||||
|
} else if eat_keyword(p, "copy") {
|
||||||
|
either::right(parse_capture_item(p, false))
|
||||||
|
} else {
|
||||||
|
parse_arg_fn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_arg(p: parser) -> arg_or_capture_item {
|
||||||
let m = parse_arg_mode(p);
|
let m = parse_arg_mode(p);
|
||||||
let i = parse_value_ident(p);
|
let i = parse_value_ident(p);
|
||||||
expect(p, token::COLON);
|
expect(p, token::COLON);
|
||||||
let t = parse_ty(p, false);
|
let t = parse_ty(p, false);
|
||||||
ret {mode: m, ty: t, ident: i, id: p.get_id()};
|
either::left({mode: m, ty: t, ident: i, id: p.get_id()})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_fn_block_arg(p: parser) -> ast::arg {
|
fn parse_arg_or_capture_item(p: parser) -> arg_or_capture_item {
|
||||||
|
parse_capture_item_or(p) {|| parse_arg(p) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_fn_block_arg(p: parser) -> arg_or_capture_item {
|
||||||
|
parse_capture_item_or(p) {||
|
||||||
let m = parse_arg_mode(p);
|
let m = parse_arg_mode(p);
|
||||||
let i = parse_value_ident(p);
|
let i = parse_value_ident(p);
|
||||||
let t = if eat(p, token::COLON) {
|
let t = if eat(p, token::COLON) {
|
||||||
|
@ -416,7 +441,8 @@ fn parse_fn_block_arg(p: parser) -> ast::arg {
|
||||||
node: ast::ty_infer,
|
node: ast::ty_infer,
|
||||||
span: mk_sp(p.span.lo, p.span.hi)}
|
span: mk_sp(p.span.lo, p.span.hi)}
|
||||||
};
|
};
|
||||||
ret {mode: m, ty: t, ident: i, id: p.get_id()};
|
either::left({mode: m, ty: t, ident: i, id: p.get_id()})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maybe_parse_dollar_mac(p: parser) -> option<ast::mac_> {
|
fn maybe_parse_dollar_mac(p: parser) -> option<ast::mac_> {
|
||||||
|
@ -1149,74 +1175,27 @@ fn parse_if_expr(p: parser) -> @ast::expr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parses:
|
|
||||||
//
|
|
||||||
// CC := [copy ID*; move ID*]
|
|
||||||
//
|
|
||||||
// where any part is optional and trailing ; is permitted.
|
|
||||||
fn parse_capture_clause(p: parser) -> @ast::capture_clause {
|
|
||||||
fn expect_opt_trailing_semi(p: parser) {
|
|
||||||
if !eat(p, token::SEMI) {
|
|
||||||
if p.token != token::RBRACKET {
|
|
||||||
p.fatal("expecting ; or ]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eat_ident_list(p: parser) -> [@ast::capture_item] {
|
|
||||||
let mut res = [];
|
|
||||||
loop {
|
|
||||||
alt p.token {
|
|
||||||
token::IDENT(_, _) {
|
|
||||||
let id = p.get_id();
|
|
||||||
let sp = mk_sp(p.span.lo, p.span.hi);
|
|
||||||
let ident = parse_ident(p);
|
|
||||||
res += [@{id:id, name:ident, span:sp}];
|
|
||||||
if !eat(p, token::COMMA) {
|
|
||||||
ret res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_ { ret res; }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut copies = [];
|
|
||||||
let mut moves = [];
|
|
||||||
|
|
||||||
if eat(p, token::LBRACKET) {
|
|
||||||
while !eat(p, token::RBRACKET) {
|
|
||||||
if eat_keyword(p, "copy") {
|
|
||||||
copies += eat_ident_list(p);
|
|
||||||
expect_opt_trailing_semi(p);
|
|
||||||
} else if eat_keyword(p, "move") {
|
|
||||||
moves += eat_ident_list(p);
|
|
||||||
expect_opt_trailing_semi(p);
|
|
||||||
} else {
|
|
||||||
let s: str = "expecting send, copy, or move clause";
|
|
||||||
p.fatal(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret @{copies: copies, moves: moves};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_fn_expr(p: parser, proto: ast::proto) -> @ast::expr {
|
fn parse_fn_expr(p: parser, proto: ast::proto) -> @ast::expr {
|
||||||
let lo = p.last_span.lo;
|
let lo = p.last_span.lo;
|
||||||
let capture_clause = parse_capture_clause(p);
|
|
||||||
let decl = parse_fn_decl(p, ast::impure_fn);
|
let cc_old = parse_old_skool_capture_clause(p);
|
||||||
|
|
||||||
|
// if we want to allow fn expression argument types to be inferred in the
|
||||||
|
// future, just have to change parse_arg to parse_fn_block_arg.
|
||||||
|
let (decl, capture_clause) =
|
||||||
|
parse_fn_decl(p, ast::impure_fn, parse_arg_or_capture_item);
|
||||||
|
|
||||||
let body = parse_block(p);
|
let body = parse_block(p);
|
||||||
ret mk_expr(p, lo, body.span.hi,
|
ret mk_expr(p, lo, body.span.hi,
|
||||||
ast::expr_fn(proto, decl, body, capture_clause));
|
ast::expr_fn(proto, decl, body, capture_clause + cc_old));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_fn_block_expr(p: parser) -> @ast::expr {
|
fn parse_fn_block_expr(p: parser) -> @ast::expr {
|
||||||
let lo = p.last_span.lo;
|
let lo = p.last_span.lo;
|
||||||
let decl = parse_fn_block_decl(p);
|
let (decl, captures) = parse_fn_block_decl(p);
|
||||||
let body = parse_block_tail(p, lo, ast::default_blk);
|
let body = parse_block_tail(p, lo, ast::default_blk);
|
||||||
ret mk_expr(p, lo, body.span.hi, ast::expr_fn_block(decl, body));
|
ret mk_expr(p, lo, body.span.hi,
|
||||||
|
ast::expr_fn_block(decl, body, captures));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_else_expr(p: parser) -> @ast::expr {
|
fn parse_else_expr(p: parser) -> @ast::expr {
|
||||||
|
@ -1699,46 +1678,107 @@ fn parse_ty_params(p: parser) -> [ast::ty_param] {
|
||||||
} else { [] }
|
} else { [] }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_fn_decl(p: parser, purity: ast::purity)
|
// FIXME Remove after snapshot
|
||||||
-> ast::fn_decl {
|
fn parse_old_skool_capture_clause(p: parser) -> ast::capture_clause {
|
||||||
let inputs: ast::spanned<[ast::arg]> =
|
fn expect_opt_trailing_semi(p: parser) {
|
||||||
|
if !eat(p, token::SEMI) {
|
||||||
|
if p.token != token::RBRACKET {
|
||||||
|
p.fatal("expecting ; or ]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eat_ident_list(p: parser, is_move: bool) -> [ast::capture_item] {
|
||||||
|
let mut res = [];
|
||||||
|
loop {
|
||||||
|
alt p.token {
|
||||||
|
token::IDENT(_, _) {
|
||||||
|
let id = p.get_id();
|
||||||
|
let sp = mk_sp(p.span.lo, p.span.hi);
|
||||||
|
let ident = parse_ident(p);
|
||||||
|
res += [{id:id, is_move: is_move, name:ident, span:sp}];
|
||||||
|
if !eat(p, token::COMMA) {
|
||||||
|
ret res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ { ret res; }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut cap_items = [];
|
||||||
|
|
||||||
|
if eat(p, token::LBRACKET) {
|
||||||
|
while !eat(p, token::RBRACKET) {
|
||||||
|
if eat_keyword(p, "copy") {
|
||||||
|
cap_items += eat_ident_list(p, false);
|
||||||
|
expect_opt_trailing_semi(p);
|
||||||
|
} else if eat_keyword(p, "move") {
|
||||||
|
cap_items += eat_ident_list(p, true);
|
||||||
|
expect_opt_trailing_semi(p);
|
||||||
|
} else {
|
||||||
|
let s: str = "expecting send, copy, or move clause";
|
||||||
|
p.fatal(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret cap_items;
|
||||||
|
}
|
||||||
|
|
||||||
|
type arg_or_capture_item = either<ast::arg, ast::capture_item>;
|
||||||
|
|
||||||
|
|
||||||
|
fn parse_fn_decl(p: parser, purity: ast::purity,
|
||||||
|
parse_arg_fn: fn(parser) -> arg_or_capture_item)
|
||||||
|
-> (ast::fn_decl, ast::capture_clause) {
|
||||||
|
|
||||||
|
let args_or_capture_items: [arg_or_capture_item] =
|
||||||
parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA),
|
parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA),
|
||||||
parse_arg, p);
|
parse_arg_fn, p).node;
|
||||||
|
|
||||||
|
let inputs = either::lefts(args_or_capture_items);
|
||||||
|
let capture_clause = either::rights(args_or_capture_items);
|
||||||
|
|
||||||
// Use the args list to translate each bound variable
|
// Use the args list to translate each bound variable
|
||||||
// mentioned in a constraint to an arg index.
|
// mentioned in a constraint to an arg index.
|
||||||
// Seems weird to do this in the parser, but I'm not sure how else to.
|
// Seems weird to do this in the parser, but I'm not sure how else to.
|
||||||
let mut constrs = [];
|
let mut constrs = [];
|
||||||
if p.token == token::COLON {
|
if p.token == token::COLON {
|
||||||
p.bump();
|
p.bump();
|
||||||
constrs = parse_constrs({|x| parse_ty_constr(inputs.node, x) }, p);
|
constrs = parse_constrs({|x| parse_ty_constr(inputs, x) }, p);
|
||||||
}
|
}
|
||||||
let (ret_style, ret_ty) = parse_ret_ty(p);
|
let (ret_style, ret_ty) = parse_ret_ty(p);
|
||||||
ret {inputs: inputs.node,
|
ret ({inputs: inputs,
|
||||||
output: ret_ty,
|
output: ret_ty,
|
||||||
purity: purity,
|
purity: purity,
|
||||||
cf: ret_style,
|
cf: ret_style,
|
||||||
constraints: constrs};
|
constraints: constrs}, capture_clause);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_fn_block_decl(p: parser) -> ast::fn_decl {
|
fn parse_fn_block_decl(p: parser) -> (ast::fn_decl, ast::capture_clause) {
|
||||||
let inputs = if eat(p, token::OROR) {
|
let inputs_captures = {
|
||||||
|
if eat(p, token::OROR) {
|
||||||
[]
|
[]
|
||||||
} else {
|
} else {
|
||||||
parse_seq(token::BINOP(token::OR),
|
parse_seq(token::BINOP(token::OR),
|
||||||
token::BINOP(token::OR),
|
token::BINOP(token::OR),
|
||||||
seq_sep(token::COMMA),
|
seq_sep(token::COMMA),
|
||||||
parse_fn_block_arg, p).node
|
parse_fn_block_arg, p).node
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let output = if eat(p, token::RARROW) {
|
let output = if eat(p, token::RARROW) {
|
||||||
parse_ty(p, false)
|
parse_ty(p, false)
|
||||||
} else {
|
} else {
|
||||||
@{id: p.get_id(), node: ast::ty_infer, span: p.span}
|
@{id: p.get_id(), node: ast::ty_infer, span: p.span}
|
||||||
};
|
};
|
||||||
ret {inputs: inputs,
|
ret ({inputs: either::lefts(inputs_captures),
|
||||||
output: output,
|
output: output,
|
||||||
purity: ast::impure_fn,
|
purity: ast::impure_fn,
|
||||||
cf: ast::return_val,
|
cf: ast::return_val,
|
||||||
constraints: []};
|
constraints: []},
|
||||||
|
either::rights(inputs_captures));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_fn_header(p: parser) -> {ident: ast::ident, tps: [ast::ty_param]} {
|
fn parse_fn_header(p: parser) -> {ident: ast::ident, tps: [ast::ty_param]} {
|
||||||
|
@ -1760,7 +1800,7 @@ fn parse_item_fn(p: parser, purity: ast::purity,
|
||||||
attrs: [ast::attribute]) -> @ast::item {
|
attrs: [ast::attribute]) -> @ast::item {
|
||||||
let lo = p.last_span.lo;
|
let lo = p.last_span.lo;
|
||||||
let t = parse_fn_header(p);
|
let t = parse_fn_header(p);
|
||||||
let decl = parse_fn_decl(p, purity);
|
let (decl, _) = parse_fn_decl(p, purity, parse_arg);
|
||||||
let (inner_attrs, body) = parse_inner_attrs_and_block(p, true);
|
let (inner_attrs, body) = parse_inner_attrs_and_block(p, true);
|
||||||
let attrs = attrs + inner_attrs;
|
let attrs = attrs + inner_attrs;
|
||||||
ret mk_item(p, lo, body.span.hi, t.ident,
|
ret mk_item(p, lo, body.span.hi, t.ident,
|
||||||
|
@ -1785,7 +1825,7 @@ fn parse_method(p: parser, pr: ast::privacy) -> @ast::method {
|
||||||
let lo = p.span.lo, pur = parse_fn_purity(p);
|
let lo = p.span.lo, pur = parse_fn_purity(p);
|
||||||
let ident = parse_method_name(p);
|
let ident = parse_method_name(p);
|
||||||
let tps = parse_ty_params(p);
|
let tps = parse_ty_params(p);
|
||||||
let decl = parse_fn_decl(p, pur);
|
let (decl, _) = parse_fn_decl(p, pur, parse_arg);
|
||||||
let (inner_attrs, body) = parse_inner_attrs_and_block(p, true);
|
let (inner_attrs, body) = parse_inner_attrs_and_block(p, true);
|
||||||
let attrs = attrs + inner_attrs;
|
let attrs = attrs + inner_attrs;
|
||||||
@{ident: ident, attrs: attrs, tps: tps, decl: decl, body: body,
|
@{ident: ident, attrs: attrs, tps: tps, decl: decl, body: body,
|
||||||
|
@ -1969,7 +2009,7 @@ fn parse_class_item(p:parser, class_name_with_tps: @ast::path)
|
||||||
let lo = p.last_span.lo;
|
let lo = p.last_span.lo;
|
||||||
// Can ctors have attrs?
|
// Can ctors have attrs?
|
||||||
// result type is always the type of the class
|
// result type is always the type of the class
|
||||||
let decl_ = parse_fn_decl(p, ast::impure_fn);
|
let (decl_, _) = parse_fn_decl(p, ast::impure_fn, parse_arg);
|
||||||
let decl = {output: @{id: p.get_id(),
|
let decl = {output: @{id: p.get_id(),
|
||||||
node: ast::ty_path(class_name_with_tps, p.get_id()),
|
node: ast::ty_path(class_name_with_tps, p.get_id()),
|
||||||
span: decl_.output.span}
|
span: decl_.output.span}
|
||||||
|
@ -2048,7 +2088,7 @@ fn parse_item_native_fn(p: parser, attrs: [ast::attribute],
|
||||||
purity: ast::purity) -> @ast::native_item {
|
purity: ast::purity) -> @ast::native_item {
|
||||||
let lo = p.last_span.lo;
|
let lo = p.last_span.lo;
|
||||||
let t = parse_fn_header(p);
|
let t = parse_fn_header(p);
|
||||||
let decl = parse_fn_decl(p, purity);
|
let (decl, _) = parse_fn_decl(p, purity, parse_arg);
|
||||||
let mut hi = p.span.hi;
|
let mut hi = p.span.hi;
|
||||||
expect(p, token::SEMI);
|
expect(p, token::SEMI);
|
||||||
ret @{ident: t.ident,
|
ret @{ident: t.ident,
|
||||||
|
|
|
@ -519,7 +519,7 @@ fn print_item(s: ps, &&item: @ast::item) {
|
||||||
hardbreak_if_not_bol(s);
|
hardbreak_if_not_bol(s);
|
||||||
maybe_print_comment(s, ctor.span.lo);
|
maybe_print_comment(s, ctor.span.lo);
|
||||||
head(s, "new");
|
head(s, "new");
|
||||||
print_fn_args_and_ret(s, ctor.node.dec);
|
print_fn_args_and_ret(s, ctor.node.dec, []);
|
||||||
space(s.s);
|
space(s.s);
|
||||||
print_block(s, ctor.node.body);
|
print_block(s, ctor.node.body);
|
||||||
for items.each {|ci|
|
for items.each {|ci|
|
||||||
|
@ -1018,18 +1018,17 @@ fn print_expr(s: ps, &&expr: @ast::expr) {
|
||||||
// head-box, will be closed by print-block at start
|
// head-box, will be closed by print-block at start
|
||||||
ibox(s, 0u);
|
ibox(s, 0u);
|
||||||
word(s.s, proto_to_str(proto));
|
word(s.s, proto_to_str(proto));
|
||||||
print_cap_clause(s, *cap_clause);
|
print_fn_args_and_ret(s, decl, cap_clause);
|
||||||
print_fn_args_and_ret(s, decl);
|
|
||||||
space(s.s);
|
space(s.s);
|
||||||
print_block(s, body);
|
print_block(s, body);
|
||||||
}
|
}
|
||||||
ast::expr_fn_block(decl, body) {
|
ast::expr_fn_block(decl, body, cap_clause) {
|
||||||
// containing cbox, will be closed by print-block at }
|
// containing cbox, will be closed by print-block at }
|
||||||
cbox(s, indent_unit);
|
cbox(s, indent_unit);
|
||||||
// head-box, will be closed by print-block at start
|
// head-box, will be closed by print-block at start
|
||||||
ibox(s, 0u);
|
ibox(s, 0u);
|
||||||
word(s.s, "{");
|
word(s.s, "{");
|
||||||
print_fn_block_args(s, decl);
|
print_fn_block_args(s, decl, cap_clause);
|
||||||
print_possibly_embedded_block(s, body, block_block_fn, indent_unit);
|
print_possibly_embedded_block(s, body, block_block_fn, indent_unit);
|
||||||
}
|
}
|
||||||
ast::expr_loop_body(body) {
|
ast::expr_loop_body(body) {
|
||||||
|
@ -1319,46 +1318,27 @@ fn print_fn(s: ps, decl: ast::fn_decl, name: ast::ident,
|
||||||
}
|
}
|
||||||
word(s.s, name);
|
word(s.s, name);
|
||||||
print_type_params(s, typarams);
|
print_type_params(s, typarams);
|
||||||
print_fn_args_and_ret(s, decl);
|
print_fn_args_and_ret(s, decl, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_cap_clause(s: ps, cap_clause: ast::capture_clause) {
|
fn print_fn_args(s: ps, decl: ast::fn_decl,
|
||||||
fn print_cap_item(s: ps, &&cap_item: @ast::capture_item) {
|
cap_items: [ast::capture_item]) {
|
||||||
|
commasep(s, inconsistent, decl.inputs, print_arg);
|
||||||
|
if cap_items.is_not_empty() {
|
||||||
|
let mut first = decl.inputs.is_empty();
|
||||||
|
for cap_items.each { |cap_item|
|
||||||
|
if first { first = false; } else { word_space(s, ","); }
|
||||||
|
if cap_item.is_move { word_nbsp(s, "move") }
|
||||||
|
else { word_nbsp(s, "copy") }
|
||||||
word(s.s, cap_item.name);
|
word(s.s, cap_item.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
let has_copies = vec::is_not_empty(cap_clause.copies);
|
|
||||||
let has_moves = vec::is_not_empty(cap_clause.moves);
|
|
||||||
if !has_copies && !has_moves { ret; }
|
|
||||||
|
|
||||||
word(s.s, "[");
|
|
||||||
|
|
||||||
if has_copies {
|
|
||||||
word_nbsp(s, "copy");
|
|
||||||
commasep(s, inconsistent, cap_clause.copies, print_cap_item);
|
|
||||||
if has_moves {
|
|
||||||
word_space(s, ";");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if has_moves {
|
fn print_fn_args_and_ret(s: ps, decl: ast::fn_decl,
|
||||||
word_nbsp(s, "move");
|
cap_items: [ast::capture_item]) {
|
||||||
commasep(s, inconsistent, cap_clause.moves, print_cap_item);
|
|
||||||
}
|
|
||||||
|
|
||||||
word(s.s, "]");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_fn_args_and_ret(s: ps, decl: ast::fn_decl) {
|
|
||||||
popen(s);
|
popen(s);
|
||||||
fn print_arg(s: ps, x: ast::arg) {
|
print_fn_args(s, decl, cap_items);
|
||||||
ibox(s, indent_unit);
|
|
||||||
print_arg_mode(s, x.mode);
|
|
||||||
word_space(s, x.ident + ":");
|
|
||||||
print_type(s, x.ty);
|
|
||||||
end(s);
|
|
||||||
}
|
|
||||||
commasep(s, inconsistent, decl.inputs, print_arg);
|
|
||||||
pclose(s);
|
pclose(s);
|
||||||
word(s.s, constrs_str(decl.constraints, {|c|
|
word(s.s, constrs_str(decl.constraints, {|c|
|
||||||
ast_fn_constr_to_str(decl, c)
|
ast_fn_constr_to_str(decl, c)
|
||||||
|
@ -1372,19 +1352,10 @@ fn print_fn_args_and_ret(s: ps, decl: ast::fn_decl) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_fn_block_args(s: ps, decl: ast::fn_decl) {
|
fn print_fn_block_args(s: ps, decl: ast::fn_decl,
|
||||||
|
cap_items: [ast::capture_item]) {
|
||||||
word(s.s, "|");
|
word(s.s, "|");
|
||||||
fn print_arg(s: ps, x: ast::arg) {
|
print_fn_args(s, decl, cap_items);
|
||||||
ibox(s, indent_unit);
|
|
||||||
print_arg_mode(s, x.mode);
|
|
||||||
word(s.s, x.ident);
|
|
||||||
if x.ty.node != ast::ty_infer {
|
|
||||||
word_space(s, ":");
|
|
||||||
print_type(s, x.ty);
|
|
||||||
}
|
|
||||||
end(s);
|
|
||||||
}
|
|
||||||
commasep(s, inconsistent, decl.inputs, print_arg);
|
|
||||||
word(s.s, "|");
|
word(s.s, "|");
|
||||||
if decl.output.node != ast::ty_infer {
|
if decl.output.node != ast::ty_infer {
|
||||||
space_if_not_bol(s);
|
space_if_not_bol(s);
|
||||||
|
@ -1541,6 +1512,23 @@ fn print_mt(s: ps, mt: ast::mt) {
|
||||||
print_type(s, mt.ty);
|
print_type(s, mt.ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn print_arg(s: ps, input: ast::arg) {
|
||||||
|
ibox(s, indent_unit);
|
||||||
|
print_arg_mode(s, input.mode);
|
||||||
|
alt input.ty.node {
|
||||||
|
ast::ty_infer {
|
||||||
|
word(s.s, input.ident);
|
||||||
|
}
|
||||||
|
_ {
|
||||||
|
if str::len(input.ident) > 0u {
|
||||||
|
word_space(s, input.ident + ":");
|
||||||
|
}
|
||||||
|
print_type(s, input.ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end(s);
|
||||||
|
}
|
||||||
|
|
||||||
fn print_ty_fn(s: ps, opt_proto: option<ast::proto>,
|
fn print_ty_fn(s: ps, opt_proto: option<ast::proto>,
|
||||||
decl: ast::fn_decl, id: option<ast::ident>,
|
decl: ast::fn_decl, id: option<ast::ident>,
|
||||||
tps: option<[ast::ty_param]>) {
|
tps: option<[ast::ty_param]>) {
|
||||||
|
@ -1550,13 +1538,6 @@ fn print_ty_fn(s: ps, opt_proto: option<ast::proto>,
|
||||||
alt tps { some(tps) { print_type_params(s, tps); } _ { } }
|
alt tps { some(tps) { print_type_params(s, tps); } _ { } }
|
||||||
zerobreak(s.s);
|
zerobreak(s.s);
|
||||||
popen(s);
|
popen(s);
|
||||||
fn print_arg(s: ps, input: ast::arg) {
|
|
||||||
print_arg_mode(s, input.mode);
|
|
||||||
if str::len(input.ident) > 0u {
|
|
||||||
word_space(s, input.ident + ":");
|
|
||||||
}
|
|
||||||
print_type(s, input.ty);
|
|
||||||
}
|
|
||||||
commasep(s, inconsistent, decl.inputs, print_arg);
|
commasep(s, inconsistent, decl.inputs, print_arg);
|
||||||
pclose(s);
|
pclose(s);
|
||||||
maybe_print_comment(s, decl.output.span.lo);
|
maybe_print_comment(s, decl.output.span.lo);
|
||||||
|
|
|
@ -384,7 +384,7 @@ fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
|
||||||
expr_fn(proto, decl, body, _) {
|
expr_fn(proto, decl, body, _) {
|
||||||
v.visit_fn(fk_anon(proto), decl, body, ex.span, ex.id, e, v);
|
v.visit_fn(fk_anon(proto), decl, body, ex.span, ex.id, e, v);
|
||||||
}
|
}
|
||||||
expr_fn_block(decl, body) {
|
expr_fn_block(decl, body, _) {
|
||||||
v.visit_fn(fk_fn_block, decl, body, ex.span, ex.id, e, v);
|
v.visit_fn(fk_fn_block, decl, body, ex.span, ex.id, e, v);
|
||||||
}
|
}
|
||||||
expr_block(b) { v.visit_block(b, e, v); }
|
expr_block(b) { v.visit_block(b, e, v); }
|
||||||
|
|
|
@ -365,15 +365,10 @@ fn mk_test_wrapper(cx: test_ctxt,
|
||||||
rules: ast::default_blk
|
rules: ast::default_blk
|
||||||
});
|
});
|
||||||
|
|
||||||
let wrapper_capture: @ast::capture_clause = @{
|
|
||||||
copies: [],
|
|
||||||
moves: []
|
|
||||||
};
|
|
||||||
|
|
||||||
let wrapper_expr: ast::expr = {
|
let wrapper_expr: ast::expr = {
|
||||||
id: cx.sess.next_node_id(),
|
id: cx.sess.next_node_id(),
|
||||||
node: ast::expr_fn(ast::proto_bare, wrapper_decl,
|
node: ast::expr_fn(ast::proto_bare, wrapper_decl,
|
||||||
wrapper_body, wrapper_capture),
|
wrapper_body, []),
|
||||||
span: span
|
span: span
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -182,8 +182,8 @@ fn cant_copy(cx: ctx, b: binding) -> bool {
|
||||||
fn local_id_for_args(cx: ctx, args: [@ast::expr]) -> uint {
|
fn local_id_for_args(cx: ctx, args: [@ast::expr]) -> uint {
|
||||||
for vec::each(args) {|arg|
|
for vec::each(args) {|arg|
|
||||||
alt arg.node {
|
alt arg.node {
|
||||||
ast::expr_fn_block(decl, _) | ast::expr_fn(_, decl, _, _) |
|
ast::expr_fn_block(decl, _, _) | ast::expr_fn(_, decl, _, _) |
|
||||||
ast::expr_loop_body(@{node: ast::expr_fn_block(decl, _), _}) {
|
ast::expr_loop_body(@{node: ast::expr_fn_block(decl, _, _), _}) {
|
||||||
if decl.inputs.len() > 0u {
|
if decl.inputs.len() > 0u {
|
||||||
ret local_id_of_node(cx, decl.inputs[0].id);
|
ret local_id_of_node(cx, decl.inputs[0].id);
|
||||||
}
|
}
|
||||||
|
@ -216,7 +216,7 @@ fn check_call(cx: @ctx, sc: scope, f: @ast::expr, args: [@ast::expr],
|
||||||
ast::by_ref | ast::by_val | ast::by_move | ast::by_copy {}
|
ast::by_ref | ast::by_val | ast::by_move | ast::by_copy {}
|
||||||
}
|
}
|
||||||
alt arg.node {
|
alt arg.node {
|
||||||
ast::expr_fn_block(_, _) { blocks += [arg]; }
|
ast::expr_fn_block(*) { blocks += [arg]; }
|
||||||
ast::expr_loop_body(b) { blocks += [b]; }
|
ast::expr_loop_body(b) { blocks += [b]; }
|
||||||
_ {
|
_ {
|
||||||
let root_var = path_def_id(*cx, root.ex);
|
let root_var = path_def_id(*cx, root.ex);
|
||||||
|
@ -267,7 +267,7 @@ fn check_call(cx: @ctx, sc: scope, f: @ast::expr, args: [@ast::expr],
|
||||||
let mut_alias =
|
let mut_alias =
|
||||||
(ast::by_mutbl_ref == ty::arg_mode(cx.tcx, arg_t));
|
(ast::by_mutbl_ref == ty::arg_mode(cx.tcx, arg_t));
|
||||||
alt args[i].node {
|
alt args[i].node {
|
||||||
ast::expr_fn_block(_, _) | ast::expr_loop_body(_) {}
|
ast::expr_fn_block(*) | ast::expr_loop_body(_) {}
|
||||||
_ {
|
_ {
|
||||||
if i != j && ty_can_unsafely_include(
|
if i != j && ty_can_unsafely_include(
|
||||||
*cx, unsafe_ty, arg_t.ty, mut_alias) &&
|
*cx, unsafe_ty, arg_t.ty, mut_alias) &&
|
||||||
|
@ -306,7 +306,7 @@ fn check_call(cx: @ctx, sc: scope, f: @ast::expr, args: [@ast::expr],
|
||||||
let inner_sc = {bs: bindings + sc.bs, invalid: sc.invalid};
|
let inner_sc = {bs: bindings + sc.bs, invalid: sc.invalid};
|
||||||
for blocks.each {|blk|
|
for blocks.each {|blk|
|
||||||
alt check blk.node {
|
alt check blk.node {
|
||||||
ast::expr_fn_block(_, body) {
|
ast::expr_fn_block(_, body, _) {
|
||||||
v.visit_block(body, inner_sc, v);
|
v.visit_block(body, inner_sc, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ fn check_capture_clause(tcx: ty::ctxt,
|
||||||
let freevars = freevars::get_freevars(tcx, fn_expr_id);
|
let freevars = freevars::get_freevars(tcx, fn_expr_id);
|
||||||
let seen_defs = map::int_hash();
|
let seen_defs = map::int_hash();
|
||||||
|
|
||||||
let check_capture_item = fn@(&&cap_item: @ast::capture_item) {
|
let check_capture_item = fn@(cap_item: ast::capture_item) {
|
||||||
let cap_def = tcx.def_map.get(cap_item.id);
|
let cap_def = tcx.def_map.get(cap_item.id);
|
||||||
if !vec::any(*freevars, {|fv| fv.def == cap_def}) {
|
if !vec::any(*freevars, {|fv| fv.def == cap_def}) {
|
||||||
tcx.sess.span_warn(
|
tcx.sess.span_warn(
|
||||||
|
@ -54,36 +54,19 @@ fn check_capture_clause(tcx: ty::ctxt,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let check_not_upvar = fn@(&&cap_item: @ast::capture_item) {
|
alt fn_proto {
|
||||||
alt tcx.def_map.get(cap_item.id) {
|
ast::proto_any | ast::proto_block {
|
||||||
ast::def_upvar(_, _, _) {
|
if vec::is_not_empty(cap_clause) {
|
||||||
tcx.sess.span_err(
|
let cap_item0 = vec::head(cap_clause);
|
||||||
cap_item.span,
|
|
||||||
#fmt("upvars (like '%s') cannot be moved into a closure",
|
|
||||||
cap_item.name));
|
|
||||||
}
|
|
||||||
_ {}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let check_block_captures = fn@(v: [@ast::capture_item]) {
|
|
||||||
if check vec::is_not_empty(v) {
|
|
||||||
let cap_item0 = vec::head(v);
|
|
||||||
tcx.sess.span_err(
|
tcx.sess.span_err(
|
||||||
cap_item0.span,
|
cap_item0.span,
|
||||||
"cannot capture values explicitly with a block closure");
|
"cannot capture values explicitly with a block closure");
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
alt fn_proto {
|
|
||||||
ast::proto_any | ast::proto_block {
|
|
||||||
check_block_captures(cap_clause.copies);
|
|
||||||
check_block_captures(cap_clause.moves);
|
|
||||||
}
|
}
|
||||||
ast::proto_bare | ast::proto_box | ast::proto_uniq {
|
ast::proto_bare | ast::proto_box | ast::proto_uniq {
|
||||||
vec::iter(cap_clause.copies, check_capture_item);
|
for cap_clause.each { |cap_item|
|
||||||
vec::iter(cap_clause.moves, check_capture_item);
|
check_capture_item(cap_item);
|
||||||
vec::iter(cap_clause.moves, check_not_upvar);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,23 +78,30 @@ fn compute_capture_vars(tcx: ty::ctxt,
|
||||||
let freevars = freevars::get_freevars(tcx, fn_expr_id);
|
let freevars = freevars::get_freevars(tcx, fn_expr_id);
|
||||||
let cap_map = map::int_hash();
|
let cap_map = map::int_hash();
|
||||||
|
|
||||||
vec::iter(cap_clause.copies) { |cap_item|
|
// first add entries for anything explicitly named in the cap clause
|
||||||
let cap_def = tcx.def_map.get(cap_item.id);
|
|
||||||
let cap_def_id = ast_util::def_id_of_def(cap_def).node;
|
|
||||||
if vec::any(*freevars, {|fv| fv.def == cap_def}) {
|
|
||||||
cap_map.insert(cap_def_id, { def:cap_def, mode:cap_copy });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vec::iter(cap_clause.moves) { |cap_item|
|
for cap_clause.each { |cap_item|
|
||||||
let cap_def = tcx.def_map.get(cap_item.id);
|
let cap_def = tcx.def_map.get(cap_item.id);
|
||||||
let cap_def_id = ast_util::def_id_of_def(cap_def).node;
|
let cap_def_id = ast_util::def_id_of_def(cap_def).node;
|
||||||
|
if cap_item.is_move {
|
||||||
|
// if we are moving the value in, but it's not actually used,
|
||||||
|
// must drop it.
|
||||||
if vec::any(*freevars, {|fv| fv.def == cap_def}) {
|
if vec::any(*freevars, {|fv| fv.def == cap_def}) {
|
||||||
cap_map.insert(cap_def_id, { def:cap_def, mode:cap_move });
|
cap_map.insert(cap_def_id, { def:cap_def, mode:cap_move });
|
||||||
} else {
|
} else {
|
||||||
cap_map.insert(cap_def_id, { def:cap_def, mode:cap_drop });
|
cap_map.insert(cap_def_id, { def:cap_def, mode:cap_drop });
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// if we are copying the value in, but it's not actually used,
|
||||||
|
// just ignore it.
|
||||||
|
if vec::any(*freevars, {|fv| fv.def == cap_def}) {
|
||||||
|
cap_map.insert(cap_def_id, { def:cap_def, mode:cap_copy });
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now go through anything that is referenced but was not explicitly
|
||||||
|
// named and add that
|
||||||
|
|
||||||
let implicit_mode = alt fn_proto {
|
let implicit_mode = alt fn_proto {
|
||||||
ast::proto_any | ast::proto_block { cap_ref }
|
ast::proto_any | ast::proto_block { cap_ref }
|
||||||
|
|
|
@ -21,10 +21,10 @@ fn check_crate(tcx: ty::ctxt, crate: @crate) {
|
||||||
expr_fn(_, _, _, _) {
|
expr_fn(_, _, _, _) {
|
||||||
visit::visit_expr(e, {in_loop: false, can_ret: true}, v);
|
visit::visit_expr(e, {in_loop: false, can_ret: true}, v);
|
||||||
}
|
}
|
||||||
expr_fn_block(_, b) {
|
expr_fn_block(_, b, _) {
|
||||||
v.visit_block(b, {in_loop: false, can_ret: false}, v);
|
v.visit_block(b, {in_loop: false, can_ret: false}, v);
|
||||||
}
|
}
|
||||||
expr_loop_body(@{node: expr_fn_block(_, b), _}) {
|
expr_loop_body(@{node: expr_fn_block(_, b, _), _}) {
|
||||||
let blk = is_blockish(ty::ty_fn_proto(ty::expr_ty(tcx, e)));
|
let blk = is_blockish(ty::ty_fn_proto(ty::expr_ty(tcx, e)));
|
||||||
v.visit_block(b, {in_loop: true, can_ret: blk}, v);
|
v.visit_block(b, {in_loop: true, can_ret: blk}, v);
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,12 +40,12 @@ fn collect_freevars(def_map: resolve::def_map, blk: ast::blk)
|
||||||
|
|
||||||
let walk_expr = fn@(expr: @ast::expr, &&depth: int, v: visit::vt<int>) {
|
let walk_expr = fn@(expr: @ast::expr, &&depth: int, v: visit::vt<int>) {
|
||||||
alt expr.node {
|
alt expr.node {
|
||||||
ast::expr_fn(proto, decl, _, captures) {
|
ast::expr_fn(proto, decl, _, _) {
|
||||||
if proto != ast::proto_bare {
|
if proto != ast::proto_bare {
|
||||||
visit::visit_expr(expr, depth + 1, v);
|
visit::visit_expr(expr, depth + 1, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::expr_fn_block(_, _) {
|
ast::expr_fn_block(_, _, _) {
|
||||||
visit::visit_expr(expr, depth + 1, v);
|
visit::visit_expr(expr, depth + 1, v);
|
||||||
}
|
}
|
||||||
ast::expr_path(path) {
|
ast::expr_path(path) {
|
||||||
|
|
|
@ -117,16 +117,14 @@ fn check_fn_cap_clause(cx: ctx,
|
||||||
});
|
});
|
||||||
//log("freevar_ids", freevar_ids);
|
//log("freevar_ids", freevar_ids);
|
||||||
with_appropriate_checker(cx, id) { |checker|
|
with_appropriate_checker(cx, id) { |checker|
|
||||||
let check_var = fn@(&&cap_item: @capture_item) {
|
for cap_clause.each { |cap_item|
|
||||||
let cap_def = cx.tcx.def_map.get(cap_item.id);
|
let cap_def = cx.tcx.def_map.get(cap_item.id);
|
||||||
let cap_def_id = ast_util::def_id_of_def(cap_def).node;
|
let cap_def_id = ast_util::def_id_of_def(cap_def).node;
|
||||||
if !vec::contains(freevar_ids, cap_def_id) {
|
if !vec::contains(freevar_ids, cap_def_id) {
|
||||||
let ty = ty::node_id_to_type(cx.tcx, cap_def_id);
|
let ty = ty::node_id_to_type(cx.tcx, cap_def_id);
|
||||||
checker(cx, ty, cap_item.span);
|
checker(cx, ty, cap_item.span);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
vec::iter(cap_clause.copies, check_var);
|
|
||||||
vec::iter(cap_clause.moves, check_var);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,8 +225,8 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expr_fn(_, _, _, cap_clause) {
|
expr_fn(_, _, _, cap_clause) | expr_fn_block(_, _, cap_clause) {
|
||||||
check_fn_cap_clause(cx, e.id, *cap_clause);
|
check_fn_cap_clause(cx, e.id, cap_clause);
|
||||||
}
|
}
|
||||||
_ { }
|
_ { }
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,13 +154,16 @@ fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) {
|
||||||
v.visit_expr(dest, cx, v);
|
v.visit_expr(dest, cx, v);
|
||||||
clear_if_path(cx, dest, v, true);
|
clear_if_path(cx, dest, v, true);
|
||||||
}
|
}
|
||||||
|
expr_fn_block(_, _, cap_clause) |
|
||||||
expr_fn(_, _, _, cap_clause) {
|
expr_fn(_, _, _, cap_clause) {
|
||||||
// n.b.: safe to ignore copies, as if they are unused
|
// n.b.: safe to ignore copies, as if they are unused
|
||||||
// then they are ignored, otherwise they will show up
|
// then they are ignored, otherwise they will show up
|
||||||
// as freevars in the body.
|
// as freevars in the body.
|
||||||
vec::iter(cap_clause.moves) {|ci|
|
for cap_clause.each { |ci|
|
||||||
|
if ci.is_move {
|
||||||
clear_def_if_local(cx, cx.def_map.get(ci.id), false);
|
clear_def_if_local(cx, cx.def_map.get(ci.id), false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
visit::visit_expr(ex, cx, v);
|
visit::visit_expr(ex, cx, v);
|
||||||
}
|
}
|
||||||
expr_call(f, args, _) {
|
expr_call(f, args, _) {
|
||||||
|
@ -169,7 +172,7 @@ fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) {
|
||||||
let arg_ts = ty::ty_fn_args(ty::expr_ty(cx.tcx, f));
|
let arg_ts = ty::ty_fn_args(ty::expr_ty(cx.tcx, f));
|
||||||
vec::iter2(args, arg_ts) {|arg, arg_t|
|
vec::iter2(args, arg_ts) {|arg, arg_t|
|
||||||
alt arg.node {
|
alt arg.node {
|
||||||
expr_fn(_, _, _, _) | expr_fn_block(_, _)
|
expr_fn(*) | expr_fn_block(*)
|
||||||
if is_blockish(ty::ty_fn_proto(arg_t.ty)) {
|
if is_blockish(ty::ty_fn_proto(arg_t.ty)) {
|
||||||
fns += [arg];
|
fns += [arg];
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,16 +199,19 @@ fn visit_expr(ex: @expr, &&cx: @ctx, v: visit::vt<@ctx>) {
|
||||||
expr_assign(dest, src) | expr_assign_op(_, dest, src) {
|
expr_assign(dest, src) | expr_assign_op(_, dest, src) {
|
||||||
check_lval(cx, dest, msg_assign);
|
check_lval(cx, dest, msg_assign);
|
||||||
}
|
}
|
||||||
expr_fn(_, _, _, cap) {
|
expr_fn(_, _, _, cap_clause) | expr_fn_block(_, _, cap_clause) {
|
||||||
for cap.moves.each {|moved|
|
for cap_clause.each { |cap_item|
|
||||||
let def = cx.tcx.def_map.get(moved.id);
|
if cap_item.is_move {
|
||||||
|
let def = cx.tcx.def_map.get(cap_item.id);
|
||||||
alt is_illegal_to_modify_def(cx, def, msg_move_out) {
|
alt is_illegal_to_modify_def(cx, def, msg_move_out) {
|
||||||
some(name) { mk_err(cx, moved.span, msg_move_out, moved.name); }
|
some(name) { mk_err(cx, cap_item.span,
|
||||||
|
msg_move_out, name); }
|
||||||
_ { }
|
_ { }
|
||||||
}
|
}
|
||||||
cx.mutbl_map.insert(ast_util::def_id_of_def(def).node, ());
|
cx.mutbl_map.insert(ast_util::def_id_of_def(def).node, ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
_ { }
|
_ { }
|
||||||
}
|
}
|
||||||
visit::visit_expr(ex, cx, v);
|
visit::visit_expr(ex, cx, v);
|
||||||
|
|
|
@ -286,7 +286,7 @@ fn resolve_pat(pat: @ast::pat, cx: ctxt, visitor: visit::vt<ctxt>) {
|
||||||
fn resolve_expr(expr: @ast::expr, cx: ctxt, visitor: visit::vt<ctxt>) {
|
fn resolve_expr(expr: @ast::expr, cx: ctxt, visitor: visit::vt<ctxt>) {
|
||||||
record_parent(cx, expr.id);
|
record_parent(cx, expr.id);
|
||||||
alt expr.node {
|
alt expr.node {
|
||||||
ast::expr_fn(_, _, _, _) | ast::expr_fn_block(_, _) {
|
ast::expr_fn(*) | ast::expr_fn_block(*) {
|
||||||
let new_cx = {parent: some(expr.id) with cx};
|
let new_cx = {parent: some(expr.id) with cx};
|
||||||
visit::visit_expr(expr, new_cx, visitor);
|
visit::visit_expr(expr, new_cx, visitor);
|
||||||
}
|
}
|
||||||
|
|
|
@ -390,7 +390,7 @@ fn check_unused_imports(e: @env, level: lint::level) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_capture_item(e: @env, sc: scopes, &&cap_item: @ast::capture_item) {
|
fn resolve_capture_item(e: @env, sc: scopes, cap_item: ast::capture_item) {
|
||||||
let dcur = lookup_in_scope_strict(
|
let dcur = lookup_in_scope_strict(
|
||||||
*e, sc, cap_item.span, cap_item.name, ns_val);
|
*e, sc, cap_item.span, cap_item.name, ns_val);
|
||||||
maybe_insert(e, cap_item.id, dcur);
|
maybe_insert(e, cap_item.id, dcur);
|
||||||
|
@ -453,10 +453,11 @@ fn resolve_names(e: @env, c: @ast::crate) {
|
||||||
maybe_insert(e, exp.id,
|
maybe_insert(e, exp.id,
|
||||||
lookup_path_strict(*e, sc, exp.span, p, ns_val));
|
lookup_path_strict(*e, sc, exp.span, p, ns_val));
|
||||||
}
|
}
|
||||||
ast::expr_fn(_, _, _, cap_clause) {
|
ast::expr_fn(_, _, _, cap_clause) |
|
||||||
let rci = bind resolve_capture_item(e, sc, _);
|
ast::expr_fn_block(_, _, cap_clause) {
|
||||||
vec::iter(cap_clause.copies, rci);
|
for cap_clause.each { |ci|
|
||||||
vec::iter(cap_clause.moves, rci);
|
resolve_capture_item(e, sc, ci);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ { }
|
_ { }
|
||||||
}
|
}
|
||||||
|
|
|
@ -2544,11 +2544,11 @@ fn trans_cast(cx: block, e: @ast::expr, id: ast::node_id,
|
||||||
fn trans_loop_body(bcx: block, e: @ast::expr, ret_flag: option<ValueRef>,
|
fn trans_loop_body(bcx: block, e: @ast::expr, ret_flag: option<ValueRef>,
|
||||||
dest: dest) -> block {
|
dest: dest) -> block {
|
||||||
alt check e.node {
|
alt check e.node {
|
||||||
ast::expr_loop_body(b@@{node: ast::expr_fn_block(decl, body), _}) {
|
ast::expr_loop_body(b@@{node: ast::expr_fn_block(decl, body, cap), _}) {
|
||||||
alt check ty::get(expr_ty(bcx, e)).struct {
|
alt check ty::get(expr_ty(bcx, e)).struct {
|
||||||
ty::ty_fn({proto, _}) {
|
ty::ty_fn({proto, _}) {
|
||||||
closure::trans_expr_fn(bcx, proto, decl, body, e.span, b.id,
|
closure::trans_expr_fn(bcx, proto, decl, body, e.span, b.id,
|
||||||
{copies: [], moves: []}, some(ret_flag),
|
cap, some(ret_flag),
|
||||||
dest)
|
dest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2800,7 +2800,7 @@ fn trans_call_inner(in_cx: block, fn_expr_ty: ty::t, ret_ty: ty::t,
|
||||||
-> block {
|
-> block {
|
||||||
let ret_in_loop = alt args {
|
let ret_in_loop = alt args {
|
||||||
arg_exprs(args) { args.len() > 0u && alt vec::last(args).node {
|
arg_exprs(args) { args.len() > 0u && alt vec::last(args).node {
|
||||||
ast::expr_loop_body(@{node: ast::expr_fn_block(_, body), _}) {
|
ast::expr_loop_body(@{node: ast::expr_fn_block(_, body, _), _}) {
|
||||||
body_contains_ret(body)
|
body_contains_ret(body)
|
||||||
}
|
}
|
||||||
_ { false }
|
_ { false }
|
||||||
|
@ -3166,15 +3166,15 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block {
|
||||||
ast::expr_addr_of(_, x) { ret trans_addr_of(bcx, x, dest); }
|
ast::expr_addr_of(_, x) { ret trans_addr_of(bcx, x, dest); }
|
||||||
ast::expr_fn(proto, decl, body, cap_clause) {
|
ast::expr_fn(proto, decl, body, cap_clause) {
|
||||||
ret closure::trans_expr_fn(bcx, proto, decl, body, e.span, e.id,
|
ret closure::trans_expr_fn(bcx, proto, decl, body, e.span, e.id,
|
||||||
*cap_clause, none, dest);
|
cap_clause, none, dest);
|
||||||
}
|
}
|
||||||
ast::expr_fn_block(decl, body) {
|
ast::expr_fn_block(decl, body, cap_clause) {
|
||||||
alt check ty::get(expr_ty(bcx, e)).struct {
|
alt check ty::get(expr_ty(bcx, e)).struct {
|
||||||
ty::ty_fn({proto, _}) {
|
ty::ty_fn({proto, _}) {
|
||||||
#debug("translating fn_block %s with type %s",
|
#debug("translating fn_block %s with type %s",
|
||||||
expr_to_str(e), ty_to_str(tcx, expr_ty(bcx, e)));
|
expr_to_str(e), ty_to_str(tcx, expr_ty(bcx, e)));
|
||||||
ret closure::trans_expr_fn(bcx, proto, decl, body, e.span, e.id,
|
ret closure::trans_expr_fn(bcx, proto, decl, body, e.span, e.id,
|
||||||
{copies: [], moves: []}, none, dest);
|
cap_clause, none, dest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -772,7 +772,7 @@ fn create_function(fcx: fn_ctxt) -> @metadata<subprogram_md> {
|
||||||
ast::expr_fn(_, decl, _, _) {
|
ast::expr_fn(_, decl, _, _) {
|
||||||
(dbg_cx.names("fn"), decl.output, expr.id)
|
(dbg_cx.names("fn"), decl.output, expr.id)
|
||||||
}
|
}
|
||||||
ast::expr_fn_block(decl, _) {
|
ast::expr_fn_block(decl, _, _) {
|
||||||
(dbg_cx.names("fn"), decl.output, expr.id)
|
(dbg_cx.names("fn"), decl.output, expr.id)
|
||||||
}
|
}
|
||||||
_ { fcx.ccx.sess.span_bug(expr.span, "create_function: \
|
_ { fcx.ccx.sess.span_bug(expr.span, "create_function: \
|
||||||
|
|
|
@ -160,7 +160,7 @@ fn mark_for_expr(cx: ctx, e: @expr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expr_fn(_, _, _, _) | expr_fn_block(_, _) {
|
expr_fn(*) | expr_fn_block(*) {
|
||||||
alt ty::ty_fn_proto(ty::expr_ty(cx.ccx.tcx, e)) {
|
alt ty::ty_fn_proto(ty::expr_ty(cx.ccx.tcx, e)) {
|
||||||
proto_bare | proto_any | proto_uniq {}
|
proto_bare | proto_any | proto_uniq {}
|
||||||
proto_box | proto_block {
|
proto_box | proto_block {
|
||||||
|
|
|
@ -340,23 +340,20 @@ fn find_pre_post_expr(fcx: fn_ctxt, e: @expr) {
|
||||||
expr_log(_, lvl, arg) {
|
expr_log(_, lvl, arg) {
|
||||||
find_pre_post_exprs(fcx, [lvl, arg], e.id);
|
find_pre_post_exprs(fcx, [lvl, arg], e.id);
|
||||||
}
|
}
|
||||||
expr_fn(_, _, _, cap_clause) {
|
expr_fn(_, _, _, cap_clause) | expr_fn_block(_, _, cap_clause) {
|
||||||
find_pre_post_expr_fn_upvars(fcx, e);
|
find_pre_post_expr_fn_upvars(fcx, e);
|
||||||
|
|
||||||
let use_cap_item = fn@(&&cap_item: @capture_item) {
|
for cap_clause.each { |cap_item|
|
||||||
let d = local_node_id_to_local_def_id(fcx, cap_item.id);
|
let d = local_node_id_to_local_def_id(fcx, cap_item.id);
|
||||||
option::iter(d, { |id| use_var(fcx, id) });
|
option::iter(d, { |id| use_var(fcx, id) });
|
||||||
};
|
}
|
||||||
vec::iter(cap_clause.copies, use_cap_item);
|
|
||||||
vec::iter(cap_clause.moves, use_cap_item);
|
|
||||||
|
|
||||||
vec::iter(cap_clause.moves) { |cap_item|
|
for cap_clause.each { |cap_item|
|
||||||
|
if cap_item.is_move {
|
||||||
log(debug, ("forget_in_postcond: ", cap_item));
|
log(debug, ("forget_in_postcond: ", cap_item));
|
||||||
forget_in_postcond(fcx, e.id, cap_item.id);
|
forget_in_postcond(fcx, e.id, cap_item.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expr_fn_block(_, _) {
|
|
||||||
find_pre_post_expr_fn_upvars(fcx, e);
|
|
||||||
}
|
}
|
||||||
expr_block(b) {
|
expr_block(b) {
|
||||||
find_pre_post_block(fcx, b);
|
find_pre_post_block(fcx, b);
|
||||||
|
|
|
@ -363,9 +363,11 @@ fn find_pre_post_state_cap_clause(fcx: fn_ctxt, e_id: node_id,
|
||||||
let ccx = fcx.ccx;
|
let ccx = fcx.ccx;
|
||||||
let pres_changed = set_prestate_ann(ccx, e_id, pres);
|
let pres_changed = set_prestate_ann(ccx, e_id, pres);
|
||||||
let post = tritv_clone(pres);
|
let post = tritv_clone(pres);
|
||||||
vec::iter(cap_clause.moves) { |cap_item|
|
for cap_clause.each { |cap_item|
|
||||||
|
if cap_item.is_move {
|
||||||
forget_in_poststate(fcx, post, cap_item.id);
|
forget_in_poststate(fcx, post, cap_item.id);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ret set_poststate_ann(ccx, e_id, post) || pres_changed;
|
ret set_poststate_ann(ccx, e_id, post) || pres_changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,9 +420,11 @@ fn find_pre_post_state_expr(fcx: fn_ctxt, pres: prestate, e: @expr) -> bool {
|
||||||
expr_mac(_) { fcx.ccx.tcx.sess.bug("unexpanded macro"); }
|
expr_mac(_) { fcx.ccx.tcx.sess.bug("unexpanded macro"); }
|
||||||
expr_lit(l) { ret pure_exp(fcx.ccx, e.id, pres); }
|
expr_lit(l) { ret pure_exp(fcx.ccx, e.id, pres); }
|
||||||
expr_fn(_, _, _, cap_clause) {
|
expr_fn(_, _, _, cap_clause) {
|
||||||
ret find_pre_post_state_cap_clause(fcx, e.id, pres, *cap_clause);
|
ret find_pre_post_state_cap_clause(fcx, e.id, pres, cap_clause);
|
||||||
|
}
|
||||||
|
expr_fn_block(_, _, cap_clause) {
|
||||||
|
ret find_pre_post_state_cap_clause(fcx, e.id, pres, cap_clause);
|
||||||
}
|
}
|
||||||
expr_fn_block(_, _) { ret pure_exp(fcx.ccx, e.id, pres); }
|
|
||||||
expr_block(b) {
|
expr_block(b) {
|
||||||
ret find_pre_post_state_block(fcx, pres, b) |
|
ret find_pre_post_state_block(fcx, pres, b) |
|
||||||
set_prestate_ann(fcx.ccx, e.id, pres) |
|
set_prestate_ann(fcx.ccx, e.id, pres) |
|
||||||
|
|
|
@ -275,7 +275,8 @@ fn instantiate_path(fcx: @fn_ctxt,
|
||||||
fcx.write_ty_substs(id, tpt.ty, substs);
|
fcx.write_ty_substs(id, tpt.ty, substs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type tests
|
// Resolves `typ` by a single level if `typ` is a type variable. If no
|
||||||
|
// resolution is possible, then an error is reported.
|
||||||
fn structurally_resolved_type(fcx: @fn_ctxt, sp: span, tp: ty::t) -> ty::t {
|
fn structurally_resolved_type(fcx: @fn_ctxt, sp: span, tp: ty::t) -> ty::t {
|
||||||
alt infer::resolve_shallow(fcx.infcx, tp, false) {
|
alt infer::resolve_shallow(fcx.infcx, tp, false) {
|
||||||
result::ok(t_s) if !ty::type_is_var(t_s) { ret t_s; }
|
result::ok(t_s) if !ty::type_is_var(t_s) { ret t_s; }
|
||||||
|
@ -286,7 +287,6 @@ fn structurally_resolved_type(fcx: @fn_ctxt, sp: span, tp: ty::t) -> ty::t {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Returns the one-level-deep structure of the given type.
|
// Returns the one-level-deep structure of the given type.
|
||||||
fn structure_of(fcx: @fn_ctxt, sp: span, typ: ty::t) -> ty::sty {
|
fn structure_of(fcx: @fn_ctxt, sp: span, typ: ty::t) -> ty::sty {
|
||||||
ty::get(structurally_resolved_type(fcx, sp, typ)).struct
|
ty::get(structurally_resolved_type(fcx, sp, typ)).struct
|
||||||
|
@ -689,7 +689,7 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy>(
|
||||||
ty::mk_rec(tcx, flds)
|
ty::mk_rec(tcx, flds)
|
||||||
}
|
}
|
||||||
ast::ty_fn(proto, decl) {
|
ast::ty_fn(proto, decl) {
|
||||||
ty::mk_fn(tcx, ty_of_fn_decl(self, rscope, proto, decl))
|
ty::mk_fn(tcx, ty_of_fn_decl(self, rscope, proto, decl, none))
|
||||||
}
|
}
|
||||||
ast::ty_path(path, id) {
|
ast::ty_path(path, id) {
|
||||||
let a_def = alt tcx.def_map.find(id) {
|
let a_def = alt tcx.def_map.find(id) {
|
||||||
|
@ -777,7 +777,13 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy>(
|
||||||
ty::mk_constr(tcx, ast_ty_to_ty(self, rscope, t), out_cs)
|
ty::mk_constr(tcx, ast_ty_to_ty(self, rscope, t), out_cs)
|
||||||
}
|
}
|
||||||
ast::ty_infer {
|
ast::ty_infer {
|
||||||
self.ty_infer(ast_ty.span)
|
// ty_infer should only appear as the type of arguments or return
|
||||||
|
// values in a fn_expr, or as the type of local variables. Both of
|
||||||
|
// these cases are handled specially and should not descend into this
|
||||||
|
// routine.
|
||||||
|
self.tcx().sess.span_bug(
|
||||||
|
ast_ty.span,
|
||||||
|
"found `ty_infer` in unexpected place");
|
||||||
}
|
}
|
||||||
ast::ty_mac(_) {
|
ast::ty_mac(_) {
|
||||||
tcx.sess.span_bug(ast_ty.span,
|
tcx.sess.span_bug(ast_ty.span,
|
||||||
|
@ -850,7 +856,8 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item)
|
||||||
}
|
}
|
||||||
ast::item_fn(decl, tps, _) {
|
ast::item_fn(decl, tps, _) {
|
||||||
let bounds = ty_param_bounds(ccx, tps);
|
let bounds = ty_param_bounds(ccx, tps);
|
||||||
let tofd = ty_of_fn_decl(ccx, empty_rscope, ast::proto_bare, decl);
|
let tofd = ty_of_fn_decl(ccx, empty_rscope, ast::proto_bare,
|
||||||
|
decl, none);
|
||||||
let tpt = {bounds: bounds,
|
let tpt = {bounds: bounds,
|
||||||
rp: ast::rp_none, // functions do not have a self
|
rp: ast::rp_none, // functions do not have a self
|
||||||
ty: ty::mk_fn(ccx.tcx, tofd)};
|
ty: ty::mk_fn(ccx.tcx, tofd)};
|
||||||
|
@ -884,7 +891,8 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item)
|
||||||
}
|
}
|
||||||
ast::item_res(decl, tps, _, _, _, rp) {
|
ast::item_res(decl, tps, _, _, _, rp) {
|
||||||
let {bounds, substs} = mk_substs(ccx, tps, rp);
|
let {bounds, substs} = mk_substs(ccx, tps, rp);
|
||||||
let t_arg = ty_of_arg(ccx, type_rscope(rp), decl.inputs[0]);
|
let t_arg = ty_of_arg(ccx, type_rscope(rp),
|
||||||
|
decl.inputs[0], none);
|
||||||
let t = ty::mk_res(tcx, local_def(it.id), t_arg.ty, substs);
|
let t = ty::mk_res(tcx, local_def(it.id), t_arg.ty, substs);
|
||||||
let t_res = {bounds: bounds, rp: rp, ty: t};
|
let t_res = {bounds: bounds, rp: rp, ty: t};
|
||||||
tcx.tcache.insert(local_def(it.id), t_res);
|
tcx.tcache.insert(local_def(it.id), t_res);
|
||||||
|
@ -1027,16 +1035,27 @@ fn replace_bound_regions(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ty_of_arg<AC: ast_conv, RS: region_scope copy>(
|
fn ty_of_arg<AC: ast_conv, RS: region_scope copy>(
|
||||||
self: AC, rscope: RS, a: ast::arg) -> ty::arg {
|
self: AC, rscope: RS, a: ast::arg,
|
||||||
|
expected_ty: option<ty::arg>) -> ty::arg {
|
||||||
|
|
||||||
fn arg_mode(tcx: ty::ctxt, m: ast::mode, ty: ty::t) -> ast::mode {
|
let ty = alt a.ty.node {
|
||||||
alt m {
|
ast::ty_infer if expected_ty.is_some() {expected_ty.get().ty}
|
||||||
|
ast::ty_infer {self.ty_infer(a.ty.span)}
|
||||||
|
_ {ast_ty_to_ty(self, rscope, a.ty)}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mode = {
|
||||||
|
alt a.mode {
|
||||||
|
ast::infer(_) if expected_ty.is_some() {
|
||||||
|
result::get(ty::unify_mode(self.tcx(), a.mode,
|
||||||
|
expected_ty.get().mode))
|
||||||
|
}
|
||||||
ast::infer(_) {
|
ast::infer(_) {
|
||||||
alt ty::get(ty).struct {
|
alt ty::get(ty).struct {
|
||||||
// If the type is not specified, then this must be a fn expr.
|
// If the type is not specified, then this must be a fn expr.
|
||||||
// Leave the mode as infer(_), it will get inferred based
|
// Leave the mode as infer(_), it will get inferred based
|
||||||
// on constraints elsewhere.
|
// on constraints elsewhere.
|
||||||
ty::ty_var(_) { m }
|
ty::ty_var(_) {a.mode}
|
||||||
|
|
||||||
// If the type is known, then use the default for that type.
|
// If the type is known, then use the default for that type.
|
||||||
// Here we unify m and the default. This should update the
|
// Here we unify m and the default. This should update the
|
||||||
|
@ -1044,30 +1063,48 @@ fn ty_of_arg<AC: ast_conv, RS: region_scope copy>(
|
||||||
// will have been unified with m yet:
|
// will have been unified with m yet:
|
||||||
_ {
|
_ {
|
||||||
let m1 = ast::expl(ty::default_arg_mode_for_ty(ty));
|
let m1 = ast::expl(ty::default_arg_mode_for_ty(ty));
|
||||||
result::get(ty::unify_mode(tcx, m, m1))
|
result::get(ty::unify_mode(self.tcx(), a.mode, m1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::expl(_) { m }
|
ast::expl(_) {a.mode}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let ty = ast_ty_to_ty(self, rscope, a.ty);
|
|
||||||
let mode = arg_mode(self.tcx(), a.mode, ty);
|
|
||||||
{mode: mode, ty: ty}
|
{mode: mode, ty: ty}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type expected_tys = option<{inputs: [ty::arg],
|
||||||
|
output: ty::t}>;
|
||||||
|
|
||||||
fn ty_of_fn_decl<AC: ast_conv, RS: region_scope copy>(
|
fn ty_of_fn_decl<AC: ast_conv, RS: region_scope copy>(
|
||||||
self: AC, rscope: RS,
|
self: AC, rscope: RS,
|
||||||
proto: ast::proto,
|
proto: ast::proto,
|
||||||
decl: ast::fn_decl) -> ty::fn_ty {
|
decl: ast::fn_decl,
|
||||||
|
expected_tys: expected_tys) -> ty::fn_ty {
|
||||||
|
|
||||||
#debug["ty_of_fn_decl"];
|
#debug["ty_of_fn_decl"];
|
||||||
indent {||
|
indent {||
|
||||||
// new region names that appear inside of the fn decl are bound to
|
// new region names that appear inside of the fn decl are bound to
|
||||||
// that function type
|
// that function type
|
||||||
let rb = in_binding_rscope(rscope);
|
let rb = in_binding_rscope(rscope);
|
||||||
let input_tys = vec::map(decl.inputs) { |a| ty_of_arg(self, rb, a) };
|
|
||||||
let output_ty = ast_ty_to_ty(self, rb, decl.output);
|
let input_tys = decl.inputs.mapi { |i, a|
|
||||||
|
let expected_arg_ty = expected_tys.chain { |e|
|
||||||
|
// no guarantee that the correct number of expected args
|
||||||
|
// were supplied
|
||||||
|
if i < e.inputs.len() {some(e.inputs[i])} else {none}
|
||||||
|
};
|
||||||
|
ty_of_arg(self, rb, a, expected_arg_ty)
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected_ret_ty = expected_tys.map { |e| e.output };
|
||||||
|
let output_ty = alt decl.output.node {
|
||||||
|
ast::ty_infer if expected_ret_ty.is_some() {expected_ret_ty.get()}
|
||||||
|
ast::ty_infer {self.ty_infer(decl.output.span)}
|
||||||
|
_ {ast_ty_to_ty(self, rb, decl.output)}
|
||||||
|
};
|
||||||
|
|
||||||
let out_constrs = vec::map(decl.constraints) {|constr|
|
let out_constrs = vec::map(decl.constraints) {|constr|
|
||||||
ty::ast_constr_to_constr(self.tcx(), constr)
|
ty::ast_constr_to_constr(self.tcx(), constr)
|
||||||
};
|
};
|
||||||
|
@ -1083,7 +1120,7 @@ fn ty_of_native_fn_decl(ccx: @crate_ctxt,
|
||||||
|
|
||||||
let bounds = ty_param_bounds(ccx, ty_params);
|
let bounds = ty_param_bounds(ccx, ty_params);
|
||||||
let rb = in_binding_rscope(empty_rscope);
|
let rb = in_binding_rscope(empty_rscope);
|
||||||
let input_tys = vec::map(decl.inputs) { |a| ty_of_arg(ccx, rb, a) };
|
let input_tys = decl.inputs.map { |a| ty_of_arg(ccx, rb, a, none) };
|
||||||
let output_ty = ast_ty_to_ty(ccx, rb, decl.output);
|
let output_ty = ast_ty_to_ty(ccx, rb, decl.output);
|
||||||
|
|
||||||
let t_fn = ty::mk_fn(ccx.tcx, {proto: ast::proto_bare,
|
let t_fn = ty::mk_fn(ccx.tcx, {proto: ast::proto_bare,
|
||||||
|
@ -1135,7 +1172,8 @@ fn ty_of_method(ccx: @crate_ctxt,
|
||||||
rp: ast::region_param) -> ty::method {
|
rp: ast::region_param) -> ty::method {
|
||||||
{ident: m.ident,
|
{ident: m.ident,
|
||||||
tps: ty_param_bounds(ccx, m.tps),
|
tps: ty_param_bounds(ccx, m.tps),
|
||||||
fty: ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare, m.decl),
|
fty: ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare,
|
||||||
|
m.decl, none),
|
||||||
purity: m.decl.purity,
|
purity: m.decl.purity,
|
||||||
privacy: m.privacy}
|
privacy: m.privacy}
|
||||||
}
|
}
|
||||||
|
@ -1145,7 +1183,8 @@ fn ty_of_ty_method(self: @crate_ctxt,
|
||||||
rp: ast::region_param) -> ty::method {
|
rp: ast::region_param) -> ty::method {
|
||||||
{ident: m.ident,
|
{ident: m.ident,
|
||||||
tps: ty_param_bounds(self, m.tps),
|
tps: ty_param_bounds(self, m.tps),
|
||||||
fty: ty_of_fn_decl(self, type_rscope(rp), ast::proto_bare, m.decl),
|
fty: ty_of_fn_decl(self, type_rscope(rp), ast::proto_bare,
|
||||||
|
m.decl, none),
|
||||||
// assume public, because this is only invoked on iface methods
|
// assume public, because this is only invoked on iface methods
|
||||||
purity: m.decl.purity, privacy: ast::pub}
|
purity: m.decl.purity, privacy: ast::pub}
|
||||||
}
|
}
|
||||||
|
@ -1649,7 +1688,8 @@ mod collect {
|
||||||
ast::item_res(decl, tps, _, dtor_id, ctor_id, rp) {
|
ast::item_res(decl, tps, _, dtor_id, ctor_id, rp) {
|
||||||
let {bounds, substs} = mk_substs(ccx, tps, rp);
|
let {bounds, substs} = mk_substs(ccx, tps, rp);
|
||||||
let def_id = local_def(it.id);
|
let def_id = local_def(it.id);
|
||||||
let t_arg = ty_of_arg(ccx, type_rscope(rp), decl.inputs[0]);
|
let t_arg = ty_of_arg(ccx, type_rscope(rp),
|
||||||
|
decl.inputs[0], none);
|
||||||
let t_res = ty::mk_res(tcx, def_id, t_arg.ty, substs);
|
let t_res = ty::mk_res(tcx, def_id, t_arg.ty, substs);
|
||||||
|
|
||||||
let t_ctor = ty::mk_fn(tcx, {
|
let t_ctor = ty::mk_fn(tcx, {
|
||||||
|
@ -1691,7 +1731,8 @@ mod collect {
|
||||||
ty_of_fn_decl(ccx,
|
ty_of_fn_decl(ccx,
|
||||||
empty_rscope,
|
empty_rscope,
|
||||||
ast::proto_any,
|
ast::proto_any,
|
||||||
ctor.node.dec));
|
ctor.node.dec,
|
||||||
|
none));
|
||||||
write_ty_to_tcx(tcx, ctor.node.id, t_ctor);
|
write_ty_to_tcx(tcx, ctor.node.id, t_ctor);
|
||||||
tcx.tcache.insert(local_def(ctor.node.id),
|
tcx.tcache.insert(local_def(ctor.node.id),
|
||||||
{bounds: tpt.bounds,
|
{bounds: tpt.bounds,
|
||||||
|
@ -1961,7 +2002,7 @@ mod writeback {
|
||||||
resolve_type_vars_for_node(wbcx, e.span, e.id);
|
resolve_type_vars_for_node(wbcx, e.span, e.id);
|
||||||
alt e.node {
|
alt e.node {
|
||||||
ast::expr_fn(_, decl, _, _) |
|
ast::expr_fn(_, decl, _, _) |
|
||||||
ast::expr_fn_block(decl, _) {
|
ast::expr_fn_block(decl, _, _) {
|
||||||
vec::iter(decl.inputs) {|input|
|
vec::iter(decl.inputs) {|input|
|
||||||
let r_ty = resolve_type_vars_for_node(wbcx, e.span, input.id);
|
let r_ty = resolve_type_vars_for_node(wbcx, e.span, input.id);
|
||||||
|
|
||||||
|
@ -2902,35 +2943,6 @@ fn region_of(fcx: @fn_ctxt, expr: @ast::expr) -> ty::region {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_expr_fn_with_unifier(fcx: @fn_ctxt,
|
|
||||||
expr: @ast::expr,
|
|
||||||
proto: ast::proto,
|
|
||||||
decl: ast::fn_decl,
|
|
||||||
body: ast::blk,
|
|
||||||
is_loop_body: bool,
|
|
||||||
unifier: fn()) {
|
|
||||||
let tcx = fcx.ccx.tcx;
|
|
||||||
let fty = ty::mk_fn(tcx, ty_of_fn_decl(fcx, fcx, proto, decl));
|
|
||||||
|
|
||||||
#debug("check_expr_fn_with_unifier %s fty=%s",
|
|
||||||
expr_to_str(expr), fcx.ty_to_str(fty));
|
|
||||||
|
|
||||||
fcx.write_ty(expr.id, fty);
|
|
||||||
|
|
||||||
// Unify the type of the function with the expected type before we
|
|
||||||
// typecheck the body so that we have more information about the
|
|
||||||
// argument types in the body. This is needed to make binops and
|
|
||||||
// record projection work on type inferred arguments.
|
|
||||||
unifier();
|
|
||||||
|
|
||||||
let ret_ty = ty::ty_fn_ret(fty);
|
|
||||||
let arg_tys = vec::map(ty::ty_fn_args(fty)) {|a| a.ty };
|
|
||||||
|
|
||||||
check_fn(fcx.ccx, proto, decl, body, expr.id,
|
|
||||||
ret_ty, arg_tys, is_loop_body, some(fcx),
|
|
||||||
fcx.self_ty);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_expr_with_unifier(fcx: @fn_ctxt,
|
fn check_expr_with_unifier(fcx: @fn_ctxt,
|
||||||
expr: @ast::expr,
|
expr: @ast::expr,
|
||||||
expected: option<ty::t>,
|
expected: option<ty::t>,
|
||||||
|
@ -2999,7 +3011,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
||||||
alt a_opt {
|
alt a_opt {
|
||||||
some(a) {
|
some(a) {
|
||||||
let is_block = alt a.node {
|
let is_block = alt a.node {
|
||||||
ast::expr_fn_block(_, _) { true }
|
ast::expr_fn_block(*) { true }
|
||||||
_ { false }
|
_ { false }
|
||||||
};
|
};
|
||||||
if is_block == check_blocks {
|
if is_block == check_blocks {
|
||||||
|
@ -3227,6 +3239,11 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resolves `expected` by a single level if it is a variable and passes it
|
||||||
|
// through the `unpack` function. It there is no expected type or
|
||||||
|
// resolution is not possible (e.g., no constraints yet present), just
|
||||||
|
// returns `none`.
|
||||||
fn unpack_expected<O: copy>(fcx: @fn_ctxt, expected: option<ty::t>,
|
fn unpack_expected<O: copy>(fcx: @fn_ctxt, expected: option<ty::t>,
|
||||||
unpack: fn(ty::sty) -> option<O>)
|
unpack: fn(ty::sty) -> option<O>)
|
||||||
-> option<O> {
|
-> option<O> {
|
||||||
|
@ -3241,6 +3258,42 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_expr_fn(fcx: @fn_ctxt,
|
||||||
|
expr: @ast::expr,
|
||||||
|
proto: ast::proto,
|
||||||
|
decl: ast::fn_decl,
|
||||||
|
body: ast::blk,
|
||||||
|
is_loop_body: bool,
|
||||||
|
expected: option<ty::t>) {
|
||||||
|
let tcx = fcx.ccx.tcx;
|
||||||
|
|
||||||
|
let expected_tys = unpack_expected(fcx, expected) { |sty|
|
||||||
|
alt sty {
|
||||||
|
ty::ty_fn(fn_ty) {some({inputs:fn_ty.inputs,
|
||||||
|
output:fn_ty.output})}
|
||||||
|
_ {none}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// construct the function type
|
||||||
|
let fty = ty::mk_fn(tcx,
|
||||||
|
ty_of_fn_decl(fcx, fcx, proto, decl,
|
||||||
|
expected_tys));
|
||||||
|
|
||||||
|
#debug("check_expr_fn_with_unifier %s fty=%s",
|
||||||
|
expr_to_str(expr), fcx.ty_to_str(fty));
|
||||||
|
|
||||||
|
fcx.write_ty(expr.id, fty);
|
||||||
|
|
||||||
|
let ret_ty = ty::ty_fn_ret(fty);
|
||||||
|
let arg_tys = vec::map(ty::ty_fn_args(fty)) {|a| a.ty };
|
||||||
|
|
||||||
|
check_fn(fcx.ccx, proto, decl, body, expr.id,
|
||||||
|
ret_ty, arg_tys, is_loop_body, some(fcx),
|
||||||
|
fcx.self_ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
let tcx = fcx.ccx.tcx;
|
let tcx = fcx.ccx.tcx;
|
||||||
let id = expr.id;
|
let id = expr.id;
|
||||||
let mut bot = false;
|
let mut bot = false;
|
||||||
|
@ -3510,20 +3563,25 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
||||||
if !arm_non_bot { result_ty = ty::mk_bot(tcx); }
|
if !arm_non_bot { result_ty = ty::mk_bot(tcx); }
|
||||||
fcx.write_ty(id, result_ty);
|
fcx.write_ty(id, result_ty);
|
||||||
}
|
}
|
||||||
ast::expr_fn(proto, decl, body, captures) {
|
ast::expr_fn(proto, decl, body, cap_clause) {
|
||||||
check_expr_fn_with_unifier(fcx, expr, proto, decl, body,
|
check_expr_fn(fcx, expr, proto, decl, body, false, expected);
|
||||||
false, unifier);
|
capture::check_capture_clause(tcx, expr.id, proto, cap_clause);
|
||||||
capture::check_capture_clause(tcx, expr.id, proto, *captures);
|
|
||||||
}
|
}
|
||||||
ast::expr_fn_block(decl, body) {
|
ast::expr_fn_block(decl, body, cap_clause) {
|
||||||
// Take the prototype from the expected type, but default to block:
|
// Take the prototype from the expected type, but default to block:
|
||||||
let proto = unpack_expected(fcx, expected, {|sty|
|
let proto = unpack_expected(fcx, expected, {|sty|
|
||||||
alt sty { ty::ty_fn({proto, _}) { some(proto) } _ { none } }
|
alt sty { ty::ty_fn({proto, _}) { some(proto) } _ { none } }
|
||||||
}).get_default(ast::proto_box);
|
}).get_default(ast::proto_box);
|
||||||
check_expr_fn_with_unifier(fcx, expr, proto, decl, body,
|
check_expr_fn(fcx, expr, proto, decl, body, false, expected);
|
||||||
false, unifier);
|
capture::check_capture_clause(tcx, expr.id, proto, cap_clause);
|
||||||
}
|
}
|
||||||
ast::expr_loop_body(b) {
|
ast::expr_loop_body(b) {
|
||||||
|
// a loop body is the special argument to a `for` loop. We know that
|
||||||
|
// there will be an expected type in this context because it can only
|
||||||
|
// appear in the context of a call, so we get the expected type of the
|
||||||
|
// parameter. The catch here is that we need to validate two things:
|
||||||
|
// 1. a closure that returns a bool is expected
|
||||||
|
// 2. the cloure that was given returns unit
|
||||||
let expected_sty = unpack_expected(fcx, expected, {|x|some(x)}).get();
|
let expected_sty = unpack_expected(fcx, expected, {|x|some(x)}).get();
|
||||||
let (inner_ty, proto) = alt expected_sty {
|
let (inner_ty, proto) = alt expected_sty {
|
||||||
ty::ty_fn(fty) {
|
ty::ty_fn(fty) {
|
||||||
|
@ -3544,10 +3602,10 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
alt check b.node {
|
alt check b.node {
|
||||||
ast::expr_fn_block(decl, body) {
|
ast::expr_fn_block(decl, body, cap_clause) {
|
||||||
check_expr_fn_with_unifier(fcx, b, proto, decl, body, true) {||
|
check_expr_fn(fcx, b, proto, decl, body, true, some(inner_ty));
|
||||||
demand::suptype(fcx, b.span, inner_ty, fcx.expr_ty(b));
|
demand::suptype(fcx, b.span, inner_ty, fcx.expr_ty(b));
|
||||||
}
|
capture::check_capture_clause(tcx, b.id, proto, cap_clause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let block_ty = structurally_resolved_type(
|
let block_ty = structurally_resolved_type(
|
||||||
|
|
|
@ -130,18 +130,9 @@ fn ty_to_str(cx: ctxt, typ: t) -> str {
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there is an id, print that instead of the structural type:
|
// if there is an id, print that instead of the structural type:
|
||||||
alt ty::type_def_id(typ) {
|
for ty::type_def_id(typ).each { |def_id|
|
||||||
some(def_id) {
|
// note that this typedef cannot have type parameters
|
||||||
let cs = ast_map::path_to_str(ty::item_path(cx, def_id));
|
ret ast_map::path_to_str(ty::item_path(cx, def_id));
|
||||||
ret alt ty::get(typ).struct {
|
|
||||||
ty_enum(_, substs) | ty_res(_, _, substs) | ty_class(_, substs) |
|
|
||||||
ty_iface(_, substs) {
|
|
||||||
parameterized(cx, cs, substs.self_r, substs.tps)
|
|
||||||
}
|
|
||||||
_ { cs }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
none { /* fallthrough */}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// pretty print the structural type representation:
|
// pretty print the structural type representation:
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
// error-pattern:upvars (like 'x') cannot be moved into a closure
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let x = 5;
|
let x = 5;
|
||||||
let _y = fn~[move x]() -> int {
|
let _y = fn~(move x) -> int {
|
||||||
let _z = fn~[move x]() -> int { x };
|
let _z = fn~(move x) -> int { x }; //! ERROR moving out of upvar
|
||||||
22
|
22
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
8
src/test/compile-fail/pptypedef.rs
Normal file
8
src/test/compile-fail/pptypedef.rs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
type foo = option<int>;
|
||||||
|
|
||||||
|
fn bar(_t: foo) {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// we used to print foo<int>:
|
||||||
|
bar(some(3u)); //! ERROR mismatched types: expected `foo`
|
||||||
|
}
|
|
@ -4,7 +4,6 @@ fn concat<T: copy>(v: [const [const T]]) -> [T] {
|
||||||
// Earlier versions of our type checker accepted this:
|
// Earlier versions of our type checker accepted this:
|
||||||
vec::iter(v) {|&&inner: [T]|
|
vec::iter(v) {|&&inner: [T]|
|
||||||
//!^ ERROR values differ in mutability
|
//!^ ERROR values differ in mutability
|
||||||
//!^^ ERROR values differ in mutability
|
|
||||||
r += inner;
|
r += inner;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,14 +4,14 @@ fn main() {
|
||||||
let x = 1;
|
let x = 1;
|
||||||
let y = 2;
|
let y = 2;
|
||||||
let z = 3;
|
let z = 3;
|
||||||
let l1 = fn@[copy x]() -> int { x + y };
|
let l1 = fn@(w: int, copy x) -> int { w + x + y };
|
||||||
let l2 = fn@[copy x; move y]() -> int { x + y };
|
let l2 = fn@(w: int, copy x, move y) -> int { w + x + y };
|
||||||
let l3 = fn@[move z]() -> int { z };
|
let l3 = fn@(w: int, move z) -> int { w + z };
|
||||||
|
|
||||||
let x = 1;
|
let x = 1;
|
||||||
let y = 2;
|
let y = 2;
|
||||||
let z = 3;
|
let z = 3;
|
||||||
let s1 = fn~[copy x]() -> int { x + y };
|
let s1 = fn~(copy x) -> int { x + y };
|
||||||
let s2 = fn~[copy x; move y]() -> int { x + y };
|
let s2 = fn~(copy x, move y) -> int { x + y };
|
||||||
let s3 = fn~[move z]() -> int { z };
|
let s3 = fn~(move z) -> int { z };
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,29 @@
|
||||||
fn main() {
|
fn main() {
|
||||||
let x = ~1;
|
let x = ~1;
|
||||||
let y = ptr::addr_of(*x) as uint;
|
let y = ptr::addr_of(*x) as uint;
|
||||||
|
let lam_copy = fn@(copy x) -> uint { ptr::addr_of(*x) as uint };
|
||||||
let lam_copy = fn@[copy x]() -> uint { ptr::addr_of(*x) as uint };
|
let lam_move = fn@(move x) -> uint { ptr::addr_of(*x) as uint };
|
||||||
let lam_move = fn@[move x]() -> uint { ptr::addr_of(*x) as uint };
|
|
||||||
assert lam_copy() != y;
|
assert lam_copy() != y;
|
||||||
assert lam_move() == y;
|
assert lam_move() == y;
|
||||||
|
|
||||||
let x = ~2;
|
let x = ~2;
|
||||||
let y = ptr::addr_of(*x) as uint;
|
let y = ptr::addr_of(*x) as uint;
|
||||||
let snd_copy = fn~[copy x]() -> uint { ptr::addr_of(*x) as uint };
|
let lam_copy: fn@() -> uint = { |copy x| ptr::addr_of(*x) as uint };
|
||||||
let snd_move = fn~[move x]() -> uint { ptr::addr_of(*x) as uint };
|
let lam_move: fn@() -> uint = { |move x| ptr::addr_of(*x) as uint };
|
||||||
|
assert lam_copy() != y;
|
||||||
|
assert lam_move() == y;
|
||||||
|
|
||||||
|
let x = ~3;
|
||||||
|
let y = ptr::addr_of(*x) as uint;
|
||||||
|
let snd_copy = fn~(copy x) -> uint { ptr::addr_of(*x) as uint };
|
||||||
|
let snd_move = fn~(move x) -> uint { ptr::addr_of(*x) as uint };
|
||||||
assert snd_copy() != y;
|
assert snd_copy() != y;
|
||||||
assert snd_move() == y;
|
assert snd_move() == y;
|
||||||
|
|
||||||
|
let x = ~4;
|
||||||
|
let y = ptr::addr_of(*x) as uint;
|
||||||
|
let lam_copy: fn~() -> uint = { |copy x| ptr::addr_of(*x) as uint };
|
||||||
|
let lam_move: fn~() -> uint = { |move x| ptr::addr_of(*x) as uint };
|
||||||
|
assert lam_copy() != y;
|
||||||
|
assert lam_move() == y;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// error-pattern: warning: Captured variable 'y' not used in closure
|
// error-pattern: warning: Captured variable 'y' not used in closure
|
||||||
fn main() {
|
fn main() {
|
||||||
let x = 5;
|
let x = 5;
|
||||||
let _y = fn~[copy x]() { };
|
let _y = fn~(copy x) { };
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
fn foo() -> fn@() -> int {
|
fn foo() -> fn@() -> int {
|
||||||
let k = ~22;
|
let k = ~22;
|
||||||
let _u = {a: k};
|
let _u = {a: k};
|
||||||
ret fn@[move k]() -> int { 22 };
|
ret fn@(move k) -> int { 22 };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue