summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xcompiler/ccgexprs.nim198
-rwxr-xr-xcompiler/ccgtypes.nim2
-rwxr-xr-xcompiler/semexprs.nim1
-rw-r--r--tests/run/tobjconstr.nim41
-rwxr-xr-xtodo.txt2
5 files changed, 160 insertions, 84 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index b20af0cfc..fd70834c2 100755
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -680,14 +680,40 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
     putIntoDest(p, d, field.typ, r)
 
 proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc)
+
+proc genFieldCheck(p: BProc, e: PNode, obj: PRope, field: PSym) =
+  var test, u, v: TLoc
+  for i in countup(1, sonsLen(e) - 1):
+    var it = e.sons[i]
+    assert(it.kind in nkCallKinds)
+    assert(it.sons[0].kind == nkSym)
+    let op = it.sons[0].sym
+    if op.magic == mNot: it = it.sons[1]
+    assert(it.sons[2].kind == nkSym)
+    initLoc(test, locNone, it.typ, OnStack)
+    InitLocExpr(p, it.sons[1], u)
+    initLoc(v, locExpr, it.sons[2].typ, OnUnknown)
+    v.r = ropef("$1.$2", [obj, it.sons[2].sym.loc.r])
+    genInExprAux(p, it, u, v, test)
+    let id = NodeTableTestOrSet(p.module.dataCache,
+                               newStrNode(nkStrLit, field.name.s), gBackendId)
+    let strLit = if id == gBackendId: getStrLit(p.module, field.name.s)
+                 else: con("TMP", toRope(id))
+    if op.magic == mNot:
+      linefmt(p, cpsStmts,
+              "if ($1) #raiseFieldError(((#NimStringDesc*) &$2));$n",
+              rdLoc(test), strLit)
+    else:
+      linefmt(p, cpsStmts,
+              "if (!($1)) #raiseFieldError(((#NimStringDesc*) &$2));$n",
+              rdLoc(test), strLit)
+
 proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
   var
-    a, u, v, test: TLoc
-    f, field, op: PSym
+    a: TLoc
+    f, field: PSym
     ty: PType
-    r, strLit: PRope
-    id: int
-    it: PNode
+    r: PRope
   if optFieldCheck in p.options:
     ty = genRecordFieldAux(p, e.sons[0], d, a)
     r = rdLoc(a)
@@ -702,69 +728,37 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
     if field == nil: InternalError(e.info, "genCheckedRecordField")
     if field.loc.r == nil:
       InternalError(e.info, "genCheckedRecordField") # generate the checks:
-    for i in countup(1, sonsLen(e) - 1):
-      it = e.sons[i]
-      assert(it.kind in nkCallKinds)
-      assert(it.sons[0].kind == nkSym)
-      op = it.sons[0].sym
-      if op.magic == mNot: it = it.sons[1]
-      assert(it.sons[2].kind == nkSym)
-      initLoc(test, locNone, it.typ, OnStack)
-      InitLocExpr(p, it.sons[1], u)
-      initLoc(v, locExpr, it.sons[2].typ, OnUnknown)
-      v.r = ropef("$1.$2", [r, it.sons[2].sym.loc.r])
-      genInExprAux(p, it, u, v, test)
-      id = NodeTableTestOrSet(p.module.dataCache,
-                              newStrNode(nkStrLit, field.name.s), gBackendId)
-      if id == gBackendId: strLit = getStrLit(p.module, field.name.s)
-      else: strLit = con("TMP", toRope(id))
-      if op.magic == mNot:
-        linefmt(p, cpsStmts,
-                "if ($1) #raiseFieldError(((#NimStringDesc*) &$2));$n",
-                rdLoc(test), strLit)
-      else:
-        linefmt(p, cpsStmts,
-                "if (!($1)) #raiseFieldError(((#NimStringDesc*) &$2));$n",
-                rdLoc(test), strLit)
+    genFieldCheck(p, e, r, field)
+    when false:
+      for i in countup(1, sonsLen(e) - 1):
+        it = e.sons[i]
+        assert(it.kind in nkCallKinds)
+        assert(it.sons[0].kind == nkSym)
+        op = it.sons[0].sym
+        if op.magic == mNot: it = it.sons[1]
+        assert(it.sons[2].kind == nkSym)
+        initLoc(test, locNone, it.typ, OnStack)
+        InitLocExpr(p, it.sons[1], u)
+        initLoc(v, locExpr, it.sons[2].typ, OnUnknown)
+        v.r = ropef("$1.$2", [r, it.sons[2].sym.loc.r])
+        genInExprAux(p, it, u, v, test)
+        id = NodeTableTestOrSet(p.module.dataCache,
+                                newStrNode(nkStrLit, field.name.s), gBackendId)
+        if id == gBackendId: strLit = getStrLit(p.module, field.name.s)
+        else: strLit = con("TMP", toRope(id))
+        if op.magic == mNot:
+          linefmt(p, cpsStmts,
+                  "if ($1) #raiseFieldError(((#NimStringDesc*) &$2));$n",
+                  rdLoc(test), strLit)
+        else:
+          linefmt(p, cpsStmts,
+                  "if (!($1)) #raiseFieldError(((#NimStringDesc*) &$2));$n",
+                  rdLoc(test), strLit)
     app(r, rfmt(nil, ".$1", field.loc.r))
     putIntoDest(p, d, field.typ, r)
   else:
     genRecordField(p, e.sons[0], d)
 
-proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
-  var tmp: TLoc
-  var t = e.typ.skipTypes(abstractInst)
-  getTemp(p, t, tmp)
-  let isRef = t.kind == tyRef
-  var r = rdLoc(tmp)
-  if isRef:
-    t = t.sons[0].skipTypes(abstractInst)
-    r = ropef("(*$1)", r)
-    # XXX generate 'new' call here
-    
-  discard getTypeDesc(p.module, t)
-  for i in 1 .. <e.len:
-    let it = e.sons[i]
-    # XXX field check here
-    var field: PSym = nil
-    var ty = t
-    while ty != nil:
-      field = lookupInRecord(ty.n, it.sons[0].sym.name)
-      if field != nil: break
-      if gCmd != cmdCompileToCpp: app(r, ".Sup")
-      ty = GetUniqueType(ty.sons[0])
-    if field == nil or field.loc.r == nil: InternalError(e.info, "genObjConstr")
-    app(r, ".")
-    app(r, field.loc.r)
-    var tmp2: TLoc
-    tmp2.r = r
-    tmp2.k = locTemp
-    tmp2.t = field.loc.t
-    tmp2.s = onHeap
-    tmp2.heapRoot = tmp.r
-    expr(p, it.sons[1], tmp2)
-  genAssignment(p, d, tmp, {})
-
 proc genArrayElem(p: BProc, e: PNode, d: var TLoc) =
   var a, b: TLoc
   initLocExpr(p, e.sons[0], a)
@@ -1006,10 +1000,9 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
   #    seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x));
   #    seq->data[seq->len-1] = x;
   let seqAppendPattern = if gCmd != cmdCompileToCpp:
-      "$1 = ($2) #incrSeq(&($1)->Sup, sizeof($3));$n"
-    else:
-      "$1 = ($2) #incrSeq($1, sizeof($3));$n"
-
+                           "$1 = ($2) #incrSeq(&($1)->Sup, sizeof($3));$n"
+                         else:
+                           "$1 = ($2) #incrSeq($1, sizeof($3));$n"
   var a, b, dest: TLoc
   InitLocExpr(p, e.sons[1], a)
   InitLocExpr(p, e.sons[2], b)
@@ -1028,20 +1021,12 @@ proc genReset(p: BProc, n: PNode) =
   linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
           addrLoc(a), genTypeInfo(p.module, skipTypes(a.t, abstractVarRange)))
 
-proc genNew(p: BProc, e: PNode) =
-  var
-    a, b: TLoc
-    reftype, bt: PType
-    sizeExpr: PRope
-  refType = skipTypes(e.sons[1].typ, abstractVarRange)
-  InitLocExpr(p, e.sons[1], a)
+proc rawGenNew(p: BProc, a: TLoc, sizeExpr: PRope) =
+  var sizeExpr = sizeExpr
+  let refType = skipTypes(a.t, abstractVarRange)
+  var b: TLoc
   initLoc(b, locExpr, a.t, OnHeap)
-  # 'genNew' also handles 'unsafeNew':
-  if e.len == 3:
-    var se: TLoc
-    InitLocExpr(p, e.sons[2], se)
-    sizeExpr = se.rdLoc
-  else:
+  if sizeExpr.isNil:
     sizeExpr = ropef("sizeof($1)",
         getTypeDesc(p.module, skipTypes(reftype.sons[0], abstractRange)))
   let args = [getTypeDesc(p.module, reftype),
@@ -1058,9 +1043,20 @@ proc genNew(p: BProc, e: PNode) =
   else:
     b.r = ropecg(p.module, "($1) #newObj($2, $3)", args)
     genAssignment(p, a, b, {needToKeepAlive})  # set the object type:
-  bt = skipTypes(refType.sons[0], abstractRange)
+  let bt = skipTypes(refType.sons[0], abstractRange)
   genObjectInit(p, cpsStmts, bt, a, false)
 
+proc genNew(p: BProc, e: PNode) =
+  var a: TLoc
+  InitLocExpr(p, e.sons[1], a)
+  # 'genNew' also handles 'unsafeNew':
+  if e.len == 3:
+    var se: TLoc
+    InitLocExpr(p, e.sons[2], se)
+    rawGenNew(p, a, se.rdLoc)
+  else:
+    rawGenNew(p, a, nil)
+
 proc genNewSeqAux(p: BProc, dest: TLoc, length: PRope) =
   let seqtype = skipTypes(dest.t, abstractVarRange)
   let args = [getTypeDesc(p.module, seqtype),
@@ -1068,7 +1064,10 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: PRope) =
   var call: TLoc
   initLoc(call, locExpr, dest.t, OnHeap)
   if dest.s == OnHeap and usesNativeGC():
-    linefmt(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", dest.rdLoc)
+    if canFormAcycle(dest.t):
+      linefmt(p, cpsStmts, "if ($1) #nimGCunref($1);$n", dest.rdLoc)
+    else:
+      linefmt(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", dest.rdLoc)
     call.r = ropecg(p.module, "($1) #newSeqRC1($2, $3)", args)
     linefmt(p, cpsStmts, "$1 = $2;$n", dest.rdLoc, call.rdLoc)
   else:
@@ -1081,6 +1080,41 @@ proc genNewSeq(p: BProc, e: PNode) =
   InitLocExpr(p, e.sons[2], b)
   genNewSeqAux(p, a, b.rdLoc)
   
+proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
+  var tmp: TLoc
+  var t = e.typ.skipTypes(abstractInst)
+  getTemp(p, t, tmp)
+  let isRef = t.kind == tyRef
+  var r = rdLoc(tmp)
+  if isRef:
+    rawGenNew(p, tmp, nil)
+    t = t.sons[0].skipTypes(abstractInst)
+    r = ropef("(*$1)", r)
+  # XXX object initialization? but not necessary for temps, is it?
+  discard getTypeDesc(p.module, t)
+  for i in 1 .. <e.len:
+    let it = e.sons[i]
+    var tmp2: TLoc
+    tmp2.r = r
+    var field: PSym = nil
+    var ty = t
+    while ty != nil:
+      field = lookupInRecord(ty.n, it.sons[0].sym.name)
+      if field != nil: break
+      if gCmd != cmdCompileToCpp: app(tmp2.r, ".Sup")
+      ty = GetUniqueType(ty.sons[0])
+    if field == nil or field.loc.r == nil: InternalError(e.info, "genObjConstr")
+    if it.len == 3 and optFieldCheck in p.options:
+      genFieldCheck(p, it.sons[2], r, field)
+    app(tmp2.r, ".")
+    app(tmp2.r, field.loc.r)
+    tmp2.k = locTemp
+    tmp2.t = field.loc.t
+    tmp2.s = onHeap
+    tmp2.heapRoot = tmp.r
+    expr(p, it.sons[1], tmp2)
+  genAssignment(p, d, tmp, {})
+  
 proc genSeqConstr(p: BProc, t: PNode, d: var TLoc) =
   var arr: TLoc
   if d.k == locNone:
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 1b5d9124b..d37e79d6b 100755
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -744,7 +744,7 @@ proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): PRope =
   if objType.sym == nil: 
     InternalError(d.info, "anonymous obj with discriminator")
   result = ropef("NimDT_$1_$2", [
-    toRope(objType.sym.name.s), toRope(d.name.s)])
+    toRope(objType.sym.name.s.mangle), toRope(d.name.s.mangle)])
 
 proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): PRope = 
   discard cgsym(m, "TNimNode")
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 762a1973f..0fd117132 100755
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -1557,6 +1557,7 @@ proc semObjConstr(c: PContext, n: PNode): PNode =
   var t = semTypeNode(c, n.sons[0], nil)
   result = n
   result.typ = t
+  result.kind = nkObjConstr
   t = skipTypes(t, abstractInst)
   if t.kind == tyRef: t = skipTypes(t.sons[0], abstractInst)
   if t.kind != tyObject:
diff --git a/tests/run/tobjconstr.nim b/tests/run/tobjconstr.nim
new file mode 100644
index 000000000..3bd785728
--- /dev/null
+++ b/tests/run/tobjconstr.nim
@@ -0,0 +1,41 @@
+discard """
+  output: '''(k: kindA, a: (x: abc, z: [1, 1, 3]), empty: ())
+(k: kindA, a: (x: abc, z: [1, 2, 3]), empty: ())
+(k: kindA, a: (x: abc, z: [1, 3, 3]), empty: ())
+(k: kindA, a: (x: abc, z: [1, 4, 3]), empty: ())
+(k: kindA, a: (x: abc, z: [1, 5, 3]), empty: ())
+(k: kindA, a: (x: abc, z: [1, 6, 3]), empty: ())
+(k: kindA, a: (x: abc, z: [1, 7, 3]), empty: ())
+(k: kindA, a: (x: abc, z: [1, 8, 3]), empty: ())
+(k: kindA, a: (x: abc, z: [1, 9, 3]), empty: ())
+(k: kindA, a: (x: abc, z: [1, 10, 3]), empty: ())'''
+"""
+
+type
+  TArg = object
+    x: string
+    z: seq[int]
+  TKind = enum kindXY, kindA
+  TEmpty = object
+  TDummy = ref object
+    case k: TKind
+    of kindXY: x, y: int
+    of kindA: 
+      a: TArg
+      empty: TEmpty
+
+proc `$`[T](s: seq[T]): string =
+  # XXX why is that not in the stdlib?
+  result = "["
+  for i, x in s:
+    if i > 0: result.add(", ")
+    result.add($x)
+  result.add("]")
+
+proc main() =
+  for i in 1..10:
+    let d = TDummy(k: kindA, a: TArg(x: "abc", z: @[1,i,3]), empty: TEmpty())
+    echo d[]
+
+main()
+
diff --git a/todo.txt b/todo.txt
index 35ed58e4e..c914e0155 100755
--- a/todo.txt
+++ b/todo.txt
@@ -10,7 +10,6 @@ version 0.9.2
 - acyclic vs prunable; introduce GC hints
 - implement constructors
   - more checks
-  - C codegen for them
   - document them
 - CGEN: ``restrict`` pragma + backend support; computed goto support
 - fix:
@@ -128,6 +127,7 @@ Optimizations
 Bugs
 ====
 
+- instantiated generics are listed in error messages
 - sneaking with qualifiedLookup() is really broken!
 - aporia.nim(968, 5) Error: ambiguous identifier: 'DELETE' -- 
   use a qualifier