diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2012-04-24 15:52:52 -0700 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2012-04-25 19:26:56 -0700 |
| commit | 825fd1808e2ac8763d16940531f037c9b387c871 (patch) | |
| tree | 493678053820169e7619bf741fa18fb3dbf72420 | |
| parent | 458d2ff067261ab646d914123f9c9c496cd612ae (diff) | |
lots of work to make iface/impls parameterized by regions
- paths can now take region parameters, replacing the dirty hack
I was doing before of abusing vstores. vstores are now a bit
of a hack though.
- fix various small bugs:
- we never checked that iface types were compatible when casting
to an iface with `as`
- we allowed nonsense like int<int>
- and more! (actually that may be it)
39 files changed, 849 insertions, 547 deletions
diff --git a/src/librustsyntax/ast.rs b/src/librustsyntax/ast.rs index 55bb480761f..48e8866d3f5 100644 --- a/src/librustsyntax/ast.rs +++ b/src/librustsyntax/ast.rs @@ -37,7 +37,11 @@ type ident = str; type fn_ident = option<ident>; #[auto_serialize] -type path = {span: span, global: bool, idents: [ident], types: [@ty]}; +type path = {span: span, + global: bool, + idents: [ident], + rp: option<@region>, + types: [@ty]}; #[auto_serialize] type crate_num = int; @@ -175,7 +179,7 @@ enum vstore { vstore_fixed(option<uint>), // [1,2,3,4]/_ or 4 vstore_uniq, // [1,2,3,4]/~ vstore_box, // [1,2,3,4]/@ - vstore_slice(region) // [1,2,3,4]/&(foo)? + vstore_slice(@region) // [1,2,3,4]/&(foo)? } pure fn is_blockish(p: ast::proto) -> bool { @@ -462,7 +466,7 @@ enum ty_ { ty_uniq(mt), ty_vec(mt), ty_ptr(mt), - ty_rptr(region, mt), + ty_rptr(@region, mt), ty_rec([ty_field]), ty_fn(proto, fn_decl), ty_tup([@ty]), @@ -671,8 +675,8 @@ enum item_ { class_ctor, region_param ), - item_iface([ty_param], [ty_method]), - item_impl([ty_param], option<@iface_ref> /* iface */, + item_iface([ty_param], region_param, [ty_method]), + item_impl([ty_param], region_param, option<@iface_ref> /* iface */, @ty /* self */, [@method]), } diff --git a/src/librustsyntax/ast_util.rs b/src/librustsyntax/ast_util.rs index f3c7e08ef9f..49a20393a5d 100644 --- a/src/librustsyntax/ast_util.rs +++ b/src/librustsyntax/ast_util.rs @@ -248,7 +248,8 @@ fn default_block(stmts1: [@stmt], expr1: option<@expr>, id1: node_id) -> } fn ident_to_path(s: span, i: ident) -> @path { - @{span: s, global: false, idents: [i], types: []} + @{span: s, global: false, idents: [i], + rp: none, types: []} } pure fn is_unguarded(&&a: arm) -> bool { diff --git a/src/librustsyntax/ext/auto_serialize.rs b/src/librustsyntax/ext/auto_serialize.rs index 0532a2c987b..7b90709b118 100644 --- a/src/librustsyntax/ext/auto_serialize.rs +++ b/src/librustsyntax/ext/auto_serialize.rs @@ -130,11 +130,11 @@ impl helpers for ext_ctxt { } fn path(span: span, strs: [str]) -> @ast::path { - @{span: span, global: false, idents: strs, types: []} + @{span: span, global: false, idents: strs, rp: none, types: []} } fn path_tps(span: span, strs: [str], tps: [@ast::ty]) -> @ast::path { - @{span: span, global: false, idents: strs, types: tps} + @{span: span, global: false, idents: strs, rp: none, types: tps} } fn ty_path(span: span, strs: [str], tps: [@ast::ty]) -> @ast::ty { @@ -193,7 +193,8 @@ impl helpers for ext_ctxt { } fn binder_pat(span: span, nm: str) -> @ast::pat { - let path = @{span: span, global: false, idents: [nm], types: []}; + let path = @{span: span, global: false, idents: [nm], + rp: none, types: []}; @{id: self.next_id(), node: ast::pat_ident(path, none), span: span} diff --git a/src/librustsyntax/ext/build.rs b/src/librustsyntax/ext/build.rs index ebf57745d9f..516deb1e793 100644 --- a/src/librustsyntax/ext/build.rs +++ b/src/librustsyntax/ext/build.rs @@ -30,7 +30,8 @@ fn mk_unary(cx: ext_ctxt, sp: span, op: ast::unop, e: @ast::expr) } fn mk_path(cx: ext_ctxt, sp: span, idents: [ast::ident]) -> @ast::expr { - let path = @{span: sp, global: false, idents: idents, types: []}; + let path = @{span: sp, global: false, idents: idents, + rp: none, types: []}; let pathexpr = ast::expr_path(path); ret @{id: cx.next_id(), node: pathexpr, span: sp}; } diff --git a/src/librustsyntax/ext/concat_idents.rs b/src/librustsyntax/ext/concat_idents.rs index 8d2c89c0d43..409a38b378d 100644 --- a/src/librustsyntax/ext/concat_idents.rs +++ b/src/librustsyntax/ext/concat_idents.rs @@ -17,6 +17,6 @@ fn expand_syntax_ext(cx: ext_ctxt, sp: codemap::span, arg: ast::mac_arg, ret @{id: cx.next_id(), node: ast::expr_path(@{span: sp, global: false, idents: [res], - types: []}), + rp: none, types: []}), span: sp}; } diff --git a/src/librustsyntax/ext/simplext.rs b/src/librustsyntax/ext/simplext.rs index f3d6b542d10..81eaa193f95 100644 --- a/src/librustsyntax/ext/simplext.rs +++ b/src/librustsyntax/ext/simplext.rs @@ -334,7 +334,8 @@ fn transcribe_path(cx: ext_ctxt, b: bindings, idx_path: @mut [uint], if vec::len(p.types) > 0u || vec::len(p.idents) != 1u { ret p; } alt follow_for_trans(cx, b.find(p.idents[0]), idx_path) { some(match_ident(id)) { - {span: id.span, global: false, idents: [id.node], types: []} + {span: id.span, global: false, idents: [id.node], + rp: none, types: []} } some(match_path(a_pth)) { *a_pth } some(m) { match_error(cx, m, "a path") } @@ -359,6 +360,7 @@ fn transcribe_expr(cx: ext_ctxt, b: bindings, idx_path: @mut [uint], (expr_path(@{span: id.span, global: false, idents: [id.node], + rp: none, types: []}), id.span) } some(match_path(a_pth)) { (expr_path(a_pth), s) } diff --git a/src/librustsyntax/fold.rs b/src/librustsyntax/fold.rs index e5c2c59a4d2..30e8c5173b2 100644 --- a/src/librustsyntax/fold.rs +++ b/src/librustsyntax/fold.rs @@ -287,12 +287,18 @@ fn noop_fold_item_underscore(i: item_, fld: ast_fold) -> item_ { with ctor}, rp) } - item_impl(tps, ifce, ty, methods) { - item_impl(tps, option::map(ifce, {|p| fold_iface_ref(p, fld)}), + item_impl(tps, rp, ifce, ty, methods) { + item_impl(fold_ty_params(tps, fld), + rp, + ifce.map { |p| fold_iface_ref(p, fld) }, fld.fold_ty(ty), - vec::map(methods, fld.fold_method)) + vec::map(methods, fld.fold_method)) + } + item_iface(tps, rp, methods) { + item_iface(fold_ty_params(tps, fld), + rp, + methods) } - item_iface(tps, methods) { item_iface(tps, methods) } item_res(decl, typms, body, did, cid, rp) { item_res(fold_fn_decl(decl, fld), fold_ty_params(typms, fld), @@ -565,6 +571,7 @@ fn noop_fold_ident(&&i: ident, _fld: ast_fold) -> ident { ret i; } fn noop_fold_path(&&p: path, fld: ast_fold) -> path { ret {span: fld.new_span(p.span), global: p.global, idents: vec::map(p.idents, fld.fold_ident), + rp: p.rp, types: vec::map(p.types, fld.fold_ty)}; } diff --git a/src/librustsyntax/parse/parser.rs b/src/librustsyntax/parse/parser.rs index dec7937a416..53d42038afa 100644 --- a/src/librustsyntax/parse/parser.rs +++ b/src/librustsyntax/parse/parser.rs @@ -175,7 +175,7 @@ fn parse_type_constr_arg(p: parser) -> @ast::ty_constr_arg { if p.token == token::DOT { // "*..." notation for record fields p.bump(); - let pth = parse_path(p); + let pth = parse_path_without_tps(p); carg = ast::carg_ident(pth); } // No literals yet, I guess? @@ -196,7 +196,7 @@ fn parse_constr_arg(args: [ast::arg], p: parser) -> @ast::constr_arg { fn parse_ty_constr(fn_args: [ast::arg], p: parser) -> @ast::constr { let lo = p.span.lo; - let path = parse_path(p); + let path = parse_path_without_tps(p); let args: {node: [@ast::constr_arg], span: span} = parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA), {|p| parse_constr_arg(fn_args, p)}, p); @@ -206,7 +206,7 @@ fn parse_ty_constr(fn_args: [ast::arg], p: parser) -> @ast::constr { fn parse_constr_in_type(p: parser) -> @ast::ty_constr { let lo = p.span.lo; - let path = parse_path(p); + let path = parse_path_without_tps(p); let args: [@ast::ty_constr_arg] = parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA), parse_type_constr_arg, p).node; @@ -231,52 +231,6 @@ fn parse_type_constraints(p: parser) -> [@ast::ty_constr] { ret parse_constrs(parse_constr_in_type, p); } -fn parse_ty_postfix(orig_t: ast::ty_, p: parser, colons_before_params: bool, - lo: uint) -> @ast::ty { - - - fn mk_ty(p: parser, t: ast::ty_, lo: uint, hi: uint) -> @ast::ty { - @{id: p.get_id(), - node: t, - span: mk_sp(lo, hi)} - } - - if p.token == token::BINOP(token::SLASH) { - let orig_hi = p.last_span.hi; - alt maybe_parse_vstore(p) { - none { } - some(v) { - let t = ast::ty_vstore(mk_ty(p, orig_t, lo, orig_hi), v); - ret mk_ty(p, t, lo, p.last_span.hi); - } - } - } - - if colons_before_params && p.token == token::MOD_SEP { - p.bump(); - expect(p, token::LT); - } else if !colons_before_params && p.token == token::LT { - p.bump(); - } else { - ret mk_ty(p, orig_t, lo, p.last_span.hi); - } - - // If we're here, we have explicit type parameter instantiation. - let seq = parse_seq_to_gt(some(token::COMMA), {|p| parse_ty(p, false)}, - p); - - alt orig_t { - ast::ty_path(pth, ann) { - ret mk_ty(p, ast::ty_path(@{span: mk_sp(lo, p.last_span.hi), - global: pth.global, - idents: pth.idents, - types: seq}, ann), - lo, p.last_span.hi); - } - _ { p.fatal("type parameter instantiation only allowed for paths"); } - } -} - fn parse_ret_ty(p: parser) -> (ast::ret_style, @ast::ty) { ret if eat(p, token::RARROW) { let lo = p.span.lo; @@ -295,7 +249,7 @@ fn parse_ret_ty(p: parser) -> (ast::ret_style, @ast::ty) { } } -fn region_from_name(p: parser, s: option<str>) -> ast::region { +fn region_from_name(p: parser, s: option<str>) -> @ast::region { let r = alt s { some (string) { // FIXME: To be consistent with our type resolution, the @@ -310,10 +264,26 @@ fn region_from_name(p: parser, s: option<str>) -> ast::region { none { ast::re_anon } }; - {id: p.get_id(), node: r} + @{id: p.get_id(), node: r} +} + +// Parses something like "&x" +fn parse_region(p: parser) -> @ast::region { + expect(p, token::BINOP(token::AND)); + alt p.token { + token::IDENT(sid, _) { + p.bump(); + let n = p.get_str(sid); + region_from_name(p, some(n)) + } + _ { + region_from_name(p, none) + } + } } -fn parse_region(p: parser) -> ast::region { +// Parses something like "&x." (note the trailing dot) +fn parse_region_dot(p: parser) -> @ast::region { let name = alt p.token { token::IDENT(sid, _) if p.look_ahead(1u) == token::DOT { @@ -384,7 +354,7 @@ fn parse_ty(p: parser, colons_before_params: bool) -> @ast::ty { t } else if p.token == token::BINOP(token::AND) { p.bump(); - let region = parse_region(p); + let region = parse_region_dot(p); let mt = parse_mt(p); ast::ty_rptr(region, mt) } else if eat_keyword(p, "fn") { @@ -398,10 +368,28 @@ fn parse_ty(p: parser, colons_before_params: bool) -> @ast::ty { expect_keyword(p, "fn"); ast::ty_fn(ast::proto_bare, parse_ty_fn(p)) } else if p.token == token::MOD_SEP || is_ident(p.token) { - let path = parse_path(p); + let path = parse_path_with_tps(p, colons_before_params); ast::ty_path(path, p.get_id()) } else { p.fatal("expecting type"); }; - ret parse_ty_postfix(t, p, colons_before_params, lo); + + fn mk_ty(p: parser, t: ast::ty_, lo: uint, hi: uint) -> @ast::ty { + @{id: p.get_id(), + node: t, + span: mk_sp(lo, hi)} + } + + let ty = mk_ty(p, t, lo, p.last_span.hi); + + // Consider a vstore suffix like /@ or /~ + alt maybe_parse_vstore(p) { + none { + ret ty; + } + some(v) { + let t1 = ast::ty_vstore(ty, v); + ret mk_ty(p, t1, lo, p.last_span.hi); + } + } } fn parse_arg_mode(p: parser) -> ast::mode { @@ -484,17 +472,7 @@ fn maybe_parse_vstore(p: parser) -> option<ast::vstore> { p.bump(); some(ast::vstore_fixed(some(i as uint))) } token::BINOP(token::AND) { - p.bump(); - alt p.token { - token::IDENT(sid, _) { - p.bump(); - let n = p.get_str(sid); - some(ast::vstore_slice(region_from_name(p, some(n)))) - } - _ { - some(ast::vstore_slice(region_from_name(p, none))) - } - } + some(ast::vstore_slice(parse_region(p))) } _ { none @@ -530,18 +508,19 @@ fn parse_lit(p: parser) -> ast::lit { ret {node: lit, span: mk_sp(lo, p.last_span.hi)}; } -fn parse_path(p: parser) -> @ast::path { +fn parse_path_without_tps(p: parser) -> @ast::path { let lo = p.span.lo; let global = eat(p, token::MOD_SEP); let mut ids = [parse_ident(p)]; while p.look_ahead(1u) != token::LT && eat(p, token::MOD_SEP) { ids += [parse_ident(p)]; } - @{span: mk_sp(lo, p.last_span.hi), global: global, idents: ids, types: []} + @{span: mk_sp(lo, p.last_span.hi), global: global, + idents: ids, rp: none, types: []} } fn parse_value_path(p: parser) -> @ast::path { - let pt = parse_path(p); + let pt = parse_path_without_tps(p); let last_word = vec::last(pt.idents); if is_restricted_keyword(p, last_word) { p.fatal("found " + last_word + " in expression position"); @@ -549,16 +528,45 @@ fn parse_value_path(p: parser) -> @ast::path { pt } -fn parse_path_and_ty_param_substs(p: parser, colons: bool) -> @ast::path { +fn parse_path_with_tps(p: parser, colons: bool) -> @ast::path { + #debug["parse_path_with_tps(colons=%b)", colons]; + let lo = p.span.lo; - let path = parse_path(p); - let b = if colons { eat(p, token::MOD_SEP) } - else { p.token == token::LT }; - if b { - let seq = parse_seq_lt_gt(some(token::COMMA), - {|p| parse_ty(p, false)}, p); - @{span: mk_sp(lo, seq.span.hi), types: seq.node with *path} - } else { path } + let path = parse_path_without_tps(p); + if colons && !eat(p, token::MOD_SEP) { + ret path; + } + + // Parse the region parameter, if any, which will + // be written "foo/&x" + let rp = { + // Hack: avoid parsing vstores like /@ and /~. This is painful + // because the notation for region bounds and the notation for vstores + // is... um... the same. I guess that's my fault. This is still not + // ideal as for str/& we end up parsing more than we ought to and have + // to sort it out later. + if p.token == token::BINOP(token::SLASH) + && p.look_ahead(1u) == token::BINOP(token::AND) { + + expect(p, token::BINOP(token::SLASH)); + some(parse_region(p)) + } else { + none + } + }; + + // Parse any type parameters which may appear: + let tps = { + if p.token == token::LT { + parse_seq_lt_gt(some(token::COMMA), {|p| parse_ty(p, false)}, p) + } else { + {node: [], span: path.span} + } + }; + + ret @{span: mk_sp(lo, tps.span.hi), + rp: rp, + types: tps.node with *path}; } fn parse_mutability(p: parser) -> ast::mutability { @@ -803,7 +811,7 @@ fn parse_bottom_expr(p: parser) -> pexpr { is_ident(p.token) && !is_keyword(p, "true") && !is_keyword(p, "false") { check_restricted_keywords(p); - let pth = parse_path_and_ty_param_substs(p, true); + let pth = parse_path_with_tps(p, true); hi = pth.span.hi; ex = ast::expr_path(pth); } else { @@ -850,7 +858,7 @@ fn parse_syntax_ext_naked(p: parser, lo: uint) -> @ast::expr { token::IDENT(_, _) {} _ { p.fatal("expected a syntax expander name"); } } - let pth = parse_path(p); + let pth = parse_path_without_tps(p); //temporary for a backwards-compatible cycle: let sep = seq_sep(token::COMMA); let mut e = none; @@ -1424,7 +1432,7 @@ fn parse_pat(p: parser) -> @ast::pat { else { none }; pat = ast::pat_ident(name, sub); } else { - let enum_path = parse_path_and_ty_param_substs(p, true); + let enum_path = parse_path_with_tps(p, true); hi = enum_path.span.hi; let mut args: [@ast::pat] = []; let mut star_pat = false; @@ -1779,24 +1787,39 @@ fn parse_method(p: parser, pr: ast::privacy) -> @ast::method { } fn parse_item_iface(p: parser, attrs: [ast::attribute]) -> @ast::item { - let lo = p.last_span.lo, ident = parse_ident(p), - tps = parse_ty_params(p), meths = parse_ty_methods(p); + let lo = p.last_span.lo, ident = parse_ident(p); + let rp = parse_region_param(p); + let tps = parse_ty_params(p); + let meths = parse_ty_methods(p); ret mk_item(p, lo, p.last_span.hi, ident, - ast::item_iface(tps, meths), attrs); + ast::item_iface(tps, rp, meths), attrs); } -// Parses three variants (with the initial params always optional): -// impl <T: copy> of to_str for [T] { ... } -// impl name<T> of to_str for [T] { ... } -// impl name<T> for [T] { ... } +// Parses three variants (with the region/type params always optional): +// impl /&<T: copy> of to_str for [T] { ... } +// impl name/&<T> of to_str for [T] { ... } +// impl name/&<T> for [T] { ... } fn parse_item_impl(p: parser, attrs: [ast::attribute]) -> @ast::item { let lo = p.last_span.lo; - let mut (ident, tps) = if !is_keyword(p, "of") { - if p.token == token::LT { (none, parse_ty_params(p)) } - else { (some(parse_ident(p)), parse_ty_params(p)) } - } else { (none, []) }; + fn wrap_path(p: parser, pt: @ast::path) -> @ast::ty { + @{id: p.get_id(), node: ast::ty_path(pt, p.get_id()), span: pt.span} + } + let mut (ident, rp, tps) = { + if p.token == token::LT { + (none, ast::rp_none, parse_ty_params(p)) + } else if p.token == token::BINOP(token::SLASH) { + (none, parse_region_param(p), parse_ty_params(p)) + } + else if is_keyword(p, "of") { + (none, ast::rp_none, []) + } else { + let id = parse_ident(p); + let rp = parse_region_param(p); + (some(id), rp, parse_ty_params(p)) + } + }; let ifce = if eat_keyword(p, "of") { - let path = parse_path_and_ty_param_substs(p, false); + let path = parse_path_with_tps(p, false); if option::is_none(ident) { ident = some(vec::last(path.idents)); } @@ -1812,7 +1835,7 @@ fn parse_item_impl(p: parser, attrs: [ast::attribute]) -> @ast::item { expect(p, token::LBRACE); while !eat(p, token::RBRACE) { meths += [parse_method(p, ast::pub)]; } ret mk_item(p, lo, p.last_span.hi, ident, - ast::item_impl(tps, ifce, ty, meths), attrs); + ast::item_impl(tps, rp, ifce, ty, meths), attrs); } fn parse_item_res(p: parser, attrs: [ast::attribute]) -> @ast::item { @@ -1842,21 +1865,32 @@ fn parse_item_res(p: parser, attrs: [ast::attribute]) -> @ast::item { attrs); } -// Instantiates ident <i> with references to <typarams> as arguments +// Instantiates ident <i> with references to <typarams> as arguments. Used to +// create a path that refers to a class which will be defined as the return +// type of the ctor function. fn ident_to_path_tys(p: parser, i: ast::ident, + rp: ast::region_param, typarams: [ast::ty_param]) -> @ast::path { let s = p.last_span; + + // Hack. But then, this whole function is in service of a hack. + let a_r = alt rp { + ast::rp_none { none } + ast::rp_self { some(region_from_name(p, some("self"))) } + }; + @{span: s, global: false, idents: [i], + rp: a_r, types: vec::map(typarams, {|tp| @{id: p.get_id(), - node: ast::ty_path(ident_to_path(s, tp.ident), - p.get_id()), + node: ast::ty_path(ident_to_path(s, tp.ident), p.get_id()), span: s}}) } } fn parse_iface_ref(p:parser) -> @ast::iface_ref { - @{path: parse_path(p), id: p.get_id()} + @{path: parse_path_with_tps(p, false), + id: p.get_id()} } fn parse_iface_ref_list(p:parser) -> [@ast::iface_ref] { @@ -1869,7 +1903,7 @@ fn parse_item_class(p: parser, attrs: [ast::attribute]) -> @ast::item { let class_name = parse_value_ident(p); let rp = parse_region_param(p); let ty_params = parse_ty_params(p); - let class_path = ident_to_path_tys(p, class_name, ty_params); + let class_path = ident_to_path_tys(p, class_name, rp, ty_params); let ifaces : [@ast::iface_ref] = if eat_keyword(p, "implements") { parse_iface_ref_list(p) } else { [] }; @@ -2240,7 +2274,7 @@ fn parse_view_path(p: parser) -> @ast::view_path { path += [id]; } let path = @{span: mk_sp(lo, p.span.hi), global: false, - idents: path, types: []}; + idents: path, rp: none, types: []}; ret @spanned(lo, p.span.hi, ast::view_path_simple(first_ident, path, p.get_id())); } @@ -2264,7 +2298,8 @@ fn parse_view_path(p: parser) -> @ast::view_path { seq_sep(token::COMMA), parse_path_list_ident, p).node; let path = @{span: mk_sp(lo, p.span.hi), - global: false, idents: path, types: []}; + global: false, idents: path, + rp: none, types: []}; ret @spanned(lo, p.span.hi, ast::view_path_list(path, idents, p.get_id())); } @@ -2273,7 +2308,8 @@ fn parse_view_path(p: parser) -> @ast::view_path { token::BINOP(token::STAR) { p.bump(); let path = @{span: mk_sp(lo, p.span.hi), - global: false, idents: path, types: []}; + global: false, idents: path, + rp: none, types: []}; ret @spanned(lo, p.span.hi, ast::view_path_glob(path, p.get_id())); } @@ -2286,7 +2322,7 @@ fn parse_view_path(p: parser) -> @ast::view_path { } let last = path[vec::len(path) - 1u]; let path = @{span: mk_sp(lo, p.span.hi), global: false, - idents: path, types: []}; + idents: path, rp: none, types: []}; ret @spanned(lo, p.span.hi, ast::view_path_simple(last, path, p.get_id())); } diff --git a/src/librustsyntax/print/pprust.rs b/src/librustsyntax/print/pprust.rs index e7be554fca8..0ccf2399292 100644 --- a/src/librustsyntax/print/pprust.rs +++ b/src/librustsyntax/print/pprust.rs @@ -325,11 +325,14 @@ fn print_native_mod(s: ps, nmod: ast::native_mod, attrs: [ast::attribute]) { for nmod.items.each {|item| print_native_item(s, item); } } -fn print_region(s: ps, region: ast::region) { +fn print_region(s: ps, region: @ast::region) { alt region.node { - ast::re_anon { /* no-op */ } - ast::re_named(name) { word(s.s, name); word(s.s, "."); } - ast::re_static { word(s.s, "static"); word(s.s, "."); } + ast::re_anon { word_space(s, "&"); } + ast::re_static { word_space(s, "&static"); } + ast::re_named(name) { + word(s.s, "&"); + word_space(s, name); + } } } @@ -353,8 +356,10 @@ fn print_type(s: ps, &&ty: @ast::ty) { } ast::ty_ptr(mt) { word(s.s, "*"); print_mt(s, mt); } ast::ty_rptr(region, mt) { - word(s.s, "&"); - print_region(s, region); + alt region.node { + ast::re_anon { word(s.s, "&"); } + _ { print_region(s, region); word(s.s, "."); } + } print_mt(s, mt); } ast::ty_rec(fields) { @@ -556,9 +561,10 @@ fn print_item(s: ps, &&item: @ast::item) { } bclose(s, item.span); } - ast::item_impl(tps, ifce, ty, methods) { + ast::item_impl(tps, rp, ifce, ty, methods) { head(s, "impl"); word(s.s, item.ident); + print_region_param(s, rp); print_type_params(s, tps); space(s.s); option::iter(ifce, {|p| @@ -575,9 +581,10 @@ fn print_item(s: ps, &&item: @ast::item) { } bclose(s, item.span); } - ast::item_iface(tps, methods) { + ast::item_iface(tps, rp, methods) { head(s, "iface"); word(s.s, item.ident); + print_region_param(s, rp); print_type_params(s, tps); word(s.s, " "); bopen(s); @@ -831,16 +838,7 @@ fn print_vstore(s: ps, t: ast::vstore) { ast::vstore_fixed(none) { word_space(s, "/_"); } ast::vstore_uniq { word_space(s, "/~"); } ast::vstore_box { word_space(s, "/@"); } - ast::vstore_slice(r) { - alt r.node { - ast::re_anon { word_space(s, "/&"); } - ast::re_static { word_space(s, "/&static"); } - ast::re_named(name) { - word(s.s, "/&"); - word_space(s, name); - } - } - } + ast::vstore_slice(r) { word(s.s, "/"); print_region(s, r); } } } @@ -1225,11 +1223,22 @@ fn print_path(s: ps, &&path: @ast::path, colons_before_params: bool) { if first { first = false; } else { word(s.s, "::"); } word(s.s, id); } - if vec::len(path.types) > 0u { + if path.rp.is_some() || !path.types.is_empty() { if colons_before_params { word(s.s, "::"); } - word(s.s, "<"); - commasep(s, inconsistent, path.types, print_type); - word(s.s, ">"); + + alt path.rp { + none { /* ok */ } + some(r) { + word(s.s, "/"); + print_region(s, r); + } + } + + if !path.types.is_empty() { + word(s.s, "<"); + commasep(s, inconsistent, path.types, print_type); + word(s.s, ">"); + } } } diff --git a/src/librustsyntax/visit.rs b/src/librustsyntax/visit.rs index ad6b787f180..04b6c002cb2 100644 --- a/src/librustsyntax/visit.rs +++ b/src/librustsyntax/visit.rs @@ -132,7 +132,7 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) { for vr.node.args.each {|va| v.visit_ty(va.ty, e, v); } } } - item_impl(tps, ifce, ty, methods) { + item_impl(tps, _rp, ifce, ty, methods) { v.visit_ty_params(tps, e, v); option::iter(ifce, {|p| visit_path(p.path, e, v)}); v.visit_ty(ty, e, v); @@ -149,7 +149,7 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) { visit_class_ctor_helper(ctor, i.ident, tps, ast_util::local_def(i.id), e, v); } - item_iface(tps, methods) { + item_iface(tps, _rp, methods) { v.visit_ty_params(tps, e, v); for methods.each {|m| for m.decl.inputs.each {|a| v.visit_ty(a.ty, e, v); } diff --git a/src/rustc/front/test.rs b/src/rustc/front/test.rs index 270b2a8b7e3..258c49daa9d 100644 --- a/src/rustc/front/test.rs +++ b/src/rustc/front/test.rs @@ -207,7 +207,7 @@ fn nospan<T: copy>(t: T) -> ast::spanned<T> { } fn path_node(ids: [ast::ident]) -> @ast::path { - @{span: dummy_sp(), global: false, idents: ids, types: []} + @{span: dummy_sp(), global: false, idents: ids, rp: none, types: []} } fn mk_tests(cx: test_ctxt) -> @ast::item { diff --git a/src/rustc/metadata/encoder.rs b/src/rustc/metadata/encoder.rs index ae3bc4e0a2c..a1c996dccf1 100644 --- a/src/rustc/metadata/encoder.rs +++ b/src/rustc/metadata/encoder.rs @@ -185,14 +185,14 @@ fn encode_module_item_paths(ebml_w: ebml::writer, ecx: @encode_ctxt, ebml_w.end_tag(); encode_enum_variant_paths(ebml_w, variants, path, index); } - item_iface(_, _) { + item_iface(*) { add_to_index(ebml_w, path, index, it.ident); ebml_w.start_tag(tag_paths_data_item); encode_name(ebml_w, it.ident); encode_def_id(ebml_w, local_def(it.id)); ebml_w.end_tag(); } - item_impl(_, _, _, _) {} + item_impl(*) {} } } } @@ -649,11 +649,12 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item, encode_path(ebml_w, path, ast_map::path_name(item.ident)); ebml_w.end_tag(); } - item_impl(tps, ifce, _, methods) { + item_impl(tps, rp, ifce, _, methods) { add_to_index(); ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, local_def(item.id)); encode_family(ebml_w, 'i'); + encode_region_param(ebml_w, rp); encode_type_param_bounds(ebml_w, ecx, tps); encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); encode_name(ebml_w, item.ident); @@ -681,11 +682,12 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item, should_inline(m.attrs), item.id, m, tps + m.tps); } } - item_iface(tps, ms) { + item_iface(tps, rp, ms) { add_to_index(); ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, local_def(item.id)); encode_family(ebml_w, 'I'); + encode_region_param(ebml_w, rp); encode_type_param_bounds(ebml_w, ecx, tps); encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); encode_name(ebml_w, item.ident); diff --git a/src/rustc/metadata/tydecode.rs b/src/rustc/metadata/tydecode.rs index 872dfa8b8d4..46c39256938 100644 --- a/src/rustc/metadata/tydecode.rs +++ b/src/rustc/metadata/tydecode.rs @@ -104,7 +104,8 @@ fn parse_path(st: @pstate) -> @ast::path { c { if c == '(' { ret @{span: ast_util::dummy_sp(), - global: false, idents: idents, types: []}; + global: false, idents: idents, + rp: none, types: []}; } else { idents += [parse_ident_(st, is_last)]; } } } @@ -286,12 +287,11 @@ fn parse_ty(st: @pstate, conv: conv_did) -> ty::t { ret ty::mk_enum(st.tcx, def, substs); } 'x' { - assert (next(st) == '['); + assert next(st) == '['; let def = parse_def(st, conv); - let mut params: [ty::t] = []; - while peek(st) != ']' { params += [parse_ty(st, conv)]; } - st.pos = st.pos + 1u; - ret ty::mk_iface(st.tcx, def, params); + let substs = parse_substs(st, conv); + assert next(st) == ']'; + ret ty::mk_iface(st.tcx, def, substs); } 'p' { let did = parse_def(st, conv); @@ -299,10 +299,9 @@ fn parse_ty(st: @pstate, conv: conv_did) -> ty::t { } 's' { assert next(st) == '['; - let mut params = []; - while peek(st) != ']' { params += [parse_ty(st, conv)]; } - st.pos += 1u; - ret ty::mk_self(st.tcx, params); + let substs = parse_substs(st, conv); + assert next(st) == ']'; + ret ty::mk_self(st.tcx, substs); } '@' { ret ty::mk_box(st.tcx, parse_mt(st, conv)); } '~' { ret ty::mk_uniq(st.tcx, parse_mt(st, conv)); } @@ -344,7 +343,7 @@ fn parse_ty(st: @pstate, conv: conv_did) -> ty::t { parse_ty_rust_fn(st, conv, proto) } 'r' { - assert (next(st) == '['); + assert next(st) == '['; let def = parse_def(st, conv); let inner = parse_ty(st, conv); let substs = parse_substs(st, conv); diff --git a/src/rustc/metadata/tyencode.rs b/src/rustc/metadata/tyencode.rs index 763e710b07a..130e7f40916 100644 --- a/src/rustc/metadata/tyencode.rs +++ b/src/rustc/metadata/tyencode.rs @@ -220,11 +220,11 @@ fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) { enc_substs(w, cx, substs); w.write_char(']'); } - ty::ty_iface(def, tys) { + ty::ty_iface(def, substs) { w.write_str("x["/&); w.write_str(cx.ds(def)); w.write_char('|'); - for tys.each {|t| enc_ty(w, cx, t); } + enc_substs(w, cx, substs); w.write_char(']'); } ty::ty_tup(ts) { @@ -281,9 +281,9 @@ fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) { w.write_char('|'); w.write_str(uint::str(id)); } - ty::ty_self(tps) { + ty::ty_self(substs) { w.write_str("s["/&); - for tps.each {|t| enc_ty(w, cx, t); } + enc_substs(w, cx, substs); w.write_char(']'); } ty::ty_type { w.write_char('Y'); } diff --git a/src/rustc/middle/ast_map.rs b/src/rustc/middle/ast_map.rs index 2988cdc6f40..f2300f9695a 100644 --- a/src/rustc/middle/ast_map.rs +++ b/src/rustc/middle/ast_map.rs @@ -177,7 +177,7 @@ fn map_item(i: @item, cx: ctx, v: vt) { let item_path = @cx.path; cx.map.insert(i.id, node_item(i, item_path)); alt i.node { - item_impl(_, _, _, ms) { + item_impl(_, _, _, _, ms) { let impl_did = ast_util::local_def(i.id); for ms.each {|m| map_method(impl_did, extend(cx, i.ident), m, cx); diff --git a/src/rustc/middle/infer.rs b/src/rustc/middle/infer.rs index 1e513d3da8c..d5e22815b7b 100644 --- a/src/rustc/middle/infer.rs +++ b/src/rustc/middle/infer.rs @@ -15,6 +15,7 @@ import util::common::{indent, indenter}; export infer_ctxt; export new_infer_ctxt; export mk_subty; +export mk_subr; export mk_eqty; export mk_assignty; export resolve_shallow; @@ -73,6 +74,11 @@ fn mk_subty(cx: infer_ctxt, a: ty::t, b: ty::t) -> ures { indent {|| cx.commit {|| sub(cx).tys(a, b) } }.to_ures() } +fn mk_subr(cx: infer_ctxt, a: ty::region, b: ty::region) -> ures { + #debug["mk_subr(%s <: %s)", a.to_str(cx), b.to_str(cx)]; + indent {|| cx.commit {|| sub(cx).regions(a, b) } }.to_ures() +} + fn mk_eqty(cx: infer_ctxt, a: ty::t, b: ty::t) -> ures { #debug["mk_eqty(%s <: %s)", a.to_str(cx), b.to_str(cx)]; indent {|| cx.commit {|| cx.eq_tys(a, b) } }.to_ures() @@ -1120,10 +1126,10 @@ fn super_tys<C:combine>( } } - (ty::ty_iface(a_id, a_tps), ty::ty_iface(b_id, b_tps)) + (ty::ty_iface(a_id, a_substs), ty::ty_iface(b_id, b_substs)) if a_id == b_id { - self.tps(a_tps, b_tps).chain {|tps| - ok(ty::mk_iface(tcx, a_id, tps)) + self.substs(a_substs, b_substs).chain {|substs| + ok(ty::mk_iface(tcx, a_id, substs)) } } diff --git a/src/rustc/middle/resolve.rs b/src/rustc/middle/resolve.rs index 1d6d506dbc1..150466a7097 100644 --- a/src/rustc/middle/resolve.rs +++ b/src/rustc/middle/resolve.rs @@ -435,14 +435,14 @@ fn resolve_names(e: @env, c: @ast::crate) { non-class items */ alt i.node { - ast::item_class(_, ifaces, _, _, _) { - /* visit the iface paths... */ - for ifaces.each {|p| resolve_iface_ref(p, sc, e)}; - } - ast::item_impl(_, ifce, _, _) { - option::iter(ifce, {|p| resolve_iface_ref(p, sc, e)}); - } - _ {} + ast::item_class(_, ifaces, _, _, _) { + /* visit the iface paths... */ + for ifaces.each {|p| resolve_iface_ref(p, sc, e) ;} + } + ast::item_impl(_, _, ifce, _, _) { + ifce.iter { |p| resolve_iface_ref(p, sc, e); } + } + _ {} } } @@ -540,7 +540,7 @@ fn visit_item_with_scope(e: @env, i: @ast::item, sc: scopes, v: vt<scopes>) { let sc = cons(scope_item(i), @sc); alt i.node { - ast::item_impl(tps, ifce, sty, methods) { + ast::item_impl(tps, _, ifce, sty, methods) { visit::visit_ty_params(tps, sc, v); option::iter(ifce) {|p| visit::visit_path(p.path, sc, v)}; v.visit_ty(sty, sc, v); @@ -551,7 +551,7 @@ fn visit_item_with_scope(e: @env, i: @ast::item, sc: scopes, v: vt<scopes>) { m.decl, m.body, m.span, m.id, msc, v); } } - ast::item_iface(tps, methods) { + ast::item_iface(tps, _, methods) { visit::visit_ty_params(tps, sc, v); for methods.each {|m| let msc = cons(scope_method(i.id, tps + m.tps), @sc); @@ -1008,13 +1008,13 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace, } scope_item(it) { alt it.node { - ast::item_impl(tps, _, _, _) { + ast::item_impl(tps, _, _, _, _) { if ns == ns_type { ret lookup_in_ty_params(e, name, tps); } } ast::item_enum(_, tps, _) | ast::item_ty(_, tps, _) { if ns == ns_type { ret lookup_in_ty_params(e, name, tps); } } - ast::item_iface(tps, _) { + ast::item_iface(tps, _, _) { if ns == ns_type { if name == "self" { ret some(def_self(it.id)); @@ -1286,7 +1286,7 @@ fn lookup_in_block(e: env, name: ident, sp: span, b: ast::blk_, pos: uint, fn found_def_item(i: @ast::item, ns: namespace) -> option<def> { alt i.node { - ast::item_const(_, _) { + ast::item_const(*) { if ns == ns_val { ret some(ast::def_const(local_def(i.id))); } } @@ -1301,7 +1301,7 @@ fn found_def_item(i: @ast::item, ns: namespace) -> option<def> { ast::item_native_mod(_) { if ns == ns_module { ret some(ast::def_native_mod(local_def(i.id))); } } - ast::item_ty(_, _, _) | item_iface(_, _) | item_enum(_, _, _) { + ast::item_ty(*) | item_iface(*) | item_enum(*) { if ns == ns_type { ret some(ast::def_ty(local_def(i.id))); } } ast::item_res(_, _, _, _, ctor_id, _) { @@ -1313,12 +1313,12 @@ fn found_def_item(i: @ast::item, ns: namespace) -> option<def> { _ { } } } - ast::item_class(_, _, _, _, _) { + ast::item_class(*) { if ns == ns_type { ret some(ast::def_class(local_def(i.id))); } } - ast::item_impl(_,_,_,_) { /* ??? */ } + ast::item_impl(*) { /* ??? */ } } ret none; } @@ -1607,8 +1607,7 @@ fn index_mod(md: ast::_mod) -> mod_index { alt it.node { ast::item_const(_, _) | ast::item_fn(_, _, _) | ast::item_mod(_) | ast::item_native_mod(_) | ast::item_ty(_, _, _) | - ast::item_res(_, _, _, _, _, _) | - ast::item_impl(_, _, _, _) | ast::item_iface(_, _) { + ast::item_res(*) | ast::item_impl(*) | ast::item_iface(*) { add_to_index(index, it.ident, mie_item(it)); } ast::item_enum(variants, _, _) { @@ -1753,11 +1752,11 @@ fn check_item(e: @env, i: @ast::item, &&x: (), v: vt<()>) { ensure_unique(*e, i.span, ty_params, {|tp| tp.ident}, "type parameter"); } - ast::item_iface(_, methods) { + ast::item_iface(_, _, methods) { ensure_unique(*e, i.span, methods, {|m| m.ident}, "method"); } - ast::item_impl(_, _, _, methods) { + ast::item_impl(_, _, _, _, methods) { ensure_unique(*e, i.span, methods, {|m| m.ident}, "method"); } @@ -1832,13 +1831,13 @@ fn check_block(e: @env, b: ast::blk, &&x: (), v: vt<()>) { ast::item_mod(_) | ast::item_native_mod(_) { add_name(mods, it.span, it.ident); } - ast::item_const(_, _) | ast::item_fn(_, _, _) { + ast::item_const(_, _) | ast::item_fn(*) { add_name(values, it.span, it.ident); } - ast::item_ty(_, _, _) | ast::item_iface(_, _) { + ast::item_ty(*) | ast::item_iface(*) { add_name(types, it.span, it.ident); } - ast::item_res(_, _, _, _, _, _) { + ast::item_res(*) { add_name(types, it.span, it.ident); add_name(values, it.span, it.ident); } @@ -2196,7 +2195,7 @@ fn find_impls_in_item(e: env, i: @ast::item, &impls: [@_impl], name: option<ident>, ck_exports: option<@indexed_mod>) { alt i.node { - ast::item_impl(_, ifce, _, mthds) { + ast::item_impl(_, _, ifce, _, mthds) { if alt name { some(n) { n == i.ident } _ { true } } && alt ck_exports { some(m) { is_exported(e, i.ident, m) } diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index 88df4687d61..6f05a0df434 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -4477,7 +4477,7 @@ fn trans_item(ccx: @crate_ctxt, item: ast::item) { } } } - ast::item_impl(tps, _, _, ms) { + ast::item_impl(tps, _rp, _, _, ms) { impl::trans_impl(ccx, *path, item.ident, ms, tps); } ast::item_res(decl, tps, body, dtor_id, ctor_id, _) { diff --git a/src/rustc/middle/trans/impl.rs b/src/rustc/middle/trans/impl.rs index 8b1873247d3..b511d653bdf 100644 --- a/src/rustc/middle/trans/impl.rs +++ b/src/rustc/middle/trans/impl.rs @@ -90,7 +90,7 @@ fn method_with_name(ccx: @crate_ctxt, impl_id: ast::def_id, name: ast::ident) -> ast::def_id { if impl_id.crate == ast::local_crate { alt check ccx.tcx.items.get(impl_id.node) { - ast_map::node_item(@{node: ast::item_impl(_, _, _, ms), _}, _) { + ast_map::node_item(@{node: ast::item_impl(_, _, _, _, ms), _}, _) { method_from_methods(ms, name) } ast_map::node_item(@{node: diff --git a/src/rustc/middle/trans/reachable.rs b/src/rustc/middle/trans/reachable.rs index 05cc2224384..bd4800c970a 100644 --- a/src/rustc/middle/trans/reachable.rs +++ b/src/rustc/middle/trans/reachable.rs @@ -94,7 +94,7 @@ fn traverse_public_item(cx: ctx, item: @item) { traverse_inline_body(cx, blk); } } - item_impl(tps, _, _, ms) { + item_impl(tps, _, _, _, ms) { for vec::each(ms) {|m| if tps.len() > 0u || m.tps.len() > 0u || attr::find_inline_attr(m.attrs) != attr::ia_none { @@ -117,8 +117,8 @@ fn traverse_public_item(cx: ctx, item: @item) { } } } - item_const(_, _) | item_ty(_, _, _) | - item_enum(_, _, _) | item_iface(_, _) {} + item_const(*) | item_ty(*) | + item_enum(*) | item_iface(*) {} } } diff --git a/src/rustc/middle/tstate/pre_post_conditions.rs b/src/rustc/middle/tstate/pre_post_conditions.rs index 03f5a56a1c0..4cc00940202 100644 --- a/src/rustc/middle/tstate/pre_post_conditions.rs +++ b/src/rustc/middle/tstate/pre_post_conditions.rs @@ -48,7 +48,7 @@ fn find_pre_post_item(ccx: crate_ctxt, i: item) { } item_mod(m) { find_pre_post_mod(m); } item_native_mod(nm) { find_pre_post_native_mod(nm); } - item_ty(_, _, _) | item_enum(_, _, _) | item_iface(_, _) { ret; } + item_ty(*) | item_enum(*) | item_iface(*) { ret; } item_res(_, _, body, dtor_id, _, _) { let fcx = {enclosing: ccx.fm.get(dtor_id), @@ -60,7 +60,7 @@ fn find_pre_post_item(ccx: crate_ctxt, i: item) { item_class(_,_,_,_,_) { fail "find_pre_post_item: shouldn't be called on item_class"; } - item_impl(_, _, _, ms) { + item_impl(_, _, _, _, ms) { for ms.each {|m| find_pre_post_method(ccx, m); } } } diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index 2f49958455f..9830fe9c36b 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -325,14 +325,14 @@ enum sty { ty_rptr(region, mt), ty_rec([field]), ty_fn(fn_ty), - ty_iface(def_id, [t]), + ty_iface(def_id, substs), ty_class(def_id, substs), ty_res(def_id, t, substs), ty_tup([t]), ty_var(ty_vid), // type variable during typechecking ty_param(uint, def_id), // type parameter - ty_self([t]), // interface method self type + ty_self(substs), // interface method self type ty_type, // type_desc* ty_opaque_box, // used by monomorphizer to represent any @ box @@ -520,16 +520,10 @@ fn mk_t_with_id(cx: ctxt, st: sty, o_def_id: option<ast::def_id>) -> t { ty_opaque_box {} ty_param(_, _) { has_params = true; } ty_var(_) | ty_self(_) { has_vars = true; } - ty_enum(_, substs) | ty_class(_, substs) { + ty_enum(_, substs) | ty_class(_, substs) | ty_iface(_, substs) { derive_sflags(has_params, has_vars, has_regions, has_resources, substs); } - ty_iface(_, tys) { - for tys.each {|tt| - derive_flags(has_params, has_vars, has_regions, - has_resources, tt); - } - } ty_box(m) | ty_uniq(m) | ty_vec(m) | ty_evec(m, _) | ty_ptr(m) { derive_flags(has_params, has_vars, has_regions, has_resources, m.ty); @@ -652,8 +646,8 @@ fn mk_tup(cx: ctxt, ts: [t]) -> t { mk_t(cx, ty_tup(ts)) } fn mk_fn(cx: ctxt, fty: fn_ty) -> t { mk_t(cx, ty_fn(fty)) } -fn mk_iface(cx: ctxt, did: ast::def_id, tys: [t]) -> t { - mk_t(cx, ty_iface(did, tys)) +fn mk_iface(cx: ctxt, did: ast::def_id, substs: substs) -> t { + mk_t(cx, ty_iface(did, substs)) } fn mk_class(cx: ctxt, class_id: ast::def_id, substs: substs) -> t { @@ -667,7 +661,7 @@ fn mk_res(cx: ctxt, did: ast::def_id, fn mk_var(cx: ctxt, v: ty_vid) -> t { mk_t(cx, ty_var(v)) } -fn mk_self(cx: ctxt, tps: [t]) -> t { mk_t(cx, ty_self(tps)) } +fn mk_self(cx: ctxt, substs: substs) -> t { mk_t(cx, ty_self(substs)) } fn mk_param(cx: ctxt, n: uint, k: def_id) -> t { mk_t(cx, ty_param(n, k)) } @@ -712,12 +706,10 @@ fn maybe_walk_ty(ty: t, f: fn(t) -> bool) { ty_ptr(tm) | ty_rptr(_, tm) { maybe_walk_ty(tm.ty, f); } - ty_enum(_, substs) | ty_class(_, substs) { + ty_enum(_, substs) | ty_class(_, substs) | + ty_iface(_, substs) | ty_self(substs) { for substs.tps.each {|subty| maybe_walk_ty(subty, f); } } - ty_iface(_, subtys) |ty_self(subtys) { - for subtys.each {|subty| maybe_walk_ty(subty, f); } - } ty_rec(fields) { for fields.each {|fl| maybe_walk_ty(fl.mt.ty, f); } } @@ -764,11 +756,11 @@ fn fold_sty(sty: sty, fldop: fn(t) -> t) -> sty { ty_enum(tid, substs) { ty_enum(tid, fold_substs(substs, fldop)) } - ty_iface(did, subtys) { - ty_iface(did, vec::map(subtys) {|t| fldop(t) }) + ty_iface(did, substs) { + ty_iface(did, fold_substs(substs, fldop)) } - ty_self(subtys) { - ty_self(vec::map(subtys) {|t| fldop(t) }) + ty_self(substs) { + ty_self(fold_substs(substs, fldop)) } ty_rec(fields) { let new_fields = vec::map(fields) {|fl| @@ -864,6 +856,12 @@ fn fold_regions_and_ty( ty_class(def_id, substs) { ty::mk_class(cx, def_id, fold_substs(substs, fldr, fldt)) } + ty_iface(def_id, substs) { + ty::mk_iface(cx, def_id, fold_substs(substs, fldr, fldt)) + } + ty_self(substs) { + ty::mk_self(cx, fold_substs(substs, fldr, fldt)) + } ty_res(def_id, t, substs) { ty::mk_res(cx, def_id, fldt(t), fold_substs(substs, fldr, fldt)) @@ -1828,10 +1826,8 @@ fn hash_type_structure(st: sty) -> uint { } ty_var(v) { hash_uint(30u, v.to_uint()) } ty_param(pid, did) { hash_def(hash_uint(31u, pid), did) } - ty_self(ts) { - let mut h = 28u; - for ts.each {|t| h = hash_subty(h, t); } - h + ty_self(substs) { + hash_substs(28u, substs) } ty_type { 32u } ty_bot { 34u } @@ -1850,10 +1846,9 @@ fn hash_type_structure(st: sty) -> uint { h } ty_uniq(mt) { hash_subty(37u, mt.ty) } - ty_iface(did, tys) { + ty_iface(did, substs) { let mut h = hash_def(40u, did); - for tys.each {|typ| h = hash_subty(h, typ); } - h + hash_substs(h, substs) } ty_opaque_closure_ptr(ck_block) { 41u } ty_opaque_closure_ptr(ck_box) { 42u } @@ -2286,7 +2281,7 @@ fn impl_iface(cx: ctxt, id: ast::def_id) -> option<t> { if id.crate == ast::local_crate { alt cx.items.find(id.node) { some(ast_map::node_item(@{node: ast::item_impl( - _, some(@{id: id, _}), _, _), _}, _)) { + _, _, some(@{id: id, _}), _, _), _}, _)) { some(node_id_to_type(cx, id)) } some(ast_map::node_item(@{node: ast::item_class(_, _, _, _, _), diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs index fd82061844f..69936c35b60 100644 --- a/src/rustc/middle/typeck.rs +++ b/src/rustc/middle/typeck.rs @@ -22,7 +22,7 @@ import std::serialization::{serialize_uint, deserialize_uint}; import std::ufind; import vec::each; import syntax::print::pprust::*; -import util::common::indent; +import util::common::{indent, indenter}; import std::list; import list::{list, nil, cons}; @@ -472,7 +472,7 @@ fn get_region_reporting_err(tcx: ty::ctxt, } fn ast_region_to_region<AC: ast_conv, RS: region_scope>( - self: AC, rscope: RS, span: span, a_r: ast::region) -> ty::region { + self: AC, rscope: RS, span: span, a_r: @ast::region) -> ty::region { let res = alt a_r.node { ast::re_anon { rscope.anon_region() } @@ -483,40 +483,67 @@ fn ast_region_to_region<AC: ast_conv, RS: region_scope>( get_region_reporting_err(self.tcx(), span, res) } -fn instantiate<AC: ast_conv, RS: region_scope copy>( - self: AC, rscope: RS, sp: span, id: ast::def_id, - path_id: ast::node_id, args: [@ast::ty]) -> ty::t { +fn ast_path_to_substs_and_ty<AC: ast_conv, RS: region_scope copy>( + self: AC, rscope: RS, did: ast::def_id, + path: @ast::path) -> ty_param_substs_and_ty { - let tcx = self.tcx(); - let {bounds, rp, ty} = self.get_item_ty(id); + let tcx = self.tcx(); + let {bounds: decl_bounds, rp: decl_rp, ty: decl_ty} = + self.get_item_ty(did); + + // If the type is parameterized by the self region, then replace self + // region with the current anon region binding (in other words, + // whatever & would get replaced with). + let self_r = alt (decl_rp, path.rp) { + (ast::rp_none, none) { + none + } + (ast::rp_none, some(_)) { + tcx.sess.span_err( + path.span, + #fmt["No region bound is permitted on %s, \ + which is not declared as containing region pointers", + ty::item_path_str(tcx, did)]); + none + } + (ast::rp_self, none) { + let res = rscope.anon_region(); + let r = get_region_reporting_err(self.tcx(), path.span, res); + some(r) + } + (ast::rp_self, some(r)) { + some(ast_region_to_region(self, rscope, path.span, r)) + } + }; - // If the type is parameterized by the self region, then replace self - // region with the current anon region binding (in other words, - // whatever & would get replaced with). - let self_r = alt rp { - ast::rp_none { none } - ast::rp_self { - let res = rscope.anon_region(); - let r = get_region_reporting_err(self.tcx(), sp, res); - some(r) - } - }; + // Convert the type parameters supplied by the user. + if !vec::same_length(*decl_bounds, path.types) { + self.tcx().sess.span_fatal( + path.span, + #fmt["wrong number of type arguments, expected %u but found %u", + (*decl_bounds).len(), path.types.len()]); + } + let tps = path.types.map { |a_t| ast_ty_to_ty(self, rscope, a_t) }; - // Convert the type parameters supplied by the user. - if vec::len(args) != vec::len(*bounds) { - tcx.sess.span_fatal( - sp, #fmt["wrong number of type arguments, \ - expected %u but found %u", - vec::len(*bounds), - vec::len(args)]); - } - let tps = args.map { |t| ast_ty_to_ty(self, rscope, t) }; + let substs = {self_r: self_r, tps: tps}; + {substs: substs, ty: ty::subst(tcx, substs, decl_ty)} +} + +fn ast_path_to_ty<AC: ast_conv, RS: region_scope copy>( + self: AC, + rscope: RS, + did: ast::def_id, + path: @ast::path, + path_id: ast::node_id) -> ty_param_substs_and_ty { - // Perform the substitution and store the tps for future ref. - let substs = {self_r: self_r, tps: tps}; - let ty = ty::subst(tcx, substs, ty); - write_substs_to_tcx(tcx, path_id, substs.tps); - ret ty; + // Lookup the polytype of the item and then substitute the provided types + // for any type/region parameters. + let tcx = self.tcx(); + let {substs: substs, ty: ty} = + ast_path_to_substs_and_ty(self, rscope, did, path); + write_ty_to_tcx(tcx, path_id, ty); + write_substs_to_tcx(tcx, path_id, substs.tps); + ret {substs: substs, ty: ty}; } /* @@ -524,23 +551,25 @@ fn instantiate<AC: ast_conv, RS: region_scope copy>( it's bound to a valid iface type. Returns the def_id for the defining iface */ -fn instantiate_iface_ref(ccx: @crate_ctxt, t: @ast::iface_ref) - -> ast::def_id { +fn instantiate_iface_ref(ccx: @crate_ctxt, t: @ast::iface_ref, + rp: ast::region_param) + -> (ast::def_id, ty_param_substs_and_ty) { + alt lookup_def_tcx(ccx.tcx, t.path.span, t.id) { - ast::def_ty(t_id) { - // tjc: will probably need to refer to - // impl or class ty params too - instantiate(ccx, empty_rscope, t.path.span, t_id, t.id, - t.path.types); - t_id - } - _ { - ccx.tcx.sess.span_fatal(t.path.span, - "can only implement interface types"); - } + ast::def_ty(t_id) { + (t_id, ast_path_to_ty(ccx, type_rscope(rp), t_id, t.path, t.id)) + } + _ { + ccx.tcx.sess.span_fatal( + t.path.span, + "can only implement interface types"); + } } } +const NO_REGIONS: uint = 1u; +const NO_TPS: uint = 2u; + // Parses the programmer's textual representation of a type into our // internal notion of a type. `getter` is a function that returns the type // corresponding to a definition ID: @@ -553,7 +582,7 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy>( ret {ty: ast_ty_to_ty(self, rscope, mt.ty), mutbl: mt.mutbl}; } - fn mk_bounded<AC: ast_conv, RS: region_scope copy>( + fn mk_vstore<AC: ast_conv, RS: region_scope copy>( self: AC, rscope: RS, a_seq_ty: @ast::ty, vst: ty::vstore) -> ty::t { let tcx = self.tcx(); @@ -568,39 +597,6 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy>( ret ty::mk_estr(tcx, vst); } - ty::ty_enum(_, subst) | - ty::ty_class(_, subst) | - ty::ty_res(_, _, subst) { - // n.b.: This is a hacky abuse of the vstore terminology to also - // make it work for region bounds. The idea is to allow a type - // Id/&r where Id is an enum, class, or resource, but not Id/@ - // etc. We also do not want to allow Id/&r if the given - // enum/class/resource does not define a region parameter. - // - // Really, these "/&r" bounds ought to be part of the path, like - // type parameters. (In fact, we could generalize to allowing - // multiple such bounds someday) - alt (subst.self_r, vst) { - (some(_), ty::vstore_slice(_)) { /* ok */ } - (none, ty::vstore_slice(_)) { - tcx.sess.span_err( - a_seq_ty.span, - #fmt["inappropriate bound for %s, \ - which is not declared as containing \ - region pointers", - ty::ty_sort_str(tcx, seq_ty)]); - } - (_, _) { - tcx.sess.span_err( - a_seq_ty.span, - #fmt["a %s bound is not appropriate for %s", - vstore_to_str(tcx, vst), - ty::ty_sort_str(tcx, seq_ty)]); - } - } - ret seq_ty; - } - _ { tcx.sess.span_err( a_seq_ty.span, @@ -611,6 +607,26 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy>( } } + fn check_path_args(tcx: ty::ctxt, + path: @ast::path, + flags: uint) { + if (flags & NO_TPS) != 0u { + if path.types.len() > 0u { + tcx.sess.span_err( + path.span, + "Type parameters are not allowed on this type."); + } + } + + if (flags & NO_REGIONS) != 0u { + if path.rp.is_some() { + tcx.sess.span_err( + path.span, + "Region parameters are not allowed on this type."); + } + } + } + let tcx = self.tcx(); alt tcx.ast_ty_to_ty_cache.find(ast_ty) { @@ -665,37 +681,52 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy>( some(d) { d }}; alt a_def { ast::def_ty(did) | ast::def_class(did) { - instantiate(self, rscope, ast_ty.span, did, id, path.types) + ast_path_to_ty(self, rscope, did, path, id).ty } ast::def_prim_ty(nty) { alt nty { - ast::ty_bool { ty::mk_bool(tcx) } - ast::ty_int(it) { ty::mk_mach_int(tcx, it) } - ast::ty_uint(uit) { ty::mk_mach_uint(tcx, uit) } - ast::ty_float(ft) { ty::mk_mach_float(tcx, ft) } - ast::ty_str { ty::mk_str(tcx) } + ast::ty_bool { + check_path_args(tcx, path, NO_TPS | NO_REGIONS); + ty::mk_bool(tcx) + } + ast::ty_int(it) { + check_path_args(tcx, path, NO_TPS | NO_REGIONS); + ty::mk_mach_int(tcx, it) + } + ast::ty_uint(uit) { + check_path_args(tcx, path, NO_TPS | NO_REGIONS); + ty::mk_mach_uint(tcx, uit) + } + ast::ty_float(ft) { + check_path_args(tcx, path, NO_TPS | NO_REGIONS); + ty::mk_mach_float(tcx, ft) + } + ast::ty_str { + check_path_args(tcx, path, NO_TPS); + // This is a bit of a hack, but basically str/& needs to be + // converted into a vstore: + alt path.rp { + none { + ty::mk_str(tcx) + } + some(ast_r) { + let r = ast_region_to_region(self, rscope, + ast_ty.span, ast_r); + ty::mk_estr(tcx, ty::vstore_slice(r)) + } + } + } } } ast::def_ty_param(id, n) { - if vec::len(path.types) > 0u { - tcx.sess.span_err(ast_ty.span, "provided type parameters \ - to a type parameter"); - } + check_path_args(tcx, path, NO_TPS | NO_REGIONS); ty::mk_param(tcx, n, id) } ast::def_self(self_id) { - alt check tcx.items.get(self_id) { - ast_map::node_item(@{node: ast::item_iface(tps, _), _}, _) { - if vec::len(tps) != vec::len(path.types) { - tcx.sess.span_err(ast_ty.span, "incorrect number of \ - type parameters to \ - self type"); - } - ty::mk_self(tcx, vec::map(path.types, {|ast_ty| - ast_ty_to_ty(self, rscope, ast_ty) - })) - } - } + let {substs, ty: _} = + ast_path_to_substs_and_ty(self, rscope, + local_def(self_id), path); + ty::mk_self(tcx, substs) } _ { tcx.sess.span_fatal(ast_ty.span, @@ -705,16 +736,16 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy>( } ast::ty_vstore(a_t, ast::vstore_slice(a_r)) { let r = ast_region_to_region(self, rscope, ast_ty.span, a_r); - mk_bounded(self, in_anon_rscope(rscope, r), a_t, ty::vstore_slice(r)) + mk_vstore(self, in_anon_rscope(rscope, r), a_t, ty::vstore_slice(r)) } ast::ty_vstore(a_t, ast::vstore_uniq) { - mk_bounded(self, rscope, a_t, ty::vstore_uniq) + mk_vstore(self, rscope, a_t, ty::vstore_uniq) } ast::ty_vstore(a_t, ast::vstore_box) { - mk_bounded(self, rscope, a_t, ty::vstore_box) + mk_vstore(self, rscope, a_t, ty::vstore_box) } ast::ty_vstore(a_t, ast::vstore_fixed(some(u))) { - mk_bounded(self, rscope, a_t, ty::vstore_fixed(u)) + mk_vstore(self, rscope, a_t, ty::vstore_fixed(u)) } ast::ty_vstore(_, ast::vstore_fixed(none)) { tcx.sess.span_bug( @@ -790,7 +821,7 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item) } ast::item_res(decl, tps, _, _, _, rp) { let {bounds, substs} = mk_substs(ccx, tps, rp); - let t_arg = ty_of_arg(ccx, empty_rscope, decl.inputs[0]); + let t_arg = ty_of_arg(ccx, type_rscope(rp), decl.inputs[0]); let t = ty::mk_res(tcx, local_def(it.id), t_arg.ty, substs); let t_res = {bounds: bounds, rp: rp, ty: t}; tcx.tcache.insert(local_def(it.id), t_res); @@ -804,11 +835,10 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item) tcx.tcache.insert(local_def(it.id), tpt); ret tpt; } - ast::item_iface(tps, ms) { - let {bounds, params} = mk_ty_params(ccx, tps); - let t = ty::mk_iface(tcx, local_def(it.id), params); - // NDM iface/impl regions - let tpt = {bounds: bounds, rp: ast::rp_none, ty: t}; + ast::item_iface(tps, rp, ms) { + let {bounds, substs} = mk_substs(ccx, tps, rp); + let t = ty::mk_iface(tcx, local_def(it.id), substs); + let tpt = {bounds: bounds, rp: rp, ty: t}; tcx.tcache.insert(local_def(it.id), tpt); ret tpt; } @@ -819,7 +849,7 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item) tcx.tcache.insert(local_def(it.id), tpt); ret tpt; } - ast::item_impl(_, _, _, _) | ast::item_mod(_) | + ast::item_impl(*) | ast::item_mod(_) | ast::item_native_mod(_) { fail; } } } @@ -1040,15 +1070,19 @@ fn ty_param_bounds(ccx: @crate_ctxt, fn ty_of_method(ccx: @crate_ctxt, m: @ast::method, rp: ast::region_param) -> ty::method { - {ident: m.ident, tps: ty_param_bounds(ccx, m.tps), + {ident: m.ident, + tps: ty_param_bounds(ccx, m.tps), fty: ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare, m.decl), - purity: m.decl.purity, privacy: m.privacy} + purity: m.decl.purity, + privacy: m.privacy} } -fn ty_of_ty_method(self: @crate_ctxt, m: ast::ty_method) -> ty::method { +fn ty_of_ty_method(self: @crate_ctxt, + m: ast::ty_method, + rp: ast::region_param) -> ty::method { {ident: m.ident, tps: ty_param_bounds(self, m.tps), - fty: ty_of_fn_decl(self, empty_rscope, ast::proto_bare, m.decl), + fty: ty_of_fn_decl(self, type_rscope(rp), ast::proto_bare, m.decl), // assume public, because this is only invoked on iface methods purity: m.decl.purity, privacy: ast::pub} } @@ -1180,6 +1214,14 @@ impl methods for @fn_ctxt { self.ty_to_str(a), ty::type_err_to_str(self.ccx.tcx, err)]); } + + fn mk_subty(sub: ty::t, sup: ty::t) -> result<(), ty::type_err> { + infer::mk_subty(self.infcx, sub, sup) + } + + fn mk_eqty(sub: ty::t, sup: ty::t) -> result<(), ty::type_err> { + infer::mk_eqty(self.infcx, sub, sup) + } } fn mk_ty_params(ccx: @crate_ctxt, atps: [ast::ty_param]) @@ -1207,7 +1249,7 @@ fn mk_substs(ccx: @crate_ctxt, atps: [ast::ty_param], rp: ast::region_param) } fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method, - impl_tps: uint, if_m: ty::method, substs: [ty::t], + impl_tps: uint, if_m: ty::method, substs: ty::substs, self_ty: ty::t) -> ty::t { if impl_m.tps != if_m.tps { @@ -1234,11 +1276,14 @@ fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method, let impl_fty = ty::mk_fn(tcx, {inputs: auto_modes with impl_m.fty}); // Add dummy substs for the parameters of the impl method - let substs = substs + vec::from_fn(vec::len(*if_m.tps), {|i| - ty::mk_param(tcx, i + impl_tps, {crate: 0, node: 0}) - }); + let substs = { + self_r: substs.self_r, + tps: substs.tps + vec::from_fn(vec::len(*if_m.tps), {|i| + ty::mk_param(tcx, i + impl_tps, {crate: 0, node: 0}) + }) + }; let mut if_fty = ty::mk_fn(tcx, if_m.fty); - if_fty = ty::subst_tps(tcx, substs, if_fty); + if_fty = ty::subst(tcx, substs, if_fty); if_fty = fixup_self_full(tcx, if_fty, substs, self_ty, impl_tps); require_same_types( tcx, sp, impl_fty, if_fty, @@ -1253,38 +1298,45 @@ fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method, // because the type parameters of ifaces and impls are not required to line up // (an impl can have less or more parameters than the iface it implements), so // some mangling of the substituted types is required. -fn fixup_self_full(cx: ty::ctxt, mty: ty::t, m_substs: [ty::t], +fn fixup_self_full(cx: ty::ctxt, mty: ty::t, m_substs: ty::substs, selfty: ty::t, impl_n_tps: uint) -> ty::t { if !ty::type_has_vars(mty) { ret mty; } ty::fold_ty(cx, mty) {|t| alt ty::get(t).struct { - ty::ty_self(tps) if vec::len(tps) == 0u { selfty } - ty::ty_self(tps) { + ty::ty_self(substs) if ty::substs_is_noop(substs) { + selfty + } + ty::ty_self(substs) { // Move the substs into the type param system of the // context. - let mut substs = vec::map(tps) {|t| + let mut substs_tps = vec::map(substs.tps) {|t| let f = fixup_self_full(cx, t, m_substs, selfty, impl_n_tps); - ty::subst_tps(cx, m_substs, f) + ty::subst(cx, m_substs, f) }; // Add extra substs for impl type parameters. - while vec::len(substs) < impl_n_tps { - substs += [ty::mk_param(cx, vec::len(substs), - {crate: 0, node: 0})]; + while vec::len(substs_tps) < impl_n_tps { + substs_tps += [ty::mk_param(cx, substs_tps.len(), + {crate: 0, node: 0})]; } // And for method type parameters. - let method_n_tps = - (vec::len(m_substs) - vec::len(tps)) as int; + let method_n_tps = ( + m_substs.tps.len() - substs_tps.len()) as int; if method_n_tps > 0 { - substs += vec::tailn(m_substs, vec::len(m_substs) - - (method_n_tps as uint)); + substs_tps += vec::tailn( + m_substs.tps, + m_substs.tps.len() - (method_n_tps as uint)); } // And then instantiate the self type using all those. - ty::subst_tps(cx, substs, selfty) + let substs_1 = { + self_r: substs.self_r, + tps: substs_tps + }; + ty::subst(cx, substs_1, selfty) } _ { t @@ -1298,27 +1350,26 @@ fn fixup_self_full(cx: ty::ctxt, mty: ty::t, m_substs: [ty::t], // because the type parameters of ifaces and impls are not required to line up // (an impl can have less or more parameters than the iface it implements), so // some mangling of the substituted types is required. -fn fixup_self_param(fcx: @fn_ctxt, mty: ty::t, m_substs: [ty::t], +fn fixup_self_param(fcx: @fn_ctxt, mty: ty::t, m_substs: ty::substs, selfty: ty::t, sp: span) -> ty::t { if !ty::type_has_vars(mty) { ret mty; } let tcx = fcx.ccx.tcx; ty::fold_ty(tcx, mty) {|t| alt ty::get(t).struct { - ty::ty_self(tps) if vec::len(tps) == 0u { selfty } - ty::ty_self(tps) { - // Move the substs into the type param system of the - // context. - let mut substs = vec::map(tps) {|t| + ty::ty_self(substs) if ty::substs_is_noop(substs) { + selfty + } + ty::ty_self(substs) { + // Move the substs into the type param system of the context. + let tps_p = vec::map(substs.tps) {|t| let f = fixup_self_param(fcx, t, m_substs, selfty, sp); - ty::subst_tps(tcx, m_substs, f) + ty::subst(tcx, m_substs, f) }; - - // Simply ensure that the type parameters for the self - // type match the context. - vec::iter2(substs, m_substs) {|s, ms| - demand::suptype(fcx, sp, s, ms); - } + let substs_p = {self_r: substs.self_r, tps: tps_p}; + let self_p = ty::mk_self(tcx, substs_p); + let m_self = ty::mk_self(tcx, m_substs); + demand::suptype(fcx, sp, m_self, self_p); selfty } _ { t } @@ -1392,9 +1443,9 @@ mod collect { let tcx = ccx.tcx; alt check tcx.items.get(id) { - ast_map::node_item(@{node: ast::item_iface(_, ms), _}, _) { + ast_map::node_item(@{node: ast::item_iface(_, rp, ms), _}, _) { store_methods::<ast::ty_method>(ccx, id, ms) {|m| - ty_of_ty_method(ccx, m) + ty_of_ty_method(ccx, m, rp) }; } ast_map::node_item(@{node: ast::item_class(_,_,its,_,rp), _}, _) { @@ -1412,52 +1463,45 @@ mod collect { tps: [ast::ty_param], rp: ast::region_param, selfty: ty::t, - t: @ast::iface_ref, - ms: [@ast::method]) -> ast::def_id { + a_ifacety: @ast::iface_ref, + ms: [@ast::method]) { let tcx = ccx.tcx; let i_bounds = ty_param_bounds(ccx, tps); let my_methods = convert_methods(ccx, ms, rp, i_bounds, selfty); - let did = instantiate_iface_ref(ccx, t); - // not sure whether it's correct to use empty_rscope - // -- tjc - let tys = vec::map(t.path.types, - {|t| ccx.to_ty(empty_rscope,t)}); - // Store the iface type in the type node - write_ty_to_tcx(tcx, t.id, ty::mk_iface(ccx.tcx, did, tys)); + let (did, tpt) = instantiate_iface_ref(ccx, a_ifacety, rp); if did.crate == ast::local_crate { ensure_iface_methods(ccx, did.node); } for vec::each(*ty::iface_methods(tcx, did)) {|if_m| - alt vec::find(my_methods, - {|m| if_m.ident == m.mty.ident}) { - some({mty: m, id, span}) { - if m.purity != if_m.purity { - ccx.tcx.sess.span_err( - span, #fmt["method `%s`'s purity \ - not match the iface method's \ - purity", m.ident]); - } - let mt = compare_impl_method( - ccx.tcx, span, m, vec::len(tps), - if_m, tys, selfty); - let old = tcx.tcache.get(local_def(id)); - if old.ty != mt { - tcx.tcache.insert( - local_def(id), - {bounds: old.bounds, - rp: old.rp, - ty: mt}); - write_ty_to_tcx(tcx, id, mt); - } - } - none { - tcx.sess.span_err(t.path.span, "missing method `" + - if_m.ident + "`"); - } - } // alt + alt vec::find(my_methods, {|m| if_m.ident == m.mty.ident}) { + some({mty: m, id, span}) { + if m.purity != if_m.purity { + ccx.tcx.sess.span_err( + span, #fmt["method `%s`'s purity \ + not match the iface method's \ + purity", m.ident]); + } + let mt = compare_impl_method( + ccx.tcx, span, m, vec::len(tps), + if_m, tpt.substs, selfty); + let old = tcx.tcache.get(local_def(id)); + if old.ty != mt { + tcx.tcache.insert( + local_def(id), + {bounds: old.bounds, + rp: old.rp, + ty: mt}); + write_ty_to_tcx(tcx, id, mt); + } + } + none { + tcx.sess.span_err( + a_ifacety.path.span, + #fmt["missing method `%s`", if_m.ident]); + } + } // alt } // |if_m| - did } // fn fn convert_class_item(ccx: @crate_ctxt, @@ -1510,26 +1554,25 @@ mod collect { get_enum_variant_types(ccx, tpt.ty, variants, ty_params, rp); } - ast::item_impl(tps, ifce, selfty, ms) { + ast::item_impl(tps, rp, ifce, selfty, ms) { let i_bounds = ty_param_bounds(ccx, tps); - // NDM iface/impl regions - let selfty = ccx.to_ty(empty_rscope, selfty); + let selfty = ccx.to_ty(type_rscope(rp), selfty); write_ty_to_tcx(tcx, it.id, selfty); tcx.tcache.insert(local_def(it.id), {bounds: i_bounds, - rp: ast::rp_none, // NDM iface/impl regions + rp: rp, ty: selfty}); alt ifce { some(t) { - check_methods_against_iface( - ccx, tps, ast::rp_none, // NDM iface/impl regions + check_methods_against_iface( + ccx, tps, rp, selfty, t, ms); } _ { // Still have to do this to write method types // into the table convert_methods( - ccx, ms, ast::rp_none, // NDM iface/impl regions + ccx, ms, rp, i_bounds, selfty); } } @@ -1555,15 +1598,17 @@ mod collect { write_ty_to_tcx(tcx, ctor_id, t_ctor); tcx.tcache.insert(local_def(ctor_id), {bounds: bounds, - rp: ast::rp_none, + rp: rp, ty: t_ctor}); tcx.tcache.insert(def_id, {bounds: bounds, - rp: ast::rp_none, + rp: rp, ty: t_res}); write_ty_to_tcx(tcx, dtor_id, t_dtor); } - ast::item_iface(_, ms) { + ast::item_iface(*) { let tpt = ty_of_item(ccx, it); + #debug["item_iface(it.id=%d, tpt.ty=%s)", + it.id, ty_to_str(tcx, tpt.ty)]; write_ty_to_tcx(tcx, it.id, tpt.ty); ensure_iface_methods(ccx, it.id); } @@ -1581,7 +1626,7 @@ mod collect { write_ty_to_tcx(tcx, ctor.node.id, t_ctor); tcx.tcache.insert(local_def(ctor.node.id), {bounds: tpt.bounds, - rp: ast::rp_none, // NDM self->anon + rp: ast::rp_none, ty: t_ctor}); ensure_iface_methods(ccx, it.id); /* FIXME: check for proper public/privateness */ @@ -1605,15 +1650,14 @@ mod collect { that it claims to implement. */ for ifaces.each { |ifce| - let t_id = check_methods_against_iface(ccx, tps, rp, selfty, - ifce, methods); + check_methods_against_iface(ccx, tps, rp, selfty, + ifce, methods); + let t = ty::node_id_to_type(tcx, ifce.id); + // FIXME: This assumes classes only implement // non-parameterized ifaces. add a test case for // a class implementing a parameterized iface. // -- tjc (#1726) - let t = ty::mk_iface(tcx, t_id, []); - write_ty_to_tcx(tcx, ifce.id, t); - // FIXME: likewise, assuming no bounds -- tjc tcx.tcache.insert(local_def(ifce.id), no_params(t)); } } @@ -1647,15 +1691,6 @@ mod collect { } -// Type unification -mod unify { - fn unify(fcx: @fn_ctxt, expected: ty::t, actual: ty::t) -> - result<(), ty::type_err> { - ret infer::mk_subty(fcx.infcx, actual, expected); - } -} - - // FIXME This is almost a duplicate of ty::type_autoderef, with structure_of // instead of ty::struct. fn do_autoderef(fcx: @fn_ctxt, sp: span, t: ty::t) -> ty::t { @@ -1732,6 +1767,7 @@ mod demand { fn suptype(fcx: @fn_ctxt, sp: span, expected: ty::t, actual: ty::t) { + // n.b.: order of actual, expected is reversed alt infer::mk_subty(fcx.infcx, actual, expected) { result::ok(()) { /* ok */ } result::err(err) { @@ -1740,6 +1776,17 @@ mod demand { } } + fn eqtype(fcx: @fn_ctxt, sp: span, + expected: ty::t, actual: ty::t) { + + alt infer::mk_eqty(fcx.infcx, actual, expected) { + result::ok(()) { /* ok */ } + result::err(err) { + fcx.report_mismatched_types(sp, expected, actual, err); + } + } + } + // Checks that the type `actual` can be assigned to `expected`. fn assign(fcx: @fn_ctxt, sp: span, expected: ty::t, expr: @ast::expr) { let expr_ty = fcx.expr_ty(expr); @@ -1755,7 +1802,7 @@ mod demand { // Returns true if the two types unify and false if they don't. fn are_compatible(fcx: @fn_ctxt, expected: ty::t, actual: ty::t) -> bool { - alt unify::unify(fcx, expected, actual) { + alt fcx.mk_eqty(expected, actual) { result::ok(_) { ret true; } result::err(_) { ret false; } } @@ -2390,14 +2437,14 @@ fn check_expr(fcx: @fn_ctxt, expr: @ast::expr, fn impl_self_ty(fcx: @fn_ctxt, did: ast::def_id) -> ty_param_substs_and_ty { let tcx = fcx.ccx.tcx; - let {n_tps, raw_ty} = if did.crate == ast::local_crate { + let {n_tps, rp, raw_ty} = if did.crate == ast::local_crate { alt check tcx.items.find(did.node) { - some(ast_map::node_item(@{node: ast::item_impl(ts, _, st, _), - _}, _)) { + some(ast_map::node_item(@{node: ast::item_impl(ts, rp, _, st, _), + _}, _)) { {n_tps: ts.len(), - raw_ty: fcx.to_ty(st)} + rp: rp, + raw_ty: fcx.ccx.to_ty(type_rscope(rp), st)} } - // Node doesn't map to an impl. It might map to a class. some(ast_map::node_item(@{node: ast::item_class(ts, _,_,_,rp), id: class_id, _},_)) { /* If the impl is a class, the self ty is just the class ty @@ -2405,6 +2452,7 @@ fn impl_self_ty(fcx: @fn_ctxt, did: ast::def_id) -> ty_param_substs_and_ty { we substitute in fresh vars for them) */ {n_tps: ts.len(), + rp: rp, raw_ty: ty::mk_class(tcx, local_def(class_id), {self_r: alt rp { ast::rp_self { some(fcx.next_region_var()) } @@ -2417,11 +2465,16 @@ fn impl_self_ty(fcx: @fn_ctxt, did: ast::def_id) -> ty_param_substs_and_ty { } else { let ity = ty::lookup_item_type(tcx, did); {n_tps: vec::len(*ity.bounds), + rp: ity.rp, raw_ty: ity.ty} }; - let self_r = none; // NDM iface/impl regions + let self_r = alt rp { + ast::rp_none { none } + ast::rp_self { some(fcx.next_region_var()) } + }; let tps = fcx.next_ty_vars(n_tps); + let substs = {self_r: self_r, tps: tps}; let substd_ty = ty::subst(tcx, substs, raw_ty); {substs: substs, ty: substd_ty} @@ -2449,8 +2502,8 @@ impl methods for lookup { ty::ty_param(n, did) { self.method_from_param(n, did) } - ty::ty_iface(did, tps) { - self.method_from_iface(did, tps) + ty::ty_iface(did, substs) { + self.method_from_iface(did, substs) } ty::ty_class(did, substs) { self.method_from_class(did, substs) @@ -2473,11 +2526,11 @@ impl methods for lookup { let mut iface_bnd_idx = 0u; // count only iface bounds let bounds = tcx.ty_param_bounds.get(did.node); for vec::each(*bounds) {|bound| - let (iid, bound_tps) = alt bound { + let (iid, bound_substs) = alt bound { ty::bound_copy | ty::bound_send { cont; /* ok */ } ty::bound_iface(bound_t) { alt check ty::get(bound_t).struct { - ty::ty_iface(i, tps) { (i, tps) } + ty::ty_iface(i, substs) { (i, substs) } } } }; @@ -2490,9 +2543,6 @@ impl methods for lookup { } some(pos) { - let bound_substs = { // NDM iface/impl regions - self_r: none, tps: bound_tps - }; ret some(self.write_mty_from_m( some(self.self_ty), bound_substs, ifce_methods[pos], method_param(iid, pos, n, iface_bnd_idx))); @@ -2503,7 +2553,7 @@ impl methods for lookup { } fn method_from_iface( - did: ast::def_id, iface_tps: [ty::t]) -> option<method_origin> { + did: ast::def_id, iface_substs: ty::substs) -> option<method_origin> { let ms = *ty::iface_methods(self.tcx(), did); for ms.eachi {|i, m| @@ -2525,10 +2575,6 @@ impl methods for lookup { boxed iface"); } - let iface_substs = { // NDM iface/impl regions - self_r: none, tps: iface_tps - }; - ret some(self.write_mty_from_m( none, iface_substs, m, method_iface(did, i))); @@ -2565,6 +2611,12 @@ impl methods for lookup { } fn ty_from_did(did: ast::def_id) -> ty::t { + alt check ty::get(ty::lookup_item_type(self.tcx(), did).ty).struct { + ty::ty_fn(fty) { + ty::mk_fn(self.tcx(), {proto: ast::proto_box with fty}) + } + } + /* if did.crate == ast::local_crate { alt check self.tcx().items.get(did.node) { ast_map::node_method(m, _, _) { @@ -2580,6 +2632,7 @@ impl methods for lookup { } } } + */ } fn method_from_scope() -> option<method_origin> { @@ -2608,7 +2661,7 @@ impl methods for lookup { // if we can assign the caller to the callee, that's a // potential match. Collect those in the vector. - alt unify::unify(self.fcx, self_ty, ty) { + alt self.fcx.mk_subty(ty, self_ty) { result::err(_) { /* keep looking */ } result::ok(_) { results += [(self_substs, m.n_tps, m.did)]; @@ -2696,7 +2749,7 @@ impl methods for lookup { if has_self && !option::is_none(self_ty_sub) { let fty = self.fcx.node_ty(self.node_id); let fty = fixup_self_param( - self.fcx, fty, all_substs.tps, self_ty_sub.get(), + self.fcx, fty, all_substs, self_ty_sub.get(), self.expr.span); self.fcx.write_ty(self.node_id, fty); } @@ -3492,9 +3545,13 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, let t_1 = fcx.to_ty(t); let t_e = fcx.expr_ty(e); + #debug["t_1=%s", fcx.ty_to_str(t_1)]; + #debug["t_e=%s", fcx.ty_to_str(t_e)]; + alt ty::get(t_1).struct { // This will be looked up later on - ty::ty_iface(_, _) {} + ty::ty_iface(*) {} + _ { if ty::type_is_nil(t_e) { tcx.sess.span_err(expr.span, "cast from nil: " + @@ -4075,7 +4132,8 @@ fn check_constraints(fcx: @fn_ctxt, cs: [@ast::constr], args: [ast::arg]) { ast::carg_ident(i) { if i < num_args { let p = @{span: a.span, global: false, - idents: [args[i].ident], types: []}; + idents: [args[i].ident], + rp: none, types: []}; let arg_occ_node_id = fcx.ccx.tcx.sess.next_node_id(); fcx.ccx.tcx.def_map.insert @@ -4356,10 +4414,8 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) { check_instantiable(ccx.tcx, it.span, it.id); check_bare_fn(ccx, decl, body, dtor_id, none); } - ast::item_impl(tps, _, ty, ms) { - let self_ty = ccx.to_ty(empty_rscope, ty); // NDM iface/impl regions - let self_region = ty::re_free(it.id, ty::br_self); - let self_ty = replace_self_region(ccx.tcx, self_region, self_ty); + ast::item_impl(tps, rp, _, ty, ms) { + let self_ty = ccx.to_ty(type_rscope(rp), ty); for ms.each {|m| check_method(ccx, m, self_ty);} } ast::item_class(tps, ifaces, members, ctor, rp) { @@ -4459,15 +4515,15 @@ mod vtable { } fn lookup_vtables(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span, - bounds: @[ty::param_bounds], tys: [ty::t], + bounds: @[ty::param_bounds], substs: ty::substs, allow_unsafe: bool) -> vtable_res { let tcx = fcx.ccx.tcx; let mut result = [], i = 0u; - for tys.each {|ty| + for substs.tps.each {|ty| for vec::each(*bounds[i]) {|bound| alt bound { ty::bound_iface(i_ty) { - let i_ty = ty::subst_tps(tcx, tys, i_ty); + let i_ty = ty::subst(tcx, substs, i_ty); result += [lookup_vtable(fcx, isc, sp, ty, i_ty, allow_unsafe)]; } @@ -4479,6 +4535,22 @@ mod vtable { @result } + fn fixup_substs(fcx: @fn_ctxt, sp: span, + substs: ty::substs) -> ty::substs { + let tcx = fcx.ccx.tcx; + // use a dummy type just to package up the substs that need fixing up + let t = ty::mk_self(tcx, substs); + let t_f = fixup_ty(fcx, sp, t); + alt check ty::get(t_f).struct { + ty::ty_self(substs_f) { substs_f } + } + } + + fn relate_iface_tys(fcx: @fn_ctxt, sp: span, + exp_iface_ty: ty::t, act_iface_ty: ty::t) { + demand::suptype(fcx, sp, exp_iface_ty, act_iface_ty) + } + /* Look up the vtable to use when treating an item of type <t> as if it has type <iface_ty> @@ -4486,29 +4558,39 @@ mod vtable { fn lookup_vtable(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span, ty: ty::t, iface_ty: ty::t, allow_unsafe: bool) -> vtable_origin { + + #debug["lookup_vtable(ty=%s, iface_ty=%s)", + fcx.ty_to_str(ty), fcx.ty_to_str(iface_ty)]; + let _i = indenter(); + let tcx = fcx.ccx.tcx; - let (iface_id, iface_tps) = alt check ty::get(iface_ty).struct { - ty::ty_iface(did, tps) { (did, tps) } + let (iface_id, iface_substs) = alt check ty::get(iface_ty).struct { + ty::ty_iface(did, substs) { (did, substs) } }; let ty = fixup_ty(fcx, sp, ty); alt ty::get(ty).struct { ty::ty_param(n, did) { let mut n_bound = 0u; - for vec::each(*tcx.ty_param_bounds.get(did.node)) {|bound| + for vec::each(*tcx.ty_param_bounds.get(did.node)) { |bound| alt bound { + ty::bound_send | ty::bound_copy { /* ignore */ } ty::bound_iface(ity) { alt check ty::get(ity).struct { - ty::ty_iface(idid, _) { - if iface_id == idid { ret vtable_param(n, n_bound); } + ty::ty_iface(idid, substs) { + if iface_id == idid { + relate_iface_tys(fcx, sp, iface_ty, ity); + ret vtable_param(n, n_bound); + } } } n_bound += 1u; } - _ {} } } } - ty::ty_iface(did, tps) if iface_id == did { + + ty::ty_iface(did, substs) if iface_id == did { + relate_iface_tys(fcx, sp, iface_ty, ty); if !allow_unsafe { for vec::each(*ty::iface_methods(tcx, did)) {|m| if ty::type_has_vars(ty::mk_fn(tcx, m.fty)) { @@ -4523,50 +4605,59 @@ mod vtable { } } } - ret vtable_iface(did, tps); + ret vtable_iface(did, substs.tps); } + _ { + let mut found = []; + for list::each(isc) {|impls| - let mut found = none; for vec::each(*impls) {|im| - /* What iface does this item implement? */ - let match = alt ty::impl_iface(tcx, im.did) { - some(ity) { - alt check ty::get(ity).struct { - /* Does it match the one we're searching for? */ - ty::ty_iface(id, _) { id == iface_id } - } - } - _ { false } + // find the iface that the impl is an impl of (if any) + let of_ty = alt ty::impl_iface(tcx, im.did) { + some(of_ty) { of_ty } + _ { cont; } }; - /* Found a matching iface */ - if match { - let {substs: substs, ty: self_ty} = - impl_self_ty(fcx, im.did); - let im_bs = ty::lookup_item_type(tcx, im.did).bounds; - alt unify::unify(fcx, ty, self_ty) { - result::ok(_) { - if option::is_some(found) { - tcx.sess.span_err( - sp, "multiple applicable implementations \ - in scope"); - } else { - let vars = substs.tps; - connect_iface_tps(fcx, sp, vars, - iface_tps, im.did); - let params = vec::map(vars, {|t| - fixup_ty(fcx, sp, t)}); - let subres = lookup_vtables( - fcx, isc, sp, im_bs, params, false); - found = some(vtable_static(im.did, params, - subres)); - } - } - result::err(_) {} - } + + // it must have the same id as the expected one + alt ty::get(of_ty).struct { + ty::ty_iface(id, _) if id != iface_id { cont; } + _ { /* ok */ } + } + + // check whether the type unifies with the type + // that the impl is for, and continue if not + let {substs: substs, ty: for_ty} = + impl_self_ty(fcx, im.did); + let im_bs = ty::lookup_item_type(tcx, im.did).bounds; + alt fcx.mk_subty(ty, for_ty) { + result::err(_) { cont; } + result::ok(()) { } } + + // check that desired iface type unifies + let of_ty = ty::subst(tcx, substs, of_ty); + relate_iface_tys(fcx, sp, iface_ty, of_ty); + + // recursively process the bounds + let iface_tps = iface_substs.tps; + let substs_f = fixup_substs(fcx, sp, substs); + connect_iface_tps(fcx, sp, substs_f.tps, + iface_tps, im.did); + let subres = lookup_vtables(fcx, isc, sp, + im_bs, substs_f, false); + found += [vtable_static(im.did, substs_f.tps, subres)]; + } + + alt found.len() { + 0u { /* fallthrough */ } + 1u { ret found[0]; } + _ { + fcx.ccx.tcx.sess.span_err( + sp, "multiple applicable methods in scope"); + ret found[0]; + } } - alt found { some(x) { ret x; } _ {} } } } } @@ -4597,8 +4688,8 @@ mod vtable { let ity = option::get(ty::impl_iface(tcx, impl_did)); let iface_ty = ty::subst_tps(tcx, impl_tys, ity); alt check ty::get(iface_ty).struct { - ty::ty_iface(_, tps) { - vec::iter2(tps, iface_tys, + ty::ty_iface(_, substs) { + vec::iter2(substs.tps, iface_tys, {|a, b| demand::suptype(fcx, sp, a, b);}); } } @@ -4607,26 +4698,25 @@ mod vtable { fn resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, v: visit::vt<@fn_ctxt>) { let cx = fcx.ccx; alt ex.node { - ast::expr_path(_) { + ast::expr_path(*) { alt fcx.opt_node_ty_substs(ex.id) { some(substs) { - let ts = substs.tps; // NDM regions for iface/impls let did = ast_util::def_id_of_def(cx.tcx.def_map.get(ex.id)); let item_ty = ty::lookup_item_type(cx.tcx, did); if has_iface_bounds(*item_ty.bounds) { let impls = cx.impl_map.get(ex.id); cx.vtable_map.insert(ex.id, lookup_vtables( fcx, impls, ex.span, - item_ty.bounds, ts, false)); + item_ty.bounds, substs, false)); } } _ {} } } // Must resolve bounds on methods with bounded params - ast::expr_field(_, _, _) | ast::expr_binary(_, _, _) | - ast::expr_unary(_, _) | ast::expr_assign_op(_, _, _) | - ast::expr_index(_, _) { + ast::expr_field(*) | ast::expr_binary(*) | + ast::expr_unary(*) | ast::expr_assign_op(*) | + ast::expr_index(*) { alt cx.method_map.find(ex.id) { some(method_static(did)) { let bounds = ty::lookup_item_type(cx.tcx, did).bounds; @@ -4635,11 +4725,10 @@ mod vtable { ast::expr_field(_, _, _) { ex.id } _ { ast_util::op_expr_callee_id(ex) } }; - // NDM iface/impl regions - let ts = fcx.node_ty_substs(callee_id).tps; + let substs = fcx.node_ty_substs(callee_id); let iscs = cx.impl_map.get(ex.id); cx.vtable_map.insert(callee_id, lookup_vtables( - fcx, iscs, ex.span, bounds, ts, false)); + fcx, iscs, ex.span, bounds, substs, false)); } } _ {} @@ -4648,7 +4737,7 @@ mod vtable { ast::expr_cast(src, _) { let target_ty = fcx.expr_ty(ex); alt ty::get(target_ty).struct { - ty::ty_iface(_, _) { + ty::ty_iface(*) { /* Casting to an interface type. Look up all impls for the cast expr... */ diff --git a/src/rustc/util/ppaux.rs b/src/rustc/util/ppaux.rs index 1a27bbdff84..227dc0c8645 100644 --- a/src/rustc/util/ppaux.rs +++ b/src/rustc/util/ppaux.rs @@ -134,12 +134,10 @@ fn ty_to_str(cx: ctxt, typ: t) -> str { some(def_id) { let cs = 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_enum(_, substs) | ty_res(_, _, substs) | ty_class(_, substs) | + ty_iface(_, substs) { parameterized(cx, cs, substs.self_r, substs.tps) } - ty_iface(_, tps) { - parameterized(cx, cs, none, tps) - } _ { cs } }; } @@ -159,7 +157,6 @@ fn ty_to_str(cx: ctxt, typ: t) -> str { ty_float(ast::ty_f) { "float" } ty_float(t) { ast_util::float_ty_to_str(t) } ty_str { "str" } - ty_self(ts) { parameterized(cx, "self", none, ts) } ty_box(tm) { "@" + mt_to_str(cx, tm) } ty_uniq(tm) { "~" + mt_to_str(cx, tm) } ty_ptr(tm) { "*" + mt_to_str(cx, tm) } @@ -191,15 +188,18 @@ fn ty_to_str(cx: ctxt, typ: t) -> str { ty_param(id, _) { "'" + str::from_bytes([('a' as u8) + (id as u8)]) } + ty_self(substs) { + parameterized(cx, "self", substs.self_r, substs.tps) + } ty_enum(did, substs) | ty_res(did, _, substs) | ty_class(did, substs) { let path = ty::item_path(cx, did); let base = ast_map::path_to_str(path); parameterized(cx, base, substs.self_r, substs.tps) } - ty_iface(did, tps) { + ty_iface(did, substs) { let path = ty::item_path(cx, did); let base = ast_map::path_to_str(path); - parameterized(cx, base, none, tps) + parameterized(cx, base, substs.self_r, substs.tps) } ty_evec(mt, vs) { #fmt["[%s]/%s", mt_to_str(cx, mt), diff --git a/src/rustdoc/attr_pass.rs b/src/rustdoc/attr_pass.rs index 232b72d369a..71a179e29f0 100644 --- a/src/rustdoc/attr_pass.rs +++ b/src/rustdoc/attr_pass.rs @@ -204,14 +204,14 @@ fn merge_method_attrs( let attrs: [(str, option<str>)] = astsrv::exec(srv) {|ctxt| alt ctxt.ast_map.get(item_id) { ast_map::node_item(@{ - node: ast::item_iface(_, methods), _ + node: ast::item_iface(_, _, methods), _ }, _) { par::seqmap(methods) {|method| (method.ident, attr_parser::parse_desc(method.attrs)) } } ast_map::node_item(@{ - node: ast::item_impl(_, _, _, methods), _ + node: ast::item_impl(_, _, _, _, methods), _ }, _) { par::seqmap(methods) {|method| (method.ident, attr_parser::parse_desc(method.attrs)) diff --git a/src/rustdoc/extract.rs b/src/rustdoc/extract.rs index e9cfdc4db90..fc54a1ea9f6 100644 --- a/src/rustdoc/extract.rs +++ b/src/rustdoc/extract.rs @@ -88,12 +88,12 @@ fn moddoc_from_mod( resdoc_from_resource(itemdoc) )) } - ast::item_iface(_, methods) { + ast::item_iface(_, _, methods) { some(doc::ifacetag( ifacedoc_from_iface(itemdoc, methods) )) } - ast::item_impl(_, _, _, methods) { + ast::item_impl(_, _, _, _, methods) { some(doc::impltag( impldoc_from_impl(itemdoc, methods) )) diff --git a/src/rustdoc/reexport_pass.rs b/src/rustdoc/reexport_pass.rs index 2b4ed05e3e5..cfb715d2fe4 100644 --- a/src/rustdoc/reexport_pass.rs +++ b/src/rustdoc/reexport_pass.rs @@ -292,7 +292,7 @@ fn all_impls(m: ast::_mod) -> map::set<ast::def_id> { let all_impls = common::new_def_hash(); for m.items.each {|item| alt item.node { - ast::item_impl(_, _, _, _) { + ast::item_impl(_, _, _, _, _) { all_impls.insert(ast_util::local_def(item.id), ()); } _ { } diff --git a/src/rustdoc/tystr_pass.rs b/src/rustdoc/tystr_pass.rs index 58f147ca6ff..56888758ede 100644 --- a/src/rustdoc/tystr_pass.rs +++ b/src/rustdoc/tystr_pass.rs @@ -197,7 +197,7 @@ fn get_method_sig( astsrv::exec(srv) {|ctxt| alt check ctxt.ast_map.get(item_id) { ast_map::node_item(@{ - node: ast::item_iface(_, methods), _ + node: ast::item_iface(_, _, methods), _ }, _) { alt check vec::find(methods) {|method| method.ident == method_name @@ -212,7 +212,7 @@ fn get_method_sig( } } ast_map::node_item(@{ - node: ast::item_impl(_, _, _, methods), _ + node: ast::item_impl(_, _, _, _, methods), _ }, _) { alt check vec::find(methods) {|method| method.ident == method_name @@ -247,7 +247,7 @@ fn fold_impl( let (iface_ty, self_ty) = astsrv::exec(srv) {|ctxt| alt ctxt.ast_map.get(doc.id()) { ast_map::node_item(@{ - node: ast::item_impl(_, iface_ty, self_ty, _), _ + node: ast::item_impl(_, _, iface_ty, self_ty, _), _ }, _) { let iface_ty = option::map(iface_ty) {|p| pprust::path_to_str(p.path) diff --git a/src/test/compile-fail/iface-cast.rs b/src/test/compile-fail/iface-cast.rs new file mode 100644 index 00000000000..5c859f21229 --- /dev/null +++ b/src/test/compile-fail/iface-cast.rs @@ -0,0 +1,8 @@ +iface foo<T> { } + +fn bar(x: foo<uint>) -> foo<int> { + ret (x as foo::<int>); + //!^ ERROR mismatched types: expected `foo<int>` but found `foo<uint>` +} + +fn main() {} diff --git a/src/test/compile-fail/prim-with-args.rs b/src/test/compile-fail/prim-with-args.rs new file mode 100644 index 00000000000..955d17cb33b --- /dev/null +++ b/src/test/compile-fail/prim-with-args.rs @@ -0,0 +1,29 @@ +fn main() { + +let x: int<int>; //! ERROR Type parameters are not allowed on this type. +let x: i8<int>; //! ERROR Type parameters are not allowed on this type. +let x: i16<int>; //! ERROR Type parameters are not allowed on this type. +let x: i32<int>; //! ERROR Type parameters are not allowed on this type. +let x: i64<int>; //! ERROR Type parameters are not allowed on this type. +let x: uint<int>; //! ERROR Type parameters are not allowed on this type. +let x: u8<int>; //! ERROR Type parameters are not allowed on this type. +let x: u16<int>; //! ERROR Type parameters are not allowed on this type. +let x: u32<int>; //! ERROR Type parameters are not allowed on this type. +let x: u64<int>; //! ERROR Type parameters are not allowed on this type. +let x: float<int>; //! ERROR Type parameters are not allowed on this type. +let x: char<int>; //! ERROR Type parameters are not allowed on this type. + +let x: int/&; //! ERROR Region parameters are not allowed on this type. +let x: i8/&; //! ERROR Region parameters are not allowed on this type. +let x: i16/&; //! ERROR Region parameters are not allowed on this type. +let x: i32/&; //! ERROR Region parameters are not allowed on this type. +let x: i64/&; //! ERROR Region parameters are not allowed on this type. +let x: uint/&; //! ERROR Region parameters are not allowed on this type. +let x: u8/&; //! ERROR Region parameters are not allowed on this type. +let x: u16/&; //! ERROR Region parameters are not allowed on this type. +let x: u32/&; //! ERROR Region parameters are not allowed on this type. +let x: u64/&; //! ERROR Region parameters are not allowed on this type. +let x: float/&; //! ERROR Region parameters are not allowed on this type. +let x: char/&; //! ERROR Region parameters are not allowed on this type. + +} diff --git a/src/test/compile-fail/regions-bounds.rs b/src/test/compile-fail/regions-bounds.rs new file mode 100644 index 00000000000..6f9c547d632 --- /dev/null +++ b/src/test/compile-fail/regions-bounds.rs @@ -0,0 +1,32 @@ +// Check that explicit region bounds are allowed on the various +// nominal types (but not on other types) and that they are type +// checked. + +enum an_enum/& { } +iface an_iface/& { } +class a_class/& { new() { } } +resource a_rsrc/&(_x: ()) { } + +fn a_fn1(e: an_enum/&a) -> an_enum/&b { + ret e; //! ERROR mismatched types: expected `an_enum/&b` but found `an_enum/&a` +} + +fn a_fn2(e: an_iface/&a) -> an_iface/&b { + ret e; //! ERROR mismatched types: expected `an_iface/&b` but found `an_iface/&a` +} + +fn a_fn3(e: a_class/&a) -> a_class/&b { + ret e; //! ERROR mismatched types: expected `a_class/&b` but found `a_class/&a` +} + +fn a_fn4(e: a_rsrc/&a) -> a_rsrc/&b { + ret e; //! ERROR mismatched types: expected `a_rsrc/&b` but found `a_rsrc/&a` +} + +fn a_fn5(e: int/&a) -> int/&b { + //!^ ERROR Region parameters are not allowed on this type. + //!^^ ERROR Region parameters are not allowed on this type. + ret e; +} + +fn main() { } \ No newline at end of file diff --git a/src/test/compile-fail/regions-iface-1.rs b/src/test/compile-fail/regions-iface-1.rs new file mode 100644 index 00000000000..a2a2e39a2f8 --- /dev/null +++ b/src/test/compile-fail/regions-iface-1.rs @@ -0,0 +1,28 @@ +type ctxt = { v: uint }; + +iface get_ctxt/& { + // Here the `&` is bound in the method definition: + fn get_ctxt() -> &ctxt; +} + +type has_ctxt/& = { c: &ctxt }; + +impl/& of get_ctxt for has_ctxt { + + // Here an error occurs because we used `&self` but + // the definition used `&`: + fn get_ctxt() -> &self.ctxt { //! ERROR method `get_ctxt` has an incompatible type + self.c + } + +} + +fn get_v(gc: get_ctxt) -> uint { + gc.get_ctxt().v +} + +fn main() { + let ctxt = { v: 22u }; + let hc = { c: &ctxt }; + assert get_v(hc as get_ctxt) == 22u; +} diff --git a/src/test/compile-fail/regions-iface-2.rs b/src/test/compile-fail/regions-iface-2.rs new file mode 100644 index 00000000000..76f4d24291a --- /dev/null +++ b/src/test/compile-fail/regions-iface-2.rs @@ -0,0 +1,21 @@ +type ctxt = { v: uint }; + +iface get_ctxt/& { + fn get_ctxt() -> &self.ctxt; +} + +type has_ctxt/& = { c: &ctxt }; + +impl/& of get_ctxt for has_ctxt { + fn get_ctxt() -> &self.ctxt { self.c } +} + +fn make_gc() -> get_ctxt { + let ctxt = { v: 22u }; + let hc = { c: &ctxt }; + ret hc as get_ctxt; //! ERROR mismatched types: expected `get_ctxt/&` +} + +fn main() { + make_gc().get_ctxt().v; +} diff --git a/src/test/compile-fail/regions-iface-3.rs b/src/test/compile-fail/regions-iface-3.rs new file mode 100644 index 00000000000..ae8d0130dff --- /dev/null +++ b/src/test/compile-fail/regions-iface-3.rs @@ -0,0 +1,14 @@ +iface get_ctxt/& { + fn get_ctxt() -> &self.uint; +} + +fn make_gc1(gc: get_ctxt/&a) -> get_ctxt/&b { + ret gc; //! ERROR mismatched types: expected `get_ctxt/&b` but found `get_ctxt/&a` +} + +fn make_gc2(gc: get_ctxt/&a) -> get_ctxt/&b { + ret gc as get_ctxt; //! ERROR mismatched types: expected `get_ctxt/&b` but found `get_ctxt/&a` +} + +fn main() { +} diff --git a/src/test/run-pass/regions-borrow-evec-at.rs b/src/test/run-pass/regions-borrow-evec-at.rs index 577cc980b00..e061f566e12 100644 --- a/src/test/run-pass/regions-borrow-evec-at.rs +++ b/src/test/run-pass/regions-borrow-evec-at.rs @@ -1,4 +1,4 @@ -// xfail-test it don't work yet +// xfail-test fn foo(x: [uint]/&) -> uint { x[0] diff --git a/src/test/run-pass/regions-borrow-evec-fixed.rs b/src/test/run-pass/regions-borrow-evec-fixed.rs index 906333aa207..50306b57139 100644 --- a/src/test/run-pass/regions-borrow-evec-fixed.rs +++ b/src/test/run-pass/regions-borrow-evec-fixed.rs @@ -1,4 +1,5 @@ // xfail-test + fn foo(x: [int]/&) -> int { x[0] } diff --git a/src/test/run-pass/regions-iface.rs b/src/test/run-pass/regions-iface.rs new file mode 100644 index 00000000000..6bc8f172f98 --- /dev/null +++ b/src/test/run-pass/regions-iface.rs @@ -0,0 +1,23 @@ +type ctxt = { v: uint }; + +iface get_ctxt/& { + fn get_ctxt() -> &self.ctxt; +} + +type has_ctxt/& = { c: &ctxt }; + +impl/& of get_ctxt for has_ctxt { + fn get_ctxt() -> &self.ctxt { + self.c + } +} + +fn get_v(gc: get_ctxt) -> uint { + gc.get_ctxt().v +} + +fn main() { + let ctxt = { v: 22u }; + let hc = { c: &ctxt }; + assert get_v(hc as get_ctxt) == 22u; +} diff --git a/src/test/run-pass/regions-self-impls.rs b/src/test/run-pass/regions-self-impls.rs index a587c19f38f..e29d88cc78d 100644 --- a/src/test/run-pass/regions-self-impls.rs +++ b/src/test/run-pass/regions-self-impls.rs @@ -1,9 +1,6 @@ -// xfail-test -// ^ handling of self is currently broken +type clam/& = { chowder: &int }; -type clam = { chowder: &int }; - -impl clam for clam { +impl clam/& for clam { fn get_chowder() -> &self.int { ret self.chowder; } } diff --git a/src/test/run-pass/regions-self-in-enums.rs b/src/test/run-pass/regions-self-in-enums.rs index 084192c3aa7..ced26c8c7db 100644 --- a/src/test/run-pass/regions-self-in-enums.rs +++ b/src/test/run-pass/regions-self-in-enums.rs @@ -1,6 +1,4 @@ -// xfail-test - -enum int_wrapper { +enum int_wrapper/& { int_wrapper_ctor(&int) } |
