github.com/guyezi/gofrontend@v0.0.0-20200228202240-7a62a49e62c0/go/ast-dump.cc (about)

     1  // ast-dump.cc -- AST debug dump.    -*- C++ -*-
     2  
     3  // Copyright 2011 The Go Authors. All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license that can be found in the LICENSE file.
     6  
     7  #include "go-system.h"
     8  
     9  #include <iostream>
    10  #include <fstream>
    11  #include <sstream>
    12  
    13  #include "gogo.h"
    14  #include "expressions.h"
    15  #include "statements.h"
    16  #include "types.h"
    17  #include "ast-dump.h"
    18  #include "go-c.h"
    19  #include "go-dump.h"
    20  #include "go-diagnostics.h"
    21  
    22  // The -fgo-dump-ast flag to activate AST dumps.
    23  
    24  Go_dump ast_dump_flag("ast");
    25  
    26  // This class is used to traverse the tree to look for blocks and
    27  // function headers.
    28  
    29  class Ast_dump_traverse_blocks_and_functions : public Traverse
    30  {
    31   public:
    32    Ast_dump_traverse_blocks_and_functions(Ast_dump_context* ast_dump_context)
    33        : Traverse(traverse_blocks | traverse_functions | traverse_variables),
    34        ast_dump_context_(ast_dump_context)
    35    { }
    36  
    37   protected:
    38    int
    39    block(Block*);
    40  
    41    int
    42    function(Named_object*);
    43  
    44    int
    45    variable(Named_object*);
    46  
    47   private:
    48    Ast_dump_context* ast_dump_context_;
    49  };
    50  
    51  // This class is used to traverse the tree to look for statements.
    52  
    53  class Ast_dump_traverse_statements : public Traverse
    54  {
    55   public:
    56    Ast_dump_traverse_statements(Ast_dump_context* ast_dump_context)
    57        : Traverse(traverse_statements),
    58        ast_dump_context_(ast_dump_context)
    59    { }
    60  
    61   protected:
    62    int
    63    statement(Block*, size_t* pindex, Statement*);
    64  
    65   private:
    66    Ast_dump_context* ast_dump_context_;
    67  };
    68  
    69  // For each block we enclose it in brackets.
    70  
    71  int Ast_dump_traverse_blocks_and_functions::block(Block * block)
    72  {
    73    if (block == NULL)
    74      {
    75        this->ast_dump_context_->ostream() << std::endl;
    76        return TRAVERSE_EXIT;
    77      }
    78  
    79    this->ast_dump_context_->print_indent();
    80    this->ast_dump_context_->ostream() << "{" << std::endl;
    81    this->ast_dump_context_->indent();
    82  
    83    // Dump statememts.
    84    Ast_dump_traverse_statements adts(this->ast_dump_context_);
    85    block->traverse(&adts);
    86  
    87    this->ast_dump_context_->unindent();
    88    this->ast_dump_context_->print_indent();
    89    this->ast_dump_context_->ostream() << "}" << std::endl;
    90  
    91    return TRAVERSE_SKIP_COMPONENTS;
    92  }
    93  
    94  // Dump each traversed statement.
    95  
    96  int
    97  Ast_dump_traverse_statements::statement(Block* block, size_t* pindex,
    98                                          Statement* statement)
    99  {
   100    statement->dump_statement(this->ast_dump_context_);
   101  
   102    if (statement->is_block_statement())
   103      {
   104        Ast_dump_traverse_blocks_and_functions adtbf(this->ast_dump_context_);
   105        statement->traverse(block, pindex, &adtbf);
   106      }
   107  
   108    return TRAVERSE_SKIP_COMPONENTS;
   109  }
   110  
   111  // Dump the function header.
   112  
   113  int
   114  Ast_dump_traverse_blocks_and_functions::function(Named_object* no)
   115  {
   116    this->ast_dump_context_->ostream() << no->name();
   117  
   118    go_assert(no->is_function());
   119    Function* func = no->func_value();
   120  
   121    this->ast_dump_context_->ostream() << "(";
   122    this->ast_dump_context_->dump_typed_identifier_list(
   123                                func->type()->parameters());
   124  
   125    this->ast_dump_context_->ostream() << ")";
   126  
   127    Function::Results* res = func->result_variables();
   128    if (res != NULL && !res->empty())
   129      {
   130        this->ast_dump_context_->ostream() << " (";
   131  
   132        for (Function::Results::const_iterator it = res->begin();
   133            it != res->end();
   134            it++)
   135          {
   136            if (it != res->begin())
   137              this->ast_dump_context_->ostream() << ",";
   138            Named_object* rno = (*it);
   139  
   140            this->ast_dump_context_->ostream() << rno->name() << " ";
   141            go_assert(rno->is_result_variable());
   142            Result_variable* resvar = rno->result_var_value();
   143  
   144            this->ast_dump_context_->dump_type(resvar->type());
   145  
   146          }
   147        this->ast_dump_context_->ostream() << ")";
   148      }
   149  
   150    this->ast_dump_context_->ostream() << " : ";
   151    this->ast_dump_context_->dump_type(func->type());
   152    this->ast_dump_context_->ostream() << std::endl;
   153  
   154    return TRAVERSE_CONTINUE;
   155  }
   156  
   157  // Dump variable preinits
   158  
   159  int
   160  Ast_dump_traverse_blocks_and_functions::variable(Named_object* no)
   161  {
   162    if (!no->is_variable())
   163      return TRAVERSE_CONTINUE;
   164  
   165    Variable* var = no->var_value();
   166    if (var->has_pre_init())
   167      {
   168        this->ast_dump_context_->ostream() << "// preinit block for var "
   169                                           << no->message_name() << "\n";
   170        var->preinit()->traverse(this);
   171      }
   172  
   173    return TRAVERSE_CONTINUE;
   174  }
   175  
   176  
   177  
   178  // Class Ast_dump_context.
   179  
   180  Ast_dump_context::Ast_dump_context(std::ostream* out /* = NULL */,
   181  				   bool dump_subblocks /* = true */)
   182    :  indent_(0), dump_subblocks_(dump_subblocks), ostream_(out), gogo_(NULL)
   183  {
   184  }
   185  
   186  // Dump files will be named %basename%.dump.ast
   187  
   188  const char* kAstDumpFileExtension = ".dump.ast";
   189  
   190  // Dump the internal representation.
   191  
   192  void
   193  Ast_dump_context::dump(Gogo* gogo, const char* basename)
   194  {
   195    std::ofstream out;
   196    std::string dumpname(basename);
   197    dumpname += ".dump.ast";
   198    out.open(dumpname.c_str());
   199  
   200    if (out.fail())
   201      {
   202        go_error_at(Linemap::unknown_location(),
   203  		  "cannot open %s:%m; %<-fgo-dump-ast%> ignored",
   204  		  dumpname.c_str());
   205        return;
   206      }
   207  
   208    this->gogo_ = gogo;
   209    this->ostream_ = &out;
   210  
   211    Ast_dump_traverse_blocks_and_functions adtbf(this);
   212    gogo->traverse(&adtbf);
   213  
   214    out.close();
   215  }
   216  
   217  // Dump a textual representation of a type to the
   218  // the dump file.
   219  
   220  void
   221  Ast_dump_context::dump_type(const Type* t)
   222  {
   223    if (t == NULL)
   224      this->ostream() << "(nil type)";
   225    else
   226      // FIXME: write a type pretty printer instead of
   227      // using mangled names.
   228      if (this->gogo_ != NULL)
   229        this->ostream() << "(" << t->mangled_name(this->gogo_) <<  ")";
   230  }
   231  
   232  // Dump a textual representation of a block to the
   233  // the dump file.
   234  
   235  void
   236  Ast_dump_context::dump_block(Block* b)
   237  {
   238    Ast_dump_traverse_blocks_and_functions adtbf(this);
   239    b->traverse(&adtbf);
   240  }
   241  
   242  // Dump a textual representation of an expression to the
   243  // the dump file.
   244  
   245  void
   246  Ast_dump_context::dump_expression(const Expression* e)
   247  {
   248    e->dump_expression(this);
   249  }
   250  
   251  // Dump a textual representation of an expression list to the
   252  // the dump file.
   253  
   254  void
   255  Ast_dump_context::dump_expression_list(const Expression_list* el,
   256  				       bool as_pairs /* = false */)
   257  {
   258    if (el == NULL)
   259      return;
   260  
   261    for (std::vector<Expression*>::const_iterator it = el->begin();
   262         it != el->end();
   263         it++)
   264      {
   265        if ( it != el->begin())
   266          this->ostream() << ",";
   267        if (*it != NULL)
   268  	(*it)->dump_expression(this);
   269        else
   270          this->ostream() << "NULL";
   271        if (as_pairs)
   272          {
   273  	  this->ostream() << ":";
   274  	  ++it;
   275  	  (*it)->dump_expression(this);
   276          }
   277      }
   278  }
   279  
   280  // Dump a textual representation of a typed identifier to the
   281  // the dump file.
   282  
   283  void
   284  Ast_dump_context::dump_typed_identifier(const Typed_identifier* ti)
   285  {
   286    this->ostream() << ti->name() << " ";
   287    this->dump_type(ti->type());
   288  }
   289  
   290  // Dump a textual representation of a typed identifier list to the
   291  // the dump file.
   292  
   293  void
   294  Ast_dump_context::dump_typed_identifier_list(
   295      const Typed_identifier_list* ti_list)
   296  {
   297    if (ti_list == NULL)
   298      return;
   299  
   300    for (Typed_identifier_list::const_iterator it = ti_list->begin();
   301         it != ti_list->end();
   302         it++)
   303      {
   304        if (it != ti_list->begin())
   305          this->ostream() << ",";
   306        this->dump_typed_identifier(&(*it));
   307      }
   308  }
   309  
   310  // Dump a textual representation of a temporary variable to the
   311  // the dump file.
   312  
   313  void
   314  Ast_dump_context::dump_temp_variable_name(const Statement* s)
   315  {
   316    go_assert(s->classification() == Statement::STATEMENT_TEMPORARY);
   317    // Use the statement address as part of the name for the temporary variable.
   318    this->ostream() << "tmp." << (uintptr_t) s;
   319  }
   320  
   321  // Dump a textual representation of a label to the
   322  // the dump file.
   323  
   324  void
   325  Ast_dump_context::dump_label_name(const Unnamed_label* l)
   326  {
   327    // Use the unnamed label address as part of the name for the temporary
   328    // variable.
   329    this->ostream() << "label." << (uintptr_t) l;
   330  }
   331  
   332  // Produce a textual representation of an operator symbol.
   333  
   334  static const char*
   335  op_string(Operator op)
   336  {
   337  // FIXME: This should be in line with symbols that are parsed,
   338  // exported and/or imported.
   339    switch (op)
   340      {
   341      case OPERATOR_PLUS:
   342        return "+";
   343      case OPERATOR_MINUS:
   344        return "-";
   345      case OPERATOR_NOT:
   346        return "!";
   347      case OPERATOR_XOR:
   348        return "^";
   349      case OPERATOR_OR:
   350        return "|";
   351      case OPERATOR_AND:
   352        return "&";
   353      case OPERATOR_MULT:
   354        return "*";
   355      case OPERATOR_OROR:
   356        return "||";
   357      case OPERATOR_ANDAND:
   358        return "&&";
   359      case OPERATOR_EQEQ:
   360        return "==";
   361      case OPERATOR_NOTEQ:
   362        return "!=";
   363      case OPERATOR_LT:
   364        return "<";
   365      case OPERATOR_LE:
   366        return "<=";
   367      case OPERATOR_GT:
   368        return ">";
   369      case OPERATOR_GE:
   370        return ">=";
   371      case OPERATOR_DIV:
   372        return "/";
   373      case OPERATOR_MOD:
   374        return "%";
   375      case OPERATOR_LSHIFT:
   376        return "<<";
   377      case OPERATOR_RSHIFT:
   378        return "//";
   379      case OPERATOR_BITCLEAR:
   380        return "&^";
   381      case OPERATOR_CHANOP:
   382        return "<-";
   383      case OPERATOR_PLUSEQ:
   384        return "+=";
   385      case OPERATOR_MINUSEQ:
   386        return "-=";
   387      case OPERATOR_OREQ:
   388        return "|=";
   389      case OPERATOR_XOREQ:
   390        return "^=";
   391      case OPERATOR_MULTEQ:
   392        return "*=";
   393      case OPERATOR_DIVEQ:
   394        return "/=";
   395      case OPERATOR_MODEQ:
   396        return "%=";
   397      case OPERATOR_LSHIFTEQ:
   398        return "<<=";
   399      case OPERATOR_RSHIFTEQ:
   400        return ">>=";
   401      case OPERATOR_ANDEQ:
   402        return "&=";
   403      case OPERATOR_BITCLEAREQ:
   404        return "&^=";
   405      case OPERATOR_PLUSPLUS:
   406        return "++";
   407      case OPERATOR_MINUSMINUS:
   408        return "--";
   409      case OPERATOR_COLON:
   410        return ":";
   411      case OPERATOR_COLONEQ:
   412        return ":=";
   413      case OPERATOR_SEMICOLON:
   414        return ";";
   415      case OPERATOR_DOT:
   416        return ".";
   417      case OPERATOR_ELLIPSIS:
   418        return "...";
   419      case OPERATOR_COMMA:
   420        return ",";
   421      case OPERATOR_LPAREN:
   422        return "(";
   423      case OPERATOR_RPAREN:
   424        return ")";
   425      case OPERATOR_LCURLY:
   426        return "{";
   427      case OPERATOR_RCURLY:
   428        return "}";
   429      case OPERATOR_LSQUARE:
   430        return "[";
   431      case OPERATOR_RSQUARE:
   432        return "]";
   433      default:
   434        go_unreachable();
   435      }
   436    return NULL;
   437  }
   438  
   439  // Dump a textual representation of an operator to the
   440  // the dump file.
   441  
   442  void
   443  Ast_dump_context::dump_operator(Operator op)
   444  {
   445    this->ostream() << op_string(op);
   446  }
   447  
   448  // Size of a single indent.
   449  
   450  const int Ast_dump_context::offset_ = 2;
   451  
   452  // Print indenting spaces to dump file.
   453  
   454  void
   455  Ast_dump_context::print_indent()
   456  {
   457    for (int i = 0; i < this->indent_ * this->offset_; i++)
   458      this->ostream() << " ";
   459  }
   460  
   461  // Dump a textual representation of the ast to the
   462  // the dump file.
   463  
   464  void Gogo::dump_ast(const char* basename)
   465  {
   466    if (::ast_dump_flag.is_enabled())
   467      {
   468        Ast_dump_context adc;
   469        adc.dump(this, basename);
   470      }
   471  }
   472  
   473  // Implementation of String_dump interface.
   474  
   475  void
   476  Ast_dump_context::write_c_string(const char* s)
   477  {
   478    this->ostream() << s;
   479  }
   480  
   481  void
   482  Ast_dump_context::write_string(const std::string& s)
   483  {
   484    this->ostream() << s;
   485  }
   486  
   487  // Dump statement to stream.
   488  
   489  void
   490  Ast_dump_context::dump_to_stream(const Statement* stm, std::ostream* out)
   491  {
   492    Ast_dump_context adc(out, false);
   493    stm->dump_statement(&adc);
   494  }
   495  
   496  // Dump expression to stream.
   497  
   498  void
   499  Ast_dump_context::dump_to_stream(const Expression* expr, std::ostream* out)
   500  {
   501    Ast_dump_context adc(out, false);
   502    expr->dump_expression(&adc);
   503  }
   504  
   505  // Dump an expression to std::cerr. This is intended to be used
   506  // from within a debugging session.
   507  
   508  void
   509  debug_go_expression(const Expression* expr)
   510  {
   511    if (expr == NULL)
   512      std::cerr << "<null>";
   513    else
   514      {
   515        Ast_dump_context::dump_to_stream(expr, &std::cerr);
   516        std::string lstr = Linemap::location_to_string(expr->location());
   517        std::cerr << " // loc " << lstr << std::endl;
   518      }
   519  }
   520  
   521  // Shallow dump of stmt to std::cerr. This is intended to be used
   522  // from within a debugging session.
   523  
   524  void
   525  debug_go_statement(const Statement* stmt)
   526  {
   527    if (stmt == NULL)
   528      std::cerr << "<null>\n";
   529    else
   530      {
   531        std::string lstr = Linemap::location_to_string(stmt->location());
   532        Statement *ncstmt = const_cast<Statement*>(stmt);
   533        Block_statement* bs = ncstmt->block_statement();
   534        if (bs != NULL)
   535          std::cerr << "Block " << bs->block()
   536                    << " // location: " << lstr << std::endl;
   537        else
   538          Ast_dump_context::dump_to_stream(stmt, &std::cerr);
   539      }
   540  }
   541  
   542  // Deep dump of statement to std::cerr. This is intended to be used
   543  // from within a debugging session.
   544  
   545  void
   546  debug_go_statement_deep(const Statement* statement)
   547  {
   548    Ast_dump_context adc(&std::cerr, true);
   549    statement->dump_statement(&adc);
   550  }
   551  
   552  // Shallow dump of a block to std::cerr. This is intended to be used
   553  // from within a debugging session.
   554  
   555  void
   556  debug_go_block(const Block* block)
   557  {
   558    if (block == NULL)
   559      std::cerr << "<null>";
   560    else
   561      {
   562        std::cerr << "Block " << block
   563                  << " (enclosing " << block->enclosing() << "):\n";
   564        const std::vector<Statement*>* stmts = block->statements();
   565        if (stmts != NULL)
   566          {
   567            for (size_t i = 0; i < stmts->size(); ++i)
   568              {
   569                debug_go_statement(stmts->at(i));
   570              }
   571          }
   572      }
   573  }
   574  
   575  // Deep dump of a block to std:cerr. This is intended to be used
   576  // from within a debugging session.
   577  
   578  void
   579  debug_go_block_deep(const Block* block)
   580  {
   581    Ast_dump_context adc(&std::cerr, true);
   582    Block* ncblock = const_cast<Block*>(block);
   583    adc.dump_block(ncblock);
   584  }
   585  
   586  class Type_dumper
   587  {
   588    typedef Unordered_map(const Type*, unsigned) idx_map;
   589   public:
   590    Type_dumper(const Type* type)
   591        : top_(type), ntypes_(0)
   592    {
   593      this->worklist_.push_back(type);
   594    }
   595  
   596    void visit();
   597  
   598    std::string stringResult() { return ss_.str(); }
   599  
   600   private:
   601    void emitpre(unsigned tag, const Type* addr);
   602    void typeref(const char*, const Type*, const char *);
   603    void visit_forward_declaration_type(const Forward_declaration_type* fdt);
   604    void visit_function_type(const Function_type* ft);
   605    void visit_struct_type(const Struct_type* st);
   606    void visit_array_type(const Array_type* at);
   607    void visit_map_type(const Map_type* mt);
   608    void visit_channel_type(const Channel_type* mt);
   609    void visit_interface_type(const Interface_type* mt);
   610    void visit_methods(const Typed_identifier_list* methods,
   611                       const char *tag);
   612    std::pair<bool, unsigned> lookup(const Type*);
   613  
   614    static const unsigned notag = 0xffffffff;
   615  
   616   private:
   617    const Type* top_;
   618    idx_map types_;
   619    unsigned ntypes_;
   620    std::list<const Type*> worklist_;
   621    std::ostringstream ss_;
   622  };
   623  
   624  // Look up a type, installing it in 'types_'. Return is <found, N>
   625  // where 'found' is true if type had been previously recorded, and N
   626  // is the index/tag assigned to N.  The input argument is appended to
   627  // the work list if this is the first time we've seen it.
   628  
   629  std::pair<bool, unsigned> Type_dumper::lookup(const Type* t)
   630  {
   631    std::pair<const Type*, unsigned> entry = std::make_pair(t, this->ntypes_);
   632    std::pair<idx_map::iterator, bool> ins = this->types_.insert(entry);
   633    if (ins.second)
   634      {
   635        this->ntypes_++;
   636        if (t != this->top_)
   637          this->worklist_.push_back(t);
   638      }
   639    return std::make_pair(ins.second, ins.first->second);
   640  }
   641  
   642  // Emit preamble prior to dumping a type, including the type
   643  // pointer itself and the tag we've assigned it.  If no
   644  // tag is specified (via special "notag" value) and/or the
   645  // pointer is null, then just emit an equivalent amount
   646  // of spaces.
   647  
   648  void Type_dumper::emitpre(unsigned tag, const Type* ptr)
   649  {
   650    char tbuf[50], pbuf[50], buf[200];
   651  
   652    tbuf[0] = '\0';
   653    if (tag != notag)
   654      snprintf(tbuf, sizeof tbuf, "T%u", tag);
   655  
   656    pbuf[0] = '\0';
   657    if (ptr != NULL)
   658      snprintf(pbuf, sizeof pbuf, "%p", (const void*) ptr);
   659  
   660    snprintf(buf, sizeof buf, "%8s %16s  ", tbuf, pbuf);
   661    this->ss_ << buf;
   662  }
   663  
   664  // Emit a reference to a type into the dump buffer. In most cases this means
   665  // just the type tag, but for named types we also emit the name, and for
   666  // simple/primitive types (ex: int64) we emit the type itself. If "pref" is
   667  // non-NULL, emit the string prior to the reference, and if "suf" is non-NULL,
   668  // emit it following the reference.
   669  
   670  void Type_dumper::typeref(const char* pref, const Type* t, const char* suf)
   671  {
   672    if (pref != NULL)
   673      this->ss_ << pref;
   674    std::pair<bool, unsigned> p = this->lookup(t);
   675    unsigned tag = p.second;
   676    switch (t->classification())
   677      {
   678        case Type::TYPE_NAMED:
   679          {
   680            const Named_type* nt = t->named_type();
   681            const Named_object* no = nt->named_object();
   682            this->ss_ << "'" << no->message_name() << "' -> ";
   683            const Type* underlying = nt->real_type();
   684            this->typeref(NULL, underlying, NULL);
   685            break;
   686          }
   687        case Type::TYPE_POINTER:
   688          this->typeref("*", t->points_to(), NULL);
   689          break;
   690        case Type::TYPE_ERROR:
   691          this->ss_ << "error_type";
   692          break;
   693        case Type::TYPE_INTEGER:
   694          {
   695            const Integer_type* it = t->integer_type();
   696            if (it->is_abstract())
   697              this->ss_ << "abstract_int";
   698            else
   699              this->ss_ << (it->is_unsigned() ? "u" : "") << "int" << it->bits();
   700            break;
   701          }
   702        case Type::TYPE_FLOAT:
   703          {
   704            const Float_type* ft = t->float_type();
   705            if (ft->is_abstract())
   706              this->ss_ << "abstract_float";
   707            else
   708              this->ss_ << "float" << ft->bits();
   709            break;
   710          }
   711        case Type::TYPE_COMPLEX:
   712          {
   713            const Complex_type* ct = t->complex_type();
   714            if (ct->is_abstract())
   715              this->ss_ << "abstract_complex";
   716            else
   717              this->ss_ << "complex" << ct->bits();
   718            break;
   719          }
   720        case Type::TYPE_BOOLEAN:
   721          this->ss_ << "bool";
   722          break;
   723        case Type::TYPE_STRING:
   724          this->ss_ << "string";
   725          break;
   726        case Type::TYPE_NIL:
   727          this->ss_ << "nil_type";
   728          break;
   729      case Type::TYPE_VOID:
   730          this->ss_ << "void_type";
   731          break;
   732      case Type::TYPE_FUNCTION:
   733      case Type::TYPE_STRUCT:
   734      case Type::TYPE_ARRAY:
   735      case Type::TYPE_MAP:
   736      case Type::TYPE_CHANNEL:
   737      case Type::TYPE_FORWARD:
   738      case Type::TYPE_INTERFACE:
   739        this->ss_ << "T" << tag;
   740        break;
   741  
   742      default:
   743        // This is a debugging routine, so instead of a go_unreachable()
   744        // issue a warning/error, to allow for the possibility that the
   745        // compiler we're debugging is in a bad state.
   746        this->ss_ << "<??? " << ((unsigned)t->classification()) << "> "
   747                  << "T" << tag;
   748      }
   749    if (suf != NULL)
   750      this->ss_ << suf;
   751  }
   752  
   753  void Type_dumper::visit_forward_declaration_type(const Forward_declaration_type* fdt)
   754  {
   755    this->ss_ << "forward_declaration_type ";
   756    if (fdt->is_defined())
   757      this->typeref("-> ", fdt->real_type(), NULL);
   758    else
   759      this->ss_ << "'" << fdt->name() << "'";
   760    this->ss_ << "\n";
   761  }
   762  
   763  void Type_dumper::visit_function_type(const Function_type* ft)
   764  {
   765    this->ss_ << "function\n";
   766    const Typed_identifier* rec = ft->receiver();
   767    if (rec != NULL)
   768      {
   769        this->emitpre(notag, NULL);
   770        this->typeref("receiver ", rec->type(), "\n");
   771      }
   772    const Typed_identifier_list* parameters = ft->parameters();
   773    if (parameters != NULL)
   774      {
   775        for (Typed_identifier_list::const_iterator p = parameters->begin();
   776  	   p != parameters->end();
   777  	   ++p)
   778          {
   779            this->emitpre(notag, NULL);
   780            this->typeref(" param ", p->type(), "\n");
   781          }
   782      }
   783    const Typed_identifier_list* results = ft->results();
   784    if (results != NULL)
   785      {
   786        for (Typed_identifier_list::const_iterator p = results->begin();
   787  	   p != results->end();
   788  	   ++p)
   789          {
   790            this->emitpre(notag, NULL);
   791            this->typeref(" result ", p->type(), "\n");
   792          }
   793      }
   794  }
   795  
   796  void Type_dumper::visit_struct_type(const Struct_type* st)
   797  {
   798    this->ss_ << "struct\n";
   799    const Struct_field_list* fields = st->fields();
   800    if (fields != NULL)
   801      {
   802        for (Struct_field_list::const_iterator p = fields->begin();
   803             p != fields->end();
   804             ++p)
   805          {
   806            this->emitpre(notag, NULL);
   807            this->typeref(" field ", p->type(), "\n");
   808          }
   809      }
   810  }
   811  
   812  void Type_dumper::visit_array_type(const Array_type* at)
   813  {
   814    this->ss_ << "array [";
   815    if (at->length() != NULL)
   816      {
   817        int64_t len = 0;
   818        if (at->int_length(&len))
   819          this->ss_ << len;
   820      }
   821    this->typeref("] ", at->element_type(), "\n");
   822  }
   823  
   824  void Type_dumper::visit_map_type(const Map_type* mt)
   825  {
   826    this->ss_ << "map [";
   827    this->typeref(NULL, mt->key_type(), NULL);
   828    this->typeref("] ", mt->val_type(), "\n");
   829  }
   830  
   831  void Type_dumper::visit_methods(const Typed_identifier_list* methods,
   832                                  const char *tag)
   833  {
   834    if (tag != NULL)
   835      {
   836        this->emitpre(notag, NULL);
   837        this->ss_ << tag << "\n";
   838      }
   839    for (Typed_identifier_list::const_iterator p = methods->begin();
   840         p != methods->end();
   841         ++p)
   842      {
   843        this->emitpre(notag, NULL);
   844        if (p->name().empty())
   845          this->typeref("  embedded method ", p->type(), "\n");
   846        else
   847          {
   848            this->ss_ << "  method '" << p->name() << "' ";
   849            this->typeref(NULL, p->type(), "\n");
   850          }
   851      }
   852  }
   853  
   854  void Type_dumper::visit_interface_type(const Interface_type* it)
   855  {
   856    const Typed_identifier_list* methods =
   857        (it->methods_are_finalized() ? it->methods() : it->local_methods());
   858    if (methods == NULL)
   859      {
   860        this->ss_ << "empty_interface\n";
   861        return;
   862      }
   863    this->ss_ << "interface";
   864    if (! it->methods_are_finalized())
   865      {
   866        this->ss_ << " [unfinalized]\n";
   867        visit_methods(it->local_methods(), NULL);
   868      }
   869    else
   870      {
   871        this->ss_ << "\n";
   872        visit_methods(it->local_methods(), "[parse_methods]");
   873        visit_methods(it->methods(), "[all_methods]");
   874      }
   875  }
   876  
   877  void Type_dumper::visit_channel_type(const Channel_type* ct)
   878  {
   879    this->ss_ << "channel {";
   880    if (ct->may_send())
   881      this->ss_ << " send";
   882    if (ct->may_receive())
   883      this->ss_ << " receive";
   884    this->typeref(" } ", ct->element_type(), "\n");
   885  }
   886  
   887  void Type_dumper::visit()
   888  {
   889    while (! this->worklist_.empty()) {
   890      const Type* t = this->worklist_.front();
   891      this->worklist_.pop_front();
   892  
   893      std::pair<bool, unsigned> p = this->lookup(t);
   894      unsigned tag = p.second;
   895      this->emitpre(tag, t);
   896  
   897      switch(t->classification())
   898        {
   899          case Type::TYPE_ERROR:
   900          case Type::TYPE_INTEGER:
   901          case Type::TYPE_FLOAT:
   902          case Type::TYPE_COMPLEX:
   903          case Type::TYPE_BOOLEAN:
   904          case Type::TYPE_STRING:
   905          case Type::TYPE_VOID:
   906          case Type::TYPE_POINTER:
   907          case Type::TYPE_NIL:
   908          case Type::TYPE_NAMED:
   909            this->typeref(NULL, t, "\n");
   910            break;
   911          case Type::TYPE_FORWARD:
   912            this->visit_forward_declaration_type(t->forward_declaration_type());
   913            break;
   914  
   915          case Type::TYPE_FUNCTION:
   916            this->visit_function_type(t->function_type());
   917            break;
   918          case Type::TYPE_STRUCT:
   919            this->visit_struct_type(t->struct_type());
   920            break;
   921          case Type::TYPE_ARRAY:
   922            this->visit_array_type(t->array_type());
   923            break;
   924          case Type::TYPE_MAP:
   925            this->visit_map_type(t->map_type());
   926            break;
   927          case Type::TYPE_CHANNEL:
   928            this->visit_channel_type(t->channel_type());
   929            break;
   930          case Type::TYPE_INTERFACE:
   931            this->visit_interface_type(t->interface_type());
   932            break;
   933          default:
   934            // This is a debugging routine, so instead of a go_unreachable()
   935            // issue a warning/error, to allow for the possibility that the
   936            // compiler we're debugging is in a bad state.
   937            this->ss_ << "<unknown/unrecognized classification "
   938                      << ((unsigned)t->classification()) << ">\n";
   939        }
   940    }
   941  }
   942  
   943  // Dump a Go type for debugging purposes. This is a deep as opposed
   944  // to shallow dump; all of the types reachable from the specified
   945  // type will be dumped in addition to the type itself.
   946  
   947  void debug_go_type(const Type* type)
   948  {
   949    if (type == NULL)
   950      {
   951        std::cerr << "<NULL type>\n";
   952        return;
   953      }
   954    Type_dumper dumper(type);
   955    dumper.visit();
   956    std::cerr << dumper.stringResult();
   957  }
   958  
   959  void debug_go_type(Type* type)
   960  {
   961    const Type* ctype = type;
   962    debug_go_type(ctype);
   963  }