summary refs log tree commit diff stats
path: root/nim/ccgexprs.pas
diff options
context:
space:
mode:
Diffstat (limited to 'nim/ccgexprs.pas')
-rw-r--r--nim/ccgexprs.pas1350
1 files changed, 719 insertions, 631 deletions
diff --git a/nim/ccgexprs.pas b/nim/ccgexprs.pas
index 027f6a816..7668f114a 100644
--- a/nim/ccgexprs.pas
+++ b/nim/ccgexprs.pas
@@ -17,25 +17,34 @@ begin
     // Nimrod has the same bug for the same reasons :-)
     result := toRope('(-2147483647 -1)')
   else if i > low(int64) then
-    result := ropeFormat('IL64($1)', [toRope(i)])
+    result := ropef('IL64($1)', [toRope(i)])
   else
     result := toRope('(IL64(-9223372036854775807) - IL64(1))')
 end;
 
+function int32Literal(i: Int): PRope;
+begin
+  if i = low(int32) then
+    // Nimrod has the same bug for the same reasons :-)
+    result := toRope('(-2147483647 -1)')
+  else
+    result := toRope(i)
+end;
+
 function genHexLiteral(v: PNode): PRope;
 // in C hex literals are unsigned (at least I think so)
 // so we don't generate hex literals any longer.
 begin
-  assert(v.kind in [nkIntLit..nkInt64Lit]);
+  if not (v.kind in [nkIntLit..nkInt64Lit]) then
+    internalError(v.info, 'genHexLiteral');
   result := intLiteral(v.intVal)
 end;
 
-function getStrLit(const s: string): PRope;
+function getStrLit(m: BModule; const s: string): PRope;
 begin
-  inc(currMod.unique);
-  result := con('Str', toRope(currMod.unique));
-  appRopeFormat(currMod.s[cfsData],
-    'STRING_LITERAL($1, $2, $3);$n',
+  inc(gunique);
+  result := con('Str', toRope(gunique));
+  appf(m.s[cfsData], 'STRING_LITERAL($1, $2, $3);$n',
     [result, makeCString(s), ToRope(length(s))])
 end;
 
@@ -45,15 +54,21 @@ var
 begin
   if ty = nil then internalError(v.info, 'genLiteral: ty is nil');
   case v.kind of
-    nkIntLit..nkInt64Lit, nkCharLit..nkRCharLit: begin
+    nkCharLit..nkInt64Lit: begin
       case skipVarGenericRange(ty).kind of
-        tyChar, tyInt..tyInt64, tyNil: result := intLiteral(v.intVal);
+        tyChar, tyInt64, tyNil: result := intLiteral(v.intVal);
+        tyInt..tyInt32: begin
+          if (v.intVal >= low(int32)) and (v.intVal <= high(int32)) then
+            result := int32Literal(int32(v.intVal))
+          else
+            result := intLiteral(v.intVal);
+        end;
         tyBool: begin
           if v.intVal <> 0 then result := toRope('NIM_TRUE')
-          else result := toRope('NIM_FALSE');        
+          else result := toRope('NIM_FALSE');
         end;
         else
-          result := ropeFormat('(($1) $2)', [getTypeDesc(
+          result := ropef('(($1) $2)', [getTypeDesc(p.module,
             skipVarGenericRange(ty)), intLiteral(v.intVal)])
       end
     end;
@@ -61,7 +76,7 @@ begin
       result := toRope('0'+'');
     nkStrLit..nkTripleStrLit: begin
       if skipVarGenericRange(ty).kind = tyString then
-        result := ropeFormat('((string) &$1)', [getStrLit(v.strVal)])
+        result := ropef('((string) &$1)', [getStrLit(p.module, v.strVal)])
       else
         result := makeCString(v.strVal)
     end;
@@ -81,71 +96,7 @@ begin
       InternalError(v.info, 'genLiteral(' +{&} nodeKindToStr[v.kind] +{&} ')');
       result := nil
     end
-  end;
-  (*
-  case ty.Kind of
-    tyRange: result := genLiteral(p, v, ty.sons[0]);
-    tyInt..tyInt64, tyEnum:
-      result := intLiteral(v.intVal);
-    tyPointer, tyRef, tyPtr, tyProc:
-      if v.kind = nkNilLit then
-        result := toRope('0'+'') // 0 is better for C++
-      else
-        result := ropeFormat('(($1) $2)',
-                             [getTypeDesc(ty), intLiteral(v.intVal)]);
-    tyFloat..tyFloat128: begin
-      f := v.floatVal;
-      // BUGFIX: handle INF and NAN correctly:
-      if f <> f then // NAN
-        result := toRope('NAN')
-      else if f = 0.0 then
-        result := toRopeF(f)
-      else if f = 0.5 * f then
-        if f > 0.0 then
-          result := toRope('INF')
-        else
-          result := toRope('-INF')
-      else
-        result := toRopeF(f);
-    end;
-    tyString: begin // also merges constants
-      if v.kind = nkNilLit then result := toRope('0'+'')
-      else result := ropeFormat('((string) &$1)', [getStrLit(v.strVal)]);
-    end;
-    tyCString: begin
-      if v.kind = nkNilLit then
-        result := toRope('0'+'')
-      else if v.kind in [nkIntLit..nkInt64Lit] then begin
-        result := ropeFormat('((NCSTRING) $1)', [intLiteral(v.intVal)])
-      end
-      else 
-        result := makeCString(v.strVal)
-    end;
-    tySequence: begin
-      if v.kind = nkNilLit then 
-        result := toRope('0'+'')      
-      else if v.kind in [nkIntLit..nkInt64Lit] then
-        result := ropeFormat('(($1) $2)',
-                            [getTypeDesc(ty), intLiteral(v.intVal)])
-      else begin
-        assert(false);
-        result := nil // XXX: to implement
-      end
-    end;
-    tyChar: begin
-      result := toRope('''' + toCChar(Chr(int(v.intVal))) + '''')
-    end;
-    tyBool:
-      if v.intVal <> 0 then result := toRope('NIM_TRUE')
-      else result := toRope('NIM_FALSE');
-    tyNil:
-      result := toRope('0'+''); // 0-pointer is better for C++
-    tyVar: result := genLiteral(p, v, ty.sons[0]);
-    else begin
-      InternalError(v.info, 'genLiteral(' +{&} typeKindToStr[ty.kind] +{&} ')');
-      result := nil
-    end
-  end*)
+  end
 end;
 
 function genLiteral(p: BProc; v: PNode): PRope; overload;
@@ -160,11 +111,13 @@ begin
   result := 0;
   if CPU[hostCPU].endian = CPU[targetCPU].endian then begin
     for j := 0 to size-1 do
-      if j < length(s) then result := result or shlu(s[j], j * 8)
+      if j < length(s) then
+        result := result or shlu(Ze64(s[j]), j * 8)
   end
   else begin
     for j := 0 to size-1 do
-      if j < length(s) then result := result or shlu(s[j], (Size - 1 - j) * 8)
+      if j < length(s) then
+        result := result or shlu(Ze64(s[j]), (Size-1-j) * 8)
   end
 end;
 
@@ -181,11 +134,11 @@ begin
         else frmt := '0x$1, '
       end
       else frmt := '0x$1}$n';
-      appRopeFormat(result, frmt, [toRope(toHex(cs[i], 2))])
+      appf(result, frmt, [toRope(toHex(Ze64(cs[i]), 2))])
     end
   end
   else
-    result := toRope('0x' + ToHex(bitSetToWord(cs, size), IntSize * 2))
+    result := toRope('0x' + ToHex(bitSetToWord(cs, size), size * 2))
 end;
 
 function genSetNode(p: BProc; n: PNode): PRope;
@@ -197,9 +150,9 @@ begin
   toBitSet(n, cs);
   if size > 8 then begin
     result := getTempName();
-    appRopeFormat(currMod.s[cfsData],
-      'static $1$2 $3 = $4;',  // BUGFIX
-      [constTok, getTypeDesc(n.typ), result, genRawSetData(cs, size)])
+    appf(p.module.s[cfsData],
+      'static NIM_CONST $1 $2 = $3;',
+      [getTypeDesc(p.module, n.typ), result, genRawSetData(cs, size)])
   end
   else
     result := genRawSetData(cs, size)
@@ -207,22 +160,45 @@ end;
 
 // --------------------------- assignment generator -----------------------
 
+function getStorageLoc(n: PNode): TStorageLoc;
+begin
+  case n.kind of
+    nkSym: begin
+      case n.sym.kind of
+        skParam, skForVar, skTemp: result := OnStack;
+        skVar: begin
+          if sfGlobal in n.sym.flags then result := OnHeap
+          else result := OnStack
+        end;
+        else result := OnUnknown;
+      end
+    end;
+    //nkHiddenAddr, nkAddr:
+    nkDerefExpr, nkHiddenDeref:
+      case n.sons[0].typ.kind of
+        tyVar: result := OnUnknown;
+        tyPtr: result := OnStack;
+        tyRef: result := OnHeap;
+        else InternalError(n.info, 'getStorageLoc');
+      end;
+    nkBracketExpr, nkDotExpr, nkObjDownConv, nkObjUpConv:
+      result := getStorageLoc(n.sons[0]);
+    else result := OnUnknown;
+  end
+end;
+
 function rdLoc(const a: TLoc): PRope; // 'read' location (deref if indirect)
 begin
   result := a.r;
-  if a.indirect > 0 then
-    result := ropeFormat('($2$1)', 
-                         [result, toRope(repeatChar(a.indirect, '*'))])
+  if lfIndirect in a.flags then
+    result := ropef('(*$1 /*rdLoc*/)', [result])
 end;
 
 function addrLoc(const a: TLoc): PRope;
 begin
   result := a.r;
-  if a.indirect = 0 then
+  if not (lfIndirect in a.flags) then
     result := con('&'+'', result)
-  else if a.indirect > 1 then
-    result := ropeFormat('($2$1)', 
-                         [result, toRope(repeatChar(a.indirect-1, '*'))])
 end;
 
 function rdCharLoc(const a: TLoc): PRope;
@@ -230,22 +206,22 @@ function rdCharLoc(const a: TLoc): PRope;
 begin
   result := rdLoc(a);
   if skipRange(a.t).kind = tyChar then
-    result := ropeFormat('((NU8)($1))', [result])
+    result := ropef('((NU8)($1))', [result])
 end;
 
 procedure genRefAssign(p: BProc; const dest, src: TLoc);
 begin
-  if (lfOnStack in dest.flags) or not (optRefcGC in gGlobalOptions) then
+  if (dest.s = OnStack) or not (optRefcGC in gGlobalOptions) then
     // location is on hardware stack
-    appRopeFormat(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)])
-  else if lfOnHeap in dest.flags then begin // location is on heap
-    UseMagic('asgnRef');
-    appRopeFormat(p.s[cpsStmts], 'asgnRef((void**) $1, $2);$n',
+    appf(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)])
+  else if dest.s = OnHeap then begin // location is on heap
+    UseMagic(p.module, 'asgnRef');
+    appf(p.s[cpsStmts], 'asgnRef((void**) $1, $2);$n',
       [addrLoc(dest), rdLoc(src)])
   end
   else begin
-    UseMagic('unsureAsgnRef');
-    appRopeFormat(p.s[cpsStmts], 'unsureAsgnRef((void**) $1, $2);$n',
+    UseMagic(p.module, 'unsureAsgnRef');
+    appf(p.s[cpsStmts], 'unsureAsgnRef((void**) $1, $2);$n',
       [addrLoc(dest), rdLoc(src)])
   end
 end;
@@ -261,8 +237,7 @@ procedure genAssignment(p: BProc; const dest, src: TLoc;
 var
   ty: PType;
 begin;
-  ty := skipAbstract(dest.t);
-  while ty.kind = tyVar do ty := ty.sons[0];
+  ty := skipVarGenericRange(dest.t);
   case ty.kind of
     tyRef:
       genRefAssign(p, dest, src);
@@ -270,92 +245,89 @@ begin;
       if not (needToCopy in flags) then
         genRefAssign(p, dest, src)
       else begin
-        useMagic('genericSeqAssign'); // BUGFIX
-        appRopeFormat(p.s[cpsStmts], 'genericSeqAssign($1, $2, $3);$n',
-          [addrLoc(dest), rdLoc(src), genTypeInfo(currMod, dest.t)])
+        useMagic(p.module, 'genericSeqAssign'); // BUGFIX
+        appf(p.s[cpsStmts], 'genericSeqAssign($1, $2, $3);$n',
+          [addrLoc(dest), rdLoc(src), genTypeInfo(p.module, dest.t)])
       end
     end;
     tyString: begin
       if not (needToCopy in flags) then
         genRefAssign(p, dest, src)
       else begin
-        useMagic('copyString');
-        if (lfOnStack in dest.flags) or not (optRefcGC in gGlobalOptions) then
-          // location is on hardware stack
-          appRopeFormat(p.s[cpsStmts], '$1 = copyString($2);$n',
+        useMagic(p.module, 'copyString');
+        if (dest.s = OnStack) or not (optRefcGC in gGlobalOptions) then
+          appf(p.s[cpsStmts], '$1 = copyString($2);$n',
             [rdLoc(dest), rdLoc(src)])
-        else if lfOnHeap in dest.flags then begin // location is on heap
-          useMagic('asgnRef');
-          useMagic('copyString'); // BUGFIX
-          appRopeFormat(p.s[cpsStmts], 'asgnRef((void**) $1, copyString($2));$n',
+        else if dest.s = OnHeap then begin
+          useMagic(p.module, 'asgnRef');
+          useMagic(p.module, 'copyString'); // BUGFIX
+          appf(p.s[cpsStmts], 'asgnRef((void**) $1, copyString($2));$n',
             [addrLoc(dest), rdLoc(src)])
         end
         else begin
-          useMagic('unsureAsgnRef');
-          useMagic('copyString'); // BUGFIX
-          appRopeFormat(p.s[cpsStmts],
+          useMagic(p.module, 'unsureAsgnRef');
+          useMagic(p.module, 'copyString'); // BUGFIX
+          appf(p.s[cpsStmts],
             'unsureAsgnRef((void**) $1, copyString($2));$n',
             [addrLoc(dest), rdLoc(src)])
         end
       end
     end;
 
-    tyRecordConstr, tyRecord:
-      // BUGFIX
+    tyTuple:
       if needsComplexAssignment(dest.t) then begin
-        useMagic('genericAssign');
-        appRopeFormat(p.s[cpsStmts],
+        useMagic(p.module, 'genericAssign');
+        appf(p.s[cpsStmts],
           'genericAssign((void*)$1, (void*)$2, $3);$n',
-          [addrLoc(dest), addrLoc(src), genTypeInfo(currMod, dest.t)])
+          [addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
       end
       else
-        appRopeFormat(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)]);
+        appf(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)]);
     tyArray, tyArrayConstr:
       if needsComplexAssignment(dest.t) then begin
-        useMagic('genericAssign');
-        appRopeFormat(p.s[cpsStmts],
+        useMagic(p.module, 'genericAssign');
+        appf(p.s[cpsStmts],
           'genericAssign((void*)$1, (void*)$2, $3);$n',
-          // XXX: is this correct for arrays?
-          [addrLoc(dest), addrLoc(src), genTypeInfo(currMod, dest.t)])
+          [addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
       end
       else
-        appRopeFormat(p.s[cpsStmts],
-          'memcpy((void*)$1, (const void*)$2, sizeof($1));$n',
-          [addrLoc(dest), addrLoc(src)]);
+        appf(p.s[cpsStmts],
+          'memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1));$n',
+          [rdLoc(dest), rdLoc(src)]);
     tyObject:
       // XXX: check for subtyping?
       if needsComplexAssignment(dest.t) then begin
-        useMagic('genericAssign');
-        appRopeFormat(p.s[cpsStmts],
+        useMagic(p.module, 'genericAssign');
+        appf(p.s[cpsStmts],
           'genericAssign((void*)$1, (void*)$2, $3);$n',
-          [addrLoc(dest), addrLoc(src), genTypeInfo(currMod, dest.t)])
+          [addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
       end
       else
-        appRopeFormat(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)]);
+        appf(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)]);
     tyOpenArray: begin
-      // open arrays are always on the stack, really? What if a sequence is
+      // open arrays are always on the stack - really? What if a sequence is
       // passed to an open array?
       if needsComplexAssignment(dest.t) then begin
-        useMagic('genericAssignOpenArray');
-        appRopeFormat(p.s[cpsStmts],// XXX: is this correct for arrays?
+        useMagic(p.module, 'genericAssignOpenArray');
+        appf(p.s[cpsStmts],// XXX: is this correct for arrays?
           'genericAssignOpenArray((void*)$1, (void*)$2, $1Len0, $3);$n',
-          [addrLoc(dest), addrLoc(src), genTypeInfo(currMod, dest.t)])
+          [addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
       end
       else
-        appRopeFormat(p.s[cpsStmts],
-          'memcpy((void*)$1, (const void*)$2, sizeof($1[0])*$1Len0);$n',
-          [addrLoc(dest), addrLoc(src)]);
+        appf(p.s[cpsStmts],
+          'memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1[0])*$1Len0);$n',
+          [rdLoc(dest), rdLoc(src)]);
     end;
     tySet:
-      if getSize(ty) <= 8 then
-        appRopeFormat(p.s[cpsStmts], '$1 = $2;$n',
-          [rdLoc(dest), rdLoc(src)])
+      if mapType(ty) = ctArray then
+        appf(p.s[cpsStmts], 'memcpy((void*)$1, (NIM_CONST void*)$2, $3);$n',
+          [rdLoc(dest), rdLoc(src), toRope(getSize(dest.t))])
       else
-        appRopeFormat(p.s[cpsStmts], 'memcpy((void*)$1, (const void*)$2, $3);$n',
-          [rdLoc(dest), rdLoc(src), toRope(getSize(dest.t))]);
+        appf(p.s[cpsStmts], '$1 = $2;$n',
+          [rdLoc(dest), rdLoc(src)]);
     tyPtr, tyPointer, tyChar, tyBool, tyProc, tyEnum,
         tyCString, tyInt..tyFloat128, tyRange:
-      appRopeFormat(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)]);
+      appf(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)]);
     else
       InternalError('genAssignment(' + typeKindToStr[ty.kind] + ')')
   end
@@ -367,7 +339,7 @@ procedure expr(p: BProc; e: PNode; var d: TLoc); forward;
 
 function initLocExpr(p: BProc; e: PNode): TLoc;
 begin
-  result := initLoc(locNone, e.typ);
+  result := initLoc(locNone, getUniqueType(e.typ), OnUnknown);
   expr(p, e, result)
 end;
 
@@ -392,7 +364,7 @@ var
   a: TLoc;
 begin
   if d.k <> locNone then begin // need to generate an assignment here
-    a := initLoc(locExpr, t);
+    a := initLoc(locExpr, getUniqueType(t), OnUnknown);
     a.r := r;
     if lfNoDeepCopy in d.flags then
       genAssignment(p, d, a, {@set}[])
@@ -402,7 +374,7 @@ begin
   else begin // we cannot call initLoc() here as that would overwrite
              // the flags field!
     d.k := locExpr;
-    d.t := t;
+    d.t := getUniqueType(t);
     d.r := r;
     d.a := -1
   end
@@ -413,12 +385,11 @@ procedure binaryStmt(p: BProc; e: PNode; var d: TLoc;
 var
   a, b: TLoc;
 begin
-  assert(d.k = locNone);
-  if magic <> '' then
-    useMagic(magic);
+  if (d.k <> locNone) then InternalError(e.info, 'binaryStmt');
+  if magic <> '' then useMagic(p.module, magic);
   a := InitLocExpr(p, e.sons[1]);
   b := InitLocExpr(p, e.sons[2]);
-  appRopeFormat(p.s[cpsStmts], frmt, [rdLoc(a), rdLoc(b)]);
+  appf(p.s[cpsStmts], frmt, [rdLoc(a), rdLoc(b)]);
   freeTemp(p, a);
   freeTemp(p, b)
 end;
@@ -428,12 +399,11 @@ procedure binaryStmtChar(p: BProc; e: PNode; var d: TLoc;
 var
   a, b: TLoc;
 begin
-  assert(d.k = locNone);
-  if magic <> '' then
-    useMagic(magic);
+  if (d.k <> locNone) then InternalError(e.info, 'binaryStmtChar');
+  if magic <> '' then useMagic(p.module, magic);
   a := InitLocExpr(p, e.sons[1]);
   b := InitLocExpr(p, e.sons[2]);
-  appRopeFormat(p.s[cpsStmts], frmt, [rdCharLoc(a), rdCharLoc(b)]);
+  appf(p.s[cpsStmts], frmt, [rdCharLoc(a), rdCharLoc(b)]);
   freeTemp(p, a);
   freeTemp(p, b)
 end;
@@ -443,13 +413,12 @@ procedure binaryExpr(p: BProc; e: PNode; var d: TLoc;
 var
   a, b: TLoc;
 begin
-  if magic <> '' then
-    useMagic(magic);
+  if magic <> '' then useMagic(p.module, magic);
   assert(e.sons[1].typ <> nil);
   assert(e.sons[2].typ <> nil);
   a := InitLocExpr(p, e.sons[1]);
   b := InitLocExpr(p, e.sons[2]);
-  putIntoDest(p, d, e.typ, ropeFormat(frmt, [rdLoc(a), rdLoc(b)]));
+  putIntoDest(p, d, e.typ, ropef(frmt, [rdLoc(a), rdLoc(b)]));
   if d.k <> locExpr then begin // BACKPORT
     freeTemp(p, a);
     freeTemp(p, b)
@@ -461,13 +430,12 @@ procedure binaryExprChar(p: BProc; e: PNode; var d: TLoc;
 var
   a, b: TLoc;
 begin
-  if magic <> '' then
-    useMagic(magic);
+  if magic <> '' then useMagic(p.module, magic);
   assert(e.sons[1].typ <> nil);
   assert(e.sons[2].typ <> nil);
   a := InitLocExpr(p, e.sons[1]);
   b := InitLocExpr(p, e.sons[2]);
-  putIntoDest(p, d, e.typ, ropeFormat(frmt, [rdCharLoc(a), rdCharLoc(b)]));
+  putIntoDest(p, d, e.typ, ropef(frmt, [rdCharLoc(a), rdCharLoc(b)]));
   if d.k <> locExpr then begin // BACKPORT
     freeTemp(p, a);
     freeTemp(p, b)
@@ -479,10 +447,9 @@ procedure unaryExpr(p: BProc; e: PNode; var d: TLoc;
 var
   a: TLoc;
 begin
-  if magic <> '' then
-    useMagic(magic);
+  if magic <> '' then useMagic(p.module, magic);
   a := InitLocExpr(p, e.sons[1]);
-  putIntoDest(p, d, e.typ, ropeFormat(frmt, [rdLoc(a)]));
+  putIntoDest(p, d, e.typ, ropef(frmt, [rdLoc(a)]));
   if d.k <> locExpr then // BACKPORT
     freeTemp(p, a)
 end;
@@ -492,10 +459,9 @@ procedure unaryExprChar(p: BProc; e: PNode; var d: TLoc;
 var
   a: TLoc;
 begin
-  if magic <> '' then
-    useMagic(magic);
+  if magic <> '' then useMagic(p.module, magic);
   a := InitLocExpr(p, e.sons[1]);
-  putIntoDest(p, d, e.typ, ropeFormat(frmt, [rdCharLoc(a)]));
+  putIntoDest(p, d, e.typ, ropef(frmt, [rdCharLoc(a)]));
   if d.k <> locExpr then // BACKPORT
     freeTemp(p, a)
 end;
@@ -510,15 +476,15 @@ const
     '($1 + $2)', '($1 - $2)', '($1 * $2)', '($1 / $2)', '($1 % $2)'
   );
   binArithTab: array [mShrI..mXor] of string = (
-    '(NS)((NU)($1) >> (NU)($2))', // ShrI
-    '(NS)((NU)($1) << (NU)($2))', // ShlI
+    '(NI)((NU)($1) >> (NU)($2))', // ShrI
+    '(NI)((NU)($1) << (NU)($2))', // ShlI
     '($1 & $2)', // BitandI
     '($1 | $2)', // BitorI
     '($1 ^ $2)', // BitxorI
     '(($1 <= $2) ? $1 : $2)', // MinI
     '(($1 >= $2) ? $1 : $2)', // MaxI
-    '(NS64)((NU64)($1) >> (NU64)($2))', // ShrI64
-    '(NS64)((NU64)($1) << (NU64)($2))', // ShlI64
+    '(NI64)((NU64)($1) >> (NU64)($2))', // ShrI64
+    '(NI64)((NU64)($1) << (NU64)($2))', // ShlI64
     '($1 & $2)', // BitandI64
     '($1 | $2)', // BitorI64
     '($1 ^ $2)', // BitxorI64
@@ -532,16 +498,16 @@ const
     '(($1 <= $2) ? $1 : $2)', // MinF64
     '(($1 >= $2) ? $1 : $2)', // MaxF64
 
-    '(NS)((NU)($1) + (NU)($2))', // AddU
-    '(NS)((NU)($1) - (NU)($2))', // SubU
-    '(NS)((NU)($1) * (NU)($2))', // MulU
-    '(NS)((NU)($1) / (NU)($2))', // DivU
-    '(NS)((NU)($1) % (NU)($2))', // ModU
-    '(NS64)((NU64)($1) + (NU64)($2))', // AddU64
-    '(NS64)((NU64)($1) - (NU64)($2))', // SubU64
-    '(NS64)((NU64)($1) * (NU64)($2))', // MulU64
-    '(NS64)((NU64)($1) / (NU64)($2))', // DivU64
-    '(NS64)((NU64)($1) % (NU64)($2))', // ModU64
+    '(NI)((NU)($1) + (NU)($2))', // AddU
+    '(NI)((NU)($1) - (NU)($2))', // SubU
+    '(NI)((NU)($1) * (NU)($2))', // MulU
+    '(NI)((NU)($1) / (NU)($2))', // DivU
+    '(NI)((NU)($1) % (NU)($2))', // ModU
+    '(NI64)((NU64)($1) + (NU64)($2))', // AddU64
+    '(NI64)((NU64)($1) - (NU64)($2))', // SubU64
+    '(NI64)((NU64)($1) * (NU64)($2))', // MulU64
+    '(NI64)((NU64)($1) / (NU64)($2))', // DivU64
+    '(NI64)((NU64)($1) % (NU64)($2))', // ModU64
 
     '($1 == $2)', // EqI
     '($1 <= $2)', // LeI
@@ -587,11 +553,16 @@ const
     '-($1)',  // UnaryMinusF64
     '($1 > 0? ($1) : -($1))',  // AbsF64; BUGFIX: fabs() makes problems for Tiny C, so we don't use it
 
-    '((NS)(NU)($1))',  // Ze
-    '((NS64)(NU64)($1))', // Ze64
-    '((NS8)(NU8)(NU)($1))', // ToU8
-    '((NS16)(NU16)(NU)($1))', // ToU16
-    '((NS32)(NU32)(NU64)($1))', // ToU32
+    '((NI)(NU)(NU8)($1))', // mZe8ToI
+    '((NI64)(NU64)(NU8)($1))', // mZe8ToI64
+    '((NI)(NU)(NU16)($1))', // mZe16ToI
+    '((NI64)(NU64)(NU16)($1))', // mZe16ToI64
+    '((NI64)(NU64)(NU32)($1))', // mZe32ToI64
+    '((NI64)(NU64)(NU)($1))', // mZeIToI64
+
+    '((NI8)(NU8)(NU)($1))', // ToU8
+    '((NI16)(NU16)(NU)($1))', // ToU16
+    '((NI32)(NU32)(NU64)($1))', // ToU32
 
     '((double) ($1))', // ToFloat
     '((double) ($1))', // ToBiggestFloat
@@ -641,29 +612,42 @@ procedure genDeref(p: BProc; e: PNode; var d: TLoc);
 var
   a: TLoc;
 begin
-  a := initLocExpr(p, e.sons[0]);
-  putIntoDest(p, d, a.t.sons[0], ropeFormat('(*$1)', [rdLoc(a)]));
-  if d.k <> locExpr then // BACKPORT
-    freeTemp(p, a)
+  if mapType(e.sons[0].typ) = ctArray then
+    expr(p, e.sons[0], d)
+  else begin
+    a := initLocExpr(p, e.sons[0]);
+    case skipGeneric(a.t).kind of
+      tyRef: d.s := OnHeap;
+      tyVar: d.s := OnUnknown;
+      tyPtr: d.s := OnStack;
+      else InternalError(e.info, 'genDeref ' + typekindToStr[a.t.kind]);
+    end;
+    putIntoDest(p, d, a.t.sons[0], ropef('(*$1)', [rdLoc(a)]));
+  end
 end;
 
-procedure fillInLocation(var a, d: TLoc);
+procedure genAddr(p: BProc; e: PNode; var d: TLoc);
+var
+  a: TLoc;
 begin
-  case skipAbstract(a.t).kind of
-    tyRef: begin
-      if d.k = locNone then d.flags := {@set}[lfOnHeap];
-      a.r := ropeFormat('(*$1)', [a.r])
-    end;
-    tyPtr: begin
-      if d.k = locNone then d.flags := {@set}[lfOnUnknown];
-      a.r := ropeFormat('(*$1)', [a.r])
-    end;
-    // element has same flags as the array (except lfIndirect):
-    else
-      if d.k = locNone then inheritStorage(d, a)
+  if mapType(e.sons[0].typ) = ctArray then
+    expr(p, e.sons[0], d)
+  else begin
+    a := InitLocExpr(p, e.sons[0]);
+    putIntoDest(p, d, e.typ, addrLoc(a));
+    if d.k <> locExpr then freeTemp(p, a)
   end
 end;
 
+function genRecordFieldAux(p: BProc; e: PNode; var d, a: TLoc): PType;
+begin
+  a := initLocExpr(p, e.sons[0]);
+  if (e.sons[1].kind <> nkSym) then InternalError(e.info, 'genRecordFieldAux');
+  if d.k = locNone then d.s := a.s;
+  {@discard} getTypeDesc(p.module, a.t); // fill the record's fields.loc
+  result := getUniqueType(a.t);
+end;
+
 procedure genRecordField(p: BProc; e: PNode; var d: TLoc);
 var
   a: TLoc;
@@ -671,45 +655,76 @@ var
   ty: PType;
   r: PRope;
 begin
-  a := initLocExpr(p, e.sons[0]);
-  assert(e.sons[1].kind = nkSym);
-  f := e.sons[1].sym;
-
-  if d.k = locNone then inheritStorage(d, a);
-  // for objects we have to search the hierarchy for determining
-  // how much ``Sup`` we need:
-  ty := skipAbstract(a.t);
-  while true do begin
-    case ty.kind of
-      tyRef: begin
-        if d.k = locNone then d.flags := {@set}[lfOnHeap];
-        inc(a.indirect);
-      end;
-      tyPtr: begin
-        if d.k = locNone then d.flags := {@set}[lfOnUnknown];
-        inc(a.indirect);
-      end;
-      tyVar: begin
-        if d.k = locNone then d.flags := {@set}[lfOnUnknown];
-      end;
-      else break
-    end;
-    ty := skipAbstract(ty.sons[0]);
-  end;
+  ty := genRecordFieldAux(p, e, d, a);
   r := rdLoc(a);
-  {@discard} getTypeDesc(ty); // fill the record's fields.loc
+  f := e.sons[1].sym;
   field := nil;
   while ty <> nil do begin
-    assert(ty.kind in [tyRecord, tyObject]);
+    assert(ty.kind in [tyTuple, tyObject]);
     field := lookupInRecord(ty.n, f.name);
     if field <> nil then break;
     if gCmd <> cmdCompileToCpp then app(r, '.Sup');
-    ty := ty.sons[0]
+    ty := GetUniqueType(ty.sons[0]);
   end;
-  assert((field <> nil) and (field.loc.r <> nil));
-  appRopeFormat(r, '.$1', [field.loc.r]);
+  if field = nil then InternalError(e.info, 'genRecordField');
+  if field.loc.r = nil then InternalError(e.info, 'genRecordField');
+  appf(r, '.$1', [field.loc.r]);
   putIntoDest(p, d, field.typ, r);
-  // freeTemp(p, a) // BACKPORT
+end;
+
+procedure genInExprAux(p: BProc; e: PNode; var a, b, d: TLoc); forward;
+
+procedure genCheckedRecordField(p: BProc; e: PNode; var d: TLoc);
+var
+  a, u, v, test: TLoc;
+  f, field, op: PSym;
+  ty: PType;
+  r: PRope;
+  i: int;
+  it: PNode;
+begin
+  if optFieldCheck in p.options then begin
+    useMagic(p.module, 'raiseFieldError');
+    ty := genRecordFieldAux(p, e.sons[0], d, a);
+    r := rdLoc(a);
+    f := e.sons[0].sons[1].sym;
+    field := nil;
+    while ty <> nil do begin
+      assert(ty.kind in [tyTuple, tyObject]);
+      field := lookupInRecord(ty.n, f.name);
+      if field <> nil then break;
+      if gCmd <> cmdCompileToCpp then app(r, '.Sup');
+      ty := getUniqueType(ty.sons[0])
+    end;
+    if field = nil then InternalError(e.info, 'genCheckedRecordField');
+    if field.loc.r = nil then InternalError(e.info, 'genCheckedRecordField');
+    // generate the checks:
+    for i := 1 to sonsLen(e)-1 do begin
+      it := e.sons[i];
+      assert(it.kind = nkCall);
+      assert(it.sons[0].kind = nkSym);
+      op := it.sons[0].sym;
+      if op.magic = mNot then it := it.sons[1];
+      assert(it.sons[2].kind = nkSym);
+      test := initLoc(locNone, it.typ, OnStack);
+      u := InitLocExpr(p, it.sons[1]);
+      v := initLoc(locExpr, it.sons[2].typ, OnUnknown);
+      v.r := ropef('$1.$2', [r, it.sons[2].sym.loc.r]);
+      genInExprAux(p, it, u, v, test);
+      if op.magic = mNot then
+        appf(p.s[cpsStmts],
+          'if ($1) raiseFieldError(((string) &$2));$n',
+          [rdLoc(test), getStrLit(p.module, field.name.s)])
+      else
+        appf(p.s[cpsStmts],
+          'if (!($1)) raiseFieldError(((string) &$2));$n',
+          [rdLoc(test), getStrLit(p.module, field.name.s)])
+    end;
+    appf(r, '.$1', [field.loc.r]);
+    putIntoDest(p, d, field.typ, r);
+  end
+  else
+    genRecordField(p, e.sons[0], d)
 end;
 
 procedure genArrayElem(p: BProc; e: PNode; var d: TLoc);
@@ -720,19 +735,18 @@ var
 begin
   a := initLocExpr(p, e.sons[0]);
   b := initLocExpr(p, e.sons[1]);
-  ty := skipAbstract(a.t);
-  if ty.kind in [tyRef, tyPtr] then ty := skipAbstract(ty.sons[0]);
+  ty := skipPtrsGeneric(skipVarGenericRange(a.t));
   first := intLiteral(firstOrd(ty));
   // emit range check:
   if optBoundsCheck in p.options then
     if b.k <> locImmediate then begin // semantic pass has already checked:
-      useMagic('raiseIndexError');
-      appRopeFormat(p.s[cpsStmts],
+      useMagic(p.module, 'raiseIndexError');
+      appf(p.s[cpsStmts],
                'if ($1 < $2 || $1 > $3) raiseIndexError();$n',
                [rdCharLoc(b), first, intLiteral(lastOrd(ty))])
     end;
-  fillInLocation(a, d);
-  putIntoDest(p, d, elemType(skipVarGeneric(ty)), ropeFormat('$1[($2)-$3]',
+  if d.k = locNone then d.s := a.s;
+  putIntoDest(p, d, elemType(skipVarGeneric(ty)), ropef('$1[($2)-$3]',
     [rdLoc(a), rdCharLoc(b), first]));
   // freeTemp(p, a); // backport
   // freeTemp(p, b)
@@ -745,9 +759,9 @@ var
 begin
   a := initLocExpr(p, e.sons[0]);
   b := initLocExpr(p, e.sons[1]);
-  ty := skipAbstract(a.t);
-  fillInLocation(a, d);
-  putIntoDest(p, d, elemType(skipVarGeneric(ty)), ropeFormat('$1[$2]',
+  ty := skipVarGenericRange(a.t);
+  if d.k = locNone then d.s := a.s;
+  putIntoDest(p, d, elemType(skipVarGeneric(ty)), ropef('$1[$2]',
     [rdLoc(a), rdCharLoc(b)]));
   // freeTemp(p, a); // backport
   // freeTemp(p, b)
@@ -760,14 +774,13 @@ begin
   a := initLocExpr(p, e.sons[0]);
   b := initLocExpr(p, e.sons[1]);
   // emit range check:
-  if optBoundsCheck in p.options then
-    if b.k <> locImmediate then begin // semantic pass has already checked:
-      useMagic('raiseIndexError');
-      appRopeFormat(p.s[cpsStmts],
-        'if ((NU)($1) > (NU)($2Len0)) raiseIndexError();$n', [rdLoc(b), a.r])
-    end;
-  if d.k = locNone then inheritStorage(d, a);
-  putIntoDest(p, d, elemType(skipVarGeneric(a.t)), ropeFormat('$1[$2]',
+  if optBoundsCheck in p.options then begin
+    useMagic(p.module, 'raiseIndexError');
+    appf(p.s[cpsStmts],
+      'if ((NU)($1) > (NU)($2Len0)) raiseIndexError();$n', [rdLoc(b), a.r])
+  end;
+  if d.k = locNone then d.s := a.s;
+  putIntoDest(p, d, elemType(skipVarGeneric(a.t)), ropef('$1[$2]',
     [rdLoc(a), rdCharLoc(b)]));
   // freeTemp(p, a); // backport
   // freeTemp(p, b)
@@ -780,26 +793,24 @@ var
 begin
   a := initLocExpr(p, e.sons[0]);
   b := initLocExpr(p, e.sons[1]);
-  ty := skipAbstract(a.t);
-  if ty.kind in [tyRef, tyPtr] then ty := skipAbstract(ty.sons[0]);
+  ty := skipVarGenericRange(a.t);
+  if ty.kind in [tyRef, tyPtr] then ty := skipVarGenericRange(ty.sons[0]);
   // emit range check:
-  if optBoundsCheck in p.options then
-    if b.k <> locImmediate then begin // semantic pass has already checked:
-      useMagic('raiseIndexError');
-      if ty.kind = tyString then
-        appRopeFormat(p.s[cpsStmts],
-          'if ((NU)($1) > (NU)($2->len)) raiseIndexError();$n',
-          [rdLoc(b), rdLoc(a)])
-      else
-        appRopeFormat(p.s[cpsStmts],
-          'if ((NU)($1) >= (NU)($2->len)) raiseIndexError();$n',
-          [rdLoc(b), rdLoc(a)])
-    end;
-  // element has same flags as the array (except lfIndirect):
-  if d.k = locNone then d.flags := {@set}[lfOnHeap];
-  if skipAbstract(a.t).kind in [tyRef, tyPtr] then
-    a.r := ropeFormat('(*$1)', [a.r]);
-  putIntoDest(p, d, elemType(skipVarGeneric(a.t)), ropeFormat('$1->data[$2]',
+  if optBoundsCheck in p.options then begin
+    useMagic(p.module, 'raiseIndexError');
+    if ty.kind = tyString then
+      appf(p.s[cpsStmts],
+        'if ((NU)($1) > (NU)($2->len)) raiseIndexError();$n',
+        [rdLoc(b), rdLoc(a)])
+    else
+      appf(p.s[cpsStmts],
+        'if ((NU)($1) >= (NU)($2->len)) raiseIndexError();$n',
+        [rdLoc(b), rdLoc(a)])
+  end;
+  if d.k = locNone then d.s := OnHeap;
+  if skipVarGenericRange(a.t).kind in [tyRef, tyPtr] then
+    a.r := ropef('(*$1)', [a.r]);
+  putIntoDest(p, d, elemType(skipVarGeneric(a.t)), ropef('$1->data[$2]',
     [rdLoc(a), rdCharLoc(b)]));
   // freeTemp(p, a); // backport
   // freeTemp(p, b)
@@ -834,9 +845,9 @@ begin
   expr(p, e.sons[1], tmp);
   L := getLabel(p);
   if m = mOr then
-    appRopeFormat(p.s[cpsStmts], 'if ($1) goto $2;$n', [rdLoc(tmp), L])
+    appf(p.s[cpsStmts], 'if ($1) goto $2;$n', [rdLoc(tmp), L])
   else // mAnd:
-    appRopeFormat(p.s[cpsStmts], 'if (!($1)) goto $2;$n', [rdLoc(tmp), L]);
+    appf(p.s[cpsStmts], 'if (!($1)) goto $2;$n', [rdLoc(tmp), L]);
   expr(p, e.sons[2], tmp);
   fixLabel(p, L);
   if d.k = locNone then
@@ -874,10 +885,10 @@ begin
       nkElifExpr: begin
         a := initLocExpr(p, it.sons[0]);
         Lelse := getLabel(p);
-        appRopeFormat(p.s[cpsStmts], 'if (!$1) goto $2;$n', [rdLoc(a), Lelse]);
+        appf(p.s[cpsStmts], 'if (!$1) goto $2;$n', [rdLoc(a), Lelse]);
         freeTemp(p, a);
         expr(p, it.sons[1], tmp);
-        appRopeFormat(p.s[cpsStmts], 'goto $1;$n', [Lend]);
+        appf(p.s[cpsStmts], 'goto $1;$n', [Lend]);
         fixLabel(p, Lelse);
       end;
       nkElseExpr: begin
@@ -905,9 +916,12 @@ var
   op, list: TLoc;
   len, i: int;
 begin
+{@emit
+  a := [];
+}
   op := initLocExpr(p, t.sons[0]);
   pl := con(op.r, '('+'');
-  typ := t.sons[0].typ;
+  typ := getUniqueType(t.sons[0].typ);
   assert(typ.kind = tyProc);
   invalidRetType := isInvalidReturnType(typ.sons[0]);
   len := sonsLen(t);
@@ -918,8 +932,8 @@ begin
     if (i < sonsLen(typ)) then begin
       assert(typ.n.sons[i].kind = nkSym);
       param := typ.n.sons[i].sym;
-      if usePtrPassing(param) then app(pl, addrLoc(a[i-1]))
-      else                         app(pl, rdLoc(a[i-1]));
+      if ccgIntroducedPtr(param) then app(pl, addrLoc(a[i-1]))
+      else                            app(pl, rdLoc(a[i-1]));
     end
     else
       app(pl, rdLoc(a[i-1]));
@@ -928,7 +942,7 @@ begin
   end;
   if (typ.sons[0] <> nil) and invalidRetType then begin
     if d.k = locNone then d := getTemp(p, typ.sons[0]);
-    app(pl, addrLoc(d))
+    app(pl, addrLoc(d));
   end;
   app(pl, ')'+'');
   for i := 0 to high(a) do
@@ -938,12 +952,12 @@ begin
     if d.k = locNone then d := getTemp(p, typ.sons[0]);
     assert(d.t <> nil);
     // generate an assignment to d:
-    list := initLoc(locCall, nil);
+    list := initLoc(locCall, nil, OnUnknown);
     list.r := pl;
     genAssignment(p, d, list, {@set}[]) // no need for deep copying
   end
   else
-    appRopeFormat(p.s[cpsStmts], '$1;$n', [pl])
+    appf(p.s[cpsStmts], '$1;$n', [pl])
 end;
 
 procedure genStrConcat(p: BProc; e: PNode; var d: TLoc);
@@ -969,30 +983,33 @@ var
   appends, lens: PRope;
   L, i: int;
 begin
-  useMagic('rawNewString');
+  useMagic(p.module, 'rawNewString');
   tmp := getTemp(p, e.typ);
   L := 0;
   appends := nil;
   lens := nil;
+{@emit
+  a := [];
+}
   setLength(a, sonsLen(e)-1);
   for i := 0 to sonsLen(e)-2 do begin
     // compute the length expression:
     a[i] := initLocExpr(p, e.sons[i+1]);
-    if skipAbstract(e.sons[i+1].Typ).kind = tyChar then begin
+    if skipVarGenericRange(e.sons[i+1].Typ).kind = tyChar then begin
       Inc(L);
-      useMagic('appendChar');
-      appRopeFormat(appends, 'appendChar($1, $2);$n', [tmp.r, rdLoc(a[i])])
+      useMagic(p.module, 'appendChar');
+      appf(appends, 'appendChar($1, $2);$n', [tmp.r, rdLoc(a[i])])
     end
     else begin
       if e.sons[i+1].kind in [nkStrLit..nkTripleStrLit] then  // string literal?
         Inc(L, length(e.sons[i+1].strVal))
       else
-        appRopeFormat(lens, '$1->len + ', [rdLoc(a[i])]);
-      useMagic('appendString');
-      appRopeFormat(appends, 'appendString($1, $2);$n', [tmp.r, rdLoc(a[i])])
+        appf(lens, '$1->len + ', [rdLoc(a[i])]);
+      useMagic(p.module, 'appendString');
+      appf(appends, 'appendString($1, $2);$n', [tmp.r, rdLoc(a[i])])
     end
   end;
-  appRopeFormat(p.s[cpsStmts], '$1 = rawNewString($2$3);$n',
+  appf(p.s[cpsStmts], '$1 = rawNewString($2$3);$n',
     [tmp.r, lens, toRope(L)]);
   app(p.s[cpsStmts], appends);
   for i := 0 to high(a) do
@@ -1023,32 +1040,35 @@ var
   appends, lens: PRope;
 begin
   assert(d.k = locNone);
-  useMagic('resizeString');
+  useMagic(p.module, 'resizeString');
   L := 0;
   appends := nil;
   lens := nil;
+{@emit
+  a := [];
+}
   setLength(a, sonsLen(e)-1);
   expr(p, e.sons[1], a[0]);
   for i := 0 to sonsLen(e)-3 do begin
     // compute the length expression:
     a[i+1] := initLocExpr(p, e.sons[i+2]);
-    if skipAbstract(e.sons[i+2].Typ).kind = tyChar then begin
+    if skipVarGenericRange(e.sons[i+2].Typ).kind = tyChar then begin
       Inc(L);
-      useMagic('appendChar');
-      appRopeFormat(appends, 'appendChar($1, $2);$n',
+      useMagic(p.module, 'appendChar');
+      appf(appends, 'appendChar($1, $2);$n',
         [rdLoc(a[0]), rdLoc(a[i+1])])
     end
     else begin
       if e.sons[i+2].kind in [nkStrLit..nkTripleStrLit] then  // string literal?
         Inc(L, length(e.sons[i+2].strVal))
       else
-        appRopeFormat(lens, '$1->len + ', [rdLoc(a[i+1])]);
-      useMagic('appendString');
-      appRopeFormat(appends, 'appendString($1, $2);$n',
+        appf(lens, '$1->len + ', [rdLoc(a[i+1])]);
+      useMagic(p.module, 'appendString');
+      appf(appends, 'appendString($1, $2);$n',
         [rdLoc(a[0]), rdLoc(a[i+1])])
     end
   end;
-  appRopeFormat(p.s[cpsStmts], '$1 = resizeString($1, $2$3);$n',
+  appf(p.s[cpsStmts], '$1 = resizeString($1, $2$3);$n',
     [rdLoc(a[0]), lens, toRope(L)]);
   app(p.s[cpsStmts], appends);
   for i := 0 to high(a) do
@@ -1062,16 +1082,15 @@ procedure genSeqElemAppend(p: BProc; e: PNode; var d: TLoc);
 var
   a, b, dest: TLoc;
 begin
-  useMagic('incrSeq');
+  useMagic(p.module, 'incrSeq');
   a := InitLocExpr(p, e.sons[1]);
   b := InitLocExpr(p, e.sons[2]);
-  appRopeFormat(p.s[cpsStmts],
+  appf(p.s[cpsStmts],
     '$1 = ($2) incrSeq((TGenericSeq*) $1, sizeof($3));$n',
-    [rdLoc(a), getTypeDesc(skipVarGeneric(e.sons[1].typ)),
-    getTypeDesc(skipVarGeneric(e.sons[2].Typ))]);
-  dest := initLoc(locExpr, b.t);
-  dest.flags := {@set}[lfOnHeap];
-  dest.r := ropeFormat('$1->data[$1->len-1]', [rdLoc(a)]);
+    [rdLoc(a), getTypeDesc(p.module, skipVarGeneric(e.sons[1].typ)),
+    getTypeDesc(p.module, skipVarGeneric(e.sons[2].Typ))]);
+  dest := initLoc(locExpr, b.t, OnHeap);
+  dest.r := ropef('$1->data[$1->len-1]', [rdLoc(a)]);
   genAssignment(p, dest, b, {@set}[needToCopy]);
   freeTemp(p, a);
   freeTemp(p, b)
@@ -1082,22 +1101,20 @@ var
   a, b: TLoc;
   reftype, bt: PType;
 begin
-  useMagic('newObj');
-  refType := skipAbstract(e.sons[1].typ);
-  if refType.kind = tyVar then refType := skipAbstract(refType.sons[0]);
+  useMagic(p.module, 'newObj');
+  refType := skipVarGenericRange(e.sons[1].typ);
   a := InitLocExpr(p, e.sons[1]);
-  b := initLoc(locExpr, a.t);
-  b.flags := {@set}[lfOnHeap];
-  b.r := ropeFormat('($1) newObj($2, sizeof($3))',
-    [getTypeDesc(reftype), genTypeInfo(currMod, refType),
-    getTypeDesc(skipAbstract(reftype.sons[0]))]);
+  b := initLoc(locExpr, a.t, OnHeap);
+  b.r := ropef('($1) newObj($2, sizeof($3))',
+    [getTypeDesc(p.module, reftype), genTypeInfo(p.module, refType),
+    getTypeDesc(p.module, skipGenericRange(reftype.sons[0]))]);
   genAssignment(p, a, b, {@set}[]);
   // set the object type:
-  bt := skipAbstract(refType.sons[0]);
+  bt := skipGenericRange(refType.sons[0]);
   if containsObject(bt) then begin
-    useMagic('objectInit');
-    appRopeFormat(p.s[cpsStmts], 'objectInit($1, $2);$n',
-                  [rdLoc(a), genTypeInfo(currMod, bt)])
+    useMagic(p.module, 'objectInit');
+    appf(p.s[cpsStmts], 'objectInit($1, $2);$n',
+        [rdLoc(a), genTypeInfo(p.module, bt)])
   end;
   freeTemp(p, a)
 end;
@@ -1108,26 +1125,24 @@ var
   refType, bt: PType;
   ti: PRope;
 begin
-  useMagic('newObj');
-  refType := skipAbstract(e.sons[1].typ);
-  if refType.kind = tyVar then refType := skipAbstract(refType.sons[0]);
+  useMagic(p.module, 'newObj');
+  refType := skipVarGenericRange(e.sons[1].typ);
   a := InitLocExpr(p, e.sons[1]);
   f := InitLocExpr(p, e.sons[2]);
-  b := initLoc(locExpr, a.t);
-  b.flags := {@set}[lfOnHeap];
-  ti := genTypeInfo(currMod, refType);
-  appRopeFormat(currMod.s[cfsTypeInit3], '$1->finalizer = (void*)$2;$n', [
+  b := initLoc(locExpr, a.t, OnHeap);
+  ti := genTypeInfo(p.module, refType);
+  appf(p.module.s[cfsTypeInit3], '$1->finalizer = (void*)$2;$n', [
     ti, rdLoc(f)]);
-  b.r := ropeFormat('($1) newObj($2, sizeof($3))',
-                   [getTypeDesc(refType), ti,
-                    getTypeDesc(skipAbstract(reftype.sons[0]))]);
+  b.r := ropef('($1) newObj($2, sizeof($3))',
+                   [getTypeDesc(p.module, refType), ti,
+                    getTypeDesc(p.module, skipGenericRange(reftype.sons[0]))]);
   genAssignment(p, a, b, {@set}[]);
   // set the object type:
-  bt := skipAbstract(refType.sons[0]);
+  bt := skipGenericRange(refType.sons[0]);
   if containsObject(bt) then begin
-    useMagic('objectInit');
-    appRopeFormat(p.s[cpsStmts], 'objectInit($1, $2);$n',
-                  [rdLoc(a), genTypeInfo(currMod, bt)])
+    useMagic(p.module, 'objectInit');
+    appf(p.s[cpsStmts], 'objectInit($1, $2);$n',
+                  [rdLoc(a), genTypeInfo(p.module, bt)])
   end;
   freeTemp(p, a);
   freeTemp(p, f)
@@ -1139,67 +1154,92 @@ var
   t: PType;
 begin
   a := InitLocExpr(p, e.sons[1]);
-  t := skipAbstract(e.sons[1].typ);
+  t := skipVarGenericRange(e.sons[1].typ);
   case t.kind of
     tyInt..tyInt64: begin
-      UseMagic('reprInt');
-      putIntoDest(p, d, e.typ, ropeFormat('reprInt($1)', [rdLoc(a)]))
+      UseMagic(p.module, 'reprInt');
+      putIntoDest(p, d, e.typ, ropef('reprInt($1)', [rdLoc(a)]))
     end;
     tyFloat..tyFloat128: begin
-      UseMagic('reprFloat');
-      putIntoDest(p, d, e.typ, ropeFormat('reprFloat($1)', [rdLoc(a)]))
+      UseMagic(p.module, 'reprFloat');
+      putIntoDest(p, d, e.typ, ropef('reprFloat($1)', [rdLoc(a)]))
     end;
     tyBool: begin
-      UseMagic('reprBool');
-      putIntoDest(p, d, e.typ, ropeFormat('reprBool($1)', [rdLoc(a)]))
+      UseMagic(p.module, 'reprBool');
+      putIntoDest(p, d, e.typ, ropef('reprBool($1)', [rdLoc(a)]))
     end;
     tyChar: begin
-      UseMagic('reprChar');
-      putIntoDest(p, d, e.typ, ropeFormat('reprChar($1)', [rdLoc(a)]))
+      UseMagic(p.module, 'reprChar');
+      putIntoDest(p, d, e.typ, ropef('reprChar($1)', [rdLoc(a)]))
     end;
     tyEnum: begin
-      UseMagic('reprEnum');
+      UseMagic(p.module, 'reprEnum');
       putIntoDest(p, d, e.typ,
-        ropeFormat('reprEnum($1, $2)', [rdLoc(a), genTypeInfo(currMod, t)]))
+        ropef('reprEnum($1, $2)', [rdLoc(a), genTypeInfo(p.module, t)]))
     end;
     tyString: begin
-      UseMagic('reprStr');
-      putIntoDest(p, d, e.typ, ropeFormat('reprStr($1)', [rdLoc(a)]))
+      UseMagic(p.module, 'reprStr');
+      putIntoDest(p, d, e.typ, ropef('reprStr($1)', [rdLoc(a)]))
     end;
     tySet: begin
-      useMagic('reprSet');
-      putIntoDest(p, d, e.typ, ropeFormat('reprSet($1, $2)',
-        [rdLoc(a), genTypeInfo(currMod, t)]))
+      useMagic(p.module, 'reprSet');
+      putIntoDest(p, d, e.typ, ropef('reprSet($1, $2)',
+        [rdLoc(a), genTypeInfo(p.module, t)]))
     end;
-    tyCString, tyArray, tyOpenArray, tyArrayConstr,
-       tyRef, tyPtr, tyPointer, tyNil: begin
-      useMagic('reprAny');
-      putIntoDest(p, d, e.typ, ropeFormat('reprAny($1, $2)',
-        [rdLoc(a), genTypeInfo(currMod, t)]))
+    tyOpenArray: begin
+      useMagic(p.module, 'reprOpenArray');
+      case a.t.kind of
+        tyOpenArray:
+          putIntoDest(p, d, e.typ, ropef('$1, $1Len0', [rdLoc(a)]));
+        tyString, tySequence:
+          putIntoDest(p, d, e.typ, ropef('$1->data, $1->len', [rdLoc(a)]));
+        tyArray, tyArrayConstr:
+          putIntoDest(p, d, e.typ, ropef('$1, $2',
+            [rdLoc(a), toRope(lengthOrd(a.t))]));
+        else InternalError(e.sons[0].info, 'genRepr()')
+      end;
+      putIntoDest(p, d, e.typ, ropef('reprOpenArray($1, $2)',
+        [rdLoc(d), genTypeInfo(p.module, elemType(t))]))
+    end;
+    tyCString, tyArray, tyArrayConstr,
+       tyRef, tyPtr, tyPointer, tyNil, tySequence: begin
+      useMagic(p.module, 'reprAny');
+      putIntoDest(p, d, e.typ, ropef('reprAny($1, $2)',
+        [rdLoc(a), genTypeInfo(p.module, t)]))
     end
     else begin
-      useMagic('reprAny');
-      putIntoDest(p, d, e.typ, ropeFormat('reprAny($1, $2)',
-        [addrLoc(a), genTypeInfo(currMod, t)]))
+      useMagic(p.module, 'reprAny');
+      putIntoDest(p, d, e.typ, ropef('reprAny($1, $2)',
+        [addrLoc(a), genTypeInfo(p.module, t)]))
     end
   end;
   if d.k <> locExpr then
     freeTemp(p, a);
 end;
 
+procedure genDollar(p: BProc; n: PNode; var d: TLoc; const magic, frmt: string);
+var
+  a: TLoc;
+begin
+  a := InitLocExpr(p, n.sons[1]);
+  UseMagic(p.module, magic);
+  putIntoDest(p, d, n.typ, ropef(frmt, [rdLoc(a)]))
+end;
+
 procedure genArrayLen(p: BProc; e: PNode; var d: TLoc; op: TMagic);
 var
   typ: PType;
 begin
-  typ := skipAbstract(e.sons[1].Typ);
-  if typ.kind in [tyRef, tyPtr, tyVar] then
-    typ := skipAbstract(typ.sons[0]);
+  typ := skipPtrsGeneric(e.sons[1].Typ);
   case typ.kind of
-    tyOpenArray:
+    tyOpenArray: begin
+      while e.sons[1].kind = nkPassAsOpenArray do
+        e.sons[1] := e.sons[1].sons[0];
       if op = mHigh then
         unaryExpr(p, e, d, '', '($1Len0-1)')
       else
-        unaryExpr(p, e, d, '', '$1Len0');
+        unaryExpr(p, e, d, '', '$1Len0/*len*/');
+    end;
     tyString, tySequence:
       if op = mHigh then
         unaryExpr(p, e, d, '', '($1->len-1)')
@@ -1223,13 +1263,14 @@ var
   t: PType;
 begin
   assert(d.k = locNone);
-  useMagic('setLengthSeq');
+  useMagic(p.module, 'setLengthSeq');
   a := InitLocExpr(p, e.sons[1]);
   b := InitLocExpr(p, e.sons[2]);
   t := skipVarGeneric(e.sons[1].typ);
-  appRopeFormat(p.s[cpsStmts],
+  appf(p.s[cpsStmts],
     '$1 = ($3) setLengthSeq((TGenericSeq*) ($1), sizeof($4), $2);$n',
-    [rdLoc(a), rdLoc(b), getTypeDesc(t), getTypeDesc(t.sons[0])]);
+    [rdLoc(a), rdLoc(b), getTypeDesc(p.module, t),
+    getTypeDesc(p.module, t.sons[0])]);
   freeTemp(p, a);
   freeTemp(p, b)
 end;
@@ -1265,16 +1306,15 @@ begin
   result := rdCharLoc(a);
   assert(setType.kind = tySet);
   if (firstOrd(setType) <> 0) then
-    result := ropeFormat('($1-$2)', [result, toRope(firstOrd(setType))])
+    result := ropef('($1-$2)', [result, toRope(firstOrd(setType))])
 end;
 
 function fewCmps(s: PNode): bool;
 // this function estimates whether it is better to emit code
 // for constructing the set or generating a bunch of comparisons directly
 begin
-  assert(s.kind in [nkSetConstr, nkConstSetConstr]);
-  if (getSize(s.typ) <= platform.intSize) and
-      (s.kind = nkConstSetConstr) then
+  if s.kind <> nkCurly then InternalError(s.info, 'fewCmps');
+  if (getSize(s.typ) <= platform.intSize) and (nfAllConst in s.flags) then
     result := false      // it is better to emit the set generation code
   else if elemType(s.typ).Kind in [tyInt, tyInt16..tyInt64] then
     result := true       // better not emit the set if int is basetype!
@@ -1282,21 +1322,27 @@ begin
     result := sonsLen(s) <= 8 // 8 seems to be a good value
 end;
 
-procedure binaryExprIn(p: BProc; e: PNode; var d: TLoc; const frmt: string);
-var
-  a, b: TLoc;
+procedure binaryExprIn(p: BProc; e: PNode; var a, b, d: TLoc;
+                       const frmt: string);
 begin
-  assert(e.sons[1].typ <> nil);
-  assert(e.sons[2].typ <> nil);
-  a := InitLocExpr(p, e.sons[1]);
-  b := InitLocExpr(p, e.sons[2]);
-  putIntoDest(p, d, e.typ, ropeFormat(frmt, [rdLoc(a), rdSetElemLoc(b, a.t)]));
+  putIntoDest(p, d, e.typ, ropef(frmt, [rdLoc(a), rdSetElemLoc(b, a.t)]));
   if d.k <> locExpr then begin
     freeTemp(p, a);
     freeTemp(p, b)
   end
 end;
 
+procedure genInExprAux(p: BProc; e: PNode; var a, b, d: TLoc);
+begin
+  case int(getSize(skipVarGeneric(e.sons[1].typ))) of
+    1: binaryExprIn(p, e, a, b, d, '(($1 &(1<<(($2)&7)))!=0)');
+    2: binaryExprIn(p, e, a, b, d, '(($1 &(1<<(($2)&15)))!=0)');
+    4: binaryExprIn(p, e, a, b, d, '(($1 &(1<<(($2)&31)))!=0)');
+    8: binaryExprIn(p, e, a, b, d, '(($1 &(IL64(1)<<(($2)&IL64(63))))!=0)');
+    else binaryExprIn(p, e, a, b, d, '(($1[$2/8] &(1<<($2%8)))!=0)');
+  end
+end;
+
 procedure binaryStmtInExcl(p: BProc; e: PNode; var d: TLoc; const frmt: string);
 var
   a, b: TLoc;
@@ -1304,7 +1350,7 @@ begin
   assert(d.k = locNone);
   a := InitLocExpr(p, e.sons[1]);
   b := InitLocExpr(p, e.sons[2]);
-  appRopeFormat(p.s[cpsStmts], frmt, [rdLoc(a), rdSetElemLoc(b, a.t)]);
+  appf(p.s[cpsStmts], frmt, [rdLoc(a), rdSetElemLoc(b, a.t)]);
   freeTemp(p, a);
   freeTemp(p, b)
 end;
@@ -1315,25 +1361,26 @@ var
   c: array of TLoc;  // Generate code for the 'in' operator
   len, i: int;
 begin
-  if (e.sons[1].Kind = nkSetConstr) and fewCmps(e.sons[1]) then begin
+  if (e.sons[1].Kind = nkCurly) and fewCmps(e.sons[1]) then begin
     // a set constructor but not a constant set:
     // do not emit the set, but generate a bunch of comparisons
     a := initLocExpr(p, e.sons[2]);
-    b := initLoc(locExpr, e.typ);
+    b := initLoc(locExpr, e.typ, OnUnknown);
     b.r := toRope('('+'');
     len := sonsLen(e.sons[1]);
+    {@emit c := [];}
     for i := 0 to len-1 do begin
       if e.sons[1].sons[i].Kind = nkRange then begin
         setLength(c, length(c)+2);
         c[high(c)-1] := InitLocExpr(p, e.sons[1].sons[i].sons[0]);
         c[high(c)] := InitLocExpr(p, e.sons[1].sons[i].sons[1]);
-        appRopeFormat(b.r, '$1 >= $2 && $1 <= $3',
+        appf(b.r, '$1 >= $2 && $1 <= $3',
           [rdCharLoc(a), rdCharLoc(c[high(c)-1]), rdCharLoc(c[high(c)])])
       end
       else begin
         setLength(c, length(c)+1);
         c[high(c)] := InitLocExpr(p, e.sons[1].sons[i]);
-        appRopeFormat(b.r, '$1 == $2', [rdCharLoc(a), rdCharLoc(c[high(c)])])
+        appf(b.r, '$1 == $2', [rdCharLoc(a), rdCharLoc(c[high(c)])])
       end;
       if i < len - 1 then
         app(b.r, ' || ')
@@ -1346,13 +1393,11 @@ begin
     end
   end
   else begin
-    case int(getSize(skipVarGeneric(e.sons[1].typ))) of
-      1: binaryExprIn(p, e, d, '(($1 &(1<<(($2)&7)))!=0)');
-      2: binaryExprIn(p, e, d, '(($1 &(1<<(($2)&15)))!=0)');
-      4: binaryExprIn(p, e, d, '(($1 &(1<<(($2)&31)))!=0)');
-      8: binaryExprIn(p, e, d, '(($1 &(1<<(($2)&63)))!=0)');
-      else binaryExprIn(p, e, d, '(($1[$2/8] &(1<<($2%8)))!=0)');
-    end
+    assert(e.sons[1].typ <> nil);
+    assert(e.sons[2].typ <> nil);
+    a := InitLocExpr(p, e.sons[1]);
+    b := InitLocExpr(p, e.sons[2]);
+    genInExprAux(p, e, a, b, d);
   end
 end;
 
@@ -1373,20 +1418,19 @@ var
   a, b, i: TLoc;
   ts: string;
 begin
-  setType := e.sons[1].Typ;
-  if setType.kind = tyVar then setType := skipAbstract(setType.sons[0]);
+  setType := skipVarGeneric(e.sons[1].Typ);
   size := int(getSize(setType));
   case size of
     1, 2, 4, 8: begin
       case op of
         mIncl: begin
-          ts := 'NS' + toString(size*8);
+          ts := 'NI' + toString(size*8);
           binaryStmtInExcl(p, e, d,
-            '$1 |=(1<<((' +{&} ts +{&} ')($2)%(sizeof(' +{&} ts +{&} 
+            '$1 |=(1<<((' +{&} ts +{&} ')($2)%(sizeof(' +{&} ts +{&}
             ')*8)));$n');
         end;
         mExcl: begin
-          ts := 'NS' + toString(size*8);
+          ts := 'NI' + toString(size*8);
           binaryStmtInExcl(p, e, d,
             '$1 &= ~(1 << ((' +{&} ts +{&} ')($2) % (sizeof(' +{&} ts +{&}
             ')*8)));$n');
@@ -1420,7 +1464,7 @@ begin
           b := initLocExpr(p, e.sons[2]);
           if d.k = locNone then
             d := getTemp(p, a.t);
-          appRopeFormat(p.s[cpsStmts], lookupOpr[op], [rdLoc(i), toRope(size),
+          appf(p.s[cpsStmts], lookupOpr[op], [rdLoc(i), toRope(size),
             rdLoc(d), rdLoc(a), rdLoc(b)]);
           freeTemp(p, a);
           freeTemp(p, b);
@@ -1436,7 +1480,7 @@ begin
           b := initLocExpr(p, e.sons[2]);
           if d.k = locNone then
             d := getTemp(p, a.t);
-          appRopeFormat(p.s[cpsStmts],
+          appf(p.s[cpsStmts],
             'for ($1 = 0; $1 < $2; $1++) $n' +
             '  $3[$1] = $4[$1] $6 $5[$1];$n', [rdLoc(i), toRope(size),
             rdLoc(d), rdLoc(a), rdLoc(b), toRope(lookupOpr[op])]);
@@ -1453,6 +1497,98 @@ end;
 
 // --------------------- end of set operations ----------------------------
 
+procedure genOrd(p: BProc; e: PNode; var d: TLoc);
+begin
+  unaryExprChar(p, e, d, '', '$1');
+end;
+
+procedure genCast(p: BProc; e: PNode; var d: TLoc);
+const
+  ValueTypes = {@set}[tyTuple, tyObject, tyArray, tyOpenArray, tyArrayConstr];
+// we use whatever C gives us. Except if we have a value-type, we
+// need to go through its address:
+var
+  a: TLoc;
+begin
+  a := InitLocExpr(p, e.sons[1]);
+  if (skipGenericRange(e.typ).kind in ValueTypes)
+  and not (lfIndirect in a.flags) then
+    putIntoDest(p, d, e.typ, ropef('(*($1*) ($2))',
+      [getTypeDesc(p.module, e.typ), addrLoc(a)]))
+  else
+    putIntoDest(p, d, e.typ, ropef('(($1) ($2))',
+      [getTypeDesc(p.module, e.typ), rdCharLoc(a)]));
+  if d.k <> locExpr then freeTemp(p, a)
+end;
+
+procedure genRangeChck(p: BProc; n: PNode; var d: TLoc; const magic: string);
+var
+  a: TLoc;
+  dest: PType;
+begin
+  dest := skipVarGeneric(n.typ);
+  if not (optRangeCheck in p.options) then begin
+    a := InitLocExpr(p, n.sons[0]);
+    putIntoDest(p, d, n.typ, ropef('(($1) ($2))',
+      [getTypeDesc(p.module, dest), rdCharLoc(a)]));
+  end
+  else begin
+    a := InitLocExpr(p, n.sons[0]);
+    useMagic(p.module, magic);
+    putIntoDest(p, d, dest,
+      ropef('(($1)' +{&} magic +{&} '($2, $3, $4))',
+        [getTypeDesc(p.module, dest),
+         rdCharLoc(a), genLiteral(p, n.sons[1], dest),
+                       genLiteral(p, n.sons[2], dest)]));
+    if d.k <> locExpr then freeTemp(p, a)
+  end
+end;
+
+procedure genConv(p: BProc; e: PNode; var d: TLoc);
+begin
+  genCast(p, e, d)
+end;
+
+procedure passToOpenArray(p: BProc; n: PNode; var d: TLoc);
+var
+  a: TLoc;
+  dest: PType;
+begin
+  dest := skipVarGeneric(n.typ);
+  a := initLocExpr(p, n.sons[0]);
+  case a.t.kind of
+    tyOpenArray:
+      putIntoDest(p, d, dest, ropef('$1, $1Len0', [rdLoc(a)]));
+    tyString, tySequence:
+      putIntoDest(p, d, dest, ropef('$1->data, $1->len', [rdLoc(a)]));
+    tyArray, tyArrayConstr:
+      putIntoDest(p, d, dest, ropef('$1, $2',
+        [rdLoc(a), toRope(lengthOrd(a.t))]));
+    else InternalError(n.sons[0].info, 'passToOpenArray()')
+  end;
+  if d.k <> locExpr then freeTemp(p, a)
+end;
+
+procedure convStrToCStr(p: BProc; n: PNode; var d: TLoc);
+var
+  a: TLoc;
+begin
+  a := initLocExpr(p, n.sons[0]);
+  putIntoDest(p, d, skipVarGeneric(n.typ), ropef('$1->data', [rdLoc(a)]));
+  if d.k <> locExpr then freeTemp(p, a)
+end;
+
+procedure convCStrToStr(p: BProc; n: PNode; var d: TLoc);
+var
+  a: TLoc;
+begin
+  useMagic(p.module, 'cstrToNimstr');
+  a := initLocExpr(p, n.sons[0]);
+  putIntoDest(p, d, skipVarGeneric(n.typ),
+              ropef('cstrToNimstr($1)', [rdLoc(a)]));
+  if d.k <> locExpr then freeTemp(p, a)
+end;
+
 procedure genMagicExpr(p: BProc; e: PNode; var d: TLoc; op: TMagic);
 var
   a: TLoc;
@@ -1491,13 +1627,21 @@ begin
     mEqStr: binaryExpr(p, e, d, 'eqStrings', 'eqStrings($1, $2)');
     mLeStr: binaryExpr(p, e, d, 'cmpStrings', '(cmpStrings($1, $2) <= 0)');
     mLtStr: binaryExpr(p, e, d, 'cmpStrings', '(cmpStrings($1, $2) < 0)');
+    mIsNil: unaryExpr(p, e, d, '', '$1 == 0');
+    mIntToStr: genDollar(p, e, d, 'nimIntToStr', 'nimIntToStr($1)');
+    mInt64ToStr: genDollar(p, e, d, 'nimInt64ToStr', 'nimInt64ToStr($1)');
+    mBoolToStr: genDollar(p, e, d, 'nimBoolToStr', 'nimBoolToStr($1)');
+    mCharToStr: genDollar(p, e, d, 'nimCharToStr', 'nimCharToStr($1)');
+    mFloatToStr: genDollar(p, e, d, 'nimFloatToStr', 'nimFloatToStr($1)');
+    mCStrToStr: genDollar(p, e, d, 'cstrToNimstr', 'cstrToNimstr($1)');
+    mStrToStr: expr(p, e.sons[1], d);
     mAssert: begin
       if (optAssert in p.Options) then begin
-        useMagic('internalAssert');
+        useMagic(p.module, 'internalAssert');
         expr(p, e.sons[1], d);
         line := toRope(toLinenumber(e.info));
         filen := makeCString(ToFilename(e.info));
-        appRopeFormat(p.s[cpsStmts], 'internalAssert($1, $2, $3);$n',
+        appf(p.s[cpsStmts], 'internalAssert($1, $2, $3);$n',
                       [filen, line, rdLoc(d)])
       end
     end;
@@ -1505,23 +1649,24 @@ begin
     mNewFinalize: genNewFinalize(p, e);
     mSizeOf:
       putIntoDest(p, d, e.typ,
-        ropeFormat('sizeof($1)', [getTypeDesc(e.sons[1].typ)]));
-    mChr: expr(p, e.sons[1], d);
-    mOrd:
-      // ord only allows things that are allowed in C anyway, so generate
-      // no code for it:
-      expr(p, e.sons[1], d);
+        ropef('sizeof($1)', [getTypeDesc(p.module, e.sons[1].typ)]));
+    mChr: genCast(p, e, d); // expr(p, e.sons[1], d);
+    mOrd: genOrd(p, e, d);
     mLengthArray, mHigh, mLengthStr, mLengthSeq, mLengthOpenArray:
       genArrayLen(p, e, d, op);
     mInc: begin
       if not (optOverflowCheck in p.Options) then
         binaryStmt(p, e, d, '', '$1 += $2;$n')
+      else if skipVarGeneric(e.sons[1].typ).kind = tyInt64 then
+        binaryStmt(p, e, d, 'addInt64', '$1 = addInt64($1, $2);$n')
       else
         binaryStmt(p, e, d, 'addInt', '$1 = addInt($1, $2);$n')
     end;
     ast.mDec: begin
       if not (optOverflowCheck in p.Options) then
         binaryStmt(p, e, d, '', '$1 -= $2;$n')
+      else if skipVarGeneric(e.sons[1].typ).kind = tyInt64 then
+        binaryStmt(p, e, d, 'subInt64', '$1 = subInt64($1, $2);$n')
       else
         binaryStmt(p, e, d, 'subInt', '$1 = subInt($1, $2);$n')
     end;
@@ -1530,6 +1675,8 @@ begin
     mIncl, mExcl, mCard, mLtSet, mLeSet, mEqSet, mMulSet, mPlusSet,
     mMinusSet, mInSet: genSetOp(p, e, d, op);
     mExit: genCall(p, e, d);
+    mNLen..mNError:
+      liMessage(e.info, errCannotGenerateCodeForX, e.sons[0].sym.name.s);
     else internalError(e.info, 'genMagicExpr: ' + magicToStr[op]);
   end
 end;
@@ -1544,18 +1691,18 @@ var
   i: int;
   ts: string;
 begin
-  if e.kind = nkConstSetConstr then
+  if nfAllConst in e.flags then
     putIntoDest(p, d, e.typ, genSetNode(p, e))
   else begin
     if d.k = locNone then d := getTemp(p, e.typ);
     if getSize(e.typ) > 8 then begin // big set:
-      appRopeFormat(p.s[cpsStmts], 'memset($1, 0, sizeof($1));$n', [rdLoc(d)]);
+      appf(p.s[cpsStmts], 'memset($1, 0, sizeof($1));$n', [rdLoc(d)]);
       for i := 0 to sonsLen(e)-1 do begin
         if e.sons[i].kind = nkRange then begin
           idx := getTemp(p, getSysType(tyInt)); // our counter
           a := initLocExpr(p, e.sons[i].sons[1]);
           b := initLocExpr(p, e.sons[i].sons[2]);
-          appRopeFormat(p.s[cpsStmts],
+          appf(p.s[cpsStmts],
             'for ($1 = $3; $1 <= $4; $1++) $n' +
             '$2[$1/8] |=(1<<($1%8));$n',
             [rdLoc(idx), rdLoc(d), rdSetElemLoc(a, e.typ),
@@ -1566,21 +1713,21 @@ begin
         end
         else begin
           a := initLocExpr(p, e.sons[i]);
-          appRopeFormat(p.s[cpsStmts], '$1[$2/8] |=(1<<($2%8));$n',
+          appf(p.s[cpsStmts], '$1[$2/8] |=(1<<($2%8));$n',
                        [rdLoc(d), rdSetElemLoc(a, e.typ)]);
           freeTemp(p, a)
         end
       end
     end
     else begin // small set
-      ts := 'NS' + toString(getSize(e.typ)*8);
-      appRopeFormat(p.s[cpsStmts], '$1 = 0;$n', [rdLoc(d)]);
+      ts := 'NI' + toString(getSize(e.typ)*8);
+      appf(p.s[cpsStmts], '$1 = 0;$n', [rdLoc(d)]);
       for i := 0 to sonsLen(e) - 1 do begin
         if e.sons[i].kind = nkRange then begin
           idx := getTemp(p, getSysType(tyInt)); // our counter
           a := initLocExpr(p, e.sons[i].sons[1]);
           b := initLocExpr(p, e.sons[i].sons[2]);
-          appRopeFormat(p.s[cpsStmts],
+          appf(p.s[cpsStmts],
             'for ($1 = $3; $1 <= $4; $1++) $n' +{&}
             '$2 |=(1<<((' +{&} ts +{&} ')($1)%(sizeof(' +{&}ts+{&}')*8)));$n',
             [rdLoc(idx), rdLoc(d), rdSetElemLoc(a, e.typ),
@@ -1591,7 +1738,7 @@ begin
         end
         else begin
           a := initLocExpr(p, e.sons[i]);
-          appRopeFormat(p.s[cpsStmts],
+          appf(p.s[cpsStmts],
                         '$1 |=(1<<((' +{&} ts +{&} ')($2)%(sizeof(' +{&}ts+{&}
                         ')*8)));$n',
                         [rdLoc(d), rdSetElemLoc(a, e.typ)]);
@@ -1602,38 +1749,42 @@ begin
   end
 end;
 
-procedure genRecordConstr(p: BProc; t: PNode; var d: TLoc);
+procedure genTupleConstr(p: BProc; n: PNode; var d: TLoc);
 var
-  i, len: int;
+  i: int;
   rec: TLoc;
+  it: PNode;
+  t: PType;
 begin
-  {@discard} getTypeDesc(t.typ); // so that any fields are initialized
-  if d.k = locNone then
-    d := getTemp(p, t.typ);
-  i := 0;
-  len := sonsLen(t);
-  while i < len do begin
-    rec := initLoc(locExpr, t.sons[i].typ);
-    assert(t.sons[i].sym.loc.r <> nil);
-    rec.r := ropeFormat('$1.$2', [rdLoc(d), t.sons[i].sym.loc.r]);
-    inheritStorage(rec, d);
-    expr(p, t.sons[i+1], rec);
-    inc(i, 2)
+  // the code generator assumes that there are only tuple constructors with
+  // field names!
+  t := getUniqueType(n.typ);
+  {@discard} getTypeDesc(p.module, t); // so that any fields are initialized
+  if d.k = locNone then d := getTemp(p, t);
+  if t.n = nil then InternalError(n.info, 'genTupleConstr');
+  if sonsLen(t.n) <> sonsLen(n) then
+    InternalError(n.info, 'genTupleConstr');
+  for i := 0 to sonsLen(n)-1 do begin
+    it := n.sons[i];
+    if it.kind <> nkExprColonExpr then InternalError(n.info, 'genTupleConstr');
+    rec := initLoc(locExpr, it.sons[1].typ, d.s);
+    if (t.n.sons[i].kind <> nkSym) then
+      InternalError(n.info, 'genTupleConstr');
+    rec.r := ropef('$1.$2', [rdLoc(d), mangleRecFieldName(t.n.sons[i].sym, t)]);
+    expr(p, it.sons[1], rec);
   end
 end;
 
-procedure genArrayConstr(p: BProc; t: PNode; var d: TLoc);
+procedure genArrayConstr(p: BProc; n: PNode; var d: TLoc);
 var
   arr: TLoc;
   i: int;
 begin
-  if d.k = locNone then
-    d := getTemp(p, t.typ);
-  for i := 0 to sonsLen(t)-1 do begin
-    arr := initLoc(locExpr, elemType(skipGeneric(t.typ)));
-    arr.r := ropeFormat('$1[$2]', [rdLoc(d), intLiteral(i)]);
-    inheritStorage(arr, d);
-    expr(p, t.sons[i], arr)
+  if d.k = locNone then d := getTemp(p, n.typ);
+  for i := 0 to sonsLen(n)-1 do begin
+    arr := initLoc(locExpr, elemType(skipGeneric(n.typ)), d.s);
+    arr.r := ropef('$1[$2]', [rdLoc(d), intLiteral(i)]);
+    expr(p, n.sons[i], arr)
   end
 end;
 
@@ -1642,157 +1793,27 @@ var
   newSeq, arr: TLoc;
   i: int;
 begin
-  useMagic('newSeq');
+  useMagic(p.module, 'newSeq');
   if d.k = locNone then
     d := getTemp(p, t.typ);
   // generate call to newSeq before adding the elements per hand:
 
-  newSeq := initLoc(locExpr, t.typ);
-  newSeq.r := ropeFormat('($1) newSeq($2, $3)',
-    [getTypeDesc(t.typ), genTypeInfo(currMod, t.typ), toRope(sonsLen(t))]);
+  newSeq := initLoc(locExpr, t.typ, OnHeap);
+  newSeq.r := ropef('($1) newSeq($2, $3)',
+    [getTypeDesc(p.module, t.typ),
+    genTypeInfo(p.module, t.typ), toRope(sonsLen(t))]);
   genAssignment(p, d, newSeq, {@set}[]);
   for i := 0 to sonsLen(t)-1 do begin
-    arr := initLoc(locExpr, elemType(skipGeneric(t.typ)));
-    arr.r := ropeFormat('$1->data[$2]', [rdLoc(d), intLiteral(i)]);
-    arr.flags := {@set}[lfOnHeap]; // we know that sequences are on the heap
+    arr := initLoc(locExpr, elemType(skipGeneric(t.typ)), OnHeap);
+    arr.r := ropef('$1->data[$2]', [rdLoc(d), intLiteral(i)]);
+    arr.s := OnHeap; // we know that sequences are on the heap
     expr(p, t.sons[i], arr)
   end
 end;
 
-procedure genCast(p: BProc; e: PNode; var d: TLoc);
-const
-  ValueTypes = {@set}[tyRecord, tyObject, tyArray, tyOpenArray, tyArrayConstr];
-// we use whatever C gives us. Except if we have a value-type, we
-// need to go through its address:
-var
-  a: TLoc;
-begin
-  a := InitLocExpr(p, e.sons[0]);
-  if (skipAbstract(e.typ).kind in ValueTypes) and (a.indirect = 0) then
-    putIntoDest(p, d, e.typ, ropeFormat('(*($1*) ($2))',
-      [getTypeDesc(e.typ), addrLoc(a)]))
-  else
-    putIntoDest(p, d, e.typ, ropeFormat('(($1) ($2))',
-      [getTypeDesc(e.typ), rdCharLoc(a)]));
-  if d.k <> locExpr then
-    freeTemp(p, a)
-end;
-
-procedure genConv(p: BProc; e: PNode; var d: TLoc);
-  // type conversion: it doesn't matter if implicit or explicit;
-  // type conversions are not casts!
-var
-  a: TLoc;
-  r: PRope;
-  source, dest: PType;
-begin
-  // numeric types need range checks:
-  dest := skipVarGeneric(e.typ);
-  case dest.kind of
-    tyRange, tyInt..tyInt64, tyEnum, tyChar, tyBool: begin
-      if not (optRangeCheck in p.options) or
-          (firstOrd(dest) <= firstOrd(skipVarGeneric(e.sons[0].typ))) and // first >= x
-           (lastOrd(skipVarGeneric(e.sons[0].typ)) <= lastOrd(dest)) then // x <= last
-        expr(p, e.sons[0], d) // no need for a range check
-      else begin // generate a range check:
-        a := InitLocExpr(p, e.sons[0]);
-        if    (a.t.kind in [tyFloat..tyFloat128]) or
-             (dest.kind in [tyFloat..tyFloat128]) then begin
-          useMagic('chckRangeF');
-          putIntoDest(p, d, dest, ropeFormat('chckRangeF($1, $2, $3)',
-            [rdCharLoc(a), genLiteral(p, dest.n.sons[0], dest),
-                           genLiteral(p, dest.n.sons[1], dest)]))
-        end
-        else if (a.t.kind = tyInt64) or (dest.kind = tyInt64) then begin
-          useMagic('chckRange64');
-          putIntoDest(p, d, dest, ropeFormat('chckRange64($1, $2, $3)',
-            [rdCharLoc(a), intLiteral(firstOrd(dest)),
-                           intLiteral(lastOrd(dest))]))
-        end
-        else begin
-          useMagic('chckRange');
-          putIntoDest(p, d, dest, ropeFormat('chckRange($1, $2, $3)',
-            [rdCharLoc(a), intLiteral(firstOrd(dest)),
-                           intLiteral(lastOrd(dest))]))
-        end;
-        if d.k <> locExpr then
-          freeTemp(p, a)
-      end
-    end;
-    // open arrays need implicit length passed:
-    tyOpenArray: begin
-      a := initLocExpr(p, e.sons[0]);
-      case a.t.kind of
-        tyOpenArray:
-          putIntoDest(p, d, dest, ropeFormat('$1, $1Len0', [rdLoc(a)]));
-        tyString, tySequence:
-          putIntoDest(p, d, dest, ropeFormat('$1->data, $1->len', [rdLoc(a)]));
-        tyArray, tyArrayConstr:
-          putIntoDest(p, d, dest, ropeFormat('$1, $2',
-            [rdLoc(a), toRope(lengthOrd(a.t))]));
-        else InternalError(e.sons[0].info, 'genConv()')
-      end;
-      if d.k <> locExpr then freeTemp(p, a)
-    end;
-    // conversions from string to cstring:
-    tyCString: begin
-      if skipVarGeneric(e.sons[0].typ).kind = tyString then begin
-        a := initLocExpr(p, e.sons[0]);
-        putIntoDest(p, d, e.typ, ropeFormat('$1->data', [rdLoc(a)]));
-        if d.k <> locExpr then freeTemp(p, a)
-      end
-      else if not isCompatibleToCString(e.sons[0].typ) then
-        // ordinary type cast:
-        genCast(p, e, d)
-      else
-        expr(p, e.sons[0], d) // BUGFIX!
-    end;
-    // conversions from cstring to string:
-    tyString: begin
-      if skipVarGeneric(e.sons[0].typ).kind = tyCString then begin
-        useMagic('cstrToNimstr');
-        a := initLocExpr(p, e.sons[0]);
-        putIntoDest(p, d, dest, ropeFormat('cstrToNimstr($1)', [rdLoc(a)]));
-        if d.k <> locExpr then freeTemp(p, a)
-      end
-      else // ordinary type cast:
-        genCast(p, e, d)
-    end;
-    // conversions between different object types:
-    tyObject: begin
-      source := skipVarGeneric(e.sons[0].typ);
-      // if source is a subtype of dest, downcast:
-      a := initLocExpr(p, e.sons[0]);
-      r := rdLoc(a);
-      while source.sons[0] <> nil do begin
-        source := source.sons[0];
-        if gCmd <> cmdCompileToCpp then
-          app(r, '.Sup');
-        if source.id = dest.id then break
-      end;
-      if source.id = dest.id then // we really have a downcast here:
-        if gCmd = cmdCompileToCpp then
-          putLocIntoDest(p, d, a) // downcast does C++ for us
-        else
-          putIntoDest(p, d, dest, r)
-      else if gCmd = cmdCompileToCpp then
-        genCast(p, e, d) // discard ``a``
-      else // upcasts are uglier in C
-        putIntoDest(p, d, dest, ropeFormat('(*($1*) ($2))',
-          [getTypeDesc(dest), addrLoc(a)]));
-      if d.k <> locExpr then freeTemp(p, a)
-    end;
-    tyGenericParam, tyAnyEnum:
-      expr(p, e.sons[0], d);
-      // happens sometimes for generated assignments, etc.
-    else // use an ordinary cast
-      genCast(p, e, d)
-  end
-end;
-
 procedure genComplexConst(p: BProc; sym: PSym; var d: TLoc);
 begin
-  genConstPrototype(sym);
+  genConstPrototype(p.module, sym);
   assert((sym.loc.r <> nil) and (sym.loc.t <> nil));
   putLocIntoDest(p, d, sym.loc)
 end;
@@ -1806,68 +1827,83 @@ begin
   if len > 0 then expr(p, n.sons[len-1], d);
 end;
 
+procedure upConv(p: BProc; n: PNode; var d: TLoc);
+var
+  a: TLoc;
+  dest, t: PType;
+  r, nilCheck: PRope;
+begin
+  a := initLocExpr(p, n.sons[0]);
+  dest := skipPtrsGeneric(n.typ);
+  if (optObjCheck in p.options) and not (isPureObject(dest)) then begin
+    useMagic(p.module, 'chckObj');
+    r := rdLoc(a);
+    nilCheck := nil;
+    t := skipGeneric(a.t);
+    while t.kind in [tyVar, tyPtr, tyRef] do begin
+      if t.kind <> tyVar then nilCheck := r;
+      r := ropef('(*$1)', [r]);
+      t := skipGeneric(t.sons[0])
+    end;
+    if gCmd <> cmdCompileToCpp then
+      while (t.kind = tyObject) and (t.sons[0] <> nil) do begin
+        app(r, '.Sup');
+        t := skipGeneric(t.sons[0]);
+      end;
+    if nilCheck <> nil then
+      appf(p.s[cpsStmts], 'if ($1) chckObj($2.m_type, $3);$n',
+        [nilCheck, r, genTypeInfo(p.module, dest)])
+    else
+      appf(p.s[cpsStmts], 'chckObj($1.m_type, $2);$n',
+        [r, genTypeInfo(p.module, dest)]);
+  end;
+  if n.sons[0].typ.kind <> tyObject then
+    putIntoDest(p, d, n.typ, ropef('(($1) ($2))',
+      [getTypeDesc(p.module, n.typ), rdLoc(a)]))
+  else
+    putIntoDest(p, d, n.typ, ropef('(*($1*) ($2))',
+      [getTypeDesc(p.module, dest), addrLoc(a)]));
+end;
+
+procedure downConv(p: BProc; n: PNode; var d: TLoc);
+var
+  a: TLoc;
+  dest, src: PType;
+  i: int;
+  r: PRope;
+begin
+  if gCmd = cmdCompileToCpp then
+    expr(p, n.sons[0], d) // downcast does C++ for us
+  else begin
+    dest := skipPtrsGeneric(n.typ);
+    src := skipPtrsGeneric(n.sons[0].typ);
+    a := initLocExpr(p, n.sons[0]);
+    r := rdLoc(a);
+    if skipGeneric(n.sons[0].typ).kind in [tyRef, tyPtr, tyVar] then begin
+      app(r, '->Sup');
+      for i := 2 to abs(inheritanceDiff(dest, src)) do app(r, '.Sup');
+      r := con('&'+'', r);
+    end
+    else
+      for i := 1 to abs(inheritanceDiff(dest, src)) do app(r, '.Sup');
+    putIntoDest(p, d, n.typ, r);
+  end
+end;
+
 procedure genBlock(p: BProc; t: PNode; var d: TLoc); forward;
 
 procedure expr(p: BProc; e: PNode; var d: TLoc);
-// do not forget that lfIndirect in d.flags may be requested!
 var
   sym: PSym;
-  a: TLoc;
   ty: PType;
 begin
   case e.kind of
-    nkQualified: expr(p, e.sons[1], d);
-    nkStrLit..nkTripleStrLit, nkIntLit..nkInt64Lit,
-    nkFloatLit..nkFloat64Lit, nkNilLit, nkCharLit, nkRCharLit: begin
-      putIntoDest(p, d, e.typ, genLiteral(p, e));
-      d.k := locImmediate // for removal of index checks
-    end;
-    nkCall, nkHiddenCallConv: begin
-      if (e.sons[0].kind = nkSym) and
-         (e.sons[0].sym.magic <> mNone) then
-        genMagicExpr(p, e, d, e.sons[0].sym.magic)
-      else
-        genCall(p, e, d)
-    end;
-    nkConstSetConstr, nkSetConstr: genSetConstr(p, e, d);
-    nkConstArrayConstr, nkArrayConstr:
-      if (skipAbstract(e.typ).kind = tySequence) then  // BUGFIX
-        genSeqConstr(p, e, d)
-      else
-        genArrayConstr(p, e, d);
-    nkConstRecordConstr, nkRecordConstr:
-      genRecordConstr(p, e, d);
-    nkCast: genCast(p, e, d);
-    nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, e, d);
-    nkAddr: begin
-      a := InitLocExpr(p, e.sons[0]);
-      putIntoDest(p, d, e.typ, addrLoc(a));
-      if d.k <> locExpr then
-        freeTemp(p, a)
-    end;
-    nkBracketExpr: begin
-      ty := skipAbstract(e.sons[0].typ);
-      if ty.kind in [tyRef, tyPtr, tyVar] then ty := skipAbstract(ty.sons[0]);
-      case ty.kind of
-        tyArray, tyArrayConstr: genArrayElem(p, e, d);
-        tyOpenArray: genOpenArrayElem(p, e, d);
-        tySequence, tyString: genSeqElem(p, e, d);
-        tyCString: genCStringElem(p, e, d);
-        else InternalError(e.info,
-               'expr(nkBracketExpr, ' + typeKindToStr[ty.kind] + ')');
-      end
-    end;
-    nkDerefExpr: genDeref(p, e, d);
-    nkDotExpr: genRecordField(p, e, d);
-    nkBlockExpr: genBlock(p, e, d);
-    nkStmtListExpr: genStmtListExpr(p, e, d);
-    nkIfExpr: genIfExpr(p, e, d);
     nkSym: begin
       sym := e.sym;
       case sym.Kind of
-        skProc: begin
+        skProc, skConverter: begin
           // generate prototype if not already declared in this translation unit
-          genProcPrototype(sym);
+          genProcPrototype(p.module, sym);
           if ((sym.loc.r = nil) or (sym.loc.t = nil)) then
             InternalError(e.info, 'expr: proc not init ' + sym.name.s);
           putLocIntoDest(p, d, sym.loc)
@@ -1879,7 +1915,7 @@ begin
             genComplexConst(p, sym, d);
         skEnumField: putIntoDest(p, d, e.typ, toRope(sym.position));
         skVar: begin
-          if (sfGlobal in sym.flags) then genVarPrototype(sym);
+          if (sfGlobal in sym.flags) then genVarPrototype(p.module, sym);
           if ((sym.loc.r = nil) or (sym.loc.t = nil)) then
             InternalError(e.info, 'expr: var not init ' + sym.name.s);
           putLocIntoDest(p, d, sym.loc);
@@ -1898,7 +1934,57 @@ begin
           InternalError(e.info, 'expr(' +{&} symKindToStr[sym.kind] +{&}
                                 '); unknown symbol')
       end
-    end
+    end;
+    nkQualified: expr(p, e.sons[1], d);
+    nkStrLit..nkTripleStrLit, nkIntLit..nkInt64Lit,
+    nkFloatLit..nkFloat64Lit, nkNilLit, nkCharLit: begin
+      putIntoDest(p, d, e.typ, genLiteral(p, e));
+      d.k := locImmediate // for removal of index checks
+    end;
+    nkCall, nkHiddenCallConv: begin
+      if (e.sons[0].kind = nkSym) and
+         (e.sons[0].sym.magic <> mNone) then
+        genMagicExpr(p, e, d, e.sons[0].sym.magic)
+      else
+        genCall(p, e, d)
+    end;
+    nkCurly: genSetConstr(p, e, d);
+    nkBracket:
+      if (skipVarGenericRange(e.typ).kind = tySequence) then  // BUGFIX
+        genSeqConstr(p, e, d)
+      else
+        genArrayConstr(p, e, d);
+    nkPar:
+      genTupleConstr(p, e, d);
+    nkCast: genCast(p, e, d);
+    nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, e, d);
+    nkHiddenAddr, nkAddr: genAddr(p, e, d);
+    nkBracketExpr: begin
+      ty := skipVarGenericRange(e.sons[0].typ);
+      if ty.kind in [tyRef, tyPtr] then ty := skipVarGenericRange(ty.sons[0]);
+      case ty.kind of
+        tyArray, tyArrayConstr: genArrayElem(p, e, d);
+        tyOpenArray: genOpenArrayElem(p, e, d);
+        tySequence, tyString: genSeqElem(p, e, d);
+        tyCString: genCStringElem(p, e, d);
+        else InternalError(e.info,
+               'expr(nkBracketExpr, ' + typeKindToStr[ty.kind] + ')');
+      end
+    end;
+    nkDerefExpr, nkHiddenDeref: genDeref(p, e, d);
+    nkDotExpr: genRecordField(p, e, d);
+    nkCheckedFieldExpr: genCheckedRecordField(p, e, d);
+    nkBlockExpr: genBlock(p, e, d);
+    nkStmtListExpr: genStmtListExpr(p, e, d);
+    nkIfExpr: genIfExpr(p, e, d);
+    nkObjDownConv: downConv(p, e, d);
+    nkObjUpConv: upConv(p, e, d);
+    nkChckRangeF: genRangeChck(p, e, d, 'chckRangeF');
+    nkChckRange64: genRangeChck(p, e, d, 'chckRange64');
+    nkChckRange: genRangeChck(p, e, d, 'chckRange');
+    nkStringToCString: convStrToCStr(p, e, d);
+    nkCStringToString: convCStrToStr(p, e, d);
+    nkPassAsOpenArray: passToOpenArray(p, e, d);
     else
       InternalError(e.info, 'expr(' +{&} nodeKindToStr[e.kind] +{&}
                             '); unknown node kind')
@@ -1915,8 +2001,8 @@ var
 begin
   result := copyNode(n);
   newSons(result, sonsLen(n));
-  t := skipAbstract(n.Typ);
-  if t.kind = tyRecordConstr then 
+  t := getUniqueType(skipVarGenericRange(n.Typ));
+  if t.n = nil then
     InternalError(n.info, 'transformRecordExpr: invalid type');
   for i := 0 to sonsLen(n)-1 do begin
     assert(n.sons[i].kind = nkExprColonExpr);
@@ -1940,7 +2026,7 @@ begin
   len := sonsLen(n);
   result := toRope('{'+'');
   for i := 0 to len - 2 do
-    app(result, ropeFormat('$1,$n', [genConstExpr(p, n.sons[i])]));
+    app(result, ropef('$1,$n', [genConstExpr(p, n.sons[i])]));
   if len > 0 then app(result, genConstExpr(p, n.sons[len-1]));
   app(result, '}' + tnl)
 end;
@@ -1951,17 +2037,19 @@ var
   cs: TBitSet;
 begin
   case n.Kind of
-    nkHiddenStdConv, nkHiddenSubConv: result := genConstExpr(p, n.sons[0]);
-    nkSetConstr, nkConstSetConstr: begin
+    nkHiddenStdConv, nkHiddenSubConv: result := genConstExpr(p, n.sons[1]);
+    nkCurly: begin
       toBitSet(n, cs);
       result := genRawSetData(cs, int(getSize(n.typ)))
+    end;
+    nkBracket: begin
       // XXX: tySequence!
+      result := genConstSimpleList(p, n);
     end;
-    nkConstArrayConstr: result := genConstSimpleList(p, n);
-    nkPar, nkConstRecordConstr, nkRecordConstr: begin
-      if hasSonWith(n, nkExprColonExpr) then 
+    nkPar: begin
+      if hasSonWith(n, nkExprColonExpr) then
         trans := transformRecordExpr(n)
-      else 
+      else
         trans := n;
       result := genConstSimpleList(p, trans);
     end