summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim3
-rw-r--r--compiler/ccgexprs.nim1
-rw-r--r--compiler/ccgmerge.nim24
-rw-r--r--compiler/parampatterns.nim7
-rw-r--r--compiler/parser.nim12
-rw-r--r--compiler/semcall.nim3
-rw-r--r--compiler/semdata.nim55
-rw-r--r--compiler/semdestruct.nim33
-rw-r--r--compiler/semexprs.nim20
-rw-r--r--compiler/semfold.nim266
-rw-r--r--compiler/semmagic.nim43
-rw-r--r--compiler/semstmts.nim2
-rw-r--r--compiler/semtypes.nim4
-rw-r--r--compiler/types.nim2
-rw-r--r--compiler/vmdeps.nim1
-rw-r--r--compiler/vmgen.nim3
16 files changed, 275 insertions, 204 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index d94f09ccb..10f2a71da 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -529,7 +529,7 @@ type
   TMagic* = enum # symbols that require compiler magic:
     mNone,
     mDefined, mDefinedInScope, mCompiles,
-    mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mAddr, mTypeOf,
+    mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mAddr, mTypeOf, mRoof,
     mEcho, mShallowCopy, mSlurp, mStaticExec,
     mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst,
     mUnaryLt, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray,
@@ -557,6 +557,7 @@ type
     mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
     mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
     mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mSlice,
+    mDotDot, # this one is only necessary to give nice compile time warnings
     mFields, mFieldPairs, mOmpParFor,
     mAppendStrCh, mAppendStrStr, mAppendSeqElem,
     mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq,
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index a280abc31..aa1bf31be 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -1749,6 +1749,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
     initLocExpr(p, x, a)
     initLocExpr(p, e.sons[2], b)
     genDeepCopy(p, a, b)
+  of mDotDot: genCall(p, e, d)
   else: internalError(e.info, "genMagicExpr: " & $op)
 
 proc genConstExpr(p: BProc, n: PNode): PRope
diff --git a/compiler/ccgmerge.nim b/compiler/ccgmerge.nim
index f4f837834..5057b9ff1 100644
--- a/compiler/ccgmerge.nim
+++ b/compiler/ccgmerge.nim
@@ -94,7 +94,7 @@ proc writeIntSet(a: IntSet, s: var string) =
     encodeVInt(x, s)
     inc i
   s.add('}')
-  
+
 proc genMergeInfo*(m: BModule): PRope =
   if optSymbolFiles notin gGlobalOptions: return nil
   var s = "/*\tNIM_merge_INFO:"
@@ -113,7 +113,7 @@ proc genMergeInfo*(m: BModule): PRope =
   s.add("*/")
   result = s.toRope
 
-template `^`(pos: expr): expr = L.buf[pos]
+template `^`(pos: int): expr = L.buf[pos]
 
 proc skipWhite(L: var TBaseLexer) =
   var pos = L.bufpos
@@ -132,7 +132,7 @@ proc skipUntilCmd(L: var TBaseLexer) =
     of CR: pos = nimlexbase.handleCR(L, pos)
     of LF: pos = nimlexbase.handleLF(L, pos)
     of '\0': break
-    of '/': 
+    of '/':
       if ^(pos+1) == '*' and ^(pos+2) == '\t':
         inc pos, 3
         break
@@ -145,7 +145,7 @@ proc atEndMark(buf: cstring, pos: int): bool =
   while s < NimMergeEndMark.len and buf[pos+s] == NimMergeEndMark[s]: inc s
   result = s == NimMergeEndMark.len
 
-proc readVerbatimSection(L: var TBaseLexer): PRope = 
+proc readVerbatimSection(L: var TBaseLexer): PRope =
   var pos = L.bufpos
   var buf = L.buf
   var r = newStringOfCap(30_000)
@@ -162,7 +162,7 @@ proc readVerbatimSection(L: var TBaseLexer): PRope =
     of '\0':
       internalError("ccgmerge: expected: " & NimMergeEndMark)
       break
-    else: 
+    else:
       if atEndMark(buf, pos):
         inc pos, NimMergeEndMark.len
         break
@@ -181,7 +181,7 @@ proc readKey(L: var TBaseLexer, result: var string) =
   if buf[pos] != ':': internalError("ccgmerge: ':' expected")
   L.bufpos = pos + 1 # skip ':'
 
-proc newFakeType(id: int): PType = 
+proc newFakeType(id: int): PType =
   new(result)
   result.id = id
 
@@ -227,8 +227,8 @@ proc processMergeInfo(L: var TBaseLexer, m: BModule) =
 
 when not defined(nimhygiene):
   {.pragma: inject.}
-  
-template withCFile(cfilename: string, body: stmt) {.immediate.} = 
+
+template withCFile(cfilename: string, body: stmt) {.immediate.} =
   var s = llStreamOpen(cfilename, fmRead)
   if s == nil: return
   var L {.inject.}: TBaseLexer
@@ -239,7 +239,7 @@ template withCFile(cfilename: string, body: stmt) {.immediate.} =
     if ^L.bufpos == '\0': break
     body
   closeBaseLexer(L)
-  
+
 proc readMergeInfo*(cfilename: string, m: BModule) =
   ## reads the merge meta information into `m`.
   withCFile(cfilename):
@@ -257,7 +257,7 @@ proc readMergeSections(cfilename: string, m: var TMergeSections) =
   ## reads the merge sections into `m`.
   withCFile(cfilename):
     readKey(L, k)
-    if k == "NIM_merge_INFO":   
+    if k == "NIM_merge_INFO":
       discard
     elif ^L.bufpos == '*' and ^(L.bufpos+1) == '/':
       inc(L.bufpos, 2)
@@ -283,7 +283,7 @@ proc mergeRequired*(m: BModule): bool =
       #echo "not empty: ", i, " ", ropeToStr(m.s[i])
       return true
   for i in low(TCProcSection)..high(TCProcSection):
-    if m.initProc.s(i) != nil: 
+    if m.initProc.s(i) != nil:
       #echo "not empty: ", i, " ", ropeToStr(m.initProc.s[i])
       return true
 
@@ -291,7 +291,7 @@ proc mergeFiles*(cfilename: string, m: BModule) =
   ## merges the C file with the old version on hard disc.
   var old: TMergeSections
   readMergeSections(cfilename, old)
-  # do the merge; old section before new section:    
+  # do the merge; old section before new section:
   for i in low(TCFileSection)..high(TCFileSection):
     m.s[i] = con(old.f[i], m.s[i])
   for i in low(TCProcSection)..high(TCProcSection):
diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim
index 8c0875ab1..3f67005b9 100644
--- a/compiler/parampatterns.nim
+++ b/compiler/parampatterns.nim
@@ -131,11 +131,10 @@ proc semNodeKindConstraints*(p: PNode): PNode =
   result.strVal.add(ppEof)
 
 type
-  TSideEffectAnalysis = enum
+  TSideEffectAnalysis* = enum
     seUnknown, seSideEffect, seNoSideEffect
 
-proc checkForSideEffects(n: PNode): TSideEffectAnalysis =
-  # XXX is 'raise' a side effect?
+proc checkForSideEffects*(n: PNode): TSideEffectAnalysis =
   case n.kind
   of nkCallKinds:
     # only calls can produce side effects:
@@ -162,6 +161,8 @@ proc checkForSideEffects(n: PNode): TSideEffectAnalysis =
     # an atom cannot produce a side effect:
     result = seNoSideEffect
   else:
+    # assume no side effect:
+    result = seNoSideEffect
     for i in 0 .. <n.len:
       let ret = checkForSideEffects(n.sons[i])
       if ret == seSideEffect: return ret
diff --git a/compiler/parser.nim b/compiler/parser.nim
index d1aa2d8e3..dcd5401e8 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -241,9 +241,15 @@ proc isOperator(tok: TToken): bool =
 
 proc isUnary(p: TParser): bool =
   ## Check if the current parser token is a unary operator
-  p.strongSpaces and p.tok.tokType in {tkOpr, tkDotDot} and
-    p.tok.strongSpaceB == 0 and
-    p.tok.strongSpaceA > 0
+  if p.tok.tokType in {tkOpr, tkDotDot} and
+     p.tok.strongSpaceB == 0 and
+     p.tok.strongSpaceA > 0:
+    # XXX change this after 0.10.4 is out
+    if p.strongSpaces:
+      result = true
+    else:
+      parMessage(p, warnDeprecated,
+        "will be parsed as unary operator; inconsistent spacing")
 
 proc checkBinary(p: TParser) {.inline.} =
   ## Check if the current parser token is a binary operator.
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index 4309661f3..c48e761e3 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -201,7 +201,8 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
 
     elif nfDotSetter in n.flags:
       internalAssert f.kind == nkIdent and n.sonsLen == 3
-      let calleeName = newStrNode(nkStrLit, f.ident.s[0.. -2]).withInfo(n.info)
+      let calleeName = newStrNode(nkStrLit,
+        f.ident.s[0..f.ident.s.len-2]).withInfo(n.info)
       let callOp = newIdentNode(getIdent".=", n.info)
       n.sons[0..1] = [callOp, n[1], calleeName]
       orig.sons[0..1] = [callOp, orig[1], calleeName]
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 27d441000..9b5d788af 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -9,13 +9,13 @@
 
 ## This module contains the data structures for the semantic checking phase.
 
-import 
+import
   strutils, lists, intsets, options, lexer, ast, astalgo, trees, treetab,
-  wordrecg, 
-  ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math, 
+  wordrecg,
+  ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math,
   magicsys, nversion, nimsets, parser, times, passes, rodread, vmdef
 
-type 
+type
   TOptionEntry* = object of lists.TListEntry # entries to put on a
                                              # stack for pragma parsing
     options*: TOptions
@@ -26,7 +26,7 @@ type
 
   POptionEntry* = ref TOptionEntry
   PProcCon* = ref TProcCon
-  TProcCon*{.final.} = object # procedure context; also used for top-level
+  TProcCon* = object          # procedure context; also used for top-level
                               # statements
     owner*: PSym              # the symbol this context belongs to
     resultSym*: PSym          # the result symbol (if we are in a proc)
@@ -36,12 +36,13 @@ type
                               # in standalone ``except`` and ``finally``
     next*: PProcCon           # used for stacking procedure contexts
     wasForwarded*: bool       # whether the current proc has a separate header
-  
+    bracketExpr*: PNode       # current bracket expression (for ^ support)
+
   TInstantiationPair* = object
     genericSym*: PSym
     inst*: PInstantiation
 
-  TExprFlag* = enum 
+  TExprFlag* = enum
     efLValue, efWantIterator, efInTypeof, efWantStmt, efDetermineType,
     efAllowDestructor, efWantValue, efOperand, efNoSemCheck
   TExprFlags* = set[TExprFlag]
@@ -57,7 +58,7 @@ type
                                # this is used so that generic instantiations
                                # can access private object fields
     instCounter*: int          # to prevent endless instantiations
-   
+
     ambiguousSymbols*: IntSet  # ids of all ambiguous symbols (cannot
                                # store this info in the syms themselves!)
     inTypeClass*: int          # > 0 if we are in a user-defined type class
@@ -95,7 +96,7 @@ type
     instDeepCopy*: proc (c: PContext; dc: PSym; t: PType;
                          info: TLineInfo): PSym {.nimcall.}
 
-   
+
 proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
   result.genericSym = s
   result.inst = inst
@@ -127,7 +128,7 @@ proc popOwner*()
 
 var gOwners*: seq[PSym] = @[]
 
-proc getCurrOwner(): PSym = 
+proc getCurrOwner(): PSym =
   # owner stack (used for initializing the
   # owner field of syms)
   # the documentation comment always gets
@@ -135,19 +136,19 @@ proc getCurrOwner(): PSym =
   # BUGFIX: global array is needed!
   result = gOwners[high(gOwners)]
 
-proc pushOwner(owner: PSym) = 
+proc pushOwner(owner: PSym) =
   add(gOwners, owner)
 
-proc popOwner() = 
+proc popOwner() =
   var length = len(gOwners)
   if length > 0: setLen(gOwners, length - 1)
   else: internalError("popOwner")
 
-proc lastOptionEntry(c: PContext): POptionEntry = 
+proc lastOptionEntry(c: PContext): POptionEntry =
   result = POptionEntry(c.optionStack.tail)
 
-proc pushProcCon*(c: PContext, owner: PSym) {.inline.} = 
-  if owner == nil: 
+proc pushProcCon*(c: PContext, owner: PSym) {.inline.} =
+  if owner == nil:
     internalError("owner is nil")
     return
   var x: PProcCon
@@ -158,7 +159,7 @@ proc pushProcCon*(c: PContext, owner: PSym) {.inline.} =
 
 proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next
 
-proc newOptionEntry(): POptionEntry = 
+proc newOptionEntry(): POptionEntry =
   new(result)
   result.options = gOptions
   result.defaultCC = ccDefault
@@ -182,8 +183,8 @@ proc newContext(module: PSym): PContext =
 
 proc inclSym(sq: var TSymSeq, s: PSym) =
   var L = len(sq)
-  for i in countup(0, L - 1): 
-    if sq[i].id == s.id: return 
+  for i in countup(0, L - 1):
+    if sq[i].id == s.id: return
   setLen(sq, L + 1)
   sq[L] = s
 
@@ -193,20 +194,20 @@ proc addConverter*(c: PContext, conv: PSym) =
 proc addPattern*(c: PContext, p: PSym) =
   inclSym(c.patterns, p)
 
-proc newLib(kind: TLibKind): PLib = 
+proc newLib(kind: TLibKind): PLib =
   new(result)
   result.kind = kind          #initObjectSet(result.syms)
-  
+
 proc addToLib(lib: PLib, sym: PSym) =
   #if sym.annex != nil and not isGenericRoutine(sym):
   #  LocalError(sym.info, errInvalidPragma)
   sym.annex = lib
 
-proc makePtrType(c: PContext, baseType: PType): PType = 
+proc makePtrType(c: PContext, baseType: PType): PType =
   result = newTypeS(tyPtr, c)
   addSonSkipIntLit(result, baseType.assertNotNil)
 
-proc makeVarType(c: PContext, baseType: PType): PType = 
+proc makeVarType(c: PContext, baseType: PType): PType =
   result = newTypeS(tyVar, c)
   addSonSkipIntLit(result, baseType.assertNotNil)
 
@@ -286,7 +287,7 @@ proc errorNode*(c: PContext, n: PNode): PNode =
   result = newNodeI(nkEmpty, n.info)
   result.typ = errorType(c)
 
-proc fillTypeS(dest: PType, kind: TTypeKind, c: PContext) = 
+proc fillTypeS(dest: PType, kind: TTypeKind, c: PContext) =
   dest.kind = kind
   dest.owner = getCurrOwner()
   dest.size = - 1
@@ -311,13 +312,13 @@ proc illFormedAst*(n: PNode) =
 proc illFormedAstLocal*(n: PNode) =
   localError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
 
-proc checkSonsLen*(n: PNode, length: int) = 
+proc checkSonsLen*(n: PNode, length: int) =
   if sonsLen(n) != length: illFormedAst(n)
-  
-proc checkMinSonsLen*(n: PNode, length: int) = 
+
+proc checkMinSonsLen*(n: PNode, length: int) =
   if sonsLen(n) < length: illFormedAst(n)
 
-proc isTopLevel*(c: PContext): bool {.inline.} = 
+proc isTopLevel*(c: PContext): bool {.inline.} =
   result = c.currentScope.depthLevel <= 2
 
 proc experimentalMode*(c: PContext): bool {.inline.} =
diff --git a/compiler/semdestruct.nim b/compiler/semdestruct.nim
index bbc68ee87..aaab49a10 100644
--- a/compiler/semdestruct.nim
+++ b/compiler/semdestruct.nim
@@ -12,7 +12,7 @@
 # included from sem.nim
 
 # special marker values that indicates that we are
-# 1) AnalyzingDestructor: currently analyzing the type for destructor 
+# 1) AnalyzingDestructor: currently analyzing the type for destructor
 # generation (needed for recursive types)
 # 2) DestructorIsTrivial: completed the analysis before and determined
 # that the type has a trivial destructor
@@ -41,7 +41,7 @@ proc doDestructorStuff(c: PContext, s: PSym, n: PNode) =
     if t.kind != tyGenericBody:
       localError(n.info, errDestructorNotGenericEnough)
       return
-  
+
   t.destructor = s
   # automatically insert calls to base classes' destructors
   if n.sons[bodyPos].kind != nkEmpty:
@@ -71,17 +71,18 @@ proc destroyCase(c: PContext, n: PNode, holder: PNode): PNode =
   result.addSon(newNode(nkDotExpr, n.info, @[holder, n.sons[0]]))
   for i in countup(1, n.len - 1):
     # of A, B:
-    var caseBranch = newNode(n[i].kind, n[i].info, n[i].sons[0 .. -2])
-    
-    let stmt = destroyFieldOrFields(c, n[i].lastSon, holder)
+    let ni = n[i]
+    var caseBranch = newNode(ni.kind, ni.info, ni.sons[0..ni.len-2])
+
+    let stmt = destroyFieldOrFields(c, ni.lastSon, holder)
     if stmt == nil:
-      caseBranch.addSon(newNode(nkStmtList, n[i].info, @[]))
+      caseBranch.addSon(newNode(nkStmtList, ni.info, @[]))
     else:
       caseBranch.addSon(stmt)
       nonTrivialFields += stmt.len
-    
+
     result.addSon(caseBranch)
-  
+
   # maybe no fields were destroyed?
   if nonTrivialFields == 0:
     result = nil
@@ -107,7 +108,7 @@ proc destroyFieldOrFields(c: PContext, field: PNode, holder: PNode): PNode =
 proc generateDestructor(c: PContext, t: PType): PNode =
   ## generate a destructor for a user-defined object or tuple type
   ## returns nil if the destructor turns out to be trivial
-  
+
   # XXX: This may be true for some C-imported types such as
   # Tposix_spawnattr
   if t.n == nil or t.n.sons == nil: return
@@ -120,13 +121,13 @@ proc generateDestructor(c: PContext, t: PType): PNode =
 
 proc instantiateDestructor(c: PContext, typ: PType): PType =
   # returns nil if a variable of type `typ` doesn't require a
-  # destructor. Otherwise, returns the type, which holds the 
+  # destructor. Otherwise, returns the type, which holds the
   # destructor that must be used for the varialbe.
   # The destructor is either user-defined or automatically
   # generated by the compiler in a member-wise fashion.
   var t = skipTypes(typ, {tyConst, tyMutable}).skipGenericAlias
   let typeHoldingUserDefinition = if t.kind == tyGenericInst: t.base else: t
-  
+
   if typeHoldingUserDefinition.destructor != nil:
     # XXX: This is not entirely correct for recursive types, but we need
     # it temporarily to hide the "destroy is already defined" problem
@@ -135,7 +136,7 @@ proc instantiateDestructor(c: PContext, typ: PType): PType =
       return typeHoldingUserDefinition
     else:
       return nil
-  
+
   t = t.skipTypes({tyGenericInst})
   case t.kind
   of tySequence, tyArray, tyArrayConstr, tyOpenArray, tyVarargs:
@@ -200,16 +201,16 @@ proc insertDestructors(c: PContext,
       varId = varSection[j][0]
       varTyp = varId.sym.typ
       info = varId.info
-    
+
     if varTyp == nil or sfGlobal in varId.sym.flags: continue
     let destructableT = instantiateDestructor(c, varTyp)
-    
+
     if destructableT != nil:
       var tryStmt = newNodeI(nkTryStmt, info)
 
       if j < totalVars - 1:
         var remainingVars = newNodeI(varSection.kind, info)
-        remainingVars.sons = varSection.sons[(j+1)..(-1)]
+        remainingVars.sons = varSection.sons[(j+1)..varSection.len-1]
         let (outer, inner) = insertDestructors(c, remainingVars)
         if outer != nil:
           tryStmt.addSon(outer)
@@ -221,7 +222,7 @@ proc insertDestructors(c: PContext,
       else:
         result.inner = newNodeI(nkStmtList, info)
         tryStmt.addSon(result.inner)
-    
+
       tryStmt.addSon(
         newNode(nkFinally, info, @[
           semStmt(c, newNode(nkCall, info, @[
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index a56de1028..28373e3c6 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -1133,19 +1133,20 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
   ## returns nil if not a built-in subscript operator; also called for the
   ## checking of assignments
   if sonsLen(n) == 1:
-    var x = semDeref(c, n)
+    let x = semDeref(c, n)
     if x == nil: return nil
     result = newNodeIT(nkDerefExpr, x.info, x.typ)
     result.add(x[0])
     return
   checkMinSonsLen(n, 2)
   n.sons[0] = semExprWithType(c, n.sons[0])
-  var arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef})
+  let arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef})
   case arr.kind
   of tyArray, tyOpenArray, tyVarargs, tyArrayConstr, tySequence, tyString,
      tyCString:
     if n.len != 2: return nil
     n.sons[0] = makeDeref(n.sons[0])
+    c.p.bracketExpr = n.sons[0]
     for i in countup(1, sonsLen(n) - 1):
       n.sons[i] = semExprWithType(c, n.sons[i],
                                   flags*{efInTypeof, efDetermineType})
@@ -1166,6 +1167,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
   of tyTuple:
     checkSonsLen(n, 2)
     n.sons[0] = makeDeref(n.sons[0])
+    c.p.bracketExpr = n.sons[0]
     # [] operator for tuples requires constant expression:
     n.sons[1] = semConstExpr(c, n.sons[1])
     if skipTypes(n.sons[1].typ, {tyGenericInst, tyRange, tyOrdinal}).kind in
@@ -1176,13 +1178,16 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
     else:
       localError(n.info, errIndexTypesDoNotMatch)
     result = n
-  else: discard
+  else:
+    c.p.bracketExpr = n.sons[0]
 
 proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
+  let oldBracketExpr = c.p.bracketExpr
   result = semSubscript(c, n, flags)
   if result == nil:
     # overloaded [] operator:
     result = semExpr(c, buildOverloadedSubscripts(n, getIdent"[]"))
+  c.p.bracketExpr = oldBracketExpr
 
 proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode =
   var id = considerQuotedIdent(a[1])
@@ -1249,11 +1254,15 @@ proc semAsgn(c: PContext, n: PNode): PNode =
   of nkBracketExpr:
     # a[i] = x
     # --> `[]=`(a, i, x)
+    let oldBracketExpr = c.p.bracketExpr
     a = semSubscript(c, a, {efLValue})
     if a == nil:
       result = buildOverloadedSubscripts(n.sons[0], getIdent"[]=")
       add(result, n[1])
-      return semExprNoType(c, result)
+      result = semExprNoType(c, result)
+      c.p.bracketExpr = oldBracketExpr
+      return result
+    c.p.bracketExpr = oldBracketExpr
   of nkCurlyExpr:
     # a{i} = x -->  `{}=`(a, i, x)
     result = buildOverloadedSubscripts(n.sons[0], getIdent"{}=")
@@ -1895,7 +1904,8 @@ proc checkInitialized(n: PNode, ids: IntSet, info: TLineInfo) =
         of nkOfBranch, nkElse: checkInitialized(lastSon(n.sons[i]), ids, info)
         else: internalError(info, "checkInitialized")
   of nkSym:
-    if tfNeedsInit in n.sym.typ.flags and n.sym.name.id notin ids:
+    if {tfNotNil, tfNeedsInit} * n.sym.typ.flags != {} and
+        n.sym.name.id notin ids:
       message(info, errGenerated, "field not initialized: " & n.sym.name.s)
   else: internalError(info, "checkInitialized")
 
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index a3f1b1c13..2e7179673 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -10,8 +10,8 @@
 # this module folds constants; used by semantic checking phase
 # and evaluation phase
 
-import 
-  strutils, lists, options, ast, astalgo, trees, treetab, nimsets, times, 
+import
+  strutils, lists, options, ast, astalgo, trees, treetab, nimsets, times,
   nversion, platform, math, msgs, os, condsyms, idents, renderer, types,
   commands, magicsys, saturate
 
@@ -41,7 +41,7 @@ proc newIntNodeT(intVal: BiggestInt, n: PNode): PNode =
     result.typ = n.typ
   result.info = n.info
 
-proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode = 
+proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode =
   result = newFloatNode(nkFloatLit, floatVal)
   if skipTypes(n.typ, abstractVarRange).kind == tyFloat:
     result.typ = getFloatLitType(result)
@@ -49,27 +49,27 @@ proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode =
     result.typ = n.typ
   result.info = n.info
 
-proc newStrNodeT(strVal: string, n: PNode): PNode = 
+proc newStrNodeT(strVal: string, n: PNode): PNode =
   result = newStrNode(nkStrLit, strVal)
   result.typ = n.typ
   result.info = n.info
 
-proc ordinalValToString*(a: PNode): string = 
+proc ordinalValToString*(a: PNode): string =
   # because $ has the param ordinal[T], `a` is not necessarily an enum, but an
   # ordinal
   var x = getInt(a)
-  
+
   var t = skipTypes(a.typ, abstractRange)
   case t.kind
-  of tyChar: 
+  of tyChar:
     result = $chr(int(x) and 0xff)
   of tyEnum:
     var n = t.n
-    for i in countup(0, sonsLen(n) - 1): 
+    for i in countup(0, sonsLen(n) - 1):
       if n.sons[i].kind != nkSym: internalError(a.info, "ordinalValToString")
       var field = n.sons[i].sym
-      if field.position == x: 
-        if field.ast == nil: 
+      if field.position == x:
+        if field.ast == nil:
           return field.name.s
         else:
           return field.ast.strVal
@@ -112,7 +112,7 @@ proc pickMaxInt(n: PNode): BiggestInt =
   else:
     internalError(n.info, "pickMaxInt")
 
-proc makeRange(typ: PType, first, last: BiggestInt): PType = 
+proc makeRange(typ: PType, first, last: BiggestInt): PType =
   let minA = min(first, last)
   let maxA = max(first, last)
   let lowerNode = newIntNode(nkIntLit, minA)
@@ -138,7 +138,7 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
   # Nimrod requires interval arithmetic for ``range`` types. Lots of tedious
   # work but the feature is very nice for reducing explicit conversions.
   result = n.typ
-  
+
   template commutativeOp(opr: expr) {.immediate.} =
     let a = n.sons[1]
     let b = n.sons[2]
@@ -146,7 +146,7 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
       result = makeRange(pickIntRange(a.typ, b.typ),
                          opr(pickMinInt(a), pickMinInt(b)),
                          opr(pickMaxInt(a), pickMaxInt(b)))
-  
+
   template binaryOp(opr: expr) {.immediate.} =
     let a = n.sons[1]
     let b = n.sons[2]
@@ -154,7 +154,7 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
       result = makeRange(a.typ,
                          opr(pickMinInt(a), pickMinInt(b)),
                          opr(pickMaxInt(a), pickMaxInt(b)))
-  
+
   case m
   of mUnaryMinusI, mUnaryMinusI64:
     let a = n.sons[1].typ
@@ -231,7 +231,7 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
   of mMaxI, mMaxI64:
     commutativeOp(max)
   else: discard
-  
+
 discard """
   mShlI, mShlI64,
   mShrI, mShrI64, mAddF64, mSubF64, mMulF64, mDivF64, mMaxF64, mMinF64
@@ -242,7 +242,7 @@ proc evalIs(n, a: PNode): PNode =
   internalAssert a.kind == nkSym and a.sym.kind == skType
   internalAssert n.sonsLen == 3 and
     n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
-  
+
   let t1 = a.sym.typ
 
   if n[2].kind in {nkStrLit..nkTripleStrLit}:
@@ -250,12 +250,12 @@ proc evalIs(n, a: PNode): PNode =
     of "closure":
       let t = skipTypes(t1, abstractRange)
       result = newIntNode(nkIntLit, ord(t.kind == tyProc and
-                                        t.callConv == ccClosure and 
+                                        t.callConv == ccClosure and
                                         tfIterator notin t.flags))
     of "iterator":
       let t = skipTypes(t1, abstractRange)
       result = newIntNode(nkIntLit, ord(t.kind == tyProc and
-                                        t.callConv == ccClosure and 
+                                        t.callConv == ccClosure and
                                         tfIterator in t.flags))
     else: discard
   else:
@@ -265,7 +265,7 @@ proc evalIs(n, a: PNode): PNode =
     result = newIntNode(nkIntLit, ord(match))
   result.typ = n.typ
 
-proc evalOp(m: TMagic, n, a, b, c: PNode): PNode = 
+proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
   # b and c may be nil
   result = nil
   case m
@@ -280,14 +280,14 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
   of mLengthArray: result = newIntNodeT(lengthOrd(a.typ), n)
   of mLengthSeq, mLengthOpenArray: result = newIntNodeT(sonsLen(a), n) # BUGFIX
   of mUnaryPlusI, mUnaryPlusI64, mUnaryPlusF64: result = a # throw `+` away
-  of mToFloat, mToBiggestFloat: 
+  of mToFloat, mToBiggestFloat:
     result = newFloatNodeT(toFloat(int(getInt(a))), n)
   of mToInt, mToBiggestInt: result = newIntNodeT(system.toInt(getFloat(a)), n)
   of mAbsF64: result = newFloatNodeT(abs(getFloat(a)), n)
-  of mAbsI, mAbsI64: 
+  of mAbsI, mAbsI64:
     if getInt(a) >= 0: result = a
     else: result = newIntNodeT(- getInt(a), n)
-  of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64: 
+  of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64:
     # byte(-128) = 1...1..1000_0000'64 --> 0...0..1000_0000'64
     result = newIntNodeT(getInt(a) and (`shl`(1, getSize(a.typ) * 8) - 1), n)
   of mToU8: result = newIntNodeT(getInt(a) and 0x000000FF, n)
@@ -299,21 +299,21 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
   of mAddI, mAddI64: result = newIntNodeT(getInt(a) + getInt(b), n)
   of mSubI, mSubI64: result = newIntNodeT(getInt(a) - getInt(b), n)
   of mMulI, mMulI64: result = newIntNodeT(getInt(a) * getInt(b), n)
-  of mMinI, mMinI64: 
+  of mMinI, mMinI64:
     if getInt(a) > getInt(b): result = newIntNodeT(getInt(b), n)
     else: result = newIntNodeT(getInt(a), n)
-  of mMaxI, mMaxI64: 
+  of mMaxI, mMaxI64:
     if getInt(a) > getInt(b): result = newIntNodeT(getInt(a), n)
     else: result = newIntNodeT(getInt(b), n)
-  of mShlI, mShlI64: 
+  of mShlI, mShlI64:
     case skipTypes(n.typ, abstractRange).kind
     of tyInt8: result = newIntNodeT(int8(getInt(a)) shl int8(getInt(b)), n)
     of tyInt16: result = newIntNodeT(int16(getInt(a)) shl int16(getInt(b)), n)
     of tyInt32: result = newIntNodeT(int32(getInt(a)) shl int32(getInt(b)), n)
-    of tyInt64, tyInt, tyUInt..tyUInt64: 
+    of tyInt64, tyInt, tyUInt..tyUInt64:
       result = newIntNodeT(`shl`(getInt(a), getInt(b)), n)
     else: internalError(n.info, "constant folding for shl")
-  of mShrI, mShrI64: 
+  of mShrI, mShrI64:
     case skipTypes(n.typ, abstractRange).kind
     of tyInt8: result = newIntNodeT(int8(getInt(a)) shr int8(getInt(b)), n)
     of tyInt16: result = newIntNodeT(int16(getInt(a)) shr int16(getInt(b)), n)
@@ -332,34 +332,34 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
   of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n)
   of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n)
   of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n)
-  of mDivF64: 
-    if getFloat(b) == 0.0: 
+  of mDivF64:
+    if getFloat(b) == 0.0:
       if getFloat(a) == 0.0: result = newFloatNodeT(NaN, n)
       else: result = newFloatNodeT(Inf, n)
-    else: 
+    else:
       result = newFloatNodeT(getFloat(a) / getFloat(b), n)
-  of mMaxF64: 
+  of mMaxF64:
     if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(a), n)
     else: result = newFloatNodeT(getFloat(b), n)
-  of mMinF64: 
+  of mMinF64:
     if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(b), n)
     else: result = newFloatNodeT(getFloat(a), n)
   of mIsNil: result = newIntNodeT(ord(a.kind == nkNilLit), n)
-  of mLtI, mLtI64, mLtB, mLtEnum, mLtCh: 
+  of mLtI, mLtI64, mLtB, mLtEnum, mLtCh:
     result = newIntNodeT(ord(getOrdValue(a) < getOrdValue(b)), n)
-  of mLeI, mLeI64, mLeB, mLeEnum, mLeCh: 
+  of mLeI, mLeI64, mLeB, mLeEnum, mLeCh:
     result = newIntNodeT(ord(getOrdValue(a) <= getOrdValue(b)), n)
-  of mEqI, mEqI64, mEqB, mEqEnum, mEqCh: 
-    result = newIntNodeT(ord(getOrdValue(a) == getOrdValue(b)), n) 
+  of mEqI, mEqI64, mEqB, mEqEnum, mEqCh:
+    result = newIntNodeT(ord(getOrdValue(a) == getOrdValue(b)), n)
   of mLtF64: result = newIntNodeT(ord(getFloat(a) < getFloat(b)), n)
   of mLeF64: result = newIntNodeT(ord(getFloat(a) <= getFloat(b)), n)
-  of mEqF64: result = newIntNodeT(ord(getFloat(a) == getFloat(b)), n) 
+  of mEqF64: result = newIntNodeT(ord(getFloat(a) == getFloat(b)), n)
   of mLtStr: result = newIntNodeT(ord(getStr(a) < getStr(b)), n)
   of mLeStr: result = newIntNodeT(ord(getStr(a) <= getStr(b)), n)
   of mEqStr: result = newIntNodeT(ord(getStr(a) == getStr(b)), n)
-  of mLtU, mLtU64: 
+  of mLtU, mLtU64:
     result = newIntNodeT(ord(`<%`(getOrdValue(a), getOrdValue(b))), n)
-  of mLeU, mLeU64: 
+  of mLeU, mLeU64:
     result = newIntNodeT(ord(`<=%`(getOrdValue(a), getOrdValue(b))), n)
   of mBitandI, mBitandI64, mAnd: result = newIntNodeT(a.getInt and b.getInt, n)
   of mBitorI, mBitorI64, mOr: result = newIntNodeT(getInt(a) or getInt(b), n)
@@ -377,18 +377,18 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
       result = newIntNodeT(`/%`(getInt(a), y), n)
   of mLeSet: result = newIntNodeT(ord(containsSets(a, b)), n)
   of mEqSet: result = newIntNodeT(ord(equalSets(a, b)), n)
-  of mLtSet: 
+  of mLtSet:
     result = newIntNodeT(ord(containsSets(a, b) and not equalSets(a, b)), n)
-  of mMulSet: 
+  of mMulSet:
     result = nimsets.intersectSets(a, b)
     result.info = n.info
-  of mPlusSet: 
+  of mPlusSet:
     result = nimsets.unionSets(a, b)
     result.info = n.info
-  of mMinusSet: 
+  of mMinusSet:
     result = nimsets.diffSets(a, b)
     result.info = n.info
-  of mSymDiffSet: 
+  of mSymDiffSet:
     result = nimsets.symdiffSets(a, b)
     result.info = n.info
   of mConStrStr: result = newStrNodeT(getStrOrChar(a) & getStrOrChar(b), n)
@@ -397,104 +397,104 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
     # BUGFIX: we cannot eval mRepr here for reasons that I forgot.
     discard
   of mIntToStr, mInt64ToStr: result = newStrNodeT($(getOrdValue(a)), n)
-  of mBoolToStr: 
+  of mBoolToStr:
     if getOrdValue(a) == 0: result = newStrNodeT("false", n)
     else: result = newStrNodeT("true", n)
   of mCopyStr: result = newStrNodeT(substr(getStr(a), int(getOrdValue(b))), n)
-  of mCopyStrLast: 
-    result = newStrNodeT(substr(getStr(a), int(getOrdValue(b)), 
+  of mCopyStrLast:
+    result = newStrNodeT(substr(getStr(a), int(getOrdValue(b)),
                                            int(getOrdValue(c))), n)
   of mFloatToStr: result = newStrNodeT($getFloat(a), n)
   of mCStrToStr, mCharToStr: result = newStrNodeT(getStrOrChar(a), n)
   of mStrToStr: result = a
   of mEnumToStr: result = newStrNodeT(ordinalValToString(a), n)
-  of mArrToSeq: 
+  of mArrToSeq:
     result = copyTree(a)
     result.typ = n.typ
   of mCompileOption:
-    result = newIntNodeT(ord(commands.testCompileOption(a.getStr, n.info)), n)  
+    result = newIntNodeT(ord(commands.testCompileOption(a.getStr, n.info)), n)
   of mCompileOptionArg:
     result = newIntNodeT(ord(
       testCompileOptionArg(getStr(a), getStr(b), n.info)), n)
-  of mNewString, mNewStringOfCap, 
-     mExit, mInc, ast.mDec, mEcho, mSwap, mAppendStrCh, 
-     mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq, 
-     mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait,
+  of mNewString, mNewStringOfCap,
+     mExit, mInc, ast.mDec, mEcho, mSwap, mAppendStrCh,
+     mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq,
+     mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait, mDotDot,
      mNLen..mNError, mEqRef, mSlurp, mStaticExec, mNGenSym, mSpawn, mParallel:
     discard
   else: internalError(a.info, "evalOp(" & $m & ')')
-  
-proc getConstIfExpr(c: PSym, n: PNode): PNode = 
+
+proc getConstIfExpr(c: PSym, n: PNode): PNode =
   result = nil
-  for i in countup(0, sonsLen(n) - 1): 
+  for i in countup(0, sonsLen(n) - 1):
     var it = n.sons[i]
     if it.len == 2:
       var e = getConstExpr(c, it.sons[0])
       if e == nil: return nil
-      if getOrdValue(e) != 0: 
-        if result == nil: 
+      if getOrdValue(e) != 0:
+        if result == nil:
           result = getConstExpr(c, it.sons[1])
-          if result == nil: return 
+          if result == nil: return
     elif it.len == 1:
       if result == nil: result = getConstExpr(c, it.sons[0])
     else: internalError(it.info, "getConstIfExpr()")
 
-proc partialAndExpr(c: PSym, n: PNode): PNode = 
+proc partialAndExpr(c: PSym, n: PNode): PNode =
   # partial evaluation
   result = n
   var a = getConstExpr(c, n.sons[1])
   var b = getConstExpr(c, n.sons[2])
-  if a != nil: 
+  if a != nil:
     if getInt(a) == 0: result = a
     elif b != nil: result = b
     else: result = n.sons[2]
-  elif b != nil: 
+  elif b != nil:
     if getInt(b) == 0: result = b
     else: result = n.sons[1]
-  
-proc partialOrExpr(c: PSym, n: PNode): PNode = 
+
+proc partialOrExpr(c: PSym, n: PNode): PNode =
   # partial evaluation
   result = n
   var a = getConstExpr(c, n.sons[1])
   var b = getConstExpr(c, n.sons[2])
-  if a != nil: 
+  if a != nil:
     if getInt(a) != 0: result = a
     elif b != nil: result = b
     else: result = n.sons[2]
-  elif b != nil: 
+  elif b != nil:
     if getInt(b) != 0: result = b
     else: result = n.sons[1]
-  
-proc leValueConv(a, b: PNode): bool = 
+
+proc leValueConv(a, b: PNode): bool =
   result = false
   case a.kind
-  of nkCharLit..nkUInt64Lit: 
+  of nkCharLit..nkUInt64Lit:
     case b.kind
     of nkCharLit..nkUInt64Lit: result = a.intVal <= b.intVal
     of nkFloatLit..nkFloat128Lit: result = a.intVal <= round(b.floatVal)
     else: internalError(a.info, "leValueConv")
-  of nkFloatLit..nkFloat128Lit: 
+  of nkFloatLit..nkFloat128Lit:
     case b.kind
     of nkFloatLit..nkFloat128Lit: result = a.floatVal <= b.floatVal
     of nkCharLit..nkUInt64Lit: result = a.floatVal <= toFloat(int(b.intVal))
     else: internalError(a.info, "leValueConv")
   else: internalError(a.info, "leValueConv")
-  
+
 proc magicCall(m: PSym, n: PNode): PNode =
   if sonsLen(n) <= 1: return
 
   var s = n.sons[0].sym
   var a = getConstExpr(m, n.sons[1])
   var b, c: PNode
-  if a == nil: return 
-  if sonsLen(n) > 2: 
+  if a == nil: return
+  if sonsLen(n) > 2:
     b = getConstExpr(m, n.sons[2])
-    if b == nil: return 
-    if sonsLen(n) > 3: 
+    if b == nil: return
+    if sonsLen(n) > 3:
       c = getConstExpr(m, n.sons[3])
-      if c == nil: return 
+      if c == nil: return
   result = evalOp(s.magic, n, a, b, c)
-  
+
 proc getAppType(n: PNode): PNode =
   if gGlobalOptions.contains(optGenDynLib):
     result = newStrNodeT("lib", n)
@@ -510,48 +510,48 @@ proc rangeCheck(n: PNode, value: BiggestInt) =
     localError(n.info, errGenerated, "cannot convert " & $value &
                                      " to " & typeToString(n.typ))
 
-proc foldConv*(n, a: PNode; check = false): PNode = 
+proc foldConv*(n, a: PNode; check = false): PNode =
   # XXX range checks?
   case skipTypes(n.typ, abstractRange).kind
-  of tyInt..tyInt64: 
+  of tyInt..tyInt64:
     case skipTypes(a.typ, abstractRange).kind
     of tyFloat..tyFloat64:
       result = newIntNodeT(int(getFloat(a)), n)
     of tyChar: result = newIntNodeT(getOrdValue(a), n)
-    else: 
+    else:
       result = a
       result.typ = n.typ
     if check: rangeCheck(n, result.intVal)
   of tyFloat..tyFloat64:
     case skipTypes(a.typ, abstractRange).kind
-    of tyInt..tyInt64, tyEnum, tyBool, tyChar: 
+    of tyInt..tyInt64, tyEnum, tyBool, tyChar:
       result = newFloatNodeT(toFloat(int(getOrdValue(a))), n)
     else:
       result = a
       result.typ = n.typ
-  of tyOpenArray, tyVarargs, tyProc: 
+  of tyOpenArray, tyVarargs, tyProc:
     discard
-  else: 
+  else:
     result = a
     result.typ = n.typ
-  
+
 proc getArrayConstr(m: PSym, n: PNode): PNode =
   if n.kind == nkBracket:
     result = n
   else:
     result = getConstExpr(m, n)
     if result == nil: result = n
-  
-proc foldArrayAccess(m: PSym, n: PNode): PNode = 
+
+proc foldArrayAccess(m: PSym, n: PNode): PNode =
   var x = getConstExpr(m, n.sons[0])
   if x == nil or x.typ.skipTypes({tyGenericInst}).kind == tyTypeDesc: return
-  
+
   var y = getConstExpr(m, n.sons[1])
   if y == nil: return
-  
+
   var idx = getOrdValue(y)
   case x.kind
-  of nkPar: 
+  of nkPar:
     if idx >= 0 and idx < sonsLen(x):
       result = x.sons[int(idx)]
       if result.kind == nkExprColonExpr: result = result.sons[1]
@@ -563,14 +563,14 @@ proc foldArrayAccess(m: PSym, n: PNode): PNode =
     else: localError(n.info, errIndexOutOfBounds)
   of nkStrLit..nkTripleStrLit:
     result = newNodeIT(nkCharLit, x.info, n.typ)
-    if idx >= 0 and idx < len(x.strVal): 
+    if idx >= 0 and idx < len(x.strVal):
       result.intVal = ord(x.strVal[int(idx)])
-    elif idx == len(x.strVal): 
+    elif idx == len(x.strVal):
       discard
-    else: 
+    else:
       localError(n.info, errIndexOutOfBounds)
   else: discard
-  
+
 proc foldFieldAccess(m: PSym, n: PNode): PNode =
   # a real field access; proc calls have already been transformed
   var x = getConstExpr(m, n.sons[0])
@@ -584,15 +584,15 @@ proc foldFieldAccess(m: PSym, n: PNode): PNode =
       result = x.sons[field.position]
       if result.kind == nkExprColonExpr: result = result.sons[1]
       return
-    if it.sons[0].sym.name.id == field.name.id: 
+    if it.sons[0].sym.name.id == field.name.id:
       result = x.sons[i].sons[1]
       return
   localError(n.info, errFieldXNotFound, field.name.s)
-  
-proc foldConStrStr(m: PSym, n: PNode): PNode = 
+
+proc foldConStrStr(m: PSym, n: PNode): PNode =
   result = newNodeIT(nkStrLit, n.info, n.typ)
   result.strVal = ""
-  for i in countup(1, sonsLen(n) - 1): 
+  for i in countup(1, sonsLen(n) - 1):
     let a = getConstExpr(m, n.sons[i])
     if a == nil: return nil
     result.strVal.add(getStrOrChar(a))
@@ -602,10 +602,10 @@ proc newSymNodeTypeDesc*(s: PSym; info: TLineInfo): PNode =
   result.typ = newType(tyTypeDesc, s.owner)
   result.typ.addSonSkipIntLit(s.typ)
 
-proc getConstExpr(m: PSym, n: PNode): PNode = 
+proc getConstExpr(m: PSym, n: PNode): PNode =
   result = nil
   case n.kind
-  of nkSym: 
+  of nkSym:
     var s = n.sym
     case s.kind
     of skEnumField:
@@ -636,14 +636,14 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
       else:
         result = newSymNodeTypeDesc(s, n.info)
     else: discard
-  of nkCharLit..nkNilLit: 
+  of nkCharLit..nkNilLit:
     result = copyNode(n)
-  of nkIfExpr: 
+  of nkIfExpr:
     result = getConstIfExpr(m, n)
-  of nkCall, nkCommand, nkCallStrLit, nkPrefix, nkInfix: 
-    if n.sons[0].kind != nkSym: return 
+  of nkCall, nkCommand, nkCallStrLit, nkPrefix, nkInfix:
+    if n.sons[0].kind != nkSym: return
     var s = n.sons[0].sym
-    if s.kind != skProc: return 
+    if s.kind != skProc: return
     try:
       case s.magic
       of mNone:
@@ -651,8 +651,8 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
         return
       of mSizeOf:
         var a = n.sons[1]
-        if computeSize(a.typ) < 0: 
-          localError(a.info, errCannotEvalXBecauseIncompletelyDefined, 
+        if computeSize(a.typ) < 0:
+          localError(a.info, errCannotEvalXBecauseIncompletelyDefined,
                      "sizeof")
           result = nil
         elif skipTypes(a.typ, typedescInst).kind in
@@ -662,21 +662,21 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
         else:
           result = nil
           # XXX: size computation for complex types is still wrong
-      of mLow: 
+      of mLow:
         result = newIntNodeT(firstOrd(n.sons[1].typ), n)
-      of mHigh: 
+      of mHigh:
         if skipTypes(n.sons[1].typ, abstractVar).kind notin
             {tySequence, tyString, tyCString, tyOpenArray, tyVarargs}:
           result = newIntNodeT(lastOrd(skipTypes(n[1].typ, abstractVar)), n)
         else:
           var a = getArrayConstr(m, n.sons[1])
           if a.kind == nkBracket:
-            # we can optimize it away: 
+            # we can optimize it away:
             result = newIntNodeT(sonsLen(a)-1, n)
       of mLengthOpenArray:
         var a = getArrayConstr(m, n.sons[1])
         if a.kind == nkBracket:
-          # we can optimize it away! This fixes the bug ``len(134)``. 
+          # we can optimize it away! This fixes the bug ``len(134)``.
           result = newIntNodeT(sonsLen(a), n)
         else:
           result = magicCall(m, n)
@@ -694,33 +694,33 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
           result = evalIs(n, a)
       else:
         result = magicCall(m, n)
-    except OverflowError: 
+    except OverflowError:
       localError(n.info, errOverOrUnderflow)
-    except DivByZeroError: 
+    except DivByZeroError:
       localError(n.info, errConstantDivisionByZero)
-  of nkAddr: 
+  of nkAddr:
     var a = getConstExpr(m, n.sons[0])
-    if a != nil: 
+    if a != nil:
       result = n
       n.sons[0] = a
-  of nkBracket: 
+  of nkBracket:
     result = copyTree(n)
-    for i in countup(0, sonsLen(n) - 1): 
+    for i in countup(0, sonsLen(n) - 1):
       var a = getConstExpr(m, n.sons[i])
       if a == nil: return nil
       result.sons[i] = a
     incl(result.flags, nfAllConst)
-  of nkRange: 
+  of nkRange:
     var a = getConstExpr(m, n.sons[0])
-    if a == nil: return 
+    if a == nil: return
     var b = getConstExpr(m, n.sons[1])
-    if b == nil: return 
+    if b == nil: return
     result = copyNode(n)
     addSon(result, a)
     addSon(result, b)
-  of nkCurly: 
+  of nkCurly:
     result = copyTree(n)
-    for i in countup(0, sonsLen(n) - 1): 
+    for i in countup(0, sonsLen(n) - 1):
       var a = getConstExpr(m, n.sons[i])
       if a == nil: return nil
       result.sons[i] = a
@@ -735,33 +735,33 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
   of nkPar:
     # tuple constructor
     result = copyTree(n)
-    if (sonsLen(n) > 0) and (n.sons[0].kind == nkExprColonExpr): 
-      for i in countup(0, sonsLen(n) - 1): 
+    if (sonsLen(n) > 0) and (n.sons[0].kind == nkExprColonExpr):
+      for i in countup(0, sonsLen(n) - 1):
         var a = getConstExpr(m, n.sons[i].sons[1])
         if a == nil: return nil
         result.sons[i].sons[1] = a
-    else: 
-      for i in countup(0, sonsLen(n) - 1): 
+    else:
+      for i in countup(0, sonsLen(n) - 1):
         var a = getConstExpr(m, n.sons[i])
         if a == nil: return nil
         result.sons[i] = a
     incl(result.flags, nfAllConst)
-  of nkChckRangeF, nkChckRange64, nkChckRange: 
+  of nkChckRangeF, nkChckRange64, nkChckRange:
     var a = getConstExpr(m, n.sons[0])
-    if a == nil: return 
-    if leValueConv(n.sons[1], a) and leValueConv(a, n.sons[2]): 
+    if a == nil: return
+    if leValueConv(n.sons[1], a) and leValueConv(a, n.sons[2]):
       result = a              # a <= x and x <= b
       result.typ = n.typ
-    else: 
+    else:
       localError(n.info, errGenerated, `%`(
-          msgKindToString(errIllegalConvFromXtoY), 
+          msgKindToString(errIllegalConvFromXtoY),
           [typeToString(n.sons[0].typ), typeToString(n.typ)]))
-  of nkStringToCString, nkCStringToString: 
+  of nkStringToCString, nkCStringToString:
     var a = getConstExpr(m, n.sons[0])
-    if a == nil: return 
+    if a == nil: return
     result = a
     result.typ = n.typ
-  of nkHiddenStdConv, nkHiddenSubConv, nkConv: 
+  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
     var a = getConstExpr(m, n.sons[1])
     if a == nil: return
     result = foldConv(n, a, check=n.kind == nkHiddenStdConv)
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index 3c9784152..de7700be6 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -130,6 +130,18 @@ proc semLocals(c: PContext, n: PNode): PNode =
         result.add(a)
 
 proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode
+
+proc isStrangeArray(t: PType): bool =
+  let t = t.skipTypes(abstractInst)
+  result = t.kind == tyArray and t.firstOrd != 0
+
+proc isNegative(n: PNode): bool =
+  let n = n.skipConv
+  if n.kind in {nkCharLit..nkUInt64Lit}:
+    result = n.intVal < 0
+  elif n.kind in nkCallKinds and n.sons[0].kind == nkSym:
+    result = n.sons[0].sym.magic in {mUnaryMinusI, mUnaryMinusI64}
+
 proc magicsAfterOverloadResolution(c: PContext, n: PNode,
                                    flags: TExprFlags): PNode =
   case n[0].sym.magic
@@ -153,4 +165,35 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
   of mProcCall:
     result = n
     result.typ = n[1].typ
+  of mDotDot:
+    result = n
+    # disallow negative indexing for now:
+    if not c.p.bracketExpr.isNil:
+      if isNegative(n.sons[1]) or (n.len > 2 and isNegative(n.sons[2])):
+        localError(n.info, "use '^' instead of '-'; negative indexing is obsolete")
+  of mRoof:
+    # error correction:
+    result = n.sons[1]
+    if c.p.bracketExpr.isNil:
+      localError(n.info, "no surrounding array access context for '^'")
+    elif c.p.bracketExpr.checkForSideEffects != seNoSideEffect:
+      localError(n.info, "invalid context for '^' as '$#' has side effects" %
+        renderTree(c.p.bracketExpr))
+    elif c.p.bracketExpr.typ.isStrangeArray:
+      localError(n.info, "invalid context for '^' as len!=high+1 for '$#'" %
+        renderTree(c.p.bracketExpr))
+    else:
+      # ^x  is rewritten to: len(a)-x
+      let lenExpr = newNodeI(nkCall, n.info)
+      lenExpr.add newIdentNode(getIdent"len", n.info)
+      lenExpr.add c.p.bracketExpr
+      let lenExprB = semExprWithType(c, lenExpr)
+      if lenExprB.typ.isNil or not isOrdinalType(lenExprB.typ):
+        localError(n.info, "'$#' has to be of an ordinal type for '^'" %
+          renderTree(lenExpr))
+      else:
+        result = newNodeIT(nkCall, n.info, getSysType(tyInt))
+        result.add newSymNode(createMagic("-", mSubI), n.info)
+        result.add lenExprB
+        result.add n.sons[1]
   else: result = n
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index ae0cbd84f..7263b21b9 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -1281,7 +1281,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
       var tryStmt = newNodeI(nkTryStmt, n.sons[i].info)
       var body = newNodeI(nkStmtList, n.sons[i].info)
       if i < n.sonsLen - 1:
-        body.sons = n.sons[(i+1)..(-1)]
+        body.sons = n.sons[(i+1)..n.len-1]
       tryStmt.addSon(body)
       tryStmt.addSon(deferPart)
       n.sons[i] = semTry(c, tryStmt)
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index a19cc65c3..1da4d7352 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -1175,6 +1175,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
         result = semAnyRef(c, n, tyPtr, prev)
       elif op.id == ord(wRef):
         result = semAnyRef(c, n, tyRef, prev)
+      elif op.id == ord(wType):
+        checkSonsLen(n, 2)
+        let typExpr = semExprWithType(c, n.sons[1], {efInTypeof})
+        result = typExpr.typ.skipTypes({tyIter})
       else:
         result = semTypeExpr(c, n)
   of nkWhenStmt:
diff --git a/compiler/types.nim b/compiler/types.nim
index f4ac4daea..153c26a42 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -590,7 +590,7 @@ proc firstOrd(t: PType): BiggestInt =
   of tyUInt..tyUInt64: result = 0
   of tyEnum:
     # if basetype <> nil then return firstOrd of basetype
-    if (sonsLen(t) > 0) and (t.sons[0] != nil):
+    if sonsLen(t) > 0 and t.sons[0] != nil:
       result = firstOrd(t.sons[0])
     else:
       assert(t.n.sons[0].kind == nkSym)
diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim
index 2b80f6aed..6148ed319 100644
--- a/compiler/vmdeps.nim
+++ b/compiler/vmdeps.nim
@@ -42,6 +42,7 @@ proc opSlurp*(file: string, info: TLineInfo, module: PSym): string =
 
 proc atomicTypeX(name: string; t: PType; info: TLineInfo): PNode =
   let sym = newSym(skType, getIdent(name), t.owner, info)
+  sym.typ = t
   result = newSymNode(sym)
   result.typ = t
 
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index 2383e2542..3178bee60 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -1008,7 +1008,8 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
     if dest < 0: dest = c.getTemp(n.typ)
     c.gABC(n, opcCallSite, dest)
   of mNGenSym: genBinaryABC(c, n, dest, opcGenSym)
-  of mMinI, mMaxI, mMinI64, mMaxI64, mAbsF64, mMinF64, mMaxF64, mAbsI, mAbsI64:
+  of mMinI, mMaxI, mMinI64, mMaxI64, mAbsF64, mMinF64, mMaxF64, mAbsI,
+     mAbsI64, mDotDot:
     c.genCall(n, dest)
   of mExpandToAst:
     if n.len != 2: