summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ast.nim3
-rw-r--r--compiler/ccgexprs.nim2
-rw-r--r--compiler/jsgen.nim4
-rw-r--r--compiler/nim.cfg1
-rw-r--r--compiler/parser.nim8
-rw-r--r--compiler/sem.nim117
-rw-r--r--compiler/semexprs.nim2
-rw-r--r--compiler/semmagic.nim43
-rw-r--r--compiler/semobjconstr.nim79
-rw-r--r--compiler/semstmts.nim11
-rw-r--r--compiler/semtypes.nim63
-rw-r--r--compiler/transf.nim8
-rw-r--r--compiler/vmgen.nim2
-rw-r--r--config/nim.cfg1
-rw-r--r--doc/grammar.txt2
-rw-r--r--lib/system.nim9
-rw-r--r--lib/system/seqs_v2.nim2
-rw-r--r--tests/config.nims1
-rw-r--r--tests/errmsgs/t5167_5.nim2
-rw-r--r--tests/js/trepr.nim2
-rw-r--r--tests/objects/mobject_default_value.nim15
-rw-r--r--tests/objects/tobject_default_value.nim429
-rw-r--r--tests/stdlib/tnetconnect.nim1
23 files changed, 727 insertions, 80 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 4174e7f34..9727cfd54 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -511,6 +511,7 @@ type
     nfFirstWrite # this node is a first write
     nfFirstWrite2 # alternative first write implementation
     nfHasComment # node has a comment
+    nfUseDefaultField # node has a default value (object constructor)
 
   TNodeFlags* = set[TNodeFlag]
   TTypeFlag* = enum   # keep below 32 for efficiency reasons (now: 45)
@@ -713,7 +714,7 @@ type
     mInstantiationInfo, mGetTypeInfo, mGetTypeInfoV2,
     mNimvm, mIntDefine, mStrDefine, mBoolDefine, mRunnableExamples,
     mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf,
-    mSymIsInstantiationOf, mNodeId, mPrivateAccess
+    mSymIsInstantiationOf, mNodeId, mPrivateAccess, mZeroDefault
 
 
 const
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index f12023595..f71a4ddbd 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -2572,7 +2572,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
         p.module.s[cfsDynLibInit].addf("\t$1 = ($2) hcrGetProc($3, \"$1\");$n",
              [mangleDynLibProc(prc), getTypeDesc(p.module, prc.loc.t), getModuleDllPath(p.module, prc)])
     genCall(p, e, d)
-  of mDefault: genDefault(p, e, d)
+  of mDefault, mZeroDefault: genDefault(p, e, d)
   of mReset: genReset(p, e)
   of mEcho: genEcho(p, e[1].skipConv)
   of mArrToSeq: genArrToSeq(p, e, d)
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index 301662f10..fd380e35c 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -2231,7 +2231,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
   of mNewSeq: genNewSeq(p, n)
   of mNewSeqOfCap: unaryExpr(p, n, r, "", "[]")
   of mOf: genOf(p, n, r)
-  of mDefault: genDefault(p, n, r)
+  of mDefault, mZeroDefault: genDefault(p, n, r)
   of mReset, mWasMoved: genReset(p, n)
   of mEcho: genEcho(p, n, r)
   of mNLen..mNError, mSlurp, mStaticExec:
@@ -2342,7 +2342,7 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
     gen(p, val, a)
     var f = it[0].sym
     if f.loc.r == "": f.loc.r = mangleName(p.module, f)
-    fieldIDs.incl(lookupFieldAgain(nTyp, f).id)
+    fieldIDs.incl(lookupFieldAgain(n.typ.skipTypes({tyDistinct}), f).id)
 
     let typ = val.typ.skipTypes(abstractInst)
     if a.typ == etyBaseIndex:
diff --git a/compiler/nim.cfg b/compiler/nim.cfg
index 926cb4c28..5156fa971 100644
--- a/compiler/nim.cfg
+++ b/compiler/nim.cfg
@@ -6,6 +6,7 @@ define:booting
 define:nimcore
 define:nimPreviewFloatRoundtrip
 define:nimPreviewSlimSystem
+define:nimPreviewRangeDefault
 threads:off
 
 #import:"$projectpath/testability"
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 8b0a9d1c6..9f4897665 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -1960,16 +1960,12 @@ proc parseObjectCase(p: var Parser): PNode =
   #| objectBranches = objectBranch (IND{=} objectBranch)*
   #|                       (IND{=} 'elif' expr colcom objectPart)*
   #|                       (IND{=} 'else' colcom objectPart)?
-  #| objectCase = 'case' identWithPragma ':' typeDesc ':'? COMMENT?
+  #| objectCase = 'case' declColonEquals ':'? COMMENT?
   #|             (IND{>} objectBranches DED
   #|             | IND{=} objectBranches)
   result = newNodeP(nkRecCase, p)
   getTokNoInd(p)
-  var a = newNodeP(nkIdentDefs, p)
-  a.add(identWithPragma(p))
-  eat(p, tkColon)
-  a.add(parseTypeDesc(p))
-  a.add(p.emptyNode)
+  var a = parseIdentColonEquals(p, {withPragma})
   result.add(a)
   if p.tok.tokType == tkColon: getTok(p)
   flexComment(p, result)
diff --git a/compiler/sem.nim b/compiler/sem.nim
index b6ee76cc9..8f766f126 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -538,6 +538,123 @@ proc setGenericParamsMisc(c: PContext; n: PNode) =
   else:
     n[miscPos][1] = orig
 
+proc caseBranchMatchesExpr(branch, matched: PNode): bool =
+  for i in 0 ..< branch.len-1:
+    if branch[i].kind == nkRange:
+      if overlap(branch[i], matched): return true
+    elif exprStructuralEquivalent(branch[i], matched):
+      return true
+
+proc pickCaseBranchIndex(caseExpr, matched: PNode): int =
+  let endsWithElse = caseExpr[^1].kind == nkElse
+  for i in 1..<caseExpr.len - endsWithElse.int:
+    if caseExpr[i].caseBranchMatchesExpr(matched):
+      return i
+  if endsWithElse:
+    return caseExpr.len - 1
+
+proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode]
+proc defaultNodeField(c: PContext, a: PNode): PNode
+proc defaultNodeField(c: PContext, a: PNode, aTyp: PType): PNode
+
+const defaultFieldsSkipTypes = {tyGenericInst, tyAlias, tySink}
+
+proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool): seq[PNode] =
+  case recNode.kind
+  of nkRecList:
+    for field in recNode:
+      result.add defaultFieldsForTuple(c, field, hasDefault)
+  of nkSym:
+    let field = recNode.sym
+    let recType = recNode.typ.skipTypes(defaultFieldsSkipTypes)
+    if field.ast != nil: #Try to use default value
+      hasDefault = true
+      result.add newTree(nkExprColonExpr, recNode, field.ast)
+    else:
+      if recType.kind in {tyObject, tyArray, tyTuple}:
+        let asgnExpr = defaultNodeField(c, recNode, recNode.typ)
+        if asgnExpr != nil:
+          hasDefault = true
+          asgnExpr.flags.incl nfUseDefaultField
+          result.add newTree(nkExprColonExpr, recNode, asgnExpr)
+          return
+
+      let asgnType = newType(tyTypeDesc, nextTypeId(c.idgen), recType.owner)
+      rawAddSon(asgnType, recType)
+      let asgnExpr = newTree(nkCall,
+                      newSymNode(getSysMagic(c.graph, recNode.info, "zeroDefault", mZeroDefault)),
+                      newNodeIT(nkType, recNode.info, asgnType)
+                    )
+      asgnExpr.flags.incl nfUseDefaultField
+      asgnExpr.typ = recType
+      result.add newTree(nkExprColonExpr, recNode, asgnExpr)
+  else:
+    doAssert false
+
+proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode] =
+  case recNode.kind
+  of nkRecList:
+    for field in recNode:
+      result.add defaultFieldsForTheUninitialized(c, field)
+  of nkRecCase:
+    let discriminator = recNode[0]
+    var selectedBranch: int
+    let defaultValue = discriminator.sym.ast
+    if defaultValue == nil:
+      # None of the branches were explicitly selected by the user and no value
+      # was given to the discrimator. We can assume that it will be initialized
+      # to zero and this will select a particular branch as a result:
+      selectedBranch = recNode.pickCaseBranchIndex newIntNode(nkIntLit#[c.graph]#, 0)
+    else: # Try to use default value
+      selectedBranch = recNode.pickCaseBranchIndex defaultValue
+      result.add newTree(nkExprColonExpr, discriminator, defaultValue)
+    result.add defaultFieldsForTheUninitialized(c, recNode[selectedBranch][^1])
+  of nkSym:
+    let field = recNode.sym
+    let recType = recNode.typ.skipTypes(defaultFieldsSkipTypes)
+    if field.ast != nil: #Try to use default value
+      result.add newTree(nkExprColonExpr, recNode, field.ast)
+    elif recType.kind in {tyObject, tyArray, tyTuple}:
+      let asgnExpr = defaultNodeField(c, recNode, recNode.typ)
+      if asgnExpr != nil:
+        asgnExpr.flags.incl nfUseDefaultField
+        result.add newTree(nkExprColonExpr, recNode, asgnExpr)
+  else:
+    doAssert false
+
+proc defaultNodeField(c: PContext, a: PNode, aTyp: PType): PNode =
+  let aTypSkip = aTyp.skipTypes(defaultFieldsSkipTypes)
+  if aTypSkip.kind == tyObject:
+    let child = defaultFieldsForTheUninitialized(c, aTyp.skipTypes(defaultFieldsSkipTypes).n)
+    if child.len > 0:
+      var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, a.info, aTyp))
+      asgnExpr.typ = aTyp
+      asgnExpr.sons.add child
+      result = semExpr(c, asgnExpr)
+  elif aTypSkip.kind == tyArray:
+    let child = defaultNodeField(c, a, aTypSkip[1])
+
+    if child != nil:
+      let node = newNode(nkIntLit)
+      node.intVal = toInt64(lengthOrd(c.graph.config, aTypSkip))
+      result = semExpr(c, newTree(nkCall, newSymNode(getSysSym(c.graph, a.info, "arrayWith"), a.info),
+              semExprWithType(c, child),
+              node
+                ))
+      result.typ = aTyp
+  elif aTypSkip.kind == tyTuple:
+    var hasDefault = false
+    if aTypSkip.n != nil:
+      let children = defaultFieldsForTuple(c, aTypSkip.n, hasDefault)
+      if hasDefault and children.len > 0:
+        result = newNodeI(nkTupleConstr, a.info)
+        result.typ = aTyp
+        result.sons.add children
+        result = semExpr(c, result)
+
+proc defaultNodeField(c: PContext, a: PNode): PNode =
+  result = defaultNodeField(c, a, a.typ)
+
 include semtempl, semgnrc, semstmts, semexprs
 
 proc addCodeForGenerics(c: PContext, n: PNode) =
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 0c6500408..2956ab4b6 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -926,8 +926,6 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
           rawAddSon(typ, result.typ)
           result.typ = typ
 
-proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode
-
 proc resolveIndirectCall(c: PContext; n, nOrig: PNode;
                          t: PType): TCandidate =
   initCandidate(c, result, t)
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index 48ea69648..5cfde46f0 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -10,6 +10,26 @@
 # This include file implements the semantic checking for magics.
 # included from sem.nim
 
+proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode
+
+
+proc addDefaultFieldForNew(c: PContext, n: PNode): PNode =
+  result = n
+  let typ = result[1].typ # new(x)
+  if typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyRef and typ.skipTypes({tyGenericInst, tyAlias, tySink})[0].kind == tyObject:
+    var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, result[1].info, typ))
+    asgnExpr.typ = typ
+    var t = typ.skipTypes({tyGenericInst, tyAlias, tySink})[0]
+    while true:
+      asgnExpr.sons.add defaultFieldsForTheUninitialized(c, t.n)
+      let base = t[0]
+      if base == nil:
+        break
+      t = skipTypes(base, skipPtrs)
+
+    if asgnExpr.sons.len > 1:
+      result = newTree(nkAsgn, result[1], asgnExpr)
+
 proc semAddrArg(c: PContext; n: PNode): PNode =
   let x = semExprWithType(c, n)
   if x.kind == nkSym:
@@ -494,13 +514,20 @@ proc semNewFinalize(c: PContext; n: PNode): PNode =
           bindTypeHook(c, transFormedSym, n, attachedDestructor)
         else:
           bindTypeHook(c, turnFinalizerIntoDestructor(c, fin, n.info), n, attachedDestructor)
-  result = n
+  result = addDefaultFieldForNew(c, n)
 
 proc semPrivateAccess(c: PContext, n: PNode): PNode =
   let t = n[1].typ[0].toObjectFromRefPtrGeneric
   c.currentScope.allowPrivateAccess.add t.sym
   result = newNodeIT(nkEmpty, n.info, getSysType(c.graph, n.info, tyVoid))
 
+proc checkDefault(c: PContext, n: PNode): PNode =
+  result = n
+  c.config.internalAssert result[1].typ.kind == tyTypeDesc
+  let constructed = result[1].typ.base
+  if constructed.requiresInit:
+    message(c.config, n.info, warnUnsafeDefault, typeToString(constructed))
+
 proc magicsAfterOverloadResolution(c: PContext, n: PNode,
                                    flags: TExprFlags): PNode =
   ## This is the preferred code point to implement magics.
@@ -559,6 +586,8 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
       result = n
     else:
       result = plugin(c, n)
+  of mNew:
+    result = addDefaultFieldForNew(c, n)
   of mNewFinalize:
     result = semNewFinalize(c, n)
   of mDestroy:
@@ -587,11 +616,13 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
     if seqType.kind == tySequence and seqType.base.requiresInit:
       message(c.config, n.info, warnUnsafeSetLen, typeToString(seqType.base))
   of mDefault:
-    result = n
-    c.config.internalAssert result[1].typ.kind == tyTypeDesc
-    let constructed = result[1].typ.base
-    if constructed.requiresInit:
-      message(c.config, n.info, warnUnsafeDefault, typeToString(constructed))
+    result = checkDefault(c, n)
+    let typ = result[^1].typ.skipTypes({tyTypeDesc})
+    let defaultExpr = defaultNodeField(c, result[^1], typ)
+    if defaultExpr != nil:
+      result = defaultExpr
+  of mZeroDefault:
+    result = checkDefault(c, n)
   of mIsolate:
     if not checkIsolate(n[1]):
       localError(c.config, n.info, "expression cannot be isolated: " & $n[1])
diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim
index 77bd6b975..1463ba833 100644
--- a/compiler/semobjconstr.nim
+++ b/compiler/semobjconstr.nim
@@ -29,6 +29,10 @@ type
     initNone     # None of the fields have been initialized
     initConflict # Fields from different branches have been initialized
 
+
+proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
+                        flags: TExprFlags): tuple[status: InitStatus, defaults: seq[PNode]]
+
 proc mergeInitStatus(existing: var InitStatus, newStatus: InitStatus) =
   case newStatus
   of initConflict:
@@ -72,7 +76,9 @@ proc semConstrField(c: PContext, flags: TExprFlags,
   let assignment = locateFieldInInitExpr(c, field, initExpr)
   if assignment != nil:
     if nfSem in assignment.flags: return assignment[1]
-    if not fieldVisible(c, field):
+    if nfUseDefaultField in assignment[1].flags:
+      discard
+    elif not fieldVisible(c, field):
       localError(c.config, initExpr.info,
         "the field '$1' is not accessible." % [field.name.s])
       return
@@ -85,15 +91,6 @@ proc semConstrField(c: PContext, flags: TExprFlags,
     assignment.flags.incl nfSem
     return initValue
 
-proc caseBranchMatchesExpr(branch, matched: PNode): bool =
-  for i in 0..<branch.len-1:
-    if branch[i].kind == nkRange:
-      if overlap(branch[i], matched): return true
-    elif exprStructuralEquivalent(branch[i], matched):
-      return true
-
-  return false
-
 proc branchVals(c: PContext, caseNode: PNode, caseIdx: int,
                 isStmtBranch: bool): IntSet =
   if caseNode[caseIdx].kind == nkOfBranch:
@@ -155,18 +152,14 @@ proc collectMissingFields(c: PContext, fieldsRecList: PNode,
       if assignment == nil:
         constrCtx.missingFields.add r.sym
 
-
-proc semConstructFields(c: PContext, n: PNode,
-                        constrCtx: var ObjConstrContext,
-                        flags: TExprFlags): InitStatus =
-  result = initUnknown
-
+proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
+                        flags: TExprFlags): tuple[status: InitStatus, defaults: seq[PNode]] =
   case n.kind
   of nkRecList:
     for field in n:
-      let status = semConstructFields(c, field, constrCtx, flags)
-      mergeInitStatus(result, status)
-
+      let (subSt, subDf) = semConstructFields(c, field, constrCtx, flags)
+      result.status.mergeInitStatus subSt
+      result.defaults.add subDf
   of nkRecCase:
     template fieldsPresentInBranch(branchIdx: int): string =
       let branch = n[branchIdx]
@@ -184,9 +177,9 @@ proc semConstructFields(c: PContext, n: PNode,
 
     for i in 1..<n.len:
       let innerRecords = n[i][^1]
-      let status = semConstructFields(c, innerRecords, constrCtx, flags)
+      let (status, _) = semConstructFields(c, innerRecords, constrCtx, flags) # todo
       if status notin {initNone, initUnknown}:
-        mergeInitStatus(result, status)
+        result.status.mergeInitStatus status
         if selectedBranch != -1:
           let prevFields = fieldsPresentInBranch(selectedBranch)
           let currentFields = fieldsPresentInBranch(i)
@@ -194,7 +187,7 @@ proc semConstructFields(c: PContext, n: PNode,
             ("The fields '$1' and '$2' cannot be initialized together, " &
             "because they are from conflicting branches in the case object.") %
             [prevFields, currentFields])
-          result = initConflict
+          result.status = initConflict
         else:
           selectedBranch = i
 
@@ -206,7 +199,7 @@ proc semConstructFields(c: PContext, n: PNode,
             ("cannot prove that it's safe to initialize $1 with " &
             "the runtime value for the discriminator '$2' ") %
             [fields, discriminator.sym.name.s])
-        mergeInitStatus(result, initNone)
+        mergeInitStatus(result.status, initNone)
 
       template wrongBranchError(i) =
         if c.inUncheckedAssignSection == 0:
@@ -289,13 +282,16 @@ proc semConstructFields(c: PContext, n: PNode,
           else:
             wrongBranchError(failedBranch)
 
+      let (_, defaults) = semConstructFields(c, branchNode[^1], constrCtx, flags)
+      result.defaults.add defaults
+
       # When a branch is selected with a partial match, some of the fields
       # that were not initialized may be mandatory. We must check for this:
-      if result == initPartial:
+      if result.status == initPartial:
         collectMissingFields branchNode
 
     else:
-      result = initNone
+      result.status = initNone
       let discriminatorVal = semConstrField(c, flags + {efPreferStatic},
                                             discriminator.sym,
                                             constrCtx.initExpr)
@@ -308,33 +304,41 @@ proc semConstructFields(c: PContext, n: PNode,
         let matchedBranch = n.pickCaseBranch defaultValue
         collectMissingFields matchedBranch
       else:
-        result = initPartial
+        result.status = initPartial
         if discriminatorVal.kind == nkIntLit:
           # When the discriminator is a compile-time value, we also know
           # which branch will be selected:
           let matchedBranch = n.pickCaseBranch discriminatorVal
-          if matchedBranch != nil: collectMissingFields matchedBranch
+          if matchedBranch != nil:
+            let (_, defaults) = semConstructFields(c, matchedBranch[^1], constrCtx, flags)
+            result.defaults.add defaults
+            collectMissingFields matchedBranch
         else:
           # All bets are off. If any of the branches has a mandatory
           # fields we must produce an error:
           for i in 1..<n.len: collectMissingFields n[i]
-
   of nkSym:
     let field = n.sym
     let e = semConstrField(c, flags, field, constrCtx.initExpr)
-    result = if e != nil: initFull else: initNone
-
+    if e != nil:
+      result.status = initFull
+    elif field.ast != nil:
+      result.status = initUnknown
+      result.defaults.add newTree(nkExprColonExpr, n, field.ast)
+    else:
+      result.status = initNone
   else:
     internalAssert c.config, false
 
 proc semConstructTypeAux(c: PContext,
                          constrCtx: var ObjConstrContext,
-                         flags: TExprFlags): InitStatus =
-  result = initUnknown
+                         flags: TExprFlags): tuple[status: InitStatus, defaults: seq[PNode]] =
+  result.status = initUnknown
   var t = constrCtx.typ
   while true:
-    let status = semConstructFields(c, t.n, constrCtx, flags)
-    mergeInitStatus(result, status)
+    let (status, defaults) = semConstructFields(c, t.n, constrCtx, flags)
+    result.status.mergeInitStatus status
+    result.defaults.add defaults
     if status in {initPartial, initNone, initUnknown}:
       collectMissingFields c, t.n, constrCtx
     let base = t[0]
@@ -378,7 +382,9 @@ proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) =
 proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
   var t = semTypeNode(c, n[0], nil)
   result = newNodeIT(nkObjConstr, n.info, t)
-  for child in n: result.add child
+  result.add newNodeIT(nkType, n.info, t) #This will contain the default values to be added in transf
+  for i in 1..<n.len:
+    result.add n[i]
 
   if t == nil:
     return localErrorNode(c, result, "object constructor needs an object type")
@@ -409,7 +415,8 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
   # field (if this is a case object, initialized fields in two different
   # branches will be reported as an error):
   var constrCtx = initConstrContext(t, result)
-  let initResult = semConstructTypeAux(c, constrCtx, flags)
+  let (initResult, defaults) = semConstructTypeAux(c, constrCtx, flags)
+  result[0].sons.add defaults
   var hasError = false # needed to split error detect/report for better msgs
 
   # It's possible that the object was not fully initialized while
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 26356a33c..72e18ec3e 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -612,6 +612,11 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
     var typFlags: TTypeAllowedFlags
 
     var def: PNode = c.graph.emptyNode
+    if a[^1].kind == nkEmpty and symkind == skVar and a[^2].typ != nil:
+      let field = defaultNodeField(c, a[^2])
+      if field != nil:
+        a[^1] = field
+        field.flags.incl nfUseDefaultField
     if a[^1].kind != nkEmpty:
       def = semExprWithType(c, a[^1], {}, typ)
 
@@ -680,6 +685,12 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
         addToVarSection(c, result, n, a)
         continue
       var v = semIdentDef(c, a[j], symkind, false)
+      if a[^1].kind != nkEmpty:
+        if {sfThread, sfNoInit} * v.flags != {} and
+                        nfUseDefaultField in a[^1].flags:
+          a[^1] = c.graph.emptyNode
+          def = c.graph.emptyNode
+        a[^1].flags.excl nfUseDefaultField
       styleCheckDef(c, v)
       onDef(a[j].info, v)
       if sfGenSym notin v.flags:
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index b732eff9c..5dd622a07 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -23,7 +23,6 @@ const
   errXExpectsOneTypeParam = "'$1' expects one type parameter"
   errArrayExpectsTwoTypeParams = "array expects two type parameters"
   errInvalidVisibilityX = "invalid visibility: '$1'"
-  errInitHereNotAllowed = "initialization not allowed here"
   errXCannotBeAssignedTo = "'$1' cannot be assigned to"
   errIteratorNotAllowed = "iterators can only be defined at the module's top level"
   errXNeedsReturnType = "$1 needs a return type"
@@ -293,17 +292,18 @@ proc semRange(c: PContext, n: PNode, prev: PType): PType =
   if n.len == 2:
     if isRange(n[1]):
       result = semRangeAux(c, n[1], prev)
-      let n = result.n
-      if n[0].kind in {nkCharLit..nkUInt64Lit} and n[0].intVal > 0:
-        incl(result.flags, tfRequiresInit)
-      elif n[1].kind in {nkCharLit..nkUInt64Lit} and n[1].intVal < 0:
-        incl(result.flags, tfRequiresInit)
-      elif n[0].kind in {nkFloatLit..nkFloat64Lit} and
-          n[0].floatVal > 0.0:
-        incl(result.flags, tfRequiresInit)
-      elif n[1].kind in {nkFloatLit..nkFloat64Lit} and
-          n[1].floatVal < 0.0:
-        incl(result.flags, tfRequiresInit)
+      if not isDefined(c.config, "nimPreviewRangeDefault"):
+        let n = result.n
+        if n[0].kind in {nkCharLit..nkUInt64Lit} and n[0].intVal > 0:
+          incl(result.flags, tfRequiresInit)
+        elif n[1].kind in {nkCharLit..nkUInt64Lit} and n[1].intVal < 0:
+          incl(result.flags, tfRequiresInit)
+        elif n[0].kind in {nkFloatLit..nkFloat64Lit} and
+            n[0].floatVal > 0.0:
+          incl(result.flags, tfRequiresInit)
+        elif n[1].kind in {nkFloatLit..nkFloat64Lit} and
+            n[1].floatVal < 0.0:
+          incl(result.flags, tfRequiresInit)
     else:
       if n[1].kind == nkInfix and considerQuotedIdent(c, n[1][0]).s == "..<":
         localError(c.config, n[0].info, "range types need to be constructed with '..', '..<' is not supported")
@@ -481,13 +481,19 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
     var a = n[i]
     if (a.kind != nkIdentDefs): illFormedAst(a, c.config)
     checkMinSonsLen(a, 3, c.config)
-    if a[^2].kind != nkEmpty:
+    var hasDefaultField = a[^1].kind != nkEmpty
+    if hasDefaultField:
+      a[^1] = semConstExpr(c, a[^1])
+      typ = a[^1].typ
+    elif a[^2].kind != nkEmpty:
       typ = semTypeNode(c, a[^2], nil)
+      if c.graph.config.isDefined("nimPreviewRangeDefault") and typ.skipTypes(abstractInst).kind == tyRange:
+        a[^1] = newIntNode(nkIntLit, firstOrd(c.config, typ))
+        a[^1].typ = typ
+        hasDefaultField = true
     else:
       localError(c.config, a.info, errTypeExpected)
       typ = errorType(c)
-    if a[^1].kind != nkEmpty:
-      localError(c.config, a[^1].info, errInitHereNotAllowed)
     for j in 0..<a.len - 2:
       var field = newSymG(skField, a[j], c)
       field.typ = typ
@@ -496,7 +502,11 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
       if containsOrIncl(check, field.name.id):
         localError(c.config, a[j].info, "attempt to redefine: '" & field.name.s & "'")
       else:
-        result.n.add newSymNode(field)
+        let fSym = newSymNode(field)
+        if hasDefaultField:
+          fSym.sym.ast = a[^1]
+          fSym.sym.ast.flags.incl nfUseDefaultField
+        result.n.add fSym
         addSonSkipIntLit(result, typ, c.idgen)
       styleCheckDef(c, a[j].info, field)
       onDef(field.info, field)
@@ -805,14 +815,21 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
     var a: PNode
     if father.kind != nkRecList and n.len >= 4: a = newNodeI(nkRecList, n.info)
     else: a = newNodeI(nkEmpty, n.info)
-    if n[^1].kind != nkEmpty:
-      localError(c.config, n[^1].info, errInitHereNotAllowed)
     var typ: PType
-    if n[^2].kind == nkEmpty:
+    var hasDefaultField = n[^1].kind != nkEmpty
+    if hasDefaultField:
+      n[^1] = semConstExpr(c, n[^1])
+      typ = n[^1].typ
+      propagateToOwner(rectype, typ)
+    elif n[^2].kind == nkEmpty:
       localError(c.config, n.info, errTypeExpected)
       typ = errorType(c)
     else:
       typ = semTypeNode(c, n[^2], nil)
+      if c.graph.config.isDefined("nimPreviewRangeDefault") and typ.skipTypes(abstractInst).kind == tyRange:
+        n[^1] = newIntNode(nkIntLit, firstOrd(c.config, typ))
+        n[^1].typ = typ
+        hasDefaultField = true
       propagateToOwner(rectype, typ)
     var fieldOwner = if c.inGenericContext > 0: c.getCurrOwner
                      else: rectype.sym
@@ -834,8 +851,12 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
       inc(pos)
       if containsOrIncl(check, f.name.id):
         localError(c.config, info, "attempt to redefine: '" & f.name.s & "'")
-      if a.kind == nkEmpty: father.add newSymNode(f)
-      else: a.add newSymNode(f)
+      let fSym = newSymNode(f)
+      if hasDefaultField:
+        fSym.sym.ast = n[^1]
+        fSym.sym.ast.flags.incl nfUseDefaultField
+      if a.kind == nkEmpty: father.add fSym
+      else: a.add fSym
       styleCheckDef(c, f)
       onDef(f.info, f)
     if a.kind != nkEmpty: father.add a
diff --git a/compiler/transf.nim b/compiler/transf.nim
index dd0d546eb..5517eeace 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -46,7 +46,6 @@ type
     module: PSym
     transCon: PTransCon      # top of a TransCon stack
     inlining: int            # > 0 if we are in inlining context (copy vars)
-    nestedProcs: int         # > 0 if we are in a nested proc
     contSyms, breakSyms: seq[PSym]  # to transform 'continue' and 'break'
     deferDetected, tooEarly: bool
     graph: ModuleGraph
@@ -1061,6 +1060,13 @@ proc transform(c: PTransf, n: PNode): PNode =
       result = n
   of nkExceptBranch:
     result = transformExceptBranch(c, n)
+  of nkObjConstr:
+    result = n
+    if result.typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyObject or
+       result.typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyRef and result.typ.skipTypes({tyGenericInst, tyAlias, tySink})[0].kind == tyObject:
+      result.sons.add result[0].sons
+      result[0] = newNodeIT(nkType, result.info, result.typ)
+    result = transformSons(c, result)
   of nkCheckedFieldExpr:
     result = transformSons(c, n)
     if result[0].kind != nkDotExpr:
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index a0bf6af56..117c1bc84 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -1181,7 +1181,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     c.gABx(n, opcLdNull, d, c.genType(n[1].typ))
     c.gABx(n, opcNodeToReg, d, d)
     c.genAsgnPatch(n[1], d)
-  of mDefault:
+  of mDefault, mZeroDefault:
     if dest < 0: dest = c.getTemp(n.typ)
     c.gABx(n, ldNullOpcode(n.typ), dest, c.genType(n.typ))
   of mOf, mIs:
diff --git a/config/nim.cfg b/config/nim.cfg
index 9f50a1f84..de525ae92 100644
--- a/config/nim.cfg
+++ b/config/nim.cfg
@@ -22,6 +22,7 @@ hint[LineTooLong]=off
 #hint[XDeclaredButNotUsed]=off
 
 threads:on
+define:nimPreviewRangeDefault
 
 # Examples of how to setup a cross-compiler:
 # Nim can target architectures and OSes different than the local host
diff --git a/doc/grammar.txt b/doc/grammar.txt
index 878a4e5e1..29a4300b6 100644
--- a/doc/grammar.txt
+++ b/doc/grammar.txt
@@ -166,7 +166,7 @@ objectBranch = 'of' exprList colcom objectPart
 objectBranches = objectBranch (IND{=} objectBranch)*
                       (IND{=} 'elif' expr colcom objectPart)*
                       (IND{=} 'else' colcom objectPart)?
-objectCase = 'case' identWithPragma ':' typeDesc ':'? COMMENT?
+objectCase = 'case' declColonEquals ':'? COMMENT?
             (IND{>} objectBranches DED
             | IND{=} objectBranches)
 objectPart = IND{>} objectPart^+IND{=} DED
diff --git a/lib/system.nim b/lib/system.nim
index 1b6b3c9a8..ed1a0077e 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -24,6 +24,9 @@
 
 include "system/basic_types"
 
+func zeroDefault*[T](_: typedesc[T]): T {.magic: "ZeroDefault".} =
+  ## returns the default value of the type `T`.
+
 include "system/compilation"
 
 {.push warning[GcMem]: off, warning[Uninit]: off.}
@@ -911,6 +914,7 @@ proc default*[T](_: typedesc[T]): T {.magic: "Default", noSideEffect.} =
   # note: the doc comment also explains why `default` can't be implemented
   # via: `template default*[T](t: typedesc[T]): T = (var v: T; v)`
 
+
 proc reset*[T](obj: var T) {.noSideEffect.} =
   ## Resets an object `obj` to its default value.
   obj = default(typeof(obj))
@@ -2753,3 +2757,8 @@ when notJSnotNims and not defined(nimSeqsV2):
       moveMem(addr y[0], addr x[0], x.len)
       assert y == "abcgh"
     discard
+
+proc arrayWith*[T](y: T, size: static int): array[size, T] {.noinit.} = # ? exempt from default value for result
+  ## Creates a new array filled with `y`.
+  for i in 0..size-1:
+    result[i] = y
diff --git a/lib/system/seqs_v2.nim b/lib/system/seqs_v2.nim
index 42d9938c5..40fd50b48 100644
--- a/lib/system/seqs_v2.nim
+++ b/lib/system/seqs_v2.nim
@@ -125,6 +125,8 @@ proc setLen[T](s: var seq[T], newlen: Natural) =
       if xu.p == nil or xu.p.cap < newlen:
         xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, newlen - oldLen, sizeof(T), alignof(T)))
       xu.len = newlen
+      for i in oldLen..<newlen:
+        xu.p.data[i] = default(T)
 
 proc newSeq[T](s: var seq[T], len: Natural) =
   shrink(s, 0)
diff --git a/tests/config.nims b/tests/config.nims
index 5195ebcaf..4b5a5e3a2 100644
--- a/tests/config.nims
+++ b/tests/config.nims
@@ -40,5 +40,6 @@ switch("define", "nimPreviewFloatRoundtrip")
 switch("define", "nimPreviewDotLikeOps")
 switch("define", "nimPreviewJsonutilsHoleyEnum")
 switch("define", "nimPreviewHashRef")
+switch("define", "nimPreviewRangeDefault")
 when defined(windows):
   switch("tlsEmulation", "off")
diff --git a/tests/errmsgs/t5167_5.nim b/tests/errmsgs/t5167_5.nim
index a9e260845..ab6f094f3 100644
--- a/tests/errmsgs/t5167_5.nim
+++ b/tests/errmsgs/t5167_5.nim
@@ -1,5 +1,5 @@
 discard """
-cmd: "nim check $file"
+cmd: "nim check --mm:refc $file"
 errormsg: "'t' has unspecified generic parameters"
 nimout: '''
 t5167_5.nim(10, 16) Error: expression 'system' has no type (or is ambiguous)
diff --git a/tests/js/trepr.nim b/tests/js/trepr.nim
index c63b64d3a..047016aea 100644
--- a/tests/js/trepr.nim
+++ b/tests/js/trepr.nim
@@ -303,7 +303,7 @@ g = {},
 h = {},
 i = ["", "", ""],
 j = @[],
-k = 0,
+k = -12,
 l = [a = "",
 b = @[]],
 m = nil,
diff --git a/tests/objects/mobject_default_value.nim b/tests/objects/mobject_default_value.nim
new file mode 100644
index 000000000..224549501
--- /dev/null
+++ b/tests/objects/mobject_default_value.nim
@@ -0,0 +1,15 @@
+type
+  Clean = object
+    mem: int
+  Default* = object
+    poi: int = 12
+    clc: Clean
+    se*: range[0'i32 .. high(int32)]
+
+  NonDefault* = object
+    poi: int
+
+  PrellDeque*[T] = object
+    pendingTasks*: range[0'i32 .. high(int32)]
+    head: T
+    tail: T
diff --git a/tests/objects/tobject_default_value.nim b/tests/objects/tobject_default_value.nim
new file mode 100644
index 000000000..d826566fd
--- /dev/null
+++ b/tests/objects/tobject_default_value.nim
@@ -0,0 +1,429 @@
+discard """
+  matrix: "-d:nimPreviewRangeDefault --mm:refc; -d:nimPreviewRangeDefault --warningAsError:ProveInit --mm:orc"
+  targets: "c cpp js"
+"""
+
+import times
+
+type
+  Guess = object
+    poi: DateTime
+
+  GuessDistinct = distinct Guess
+
+block:
+  var x: Guess
+  discard Guess()
+
+  var y: GuessDistinct
+
+  discard y
+
+  discard GuessDistinct(x)
+
+
+import mobject_default_value
+
+block:
+  let x = Default()
+  doAssert x.se == 0'i32
+# echo Default(poi: 12)
+# echo Default(poi: 17)
+
+# echo NonDefault(poi: 77)
+
+block:
+  var x: Default
+  doAssert x.se == 0'i32
+
+type
+  ObjectBase = object of RootObj
+    value = 12
+
+  ObjectBaseDistinct = distinct ObjectBase
+
+  DinstinctInObject = object
+    data: ObjectBaseDistinct
+
+  Object = object of ObjectBase
+    time: float = 1.2
+    date: int
+    scale: range[1..10]
+
+  Object2 = object
+    name: Object
+
+  Object3 = object
+    obj: Object2
+
+  ObjectTuple = tuple
+    base: ObjectBase
+    typ: int
+    obj: Object
+
+  TupleInObject = object
+    size = 777
+    data: ObjectTuple
+
+  Ref = ref object of ObjectBase
+
+  RefInt = ref object of Ref
+    data = 73
+
+  Ref2 = ref object of ObjectBase
+
+  RefInt2 = ref object of Ref
+    data = 73
+
+var t {.threadvar.}: Default
+# var m1, m2 {.threadvar.}: Default
+
+block:
+  doAssert t.se == 0'i32
+
+block: # ARC/ORC cannot bind destructors twice, so it cannot
+      # be moved into main
+  block:
+    var x: Ref
+    new(x)
+    doAssert x.value == 12, "Ref.value = " & $x.value
+
+    var y: RefInt
+    new(y)
+    doAssert y.value == 12
+    doAssert y.data == 73
+
+  block:
+    var x: Ref2
+    new(x, proc (x: Ref2) {.nimcall.} = discard "call Ref")
+    doAssert x.value == 12, "Ref.value = " & $x.value
+
+    proc call(x: RefInt2) =
+      discard "call RefInt"
+
+    var y: RefInt2
+    new(y, call)
+    doAssert y.value == 12
+    doAssert y.data == 73
+
+template main {.dirty.} =
+  block: # bug #16744
+    type
+      R = range[1..10]
+      Obj = object
+        r: R
+
+    var
+      rVal: R  # Works fine
+      objVal: Obj
+
+    doAssert rVal == 0 # it should be 1
+    doAssert objVal.r == 1
+
+  block: # bug #3608
+    type
+      abc = ref object
+        w: range[2..100]
+
+    proc createABC(): abc =
+      new(result)
+      result.w = 20
+
+    doAssert createABC().w == 20
+
+  block:
+    var x = new ObjectBase
+    doAssert x.value == 12
+
+    proc hello(): ref ObjectBase =
+      new result
+
+    let z = hello()
+    doAssert z.value == 12
+
+  block:
+    var base: ObjectBase
+    var x: ObjectBaseDistinct = ObjectBaseDistinct(base)
+    doAssert ObjectBase(x).value == 12
+    let y = ObjectBaseDistinct(default(ObjectBase))
+    doAssert ObjectBase(y).value == 12
+
+    proc hello(): ObjectBaseDistinct =
+      result = ObjectBaseDistinct(default(ObjectBase))
+
+    let z = hello()
+    doAssert ObjectBase(z).value == 12
+
+  block:
+    var x: DinstinctInObject
+    x.data = ObjectBaseDistinct(default(ObjectBase))
+
+    doAssert ObjectBase(x.data).value == 12
+
+  block:
+    var x: Object
+    doAssert x.value == 12
+    doAssert x.time == 1.2
+    doAssert x.scale == 1
+
+    let y = default(Object)
+    doAssert y.value == 12
+    doAssert y.time == 1.2
+    doAssert y.scale == 1
+
+    var x1, x2, x3: Object
+    doAssert x1.value == 12
+    doAssert x1.time == 1.2
+    doAssert x1.scale == 1
+    doAssert x2.value == 12
+    doAssert x2.time == 1.2
+    doAssert x2.scale == 1
+    doAssert x3.value == 12
+    doAssert x3.time == 1.2
+    doAssert x3.scale == 1
+
+  block:
+    var x = new Object
+    doAssert x[] == default(Object)
+
+  block:
+    var x: Object2
+    doAssert x.name.value == 12
+    doAssert x.name.time == 1.2
+    doAssert x.name.scale == 1
+
+  block:
+    var x: ref Object2
+    new x
+    doAssert x[] == default(Object2)
+
+  block:
+    var x: Object3
+    doAssert x.obj.name.value == 12
+    doAssert x.obj.name.time == 1.2
+    doAssert x.obj.name.scale == 1
+
+  when nimvm:
+    discard "fixme"
+  else:
+    when defined(gcArc) or defined(gcOrc):
+      block: #seq
+        var x = newSeq[Object](10)
+        let y = x[0]
+        doAssert y.value == 12
+        doAssert y.time == 1.2
+        doAssert y.scale == 1
+
+      block:
+        var x: seq[Object]
+        setLen(x, 5)
+        let y = x[^1]
+        doAssert y.value == 12
+        doAssert y.time == 1.2
+        doAssert y.scale == 1
+
+  block: # array
+    var x: array[10, Object]
+    let y = x[0]
+    doAssert y.value == 12
+    doAssert y.time == 1.2
+    doAssert y.scale == 1
+
+  block: # array
+    var x {.noinit.}: array[10, Object]
+    discard x
+
+  block: # tuple
+    var x: ObjectTuple
+    doAssert x.base.value == 12
+    doAssert x.typ == 0
+    doAssert x.obj.time == 1.2
+    doAssert x.obj.date == 0
+    doAssert x.obj.scale == 1
+    doAssert x.obj.value == 12
+
+  block: # tuple in object
+    var x: TupleInObject
+    doAssert x.data.base.value == 12
+    doAssert x.data.typ == 0
+    doAssert x.data.obj.time == 1.2
+    doAssert x.data.obj.date == 0
+    doAssert x.data.obj.scale == 1
+    doAssert x.data.obj.value == 12
+    doAssert x.size == 777
+
+  type
+    ObjectArray = object
+      data: array[10, Object]
+
+  block:
+    var x: ObjectArray
+    let y = x.data[0]
+    doAssert y.value == 12
+    doAssert y.time == 1.2
+    doAssert y.scale == 1
+
+
+  block:
+    var x: PrellDeque[int]
+    doAssert x.pendingTasks == 0
+
+  type
+    Color = enum
+      Red, Blue, Yellow
+
+    ObjectVarint = object
+      case kind: Color
+      of Red:
+        data: int = 10
+      of Blue:
+        fill = "123"
+      of Yellow:
+        time = 1.8'f32
+
+    ObjectVarint1 = object
+      case kind: Color = Blue
+      of Red:
+        data1: int = 10
+      of Blue:
+        fill2 = "123"
+        cry: float
+      of Yellow:
+        time3 = 1.8'f32
+        him: int
+
+  block:
+    var x = ObjectVarint(kind: Red)
+    doAssert x.kind == Red
+    doAssert x.data == 10
+
+  block:
+    var x = ObjectVarint(kind: Blue)
+    doAssert x.kind == Blue
+    doAssert x.fill == "123"
+
+  block:
+    var x = ObjectVarint(kind: Yellow)
+    doAssert x.kind == Yellow
+    doAssert typeof(x.time) is float32
+
+  block:
+    var x: ObjectVarint1
+    doAssert x.kind == Blue
+    doAssert x.fill2 == "123"
+    x.cry = 326
+
+  type
+    ObjectVarint2 = object
+      case kind: Color
+      of Red:
+        data: int = 10
+      of Blue:
+        fill = "123"
+      of Yellow:
+        time = 1.8'f32
+
+  block:
+    var x = ObjectVarint2(kind: Blue)
+    doAssert x.fill == "123"
+
+  block:
+    type
+      Color = enum
+        Red, Blue, Yellow
+  
+    type
+      ObjectVarint3 = object # fixme it doesn't work with static
+        case kind: Color = Blue
+        of Red:
+          data1: int = 10
+        of Blue:
+          case name: Color = Blue
+          of Blue:
+            go = 12
+          else:
+            temp = 66
+          fill2 = "123"
+          cry: float
+        of Yellow:
+          time3 = 1.8'f32
+          him: int
+
+    block:
+      var x: ObjectVarint3
+      doAssert x.kind == Blue
+      doAssert x.name == Blue
+      doAssert x.go == 12
+
+    block:
+      var x = ObjectVarint3(kind: Blue, name: Red, temp: 99)
+      doAssert x.kind == Blue
+      doAssert x.name == Red
+      doAssert x.temp == 99
+
+  block:
+    type
+      Default = tuple
+        id: int = 1
+        obj: ObjectBase
+        name: string
+
+      Class = object
+        def: Default
+
+      Member = object
+        def: Default = (id: 777, obj: ObjectBase(), name: "fine")
+
+    block:
+      var x: Default
+      doAssert x.id == 1
+      doAssert x.obj == default(ObjectBase)
+      doAssert x.name == ""
+    
+    block:
+      var x: Class
+      doAssert x.def == default(Default)
+      doAssert x.def.id == 1
+      doAssert x.def.obj == default(ObjectBase)
+      doAssert x.def.name == ""
+
+    when not defined(cpp):
+      block:
+        var x: Member
+        doAssert x.def.id == 777
+        doAssert x.def.obj == default(ObjectBase)
+        doAssert x.def.name == "fine"
+
+  block:
+    var x {.noinit.} = 12
+    doAssert x == 12
+
+    type
+      Pure = object
+        id: int = 12
+
+    var y {.noinit.}: Pure
+    doAssert y.id == 0
+
+    var z {.noinit.}: Pure = Pure(id: 77)
+    doAssert z.id == 77
+
+
+proc main1 =
+  var my = @[1, 2, 3, 4, 5]
+  my.setLen(0)
+  my.setLen(5)
+  doAssert my == @[0, 0, 0, 0, 0]
+
+proc main2 =
+  var my = "hello"
+  my.setLen(0)
+  my.setLen(5)
+  doAssert $(@my) == """@['\x00', '\x00', '\x00', '\x00', '\x00']"""
+
+when defined(gcArc) or defined(gcOrc):
+  main1()
+  main2()
+
+static: main()
+main()
diff --git a/tests/stdlib/tnetconnect.nim b/tests/stdlib/tnetconnect.nim
index 3a80df19f..0fff8fdce 100644
--- a/tests/stdlib/tnetconnect.nim
+++ b/tests/stdlib/tnetconnect.nim
@@ -1,4 +1,5 @@
 discard """
+  disabled: "i386"
   matrix: "-d:ssl"
 """