rustc: Implement parsing and typechecking for "once fn"
This commit is contained in:
parent
9aadfc3f4b
commit
be93b29d30
@ -1059,6 +1059,25 @@ enum region_ {
|
||||
re_named(ident)
|
||||
}
|
||||
|
||||
#[auto_serialize]
|
||||
#[auto_deserialize]
|
||||
enum Onceness {
|
||||
Once,
|
||||
Many
|
||||
}
|
||||
|
||||
impl Onceness : cmp::Eq {
|
||||
pure fn eq(other: &Onceness) -> bool {
|
||||
match (self, *other) {
|
||||
(Once, Once) | (Many, Many) => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
pure fn ne(other: &Onceness) -> bool {
|
||||
!self.eq(other)
|
||||
}
|
||||
}
|
||||
|
||||
#[auto_serialize]
|
||||
#[auto_deserialize]
|
||||
enum ty_ {
|
||||
@ -1070,7 +1089,7 @@ enum ty_ {
|
||||
ty_ptr(mt),
|
||||
ty_rptr(@region, mt),
|
||||
ty_rec(~[ty_field]),
|
||||
ty_fn(proto, purity, @~[ty_param_bound], fn_decl),
|
||||
ty_fn(proto, purity, Onceness, @~[ty_param_bound], fn_decl),
|
||||
ty_tup(~[@Ty]),
|
||||
ty_path(@path, node_id),
|
||||
ty_fixed_length(@Ty, Option<uint>),
|
||||
|
@ -524,10 +524,11 @@ fn noop_fold_ty(t: ty_, fld: ast_fold) -> ty_ {
|
||||
ty_ptr(mt) => ty_ptr(fold_mt(mt, fld)),
|
||||
ty_rptr(region, mt) => ty_rptr(region, fold_mt(mt, fld)),
|
||||
ty_rec(fields) => ty_rec(vec::map(fields, |f| fold_field(*f, fld))),
|
||||
ty_fn(proto, purity, bounds, decl) =>
|
||||
ty_fn(proto, purity,
|
||||
@vec::map(*bounds,
|
||||
|x| fold_ty_param_bound(*x, fld)),
|
||||
ty_fn(proto, purity, onceness, bounds, decl) =>
|
||||
ty_fn(proto,
|
||||
purity,
|
||||
onceness,
|
||||
@vec::map(*bounds, |x| fold_ty_param_bound(*x, fld)),
|
||||
fold_fn_decl(decl, fld)),
|
||||
ty_tup(tys) => ty_tup(vec::map(tys, |ty| fld.fold_ty(*ty))),
|
||||
ty_path(path, id) => ty_path(fld.fold_path(path), fld.new_id(id)),
|
||||
|
@ -287,7 +287,7 @@ impl Parser {
|
||||
|
||||
pure fn id_to_str(id: ident) -> @~str { self.sess.interner.get(id) }
|
||||
|
||||
fn parse_ty_fn(purity: ast::purity) -> ty_ {
|
||||
fn parse_ty_fn(purity: ast::purity, onceness: ast::Onceness) -> ty_ {
|
||||
let proto, bounds;
|
||||
if self.eat_keyword(~"extern") {
|
||||
self.expect_keyword(~"fn");
|
||||
@ -298,7 +298,17 @@ impl Parser {
|
||||
proto = self.parse_fn_ty_proto();
|
||||
bounds = self.parse_optional_ty_param_bounds();
|
||||
};
|
||||
ty_fn(proto, purity, bounds, self.parse_ty_fn_decl())
|
||||
ty_fn(proto, purity, onceness, bounds, self.parse_ty_fn_decl())
|
||||
}
|
||||
|
||||
fn parse_ty_fn_with_onceness(purity: ast::purity) -> ty_ {
|
||||
let onceness = self.parse_optional_onceness();
|
||||
self.parse_ty_fn(purity, onceness)
|
||||
}
|
||||
|
||||
fn parse_ty_fn_with_purity_and_onceness() -> ty_ {
|
||||
let purity = self.parse_optional_purity();
|
||||
self.parse_ty_fn_with_onceness(purity)
|
||||
}
|
||||
|
||||
fn parse_ty_fn_decl() -> fn_decl {
|
||||
@ -526,15 +536,18 @@ impl Parser {
|
||||
let region = self.parse_region_with_sep();
|
||||
let mt = self.parse_mt();
|
||||
ty_rptr(region, mt)
|
||||
} else if self.eat_keyword(~"once") {
|
||||
self.parse_ty_fn(ast::impure_fn, ast::Once)
|
||||
} else if self.eat_keyword(~"pure") {
|
||||
self.parse_ty_fn(ast::pure_fn)
|
||||
self.parse_ty_fn_with_onceness(ast::pure_fn)
|
||||
} else if self.eat_keyword(~"unsafe") {
|
||||
self.parse_ty_fn(ast::unsafe_fn)
|
||||
self.parse_ty_fn_with_onceness(ast::unsafe_fn)
|
||||
} else if self.is_keyword(~"fn") {
|
||||
self.parse_ty_fn(ast::impure_fn)
|
||||
self.parse_ty_fn_with_onceness(ast::impure_fn)
|
||||
} else if self.eat_keyword(~"extern") {
|
||||
self.expect_keyword(~"fn");
|
||||
ty_fn(proto_bare, ast::impure_fn, @~[], self.parse_ty_fn_decl())
|
||||
ty_fn(proto_bare, ast::impure_fn, ast::Many, @~[],
|
||||
self.parse_ty_fn_decl())
|
||||
} else if self.token == token::MOD_SEP || is_ident(self.token) {
|
||||
let path = self.parse_path_with_tps(colons_before_params);
|
||||
ty_path(path, self.get_id())
|
||||
@ -2275,6 +2288,20 @@ impl Parser {
|
||||
self.get_id()), span: self.last_span}
|
||||
}
|
||||
|
||||
fn parse_optional_purity() -> ast::purity {
|
||||
if self.eat_keyword(~"pure") {
|
||||
ast::pure_fn
|
||||
} else if self.eat_keyword(~"unsafe") {
|
||||
ast::unsafe_fn
|
||||
} else {
|
||||
ast::impure_fn
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_optional_onceness() -> ast::Onceness {
|
||||
if self.eat_keyword(~"once") { ast::Once } else { ast::Many }
|
||||
}
|
||||
|
||||
fn parse_optional_ty_param_bounds() -> @~[ty_param_bound] {
|
||||
let mut bounds = ~[];
|
||||
if self.eat(token::COLON) {
|
||||
|
@ -427,6 +427,7 @@ fn strict_keyword_table() -> HashMap<~str, ()> {
|
||||
~"if", ~"impl",
|
||||
~"let", ~"log", ~"loop",
|
||||
~"match", ~"mod", ~"move", ~"mut",
|
||||
~"once",
|
||||
~"priv", ~"pub", ~"pure",
|
||||
~"ref", ~"return",
|
||||
~"struct",
|
||||
|
@ -394,8 +394,9 @@ fn print_type_ex(s: ps, &&ty: @ast::Ty, print_colons: bool) {
|
||||
commasep(s, inconsistent, elts, print_type);
|
||||
pclose(s);
|
||||
}
|
||||
ast::ty_fn(proto, purity, bounds, d) => {
|
||||
print_ty_fn(s, Some(proto), purity, bounds, d, None, None, None);
|
||||
ast::ty_fn(proto, purity, onceness, bounds, d) => {
|
||||
print_ty_fn(s, Some(proto), purity, onceness, bounds, d, None, None,
|
||||
None);
|
||||
}
|
||||
ast::ty_path(path, _) => print_path(s, path, print_colons),
|
||||
ast::ty_fixed_length(t, v) => {
|
||||
@ -804,7 +805,7 @@ fn print_ty_method(s: ps, m: ast::ty_method) {
|
||||
hardbreak_if_not_bol(s);
|
||||
maybe_print_comment(s, m.span.lo);
|
||||
print_outer_attributes(s, m.attrs);
|
||||
print_ty_fn(s, None, m.purity,
|
||||
print_ty_fn(s, None, m.purity, ast::Many,
|
||||
@~[], m.decl, Some(m.ident), Some(m.tps),
|
||||
Some(m.self_ty.node));
|
||||
word(s.s, ~";");
|
||||
@ -1273,7 +1274,7 @@ fn print_expr(s: ps, &&expr: @ast::expr) {
|
||||
cbox(s, indent_unit);
|
||||
// head-box, will be closed by print-block at start
|
||||
ibox(s, 0u);
|
||||
word(s.s, fn_header_info_to_str(None, None, Some(proto),
|
||||
word(s.s, fn_header_info_to_str(None, None, Some(proto), ast::Many,
|
||||
ast::inherited));
|
||||
print_fn_args_and_ret(s, decl, *cap_clause, None);
|
||||
space(s.s);
|
||||
@ -1606,12 +1607,15 @@ fn print_self_ty(s: ps, self_ty: ast::self_ty_) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
fn print_fn(s: ps, decl: ast::fn_decl, purity: Option<ast::purity>,
|
||||
fn print_fn(s: ps,
|
||||
decl: ast::fn_decl,
|
||||
purity: Option<ast::purity>,
|
||||
name: ast::ident,
|
||||
typarams: ~[ast::ty_param],
|
||||
opt_self_ty: Option<ast::self_ty_>,
|
||||
vis: ast::visibility) {
|
||||
head(s, fn_header_info_to_str(opt_self_ty, purity, None, vis));
|
||||
head(s, fn_header_info_to_str(opt_self_ty, purity, None, ast::Many,
|
||||
vis));
|
||||
print_ident(s, name);
|
||||
print_type_params(s, typarams);
|
||||
print_fn_args_and_ret(s, decl, ~[], opt_self_ty);
|
||||
@ -1831,14 +1835,17 @@ fn print_arg(s: ps, input: ast::arg) {
|
||||
end(s);
|
||||
}
|
||||
|
||||
fn print_ty_fn(s: ps, opt_proto: Option<ast::proto>, purity: ast::purity,
|
||||
fn print_ty_fn(s: ps,
|
||||
opt_proto: Option<ast::proto>,
|
||||
purity: ast::purity,
|
||||
onceness: ast::Onceness,
|
||||
bounds: @~[ast::ty_param_bound],
|
||||
decl: ast::fn_decl, id: Option<ast::ident>,
|
||||
tps: Option<~[ast::ty_param]>,
|
||||
opt_self_ty: Option<ast::self_ty_>) {
|
||||
ibox(s, indent_unit);
|
||||
word(s.s, fn_header_info_to_str(opt_self_ty, Some(purity), opt_proto,
|
||||
ast::inherited));
|
||||
onceness, ast::inherited));
|
||||
print_bounds(s, bounds);
|
||||
match id { Some(id) => { word(s.s, ~" "); print_ident(s, id); } _ => () }
|
||||
match tps { Some(tps) => print_type_params(s, tps), _ => () }
|
||||
@ -2062,6 +2069,7 @@ fn next_comment(s: ps) -> Option<comments::cmnt> {
|
||||
fn fn_header_info_to_str(opt_sty: Option<ast::self_ty_>,
|
||||
opt_purity: Option<ast::purity>,
|
||||
opt_p: Option<ast::proto>,
|
||||
onceness: ast::Onceness,
|
||||
vis: ast::visibility) -> ~str {
|
||||
|
||||
let mut s = visibility_qualified(vis, ~"");
|
||||
@ -2082,6 +2090,11 @@ fn fn_header_info_to_str(opt_sty: Option<ast::self_ty_>,
|
||||
|
||||
str::push_str(&mut s, opt_proto_to_str(opt_p));
|
||||
|
||||
match onceness {
|
||||
ast::Once => str::push_str(&mut s, ~"once "),
|
||||
ast::Many => {}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@ -2101,6 +2114,13 @@ pure fn purity_to_str(p: ast::purity) -> ~str {
|
||||
}
|
||||
}
|
||||
|
||||
pure fn onceness_to_str(o: ast::Onceness) -> ~str {
|
||||
match o {
|
||||
ast::Once => ~"once",
|
||||
ast::Many => ~"many"
|
||||
}
|
||||
}
|
||||
|
||||
fn print_purity(s: ps, p: ast::purity) {
|
||||
match p {
|
||||
ast::impure_fn => (),
|
||||
|
@ -203,7 +203,7 @@ fn visit_ty<E>(t: @Ty, e: E, v: vt<E>) {
|
||||
ty_tup(ts) => for ts.each |tt| {
|
||||
v.visit_ty(*tt, e, v);
|
||||
},
|
||||
ty_fn(_, _, bounds, decl) => {
|
||||
ty_fn(_, _, _, bounds, decl) => {
|
||||
for decl.inputs.each |a| { v.visit_ty(a.ty, e, v); }
|
||||
visit_ty_param_bounds(bounds, e, v);
|
||||
v.visit_ty(decl.output, e, v);
|
||||
|
@ -387,6 +387,14 @@ fn parse_purity(c: char) -> purity {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_onceness(c: char) -> ast::Onceness {
|
||||
match c {
|
||||
'o' => ast::Once,
|
||||
'm' => ast::Many,
|
||||
_ => fail ~"parse_onceness: bad onceness"
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_arg(st: @pstate, conv: conv_did) -> ty::arg {
|
||||
{mode: parse_mode(st),
|
||||
ty: parse_ty(st, conv)}
|
||||
@ -406,6 +414,7 @@ fn parse_mode(st: @pstate) -> ast::mode {
|
||||
fn parse_ty_fn(st: @pstate, conv: conv_did) -> ty::FnTy {
|
||||
let proto = parse_proto(st);
|
||||
let purity = parse_purity(next(st));
|
||||
let onceness = parse_onceness(next(st));
|
||||
let bounds = parse_bounds(st, conv);
|
||||
assert (next(st) == '[');
|
||||
let mut inputs: ~[ty::arg] = ~[];
|
||||
@ -418,6 +427,7 @@ fn parse_ty_fn(st: @pstate, conv: conv_did) -> ty::FnTy {
|
||||
return FnTyBase {
|
||||
meta: FnMeta {purity: purity,
|
||||
proto: proto,
|
||||
onceness: onceness,
|
||||
bounds: bounds,
|
||||
ret_style: ret_style},
|
||||
sig: FnSig {inputs: inputs,
|
||||
|
@ -349,9 +349,17 @@ fn enc_purity(w: io::Writer, p: purity) {
|
||||
}
|
||||
}
|
||||
|
||||
fn enc_onceness(w: io::Writer, o: Onceness) {
|
||||
match o {
|
||||
Once => w.write_char('o'),
|
||||
Many => w.write_char('m')
|
||||
}
|
||||
}
|
||||
|
||||
fn enc_ty_fn(w: io::Writer, cx: @ctxt, ft: ty::FnTy) {
|
||||
enc_proto(w, cx, ft.meta.proto);
|
||||
enc_purity(w, ft.meta.purity);
|
||||
enc_onceness(w, ft.meta.onceness);
|
||||
enc_bounds(w, cx, ft.meta.bounds);
|
||||
w.write_char('[');
|
||||
for ft.sig.inputs.each |arg| {
|
||||
|
@ -841,7 +841,7 @@ fn check_fn_deprecated_modes(tcx: ty::ctxt, fn_ty: ty::t, decl: ast::fn_decl,
|
||||
let span = arg_ast.ty.span;
|
||||
// Recurse to check fn-type argument
|
||||
match arg_ast.ty.node {
|
||||
ast::ty_fn(_, _, _, decl) => {
|
||||
ast::ty_fn(_, _, _, _, decl) => {
|
||||
check_fn_deprecated_modes(tcx, arg_ty.ty,
|
||||
decl, span, id);
|
||||
}
|
||||
@ -856,7 +856,7 @@ fn check_fn_deprecated_modes(tcx: ty::ctxt, fn_ty: ty::t, decl: ast::fn_decl,
|
||||
// Functions with preceding sigil are parsed
|
||||
// as pointers of functions
|
||||
match mt.ty.node {
|
||||
ast::ty_fn(_, _, _, decl) => {
|
||||
ast::ty_fn(_, _, _, _, decl) => {
|
||||
check_fn_deprecated_modes(
|
||||
tcx, arg_ty.ty,
|
||||
decl, span, id);
|
||||
@ -889,7 +889,7 @@ fn check_item_deprecated_modes(tcx: ty::ctxt, it: @ast::item) {
|
||||
match it.node {
|
||||
ast::item_ty(ty, _) => {
|
||||
match ty.node {
|
||||
ast::ty_fn(_, _, _, decl) => {
|
||||
ast::ty_fn(_, _, _, _, decl) => {
|
||||
let fn_ty = ty::node_id_to_type(tcx, it.id);
|
||||
check_fn_deprecated_modes(
|
||||
tcx, fn_ty, decl, ty.span, it.id)
|
||||
|
@ -624,8 +624,8 @@ fn determine_rp_in_ty(ty: @ast::Ty,
|
||||
}
|
||||
}
|
||||
|
||||
ast::ty_fn(ast::proto_bare, _, _, _) |
|
||||
ast::ty_fn(ast::proto_block, _, _, _) if cx.anon_implies_rp => {
|
||||
ast::ty_fn(ast::proto_bare, _, _, _, _) |
|
||||
ast::ty_fn(ast::proto_block, _, _, _, _) if cx.anon_implies_rp => {
|
||||
debug!("referenced bare fn type with regions %s",
|
||||
pprust::ty_to_str(ty, cx.sess.intr()));
|
||||
cx.add_rp(cx.item_id, cx.add_variance(rv_contravariant));
|
||||
@ -672,8 +672,8 @@ fn determine_rp_in_ty(ty: @ast::Ty,
|
||||
match ty.node {
|
||||
ast::ty_box(mt) | ast::ty_uniq(mt) => {
|
||||
match mt.ty.node {
|
||||
ast::ty_fn(ast::proto_bare, _, _, _) |
|
||||
ast::ty_fn(ast::proto_block, _, _, _) => {
|
||||
ast::ty_fn(ast::proto_bare, _, _, _, _) |
|
||||
ast::ty_fn(ast::proto_block, _, _, _, _) => {
|
||||
do cx.with(cx.item_id, false) {
|
||||
visit_mt(mt, cx, visitor);
|
||||
}
|
||||
@ -706,7 +706,7 @@ fn determine_rp_in_ty(ty: @ast::Ty,
|
||||
}
|
||||
}
|
||||
|
||||
ast::ty_fn(_, _, bounds, decl) => {
|
||||
ast::ty_fn(_, _, _, bounds, decl) => {
|
||||
// fn() binds the & region, so do not consider &T types that
|
||||
// appear *inside* a fn() type to affect the enclosing item:
|
||||
do cx.with(cx.item_id, false) {
|
||||
|
@ -1000,6 +1000,7 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item,
|
||||
proto:
|
||||
ty::proto_vstore(ty::vstore_slice(
|
||||
ty::re_bound(ty::br_anon(0)))),
|
||||
onceness: ast::Many,
|
||||
bounds: @~[],
|
||||
ret_style: ast::return_val},
|
||||
sig: FnSig {inputs: ~[{mode: ast::expl(ast::by_val),
|
||||
|
@ -250,6 +250,7 @@ fn normalize_for_monomorphization(tcx: ty::ctxt, ty: ty::t) -> Option<ty::t> {
|
||||
tcx,
|
||||
FnTyBase {meta: FnMeta {purity: ast::impure_fn,
|
||||
proto: fty.meta.proto,
|
||||
onceness: ast::Many,
|
||||
bounds: @~[],
|
||||
ret_style: ast::return_val},
|
||||
sig: FnSig {inputs: ~[],
|
||||
@ -261,6 +262,7 @@ fn normalize_for_monomorphization(tcx: ty::ctxt, ty: ty::t) -> Option<ty::t> {
|
||||
tcx,
|
||||
FnTyBase {meta: FnMeta {purity: ast::impure_fn,
|
||||
proto: box_proto,
|
||||
onceness: ast::Many,
|
||||
bounds: @~[],
|
||||
ret_style: ast::return_val},
|
||||
sig: FnSig {inputs: ~[],
|
||||
|
@ -126,6 +126,7 @@ export kind_is_owned;
|
||||
export meta_kind, kind_lteq, type_kind;
|
||||
export operators;
|
||||
export type_err, terr_vstore_kind;
|
||||
export terr_onceness_mismatch;
|
||||
export type_err_to_str, note_and_explain_type_err;
|
||||
export expected_found;
|
||||
export type_needs_drop;
|
||||
@ -186,6 +187,7 @@ export terr_proto_mismatch;
|
||||
export terr_ret_style_mismatch;
|
||||
export terr_fn, terr_trait;
|
||||
export purity_to_str;
|
||||
export onceness_to_str;
|
||||
export param_tys_in_type;
|
||||
export eval_repeat_count;
|
||||
export fn_proto, proto_bare, proto_vstore;
|
||||
@ -504,11 +506,14 @@ impl fn_proto : cmp::Eq {
|
||||
*
|
||||
* - `purity` is the function's effect (pure, impure, unsafe).
|
||||
* - `proto` is the protocol (fn@, fn~, etc).
|
||||
* - `onceness` indicates whether the function can be called one time or many
|
||||
* times.
|
||||
* - `bounds` is the parameter bounds on the function's upvars.
|
||||
* - `ret_style` indicates whether the function returns a value or fails. */
|
||||
struct FnMeta {
|
||||
purity: ast::purity,
|
||||
proto: fn_proto,
|
||||
onceness: ast::Onceness,
|
||||
bounds: @~[param_bound],
|
||||
ret_style: ret_style
|
||||
}
|
||||
@ -679,6 +684,7 @@ enum type_err {
|
||||
terr_mismatch,
|
||||
terr_ret_style_mismatch(expected_found<ast::ret_style>),
|
||||
terr_purity_mismatch(expected_found<purity>),
|
||||
terr_onceness_mismatch(expected_found<Onceness>),
|
||||
terr_mutability,
|
||||
terr_proto_mismatch(expected_found<ty::fn_proto>),
|
||||
terr_box_mutability,
|
||||
@ -3326,6 +3332,11 @@ fn type_err_to_str(cx: ctxt, err: &type_err) -> ~str {
|
||||
purity_to_str(values.expected),
|
||||
purity_to_str(values.found))
|
||||
}
|
||||
terr_onceness_mismatch(values) => {
|
||||
fmt!("expected %s fn but found %s fn",
|
||||
onceness_to_str(values.expected),
|
||||
onceness_to_str(values.found))
|
||||
}
|
||||
terr_proto_mismatch(values) => {
|
||||
fmt!("expected %s closure, found %s closure",
|
||||
proto_ty_to_str(cx, values.expected),
|
||||
|
@ -208,7 +208,8 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope Copy Owned>(
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
ast::ty_fn(ast::proto_block, purity, ast_bounds, ast_fn_decl) => {
|
||||
ast::ty_fn(ast::proto_block, purity, onceness, ast_bounds,
|
||||
ast_fn_decl) => {
|
||||
let new_proto;
|
||||
match vst {
|
||||
ty::vstore_fixed(_) => {
|
||||
@ -223,9 +224,15 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope Copy Owned>(
|
||||
|
||||
// Run through the normal function type conversion process.
|
||||
let bounds = collect::compute_bounds(self.ccx(), ast_bounds);
|
||||
let fn_decl = ty_of_fn_decl(self, rscope, new_proto, purity,
|
||||
let fn_decl = ty_of_fn_decl(self,
|
||||
rscope,
|
||||
new_proto,
|
||||
purity,
|
||||
onceness,
|
||||
bounds,
|
||||
ast_fn_decl, None, span);
|
||||
ast_fn_decl,
|
||||
None,
|
||||
span);
|
||||
return ty::mk_fn(tcx, fn_decl);
|
||||
}
|
||||
_ => ()
|
||||
@ -309,10 +316,10 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope Copy Owned>(
|
||||
};
|
||||
ty::mk_rec(tcx, flds)
|
||||
}
|
||||
ast::ty_fn(proto, purity, ast_bounds, decl) => {
|
||||
ast::ty_fn(proto, purity, onceness, ast_bounds, decl) => {
|
||||
let bounds = collect::compute_bounds(self.ccx(), ast_bounds);
|
||||
let fn_decl = ty_of_fn_decl(self, rscope, proto, purity,
|
||||
bounds, decl, None,
|
||||
onceness, bounds, decl, None,
|
||||
ast_ty.span);
|
||||
ty::mk_fn(tcx, fn_decl)
|
||||
}
|
||||
@ -476,6 +483,7 @@ fn ty_of_fn_decl<AC: ast_conv, RS: region_scope Copy Owned>(
|
||||
self: AC, rscope: RS,
|
||||
ast_proto: ast::proto,
|
||||
purity: ast::purity,
|
||||
onceness: ast::Onceness,
|
||||
bounds: @~[ty::param_bound],
|
||||
decl: ast::fn_decl,
|
||||
expected_tys: expected_tys,
|
||||
@ -508,6 +516,7 @@ fn ty_of_fn_decl<AC: ast_conv, RS: region_scope Copy Owned>(
|
||||
FnTyBase {
|
||||
meta: FnMeta {purity: purity,
|
||||
proto: proto,
|
||||
onceness: onceness,
|
||||
bounds: bounds,
|
||||
ret_style: decl.cf},
|
||||
sig: FnSig {inputs: input_tys,
|
||||
|
@ -1310,7 +1310,10 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
||||
// block syntax lambdas; that is, lambdas without explicit
|
||||
// protos.
|
||||
let expected_sty = unpack_expected(fcx, expected, |x| Some(x));
|
||||
let (expected_tys, expected_purity, expected_proto) =
|
||||
let (expected_tys,
|
||||
expected_purity,
|
||||
expected_proto,
|
||||
expected_onceness) =
|
||||
match expected_sty {
|
||||
Some(ty::ty_fn(ref fn_ty)) => {
|
||||
let {fn_ty, _} =
|
||||
@ -1320,10 +1323,14 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
||||
(Some({inputs: fn_ty.sig.inputs,
|
||||
output: fn_ty.sig.output}),
|
||||
fn_ty.meta.purity,
|
||||
fn_ty.meta.proto)
|
||||
fn_ty.meta.proto,
|
||||
fn_ty.meta.onceness)
|
||||
}
|
||||
_ => {
|
||||
(None, ast::impure_fn, ty::proto_vstore(ty::vstore_box))
|
||||
(None,
|
||||
ast::impure_fn,
|
||||
ty::proto_vstore(ty::vstore_box),
|
||||
ast::Many)
|
||||
}
|
||||
};
|
||||
|
||||
@ -1334,17 +1341,25 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
||||
// XXX: This is a hack.
|
||||
let ast_proto = ast_proto_opt.get_default(ast::proto_box);
|
||||
let ast_purity = ast::impure_fn;
|
||||
let ast_onceness = ast::Many;
|
||||
|
||||
// construct the function type
|
||||
let mut fn_ty = astconv::ty_of_fn_decl(fcx, fcx,
|
||||
ast_proto, ast_purity, @~[],
|
||||
decl, expected_tys, expr.span);
|
||||
let mut fn_ty = astconv::ty_of_fn_decl(fcx,
|
||||
fcx,
|
||||
ast_proto,
|
||||
ast_purity,
|
||||
ast_onceness,
|
||||
@~[],
|
||||
decl,
|
||||
expected_tys,
|
||||
expr.span);
|
||||
|
||||
// Patch up the function declaration, if necessary.
|
||||
match ast_proto_opt {
|
||||
None => {
|
||||
fn_ty.meta.purity = expected_purity;
|
||||
fn_ty.meta.proto = expected_proto;
|
||||
fn_ty.meta.onceness = expected_onceness;
|
||||
}
|
||||
Some(_) => { }
|
||||
}
|
||||
@ -2802,6 +2817,7 @@ fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::foreign_item) {
|
||||
meta: FnMeta {purity: ast::impure_fn,
|
||||
proto: ty::proto_vstore(ty::vstore_slice(
|
||||
ty::re_bound(ty::br_anon(0)))),
|
||||
onceness: ast::Many,
|
||||
bounds: @~[],
|
||||
ret_style: ast::return_val},
|
||||
sig: FnSig {inputs: ~[{mode: ast::expl(ast::by_val),
|
||||
@ -2825,6 +2841,7 @@ fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::foreign_item) {
|
||||
let fty = ty::mk_fn(tcx, FnTyBase {
|
||||
meta: FnMeta {purity: ast::impure_fn,
|
||||
proto: ty::proto_bare,
|
||||
onceness: ast::Many,
|
||||
bounds: @~[],
|
||||
ret_style: ast::return_val},
|
||||
sig: FnSig {inputs: inputs,
|
||||
|
@ -134,6 +134,7 @@ fn get_enum_variant_types(ccx: @crate_ctxt,
|
||||
result_ty = Some(ty::mk_fn(tcx, FnTyBase {
|
||||
meta: FnMeta {purity: ast::pure_fn,
|
||||
proto: ty::proto_vstore(ty::vstore_box),
|
||||
onceness: ast::Many,
|
||||
bounds: @~[],
|
||||
ret_style: ast::return_val},
|
||||
sig: FnSig {inputs: args,
|
||||
@ -604,7 +605,7 @@ fn convert_struct(ccx: @crate_ctxt,
|
||||
let t_dtor = ty::mk_fn(
|
||||
tcx,
|
||||
ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare,
|
||||
ast::impure_fn, @~[],
|
||||
ast::impure_fn, ast::Many, @~[],
|
||||
ast_util::dtor_dec(), None, dtor.span));
|
||||
write_ty_to_tcx(tcx, dtor.node.id, t_dtor);
|
||||
tcx.tcache.insert(local_def(dtor.node.id),
|
||||
@ -643,6 +644,7 @@ fn convert_struct(ccx: @crate_ctxt,
|
||||
meta: FnMeta {
|
||||
purity: ast::pure_fn,
|
||||
proto: ty::proto_bare,
|
||||
onceness: ast::Many,
|
||||
bounds: @~[],
|
||||
ret_style: ast::return_val,
|
||||
},
|
||||
@ -682,9 +684,15 @@ fn ty_of_method(ccx: @crate_ctxt,
|
||||
rp: Option<ty::region_variance>) -> ty::method {
|
||||
{ident: m.ident,
|
||||
tps: ty_param_bounds(ccx, m.tps),
|
||||
fty: ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare,
|
||||
m.purity, @~[],
|
||||
m.decl, None, m.span),
|
||||
fty: ty_of_fn_decl(ccx,
|
||||
type_rscope(rp),
|
||||
ast::proto_bare,
|
||||
m.purity,
|
||||
ast::Many,
|
||||
@~[],
|
||||
m.decl,
|
||||
None,
|
||||
m.span),
|
||||
self_ty: m.self_ty.node,
|
||||
vis: m.vis,
|
||||
def_id: local_def(m.id)}
|
||||
@ -696,8 +704,15 @@ fn ty_of_ty_method(self: @crate_ctxt,
|
||||
id: ast::def_id) -> ty::method {
|
||||
{ident: m.ident,
|
||||
tps: ty_param_bounds(self, m.tps),
|
||||
fty: ty_of_fn_decl(self, type_rscope(rp), ast::proto_bare, m.purity,
|
||||
@~[], m.decl, None, m.span),
|
||||
fty: ty_of_fn_decl(self,
|
||||
type_rscope(rp),
|
||||
ast::proto_bare,
|
||||
m.purity,
|
||||
ast::Many,
|
||||
@~[],
|
||||
m.decl,
|
||||
None,
|
||||
m.span),
|
||||
// assume public, because this is only invoked on trait methods
|
||||
self_ty: m.self_ty.node,
|
||||
vis: ast::public,
|
||||
@ -752,9 +767,15 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item)
|
||||
}
|
||||
ast::item_fn(decl, purity, tps, _) => {
|
||||
let bounds = ty_param_bounds(ccx, tps);
|
||||
let tofd = ty_of_fn_decl(ccx, empty_rscope,
|
||||
ast::proto_bare, purity, @~[],
|
||||
decl, None, it.span);
|
||||
let tofd = ty_of_fn_decl(ccx,
|
||||
empty_rscope,
|
||||
ast::proto_bare,
|
||||
purity,
|
||||
ast::Many,
|
||||
@~[],
|
||||
decl,
|
||||
None,
|
||||
it.span);
|
||||
let tpt = {bounds: bounds,
|
||||
region_param: None,
|
||||
ty: ty::mk_fn(ccx.tcx, tofd)};
|
||||
@ -910,6 +931,7 @@ fn ty_of_foreign_fn_decl(ccx: @crate_ctxt,
|
||||
let t_fn = ty::mk_fn(ccx.tcx, FnTyBase {
|
||||
meta: FnMeta {purity: purity,
|
||||
proto: ty::proto_bare,
|
||||
onceness: ast::Many,
|
||||
bounds: @~[],
|
||||
ret_style: ast::return_val},
|
||||
sig: FnSig {inputs: input_tys,
|
||||
|
@ -46,6 +46,7 @@
|
||||
|
||||
use to_str::ToStr;
|
||||
use ty::{FnTyBase, FnMeta, FnSig};
|
||||
use syntax::ast::Onceness;
|
||||
|
||||
trait combine {
|
||||
fn infcx() -> infer_ctxt;
|
||||
@ -72,6 +73,7 @@ trait combine {
|
||||
fn protos(p1: ty::fn_proto, p2: ty::fn_proto) -> cres<ty::fn_proto>;
|
||||
fn ret_styles(r1: ret_style, r2: ret_style) -> cres<ret_style>;
|
||||
fn purities(a: purity, b: purity) -> cres<purity>;
|
||||
fn oncenesses(a: Onceness, b: Onceness) -> cres<Onceness>;
|
||||
fn contraregions(a: ty::Region, b: ty::Region) -> cres<ty::Region>;
|
||||
fn regions(a: ty::Region, b: ty::Region) -> cres<ty::Region>;
|
||||
fn vstores(vk: ty::terr_vstore_kind,
|
||||
@ -311,13 +313,17 @@ fn super_fn_metas<C:combine>(
|
||||
do self.protos(a_f.proto, b_f.proto).chain |p| {
|
||||
do self.ret_styles(a_f.ret_style, b_f.ret_style).chain |rs| {
|
||||
do self.purities(a_f.purity, b_f.purity).chain |purity| {
|
||||
do self.oncenesses(a_f.onceness, b_f.onceness).chain
|
||||
|onceness| {
|
||||
Ok(FnMeta {purity: purity,
|
||||
proto: p,
|
||||
onceness: onceness,
|
||||
bounds: a_f.bounds, // XXX: This is wrong!
|
||||
ret_style: rs})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn super_fn_sigs<C:combine>(
|
||||
|
@ -1,6 +1,7 @@
|
||||
use combine::*;
|
||||
use lattice::*;
|
||||
use to_str::ToStr;
|
||||
use syntax::ast::{Many, Once};
|
||||
|
||||
enum Glb = combine_fields; // "greatest lower bound" (common subtype)
|
||||
|
||||
@ -97,6 +98,13 @@ impl Glb: combine {
|
||||
}
|
||||
}
|
||||
|
||||
fn oncenesses(a: Onceness, b: Onceness) -> cres<Onceness> {
|
||||
match (a, b) {
|
||||
(Many, _) | (_, Many) => Ok(Many),
|
||||
(Once, Once) => Ok(Once)
|
||||
}
|
||||
}
|
||||
|
||||
fn ret_styles(r1: ret_style, r2: ret_style) -> cres<ret_style> {
|
||||
match (r1, r2) {
|
||||
(ast::return_val, ast::return_val) => {
|
||||
|
@ -1,6 +1,7 @@
|
||||
use combine::*;
|
||||
use lattice::*;
|
||||
use to_str::ToStr;
|
||||
use syntax::ast::{Many, Once};
|
||||
|
||||
enum Lub = combine_fields; // "subtype", "subregion" etc
|
||||
|
||||
@ -80,6 +81,13 @@ impl Lub: combine {
|
||||
}
|
||||
}
|
||||
|
||||
fn oncenesses(a: Onceness, b: Onceness) -> cres<Onceness> {
|
||||
match (a, b) {
|
||||
(Once, _) | (_, Once) => Ok(Once),
|
||||
(Many, Many) => Ok(Many)
|
||||
}
|
||||
}
|
||||
|
||||
fn ret_styles(r1: ret_style, r2: ret_style) -> cres<ret_style> {
|
||||
match (r1, r2) {
|
||||
(ast::return_val, _) |
|
||||
|
@ -93,6 +93,12 @@ impl Sub: combine {
|
||||
})
|
||||
}
|
||||
|
||||
fn oncenesses(a: Onceness, b: Onceness) -> cres<Onceness> {
|
||||
self.lub().oncenesses(a, b).compare(b, || {
|
||||
ty::terr_onceness_mismatch(expected_found(&self, a, b))
|
||||
})
|
||||
}
|
||||
|
||||
fn ret_styles(a: ret_style, b: ret_style) -> cres<ret_style> {
|
||||
self.lub().ret_styles(a, b).compare(b, || {
|
||||
ty::terr_ret_style_mismatch(expected_found(&self, a, b))
|
||||
|
@ -19,7 +19,8 @@ use syntax::codemap;
|
||||
use syntax::codemap::span;
|
||||
use syntax::print::pprust;
|
||||
use syntax::print::pprust::{path_to_str, proto_to_str,
|
||||
mode_to_str, purity_to_str};
|
||||
mode_to_str, purity_to_str,
|
||||
onceness_to_str};
|
||||
use syntax::{ast, ast_util};
|
||||
use syntax::ast_map;
|
||||
|
||||
@ -266,9 +267,14 @@ fn ty_to_str(cx: ctxt, typ: t) -> ~str {
|
||||
};
|
||||
modestr + ty_to_str(cx, ty)
|
||||
}
|
||||
fn fn_to_str(cx: ctxt, purity: ast::purity, proto: ty::fn_proto,
|
||||
fn fn_to_str(cx: ctxt,
|
||||
purity: ast::purity,
|
||||
proto: ty::fn_proto,
|
||||
onceness: ast::Onceness,
|
||||
ident: Option<ast::ident>,
|
||||
inputs: ~[arg], output: t, cf: ast::ret_style) -> ~str {
|
||||
inputs: ~[arg],
|
||||
output: t,
|
||||
cf: ast::ret_style) -> ~str {
|
||||
let mut s;
|
||||
|
||||
s = match purity {
|
||||
@ -276,6 +282,11 @@ fn ty_to_str(cx: ctxt, typ: t) -> ~str {
|
||||
_ => purity_to_str(purity) + ~" "
|
||||
};
|
||||
|
||||
s += match onceness {
|
||||
ast::Many => ~"",
|
||||
ast::Once => onceness_to_str(onceness) + ~" "
|
||||
};
|
||||
|
||||
s += ~"fn";
|
||||
|
||||
s += proto_ty_to_str(cx, proto);
|
||||
@ -298,8 +309,13 @@ fn ty_to_str(cx: ctxt, typ: t) -> ~str {
|
||||
}
|
||||
fn method_to_str(cx: ctxt, m: method) -> ~str {
|
||||
return fn_to_str(
|
||||
cx, m.fty.meta.purity, m.fty.meta.proto, Some(m.ident),
|
||||
m.fty.sig.inputs, m.fty.sig.output,
|
||||
cx,
|
||||
m.fty.meta.purity,
|
||||
m.fty.meta.proto,
|
||||
m.fty.meta.onceness,
|
||||
Some(m.ident),
|
||||
m.fty.sig.inputs,
|
||||
m.fty.sig.output,
|
||||
m.fty.meta.ret_style) + ~";";
|
||||
}
|
||||
fn field_to_str(cx: ctxt, f: field) -> ~str {
|
||||
@ -347,8 +363,14 @@ fn ty_to_str(cx: ctxt, typ: t) -> ~str {
|
||||
~"(" + str::connect(strs, ~",") + ~")"
|
||||
}
|
||||
ty_fn(ref f) => {
|
||||
fn_to_str(cx, f.meta.purity, f.meta.proto, None, f.sig.inputs,
|
||||
f.sig.output, f.meta.ret_style)
|
||||
fn_to_str(cx,
|
||||
f.meta.purity,
|
||||
f.meta.proto,
|
||||
f.meta.onceness,
|
||||
None,
|
||||
f.sig.inputs,
|
||||
f.sig.output,
|
||||
f.meta.ret_style)
|
||||
}
|
||||
ty_infer(infer_ty) => infer_ty.to_str(),
|
||||
ty_param({idx: id, _}) => {
|
||||
|
7
src/test/compile-fail/once-fn-subtyping.rs
Normal file
7
src/test/compile-fail/once-fn-subtyping.rs
Normal file
@ -0,0 +1,7 @@
|
||||
fn main() {
|
||||
let f: &once fn() = ||();
|
||||
let g: &fn() = f; //~ ERROR mismatched types
|
||||
let h: &fn() = ||();
|
||||
let i: &once fn() = h; // ok
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user