// expressions.h -- Go frontend expression handling.     -*- C++ -*-

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#ifndef GO_EXPRESSIONS_H
#define GO_EXPRESSIONS_H

#include <mpfr.h>
#include <mpc.h>

#include "operator.h"
#include "runtime.h"

class Gogo;
class Translate_context;
class Traverse;
class Statement_inserter;
class Type;
class Method;
struct Type_context;
class Integer_type;
class Float_type;
class Complex_type;
class Function_type;
class Map_type;
class Struct_type;
class Struct_field;
class Expression_list;
class Var_expression;
class Enclosed_var_expression;
class Temporary_reference_expression;
class Set_and_use_temporary_expression;
class String_expression;
class Type_conversion_expression;
class Unsafe_type_conversion_expression;
class Unary_expression;
class Binary_expression;
class String_concat_expression;
class Call_expression;
class Call_result_expression;
class Func_expression;
class Func_descriptor_expression;
class Unknown_expression;
class Index_expression;
class Array_index_expression;
class String_index_expression;
class Map_index_expression;
class Bound_method_expression;
class Field_reference_expression;
class Interface_field_reference_expression;
class Allocation_expression;
class Composite_literal_expression;
class Struct_construction_expression;
class Array_construction_expression;
class Fixed_array_construction_expression;
class Slice_construction_expression;
class Map_construction_expression;
class Type_guard_expression;
class Heap_expression;
class Receive_expression;
class Conditional_expression;
class Compound_expression;
class Numeric_constant;
class Named_object;
class Export;
class Import;
class Temporary_statement;
class Label;
class Ast_dump_context;
class String_dump;

// The precision to use for complex values represented as an mpc_t.
const int mpc_precision = 256;

// The base class for all expressions.

class Expression
{
 public:
  // The types of expressions.
  enum Expression_classification
  {
    EXPRESSION_ERROR,
    EXPRESSION_TYPE,
    EXPRESSION_UNARY,
    EXPRESSION_BINARY,
    EXPRESSION_STRING_CONCAT,
    EXPRESSION_CONST_REFERENCE,
    EXPRESSION_VAR_REFERENCE,
    EXPRESSION_ENCLOSED_VAR_REFERENCE,
    EXPRESSION_TEMPORARY_REFERENCE,
    EXPRESSION_SET_AND_USE_TEMPORARY,
    EXPRESSION_SINK,
    EXPRESSION_FUNC_REFERENCE,
    EXPRESSION_FUNC_DESCRIPTOR,
    EXPRESSION_FUNC_CODE_REFERENCE,
    EXPRESSION_UNKNOWN_REFERENCE,
    EXPRESSION_BOOLEAN,
    EXPRESSION_STRING,
    EXPRESSION_STRING_INFO,
    EXPRESSION_INTEGER,
    EXPRESSION_FLOAT,
    EXPRESSION_COMPLEX,
    EXPRESSION_NIL,
    EXPRESSION_IOTA,
    EXPRESSION_CALL,
    EXPRESSION_CALL_RESULT,
    EXPRESSION_BOUND_METHOD,
    EXPRESSION_INDEX,
    EXPRESSION_ARRAY_INDEX,
    EXPRESSION_STRING_INDEX,
    EXPRESSION_MAP_INDEX,
    EXPRESSION_SELECTOR,
    EXPRESSION_FIELD_REFERENCE,
    EXPRESSION_INTERFACE_FIELD_REFERENCE,
    EXPRESSION_ALLOCATION,
    EXPRESSION_TYPE_GUARD,
    EXPRESSION_CONVERSION,
    EXPRESSION_UNSAFE_CONVERSION,
    EXPRESSION_STRUCT_CONSTRUCTION,
    EXPRESSION_FIXED_ARRAY_CONSTRUCTION,
    EXPRESSION_SLICE_CONSTRUCTION,
    EXPRESSION_MAP_CONSTRUCTION,
    EXPRESSION_COMPOSITE_LITERAL,
    EXPRESSION_HEAP,
    EXPRESSION_RECEIVE,
    EXPRESSION_TYPE_DESCRIPTOR,
    EXPRESSION_GC_SYMBOL,
    EXPRESSION_TYPE_INFO,
    EXPRESSION_SLICE_INFO,
    EXPRESSION_SLICE_VALUE,
    EXPRESSION_INTERFACE_INFO,
    EXPRESSION_INTERFACE_VALUE,
    EXPRESSION_INTERFACE_MTABLE,
    EXPRESSION_STRUCT_FIELD_OFFSET,
    EXPRESSION_LABEL_ADDR,
    EXPRESSION_CONDITIONAL,
    EXPRESSION_COMPOUND,
    EXPRESSION_BACKEND
  };

  Expression(Expression_classification, Location);

  virtual ~Expression();

  // Make an error expression.  This is used when a parse error occurs
  // to prevent cascading errors.
  static Expression*
  make_error(Location);

  // Make an expression which is really a type.  This is used during
  // parsing.
  static Expression*
  make_type(Type*, Location);

  // Make a unary expression.
  static Expression*
  make_unary(Operator, Expression*, Location);

  // Make a binary expression.
  static Expression*
  make_binary(Operator, Expression*, Expression*, Location);

  // Make a string concatenation expression.
  static Expression*
  make_string_concat(Expression_list*);

  // Make a reference to a constant in an expression.
  static Expression*
  make_const_reference(Named_object*, Location);

  // Make a reference to a variable in an expression.
  static Expression*
  make_var_reference(Named_object*, Location);

  // Make a reference to a variable within an enclosing function.
  static Expression*
  make_enclosing_var_reference(Expression*, Named_object*, Location);

  // Make a reference to a temporary variable.  Temporary variables
  // are always created by a single statement, which is what we use to
  // refer to them.
  static Temporary_reference_expression*
  make_temporary_reference(Temporary_statement*, Location);

  // Make an expressions which sets a temporary variable and then
  // evaluates to a reference to that temporary variable.  This is
  // used to set a temporary variable while retaining the order of
  // evaluation.
  static Set_and_use_temporary_expression*
  make_set_and_use_temporary(Temporary_statement*, Expression*, Location);

  // Make a sink expression--a reference to the blank identifier _.
  static Expression*
  make_sink(Location);

  // Make a reference to a function in an expression.  This returns a
  // pointer to the struct holding the address of the function
  // followed by any closed-over variables.
  static Expression*
  make_func_reference(Named_object*, Expression* closure, Location);

  // Make a function descriptor, an immutable struct with a single
  // field that points to the function code.  This may only be used
  // with functions that do not have closures.  FN is the function for
  // which we are making the descriptor.
  static Func_descriptor_expression*
  make_func_descriptor(Named_object* fn);

  // Make a reference to the code of a function.  This is used to set
  // descriptor and closure fields.
  static Expression*
  make_func_code_reference(Named_object*, Location);

  // Make a reference to an unknown name.  In a correct program this
  // will always be lowered to a real const/var/func reference.
  static Unknown_expression*
  make_unknown_reference(Named_object*, Location);

  // Make a constant bool expression.
  static Expression*
  make_boolean(bool val, Location);

  // Make a constant string expression.
  static Expression*
  make_string(const std::string&, Location);

  // Make an expression that evaluates to some characteristic of an string.
  // For simplicity, the enum values must match the field indexes in the
  // underlying struct.
  enum String_info
    {
      // The underlying data in the string.
      STRING_INFO_DATA,
      // The length of the string.
      STRING_INFO_LENGTH
    };

  static Expression*
  make_string_info(Expression* string, String_info, Location);

  // Make a character constant expression.  TYPE should be NULL for an
  // abstract type.
  static Expression*
  make_character(const mpz_t*, Type*, Location);

  // Make a constant integer expression from a multi-precision
  // integer.  TYPE should be NULL for an abstract type.
  static Expression*
  make_integer_z(const mpz_t*, Type*, Location);

  // Make a constant integer expression from an unsigned long.  TYPE
  // should be NULL for an abstract type.
  static Expression*
  make_integer_ul(unsigned long, Type*, Location);

  // Make a constant integer expression from a signed long.  TYPE
  // should be NULL for an abstract type.
  static Expression*
  make_integer_sl(long, Type*, Location);

  // Make a constant integer expression from an int64_t.  TYPE should
  // be NULL for an abstract type.
  static Expression*
  make_integer_int64(int64_t, Type*, Location);

  // Make a constant float expression.  TYPE should be NULL for an
  // abstract type.
  static Expression*
  make_float(const mpfr_t*, Type*, Location);

  // Make a constant complex expression.  TYPE should be NULL for an
  // abstract type.
  static Expression*
  make_complex(const mpc_t*, Type*, Location);

  // Make a nil expression.
  static Expression*
  make_nil(Location);

  // Make an iota expression.  This is used for the predeclared
  // constant iota.
  static Expression*
  make_iota();

  // Make a call expression.
  static Call_expression*
  make_call(Expression* func, Expression_list* args, bool is_varargs,
	    Location);

  // Make a reference to a specific result of a call expression which
  // returns a tuple.
  static Expression*
  make_call_result(Call_expression*, unsigned int index);

  // Make an expression which is a method bound to its first
  // parameter.  METHOD is the method being called, FUNCTION is the
  // function to call.
  static Bound_method_expression*
  make_bound_method(Expression* object, const Method* method,
		    Named_object* function, Location);

  // Make an index or slice expression.  This is a parser expression
  // which represents LEFT[START:END:CAP].  END may be NULL, meaning an
  // index rather than a slice.  CAP may be NULL, meaning we use the default
  // capacity of LEFT. At parse time we may not know the type of LEFT.
  // After parsing this is lowered to an array index, a string index,
  // or a map index.
  static Expression*
  make_index(Expression* left, Expression* start, Expression* end,
             Expression* cap, Location);

  // Make an array index expression.  END may be NULL, in which case
  // this is an lvalue.  CAP may be NULL, in which case it defaults
  // to cap(ARRAY).
  static Expression*
  make_array_index(Expression* array, Expression* start, Expression* end,
                   Expression* cap, Location);

  // Make a string index expression.  END may be NULL.  This is never
  // an lvalue.
  static Expression*
  make_string_index(Expression* string, Expression* start, Expression* end,
		    Location);

  // Make a map index expression.  This is an lvalue.
  static Map_index_expression*
  make_map_index(Expression* map, Expression* val, Location);

  // Make a selector.  This is a parser expression which represents
  // LEFT.NAME.  At parse time we may not know the type of the left
  // hand side.
  static Expression*
  make_selector(Expression* left, const std::string& name, Location);

  // Make a reference to a field in a struct.
  static Field_reference_expression*
  make_field_reference(Expression*, unsigned int field_index, Location);

  // Make a reference to a field of an interface, with an associated
  // object.
  static Expression*
  make_interface_field_reference(Expression*, const std::string&,
				 Location);

  // Make an allocation expression.
  static Expression*
  make_allocation(Type*, Location);

  // Make a type guard expression.
  static Expression*
  make_type_guard(Expression*, Type*, Location);

  // Make a type cast expression.
  static Expression*
  make_cast(Type*, Expression*, Location);

  // Make an unsafe type cast expression.  This is only used when
  // passing parameter to builtin functions that are part of the Go
  // runtime.
  static Expression*
  make_unsafe_cast(Type*, Expression*, Location);

  // Make a composite literal.  The DEPTH parameter is how far down we
  // are in a list of composite literals with omitted types.  HAS_KEYS
  // is true if the expression list has keys alternating with values.
  // ALL_ARE_NAMES is true if all the keys could be struct field
  // names.
  static Expression*
  make_composite_literal(Type*, int depth, bool has_keys, Expression_list*,
			 bool all_are_names, Location);

  // Make a struct composite literal.
  static Expression*
  make_struct_composite_literal(Type*, Expression_list*, Location);

  // Make an array composite literal.
  static Expression*
  make_array_composite_literal(Type*, Expression_list*, Location);

  // Make a slice composite literal.
  static Slice_construction_expression*
  make_slice_composite_literal(Type*, Expression_list*, Location);

  // Take an expression and allocate it on the heap.
  static Expression*
  make_heap_expression(Expression*, Location);

  // Make a receive expression.  VAL is NULL for a unary receive.
  static Receive_expression*
  make_receive(Expression* channel, Location);

  // Make an expression which evaluates to the address of the type
  // descriptor for TYPE.
  static Expression*
  make_type_descriptor(Type* type, Location);

  // Make an expression which evaluates to the address of the gc
  // symbol for TYPE.
  static Expression*
  make_gc_symbol(Type* type);

  // Make an expression which evaluates to some characteristic of a
  // type.  These are only used for type descriptors, so there is no
  // location parameter.
  enum Type_info
    {
      // The size of a value of the type.
      TYPE_INFO_SIZE,
      // The required alignment of a value of the type.
      TYPE_INFO_ALIGNMENT,
      // The required alignment of a value of the type when used as a
      // field in a struct.
      TYPE_INFO_FIELD_ALIGNMENT
    };

  static Expression*
  make_type_info(Type* type, Type_info);

  // Make an expression that evaluates to some characteristic of a
  // slice.  For simplicity, the enum values must match the field indexes
  // in the underlying struct.
  enum Slice_info
    {
      // The underlying data of the slice.
      SLICE_INFO_VALUE_POINTER,
      // The length of the slice.
      SLICE_INFO_LENGTH,
      // The capacity of the slice.
      SLICE_INFO_CAPACITY
    };

  static Expression*
  make_slice_info(Expression* slice, Slice_info, Location);

  // Make an expression for a slice value.
  static Expression*
  make_slice_value(Type*, Expression* valptr, Expression* len, Expression* cap,
                   Location);

  // Make an expression that evaluates to some characteristic of an
  // interface.  For simplicity, the enum values must match the field indexes
  // in the underlying struct.
  enum Interface_info
    {
      // The type descriptor of an empty interface.
      INTERFACE_INFO_TYPE_DESCRIPTOR = 0,
      // The methods of an interface.
      INTERFACE_INFO_METHODS = 0,
      // The first argument to pass to an interface method.
      INTERFACE_INFO_OBJECT
    };

  static Expression*
  make_interface_info(Expression* iface, Interface_info, Location);

  // Make an expression for an interface value.
  static Expression*
  make_interface_value(Type*, Expression*, Expression*, Location);

  // Make an expression that builds a reference to the interface method table
  // for TYPE that satisfies interface ITYPE. IS_POINTER is true if this is a
  // reference to the interface method table for the pointer receiver type.
  static Expression*
  make_interface_mtable_ref(Interface_type* itype, Type* type,
                            bool is_pointer, Location);

  // Make an expression which evaluates to the offset of a field in a
  // struct.  This is only used for type descriptors, so there is no
  // location parameter.
  static Expression*
  make_struct_field_offset(Struct_type*, const Struct_field*);

  // Make an expression which evaluates to the address of an unnamed
  // label.
  static Expression*
  make_label_addr(Label*, Location);

  // Make a conditional expression.
  static Expression*
  make_conditional(Expression*, Expression*, Expression*, Location);

  // Make a compound expression.
  static Expression*
  make_compound(Expression*, Expression*, Location);

  // Make a backend expression.
  static Expression*
  make_backend(Bexpression*, Type*, Location);

  // Return the expression classification.
  Expression_classification
  classification() const
  { return this->classification_; }

  // Return the location of the expression.
  Location
  location() const
  { return this->location_; }

  // Return whether this is a constant expression.
  bool
  is_constant() const
  { return this->do_is_constant(); }

  // Return whether this expression can be used as a static
  // initializer.  This is true for an expression that has only
  // numbers and pointers to global variables or composite literals
  // that do not require runtime initialization.  It is false if we
  // must generate code to compute this expression when it is used to
  // initialize a global variable.  This is not a language-level
  // concept, but an implementation-level one.  If this expression is
  // used to initialize a global variable, this is true if we can pass
  // an initializer to the backend, false if we must generate code to
  // initialize the variable.  It is always safe for this method to
  // return false, but the resulting code may be less efficient.
  bool
  is_static_initializer() const
  { return this->do_is_static_initializer(); }

  // If this is not a numeric constant, return false.  If it is one,
  // return true, and set VAL to hold the value.
  bool
  numeric_constant_value(Numeric_constant* val) const
  { return this->do_numeric_constant_value(val); }

  // If this is not a constant expression with string type, return
  // false.  If it is one, return true, and set VAL to the value.
  bool
  string_constant_value(std::string* val) const
  { return this->do_string_constant_value(val); }

  // This is called if the value of this expression is being
  // discarded.  This issues warnings about computed values being
  // unused.  This returns true if all is well, false if it issued an
  // error message.
  bool
  discarding_value()
  { return this->do_discarding_value(); }

  // Return whether this is an error expression.
  bool
  is_error_expression() const
  { return this->classification_ == EXPRESSION_ERROR; }

  // Return whether this expression really represents a type.
  bool
  is_type_expression() const
  { return this->classification_ == EXPRESSION_TYPE; }

  // If this is a variable reference, return the Var_expression
  // structure.  Otherwise, return NULL.  This is a controlled dynamic
  // cast.
  Var_expression*
  var_expression()
  { return this->convert<Var_expression, EXPRESSION_VAR_REFERENCE>(); }

  const Var_expression*
  var_expression() const
  { return this->convert<const Var_expression, EXPRESSION_VAR_REFERENCE>(); }

  // If this is a enclosed_variable reference, return the
  // Enclosed_var_expression structure.  Otherwise, return NULL.
  // This is a controlled dynamic cast.
  Enclosed_var_expression*
  enclosed_var_expression()
  { return this->convert<Enclosed_var_expression,
			 EXPRESSION_ENCLOSED_VAR_REFERENCE>(); }

  const Enclosed_var_expression*
  enclosed_var_expression() const
  { return this->convert<const Enclosed_var_expression,
			 EXPRESSION_ENCLOSED_VAR_REFERENCE>(); }


  // If this is a reference to a temporary variable, return the
  // Temporary_reference_expression.  Otherwise, return NULL.
  Temporary_reference_expression*
  temporary_reference_expression()
  {
    return this->convert<Temporary_reference_expression,
			 EXPRESSION_TEMPORARY_REFERENCE>();
  }

  // If this is a set-and-use-temporary, return the
  // Set_and_use_temporary_expression.  Otherwise, return NULL.
  Set_and_use_temporary_expression*
  set_and_use_temporary_expression()
  {
    return this->convert<Set_and_use_temporary_expression,
			 EXPRESSION_SET_AND_USE_TEMPORARY>();
  }

  // Return whether this is a sink expression.
  bool
  is_sink_expression() const
  { return this->classification_ == EXPRESSION_SINK; }

  // If this is a string expression, return the String_expression
  // structure.  Otherwise, return NULL.
  String_expression*
  string_expression()
  { return this->convert<String_expression, EXPRESSION_STRING>(); }

  // If this is a conversion expression, return the Type_conversion_expression
  // structure.  Otherwise, return NULL.
  Type_conversion_expression*
  conversion_expression()
  { return this->convert<Type_conversion_expression, EXPRESSION_CONVERSION>(); }

  // If this is an unsafe conversion expression, return the
  // Unsafe_type_conversion_expression structure.  Otherwise, return NULL.
  Unsafe_type_conversion_expression*
  unsafe_conversion_expression()
  {
    return this->convert<Unsafe_type_conversion_expression,
			 EXPRESSION_UNSAFE_CONVERSION>();
  }

  // Return whether this is the expression nil.
  bool
  is_nil_expression() const
  { return this->classification_ == EXPRESSION_NIL; }

  // If this is an indirection through a pointer, return the
  // expression being pointed through.  Otherwise return this.
  Expression*
  deref();

  // If this is a unary expression, return the Unary_expression
  // structure.  Otherwise return NULL.
  Unary_expression*
  unary_expression()
  { return this->convert<Unary_expression, EXPRESSION_UNARY>(); }

  // If this is a binary expression, return the Binary_expression
  // structure.  Otherwise return NULL.
  Binary_expression*
  binary_expression()
  { return this->convert<Binary_expression, EXPRESSION_BINARY>(); }

  // If this is a string concatenation expression, return the
  // String_concat_expression structure.  Otherwise, return NULL.
  String_concat_expression*
  string_concat_expression()
  {
    return this->convert<String_concat_expression, EXPRESSION_STRING_CONCAT>();
  }

  // If this is a call expression, return the Call_expression
  // structure.  Otherwise, return NULL.  This is a controlled dynamic
  // cast.
  Call_expression*
  call_expression()
  { return this->convert<Call_expression, EXPRESSION_CALL>(); }

  // If this is a call_result expression, return the Call_result_expression
  // structure.  Otherwise, return NULL.  This is a controlled dynamic
  // cast.
  Call_result_expression*
  call_result_expression()
  { return this->convert<Call_result_expression, EXPRESSION_CALL_RESULT>(); }

  // If this is an expression which refers to a function, return the
  // Func_expression structure.  Otherwise, return NULL.
  Func_expression*
  func_expression()
  { return this->convert<Func_expression, EXPRESSION_FUNC_REFERENCE>(); }

  const Func_expression*
  func_expression() const
  { return this->convert<const Func_expression, EXPRESSION_FUNC_REFERENCE>(); }

  // If this is an expression which refers to an unknown name, return
  // the Unknown_expression structure.  Otherwise, return NULL.
  Unknown_expression*
  unknown_expression()
  { return this->convert<Unknown_expression, EXPRESSION_UNKNOWN_REFERENCE>(); }

  const Unknown_expression*
  unknown_expression() const
  {
    return this->convert<const Unknown_expression,
			 EXPRESSION_UNKNOWN_REFERENCE>();
  }

  // If this is an index expression, return the Index_expression
  // structure.  Otherwise, return NULL.
  Index_expression*
  index_expression()
  { return this->convert<Index_expression, EXPRESSION_INDEX>(); }

  // If this is an expression which refers to indexing in a array,
  // return the Array_index_expression structure.  Otherwise, return
  // NULL.
  Array_index_expression*
  array_index_expression()
  { return this->convert<Array_index_expression, EXPRESSION_ARRAY_INDEX>(); }

  // If this is an expression which refers to indexing in a string,
  // return the String_index_expression structure.  Otherwise, return
  // NULL.
  String_index_expression*
  string_index_expression()
  { return this->convert<String_index_expression, EXPRESSION_STRING_INDEX>(); }

  // If this is an expression which refers to indexing in a map,
  // return the Map_index_expression structure.  Otherwise, return
  // NULL.
  Map_index_expression*
  map_index_expression()
  { return this->convert<Map_index_expression, EXPRESSION_MAP_INDEX>(); }

  // If this is a bound method expression, return the
  // Bound_method_expression structure.  Otherwise, return NULL.
  Bound_method_expression*
  bound_method_expression()
  { return this->convert<Bound_method_expression, EXPRESSION_BOUND_METHOD>(); }

  // If this is a reference to a field in a struct, return the
  // Field_reference_expression structure.  Otherwise, return NULL.
  Field_reference_expression*
  field_reference_expression()
  {
    return this->convert<Field_reference_expression,
			 EXPRESSION_FIELD_REFERENCE>();
  }

  // If this is a reference to a field in an interface, return the
  // Interface_field_reference_expression structure.  Otherwise,
  // return NULL.
  Interface_field_reference_expression*
  interface_field_reference_expression()
  {
    return this->convert<Interface_field_reference_expression,
			 EXPRESSION_INTERFACE_FIELD_REFERENCE>();
  }

  // If this is an allocation expression, return the Allocation_expression
  // structure.  Otherwise, return NULL.
  Allocation_expression*
  allocation_expression()
  { return this->convert<Allocation_expression, EXPRESSION_ALLOCATION>(); }

  // If this is a general composite literal, return the
  // Composite_literal_expression structure.  Otherwise, return NULL.
  Composite_literal_expression*
  complit()
  {
    return this->convert<Composite_literal_expression,
			 EXPRESSION_COMPOSITE_LITERAL>();
  }

  // If this is a struct composite literal, return the
  // Struct_construction_expression structure.  Otherwise, return NULL.
  Struct_construction_expression*
  struct_literal()
  {
    return this->convert<Struct_construction_expression,
			 EXPRESSION_STRUCT_CONSTRUCTION>();
  }

  // If this is a array composite literal, return the
  // Array_construction_expression structure.  Otherwise, return NULL.
  Fixed_array_construction_expression*
  array_literal()
  {
    return this->convert<Fixed_array_construction_expression,
			 EXPRESSION_FIXED_ARRAY_CONSTRUCTION>();
  }

  // If this is a slice composite literal, return the
  // Slice_construction_expression structure.  Otherwise, return NULL.
  Slice_construction_expression*
  slice_literal()
  {
    return this->convert<Slice_construction_expression,
			 EXPRESSION_SLICE_CONSTRUCTION>();
  }

  // If this is a map composite literal, return the
  // Map_construction_expression structure.  Otherwise, return NULL.
  Map_construction_expression*
  map_literal()
  {
    return this->convert<Map_construction_expression,
			 EXPRESSION_MAP_CONSTRUCTION>();
  }

  // If this is a type guard expression, return the
  // Type_guard_expression structure.  Otherwise, return NULL.
  Type_guard_expression*
  type_guard_expression()
  { return this->convert<Type_guard_expression, EXPRESSION_TYPE_GUARD>(); }

  // If this is a heap expression, returhn the Heap_expression structure.
  // Otherwise, return NULL.
  Heap_expression*
  heap_expression()
  { return this->convert<Heap_expression, EXPRESSION_HEAP>(); }

  // If this is a receive expression, return the Receive_expression
  // structure.  Otherwise, return NULL.
  Receive_expression*
  receive_expression()
  { return this->convert<Receive_expression, EXPRESSION_RECEIVE>(); }

  // If this is a conditional expression, return the Conditional_expression
  // structure.  Otherwise, return NULL.
  Conditional_expression*
  conditional_expression()
  { return this->convert<Conditional_expression, EXPRESSION_CONDITIONAL>(); }

  // If this is a compound expression, return the Compound_expression structure.
  // Otherwise, return NULL.
  Compound_expression*
  compound_expression()
  { return this->convert<Compound_expression, EXPRESSION_COMPOUND>(); }

  // Return true if this is a composite literal.
  bool
  is_composite_literal() const;

  // Return true if this is a composite literal which is not constant.
  bool
  is_nonconstant_composite_literal() const;

  // Return true if this is a variable or temporary variable.
  bool
  is_variable() const;

  // Return true if this is a reference to a local variable.
  bool
  is_local_variable() const;

  // Make the builtin function descriptor type, so that it can be
  // converted.
  static void
  make_func_descriptor_type();

  // Traverse an expression.
  static int
  traverse(Expression**, Traverse*);

  // Traverse subexpressions of this expression.
  int
  traverse_subexpressions(Traverse*);

  // Lower an expression.  This is called immediately after parsing.
  // FUNCTION is the function we are in; it will be NULL for an
  // expression initializing a global variable.  INSERTER may be used
  // to insert statements before the statement or initializer
  // containing this expression; it is normally used to create
  // temporary variables.  IOTA_VALUE is the value that we should give
  // to any iota expressions.  This function must resolve expressions
  // which could not be fully parsed into their final form.  It
  // returns the same Expression or a new one.
  Expression*
  lower(Gogo* gogo, Named_object* function, Statement_inserter* inserter,
	int iota_value)
  { return this->do_lower(gogo, function, inserter, iota_value); }

  // Flatten an expression. This is called after order_evaluation.
  // FUNCTION is the function we are in; it will be NULL for an
  // expression initializing a global variable.  INSERTER may be used
  // to insert statements before the statement or initializer
  // containing this expression; it is normally used to create
  // temporary variables. This function must resolve expressions
  // which could not be fully parsed into their final form.  It
  // returns the same Expression or a new one.
  Expression*
  flatten(Gogo* gogo, Named_object* function, Statement_inserter* inserter)
  { return this->do_flatten(gogo, function, inserter); }

  // Determine the real type of an expression with abstract integer,
  // floating point, or complex type.  TYPE_CONTEXT describes the
  // expected type.
  void
  determine_type(const Type_context*);

  // Check types in an expression.
  void
  check_types(Gogo* gogo)
  { this->do_check_types(gogo); }

  // Determine the type when there is no context.
  void
  determine_type_no_context();

  // Return the current type of the expression.  This may be changed
  // by determine_type.
  Type*
  type()
  { return this->do_type(); }

  // Return a copy of an expression.
  Expression*
  copy()
  { return this->do_copy(); }

  // Return whether the expression is addressable--something which may
  // be used as the operand of the unary & operator.
  bool
  is_addressable() const
  { return this->do_is_addressable(); }

  // Note that we are taking the address of this expression.  ESCAPES
  // is true if this address escapes the current function.
  void
  address_taken(bool escapes)
  { this->do_address_taken(escapes); }

  // Note that a nil check must be issued for this expression.
  void
  issue_nil_check()
  { this->do_issue_nil_check(); }

  // Return whether this expression must be evaluated in order
  // according to the order of evaluation rules.  This is basically
  // true of all expressions with side-effects.
  bool
  must_eval_in_order() const
  { return this->do_must_eval_in_order(); }

  // Return whether subexpressions of this expression must be
  // evaluated in order.  This is true of index expressions and
  // pointer indirections.  This sets *SKIP to the number of
  // subexpressions to skip during traversing, as index expressions
  // only requiring moving the index, not the array.
  bool
  must_eval_subexpressions_in_order(int* skip) const
  {
    *skip = 0;
    return this->do_must_eval_subexpressions_in_order(skip);
  }

  // Return the backend representation for this expression.
  Bexpression*
  get_backend(Translate_context*);

  // Return an expression handling any conversions which must be done during
  // assignment.
  static Expression*
  convert_for_assignment(Gogo*, Type* lhs_type, Expression* rhs,
                         Location location);

  // Return an expression converting a value of one interface type to another
  // interface type.  If FOR_TYPE_GUARD is true this is for a type
  // assertion.
  static Expression*
  convert_interface_to_interface(Type* lhs_type,
                                 Expression* rhs, bool for_type_guard,
                                 Location);

  // Return a backend expression implementing the comparison LEFT OP RIGHT.
  // TYPE is the type of both sides.
  static Bexpression*
  comparison(Translate_context*, Type* result_type, Operator op,
	     Expression* left, Expression* right, Location);

  // Return the backend expression for the numeric constant VAL.
  static Bexpression*
  backend_numeric_constant_expression(Translate_context*,
                                      Numeric_constant* val);

  // Export the expression.  This is only used for constants.  It will
  // be used for things like values of named constants and sizes of
  // arrays.
  void
  export_expression(Export* exp) const
  { this->do_export(exp); }

  // Import an expression.
  static Expression*
  import_expression(Import*);

  // Return an expression which checks that VAL, of arbitrary integer type,
  // is non-negative and is not more than the maximum integer value.
  static Expression*
  check_bounds(Expression* val, Location);

  // Dump an expression to a dump constext.
  void
  dump_expression(Ast_dump_context*) const;

 protected:
  // May be implemented by child class: traverse the expressions.
  virtual int
  do_traverse(Traverse*);

  // Return a lowered expression.
  virtual Expression*
  do_lower(Gogo*, Named_object*, Statement_inserter*, int)
  { return this; }

  // Return a flattened expression.
  virtual Expression*
  do_flatten(Gogo*, Named_object*, Statement_inserter*)
  { return this; }


  // Return whether this is a constant expression.
  virtual bool
  do_is_constant() const
  { return false; }

  // Return whether this expression can be used as a constant
  // initializer.
  virtual bool
  do_is_static_initializer() const
  { return false; }

  // Return whether this is a constant expression of numeric type, and
  // set the Numeric_constant to the value.
  virtual bool
  do_numeric_constant_value(Numeric_constant*) const
  { return false; }

  // Return whether this is a constant expression of string type, and
  // set VAL to the value.
  virtual bool
  do_string_constant_value(std::string*) const
  { return false; }

  // Called by the parser if the value is being discarded.
  virtual bool
  do_discarding_value();

  // Child class holds type.
  virtual Type*
  do_type() = 0;

  // Child class implements determining type information.
  virtual void
  do_determine_type(const Type_context*) = 0;

  // Child class implements type checking if needed.
  virtual void
  do_check_types(Gogo*)
  { }

  // Child class implements copying.
  virtual Expression*
  do_copy() = 0;

  // Child class implements whether the expression is addressable.
  virtual bool
  do_is_addressable() const
  { return false; }

  // Child class implements taking the address of an expression.
  virtual void
  do_address_taken(bool)
  { }

  // Child class implements issuing a nil check if the address is taken.
  virtual void
  do_issue_nil_check()
  { }

  // Child class implements whether this expression must be evaluated
  // in order.
  virtual bool
  do_must_eval_in_order() const
  { return false; }

  // Child class implements whether this expressions requires that
  // subexpressions be evaluated in order.  The child implementation
  // may set *SKIP if it should be non-zero.
  virtual bool
  do_must_eval_subexpressions_in_order(int* /* skip */) const
  { return false; }

  // Child class implements conversion to backend representation.
  virtual Bexpression*
  do_get_backend(Translate_context*) = 0;

  // Child class implements export.
  virtual void
  do_export(Export*) const;

  // For children to call to give an error for an unused value.
  void
  unused_value_error();

  // For children to call when they detect that they are in error.
  void
  set_is_error();

  // For children to call to report an error conveniently.
  void
  report_error(const char*);

  // Child class implements dumping to a dump context.
  virtual void
  do_dump_expression(Ast_dump_context*) const = 0;

  // Varargs lowering creates a slice object (unnamed compiler temp)
  // to contain the variable length collection of values. The enum
  // below tells the lowering routine whether it can mark that temp
  // as non-escaping or not. For general varargs calls it is not always
  // safe to stack-allocated the storage, but for specific cases (ex:
  // call to append()) it is legal.
  enum Slice_storage_escape_disp
  {
    SLICE_STORAGE_MAY_ESCAPE,
    SLICE_STORAGE_DOES_NOT_ESCAPE
  };

 private:
  // Convert to the desired statement classification, or return NULL.
  // This is a controlled dynamic cast.
  template<typename Expression_class,
	   Expression_classification expr_classification>
  Expression_class*
  convert()
  {
    return (this->classification_ == expr_classification
	    ? static_cast<Expression_class*>(this)
	    : NULL);
  }

  template<typename Expression_class,
	   Expression_classification expr_classification>
  const Expression_class*
  convert() const
  {
    return (this->classification_ == expr_classification
	    ? static_cast<const Expression_class*>(this)
	    : NULL);
  }

  static Expression*
  convert_type_to_interface(Type*, Expression*, Location);

  static Expression*
  get_interface_type_descriptor(Expression*);

  static Expression*
  convert_interface_to_type(Type*, Expression*, Location);

  // The expression classification.
  Expression_classification classification_;
  // The location in the input file.
  Location location_;
};

// A list of Expressions.

class Expression_list
{
 public:
  Expression_list()
    : entries_()
  { }

  // Return whether the list is empty.
  bool
  empty() const
  { return this->entries_.empty(); }

  // Return the number of entries in the list.
  size_t
  size() const
  { return this->entries_.size(); }

  // Add an entry to the end of the list.
  void
  push_back(Expression* expr)
  { this->entries_.push_back(expr); }

  void
  append(Expression_list* add)
  { this->entries_.insert(this->entries_.end(), add->begin(), add->end()); }

  // Reserve space in the list.
  void
  reserve(size_t size)
  { this->entries_.reserve(size); }

  // Traverse the expressions in the list.
  int
  traverse(Traverse*);

  // Copy the list.
  Expression_list*
  copy();

  // Return true if the list contains an error expression.
  bool
  contains_error() const;

  // Retrieve an element by index.
  Expression*&
  at(size_t i)
  { return this->entries_.at(i); }

  // Return the first and last elements.
  Expression*&
  front()
  { return this->entries_.front(); }

  Expression*
  front() const
  { return this->entries_.front(); }

  Expression*&
  back()
  { return this->entries_.back(); }

  Expression*
  back() const
  { return this->entries_.back(); }

  // Iterators.

  typedef std::vector<Expression*>::iterator iterator;
  typedef std::vector<Expression*>::const_iterator const_iterator;

  iterator
  begin()
  { return this->entries_.begin(); }

  const_iterator
  begin() const
  { return this->entries_.begin(); }

  iterator
  end()
  { return this->entries_.end(); }

  const_iterator
  end() const
  { return this->entries_.end(); }

  // Erase an entry.
  void
  erase(iterator p)
  { this->entries_.erase(p); }

 private:
  std::vector<Expression*> entries_;
};

// An abstract base class for an expression which is only used by the
// parser, and is lowered in the lowering pass.

class Parser_expression : public Expression
{
 public:
  Parser_expression(Expression_classification classification,
		    Location location)
    : Expression(classification, location)
  { }

 protected:
  virtual Expression*
  do_lower(Gogo*, Named_object*, Statement_inserter*, int) = 0;

  Type*
  do_type();

  void
  do_determine_type(const Type_context*)
  { go_unreachable(); }

  void
  do_check_types(Gogo*)
  { go_unreachable(); }

  Bexpression*
  do_get_backend(Translate_context*)
  { go_unreachable(); }
};

// An expression which is simply a variable.

class Var_expression : public Expression
{
 public:
  Var_expression(Named_object* variable, Location location)
    : Expression(EXPRESSION_VAR_REFERENCE, location),
      variable_(variable), in_lvalue_pos_(VE_rvalue)
  { }

  // Return the variable.
  Named_object*
  named_object() const
  { return this->variable_; }

  // Does this var expression appear in an lvalue (assigned-to) context?
  bool
  in_lvalue_pos() const
  { return this->in_lvalue_pos_ == VE_lvalue; }

  // Mark a var_expression as appearing in an lvalue context.
  void
  set_in_lvalue_pos()
  { this->in_lvalue_pos_ = VE_lvalue; }

 protected:
  Expression*
  do_lower(Gogo*, Named_object*, Statement_inserter*, int);

  Type*
  do_type();

  void
  do_determine_type(const Type_context*);

  Expression*
  do_copy()
  { return this; }

  bool
  do_is_addressable() const
  { return true; }

  void
  do_address_taken(bool);

  Bexpression*
  do_get_backend(Translate_context*);

  void
  do_dump_expression(Ast_dump_context*) const;

 private:
  // The variable we are referencing.
  Named_object* variable_;
  // Set to TRUE if var expression appears in lvalue context
  Varexpr_context in_lvalue_pos_;
};

// A reference to a variable within an enclosing function.

class Enclosed_var_expression : public Expression
{
 public:
  Enclosed_var_expression(Expression* reference, Named_object* variable,
			  Location location)
    : Expression(EXPRESSION_ENCLOSED_VAR_REFERENCE, location),
      reference_(reference), variable_(variable)
  { }

  // The reference to the enclosed variable.  This will be an indirection of the
  // the field stored within closure variable.
  Expression*
  reference() const
  { return this->reference_; }

  // The variable being enclosed and referenced.
  Named_object*
  variable() const
  { return this->variable_; }

 protected:
  int
  do_traverse(Traverse*);

  Expression*
  do_lower(Gogo*, Named_object*, Statement_inserter*, int);

  Expression*
  do_flatten(Gogo*, Named_object*, Statement_inserter*);

  Type*
  do_type()
  { return this->reference_->type(); }

  void
  do_determine_type(const Type_context* context)
  { return this->reference_->determine_type(context); }

  Expression*
  do_copy()
  { return this; }

  bool
  do_is_addressable() const
  { return this->reference_->is_addressable(); }

  void
  do_address_taken(bool escapes);

  Bexpression*
  do_get_backend(Translate_context* context)
  { return this->reference_->get_backend(context); }

  void
  do_dump_expression(Ast_dump_context*) const;

 private:
  // The reference to the enclosed variable.
  Expression* reference_;
  // The variable being enclosed.
  Named_object* variable_;
};

// A reference to a temporary variable.

class Temporary_reference_expression : public Expression
{
 public:
  Temporary_reference_expression(Temporary_statement* statement,
				 Location location)
    : Expression(EXPRESSION_TEMPORARY_REFERENCE, location),
      statement_(statement), is_lvalue_(false)
  { }

  // The temporary that this expression refers to.
  Temporary_statement*
  statement() const
  { return this->statement_; }

  // Indicate that this reference appears on the left hand side of an
  // assignment statement.
  void
  set_is_lvalue()
  { this->is_lvalue_ = true; }

 protected:
  Type*
  do_type();

  void
  do_determine_type(const Type_context*)
  { }

  Expression*
  do_copy()
  { return make_temporary_reference(this->statement_, this->location()); }

  bool
  do_is_addressable() const
  { return true; }

  void
  do_address_taken(bool);

  Bexpression*
  do_get_backend(Translate_context*);

  void
  do_dump_expression(Ast_dump_context*) const;

 private:
  // The statement where the temporary variable is defined.
  Temporary_statement* statement_;
  // Whether this reference appears on the left hand side of an
  // assignment statement.
  bool is_lvalue_;
};

// Set and use a temporary variable.

class Set_and_use_temporary_expression : public Expression
{
 public:
  Set_and_use_temporary_expression(Temporary_statement* statement,
				   Expression* expr, Location location)
    : Expression(EXPRESSION_SET_AND_USE_TEMPORARY, location),
      statement_(statement), expr_(expr)
  { }

  // Return the temporary.
  Temporary_statement*
  temporary() const
  { return this->statement_; }

  // Return the expression.
  Expression*
  expression() const
  { return this->expr_; }

 protected:
  int
  do_traverse(Traverse* traverse)
  { return Expression::traverse(&this->expr_, traverse); }

  Type*
  do_type();

  void
  do_determine_type(const Type_context*);

  Expression*
  do_copy()
  {
    return make_set_and_use_temporary(this->statement_, this->expr_,
				      this->location());
  }

  bool
  do_is_addressable() const
  { return true; }

  void
  do_address_taken(bool);

  Bexpression*
  do_get_backend(Translate_context*);

  void
  do_dump_expression(Ast_dump_context*) const;

 private:
  // The statement where the temporary variable is defined.
  Temporary_statement* statement_;
  // The expression to assign to the temporary.
  Expression* expr_;
};

// A string expression.

class String_expression : public Expression
{
 public:
  String_expression(const std::string& val, Location location)
    : Expression(EXPRESSION_STRING, location),
      val_(val), type_(NULL)
  { }

  const std::string&
  val() const
  { return this->val_; }

  static Expression*
  do_import(Import*);

 protected:
  bool
  do_is_constant() const
  { return true; }

  bool
  do_is_static_initializer() const
  { return true; }

  bool
  do_string_constant_value(std::string* val) const
  {
    *val = this->val_;
    return true;
  }

  Type*
  do_type();

  void
  do_determine_type(const Type_context*);

  Expression*
  do_copy()
  { return this; }

  Bexpression*
  do_get_backend(Translate_context*);

  // Write string literal to a string dump.
  static void
  export_string(String_dump* exp, const String_expression* str);

  void
  do_export(Export*) const;

  void
  do_dump_expression(Ast_dump_context*) const;

 private:
  // The string value.  This is immutable.
  const std::string val_;
  // The type as determined by context.
  Type* type_;
};

// A type conversion expression.

class Type_conversion_expression : public Expression
{
 public:
  Type_conversion_expression(Type* type, Expression* expr,
			     Location location)
    : Expression(EXPRESSION_CONVERSION, location),
      type_(type), expr_(expr), may_convert_function_types_(false)
  { }

  // Return the type to which we are converting.
  Type*
  type() const
  { return this->type_; }

  // Return the expression which we are converting.
  Expression*
  expr() const
  { return this->expr_; }

  // Permit converting from one function type to another.  This is
  // used internally for method expressions.
  void
  set_may_convert_function_types()
  {
    this->may_convert_function_types_ = true;
  }

  // Import a type conversion expression.
  static Expression*
  do_import(Import*);

 protected:
  int
  do_traverse(Traverse* traverse);

  Expression*
  do_lower(Gogo*, Named_object*, Statement_inserter*, int);

  Expression*
  do_flatten(Gogo*, Named_object*, Statement_inserter*);

  bool
  do_is_constant() const;

  bool
  do_is_static_initializer() const;

  bool
  do_numeric_constant_value(Numeric_constant*) const;

  bool
  do_string_constant_value(std::string*) const;

  Type*
  do_type()
  { return this->type_; }

  void
  do_determine_type(const Type_context*);

  void
  do_check_types(Gogo*);

  Expression*
  do_copy()
  {
    return new Type_conversion_expression(this->type_, this->expr_->copy(),
					  this->location());
  }

  Bexpression*
  do_get_backend(Translate_context* context);

  void
  do_export(Export*) const;

  void
  do_dump_expression(Ast_dump_context*) const;

 private:
  // The type to convert to.
  Type* type_;
  // The expression to convert.
  Expression* expr_;
  // True if this is permitted to convert function types.  This is
  // used internally for method expressions.
  bool may_convert_function_types_;
};

// An unsafe type conversion, used to pass values to builtin functions.

class Unsafe_type_conversion_expression : public Expression
{
 public:
  Unsafe_type_conversion_expression(Type* type, Expression* expr,
				    Location location)
    : Expression(EXPRESSION_UNSAFE_CONVERSION, location),
      type_(type), expr_(expr)
  { }

  Expression*
  expr() const
  { return this->expr_; }

 protected:
  int
  do_traverse(Traverse* traverse);

  bool
  do_is_static_initializer() const;

  Type*
  do_type()
  { return this->type_; }

  void
  do_determine_type(const Type_context*)
  { this->expr_->determine_type_no_context(); }

  Expression*
  do_copy()
  {
    return new Unsafe_type_conversion_expression(this->type_,
						 this->expr_->copy(),
						 this->location());
  }

  Bexpression*
  do_get_backend(Translate_context*);

  void
  do_dump_expression(Ast_dump_context*) const;

 private:
  // The type to convert to.
  Type* type_;
  // The expression to convert.
  Expression* expr_;
};

// A Unary expression.

class Unary_expression : public Expression
{
 public:
  Unary_expression(Operator op, Expression* expr, Location location)
    : Expression(EXPRESSION_UNARY, location),
      op_(op), escapes_(true), create_temp_(false), is_gc_root_(false),
      is_slice_init_(false), expr_(expr), issue_nil_check_(false)
  { }

  // Return the operator.
  Operator
  op() const
  { return this->op_; }

  // Return the operand.
  Expression*
  operand() const
  { return this->expr_; }

  // Record that an address expression does not escape.
  void
  set_does_not_escape()
  {
    go_assert(this->op_ == OPERATOR_AND);
    this->escapes_ = false;
  }

  // Record that this is an address expression which should create a
  // temporary variable if necessary.  This is used for method calls.
  void
  set_create_temp()
  {
    go_assert(this->op_ == OPERATOR_AND);
    this->create_temp_ = true;
  }

  // Record that this is an address expression of a GC root, which is a
  // mutable composite literal.  This used for registering GC variables.
  void
  set_is_gc_root()
  {
    go_assert(this->op_ == OPERATOR_AND);
    this->is_gc_root_ = true;
  }

  // Record that this is an address expression of a slice value initializer,
  // which is mutable if the values are not copied to the heap.
  void
  set_is_slice_init()
  {
    go_assert(this->op_ == OPERATOR_AND);
    this->is_slice_init_ = true;
  }

  // Apply unary opcode OP to UNC, setting NC.  Return true if this
  // could be done, false if not.  On overflow, issues an error and
  // sets *ISSUED_ERROR.
  static bool
  eval_constant(Operator op, const Numeric_constant* unc,
		Location, Numeric_constant* nc, bool *issued_error);

  static Expression*
  do_import(Import*);

 protected:
  int
  do_traverse(Traverse* traverse)
  { return Expression::traverse(&this->expr_, traverse); }

  Expression*
  do_lower(Gogo*, Named_object*, Statement_inserter*, int);

  Expression*
  do_flatten(Gogo*, Named_object*, Statement_inserter*);

  bool
  do_is_constant() const;

  bool
  do_is_static_initializer() const;

  bool
  do_numeric_constant_value(Numeric_constant*) const;

  Type*
  do_type();

  void
  do_determine_type(const Type_context*);

  void
  do_check_types(Gogo*);

  Expression*
  do_copy()
  {
    return Expression::make_unary(this->op_, this->expr_->copy(),
				  this->location());
  }

  bool
  do_must_eval_subexpressions_in_order(int*) const
  { return this->op_ == OPERATOR_MULT; }

  bool
  do_is_addressable() const
  { return this->op_ == OPERATOR_MULT; }

  Bexpression*
  do_get_backend(Translate_context*);

  void
  do_export(Export*) const;

  void
  do_dump_expression(Ast_dump_context*) const;

  void
  do_issue_nil_check()
  { this->issue_nil_check_ = (this->op_ == OPERATOR_MULT); }

 private:
  static bool
  base_is_static_initializer(Expression*);

  // The unary operator to apply.
  Operator op_;
  // Normally true.  False if this is an address expression which does
  // not escape the current function.
  bool escapes_;
  // True if this is an address expression which should create a
  // temporary variable if necessary.
  bool create_temp_;
  // True if this is an address expression for a GC root.  A GC root is a
  // special struct composite literal that is mutable when addressed, meaning
  // it cannot be represented as an immutable_struct in the backend.
  bool is_gc_root_;
  // True if this is an address expression for a slice value with an immutable
  // initializer.  The initializer for a slice's value pointer has an array
  // type, meaning it cannot be represented as an immutable_struct in the
  // backend.
  bool is_slice_init_;
  // The operand.
  Expression* expr_;
  // Whether or not to issue a nil check for this expression if its address
  // is being taken.
  bool issue_nil_check_;
};

// A binary expression.

class Binary_expression : public Expression
{
 public:
  Binary_expression(Operator op, Expression* left, Expression* right,
		    Location location)
    : Expression(EXPRESSION_BINARY, location),
      op_(op), left_(left), right_(right), type_(NULL)
  { }

  // Return the operator.
  Operator
  op()
  { return this->op_; }

  // Return the left hand expression.
  Expression*
  left()
  { return this->left_; }

  // Return the right hand expression.
  Expression*
  right()
  { return this->right_; }

  // Apply binary opcode OP to LEFT_NC and RIGHT_NC, setting NC.
  // Return true if this could be done, false if not.  Issue errors at
  // LOCATION as appropriate, and sets *ISSUED_ERROR if it did.
  static bool
  eval_constant(Operator op, Numeric_constant* left_nc,
		Numeric_constant* right_nc, Location location,
		Numeric_constant* nc, bool* issued_error);

  // Compare constants LEFT_NC and RIGHT_NC according to OP, setting
  // *RESULT.  Return true if this could be done, false if not.  Issue
  // errors at LOCATION as appropriate.
  static bool
  compare_constant(Operator op, Numeric_constant* left_nc,
		   Numeric_constant* right_nc, Location location,
		   bool* result);

  static Expression*
  do_import(Import*);

  // Report an error if OP can not be applied to TYPE.  Return whether
  // it can.  OTYPE is the type of the other operand.
  static bool
  check_operator_type(Operator op, Type* type, Type* otype, Location);

  // Set *RESULT_TYPE to the resulting type when OP is applied to
  // operands of type LEFT_TYPE and RIGHT_TYPE.  Return true on
  // success, false on failure.
  static bool
  operation_type(Operator op, Type* left_type, Type* right_type,
		 Type** result_type);

 protected:
  int
  do_traverse(Traverse* traverse);

  Expression*
  do_lower(Gogo*, Named_object*, Statement_inserter*, int);

  Expression*
  do_flatten(Gogo*, Named_object*, Statement_inserter*);

  bool
  do_is_constant() const
  { return this->left_->is_constant() && this->right_->is_constant(); }

  bool
  do_is_static_initializer() const;

  bool
  do_numeric_constant_value(Numeric_constant*) const;

  bool
  do_discarding_value();

  Type*
  do_type();

  void
  do_determine_type(const Type_context*);

  void
  do_check_types(Gogo*);

  Expression*
  do_copy()
  {
    return Expression::make_binary(this->op_, this->left_->copy(),
				   this->right_->copy(), this->location());
  }

  Bexpression*
  do_get_backend(Translate_context*);

  void
  do_export(Export*) const;

  void
  do_dump_expression(Ast_dump_context*) const;

 private:
  static bool
  cmp_to_bool(Operator op, int cmp);

  static bool
  eval_integer(Operator op, const Numeric_constant*, const Numeric_constant*,
	       Location, Numeric_constant*);

  static bool
  eval_float(Operator op, const Numeric_constant*, const Numeric_constant*,
	     Location, Numeric_constant*);

  static bool
  eval_complex(Operator op, const Numeric_constant*, const Numeric_constant*,
	       Location, Numeric_constant*);

  static bool
  compare_integer(const Numeric_constant*, const Numeric_constant*, int*);

  static bool
  compare_float(const Numeric_constant*, const Numeric_constant *, int*);

  static bool
  compare_complex(const Numeric_constant*, const Numeric_constant*, int*);

  Expression*
  lower_struct_comparison(Gogo*, Statement_inserter*);

  Expression*
  lower_array_comparison(Gogo*, Statement_inserter*);

  Expression*
  lower_interface_value_comparison(Gogo*, Statement_inserter*);

  Expression*
  lower_compare_to_memcmp(Gogo*, Statement_inserter*);

  Expression*
  operand_address(Statement_inserter*, Expression*);

  // The binary operator to apply.
  Operator op_;
  // The left hand side operand.
  Expression* left_;
  // The right hand side operand.
  Expression* right_;
  // The type of a comparison operation.
  Type* type_;
};

// A string concatenation expression.  This is a sequence of strings
// added together.  It is created when lowering Binary_expression.

class String_concat_expression : public Expression
{
 public:
  String_concat_expression(Expression_list* exprs)
    : Expression(EXPRESSION_STRING_CONCAT, exprs->front()->location()),
      exprs_(exprs)
  { }

  // Return the list of string expressions to be concatenated.
  Expression_list*
  exprs()
  { return this->exprs_; }

 protected:
  int
  do_traverse(Traverse* traverse)
  { return this->exprs_->traverse(traverse); }

  Expression*
  do_lower(Gogo*, Named_object*, Statement_inserter*, int)
  { return this; }

  Expression*
  do_flatten(Gogo*, Named_object*, Statement_inserter*);

  bool
  do_is_constant() const;

  bool
  do_is_static_initializer() const;

  Type*
  do_type();

  void
  do_determine_type(const Type_context*);

  void
  do_check_types(Gogo*);

  Expression*
  do_copy()
  { return Expression::make_string_concat(this->exprs_->copy()); }

  Bexpression*
  do_get_backend(Translate_context*)
  { go_unreachable(); }

  void
  do_export(Export*) const
  { go_unreachable(); }

  void
  do_dump_expression(Ast_dump_context*) const;

 private:
  // The string expressions to concatenate.
  Expression_list* exprs_;
};

// A call expression.  The go statement needs to dig inside this.

class Call_expression : public Expression
{
 public:
  Call_expression(Expression* fn, Expression_list* args, bool is_varargs,
		  Location location)
    : Expression(EXPRESSION_CALL, location),
      fn_(fn), args_(args), type_(NULL), results_(NULL), call_(NULL),
      call_temp_(NULL), expected_result_count_(0), is_varargs_(is_varargs),
      varargs_are_lowered_(false), types_are_determined_(false),
      is_deferred_(false), is_concurrent_(false), issued_error_(false),
      is_multi_value_arg_(false), is_flattened_(false)
  { }

  // The function to call.
  Expression*
  fn() const
  { return this->fn_; }

  // The arguments.
  Expression_list*
  args()
  { return this->args_; }

  const Expression_list*
  args() const
  { return this->args_; }

  // Get the function type.
  Function_type*
  get_function_type() const;

  // Return the number of values this call will return.
  size_t
  result_count() const;

  // Return the temporary variable which holds result I.  This is only
  // valid after the expression has been lowered, and is only valid
  // for calls which return multiple results.
  Temporary_statement*
  result(size_t i) const;

  // Set the number of results expected from this call.  This is used
  // when the call appears in a context that expects multiple results,
  // such as a, b = f().
  void
  set_expected_result_count(size_t);

  // Return whether this is a call to the predeclared function
  // recover.
  bool
  is_recover_call() const;

  // Set the argument for a call to recover.
  void
  set_recover_arg(Expression*);

  // Whether the last argument is a varargs argument (f(a...)).
  bool
  is_varargs() const
  { return this->is_varargs_; }

  // Return whether varargs have already been lowered.
  bool
  varargs_are_lowered() const
  { return this->varargs_are_lowered_; }

  // Note that varargs have already been lowered.
  void
  set_varargs_are_lowered()
  { this->varargs_are_lowered_ = true; }

  // Whether this call is being deferred.
  bool
  is_deferred() const
  { return this->is_deferred_; }

  // Note that the call is being deferred.
  void
  set_is_deferred()
  { this->is_deferred_ = true; }

  // Whether this call is concurrently executed.
  bool
  is_concurrent() const
  { return this->is_concurrent_; }

  // Note that the call is concurrently executed.
  void
  set_is_concurrent()
  { this->is_concurrent_ = true; }

  // We have found an error with this call expression; return true if
  // we should report it.
  bool
  issue_error();

  // Whether or not this call contains errors, either in the call or the
  // arguments to the call.
  bool
  is_erroneous_call();

  // Whether this call returns multiple results that are used as an
  // multi-valued argument.
  bool
  is_multi_value_arg() const
  { return this->is_multi_value_arg_; }

  // Note this call is used as a multi-valued argument.
  void
  set_is_multi_value_arg()
  { this->is_multi_value_arg_ = true; }

 protected:
  int
  do_traverse(Traverse*);

  virtual Expression*
  do_lower(Gogo*, Named_object*, Statement_inserter*, int);

  virtual Expression*
  do_flatten(Gogo*, Named_object*, Statement_inserter*);

  bool
  do_discarding_value()
  { return true; }

  virtual Type*
  do_type();

  virtual void
  do_determine_type(const Type_context*);

  virtual void
  do_check_types(Gogo*);

  Expression*
  do_copy();

  bool
  do_must_eval_in_order() const;

  virtual Bexpression*
  do_get_backend(Translate_context*);

  virtual bool
  do_is_recover_call() const;

  virtual void
  do_set_recover_arg(Expression*);

  // Let a builtin expression change the argument list.
  void
  set_args(Expression_list* args)
  { this->args_ = args; }

  // Let a builtin expression lower varargs.
  void
  lower_varargs(Gogo*, Named_object* function, Statement_inserter* inserter,
		Type* varargs_type, size_t param_count,
		Slice_storage_escape_disp escape_disp);

  // Let a builtin expression check whether types have been
  // determined.
  bool
  determining_types();

  void
  do_dump_expression(Ast_dump_context*) const;

 private:
  bool
  check_argument_type(int, const Type*, const Type*, Location, bool);

  Expression*
  lower_to_builtin(Named_object**, const char*, int);

  Expression*
  interface_method_function(Interface_field_reference_expression*,
			    Expression**);

  Bexpression*
  set_results(Translate_context*, Bexpression*);

  // The function to call.
  Expression* fn_;
  // The arguments to pass.  This may be NULL if there are no
  // arguments.
  Expression_list* args_;
  // The type of the expression, to avoid recomputing it.
  Type* type_;
  // The list of temporaries which will hold the results if the
  // function returns a tuple.
  std::vector<Temporary_statement*>* results_;
  // The backend expression for the call, used for a call which returns a tuple.
  Bexpression* call_;
  // A temporary variable to store this call if the function returns a tuple.
  Temporary_statement* call_temp_;
  // If not 0, the number of results expected from this call, when
  // used in a context that expects multiple values.
  size_t expected_result_count_;
  // True if the last argument is a varargs argument (f(a...)).
  bool is_varargs_;
  // True if varargs have already been lowered.
  bool varargs_are_lowered_;
  // True if types have been determined.
  bool types_are_determined_;
  // True if the call is an argument to a defer statement.
  bool is_deferred_;
  // True if the call is an argument to a go statement.
  bool is_concurrent_;
  // True if we reported an error about a mismatch between call
  // results and uses.  This is to avoid producing multiple errors
  // when there are multiple Call_result_expressions.
  bool issued_error_;
  // True if this call is used as an argument that returns multiple results.
  bool is_multi_value_arg_;
  // True if this expression has already been flattened.
  bool is_flattened_;
};

// A single result from a call which returns multiple results.

class Call_result_expression : public Expression
{
 public:
  Call_result_expression(Call_expression* call, unsigned int index)
    : Expression(EXPRESSION_CALL_RESULT, call->location()),
      call_(call), index_(index)
  { }

  Expression*
  call() const
  { return this->call_; }

  unsigned int
  index() const
  { return this->index_; }

 protected:
  int
  do_traverse(Traverse*);

  Type*
  do_type();

  void
  do_determine_type(const Type_context*);

  void
  do_check_types(Gogo*);

  Expression*
  do_copy()
  {
    return new Call_result_expression(this->call_->call_expression(),
				      this->index_);
  }

  bool
  do_must_eval_in_order() const
  { return true; }

  Bexpression*
  do_get_backend(Translate_context*);

  void
  do_dump_expression(Ast_dump_context*) const;

 private:
  // The underlying call expression.
  Expression* call_;
  // Which result we want.
  unsigned int index_;
};

// An expression which represents a pointer to a function.

class Func_expression : public Expression
{
 public:
  Func_expression(Named_object* function, Expression* closure,
		  Location location)
    : Expression(EXPRESSION_FUNC_REFERENCE, location),
      function_(function), closure_(closure),
      runtime_code_(Runtime::NUMBER_OF_FUNCTIONS)
  { }

  // Return the object associated with the function.
  Named_object*
  named_object() const
  { return this->function_; }

  // Return the closure for this function.  This will return NULL if
  // the function has no closure, which is the normal case.
  Expression*
  closure()
  { return this->closure_; }

  // Return whether this is a reference to a runtime function.
  bool
  is_runtime_function() const
  { return this->runtime_code_ != Runtime::NUMBER_OF_FUNCTIONS; }

  // Return the runtime code for this function expression.
  // Returns Runtime::NUMBER_OF_FUNCTIONS if this is not a reference to a
  // runtime function.
  Runtime::Function
  runtime_code() const
  { return this->runtime_code_; }

  // Set the runtime code for this function expression.
  void
  set_runtime_code(Runtime::Function code)
  { this->runtime_code_ = code; }

  // Return a backend expression for the code of a function.
  static Bexpression*
  get_code_pointer(Gogo*, Named_object* function, Location loc);

 protected:
  int
  do_traverse(Traverse*);

  Type*
  do_type();

  void
  do_determine_type(const Type_context*)
  {
    if (this->closure_ != NULL)
      this->closure_->determine_type_no_context();
  }

  Expression*
  do_copy()
  {
    return Expression::make_func_reference(this->function_,
					   (this->closure_ == NULL
					    ? NULL
					    : this->closure_->copy()),
					   this->location());
  }

  Bexpression*
  do_get_backend(Translate_context*);

  void
  do_dump_expression(Ast_dump_context*) const;

 private:
  // The function itself.
  Named_object* function_;
  // A closure.  This is normally NULL.  For a nested function, it may
  // be a struct holding pointers to all the variables referenced by
  // this function and defined in enclosing functions.
  Expression* closure_;
  // The runtime code for the referenced function.
  Runtime::Function runtime_code_;
};

// A function descriptor.  A function descriptor is a struct with a
// single field pointing to the function code.  This is used for
// functions without closures.

class Func_descriptor_expression : public Expression
{
 public:
  Func_descriptor_expression(Named_object* fn);

  // Make the function descriptor type, so that it can be converted.
  static void
  make_func_descriptor_type();

 protected:
  int
  do_traverse(Traverse*);

  Type*
  do_type();

  void
  do_determine_type(const Type_context*)
  { }

  Expression*
  do_copy()
  { return Expression::make_func_descriptor(this->fn_); }

  bool
  do_is_addressable() const
  { return true; }

  Bexpression*
  do_get_backend(Translate_context*);

  void
  do_dump_expression(Ast_dump_context* context) const;

 private:
  // The type of all function descriptors.
  static Type* descriptor_type;

  // The function for which this is the descriptor.
  Named_object* fn_;
  // The descriptor variable.
  Bvariable* dvar_;
};

// A reference to an unknown name.

class Unknown_expression : public Parser_expression
{
 public:
  Unknown_expression(Named_object* named_object, Location location)
    : Parser_expression(EXPRESSION_UNKNOWN_REFERENCE, location),
      named_object_(named_object), no_error_message_(false),
      is_composite_literal_key_(false)
  { }

  // The associated named object.
  Named_object*
  named_object() const
  { return this->named_object_; }

  // The name of the identifier which was unknown.
  const std::string&
  name() const;

  // Call this to indicate that we should not give an error if this
  // name is never defined.  This is used to avoid knock-on errors
  // during an erroneous parse.
  void
  set_no_error_message()
  { this->no_error_message_ = true; }

  // Note that this expression is being used as the key in a composite
  // literal, so it may be OK if it is not resolved.
  void
  set_is_composite_literal_key()
  { this->is_composite_literal_key_ = true; }

  // Note that this expression should no longer be treated as a
  // composite literal key.
  void
  clear_is_composite_literal_key()
  { this->is_composite_literal_key_ = false; }

 protected:
  Expression*
  do_lower(Gogo*, Named_object*, Statement_inserter*, int);

  Expression*
  do_copy()
  { return new Unknown_expression(this->named_object_, this->location()); }

  void
  do_dump_expression(Ast_dump_context*) const;
  
 private:
  // The unknown name.
  Named_object* named_object_;
  // True if we should not give errors if this is undefined.  This is
  // used if there was a parse failure.
  bool no_error_message_;
  // True if this is the key in a composite literal.
  bool is_composite_literal_key_;
};

// An index expression.  This is lowered to an array index, a string
// index, or a map index.

class Index_expression : public Parser_expression
{
 public:
  Index_expression(Expression* left, Expression* start, Expression* end,
                   Expression* cap, Location location)
    : Parser_expression(EXPRESSION_INDEX, location),
      left_(left), start_(start), end_(end), cap_(cap)
  { }

  // Dump an index expression, i.e. an expression of the form
  // expr[expr], expr[expr:expr], or expr[expr:expr:expr] to a dump context.
  static void
  dump_index_expression(Ast_dump_context*, const Expression* expr, 
                        const Expression* start, const Expression* end,
                        const Expression* cap);

 protected:
  int
  do_traverse(Traverse*);

  Expression*
  do_lower(Gogo*, Named_object*, Statement_inserter*, int);

  Expression*
  do_copy()
  {
    return new Index_expression(this->left_->copy(), this->start_->copy(),
				(this->end_ == NULL
				 ? NULL
				 : this->end_->copy()),
				(this->cap_ == NULL
				 ? NULL
				 : this->cap_->copy()),
				this->location());
  }

  bool
  do_must_eval_subexpressions_in_order(int* skip) const
  {
    *skip = 1;
    return true;
  }

  void
  do_dump_expression(Ast_dump_context*) const;

  void
  do_issue_nil_check()
  { this->left_->issue_nil_check(); }
 private:
  // The expression being indexed.
  Expression* left_;
  // The first index.
  Expression* start_;
  // The second index.  This is NULL for an index, non-NULL for a
  // slice.
  Expression* end_;
  // The capacity argument.  This is NULL for indices and slices that use the
  // default capacity, non-NULL for indices and slices that specify the
  // capacity.
  Expression* cap_;
};

// An array index.  This is used for both indexing and slicing.

class Array_index_expression : public Expression
{
 public:
  Array_index_expression(Expression* array, Expression* start,
			 Expression* end, Expression* cap, Location location)
    : Expression(EXPRESSION_ARRAY_INDEX, location),
      array_(array), start_(start), end_(end), cap_(cap), type_(NULL)
  { }

  // Return the array.
  Expression*
  array()
  { return this->array_; }

  const Expression*
  array() const
  { return this->array_; }

  // Return the index of a simple index expression, or the start index
  // of a slice expression.
  Expression*
  start()
  { return this->start_; }

  const Expression*
  start() const
  { return this->start_; }

  // Return the end index of a slice expression.  This is NULL for a
  // simple index expression.
  Expression*
  end()
  { return this->end_; }

  const Expression*
  end() const
  { return this->end_; }

 protected:
  int
  do_traverse(Traverse*);

  Expression*
  do_flatten(Gogo*, Named_object*, Statement_inserter*);

  Type*
  do_type();

  void
  do_determine_type(const Type_context*);

  void
  do_check_types(Gogo*);

  Expression*
  do_copy()
  {
    return Expression::make_array_index(this->array_->copy(),
					this->start_->copy(),
					(this->end_ == NULL
					 ? NULL
					 : this->end_->copy()),
					(this->cap_ == NULL
					 ? NULL
					 : this->cap_->copy()),
					this->location());
  }

  bool
  do_must_eval_subexpressions_in_order(int* skip) const
  {
    *skip = 1;
    return true;
  }

  bool
  do_is_addressable() const;

  void
  do_address_taken(bool escapes)
  { this->array_->address_taken(escapes); }

  void
  do_issue_nil_check()
  { this->array_->issue_nil_check(); }

  Bexpression*
  do_get_backend(Translate_context*);

  void
  do_dump_expression(Ast_dump_context*) const;
  
 private:
  // The array we are getting a value from.
  Expression* array_;
  // The start or only index.
  Expression* start_;
  // The end index of a slice.  This may be NULL for a simple array
  // index, or it may be a nil expression for the length of the array.
  Expression* end_;
  // The capacity argument of a slice.  This may be NULL for an array index or
  // slice.
  Expression* cap_;
  // The type of the expression.
  Type* type_;
};

// A string index.  This is used for both indexing and slicing.

class String_index_expression : public Expression
{
 public:
  String_index_expression(Expression* string, Expression* start,
			  Expression* end, Location location)
    : Expression(EXPRESSION_STRING_INDEX, location),
      string_(string), start_(start), end_(end)
  { }

  // Return the string being indexed.
  Expression*
  string() const
  { return this->string_; }

 protected:
  int
  do_traverse(Traverse*);

  Expression*
  do_flatten(Gogo*, Named_object*, Statement_inserter*);

  Type*
  do_type();

  void
  do_determine_type(const Type_context*);

  void
  do_check_types(Gogo*);

  Expression*
  do_copy()
  {
    return Expression::make_string_index(this->string_->copy(),
					 this->start_->copy(),
					 (this->end_ == NULL
					  ? NULL
					  : this->end_->copy()),
					 this->location());
  }

  bool
  do_must_eval_subexpressions_in_order(int* skip) const
  {
    *skip = 1;
    return true;
  }

  Bexpression*
  do_get_backend(Translate_context*);

  void
  do_dump_expression(Ast_dump_context*) const;

 private:
  // The string we are getting a value from.
  Expression* string_;
  // The start or only index.
  Expression* start_;
  // The end index of a slice.  This may be NULL for a single index,
  // or it may be a nil expression for the length of the string.
  Expression* end_;
};

// An index into a map.

class Map_index_expression : public Expression
{
 public:
  Map_index_expression(Expression* map, Expression* index,
		       Location location)
    : Expression(EXPRESSION_MAP_INDEX, location),
      map_(map), index_(index), value_pointer_(NULL)
  { }

  // Return the map.
  Expression*
  map()
  { return this->map_; }

  const Expression*
  map() const
  { return this->map_; }

  // Return the index.
  Expression*
  index()
  { return this->index_; }

  const Expression*
  index() const
  { return this->index_; }

  // Get the type of the map being indexed.
  Map_type*
  get_map_type() const;

  // Return an expression for the map index.  This returns an
  // expression that evaluates to a pointer to a value in the map.  If
  // the key is not present in the map, this will return a pointer to
  // the zero value.
  Expression*
  get_value_pointer(Gogo*);

 protected:
  int
  do_traverse(Traverse*);

  Expression*
  do_flatten(Gogo*, Named_object*, Statement_inserter*);

  Type*
  do_type();

  void
  do_determine_type(const Type_context*);

  void
  do_check_types(Gogo*);

  Expression*
  do_copy()
  {
    return Expression::make_map_index(this->map_->copy(),
				      this->index_->copy(),
				      this->location());
  }

  bool
  do_must_eval_subexpressions_in_order(int* skip) const
  {
    *skip = 1;
    return true;
  }

  // A map index expression is an lvalue but it is not addressable.

  Bexpression*
  do_get_backend(Translate_context*);

  void
  do_dump_expression(Ast_dump_context*) const;

 private:
  // The map we are looking into.
  Expression* map_;
  // The index.
  Expression* index_;
  // A pointer to the value at this index.
  Expression* value_pointer_;
};

// An expression which represents a method bound to its first
// argument.

class Bound_method_expression : public Expression
{
 public:
  Bound_method_expression(Expression* expr, const Method *method,
			  Named_object* function, Location location)
    : Expression(EXPRESSION_BOUND_METHOD, location),
      expr_(expr), expr_type_(NULL), method_(method), function_(function)
  { }

  // Return the object which is the first argument.
  Expression*
  first_argument()
  { return this->expr_; }

  // Return the implicit type of the first argument.  This will be
  // non-NULL when using a method from an anonymous field without
  // using an explicit stub.
  Type*
  first_argument_type() const
  { return this->expr_type_; }

  // Return the method.
  const Method*
  method() const
  { return this->method_; }

  // Return the function to call.
  Named_object*
  function() const
  { return this->function_; }

  // Set the implicit type of the expression.
  void
  set_first_argument_type(Type* type)
  { this->expr_type_ = type; }

  // Create a thunk to call FUNCTION, for METHOD, when it is used as
  // part of a method value.
  static Named_object*
  create_thunk(Gogo*, const Method* method, Named_object* function);

 protected:
  int
  do_traverse(Traverse*);

  Expression*
  do_flatten(Gogo*, Named_object*, Statement_inserter*);

  Type*
  do_type();

  void
  do_determine_type(const Type_context*);

  void
  do_check_types(Gogo*);

  Expression*
  do_copy()
  {
    return new Bound_method_expression(this->expr_->copy(), this->method_,
				       this->function_, this->location());
  }

  Bexpression*
  do_get_backend(Translate_context*)
  { go_unreachable(); }

  void
  do_dump_expression(Ast_dump_context*) const;

 private:
  // A mapping from method functions to the thunks we have created for
  // them.
  typedef Unordered_map(Named_object*, Named_object*) Method_value_thunks;
  static Method_value_thunks method_value_thunks;

  // The object used to find the method.  This is passed to the method
  // as the first argument.
  Expression* expr_;
  // The implicit type of the object to pass to the method.  This is
  // NULL in the normal case, non-NULL when using a method from an
  // anonymous field which does not require a stub.
  Type* expr_type_;
  // The method.
  const Method* method_;
  // The function to call.  This is not the same as
  // method_->named_object() when the method has a stub.  This will be
  // the real function rather than the stub.
  Named_object* function_;
};

// A reference to a field in a struct.

class Field_reference_expression : public Expression
{
 public:
  Field_reference_expression(Expression* expr, unsigned int field_index,
			     Location location)
    : Expression(EXPRESSION_FIELD_REFERENCE, location),
      expr_(expr), field_index_(field_index), implicit_(false), called_fieldtrack_(false)
  { }

  // Return the struct expression.
  Expression*
  expr() const
  { return this->expr_; }

  // Return the field index.
  unsigned int
  field_index() const
  { return this->field_index_; }

  // Return whether this node was implied by an anonymous field.
  bool
  implicit() const
  { return this->implicit_; }

  void
  set_implicit(bool implicit)
  { this->implicit_ = implicit; }

  // Set the struct expression.  This is used when parsing.
  void
  set_struct_expression(Expression* expr)
  {
    go_assert(this->expr_ == NULL);
    this->expr_ = expr;
  }

 protected:
  int
  do_traverse(Traverse* traverse)
  { return Expression::traverse(&this->expr_, traverse); }

  Expression*
  do_lower(Gogo*, Named_object*, Statement_inserter*, int);

  Type*
  do_type();

  void
  do_determine_type(const Type_context*)
  { this->expr_->determine_type_no_context(); }

  void
  do_check_types(Gogo*);

  Expression*
  do_copy()
  {
    return Expression::make_field_reference(this->expr_->copy(),
					    this->field_index_,
					    this->location());
  }

  bool
  do_is_addressable() const
  { return this->expr_->is_addressable(); }

  void
  do_address_taken(bool escapes)
  { this->expr_->address_taken(escapes); }

  void
  do_issue_nil_check()
  { this->expr_->issue_nil_check(); }

  Bexpression*
  do_get_backend(Translate_context*);

  void
  do_dump_expression(Ast_dump_context*) const;

 private:
  // The expression we are looking into.  This should have a type of
  // struct.
  Expression* expr_;
  // The zero-based index of the field we are retrieving.
  unsigned int field_index_;
  // Whether this node was emitted implicitly for an embedded field,
  // that is, expr_ is not the expr_ of the original user node.
  bool implicit_;
  // Whether we have already emitted a fieldtrack call.
  bool called_fieldtrack_;
};

// A reference to a field of an interface.

class Interface_field_reference_expression : public Expression
{
 public:
  Interface_field_reference_expression(Expression* expr,
				       const std::string& name,
				       Location location)
    : Expression(EXPRESSION_INTERFACE_FIELD_REFERENCE, location),
      expr_(expr), name_(name)
  { }

  // Return the expression for the interface object.
  Expression*
  expr()
  { return this->expr_; }

  // Return the name of the method to call.
  const std::string&
  name() const
  { return this->name_; }

  // Create a thunk to call the method NAME in TYPE when it is used as
  // part of a method value.
  static Named_object*
  create_thunk(Gogo*, Interface_type* type, const std::string& name);

  // Return an expression for the pointer to the function to call.
  Expression*
  get_function();

  // Return an expression for the first argument to pass to the interface
  // function.  This is the real object associated with the interface object.
  Expression*
  get_underlying_object();

 protected:
  int
  do_traverse(Traverse* traverse);

  Expression*
  do_flatten(Gogo*, Named_object*, Statement_inserter*);

  Type*
  do_type();

  void
  do_determine_type(const Type_context*);

  void
  do_check_types(Gogo*);

  Expression*
  do_copy()
  {
    return Expression::make_interface_field_reference(this->expr_->copy(),
						      this->name_,
						      this->location());
  }

  Bexpression*
  do_get_backend(Translate_context*);

  void
  do_dump_expression(Ast_dump_context*) const;

 private:
  // A mapping from interface types to a list of thunks we have
  // created for methods.
  typedef std::vector<std::pair<std::string, Named_object*> > Method_thunks;
  typedef Unordered_map(Interface_type*, Method_thunks*)
    Interface_method_thunks;
  static Interface_method_thunks interface_method_thunks;

  // The expression for the interface object.  This should have a type
  // of interface or pointer to interface.
  Expression* expr_;
  // The field we are retrieving--the name of the method.
  std::string name_;
};

// Implement the builtin function new.

class Allocation_expression : public Expression
{
 public:
  Allocation_expression(Type* type, Location location)
    : Expression(EXPRESSION_ALLOCATION, location),
      type_(type), allocate_on_stack_(false)
  { }

  void
  set_allocate_on_stack()
  { this->allocate_on_stack_ = true; }

 protected:
  int
  do_traverse(Traverse*);

  Type*
  do_type();

  void
  do_determine_type(const Type_context*)
  { }

  Expression*
  do_copy();

  Bexpression*
  do_get_backend(Translate_context*);

  void
  do_dump_expression(Ast_dump_context*) const;

 private:
  // The type we are allocating.
  Type* type_;
  // Whether or not this is a stack allocation.
  bool allocate_on_stack_;
};

// A general composite literal.  This is lowered to a type specific
// version.

class Composite_literal_expression : public Parser_expression
{
 public:
  Composite_literal_expression(Type* type, int depth, bool has_keys,
			       Expression_list* vals, bool all_are_names,
			       Location location)
    : Parser_expression(EXPRESSION_COMPOSITE_LITERAL, location),
      type_(type), depth_(depth), vals_(vals), has_keys_(has_keys),
      all_are_names_(all_are_names), key_path_(std::vector<bool>(depth))
  {}


  // Mark the DEPTH entry of KEY_PATH as containing a key.
  void
  update_key_path(size_t depth)
  {
    go_assert(depth < this->key_path_.size());
    this->key_path_[depth] = true;
  }

 protected:
  int
  do_traverse(Traverse* traverse);

  Expression*
  do_lower(Gogo*, Named_object*, Statement_inserter*, int);

  Expression*
  do_copy()
  {
    Composite_literal_expression *ret =
      new Composite_literal_expression(this->type_, this->depth_,
				       this->has_keys_,
				       (this->vals_ == NULL
					? NULL
					: this->vals_->copy()),
				       this->all_are_names_,
				       this->location());
    ret->key_path_ = this->key_path_;
    return ret;
  }

  void
  do_dump_expression(Ast_dump_context*) const;

 private:
  Expression*
  lower_struct(Gogo*, Type*);

  Expression*
  lower_array(Type*);

  Expression*
  make_array(Type*, const std::vector<unsigned long>*, Expression_list*);

  Expression*
  lower_map(Gogo*, Named_object*, Statement_inserter*, Type*);

  // The type of the composite literal.
  Type* type_;
  // The depth within a list of composite literals within a composite
  // literal, when the type is omitted.
  int depth_;
  // The values to put in the composite literal.
  Expression_list* vals_;
  // If this is true, then VALS_ is a list of pairs: a key and a
  // value.  In an array initializer, a missing key will be NULL.
  bool has_keys_;
  // If this is true, then HAS_KEYS_ is true, and every key is a
  // simple identifier.
  bool all_are_names_;
  // A complement to DEPTH that indicates for each level starting from 0 to
  // DEPTH-1 whether or not this composite literal is nested inside of key or
  // a value.  This is used to decide which type to use when given a map literal
  // with omitted key types.
  std::vector<bool> key_path_;
};

// Helper/mixin class for struct and array construction expressions;
// encapsulates a list of values plus an optional traversal order
// recording the order in which the values should be visited.

class Ordered_value_list
{
 public:
  Ordered_value_list(Expression_list* vals)
      : vals_(vals), traverse_order_(NULL)
  { }

  Expression_list*
  vals() const
  { return this->vals_; }

  int
  traverse_vals(Traverse* traverse);

  // Get the traversal order (may be NULL)
  std::vector<unsigned long>*
  traverse_order()
  { return traverse_order_; }

  // Set the traversal order, used to ensure that we implement the
  // order of evaluation rules.  Takes ownership of the argument.
  void
  set_traverse_order(std::vector<unsigned long>* traverse_order)
  { this->traverse_order_ = traverse_order; }

 private:
  // The list of values, in order of the fields in the struct or in
  // order of indices in an array. A NULL value of vals_ means that
  // all fields/slots should be zero-initialized; a single NULL entry
  // in the list means that the corresponding field or array slot
  // should be zero-initialized.
  Expression_list* vals_;
  // If not NULL, the order in which to traverse vals_.  This is used
  // so that we implement the order of evaluation rules correctly.
  std::vector<unsigned long>* traverse_order_;
};

// Construct a struct.

class Struct_construction_expression : public Expression,
				       public Ordered_value_list
{
 public:
  Struct_construction_expression(Type* type, Expression_list* vals,
				 Location location)
      : Expression(EXPRESSION_STRUCT_CONSTRUCTION, location),
	Ordered_value_list(vals),
	type_(type)
  { }

 // Return whether this is a constant initializer.
  bool
  is_constant_struct() const;

 protected:
  int
  do_traverse(Traverse* traverse);

  bool
  do_is_static_initializer() const;

  Type*
  do_type()
  { return this->type_; }

  void
  do_determine_type(const Type_context*);

  void
  do_check_types(Gogo*);

  Expression*
  do_copy()
  {
    Struct_construction_expression* ret =
      new Struct_construction_expression(this->type_,
					 (this->vals() == NULL
					  ? NULL
					  : this->vals()->copy()),
					 this->location());
    if (this->traverse_order() != NULL)
      ret->set_traverse_order(this->traverse_order());
    return ret;
  }

  Expression*
  do_flatten(Gogo*, Named_object*, Statement_inserter*);

  Bexpression*
  do_get_backend(Translate_context*);

  void
  do_export(Export*) const;

  void
  do_dump_expression(Ast_dump_context*) const;

 private:
  // The type of the struct to construct.
  Type* type_;
};

// Construct an array.  This class is not used directly; instead we
// use the child classes, Fixed_array_construction_expression and
// Slice_construction_expression.

class Array_construction_expression : public Expression,
				      public Ordered_value_list
{
 protected:
  Array_construction_expression(Expression_classification classification,
				Type* type,
				const std::vector<unsigned long>* indexes,
				Expression_list* vals, Location location)
    : Expression(classification, location),
      Ordered_value_list(vals),
      type_(type), indexes_(indexes)
  { go_assert(indexes == NULL || indexes->size() == vals->size()); }

 public:
  // Return whether this is a constant initializer.
  bool
  is_constant_array() const;

  // Return the number of elements.
  size_t
  element_count() const
  { return this->vals() == NULL ? 0 : this->vals()->size(); }

protected:
  virtual int
  do_traverse(Traverse* traverse);

  bool
  do_is_static_initializer() const;

  Type*
  do_type()
  { return this->type_; }

  void
  do_determine_type(const Type_context*);

  void
  do_check_types(Gogo*);

  void
  do_export(Export*) const;

  // The indexes.
  const std::vector<unsigned long>*
  indexes()
  { return this->indexes_; }

  Expression*
  do_flatten(Gogo*, Named_object*, Statement_inserter*);

  // Get the backend constructor for the array values.
  Bexpression*
  get_constructor(Translate_context* context, Btype* btype);

  void
  do_dump_expression(Ast_dump_context*) const;

  virtual void
  dump_slice_storage_expression(Ast_dump_context*) const { }

 private:
  // The type of the array to construct.
  Type* type_;
  // The list of indexes into the array, one for each value.  This may
  // be NULL, in which case the indexes start at zero and increment.
  const std::vector<unsigned long>* indexes_;
};

// Construct a fixed array.

class Fixed_array_construction_expression :
  public Array_construction_expression
{
 public:
  Fixed_array_construction_expression(Type* type,
				      const std::vector<unsigned long>* indexes,
				      Expression_list* vals, Location location);

 protected:
  Expression*
  do_copy()
  {
    return new Fixed_array_construction_expression(this->type(),
						   this->indexes(),
						   (this->vals() == NULL
						    ? NULL
						    : this->vals()->copy()),
						   this->location());
  }

  Bexpression*
  do_get_backend(Translate_context*);
};

// Construct a slice.

class Slice_construction_expression : public Array_construction_expression
{
 public:
  Slice_construction_expression(Type* type,
				const std::vector<unsigned long>* indexes,
				Expression_list* vals, Location location);

  Expression*
  do_flatten(Gogo*, Named_object*, Statement_inserter*);

  // Record that the storage for this slice (e.g. vals) cannot escape,
  // hence it can be stack-allocated.
  void
  set_storage_does_not_escape()
  {
    this->storage_escapes_ = false;
  }

 protected:
  // Note that taking the address of a slice literal is invalid.

  int
  do_traverse(Traverse* traverse);

  Expression*
  do_copy()
  {
    return new Slice_construction_expression(this->type(), this->indexes(),
					     (this->vals() == NULL
					      ? NULL
					      : this->vals()->copy()),
					     this->location());
  }

  Bexpression*
  do_get_backend(Translate_context*);

  void
  dump_slice_storage_expression(Ast_dump_context* ast_dump_context) const;

  // Create an array value for the constructed slice. Invoked during
  // flattening if slice storage does not escape, otherwise invoked
  // later on during do_get_backend().
  Expression*
  create_array_val();

 private:
  // The type of the values in this slice.
  Type* valtype_;
  // Array value expression, optionally filled in during flattening.
  Expression* array_val_;
  // Slice storage expression, optionally filled in during flattening.
  Expression* slice_storage_;
  // Normally true. Can be set to false if we know that the resulting
  // storage for the slice cannot escape.
  bool storage_escapes_;
};

// Construct a map.

class Map_construction_expression : public Expression
{
 public:
  Map_construction_expression(Type* type, Expression_list* vals,
			      Location location)
    : Expression(EXPRESSION_MAP_CONSTRUCTION, location),
      type_(type), vals_(vals), element_type_(NULL), constructor_temp_(NULL)
  { go_assert(vals == NULL || vals->size() % 2 == 0); }

  Expression_list*
  vals() const
  { return this->vals_; }

 protected:
  int
  do_traverse(Traverse* traverse);

  Expression*
  do_flatten(Gogo*, Named_object*, Statement_inserter*);

  Type*
  do_type()
  { return this->type_; }

  void
  do_determine_type(const Type_context*);

  void
  do_check_types(Gogo*);

  Expression*
  do_copy()
  {
    return new Map_construction_expression(this->type_,
					   (this->vals_ == NULL
					    ? NULL
					    : this->vals_->copy()),
					   this->location());
  }

  Bexpression*
  do_get_backend(Translate_context*);

  void
  do_export(Export*) const;

  void
  do_dump_expression(Ast_dump_context*) const;
  
 private:
  // The type of the map to construct.
  Type* type_;
  // The list of values.
  Expression_list* vals_;
  // The type of the key-value pair struct for each map element.
  Struct_type* element_type_;
  // A temporary reference to the variable storing the constructor initializer.
  Temporary_statement* constructor_temp_;
};

// A type guard expression.

class Type_guard_expression : public Expression
{
 public:
  Type_guard_expression(Expression* expr, Type* type, Location location)
    : Expression(EXPRESSION_TYPE_GUARD, location),
      expr_(expr), type_(type)
  { }

  // Return the expression to convert.
  Expression*
  expr()
  { return this->expr_; }

  // Return the type to which to convert.
  Type*
  type()
  { return this->type_; }

 protected:
  int
  do_traverse(Traverse* traverse);

  Expression*
  do_flatten(Gogo*, Named_object*, Statement_inserter*);

  Type*
  do_type()
  { return this->type_; }

  void
  do_determine_type(const Type_context*)
  { this->expr_->determine_type_no_context(); }

  void
  do_check_types(Gogo*);

  Expression*
  do_copy()
  {
    return new Type_guard_expression(this->expr_->copy(), this->type_,
				     this->location());
  }

  Bexpression*
  do_get_backend(Translate_context*);

  void
  do_dump_expression(Ast_dump_context*) const;

 private:
  // The expression to convert.
  Expression* expr_;
  // The type to which to convert.
  Type* type_;
};

// Class Heap_expression.

// When you take the address of an escaping expression, it is allocated
// on the heap.  This class implements that.

class Heap_expression : public Expression
{
 public:
  Heap_expression(Expression* expr, Location location)
    : Expression(EXPRESSION_HEAP, location),
      expr_(expr)
  { }

  Expression*
  expr() const
  { return this->expr_; }

 protected:
  int
  do_traverse(Traverse* traverse)
  { return Expression::traverse(&this->expr_, traverse); }

  Type*
  do_type();
  void
  do_determine_type(const Type_context*)
  { this->expr_->determine_type_no_context(); }

  Expression*
  do_copy()
  {
    return Expression::make_heap_expression(this->expr_->copy(),
                                            this->location());
  }

  Bexpression*
  do_get_backend(Translate_context*);

  // We only export global objects, and the parser does not generate
  // this in global scope.
  void
  do_export(Export*) const
  { go_unreachable(); }

  void
  do_dump_expression(Ast_dump_context*) const;

 private:
  // The expression which is being put on the heap.
  Expression* expr_;
};

// A receive expression.

class Receive_expression : public Expression
{
 public:
  Receive_expression(Expression* channel, Location location)
    : Expression(EXPRESSION_RECEIVE, location),
      channel_(channel), temp_receiver_(NULL)
  { }

  // Return the channel.
  Expression*
  channel()
  { return this->channel_; }

 protected:
  int
  do_traverse(Traverse* traverse)
  { return Expression::traverse(&this->channel_, traverse); }

  bool
  do_discarding_value()
  { return true; }

  Type*
  do_type();

  Expression*
  do_flatten(Gogo*, Named_object*, Statement_inserter*);

  void
  do_determine_type(const Type_context*)
  { this->channel_->determine_type_no_context(); }

  void
  do_check_types(Gogo*);

  Expression*
  do_copy()
  {
    return Expression::make_receive(this->channel_->copy(), this->location());
  }

  bool
  do_must_eval_in_order() const
  { return true; }

  Bexpression*
  do_get_backend(Translate_context*);

  void
  do_dump_expression(Ast_dump_context*) const;

 private:
  // The channel from which we are receiving.
  Expression* channel_;
  // A temporary reference to the variable storing the received data.
  Temporary_statement* temp_receiver_;
};

// Conditional expressions.

class Conditional_expression : public Expression
{
 public:
  Conditional_expression(Expression* cond, Expression* then_expr,
                         Expression* else_expr, Location location)
      : Expression(EXPRESSION_CONDITIONAL, location),
        cond_(cond), then_(then_expr), else_(else_expr)
  {}

  Expression*
  condition() const
  { return this->cond_; }

 protected:
  int
  do_traverse(Traverse*);

  Type*
  do_type();

  void
  do_determine_type(const Type_context*);

  Expression*
  do_copy()
  {
    return new Conditional_expression(this->cond_->copy(), this->then_->copy(),
                                      this->else_->copy(), this->location());
  }

  Bexpression*
  do_get_backend(Translate_context* context);

  void
  do_dump_expression(Ast_dump_context*) const;

 private:
  // The condition to be checked.
  Expression* cond_;
  // The expression to execute if the condition is true.
  Expression* then_;
  // The expression to execute if the condition is false.
  Expression* else_;
};

// Compound expressions.

class Compound_expression : public Expression
{
 public:
  Compound_expression(Expression* init, Expression* expr, Location location)
      : Expression(EXPRESSION_COMPOUND, location), init_(init), expr_(expr)
  {}

  Expression*
  init() const
  { return this->init_; }

 protected:
  int
  do_traverse(Traverse*);

  Type*
  do_type();

  void
  do_determine_type(const Type_context*);

  Expression*
  do_copy()
  {
    return new Compound_expression(this->init_->copy(), this->expr_->copy(),
                                   this->location());
  }

  Bexpression*
  do_get_backend(Translate_context* context);

  void
  do_dump_expression(Ast_dump_context*) const;

 private:
  // The expression that is evaluated first and discarded.
  Expression* init_;
  // The expression that is evaluated and returned.
  Expression* expr_;
};

// A backend expression.  This is a backend expression wrapped in an
// Expression, for convenience during backend generation.

class Backend_expression : public Expression
{
 public:
  Backend_expression(Bexpression* bexpr, Type* type, Location location)
    : Expression(EXPRESSION_BACKEND, location), bexpr_(bexpr), type_(type)
  {}

 protected:
  int
  do_traverse(Traverse*);

  // For now these are always valid static initializers.  If that
  // changes we can change this.
  bool
  do_is_static_initializer() const
  { return true; }

  Type*
  do_type()
  { return this->type_; }

  void
  do_determine_type(const Type_context*)
  { }

  Expression*
  do_copy()
  {
    return new Backend_expression(this->bexpr_, this->type_, this->location());
  }

  Bexpression*
  do_get_backend(Translate_context*)
  { return this->bexpr_; }

  void
  do_dump_expression(Ast_dump_context*) const;

 private:
  // The backend expression we are wrapping.
  Bexpression* bexpr_;
  // The type of the expression;
  Type* type_;
};

// A numeric constant.  This is used both for untyped constants and
// for constants that have a type.

class Numeric_constant
{
 public:
  Numeric_constant()
    : classification_(NC_INVALID), type_(NULL)
  { }

  ~Numeric_constant();

  Numeric_constant(const Numeric_constant&);

  Numeric_constant& operator=(const Numeric_constant&);

  // Set to an unsigned long value.
  void
  set_unsigned_long(Type*, unsigned long);

  // Set to an integer value.
  void
  set_int(Type*, const mpz_t);

  // Set to a rune value.
  void
  set_rune(Type*, const mpz_t);

  // Set to a floating point value.
  void
  set_float(Type*, const mpfr_t);

  // Set to a complex value.
  void
  set_complex(Type*, const mpc_t);

  // Mark numeric constant as invalid.
  void
  set_invalid()
  { this->classification_ = NC_INVALID; }

  // Classifiers.
  bool
  is_int() const
  { return this->classification_ == Numeric_constant::NC_INT; }

  bool
  is_rune() const
  { return this->classification_ == Numeric_constant::NC_RUNE; }

  bool
  is_float() const
  { return this->classification_ == Numeric_constant::NC_FLOAT; }

  bool
  is_complex() const
  { return this->classification_ == Numeric_constant::NC_COMPLEX; }

  bool
  is_invalid() const
  { return this->classification_ == Numeric_constant::NC_INVALID; }

  // Value retrievers.  These will initialize the values as well as
  // set them.  GET_INT is only valid if IS_INT returns true, and
  // likewise respectively.
  void
  get_int(mpz_t*) const;

  void
  get_rune(mpz_t*) const;

  void
  get_float(mpfr_t*) const;

  void
  get_complex(mpc_t*) const;

  // Codes returned by to_unsigned_long.
  enum To_unsigned_long
  {
    // Value is integer and fits in unsigned long.
    NC_UL_VALID,
    // Value is not integer.
    NC_UL_NOTINT,
    // Value is integer but is negative.
    NC_UL_NEGATIVE,
    // Value is non-negative integer but does not fit in unsigned
    // long.
    NC_UL_BIG
  };

  // If the value can be expressed as an integer that fits in an
  // unsigned long, set *VAL and return NC_UL_VALID.  Otherwise return
  // one of the other To_unsigned_long codes.
  To_unsigned_long
  to_unsigned_long(unsigned long* val) const;

  // If the value can be expressed as an int, return true and
  // initialize and set VAL.  This will return false for a value with
  // an explicit float or complex type, even if the value is integral.
  bool
  to_int(mpz_t* val) const;

  // If the value can be expressed as a float, return true and
  // initialize and set VAL.
  bool
  to_float(mpfr_t* val) const;

  // If the value can be expressed as a complex, return true and
  // initialize and set VR and VI.
  bool
  to_complex(mpc_t* val) const;

  // Get the type.
  Type*
  type() const;

  // If the constant can be expressed in TYPE, then set the type of
  // the constant to TYPE and return true.  Otherwise return false,
  // and, if ISSUE_ERROR is true, issue an error message.  LOCATION is
  // the location to use for the error.
  bool
  set_type(Type* type, bool issue_error, Location location);

  // Return an Expression for this value.
  Expression*
  expression(Location) const;

 private:
  void
  clear();

  To_unsigned_long
  mpz_to_unsigned_long(const mpz_t ival, unsigned long *val) const;

  To_unsigned_long
  mpfr_to_unsigned_long(const mpfr_t fval, unsigned long *val) const;

  bool
  check_int_type(Integer_type*, bool, Location);

  bool
  check_float_type(Float_type*, bool, Location);

  bool
  check_complex_type(Complex_type*, bool, Location);

  // The kinds of constants.
  enum Classification
  {
    NC_INVALID,
    NC_RUNE,
    NC_INT,
    NC_FLOAT,
    NC_COMPLEX
  };

  // The kind of constant.
  Classification classification_;
  // The value.
  union
  {
    // If NC_INT or NC_RUNE.
    mpz_t int_val;
    // If NC_FLOAT.
    mpfr_t float_val;
    // If NC_COMPLEX.
    mpc_t complex_val;
  } u_;
  // The type if there is one.  This will be NULL for an untyped
  // constant.
  Type* type_;
};

#endif // !defined(GO_EXPRESSIONS_H)
