summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/aliases.nim2
-rw-r--r--compiler/ast.nim13
-rw-r--r--compiler/ccgexprs.nim4
-rw-r--r--compiler/ccgstmts.nim2
-rw-r--r--compiler/cgen.nim2
-rw-r--r--compiler/docgen.nim14
-rw-r--r--compiler/jsgen.nim8
-rw-r--r--compiler/lambdalifting.nim9
-rw-r--r--compiler/lookups.nim6
-rw-r--r--compiler/lowerings.nim2
-rw-r--r--compiler/parser.nim30
-rw-r--r--compiler/passes.nim2
-rw-r--r--compiler/renderer.nim5
-rw-r--r--compiler/rodwrite.nim2
-rw-r--r--compiler/sem.nim2
-rw-r--r--compiler/semcall.nim2
-rw-r--r--compiler/semdata.nim2
-rw-r--r--compiler/semexprs.nim16
-rw-r--r--compiler/semfold.nim4
-rw-r--r--compiler/semgnrc.nim6
-rw-r--r--compiler/seminst.nim2
-rw-r--r--compiler/semparallel.nim2
-rw-r--r--compiler/sempass2.nim8
-rw-r--r--compiler/semtempl.nim2
-rw-r--r--compiler/semtypinst.nim2
-rw-r--r--compiler/sigmatch.nim8
-rw-r--r--compiler/transf.nim2
-rw-r--r--compiler/types.nim8
-rw-r--r--compiler/vmgen.nim4
-rw-r--r--compiler/writetracking.nim2
30 files changed, 92 insertions, 81 deletions
diff --git a/compiler/aliases.nim b/compiler/aliases.nim
index 0c836bb24..c0371e159 100644
--- a/compiler/aliases.nim
+++ b/compiler/aliases.nim
@@ -95,7 +95,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
   if a.kind == b.kind:
     case a.kind
     of nkSym:
-      const varKinds = {skVar, skTemp, skProc}
+      const varKinds = {skVar, skTemp, skProc, skFunc}
       # same symbol: aliasing:
       if a.sym.id == b.sym.id: result = arYes
       elif a.sym.kind in varKinds or b.sym.kind in varKinds:
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 6e87959bf..79e1105e1 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -221,6 +221,8 @@ type
     nkGotoState,          # used for the state machine (for iterators)
     nkState,              # give a label to a code section (for iterators)
     nkBreakState,         # special break statement for easier code generation
+    nkFuncDef             # a func
+
   TNodeKinds* = set[TNodeKind]
 
 type
@@ -534,6 +536,7 @@ type
     skConst,              # a constant
     skResult,             # special 'result' variable
     skProc,               # a proc
+    skFunc,               # a func
     skMethod,             # a method
     skIterator,           # an iterator
     skConverter,          # a type converter
@@ -552,7 +555,7 @@ type
   TSymKinds* = set[TSymKind]
 
 const
-  routineKinds* = {skProc, skMethod, skIterator,
+  routineKinds* = {skProc, skFunc, skMethod, skIterator,
                    skConverter, skMacro, skTemplate}
   tfIncompleteStruct* = tfVarargs
   tfUncheckedArray* = tfVarargs
@@ -931,7 +934,7 @@ type
 # the poor naming choices in the standard library.
 
 const
-  OverloadableSyms* = {skProc, skMethod, skIterator,
+  OverloadableSyms* = {skProc, skFunc, skMethod, skIterator,
     skConverter, skModule, skTemplate, skMacro}
 
   GenericTypes*: TTypeKinds = {tyGenericInvocation, tyGenericBody,
@@ -954,7 +957,7 @@ const
                                     tyTuple, tySequence}
   NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, tySequence,
     tyProc, tyString, tyError}
-  ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType,
+  ExportableSymKinds* = {skVar, skConst, skProc, skFunc, skMethod, skType,
     skIterator,
     skMacro, skTemplate, skConverter, skEnumField, skLet, skStub, skAlias}
   PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16,
@@ -978,14 +981,14 @@ const
 
   nkLiterals* = {nkCharLit..nkTripleStrLit}
   nkLambdaKinds* = {nkLambda, nkDo}
-  declarativeDefs* = {nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef}
+  declarativeDefs* = {nkProcDef, nkFuncDef, nkMethodDef, nkIteratorDef, nkConverterDef}
   procDefs* = nkLambdaKinds + declarativeDefs
 
   nkSymChoices* = {nkClosedSymChoice, nkOpenSymChoice}
   nkStrKinds* = {nkStrLit..nkTripleStrLit}
 
   skLocalVars* = {skVar, skLet, skForVar, skParam, skResult}
-  skProcKinds* = {skProc, skTemplate, skMacro, skIterator,
+  skProcKinds* = {skProc, skFunc, skTemplate, skMacro, skIterator,
                   skMethod, skConverter}
 
 var ggDebug* {.deprecated.}: bool ## convenience switch for trying out things
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 25681c330..88944aea6 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -2039,7 +2039,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
       else:
         genProc(p.module, sym)
       putLocIntoDest(p, d, sym.loc)
-    of skProc, skConverter, skIterator:
+    of skProc, skConverter, skIterator, skFunc:
       #if sym.kind == skIterator:
       #  echo renderTree(sym.getBody, {renderIds})
       if sfCompileTime in sym.flags:
@@ -2205,7 +2205,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
     discard
   of nkPragma: genPragma(p, n)
   of nkPragmaBlock: expr(p, n.lastSon, d)
-  of nkProcDef, nkMethodDef, nkConverterDef:
+  of nkProcDef, nkFuncDef, nkMethodDef, nkConverterDef:
     if n.sons[genericParamsPos].kind == nkEmpty:
       var prc = n.sons[namePos].sym
       # due to a bug/limitation in the lambda lifting, unused inner procs
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 74ffb4603..eb32e7dd0 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -960,7 +960,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope =
       res.add(t.sons[i].strVal)
     of nkSym:
       var sym = t.sons[i].sym
-      if sym.kind in {skProc, skIterator, skMethod}:
+      if sym.kind in {skProc, skFunc, skIterator, skMethod}:
         var a: TLoc
         initLocExpr(p, t.sons[i], a)
         res.add($rdLoc(a))
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index d0add6bcc..6970d09c3 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -603,7 +603,7 @@ proc cgsym(m: BModule, name: string): Rope =
   var sym = magicsys.getCompilerProc(name)
   if sym != nil:
     case sym.kind
-    of skProc, skMethod, skConverter, skIterator: genProc(m, sym)
+    of skProc, skFunc, skMethod, skConverter, skIterator: genProc(m, sym)
     of skVar, skResult, skLet: genVarPrototype(m, newSymNode sym)
     of skType: discard getTypeDesc(m, sym.typ)
     else: internalError("cgsym: " & name & ": " & $sym.kind)
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index 3f4f7b164..8c50a4f1d 100644
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -325,7 +325,7 @@ proc complexName(k: TSymKind, n: PNode, baseName: string): string =
   ## section of ``doc/docgen.txt``.
   result = baseName
   case k:
-  of skProc: result.add(defaultParamSeparator)
+  of skProc, skFunc: result.add(defaultParamSeparator)
   of skMacro: result.add(".m" & defaultParamSeparator)
   of skMethod: result.add(".e" & defaultParamSeparator)
   of skIterator: result.add(".i" & defaultParamSeparator)
@@ -341,7 +341,7 @@ proc isCallable(n: PNode): bool =
   ## Returns true if `n` contains a callable node.
   case n.kind
   of nkProcDef, nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef,
-    nkConverterDef: result = true
+    nkConverterDef, nkFuncDef: result = true
   else:
     result = false
 
@@ -533,6 +533,9 @@ proc generateDoc*(d: PDoc, n: PNode) =
   of nkProcDef:
     when useEffectSystem: documentRaises(n)
     genItem(d, n, n.sons[namePos], skProc)
+  of nkFuncDef:
+    when useEffectSystem: documentRaises(n)
+    genItem(d, n, n.sons[namePos], skFunc)
   of nkMethodDef:
     when useEffectSystem: documentRaises(n)
     genItem(d, n, n.sons[namePos], skMethod)
@@ -574,6 +577,9 @@ proc generateJson*(d: PDoc, n: PNode) =
   of nkProcDef:
     when useEffectSystem: documentRaises(n)
     d.add genJsonItem(d, n, n.sons[namePos], skProc)
+  of nkFuncDef:
+    when useEffectSystem: documentRaises(n)
+    d.add genJsonItem(d, n, n.sons[namePos], skFunc)
   of nkMethodDef:
     when useEffectSystem: documentRaises(n)
     d.add genJsonItem(d, n, n.sons[namePos], skMethod)
@@ -604,8 +610,8 @@ proc generateJson*(d: PDoc, n: PNode) =
 
 proc genSection(d: PDoc, kind: TSymKind) =
   const sectionNames: array[skModule..skTemplate, string] = [
-    "Imports", "Types", "Vars", "Lets", "Consts", "Vars", "Procs", "Methods",
-    "Iterators", "Converters", "Macros", "Templates"
+    "Imports", "Types", "Vars", "Lets", "Consts", "Vars", "Procs", "Funcs",
+    "Methods", "Iterators", "Converters", "Macros", "Templates"
   ]
   if d.section[kind] == nil: return
   var title = sectionNames[kind].rope
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index 73e6a9948..bffe196df 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -292,7 +292,7 @@ proc useMagic(p: PProc, name: string) =
   if name.len == 0: return
   var s = magicsys.getCompilerProc(name)
   if s != nil:
-    internalAssert s.kind in {skProc, skMethod, skConverter}
+    internalAssert s.kind in {skProc, skFunc, skMethod, skConverter}
     if not p.g.generatedSyms.containsOrIncl(s.id):
       let code = genProc(p, s)
       add(p.g.constants, code)
@@ -1111,7 +1111,7 @@ template isIndirect(x: PSym): bool =
   ({sfAddrTaken, sfGlobal} * v.flags != {} and
     #(mapType(v.typ) != etyObject) and
     {sfImportc, sfVolatile, sfExportc} * v.flags == {} and
-    v.kind notin {skProc, skConverter, skMethod, skIterator,
+    v.kind notin {skProc, skFunc, skConverter, skMethod, skIterator,
                   skConst, skTemp, skLet} and p.target == targetJS)
 
 proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
@@ -1237,7 +1237,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
     else:
       r.res = "$" & s.loc.r
       p.declareGlobal(s.id, r.res)
-  of skProc, skConverter, skMethod:
+  of skProc, skFunc, skConverter, skMethod:
     discard mangleName(s, p.target)
     if p.target == targetPHP and r.kind != resCallee:
       r.res = makeJsString($s.loc.r)
@@ -2338,7 +2338,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
      nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
      nkFromStmt, nkTemplateDef, nkMacroDef: discard
   of nkPragma: genPragma(p, n)
-  of nkProcDef, nkMethodDef, nkConverterDef:
+  of nkProcDef, nkFuncDef, nkMethodDef, nkConverterDef:
     var s = n.sons[namePos].sym
     if {sfExportc, sfCompilerProc} * s.flags == {sfExportc}:
       genSym(p, n.sons[namePos], r)
diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim
index 986d8c716..e64e0a898 100644
--- a/compiler/lambdalifting.nim
+++ b/compiler/lambdalifting.nim
@@ -194,7 +194,7 @@ proc illegalCapture(s: PSym): bool {.inline.} =
       s.kind == skResult
 
 proc isInnerProc(s: PSym): bool =
-  if s.kind in {skProc, skMethod, skConverter, skIterator} and s.magic == mNone:
+  if s.kind in {skProc, skFunc, skMethod, skConverter, skIterator} and s.magic == mNone:
     result = s.skipGenericOwner.kind in routineKinds
 
 proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode =
@@ -371,7 +371,8 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
   case n.kind
   of nkSym:
     let s = n.sym
-    if s.kind in {skProc, skMethod, skConverter, skIterator} and s.typ != nil and s.typ.callConv == ccClosure:
+    if s.kind in {skProc, skFunc, skMethod, skConverter, skIterator} and
+        s.typ != nil and s.typ.callConv == ccClosure:
       # this handles the case that the inner proc was declared as
       # .closure but does not actually capture anything:
       addClosureParam(c, s, n.info)
@@ -443,7 +444,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
     discard
   of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef:
     discard
-  of nkLambdaKinds, nkIteratorDef:
+  of nkLambdaKinds, nkIteratorDef, nkFuncDef:
     if n.typ != nil:
       detectCapturedVars(n[namePos], owner, c)
   else:
@@ -730,7 +731,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
         # now we know better, so patch it:
         n.sons[0] = x.sons[0]
         n.sons[1] = x.sons[1]
-  of nkLambdaKinds, nkIteratorDef:
+  of nkLambdaKinds, nkIteratorDef, nkFuncDef:
     if n.typ != nil and n[namePos].kind == nkSym:
       let m = newSymNode(n[namePos].sym)
       m.typ = n.typ
diff --git a/compiler/lookups.nim b/compiler/lookups.nim
index 5a5dfc46a..eddfeea56 100644
--- a/compiler/lookups.nim
+++ b/compiler/lookups.nim
@@ -144,8 +144,10 @@ type
 
 proc getSymRepr*(s: PSym): string =
   case s.kind
-  of skProc, skMethod, skConverter, skIterator: result = getProcHeader(s)
-  else: result = s.name.s
+  of skProc, skFunc, skMethod, skConverter, skIterator:
+    result = getProcHeader(s)
+  else:
+    result = s.name.s
 
 proc ensureNoMissingOrUnusedSymbols(scope: PScope) =
   # check if all symbols have been used and defined:
diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim
index ce76b63a4..033472c07 100644
--- a/compiler/lowerings.nim
+++ b/compiler/lowerings.nim
@@ -633,7 +633,7 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
   if fn.kind == nkClosure:
     localError(n.info, "closure in spawn environment is not allowed")
   if not (fn.kind == nkSym and fn.sym.kind in {skProc, skTemplate, skMacro,
-                                               skMethod, skConverter}):
+                                               skFunc, skMethod, skConverter}):
     # for indirect calls we pass the function pointer in the scratchObj
     var argType = n[0].typ.skipTypes(abstractInst)
     var field = newSym(skField, getIdent"fn", owner, n.info)
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 253716247..06ecf900e 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -991,7 +991,7 @@ proc parseDoBlock(p: var TParser; info: TLineInfo): PNode =
   if params.kind != nkEmpty:
     result = newProcNode(nkDo, info, result, params = params, pragmas = pragmas)
 
-proc parseProcExpr(p: var TParser, isExpr: bool): PNode =
+proc parseProcExpr(p: var TParser; isExpr: bool; kind: TNodeKind): PNode =
   #| procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)?
   # either a proc type or a anonymous proc
   let info = parLineInfo(p)
@@ -1002,7 +1002,7 @@ proc parseProcExpr(p: var TParser, isExpr: bool): PNode =
   if p.tok.tokType == tkEquals and isExpr:
     getTok(p)
     skipComment(p, result)
-    result = newProcNode(nkLambda, info, parseStmt(p),
+    result = newProcNode(kind, info, parseStmt(p),
                          params = params,
                          pragmas = pragmas)
   else:
@@ -1014,7 +1014,7 @@ proc parseProcExpr(p: var TParser, isExpr: bool): PNode =
 proc isExprStart(p: TParser): bool =
   case p.tok.tokType
   of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf,
-     tkProc, tkIterator, tkBind, tkAddr,
+     tkProc, tkFunc, tkIterator, tkBind, tkAddr,
      tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr,
      tkTuple, tkObject, tkType, tkWhen, tkCase, tkOut:
     result = true
@@ -1088,21 +1088,12 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
 
   case p.tok.tokType:
   of tkTuple: result = parseTuple(p, mode == pmTypeDef)
-  of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
+  of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}, nkLambda)
+  of tkFunc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}, nkFuncDef)
   of tkIterator:
-    when false:
-      if mode in {pmTypeDesc, pmTypeDef}:
-        result = parseProcExpr(p, false)
-        result.kind = nkIteratorTy
-      else:
-        # no anon iterators for now:
-        parMessage(p, errExprExpected, p.tok)
-        getTok(p)  # we must consume a token here to prevend endless loops!
-        result = ast.emptyNode
-    else:
-      result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
-      if result.kind == nkLambda: result.kind = nkIteratorDef
-      else: result.kind = nkIteratorTy
+    result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}, nkLambda)
+    if result.kind == nkLambda: result.kind = nkIteratorDef
+    else: result.kind = nkIteratorTy
   of tkEnum:
     if mode == pmTypeDef:
       result = parseEnum(p)
@@ -2000,6 +1991,7 @@ proc complexOrSimpleStmt(p: var TParser): PNode =
   of tkDefer: result = parseStaticOrDefer(p, nkDefer)
   of tkAsm: result = parseAsm(p)
   of tkProc: result = parseRoutine(p, nkProcDef)
+  of tkFunc: result = parseRoutine(p, nkFuncDef)
   of tkMethod: result = parseRoutine(p, nkMethodDef)
   of tkIterator: result = parseRoutine(p, nkIteratorDef)
   of tkMacro: result = parseRoutine(p, nkMacroDef)
@@ -2056,8 +2048,8 @@ proc parseStmt(p: var TParser): PNode =
   else:
     # the case statement is only needed for better error messages:
     case p.tok.tokType
-    of tkIf, tkWhile, tkCase, tkTry, tkFor, tkBlock, tkAsm, tkProc, tkIterator,
-       tkMacro, tkType, tkConst, tkWhen, tkVar:
+    of tkIf, tkWhile, tkCase, tkTry, tkFor, tkBlock, tkAsm, tkProc, tkFunc,
+       tkIterator, tkMacro, tkType, tkConst, tkWhen, tkVar:
       parMessage(p, errComplexStmtRequiresInd)
       result = ast.emptyNode
     else:
diff --git a/compiler/passes.nim b/compiler/passes.nim
index bf6ce1a0a..6efd50385 100644
--- a/compiler/passes.nim
+++ b/compiler/passes.nim
@@ -64,7 +64,7 @@ proc astNeeded*(s: PSym): bool =
   # needs to be stored. The passes manager frees s.sons[codePos] when
   # appropriate to free the procedure body's memory. This is important
   # to keep memory usage down.
-  if (s.kind in {skMethod, skProc}) and
+  if (s.kind in {skMethod, skProc, skFunc}) and
       ({sfCompilerProc, sfCompileTime} * s.flags == {}) and
       (s.typ.callConv != ccInline) and
       (s.ast.sons[genericParamsPos].kind == nkEmpty):
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index 220693f68..c52161a55 100644
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -1166,6 +1166,9 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
   of nkProcDef:
     if renderNoProcDefs notin g.flags: putWithSpace(g, tkProc, "proc")
     gproc(g, n)
+  of nkFuncDef:
+    if renderNoProcDefs notin g.flags: putWithSpace(g, tkFunc, "func")
+    gproc(g, n)
   of nkConverterDef:
     if renderNoProcDefs notin g.flags: putWithSpace(g, tkConverter, "converter")
     gproc(g, n)
@@ -1324,7 +1327,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
         if p.typ == nil or tfImplicitTypeParam notin p.typ.flags:
           return true
       return false
-    
+
     if n.hasExplicitParams:
       put(g, tkBracketLe, "[")
       gsemicolon(g, n)
diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim
index 9a8fafd86..fb50c6473 100644
--- a/compiler/rodwrite.nim
+++ b/compiler/rodwrite.nim
@@ -580,7 +580,7 @@ proc process(c: PPassContext, n: PNode): PNode =
     for i in countup(0, sonsLen(n) - 1): discard process(c, n.sons[i])
     #var s = n.sons[namePos].sym
     #addInterfaceSym(w, s)
-  of nkProcDef, nkIteratorDef, nkConverterDef,
+  of nkProcDef, nkFuncDef, nkIteratorDef, nkConverterDef,
       nkTemplateDef, nkMacroDef:
     let s = n.sons[namePos].sym
     if s == nil: internalError(n.info, "rodwrite.process")
diff --git a/compiler/sem.nim b/compiler/sem.nim
index cd0df0de0..21fd0b383 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -449,7 +449,7 @@ include semtypes, semtempl, semgnrc, semstmts, semexprs
 proc addCodeForGenerics(c: PContext, n: PNode) =
   for i in countup(c.lastGenericIdx, c.generics.len - 1):
     var prc = c.generics[i].inst.sym
-    if prc.kind in {skProc, skMethod, skConverter} and prc.magic == mNone:
+    if prc.kind in {skProc, skFunc, skMethod, skConverter} and prc.magic == mNone:
       if prc.ast == nil or prc.ast.sons[bodyPos] == nil:
         internalError(prc.info, "no code for " & prc.name.s)
       else:
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index 5984e25e0..9492e63f4 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -468,7 +468,7 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
     for i in countup(0, len(a)-1):
       var candidate = a.sons[i].sym
       if candidate.kind in {skProc, skMethod, skConverter,
-                            skIterator}:
+                            skFunc, skIterator}:
         # it suffices that the candidate has the proper number of generic
         # type parameters:
         if safeLen(candidate.ast.sons[genericParamsPos]) == n.len-1:
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 97212d2cd..a3f0f715b 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -373,7 +373,7 @@ proc makeRangeType*(c: PContext; first, last: BiggestInt;
   addSonSkipIntLit(result, intType) # basetype of range
 
 proc markIndirect*(c: PContext, s: PSym) {.inline.} =
-  if s.kind in {skProc, skConverter, skMethod, skIterator}:
+  if s.kind in {skProc, skFunc, skConverter, skMethod, skIterator}:
     incl(s.flags, sfAddrTaken)
     # XXX add to 'c' for global analysis
 
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 9930e127e..315efa440 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -574,7 +574,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
         optImplicitStatic notin gOptions: return
 
     if callee.magic notin ctfeWhitelist: return
-    if callee.kind notin {skProc, skConverter} or callee.isGenericRoutine:
+    if callee.kind notin {skProc, skFunc, skConverter} or callee.isGenericRoutine:
       return
 
     if n.typ != nil and typeAllowed(n.typ, skConst) != nil: return
@@ -616,10 +616,10 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
     # for typeof support.
     # for ``type(countup(1,3))``, see ``tests/ttoseq``.
     result = semOverloadedCall(c, n, nOrig,
-      {skProc, skMethod, skConverter, skMacro, skTemplate, skIterator}, flags)
+      {skProc, skFunc, skMethod, skConverter, skMacro, skTemplate, skIterator}, flags)
   else:
     result = semOverloadedCall(c, n, nOrig,
-      {skProc, skMethod, skConverter, skMacro, skTemplate}, flags)
+      {skProc, skFunc, skMethod, skConverter, skMacro, skTemplate}, flags)
 
   if result != nil:
     if result.sons[0].kind != nkSym:
@@ -1230,7 +1230,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
             else: nil
     if s != nil:
       case s.kind
-      of skProc, skMethod, skConverter, skIterator:
+      of skProc, skFunc, skMethod, skConverter, skIterator:
         # type parameters: partial generic specialization
         n.sons[0] = semSymGenericInstantiation(c, n.sons[0], s)
         result = explicitGenericInstantiation(c, n, s)
@@ -1398,7 +1398,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
 proc semReturn(c: PContext, n: PNode): PNode =
   result = n
   checkSonsLen(n, 1)
-  if c.p.owner.kind in {skConverter, skMethod, skProc, skMacro} or (
+  if c.p.owner.kind in {skConverter, skMethod, skProc, skFunc, skMacro} or (
      c.p.owner.kind == skIterator and c.p.owner.typ.callConv == ccClosure):
     if n.sons[0].kind != nkEmpty:
       # transform ``return expr`` to ``result = expr; return``
@@ -2122,7 +2122,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     var s = qualifiedLookUp(c, n, checks)
     if c.matchedConcept == nil: semCaptureSym(s, c.p.owner)
     result = semSym(c, n, s, flags)
-    if s.kind in {skProc, skMethod, skConverter, skIterator}:
+    if s.kind in {skProc, skFunc, skMethod, skConverter, skIterator}:
       #performProcvarCheck(c, n, s)
       result = symChoice(c, n, s, scClosed)
       if result.kind == nkSym:
@@ -2217,7 +2217,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
           errorUseQualifier(c, n.info, s)
         elif s.magic == mNone: result = semDirectOp(c, n, flags)
         else: result = semMagic(c, n, s, flags)
-      of skProc, skMethod, skConverter, skIterator:
+      of skProc, skFunc, skMethod, skConverter, skIterator:
         if s.magic == mNone: result = semDirectOp(c, n, flags)
         else: result = semMagic(c, n, s, flags)
       else:
@@ -2330,7 +2330,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   of nkYieldStmt: result = semYield(c, n)
   of nkPragma: pragma(c, c.p.owner, n, stmtPragmas)
   of nkIteratorDef: result = semIterator(c, n)
-  of nkProcDef: result = semProc(c, n)
+  of nkProcDef, nkFuncDef: result = semProc(c, n)
   of nkMethodDef: result = semMethod(c, n)
   of nkConverterDef: result = semConverterDef(c, n)
   of nkMacroDef: result = semMacroDef(c, n)
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index 9733564e7..d961a47a3 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -630,7 +630,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
           result = newStrNodeT(lookupSymbol(s.name), n)
       else:
         result = copyTree(s.ast)
-    of {skProc, skMethod}:
+    of {skProc, skFunc, skMethod}:
       result = n
     of skType:
       # XXX gensym'ed symbols can come here and cannot be resolved. This is
@@ -654,7 +654,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
   of nkCallKinds:
     if n.sons[0].kind != nkSym: return
     var s = n.sons[0].sym
-    if s.kind != skProc: return
+    if s.kind != skProc and s.kind != skFunc: return
     try:
       case s.magic
       of mNone:
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index e3d078432..3cdb68df6 100644
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -61,7 +61,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
   of skUnknown:
     # Introduced in this pass! Leave it as an identifier.
     result = n
-  of skProc, skMethod, skIterator, skConverter, skModule:
+  of skProc, skFunc, skMethod, skIterator, skConverter, skModule:
     result = symChoice(c, n, s, scOpen)
   of skTemplate:
     if macroToExpandSym(s):
@@ -243,7 +243,7 @@ proc semGenericStmt(c: PContext, n: PNode,
       of skUnknown, skParam:
         # Leave it as an identifier.
         discard
-      of skProc, skMethod, skIterator, skConverter, skModule:
+      of skProc, skFunc, skMethod, skIterator, skConverter, skModule:
         result.sons[0] = sc
         # do not check of 's.magic==mRoof' here because it might be some
         # other '^' but after overload resolution the proper one:
@@ -437,7 +437,7 @@ proc semGenericStmt(c: PContext, n: PNode,
       for j in countup(0, L-3):
         addTempDecl(c, getIdentNode(a.sons[j]), skParam)
   of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
-     nkIteratorDef, nkLambdaKinds:
+     nkFuncDef, nkIteratorDef, nkLambdaKinds:
     checkSonsLen(n, bodyPos + 1)
     if n.sons[namePos].kind != nkEmpty:
       addTempDecl(c, getIdentNode(n.sons[0]), skProc)
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index a28d322b1..6abb34e90 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -36,7 +36,7 @@ proc rawPushProcCon(c: PContext, owner: PSym) =
   c.p = x
 
 proc rawHandleSelf(c: PContext; owner: PSym) =
-  const callableSymbols = {skProc, skMethod, skConverter, skIterator, skMacro}
+  const callableSymbols = {skProc, skFunc, skMethod, skConverter, skIterator, skMacro}
   if c.selfName != nil and owner.kind in callableSymbols and owner.typ != nil:
     let params = owner.typ.n
     if params.len > 1:
diff --git a/compiler/semparallel.nim b/compiler/semparallel.nim
index 90c1a315a..2581f5728 100644
--- a/compiler/semparallel.nim
+++ b/compiler/semparallel.nim
@@ -387,7 +387,7 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
         addFactNeg(c.guards, canon(n.sons[0]))
     dec c.inLoop
   of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
-      nkMacroDef, nkTemplateDef, nkConstSection, nkPragma:
+      nkMacroDef, nkTemplateDef, nkConstSection, nkPragma, nkFuncDef:
     discard
   else:
     analyseSons(c, n)
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index e24c5fd29..e1a3939fc 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -835,7 +835,7 @@ proc track(tracked: PEffects, n: PNode) =
     setLen(tracked.locked, oldLocked)
     tracked.currLockLevel = oldLockLevel
   of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
-      nkMacroDef, nkTemplateDef, nkLambda, nkDo:
+      nkMacroDef, nkTemplateDef, nkLambda, nkDo, nkFuncDef:
     discard
   of nkCast, nkHiddenStdConv, nkHiddenSubConv, nkConv:
     if n.len == 2: track(tracked, n.sons[1])
@@ -937,7 +937,7 @@ proc trackProc*(s: PSym, body: PNode) =
   track(t, body)
   if not isEmptyType(s.typ.sons[0]) and
       {tfNeedsInit, tfNotNil} * s.typ.sons[0].flags != {} and
-      s.kind in {skProc, skConverter, skMethod}:
+      s.kind in {skProc, skFunc, skConverter, skMethod}:
     var res = s.ast.sons[resultPos].sym # get result symbol
     if res.id notin t.init:
       message(body.info, warnProveInit, "result")
@@ -979,10 +979,10 @@ proc trackProc*(s: PSym, body: PNode) =
     message(s.info, warnLockLevel,
       "declared lock level is $1, but real lock level is $2" %
         [$s.typ.lockLevel, $t.maxLockLevel])
-  when useWriteTracking: trackWrites(s, body)
+  if s.kind == skFunc: trackWrites(s, body)
 
 proc trackTopLevelStmt*(module: PSym; n: PNode) =
-  if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef,
+  if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef, nkFuncDef,
                 nkTypeSection, nkConverterDef, nkMethodDef, nkIteratorDef}:
     return
   var effects = newNode(nkEffectList, n.info)
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index 8ad8a6288..be8567c9c 100644
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -449,6 +449,8 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
         a.sons[2] = semTemplBody(c, a.sons[2])
   of nkProcDef, nkLambdaKinds:
     result = semRoutineInTemplBody(c, n, skProc)
+  of nkFuncDef:
+    result = semRoutineInTemplBody(c, n, skFunc)
   of nkMethodDef:
     result = semRoutineInTemplBody(c, n, skMethod)
   of nkIteratorDef:
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index b4a61deb7..a3953d87e 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -170,7 +170,7 @@ proc reResolveCallsWithTypedescParams(cl: var TReplTypeVars, n: PNode): PNode =
       if isTypeParam(n[i]): needsFixing = true
     if needsFixing:
       n.sons[0] = newSymNode(n.sons[0].sym.owner)
-      return cl.c.semOverloadedCall(cl.c, n, n, {skProc}, {})
+      return cl.c.semOverloadedCall(cl.c, n, n, {skProc, skFunc}, {})
 
   for i in 0 .. <n.safeLen:
     n.sons[i] = reResolveCallsWithTypedescParams(cl, n[i])
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 41596f05c..cde9d70ac 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -1373,7 +1373,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
     # XXX: This is very hacky. It should be moved back into liftTypeParam
     if x.kind in {tyGenericInst, tyArray} and
        c.calleeSym != nil and
-       c.calleeSym.kind == skProc:
+       c.calleeSym.kind in {skProc, skFunc}:
       let inst = prepareMetatypeForSigmatch(c.c, c.bindings, c.call.info, f)
       return typeRel(c, inst, a)
 
@@ -1832,7 +1832,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
       bothMetaCounter < 100:
     lastBindingsLength = m.bindings.counter
     inc(bothMetaCounter)
-    if arg.kind in {nkProcDef, nkIteratorDef} + nkLambdaKinds:
+    if arg.kind in {nkProcDef, nkFuncDef, nkIteratorDef} + nkLambdaKinds:
       result = c.semInferredLambda(c, m.bindings, arg)
     elif arg.kind != nkSym:
       return nil
@@ -1865,7 +1865,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
     else:
       result = implicitConv(nkHiddenStdConv, f, arg, m, c)
   of isInferred, isInferredConvertible:
-    if arg.kind in {nkProcDef, nkIteratorDef} + nkLambdaKinds:
+    if arg.kind in {nkProcDef, nkFuncDef, nkIteratorDef} + nkLambdaKinds:
       result = c.semInferredLambda(c, m.bindings, arg)
     elif arg.kind != nkSym:
       return nil
@@ -1952,7 +1952,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
     z.calleeSym = m.calleeSym
     var best = -1
     for i in countup(0, sonsLen(arg) - 1):
-      if arg.sons[i].sym.kind in {skProc, skMethod, skConverter, skIterator}:
+      if arg.sons[i].sym.kind in {skProc, skFunc, skMethod, skConverter, skIterator}:
         copyCandidate(z, m)
         z.callee = arg.sons[i].typ
         if tfUnresolved in z.callee.flags: continue
diff --git a/compiler/transf.nim b/compiler/transf.nim
index 41959b018..f1ee49a54 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -121,7 +121,7 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
     if s.kind == skIterator:
       if c.tooEarly: return n
       else: return liftIterSym(n, getCurrOwner(c))
-    elif s.kind in {skProc, skConverter, skMethod} and not c.tooEarly:
+    elif s.kind in {skProc, skFunc, skConverter, skMethod} and not c.tooEarly:
       # top level .closure procs are still somewhat supported for 'Nake':
       return makeClosure(s, nil, n.info)
   #elif n.sym.kind in {skVar, skLet} and n.sym.typ.callConv == ccClosure:
diff --git a/compiler/types.nim b/compiler/types.nim
index dc7cd52db..a1581dac1 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -1089,7 +1089,7 @@ proc typeAllowedNode(marker: var IntSet, n: PNode, kind: TSymKind,
       of nkNone..nkNilLit:
         discard
       else:
-        if n.kind == nkRecCase and kind in {skProc, skConst}:
+        if n.kind == nkRecCase and kind in {skProc, skFunc, skConst}:
           return n[0].typ
         for i in countup(0, sonsLen(n) - 1):
           let it = n.sons[i]
@@ -1107,7 +1107,7 @@ proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
 
 proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
                     flags: TTypeAllowedFlags = {}): PType =
-  assert(kind in {skVar, skLet, skConst, skProc, skParam, skResult})
+  assert(kind in {skVar, skLet, skConst, skProc, skFunc, skParam, skResult})
   # if we have already checked the type, return true, because we stop the
   # evaluation if something is wrong:
   result = nil
@@ -1116,7 +1116,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
   var t = skipTypes(typ, abstractInst-{tyTypeDesc})
   case t.kind
   of tyVar:
-    if kind in {skProc, skConst}: return t
+    if kind in {skProc, skFunc, skConst}: return t
     var t2 = skipTypes(t.sons[0], abstractInst-{tyTypeDesc})
     case t2.kind
     of tyVar:
@@ -1176,7 +1176,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
       result = typeAllowedAux(marker, t.sons[i], kind, flags)
       if result != nil: break
   of tyObject, tyTuple:
-    if kind in {skProc, skConst} and
+    if kind in {skProc, skFunc, skConst} and
         t.kind == tyObject and t.sons[0] != nil: return t
     let flags = flags+{taField}
     for i in countup(0, sonsLen(t) - 1):
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index 3d291d8a2..6f9d70495 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -1289,7 +1289,7 @@ proc checkCanEval(c: PCtx; n: PNode) =
   if s.kind in {skVar, skTemp, skLet, skParam, skResult} and
       not s.isOwnedBy(c.prc.sym) and s.owner != c.module and c.mode != emRepl:
     cannotEval(n)
-  elif s.kind in {skProc, skConverter, skMethod,
+  elif s.kind in {skProc, skFunc, skConverter, skMethod,
                   skIterator} and sfForward in s.flags:
     cannotEval(n)
 
@@ -1712,7 +1712,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
     case s.kind
     of skVar, skForVar, skTemp, skLet, skParam, skResult:
       genRdVar(c, n, dest, flags)
-    of skProc, skConverter, skMacro, skTemplate, skMethod, skIterator:
+    of skProc, skFunc, skConverter, skMacro, skTemplate, skMethod, skIterator:
       # 'skTemplate' is only allowed for 'getAst' support:
       if procIsCallback(c, s): discard
       elif sfImportc in s.flags: c.importcSym(n.info, s)
diff --git a/compiler/writetracking.nim b/compiler/writetracking.nim
index 443e8ddf1..fe71e5b31 100644
--- a/compiler/writetracking.nim
+++ b/compiler/writetracking.nim
@@ -248,6 +248,8 @@ proc markWriteOrEscape(w: var W) =
       for p in a.dest:
         if p.kind == skParam and p.owner == w.owner:
           incl(p.flags, sfWrittenTo)
+          if w.owner.kind == skFunc and p.typ.kind != tyVar:
+            localError(a.info, "write access to non-var parameter: " & p.name.s)
 
     if {rootIsResultOrParam, rootIsHeapAccess, markAsEscaping}*a.destInfo != {}:
       var destIsParam = false