summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim5
-rw-r--r--compiler/ccgexprs.nim7
-rw-r--r--compiler/cgen.nim2
-rw-r--r--compiler/condsyms.nim1
-rw-r--r--compiler/msgs.nim1
-rw-r--r--compiler/semcall.nim5
-rw-r--r--compiler/semdata.nim3
-rw-r--r--compiler/semexprs.nim62
-rw-r--r--compiler/semfold.nim9
-rw-r--r--compiler/semgnrc.nim23
-rw-r--r--compiler/seminst.nim2
-rw-r--r--compiler/semmagic.nim34
-rw-r--r--compiler/semstmts.nim2
-rw-r--r--compiler/semtempl.nim51
-rw-r--r--compiler/semtypes.nim35
-rw-r--r--compiler/sigmatch.nim4
16 files changed, 206 insertions, 40 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 860bf67e8..be11e80be 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -477,6 +477,8 @@ type
                       # wildcard type.
     tfHasAsgn         # type has overloaded assignment operator
     tfBorrowDot       # distinct type borrows '.'
+    tfTriggersCompileTime # uses the NimNode type which make the proc
+                          # implicitly '.compiletime'
 
   TTypeFlags* = set[TTypeFlag]
 
@@ -1380,6 +1382,9 @@ proc propagateToOwner*(owner, elem: PType) =
       o2.flags.incl tfHasAsgn
       owner.flags.incl tfHasAsgn
 
+  if tfTriggersCompileTime in elem.flags:
+    owner.flags.incl tfTriggersCompileTime
+
   if owner.kind notin {tyProc, tyGenericInst, tyGenericBody,
                        tyGenericInvocation, tyPtr}:
     let elemB = elem.skipTypes({tyGenericInst})
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 54063229f..32fc76470 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -1741,6 +1741,8 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   of mEcho: genEcho(p, e[1].skipConv)
   of mArrToSeq: genArrToSeq(p, e, d)
   of mNLen..mNError, mSlurp..mQuoteAst:
+    echo "from here ", p.prc.name.s, " ", p.prc.info
+    writestacktrace()
     localError(e.info, errXMustBeCompileTime, e.sons[0].sym.name.s)
   of mSpawn:
     let n = lowerings.wrapProcForSpawn(p.module.module, e, e.typ, nil, nil)
@@ -1973,6 +1975,9 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
         genProc(p.module, sym)
       putLocIntoDest(p, d, sym.loc)
     of skProc, skConverter, skIterators:
+      if sfCompileTime in sym.flags:
+        localError(n.info, "request to generate code for .compileTime proc: " &
+           sym.name.s)
       genProc(p.module, sym)
       if sym.loc.r == nil or sym.loc.t == nil:
         internalError(n.info, "expr: proc not init " & sym.name.s)
@@ -2126,7 +2131,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
       # due to a bug/limitation in the lambda lifting, unused inner procs
       # are not transformed correctly. We work around this issue (#411) here
       # by ensuring it's no inner proc (owner is a module):
-      if prc.skipGenericOwner.kind == skModule:
+      if prc.skipGenericOwner.kind == skModule and sfCompileTime notin prc.flags:
         if (optDeadCodeElim notin gGlobalOptions and
             sfDeadCodeElim notin getModule(prc).flags) or
             ({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 3f88e63ee..f63134b66 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -1110,7 +1110,7 @@ proc rawNewModule(module: PSym, filename: string): BModule =
 
 proc nullify[T](arr: var T) =
   for i in low(arr)..high(arr):
-    arr[i] = nil
+    arr[i] = Rope(nil)
 
 proc resetModule*(m: BModule) =
   # between two compilations in CAAS mode, we can throw
diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim
index 31bd85a06..60e8f2826 100644
--- a/compiler/condsyms.nim
+++ b/compiler/condsyms.nim
@@ -92,3 +92,4 @@ proc initDefines*() =
   defineSymbol("nimvarargstyped")
   defineSymbol("nimtypedescfixed")
   defineSymbol("nimKnowsNimvm")
+  defineSymbol("nimArrIdx")
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 8b3b11f4a..c5bc44664 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -514,6 +514,7 @@ const
     {low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit,
                                          warnProveField, warnProveIndex,
                                          warnGcUnsafe,
+                                         hintPath, hintConf,
                                          hintDependency,
                                          hintExecuting,
                                          hintCodeBegin, hintCodeEnd,
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index 2f181b5f3..f9fadeec7 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -308,7 +308,10 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
   let gp = finalCallee.ast.sons[genericParamsPos]
   if gp.kind != nkEmpty:
     if x.calleeSym.kind notin {skMacro, skTemplate}:
-      finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info)
+      if x.calleeSym.magic in {mArrGet, mArrPut}:
+        finalCallee = x.calleeSym
+      else:
+        finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info)
     else:
       # For macros and templates, the resolved generic params
       # are added as normal params.
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 345a8c0d1..e6456293c 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -45,7 +45,8 @@ type
   TExprFlag* = enum
     efLValue, efWantIterator, efInTypeof,
     efWantStmt, efAllowStmt, efDetermineType,
-    efAllowDestructor, efWantValue, efOperand, efNoSemCheck
+    efAllowDestructor, efWantValue, efOperand, efNoSemCheck,
+    efNoProcvarCheck
   TExprFlags* = set[TExprFlag]
 
   TTypeAttachedOp* = enum
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 3ff04a4fc..0e1d52fd4 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -52,7 +52,7 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     result.typ = errorType(c)
   else:
     # XXX tyGenericInst here?
-    semProcvarCheck(c, result)
+    if efNoProcvarCheck notin flags: semProcvarCheck(c, result)
     if result.typ.kind == tyVar: result = newDeref(result)
     semDestructorCheck(c, result, flags)
 
@@ -452,18 +452,18 @@ proc changeType(n: PNode, newType: PType, check: bool) =
     let tup = newType.skipTypes({tyGenericInst})
     if tup.kind != tyTuple:
       if tup.kind == tyObject: return
-      internalError(n.info, "changeType: no tuple type for constructor")
+      globalError(n.info, "no tuple type for constructor")
     elif sonsLen(n) > 0 and n.sons[0].kind == nkExprColonExpr:
       # named tuple?
       for i in countup(0, sonsLen(n) - 1):
         var m = n.sons[i].sons[0]
         if m.kind != nkSym:
-          internalError(m.info, "changeType(): invalid tuple constr")
+          globalError(m.info, "invalid tuple constructor")
           return
         if tup.n != nil:
           var f = getSymFromList(tup.n, m.sym.name)
           if f == nil:
-            internalError(m.info, "changeType(): invalid identifier")
+            globalError(m.info, "unknown identifier: " & m.sym.name.s)
             return
           changeType(n.sons[i].sons[1], f.typ, check)
         else:
@@ -1156,7 +1156,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
     result.add(x[0])
     return
   checkMinSonsLen(n, 2)
-  n.sons[0] = semExprWithType(c, n.sons[0])
+  n.sons[0] = semExprWithType(c, n.sons[0], {efNoProcvarCheck})
   let arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef})
   case arr.kind
   of tyArray, tyOpenArray, tyVarargs, tyArrayConstr, tySequence, tyString,
@@ -1196,7 +1196,17 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
       localError(n.info, errIndexTypesDoNotMatch)
     result = n
   else:
-    c.p.bracketExpr = n.sons[0]
+    let s = if n.sons[0].kind == nkSym: n.sons[0].sym
+            elif n[0].kind in nkSymChoices: n.sons[0][0].sym
+            else: nil
+    if s != nil and s.kind in {skProc, skMethod, skConverter}+skIterators:
+      # type parameters: partial generic specialization
+      n.sons[0] = semSymGenericInstantiation(c, n.sons[0], s)
+      result = explicitGenericInstantiation(c, n, s)
+    elif s != nil and s.kind == skType:
+      result = symNodeFromType(c, semTypeNode(c, n, nil), n.info)
+    else:
+      c.p.bracketExpr = n.sons[0]
 
 proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
   let oldBracketExpr = c.p.bracketExpr
@@ -1250,7 +1260,7 @@ proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} =
 template resultTypeIsInferrable(typ: PType): expr =
   typ.isMetaType and typ.kind != tyTypeDesc
 
-proc semAsgn(c: PContext, n: PNode): PNode =
+proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
   checkSonsLen(n, 2)
   var a = n.sons[0]
   case a.kind
@@ -1273,12 +1283,15 @@ proc semAsgn(c: PContext, n: PNode): PNode =
     # --> `[]=`(a, i, x)
     let oldBracketExpr = c.p.bracketExpr
     a = semSubscript(c, a, {efLValue})
-    if a == nil:
+    if a == nil and mode != noOverloadedSubscript:
       result = buildOverloadedSubscripts(n.sons[0], getIdent"[]=")
       add(result, n[1])
       result = semExprNoType(c, result)
       c.p.bracketExpr = oldBracketExpr
       return result
+    elif a == nil:
+      localError(n.info, "could not resolve: " & $n[0])
+      return n
     c.p.bracketExpr = oldBracketExpr
   of nkCurlyExpr:
     # a{i} = x -->  `{}=`(a, i, x)
@@ -1323,7 +1336,8 @@ proc semAsgn(c: PContext, n: PNode): PNode =
           typeMismatch(n, lhs.typ, rhs.typ)
 
     n.sons[1] = fitNode(c, le, rhs)
-    if tfHasAsgn in lhs.typ.flags and not lhsIsResult:
+    if tfHasAsgn in lhs.typ.flags and not lhsIsResult and
+        mode != noOverloadedAsgn:
       return overloadedAsgn(c, lhs, n.sons[1])
 
     fixAbstractType(c, n)
@@ -1715,6 +1729,9 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
   of mTypeOf:
     checkSonsLen(n, 2)
     result = semTypeOf(c, n.sons[1])
+  #of mArrGet: result = semArrGet(c, n, flags)
+  #of mArrPut: result = semArrPut(c, n, flags)
+  #of mAsgn: result = semAsgnOpr(c, n)
   of mDefined: result = semDefined(c, setMs(n, s), false)
   of mDefinedInScope: result = semDefined(c, setMs(n, s), true)
   of mCompiles: result = semCompiles(c, setMs(n, s), flags)
@@ -2066,6 +2083,19 @@ proc semExport(c: PContext, n: PNode): PNode =
     c.module.ast.add x
   result = n
 
+proc shouldBeBracketExpr(n: PNode): bool =
+  assert n.kind in nkCallKinds
+  let a = n.sons[0]
+  if a.kind in nkCallKinds:
+    let b = a[0]
+    if b.kind in nkSymChoices:
+      for i in 0..<b.len:
+        if b[i].sym.magic == mArrGet:
+          let be = newNodeI(nkBracketExpr, n.info)
+          for i in 1..<a.len: be.add(a[i])
+          n.sons[0] = be
+          return true
+
 proc setGenericParams(c: PContext, n: PNode) =
   for i in 1 .. <n.len:
     n[i].typ = semTypeNode(c, n[i], nil)
@@ -2173,7 +2203,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
       else:
         #liMessage(n.info, warnUser, renderTree(n));
         result = semIndirectOp(c, n, flags)
-    elif n[0].kind == nkBracketExpr and isSymChoice(n[0][0]):
+    elif (n[0].kind == nkBracketExpr or shouldBeBracketExpr(n)) and
+        isSymChoice(n[0][0]):
       # indirectOp can deal with explicit instantiations; the fixes
       # the 'newSeq[T](x)' bug
       setGenericParams(c, n.sons[0])
@@ -2194,16 +2225,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
         result = semExpr(c, result, flags)
   of nkBracketExpr:
     checkMinSonsLen(n, 1)
-    var s = qualifiedLookUp(c, n.sons[0], {checkUndeclared})
-    if (s != nil and s.kind in {skProc, skMethod, skConverter}+skIterators) or
-        n[0].kind in nkSymChoices:
-      # type parameters: partial generic specialization
-      n.sons[0] = semSymGenericInstantiation(c, n.sons[0], s)
-      result = explicitGenericInstantiation(c, n, s)
-    elif s != nil and s.kind in {skType}:
-      result = symNodeFromType(c, semTypeNode(c, n, nil), n.info)
-    else:
-      result = semArrayAccess(c, n, flags)
+    result = semArrayAccess(c, n, flags)
   of nkCurlyExpr:
     result = semExpr(c, buildOverloadedSubscripts(n, getIdent"{}"), flags)
   of nkPragmaExpr:
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index 70276a6d4..5fe4e3299 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -430,17 +430,10 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
   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, mDotDot,
-     mNLen..mNError, mEqRef, mSlurp, mStaticExec, mNGenSym, mSpawn,
-     mParallel, mPlugin, mGetTypeInfo, mTypeOf:
-    discard
   of mEqProc:
     result = newIntNodeT(ord(
         exprStructuralEquivalent(a, b, strictSymEquality=true)), n)
-  else: internalError(a.info, "evalOp(" & $m & ')')
+  else: discard
 
 proc getConstIfExpr(c: PSym, n: PNode): PNode =
   result = nil
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index e3b598919..ed0244b0c 100644
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -251,6 +251,29 @@ proc semGenericStmt(c: PContext, n: PNode,
     let flags = if mixinContext: flags+{withinMixin} else: flags
     for i in countup(first, sonsLen(result) - 1):
       result.sons[i] = semGenericStmt(c, result.sons[i], flags, ctx)
+  of nkBracketExpr, nkCurlyExpr:
+    result = newNodeI(nkCall, n.info)
+    result.add newIdentNode(getIdent(if n.kind == nkBracketExpr:"[]" else:"{}"),
+                            n.info)
+    for i in 0 ..< n.len: result.add(n[i])
+    result = semGenericStmt(c, result, flags, ctx)
+  of nkAsgn, nkFastAsgn:
+    checkSonsLen(n, 2)
+    let a = n.sons[0]
+    let b = n.sons[1]
+
+    let k = a.kind
+    case k
+    of nkBracketExpr, nkCurlyExpr:
+      result = newNodeI(nkCall, n.info)
+      result.add newIdentNode(getIdent(if k == nkBracketExpr:"[]=" else:"{}="),
+                              n.info)
+      for i in 0 ..< a.len: result.add(a[i])
+      result.add(b)
+      result = semGenericStmt(c, result, flags, ctx)
+    else:
+      for i in countup(0, sonsLen(n) - 1):
+        result.sons[i] = semGenericStmt(c, n.sons[i], flags, ctx)
   of nkIfStmt:
     for i in countup(0, sonsLen(n)-1):
       n.sons[i] = semGenericStmtScope(c, n.sons[i], flags, ctx)
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index 42a39d0df..64e3e8cb8 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -246,6 +246,8 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
     inc i
   pushProcCon(c, result)
   instantiateProcType(c, pt, result, info)
+  if tfTriggersCompileTime in result.typ.flags:
+    incl(result.flags, sfCompileTime)
   n.sons[genericParamsPos] = ast.emptyNode
   var oldPrc = genericCacheGet(fn, entry[])
   if oldPrc == nil:
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index 5d16470b0..65185f762 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -26,6 +26,37 @@ proc semTypeOf(c: PContext; n: PNode): PNode =
   result.add typExpr
   result.typ = makeTypeDesc(c, typExpr.typ.skipTypes({tyTypeDesc, tyIter}))
 
+type
+  SemAsgnMode = enum asgnNormal, noOverloadedSubscript, noOverloadedAsgn
+
+proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode
+proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode
+
+proc semArrGet(c: PContext; n: PNode; flags: TExprFlags): PNode =
+  result = newNodeI(nkBracketExpr, n.info)
+  for i in 1..<n.len: result.add(n[i])
+  let oldBracketExpr = c.p.bracketExpr
+  result = semSubscript(c, result, flags)
+  c.p.bracketExpr = oldBracketExpr
+  if result.isNil:
+    localError(n.info, "could not resolve: " & $n)
+    result = n
+
+proc semArrPut(c: PContext; n: PNode; flags: TExprFlags): PNode =
+  # rewrite `[]=`(a, i, x)  back to ``a[i] = x``.
+  let b = newNodeI(nkBracketExpr, n.info)
+  for i in 1..n.len-2: b.add(n[i])
+  result = newNodeI(nkAsgn, n.info, 2)
+  result.sons[0] = b
+  result.sons[1] = n.lastSon
+  result = semAsgn(c, result, noOverloadedSubscript)
+
+proc semAsgnOpr(c: PContext; n: PNode): PNode =
+  result = newNodeI(nkAsgn, n.info, 2)
+  result.sons[0] = n[1]
+  result.sons[1] = n[2]
+  result = semAsgn(c, result, noOverloadedAsgn)
+
 proc semIsPartOf(c: PContext, n: PNode, flags: TExprFlags): PNode =
   var r = isPartOf(n[1], n[2])
   result = newIntNodeT(ord(r), n)
@@ -125,6 +156,9 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
   of mTypeOf:
     checkSonsLen(n, 2)
     result = semTypeOf(c, n.sons[1])
+  of mArrGet: result = semArrGet(c, n, flags)
+  of mArrPut: result = semArrPut(c, n, flags)
+  of mAsgn: result = semAsgnOpr(c, n)
   of mIsPartOf: result = semIsPartOf(c, n, flags)
   of mTypeTrait: result = semTypeTraits(c, n)
   of mAstToStr:
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 4399c0ab0..f67ee2822 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -1033,6 +1033,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
                  "signature for 'deepCopy' must be proc[T: ptr|ref](x: T): T")
     incl(s.flags, sfUsed)
   of "=":
+    if s.magic == mAsgn: return
     incl(s.flags, sfUsed)
     let t = s.typ
     if t.len == 3 and t.sons[0] == nil and t.sons[1].kind == tyVar:
@@ -1131,6 +1132,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
         # semParamList(c, n.sons[ParamsPos], nil, s)
   else:
     s.typ = newProcType(c, n.info)
+  if tfTriggersCompileTime in s.typ.flags: incl(s.flags, sfCompileTime)
   if n.sons[patternPos].kind != nkEmpty:
     n.sons[patternPos] = semPattern(c, n.sons[patternPos])
   if s.kind in skIterators:
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index 371abe1e3..fc1af7246 100644
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -281,6 +281,35 @@ proc semTemplBodySons(c: var TemplCtx, n: PNode): PNode =
   for i in 0.. < n.len:
     result.sons[i] = semTemplBody(c, n.sons[i])
 
+proc wrapInBind(c: var TemplCtx; n: PNode; opr: string): PNode =
+  let ident = getIdent(opr)
+  if ident.id in c.toInject: return n
+
+  let s = searchInScopes(c.c, ident)
+  if s != nil:
+    var callee: PNode
+    if contains(c.toBind, s.id):
+      callee = symChoice(c.c, n, s, scClosed)
+    elif contains(c.toMixin, s.name.id):
+      callee = symChoice(c.c, n, s, scForceOpen)
+    elif s.owner == c.owner and sfGenSym in s.flags:
+      # template tmp[T](x: var seq[T]) =
+      # var yz: T
+      incl(s.flags, sfUsed)
+      callee = newSymNode(s, n.info)
+      styleCheckUse(n.info, s)
+    else:
+      callee = semTemplSymbol(c.c, n, s)
+
+    let call = newNodeI(nkCall, n.info)
+    call.add(callee)
+    for i in 0 .. n.len-1: call.add(n[i])
+    result = newNodeI(nkBind, n.info, 2)
+    result.sons[0] = n
+    result.sons[1] = call
+  else:
+    result = n
+
 proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
   result = n
   semIdeForTemplateOrGenericCheck(n, c.cursorInBody)
@@ -423,6 +452,28 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
     result.sons[1] = semTemplBody(c, n.sons[1])
   of nkPragma:
     result = onlyReplaceParams(c, n)
+  of nkBracketExpr, nkCurlyExpr:
+    result = newNodeI(nkCall, n.info)
+    result.add newIdentNode(getIdent(if n.kind == nkBracketExpr:"[]" else:"{}"),
+                            n.info)
+    for i in 0 ..< n.len: result.add(n[i])
+    result = semTemplBodySons(c, result)
+  of nkAsgn, nkFastAsgn:
+    checkSonsLen(n, 2)
+    let a = n.sons[0]
+    let b = n.sons[1]
+
+    let k = a.kind
+    case k
+    of nkBracketExpr, nkCurlyExpr:
+      result = newNodeI(nkCall, n.info)
+      result.add newIdentNode(getIdent(if k == nkBracketExpr:"[]=" else:"{}="),
+                              n.info)
+      for i in 0 ..< a.len: result.add(a[i])
+      result.add(b)
+    else:
+      result = n
+    result = semTemplBodySons(c, result)
   else:
     # dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam',
     # so we use the generic code for nkDotExpr too
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 2ee17fcaf..1cfbc368b 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -718,12 +718,12 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
   if paramType == nil: return # (e.g. proc return type)
 
   proc addImplicitGenericImpl(typeClass: PType, typId: PIdent): PType =
-    let finalTypId = if typId != nil: typId
-                     else: getIdent(paramName & ":type")
     if genericParams == nil:
       # This happens with anonymous proc types appearing in signatures
       # XXX: we need to lift these earlier
       return
+    let finalTypId = if typId != nil: typId
+                     else: getIdent(paramName & ":type")
     # is this a bindOnce type class already present in the param list?
     for i in countup(0, genericParams.len - 1):
       if genericParams.sons[i].sym.name.id == finalTypId.id:
@@ -757,7 +757,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
 
   case paramType.kind:
   of tyAnything:
-    result = addImplicitGeneric(newTypeS(tyGenericParam, c))
+    result = addImplicitGenericImpl(newTypeS(tyGenericParam, c), nil)
 
   of tyStatic:
     # proc(a: expr{string}, b: expr{nkLambda})
@@ -868,6 +868,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
   of tyExpr:
     if procKind notin {skMacro, skTemplate}:
       result = addImplicitGeneric(newTypeS(tyAnything, c))
+      #result = addImplicitGenericImpl(newTypeS(tyGenericParam, c), nil)
 
   of tyGenericParam:
     markUsed(info, paramType.sym)
@@ -977,7 +978,11 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
     # compiler only checks for 'nil':
     if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
       # 'auto' as a return type does not imply a generic:
-      if r.kind != tyExpr:
+      if r.kind == tyAnything:
+        # 'p(): auto' and 'p(): expr' are equivalent, but the rest of the
+        # compiler is hardly aware of 'auto':
+        r = newTypeS(tyExpr, c)
+      elif r.kind != tyExpr:
         if r.sym == nil or sfAnon notin r.sym.flags:
           let lifted = liftParamType(c, kind, genericParams, r, "result",
                                      n.sons[0].info)
@@ -1149,7 +1154,17 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
     else:
       result = semAnonTuple(c, n, prev)
   of nkCallKinds:
-    if isRange(n):
+    let x = n[0]
+    let ident = case x.kind
+                of nkIdent: x.ident
+                of nkSym: x.sym.name
+                of nkClosedSymChoice, nkOpenSymChoice: x[0].sym.name
+                else: nil
+    if ident != nil and ident.s == "[]":
+      let b = newNodeI(nkBracketExpr, n.info)
+      for i in 1..<n.len: b.add(n[i])
+      result = semTypeNode(c, b, prev)
+    elif ident != nil and ident.id == ord(wDotDot):
       result = semRangeAux(c, n, prev)
     elif n[0].kind notin nkIdentKinds:
       result = semTypeExpr(c, n)
@@ -1336,8 +1351,11 @@ proc processMagicType(c: PContext, m: PSym) =
   of mIntSetBaseType: setMagicType(m, tyRange, intSize)
   of mNil: setMagicType(m, tyNil, ptrSize)
   of mExpr:
-    setMagicType(m, tyExpr, 0)
-    if m.name.s == "expr": m.typ.flags.incl tfOldSchoolExprStmt
+    if m.name.s == "auto":
+      setMagicType(m, tyAnything, 0)
+    else:
+      setMagicType(m, tyExpr, 0)
+      if m.name.s == "expr": m.typ.flags.incl tfOldSchoolExprStmt
   of mStmt:
     setMagicType(m, tyStmt, 0)
     if m.name.s == "stmt": m.typ.flags.incl tfOldSchoolExprStmt
@@ -1365,7 +1383,8 @@ proc processMagicType(c: PContext, m: PSym) =
   of mOrdinal:
     setMagicType(m, tyOrdinal, 0)
     rawAddSon(m.typ, newTypeS(tyNone, c))
-  of mPNimrodNode: discard
+  of mPNimrodNode:
+    incl m.typ.flags, tfTriggersCompileTime
   of mShared:
     setMagicType(m, tyObject, 0)
     m.typ.n = newNodeI(nkRecList, m.info)
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 61f1a7444..f6f029936 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -1691,6 +1691,10 @@ proc partialMatch*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
   matchesAux(c, n, nOrig, m, marker)
 
 proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
+  if m.calleeSym != nil and m.calleeSym.magic in {mArrGet, mArrPut}:
+    m.state = csMatch
+    m.call = n
+    return
   var marker = initIntSet()
   matchesAux(c, n, nOrig, m, marker)
   if m.state == csNoMatch: return