]> git.lizzy.rs Git - rust.git/blob - src/comp/middle/resolve.rs
664b2418d63bee7d91570c055577ad9f25718e9c
[rust.git] / src / comp / middle / resolve.rs
1
2 import syntax::{ast, ast_util, codemap};
3 import syntax::ast::*;
4 import ast::{ident, fn_ident, def, def_id, node_id};
5 import syntax::ast_util::{local_def, def_id_of_def};
6
7 import front::attr;
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;
13 import syntax::visit;
14 import visit::vt;
15 import core::{vec, option, str};
16 import std::list;
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::*;
21
22 export resolve_crate;
23 export def_map, ext_map, exp_map, impl_map;
24 export _impl, iscopes, method_info;
25
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.
31
32 tag scope {
33     scope_crate;
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);
40     scope_arm(ast::arm);
41     scope_method(ast::node_id, [ast::ty_param]);
42 }
43
44 type scopes = list<scope>;
45
46 tag import_state {
47     todo(ast::node_id, ast::ident, @[ast::ident], codemap::span, scopes);
48     is_glob(@[ast::ident], scopes, codemap::span);
49     resolving(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);
56 }
57
58 tag glob_import_state {
59     glob_resolving(span);
60     glob_resolved(option::t<def>,  /* value */
61                   option::t<def>,  /* type */
62                   option::t<def>); /* module */
63 }
64
65 type ext_hash = hashmap<{did: def_id, ident: str, ns: namespace}, def>;
66
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) +
71                 alt v.ns {
72                   ns_val(_) { 1u }
73                   ns_type. { 2u }
74                   ns_module. { 3u }
75                 };
76     }
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;
80     }
81     ret std::map::mk_hashmap::<key, def>(hash, eq);
82 }
83
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) +
88                 alt v.ns {
89                   ns_val(_) { 1u }
90                   ns_type. { 2u }
91                   ns_module. { 3u }
92                 };
93     }
94     fn eq(v1: key, v2: key) -> bool {
95         ret str::eq(v1.path, v2.path) && v1.ns == v2.ns;
96     }
97     ret std::map::mk_hashmap::<key, def>(hash, eq);
98 }
99
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);
106 }
107
108 type mod_index = hashmap<ident, list<mod_index_entry>>;
109
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};
112
113 type indexed_mod = {
114     m: option::t<ast::_mod>,
115     index: mod_index,
116     mutable glob_imports: [glob_imp_def],
117     glob_imported_names: hashmap<str, glob_import_state>,
118     path: str
119 };
120
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.*/
123
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]>;
129
130 type env =
131     {cstore: cstore::cstore,
132      def_map: def_map,
133      ast_map: ast_map::map,
134      imports: hashmap<ast::node_id, import_state>,
135      exp_map: exp_map,
136      mod_map: hashmap<ast::node_id, @indexed_mod>,
137      block_map: hashmap<ast::node_id, [glob_imp_def]>,
138      ext_map: ext_map,
139      impl_map: impl_map,
140      impl_cache: impl_cache,
141      ext_cache: ext_hash,
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,
148      sess: session};
149
150
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; }
154
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; }
161
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} {
164     let e =
165         @{cstore: sess.get_cstore(),
166           def_map: new_int_hash(),
167           ast_map: amap,
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,
181           sess: sess};
182     map_crate(e, crate);
183     resolve_imports(*e);
184     check_for_collisions(e, *crate);
185     check_exports(e);
186     resolve_names(e, crate);
187     resolve_impls(e, crate);
188     if sess.get_opts().warn_unused_imports {
189         check_unused_imports(e);
190     }
191     ret {def_map: e.def_map, exp_map: e.exp_map, impl_map: e.impl_map};
192 }
193
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
198     let v_map_mod =
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));
204
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(),
211                        path: ""});
212     fn index_vi(e: @env, i: @ast::view_item, sc: scopes, _v: vt<scopes>) {
213         alt i.node {
214           ast::view_item_import(name, ids, id) {
215             e.imports.insert(id, todo(id, name, ids, i.span, sc));
216           }
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]),
222                                       ident.span, sc));
223             }
224           }
225           ast::view_item_import_glob(pth, id) {
226             e.imports.insert(id, is_glob(pth, sc, i.span));
227           }
228           _ { }
229         }
230     }
231     fn path_from_scope(sc: scopes, n: str) -> str {
232         let path = n + "::";
233         list::iter(sc) {|s|
234             alt s {
235               scope_item(i) { path = i.ident + "::" + path; }
236               _ {}
237             }
238         }
239         path
240     }
241     fn index_i(e: @env, i: @ast::item, sc: scopes, v: vt<scopes>) {
242         visit_item_with_scope(e, i, sc, v);
243         alt i.node {
244           ast::item_mod(md) {
245             e.mod_map.insert(i.id,
246                              @{m: some(md),
247                                index: index_mod(md),
248                                mutable glob_imports: [],
249                                glob_imported_names: new_str_hash(),
250                                path: path_from_scope(sc, i.ident)});
251           }
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)});
259           }
260           _ { }
261         }
262     }
263
264     // Next, assemble the links for globbed imports.
265     let v_link_glob =
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>) {
273         alt vi.node {
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);
280                 alt list::head(sc) {
281                   scope_item(i) {
282                     e.mod_map.get(i.id).glob_imports += [glob];
283                   }
284                   scope_block(b, _, _) {
285                     let globs = alt e.block_map.find(b.node.id) {
286                       some(globs) { globs + [glob] } none. { [glob] }
287                     };
288                     e.block_map.insert(b.node.id, globs);
289                   }
290                   scope_crate. {
291                     e.mod_map.get(ast::crate_node_id).glob_imports += [glob];
292                   }
293                 }
294             }
295           }
296           _ { }
297         }
298     }
299 }
300
301 fn resolve_imports(e: env) {
302     e.used_imports.track = true;
303     e.imports.values {|v|
304         alt v {
305           todo(node_id, name, path, span, scopes) {
306             resolve_import(e, local_def(node_id), name, *path, span, scopes);
307           }
308           resolved(_, _, _, _, _, _) | is_glob(_, _, _) { }
309         }
310     };
311     e.used_imports.track = false;
312     e.sess.abort_if_errors();
313 }
314
315 fn check_unused_imports(e: @env) {
316     e.imports.items {|k, v|
317         alt v {
318             resolved(_, _, _, _, name, sp) {
319               if !vec::member(k, e.used_imports.data) {
320                 e.sess.span_warn(sp, "unused import " + name);
321               }
322             }
323             _ { }
324         }
325     };
326 }
327
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);
332 }
333
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)); }
336 }
337
338 fn resolve_names(e: @env, c: @ast::crate) {
339     e.used_imports.track = true;
340     let v =
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();
357
358     fn walk_expr(e: @env, exp: @ast::expr, sc: scopes, v: vt<scopes>) {
359         visit_expr_with_scope(exp, sc, v);
360         alt exp.node {
361           ast::expr_path(p) {
362             maybe_insert(e, exp.id,
363                          lookup_path_strict(*e, sc, exp.span, p.node,
364                                             ns_val(ns_any_value)));
365           }
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);
370           }
371           _ { }
372         }
373     }
374     fn walk_ty(e: @env, t: @ast::ty, sc: scopes, v: vt<scopes>) {
375         visit::visit_ty(t, sc, v);
376         alt t.node {
377           ast::ty_path(p, id) {
378             maybe_insert(e, id,
379                          lookup_path_strict(*e, sc, t.span, p.node, ns_type));
380           }
381           _ { }
382         }
383     }
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;
386         for tp in tps {
387             e.current_tp = some(current);
388             for bound in *tp.bounds {
389                 alt bound {
390                   bound_iface(t) { v.visit_ty(t, sc, v); }
391                   _ {}
392                 }
393             }
394             current += 1u;
395         }
396         e.current_tp = outer_current_tp;
397     }
398     fn walk_constr(e: @env, p: @ast::path, sp: span, id: node_id, sc: scopes,
399                    _v: vt<scopes>) {
400         maybe_insert(e, id, lookup_path_strict(*e, sc,
401                          sp, p.node, ns_val(ns_any_value)));
402     }
403     fn walk_pat(e: @env, pat: @ast::pat, sc: scopes, v: vt<scopes>) {
404         visit::visit_pat(pat, sc, v);
405         alt pat.node {
406           ast::pat_tag(p, _) {
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));
412               }
413               _ {
414                 e.sess.span_err(p.span,
415                                 "not a tag variant: " +
416                                     ast_util::path_name(p));
417               }
418             }
419           }
420           _ { }
421         }
422     }
423 }
424
425
426 // Visit helper functions
427 fn visit_item_with_scope(e: @env, i: @ast::item, sc: scopes, v: vt<scopes>) {
428
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
432     // tests.
433     let old_resolve_unexported = e.resolve_unexported;
434     e.resolve_unexported |=
435         attr::contains_name(attr::attr_metas(i.attrs),
436                             "!resolve_unexported");
437
438     let sc = cons(scope_item(i), @sc);
439     alt i.node {
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);
444         for m in methods {
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);
448         }
449       }
450       ast::item_iface(tps, methods) {
451         visit::visit_ty_params(tps, sc, v);
452         for m in methods {
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);
456         }
457       }
458       _ { visit::visit_item(i, sc, v); }
459     }
460
461     e.resolve_unexported = old_resolve_unexported;
462 }
463
464 fn visit_native_item_with_scope(ni: @ast::native_item, sc: scopes,
465                                 v: vt<scopes>) {
466     visit::visit_native_item(ni, cons(scope_native_item(ni), @sc), v);
467 }
468
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?
473     alt fk {
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
477             // as the main ID
478             e.sess.set_main_id(id);
479         }
480       }
481       _ { /* fallthrough */ }
482     }
483
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); }
487     let scope = alt fk {
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, []) }
492     };
493
494     visit::visit_fn(fk, decl, body, sp, id, cons(scope, @sc), v);
495 }
496
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);;
503         *pos += 1u;;
504         *loc = 0u;
505     }
506     visit::visit_expr_opt(b.node.expr, block_sc, v);
507 }
508
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 }
513       _ { @mutable 0u }
514     };
515     alt d.node {
516       decl_local(locs) {
517         for (_, loc) in locs { v.visit_local(loc, sc, v);; *loc_pos += 1u; }
518       }
519       decl_item(it) { v.visit_item(it, sc, v); }
520     }
521 }
522
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);
528 }
529
530 fn visit_expr_with_scope(x: @ast::expr, sc: scopes, v: vt<scopes>) {
531     alt x.node {
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);
537       }
538       ast::expr_anon_obj(_) {
539         visit::visit_expr(x, cons(scope_method(x.id, []), @sc), v);
540       }
541       _ { visit::visit_expr(x, sc, v); }
542     }
543 }
544
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
547     // in scope
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.
558                   // That's an error.
559                   e.sess.span_err(loc.span,
560                     #fmt("Declaration of %s shadows a tag that's in scope",
561                          an_ident));
562                   }
563               _ {}
564           }
565       }
566       _ {}
567     }
568
569     visit::visit_local(loc, sc, v);
570 }
571
572
573 fn follow_import(e: env, sc: scopes, path: [ident], sp: span) ->
574    option::t<def> {
575     let path_len = vec::len(path);
576     let dcur = lookup_in_scope_strict(e, sc, sp, path[0], ns_module);
577     let i = 1u;
578     while true && option::is_some(dcur) {
579         if i == path_len { break; }
580         dcur =
581             lookup_in_mod_strict(e, option::get(dcur), sp, path[i],
582                                  ns_module, outside);
583         i += 1u;
584     }
585     if i == path_len {
586         alt option::get(dcur) {
587           ast::def_mod(_) | ast::def_native_mod(_) { ret dcur; }
588           _ {
589             e.sess.span_err(sp, str::connect(path, "::") +
590                             " does not name a module.");
591             ret none;
592           }
593         }
594     } else { ret none; }
595 }
596
597 fn resolve_constr(e: @env, c: @ast::constr, sc: scopes, _v: vt<scopes>) {
598     let new_def =
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));
605           }
606           _ {
607             e.sess.span_err(c.span,
608                             "Non-predicate in constraint: " +
609                                 path_to_str(c.node.path));
610           }
611         }
612     }
613 }
614
615 // Import resolution
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>,
620                 impls: [@_impl]) {
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");
626         } else {
627             e.imports.insert(id, resolved(val, typ, md, @impls, name, sp));
628         }
629     }
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;
635             for vi in vis {
636                 alt vi.node {
637                   view_item_import(_, _, id) | view_item_import_glob(_, id) {
638                     if id == my_id { found = true; }
639                     if found { imports += [id]; }
640                   }
641                   view_item_import_from(_, ids, _) {
642                     for id in ids {
643                         if id.node.id == my_id { found = true; }
644                         if found { imports += [id.node.id]; }
645                     }
646                   }
647                   _ {}
648                 }
649             }
650             imports
651         }
652         alt sc {
653           cons(scope_item(@{node: item_mod(m), _}), _) {
654             lst(id, m.view_items)
655           }
656           cons(scope_item(@{node: item_native_mod(m), _}), _) {
657             lst(id, m.view_items)
658           }
659           cons(scope_block(b, _, _), _) {
660             lst(id, b.node.view_items)
661           }
662           cons(scope_crate., _) {
663             lst(id,
664                 option::get(e.mod_map.get(ast::crate_node_id).m).view_items)
665           }
666         }
667     }
668     // This function has cleanup code at the end. Do not return without going
669     // through that.
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];
675     if n_idents == 1u {
676         register(e, defid.node, in_scope(sc), sp, name,
677                  {|ns| lookup_in_scope(e, sc, sp, end_id, ns) }, []);
678     } else {
679         alt lookup_in_scope(e, sc, sp, ids[0], ns_module) {
680           none. {
681             unresolved_err(e, in_scope(sc), sp, ids[0], ns_name(ns_module));
682           }
683           some(dcur_) {
684             let dcur = dcur_, i = 1u;
685             while true {
686                 if i == n_idents - 1u {
687                     let impls = [];
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)
691                     }, impls);
692                     break;
693                 } else {
694                     dcur = alt lookup_in_mod(e, dcur, sp, ids[i], ns_module,
695                                              outside) {
696                       some(dcur) { dcur }
697                       none. {
698                         unresolved_err(e, in_mod(dcur), sp, ids[i],
699                                        ns_name(ns_module));
700                         break;
701                       }
702                     };
703                     i += 1u;
704                 }
705             }
706           }
707         }
708     }
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
712     // import
713     alt e.imports.find(defid.node) {
714       some(resolving(sp)) {
715         e.imports.insert(defid.node, resolved(none, none, none, @[], "", sp));
716       }
717       _ { }
718     }
719 }
720
721
722 // Utilities
723 fn ns_name(ns: namespace) -> str {
724     alt ns {
725       ns_type. { "typename" }
726       ns_val(v) {
727           alt (v) {
728               ns_any_value. { "name" }
729               ns_a_tag.     { "tag" }
730           }
731       }
732       ns_module. { ret "modulename" }
733     }
734 }
735
736 tag ctxt { in_mod(def); in_scope(scopes); }
737
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> {
740         let sc = sc;
741         while true {
742             alt sc {
743               cons(cur, rest) {
744                 alt cur {
745                   scope_crate. | scope_bare_fn(_, _, _) |
746                   scope_fn_expr(_, _, _) |
747                   scope_item(@{node: ast::item_mod(_), _}) {
748                     ret some(cur);
749                   }
750                   _ { sc = *rest; }
751                 }
752               }
753               _ { ret none; }
754             }
755         }
756         fail;
757     }
758     let path = name;
759     alt cx {
760       in_scope(sc) {
761         alt find_fn_or_mod_scope(sc) {
762           some(err_scope) {
763             for rs: {ident: str, sc: scope} in e.reported {
764                 if str::eq(rs.ident, name) && err_scope == rs.sc { ret; }
765             }
766             e.reported += [{ident: name, sc: err_scope}];
767           }
768           _ {}
769         }
770       }
771       in_mod(def) {
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;
779             }
780         }
781       }
782     }
783     e.sess.span_err(sp, mk_unresolved_msg(path, kind));
784 }
785
786 fn unresolved_fatal(e: env, sp: span, id: ident, kind: str) -> ! {
787     e.sess.span_fatal(sp, mk_unresolved_msg(id, kind));
788 }
789
790 fn mk_unresolved_msg(id: ident, kind: str) -> str {
791     ret #fmt["unresolved %s: %s", kind, id];
792 }
793
794 // Lookup helpers
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 };
799
800     let first_scope;
801     if pth.global {
802         first_scope = list::cons(scope_crate, @list::nil);
803     } else { first_scope = sc; }
804
805     let dcur =
806         lookup_in_scope_strict(e, first_scope, sp, pth.idents[0], headns);
807
808     let i = 1u;
809     while i < n_idents && option::is_some(dcur) {
810         let curns = if n_idents == i + 1u { ns } else { ns_module };
811         dcur =
812             lookup_in_mod_strict(e, option::get(dcur), sp, pth.idents[i],
813                                  curns, outside);
814         i += 1u;
815     }
816     ret dcur;
817 }
818
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) {
822       none. {
823         unresolved_err(e, in_scope(sc), sp, name, ns_name(ns));
824         ret none;
825       }
826       some(d) { ret some(d); }
827     }
828 }
829
830 fn scope_is_fn(sc: scope) -> bool {
831     ret alt sc {
832       scope_bare_fn(_, _, _) | scope_native_item(_) { true }
833       _ { false }
834     };
835 }
836
837 // Returns:
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> {
841     alt sc {
842       scope_fn_expr(_, node_id, _) { some(node_id) }
843       _ { none }
844     }
845 }
846
847 fn def_is_local(d: def) -> bool {
848     ret alt d {
849           ast::def_arg(_, _) | ast::def_local(_, _) | ast::def_binding(_) |
850           ast::def_upvar(_, _, _) {
851             true
852           }
853           _ { false }
854         };
855 }
856
857 fn def_is_obj_field(d: def) -> bool {
858     alt d {
859       ast::def_obj_field(_, _) | ast::def_self(_) { true }
860       _ { false }
861     }
862 }
863
864 fn def_is_ty_arg(d: def) -> bool {
865     ret alt d { ast::def_ty_param(_, _) { true } _ { false } };
866 }
867
868 fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace)
869    -> option::t<def> {
870     fn in_scope(e: env, sp: span, name: ident, s: scope, ns: namespace) ->
871        option::t<def> {
872         alt s {
873           scope_crate. {
874             ret lookup_in_local_mod(e, ast::crate_node_id, sp,
875                                     name, ns, inside);
876           }
877           scope_item(it) {
878             alt it.node {
879               ast::item_obj(ob, ty_params, _) {
880                 ret lookup_in_obj(e, name, ob, ty_params, ns, it.id);
881               }
882               ast::item_impl(tps, _, _, _) {
883                 if ns == ns_type { ret lookup_in_ty_params(e, name, tps); }
884               }
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); }
888               }
889               ast::item_mod(_) {
890                 ret lookup_in_local_mod(e, it.id, sp, name, ns, inside);
891               }
892               ast::item_native_mod(m) {
893                 ret lookup_in_local_native_mod(e, it.id, sp, name, ns);
894               }
895               _ { }
896             }
897           }
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);
903             }
904           }
905           scope_native_item(it) {
906             alt it.node {
907               ast::native_item_fn(decl, ty_params) {
908                 ret lookup_in_fn(e, name, decl, ty_params, ns);
909               }
910             }
911           }
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);
915           }
916           scope_loop(local) {
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)); }
920                   _ { }
921                 }
922             }
923           }
924           scope_block(b, pos, loc) {
925             ret lookup_in_block(e, name, sp, b.node, *pos, *loc, ns);
926           }
927           scope_arm(a) {
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)); }
931                   _ { ret none; }
932                 }
933             }
934           }
935         }
936         ret none::<def>;
937     }
938     let left_fn = false;
939     let closing = [];
940     // Used to determine whether obj fields are in scope
941     let left_fn_level2 = false;
942     let sc = sc;
943     while true {
944         alt copy sc {
945           nil. { ret none::<def>; }
946           cons(hd, tl) {
947             let fnd = in_scope(e, sp, name, hd, ns);
948             if !is_none(fnd) {
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) {
953                     let msg =
954                         alt ns {
955                           ns_type. {
956                             "Attempt to use a type argument out of scope"
957                           }
958                           ns_val(v) {
959                               alt(v) {
960                                   ns_a_tag. {
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 */
964                                       ret none;
965                                   }
966                                   _ {
967                                       "attempted dynamic environment-capture"
968                                   }
969                               }
970                           }
971                           _ { "attempted dynamic environment-capture" }
972                         };
973                     e.sess.span_fatal(sp, msg);
974                 } else if local {
975                     let i = vec::len(closing);
976                     while i > 0u {
977                         i -= 1u;
978                         df =
979                             ast::def_upvar(def_id_of_def(df), @df,
980                                            closing[i]);
981                         fnd = some(df);
982                     }
983                 }
984                 ret fnd;
985             }
986             if left_fn {
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]; }
992                   _ { }
993                 }
994             }
995             sc = *tl;
996           }
997         }
998     }
999     e.sess.bug("reached unreachable code in lookup_in_scope"); // sigh
1000 }
1001
1002 fn lookup_in_ty_params(e: env, name: ident, ty_params: [ast::ty_param])
1003     -> option::t<def> {
1004     let n = 0u;
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)); }
1009         n += 1u;
1010     }
1011     ret none::<def>;
1012 }
1013
1014 fn lookup_in_pat(name: ident, pat: @ast::pat) -> option::t<def_id> {
1015     let found = none;
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)); }
1019     };
1020     ret found;
1021 }
1022
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> {
1026     alt ns {
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));
1031             }
1032         }
1033         ret none::<def>;
1034       }
1035       ns_type. { ret lookup_in_ty_params(e, name, ty_params); }
1036       _ { ret none::<def>; }
1037     }
1038 }
1039
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> {
1043     alt ns {
1044       ns_val(val_ty) {
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));
1050             }
1051         }
1052         ret none::<def>;
1053       }
1054       ns_type. { ret lookup_in_ty_params(e, name, ty_params); }
1055       _ { ret none::<def>; }
1056     }
1057 }
1058
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);
1062     while i > 0u {
1063         i -= 1u;
1064         let st = b.stmts[i];
1065         alt st.node {
1066           ast::stmt_decl(d, _) {
1067             alt d.node {
1068               ast::decl_local(locs) {
1069                 if i <= pos {
1070                     let j = vec::len(locs);
1071                     while j > 0u {
1072                         j -= 1u;
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) {
1077                               some(did) {
1078                                 ret some(ast::def_local(did, style));
1079                               }
1080                               _ { }
1081                             }
1082                         }
1083                     }
1084                 }
1085               }
1086               ast::decl_item(it) {
1087                 alt it.node {
1088                   ast::item_tag(variants, _) {
1089                     if ns == ns_type {
1090                         if str::eq(it.ident, name) {
1091                             ret some(ast::def_ty(local_def(it.id)));
1092                         }
1093                     } else {
1094                         alt ns {
1095                            ns_val(_) {
1096                                for v: ast::variant in variants {
1097                                   if str::eq(v.node.name, name) {
1098                                      let i = v.node.id;
1099                                      ret some(ast::def_variant
1100                                         (local_def(it.id), local_def(i)));
1101                                   }
1102                                }
1103                           }
1104                            _ {}
1105                         }
1106                     }
1107                   }
1108                   _ {
1109                     if str::eq(it.ident, name) {
1110                         let found = found_def_item(it, ns);
1111                         if !is_none(found) { ret found; }
1112                     }
1113                   }
1114                 }
1115               }
1116             }
1117           }
1118           _ { }
1119         }
1120     }
1121     for vi in b.view_items {
1122         alt vi.node {
1123           ast::view_item_import(ident, _, id) {
1124             if name == ident { ret lookup_import(e, local_def(id), ns); }
1125           }
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);
1130                 }
1131             }
1132           }
1133           ast::view_item_import_glob(_, _) {
1134             alt e.block_map.find(b.id) {
1135               some(globs) {
1136                 let found = lookup_in_globs(e, globs, sp, name, ns, inside);
1137                 if found != none { ret found; }
1138               }
1139               _ {}
1140             }
1141           }
1142         }
1143     }
1144     ret none;
1145 }
1146
1147 fn found_def_item(i: @ast::item, ns: namespace) -> option::t<def> {
1148     alt i.node {
1149       ast::item_const(_, _) {
1150         if ns == ns_val(ns_any_value) {
1151             ret some(ast::def_const(local_def(i.id))); }
1152       }
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));
1156         }
1157       }
1158       ast::item_mod(_) {
1159         if ns == ns_module { ret some(ast::def_mod(local_def(i.id))); }
1160       }
1161       ast::item_native_mod(_) {
1162         if ns == ns_module { ret some(ast::def_native_mod(local_def(i.id))); }
1163       }
1164       ast::item_ty(_, _) | item_iface(_, _) | item_tag(_, _) {
1165         if ns == ns_type { ret some(ast::def_ty(local_def(i.id))); }
1166       }
1167       ast::item_res(_, _, _, _, ctor_id) {
1168         alt ns {
1169           ns_val(ns_any_value.) {
1170             ret some(ast::def_fn(local_def(ctor_id), ast::impure_fn));
1171           }
1172           ns_type. { ret some(ast::def_ty(local_def(i.id))); }
1173           _ { }
1174         }
1175       }
1176       ast::item_obj(_, _, ctor_id) {
1177         alt ns {
1178           ns_val(ns_any_value.) {
1179             ret some(ast::def_fn(local_def(ctor_id), ast::impure_fn));
1180           }
1181           ns_type. { ret some(ast::def_ty(local_def(i.id))); }
1182           _ { }
1183         }
1184       }
1185       _ { }
1186     }
1187     ret none;
1188 }
1189
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) {
1193       none. {
1194         unresolved_err(e, in_mod(m), sp, name, ns_name(ns));
1195         ret none;
1196       }
1197       some(d) { ret some(d); }
1198     }
1199 }
1200
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; }
1208         let path = [name];
1209         if defid.node != ast::crate_node_id {
1210             path = e.ext_map.get(defid) + path;
1211         }
1212         let fnd = lookup_external(e, defid.crate, path, ns);
1213         if !is_none(fnd) {
1214             e.ext_cache.insert({did: defid, ident: name, ns: ns},
1215                                option::get(fnd));
1216         }
1217         ret fnd;
1218     }
1219     alt m {
1220       ast::def_mod(defid) {
1221         ret lookup_in_local_mod(e, defid.node, sp, name, ns, dr);
1222       }
1223       ast::def_native_mod(defid) {
1224         ret lookup_in_local_native_mod(e, defid.node, sp, name, ns);
1225       }
1226     }
1227 }
1228
1229 fn found_view_item(e: env, vi: @ast::view_item) -> option::t<def> {
1230     alt vi.node {
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}));
1234       }
1235     }
1236 }
1237
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);
1245       }
1246       resolving(sp) {
1247         e.sess.span_err(sp, "cyclic import");
1248         ret none;
1249       }
1250       resolved(val, typ, md, _, _, _) {
1251         if e.used_imports.track {
1252             e.used_imports.data += [defid.node];
1253         }
1254         ret alt ns { ns_val(_) { val } ns_type. { typ }
1255                      ns_module. { md } };
1256       }
1257     }
1258 }
1259
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);
1263 }
1264
1265 fn is_exported(e: env, i: ident, m: _mod) -> bool {
1266     ast_util::is_exported(i, m) || e.resolve_unexported
1267 }
1268
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
1275     }
1276     alt info.index.find(id) {
1277       none. { }
1278       some(lst_) {
1279         let lst = lst_;
1280         while true {
1281             alt lst {
1282               nil. { break; }
1283               cons(hd, tl) {
1284                 let found = lookup_in_mie(e, hd, ns);
1285                 if !is_none(found) { ret found; }
1286                 lst = *tl;
1287               }
1288             }
1289         }
1290       }
1291     }
1292     // not local or explicitly imported; try globs:
1293     ret lookup_glob_in_mod(e, info, sp, id, ns, outside);
1294 }
1295
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> {
1300         alt def.item.node {
1301           ast::view_item_import_glob(_, id) {
1302             if vec::member(id, e.ignored_imports) { ret none; }
1303           }
1304         }
1305         alt lookup_in_mod(e, def.def, sp, name, ns, dr) {
1306           some(d) { option::some({def: d, item: def.item}) }
1307           none. { none }
1308         }
1309     }
1310     let matches = vec::filter_map(copy globs,
1311                                   bind lookup_in_mod_(e, _, sp, id, ns, dr));
1312     if vec::len(matches) == 0u {
1313         ret none;
1314         }
1315     else if vec::len(matches) == 1u || ns == ns_val(ns_a_tag) {
1316         ret some(matches[0].def);
1317     } else {
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]);
1321         }
1322         e.sess.span_fatal(sp, "'" + id + "' is glob-imported from" +
1323                           " multiple different modules.");
1324     }
1325 }
1326
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,
1334                                   // kludge
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));
1341     }
1342     alt info.glob_imported_names.get(id) {
1343       glob_resolving(sp) {
1344           ret none::<def>;
1345       }
1346       glob_resolved(val, typ, md) {
1347         ret alt wanted_ns {
1348                 ns_val(_) { val }
1349                 ns_type. { typ }
1350                 ns_module. { md }
1351         };
1352       }
1353     }
1354 }
1355
1356 fn lookup_in_mie(e: env, mie: mod_index_entry, ns: namespace) ->
1357    option::t<def> {
1358     alt mie {
1359       mie_view_item(view_item) {
1360         if ns == ns_module { ret found_view_item(e, view_item); }
1361       }
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) {
1365         alt item.node {
1366           ast::item_tag(variants, _) {
1367               alt ns {
1368                   ns_val(_) {
1369                      let vid = variants[variant_idx].node.id;
1370                      ret some(ast::def_variant(local_def(item.id),
1371                                         local_def(vid)));
1372                   }
1373                   _ { ret none::<def>; }
1374               }
1375           }
1376         }
1377       }
1378       mie_native_item(native_item) {
1379         alt native_item.node {
1380           ast::native_item_ty. {
1381             if ns == ns_type {
1382                 ret some(ast::def_native_ty(local_def(native_item.id)));
1383             }
1384           }
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),
1389                     decl.purity));
1390             }
1391           }
1392         }
1393       }
1394     }
1395     ret none::<def>;
1396 }
1397
1398
1399 // Module indexing
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)); }
1405     }
1406 }
1407
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 {
1411         alt it.node {
1412           ast::view_item_use(ident, _, _) {
1413             add_to_index(index, ident, mie_view_item(it));
1414           }
1415           ast::view_item_import(ident, _, id) {
1416             add_to_index(index, ident, mie_import_ident(id, it.span));
1417           }
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));
1422             }
1423           }
1424           //globbed imports have to be resolved lazily.
1425           ast::view_item_import_glob(_, _) | ast::view_item_export(_, _) {}
1426         }
1427     }
1428     for it: @ast::item in md.items {
1429         alt it.node {
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));
1435           }
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));
1442                 variant_idx += 1u;
1443             }
1444           }
1445         }
1446     }
1447     ret index;
1448 }
1449
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 {
1453         alt it.node {
1454           ast::view_item_use(ident, _, _) {
1455             add_to_index(index, ident, mie_view_item(it));
1456           }
1457           ast::view_item_import(ident, _, id) {
1458             add_to_index(index, ident, mie_import_ident(id, it.span));
1459           }
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));
1464             }
1465           }
1466           ast::view_item_import_glob(_, _) | ast::view_item_export(_, _) { }
1467         }
1468     }
1469     for it: @ast::native_item in md.items {
1470         add_to_index(index, it.ident, mie_native_item(it));
1471     }
1472     ret index;
1473 }
1474
1475
1476 // External lookups
1477 fn ns_for_def(d: def) -> namespace {
1478     alt d {
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 }
1487     }
1488 }
1489
1490 // if we're searching for a value, it's ok if we found
1491 // a tag
1492 fn ns_ok(wanted:namespace, actual:namespace) -> bool {
1493     alt actual {
1494       ns_val(ns_a_tag.) {
1495         alt wanted {
1496           ns_val(_) { true }
1497           _ { false }
1498         }
1499       }
1500       _ { wanted == actual}
1501     }
1502 }
1503
1504 fn lookup_external(e: env, cnum: int, ids: [ident], ns: namespace) ->
1505    option::t<def> {
1506     for d: def in csearch::lookup_defs(e.sess.get_cstore(), cnum, ids) {
1507         let did = def_id_of_def(d);
1508         alt 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
1512             // [native] module
1513             if did.crate != ast::local_crate {
1514                 let cname = cstore::get_crate_data(e.cstore, did.crate).name;
1515                 let 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]);
1520             } else {
1521                 e.ext_map.insert(did, ids);
1522             }
1523           }
1524           _ {
1525             e.ext_map.insert(did, ids);
1526           }
1527         }
1528         if ns_ok(ns, ns_for_def(d)) { ret some(d); }
1529     }
1530     ret none::<def>;
1531 }
1532
1533
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); };
1540     };
1541     // Other scopes have to be checked the hard way.
1542     let v =
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));
1549 }
1550
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);
1558     }
1559     while true {
1560         alt entries {
1561           cons(entry, rest) {
1562             if !is_none(lookup_in_mie(e, entry, ns_val(ns_any_value))) {
1563                 if saw_value {
1564                     dup(e, mie_span(entry), "", name);
1565                 } else { saw_value = true; }
1566             }
1567             if !is_none(lookup_in_mie(e, entry, ns_type)) {
1568                 if saw_type {
1569                     dup(e, mie_span(entry), "type ", name);
1570                 } else { saw_type = true; }
1571             }
1572             if !is_none(lookup_in_mie(e, entry, ns_module)) {
1573                 if saw_mod {
1574                     dup(e, mie_span(entry), "module ", name);
1575                 } else { saw_mod = true; }
1576             }
1577             entries = *rest;
1578           }
1579           nil. { break; }
1580         }
1581     }
1582 }
1583
1584 fn mie_span(mie: mod_index_entry) -> span {
1585     ret alt mie {
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 }
1591         };
1592 }
1593
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]; }
1598         ret x;
1599     }
1600     visit::visit_item(i, x, v);
1601     alt i.node {
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,
1605                       "type parameter");
1606       }
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);
1612         }
1613         ensure_unique(*e, i.span, typaram_names(ty_params), ident_id,
1614                       "type parameter");
1615       }
1616       ast::item_tag(_, ty_params) {
1617         ensure_unique(*e, i.span, typaram_names(ty_params), ident_id,
1618                       "type parameter");
1619       }
1620       _ { }
1621     }
1622 }
1623
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);
1628     };
1629 }
1630
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);
1637     while i > 1u {
1638         i -= 1u;
1639         let ch = checker(*e, "binding");
1640         check_pat(ch, a.pats[i]);
1641
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");
1647         } else {
1648             for name: ident in ch.seen {
1649                 if is_none(vec::find(seen0, bind str::eq(name, _))) {
1650                     // Fight the alias checker
1651                     let name_ = name;
1652                     e.sess.span_err(a.pats[i].span,
1653                                     "binding " + name_ +
1654                                         " does not occur in first pattern");
1655                 }
1656             }
1657         }
1658     }
1659 }
1660
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 {
1667         alt st.node {
1668           ast::stmt_decl(d, _) {
1669             alt d.node {
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);
1677                     };
1678                 }
1679               }
1680               ast::decl_item(it) {
1681                 alt it.node {
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);
1686                     }
1687                   }
1688                   ast::item_mod(_) | ast::item_native_mod(_) {
1689                     add_name(mods, it.span, it.ident);
1690                   }
1691                   ast::item_const(_, _) | ast::item_fn(_, _, _) {
1692                     add_name(values, it.span, it.ident);
1693                   }
1694                   ast::item_ty(_, _) | ast::item_iface(_, _) {
1695                     add_name(types, it.span, it.ident);
1696                   }
1697                   ast::item_res(_, _, _, _, _) | ast::item_obj(_, _, _) {
1698                     add_name(types, it.span, it.ident);
1699                     add_name(values, it.span, it.ident);
1700                   }
1701                   _ { }
1702                 }
1703               }
1704             }
1705           }
1706           _ { }
1707         }
1708     }
1709 }
1710
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");
1714 }
1715
1716 fn check_expr(e: @env, ex: @ast::expr, &&x: (), v: vt<()>) {
1717     alt ex.node {
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");
1721       }
1722       _ { }
1723     }
1724     visit::visit_expr(ex, x, v);
1725 }
1726
1727 fn check_ty(e: @env, ty: @ast::ty, &&x: (), v: vt<()>) {
1728     alt ty.node {
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");
1732       }
1733       _ { }
1734     }
1735     visit::visit_ty(ty, x, v);
1736 }
1737
1738 type checker = @{mutable seen: [ident], kind: str, sess: session};
1739
1740 fn checker(e: env, kind: str) -> checker {
1741     let seen: [ident] = [];
1742     ret @{mutable seen: seen, kind: kind, sess: e.sess};
1743 }
1744
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);
1749         }
1750     }
1751 }
1752 fn add_name(ch: checker, sp: span, name: ident) {
1753     check_name(ch, sp, name);
1754     ch.seen += [name];
1755 }
1756
1757 fn ident_id(&&i: ident) -> ident { ret i; }
1758
1759 fn ensure_unique<T>(e: env, sp: span, elts: [T], id: fn(T) -> ident,
1760                     kind: str) {
1761     let ch = checker(e, kind);
1762     for elt: T in elts { add_name(ch, sp, id(elt)); }
1763 }
1764
1765 fn check_exports(e: @env) {
1766     fn lookup_glob_any(e: @env, info: @indexed_mod, sp: span, path: str,
1767                        ident: ident) -> bool {
1768         let lookup =
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)),
1772                          lookup(ns_type));
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);
1777     }
1778
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));
1783         }
1784     }
1785
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);
1789             list::iter(xs) {|x|
1790                 alt x {
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);
1798                       }
1799                       _ { }
1800                     }
1801                   }
1802                   _ { }
1803                 }
1804             }
1805         } else if lookup_glob_any(e, val, vi.span, val.path, ident) {
1806             // do nothing
1807         } else {
1808             e.sess.span_warn(vi.span,
1809                              #fmt("exported item %s is not defined", ident));
1810         }
1811     }
1812
1813     e.mod_map.values {|val|
1814         alt val.m {
1815           some(m) {
1816             for vi in m.view_items {
1817                 alt vi.node {
1818                   ast::view_item_export(idents, _) {
1819                     for ident in idents {
1820                         check_export(e, ident, val, vi);
1821                     }
1822                   }
1823                   _ { }
1824                 }
1825             }
1826           }
1827           none. { }
1828         }
1829     };
1830 }
1831
1832 // Impl resolution
1833
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]>;
1838
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()
1845     }));
1846 }
1847
1848 fn find_impls_in_view_item(e: env, vi: @ast::view_item,
1849                            &impls: [@_impl], sc: iscopes) {
1850     alt vi.node {
1851       ast::view_item_import(name, pt, id) {
1852         let found = [];
1853         if vec::len(*pt) == 1u {
1854             list::iter(sc) {|level|
1855                 if vec::len(found) > 0u { ret; }
1856                 for imp in *level {
1857                     if imp.ident == pt[0] {
1858                         found += [@{ident: name with *imp}];
1859                     }
1860                 }
1861                 if vec::len(found) > 0u { impls += found; }
1862             }
1863         } else {
1864             alt e.imports.get(id) {
1865               resolved(_, _, _, is, _, _) {
1866                 for i in *is { impls += [@{ident: name with *i}]; }
1867               }
1868             }
1869         }
1870       }
1871       ast::view_item_import_from(base, names, _) {
1872         for nm in names {
1873             alt e.imports.get(nm.node.id) {
1874               resolved(_, _, _, is, _, _) { impls += *is; }
1875             }
1876         }
1877       }
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); }
1883                 _ {}
1884               }
1885             }
1886           }
1887       }
1888       _ {}
1889     }
1890 }
1891
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>) {
1895     alt i.node {
1896       ast::item_impl(_, ifce, _, mthds) {
1897         if alt name { some(n) { n == i.ident } _ { true } } &&
1898            alt ck_exports {
1899              some(m) { is_exported(e, i.ident, m) }
1900              _ { true }
1901            } {
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)))
1906                             }
1907                             _ { none }
1908                         },
1909                         ident: i.ident,
1910                         methods: vec::map(mthds, {|m|
1911                             @{did: local_def(m.id),
1912                               n_tps: vec::len(m.tps),
1913                               ident: m.ident}
1914                         })}];
1915         }
1916       }
1917       _ {}
1918     }
1919 }
1920
1921 fn find_impls_in_mod(e: env, m: def, &impls: [@_impl],
1922                      name: option::t<ident>) {
1923     alt m {
1924       ast::def_mod(defid) {
1925         let cached;
1926         alt e.impl_cache.find(defid) {
1927           some(v) { cached = v; }
1928           none. {
1929             cached = if defid.crate == ast::local_crate {
1930                 let tmp = [];
1931                 for i in option::get(e.mod_map.get(defid.node).m).items {
1932                     find_impls_in_item(e, i, tmp, name, none);
1933                 }
1934                 @tmp
1935             } else {
1936                 csearch::get_impls_for_mod(e.sess.get_cstore(), defid, name)
1937             };
1938             e.impl_cache.insert(defid, cached);
1939           }
1940         }
1941         for im in *cached {
1942             if alt name { some(n) { n == im.ident } _ { true } } {
1943                 impls += [im];
1944             }
1945         }
1946       }
1947       _ {}
1948     }
1949 }
1950
1951 fn visit_block_with_impl_scope(e: @env, b: ast::blk, sc: iscopes,
1952                                v: vt<iscopes>) {
1953     let impls = [];
1954     for vi in b.node.view_items {
1955         find_impls_in_view_item(*e, vi, impls, sc);
1956     }
1957     for st in b.node.stmts {
1958         alt st.node {
1959           ast::stmt_decl(@{node: ast::decl_item(i), _}, _) {
1960             find_impls_in_item(*e, i, impls, none, none);
1961           }
1962           _ {}
1963         }
1964     }
1965     let sc = vec::len(impls) > 0u ? cons(@impls, @sc) : sc;
1966     visit::visit_block(b, sc, v);
1967 }
1968
1969 fn visit_mod_with_impl_scope(e: @env, m: ast::_mod, s: span, sc: iscopes,
1970                              v: vt<iscopes>) {
1971     let impls = [];
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);
1975 }
1976
1977 fn resolve_impl_in_expr(e: @env, x: @ast::expr, sc: iscopes, v: vt<iscopes>) {
1978     alt x.node {
1979       ast::expr_field(_, _, _) | ast::expr_path(_) | ast::expr_cast(_, _) {
1980         e.impl_map.insert(x.id, sc);
1981       }
1982       _ {}
1983     }
1984     visit::visit_expr(x, sc, v);
1985 }
1986
1987 // Local Variables:
1988 // mode: rust
1989 // fill-column: 78;
1990 // indent-tabs-mode: nil
1991 // c-basic-offset: 4
1992 // buffer-file-coding-system: utf-8-unix
1993 // End: