Skip to content

Commit

Permalink
Merge branch 'devel' into pr_iterator_array_lent
Browse files Browse the repository at this point in the history
  • Loading branch information
ringabout authored Feb 5, 2024
2 parents a693e9c + dd753b3 commit 5918bdb
Show file tree
Hide file tree
Showing 34 changed files with 369 additions and 159 deletions.
8 changes: 6 additions & 2 deletions compiler/ccgcalls.nim
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInst)
if typ.returnType != nil:
var flags: TAssignmentFlags = {}
if typ.returnType.kind in {tyOpenArray, tyVarargs}:
# perhaps generate no temp if the call doesn't have side effects
flags.incl needTempForOpenArray
if isInvalidReturnType(p.config, typ):
if params.len != 0: pl.add(", ")
# beware of 'result = p(result)'. We may need to allocate a temporary:
Expand Down Expand Up @@ -128,13 +132,13 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
assert(d.t != nil) # generate an assignment to d:
var list = initLoc(locCall, d.lode, OnUnknown)
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
genAssignment(p, d, list, flags) # no need for deep copying
if canRaise: raiseExit(p)
else:
var tmp: TLoc = getTemp(p, typ.returnType, needsInit=true)
var list = initLoc(locCall, d.lode, OnUnknown)
list.r = pl
genAssignment(p, tmp, list, {}) # no need for deep copying
genAssignment(p, tmp, list, flags) # no need for deep copying
if canRaise: raiseExit(p)
genAssignment(p, d, tmp, {})
else:
Expand Down
15 changes: 11 additions & 4 deletions compiler/ccgexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -285,15 +285,22 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
linefmt(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n",
[addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfoV1(p.module, dest.t, dest.lode.info)])

proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc) =
proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc; flags: TAssignmentFlags) =
assert d.k != locNone
# getTemp(p, d.t, d)

case a.t.skipTypes(abstractVar).kind
of tyOpenArray, tyVarargs:
if reifiedOpenArray(a.lode):
linefmt(p, cpsStmts, "$1.Field0 = $2.Field0; $1.Field1 = $2.Field1;$n",
[rdLoc(d), a.rdLoc])
if needTempForOpenArray in flags:
var tmp: TLoc = getTemp(p, a.t)
linefmt(p, cpsStmts, "$2 = $1; $n",
[a.rdLoc, tmp.rdLoc])
linefmt(p, cpsStmts, "$1.Field0 = $2.Field0; $1.Field1 = $2.Field1;$n",
[rdLoc(d), tmp.rdLoc])
else:
linefmt(p, cpsStmts, "$1.Field0 = $2.Field0; $1.Field1 = $2.Field1;$n",
[rdLoc(d), a.rdLoc])
else:
linefmt(p, cpsStmts, "$1.Field0 = $2; $1.Field1 = $2Len_0;$n",
[rdLoc(d), a.rdLoc])
Expand Down Expand Up @@ -391,7 +398,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
# open arrays are always on the stack - really? What if a sequence is
# passed to an open array?
if reifiedOpenArray(dest.lode):
genOpenArrayConv(p, dest, src)
genOpenArrayConv(p, dest, src, flags)
elif containsGarbageCollectedRef(dest.t):
linefmt(p, cpsStmts, # XXX: is this correct for arrays?
"#genericAssignOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n",
Expand Down
29 changes: 20 additions & 9 deletions compiler/cgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,7 @@ proc rdCharLoc(a: TLoc): Rope =
type
TAssignmentFlag = enum
needToCopy
needTempForOpenArray
TAssignmentFlags = set[TAssignmentFlag]

proc genObjConstr(p: BProc, e: PNode, d: var TLoc)
Expand Down Expand Up @@ -1032,7 +1033,7 @@ proc easyResultAsgn(n: PNode): PNode =
type
InitResultEnum = enum Unknown, InitSkippable, InitRequired

proc allPathsAsgnResult(n: PNode): InitResultEnum =
proc allPathsAsgnResult(p: BProc; n: PNode): InitResultEnum =
# Exceptions coming from calls don't have not be considered here:
#
# proc bar(): string = raise newException(...)
Expand All @@ -1047,7 +1048,7 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum =
# echo "a was not written to"
#
template allPathsInBranch(it) =
let a = allPathsAsgnResult(it)
let a = allPathsAsgnResult(p, it)
case a
of InitRequired: return InitRequired
of InitSkippable: discard
Expand All @@ -1059,14 +1060,16 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum =
case n.kind
of nkStmtList, nkStmtListExpr:
for it in n:
result = allPathsAsgnResult(it)
result = allPathsAsgnResult(p, it)
if result != Unknown: return result
of nkAsgn, nkFastAsgn, nkSinkAsgn:
if n[0].kind == nkSym and n[0].sym.kind == skResult:
if not containsResult(n[1]): result = InitSkippable
else: result = InitRequired
elif containsResult(n):
result = InitRequired
else:
result = allPathsAsgnResult(p, n[1])
of nkReturnStmt:
if n.len > 0:
if n[0].kind == nkEmpty and result != InitSkippable:
Expand All @@ -1075,7 +1078,7 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum =
# initialized. This avoids cases like #9286 where this heuristic lead to
# wrong code being generated.
result = InitRequired
else: result = allPathsAsgnResult(n[0])
else: result = allPathsAsgnResult(p, n[0])
of nkIfStmt, nkIfExpr:
var exhaustive = false
result = InitSkippable
Expand All @@ -1101,9 +1104,9 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum =
of nkWhileStmt:
# some dubious code can assign the result in the 'while'
# condition and that would be fine. Everything else isn't:
result = allPathsAsgnResult(n[0])
result = allPathsAsgnResult(p, n[0])
if result == Unknown:
result = allPathsAsgnResult(n[1])
result = allPathsAsgnResult(p, n[1])
# we cannot assume that the 'while' loop is really executed at least once:
if result == InitSkippable: result = Unknown
of harmless:
Expand All @@ -1128,9 +1131,17 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum =
allPathsInBranch(n[0])
for i in 1..<n.len:
if n[i].kind == nkFinally:
result = allPathsAsgnResult(n[i].lastSon)
result = allPathsAsgnResult(p, n[i].lastSon)
else:
allPathsInBranch(n[i].lastSon)
of nkCallKinds:
if canRaiseDisp(p, n[0]):
result = InitRequired
else:
for i in 0..<n.safeLen:
allPathsInBranch(n[i])
of nkRaiseStmt:
result = InitRequired
else:
for i in 0..<n.safeLen:
allPathsInBranch(n[i])
Expand Down Expand Up @@ -1187,7 +1198,7 @@ proc genProcAux*(m: BModule, prc: PSym) =
assignLocalVar(p, resNode)
assert(res.loc.r != "")
if p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc} and
allPathsAsgnResult(procBody) == InitSkippable:
allPathsAsgnResult(p, procBody) == InitSkippable:
# In an ideal world the codegen could rely on injectdestructors doing its job properly
# and then the analysis step would not be required.
discard "result init optimized out"
Expand All @@ -1207,7 +1218,7 @@ proc genProcAux*(m: BModule, prc: PSym) =
# global is either 'nil' or points to valid memory and so the RC operation
# succeeds without touching not-initialized memory.
if sfNoInit in prc.flags: discard
elif allPathsAsgnResult(procBody) == InitSkippable: discard
elif allPathsAsgnResult(p, procBody) == InitSkippable: discard
else:
resetLoc(p, res.loc)
if skipTypes(res.typ, abstractInst).kind == tyArray:
Expand Down
12 changes: 8 additions & 4 deletions compiler/extccomp.nim
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import std/[os, osproc, streams, sequtils, times, strtabs, json, jsonutils, suga
import std / strutils except addf

when defined(nimPreviewSlimSystem):
import std/syncio
import std/[syncio, assertions]

import ../dist/checksums/src/checksums/sha1

Expand Down Expand Up @@ -999,7 +999,7 @@ type BuildCache = object
depfiles: seq[(string, string)]
nimexe: string

proc writeJsonBuildInstructions*(conf: ConfigRef) =
proc writeJsonBuildInstructions*(conf: ConfigRef; deps: StringTableRef) =
var linkFiles = collect(for it in conf.externalToLink:
var it = it
if conf.noAbsolutePaths: it = it.extractFilename
Expand All @@ -1020,10 +1020,14 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) =
currentDir: getCurrentDir())
if optRun in conf.globalOptions or isDefined(conf, "nimBetterRun"):
bcache.cmdline = conf.commandLine
bcache.depfiles = collect(for it in conf.m.fileInfos:
for it in conf.m.fileInfos:
let path = it.fullPath.string
if isAbsolute(path): # TODO: else?
(path, $secureHashFile(path)))
if path in deps:
bcache.depfiles.add (path, deps[path])
else: # backup for configs etc.
bcache.depfiles.add (path, $secureHashFile(path))

bcache.nimexe = hashNimExe()
conf.jsonBuildFile = conf.jsonBuildInstructionsFile
conf.jsonBuildFile.string.writeFile(bcache.toJson.pretty)
Expand Down
9 changes: 7 additions & 2 deletions compiler/injectdestructors.nim
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,9 @@ template processScopeExpr(c: var Con; s: var Scope; ret: PNode, processCall: unt
# tricky because you would have to intercept moveOrCopy at a certain point
let tmp = c.getTemp(s.parent[], ret.typ, ret.info)
tmp.sym.flags = tmpFlags
let cpy = if hasDestructor(c, ret.typ):
let cpy = if hasDestructor(c, ret.typ) and
ret.typ.kind notin {tyOpenArray, tyVarargs}:
# bug #23247 we don't own the data, so it's harmful to destroy it
s.parent[].final.add c.genDestroy(tmp)
moveOrCopy(tmp, ret, c, s, {IsDecl})
else:
Expand Down Expand Up @@ -907,7 +909,10 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
result[0] = p(n[0], c, s, normal)
if canRaise(n[0]): s.needsTry = true
if mode == normal:
result = ensureDestruction(result, n, c, s)
if result.typ != nil and result.typ.kind notin {tyOpenArray, tyVarargs}:
# Returns of openarray types shouldn't be destroyed
# bug #19435; # bug #23247
result = ensureDestruction(result, n, c, s)
of nkDiscardStmt: # Small optimization
result = shallowCopy(n)
if n[0].kind != nkEmpty:
Expand Down
5 changes: 3 additions & 2 deletions compiler/main.nim
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ proc commandCompileToC(graph: ModuleGraph) =
extccomp.callCCompiler(conf)
# for now we do not support writing out a .json file with the build instructions when HCR is on
if not conf.hcrOn:
extccomp.writeJsonBuildInstructions(conf)
extccomp.writeJsonBuildInstructions(conf, graph.cachedFiles)
if optGenScript in graph.config.globalOptions:
writeDepsFile(graph)
if optGenCDeps in graph.config.globalOptions:
Expand Down Expand Up @@ -326,7 +326,8 @@ proc mainCommand*(graph: ModuleGraph) =
# so by default should not end up in $PWD nor in $projectPath.
var ret = if optUseNimcache in conf.globalOptions: getNimcacheDir(conf)
else: conf.projectPath
doAssert ret.string.isAbsolute # `AbsoluteDir` is not a real guarantee
if not ret.string.isAbsolute: # `AbsoluteDir` is not a real guarantee
rawMessage(conf, errCannotOpenFile, ret.string & "/")
if conf.cmd in cmdDocLike + {cmdRst2html, cmdRst2tex, cmdMd2html, cmdMd2tex}:
ret = ret / htmldocsDir
conf.outDir = ret
Expand Down
5 changes: 4 additions & 1 deletion compiler/modulegraphs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
## represents a complete Nim project. Single modules can either be kept in RAM
## or stored in a rod-file.

import std/[intsets, tables, hashes]
import std/[intsets, tables, hashes, strtabs]
import ../dist/checksums/src/checksums/md5
import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils, packages
import ic / [packed_ast, ic]
Expand Down Expand Up @@ -140,6 +140,8 @@ type
idgen*: IdGenerator
operators*: Operators

cachedFiles*: StringTableRef

TPassContext* = object of RootObj # the pass's context
idgen*: IdGenerator
PPassContext* = ref TPassContext
Expand Down Expand Up @@ -518,6 +520,7 @@ proc initModuleGraphFields(result: ModuleGraph) =
result.symBodyHashes = initTable[int, SigHash]()
result.operators = initOperators(result)
result.emittedTypeInfo = initTable[string, FileIndex]()
result.cachedFiles = newStringTable()

proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
result = ModuleGraph()
Expand Down
5 changes: 5 additions & 0 deletions compiler/modules.nim
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import
idents, lexer, syntaxes, modulegraphs,
lineinfos, pathutils

import ../dist/checksums/src/checksums/sha1
import std/strtabs

proc resetSystemArtifacts*(g: ModuleGraph) =
magicsys.resetSysTypes(g)

Expand Down Expand Up @@ -42,6 +45,8 @@ proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PNode =
result = syntaxes.parseFile(fileIdx, graph.cache, graph.config)
graph.addDep(s, fileIdx)
graph.addIncludeDep(s.position.FileIndex, fileIdx)
let path = toFullPath(graph.config, fileIdx)
graph.cachedFiles[path] = $secureHashFile(path)

proc wantMainModule*(conf: ConfigRef) =
if conf.projectFull.isEmpty:
Expand Down
4 changes: 2 additions & 2 deletions compiler/nimeval.nim
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
import
ast, modules, condsyms,
options, llstream, lineinfos, vm,
vmdef, modulegraphs, idents, os, pathutils,
scriptconfig, std/[compilesettings, tables]
vmdef, modulegraphs, idents, pathutils,
scriptconfig, std/[compilesettings, tables, os]

import pipelines

Expand Down
5 changes: 3 additions & 2 deletions compiler/parser.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2189,7 +2189,8 @@ proc parseObject(p: var Parser): PNode =
proc parseTypeClassParam(p: var Parser): PNode =
let modifier =
case p.tok.tokType
of tkOut, tkVar: nkVarTy
of tkVar: nkVarTy
of tkOut: nkOutTy
of tkPtr: nkPtrTy
of tkRef: nkRefTy
of tkStatic: nkStaticTy
Expand All @@ -2205,7 +2206,7 @@ proc parseTypeClassParam(p: var Parser): PNode =
setEndInfo()

proc parseTypeClass(p: var Parser): PNode =
#| conceptParam = ('var' | 'out')? symbol
#| conceptParam = ('var' | 'out' | 'ptr' | 'ref' | 'static' | 'type')? symbol
#| conceptDecl = 'concept' conceptParam ^* ',' (pragma)? ('of' typeDesc ^* ',')?
#| &IND{>} stmt
result = newNodeP(nkTypeClassTy, p)
Expand Down
9 changes: 7 additions & 2 deletions compiler/pipelines.nim
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import sem, cgen, modulegraphs, ast, llstream, parser, msgs,

import pipelineutils

import ../dist/checksums/src/checksums/sha1

when not defined(leanCompiler):
import jsgen, docgen2

import std/[syncio, objectdollar, assertions, tables, strutils]
import std/[syncio, objectdollar, assertions, tables, strutils, strtabs]
import renderer
import ic/replayer
import nir/nir
Expand Down Expand Up @@ -244,7 +246,10 @@ proc compilePipelineModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymF
if result == nil:
var cachedModules: seq[FileIndex] = @[]
result = moduleFromRodFile(graph, fileIdx, cachedModules)
let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
let path = toFullPath(graph.config, fileIdx)
let filename = AbsoluteFile path
if fileExists(filename): # it could be a stdinfile
graph.cachedFiles[path] = $secureHashFile(path)
if result == nil:
result = newModule(graph, fileIdx)
result.flags.incl flags
Expand Down
3 changes: 2 additions & 1 deletion compiler/sigmatch.nim
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,8 @@ proc sumGeneric(t: PType): int =
result += sumGeneric(a)
break
of tyProc:
result += sumGeneric(t.returnType)
if t.returnType != nil:
result += sumGeneric(t.returnType)
for _, a in t.paramTypes:
result += sumGeneric(a)
break
Expand Down
3 changes: 2 additions & 1 deletion compiler/transf.nim
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,8 @@ proc transformYield(c: PTransf, n: PNode): PNode =

proc transformAddrDeref(c: PTransf, n: PNode, kinds: TNodeKinds): PNode =
result = transformSons(c, n)
if c.graph.config.backend == backendCpp or sfCompileToCpp in c.module.flags: return
# inlining of 'var openarray' iterators; bug #19977
if n.typ.kind != tyOpenArray and (c.graph.config.backend == backendCpp or sfCompileToCpp in c.module.flags): return
var n = result
case n[0].kind
of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
Expand Down
2 changes: 1 addition & 1 deletion doc/grammar.txt
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ objectCase = 'case' declColonEquals ':'? COMMENT?
objectPart = IND{>} objectPart^+IND{=} DED
/ objectWhen / objectCase / 'nil' / 'discard' / declColonEquals
objectDecl = 'object' ('of' typeDesc)? COMMENT? objectPart
conceptParam = ('var' | 'out')? symbol
conceptParam = ('var' | 'out' | 'ptr' | 'ref' | 'static' | 'type')? symbol
conceptDecl = 'concept' conceptParam ^* ',' (pragma)? ('of' typeDesc ^* ',')?
&IND{>} stmt
typeDef = identVisDot genericParamList? pragma '=' optInd typeDefValue
Expand Down
2 changes: 1 addition & 1 deletion doc/manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ You can also use the [discard statement](#statements-and-expressions-discard-sta
```

This was how multiline comments were done before version 0.13.0,
and it is used to provide specifications to [testament](testament.html#writing-unitests) test framework.
and it is used to provide specifications to [testament](testament.html#writing-unit-tests) test framework.


Identifiers & Keywords
Expand Down
2 changes: 1 addition & 1 deletion lib/pure/algorithm.nim
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ func sort*[T](a: var openArray[T],
## ```
##
## You can inline adhoc comparison procs with the `do notation
## <manual_experimental.html#do-notation>`_. Example:
## <manual.html#procedures-do-notation>`_. Example:
##
## ```nim
## people.sort do (x, y: Person) -> int:
Expand Down
Loading

0 comments on commit 5918bdb

Please sign in to comment.