Re-added support for reference arguments.
authorDavid Anderson <dvander@alliedmods.net>
Thu Dec 20 00:59:38 2012 -0800 (2012-12-20)
changeset 2220cde1379b29f
parent 221 0c588a96837c
child 223 38e6d2e0e702
Re-added support for reference arguments.
src/API.cpp
src/Messages.tbl
src/ObjectVisitor.h
src/Objects.h
src/TypeManager.cpp
src/Types.cpp
src/Types.h
src/Zone.cpp
src/compiler/BytecodeEmitter.cpp
src/compiler/BytecodeEmitter.h
src/compiler/HIR.cpp
src/compiler/HIR.h
src/compiler/NameBinding.cpp
src/compiler/SemanticAnalysis.cpp
tests/basic/ref-arg.out
tests/basic/ref-arg.sp
tests/prototype/ref-arg.sp
     1.1 --- a/src/API.cpp	Mon Nov 19 02:12:13 2012 -0800
     1.2 +++ b/src/API.cpp	Thu Dec 20 00:59:38 2012 -0800
     1.3 @@ -289,11 +289,13 @@
     1.4        case Ke::Parameter::Float:
     1.5          return type->isFloat();
     1.6        case Ke::Parameter::FloatRef:
     1.7 -        return type->isReference() && type->contained_ref()->isFloat();
     1.8 +        return type->isReference() && ReferenceType::cast(type)->contained()->isFloat();
     1.9        case Ke::Parameter::Int:
    1.10          return type->isInt32() || type->isEnum();
    1.11        case Ke::Parameter::IntRef:
    1.12 -       return type->isReference() && (type->contained_ref()->isInt32() || type->contained_ref()->isEnum());
    1.13 +       return type->isReference() &&
    1.14 +              (ReferenceType::cast(type)->contained()->isInt32() ||
    1.15 +               ReferenceType::cast(type)->contained()->isEnum());
    1.16        default:
    1.17          return false;
    1.18      }
     2.1 --- a/src/Messages.tbl	Mon Nov 19 02:12:13 2012 -0800
     2.2 +++ b/src/Messages.tbl	Thu Dec 20 00:59:38 2012 -0800
     2.3 @@ -41,8 +41,7 @@
     2.4  MSG(ExpectedGlobal,                 SyntaxError,            "expected global variable or function")
     2.5  MSG(ForwardNotImplemented,          SyntaxError,            "forward '%s' not implemented")
     2.6  MSG(ForwardDeclareMismatches,       SyntaxError,            "declaration does not match original forward signature")
     2.7 -MSG(ArrayCantBeReference,           SyntaxError,            "redundant reference qualifier on array parameter")
     2.8 -MSG(StructCantBeReference,          SyntaxError,            "redundant reference qualifier on struct parameter")
     2.9 +MSG(ArrayCantBeReference,           SyntaxError,            "this type cannot be used with a reference")
    2.10  MSG(ArraySizeMustBeConstant,        SyntaxError,            "array size must be a constant integer")
    2.11  MSG(ReferenceIsConstant,            SyntaxError,            "cannot assign to a constant lvalue")
    2.12  MSG(MultiArrayInNative,             SyntaxError,            "multidimensional arrays cannot be passed to natives")
     3.1 --- a/src/ObjectVisitor.h	Mon Nov 19 02:12:13 2012 -0800
     3.2 +++ b/src/ObjectVisitor.h	Thu Dec 20 00:59:38 2012 -0800
     3.3 @@ -50,6 +50,12 @@
     3.4          return sizeof(Type);
     3.5      }
     3.6  
     3.7 +    size_t iterateReferenceType(Object *obj) {
     3.8 +        iterateType(obj);
     3.9 +        visitField(obj, ReferenceType::offsetOfContained());
    3.10 +        return sizeof(ReferenceType);
    3.11 +    }
    3.12 +
    3.13      size_t iterateArrayType(Object *obj) {
    3.14          iterateType(obj);
    3.15          visitField(obj, ArrayType::offsetOfContained());
    3.16 @@ -195,6 +201,9 @@
    3.17            case MapKind_Type:
    3.18              return iterateType(obj);
    3.19  
    3.20 +          case MapKind_ReferenceType:
    3.21 +            return iterateReferenceType(obj);
    3.22 +
    3.23            case MapKind_ArrayType:
    3.24              return iterateArrayType(obj);
    3.25  
    3.26 @@ -278,6 +287,9 @@
    3.27        case MapKind_Type:
    3.28          return sizeof(Type);
    3.29  
    3.30 +      case MapKind_ReferenceType:
    3.31 +        return sizeof(ReferenceType);
    3.32 +
    3.33        case MapKind_ArrayType:
    3.34          return sizeof(ArrayType);
    3.35  
     4.1 --- a/src/Objects.h	Mon Nov 19 02:12:13 2012 -0800
     4.2 +++ b/src/Objects.h	Thu Dec 20 00:59:38 2012 -0800
     4.3 @@ -38,6 +38,7 @@
     4.4      MapKind_FunctionType,
     4.5      MapKind_StructType,
     4.6      MapKind_ArrayType,
     4.7 +    MapKind_ReferenceType,
     4.8  
     4.9      // Represents basic data structures. When adding to this, don't forget
    4.10      // to update Zone::initialize(), or you'll get a NULL crash trying to
     5.1 --- a/src/TypeManager.cpp	Mon Nov 19 02:12:13 2012 -0800
     5.2 +++ b/src/TypeManager.cpp	Thu Dec 20 00:59:38 2012 -0800
     5.3 @@ -57,7 +57,7 @@
     5.4      Local<Type> type(zone_);
     5.5      for (unsigned i = 0; i < PrimitiveTypes_Total; i++) {
     5.6          type = primitiveTypes_[i];
     5.7 -        if ((referenceTypes_[i] = Type::NewReference(zone_, type, false)) == NULL)
     5.8 +        if ((referenceTypes_[i] = ReferenceType::New(zone_, type)) == NULL)
     5.9              return false;
    5.10      }
    5.11  
    5.12 @@ -84,7 +84,7 @@
    5.13          return referenceTypes_[type->primitive()];
    5.14  
    5.15      // :TODO: cache this.
    5.16 -    return Type::NewReference(zone_, type, isConst);
    5.17 +    return ReferenceType::New(zone_, type);
    5.18  }
    5.19  
    5.20  Type *
     6.1 --- a/src/Types.cpp	Mon Nov 19 02:12:13 2012 -0800
     6.2 +++ b/src/Types.cpp	Thu Dec 20 00:59:38 2012 -0800
     6.3 @@ -102,16 +102,17 @@
     6.4      return type;
     6.5  }
     6.6  
     6.7 -Type *
     6.8 -Type::NewReference(Zone *zone, Handle<Type> contained, bool isConst)
     6.9 +ReferenceType *
    6.10 +ReferenceType::New(Zone *zone, Handle<Type> contained)
    6.11  {
    6.12 -    Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
    6.13 +    Local<ReferenceType> type(zone, ReferenceType::cast(zone->allocate(MapKind_ReferenceType, sizeof(ReferenceType), Heap::Tenure_Old)));
    6.14      if (!type)
    6.15          return NULL;
    6.16  
    6.17      type->kind_ = REFERENCE;
    6.18      type->name_ = NULL;
    6.19 -    type->const_ = isConst;
    6.20 +    type->const_ = false;
    6.21 +    type->contained_ = contained;
    6.22      return type;
    6.23  }
    6.24  
    6.25 @@ -204,7 +205,7 @@
    6.26  
    6.27        default:
    6.28          assert(left->kind() == Type::REFERENCE);
    6.29 -        return Compare(left->contained_ref(), right->contained_ref());
    6.30 +        return Compare(ReferenceType::cast(left)->contained(), ReferenceType::cast(right)->contained());
    6.31      }
    6.32  }
    6.33  
    6.34 @@ -286,7 +287,7 @@
    6.35      if (type->isEnum() || type->isStruct())
    6.36          return type->name()->chars();
    6.37      if (type->isReference())
    6.38 -        type = type->contained_ref();
    6.39 +        type = ReferenceType::cast(type)->contained();
    6.40      switch (type->primitive()) {
    6.41        case PrimitiveType_Bool:
    6.42          return "bool";
     7.1 --- a/src/Types.h	Mon Nov 19 02:12:13 2012 -0800
     7.2 +++ b/src/Types.h	Thu Dec 20 00:59:38 2012 -0800
     7.3 @@ -104,7 +104,6 @@
     7.4      static Type *NewVoid(Zone *zone);
     7.5      static Type *NewUnchecked(Zone *zone);
     7.6      static Type *NewPrimitive(Zone *zone, PrimitiveType type);
     7.7 -    static Type *NewReference(Zone *zone, Handle<Type> contained, bool isConst);
     7.8      static Type *NewEnum(Zone *zone, Handle<String> name);
     7.9  
    7.10      static bool Compare(Type *left, Type *right);
    7.11 @@ -114,7 +113,8 @@
    7.12                 obj->is(MapKind_Type) ||
    7.13                 obj->is(MapKind_FunctionType) ||
    7.14                 obj->is(MapKind_StructType) ||
    7.15 -               obj->is(MapKind_ArrayType));
    7.16 +               obj->is(MapKind_ArrayType) ||
    7.17 +               obj->is(MapKind_ReferenceType));
    7.18          return (Type *)obj;
    7.19      }
    7.20  
    7.21 @@ -189,10 +189,6 @@
    7.22          assert(isEnum() || isStruct());
    7.23          return name_;
    7.24      }
    7.25 -    Type *contained_ref() {
    7.26 -        assert(false);
    7.27 -        return NULL;
    7.28 -    }
    7.29  
    7.30      // GC Descriptor.
    7.31      static inline size_t offsetOfName() {
    7.32 @@ -211,6 +207,30 @@
    7.33      Barriered<String> name_;
    7.34  };
    7.35  
    7.36 +class ReferenceType : public Type
    7.37 +{
    7.38 +  public:
    7.39 +    static ReferenceType *New(Zone *zone, Handle<Type> contained);
    7.40 +    
    7.41 +    Type *contained() {
    7.42 +        return contained_;
    7.43 +    }
    7.44 +
    7.45 +    // GC Descriptor.
    7.46 +    static inline size_t offsetOfContained() {
    7.47 +        return OFFSETOF(ReferenceType, contained_);
    7.48 +    }
    7.49 +    // End GC Descriptor.
    7.50 +
    7.51 +    static ReferenceType *cast(Object *obj) {
    7.52 +        assert(!obj || obj->is(MapKind_ReferenceType));
    7.53 +        return (ReferenceType *)obj;
    7.54 +    }
    7.55 +
    7.56 +  private:
    7.57 +    Barriered<Type> contained_;
    7.58 +};
    7.59 +
    7.60  class ArrayType : public Type
    7.61  {
    7.62    public:
     8.1 --- a/src/Zone.cpp	Mon Nov 19 02:12:13 2012 -0800
     8.2 +++ b/src/Zone.cpp	Thu Dec 20 00:59:38 2012 -0800
     8.3 @@ -80,6 +80,7 @@
     8.4          MapKind_ArrayType,
     8.5          MapKind_FunctionType,
     8.6          MapKind_StructType,
     8.7 +        MapKind_ReferenceType,
     8.8          MapKind_FixedArray,
     8.9          MapKind_ByteArray,
    8.10          MapKind_Code,
     9.1 --- a/src/compiler/BytecodeEmitter.cpp	Mon Nov 19 02:12:13 2012 -0800
     9.2 +++ b/src/compiler/BytecodeEmitter.cpp	Thu Dec 20 00:59:38 2012 -0800
     9.3 @@ -282,6 +282,22 @@
     9.4      return true;
     9.5  }
     9.6  
     9.7 +void
     9.8 +BytecodeEmitter::newref(VariableSymbol *var)
     9.9 +{
    9.10 +    recordOops();
    9.11 +    if (var->storage() == VariableSymbol::Local) {
    9.12 +        ensure(OP_VARREF_LIFO_LENGTH);
    9.13 +        writeOp(OP_VARREF_LIFO);
    9.14 +    } else {
    9.15 +        assert(var->storage() == VariableSymbol::Arg);
    9.16 +        ensure(OP_ARGREF_LIFO_LENGTH);
    9.17 +        writeOp(OP_ARGREF_LIFO);
    9.18 +    }
    9.19 +    writeUint32(var->slot());
    9.20 +    markOop(1);
    9.21 +}
    9.22 +
    9.23  Code *
    9.24  BytecodeEmitter::finish()
    9.25  {
    10.1 --- a/src/compiler/BytecodeEmitter.h	Mon Nov 19 02:12:13 2012 -0800
    10.2 +++ b/src/compiler/BytecodeEmitter.h	Thu Dec 20 00:59:38 2012 -0800
    10.3 @@ -513,21 +513,8 @@
    10.4          writeOp(OP_UNWINDLIFO);
    10.5          writeUint32(slot);
    10.6      }
    10.7 -#if 0
    10.8 -    void newref(Variable *var) {
    10.9 -        recordOops();
   10.10 -        if (var->location() == Variable::STACK) {
   10.11 -            ensure(OP_VARREF_LIFO_LENGTH);
   10.12 -            writeOp(OP_VARREF_LIFO);
   10.13 -        } else {
   10.14 -            assert(var->location() == Variable::PARAMETER);
   10.15 -            ensure(OP_ARGREF_LIFO_LENGTH);
   10.16 -            writeOp(OP_ARGREF_LIFO);
   10.17 -        }
   10.18 -        writeUint32(var->slot());
   10.19 -        markOop(1);
   10.20 -    }
   10.21 -#endif
   10.22 +
   10.23 +    void newref(VariableSymbol *var);
   10.24  
   10.25      void slotref_lifo() {
   10.26          recordOops();
    11.1 --- a/src/compiler/HIR.cpp	Mon Nov 19 02:12:13 2012 -0800
    11.2 +++ b/src/compiler/HIR.cpp	Thu Dec 20 00:59:38 2012 -0800
    11.3 @@ -47,6 +47,7 @@
    11.4      void visitConvert(HConvert *convert);
    11.5      void visitIndex(HIndex *index);
    11.6      void visitPostIncDec(HPostIncDec *hir);
    11.7 +    void visitToRef(HToRef *hir);
    11.8  
    11.9    private:
   11.10      Zone *zone_;
   11.11 @@ -114,6 +115,26 @@
   11.12      __ getglobal(sym_);
   11.13  }
   11.14  
   11.15 +bool
   11.16 +HGlobal::ref(BytecodeEmitter &emitter_)
   11.17 +{
   11.18 +    return false;
   11.19 +}
   11.20 +
   11.21 +static inline Type *
   11.22 +MaybeDereference(Type *type)
   11.23 +{
   11.24 +    if (type->isReference())
   11.25 +        return ReferenceType::cast(type)->contained();
   11.26 +    return type;
   11.27 +}
   11.28 +
   11.29 +HLocal::HLocal(AstNode *node, VariableSymbol *sym)
   11.30 +  : HLValue(node, MaybeDereference(sym->type())),
   11.31 +    sym_(sym)
   11.32 +{
   11.33 +}
   11.34 +
   11.35  void
   11.36  HLocal::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
   11.37  {
   11.38 @@ -149,7 +170,7 @@
   11.39  HLocal::store(BytecodeEmitter &emitter_)
   11.40  {
   11.41      if (sym_->type()->isReference()) {
   11.42 -        __ setref(sym_->type()->contained_ref());
   11.43 +        __ setref(ReferenceType::cast(sym_->type())->contained());
   11.44      } else {
   11.45          if (sym_->storage() == VariableSymbol::Local)
   11.46              __ setlocal(sym_);
   11.47 @@ -164,7 +185,7 @@
   11.48  HLocal::load(BytecodeEmitter &emitter_)
   11.49  {
   11.50      if (sym_->type()->isReference())
   11.51 -        __ getref(sym_->type());
   11.52 +        __ getref(ReferenceType::cast(sym_->type())->contained());
   11.53      else if (sym_->storage() == VariableSymbol::Local)
   11.54          __ getlocal(sym_);
   11.55      else if (sym_->storage() == VariableSymbol::Arg)
   11.56 @@ -173,6 +194,33 @@
   11.57          assert(false);
   11.58  }
   11.59  
   11.60 +bool
   11.61 +HLocal::ref(BytecodeEmitter &emitter_)
   11.62 +{
   11.63 +    if (sym_->storage() == VariableSymbol::Heap) {
   11.64 +        // Closing over a reference should never pass SemA.
   11.65 +        assert(!sym_->type()->isReference());
   11.66 +
   11.67 +        // We don't support direct references to heap-allocated locals. This
   11.68 +        // should probably be banned in SemA? But for now, just assert. :TODO:
   11.69 +        assert(false);
   11.70 +        return false;
   11.71 +    }
   11.72 +        
   11.73 +    if (sym_->type()->isReference()) {
   11.74 +        if (sym_->storage() == VariableSymbol::Local)
   11.75 +            __ getlocal(sym_);
   11.76 +        else if (sym_->storage() == VariableSymbol::Arg)
   11.77 +            __ getarg(sym_);
   11.78 +        else
   11.79 +            assert(false);
   11.80 +    } else {
   11.81 +        __ newref(sym_);
   11.82 +    }
   11.83 +
   11.84 +    return true;
   11.85 +}
   11.86 +
   11.87  void
   11.88  HIndex::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
   11.89  {
   11.90 @@ -208,6 +256,12 @@
   11.91      __ getelem(type());
   11.92  }
   11.93  
   11.94 +bool
   11.95 +HIndex::ref(BytecodeEmitter &emitter_)
   11.96 +{
   11.97 +    return false;
   11.98 +}
   11.99 +
  11.100  void
  11.101  HIRTranslator::visitLocal(HLocal *local)
  11.102  {
  11.103 @@ -350,6 +404,20 @@
  11.104  }
  11.105  
  11.106  void
  11.107 +HIRTranslator::visitToRef(HToRef *hir)
  11.108 +{
  11.109 +    HIR *in = hir->in();
  11.110 +
  11.111 +    // See if we can bind a direct reference.
  11.112 +    if (in->isLValue() && in->toLValue()->ref(emitter_))
  11.113 +        return;
  11.114 +
  11.115 +    // No, we can't. So instead we create an on-stack reference.
  11.116 +    in->accept(this);
  11.117 +    __ slotref_lifo();
  11.118 +}
  11.119 +
  11.120 +void
  11.121  ke::EmitHIR(Zone *zone, BytecodeEmitter &emitter, HIR *hir)
  11.122  {
  11.123      HIRTranslator translator(zone, emitter);
    12.1 --- a/src/compiler/HIR.h	Mon Nov 19 02:12:13 2012 -0800
    12.2 +++ b/src/compiler/HIR.h	Thu Dec 20 00:59:38 2012 -0800
    12.3 @@ -30,6 +30,7 @@
    12.4      _(Integer)                          \
    12.5      _(Float)                            \
    12.6      _(Store)                            \
    12.7 +    _(ToRef)                            \
    12.8      /* Special LValue types */          \
    12.9      _(Index)                            \
   12.10      _(Local)                            \
   12.11 @@ -46,6 +47,7 @@
   12.12  
   12.13  class HIRVisitor;
   12.14  class AstNode;
   12.15 +class HLValue;
   12.16  
   12.17  class HIR : public PoolObject
   12.18  {
   12.19 @@ -78,6 +80,22 @@
   12.20      virtual HOp op() const = 0;
   12.21      virtual void accept(HIRVisitor *visitor) = 0;
   12.22  
   12.23 +#define _(name)                                         \
   12.24 +    bool is##name() const {                             \
   12.25 +        return op() == k##name;                         \
   12.26 +    }                                                   \
   12.27 +    H##name *to##name() {                               \
   12.28 +        assert(is##name());                             \
   12.29 +        return reinterpret_cast<H##name *>(this);       \
   12.30 +    }
   12.31 +    HIR_OPS(_)
   12.32 +#undef _
   12.33 +
   12.34 +    HLValue *toLValue() {
   12.35 +        assert(isLValue());
   12.36 +        return reinterpret_cast<HLValue *>(this);
   12.37 +    }
   12.38 +
   12.39    private:
   12.40      AstNode *node_;
   12.41      ScopedRoot<Type> type_;
   12.42 @@ -173,6 +191,10 @@
   12.43      virtual void store(BytecodeEmitter &emitter_) = 0;
   12.44      virtual void load(BytecodeEmitter &emitter_) = 0;
   12.45  
   12.46 +    // Try to make a direct reference, if semantics allow it. False if the
   12.47 +    // caller must allocate a reference to the stack.
   12.48 +    virtual bool ref(BytecodeEmitter &emitter_) = 0;
   12.49 +
   12.50      bool isLValue() const {
   12.51          return true;
   12.52      }
   12.53 @@ -181,11 +203,7 @@
   12.54  class HLocal : public HLValue
   12.55  {
   12.56    public:
   12.57 -    HLocal(AstNode *node, VariableSymbol *sym)
   12.58 -      : HLValue(node, sym->type()),
   12.59 -        sym_(sym)
   12.60 -    {
   12.61 -    }
   12.62 +    HLocal(AstNode *node, VariableSymbol *sym);
   12.63  
   12.64      DEFINE_HIR(Local);
   12.65  
   12.66 @@ -195,6 +213,11 @@
   12.67      void swapAndPick(BytecodeEmitter &emitter_);
   12.68      void store(BytecodeEmitter &emitter_);
   12.69      void load(BytecodeEmitter &emitter_);
   12.70 +    bool ref(BytecodeEmitter &emitter_);
   12.71 +
   12.72 +    VariableSymbol *sym() const {
   12.73 +        return sym_;
   12.74 +    }
   12.75  
   12.76    private:
   12.77      VariableSymbol *sym_;
   12.78 @@ -217,6 +240,7 @@
   12.79      void swapAndPick(BytecodeEmitter &emitter_);
   12.80      void store(BytecodeEmitter &emitter_);
   12.81      void load(BytecodeEmitter &emitter_);
   12.82 +    bool ref(BytecodeEmitter &emitter_);
   12.83  
   12.84    private:
   12.85      HIR *left_;
   12.86 @@ -239,6 +263,7 @@
   12.87      void swapAndPick(BytecodeEmitter &emitter_);
   12.88      void store(BytecodeEmitter &emitter_);
   12.89      void load(BytecodeEmitter &emitter_);
   12.90 +    bool ref(BytecodeEmitter &emitter_);
   12.91  
   12.92      Symbol *sym() const {
   12.93          return sym_;
   12.94 @@ -384,6 +409,25 @@
   12.95      HIRList *args_;
   12.96  };
   12.97  
   12.98 +class HToRef : public HIR
   12.99 +{
  12.100 +  public:
  12.101 +    HToRef(AstNode *node, Type *type, HIR *in)
  12.102 +      : HIR(node, type),
  12.103 +        in_(in)
  12.104 +    {
  12.105 +    }
  12.106 +
  12.107 +    DEFINE_HIR(ToRef);
  12.108 +
  12.109 +    HIR *in() const {
  12.110 +        return in_;
  12.111 +    }
  12.112 +
  12.113 +  private:
  12.114 +    HIR *in_;
  12.115 +};
  12.116 +
  12.117  #undef DEFINE_HIR
  12.118  
  12.119  void EmitHIR(Zone *zone, BytecodeEmitter &emitter, HIR *hir);
    13.1 --- a/src/compiler/NameBinding.cpp	Mon Nov 19 02:12:13 2012 -0800
    13.2 +++ b/src/compiler/NameBinding.cpp	Thu Dec 20 00:59:38 2012 -0800
    13.3 @@ -818,6 +818,15 @@
    13.4                  }
    13.5              }
    13.6  
    13.7 +			if (param->reference()) {
    13.8 +				if (!type->isPod()) {
    13.9 +					cc_.reportError(param->pos(), Message_ArrayCantBeReference);
   13.10 +					return false;
   13.11 +				}
   13.12 +				if ((type = zone_->types()->getReference(type, false)) == NULL)
   13.13 +					return false;
   13.14 +			}
   13.15 +
   13.16              params->set(zone_, i, type);
   13.17              param->sym()->setType(type);
   13.18          }
    14.1 --- a/src/compiler/SemanticAnalysis.cpp	Mon Nov 19 02:12:13 2012 -0800
    14.2 +++ b/src/compiler/SemanticAnalysis.cpp	Thu Dec 20 00:59:38 2012 -0800
    14.3 @@ -516,16 +516,23 @@
    14.4                  }
    14.5              }
    14.6  
    14.7 -            // When we start overloading, coercion will have to happen later.
    14.8 -            arg = coerce(arg, actual, Coerce_Arg);
    14.9 -            if (!arg)
   14.10 -                return;
   14.11 +            if (actual->isReference()) {
   14.12 +                // If the actual is a reference, the coercion rules are much
   14.13 +                // stricter; the contained types must be identical.
   14.14 +                // :TODO: make this not an assert
   14.15 +                assert(ReferenceType::cast(actual)->contained() == arg->type());
   14.16 +            } else {
   14.17 +                // When we start overloading, coercion will have to happen later.
   14.18 +                arg = coerce(arg, actual, Coerce_Arg);
   14.19 +                if (!arg)
   14.20 +                    return;
   14.21 +            }
   14.22  
   14.23              mustComputeReference = actual->isReference() && !given->isReference();
   14.24          }
   14.25  
   14.26 -        // :TODO: handle mustComputeReference
   14.27 -        assert(!mustComputeReference);
   14.28 +        if (mustComputeReference)
   14.29 +            arg = new (pool_) HToRef(arg->node(), arg->type(), arg);
   14.30  
   14.31          if (!args->append(arg))
   14.32              return;
   14.33 @@ -640,6 +647,7 @@
   14.34              return l;
   14.35      }
   14.36  
   14.37 +    // :TODO: remove
   14.38      assert(l == r);
   14.39  
   14.40      return left->type();
   14.41 @@ -741,8 +749,6 @@
   14.42              return NULL;
   14.43          return hir;
   14.44      }
   14.45 -
   14.46 -    assert(from == to);
   14.47      
   14.48      return hir;
   14.49  }
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/tests/basic/ref-arg.out	Thu Dec 20 00:59:38 2012 -0800
    15.3 @@ -0,0 +1,1 @@
    15.4 +122
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/tests/basic/ref-arg.sp	Thu Dec 20 00:59:38 2012 -0800
    16.3 @@ -0,0 +1,20 @@
    16.4 +native PrintNum(b);
    16.5 +
    16.6 +f(&a)
    16.7 +{
    16.8 +    for (new i = 0; i < 10; i = i + 1)
    16.9 +        a = a + i;
   16.10 +    return 0;
   16.11 +}
   16.12 +
   16.13 +g(&b)
   16.14 +{
   16.15 +    return f(b);
   16.16 +}
   16.17 +
   16.18 +public main()
   16.19 +{
   16.20 +    new b = 77;
   16.21 +    g(b);
   16.22 +    PrintNum(b);
   16.23 +}
    17.1 --- a/tests/prototype/ref-arg.sp	Mon Nov 19 02:12:13 2012 -0800
    17.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.3 @@ -1,18 +0,0 @@
    17.4 -f(&a)
    17.5 -{
    17.6 -    for (new i = 0; i < 10; i = i + 1)
    17.7 -        a = a + i;
    17.8 -    return 0;
    17.9 -}
   17.10 -
   17.11 -g(&b)
   17.12 -{
   17.13 -    return f(b);
   17.14 -}
   17.15 -
   17.16 -main()
   17.17 -{
   17.18 -    new b = 77;
   17.19 -    g(b);
   17.20 -    return b;
   17.21 -}