1
Fork 0

Prevent typenames in param bounds from resolving to their own param

I.e. fn foo<T: seq<T>>(...). This leads to weird circularities that seem to
never make any sense, so it seems prudent to forbid it.

Issue #1227
This commit is contained in:
Marijn Haverbeke 2012-01-04 16:51:25 +01:00
parent 42f6608ffd
commit 94d40be746
2 changed files with 38 additions and 19 deletions

View file

@ -142,6 +142,7 @@ type env =
mutable data: [ast::node_id]}, mutable data: [ast::node_id]},
mutable reported: [{ident: str, sc: scope}], mutable reported: [{ident: str, sc: scope}],
mutable ignored_imports: [node_id], mutable ignored_imports: [node_id],
mutable current_tp: option::t<uint>,
sess: session}; sess: session};
@ -168,6 +169,7 @@ fn resolve_crate(sess: session, amap: ast_map::map, crate: @ast::crate) ->
used_imports: {mutable track: false, mutable data: []}, used_imports: {mutable track: false, mutable data: []},
mutable reported: [], mutable reported: [],
mutable ignored_imports: [], mutable ignored_imports: [],
mutable current_tp: none,
sess: sess}; sess: sess};
map_crate(e, crate); map_crate(e, crate);
resolve_imports(*e); resolve_imports(*e);
@ -336,6 +338,7 @@ fn resolve_names(e: @env, c: @ast::crate) {
visit_pat: bind walk_pat(e, _, _, _), visit_pat: bind walk_pat(e, _, _, _),
visit_expr: bind walk_expr(e, _, _, _), visit_expr: bind walk_expr(e, _, _, _),
visit_ty: bind walk_ty(e, _, _, _), visit_ty: bind walk_ty(e, _, _, _),
visit_ty_params: bind walk_tps(e, _, _, _),
visit_constr: bind walk_constr(e, _, _, _, _, _), visit_constr: bind walk_constr(e, _, _, _, _, _),
visit_fn: bind visit_fn_with_scope(e, _, _, _, _, _, _, _) visit_fn: bind visit_fn_with_scope(e, _, _, _, _, _, _, _)
with *visit::default_visitor()}; with *visit::default_visitor()};
@ -369,6 +372,20 @@ fn resolve_names(e: @env, c: @ast::crate) {
_ { } _ { }
} }
} }
fn walk_tps(e: @env, tps: [ast::ty_param], sc: scopes, v: vt<scopes>) {
let outer_current_tp = e.current_tp, current = 0u;
for tp in tps {
e.current_tp = some(current);
for bound in *tp.bounds {
alt bound {
bound_iface(t) { v.visit_ty(t, sc, v); }
_ {}
}
}
current += 1u;
}
e.current_tp = outer_current_tp;
}
fn walk_constr(e: @env, p: @ast::path, sp: span, id: node_id, sc: scopes, fn walk_constr(e: @env, p: @ast::path, sp: span, id: node_id, sc: scopes,
_v: vt<scopes>) { _v: vt<scopes>) {
maybe_insert(e, id, lookup_path_strict(*e, sc, sp, p.node, ns_value)); maybe_insert(e, id, lookup_path_strict(*e, sc, sp, p.node, ns_value));
@ -806,14 +823,14 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace)
scope_item(it) { scope_item(it) {
alt it.node { alt it.node {
ast::item_obj(ob, ty_params, _) { ast::item_obj(ob, ty_params, _) {
ret lookup_in_obj(name, ob, ty_params, ns, it.id); ret lookup_in_obj(e, name, ob, ty_params, ns, it.id);
} }
ast::item_impl(ty_params, _, _, _) { ast::item_impl(tps, _, _, _) {
if ns == ns_type { ret lookup_in_ty_params(name, ty_params); } if ns == ns_type { ret lookup_in_ty_params(e, name, tps); }
} }
ast::item_iface(tps, _) | ast::item_tag(_, tps) | ast::item_iface(tps, _) | ast::item_tag(_, tps) |
ast::item_ty(_, tps) { ast::item_ty(_, tps) {
if ns == ns_type { ret lookup_in_ty_params(name, tps); } if ns == ns_type { ret lookup_in_ty_params(e, name, tps); }
} }
ast::item_mod(_) { ast::item_mod(_) {
ret lookup_in_local_mod(e, it.id, sp, name, ns, inside); ret lookup_in_local_mod(e, it.id, sp, name, ns, inside);
@ -828,19 +845,19 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace)
if (name == "self" && ns == ns_value) { if (name == "self" && ns == ns_value) {
ret some(ast::def_self(local_def(id))); ret some(ast::def_self(local_def(id)));
} else if ns == ns_type { } else if ns == ns_type {
ret lookup_in_ty_params(name, tps); ret lookup_in_ty_params(e, name, tps);
} }
} }
scope_native_item(it) { scope_native_item(it) {
alt it.node { alt it.node {
ast::native_item_fn(decl, ty_params) { ast::native_item_fn(decl, ty_params) {
ret lookup_in_fn(name, decl, ty_params, ns); ret lookup_in_fn(e, name, decl, ty_params, ns);
} }
} }
} }
scope_bare_fn(decl, _, ty_params) | scope_bare_fn(decl, _, ty_params) |
scope_fn_expr(decl, _, ty_params) { scope_fn_expr(decl, _, ty_params) {
ret lookup_in_fn(name, decl, ty_params, ns); ret lookup_in_fn(e, name, decl, ty_params, ns);
} }
scope_loop(local) { scope_loop(local) {
if ns == ns_value { if ns == ns_value {
@ -915,13 +932,13 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace)
e.sess.bug("reached unreachable code in lookup_in_scope"); // sigh e.sess.bug("reached unreachable code in lookup_in_scope"); // sigh
} }
fn lookup_in_ty_params(name: ident, ty_params: [ast::ty_param]) -> fn lookup_in_ty_params(e: env, name: ident, ty_params: [ast::ty_param])
option::t<def> { -> option::t<def> {
let n = 0u; let n = 0u;
for tp: ast::ty_param in ty_params { for tp: ast::ty_param in ty_params {
if str::eq(tp.ident, name) { if str::eq(tp.ident, name) && alt e.current_tp {
ret some(ast::def_ty_param(local_def(tp.id), n)); some(cur) { n < cur } none. { true }
} } { ret some(ast::def_ty_param(local_def(tp.id), n)); }
n += 1u; n += 1u;
} }
ret none::<def>; ret none::<def>;
@ -936,7 +953,8 @@ fn lookup_in_pat(name: ident, pat: @ast::pat) -> option::t<def_id> {
ret found; ret found;
} }
fn lookup_in_fn(name: ident, decl: ast::fn_decl, ty_params: [ast::ty_param], fn lookup_in_fn(e: env, name: ident, decl: ast::fn_decl,
ty_params: [ast::ty_param],
ns: namespace) -> option::t<def> { ns: namespace) -> option::t<def> {
alt ns { alt ns {
ns_value. { ns_value. {
@ -947,12 +965,13 @@ fn lookup_in_fn(name: ident, decl: ast::fn_decl, ty_params: [ast::ty_param],
} }
ret none::<def>; ret none::<def>;
} }
ns_type. { ret lookup_in_ty_params(name, ty_params); } ns_type. { ret lookup_in_ty_params(e, name, ty_params); }
_ { ret none::<def>; } _ { ret none::<def>; }
} }
} }
fn lookup_in_obj(name: ident, ob: ast::_obj, ty_params: [ast::ty_param], fn lookup_in_obj(e: env, name: ident, ob: ast::_obj,
ty_params: [ast::ty_param],
ns: namespace, id: node_id) -> option::t<def> { ns: namespace, id: node_id) -> option::t<def> {
alt ns { alt ns {
ns_value. { ns_value. {
@ -964,7 +983,7 @@ fn lookup_in_obj(name: ident, ob: ast::_obj, ty_params: [ast::ty_param],
} }
ret none::<def>; ret none::<def>;
} }
ns_type. { ret lookup_in_ty_params(name, ty_params); } ns_type. { ret lookup_in_ty_params(e, name, ty_params); }
_ { ret none::<def>; } _ { ret none::<def>; }
} }
} }

View file

@ -2748,7 +2748,7 @@ fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method,
let substs = substs + vec::init_fn({|i| let substs = substs + vec::init_fn({|i|
ty::mk_param(tcx, i + impl_tps, {crate: 0, node: 0}) ty::mk_param(tcx, i + impl_tps, {crate: 0, node: 0})
}, vec::len(*if_m.tps)); }, vec::len(*if_m.tps));
let if_fty = ty::substitute_type_params(tcx, substs, let if_fty = ty::substitute_type_params(tcx, substs,
ty::mk_fn(tcx, if_m.fty)); ty::mk_fn(tcx, if_m.fty));
alt ty::unify::unify(impl_fty, if_fty, ty::unify::precise, tcx) { alt ty::unify::unify(impl_fty, if_fty, ty::unify::precise, tcx) {
ty::unify::ures_err(err) { ty::unify::ures_err(err) {
@ -3064,8 +3064,8 @@ mod dict {
visit::visit_expr(ex, fcx, v); visit::visit_expr(ex, fcx, v);
} }
// Detect points where an interface-bounded type parameter is instantiated, // Detect points where an interface-bounded type parameter is
// resolve the impls for the parameters. // instantiated, resolve the impls for the parameters.
fn resolve_in_block(fcx: @fn_ctxt, bl: ast::blk) { fn resolve_in_block(fcx: @fn_ctxt, bl: ast::blk) {
visit::visit_block(bl, fcx, visit::mk_vt(@{ visit::visit_block(bl, fcx, visit::mk_vt(@{
visit_expr: resolve_expr, visit_expr: resolve_expr,