2 import syntax::{ast, ast_util, codemap};
4 import ast::{ident, fn_ident, def, def_id, node_id};
5 import syntax::ast_util::{local_def, def_id_of_def};
8 import metadata::{csearch, cstore};
9 import driver::session::session;
10 import util::common::*;
11 import std::map::{new_int_hash, new_str_hash};
12 import syntax::codemap::span;
15 import core::{vec, option, str};
17 import std::map::hashmap;
18 import std::list::{list, nil, cons};
19 import option::{some, none, is_none, is_some};
20 import syntax::print::pprust::*;
23 export def_map, ext_map, exp_map, impl_map;
24 export _impl, iscopes, method_info;
26 // Resolving happens in two passes. The first pass collects defids of all
27 // (internal) imports and modules, so that they can be looked up when needed,
28 // and then uses this information to resolve the imports. The second pass
29 // locates all names (in expressions, types, and alt patterns) and resolves
30 // them, storing the resulting def in the AST nodes.
34 scope_item(@ast::item);
35 scope_bare_fn(ast::fn_decl, node_id, [ast::ty_param]);
36 scope_fn_expr(ast::fn_decl, node_id, [ast::ty_param]);
37 scope_native_item(@ast::native_item);
38 scope_loop(@ast::local); // there's only 1 decl per loop.
39 scope_block(ast::blk, @mutable uint, @mutable uint);
41 scope_method(ast::node_id, [ast::ty_param]);
44 type scopes = list<scope>;
47 todo(ast::node_id, ast::ident, @[ast::ident], codemap::span, scopes);
48 is_glob(@[ast::ident], scopes, codemap::span);
50 resolved(option::t<def>, /* value */
51 option::t<def>, /* type */
52 option::t<def>, /* module */
53 @[@_impl], /* impls */
54 /* used for reporting unused import warning */
55 ast::ident, codemap::span);
58 tag glob_import_state {
60 glob_resolved(option::t<def>, /* value */
61 option::t<def>, /* type */
62 option::t<def>); /* module */
65 type ext_hash = hashmap<{did: def_id, ident: str, ns: namespace}, def>;
67 fn new_ext_hash() -> ext_hash {
68 type key = {did: def_id, ident: str, ns: namespace};
69 fn hash(v: key) -> uint {
70 ret str::hash(v.ident) + util::common::hash_def(v.did) +
77 fn eq(v1: key, v2: key) -> bool {
78 ret util::common::def_eq(v1.did, v2.did) &&
79 str::eq(v1.ident, v2.ident) && v1.ns == v2.ns;
81 ret std::map::mk_hashmap::<key, def>(hash, eq);
84 fn new_exp_hash() -> exp_map {
85 type key = {path: str, ns: namespace};
86 fn hash(v: key) -> uint {
87 ret str::hash(v.path) +
94 fn eq(v1: key, v2: key) -> bool {
95 ret str::eq(v1.path, v2.path) && v1.ns == v2.ns;
97 ret std::map::mk_hashmap::<key, def>(hash, eq);
100 tag mod_index_entry {
101 mie_view_item(@ast::view_item);
102 mie_import_ident(node_id, codemap::span);
103 mie_item(@ast::item);
104 mie_native_item(@ast::native_item);
105 mie_tag_variant(/* tag item */@ast::item, /* variant index */uint);
108 type mod_index = hashmap<ident, list<mod_index_entry>>;
110 // A tuple of an imported def and the import stmt that brung it
111 type glob_imp_def = {def: def, item: @ast::view_item};
114 m: option::t<ast::_mod>,
116 mutable glob_imports: [glob_imp_def],
117 glob_imported_names: hashmap<str, glob_import_state>,
121 /* native modules can't contain tags, and we don't store their ASTs because we
122 only need to look at them to determine exports, which they can't control.*/
124 type def_map = hashmap<node_id, def>;
125 type ext_map = hashmap<def_id, [ident]>;
126 type exp_map = hashmap<{path: str, ns: namespace}, def>;
127 type impl_map = hashmap<node_id, iscopes>;
128 type impl_cache = hashmap<def_id, @[@_impl]>;
131 {cstore: cstore::cstore,
133 ast_map: ast_map::map,
134 imports: hashmap<ast::node_id, import_state>,
136 mod_map: hashmap<ast::node_id, @indexed_mod>,
137 block_map: hashmap<ast::node_id, [glob_imp_def]>,
140 impl_cache: impl_cache,
142 used_imports: {mutable track: bool,
143 mutable data: [ast::node_id]},
144 mutable reported: [{ident: str, sc: scope}],
145 mutable ignored_imports: [node_id],
146 mutable current_tp: option::t<uint>,
147 mutable resolve_unexported: bool,
151 // Used to distinguish between lookups from outside and from inside modules,
152 // since export restrictions should only be applied for the former.
153 tag dir { inside; outside; }
155 // There are two types of ns_value tag: "definitely a tag";
156 // and "any value". This is so that lookup can behave differently
157 // when looking up a variable name that's not yet in scope to check
158 // if it's already bound to a tag.
159 tag namespace { ns_val(ns_value_type); ns_type; ns_module; }
160 tag ns_value_type { ns_a_tag; ns_any_value; }
162 fn resolve_crate(sess: session, amap: ast_map::map, crate: @ast::crate) ->
163 {def_map: def_map, exp_map: exp_map, impl_map: impl_map} {
165 @{cstore: sess.get_cstore(),
166 def_map: new_int_hash(),
168 imports: new_int_hash(),
169 exp_map: new_exp_hash(),
170 mod_map: new_int_hash(),
171 block_map: new_int_hash(),
172 ext_map: new_def_hash(),
173 impl_map: new_int_hash(),
174 impl_cache: new_def_hash(),
175 ext_cache: new_ext_hash(),
176 used_imports: {mutable track: false, mutable data: []},
177 mutable reported: [],
178 mutable ignored_imports: [],
179 mutable current_tp: none,
180 mutable resolve_unexported: false,
184 check_for_collisions(e, *crate);
186 resolve_names(e, crate);
187 resolve_impls(e, crate);
188 if sess.get_opts().warn_unused_imports {
189 check_unused_imports(e);
191 ret {def_map: e.def_map, exp_map: e.exp_map, impl_map: e.impl_map};
194 // Locate all modules and imports and index them, so that the next passes can
195 // resolve through them.
196 fn map_crate(e: @env, c: @ast::crate) {
197 // First, find all the modules, and index the names that they contain
199 @{visit_view_item: bind index_vi(e, _, _, _),
200 visit_item: bind index_i(e, _, _, _),
201 visit_block: visit_block_with_scope
202 with *visit::default_visitor::<scopes>()};
203 visit::visit_crate(*c, cons(scope_crate, @nil), visit::mk_vt(v_map_mod));
205 // Register the top-level mod
206 e.mod_map.insert(ast::crate_node_id,
207 @{m: some(c.node.module),
208 index: index_mod(c.node.module),
209 mutable glob_imports: [],
210 glob_imported_names: new_str_hash(),
212 fn index_vi(e: @env, i: @ast::view_item, sc: scopes, _v: vt<scopes>) {
214 ast::view_item_import(name, ids, id) {
215 e.imports.insert(id, todo(id, name, ids, i.span, sc));
217 ast::view_item_import_from(mod_path, idents, id) {
218 for ident in idents {
219 e.imports.insert(ident.node.id,
220 todo(ident.node.id, ident.node.name,
221 @(*mod_path + [ident.node.name]),
225 ast::view_item_import_glob(pth, id) {
226 e.imports.insert(id, is_glob(pth, sc, i.span));
231 fn path_from_scope(sc: scopes, n: str) -> str {
235 scope_item(i) { path = i.ident + "::" + path; }
241 fn index_i(e: @env, i: @ast::item, sc: scopes, v: vt<scopes>) {
242 visit_item_with_scope(e, i, sc, v);
245 e.mod_map.insert(i.id,
247 index: index_mod(md),
248 mutable glob_imports: [],
249 glob_imported_names: new_str_hash(),
250 path: path_from_scope(sc, i.ident)});
252 ast::item_native_mod(nmd) {
253 e.mod_map.insert(i.id,
254 @{m: none::<ast::_mod>,
255 index: index_nmod(nmd),
256 mutable glob_imports: [],
257 glob_imported_names: new_str_hash(),
258 path: path_from_scope(sc, i.ident)});
264 // Next, assemble the links for globbed imports.
266 @{visit_view_item: bind link_glob(e, _, _, _),
267 visit_block: visit_block_with_scope,
268 visit_item: bind visit_item_with_scope(e, _, _, _)
269 with *visit::default_visitor::<scopes>()};
270 visit::visit_crate(*c, cons(scope_crate, @nil),
271 visit::mk_vt(v_link_glob));
272 fn link_glob(e: @env, vi: @ast::view_item, sc: scopes, _v: vt<scopes>) {
274 //if it really is a glob import, that is
275 ast::view_item_import_glob(path, _) {
276 let imp = follow_import(*e, sc, *path, vi.span);
277 if option::is_some(imp) {
278 let glob = {def: option::get(imp), item: vi};
279 check list::is_not_empty(sc);
282 e.mod_map.get(i.id).glob_imports += [glob];
284 scope_block(b, _, _) {
285 let globs = alt e.block_map.find(b.node.id) {
286 some(globs) { globs + [glob] } none. { [glob] }
288 e.block_map.insert(b.node.id, globs);
291 e.mod_map.get(ast::crate_node_id).glob_imports += [glob];
301 fn resolve_imports(e: env) {
302 e.used_imports.track = true;
303 e.imports.values {|v|
305 todo(node_id, name, path, span, scopes) {
306 resolve_import(e, local_def(node_id), name, *path, span, scopes);
308 resolved(_, _, _, _, _, _) | is_glob(_, _, _) { }
311 e.used_imports.track = false;
312 e.sess.abort_if_errors();
315 fn check_unused_imports(e: @env) {
316 e.imports.items {|k, v|
318 resolved(_, _, _, _, name, sp) {
319 if !vec::member(k, e.used_imports.data) {
320 e.sess.span_warn(sp, "unused import " + name);
328 fn resolve_capture_item(e: @env, sc: scopes, &&cap_item: @ast::capture_item) {
329 let dcur = lookup_in_scope_strict(
330 *e, sc, cap_item.span, cap_item.name, ns_val(ns_any_value));
331 maybe_insert(e, cap_item.id, dcur);
334 fn maybe_insert(e: @env, id: node_id, def: option::t<def>) {
335 if option::is_some(def) { e.def_map.insert(id, option::get(def)); }
338 fn resolve_names(e: @env, c: @ast::crate) {
339 e.used_imports.track = true;
341 @{visit_native_item: visit_native_item_with_scope,
342 visit_item: bind visit_item_with_scope(e, _, _, _),
343 visit_block: visit_block_with_scope,
344 visit_decl: visit_decl_with_scope,
345 visit_arm: visit_arm_with_scope,
346 visit_local: bind visit_local_with_scope(e, _, _, _),
347 visit_pat: bind walk_pat(e, _, _, _),
348 visit_expr: bind walk_expr(e, _, _, _),
349 visit_ty: bind walk_ty(e, _, _, _),
350 visit_ty_params: bind walk_tps(e, _, _, _),
351 visit_constr: bind walk_constr(e, _, _, _, _, _),
352 visit_fn: bind visit_fn_with_scope(e, _, _, _, _, _, _, _)
353 with *visit::default_visitor()};
354 visit::visit_crate(*c, cons(scope_crate, @nil), visit::mk_vt(v));
355 e.used_imports.track = false;
356 e.sess.abort_if_errors();
358 fn walk_expr(e: @env, exp: @ast::expr, sc: scopes, v: vt<scopes>) {
359 visit_expr_with_scope(exp, sc, v);
362 maybe_insert(e, exp.id,
363 lookup_path_strict(*e, sc, exp.span, p.node,
364 ns_val(ns_any_value)));
366 ast::expr_fn(_, _, _, cap_clause) {
367 let rci = bind resolve_capture_item(e, sc, _);
368 vec::iter(cap_clause.copies, rci);
369 vec::iter(cap_clause.moves, rci);
374 fn walk_ty(e: @env, t: @ast::ty, sc: scopes, v: vt<scopes>) {
375 visit::visit_ty(t, sc, v);
377 ast::ty_path(p, id) {
379 lookup_path_strict(*e, sc, t.span, p.node, ns_type));
384 fn walk_tps(e: @env, tps: [ast::ty_param], sc: scopes, v: vt<scopes>) {
385 let outer_current_tp = e.current_tp, current = 0u;
387 e.current_tp = some(current);
388 for bound in *tp.bounds {
390 bound_iface(t) { v.visit_ty(t, sc, v); }
396 e.current_tp = outer_current_tp;
398 fn walk_constr(e: @env, p: @ast::path, sp: span, id: node_id, sc: scopes,
400 maybe_insert(e, id, lookup_path_strict(*e, sc,
401 sp, p.node, ns_val(ns_any_value)));
403 fn walk_pat(e: @env, pat: @ast::pat, sc: scopes, v: vt<scopes>) {
404 visit::visit_pat(pat, sc, v);
407 let fnd = lookup_path_strict(*e, sc, p.span, p.node,
408 ns_val(ns_any_value));
409 alt option::get(fnd) {
410 ast::def_variant(did, vid) {
411 e.def_map.insert(pat.id, option::get(fnd));
414 e.sess.span_err(p.span,
415 "not a tag variant: " +
416 ast_util::path_name(p));
426 // Visit helper functions
427 fn visit_item_with_scope(e: @env, i: @ast::item, sc: scopes, v: vt<scopes>) {
429 // Some magic here. Items with the !resolve_unexported attribute
430 // cause us to consider every name to be exported when resolving their
431 // contents. This is used to allow the test runner to run unexported
433 let old_resolve_unexported = e.resolve_unexported;
434 e.resolve_unexported |=
435 attr::contains_name(attr::attr_metas(i.attrs),
436 "!resolve_unexported");
438 let sc = cons(scope_item(i), @sc);
440 ast::item_impl(tps, ifce, sty, methods) {
441 visit::visit_ty_params(tps, sc, v);
442 alt ifce { some(ty) { v.visit_ty(ty, sc, v); } _ {} }
443 v.visit_ty(sty, sc, v);
445 let msc = cons(scope_method(i.id, tps + m.tps), @sc);
446 v.visit_fn(visit::fk_method(m.ident, []),
447 m.decl, m.body, m.span, m.id, msc, v);
450 ast::item_iface(tps, methods) {
451 visit::visit_ty_params(tps, sc, v);
453 let msc = cons(scope_method(i.id, tps + m.tps), @sc);
454 for a in m.decl.inputs { v.visit_ty(a.ty, msc, v); }
455 v.visit_ty(m.decl.output, msc, v);
458 _ { visit::visit_item(i, sc, v); }
461 e.resolve_unexported = old_resolve_unexported;
464 fn visit_native_item_with_scope(ni: @ast::native_item, sc: scopes,
466 visit::visit_native_item(ni, cons(scope_native_item(ni), @sc), v);
469 fn visit_fn_with_scope(e: @env, fk: visit::fn_kind, decl: ast::fn_decl,
470 body: ast::blk, sp: span,
471 id: node_id, sc: scopes, v: vt<scopes>) {
472 // is this a main fn declaration?
474 visit::fk_item_fn(nm, _) {
475 if is_main_name([nm]) && !e.sess.building_library() {
476 // This is a main function -- set it in the session
478 e.sess.set_main_id(id);
481 _ { /* fallthrough */ }
484 // here's where we need to set up the mapping
485 // for f's constrs in the table.
486 for c: @ast::constr in decl.constraints { resolve_constr(e, c, sc, v); }
488 visit::fk_item_fn(_, tps) | visit::fk_res(_, tps) |
489 visit::fk_method(_, tps) { scope_bare_fn(decl, id, tps) }
490 visit::fk_anon(ast::proto_bare.) { scope_bare_fn(decl, id, []) }
491 visit::fk_anon(_) | visit::fk_fn_block. { scope_fn_expr(decl, id, []) }
494 visit::visit_fn(fk, decl, body, sp, id, cons(scope, @sc), v);
497 fn visit_block_with_scope(b: ast::blk, sc: scopes, v: vt<scopes>) {
498 let pos = @mutable 0u, loc = @mutable 0u;
499 let block_sc = cons(scope_block(b, pos, loc), @sc);
500 for vi in b.node.view_items { v.visit_view_item(vi, block_sc, v); }
501 for stmt in b.node.stmts {
502 v.visit_stmt(stmt, block_sc, v);;
506 visit::visit_expr_opt(b.node.expr, block_sc, v);
509 fn visit_decl_with_scope(d: @decl, sc: scopes, v: vt<scopes>) {
510 check list::is_not_empty(sc);
511 let loc_pos = alt list::head(sc) {
512 scope_block(_, _, pos) { pos }
517 for (_, loc) in locs { v.visit_local(loc, sc, v);; *loc_pos += 1u; }
519 decl_item(it) { v.visit_item(it, sc, v); }
523 fn visit_arm_with_scope(a: ast::arm, sc: scopes, v: vt<scopes>) {
524 for p: @pat in a.pats { v.visit_pat(p, sc, v); }
525 let sc_inner = cons(scope_arm(a), @sc);
526 visit::visit_expr_opt(a.guard, sc_inner, v);
527 v.visit_block(a.body, sc_inner, v);
530 fn visit_expr_with_scope(x: @ast::expr, sc: scopes, v: vt<scopes>) {
532 ast::expr_for(decl, coll, blk) {
533 let new_sc = cons(scope_loop(decl), @sc);
534 v.visit_expr(coll, sc, v);
535 v.visit_local(decl, new_sc, v);
536 v.visit_block(blk, new_sc, v);
538 ast::expr_anon_obj(_) {
539 visit::visit_expr(x, cons(scope_method(x.id, []), @sc), v);
541 _ { visit::visit_expr(x, sc, v); }
545 fn visit_local_with_scope(e: @env, loc: @local, sc:scopes, v:vt<scopes>) {
546 // Checks whether the given local has the same name as a tag that's
548 // We disallow this, in order to make alt patterns consisting of
549 // a single identifier unambiguous (does the pattern "foo" refer
550 // to tag foo, or is it binding a new name foo?)
551 alt loc.node.pat.node {
552 pat_bind(an_ident,_) {
553 // Be sure to pass ns_a_tag to lookup_in_scope so that
554 // if this is a name that's being shadowed, we don't die
555 alt lookup_in_scope(*e, sc, loc.span, an_ident, ns_val(ns_a_tag)) {
556 some(ast::def_variant(tag_id,variant_id)) {
557 // Declaration shadows a tag that's in scope.
559 e.sess.span_err(loc.span,
560 #fmt("Declaration of %s shadows a tag that's in scope",
569 visit::visit_local(loc, sc, v);
573 fn follow_import(e: env, sc: scopes, path: [ident], sp: span) ->
575 let path_len = vec::len(path);
576 let dcur = lookup_in_scope_strict(e, sc, sp, path[0], ns_module);
578 while true && option::is_some(dcur) {
579 if i == path_len { break; }
581 lookup_in_mod_strict(e, option::get(dcur), sp, path[i],
586 alt option::get(dcur) {
587 ast::def_mod(_) | ast::def_native_mod(_) { ret dcur; }
589 e.sess.span_err(sp, str::connect(path, "::") +
590 " does not name a module.");
597 fn resolve_constr(e: @env, c: @ast::constr, sc: scopes, _v: vt<scopes>) {
599 lookup_path_strict(*e, sc, c.span, c.node.path.node,
600 ns_val(ns_any_value));
601 if option::is_some(new_def) {
602 alt option::get(new_def) {
603 ast::def_fn(pred_id, ast::pure_fn.) {
604 e.def_map.insert(c.node.id, ast::def_fn(pred_id, ast::pure_fn));
607 e.sess.span_err(c.span,
608 "Non-predicate in constraint: " +
609 path_to_str(c.node.path));
616 fn resolve_import(e: env, defid: ast::def_id, name: ast::ident,
617 ids: [ast::ident], sp: codemap::span, sc: scopes) {
618 fn register(e: env, id: node_id, cx: ctxt, sp: codemap::span,
619 name: ast::ident, lookup: block(namespace) -> option::t<def>,
621 let val = lookup(ns_val(ns_any_value)), typ = lookup(ns_type),
622 md = lookup(ns_module);
623 if is_none(val) && is_none(typ) && is_none(md) &&
624 vec::len(impls) == 0u {
625 unresolved_err(e, cx, sp, name, "import");
627 e.imports.insert(id, resolved(val, typ, md, @impls, name, sp));
630 // Temporarily disable this import and the imports coming after during
631 // resolution of this import.
632 fn find_imports_after(e: env, id: node_id, sc: scopes) -> [node_id] {
633 fn lst(my_id: node_id, vis: [@view_item]) -> [node_id] {
634 let imports = [], found = false;
637 view_item_import(_, _, id) | view_item_import_glob(_, id) {
638 if id == my_id { found = true; }
639 if found { imports += [id]; }
641 view_item_import_from(_, ids, _) {
643 if id.node.id == my_id { found = true; }
644 if found { imports += [id.node.id]; }
653 cons(scope_item(@{node: item_mod(m), _}), _) {
654 lst(id, m.view_items)
656 cons(scope_item(@{node: item_native_mod(m), _}), _) {
657 lst(id, m.view_items)
659 cons(scope_block(b, _, _), _) {
660 lst(id, b.node.view_items)
662 cons(scope_crate., _) {
664 option::get(e.mod_map.get(ast::crate_node_id).m).view_items)
668 // This function has cleanup code at the end. Do not return without going
670 e.imports.insert(defid.node, resolving(sp));
671 let ignored = find_imports_after(e, defid.node, sc);
672 e.ignored_imports <-> ignored;
673 let n_idents = vec::len(ids);
674 let end_id = ids[n_idents - 1u];
676 register(e, defid.node, in_scope(sc), sp, name,
677 {|ns| lookup_in_scope(e, sc, sp, end_id, ns) }, []);
679 alt lookup_in_scope(e, sc, sp, ids[0], ns_module) {
681 unresolved_err(e, in_scope(sc), sp, ids[0], ns_name(ns_module));
684 let dcur = dcur_, i = 1u;
686 if i == n_idents - 1u {
688 find_impls_in_mod(e, dcur, impls, some(end_id));
689 register(e, defid.node, in_mod(dcur), sp, name, {|ns|
690 lookup_in_mod(e, dcur, sp, end_id, ns, outside)
694 dcur = alt lookup_in_mod(e, dcur, sp, ids[i], ns_module,
698 unresolved_err(e, in_mod(dcur), sp, ids[i],
709 e.ignored_imports <-> ignored;
710 // If we couldn't resolve the import, don't leave it in a partially
711 // resolved state, to avoid having it reported later as a cyclic
713 alt e.imports.find(defid.node) {
714 some(resolving(sp)) {
715 e.imports.insert(defid.node, resolved(none, none, none, @[], "", sp));
723 fn ns_name(ns: namespace) -> str {
725 ns_type. { "typename" }
728 ns_any_value. { "name" }
732 ns_module. { ret "modulename" }
736 tag ctxt { in_mod(def); in_scope(scopes); }
738 fn unresolved_err(e: env, cx: ctxt, sp: span, name: ident, kind: str) {
739 fn find_fn_or_mod_scope(sc: scopes) -> option::t<scope> {
745 scope_crate. | scope_bare_fn(_, _, _) |
746 scope_fn_expr(_, _, _) |
747 scope_item(@{node: ast::item_mod(_), _}) {
761 alt find_fn_or_mod_scope(sc) {
763 for rs: {ident: str, sc: scope} in e.reported {
764 if str::eq(rs.ident, name) && err_scope == rs.sc { ret; }
766 e.reported += [{ident: name, sc: err_scope}];
772 let did = def_id_of_def(def);
773 if did.crate == ast::local_crate {
774 path = e.mod_map.get(did.node).path + path;
775 } else if did.node != ast::crate_node_id {
776 let paths = e.ext_map.get(did);
777 if vec::len(paths) > 0u {
778 path = str::connect(paths, "::") + "::" + path;
783 e.sess.span_err(sp, mk_unresolved_msg(path, kind));
786 fn unresolved_fatal(e: env, sp: span, id: ident, kind: str) -> ! {
787 e.sess.span_fatal(sp, mk_unresolved_msg(id, kind));
790 fn mk_unresolved_msg(id: ident, kind: str) -> str {
791 ret #fmt["unresolved %s: %s", kind, id];
795 fn lookup_path_strict(e: env, sc: scopes, sp: span, pth: ast::path_,
796 ns: namespace) -> option::t<def> {
797 let n_idents = vec::len(pth.idents);
798 let headns = if n_idents == 1u { ns } else { ns_module };
802 first_scope = list::cons(scope_crate, @list::nil);
803 } else { first_scope = sc; }
806 lookup_in_scope_strict(e, first_scope, sp, pth.idents[0], headns);
809 while i < n_idents && option::is_some(dcur) {
810 let curns = if n_idents == i + 1u { ns } else { ns_module };
812 lookup_in_mod_strict(e, option::get(dcur), sp, pth.idents[i],
819 fn lookup_in_scope_strict(e: env, sc: scopes, sp: span, name: ident,
820 ns: namespace) -> option::t<def> {
821 alt lookup_in_scope(e, sc, sp, name, ns) {
823 unresolved_err(e, in_scope(sc), sp, name, ns_name(ns));
826 some(d) { ret some(d); }
830 fn scope_is_fn(sc: scope) -> bool {
832 scope_bare_fn(_, _, _) | scope_native_item(_) { true }
838 // none - does not close
839 // some(node_id) - closes via the expr w/ node_id
840 fn scope_closes(sc: scope) -> option::t<node_id> {
842 scope_fn_expr(_, node_id, _) { some(node_id) }
847 fn def_is_local(d: def) -> bool {
849 ast::def_arg(_, _) | ast::def_local(_, _) | ast::def_binding(_) |
850 ast::def_upvar(_, _, _) {
857 fn def_is_obj_field(d: def) -> bool {
859 ast::def_obj_field(_, _) | ast::def_self(_) { true }
864 fn def_is_ty_arg(d: def) -> bool {
865 ret alt d { ast::def_ty_param(_, _) { true } _ { false } };
868 fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace)
870 fn in_scope(e: env, sp: span, name: ident, s: scope, ns: namespace) ->
874 ret lookup_in_local_mod(e, ast::crate_node_id, sp,
879 ast::item_obj(ob, ty_params, _) {
880 ret lookup_in_obj(e, name, ob, ty_params, ns, it.id);
882 ast::item_impl(tps, _, _, _) {
883 if ns == ns_type { ret lookup_in_ty_params(e, name, tps); }
885 ast::item_iface(tps, _) | ast::item_tag(_, tps) |
886 ast::item_ty(_, tps) {
887 if ns == ns_type { ret lookup_in_ty_params(e, name, tps); }
890 ret lookup_in_local_mod(e, it.id, sp, name, ns, inside);
892 ast::item_native_mod(m) {
893 ret lookup_in_local_native_mod(e, it.id, sp, name, ns);
898 scope_method(id, tps) {
899 if (name == "self" && ns == ns_val(ns_any_value)) {
900 ret some(ast::def_self(local_def(id)));
901 } else if ns == ns_type {
902 ret lookup_in_ty_params(e, name, tps);
905 scope_native_item(it) {
907 ast::native_item_fn(decl, ty_params) {
908 ret lookup_in_fn(e, name, decl, ty_params, ns);
912 scope_bare_fn(decl, _, ty_params) |
913 scope_fn_expr(decl, _, ty_params) {
914 ret lookup_in_fn(e, name, decl, ty_params, ns);
917 if ns == ns_val(ns_any_value) {
918 alt lookup_in_pat(name, local.node.pat) {
919 some(did) { ret some(ast::def_binding(did)); }
924 scope_block(b, pos, loc) {
925 ret lookup_in_block(e, name, sp, b.node, *pos, *loc, ns);
928 if ns == ns_val(ns_any_value) {
929 alt lookup_in_pat(name, a.pats[0]) {
930 some(did) { ret some(ast::def_binding(did)); }
940 // Used to determine whether obj fields are in scope
941 let left_fn_level2 = false;
945 nil. { ret none::<def>; }
947 let fnd = in_scope(e, sp, name, hd, ns);
949 let df = option::get(fnd);
950 let local = def_is_local(df);
951 if left_fn && local || left_fn_level2 && def_is_obj_field(df)
952 || scope_is_fn(hd) && left_fn && def_is_ty_arg(df) {
956 "Attempt to use a type argument out of scope"
961 /* If we were looking for a tag, at this point
962 we know it's bound to a non-tag value, and
963 we can return none instead of failing */
967 "attempted dynamic environment-capture"
971 _ { "attempted dynamic environment-capture" }
973 e.sess.span_fatal(sp, msg);
975 let i = vec::len(closing);
979 ast::def_upvar(def_id_of_def(df), @df,
987 left_fn_level2 = true;
988 } else if ns != ns_module {
989 left_fn = scope_is_fn(hd);
990 alt scope_closes(hd) {
991 some(node_id) { closing += [node_id]; }
999 e.sess.bug("reached unreachable code in lookup_in_scope"); // sigh
1002 fn lookup_in_ty_params(e: env, name: ident, ty_params: [ast::ty_param])
1005 for tp: ast::ty_param in ty_params {
1006 if str::eq(tp.ident, name) && alt e.current_tp {
1007 some(cur) { n < cur } none. { true }
1008 } { ret some(ast::def_ty_param(local_def(tp.id), n)); }
1014 fn lookup_in_pat(name: ident, pat: @ast::pat) -> option::t<def_id> {
1016 ast_util::pat_bindings(pat) {|bound|
1017 let p_name = alt bound.node { ast::pat_bind(n, _) { n } };
1018 if str::eq(p_name, name) { found = some(local_def(bound.id)); }
1023 fn lookup_in_fn(e: env, name: ident, decl: ast::fn_decl,
1024 ty_params: [ast::ty_param],
1025 ns: namespace) -> option::t<def> {
1027 ns_val(ns_any_value.) {
1028 for a: ast::arg in decl.inputs {
1029 if str::eq(a.ident, name) {
1030 ret some(ast::def_arg(local_def(a.id), a.mode));
1035 ns_type. { ret lookup_in_ty_params(e, name, ty_params); }
1036 _ { ret none::<def>; }
1040 fn lookup_in_obj(e: env, name: ident, ob: ast::_obj,
1041 ty_params: [ast::ty_param],
1042 ns: namespace, id: node_id) -> option::t<def> {
1045 if name == "self" && val_ty == ns_any_value
1046 { ret some(ast::def_self(local_def(id))); }
1047 for f: ast::obj_field in ob.fields {
1048 if str::eq(f.ident, name) && val_ty == ns_any_value {
1049 ret some(ast::def_obj_field(local_def(f.id), f.mut));
1054 ns_type. { ret lookup_in_ty_params(e, name, ty_params); }
1055 _ { ret none::<def>; }
1059 fn lookup_in_block(e: env, name: ident, sp: span, b: ast::blk_, pos: uint,
1060 loc_pos: uint, ns: namespace) -> option::t<def> {
1061 let i = vec::len(b.stmts);
1064 let st = b.stmts[i];
1066 ast::stmt_decl(d, _) {
1068 ast::decl_local(locs) {
1070 let j = vec::len(locs);
1073 let (style, loc) = locs[j];
1074 if ns == ns_val(ns_any_value)
1075 && (i < pos || j < loc_pos) {
1076 alt lookup_in_pat(name, loc.node.pat) {
1078 ret some(ast::def_local(did, style));
1086 ast::decl_item(it) {
1088 ast::item_tag(variants, _) {
1090 if str::eq(it.ident, name) {
1091 ret some(ast::def_ty(local_def(it.id)));
1096 for v: ast::variant in variants {
1097 if str::eq(v.node.name, name) {
1099 ret some(ast::def_variant
1100 (local_def(it.id), local_def(i)));
1109 if str::eq(it.ident, name) {
1110 let found = found_def_item(it, ns);
1111 if !is_none(found) { ret found; }
1121 for vi in b.view_items {
1123 ast::view_item_import(ident, _, id) {
1124 if name == ident { ret lookup_import(e, local_def(id), ns); }
1126 ast::view_item_import_from(mod_path, idents, id) {
1127 for ident in idents {
1128 if name == ident.node.name {
1129 ret lookup_import(e, local_def(ident.node.id), ns);
1133 ast::view_item_import_glob(_, _) {
1134 alt e.block_map.find(b.id) {
1136 let found = lookup_in_globs(e, globs, sp, name, ns, inside);
1137 if found != none { ret found; }
1147 fn found_def_item(i: @ast::item, ns: namespace) -> option::t<def> {
1149 ast::item_const(_, _) {
1150 if ns == ns_val(ns_any_value) {
1151 ret some(ast::def_const(local_def(i.id))); }
1153 ast::item_fn(decl, _, _) {
1154 if ns == ns_val(ns_any_value) {
1155 ret some(ast::def_fn(local_def(i.id), decl.purity));
1159 if ns == ns_module { ret some(ast::def_mod(local_def(i.id))); }
1161 ast::item_native_mod(_) {
1162 if ns == ns_module { ret some(ast::def_native_mod(local_def(i.id))); }
1164 ast::item_ty(_, _) | item_iface(_, _) | item_tag(_, _) {
1165 if ns == ns_type { ret some(ast::def_ty(local_def(i.id))); }
1167 ast::item_res(_, _, _, _, ctor_id) {
1169 ns_val(ns_any_value.) {
1170 ret some(ast::def_fn(local_def(ctor_id), ast::impure_fn));
1172 ns_type. { ret some(ast::def_ty(local_def(i.id))); }
1176 ast::item_obj(_, _, ctor_id) {
1178 ns_val(ns_any_value.) {
1179 ret some(ast::def_fn(local_def(ctor_id), ast::impure_fn));
1181 ns_type. { ret some(ast::def_ty(local_def(i.id))); }
1190 fn lookup_in_mod_strict(e: env, m: def, sp: span, name: ident,
1191 ns: namespace, dr: dir) -> option::t<def> {
1192 alt lookup_in_mod(e, m, sp, name, ns, dr) {
1194 unresolved_err(e, in_mod(m), sp, name, ns_name(ns));
1197 some(d) { ret some(d); }
1201 fn lookup_in_mod(e: env, m: def, sp: span, name: ident, ns: namespace,
1202 dr: dir) -> option::t<def> {
1203 let defid = def_id_of_def(m);
1204 if defid.crate != ast::local_crate {
1205 // examining a module in an external crate
1206 let cached = e.ext_cache.find({did: defid, ident: name, ns: ns});
1207 if !is_none(cached) { ret cached; }
1209 if defid.node != ast::crate_node_id {
1210 path = e.ext_map.get(defid) + path;
1212 let fnd = lookup_external(e, defid.crate, path, ns);
1214 e.ext_cache.insert({did: defid, ident: name, ns: ns},
1220 ast::def_mod(defid) {
1221 ret lookup_in_local_mod(e, defid.node, sp, name, ns, dr);
1223 ast::def_native_mod(defid) {
1224 ret lookup_in_local_native_mod(e, defid.node, sp, name, ns);
1229 fn found_view_item(e: env, vi: @ast::view_item) -> option::t<def> {
1231 ast::view_item_use(_, _, id) {
1232 let cnum = cstore::get_use_stmt_cnum(e.cstore, id);
1233 ret some(ast::def_mod({crate: cnum, node: ast::crate_node_id}));
1238 fn lookup_import(e: env, defid: def_id, ns: namespace) -> option::t<def> {
1239 // Imports are simply ignored when resolving themselves.
1240 if vec::member(defid.node, e.ignored_imports) { ret none; }
1241 alt e.imports.get(defid.node) {
1242 todo(node_id, name, path, span, scopes) {
1243 resolve_import(e, local_def(node_id), name, *path, span, scopes);
1244 ret lookup_import(e, defid, ns);
1247 e.sess.span_err(sp, "cyclic import");
1250 resolved(val, typ, md, _, _, _) {
1251 if e.used_imports.track {
1252 e.used_imports.data += [defid.node];
1254 ret alt ns { ns_val(_) { val } ns_type. { typ }
1255 ns_module. { md } };
1260 fn lookup_in_local_native_mod(e: env, node_id: node_id, sp: span, id: ident,
1261 ns: namespace) -> option::t<def> {
1262 ret lookup_in_local_mod(e, node_id, sp, id, ns, inside);
1265 fn is_exported(e: env, i: ident, m: _mod) -> bool {
1266 ast_util::is_exported(i, m) || e.resolve_unexported
1269 fn lookup_in_local_mod(e: env, node_id: node_id, sp: span, id: ident,
1270 ns: namespace, dr: dir) -> option::t<def> {
1271 let info = e.mod_map.get(node_id);
1272 if dr == outside && !is_exported(e, id, option::get(info.m)) {
1273 // if we're in a native mod, then dr==inside, so info.m is some _mod
1274 ret none::<def>; // name is not visible
1276 alt info.index.find(id) {
1284 let found = lookup_in_mie(e, hd, ns);
1285 if !is_none(found) { ret found; }
1292 // not local or explicitly imported; try globs:
1293 ret lookup_glob_in_mod(e, info, sp, id, ns, outside);
1296 fn lookup_in_globs(e: env, globs: [glob_imp_def], sp: span, id: ident,
1297 ns: namespace, dr: dir) -> option::t<def> {
1298 fn lookup_in_mod_(e: env, def: glob_imp_def, sp: span, name: ident,
1299 ns: namespace, dr: dir) -> option::t<glob_imp_def> {
1301 ast::view_item_import_glob(_, id) {
1302 if vec::member(id, e.ignored_imports) { ret none; }
1305 alt lookup_in_mod(e, def.def, sp, name, ns, dr) {
1306 some(d) { option::some({def: d, item: def.item}) }
1310 let matches = vec::filter_map(copy globs,
1311 bind lookup_in_mod_(e, _, sp, id, ns, dr));
1312 if vec::len(matches) == 0u {
1315 else if vec::len(matches) == 1u || ns == ns_val(ns_a_tag) {
1316 ret some(matches[0].def);
1318 for match: glob_imp_def in matches {
1319 let sp = match.item.span;
1320 e.sess.span_note(sp, #fmt["'%s' is imported here", id]);
1322 e.sess.span_fatal(sp, "'" + id + "' is glob-imported from" +
1323 " multiple different modules.");
1327 fn lookup_glob_in_mod(e: env, info: @indexed_mod, sp: span, id: ident,
1328 wanted_ns: namespace, dr: dir) -> option::t<def> {
1329 // since we don't know what names we have in advance,
1330 // absence takes the place of todo()
1331 if !info.glob_imported_names.contains_key(id) {
1332 info.glob_imported_names.insert(id, glob_resolving(sp));
1333 let val = lookup_in_globs(e, info.glob_imports, sp, id,
1335 (if wanted_ns == ns_val(ns_a_tag)
1336 { ns_val(ns_a_tag) }
1337 else { ns_val(ns_any_value) }), dr);
1338 let typ = lookup_in_globs(e, info.glob_imports, sp, id, ns_type, dr);
1339 let md = lookup_in_globs(e, info.glob_imports, sp, id, ns_module, dr);
1340 info.glob_imported_names.insert(id, glob_resolved(val, typ, md));
1342 alt info.glob_imported_names.get(id) {
1343 glob_resolving(sp) {
1346 glob_resolved(val, typ, md) {
1356 fn lookup_in_mie(e: env, mie: mod_index_entry, ns: namespace) ->
1359 mie_view_item(view_item) {
1360 if ns == ns_module { ret found_view_item(e, view_item); }
1362 mie_import_ident(id, _) { ret lookup_import(e, local_def(id), ns); }
1363 mie_item(item) { ret found_def_item(item, ns); }
1364 mie_tag_variant(item, variant_idx) {
1366 ast::item_tag(variants, _) {
1369 let vid = variants[variant_idx].node.id;
1370 ret some(ast::def_variant(local_def(item.id),
1373 _ { ret none::<def>; }
1378 mie_native_item(native_item) {
1379 alt native_item.node {
1380 ast::native_item_ty. {
1382 ret some(ast::def_native_ty(local_def(native_item.id)));
1385 ast::native_item_fn(decl, _) {
1386 if ns == ns_val(ns_any_value) {
1387 ret some(ast::def_native_fn(
1388 local_def(native_item.id),
1400 fn add_to_index(index: hashmap<ident, list<mod_index_entry>>, id: ident,
1401 ent: mod_index_entry) {
1402 alt index.find(id) {
1403 none. { index.insert(id, cons(ent, @nil::<mod_index_entry>)); }
1404 some(prev) { index.insert(id, cons(ent, @prev)); }
1408 fn index_mod(md: ast::_mod) -> mod_index {
1409 let index = new_str_hash::<list<mod_index_entry>>();
1410 for it: @ast::view_item in md.view_items {
1412 ast::view_item_use(ident, _, _) {
1413 add_to_index(index, ident, mie_view_item(it));
1415 ast::view_item_import(ident, _, id) {
1416 add_to_index(index, ident, mie_import_ident(id, it.span));
1418 ast::view_item_import_from(_, idents, _) {
1419 for ident in idents {
1420 add_to_index(index, ident.node.name,
1421 mie_import_ident(ident.node.id, ident.span));
1424 //globbed imports have to be resolved lazily.
1425 ast::view_item_import_glob(_, _) | ast::view_item_export(_, _) {}
1428 for it: @ast::item in md.items {
1430 ast::item_const(_, _) | ast::item_fn(_, _, _) | ast::item_mod(_) |
1431 ast::item_native_mod(_) | ast::item_ty(_, _) |
1432 ast::item_res(_, _, _, _, _) | ast::item_obj(_, _, _) |
1433 ast::item_impl(_, _, _, _) | ast::item_iface(_, _) {
1434 add_to_index(index, it.ident, mie_item(it));
1436 ast::item_tag(variants, _) {
1437 add_to_index(index, it.ident, mie_item(it));
1438 let variant_idx: uint = 0u;
1439 for v: ast::variant in variants {
1440 add_to_index(index, v.node.name,
1441 mie_tag_variant(it, variant_idx));
1450 fn index_nmod(md: ast::native_mod) -> mod_index {
1451 let index = new_str_hash::<list<mod_index_entry>>();
1452 for it: @ast::view_item in md.view_items {
1454 ast::view_item_use(ident, _, _) {
1455 add_to_index(index, ident, mie_view_item(it));
1457 ast::view_item_import(ident, _, id) {
1458 add_to_index(index, ident, mie_import_ident(id, it.span));
1460 ast::view_item_import_from(_, idents, _) {
1461 for ident in idents {
1462 add_to_index(index, ident.node.name,
1463 mie_import_ident(ident.node.id, ident.span));
1466 ast::view_item_import_glob(_, _) | ast::view_item_export(_, _) { }
1469 for it: @ast::native_item in md.items {
1470 add_to_index(index, it.ident, mie_native_item(it));
1477 fn ns_for_def(d: def) -> namespace {
1479 ast::def_variant(_, _) { ns_val(ns_a_tag) }
1480 ast::def_fn(_, _) | ast::def_obj_field(_, _) | ast::def_self(_) |
1481 ast::def_const(_) | ast::def_arg(_, _) | ast::def_local(_, _) |
1482 ast::def_upvar(_, _, _) | ast::def_native_fn(_, _) | ast::def_self(_)
1483 { ns_val(ns_any_value) }
1484 ast::def_mod(_) | ast::def_native_mod(_) { ns_module }
1485 ast::def_ty(_) | ast::def_binding(_) | ast::def_use(_) |
1486 ast::def_native_ty(_) { ns_type }
1490 // if we're searching for a value, it's ok if we found
1492 fn ns_ok(wanted:namespace, actual:namespace) -> bool {
1500 _ { wanted == actual}
1504 fn lookup_external(e: env, cnum: int, ids: [ident], ns: namespace) ->
1506 for d: def in csearch::lookup_defs(e.sess.get_cstore(), cnum, ids) {
1507 let did = def_id_of_def(d);
1509 def_mod(_) | def_native_mod(_) {
1510 // The [native] module name might have renamed when importing,
1511 // find the original name for further lookup of names inside the
1513 if did.crate != ast::local_crate {
1514 let cname = cstore::get_crate_data(e.cstore, did.crate).name;
1516 csearch::get_item_name(e.cstore, did.crate, did.node);
1517 #debug("lookup_external: %s %d, %d, %s, %s", cname,
1518 did.crate, did.node, str::connect(ids, "::"), name);
1519 e.ext_map.insert(did, vec::init(ids) + [name]);
1521 e.ext_map.insert(did, ids);
1525 e.ext_map.insert(did, ids);
1528 if ns_ok(ns, ns_for_def(d)) { ret some(d); }
1534 // Collision detection
1535 fn check_for_collisions(e: @env, c: ast::crate) {
1536 // Module indices make checking those relatively simple -- just check each
1537 // name for multiple entities in the same namespace.
1538 e.mod_map.values {|val|
1539 val.index.items {|k, v| check_mod_name(*e, k, v); };
1541 // Other scopes have to be checked the hard way.
1543 @{visit_item: bind check_item(e, _, _, _),
1544 visit_block: bind check_block(e, _, _, _),
1545 visit_arm: bind check_arm(e, _, _, _),
1546 visit_expr: bind check_expr(e, _, _, _),
1547 visit_ty: bind check_ty(e, _, _, _) with *visit::default_visitor()};
1548 visit::visit_crate(c, (), visit::mk_vt(v));
1551 fn check_mod_name(e: env, name: ident, entries: list<mod_index_entry>) {
1552 let saw_mod = false;
1553 let saw_type = false;
1554 let saw_value = false;
1555 let entries = entries;
1556 fn dup(e: env, sp: span, word: str, name: ident) {
1557 e.sess.span_fatal(sp, "duplicate definition of " + word + name);
1562 if !is_none(lookup_in_mie(e, entry, ns_val(ns_any_value))) {
1564 dup(e, mie_span(entry), "", name);
1565 } else { saw_value = true; }
1567 if !is_none(lookup_in_mie(e, entry, ns_type)) {
1569 dup(e, mie_span(entry), "type ", name);
1570 } else { saw_type = true; }
1572 if !is_none(lookup_in_mie(e, entry, ns_module)) {
1574 dup(e, mie_span(entry), "module ", name);
1575 } else { saw_mod = true; }
1584 fn mie_span(mie: mod_index_entry) -> span {
1586 mie_view_item(item) { item.span }
1587 mie_import_ident(_, span) { span }
1588 mie_item(item) { item.span }
1589 mie_tag_variant(item, _) { item.span }
1590 mie_native_item(item) { item.span }
1594 fn check_item(e: @env, i: @ast::item, &&x: (), v: vt<()>) {
1595 fn typaram_names(tps: [ast::ty_param]) -> [ident] {
1596 let x: [ast::ident] = [];
1597 for tp: ast::ty_param in tps { x += [tp.ident]; }
1600 visit::visit_item(i, x, v);
1602 ast::item_fn(decl, ty_params, _) {
1603 check_fn(*e, i.span, decl);
1604 ensure_unique(*e, i.span, typaram_names(ty_params), ident_id,
1607 ast::item_obj(ob, ty_params, _) {
1608 fn field_name(field: ast::obj_field) -> ident { ret field.ident; }
1609 ensure_unique(*e, i.span, ob.fields, field_name, "object field");
1610 for m: @ast::method in ob.methods {
1611 check_fn(*e, m.span, m.decl);
1613 ensure_unique(*e, i.span, typaram_names(ty_params), ident_id,
1616 ast::item_tag(_, ty_params) {
1617 ensure_unique(*e, i.span, typaram_names(ty_params), ident_id,
1624 fn check_pat(ch: checker, p: @ast::pat) {
1625 ast_util::pat_bindings(p) {|p|
1626 let ident = alt p.node { pat_bind(n, _) { n } };
1627 add_name(ch, p.span, ident);
1631 fn check_arm(e: @env, a: ast::arm, &&x: (), v: vt<()>) {
1632 visit::visit_arm(a, x, v);
1633 let ch0 = checker(*e, "binding");
1634 check_pat(ch0, a.pats[0]);
1635 let seen0 = ch0.seen;
1636 let i = vec::len(a.pats);
1639 let ch = checker(*e, "binding");
1640 check_pat(ch, a.pats[i]);
1642 // Ensure the bindings introduced in this pattern are the same as in
1643 // the first pattern.
1644 if vec::len(ch.seen) != vec::len(seen0) {
1645 e.sess.span_err(a.pats[i].span,
1646 "inconsistent number of bindings");
1648 for name: ident in ch.seen {
1649 if is_none(vec::find(seen0, bind str::eq(name, _))) {
1650 // Fight the alias checker
1652 e.sess.span_err(a.pats[i].span,
1653 "binding " + name_ +
1654 " does not occur in first pattern");
1661 fn check_block(e: @env, b: ast::blk, &&x: (), v: vt<()>) {
1662 visit::visit_block(b, x, v);
1663 let values = checker(*e, "value");
1664 let types = checker(*e, "type");
1665 let mods = checker(*e, "module");
1666 for st: @ast::stmt in b.node.stmts {
1668 ast::stmt_decl(d, _) {
1670 ast::decl_local(locs) {
1671 let local_values = checker(*e, "value");
1672 for (_, loc) in locs {
1673 ast_util::pat_bindings(loc.node.pat) {|p|
1674 let ident = alt p.node { pat_bind(n, _) { n } };
1675 add_name(local_values, p.span, ident);
1676 check_name(values, p.span, ident);
1680 ast::decl_item(it) {
1682 ast::item_tag(variants, _) {
1683 add_name(types, it.span, it.ident);
1684 for v: ast::variant in variants {
1685 add_name(values, v.span, v.node.name);
1688 ast::item_mod(_) | ast::item_native_mod(_) {
1689 add_name(mods, it.span, it.ident);
1691 ast::item_const(_, _) | ast::item_fn(_, _, _) {
1692 add_name(values, it.span, it.ident);
1694 ast::item_ty(_, _) | ast::item_iface(_, _) {
1695 add_name(types, it.span, it.ident);
1697 ast::item_res(_, _, _, _, _) | ast::item_obj(_, _, _) {
1698 add_name(types, it.span, it.ident);
1699 add_name(values, it.span, it.ident);
1711 fn check_fn(e: env, sp: span, decl: ast::fn_decl) {
1712 fn arg_name(a: ast::arg) -> ident { ret a.ident; }
1713 ensure_unique(e, sp, decl.inputs, arg_name, "argument");
1716 fn check_expr(e: @env, ex: @ast::expr, &&x: (), v: vt<()>) {
1718 ast::expr_rec(fields, _) {
1719 fn field_name(f: ast::field) -> ident { ret f.node.ident; }
1720 ensure_unique(*e, ex.span, fields, field_name, "field");
1724 visit::visit_expr(ex, x, v);
1727 fn check_ty(e: @env, ty: @ast::ty, &&x: (), v: vt<()>) {
1729 ast::ty_rec(fields) {
1730 fn field_name(f: ast::ty_field) -> ident { ret f.node.ident; }
1731 ensure_unique(*e, ty.span, fields, field_name, "field");
1735 visit::visit_ty(ty, x, v);
1738 type checker = @{mutable seen: [ident], kind: str, sess: session};
1740 fn checker(e: env, kind: str) -> checker {
1741 let seen: [ident] = [];
1742 ret @{mutable seen: seen, kind: kind, sess: e.sess};
1745 fn check_name(ch: checker, sp: span, name: ident) {
1746 for s: ident in ch.seen {
1747 if str::eq(s, name) {
1748 ch.sess.span_fatal(sp, "duplicate " + ch.kind + " name: " + name);
1752 fn add_name(ch: checker, sp: span, name: ident) {
1753 check_name(ch, sp, name);
1757 fn ident_id(&&i: ident) -> ident { ret i; }
1759 fn ensure_unique<T>(e: env, sp: span, elts: [T], id: fn(T) -> ident,
1761 let ch = checker(e, kind);
1762 for elt: T in elts { add_name(ch, sp, id(elt)); }
1765 fn check_exports(e: @env) {
1766 fn lookup_glob_any(e: @env, info: @indexed_mod, sp: span, path: str,
1767 ident: ident) -> bool {
1769 bind lookup_glob_in_mod(*e, info, sp, ident, _, inside);
1770 let (m, v, t) = (lookup(ns_module),
1771 lookup(ns_val(ns_any_value)),
1773 maybe_add_reexport(e, path + ident, ns_module, m);
1774 maybe_add_reexport(e, path + ident, ns_val(ns_any_value), v);
1775 maybe_add_reexport(e, path + ident, ns_type, t);
1776 ret is_some(m) || is_some(v) || is_some(t);
1779 fn maybe_add_reexport(e: @env, path: str, ns: namespace,
1780 def: option::t<def>) {
1781 if option::is_some(def) {
1782 e.exp_map.insert({path: path, ns: ns}, option::get(def));
1786 fn check_export(e: @env, ident: str, val: @indexed_mod, vi: @view_item) {
1787 if val.index.contains_key(ident) {
1788 let xs = val.index.get(ident);
1791 mie_import_ident(id, _) {
1792 alt e.imports.get(id) {
1793 resolved(v, t, m, _, rid, _) {
1794 maybe_add_reexport(e, val.path + rid,
1795 ns_val(ns_any_value), v);
1796 maybe_add_reexport(e, val.path + rid, ns_type, t);
1797 maybe_add_reexport(e, val.path + rid, ns_module, m);
1805 } else if lookup_glob_any(e, val, vi.span, val.path, ident) {
1808 e.sess.span_warn(vi.span,
1809 #fmt("exported item %s is not defined", ident));
1813 e.mod_map.values {|val|
1816 for vi in m.view_items {
1818 ast::view_item_export(idents, _) {
1819 for ident in idents {
1820 check_export(e, ident, val, vi);
1834 type method_info = {did: def_id, n_tps: uint, ident: ast::ident};
1835 type _impl = {did: def_id, iface_did: option::t<def_id>,
1836 ident: ast::ident, methods: [@method_info]};
1837 type iscopes = list<@[@_impl]>;
1839 fn resolve_impls(e: @env, c: @ast::crate) {
1840 visit::visit_crate(*c, nil, visit::mk_vt(@{
1841 visit_block: bind visit_block_with_impl_scope(e, _, _, _),
1842 visit_mod: bind visit_mod_with_impl_scope(e, _, _, _, _),
1843 visit_expr: bind resolve_impl_in_expr(e, _, _, _)
1844 with *visit::default_visitor()
1848 fn find_impls_in_view_item(e: env, vi: @ast::view_item,
1849 &impls: [@_impl], sc: iscopes) {
1851 ast::view_item_import(name, pt, id) {
1853 if vec::len(*pt) == 1u {
1854 list::iter(sc) {|level|
1855 if vec::len(found) > 0u { ret; }
1857 if imp.ident == pt[0] {
1858 found += [@{ident: name with *imp}];
1861 if vec::len(found) > 0u { impls += found; }
1864 alt e.imports.get(id) {
1865 resolved(_, _, _, is, _, _) {
1866 for i in *is { impls += [@{ident: name with *i}]; }
1871 ast::view_item_import_from(base, names, _) {
1873 alt e.imports.get(nm.node.id) {
1874 resolved(_, _, _, is, _, _) { impls += *is; }
1878 ast::view_item_import_glob(ids, id) {
1879 alt e.imports.get(id) {
1880 is_glob(path, sc, sp) {
1881 alt follow_import(e, sc, *path, sp) {
1882 some(def) { find_impls_in_mod(e, def, impls, none); }
1892 fn find_impls_in_item(e: env, i: @ast::item, &impls: [@_impl],
1893 name: option::t<ident>,
1894 ck_exports: option::t<ast::_mod>) {
1896 ast::item_impl(_, ifce, _, mthds) {
1897 if alt name { some(n) { n == i.ident } _ { true } } &&
1899 some(m) { is_exported(e, i.ident, m) }
1902 impls += [@{did: local_def(i.id),
1903 iface_did: alt ifce {
1904 some(@{node: ast::ty_path(_, id), _}) {
1905 some(def_id_of_def(e.def_map.get(id)))
1910 methods: vec::map(mthds, {|m|
1911 @{did: local_def(m.id),
1912 n_tps: vec::len(m.tps),
1921 fn find_impls_in_mod(e: env, m: def, &impls: [@_impl],
1922 name: option::t<ident>) {
1924 ast::def_mod(defid) {
1926 alt e.impl_cache.find(defid) {
1927 some(v) { cached = v; }
1929 cached = if defid.crate == ast::local_crate {
1931 for i in option::get(e.mod_map.get(defid.node).m).items {
1932 find_impls_in_item(e, i, tmp, name, none);
1936 csearch::get_impls_for_mod(e.sess.get_cstore(), defid, name)
1938 e.impl_cache.insert(defid, cached);
1942 if alt name { some(n) { n == im.ident } _ { true } } {
1951 fn visit_block_with_impl_scope(e: @env, b: ast::blk, sc: iscopes,
1954 for vi in b.node.view_items {
1955 find_impls_in_view_item(*e, vi, impls, sc);
1957 for st in b.node.stmts {
1959 ast::stmt_decl(@{node: ast::decl_item(i), _}, _) {
1960 find_impls_in_item(*e, i, impls, none, none);
1965 let sc = vec::len(impls) > 0u ? cons(@impls, @sc) : sc;
1966 visit::visit_block(b, sc, v);
1969 fn visit_mod_with_impl_scope(e: @env, m: ast::_mod, s: span, sc: iscopes,
1972 for vi in m.view_items { find_impls_in_view_item(*e, vi, impls, sc); }
1973 for i in m.items { find_impls_in_item(*e, i, impls, none, none); }
1974 visit::visit_mod(m, s, vec::len(impls) > 0u ? cons(@impls, @sc) : sc, v);
1977 fn resolve_impl_in_expr(e: @env, x: @ast::expr, sc: iscopes, v: vt<iscopes>) {
1979 ast::expr_field(_, _, _) | ast::expr_path(_) | ast::expr_cast(_, _) {
1980 e.impl_map.insert(x.id, sc);
1984 visit::visit_expr(x, sc, v);
1990 // indent-tabs-mode: nil
1991 // c-basic-offset: 4
1992 // buffer-file-coding-system: utf-8-unix