rustc: Implement parsing and typechecking for "once fn"

This commit is contained in:
Patrick Walton 2012-11-02 13:33:51 -07:00
parent 9aadfc3f4b
commit be93b29d30
22 changed files with 266 additions and 61 deletions

View File

@ -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>),

View File

@ -524,10 +524,11 @@ fn fold_field(f: ty_field, fld: ast_fold) -> ty_field {
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)),

View File

@ -287,7 +287,7 @@ fn get_id() -> node_id { next_node_id(self.sess) }
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 @@ fn parse_ty_fn(purity: ast::purity) -> ty_ {
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 @@ fn parse_ty(colons_before_params: bool) -> @Ty {
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 @@ fn mk_ty_path(i: ident) -> @Ty {
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) {

View File

@ -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",

View File

@ -394,8 +394,9 @@ fn print_field(s: ps, f: ast::ty_field) {
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_field(s: ps, field: ast::field) {
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 @@ fn opt_proto_to_str(opt_p: Option<ast::proto>) -> ~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 => (),

View File

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

View File

@ -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,

View File

@ -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| {

View File

@ -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)

View File

@ -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) {

View File

@ -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),

View File

@ -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: ~[],

View File

@ -126,6 +126,7 @@
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_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 to_str(s: ast::ret_style) -> ~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),

View File

@ -208,7 +208,8 @@ fn mk_maybe_vstore<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 mk_maybe_vstore<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 check_path_args(tcx: ty::ctxt,
};
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,

View File

@ -1310,7 +1310,10 @@ fn check_expr_fn(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_fn(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_fn(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 arg(m: ast::rmode, ty: ty::t) -> ty::arg {
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 arg(m: ast::rmode, ty: ty::t) -> ty::arg {
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,

View File

@ -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,

View File

@ -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 @@ fn substs(did: ast::def_id, as_: &ty::substs,
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,14 +313,18 @@ 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>(
self: &C, a_f: &ty::FnSig, b_f: &ty::FnSig) -> cres<ty::FnSig>

View File

@ -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 @@ fn purities(a: purity, b: purity) -> cres<purity> {
}
}
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) => {

View File

@ -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 @@ fn purities(a: purity, b: purity) -> cres<purity> {
}
}
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, _) |

View File

@ -93,6 +93,12 @@ fn purities(a: purity, b: purity) -> cres<purity> {
})
}
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))

View File

@ -19,7 +19,8 @@
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 fn_input_to_str(cx: ctxt, input: {mode: ast::mode, ty: t}) ->
};
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 fn_to_str(cx: ctxt, purity: ast::purity, proto: ty::fn_proto,
_ => 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 fn_to_str(cx: ctxt, purity: ast::purity, proto: ty::fn_proto,
}
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 field_to_str(cx: ctxt, f: field) -> ~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, _}) => {

View 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
}