import std::map::hashmap; import middle::ty; import middle::ty::{arg, bound_region, br_anon, br_named, canon_mode}; import middle::ty::{ck_block, ck_box, ck_uniq, constr, ctxt, field, method}; import middle::ty::{mt, re_bound, re_free, re_scope, re_var, region, t}; import middle::ty::{ty_bool, ty_bot, ty_box, ty_class, ty_constr, ty_enum}; import middle::ty::{ty_estr, ty_evec, ty_float, ty_fn, ty_trait, ty_int}; import middle::ty::{ty_nil, ty_opaque_box, ty_opaque_closure_ptr, ty_param}; import middle::ty::{ty_ptr, ty_rec, ty_rptr, ty_self, ty_str, ty_tup}; import middle::ty::{ty_type, ty_uniq, ty_uint, ty_var, ty_var_integral}; import middle::ty::{ty_vec, ty_unboxed_vec, vid}; import metadata::encoder; import syntax::codemap; import syntax::print::pprust; import syntax::print::pprust::{path_to_str, constr_args_to_str, proto_to_str, mode_to_str, purity_to_str}; import syntax::{ast, ast_util}; import syntax::ast_map; import driver::session::session; fn bound_region_to_str(cx: ctxt, br: bound_region) -> str { alt br { br_anon { "&" } br_named(str) { #fmt["&%s", *str] } br_self if cx.sess.ppregions() { "&" } br_self { "&self" } } } fn re_scope_id_to_str(cx: ctxt, node_id: ast::node_id) -> str { alt cx.items.find(node_id) { some(ast_map::node_block(blk)) { #fmt("", codemap::span_to_str(blk.span, cx.sess.codemap)) } some(ast_map::node_expr(expr)) { alt expr.node { ast::expr_call(*) { #fmt("", codemap::span_to_str(expr.span, cx.sess.codemap)) } ast::expr_alt(*) { #fmt("", codemap::span_to_str(expr.span, cx.sess.codemap)) } ast::expr_field(*) | ast::expr_unary(*) | ast::expr_binary(*) { #fmt("", codemap::span_to_str(expr.span, cx.sess.codemap)) } _ { cx.sess.bug( #fmt["re_scope refers to %s", ast_map::node_id_to_str(cx.items, node_id)]) } } } none { // FIXME(#2586) #fmt["", node_id] } _ { cx.sess.bug( #fmt["re_scope refers to %s", ast_map::node_id_to_str(cx.items, node_id)]) } } } fn region_to_str(cx: ctxt, region: region) -> str { alt region { re_scope(node_id) { #fmt["&%s", re_scope_id_to_str(cx, node_id)] } re_bound(br) { bound_region_to_str(cx, br) } re_free(id, br) { if cx.sess.ppregions() { // For debugging, this version is sometimes helpful: #fmt["{%d} %s", id, bound_region_to_str(cx, br)] } else { // But this version is what the user expects to see: bound_region_to_str(cx, br) } } // These two should not be seen by end-users (very often, anyhow): re_var(id) { #fmt("&%s", id.to_str()) } re_static { "&static" } } } fn mt_to_str(cx: ctxt, m: mt) -> str { let mstr = alt m.mutbl { ast::m_mutbl { "mut " } ast::m_imm { "" } ast::m_const { "const " } }; ret mstr + ty_to_str(cx, m.ty); } fn vstore_to_str(cx: ctxt, vs: ty::vstore) -> str { alt vs { ty::vstore_fixed(n) { #fmt["%u", n] } ty::vstore_uniq { "~" } ty::vstore_box { "@" } ty::vstore_slice(r) { region_to_str(cx, r) } } } fn tys_to_str(cx: ctxt, ts: ~[t]) -> str { let mut rs = ""; for ts.each |t| { rs += ty_to_str(cx, t); } rs } fn ty_to_str(cx: ctxt, typ: t) -> str { fn fn_input_to_str(cx: ctxt, input: {mode: ast::mode, ty: t}) -> str { let {mode, ty} = input; let modestr = alt canon_mode(cx, mode) { ast::infer(_) { "" } ast::expl(m) { if !ty::type_needs_infer(ty) && m == ty::default_arg_mode_for_ty(ty) { "" } else { mode_to_str(ast::expl(m)) } } }; modestr + ty_to_str(cx, ty) } fn fn_to_str(cx: ctxt, purity: ast::purity, proto: ast::proto, ident: option, inputs: ~[arg], output: t, cf: ast::ret_style, constrs: ~[@constr]) -> str { let mut s; s = alt purity { ast::impure_fn {""} _ {purity_to_str(purity) + " "} }; s += proto_to_str(proto); alt ident { some(i) { s += " "; s += *i; } _ { } } s += "("; let mut strs = ~[]; for inputs.each |a| { vec::push(strs, fn_input_to_str(cx, a)); } s += str::connect(strs, ", "); s += ")"; if ty::get(output).struct != ty_nil { s += " -> "; alt cf { ast::noreturn { s += "!"; } ast::return_val { s += ty_to_str(cx, output); } } } s += constrs_str(constrs); ret s; } fn method_to_str(cx: ctxt, m: method) -> str { ret fn_to_str( cx, m.fty.purity, m.fty.proto, some(m.ident), m.fty.inputs, m.fty.output, m.fty.ret_style, m.fty.constraints) + ";"; } fn field_to_str(cx: ctxt, f: field) -> str { ret *f.ident + ": " + mt_to_str(cx, f.mt); } // if there is an id, print that instead of the structural type: for ty::type_def_id(typ).each |def_id| { // note that this typedef cannot have type parameters ret ast_map::path_to_str(ty::item_path(cx, def_id)); } // pretty print the structural type representation: ret alt ty::get(typ).struct { ty_nil { "()" } ty_bot { "_|_" } ty_bool { "bool" } ty_int(ast::ty_i) { "int" } ty_int(ast::ty_char) { "char" } ty_int(t) { ast_util::int_ty_to_str(t) } ty_uint(ast::ty_u) { "uint" } ty_uint(t) { ast_util::uint_ty_to_str(t) } ty_float(ast::ty_f) { "float" } ty_float(t) { ast_util::float_ty_to_str(t) } ty_str { "str" } ty_box(tm) { "@" + mt_to_str(cx, tm) } ty_uniq(tm) { "~" + mt_to_str(cx, tm) } ty_ptr(tm) { "*" + mt_to_str(cx, tm) } ty_rptr(r, tm) { let rs = region_to_str(cx, r); if rs == "&" { rs + mt_to_str(cx, tm) } else { rs + "/" + mt_to_str(cx, tm) } } ty_vec(tm) { "[" + mt_to_str(cx, tm) + "]" } ty_unboxed_vec(tm) { "unboxed_vec<" + mt_to_str(cx, tm) + ">" } ty_type { "type" } ty_rec(elems) { let mut strs: ~[str] = ~[]; for elems.each |fld| { vec::push(strs, field_to_str(cx, fld)); } "{" + str::connect(strs, ",") + "}" } ty_tup(elems) { let mut strs = ~[]; for elems.each |elem| { vec::push(strs, ty_to_str(cx, elem)); } "(" + str::connect(strs, ",") + ")" } ty_fn(f) { fn_to_str(cx, f.purity, f.proto, none, f.inputs, f.output, f.ret_style, f.constraints) } ty_var(v) { v.to_str() } ty_var_integral(v) { v.to_str() } ty_param(id, _) { "'" + str::from_bytes(~[('a' as u8) + (id as u8)]) } ty_self { "self" } ty_enum(did, substs) | ty_class(did, substs) { let path = ty::item_path(cx, did); let base = ast_map::path_to_str(path); parameterized(cx, base, substs.self_r, substs.tps) } ty_trait(did, substs) { let path = ty::item_path(cx, did); let base = ast_map::path_to_str(path); parameterized(cx, base, substs.self_r, substs.tps) } ty_evec(mt, vs) { alt vs { ty::vstore_fixed(_) { #fmt["[%s]/%s", mt_to_str(cx, mt), vstore_to_str(cx, vs)] } _ { #fmt["%s[%s]", vstore_to_str(cx, vs), mt_to_str(cx, mt)] } } } ty_estr(vs) { #fmt["str/%s", vstore_to_str(cx, vs)] } ty_opaque_box { "@?" } ty_constr(t, _) { "@?" } ty_opaque_closure_ptr(ck_block) { "closure&" } ty_opaque_closure_ptr(ck_box) { "closure@" } ty_opaque_closure_ptr(ck_uniq) { "closure~" } } } fn parameterized(cx: ctxt, base: str, self_r: option, tps: ~[ty::t]) -> str { let r_str = alt self_r { none { "" } some(r) { #fmt["/%s", region_to_str(cx, r)] } }; if vec::len(tps) > 0u { let strs = vec::map(tps, |t| ty_to_str(cx, t) ); #fmt["%s%s<%s>", base, r_str, str::connect(strs, ",")] } else { #fmt["%s%s", base, r_str] } } fn ty_to_short_str(cx: ctxt, typ: t) -> str { let mut s = encoder::encoded_ty(cx, typ); if str::len(s) >= 32u { s = str::slice(s, 0u, 32u); } ret s; } fn constr_to_str(c: @constr) -> str { ret path_to_str(c.node.path) + pprust::constr_args_to_str(pprust::uint_to_str, c.node.args); } fn constrs_str(constrs: ~[@constr]) -> str { let mut s = ""; let mut colon = true; for constrs.each |c| { if colon { s += " : "; colon = false; } else { s += ", "; } s += constr_to_str(c); } ret s; } fn ty_constr_to_str(c: @ast::spanned>) -> str { ret path_to_str(c.node.path) + constr_args_to_str::<@ast::path>(path_to_str, c.node.args); } // Local Variables: // mode: rust // fill-column: 78; // indent-tabs-mode: nil // c-basic-offset: 4 // buffer-file-coding-system: utf-8-unix // End: