mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-30 23:03:06 +03:00
rustc: Implement a new resolve pass behind a compile flag
This commit is contained in:
+2
-2
@@ -27,8 +27,8 @@
|
||||
import either::either;
|
||||
import libc::size_t;
|
||||
|
||||
export port::{};
|
||||
export chan::{};
|
||||
export port;
|
||||
export chan;
|
||||
export send;
|
||||
export recv;
|
||||
export peek;
|
||||
|
||||
+24
-1
@@ -200,6 +200,7 @@ fn push_slice(ts: &[const A], from_idx: uint, to_idx: uint) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#[doc = "
|
||||
Append all elements of an iterable.
|
||||
|
||||
@@ -222,6 +223,7 @@ fn append_iter<A, I:iter::base_iter<A>>(ts: I) {
|
||||
v
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
#[doc = "
|
||||
Gets a copy of the current contents.
|
||||
@@ -267,7 +269,28 @@ fn grow_set_elt(idx: uint, initval: A, val: A) {
|
||||
}
|
||||
|
||||
#[doc = "Returns the last element, failing if the vector is empty"]
|
||||
#[inline(always)]
|
||||
fn last() -> A {
|
||||
self.get_elt(self.len() - 1u)
|
||||
self.check_not_borrowed();
|
||||
|
||||
let length = self.len();
|
||||
if length == 0u {
|
||||
fail "attempt to retrieve the last element of an empty vector";
|
||||
}
|
||||
|
||||
ret self.data[length - 1u];
|
||||
}
|
||||
|
||||
#[doc="Iterates over the elements in reverse order"]
|
||||
#[inline(always)]
|
||||
fn reach(f: fn(A) -> bool) {
|
||||
let length = self.len();
|
||||
let mut i = 0u;
|
||||
while i < length {
|
||||
if !f(self.get_elt(i)) {
|
||||
break;
|
||||
}
|
||||
i += 1u;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
import either::either;
|
||||
|
||||
export future;
|
||||
export future::{};
|
||||
export from_value;
|
||||
export from_port;
|
||||
export from_fn;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import arc::methods;
|
||||
import dvec::dvec;
|
||||
import dvec::{extensions};
|
||||
import sys::methods;
|
||||
|
||||
export port;
|
||||
export chan;
|
||||
|
||||
+2
-1
@@ -24,6 +24,7 @@
|
||||
|
||||
import result::result;
|
||||
import dvec::extensions;
|
||||
import dvec_iter::extensions;
|
||||
|
||||
export task;
|
||||
export task_result;
|
||||
@@ -31,7 +32,7 @@
|
||||
export sched_mode;
|
||||
export sched_opts;
|
||||
export task_opts;
|
||||
export builder::{};
|
||||
export builder;
|
||||
|
||||
export default_task_opts;
|
||||
export get_opts;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import io::{reader_util, writer_util};
|
||||
import map;
|
||||
import map::hashmap;
|
||||
import core::vec::extensions;
|
||||
|
||||
export json;
|
||||
export error;
|
||||
|
||||
@@ -102,6 +102,11 @@ fn len<T>(ls: @list<T>) -> uint {
|
||||
}
|
||||
}
|
||||
|
||||
#[doc = "Push an element to the front of a list"]
|
||||
fn push<T: copy>(&l: list<T>, v: T) {
|
||||
l = cons(v, @l);
|
||||
}
|
||||
|
||||
#[doc = "Iterate over a list"]
|
||||
fn iter<T>(l: @list<T>, f: fn(T)) {
|
||||
let mut cur = l;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import comm::recv;
|
||||
import future_spawn = future::spawn;
|
||||
import future::future;
|
||||
import core::vec::extensions;
|
||||
|
||||
export map, mapi, alli, any, mapi_factory;
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import core::option;
|
||||
import option::{none, some};
|
||||
import rand;
|
||||
import core::rand::extensions;
|
||||
|
||||
fn mkdtemp(prefix: str, suffix: str) -> option<str> {
|
||||
let r = rand::rng();
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
"];
|
||||
|
||||
export iotask::{};
|
||||
export iotask;
|
||||
export spawn_iotask;
|
||||
export interact;
|
||||
export exit;
|
||||
|
||||
@@ -572,6 +572,13 @@ fn walk_pat(pat: @pat, it: fn(@pat)) {
|
||||
}
|
||||
}
|
||||
|
||||
fn view_path_id(p: @view_path) -> node_id {
|
||||
alt p.node {
|
||||
view_path_simple(_, _, id) | view_path_glob(_, id) |
|
||||
view_path_list(_, _, id) { id }
|
||||
}
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
// fill-column: 78;
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
export filemap;
|
||||
export span;
|
||||
export file_substr;
|
||||
export fss_none;
|
||||
export fss_internal;
|
||||
export fss_external;
|
||||
export codemap;
|
||||
export expn_info;
|
||||
export expn_info_;
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
import ast::node_id;
|
||||
import util::interner;
|
||||
// FIXME (#1935): resolve badness
|
||||
import lexer::*;//{string_reader_as_reader, tt_reader_as_reader,
|
||||
//reader, string_reader, tt_reader};
|
||||
import lexer::{string_reader_as_reader, tt_reader_as_reader, reader,
|
||||
string_reader, tt_reader};
|
||||
import diagnostic::{span_handler, mk_span_handler, mk_handler, emitter};
|
||||
|
||||
type parse_sess = @{
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
Predicates on exprs and stmts that the pretty-printer and parser use
|
||||
*/
|
||||
import ast_util::*;
|
||||
|
||||
import ast_util::operator_prec;
|
||||
|
||||
fn expr_requires_semi_to_be_stmt(e: @ast::expr) -> bool {
|
||||
alt e.node {
|
||||
|
||||
@@ -5,18 +5,21 @@
|
||||
import codemap::{span,fss_none};
|
||||
import util::interner;
|
||||
import ast_util::{spanned, respan, mk_sp, ident_to_path, operator_prec};
|
||||
import ast::*;
|
||||
import lexer::reader;
|
||||
import prec::{as_prec, token_to_binop};
|
||||
import attr::parser_attr;
|
||||
import common::{seq_sep_trailing_disallowed, seq_sep_trailing_allowed,
|
||||
seq_sep_none, token_to_str};
|
||||
import common::*;//{parser_common};
|
||||
seq_sep_none, token_to_str, parser_common};
|
||||
import dvec::{dvec, extensions};
|
||||
import vec::{push};
|
||||
import ast::*;
|
||||
|
||||
export file_type;
|
||||
export parser;
|
||||
export parse_expr;
|
||||
export parse_pat;
|
||||
export CRATE_FILE;
|
||||
export SOURCE_FILE;
|
||||
|
||||
// FIXME (#1893): #ast expects to find this here but it's actually
|
||||
// defined in `parse` Fixing this will be easier when we have export
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import parse::classify::*;
|
||||
import parse::comments;
|
||||
import parse::lexer;
|
||||
import codemap::codemap;
|
||||
@@ -8,6 +7,7 @@
|
||||
import diagnostic;
|
||||
import ast_util::operator_prec;
|
||||
import dvec::{dvec, extensions};
|
||||
import parse::classify::*;
|
||||
|
||||
// The ps is stored here to prevent recursive type.
|
||||
enum ann_node {
|
||||
|
||||
+75
-83
@@ -13,6 +13,7 @@
|
||||
import io::{reader_util, writer_util};
|
||||
import getopts::{optopt, optmulti, optflag, optflagopt, opt_present};
|
||||
import back::{x86, x86_64};
|
||||
import std::map::hashmap;
|
||||
|
||||
enum pp_mode {ppm_normal, ppm_expanded, ppm_typed, ppm_identified,
|
||||
ppm_expanded_identified }
|
||||
@@ -107,7 +108,7 @@ fn parse_input(sess: session, cfg: ast::crate_cfg, input: input)
|
||||
}
|
||||
}
|
||||
|
||||
fn time<T>(do_it: bool, what: str, thunk: fn@() -> T) -> T {
|
||||
fn time<T>(do_it: bool, what: str, thunk: fn() -> T) -> T {
|
||||
if !do_it { ret thunk(); }
|
||||
let start = std::time::precise_time_s();
|
||||
let rv = thunk();
|
||||
@@ -137,105 +138,99 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg,
|
||||
sess.building_library = session::building_library(
|
||||
sess.opts.crate_type, crate, sess.opts.test);
|
||||
|
||||
crate = time(time_passes, "configuration", |copy crate| {
|
||||
front::config::strip_unconfigured_items(crate)
|
||||
});
|
||||
crate = time(time_passes, "configuration", ||
|
||||
front::config::strip_unconfigured_items(crate));
|
||||
|
||||
crate = time(time_passes, "maybe building test harness", |copy crate| {
|
||||
front::test::modify_for_testing(sess, crate)
|
||||
});
|
||||
crate = time(time_passes, "maybe building test harness", ||
|
||||
front::test::modify_for_testing(sess, crate));
|
||||
|
||||
crate = time(time_passes, "expansion", |copy crate| {
|
||||
syntax::ext::expand::expand_crate(
|
||||
sess.parse_sess, sess.opts.cfg, crate)
|
||||
});
|
||||
crate = time(time_passes, "expansion", ||
|
||||
syntax::ext::expand::expand_crate(sess.parse_sess, sess.opts.cfg,
|
||||
crate));
|
||||
|
||||
if upto == cu_expand { ret {crate: crate, tcx: none}; }
|
||||
|
||||
crate = time(time_passes, "intrinsic injection", |copy crate| {
|
||||
front::intrinsic_inject::inject_intrinsic(sess, crate)
|
||||
});
|
||||
crate = time(time_passes, "intrinsic injection", ||
|
||||
front::intrinsic_inject::inject_intrinsic(sess, crate));
|
||||
|
||||
crate = time(time_passes, "core injection", |copy crate| {
|
||||
front::core_inject::maybe_inject_libcore_ref(sess, crate)
|
||||
});
|
||||
crate = time(time_passes, "core injection", ||
|
||||
front::core_inject::maybe_inject_libcore_ref(sess, crate));
|
||||
|
||||
time(time_passes, "building warning settings table", |copy crate| {
|
||||
lint::build_settings_crate(sess, crate)
|
||||
});
|
||||
time(time_passes, "building warning settings table", ||
|
||||
lint::build_settings_crate(sess, crate));
|
||||
|
||||
let ast_map = time(time_passes, "ast indexing", |copy crate| {
|
||||
syntax::ast_map::map_crate(sess.diagnostic(), *crate)
|
||||
});
|
||||
let ast_map = time(time_passes, "ast indexing", ||
|
||||
syntax::ast_map::map_crate(sess.diagnostic(), *crate));
|
||||
|
||||
time(time_passes, "external crate/lib resolution", |copy crate| {
|
||||
creader::read_crates(
|
||||
sess.diagnostic(), *crate, sess.cstore,
|
||||
sess.filesearch,
|
||||
session::sess_os_to_meta_os(sess.targ_cfg.os),
|
||||
sess.opts.static)
|
||||
});
|
||||
time(time_passes, "external crate/lib resolution", ||
|
||||
creader::read_crates(sess.diagnostic(), *crate, sess.cstore,
|
||||
sess.filesearch,
|
||||
session::sess_os_to_meta_os(sess.targ_cfg.os),
|
||||
sess.opts.static));
|
||||
|
||||
let { def_map, exp_map, impl_map
|
||||
} = time(time_passes, "resolution", |copy crate| {
|
||||
resolve::resolve_crate(sess, ast_map, crate)
|
||||
});
|
||||
let mut def_map;
|
||||
let mut impl_map;
|
||||
let mut exp_map;
|
||||
if sess.fast_resolve() {
|
||||
let { def_map: fast_dm, exp_map: fast_em, impl_map: fast_im } =
|
||||
time(time_passes, "fast resolution", ||
|
||||
middle::resolve3::resolve_crate(sess, ast_map, crate));
|
||||
|
||||
let freevars = time(time_passes, "freevar finding", |copy crate| {
|
||||
freevars::annotate_freevars(def_map, crate)
|
||||
});
|
||||
def_map = fast_dm;
|
||||
impl_map = fast_im;
|
||||
exp_map = fast_em;
|
||||
} else {
|
||||
let { def_map: normal_dm, exp_map: normal_em, impl_map: normal_im } =
|
||||
time(time_passes, "resolution", ||
|
||||
resolve::resolve_crate(sess, ast_map, crate));
|
||||
|
||||
let region_map = time(time_passes, "region resolution", |copy crate| {
|
||||
middle::region::resolve_crate(sess, def_map, crate)
|
||||
});
|
||||
def_map = normal_dm;
|
||||
impl_map = normal_im;
|
||||
exp_map = normal_em;
|
||||
}
|
||||
|
||||
let freevars = time(time_passes, "freevar finding", ||
|
||||
freevars::annotate_freevars(def_map, crate));
|
||||
|
||||
let region_map = time(time_passes, "region resolution", ||
|
||||
middle::region::resolve_crate(sess, def_map, crate));
|
||||
|
||||
let ty_cx = ty::mk_ctxt(sess, def_map, ast_map, freevars, region_map);
|
||||
|
||||
let ( method_map, vtable_map
|
||||
) = time(time_passes, "typechecking", |copy crate| {
|
||||
typeck::check_crate(ty_cx, impl_map, crate)
|
||||
});
|
||||
let (method_map, vtable_map) = time(time_passes, "typechecking", ||
|
||||
typeck::check_crate(ty_cx,
|
||||
impl_map,
|
||||
crate));
|
||||
|
||||
time(time_passes, "const checking", |copy crate| {
|
||||
middle::check_const::check_crate(
|
||||
sess, crate, ast_map, def_map, method_map, ty_cx)
|
||||
});
|
||||
time(time_passes, "const checking", ||
|
||||
middle::check_const::check_crate(sess, crate, ast_map, def_map,
|
||||
method_map, ty_cx));
|
||||
|
||||
if upto == cu_typeck { ret {crate: crate, tcx: some(ty_cx)}; }
|
||||
|
||||
time(time_passes, "block-use checking", |copy crate| {
|
||||
middle::block_use::check_crate(ty_cx, crate)
|
||||
});
|
||||
time(time_passes, "block-use checking", ||
|
||||
middle::block_use::check_crate(ty_cx, crate));
|
||||
|
||||
time(time_passes, "loop checking", |copy crate| {
|
||||
middle::check_loop::check_crate(ty_cx, crate)
|
||||
});
|
||||
time(time_passes, "loop checking", ||
|
||||
middle::check_loop::check_crate(ty_cx, crate));
|
||||
|
||||
time(time_passes, "alt checking", |copy crate| {
|
||||
middle::check_alt::check_crate(ty_cx, crate)
|
||||
});
|
||||
time(time_passes, "alt checking", ||
|
||||
middle::check_alt::check_crate(ty_cx, crate));
|
||||
|
||||
let last_use_map = time(time_passes, "liveness checking", |copy crate| {
|
||||
middle::liveness::check_crate(ty_cx, method_map, crate)
|
||||
});
|
||||
let last_use_map = time(time_passes, "liveness checking", ||
|
||||
middle::liveness::check_crate(ty_cx, method_map, crate));
|
||||
|
||||
time(time_passes, "typestate checking", |copy crate| {
|
||||
middle::tstate::ck::check_crate(ty_cx, crate)
|
||||
});
|
||||
time(time_passes, "typestate checking", ||
|
||||
middle::tstate::ck::check_crate(ty_cx, crate));
|
||||
|
||||
let ( root_map, mutbl_map
|
||||
) = time(time_passes, "borrow checking", |copy crate| {
|
||||
let (root_map, mutbl_map) = time(time_passes, "borrow checking", ||
|
||||
middle::borrowck::check_crate(ty_cx, method_map,
|
||||
last_use_map, crate)
|
||||
});
|
||||
last_use_map, crate));
|
||||
|
||||
time(time_passes, "kind checking", |copy crate| {
|
||||
kind::check_crate(ty_cx, method_map, last_use_map, crate)
|
||||
});
|
||||
time(time_passes, "kind checking", ||
|
||||
kind::check_crate(ty_cx, method_map, last_use_map, crate));
|
||||
|
||||
time(time_passes, "lint checking", |copy crate| {
|
||||
lint::check_crate(ty_cx, crate)
|
||||
});
|
||||
time(time_passes, "lint checking", || lint::check_crate(ty_cx, crate));
|
||||
|
||||
if upto == cu_no_trans { ret {crate: crate, tcx: some(ty_cx)}; }
|
||||
let outputs = option::get(outputs);
|
||||
@@ -245,14 +240,12 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg,
|
||||
impl_map: impl_map, method_map: method_map,
|
||||
vtable_map: vtable_map};
|
||||
|
||||
let (llmod, link_meta) = time(time_passes, "translation", |copy crate| {
|
||||
let (llmod, link_meta) = time(time_passes, "translation", ||
|
||||
trans::base::trans_crate(sess, crate, ty_cx, outputs.obj_filename,
|
||||
exp_map, maps)
|
||||
});
|
||||
exp_map, maps));
|
||||
|
||||
time(time_passes, "LLVM passes", || {
|
||||
link::write::run_passes(sess, llmod, outputs.obj_filename)
|
||||
});
|
||||
time(time_passes, "LLVM passes", ||
|
||||
link::write::run_passes(sess, llmod, outputs.obj_filename));
|
||||
|
||||
let stop_after_codegen =
|
||||
sess.opts.output_type != link::output_type_exe ||
|
||||
@@ -260,10 +253,9 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg,
|
||||
|
||||
if stop_after_codegen { ret {crate: crate, tcx: some(ty_cx)}; }
|
||||
|
||||
time(time_passes, "linking", || {
|
||||
link::link_binary(sess, outputs.obj_filename,
|
||||
outputs.out_filename, link_meta)
|
||||
});
|
||||
time(time_passes, "linking", ||
|
||||
link::link_binary(sess, outputs.obj_filename,
|
||||
outputs.out_filename, link_meta));
|
||||
|
||||
ret {crate: crate, tcx: some(ty_cx)};
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ enum crate_type { bin_crate, lib_crate, unknown_crate, }
|
||||
// FIXME (#2377): This exists to transition to a Rust crate runtime
|
||||
// It should be removed
|
||||
const no_rt: uint = 256u;
|
||||
const fast_resolve: uint = 512u;
|
||||
|
||||
fn debugging_opts_map() -> ~[(str, str, uint)] {
|
||||
~[("ppregions", "prettyprint regions with \
|
||||
@@ -47,7 +48,8 @@ fn debugging_opts_map() -> ~[(str, str, uint)] {
|
||||
("no-asm-comments", "omit comments when using -S", no_asm_comments),
|
||||
("no-verify", "skip LLVM verification", no_verify),
|
||||
("trace", "emit trace logs", trace),
|
||||
("no-rt", "do not link to the runtime", no_rt)
|
||||
("no-rt", "do not link to the runtime", no_rt),
|
||||
("fast-resolve", "use fast name resolution", fast_resolve)
|
||||
]
|
||||
}
|
||||
|
||||
@@ -162,6 +164,7 @@ fn stats() -> bool { self.debugging_opt(stats) }
|
||||
fn no_asm_comments() -> bool { self.debugging_opt(no_asm_comments) }
|
||||
fn no_verify() -> bool { self.debugging_opt(no_verify) }
|
||||
fn trace() -> bool { self.debugging_opt(trace) }
|
||||
fn fast_resolve() -> bool { self.debugging_opt(fast_resolve) }
|
||||
}
|
||||
|
||||
#[doc = "Some reasonable defaults"]
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
export get_enum_variants;
|
||||
export get_impls_for_mod;
|
||||
export get_iface_methods;
|
||||
export each_path;
|
||||
export get_type;
|
||||
export get_impl_iface;
|
||||
export get_impl_method;
|
||||
@@ -81,6 +82,13 @@ fn resolve_path(cstore: cstore::cstore, cnum: ast::crate_num,
|
||||
ret result;
|
||||
}
|
||||
|
||||
#[doc="Iterates over all the paths in the given crate."]
|
||||
fn each_path(cstore: cstore::cstore, cnum: ast::crate_num,
|
||||
f: fn(decoder::path_entry) -> bool) {
|
||||
let crate_data = cstore::get_crate_data(cstore, cnum);
|
||||
decoder::each_path(crate_data, f);
|
||||
}
|
||||
|
||||
fn get_item_path(tcx: ty::ctxt, def: ast::def_id) -> ast_map::path {
|
||||
let cstore = tcx.cstore;
|
||||
let cdata = cstore::get_crate_data(cstore, def.crate);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import syntax::{ast, attr};
|
||||
import syntax::ast_util::new_def_hash;
|
||||
|
||||
export cstore::{};
|
||||
export cstore;
|
||||
export cnum_map;
|
||||
export crate_metadata;
|
||||
export mk_cstore;
|
||||
|
||||
+135
-20
@@ -1,7 +1,7 @@
|
||||
// Decoding metadata from a single crate's metadata
|
||||
|
||||
import std::{ebml, map};
|
||||
import std::map::hashmap;
|
||||
import std::map::{hashmap, str_hash};
|
||||
import io::writer_util;
|
||||
import syntax::{ast, ast_util};
|
||||
import syntax::attr;
|
||||
@@ -37,6 +37,12 @@
|
||||
export get_impls_for_mod;
|
||||
export get_iface_methods;
|
||||
export get_crate_module_paths;
|
||||
export def_like;
|
||||
export dl_def;
|
||||
export dl_impl;
|
||||
export dl_field;
|
||||
export path_entry;
|
||||
export each_path;
|
||||
export get_item_path;
|
||||
export maybe_find_item; // sketchy
|
||||
export item_type; // sketchy
|
||||
@@ -116,6 +122,7 @@ fn item_parent_item(d: ebml::doc) -> option<ast::def_id> {
|
||||
found
|
||||
}
|
||||
|
||||
// XXX: This has nothing to do with classes.
|
||||
fn class_member_id(d: ebml::doc, cdata: cmd) -> ast::def_id {
|
||||
let tagdoc = ebml::get_doc(d, tag_def_id);
|
||||
ret translate_def_id(cdata, parse_def_id(ebml::doc_data(tagdoc)));
|
||||
@@ -257,31 +264,39 @@ fn lookup_item_name(data: @~[u8], id: ast::node_id) -> ast::ident {
|
||||
item_name(lookup_item(id, data))
|
||||
}
|
||||
|
||||
fn lookup_def(cnum: ast::crate_num, data: @~[u8], did_: ast::def_id) ->
|
||||
ast::def {
|
||||
let item = lookup_item(did_.node, data);
|
||||
fn item_to_def_like(item: ebml::doc, did: ast::def_id, cnum: ast::crate_num)
|
||||
-> def_like {
|
||||
let fam_ch = item_family(item);
|
||||
let did = {crate: cnum, node: did_.node};
|
||||
// We treat references to enums as references to types.
|
||||
alt check fam_ch {
|
||||
'c' { ast::def_const(did) }
|
||||
'C' { ast::def_class(did) }
|
||||
'u' { ast::def_fn(did, ast::unsafe_fn) }
|
||||
'f' { ast::def_fn(did, ast::impure_fn) }
|
||||
'p' { ast::def_fn(did, ast::pure_fn) }
|
||||
'y' { ast::def_ty(did) }
|
||||
't' { ast::def_ty(did) }
|
||||
'm' { ast::def_mod(did) }
|
||||
'n' { ast::def_foreign_mod(did) }
|
||||
alt fam_ch {
|
||||
'c' { dl_def(ast::def_const(did)) }
|
||||
'C' { dl_def(ast::def_class(did)) }
|
||||
'u' { dl_def(ast::def_fn(did, ast::unsafe_fn)) }
|
||||
'f' { dl_def(ast::def_fn(did, ast::impure_fn)) }
|
||||
'p' { dl_def(ast::def_fn(did, ast::pure_fn)) }
|
||||
'y' { dl_def(ast::def_ty(did)) }
|
||||
't' { dl_def(ast::def_ty(did)) }
|
||||
'm' { dl_def(ast::def_mod(did)) }
|
||||
'n' { dl_def(ast::def_foreign_mod(did)) }
|
||||
'v' {
|
||||
let mut tid = option::get(item_parent_item(item));
|
||||
tid = {crate: cnum, node: tid.node};
|
||||
ast::def_variant(tid, did)
|
||||
dl_def(ast::def_variant(tid, did))
|
||||
}
|
||||
'I' { ast::def_ty(did) }
|
||||
'I' { dl_def(ast::def_ty(did)) }
|
||||
'i' { dl_impl(did) }
|
||||
'g' | 'j' { dl_field }
|
||||
ch { fail #fmt("unexpected family code: '%c'", ch) }
|
||||
}
|
||||
}
|
||||
|
||||
fn lookup_def(cnum: ast::crate_num, data: @~[u8], did_: ast::def_id) ->
|
||||
ast::def {
|
||||
let item = lookup_item(did_.node, data);
|
||||
let did = {crate: cnum, node: did_.node};
|
||||
// We treat references to enums as references to types.
|
||||
ret def_like_to_def(item_to_def_like(item, did, cnum));
|
||||
}
|
||||
|
||||
fn get_type(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
|
||||
-> ty::ty_param_bounds_and_ty {
|
||||
|
||||
@@ -356,6 +371,104 @@ fn get_symbol(data: @~[u8], id: ast::node_id) -> str {
|
||||
ret item_symbol(lookup_item(id, data));
|
||||
}
|
||||
|
||||
// Something that a name can resolve to.
|
||||
enum def_like {
|
||||
dl_def(ast::def),
|
||||
dl_impl(ast::def_id),
|
||||
dl_field
|
||||
}
|
||||
|
||||
fn def_like_to_def(def_like: def_like) -> ast::def {
|
||||
alt def_like {
|
||||
dl_def(def) { ret def; }
|
||||
dl_impl(*) { fail "found impl in def_like_to_def"; }
|
||||
dl_field { fail "found field in def_like_to_def"; }
|
||||
}
|
||||
}
|
||||
|
||||
// A path.
|
||||
class path_entry {
|
||||
// The full path, separated by '::'.
|
||||
let path_string: str;
|
||||
// The definition, implementation, or field that this path corresponds to.
|
||||
let def_like: def_like;
|
||||
|
||||
new(path_string: str, def_like: def_like) {
|
||||
self.path_string = path_string;
|
||||
self.def_like = def_like;
|
||||
}
|
||||
}
|
||||
|
||||
#[doc="Iterates over all the paths in the given crate."]
|
||||
fn each_path(cdata: cmd, f: fn(path_entry) -> bool) {
|
||||
let root = ebml::doc(cdata.data);
|
||||
let items = ebml::get_doc(root, tag_items);
|
||||
let items_data = ebml::get_doc(items, tag_items_data);
|
||||
|
||||
let mut broken = false;
|
||||
|
||||
// First, go through all the explicit items.
|
||||
do ebml::tagged_docs(items_data, tag_items_data_item) |item_doc| {
|
||||
if !broken {
|
||||
let name = ast_map::path_to_str_with_sep(item_path(item_doc),
|
||||
"::");
|
||||
if name != "" {
|
||||
// Extract the def ID.
|
||||
let def_id = class_member_id(item_doc, cdata);
|
||||
|
||||
// Construct the def for this item.
|
||||
#debug("(each_path) yielding explicit item: %s", name);
|
||||
let def_like = item_to_def_like(item_doc, def_id, cdata.cnum);
|
||||
|
||||
// Hand the information off to the iteratee.
|
||||
let this_path_entry = path_entry(name, def_like);
|
||||
if !f(this_path_entry) {
|
||||
broken = true; // XXX: This is awful.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If broken, stop here.
|
||||
if broken {
|
||||
ret;
|
||||
}
|
||||
|
||||
// Next, go through all the paths. We will find items that we didn't know
|
||||
// about before (reexports in particular).
|
||||
let outer_paths = ebml::get_doc(root, tag_paths);
|
||||
let inner_paths = ebml::get_doc(outer_paths, tag_paths);
|
||||
do ebml::tagged_docs(inner_paths, tag_paths_data_item) |path_doc| {
|
||||
if !broken {
|
||||
let path = item_name(path_doc);
|
||||
|
||||
// Extract the def ID.
|
||||
let def_id = class_member_id(path_doc, cdata);
|
||||
|
||||
// Get the item.
|
||||
alt maybe_find_item(def_id.node, items) {
|
||||
none {
|
||||
#debug("(each_path) ignoring implicit item: %s",
|
||||
*path);
|
||||
}
|
||||
some(item_doc) {
|
||||
// Construct the def for this item.
|
||||
let def_like = item_to_def_like(item_doc, def_id,
|
||||
cdata.cnum);
|
||||
|
||||
// Hand the information off to the iteratee.
|
||||
#debug("(each_path) yielding implicit item: %s",
|
||||
*path);
|
||||
let this_path_entry = path_entry(*path, def_like);
|
||||
if (!f(this_path_entry)) {
|
||||
broken = true; // XXX: This is awful.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_item_path(cdata: cmd, id: ast::node_id) -> ast_map::path {
|
||||
item_path(lookup_item(id, cdata.data))
|
||||
}
|
||||
@@ -441,10 +554,12 @@ fn item_impl_methods(cdata: cmd, item: ebml::doc, base_tps: uint)
|
||||
rslt
|
||||
}
|
||||
|
||||
fn get_impls_for_mod(cdata: cmd, m_id: ast::node_id,
|
||||
fn get_impls_for_mod(cdata: cmd,
|
||||
m_id: ast::node_id,
|
||||
name: option<ast::ident>,
|
||||
get_cdata: fn(ast::crate_num) -> cmd)
|
||||
-> @~[@_impl] {
|
||||
-> @~[@_impl] {
|
||||
|
||||
let data = cdata.data;
|
||||
let mod_item = lookup_item(m_id, data);
|
||||
let mut result = ~[];
|
||||
|
||||
@@ -385,9 +385,13 @@ fn encode_info_for_mod(ecx: @encode_ctxt, ebml_w: ebml::writer, md: _mod,
|
||||
encode_def_id(ebml_w, local_def(id));
|
||||
encode_family(ebml_w, 'm');
|
||||
encode_name(ebml_w, name);
|
||||
#debug("(encoding info for module) encoding info for module ID %d", id);
|
||||
let impls = ecx.impl_map(id);
|
||||
for impls.each |i| {
|
||||
let (ident, did) = i;
|
||||
#debug("(encoding info for module) ... encoding impl %s (%?), \
|
||||
exported? %?",
|
||||
*ident, did, ast_util::is_exported(ident, md));
|
||||
if ast_util::is_exported(ident, md) {
|
||||
ebml_w.start_tag(tag_mod_impl);
|
||||
alt ecx.tcx.items.find(did.node) {
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
import std::smallintmap::{map,smallintmap};
|
||||
import io::writer_util;
|
||||
import syntax::print::pprust::expr_to_str;
|
||||
export lint, ctypes, unused_imports;
|
||||
export lint, ctypes, unused_imports, while_true, path_statement, old_vecs;
|
||||
export unrecognized_warning, non_implicitly_copyable_typarams;
|
||||
export vecs_not_implicitly_copyable, implicit_copies;
|
||||
export level, ignore, warn, error;
|
||||
export lookup_lint, lint_dict, get_lint_dict;
|
||||
export get_warning_level, get_warning_settings_level;
|
||||
|
||||
@@ -283,7 +283,7 @@ fn variable(node_id: node_id, span: span) -> variable {
|
||||
some(var) {var}
|
||||
none {
|
||||
self.tcx.sess.span_bug(
|
||||
span, "No variable registered for this id");
|
||||
span, #fmt("No variable registered for id %d", node_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3946 @@
|
||||
import driver::session::session;
|
||||
import metadata::csearch::{each_path, get_impls_for_mod, lookup_defs};
|
||||
import metadata::cstore::find_use_stmt_cnum;
|
||||
import metadata::decoder::{def_like, dl_def, dl_field, dl_impl};
|
||||
import syntax::ast::{_mod, arm, blk, bound_const, bound_copy, bound_iface};
|
||||
import syntax::ast::{bound_send, capture_clause, class_ctor, class_dtor};
|
||||
import syntax::ast::{class_member, class_method, crate, crate_num, decl_item};
|
||||
import syntax::ast::{def, def_arg, def_binding, def_class, def_const, def_fn};
|
||||
import syntax::ast::{def_foreign_mod, def_id, def_local, def_mod};
|
||||
import syntax::ast::{def_prim_ty, def_region, def_self, def_ty, def_ty_param};
|
||||
import syntax::ast::{def_upvar, def_use, def_variant, expr, expr_assign_op};
|
||||
import syntax::ast::{expr_binary, expr_cast, expr_field, expr_fn};
|
||||
import syntax::ast::{expr_fn_block, expr_index, expr_new, expr_path};
|
||||
import syntax::ast::{expr_unary, fn_decl, foreign_item, foreign_item_fn};
|
||||
import syntax::ast::{ident, iface_ref, impure_fn, instance_var, item};
|
||||
import syntax::ast::{item_class, item_const, item_enum, item_fn};
|
||||
import syntax::ast::{item_foreign_mod, item_iface, item_impl, item_mod};
|
||||
import syntax::ast::{item_ty, local, local_crate, method, node_id, pat};
|
||||
import syntax::ast::{pat_enum, pat_ident, path, prim_ty, stmt_decl, ty};
|
||||
import syntax::ast::{ty_bool, ty_char, ty_constr, ty_f, ty_f32, ty_f64};
|
||||
import syntax::ast::{ty_float, ty_i, ty_i16, ty_i32, ty_i64, ty_i8, ty_int};
|
||||
import syntax::ast::{ty_param, ty_path, ty_str, ty_u, ty_u16, ty_u32, ty_u64};
|
||||
import syntax::ast::{ty_u8, ty_uint, variant, view_item, view_item_export};
|
||||
import syntax::ast::{view_item_import, view_item_use, view_path_glob};
|
||||
import syntax::ast::{view_path_list, view_path_simple};
|
||||
import syntax::ast_util::{def_id_of_def, local_def, new_def_hash, walk_pat};
|
||||
import syntax::codemap::span;
|
||||
import syntax::visit::{default_visitor, fk_method, mk_vt, visit_block};
|
||||
import syntax::visit::{visit_crate, visit_expr, visit_expr_opt, visit_fn};
|
||||
import syntax::visit::{visit_foreign_item, visit_item, visit_method_helper};
|
||||
import syntax::visit::{visit_mod, visit_ty, vt};
|
||||
|
||||
import box::ptr_eq;
|
||||
import dvec::{dvec, extensions};
|
||||
import option::get;
|
||||
import str::{connect, split_str};
|
||||
import vec::pop;
|
||||
|
||||
import std::list::{cons, list, nil};
|
||||
import std::map::{hashmap, int_hash, str_hash};
|
||||
import ASTMap = syntax::ast_map::map;
|
||||
import str_eq = str::eq;
|
||||
|
||||
// Definition mapping
|
||||
type DefMap = hashmap<node_id,def>;
|
||||
|
||||
// Implementation resolution
|
||||
type MethodInfo = { did: def_id, n_tps: uint, ident: ident };
|
||||
type Impl = { did: def_id, ident: ident, methods: ~[@MethodInfo] };
|
||||
type ImplScope = @~[@Impl];
|
||||
type ImplScopes = @list<ImplScope>;
|
||||
type ImplMap = hashmap<node_id,ImplScopes>;
|
||||
|
||||
// Export mapping
|
||||
type Export = { reexp: bool, id: def_id };
|
||||
type ExportMap = hashmap<node_id, ~[Export]>;
|
||||
|
||||
enum PatternBindingMode {
|
||||
RefutableMode,
|
||||
IrrefutableMode
|
||||
}
|
||||
|
||||
enum Namespace {
|
||||
ModuleNS,
|
||||
TypeNS,
|
||||
ValueNS,
|
||||
ImplNS
|
||||
}
|
||||
|
||||
enum NamespaceResult {
|
||||
UnknownResult,
|
||||
UnboundResult,
|
||||
BoundResult(@Module, @NameBindings)
|
||||
}
|
||||
|
||||
enum ImplNamespaceResult {
|
||||
UnknownImplResult,
|
||||
UnboundImplResult,
|
||||
BoundImplResult(@dvec<@Target>)
|
||||
}
|
||||
|
||||
enum NameDefinition {
|
||||
NoNameDefinition, //< The name was unbound.
|
||||
ChildNameDefinition(def), //< The name identifies an immediate child.
|
||||
ImportNameDefinition(def) //< The name identifies an import.
|
||||
|
||||
}
|
||||
|
||||
enum Mutability {
|
||||
Mutable,
|
||||
Immutable
|
||||
}
|
||||
|
||||
enum SelfBinding {
|
||||
NoSelfBinding,
|
||||
HasSelfBinding(node_id)
|
||||
}
|
||||
|
||||
enum CaptureClause {
|
||||
NoCaptureClause,
|
||||
HasCaptureClause(capture_clause)
|
||||
}
|
||||
|
||||
type ResolveVisitor = vt<()>;
|
||||
|
||||
enum ModuleDef {
|
||||
NoModuleDef, // Does not define a module.
|
||||
ModuleDef(@Module), // Defines a module.
|
||||
}
|
||||
|
||||
#[doc="Contains data for specific types of import directives."]
|
||||
enum ImportDirectiveSubclass {
|
||||
SingleImport(Atom /* target */, Atom /* source */),
|
||||
GlobImport
|
||||
}
|
||||
|
||||
#[doc="The context that we thread through while building the reduced graph."]
|
||||
enum ReducedGraphParent {
|
||||
ModuleReducedGraphParent(@Module)
|
||||
}
|
||||
|
||||
enum ResolveResult<T> {
|
||||
Failed, // Failed to resolve the name.
|
||||
Indeterminate, // Couldn't determine due to unresolved globs.
|
||||
Success(T) // Successfully resolved the import.
|
||||
}
|
||||
|
||||
enum PrivacyFilter {
|
||||
PrivateOrPublic, //< Will match both public and private items.
|
||||
PublicOnly //< Will match only public items.
|
||||
}
|
||||
|
||||
enum TypeParameters/& {
|
||||
NoTypeParameters, //< No type parameters.
|
||||
HasTypeParameters(&~[ty_param], //< Type parameters.
|
||||
node_id, //< ID of the enclosing item
|
||||
|
||||
// The index to start numbering the type parameters at.
|
||||
// This is zero if this is the outermost set of type
|
||||
// parameters, or equal to the number of outer type
|
||||
// parameters. For example, if we have:
|
||||
//
|
||||
// impl I<T> {
|
||||
// fn method<U>() { ... }
|
||||
// }
|
||||
//
|
||||
// The index at the method site will be 1, because the
|
||||
// outer T had index 0.
|
||||
|
||||
uint)
|
||||
}
|
||||
|
||||
// The rib kind controls the translation of argument or local definitions
|
||||
// (`def_arg` or `def_local`) to upvars (`def_upvar`).
|
||||
|
||||
enum RibKind {
|
||||
// No translation needs to be applied.
|
||||
NormalRibKind,
|
||||
// We passed through a function scope at the given node ID. Translate
|
||||
// upvars as appropriate.
|
||||
FunctionRibKind(node_id)
|
||||
}
|
||||
|
||||
// FIXME (issue #2550): Should be a class but then it becomes not implicitly
|
||||
// copyable due to a kind bug.
|
||||
|
||||
type Atom = uint;
|
||||
|
||||
fn Atom(n: uint) -> Atom {
|
||||
ret n;
|
||||
}
|
||||
|
||||
class AtomTable {
|
||||
let atoms: hashmap<@str,Atom>;
|
||||
let strings: dvec<@str>;
|
||||
let mut atom_count: uint;
|
||||
|
||||
new() {
|
||||
self.atoms = hashmap::<@str,Atom>(|x| str::hash(*x),
|
||||
|x, y| str::eq(*x, *y));
|
||||
self.strings = dvec();
|
||||
self.atom_count = 0u;
|
||||
}
|
||||
|
||||
fn intern(string: @str) -> Atom {
|
||||
alt self.atoms.find(string) {
|
||||
none { /* fall through */ }
|
||||
some(atom) { ret atom; }
|
||||
}
|
||||
|
||||
let atom = Atom(self.atom_count);
|
||||
self.atom_count += 1u;
|
||||
self.atoms.insert(string, atom);
|
||||
self.strings.push(string);
|
||||
|
||||
ret atom;
|
||||
}
|
||||
|
||||
fn atom_to_str(atom: Atom) -> @str {
|
||||
ret self.strings.get_elt(atom);
|
||||
}
|
||||
|
||||
fn atoms_to_strs(atoms: ~[Atom], f: fn(@str) -> bool) {
|
||||
for atoms.each |atom| {
|
||||
if !f(self.atom_to_str(atom)) {
|
||||
ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn atoms_to_str(atoms: ~[Atom]) -> @str {
|
||||
// XXX: str::connect should do this.
|
||||
let mut result = "";
|
||||
let mut first = true;
|
||||
for self.atoms_to_strs(atoms) |string| {
|
||||
if first {
|
||||
first = false;
|
||||
} else {
|
||||
result += "::";
|
||||
}
|
||||
|
||||
result += *string;
|
||||
}
|
||||
|
||||
// XXX: Shouldn't copy here. We need string builder functionality.
|
||||
ret @result;
|
||||
}
|
||||
}
|
||||
|
||||
#[doc="Creates a hash table of atoms."]
|
||||
fn atom_hashmap<V:copy>() -> hashmap<Atom,V> {
|
||||
ret hashmap::<Atom,V>(|a| a, |a, b| a == b);
|
||||
}
|
||||
|
||||
#[doc="
|
||||
One local scope. In Rust, local scopes can only contain value bindings.
|
||||
Therefore, we don't have to worry about the other namespaces here.
|
||||
"]
|
||||
class Rib {
|
||||
let bindings: hashmap<Atom,def_like>;
|
||||
let kind: RibKind;
|
||||
|
||||
new(kind: RibKind) {
|
||||
self.bindings = atom_hashmap();
|
||||
self.kind = kind;
|
||||
}
|
||||
}
|
||||
|
||||
#[doc="One import directive."]
|
||||
class ImportDirective {
|
||||
let module_path: @dvec<Atom>;
|
||||
let subclass: @ImportDirectiveSubclass;
|
||||
|
||||
new(module_path: @dvec<Atom>, subclass: @ImportDirectiveSubclass) {
|
||||
self.module_path = module_path;
|
||||
self.subclass = subclass;
|
||||
}
|
||||
}
|
||||
|
||||
#[doc="The item that an import resolves to."]
|
||||
class Target {
|
||||
let target_module: @Module;
|
||||
let bindings: @NameBindings;
|
||||
|
||||
new(target_module: @Module, bindings: @NameBindings) {
|
||||
self.target_module = target_module;
|
||||
self.bindings = bindings;
|
||||
}
|
||||
}
|
||||
|
||||
class ImportResolution {
|
||||
// The number of outstanding references to this name. When this reaches
|
||||
// zero, outside modules can count on the targets being correct. Before
|
||||
// then, all bets are off; future imports could override this name.
|
||||
|
||||
let mut outstanding_references: uint;
|
||||
|
||||
let mut module_target: option<Target>;
|
||||
let mut value_target: option<Target>;
|
||||
let mut type_target: option<Target>;
|
||||
let mut impl_target: @dvec<@Target>;
|
||||
|
||||
new() {
|
||||
self.outstanding_references = 0u;
|
||||
|
||||
self.module_target = none;
|
||||
self.value_target = none;
|
||||
self.type_target = none;
|
||||
self.impl_target = @dvec();
|
||||
}
|
||||
|
||||
fn target_for_namespace(namespace: Namespace) -> option<Target> {
|
||||
alt namespace {
|
||||
ModuleNS { ret copy self.module_target; }
|
||||
TypeNS { ret copy self.type_target; }
|
||||
ValueNS { ret copy self.value_target; }
|
||||
|
||||
ImplNS {
|
||||
if (*self.impl_target).len() > 0u {
|
||||
ret some(copy *(*self.impl_target).get_elt(0u));
|
||||
}
|
||||
ret none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc="The link from a module up to its nearest parent node."]
|
||||
enum ParentLink {
|
||||
NoParentLink,
|
||||
ModuleParentLink(@Module, Atom),
|
||||
BlockParentLink(@Module, node_id)
|
||||
}
|
||||
|
||||
#[doc="One node in the tree of modules."]
|
||||
class Module {
|
||||
let parent_link: ParentLink;
|
||||
let mut def_id: option<def_id>;
|
||||
|
||||
let children: hashmap<Atom,@NameBindings>;
|
||||
let imports: dvec<@ImportDirective>;
|
||||
|
||||
// The anonymous children of this node. Anonymous children are pseudo-
|
||||
// modules that are implicitly created around items contained within
|
||||
// blocks.
|
||||
//
|
||||
// For example, if we have this:
|
||||
//
|
||||
// fn f() {
|
||||
// fn g() {
|
||||
// ...
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// There will be an anonymous module created around `g` with the ID of the
|
||||
// entry block for `f`.
|
||||
|
||||
let anonymous_children: hashmap<node_id,@Module>;
|
||||
|
||||
// XXX: This is about to be reworked so that exports are on individual
|
||||
// items, not names.
|
||||
//
|
||||
// The atom is the name of the exported item, while the node ID is the
|
||||
// ID of the export path.
|
||||
|
||||
let exported_names: hashmap<Atom,node_id>;
|
||||
|
||||
// The status of resolving each import in this module.
|
||||
let import_resolutions: hashmap<Atom,@ImportResolution>;
|
||||
|
||||
// The number of unresolved globs that this module exports.
|
||||
let mut glob_count: uint;
|
||||
|
||||
// The index of the import we're resolving.
|
||||
let mut resolved_import_count: uint;
|
||||
|
||||
// The list of implementation scopes, rooted from this module.
|
||||
let mut impl_scopes: ImplScopes;
|
||||
|
||||
new(parent_link: ParentLink, def_id: option<def_id>) {
|
||||
self.parent_link = parent_link;
|
||||
self.def_id = def_id;
|
||||
|
||||
self.children = atom_hashmap();
|
||||
self.imports = dvec();
|
||||
|
||||
self.anonymous_children = int_hash();
|
||||
|
||||
self.exported_names = atom_hashmap();
|
||||
|
||||
self.import_resolutions = atom_hashmap();
|
||||
self.glob_count = 0u;
|
||||
self.resolved_import_count = 0u;
|
||||
|
||||
self.impl_scopes = @nil;
|
||||
}
|
||||
|
||||
fn all_imports_resolved() -> bool {
|
||||
ret self.imports.len() == self.resolved_import_count;
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: This is a workaround due to is_none in the standard library mistakenly
|
||||
// requiring a T:copy.
|
||||
|
||||
pure fn is_none<T>(x: option<T>) -> bool {
|
||||
alt x {
|
||||
none { ret true; }
|
||||
some(_) { ret false; }
|
||||
}
|
||||
}
|
||||
|
||||
#[doc="
|
||||
Records the definitions (at most one for each namespace) that a name is
|
||||
bound to.
|
||||
"]
|
||||
class NameBindings {
|
||||
let mut module_def: ModuleDef; ///< Meaning in the module namespace.
|
||||
let mut type_def: option<def>; ///< Meaning in the type namespace.
|
||||
let mut value_def: option<def>; ///< Meaning in the value namespace.
|
||||
let mut impl_defs: ~[@Impl]; ///< Meaning in the impl namespace.
|
||||
|
||||
new() {
|
||||
self.module_def = NoModuleDef;
|
||||
self.type_def = none;
|
||||
self.value_def = none;
|
||||
self.impl_defs = ~[];
|
||||
}
|
||||
|
||||
#[doc="Creates a new module in this set of name bindings."]
|
||||
fn define_module(parent_link: ParentLink, def_id: option<def_id>) {
|
||||
if self.module_def == NoModuleDef {
|
||||
let module = @Module(parent_link, def_id);
|
||||
self.module_def = ModuleDef(module);
|
||||
}
|
||||
}
|
||||
|
||||
#[doc="Records a type definition."]
|
||||
fn define_type(def: def) {
|
||||
self.type_def = some(def);
|
||||
}
|
||||
|
||||
#[doc="Records a value definition."]
|
||||
fn define_value(def: def) {
|
||||
self.value_def = some(def);
|
||||
}
|
||||
|
||||
#[doc="Records an impl definition."]
|
||||
fn define_impl(implementation: @Impl) {
|
||||
self.impl_defs += ~[implementation];
|
||||
}
|
||||
|
||||
#[doc="Returns the module node if applicable."]
|
||||
fn get_module_if_available() -> option<@Module> {
|
||||
alt self.module_def {
|
||||
NoModuleDef { ret none; }
|
||||
ModuleDef(module) { ret some(module); }
|
||||
}
|
||||
}
|
||||
|
||||
#[doc="
|
||||
Returns the module node. Fails if this node does not have a module
|
||||
definition.
|
||||
"]
|
||||
fn get_module() -> @Module {
|
||||
alt self.module_def {
|
||||
NoModuleDef {
|
||||
fail "get_module called on a node with no module definition!";
|
||||
}
|
||||
ModuleDef(module) {
|
||||
ret module;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn defined_in_namespace(namespace: Namespace) -> bool {
|
||||
alt namespace {
|
||||
ModuleNS { ret self.module_def != NoModuleDef; }
|
||||
TypeNS { ret self.type_def != none; }
|
||||
ValueNS { ret self.value_def != none; }
|
||||
ImplNS { ret self.impl_defs.len() >= 1u; }
|
||||
}
|
||||
}
|
||||
|
||||
fn def_for_namespace(namespace: Namespace) -> option<def> {
|
||||
alt namespace {
|
||||
TypeNS {
|
||||
ret self.type_def;
|
||||
}
|
||||
ValueNS {
|
||||
ret self.value_def;
|
||||
}
|
||||
ModuleNS {
|
||||
alt self.module_def {
|
||||
NoModuleDef {
|
||||
ret none;
|
||||
}
|
||||
ModuleDef(module) {
|
||||
alt module.def_id {
|
||||
none {
|
||||
ret none;
|
||||
}
|
||||
some(def_id) {
|
||||
ret some(def_mod(def_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ImplNS {
|
||||
// Danger: Be careful what you use this for! def_ty is not
|
||||
// necessarily the right def.
|
||||
|
||||
if self.impl_defs.len() == 0u {
|
||||
ret none;
|
||||
}
|
||||
ret some(def_ty(self.impl_defs[0].did));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc="Interns the names of the primitive types."]
|
||||
class PrimitiveTypeTable {
|
||||
let primitive_types: hashmap<Atom,prim_ty>;
|
||||
|
||||
new(atom_table: @AtomTable) {
|
||||
self.primitive_types = atom_hashmap();
|
||||
|
||||
self.intern(atom_table, @"bool", ty_bool);
|
||||
self.intern(atom_table, @"char", ty_int(ty_char));
|
||||
self.intern(atom_table, @"float", ty_float(ty_f));
|
||||
self.intern(atom_table, @"f32", ty_float(ty_f32));
|
||||
self.intern(atom_table, @"f64", ty_float(ty_f64));
|
||||
self.intern(atom_table, @"int", ty_int(ty_i));
|
||||
self.intern(atom_table, @"i8", ty_int(ty_i8));
|
||||
self.intern(atom_table, @"i16", ty_int(ty_i16));
|
||||
self.intern(atom_table, @"i32", ty_int(ty_i32));
|
||||
self.intern(atom_table, @"i64", ty_int(ty_i64));
|
||||
self.intern(atom_table, @"str", ty_str);
|
||||
self.intern(atom_table, @"uint", ty_uint(ty_u));
|
||||
self.intern(atom_table, @"u8", ty_uint(ty_u8));
|
||||
self.intern(atom_table, @"u16", ty_uint(ty_u16));
|
||||
self.intern(atom_table, @"u32", ty_uint(ty_u32));
|
||||
self.intern(atom_table, @"u64", ty_uint(ty_u64));
|
||||
}
|
||||
|
||||
fn intern(atom_table: @AtomTable, string: @str, primitive_type: prim_ty) {
|
||||
let atom = (*atom_table).intern(string);
|
||||
self.primitive_types.insert(atom, primitive_type);
|
||||
}
|
||||
}
|
||||
|
||||
#[doc="The main resolver class."]
|
||||
class Resolver {
|
||||
let session: session;
|
||||
let ast_map: ASTMap;
|
||||
let crate: @crate;
|
||||
|
||||
let atom_table: @AtomTable;
|
||||
|
||||
let graph_root: @NameBindings;
|
||||
|
||||
// The number of imports that are currently unresolved.
|
||||
let mut unresolved_imports: uint;
|
||||
|
||||
// The module that represents the current item scope.
|
||||
let mut current_module: @Module;
|
||||
|
||||
// The current set of local scopes, for values.
|
||||
// XXX: Reuse ribs to avoid allocation.
|
||||
|
||||
let value_ribs: @dvec<@Rib>;
|
||||
|
||||
// The current set of local scopes, for types.
|
||||
let type_ribs: @dvec<@Rib>;
|
||||
|
||||
// The atom for the keyword "self".
|
||||
let self_atom: Atom;
|
||||
|
||||
// The atoms for the primitive types.
|
||||
let primitive_type_table: @PrimitiveTypeTable;
|
||||
|
||||
// The four namespaces.
|
||||
let namespaces: ~[Namespace];
|
||||
|
||||
let def_map: DefMap;
|
||||
let impl_map: ImplMap;
|
||||
let export_map: ExportMap;
|
||||
|
||||
new(session: session, ast_map: ASTMap, crate: @crate) {
|
||||
self.session = session;
|
||||
self.ast_map = ast_map;
|
||||
self.crate = crate;
|
||||
|
||||
self.atom_table = @AtomTable();
|
||||
|
||||
// The outermost module has def ID 0; this is not reflected in the
|
||||
// AST.
|
||||
|
||||
self.graph_root = @NameBindings();
|
||||
(*self.graph_root).define_module(NoParentLink,
|
||||
some({ crate: 0, node: 0 }));
|
||||
|
||||
self.unresolved_imports = 0u;
|
||||
|
||||
self.current_module = (*self.graph_root).get_module();
|
||||
self.value_ribs = @dvec();
|
||||
self.type_ribs = @dvec();
|
||||
|
||||
self.self_atom = (*self.atom_table).intern(@"self");
|
||||
self.primitive_type_table = @PrimitiveTypeTable(self.atom_table);
|
||||
|
||||
self.namespaces = ~[ ModuleNS, TypeNS, ValueNS, ImplNS ];
|
||||
|
||||
self.def_map = int_hash();
|
||||
self.impl_map = int_hash();
|
||||
self.export_map = int_hash();
|
||||
}
|
||||
|
||||
#[doc="The main name resolution procedure."]
|
||||
fn resolve(this: @Resolver) {
|
||||
self.build_reduced_graph(this);
|
||||
self.resolve_imports();
|
||||
self.record_exports();
|
||||
self.build_impl_scopes();
|
||||
self.resolve_crate();
|
||||
}
|
||||
|
||||
//
|
||||
// Reduced graph building
|
||||
//
|
||||
// Here we build the "reduced graph": the graph of the module tree without
|
||||
// any imports resolved.
|
||||
//
|
||||
|
||||
#[doc="Constructs the reduced graph for the entire crate."]
|
||||
fn build_reduced_graph(this: @Resolver) {
|
||||
let initial_parent =
|
||||
ModuleReducedGraphParent((*self.graph_root).get_module());
|
||||
visit_crate(*self.crate, initial_parent, mk_vt(@{
|
||||
visit_item: |item, context, visitor|
|
||||
(*this).build_reduced_graph_for_item(item, context, visitor),
|
||||
|
||||
visit_foreign_item: |foreign_item, context, visitor|
|
||||
(*this).build_reduced_graph_for_foreign_item(foreign_item,
|
||||
context,
|
||||
visitor),
|
||||
|
||||
visit_view_item: |view_item, context, visitor|
|
||||
(*this).build_reduced_graph_for_view_item(view_item,
|
||||
context,
|
||||
visitor),
|
||||
|
||||
visit_block: |block, context, visitor|
|
||||
(*this).build_reduced_graph_for_block(block,
|
||||
context,
|
||||
visitor)
|
||||
|
||||
with *default_visitor()
|
||||
}));
|
||||
}
|
||||
|
||||
#[doc="Returns the current module tracked by the reduced graph parent."]
|
||||
fn get_module_from_parent(reduced_graph_parent: ReducedGraphParent)
|
||||
-> @Module {
|
||||
alt reduced_graph_parent {
|
||||
ModuleReducedGraphParent(module) {
|
||||
ret module;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc="
|
||||
Adds a new child item to the module definition of the parent node and
|
||||
returns its corresponding name bindings as well as the current parent.
|
||||
Or, if we're inside a block, creates (or reuses) an anonymous module
|
||||
corresponding to the innermost block ID and returns the name bindings
|
||||
as well as the newly-created parent.
|
||||
|
||||
If this node does not have a module definition and we are not inside
|
||||
a block, fails.
|
||||
"]
|
||||
fn add_child(name: Atom,
|
||||
reduced_graph_parent: ReducedGraphParent)
|
||||
-> (@NameBindings, ReducedGraphParent) {
|
||||
|
||||
// If this is the immediate descendant of a module, then we add the
|
||||
// child name directly. Otherwise, we create or reuse an anonymous
|
||||
// module and add the child to that.
|
||||
|
||||
let mut module;
|
||||
alt reduced_graph_parent {
|
||||
ModuleReducedGraphParent(parent_module) {
|
||||
module = parent_module;
|
||||
}
|
||||
}
|
||||
|
||||
// Add or reuse the child.
|
||||
let new_parent = ModuleReducedGraphParent(module);
|
||||
alt module.children.find(name) {
|
||||
none {
|
||||
let child = @NameBindings();
|
||||
module.children.insert(name, child);
|
||||
ret (child, new_parent);
|
||||
}
|
||||
some(child) {
|
||||
ret (child, new_parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn block_needs_anonymous_module(block: blk) -> bool {
|
||||
// If the block has view items, we need an anonymous module.
|
||||
if block.node.view_items.len() > 0u {
|
||||
ret true;
|
||||
}
|
||||
|
||||
// Check each statement.
|
||||
for block.node.stmts.each |statement| {
|
||||
alt statement.node {
|
||||
stmt_decl(declaration, _) {
|
||||
alt declaration.node {
|
||||
decl_item(_) {
|
||||
ret true;
|
||||
}
|
||||
_ {
|
||||
// Keep searching.
|
||||
}
|
||||
}
|
||||
}
|
||||
_ {
|
||||
// Keep searching.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we found neither view items nor items, we don't need to create
|
||||
// an anonymous module.
|
||||
|
||||
ret false;
|
||||
}
|
||||
|
||||
fn get_parent_link(parent: ReducedGraphParent, name: Atom) -> ParentLink {
|
||||
alt parent {
|
||||
ModuleReducedGraphParent(module) {
|
||||
ret ModuleParentLink(module, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc="Constructs the reduced graph for one item."]
|
||||
fn build_reduced_graph_for_item(item: @item,
|
||||
parent: ReducedGraphParent,
|
||||
&&visitor: vt<ReducedGraphParent>) {
|
||||
|
||||
let atom = (*self.atom_table).intern(item.ident);
|
||||
let (name_bindings, new_parent) = self.add_child(atom, parent);
|
||||
|
||||
alt item.node {
|
||||
item_mod(module) {
|
||||
let parent_link = self.get_parent_link(new_parent, atom);
|
||||
let def_id = { crate: 0, node: item.id };
|
||||
(*name_bindings).define_module(parent_link, some(def_id));
|
||||
|
||||
let new_parent =
|
||||
ModuleReducedGraphParent((*name_bindings).get_module());
|
||||
|
||||
visit_mod(module, item.span, item.id, new_parent, visitor);
|
||||
}
|
||||
item_foreign_mod(foreign_module) {
|
||||
let parent_link = self.get_parent_link(new_parent, atom);
|
||||
let def_id = { crate: 0, node: item.id };
|
||||
(*name_bindings).define_module(parent_link, some(def_id));
|
||||
|
||||
let new_parent =
|
||||
ModuleReducedGraphParent((*name_bindings).get_module());
|
||||
|
||||
visit_item(item, new_parent, visitor);
|
||||
}
|
||||
|
||||
// These items live in the value namespace.
|
||||
item_const(*) {
|
||||
(*name_bindings).define_value(def_const(local_def(item.id)));
|
||||
}
|
||||
item_fn(decl, _, _) {
|
||||
let def = def_fn(local_def(item.id), decl.purity);
|
||||
(*name_bindings).define_value(def);
|
||||
visit_item(item, new_parent, visitor);
|
||||
}
|
||||
|
||||
// These items live in the type namespace.
|
||||
item_ty(*) {
|
||||
(*name_bindings).define_type(def_ty(local_def(item.id)));
|
||||
}
|
||||
|
||||
// These items live in both the type and value namespaces.
|
||||
item_enum(variants, _, _) {
|
||||
(*name_bindings).define_type(def_ty(local_def(item.id)));
|
||||
|
||||
for variants.each |variant| {
|
||||
self.build_reduced_graph_for_variant(variant,
|
||||
local_def(item.id),
|
||||
new_parent,
|
||||
visitor);
|
||||
}
|
||||
}
|
||||
item_class(_, _, class_members, ctor, _, _) {
|
||||
(*name_bindings).define_type(def_ty(local_def(item.id)));
|
||||
|
||||
let purity = ctor.node.dec.purity;
|
||||
let ctor_def = def_fn(local_def(ctor.node.id), purity);
|
||||
(*name_bindings).define_value(ctor_def);
|
||||
|
||||
// Create the set of implementation information that the
|
||||
// implementation scopes (ImplScopes) need and write it into
|
||||
// the implementation definition list for this set of name
|
||||
// bindings.
|
||||
|
||||
let mut method_infos = ~[];
|
||||
for class_members.each |class_member| {
|
||||
alt class_member.node {
|
||||
class_method(method) {
|
||||
// XXX: Combine with impl method code below.
|
||||
method_infos += ~[
|
||||
@{
|
||||
did: local_def(method.id),
|
||||
n_tps: method.tps.len(),
|
||||
ident: method.ident
|
||||
}
|
||||
];
|
||||
}
|
||||
instance_var(*) {
|
||||
// Don't need to do anything with this.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let impl_info = @{
|
||||
did: local_def(item.id),
|
||||
ident: /* XXX: bad */ copy item.ident,
|
||||
methods: method_infos
|
||||
};
|
||||
|
||||
(*name_bindings).define_impl(impl_info);
|
||||
|
||||
visit_item(item, new_parent, visitor);
|
||||
}
|
||||
|
||||
item_impl(_, _, _, _, methods) {
|
||||
// Create the set of implementation information that the
|
||||
// implementation scopes (ImplScopes) need and write it into
|
||||
// the implementation definition list for this set of name
|
||||
// bindings.
|
||||
|
||||
let mut method_infos = ~[];
|
||||
for methods.each |method| {
|
||||
method_infos += ~[
|
||||
@{
|
||||
did: local_def(method.id),
|
||||
n_tps: method.tps.len(),
|
||||
ident: method.ident
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
let impl_info = @{
|
||||
did: local_def(item.id),
|
||||
ident: /* XXX: bad */ copy item.ident,
|
||||
methods: method_infos
|
||||
};
|
||||
|
||||
(*name_bindings).define_impl(impl_info);
|
||||
visit_item(item, new_parent, visitor);
|
||||
}
|
||||
|
||||
item_iface(*) {
|
||||
(*name_bindings).define_type(def_ty(local_def(item.id)));
|
||||
visit_item(item, new_parent, visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc="
|
||||
Constructs the reduced graph for one variant. Variants exist in the
|
||||
type namespace.
|
||||
"]
|
||||
fn build_reduced_graph_for_variant(variant: variant,
|
||||
item_id: def_id,
|
||||
parent: ReducedGraphParent,
|
||||
&&_visitor: vt<ReducedGraphParent>) {
|
||||
|
||||
let atom = (*self.atom_table).intern(variant.node.name);
|
||||
let (child, _) = self.add_child(atom, parent);
|
||||
|
||||
(*child).define_value(def_variant(item_id,
|
||||
local_def(variant.node.id)));
|
||||
}
|
||||
|
||||
#[doc="
|
||||
Constructs the reduced graph for one 'view item'. View items consist
|
||||
of imports and use directives.
|
||||
"]
|
||||
fn build_reduced_graph_for_view_item(view_item: @view_item,
|
||||
parent: ReducedGraphParent,
|
||||
&&_visitor: vt<ReducedGraphParent>) {
|
||||
alt view_item.node {
|
||||
view_item_import(view_paths) {
|
||||
for view_paths.each |view_path| {
|
||||
// Extract and intern the module part of the path. For
|
||||
// globs and lists, the path is found directly in the AST;
|
||||
// for simple paths we have to munge the path a little.
|
||||
|
||||
let module_path = @dvec();
|
||||
alt view_path.node {
|
||||
view_path_simple(_, full_path, _) {
|
||||
let path_len = full_path.idents.len();
|
||||
assert path_len != 0u;
|
||||
|
||||
for full_path.idents.eachi |i, ident| {
|
||||
if i != path_len - 1u {
|
||||
let atom =
|
||||
(*self.atom_table).intern(ident);
|
||||
(*module_path).push(atom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
view_path_glob(module_ident_path, _) |
|
||||
view_path_list(module_ident_path, _, _) {
|
||||
for module_ident_path.idents.each |ident| {
|
||||
let atom = (*self.atom_table).intern(ident);
|
||||
(*module_path).push(atom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build up the import directives.
|
||||
let module = self.get_module_from_parent(parent);
|
||||
alt view_path.node {
|
||||
view_path_simple(binding, full_path, _) {
|
||||
let target_atom =
|
||||
(*self.atom_table).intern(binding);
|
||||
let source_ident = full_path.idents.last();
|
||||
let source_atom =
|
||||
(*self.atom_table).intern(source_ident);
|
||||
let subclass = @SingleImport(target_atom,
|
||||
source_atom);
|
||||
self.build_import_directive(module,
|
||||
module_path,
|
||||
subclass);
|
||||
}
|
||||
view_path_list(_, source_idents, _) {
|
||||
for source_idents.each |source_ident| {
|
||||
let name = source_ident.node.name;
|
||||
let atom = (*self.atom_table).intern(name);
|
||||
let subclass = @SingleImport(atom, atom);
|
||||
self.build_import_directive(module,
|
||||
module_path,
|
||||
subclass);
|
||||
}
|
||||
}
|
||||
view_path_glob(_, _) {
|
||||
self.build_import_directive(module,
|
||||
module_path,
|
||||
@GlobImport);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
view_item_export(view_paths) {
|
||||
let module = self.get_module_from_parent(parent);
|
||||
for view_paths.each |view_path| {
|
||||
alt view_path.node {
|
||||
view_path_simple(ident, full_path, ident_id) {
|
||||
let last_ident = full_path.idents.last();
|
||||
if last_ident != ident {
|
||||
self.session.span_err(view_item.span,
|
||||
"cannot export under \
|
||||
a new name");
|
||||
}
|
||||
if full_path.idents.len() != 1u {
|
||||
self.session.span_err(view_item.span,
|
||||
"cannot export an item \
|
||||
that is not in this \
|
||||
module");
|
||||
}
|
||||
|
||||
let atom = (*self.atom_table).intern(ident);
|
||||
module.exported_names.insert(atom, ident_id);
|
||||
}
|
||||
|
||||
view_path_glob(*) {
|
||||
self.session.span_err(view_item.span,
|
||||
"export globs are \
|
||||
unsupported");
|
||||
}
|
||||
|
||||
view_path_list(path, path_list_idents, _) {
|
||||
if path.idents.len() == 1u &&
|
||||
path_list_idents.len() == 0u {
|
||||
|
||||
self.session.span_warn(view_item.span,
|
||||
"this syntax for \
|
||||
exporting no \
|
||||
variants is \
|
||||
unsupported; export \
|
||||
variants \
|
||||
individually");
|
||||
} else {
|
||||
if path.idents.len() != 0u {
|
||||
self.session.span_err(view_item.span,
|
||||
"cannot export an \
|
||||
item that is not \
|
||||
in this module");
|
||||
}
|
||||
|
||||
for path_list_idents.each |path_list_ident| {
|
||||
let atom = (*self.atom_table).intern
|
||||
(path_list_ident.node.name);
|
||||
let id = path_list_ident.node.id;
|
||||
module.exported_names.insert(atom, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
view_item_use(name, _, node_id) {
|
||||
alt find_use_stmt_cnum(self.session.cstore, node_id) {
|
||||
some(crate_id) {
|
||||
let atom = (*self.atom_table).intern(name);
|
||||
let (child_name_bindings, new_parent) =
|
||||
self.add_child(atom, parent);
|
||||
|
||||
let def_id = { crate: crate_id, node: 0 };
|
||||
let parent_link = ModuleParentLink
|
||||
(self.get_module_from_parent(new_parent), atom);
|
||||
|
||||
(*child_name_bindings).define_module(parent_link,
|
||||
some(def_id));
|
||||
self.build_reduced_graph_for_external_crate
|
||||
((*child_name_bindings).get_module());
|
||||
}
|
||||
none {
|
||||
/* Ignore. */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc="Constructs the reduced graph for one foreign item."]
|
||||
fn build_reduced_graph_for_foreign_item(foreign_item: @foreign_item,
|
||||
parent: ReducedGraphParent,
|
||||
&&visitor:
|
||||
vt<ReducedGraphParent>) {
|
||||
|
||||
let name = (*self.atom_table).intern(foreign_item.ident);
|
||||
let (name_bindings, new_parent) = self.add_child(name, parent);
|
||||
|
||||
alt foreign_item.node {
|
||||
foreign_item_fn(fn_decl, type_parameters) {
|
||||
let def = def_fn(local_def(foreign_item.id), impure_fn);
|
||||
(*name_bindings).define_value(def);
|
||||
|
||||
do self.with_type_parameter_rib
|
||||
(HasTypeParameters(&type_parameters,
|
||||
foreign_item.id,
|
||||
0u)) || {
|
||||
|
||||
visit_foreign_item(foreign_item, new_parent, visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn build_reduced_graph_for_block(block: blk,
|
||||
parent: ReducedGraphParent,
|
||||
&&visitor: vt<ReducedGraphParent>) {
|
||||
|
||||
let mut new_parent;
|
||||
if self.block_needs_anonymous_module(block) {
|
||||
let block_id = block.node.id;
|
||||
|
||||
#debug("(building reduced graph for block) creating a new \
|
||||
anonymous module for block %d",
|
||||
block_id);
|
||||
|
||||
let parent_module = self.get_module_from_parent(parent);
|
||||
let new_module = @Module(BlockParentLink(parent_module, block_id),
|
||||
none);
|
||||
parent_module.anonymous_children.insert(block_id, new_module);
|
||||
new_parent = ModuleReducedGraphParent(new_module);
|
||||
} else {
|
||||
new_parent = parent;
|
||||
}
|
||||
|
||||
visit_block(block, new_parent, visitor);
|
||||
}
|
||||
|
||||
#[doc="
|
||||
Builds the reduced graph rooted at the 'use' directive for an external
|
||||
crate.
|
||||
"]
|
||||
fn build_reduced_graph_for_external_crate(root: @Module) {
|
||||
// Create all the items reachable by paths.
|
||||
for each_path(self.session.cstore, get(root.def_id).crate)
|
||||
|path_entry| {
|
||||
|
||||
#debug("(building reduced graph for external crate) found path \
|
||||
entry: %s (%?)",
|
||||
path_entry.path_string,
|
||||
path_entry.def_like);
|
||||
|
||||
let mut pieces = split_str(path_entry.path_string, "::");
|
||||
let final_ident = pop(pieces);
|
||||
|
||||
// Find the module we need, creating modules along the way if we
|
||||
// need to.
|
||||
|
||||
let mut current_module = root;
|
||||
for pieces.each |ident| {
|
||||
// Create or reuse a graph node for the child.
|
||||
let atom = (*self.atom_table).intern(@copy ident);
|
||||
let (child_name_bindings, new_parent) =
|
||||
self.add_child(atom,
|
||||
ModuleReducedGraphParent(current_module));
|
||||
|
||||
// Define or reuse the module node.
|
||||
alt child_name_bindings.module_def {
|
||||
NoModuleDef {
|
||||
#debug("(building reduced graph for external crate) \
|
||||
autovivifying %s", ident);
|
||||
let parent_link = self.get_parent_link(new_parent,
|
||||
atom);
|
||||
(*child_name_bindings).define_module(parent_link,
|
||||
none);
|
||||
}
|
||||
ModuleDef(_) { /* Fall through. */ }
|
||||
}
|
||||
|
||||
current_module = (*child_name_bindings).get_module();
|
||||
}
|
||||
|
||||
// Add the new child item.
|
||||
let atom = (*self.atom_table).intern(@copy final_ident);
|
||||
let (child_name_bindings, new_parent) =
|
||||
self.add_child(atom,
|
||||
ModuleReducedGraphParent(current_module));
|
||||
|
||||
alt path_entry.def_like {
|
||||
dl_def(def) {
|
||||
alt def {
|
||||
def_mod(def_id) | def_foreign_mod(def_id) {
|
||||
alt copy child_name_bindings.module_def {
|
||||
NoModuleDef {
|
||||
#debug("(building reduced graph for \
|
||||
external crate) building module \
|
||||
%s", final_ident);
|
||||
let parent_link =
|
||||
self.get_parent_link(new_parent,
|
||||
atom);
|
||||
(*child_name_bindings).
|
||||
define_module(parent_link,
|
||||
some(def_id));
|
||||
}
|
||||
ModuleDef(module) {
|
||||
#debug("(building reduced graph for \
|
||||
external crate) already created \
|
||||
module");
|
||||
module.def_id = some(def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
def_fn(def_id, _) | def_const(def_id) |
|
||||
def_variant(_, def_id) {
|
||||
#debug("(building reduced graph for external \
|
||||
crate) building value %s", final_ident);
|
||||
(*child_name_bindings).define_value(def);
|
||||
}
|
||||
def_ty(def_id) {
|
||||
#debug("(building reduced graph for external \
|
||||
crate) building type %s", final_ident);
|
||||
(*child_name_bindings).define_type(def);
|
||||
}
|
||||
def_class(def_id) {
|
||||
#debug("(building reduced graph for external \
|
||||
crate) building value and type %s",
|
||||
final_ident);
|
||||
(*child_name_bindings).define_value(def);
|
||||
(*child_name_bindings).define_type(def);
|
||||
}
|
||||
def_self(*) | def_arg(*) | def_local(*) |
|
||||
def_prim_ty(*) | def_ty_param(*) | def_binding(*) |
|
||||
def_use(*) | def_upvar(*) | def_region(*) {
|
||||
fail #fmt("didn't expect %?", def);
|
||||
}
|
||||
}
|
||||
}
|
||||
dl_impl(_) {
|
||||
// Because of the infelicitous way the metadata is
|
||||
// written, we can't process this impl now. We'll get it
|
||||
// later.
|
||||
|
||||
#debug("(building reduced graph for external crate) \
|
||||
ignoring impl %s", final_ident);
|
||||
}
|
||||
dl_field {
|
||||
#debug("(building reduced graph for external crate) \
|
||||
ignoring field %s", final_ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create nodes for all the impls.
|
||||
self.build_reduced_graph_for_impls_in_external_module_subtree(root);
|
||||
}
|
||||
|
||||
fn build_reduced_graph_for_impls_in_external_module_subtree(module:
|
||||
@Module) {
|
||||
self.build_reduced_graph_for_impls_in_external_module(module);
|
||||
|
||||
for module.children.each |_name, child_node| {
|
||||
alt (*child_node).get_module_if_available() {
|
||||
none {
|
||||
// Nothing to do.
|
||||
}
|
||||
some(child_module) {
|
||||
self.
|
||||
build_reduced_graph_for_impls_in_external_module_subtree
|
||||
(child_module);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn build_reduced_graph_for_impls_in_external_module(module: @Module) {
|
||||
// XXX: This is really unfortunate. decoder::each_path can produce
|
||||
// false positives, since, in the crate metadata, an iface named 'bar'
|
||||
// in module 'foo' defining a method named 'baz' will result in the
|
||||
// creation of a (bogus) path entry named 'foo::bar::baz', and we will
|
||||
// create a module node for "bar". We can identify these fake modules
|
||||
// by the fact that they have no def ID, which we do here in order to
|
||||
// skip them.
|
||||
|
||||
#debug("(building reduced graph for impls in external crate) looking \
|
||||
for impls in '%s' (%?)",
|
||||
self.module_to_str(module),
|
||||
copy module.def_id);
|
||||
|
||||
alt module.def_id {
|
||||
none {
|
||||
#debug("(building reduced graph for impls in external \
|
||||
module) no def ID for '%s', skipping",
|
||||
self.module_to_str(module));
|
||||
ret;
|
||||
}
|
||||
some(_) {
|
||||
// Continue.
|
||||
}
|
||||
}
|
||||
|
||||
let impls_in_module = get_impls_for_mod(self.session.cstore,
|
||||
get(module.def_id),
|
||||
none);
|
||||
|
||||
// Intern def IDs to prevent duplicates.
|
||||
let def_ids = new_def_hash();
|
||||
|
||||
for (*impls_in_module).each |implementation| {
|
||||
if def_ids.contains_key(implementation.did) {
|
||||
cont;
|
||||
}
|
||||
def_ids.insert(implementation.did, ());
|
||||
|
||||
#debug("(building reduced graph for impls in external module) \
|
||||
added impl '%s' (%?) to '%s'",
|
||||
*implementation.ident,
|
||||
implementation.did,
|
||||
self.module_to_str(module));
|
||||
|
||||
let name = (*self.atom_table).intern(implementation.ident);
|
||||
|
||||
let (name_bindings, _) =
|
||||
self.add_child(name, ModuleReducedGraphParent(module));
|
||||
|
||||
name_bindings.impl_defs += ~[implementation];
|
||||
}
|
||||
}
|
||||
|
||||
#[doc="Creates and adds an import directive to the given module."]
|
||||
fn build_import_directive(module: @Module,
|
||||
module_path: @dvec<Atom>,
|
||||
subclass: @ImportDirectiveSubclass) {
|
||||
|
||||
let directive = @ImportDirective(module_path, subclass);
|
||||
module.imports.push(directive);
|
||||
|
||||
// Bump the reference count on the name. Or, if this is a glob, set
|
||||
// the appropriate flag.
|
||||
|
||||
alt *subclass {
|
||||
SingleImport(target, _) {
|
||||
alt module.import_resolutions.find(target) {
|
||||
some(resolution) {
|
||||
resolution.outstanding_references += 1u;
|
||||
}
|
||||
none {
|
||||
let resolution = @ImportResolution();
|
||||
resolution.outstanding_references = 1u;
|
||||
module.import_resolutions.insert(target, resolution);
|
||||
}
|
||||
}
|
||||
}
|
||||
GlobImport {
|
||||
// Set the glob flag. This tells us that we don't know the
|
||||
// module's exports ahead of time.
|
||||
|
||||
module.glob_count += 1u;
|
||||
}
|
||||
}
|
||||
|
||||
self.unresolved_imports += 1u;
|
||||
}
|
||||
|
||||
// Import resolution
|
||||
//
|
||||
// This is a fixed-point algorithm. We resolve imports until our efforts
|
||||
// are stymied by an unresolved import; then we bail out of the current
|
||||
// module and continue. We terminate successfully once no more imports
|
||||
// remain or unsuccessfully when no forward progress in resolving imports
|
||||
// is made.
|
||||
|
||||
#[doc="
|
||||
Resolves all imports for the crate. This method performs the fixed-
|
||||
point iteration.
|
||||
"]
|
||||
fn resolve_imports() {
|
||||
let mut i = 0u;
|
||||
let mut prev_unresolved_imports = 0u;
|
||||
loop {
|
||||
#debug("(resolving imports) iteration %u, %u imports left",
|
||||
i, self.unresolved_imports);
|
||||
|
||||
let module_root = (*self.graph_root).get_module();
|
||||
self.resolve_imports_for_module_subtree(module_root);
|
||||
|
||||
if self.unresolved_imports == 0u {
|
||||
#debug("(resolving imports) success");
|
||||
break;
|
||||
}
|
||||
|
||||
if self.unresolved_imports == prev_unresolved_imports {
|
||||
self.session.err("failed to resolve imports");
|
||||
self.report_unresolved_imports(module_root);
|
||||
break;
|
||||
}
|
||||
|
||||
i += 1u;
|
||||
prev_unresolved_imports = self.unresolved_imports;
|
||||
}
|
||||
}
|
||||
|
||||
#[doc="
|
||||
Attempts to resolve imports for the given module and all of its
|
||||
submodules.
|
||||
"]
|
||||
fn resolve_imports_for_module_subtree(module: @Module) {
|
||||
#debug("(resolving imports for module subtree) resolving %s",
|
||||
self.module_to_str(module));
|
||||
self.resolve_imports_for_module(module);
|
||||
|
||||
for module.children.each |_name, child_node| {
|
||||
alt (*child_node).get_module_if_available() {
|
||||
none {
|
||||
// Nothing to do.
|
||||
}
|
||||
some(child_module) {
|
||||
self.resolve_imports_for_module_subtree(child_module);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for module.anonymous_children.each |_block_id, child_module| {
|
||||
self.resolve_imports_for_module_subtree(child_module);
|
||||
}
|
||||
}
|
||||
|
||||
#[doc="Attempts to resolve imports for the given module only."]
|
||||
fn resolve_imports_for_module(module: @Module) {
|
||||
if (*module).all_imports_resolved() {
|
||||
#debug("(resolving imports for module) all imports resolved for \
|
||||
%s",
|
||||
self.module_to_str(module));
|
||||
ret;
|
||||
}
|
||||
|
||||
let import_count = module.imports.len();
|
||||
while module.resolved_import_count < import_count {
|
||||
let import_index = module.resolved_import_count;
|
||||
let import_directive = module.imports.get_elt(import_index);
|
||||
alt self.resolve_import_for_module(module, import_directive) {
|
||||
Failed {
|
||||
// We presumably emitted an error. Continue.
|
||||
// XXX: span_err
|
||||
self.session.err(#fmt("failed to resolve import in: %s",
|
||||
self.module_to_str(module)));
|
||||
}
|
||||
Indeterminate {
|
||||
// Bail out. We'll come around next time.
|
||||
break;
|
||||
}
|
||||
Success(()) {
|
||||
// Good. Continue.
|
||||
}
|
||||
}
|
||||
|
||||
module.resolved_import_count += 1u;
|
||||
}
|
||||
}
|
||||
|
||||
#[doc="
|
||||
Attempts to resolve the given import. The return value indicates
|
||||
failure if we're certain the name does not exist, indeterminate if we
|
||||
don't know whether the name exists at the moment due to other
|
||||
currently-unresolved imports, or success if we know the name exists.
|
||||
If successful, the resolved bindings are written into the module.
|
||||
"]
|
||||
fn resolve_import_for_module(module: @Module,
|
||||
import_directive: @ImportDirective)
|
||||
-> ResolveResult<()> {
|
||||
|
||||
let mut resolution_result;
|
||||
let module_path = import_directive.module_path;
|
||||
|
||||
#debug("(resolving import for module) resolving import '%s::...' in \
|
||||
'%s'",
|
||||
*(*self.atom_table).atoms_to_str((*module_path).get()),
|
||||
self.module_to_str(module));
|
||||
|
||||
// One-level renaming imports of the form `import foo = bar;` are
|
||||
// handled specially.
|
||||
|
||||
if (*module_path).len() == 0u {
|
||||
resolution_result =
|
||||
self.resolve_one_level_renaming_import(module,
|
||||
import_directive);
|
||||
} else {
|
||||
// First, resolve the module path for the directive, if necessary.
|
||||
alt self.resolve_module_path_for_import(module, module_path) {
|
||||
Failed {
|
||||
resolution_result = Failed;
|
||||
}
|
||||
Indeterminate {
|
||||
resolution_result = Indeterminate;
|
||||
}
|
||||
Success(containing_module) {
|
||||
// We found the module that the target is contained
|
||||
// within. Attempt to resolve the import within it.
|
||||
|
||||
alt *import_directive.subclass {
|
||||
SingleImport(target, source) {
|
||||
resolution_result =
|
||||
self.resolve_single_import(module,
|
||||
containing_module,
|
||||
target,
|
||||
source);
|
||||
}
|
||||
GlobImport {
|
||||
resolution_result =
|
||||
self.resolve_glob_import(module,
|
||||
containing_module);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Decrement the count of unresolved imports.
|
||||
alt resolution_result {
|
||||
Success(()) {
|
||||
assert self.unresolved_imports >= 1u;
|
||||
self.unresolved_imports -= 1u;
|
||||
}
|
||||
_ {
|
||||
// Nothing to do here; just return the error.
|
||||
}
|
||||
}
|
||||
|
||||
// Decrement the count of unresolved globs if necessary. But only if
|
||||
// the resolution result is indeterminate -- otherwise we'll stop
|
||||
// processing imports here. (See the loop in
|
||||
// resolve_imports_for_module.)
|
||||
|
||||
if resolution_result != Indeterminate {
|
||||
alt *import_directive.subclass {
|
||||
GlobImport {
|
||||
assert module.glob_count >= 1u;
|
||||
module.glob_count -= 1u;
|
||||
}
|
||||
SingleImport(*) {
|
||||
// Ignore.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret resolution_result;
|
||||
}
|
||||
|
||||
fn resolve_single_import(module: @Module, containing_module: @Module,
|
||||
target: Atom, source: Atom)
|
||||
-> ResolveResult<()> {
|
||||
|
||||
#debug("(resolving single import) resolving '%s' = '%s::%s' from \
|
||||
'%s'",
|
||||
*(*self.atom_table).atom_to_str(target),
|
||||
self.module_to_str(containing_module),
|
||||
*(*self.atom_table).atom_to_str(source),
|
||||
self.module_to_str(module));
|
||||
|
||||
if !self.name_is_exported(containing_module, source) {
|
||||
#debug("(resolving single import) name '%s' is unexported",
|
||||
*(*self.atom_table).atom_to_str(source));
|
||||
ret Failed;
|
||||
}
|
||||
|
||||
// We need to resolve all four namespaces for this to succeed.
|
||||
//
|
||||
// XXX: See if there's some way of handling namespaces in a more
|
||||
// generic way. We have four of them; it seems worth doing...
|
||||
|
||||
let mut module_result = UnknownResult;
|
||||
let mut value_result = UnknownResult;
|
||||
let mut type_result = UnknownResult;
|
||||
let mut impl_result = UnknownImplResult;
|
||||
|
||||
// Search for direct children of the containing module.
|
||||
alt containing_module.children.find(source) {
|
||||
none {
|
||||
// Continue.
|
||||
}
|
||||
some(child_name_bindings) {
|
||||
if (*child_name_bindings).defined_in_namespace(ModuleNS) {
|
||||
module_result = BoundResult(containing_module,
|
||||
child_name_bindings);
|
||||
}
|
||||
if (*child_name_bindings).defined_in_namespace(ValueNS) {
|
||||
value_result = BoundResult(containing_module,
|
||||
child_name_bindings);
|
||||
}
|
||||
if (*child_name_bindings).defined_in_namespace(TypeNS) {
|
||||
type_result = BoundResult(containing_module,
|
||||
child_name_bindings);
|
||||
}
|
||||
if (*child_name_bindings).defined_in_namespace(ImplNS) {
|
||||
let targets = @dvec();
|
||||
(*targets).push(@Target(containing_module,
|
||||
child_name_bindings));
|
||||
impl_result = BoundImplResult(targets);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unless we managed to find a result in all four namespaces
|
||||
// (exceedingly unlikely), search imports as well.
|
||||
|
||||
alt (module_result, value_result, type_result, impl_result) {
|
||||
(BoundResult(*), BoundResult(*), BoundResult(*),
|
||||
BoundImplResult(*)) {
|
||||
// Continue.
|
||||
}
|
||||
_ {
|
||||
// If there is an unresolved glob at this point in the
|
||||
// containing module, bail out. We don't know enough to be
|
||||
// able to resolve this import.
|
||||
|
||||
if containing_module.glob_count > 0u {
|
||||
#debug("(resolving single import) unresolved glob; \
|
||||
bailing out");
|
||||
ret Indeterminate;
|
||||
}
|
||||
|
||||
// Now search the exported imports within the containing
|
||||
// module.
|
||||
|
||||
alt containing_module.import_resolutions.find(source) {
|
||||
none {
|
||||
// The containing module definitely doesn't have an
|
||||
// exported import with the name in question. We can
|
||||
// therefore accurately report that the names are
|
||||
// unbound.
|
||||
|
||||
if module_result == UnknownResult {
|
||||
module_result = UnboundResult;
|
||||
}
|
||||
if value_result == UnknownResult {
|
||||
value_result = UnboundResult;
|
||||
}
|
||||
if type_result == UnknownResult {
|
||||
type_result = UnboundResult;
|
||||
}
|
||||
if impl_result == UnknownImplResult {
|
||||
impl_result = UnboundImplResult;
|
||||
}
|
||||
}
|
||||
some(import_resolution)
|
||||
if import_resolution.outstanding_references
|
||||
== 0u {
|
||||
fn get_binding(import_resolution: @ImportResolution,
|
||||
namespace: Namespace)
|
||||
-> NamespaceResult {
|
||||
|
||||
alt (*import_resolution).
|
||||
target_for_namespace(namespace) {
|
||||
none {
|
||||
ret UnboundResult;
|
||||
}
|
||||
some(target) {
|
||||
ret BoundResult(target.target_module,
|
||||
target.bindings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_import_binding(import_resolution:
|
||||
@ImportResolution)
|
||||
-> ImplNamespaceResult {
|
||||
|
||||
if (*import_resolution.impl_target).len() == 0u {
|
||||
ret UnboundImplResult;
|
||||
}
|
||||
ret BoundImplResult(import_resolution.
|
||||
impl_target);
|
||||
}
|
||||
|
||||
|
||||
// The name is an import which has been fully
|
||||
// resolved. We can, therefore, just follow it.
|
||||
|
||||
if module_result == UnknownResult {
|
||||
module_result = get_binding(import_resolution,
|
||||
ModuleNS);
|
||||
}
|
||||
if value_result == UnknownResult {
|
||||
value_result = get_binding(import_resolution,
|
||||
ValueNS);
|
||||
}
|
||||
if type_result == UnknownResult {
|
||||
type_result = get_binding(import_resolution,
|
||||
TypeNS);
|
||||
}
|
||||
if impl_result == UnknownImplResult {
|
||||
impl_result =
|
||||
get_import_binding(import_resolution);
|
||||
}
|
||||
}
|
||||
some(_) {
|
||||
// The import is unresolved. Bail out.
|
||||
#debug("(resolving single import) unresolved import; \
|
||||
bailing out");
|
||||
ret Indeterminate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We've successfully resolved the import. Write the results in.
|
||||
assert module.import_resolutions.contains_key(target);
|
||||
let import_resolution = module.import_resolutions.get(target);
|
||||
|
||||
alt module_result {
|
||||
BoundResult(target_module, name_bindings) {
|
||||
#debug("(resolving single import) found module binding");
|
||||
import_resolution.module_target =
|
||||
some(Target(target_module, name_bindings));
|
||||
}
|
||||
UnboundResult {
|
||||
#debug("(resolving single import) didn't find module \
|
||||
binding");
|
||||
}
|
||||
UnknownResult {
|
||||
fail "module result should be known at this point";
|
||||
}
|
||||
}
|
||||
alt value_result {
|
||||
BoundResult(target_module, name_bindings) {
|
||||
import_resolution.value_target =
|
||||
some(Target(target_module, name_bindings));
|
||||
}
|
||||
UnboundResult { /* Continue. */ }
|
||||
UnknownResult {
|
||||
fail "value result should be known at this point";
|
||||
}
|
||||
}
|
||||
alt type_result {
|
||||
BoundResult(target_module, name_bindings) {
|
||||
import_resolution.type_target =
|
||||
some(Target(target_module, name_bindings));
|
||||
}
|
||||
UnboundResult { /* Continue. */ }
|
||||
UnknownResult {
|
||||
fail "type result should be known at this point";
|
||||
}
|
||||
}
|
||||
alt impl_result {
|
||||
BoundImplResult(targets) {
|
||||
for (*targets).each |target| {
|
||||
(*import_resolution.impl_target).push(target);
|
||||
}
|
||||
}
|
||||
UnboundImplResult { /* Continue. */ }
|
||||
UnknownImplResult {
|
||||
fail "impl result should be known at this point";
|
||||
}
|
||||
}
|
||||
|
||||
assert import_resolution.outstanding_references >= 1u;
|
||||
import_resolution.outstanding_references -= 1u;
|
||||
|
||||
#debug("(resolving single import) successfully resolved import");
|
||||
ret Success(());
|
||||
}
|
||||
|
||||
#[doc="
|
||||
Resolves a glob import. Note that this function cannot fail; it either
|
||||
succeeds or bails out (as importing * from an empty module or a module
|
||||
that exports nothing is valid).
|
||||
"]
|
||||
fn resolve_glob_import(module: @Module, containing_module: @Module)
|
||||
-> ResolveResult<()> {
|
||||
|
||||
// This function works in a highly imperative manner; it eagerly adds
|
||||
// everything it can to the list of import resolutions of the module
|
||||
// node.
|
||||
|
||||
// We must bail out if the node has unresolved imports of any kind
|
||||
// (including globs).
|
||||
|
||||
if !(*containing_module).all_imports_resolved() {
|
||||
#debug("(resolving glob import) target module has unresolved \
|
||||
imports; bailing out");
|
||||
ret Indeterminate;
|
||||
}
|
||||
|
||||
assert containing_module.glob_count == 0u;
|
||||
|
||||
// Add all resolved imports from the containing module.
|
||||
for containing_module.import_resolutions.each
|
||||
|atom, target_import_resolution| {
|
||||
|
||||
if !self.name_is_exported(containing_module, atom) {
|
||||
#debug("(resolving glob import) name '%s' is unexported",
|
||||
*(*self.atom_table).atom_to_str(atom));
|
||||
cont;
|
||||
}
|
||||
|
||||
#debug("(resolving glob import) writing module resolution \
|
||||
%? into '%s'",
|
||||
is_none(target_import_resolution.module_target),
|
||||
self.module_to_str(module));
|
||||
|
||||
// Here we merge two import resolutions.
|
||||
alt module.import_resolutions.find(atom) {
|
||||
none {
|
||||
// Simple: just copy the old import resolution.
|
||||
let new_import_resolution = @ImportResolution();
|
||||
new_import_resolution.module_target =
|
||||
copy target_import_resolution.module_target;
|
||||
new_import_resolution.value_target =
|
||||
copy target_import_resolution.value_target;
|
||||
new_import_resolution.type_target =
|
||||
copy target_import_resolution.type_target;
|
||||
new_import_resolution.impl_target =
|
||||
copy target_import_resolution.impl_target;
|
||||
|
||||
module.import_resolutions.insert
|
||||
(atom, new_import_resolution);
|
||||
}
|
||||
some(dest_import_resolution) {
|
||||
// Merge the two import resolutions at a finer-grained
|
||||
// level.
|
||||
|
||||
alt copy target_import_resolution.module_target {
|
||||
none {
|
||||
// Continue.
|
||||
}
|
||||
some(module_target) {
|
||||
dest_import_resolution.module_target =
|
||||
some(copy module_target);
|
||||
}
|
||||
}
|
||||
alt copy target_import_resolution.value_target {
|
||||
none {
|
||||
// Continue.
|
||||
}
|
||||
some(value_target) {
|
||||
dest_import_resolution.value_target =
|
||||
some(copy value_target);
|
||||
}
|
||||
}
|
||||
alt copy target_import_resolution.type_target {
|
||||
none {
|
||||
// Continue.
|
||||
}
|
||||
some(type_target) {
|
||||
dest_import_resolution.type_target =
|
||||
some(copy type_target);
|
||||
}
|
||||
}
|
||||
if (*target_import_resolution.impl_target).len() > 0u &&
|
||||
!ptr_eq(target_import_resolution.impl_target,
|
||||
dest_import_resolution.impl_target) {
|
||||
for (*target_import_resolution.impl_target).each
|
||||
|impl_target| {
|
||||
|
||||
(*dest_import_resolution.impl_target).
|
||||
push(impl_target);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add all children from the containing module.
|
||||
for containing_module.children.each |atom, name_bindings| {
|
||||
|
||||
let mut dest_import_resolution;
|
||||
alt module.import_resolutions.find(atom) {
|
||||
none {
|
||||
// Create a new import resolution from this child.
|
||||
dest_import_resolution = @ImportResolution();
|
||||
module.import_resolutions.insert
|
||||
(atom, dest_import_resolution);
|
||||
}
|
||||
some(existing_import_resolution) {
|
||||
dest_import_resolution = existing_import_resolution;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#debug("(resolving glob import) writing resolution '%s' in '%s' \
|
||||
to '%s'",
|
||||
*(*self.atom_table).atom_to_str(atom),
|
||||
self.module_to_str(containing_module),
|
||||
self.module_to_str(module));
|
||||
|
||||
// Merge the child item into the import resolution.
|
||||
if (*name_bindings).defined_in_namespace(ModuleNS) {
|
||||
#debug("(resolving glob import) ... for module target");
|
||||
dest_import_resolution.module_target =
|
||||
some(Target(containing_module, name_bindings));
|
||||
}
|
||||
if (*name_bindings).defined_in_namespace(ValueNS) {
|
||||
#debug("(resolving glob import) ... for value target");
|
||||
dest_import_resolution.value_target =
|
||||
some(Target(containing_module, name_bindings));
|
||||
}
|
||||
if (*name_bindings).defined_in_namespace(TypeNS) {
|
||||
#debug("(resolving glob import) ... for type target");
|
||||
dest_import_resolution.type_target =
|
||||
some(Target(containing_module, name_bindings));
|
||||
}
|
||||
if (*name_bindings).defined_in_namespace(ImplNS) {
|
||||
#debug("(resolving glob import) ... for impl target");
|
||||
(*dest_import_resolution.impl_target).push
|
||||
(@Target(containing_module, name_bindings));
|
||||
}
|
||||
}
|
||||
|
||||
#debug("(resolving glob import) successfully resolved import");
|
||||
ret Success(());
|
||||
}
|
||||
|
||||
fn resolve_module_path_from_root(module: @Module,
|
||||
module_path: @dvec<Atom>,
|
||||
index: uint)
|
||||
-> ResolveResult<@Module> {
|
||||
let mut search_module = module;
|
||||
let mut index = index;
|
||||
let module_path_len = (*module_path).len();
|
||||
|
||||
// Resolve the module part of the path. This does not involve looking
|
||||
// upward though scope chains; we simply resolve names directly in
|
||||
// modules as we go.
|
||||
|
||||
while index < module_path_len {
|
||||
let name = (*module_path).get_elt(index);
|
||||
alt self.resolve_name_in_module(search_module, name, ModuleNS,
|
||||
PublicOnly) {
|
||||
|
||||
Failed {
|
||||
// XXX: span_err
|
||||
self.session.err(#fmt("module resolution failed: %s",
|
||||
*(*self.atom_table)
|
||||
.atom_to_str(name)));
|
||||
ret Failed;
|
||||
}
|
||||
Indeterminate {
|
||||
#debug("(resolving module path for import) module \
|
||||
resolution is indeterminate: %s",
|
||||
*(*self.atom_table).atom_to_str(name));
|
||||
ret Indeterminate;
|
||||
}
|
||||
Success(target) {
|
||||
alt target.bindings.module_def {
|
||||
NoModuleDef {
|
||||
// Not a module.
|
||||
// XXX: span_err
|
||||
self.session.err(#fmt("not a module: %s",
|
||||
*(*self.atom_table).
|
||||
atom_to_str(name)));
|
||||
ret Failed;
|
||||
}
|
||||
ModuleDef(module) {
|
||||
search_module = module;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
index += 1u;
|
||||
}
|
||||
|
||||
ret Success(search_module);
|
||||
}
|
||||
|
||||
#[doc="
|
||||
Attempts to resolve the module part of an import directive rooted at
|
||||
the given module.
|
||||
"]
|
||||
fn resolve_module_path_for_import(module: @Module,
|
||||
module_path: @dvec<Atom>)
|
||||
-> ResolveResult<@Module> {
|
||||
|
||||
let module_path_len = (*module_path).len();
|
||||
assert module_path_len > 0u;
|
||||
|
||||
#debug("(resolving module path for import) processing '%s' rooted at \
|
||||
'%s'",
|
||||
*(*self.atom_table).atoms_to_str((*module_path).get()),
|
||||
self.module_to_str(module));
|
||||
|
||||
// The first element of the module path must be in the current scope
|
||||
// chain.
|
||||
|
||||
let first_element = (*module_path).get_elt(0u);
|
||||
let mut search_module;
|
||||
alt self.resolve_module_in_lexical_scope(module, first_element) {
|
||||
Failed {
|
||||
// XXX: span_err
|
||||
self.session.err(#fmt("unresolved name: %s",
|
||||
*(*self.atom_table).
|
||||
atom_to_str(first_element)));
|
||||
ret Failed;
|
||||
}
|
||||
Indeterminate {
|
||||
#debug("(resolving module path for import) indeterminate; \
|
||||
bailing");
|
||||
ret Indeterminate;
|
||||
}
|
||||
Success(resulting_module) {
|
||||
search_module = resulting_module;
|
||||
}
|
||||
}
|
||||
|
||||
ret self.resolve_module_path_from_root(search_module,
|
||||
module_path,
|
||||
1u);
|
||||
}
|
||||
|
||||
fn resolve_item_in_lexical_scope(module: @Module,
|
||||
name: Atom,
|
||||
namespace: Namespace)
|
||||
-> ResolveResult<Target> {
|
||||
|
||||
#debug("(resolving item in lexical scope) resolving '%s' in \
|
||||
namespace %? in '%s'",
|
||||
*(*self.atom_table).atom_to_str(name),
|
||||
namespace,
|
||||
self.module_to_str(module));
|
||||
|
||||
// The current module node is handled specially. First, check for
|
||||
// its immediate children.
|
||||
|
||||
alt module.children.find(name) {
|
||||
some(name_bindings)
|
||||
if (*name_bindings).defined_in_namespace(namespace) {
|
||||
|
||||
ret Success(Target(module, name_bindings));
|
||||
}
|
||||
some(_) | none { /* Not found; continue. */ }
|
||||
}
|
||||
|
||||
// Now check for its import directives. We don't have to have resolved
|
||||
// all its imports in the usual way; this is because chains of
|
||||
// adjacent import statements are processed as though they mutated the
|
||||
// current scope.
|
||||
|
||||
alt module.import_resolutions.find(name) {
|
||||
none {
|
||||
// Not found; continue.
|
||||
}
|
||||
some(import_resolution) {
|
||||
alt (*import_resolution).target_for_namespace(namespace) {
|
||||
none {
|
||||
// Not found; continue.
|
||||
#debug("(resolving item in lexical scope) found \
|
||||
import resolution, but not in namespace %?",
|
||||
namespace);
|
||||
}
|
||||
some(target) {
|
||||
ret Success(copy target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, proceed up the scope chain looking for parent modules.
|
||||
let mut search_module = module;
|
||||
loop {
|
||||
// Go to the next parent.
|
||||
alt search_module.parent_link {
|
||||
NoParentLink {
|
||||
// No more parents. This module was unresolved.
|
||||
#debug("(resolving item in lexical scope) unresolved \
|
||||
module");
|
||||
ret Failed;
|
||||
}
|
||||
ModuleParentLink(parent_module_node, _) |
|
||||
BlockParentLink(parent_module_node, _) {
|
||||
search_module = parent_module_node;
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve the name in the parent module.
|
||||
alt self.resolve_name_in_module(search_module, name, namespace,
|
||||
PrivateOrPublic) {
|
||||
Failed {
|
||||
// Continue up the search chain.
|
||||
}
|
||||
Indeterminate {
|
||||
// We couldn't see through the higher scope because of an
|
||||
// unresolved import higher up. Bail.
|
||||
|
||||
#debug("(resolving item in lexical scope) indeterminate \
|
||||
higher scope; bailing");
|
||||
ret Indeterminate;
|
||||
}
|
||||
Success(target) {
|
||||
// We found the module.
|
||||
ret Success(copy target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_module_in_lexical_scope(module: @Module, name: Atom)
|
||||
-> ResolveResult<@Module> {
|
||||
|
||||
alt self.resolve_item_in_lexical_scope(module, name, ModuleNS) {
|
||||
Success(target) {
|
||||
alt target.bindings.module_def {
|
||||
NoModuleDef {
|
||||
#error("!!! (resolving module in lexical scope) module
|
||||
wasn't actually a module!");
|
||||
ret Failed;
|
||||
}
|
||||
ModuleDef(module) {
|
||||
ret Success(module);
|
||||
}
|
||||
}
|
||||
}
|
||||
Indeterminate {
|
||||
#debug("(resolving module in lexical scope) indeterminate; \
|
||||
bailing");
|
||||
ret Indeterminate;
|
||||
}
|
||||
Failed {
|
||||
#debug("(resolving module in lexical scope) failed to \
|
||||
resolve");
|
||||
ret Failed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn name_is_exported(module: @Module, name: Atom) -> bool {
|
||||
ret module.exported_names.size() == 0u ||
|
||||
module.exported_names.contains_key(name);
|
||||
}
|
||||
|
||||
#[doc="
|
||||
Attempts to resolve the supplied name in the given module for the
|
||||
given namespace. If successful, returns the target corresponding to
|
||||
the name.
|
||||
"]
|
||||
fn resolve_name_in_module(module: @Module,
|
||||
name: Atom,
|
||||
namespace: Namespace,
|
||||
privacy_filter: PrivacyFilter)
|
||||
-> ResolveResult<Target> {
|
||||
|
||||
#debug("(resolving name in module) resolving '%s' in '%s'",
|
||||
*(*self.atom_table).atom_to_str(name),
|
||||
self.module_to_str(module));
|
||||
|
||||
if privacy_filter == PublicOnly &&
|
||||
!self.name_is_exported(module, name) {
|
||||
|
||||
#debug("(resolving name in module) name '%s' is unexported",
|
||||
*(*self.atom_table).atom_to_str(name));
|
||||
ret Failed;
|
||||
}
|
||||
|
||||
// First, check the direct children of the module.
|
||||
alt module.children.find(name) {
|
||||
some(name_bindings)
|
||||
if (*name_bindings).defined_in_namespace(namespace) {
|
||||
|
||||
#debug("(resolving name in module) found node as child");
|
||||
ret Success(Target(module, name_bindings));
|
||||
}
|
||||
some(_) | none {
|
||||
// Continue.
|
||||
}
|
||||
}
|
||||
|
||||
// Next, check the module's imports. If the module has a glob, then
|
||||
// we bail out; we don't know its imports yet.
|
||||
|
||||
if module.glob_count > 0u {
|
||||
#debug("(resolving name in module) module has glob; bailing out");
|
||||
ret Indeterminate;
|
||||
}
|
||||
|
||||
// Otherwise, we check the list of resolved imports.
|
||||
alt module.import_resolutions.find(name) {
|
||||
some(import_resolution) {
|
||||
if import_resolution.outstanding_references != 0u {
|
||||
#debug("(resolving name in module) import unresolved; \
|
||||
bailing out");
|
||||
ret Indeterminate;
|
||||
}
|
||||
|
||||
alt (*import_resolution).target_for_namespace(namespace) {
|
||||
none {
|
||||
#debug("(resolving name in module) name found, but \
|
||||
not in namespace %?",
|
||||
namespace);
|
||||
}
|
||||
some(target) {
|
||||
#debug("(resolving name in module) resolved to \
|
||||
import");
|
||||
ret Success(copy target);
|
||||
}
|
||||
}
|
||||
}
|
||||
none {
|
||||
// Continue.
|
||||
}
|
||||
}
|
||||
|
||||
// We're out of luck.
|
||||
#debug("(resolving name in module) failed to resolve %s",
|
||||
*(*self.atom_table).atom_to_str(name));
|
||||
ret Failed;
|
||||
}
|
||||
|
||||
#[doc="
|
||||
Resolves a one-level renaming import of the kind `import foo = bar;`
|
||||
This needs special handling, as, unlike all of the other imports, it
|
||||
needs to look in the scope chain for modules and non-modules alike.
|
||||
"]
|
||||
fn resolve_one_level_renaming_import(module: @Module,
|
||||
import_directive: @ImportDirective)
|
||||
-> ResolveResult<()> {
|
||||
|
||||
let mut target_name;
|
||||
let mut source_name;
|
||||
alt *import_directive.subclass {
|
||||
SingleImport(target, source) {
|
||||
target_name = target;
|
||||
source_name = source;
|
||||
}
|
||||
GlobImport {
|
||||
fail "found `import *`, which is invalid";
|
||||
}
|
||||
}
|
||||
|
||||
#debug("(resolving one-level naming result) resolving import '%s' = \
|
||||
'%s' in '%s'",
|
||||
*(*self.atom_table).atom_to_str(target_name),
|
||||
*(*self.atom_table).atom_to_str(source_name),
|
||||
self.module_to_str(module));
|
||||
|
||||
// Find the matching items in the lexical scope chain for every
|
||||
// namespace. If any of them come back indeterminate, this entire
|
||||
// import is indeterminate.
|
||||
|
||||
let mut module_result;
|
||||
#debug("(resolving one-level naming result) searching for module");
|
||||
alt self.resolve_item_in_lexical_scope(module,
|
||||
source_name,
|
||||
ModuleNS) {
|
||||
|
||||
Failed {
|
||||
#debug("(resolving one-level renaming import) didn't find \
|
||||
module result");
|
||||
module_result = none;
|
||||
}
|
||||
Indeterminate {
|
||||
#debug("(resolving one-level renaming import) module result \
|
||||
is indeterminate; bailing");
|
||||
ret Indeterminate;
|
||||
}
|
||||
Success(name_bindings) {
|
||||
#debug("(resolving one-level renaming import) module result \
|
||||
found");
|
||||
module_result = some(copy name_bindings);
|
||||
}
|
||||
}
|
||||
|
||||
let mut value_result;
|
||||
#debug("(resolving one-level naming result) searching for value");
|
||||
alt self.resolve_item_in_lexical_scope(module,
|
||||
source_name,
|
||||
ValueNS) {
|
||||
|
||||
Failed {
|
||||
#debug("(resolving one-level renaming import) didn't find \
|
||||
value result");
|
||||
value_result = none;
|
||||
}
|
||||
Indeterminate {
|
||||
#debug("(resolving one-level renaming import) value result \
|
||||
is indeterminate; bailing");
|
||||
ret Indeterminate;
|
||||
}
|
||||
Success(name_bindings) {
|
||||
#debug("(resolving one-level renaming import) value result \
|
||||
found");
|
||||
value_result = some(copy name_bindings);
|
||||
}
|
||||
}
|
||||
|
||||
let mut type_result;
|
||||
#debug("(resolving one-level naming result) searching for type");
|
||||
alt self.resolve_item_in_lexical_scope(module,
|
||||
source_name,
|
||||
TypeNS) {
|
||||
|
||||
Failed {
|
||||
#debug("(resolving one-level renaming import) didn't find \
|
||||
type result");
|
||||
type_result = none;
|
||||
}
|
||||
Indeterminate {
|
||||
#debug("(resolving one-level renaming import) type result is \
|
||||
indeterminate; bailing");
|
||||
ret Indeterminate;
|
||||
}
|
||||
Success(name_bindings) {
|
||||
#debug("(resolving one-level renaming import) type result \
|
||||
found");
|
||||
type_result = some(copy name_bindings);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// NB: This one results in effects that may be somewhat surprising. It
|
||||
// means that this:
|
||||
//
|
||||
// mod A {
|
||||
// impl foo for ... { ... }
|
||||
// mod B {
|
||||
// impl foo for ... { ... }
|
||||
// import bar = foo;
|
||||
// ...
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// results in only A::B::foo being aliased to A::B::bar, not A::foo
|
||||
// *and* A::B::foo being aliased to A::B::bar.
|
||||
//
|
||||
|
||||
let mut impl_result;
|
||||
#debug("(resolving one-level naming result) searching for impl");
|
||||
alt self.resolve_item_in_lexical_scope(module,
|
||||
source_name,
|
||||
ImplNS) {
|
||||
|
||||
Failed {
|
||||
#debug("(resolving one-level renaming import) didn't find \
|
||||
impl result");
|
||||
impl_result = none;
|
||||
}
|
||||
Indeterminate {
|
||||
#debug("(resolving one-level renaming import) impl result is \
|
||||
indeterminate; bailing");
|
||||
ret Indeterminate;
|
||||
}
|
||||
Success(name_bindings) {
|
||||
#debug("(resolving one-level renaming import) impl result \
|
||||
found");
|
||||
impl_result = some(@copy name_bindings);
|
||||
}
|
||||
}
|
||||
|
||||
// If nothing at all was found, that's an error.
|
||||
if is_none(module_result) && is_none(value_result) &&
|
||||
is_none(type_result) && is_none(impl_result) {
|
||||
|
||||
// XXX: span_err, better error
|
||||
self.session.err("couldn't find anything with that name");
|
||||
ret Failed;
|
||||
}
|
||||
|
||||
// Otherwise, proceed and write in the bindings.
|
||||
alt module.import_resolutions.find(target_name) {
|
||||
none {
|
||||
fail "(resolving one-level renaming import) reduced graph \
|
||||
construction or glob importing should have created the \
|
||||
import resolution name by now";
|
||||
}
|
||||
some(import_resolution) {
|
||||
#debug("(resolving one-level renaming import) writing module \
|
||||
result %? for '%s' into '%s'",
|
||||
is_none(module_result),
|
||||
*(*self.atom_table).atom_to_str(target_name),
|
||||
self.module_to_str(module));
|
||||
|
||||
import_resolution.module_target = module_result;
|
||||
import_resolution.value_target = value_result;
|
||||
import_resolution.type_target = type_result;
|
||||
|
||||
alt impl_result {
|
||||
none {
|
||||
// Nothing to do.
|
||||
}
|
||||
some(impl_result) {
|
||||
(*import_resolution.impl_target).push(impl_result);
|
||||
}
|
||||
}
|
||||
|
||||
assert import_resolution.outstanding_references >= 1u;
|
||||
import_resolution.outstanding_references -= 1u;
|
||||
}
|
||||
}
|
||||
|
||||
#debug("(resolving one-level renaming import) successfully resolved");
|
||||
ret Success(());
|
||||
}
|
||||
|
||||
fn report_unresolved_imports(module: @Module) {
|
||||
let index = module.resolved_import_count;
|
||||
let import_count = module.imports.len();
|
||||
if index != import_count {
|
||||
let module_path = module.imports.get_elt(index).module_path;
|
||||
|
||||
// XXX: span_err
|
||||
self.session.err(#fmt("unresolved import in %s: %s",
|
||||
self.module_to_str(module),
|
||||
*(*self.atom_table)
|
||||
.atoms_to_str((*module_path).get())));
|
||||
}
|
||||
|
||||
// Descend into children and anonymous children.
|
||||
for module.children.each |_name, child_node| {
|
||||
alt (*child_node).get_module_if_available() {
|
||||
none {
|
||||
// Continue.
|
||||
}
|
||||
some(child_module) {
|
||||
self.report_unresolved_imports(child_module);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for module.anonymous_children.each |_name, module| {
|
||||
self.report_unresolved_imports(module);
|
||||
}
|
||||
}
|
||||
|
||||
// Export recording
|
||||
//
|
||||
// This pass simply determines what all "export" keywords refer to and
|
||||
// writes the results into the export map.
|
||||
//
|
||||
// XXX: This pass will be removed once exports change to per-item. Then
|
||||
// this operation can simply be performed as part of item (or import)
|
||||
// processing.
|
||||
|
||||
fn record_exports() {
|
||||
let root_module = (*self.graph_root).get_module();
|
||||
self.record_exports_for_module_subtree(root_module);
|
||||
}
|
||||
|
||||
fn record_exports_for_module_subtree(module: @Module) {
|
||||
// If this isn't a local crate, then bail out. We don't need to record
|
||||
// exports for local crates.
|
||||
|
||||
alt module.def_id {
|
||||
some(def_id) if def_id.crate == local_crate {
|
||||
// OK. Continue.
|
||||
}
|
||||
none {
|
||||
// Record exports for the root module.
|
||||
}
|
||||
some(_) {
|
||||
// Bail out.
|
||||
#debug("(recording exports for module subtree) not recording \
|
||||
exports for '%s'",
|
||||
self.module_to_str(module));
|
||||
ret;
|
||||
}
|
||||
}
|
||||
|
||||
self.record_exports_for_module(module);
|
||||
|
||||
for module.children.each |_atom, child_name_bindings| {
|
||||
alt (*child_name_bindings).get_module_if_available() {
|
||||
none {
|
||||
// Nothing to do.
|
||||
}
|
||||
some(child_module) {
|
||||
self.record_exports_for_module_subtree(child_module);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for module.anonymous_children.each |_node_id, child_module| {
|
||||
self.record_exports_for_module_subtree(child_module);
|
||||
}
|
||||
}
|
||||
|
||||
fn record_exports_for_module(module: @Module) {
|
||||
for module.exported_names.each |name, node_id| {
|
||||
let mut exports = ~[];
|
||||
for self.namespaces.each |namespace| {
|
||||
// Ignore impl namespaces; they cause the original resolve
|
||||
// to fail.
|
||||
|
||||
if namespace == ImplNS {
|
||||
cont;
|
||||
}
|
||||
|
||||
alt self.resolve_definition_of_name_in_module(module,
|
||||
name,
|
||||
namespace) {
|
||||
NoNameDefinition {
|
||||
// Nothing to do.
|
||||
}
|
||||
ChildNameDefinition(target_def) {
|
||||
vec::push(exports, {
|
||||
reexp: false,
|
||||
id: def_id_of_def(target_def)
|
||||
});
|
||||
}
|
||||
ImportNameDefinition(target_def) {
|
||||
vec::push(exports, {
|
||||
reexp: true,
|
||||
id: def_id_of_def(target_def)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.export_map.insert(node_id, exports);
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation scope creation
|
||||
//
|
||||
// This is a fairly simple pass that simply gathers up all the typeclass
|
||||
// implementations in scope and threads a series of singly-linked series
|
||||
// of impls through the tree.
|
||||
|
||||
fn build_impl_scopes() {
|
||||
let root_module = (*self.graph_root).get_module();
|
||||
self.build_impl_scopes_for_module_subtree(root_module);
|
||||
}
|
||||
|
||||
fn build_impl_scopes_for_module_subtree(module: @Module) {
|
||||
// If this isn't a local crate, then bail out. We don't need to
|
||||
// resolve implementations for external crates.
|
||||
|
||||
alt module.def_id {
|
||||
some(def_id) if def_id.crate == local_crate {
|
||||
// OK. Continue.
|
||||
}
|
||||
none {
|
||||
// Resolve implementation scopes for the root module.
|
||||
}
|
||||
some(_) {
|
||||
// Bail out.
|
||||
#debug("(building impl scopes for module subtree) not \
|
||||
resolving implementations for '%s'",
|
||||
self.module_to_str(module));
|
||||
ret;
|
||||
}
|
||||
}
|
||||
|
||||
self.build_impl_scope_for_module(module);
|
||||
|
||||
for module.children.each |_atom, child_name_bindings| {
|
||||
alt (*child_name_bindings).get_module_if_available() {
|
||||
none {
|
||||
/* Nothing to do. */
|
||||
}
|
||||
some(child_module) {
|
||||
self.build_impl_scopes_for_module_subtree(child_module);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for module.anonymous_children.each |_node_id, child_module| {
|
||||
self.build_impl_scopes_for_module_subtree(child_module);
|
||||
}
|
||||
}
|
||||
|
||||
fn build_impl_scope_for_module(module: @Module) {
|
||||
let mut impl_scope = ~[];
|
||||
|
||||
#debug("(building impl scope for module) processing module %s (%?)",
|
||||
self.module_to_str(module),
|
||||
copy module.def_id);
|
||||
|
||||
// Gather up all direct children implementations in the module.
|
||||
for module.children.each |_impl_name, child_name_bindings| {
|
||||
if child_name_bindings.impl_defs.len() >= 1u {
|
||||
impl_scope += child_name_bindings.impl_defs;
|
||||
}
|
||||
}
|
||||
|
||||
#debug("(building impl scope for module) found %u impl(s) as direct \
|
||||
children",
|
||||
impl_scope.len());
|
||||
|
||||
// Gather up all imports.
|
||||
for module.import_resolutions.each |_impl_name, import_resolution| {
|
||||
for (*import_resolution.impl_target).each |impl_target| {
|
||||
#debug("(building impl scope for module) found impl def");
|
||||
impl_scope += impl_target.bindings.impl_defs;
|
||||
}
|
||||
}
|
||||
|
||||
#debug("(building impl scope for module) found %u impl(s) in total",
|
||||
impl_scope.len());
|
||||
|
||||
// Determine the parent's implementation scope.
|
||||
let mut parent_impl_scopes;
|
||||
alt module.parent_link {
|
||||
NoParentLink {
|
||||
parent_impl_scopes = @nil;
|
||||
}
|
||||
ModuleParentLink(parent_module_node, _) |
|
||||
BlockParentLink(parent_module_node, _) {
|
||||
parent_impl_scopes = parent_module_node.impl_scopes;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the new implementation scope, if it was nonempty, and chain
|
||||
// it up to the parent.
|
||||
|
||||
if impl_scope.len() >= 1u {
|
||||
module.impl_scopes = @cons(@impl_scope, parent_impl_scopes);
|
||||
} else {
|
||||
module.impl_scopes = parent_impl_scopes;
|
||||
}
|
||||
}
|
||||
|
||||
// AST resolution
|
||||
//
|
||||
// We maintain a list of value ribs and type ribs. Since ribs are
|
||||
// somewhat expensive to allocate, we try to avoid creating ribs unless
|
||||
// we know we need to. For instance, we don't allocate a type rib for
|
||||
// a function with no type parameters.
|
||||
//
|
||||
// Simultaneously, we keep track of the current position in the module
|
||||
// graph in the `current_module` pointer. When we go to resolve a name in
|
||||
// the value or type namespaces, we first look through all the ribs and
|
||||
// then query the module graph. When we resolve a name in the module
|
||||
// namespace, we can skip all the ribs (since nested modules are not
|
||||
// allowed within blocks in Rust) and jump straight to the current module
|
||||
// graph node.
|
||||
//
|
||||
// Named implementations are handled separately. When we find a method
|
||||
// call, we consult the module node to find all of the implementations in
|
||||
// scope. This information is lazily cached in the module node. We then
|
||||
// generate a fake "implementation scope" containing all the
|
||||
// implementations thus found, for compatibility with old resolve pass.
|
||||
|
||||
fn with_scope(name: option<Atom>, f: fn()) {
|
||||
let orig_module = self.current_module;
|
||||
|
||||
// Move down in the graph.
|
||||
alt name {
|
||||
none { /* Nothing to do. */ }
|
||||
some(name) {
|
||||
alt orig_module.children.find(name) {
|
||||
none {
|
||||
#debug("!!! (with scope) didn't find '%s' in '%s'",
|
||||
*(*self.atom_table).atom_to_str(name),
|
||||
self.module_to_str(orig_module));
|
||||
}
|
||||
some(name_bindings) {
|
||||
alt (*name_bindings).get_module_if_available() {
|
||||
none {
|
||||
#debug("!!! (with scope) didn't find module \
|
||||
for '%s' in '%s'",
|
||||
*(*self.atom_table).atom_to_str(name),
|
||||
self.module_to_str(orig_module));
|
||||
}
|
||||
some(module) {
|
||||
self.current_module = module;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
f();
|
||||
|
||||
self.current_module = orig_module;
|
||||
}
|
||||
|
||||
// Wraps the given definition in the appropriate number of `def_upvar`
|
||||
// wrappers.
|
||||
|
||||
fn upvarify(ribs: @dvec<@Rib>, rib_index: uint, def_like: def_like)
|
||||
-> def_like {
|
||||
|
||||
let mut def;
|
||||
alt def_like {
|
||||
dl_def(d @ def_local(*)) | dl_def(d @ def_upvar(*)) |
|
||||
dl_def(d @ def_arg(*)) | dl_def(d @ def_self(*)) |
|
||||
dl_def(d @ def_binding(*)) {
|
||||
def = d;
|
||||
}
|
||||
_ {
|
||||
ret def_like;
|
||||
}
|
||||
}
|
||||
|
||||
let mut rib_index = rib_index + 1u;
|
||||
while rib_index < (*ribs).len() {
|
||||
let rib = (*ribs).get_elt(rib_index);
|
||||
alt rib.kind {
|
||||
NormalRibKind {
|
||||
// Nothing to do. Continue.
|
||||
}
|
||||
FunctionRibKind(function_id) {
|
||||
def = def_upvar(def_id_of_def(def).node,
|
||||
@def,
|
||||
function_id);
|
||||
}
|
||||
}
|
||||
|
||||
rib_index += 1u;
|
||||
}
|
||||
|
||||
ret dl_def(def);
|
||||
}
|
||||
|
||||
fn search_ribs(ribs: @dvec<@Rib>, name: Atom) -> option<def_like> {
|
||||
|
||||
// XXX: This should not use a while loop.
|
||||
// XXX: Try caching?
|
||||
|
||||
let mut i = (*ribs).len();
|
||||
while i != 0u {
|
||||
i -= 1u;
|
||||
let rib = (*ribs).get_elt(i);
|
||||
alt rib.bindings.find(name) {
|
||||
some(def_like) {
|
||||
ret some(self.upvarify(ribs, i, def_like));
|
||||
}
|
||||
none {
|
||||
// Continue.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret none;
|
||||
}
|
||||
|
||||
// XXX: This shouldn't be unsafe!
|
||||
fn resolve_crate() unsafe {
|
||||
#debug("(resolving crate) starting");
|
||||
|
||||
// To avoid a failure in metadata encoding later, we have to add the
|
||||
// crate-level implementation scopes
|
||||
|
||||
self.impl_map.insert(0, (*self.graph_root).get_module().impl_scopes);
|
||||
|
||||
// XXX: This is awful!
|
||||
let this = ptr::addr_of(self);
|
||||
visit_crate(*self.crate, (), mk_vt(@{
|
||||
visit_item: |item, _context, visitor|
|
||||
(*this).resolve_item(item, visitor),
|
||||
visit_arm: |arm, _context, visitor|
|
||||
(*this).resolve_arm(arm, visitor),
|
||||
visit_block: |block, _context, visitor|
|
||||
(*this).resolve_block(block, visitor),
|
||||
visit_expr: |expr, _context, visitor|
|
||||
(*this).resolve_expr(expr, visitor),
|
||||
visit_local: |local, _context, visitor|
|
||||
(*this).resolve_local(local, visitor),
|
||||
visit_ty: |ty, _context, visitor|
|
||||
(*this).resolve_type(ty, visitor)
|
||||
with *default_visitor()
|
||||
}));
|
||||
}
|
||||
|
||||
fn resolve_item(item: @item, visitor: ResolveVisitor) {
|
||||
#debug("(resolving item) resolving %s", *item.ident);
|
||||
|
||||
alt item.node {
|
||||
item_enum(_, type_parameters, _) |
|
||||
item_ty(_, type_parameters, _) {
|
||||
do self.with_type_parameter_rib
|
||||
(HasTypeParameters(&type_parameters, item.id, 0u))
|
||||
|| {
|
||||
|
||||
visit_item(item, (), visitor);
|
||||
}
|
||||
}
|
||||
|
||||
item_impl(type_parameters, _, interface_reference, self_type,
|
||||
methods) {
|
||||
self.resolve_implementation(item.id,
|
||||
item.span,
|
||||
type_parameters,
|
||||
interface_reference,
|
||||
self_type,
|
||||
methods,
|
||||
visitor);
|
||||
}
|
||||
|
||||
item_iface(type_parameters, _, methods) {
|
||||
// Create a new rib for the self type.
|
||||
let self_type_rib = @Rib(NormalRibKind);
|
||||
(*self.type_ribs).push(self_type_rib);
|
||||
self_type_rib.bindings.insert(self.self_atom,
|
||||
dl_def(def_self(item.id)));
|
||||
|
||||
// Create a new rib for the interface-wide type parameters.
|
||||
do self.with_type_parameter_rib
|
||||
(HasTypeParameters(&type_parameters, item.id, 0u))
|
||||
|| {
|
||||
|
||||
for methods.each |method| {
|
||||
// Create a new rib for the method-specific type
|
||||
// parameters.
|
||||
//
|
||||
// XXX: Do we need a node ID here?
|
||||
|
||||
do self.with_type_parameter_rib
|
||||
(HasTypeParameters(&method.tps,
|
||||
item.id,
|
||||
type_parameters.len()))
|
||||
|| {
|
||||
|
||||
// Resolve the method-specific type parameters.
|
||||
self.resolve_type_parameters(method.tps, visitor);
|
||||
|
||||
for method.decl.inputs.each |argument| {
|
||||
self.resolve_type(argument.ty, visitor);
|
||||
}
|
||||
|
||||
self.resolve_type(method.decl.output, visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(*self.type_ribs).pop();
|
||||
}
|
||||
|
||||
item_class(ty_params, interfaces, class_members, constructor,
|
||||
optional_destructor, _) {
|
||||
|
||||
self.resolve_class(item.id,
|
||||
@copy ty_params,
|
||||
interfaces,
|
||||
class_members,
|
||||
constructor,
|
||||
optional_destructor,
|
||||
visitor);
|
||||
}
|
||||
|
||||
item_mod(module) {
|
||||
let atom = (*self.atom_table).intern(item.ident);
|
||||
do self.with_scope(some(atom)) || {
|
||||
self.resolve_module(module, item.span, item.ident,
|
||||
item.id, visitor);
|
||||
}
|
||||
}
|
||||
|
||||
item_foreign_mod(foreign_module) {
|
||||
let atom = (*self.atom_table).intern(item.ident);
|
||||
do self.with_scope(some(atom)) || {
|
||||
for foreign_module.items.each |foreign_item| {
|
||||
alt foreign_item.node {
|
||||
foreign_item_fn(_, type_parameters) {
|
||||
do self.with_type_parameter_rib
|
||||
(HasTypeParameters(&type_parameters,
|
||||
foreign_item.id,
|
||||
0u)) || {
|
||||
|
||||
visit_foreign_item(foreign_item, (),
|
||||
visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
item_fn(fn_decl, ty_params, block) {
|
||||
self.resolve_function(NormalRibKind,
|
||||
some(@fn_decl),
|
||||
HasTypeParameters(&ty_params,
|
||||
item.id,
|
||||
0u),
|
||||
block,
|
||||
NoSelfBinding,
|
||||
NoCaptureClause,
|
||||
visitor);
|
||||
}
|
||||
|
||||
item_const(*) {
|
||||
visit_item(item, (), visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn with_type_parameter_rib(type_parameters: TypeParameters, f: fn()) {
|
||||
|
||||
alt type_parameters {
|
||||
HasTypeParameters(type_parameters, node_id, initial_index)
|
||||
if (*type_parameters).len() >= 1u {
|
||||
|
||||
let function_type_rib = @Rib(NormalRibKind);
|
||||
(*self.type_ribs).push(function_type_rib);
|
||||
|
||||
for (*type_parameters).eachi |index, type_parameter| {
|
||||
let name =
|
||||
(*self.atom_table).intern(type_parameter.ident);
|
||||
let def_like = dl_def(def_ty_param
|
||||
(local_def(type_parameter.id),
|
||||
index + initial_index));
|
||||
(*function_type_rib).bindings.insert(name, def_like);
|
||||
}
|
||||
}
|
||||
|
||||
HasTypeParameters(*) | NoTypeParameters {
|
||||
// Nothing to do.
|
||||
}
|
||||
}
|
||||
|
||||
f();
|
||||
|
||||
alt type_parameters {
|
||||
HasTypeParameters(type_parameters, _, _)
|
||||
if (*type_parameters).len() >= 1u {
|
||||
|
||||
(*self.type_ribs).pop();
|
||||
}
|
||||
|
||||
HasTypeParameters(*) | NoTypeParameters {
|
||||
// Nothing to do.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_function(rib_kind: RibKind,
|
||||
optional_declaration: option<@fn_decl>,
|
||||
type_parameters: TypeParameters,
|
||||
block: blk,
|
||||
self_binding: SelfBinding,
|
||||
capture_clause: CaptureClause,
|
||||
visitor: ResolveVisitor) {
|
||||
|
||||
// Check each element of the capture clause.
|
||||
alt capture_clause {
|
||||
NoCaptureClause {
|
||||
// Nothing to do.
|
||||
}
|
||||
HasCaptureClause(capture_clause) {
|
||||
// Resolve each captured item.
|
||||
for (*capture_clause).each |capture_item| {
|
||||
alt self.resolve_identifier(capture_item.name,
|
||||
ValueNS,
|
||||
true) {
|
||||
none {
|
||||
self.session.span_err(capture_item.span,
|
||||
"use of undeclared \
|
||||
identifier in \
|
||||
capture clause");
|
||||
}
|
||||
some(def) {
|
||||
self.record_def(capture_item.id, def);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create a value rib for the function.
|
||||
let function_value_rib = @Rib(rib_kind);
|
||||
(*self.value_ribs).push(function_value_rib);
|
||||
|
||||
// If this function has type parameters, add them now.
|
||||
do self.with_type_parameter_rib(type_parameters) || {
|
||||
// Resolve the type parameters.
|
||||
alt type_parameters {
|
||||
NoTypeParameters {
|
||||
// Continue.
|
||||
}
|
||||
HasTypeParameters(type_parameters, _, _) {
|
||||
self.resolve_type_parameters(*type_parameters, visitor);
|
||||
}
|
||||
}
|
||||
|
||||
// Add self to the rib, if necessary.
|
||||
alt self_binding {
|
||||
NoSelfBinding {
|
||||
// Nothing to do.
|
||||
}
|
||||
HasSelfBinding(self_node_id) {
|
||||
let def_like = dl_def(def_self(self_node_id));
|
||||
(*function_value_rib).bindings.insert(self.self_atom,
|
||||
def_like);
|
||||
}
|
||||
}
|
||||
|
||||
// Add each argument to the rib.
|
||||
alt optional_declaration {
|
||||
none {
|
||||
// Nothing to do.
|
||||
}
|
||||
some(declaration) {
|
||||
for declaration.inputs.each |argument| {
|
||||
let name = (*self.atom_table).intern(argument.ident);
|
||||
let def_like = dl_def(def_arg(argument.id,
|
||||
argument.mode));
|
||||
(*function_value_rib).bindings.insert(name, def_like);
|
||||
|
||||
self.resolve_type(argument.ty, visitor);
|
||||
|
||||
#debug("(resolving function) recorded argument '%s'",
|
||||
*(*self.atom_table).atom_to_str(name));
|
||||
}
|
||||
|
||||
self.resolve_type(declaration.output, visitor);
|
||||
|
||||
// Resolve constraints.
|
||||
for declaration.constraints.each |constraint| {
|
||||
alt self.resolve_path(constraint.node.path, ValueNS,
|
||||
false, visitor) {
|
||||
none {
|
||||
self.session.span_err(constraint.span,
|
||||
"use of undeclared \
|
||||
constraint");
|
||||
}
|
||||
some(def) {
|
||||
self.record_def(constraint.node.id, def);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve the function body.
|
||||
self.resolve_block(block, visitor);
|
||||
|
||||
#debug("(resolving function) leaving function");
|
||||
}
|
||||
|
||||
(*self.value_ribs).pop();
|
||||
}
|
||||
|
||||
fn resolve_type_parameters(type_parameters: ~[ty_param],
|
||||
visitor: ResolveVisitor) {
|
||||
|
||||
for type_parameters.each |type_parameter| {
|
||||
for (*type_parameter.bounds).each |bound| {
|
||||
alt bound {
|
||||
bound_copy | bound_send | bound_const {
|
||||
// Nothing to do.
|
||||
}
|
||||
bound_iface(interface_type) {
|
||||
self.resolve_type(interface_type, visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_class(id: node_id,
|
||||
type_parameters: @~[ty_param],
|
||||
interfaces: ~[@iface_ref],
|
||||
class_members: ~[@class_member],
|
||||
constructor: class_ctor,
|
||||
optional_destructor: option<class_dtor>,
|
||||
visitor: ResolveVisitor) {
|
||||
|
||||
// Add a type into the def map. This is needed to prevent an ICE in
|
||||
// ty::impl_iface.
|
||||
|
||||
// If applicable, create a rib for the type parameters.
|
||||
let outer_type_parameter_count = (*type_parameters).len();
|
||||
let borrowed_type_parameters: &~[ty_param] = &*type_parameters;
|
||||
do self.with_type_parameter_rib(HasTypeParameters
|
||||
(borrowed_type_parameters, id, 0u))
|
||||
|| {
|
||||
|
||||
// Resolve the type parameters.
|
||||
self.resolve_type_parameters(*type_parameters, visitor);
|
||||
|
||||
// Resolve implemented interfaces.
|
||||
for interfaces.each |interface| {
|
||||
alt self.resolve_path(interface.path, TypeNS, true, visitor) {
|
||||
none {
|
||||
self.session.span_err(interface.path.span,
|
||||
"attempt to implement an \
|
||||
unknown interface");
|
||||
}
|
||||
some(def) {
|
||||
// Write a mapping from the interface ID to the
|
||||
// definition of the interface into the definition
|
||||
// map.
|
||||
|
||||
#debug("(resolving class) found iface def: %?", def);
|
||||
|
||||
self.record_def(interface.id, def);
|
||||
|
||||
// XXX: This is wrong but is needed for tests to
|
||||
// pass.
|
||||
|
||||
self.record_def(id, def);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve methods.
|
||||
for class_members.each |class_member| {
|
||||
alt class_member.node {
|
||||
class_method(method) {
|
||||
let borrowed_method_type_parameters = &method.tps;
|
||||
let type_parameters =
|
||||
HasTypeParameters(borrowed_method_type_parameters,
|
||||
method.id,
|
||||
outer_type_parameter_count);
|
||||
self.resolve_function(NormalRibKind,
|
||||
some(@method.decl),
|
||||
type_parameters,
|
||||
method.body,
|
||||
HasSelfBinding(method.self_id),
|
||||
NoCaptureClause,
|
||||
visitor);
|
||||
}
|
||||
instance_var(_, field_type, _, _, _) {
|
||||
self.resolve_type(field_type, visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve the constructor.
|
||||
self.resolve_function(NormalRibKind,
|
||||
some(@constructor.node.dec),
|
||||
NoTypeParameters,
|
||||
constructor.node.body,
|
||||
HasSelfBinding(constructor.node.self_id),
|
||||
NoCaptureClause,
|
||||
visitor);
|
||||
|
||||
|
||||
// Resolve the destructor, if applicable.
|
||||
alt optional_destructor {
|
||||
none {
|
||||
// Nothing to do.
|
||||
}
|
||||
some(destructor) {
|
||||
self.resolve_function(NormalRibKind,
|
||||
none,
|
||||
NoTypeParameters,
|
||||
destructor.node.body,
|
||||
HasSelfBinding
|
||||
(destructor.node.self_id),
|
||||
NoCaptureClause,
|
||||
visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_implementation(id: node_id,
|
||||
span: span,
|
||||
type_parameters: ~[ty_param],
|
||||
interface_reference: option<@iface_ref>,
|
||||
self_type: @ty,
|
||||
methods: ~[@method],
|
||||
visitor: ResolveVisitor) {
|
||||
|
||||
// If applicable, create a rib for the type parameters.
|
||||
let outer_type_parameter_count = type_parameters.len();
|
||||
let borrowed_type_parameters: &~[ty_param] = &type_parameters;
|
||||
do self.with_type_parameter_rib(HasTypeParameters
|
||||
(borrowed_type_parameters, id, 0u))
|
||||
|| {
|
||||
|
||||
// Resolve the type parameters.
|
||||
self.resolve_type_parameters(type_parameters, visitor);
|
||||
|
||||
// Resolve the interface reference, if necessary.
|
||||
alt interface_reference {
|
||||
none {
|
||||
// Nothing to do.
|
||||
}
|
||||
some(interface_reference) {
|
||||
alt self.resolve_path(interface_reference.path, TypeNS,
|
||||
true, visitor) {
|
||||
none {
|
||||
self.session.span_err(span,
|
||||
"attempt to implement an \
|
||||
unknown interface");
|
||||
}
|
||||
some(def) {
|
||||
self.record_def(interface_reference.id, def);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve the self type.
|
||||
self.resolve_type(self_type, visitor);
|
||||
|
||||
for methods.each |method| {
|
||||
// We also need a new scope for the method-specific
|
||||
// type parameters.
|
||||
|
||||
let borrowed_type_parameters = &method.tps;
|
||||
self.resolve_function(NormalRibKind,
|
||||
some(@method.decl),
|
||||
HasTypeParameters
|
||||
(borrowed_type_parameters,
|
||||
method.id,
|
||||
outer_type_parameter_count),
|
||||
method.body,
|
||||
HasSelfBinding(method.self_id),
|
||||
NoCaptureClause,
|
||||
visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_module(module: _mod, span: span, _name: ident, id: node_id,
|
||||
visitor: ResolveVisitor) {
|
||||
|
||||
// Write the implementations in scope into the module metadata.
|
||||
#debug("(resolving module) resolving module ID %d", id);
|
||||
self.impl_map.insert(id, self.current_module.impl_scopes);
|
||||
|
||||
visit_mod(module, span, id, (), visitor);
|
||||
}
|
||||
|
||||
fn resolve_local(local: @local, visitor: ResolveVisitor) {
|
||||
let mut mutability;
|
||||
if local.node.is_mutbl {
|
||||
mutability = Mutable;
|
||||
} else {
|
||||
mutability = Immutable;
|
||||
}
|
||||
|
||||
// Resolve the type.
|
||||
self.resolve_type(local.node.ty, visitor);
|
||||
|
||||
// Resolve the initializer, if necessary.
|
||||
alt local.node.init {
|
||||
none {
|
||||
// Nothing to do.
|
||||
}
|
||||
some(initializer) {
|
||||
self.resolve_expr(initializer.expr, visitor);
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve the pattern.
|
||||
self.resolve_pattern(local.node.pat, IrrefutableMode, mutability,
|
||||
none, visitor);
|
||||
}
|
||||
|
||||
fn resolve_arm(arm: arm, visitor: ResolveVisitor) {
|
||||
(*self.value_ribs).push(@Rib(NormalRibKind));
|
||||
|
||||
let bindings_list = atom_hashmap();
|
||||
for arm.pats.each |pattern| {
|
||||
self.resolve_pattern(pattern, RefutableMode, Immutable,
|
||||
some(bindings_list), visitor);
|
||||
}
|
||||
|
||||
visit_expr_opt(arm.guard, (), visitor);
|
||||
self.resolve_block(arm.body, visitor);
|
||||
|
||||
(*self.value_ribs).pop();
|
||||
}
|
||||
|
||||
fn resolve_block(block: blk, visitor: ResolveVisitor) {
|
||||
#debug("(resolving block) entering block");
|
||||
(*self.value_ribs).push(@Rib(NormalRibKind));
|
||||
|
||||
// Move down in the graph, if there's an anonymous module rooted here.
|
||||
let orig_module = self.current_module;
|
||||
alt self.current_module.anonymous_children.find(block.node.id) {
|
||||
none { /* Nothing to do. */ }
|
||||
some(anonymous_module) {
|
||||
#debug("(resolving block) found anonymous module, moving \
|
||||
down");
|
||||
self.current_module = anonymous_module;
|
||||
}
|
||||
}
|
||||
|
||||
// Descend into the block.
|
||||
visit_block(block, (), visitor);
|
||||
|
||||
// Move back up.
|
||||
self.current_module = orig_module;
|
||||
|
||||
(*self.value_ribs).pop();
|
||||
#debug("(resolving block) leaving block");
|
||||
}
|
||||
|
||||
fn resolve_type(ty: @ty, visitor: ResolveVisitor) {
|
||||
alt ty.node {
|
||||
// Like path expressions, the interpretation of path types depends
|
||||
// on whether the path has multiple elements in it or not.
|
||||
|
||||
ty_path(path, path_id) {
|
||||
// This is a path in the type namespace. Walk through scopes
|
||||
// scopes looking for it.
|
||||
|
||||
let mut result_def;
|
||||
alt self.resolve_path(path, TypeNS, true, visitor) {
|
||||
some(def) {
|
||||
#debug("(resolving type) resolved '%s' to type",
|
||||
*path.idents.last());
|
||||
result_def = some(def);
|
||||
}
|
||||
none {
|
||||
result_def = none;
|
||||
}
|
||||
}
|
||||
|
||||
alt result_def {
|
||||
some(_) {
|
||||
// Continue.
|
||||
}
|
||||
none {
|
||||
// Check to see whether the name is a primitive type.
|
||||
if path.idents.len() == 1u {
|
||||
let name =
|
||||
(*self.atom_table).intern(path.idents.last());
|
||||
|
||||
alt self.primitive_type_table
|
||||
.primitive_types
|
||||
.find(name) {
|
||||
|
||||
some(primitive_type) {
|
||||
result_def =
|
||||
some(def_prim_ty(primitive_type));
|
||||
}
|
||||
none {
|
||||
// Continue.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
alt copy result_def {
|
||||
some(def) {
|
||||
// Write the result into the def map.
|
||||
#debug("(resolving type) writing resolution for '%s' \
|
||||
(id %d)",
|
||||
connect(path.idents.map(|x| *x), "::"),
|
||||
path_id);
|
||||
self.record_def(path_id, def);
|
||||
}
|
||||
none {
|
||||
self.session.span_err
|
||||
(ty.span, #fmt("use of undeclared type name '%s'",
|
||||
connect(path.idents.map(|x| *x),
|
||||
"::")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ty_constr(base_type, constraints) {
|
||||
self.resolve_type(base_type, visitor);
|
||||
|
||||
for constraints.each |constraint| {
|
||||
alt self.resolve_path(constraint.node.path, ValueNS,
|
||||
false, visitor) {
|
||||
none {
|
||||
self.session.span_err(constraint.span,
|
||||
"(resolving function) \
|
||||
use of undeclared \
|
||||
constraint");
|
||||
}
|
||||
some(def) {
|
||||
self.record_def(constraint.node.id, def);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ {
|
||||
// Just resolve embedded types.
|
||||
visit_ty(ty, (), visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_pattern(pattern: @pat,
|
||||
mode: PatternBindingMode,
|
||||
mutability: Mutability,
|
||||
bindings_list: option<hashmap<Atom,()>>,
|
||||
visitor: ResolveVisitor) {
|
||||
|
||||
do walk_pat(pattern) |pattern| {
|
||||
alt pattern.node {
|
||||
pat_ident(path, _)
|
||||
if !path.global && path.idents.len() == 1u {
|
||||
|
||||
// The meaning of pat_ident with no type parameters
|
||||
// depends on whether an enum variant with that name is in
|
||||
// scope. The probing lookup has to be careful not to emit
|
||||
// spurious errors. Only matching patterns (alt) can match
|
||||
// nullary variants. For binding patterns (let), matching
|
||||
// such a variant is simply disallowed (since it's rarely
|
||||
// what you want).
|
||||
|
||||
// XXX: This restriction is not yet implemented.
|
||||
|
||||
let atom = (*self.atom_table).intern(path.idents[0]);
|
||||
|
||||
alt self.resolve_enum_variant(atom) {
|
||||
some(def) {
|
||||
#debug("(resolving pattern) resolving '%s' to \
|
||||
enum variant",
|
||||
*path.idents[0]);
|
||||
|
||||
self.record_def(pattern.id, def);
|
||||
}
|
||||
none {
|
||||
#debug("(resolving pattern) binding '%s'",
|
||||
*path.idents[0]);
|
||||
|
||||
let is_mutable = mutability == Mutable;
|
||||
|
||||
let mut def;
|
||||
alt mode {
|
||||
RefutableMode {
|
||||
// For pattern arms, we must use
|
||||
// `def_binding` definitions.
|
||||
|
||||
def = def_binding(pattern.id);
|
||||
}
|
||||
IrrefutableMode {
|
||||
// But for locals, we use `def_local`.
|
||||
def = def_local(pattern.id, is_mutable);
|
||||
}
|
||||
}
|
||||
|
||||
// Record the definition so that later passes
|
||||
// will be able to distinguish variants from
|
||||
// locals in patterns.
|
||||
|
||||
self.record_def(pattern.id, def);
|
||||
|
||||
// Add the binding to the local ribs, if it
|
||||
// doesn't already exist in the bindings list. (We
|
||||
// must not add it if it's in the bindings list
|
||||
// because that breaks the assumptions later
|
||||
// passes make about or-patterns.)
|
||||
|
||||
alt bindings_list {
|
||||
some(bindings_list)
|
||||
if !bindings_list.contains_key(atom) {
|
||||
let last_rib = (*self.value_ribs).last();
|
||||
last_rib.bindings.insert(atom,
|
||||
dl_def(def));
|
||||
bindings_list.insert(atom, ());
|
||||
}
|
||||
some(_) {
|
||||
// Do nothing.
|
||||
}
|
||||
none {
|
||||
let last_rib = (*self.value_ribs).last();
|
||||
last_rib.bindings.insert(atom,
|
||||
dl_def(def));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check the types in the path pattern.
|
||||
for path.types.each |ty| {
|
||||
self.resolve_type(ty, visitor);
|
||||
}
|
||||
}
|
||||
|
||||
pat_ident(path, _) | pat_enum(path, _) {
|
||||
// These two must be enum variants.
|
||||
alt self.resolve_path(path, ValueNS, false, visitor) {
|
||||
some(def @ def_variant(*)) {
|
||||
self.record_def(pattern.id, def);
|
||||
}
|
||||
some(_) {
|
||||
self.session.span_err(path.span,
|
||||
#fmt("not an enum \
|
||||
variant: %s",
|
||||
*path.idents.last()));
|
||||
}
|
||||
none {
|
||||
self.session.span_err(path.span,
|
||||
"undeclared enum variant");
|
||||
}
|
||||
}
|
||||
|
||||
// Check the types in the path pattern.
|
||||
for path.types.each |ty| {
|
||||
self.resolve_type(ty, visitor);
|
||||
}
|
||||
}
|
||||
|
||||
_ {
|
||||
// Nothing to do.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_enum_variant(name: Atom) -> option<def> {
|
||||
alt self.resolve_item_in_lexical_scope(self.current_module,
|
||||
name,
|
||||
ValueNS) {
|
||||
|
||||
Success(target) {
|
||||
alt target.bindings.value_def {
|
||||
none {
|
||||
fail "resolved name in the value namespace to a set \
|
||||
of name bindings with no def?!";
|
||||
}
|
||||
some(def @ def_variant(*)) {
|
||||
ret some(def);
|
||||
}
|
||||
some(_) {
|
||||
ret none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Indeterminate {
|
||||
fail "unexpected indeterminate result";
|
||||
}
|
||||
|
||||
Failed {
|
||||
ret none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc="
|
||||
If `check_ribs` is true, checks the local definitions first; i.e.
|
||||
doesn't skip straight to the containing module.
|
||||
"]
|
||||
fn resolve_path(path: @path, namespace: Namespace, check_ribs: bool,
|
||||
visitor: ResolveVisitor)
|
||||
-> option<def> {
|
||||
|
||||
// First, resolve the types.
|
||||
for path.types.each |ty| {
|
||||
self.resolve_type(ty, visitor);
|
||||
}
|
||||
|
||||
if path.global {
|
||||
ret self.resolve_crate_relative_path(path, namespace);
|
||||
}
|
||||
|
||||
if path.idents.len() > 1u {
|
||||
ret self.resolve_module_relative_path(path, namespace);
|
||||
}
|
||||
|
||||
ret self.resolve_identifier(path.idents.last(),
|
||||
namespace,
|
||||
check_ribs);
|
||||
}
|
||||
|
||||
fn resolve_identifier(identifier: ident,
|
||||
namespace: Namespace,
|
||||
check_ribs: bool)
|
||||
-> option<def> {
|
||||
|
||||
if check_ribs {
|
||||
alt self.resolve_identifier_in_local_ribs(identifier, namespace) {
|
||||
some(def) {
|
||||
ret some(def);
|
||||
}
|
||||
none {
|
||||
// Continue.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret self.resolve_item_by_identifier_in_lexical_scope(identifier,
|
||||
namespace);
|
||||
}
|
||||
|
||||
// XXX: Merge me with resolve_name_in_module?
|
||||
fn resolve_definition_of_name_in_module(containing_module: @Module,
|
||||
name: Atom,
|
||||
namespace: Namespace)
|
||||
-> NameDefinition {
|
||||
|
||||
// First, search children.
|
||||
alt containing_module.children.find(name) {
|
||||
some(child_name_bindings) {
|
||||
alt (*child_name_bindings).def_for_namespace(namespace) {
|
||||
some(def) {
|
||||
// Found it. Stop the search here.
|
||||
ret ChildNameDefinition(def);
|
||||
}
|
||||
none {
|
||||
// Continue.
|
||||
}
|
||||
}
|
||||
}
|
||||
none {
|
||||
// Continue.
|
||||
}
|
||||
}
|
||||
|
||||
// Next, search import resolutions.
|
||||
alt containing_module.import_resolutions.find(name) {
|
||||
some(import_resolution) {
|
||||
alt (*import_resolution).target_for_namespace(namespace) {
|
||||
some(target) {
|
||||
alt (*target.bindings).def_for_namespace(namespace) {
|
||||
some(def) {
|
||||
// Found it.
|
||||
ret ImportNameDefinition(def);
|
||||
}
|
||||
none {
|
||||
fail "target for namespace doesn't refer to \
|
||||
bindings that contain a definition for \
|
||||
that namespace!";
|
||||
}
|
||||
}
|
||||
}
|
||||
none {
|
||||
ret NoNameDefinition;
|
||||
}
|
||||
}
|
||||
}
|
||||
none {
|
||||
ret NoNameDefinition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn intern_module_part_of_path(path: @path) -> @dvec<Atom> {
|
||||
let module_path_atoms = @dvec();
|
||||
for path.idents.eachi |index, ident| {
|
||||
if index == path.idents.len() - 1u {
|
||||
break;
|
||||
}
|
||||
|
||||
(*module_path_atoms).push((*self.atom_table).intern(ident));
|
||||
}
|
||||
|
||||
ret module_path_atoms;
|
||||
}
|
||||
|
||||
fn resolve_module_relative_path(path: @path, namespace: Namespace)
|
||||
-> option<def> {
|
||||
|
||||
let module_path_atoms = self.intern_module_part_of_path(path);
|
||||
|
||||
let mut containing_module;
|
||||
alt self.resolve_module_path_for_import(self.current_module,
|
||||
module_path_atoms) {
|
||||
|
||||
Failed {
|
||||
self.session.span_err(path.span,
|
||||
#fmt("use of undeclared module `%s`",
|
||||
*(*self.atom_table).atoms_to_str
|
||||
((*module_path_atoms).get())));
|
||||
ret none;
|
||||
}
|
||||
|
||||
Indeterminate {
|
||||
fail "indeterminate unexpected";
|
||||
}
|
||||
|
||||
Success(resulting_module) {
|
||||
containing_module = resulting_module;
|
||||
}
|
||||
}
|
||||
|
||||
let name = (*self.atom_table).intern(path.idents.last());
|
||||
alt self.resolve_definition_of_name_in_module(containing_module,
|
||||
name,
|
||||
namespace) {
|
||||
NoNameDefinition {
|
||||
// We failed to resolve the name. Report an error.
|
||||
self.session.span_err(path.span,
|
||||
#fmt("use of undeclared identifier: \
|
||||
%s::%s",
|
||||
*(*self.atom_table).atoms_to_str
|
||||
((*module_path_atoms).get()),
|
||||
*(*self.atom_table).atom_to_str
|
||||
(name)));
|
||||
ret none;
|
||||
}
|
||||
ChildNameDefinition(def) | ImportNameDefinition(def) {
|
||||
ret some(def);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_crate_relative_path(path: @path, namespace: Namespace)
|
||||
-> option<def> {
|
||||
|
||||
let module_path_atoms = self.intern_module_part_of_path(path);
|
||||
|
||||
let root_module = (*self.graph_root).get_module();
|
||||
|
||||
let mut containing_module;
|
||||
alt self.resolve_module_path_from_root(root_module,
|
||||
module_path_atoms,
|
||||
0u) {
|
||||
|
||||
Failed {
|
||||
self.session.span_err(path.span,
|
||||
#fmt("use of undeclared module `::%s`",
|
||||
*(*self.atom_table).atoms_to_str
|
||||
((*module_path_atoms).get())));
|
||||
ret none;
|
||||
}
|
||||
|
||||
Indeterminate {
|
||||
fail "indeterminate unexpected";
|
||||
}
|
||||
|
||||
Success(resulting_module) {
|
||||
containing_module = resulting_module;
|
||||
}
|
||||
}
|
||||
|
||||
let name = (*self.atom_table).intern(path.idents.last());
|
||||
alt self.resolve_definition_of_name_in_module(containing_module,
|
||||
name,
|
||||
namespace) {
|
||||
NoNameDefinition {
|
||||
// We failed to resolve the name. Report an error.
|
||||
self.session.span_err(path.span,
|
||||
#fmt("use of undeclared identifier: \
|
||||
%s::%s",
|
||||
*(*self.atom_table).atoms_to_str
|
||||
((*module_path_atoms).get()),
|
||||
*(*self.atom_table).atom_to_str
|
||||
(name)));
|
||||
ret none;
|
||||
}
|
||||
ChildNameDefinition(def) | ImportNameDefinition(def) {
|
||||
ret some(def);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_identifier_in_local_ribs(identifier: ident,
|
||||
namespace: Namespace)
|
||||
-> option<def> {
|
||||
|
||||
let name = (*self.atom_table).intern(identifier);
|
||||
|
||||
// Check the local set of ribs.
|
||||
let mut search_result;
|
||||
alt namespace {
|
||||
ValueNS {
|
||||
search_result = self.search_ribs(self.value_ribs, name);
|
||||
}
|
||||
TypeNS {
|
||||
search_result = self.search_ribs(self.type_ribs, name);
|
||||
}
|
||||
ModuleNS | ImplNS {
|
||||
fail "module or impl namespaces do not have local ribs";
|
||||
}
|
||||
}
|
||||
|
||||
alt copy search_result {
|
||||
some(dl_def(def)) {
|
||||
#debug("(resolving path in local ribs) resolved '%s' to \
|
||||
local: %?",
|
||||
*(*self.atom_table).atom_to_str(name),
|
||||
def);
|
||||
ret some(def);
|
||||
}
|
||||
some(dl_field) | some(dl_impl(_)) | none {
|
||||
ret none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_item_by_identifier_in_lexical_scope(ident: ident,
|
||||
namespace: Namespace)
|
||||
-> option<def> {
|
||||
|
||||
let name = (*self.atom_table).intern(ident);
|
||||
|
||||
// Check the items.
|
||||
alt self.resolve_item_in_lexical_scope(self.current_module,
|
||||
name,
|
||||
namespace) {
|
||||
|
||||
Success(target) {
|
||||
alt (*target.bindings).def_for_namespace(namespace) {
|
||||
none {
|
||||
fail "resolved name in a namespace to a set of name \
|
||||
bindings with no def for that namespace?!";
|
||||
}
|
||||
some(def) {
|
||||
#debug("(resolving item path in lexical scope) \
|
||||
resolved '%s' to item",
|
||||
*(*self.atom_table).atom_to_str(name));
|
||||
ret some(def);
|
||||
}
|
||||
}
|
||||
}
|
||||
Indeterminate {
|
||||
fail "unexpected indeterminate result";
|
||||
}
|
||||
Failed {
|
||||
ret none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_expr(expr: @expr, visitor: ResolveVisitor) {
|
||||
// First, write the implementations in scope into a table if the
|
||||
// expression might need them.
|
||||
|
||||
self.record_impls_for_expr_if_necessary(expr);
|
||||
|
||||
// Next, resolve the node.
|
||||
alt expr.node {
|
||||
// The interpretation of paths depends on whether the path has
|
||||
// multiple elements in it or not.
|
||||
|
||||
expr_path(path) {
|
||||
// This is a local path in the value namespace. Walk through
|
||||
// scopes looking for it.
|
||||
|
||||
alt self.resolve_path(path, ValueNS, true, visitor) {
|
||||
some(def) {
|
||||
// Write the result into the def map.
|
||||
#debug("(resolving expr) resolved '%s'",
|
||||
connect(path.idents.map(|x| *x), "::"));
|
||||
self.record_def(expr.id, def);
|
||||
}
|
||||
none {
|
||||
self.session.span_err(expr.span,
|
||||
#fmt("use of undeclared \
|
||||
identifier '%s'",
|
||||
connect(path.idents.map(|x| *x),
|
||||
"::")));
|
||||
}
|
||||
}
|
||||
|
||||
visit_expr(expr, (), visitor);
|
||||
}
|
||||
|
||||
expr_fn(_, fn_decl, block, capture_clause) |
|
||||
expr_fn_block(fn_decl, block, capture_clause) {
|
||||
self.resolve_function(FunctionRibKind(expr.id),
|
||||
some(@fn_decl),
|
||||
NoTypeParameters,
|
||||
block,
|
||||
NoSelfBinding,
|
||||
HasCaptureClause(capture_clause),
|
||||
visitor);
|
||||
}
|
||||
|
||||
_ {
|
||||
visit_expr(expr, (), visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn record_impls_for_expr_if_necessary(expr: @expr) {
|
||||
alt expr.node {
|
||||
expr_field(*) | expr_path(*) | expr_cast(*) | expr_binary(*) |
|
||||
expr_unary(*) | expr_assign_op(*) | expr_index(*) {
|
||||
self.impl_map.insert(expr.id,
|
||||
self.current_module.impl_scopes);
|
||||
}
|
||||
expr_new(container, _, _) {
|
||||
self.impl_map.insert(container.id,
|
||||
self.current_module.impl_scopes);
|
||||
}
|
||||
_ {
|
||||
// Nothing to do.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn record_def(node_id: node_id, def: def) {
|
||||
#debug("(recording def) recording %? for %?", def, node_id);
|
||||
self.def_map.insert(node_id, def);
|
||||
}
|
||||
|
||||
//
|
||||
// Diagnostics
|
||||
//
|
||||
// Diagnostics are not particularly efficient, because they're rarely
|
||||
// hit.
|
||||
//
|
||||
|
||||
#[doc="A somewhat inefficient routine to print out the name of a module."]
|
||||
fn module_to_str(module: @Module) -> str {
|
||||
let atoms = dvec();
|
||||
let mut current_module = module;
|
||||
loop {
|
||||
alt current_module.parent_link {
|
||||
NoParentLink {
|
||||
break;
|
||||
}
|
||||
ModuleParentLink(module, name) {
|
||||
atoms.push(name);
|
||||
current_module = module;
|
||||
}
|
||||
BlockParentLink(module, node_id) {
|
||||
atoms.push((*self.atom_table).intern(@"<opaque>"));
|
||||
current_module = module;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if atoms.len() == 0u {
|
||||
ret "???";
|
||||
}
|
||||
|
||||
let mut string = "";
|
||||
let mut i = atoms.len() - 1u;
|
||||
loop {
|
||||
if i < atoms.len() - 1u {
|
||||
string += "::";
|
||||
}
|
||||
string += *(*self.atom_table).atom_to_str(atoms.get_elt(i));
|
||||
|
||||
if i == 0u {
|
||||
break;
|
||||
}
|
||||
i -= 1u;
|
||||
}
|
||||
|
||||
ret string;
|
||||
}
|
||||
|
||||
fn dump_module(module: @Module) {
|
||||
#debug("Dump of module '%s':", self.module_to_str(module));
|
||||
|
||||
#debug("Children:");
|
||||
for module.children.each |name, _child| {
|
||||
#debug("* %s", *(*self.atom_table).atom_to_str(name));
|
||||
}
|
||||
|
||||
#debug("Import resolutions:");
|
||||
for module.import_resolutions.each |name, import_resolution| {
|
||||
let mut module_repr;
|
||||
alt (*import_resolution).target_for_namespace(ModuleNS) {
|
||||
none { module_repr = ""; }
|
||||
some(target) {
|
||||
module_repr = " module:?";
|
||||
// XXX
|
||||
}
|
||||
}
|
||||
|
||||
let mut value_repr;
|
||||
alt (*import_resolution).target_for_namespace(ValueNS) {
|
||||
none { value_repr = ""; }
|
||||
some(target) {
|
||||
value_repr = " value:?";
|
||||
// XXX
|
||||
}
|
||||
}
|
||||
|
||||
let mut type_repr;
|
||||
alt (*import_resolution).target_for_namespace(TypeNS) {
|
||||
none { type_repr = ""; }
|
||||
some(target) {
|
||||
type_repr = " type:?";
|
||||
// XXX
|
||||
}
|
||||
}
|
||||
|
||||
let mut impl_repr;
|
||||
alt (*import_resolution).target_for_namespace(ImplNS) {
|
||||
none { impl_repr = ""; }
|
||||
some(target) {
|
||||
impl_repr = " impl:?";
|
||||
// XXX
|
||||
}
|
||||
}
|
||||
|
||||
#debug("* %s:%s%s%s%s",
|
||||
*(*self.atom_table).atom_to_str(name),
|
||||
module_repr, value_repr, type_repr, impl_repr);
|
||||
}
|
||||
}
|
||||
|
||||
fn dump_impl_scopes(impl_scopes: ImplScopes) {
|
||||
#debug("Dump of impl scopes:");
|
||||
|
||||
let mut i = 0u;
|
||||
let mut impl_scopes = impl_scopes;
|
||||
loop {
|
||||
alt *impl_scopes {
|
||||
cons(impl_scope, rest_impl_scopes) {
|
||||
#debug("Impl scope %u:", i);
|
||||
|
||||
for (*impl_scope).each |implementation| {
|
||||
#debug("Impl: %s", *implementation.ident);
|
||||
}
|
||||
|
||||
i += 1u;
|
||||
impl_scopes = rest_impl_scopes;
|
||||
}
|
||||
nil {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc="Entry point to crate resolution."]
|
||||
fn resolve_crate(session: session, ast_map: ASTMap, crate: @crate)
|
||||
-> { def_map: DefMap, exp_map: ExportMap, impl_map: ImplMap } {
|
||||
|
||||
let resolver = @Resolver(session, ast_map, crate);
|
||||
(*resolver).resolve(resolver);
|
||||
ret {
|
||||
def_map: resolver.def_map,
|
||||
exp_map: resolver.export_map,
|
||||
impl_map: resolver.impl_map
|
||||
};
|
||||
}
|
||||
|
||||
@@ -39,14 +39,16 @@
|
||||
mangle_exported_name};
|
||||
import metadata::{csearch, cstore, encoder};
|
||||
import metadata::common::link_meta;
|
||||
import util::ppaux;
|
||||
import util::ppaux::{ty_to_str, ty_to_short_str};
|
||||
import syntax::diagnostic::expect;
|
||||
|
||||
import common::*;
|
||||
import build::*;
|
||||
import shape::*;
|
||||
import type_of::*;
|
||||
import common::*;
|
||||
import type_of::type_of; // Issue #1873
|
||||
import common::result;
|
||||
import syntax::ast_map::{path, path_mod, path_name};
|
||||
|
||||
import std::smallintmap;
|
||||
@@ -511,7 +513,7 @@ fn declare_tydesc(ccx: @crate_ctxt, t: ty::t) -> @tydesc_info {
|
||||
mut drop_glue: none,
|
||||
mut free_glue: none,
|
||||
mut visit_glue: none};
|
||||
log(debug, "--- declare_tydesc " + ty_to_str(ccx.tcx, t));
|
||||
log(debug, "--- declare_tydesc " + ppaux::ty_to_str(ccx.tcx, t));
|
||||
ret inf;
|
||||
}
|
||||
|
||||
@@ -1106,14 +1108,14 @@ fn lazily_emit_tydesc_glue(ccx: @crate_ctxt, field: uint,
|
||||
some(_) { }
|
||||
none {
|
||||
#debug("+++ lazily_emit_tydesc_glue TAKE %s",
|
||||
ty_to_str(ccx.tcx, ti.ty));
|
||||
ppaux::ty_to_str(ccx.tcx, ti.ty));
|
||||
let glue_fn = declare_generic_glue
|
||||
(ccx, ti.ty, T_glue_fn(ccx), "take");
|
||||
ti.take_glue = some(glue_fn);
|
||||
make_generic_glue(ccx, ti.ty, glue_fn,
|
||||
make_take_glue, "take");
|
||||
#debug("--- lazily_emit_tydesc_glue TAKE %s",
|
||||
ty_to_str(ccx.tcx, ti.ty));
|
||||
ppaux::ty_to_str(ccx.tcx, ti.ty));
|
||||
}
|
||||
}
|
||||
} else if field == abi::tydesc_field_drop_glue {
|
||||
@@ -1121,14 +1123,14 @@ fn lazily_emit_tydesc_glue(ccx: @crate_ctxt, field: uint,
|
||||
some(_) { }
|
||||
none {
|
||||
#debug("+++ lazily_emit_tydesc_glue DROP %s",
|
||||
ty_to_str(ccx.tcx, ti.ty));
|
||||
ppaux::ty_to_str(ccx.tcx, ti.ty));
|
||||
let glue_fn =
|
||||
declare_generic_glue(ccx, ti.ty, T_glue_fn(ccx), "drop");
|
||||
ti.drop_glue = some(glue_fn);
|
||||
make_generic_glue(ccx, ti.ty, glue_fn,
|
||||
make_drop_glue, "drop");
|
||||
#debug("--- lazily_emit_tydesc_glue DROP %s",
|
||||
ty_to_str(ccx.tcx, ti.ty));
|
||||
ppaux::ty_to_str(ccx.tcx, ti.ty));
|
||||
}
|
||||
}
|
||||
} else if field == abi::tydesc_field_free_glue {
|
||||
@@ -1136,14 +1138,14 @@ fn lazily_emit_tydesc_glue(ccx: @crate_ctxt, field: uint,
|
||||
some(_) { }
|
||||
none {
|
||||
#debug("+++ lazily_emit_tydesc_glue FREE %s",
|
||||
ty_to_str(ccx.tcx, ti.ty));
|
||||
ppaux::ty_to_str(ccx.tcx, ti.ty));
|
||||
let glue_fn =
|
||||
declare_generic_glue(ccx, ti.ty, T_glue_fn(ccx), "free");
|
||||
ti.free_glue = some(glue_fn);
|
||||
make_generic_glue(ccx, ti.ty, glue_fn,
|
||||
make_free_glue, "free");
|
||||
#debug("--- lazily_emit_tydesc_glue FREE %s",
|
||||
ty_to_str(ccx.tcx, ti.ty));
|
||||
ppaux::ty_to_str(ccx.tcx, ti.ty));
|
||||
}
|
||||
}
|
||||
} else if field == abi::tydesc_field_visit_glue {
|
||||
@@ -1151,14 +1153,14 @@ fn lazily_emit_tydesc_glue(ccx: @crate_ctxt, field: uint,
|
||||
some(_) { }
|
||||
none {
|
||||
#debug("+++ lazily_emit_tydesc_glue VISIT %s",
|
||||
ty_to_str(ccx.tcx, ti.ty));
|
||||
ppaux::ty_to_str(ccx.tcx, ti.ty));
|
||||
let glue_fn =
|
||||
declare_generic_glue(ccx, ti.ty, T_glue_fn(ccx), "visit");
|
||||
ti.visit_glue = some(glue_fn);
|
||||
make_generic_glue(ccx, ti.ty, glue_fn,
|
||||
make_visit_glue, "visit");
|
||||
#debug("--- lazily_emit_tydesc_glue VISIT %s",
|
||||
ty_to_str(ccx.tcx, ti.ty));
|
||||
ppaux::ty_to_str(ccx.tcx, ti.ty));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1383,7 +1385,7 @@ fn copy_val_no_check(bcx: block, action: copy_action, dst: ValueRef,
|
||||
ret take_ty(bcx, dst, t);
|
||||
}
|
||||
ccx.sess.bug("unexpected type in trans::copy_val_no_check: " +
|
||||
ty_to_str(ccx.tcx, t));
|
||||
ppaux::ty_to_str(ccx.tcx, t));
|
||||
}
|
||||
|
||||
|
||||
@@ -1422,7 +1424,7 @@ fn move_val(cx: block, action: copy_action, dst: ValueRef,
|
||||
ret cx;
|
||||
}
|
||||
cx.sess().bug("unexpected type in trans::move_val: " +
|
||||
ty_to_str(tcx, t));
|
||||
ppaux::ty_to_str(tcx, t));
|
||||
}
|
||||
|
||||
fn store_temp_expr(cx: block, action: copy_action, dst: ValueRef,
|
||||
@@ -1810,7 +1812,7 @@ fn autoderef(cx: block, e_id: ast::node_id,
|
||||
let mut derefs = 0u;
|
||||
while derefs < max {
|
||||
#debug["autoderef(e_id=%d, v1=%s, t1=%s, derefs=%u)",
|
||||
e_id, val_str(ccx.tn, v1), ty_to_str(ccx.tcx, t1),
|
||||
e_id, val_str(ccx.tn, v1), ppaux::ty_to_str(ccx.tcx, t1),
|
||||
derefs];
|
||||
|
||||
// root the autoderef'd value, if necessary:
|
||||
@@ -2140,7 +2142,6 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id,
|
||||
|
||||
for real_substs.each() |s| { assert !ty::type_has_params(s); }
|
||||
for substs.each() |s| { assert !ty::type_has_params(s); }
|
||||
|
||||
let param_uses = type_use::type_uses_for(ccx, fn_id, substs.len());
|
||||
let hash_id = make_mono_id(ccx, fn_id, substs, vtables, some(param_uses));
|
||||
if vec::any(hash_id.params,
|
||||
@@ -2156,6 +2157,8 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id,
|
||||
|
||||
alt ccx.monomorphized.find(hash_id) {
|
||||
some(val) {
|
||||
#debug["leaving monomorphic fn %s",
|
||||
ty::item_path_str(ccx.tcx, fn_id)];
|
||||
ret {val: val, must_cast: must_cast};
|
||||
}
|
||||
none {}
|
||||
@@ -2286,6 +2289,8 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id,
|
||||
}
|
||||
};
|
||||
ccx.monomorphizing.insert(fn_id, depth);
|
||||
|
||||
#debug["leaving monomorphic fn %s", ty::item_path_str(ccx.tcx, fn_id)];
|
||||
{val: lldecl, must_cast: must_cast}
|
||||
}
|
||||
|
||||
@@ -3056,7 +3061,7 @@ fn adapt_borrowed_value(lv: lval_result,
|
||||
_ {
|
||||
bcx.tcx().sess.span_bug(
|
||||
e.span, #fmt["cannot borrow a value of type %s",
|
||||
ty_to_str(bcx.tcx(), e_ty)]);
|
||||
ppaux::ty_to_str(bcx.tcx(), e_ty)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3517,7 +3522,7 @@ fn add_root_cleanup(bcx: block, scope_id: ast::node_id,
|
||||
|
||||
#debug["add_root_cleanup(bcx=%s, scope_id=%d, root_loc=%s, ty=%s)",
|
||||
bcx.to_str(), scope_id, val_str(bcx.ccx().tn, root_loc),
|
||||
ty_to_str(bcx.ccx().tcx, ty)];
|
||||
ppaux::ty_to_str(bcx.ccx().tcx, ty)];
|
||||
|
||||
let bcx_scope = find_bcx_for_scope(bcx, scope_id);
|
||||
add_clean_temp_mem(bcx_scope, root_loc, ty);
|
||||
@@ -3614,7 +3619,8 @@ fn unrooted(bcx: block, e: @ast::expr, dest: dest) -> block {
|
||||
alt check ty::get(expr_ty(bcx, e)).struct {
|
||||
ty::ty_fn({proto, _}) {
|
||||
#debug("translating fn_block %s with type %s",
|
||||
expr_to_str(e), ty_to_str(tcx, expr_ty(bcx, e)));
|
||||
expr_to_str(e),
|
||||
ppaux::ty_to_str(tcx, expr_ty(bcx, e)));
|
||||
ret closure::trans_expr_fn(bcx, proto, decl, body,
|
||||
e.id, cap_clause, none, dest);
|
||||
}
|
||||
@@ -3754,7 +3760,7 @@ fn unrooted(bcx: block, e: @ast::expr, dest: dest) -> block {
|
||||
let ptr_ty = expr_ty(bcx, e);
|
||||
let ptr_ptr_val = alloc_ty(bcx, ptr_ty);
|
||||
|
||||
#debug["ptr_ty = %s", ty_to_str(tcx, ptr_ty)];
|
||||
#debug["ptr_ty = %s", ppaux::ty_to_str(tcx, ptr_ty)];
|
||||
#debug["ptr_ptr_val = %s", val_str(ccx.tn, ptr_ptr_val)];
|
||||
|
||||
let void_ty = ty::mk_ptr(tcx, {ty: ty::mk_nil(tcx),
|
||||
@@ -3947,7 +3953,7 @@ fn trans_fail_expr(bcx: block, sp_opt: option<span>,
|
||||
} else {
|
||||
bcx.sess().span_bug(
|
||||
expr.span, "fail called with unsupported type " +
|
||||
ty_to_str(tcx, e_ty));
|
||||
ppaux::ty_to_str(tcx, e_ty));
|
||||
}
|
||||
}
|
||||
_ { ret trans_fail(bcx, sp_opt, "explicit failure"); }
|
||||
@@ -4345,7 +4351,7 @@ fn alloc_ty(bcx: block, t: ty::t) -> ValueRef {
|
||||
let _icx = bcx.insn_ctxt("alloc_ty");
|
||||
let ccx = bcx.ccx();
|
||||
let llty = type_of(ccx, t);
|
||||
if ty::type_has_params(t) { log(error, ty_to_str(ccx.tcx, t)); }
|
||||
if ty::type_has_params(t) { log(error, ppaux::ty_to_str(ccx.tcx, t)); }
|
||||
assert !ty::type_has_params(t);
|
||||
let val = alloca(bcx, llty);
|
||||
ret val;
|
||||
|
||||
@@ -264,6 +264,9 @@ fn store_environment(bcx: block,
|
||||
bcx = move_val(bcx, INIT, bound_data, src, ty);
|
||||
}
|
||||
env_ref(val, ty, owned) {
|
||||
#debug["> storing %s into %s",
|
||||
val_str(bcx.ccx().tn, val),
|
||||
val_str(bcx.ccx().tn, bound_data)];
|
||||
Store(bcx, val, bound_data);
|
||||
}
|
||||
env_ref(val, ty, owned_imm) {
|
||||
@@ -298,6 +301,8 @@ fn build_closure(bcx0: block,
|
||||
#debug["Building closure: captured variable %?", cap_var];
|
||||
let lv = trans_local_var(bcx, cap_var.def);
|
||||
let nid = ast_util::def_id_of_def(cap_var.def).node;
|
||||
#debug["Node id is %s",
|
||||
syntax::ast_map::node_id_to_str(bcx.ccx().tcx.items, nid)];
|
||||
let mut ty = node_id_type(bcx, nid);
|
||||
alt cap_var.mode {
|
||||
capture::cap_ref {
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
ModuleRef, CallConv, Attribute,
|
||||
StructRetAttribute, ByValAttribute,
|
||||
SequentiallyConsistent, Acquire, Release,
|
||||
Xchg, Add, Sub
|
||||
};
|
||||
Xchg };
|
||||
import syntax::{ast, ast_util};
|
||||
import back::{link, abi};
|
||||
import common::*;
|
||||
@@ -830,42 +829,42 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item,
|
||||
Store(bcx, old, fcx.llretptr);
|
||||
}
|
||||
"atomic_add" {
|
||||
let old = AtomicRMW(bcx, Add,
|
||||
let old = AtomicRMW(bcx, lib::llvm::Add,
|
||||
get_param(decl, first_real_arg),
|
||||
get_param(decl, first_real_arg + 1u),
|
||||
SequentiallyConsistent);
|
||||
Store(bcx, old, fcx.llretptr);
|
||||
}
|
||||
"atomic_add_acq" {
|
||||
let old = AtomicRMW(bcx, Add,
|
||||
let old = AtomicRMW(bcx, lib::llvm::Add,
|
||||
get_param(decl, first_real_arg),
|
||||
get_param(decl, first_real_arg + 1u),
|
||||
Acquire);
|
||||
Store(bcx, old, fcx.llretptr);
|
||||
}
|
||||
"atomic_add_rel" {
|
||||
let old = AtomicRMW(bcx, Add,
|
||||
let old = AtomicRMW(bcx, lib::llvm::Add,
|
||||
get_param(decl, first_real_arg),
|
||||
get_param(decl, first_real_arg + 1u),
|
||||
Release);
|
||||
Store(bcx, old, fcx.llretptr);
|
||||
}
|
||||
"atomic_sub" {
|
||||
let old = AtomicRMW(bcx, Sub,
|
||||
let old = AtomicRMW(bcx, lib::llvm::Sub,
|
||||
get_param(decl, first_real_arg),
|
||||
get_param(decl, first_real_arg + 1u),
|
||||
SequentiallyConsistent);
|
||||
Store(bcx, old, fcx.llretptr);
|
||||
}
|
||||
"atomic_sub_acq" {
|
||||
let old = AtomicRMW(bcx, Sub,
|
||||
let old = AtomicRMW(bcx, lib::llvm::Sub,
|
||||
get_param(decl, first_real_arg),
|
||||
get_param(decl, first_real_arg + 1u),
|
||||
Acquire);
|
||||
Store(bcx, old, fcx.llretptr);
|
||||
}
|
||||
"atomic_sub_rel" {
|
||||
let old = AtomicRMW(bcx, Sub,
|
||||
let old = AtomicRMW(bcx, lib::llvm::Sub,
|
||||
get_param(decl, first_real_arg),
|
||||
get_param(decl, first_real_arg + 1u),
|
||||
Release);
|
||||
|
||||
@@ -81,6 +81,18 @@ fn traverse_public_mod(cx: ctx, m: _mod) {
|
||||
if !traverse_exports(cx, m.view_items) {
|
||||
// No exports, so every local item is exported
|
||||
for vec::each(m.items) |item| { traverse_public_item(cx, item); }
|
||||
} else {
|
||||
// Make impls always reachable.
|
||||
for vec::each(m.items) |item| {
|
||||
alt item.node {
|
||||
item_impl(*) {
|
||||
traverse_public_item(cx, item);
|
||||
}
|
||||
_ {
|
||||
// Nothing to do.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
import driver::session::session;
|
||||
import std::map::hashmap;
|
||||
|
||||
import ty::*;
|
||||
|
||||
export type_of;
|
||||
export type_of_dtor;
|
||||
export type_of_explicit_args;
|
||||
@@ -174,7 +172,7 @@ fn type_of(cx: @crate_ctxt, t: ty::t) -> TypeRef {
|
||||
alt ty::get(t).struct {
|
||||
ty::ty_class(did, ts) {
|
||||
// Only instance vars are record fields at runtime.
|
||||
let fields = lookup_class_fields(cx.tcx, did);
|
||||
let fields = ty::lookup_class_fields(cx.tcx, did);
|
||||
let mut tys = do vec::map(fields) |f| {
|
||||
let t = ty::lookup_field_type(cx.tcx, did, f.id, ts);
|
||||
type_of(cx, t)
|
||||
|
||||
+14
-5
@@ -11,11 +11,11 @@
|
||||
import metadata::csearch;
|
||||
import util::ppaux::region_to_str;
|
||||
import util::ppaux::vstore_to_str;
|
||||
import util::ppaux::{ty_to_str, tys_to_str, ty_constr_to_str};
|
||||
import middle::lint::{get_warning_level, vecs_not_implicitly_copyable,
|
||||
ignore};
|
||||
import syntax::ast::*;
|
||||
import syntax::print::pprust::*;
|
||||
import util::ppaux::{ty_to_str, tys_to_str, ty_constr_to_str};
|
||||
|
||||
export tv_vid, tvi_vid, region_vid, vid;
|
||||
export br_hashmap;
|
||||
@@ -105,7 +105,10 @@
|
||||
export ty_var, mk_var, type_is_var;
|
||||
export ty_var_integral, mk_var_integral, type_is_var_integral;
|
||||
export ty_self, mk_self, type_has_self;
|
||||
export ty_class;
|
||||
export region, bound_region, encl_region;
|
||||
export re_bound, re_free, re_scope, re_static, re_var;
|
||||
export br_self, br_anon, br_named;
|
||||
export get, type_has_params, type_needs_infer, type_has_regions;
|
||||
export type_has_resources, type_id;
|
||||
export tbox_has_flag;
|
||||
@@ -2528,6 +2531,7 @@ fn iface_methods(cx: ctxt, id: ast::def_id) -> @~[method] {
|
||||
|
||||
fn impl_iface(cx: ctxt, id: ast::def_id) -> option<t> {
|
||||
if id.crate == ast::local_crate {
|
||||
#debug("(impl_iface) searching for iface impl %?", id);
|
||||
alt cx.items.find(id.node) {
|
||||
some(ast_map::node_item(@{node: ast::item_impl(
|
||||
_, _, some(@{id: id, _}), _, _), _}, _)) {
|
||||
@@ -2537,11 +2541,16 @@ fn impl_iface(cx: ctxt, id: ast::def_id) -> option<t> {
|
||||
_},_)) {
|
||||
alt cx.def_map.find(id.node) {
|
||||
some(def_ty(iface_id)) {
|
||||
some(node_id_to_type(cx, id.node))
|
||||
// XXX: Doesn't work cross-crate.
|
||||
#debug("(impl_iface) found iface id %?", iface_id);
|
||||
some(node_id_to_type(cx, iface_id.node))
|
||||
}
|
||||
_ {
|
||||
cx.sess.bug("impl_iface: iface ref isn't in iface map \
|
||||
and isn't bound to a def_ty");
|
||||
some(x) {
|
||||
cx.sess.bug(#fmt("impl_iface: iface ref is in iface map \
|
||||
but is bound to %?", x));
|
||||
}
|
||||
none {
|
||||
none
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,8 +53,6 @@
|
||||
import middle::ty::{arg, field, node_type_table, mk_nil,
|
||||
ty_param_bounds_and_ty, lookup_public_fields};
|
||||
import middle::typeck::infer::methods;
|
||||
import util::ppaux::{ty_to_str, tys_to_str, region_to_str,
|
||||
bound_region_to_str, vstore_to_str};
|
||||
import std::smallintmap;
|
||||
import std::smallintmap::map;
|
||||
import std::map;
|
||||
@@ -62,6 +60,8 @@
|
||||
import std::serialization::{serialize_uint, deserialize_uint};
|
||||
import vec::each;
|
||||
import syntax::print::pprust::*;
|
||||
import util::ppaux::{ty_to_str, tys_to_str, region_to_str,
|
||||
bound_region_to_str, vstore_to_str};
|
||||
import util::common::{indent, indenter};
|
||||
import std::list;
|
||||
import list::{list, nil, cons};
|
||||
|
||||
@@ -74,6 +74,8 @@ fn lookup_vtable(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span,
|
||||
alt check ty::get(ity).struct {
|
||||
ty::ty_iface(idid, substs) {
|
||||
if iface_id == idid {
|
||||
#debug("(checking vtable) @0 relating ty to iface ty
|
||||
with did %?", idid);
|
||||
relate_iface_tys(fcx, sp, iface_ty, ity);
|
||||
ret vtable_param(n, n_bound);
|
||||
}
|
||||
@@ -86,6 +88,9 @@ fn lookup_vtable(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span,
|
||||
}
|
||||
|
||||
ty::ty_iface(did, substs) if iface_id == did {
|
||||
#debug("(checking vtable) @1 relating ty to iface ty with did %?",
|
||||
did);
|
||||
|
||||
relate_iface_tys(fcx, sp, iface_ty, ty);
|
||||
if !allow_unsafe {
|
||||
for vec::each(*ty::iface_methods(tcx, did)) |m| {
|
||||
@@ -134,6 +139,10 @@ fn lookup_vtable(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span,
|
||||
}
|
||||
|
||||
// check that desired iface type unifies
|
||||
#debug("(checking vtable) @2 relating iface ty %s to \
|
||||
of_ty %s",
|
||||
fcx.infcx.ty_to_str(iface_ty),
|
||||
fcx.infcx.ty_to_str(of_ty));
|
||||
let of_ty = ty::subst(tcx, substs, of_ty);
|
||||
relate_iface_tys(fcx, sp, iface_ty, of_ty);
|
||||
|
||||
@@ -186,6 +195,8 @@ fn connect_iface_tps(fcx: @fn_ctxt, sp: span, impl_tys: ~[ty::t],
|
||||
let tcx = fcx.ccx.tcx;
|
||||
let ity = option::get(ty::impl_iface(tcx, impl_did));
|
||||
let iface_ty = ty::subst_tps(tcx, impl_tys, ity);
|
||||
#debug("(connect iface tps) iface type is %?, impl did is %?",
|
||||
ty::get(iface_ty).struct, impl_did);
|
||||
alt check ty::get(iface_ty).struct {
|
||||
ty::ty_iface(_, substs) {
|
||||
vec::iter2(substs.tps, iface_tys,
|
||||
|
||||
@@ -52,6 +52,7 @@ mod middle {
|
||||
}
|
||||
mod ty;
|
||||
mod resolve;
|
||||
mod resolve3;
|
||||
mod typeck {
|
||||
mod check {
|
||||
mod alt;
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
export ctxt;
|
||||
export ctxt_handler;
|
||||
export srv::{};
|
||||
export srv;
|
||||
export from_str;
|
||||
export from_file;
|
||||
export exec;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// xfail-test
|
||||
|
||||
import to_str::*;
|
||||
import to_str::to_str;
|
||||
|
||||
@@ -45,4 +47,4 @@ fn print_out<T: to_str>(thing: T, expected: str) {
|
||||
fn main() {
|
||||
let nyan : to_str = cat(0u, 2, "nyan") as to_str;
|
||||
print_out(nyan, "nyan");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// xfail-test
|
||||
|
||||
use std;
|
||||
import std::map::{map, hashmap, int_hash};
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
// xfail-test
|
||||
// xfail-fast
|
||||
|
||||
use std;
|
||||
import std::map::*;
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// xfail-test
|
||||
|
||||
use std;
|
||||
import std::map::*;
|
||||
import vec::*;
|
||||
@@ -116,4 +118,4 @@ fn main() {
|
||||
assert(nyan.meow_count() == 10u);
|
||||
assert(bite_everything(nyan as bitey));
|
||||
assert(scratched_something(nyan as scratchy));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// xfail-test
|
||||
// xfail-fast
|
||||
// (Not sure why, though -- FIXME (tjc)
|
||||
import to_str::*;
|
||||
import to_str::to_str;
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// Test that a glob-export functions as an import
|
||||
// when referenced within its own local scope.
|
||||
|
||||
// Modified to not use export since it's going away. --pcw
|
||||
|
||||
mod foo {
|
||||
export bar::*;
|
||||
import bar::*;
|
||||
mod bar {
|
||||
const a : int = 10;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
// Test that a glob-export functions as an explicit
|
||||
// named export when referenced from outside its scope.
|
||||
|
||||
// Modified to not use export since it's going away. --pcw
|
||||
|
||||
mod foo {
|
||||
export bar::*;
|
||||
import bar::*;
|
||||
export a;
|
||||
mod bar {
|
||||
const a : int = 10;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user