Compare commits

..

9 Commits

Author SHA1 Message Date
ringabout
a659dbff1b Merge branch 'devel' into pr_nodecl_type 2025-10-10 21:00:12 +08:00
ringabout
276840610b adds a changelog 2025-01-09 21:31:32 +08:00
ringabout
449511995f uses nodecl 2025-01-08 22:32:29 +08:00
ringabout
33263ef806 fixes tests 2025-01-08 21:45:26 +08:00
ringabout
ce20f1b31a use nodecl 2025-01-08 19:53:43 +08:00
ringabout
c1f99aa362 fixes macos 2025-01-08 19:50:25 +08:00
ringabout
67d80c4971 oops 2025-01-08 19:32:40 +08:00
ringabout
237669a1b2 fixes types with a header 2025-01-08 19:27:25 +08:00
ringabout
d39c76b8bd fixes #24604; importc fails to generate stub type 2025-01-08 18:44:28 +08:00
339 changed files with 7879 additions and 16582 deletions

View File

@@ -1,11 +0,0 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "github-actions" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "weekly"

View File

@@ -15,16 +15,9 @@ jobs:
name: ${{ matrix.platform }}-bisects
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
- name: Install OpenSSL (Windows)
if: |
runner.os == 'Windows'
run: choco install openssl.light --version=1.1.1.0 # OpenSSL 3.x removed SSL_library_init
shell: 'powershell'
# v2 wont work here, because uses "hardcoded" nim versions, action "dynamically" finds version with bug.
- uses: jiro4989/setup-nim-action@v1
- uses: jiro4989/setup-nim-action@v1
with:
nim-version: 'devel'

View File

@@ -45,7 +45,7 @@ jobs:
- target: windows
os: windows-latest
- target: osx
os: macos-15
os: macos-13
name: ${{ matrix.target }}
runs-on: ${{ matrix.os }}
@@ -53,7 +53,7 @@ jobs:
steps:
- name: 'Checkout'
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
fetch-depth: 2

View File

@@ -33,14 +33,14 @@ jobs:
NIM_TESTAMENT_BATCH: ${{ matrix.batch }}
steps:
- name: 'Checkout'
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: 'Install node.js'
uses: actions/setup-node@v6
- name: 'Install node.js 20.x'
uses: actions/setup-node@v4
with:
node-version: 24
node-version: '20.x'
- name: 'Install dependencies (Linux amd64)'
if: runner.os == 'Linux' && matrix.cpu == 'amd64'

View File

@@ -17,14 +17,14 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: 'Checkout'
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: 'Install node.js'
uses: actions/setup-node@v6
uses: actions/setup-node@v4
with:
node-version: 24
node-version: ''
- name: 'Install dependencies (Linux amd64)'
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
@@ -60,7 +60,7 @@ jobs:
run: nim c -r -d:release ci/action.nim
- name: 'Comment'
uses: actions/github-script@v8
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');

View File

@@ -9,7 +9,7 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v10
- uses: actions/stale@v9
with:
days-before-pr-stale: 365
days-before-pr-close: 30

1
.gitignore vendored
View File

@@ -68,7 +68,6 @@ testament.db
/csources
/csources_v1
/csources_v2
/csources_v3
/dist/
# /lib/fusion # fusion is now unbundled; `git status` should reveal if it's there so users can act on it

View File

@@ -28,12 +28,12 @@ jobs:
# # g++-multilib : Depends: gcc-multilib (>= 4:5.3.1-1ubuntu1) but it is not going to be installed
# vmImage: 'ubuntu-18.04'
# CPU: i386
OSX_arm64:
vmImage: 'macos-15'
CPU: arm64
OSX_arm64_cpp:
vmImage: 'macos-15'
CPU: arm64
OSX_amd64:
vmImage: 'macOS-13'
CPU: amd64
OSX_amd64_cpp:
vmImage: 'macOS-13'
CPU: amd64
NIM_COMPILE_TO_CPP: true
Windows_amd64_batch0_3:
vmImage: 'windows-2025'

View File

@@ -19,6 +19,8 @@ errors.
- With `-d:nimPreviewAsmSemSymbol`, backticked symbols are type checked in the `asm/emit` statements.
- `importc` no longer implies `nodecl` for imported types. Use `header` or `nodecl` pragmas so that it doesn't generate a declaration for the type symbol.
- The bare `except:` now panics on `Defect`. Use `except Exception:` or `except Defect:` to catch `Defect`. `--legacy:noPanicOnExcept` is provided for a transition period.
- With `-d:nimPreviewCStringComparisons`, comparsions (`<`, `>`, `<=`, `>=`) between cstrings switch from reference semantics to value semantics like `==` and `!=`.
@@ -27,13 +29,6 @@ errors.
- With `-d:nimPreviewDuplicateModuleError`, importing two modules that share the same name becomes a compile-time error. This includes importing the same module more than once. Use `import foo as foo1` (or other aliases) to avoid collisions.
- Adds the switch `--mangle:nim|cpp`, which selects `nim` or `cpp` style name mangling when used with `debuginfo` on, defaults to `cpp`.
- The second parameter of `succ`, `pred`, `inc`, and `dec` in `system` now accepts `SomeInteger` (previously `Ordinal`).
- Bitshift operators (`shl`, `shr`, `ashr`) now apply bitmasking to the right operand in the C/C++/VM/JS backends.
- Adds a new warning `--warning:ImplicitRangeConversion` that detects downsizing implicit conversions to range types (e.g., `int -> range[0..255]` or `range[1..256] -> range[0..255]`) that could cause runtime panics. Safe conversions like `range[0..255] -> range[0..65535]` and explicit casts do not trigger warnings. `int` to `Natural` and `Positive` conversions do not trigger warnings, which can be enabled with `--warning:systemRangeConversion`.
## Standard library additions and changes
@@ -61,10 +56,6 @@ errors.
- `system.setLenUninit` now supports refc, JS and VM backends.
- `std/parseopt` now supports multiple parser modes via a `CliMode` enum.
Modes include `Nim` (default, fully compatible) and two new experimental modes:
`Lax` and `Gnu` for different option parsing behaviors.
[//]: # "Changes:"
- `std/math` The `^` symbol now supports floating-point as exponent in addition to the Natural type.
@@ -111,17 +102,7 @@ errors.
## Compiler changes
- Fixed a bug where `sizeof(T)` inside a `typedesc` template called from a generic type's
`when` clause would error with "'sizeof' requires '.importc' types to be '.completeStruct'".
The issue was that `hasValuelessStatics` in `semtypinst.nim` didn't recognize
`tyTypeDesc(tyGenericParam)` as an unresolved generic parameter.
## Tool changes
- Added `--raw` flag when generating JSON docs to not render markup.
- Added `--stdinfile` flag to name of the file used when running program from stdin (defaults to `stdinfile.nim`)
- Added `--styleCheck:warning` flag to treat style check violations as warnings.
## Documentation changes
- Added documentation for the `completeStruct` pragma in the manual.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -68,6 +68,8 @@ template mdbg*: bool {.deprecated.} =
# ---------------------------------------------------------------------------
proc lookupInRecord*(n: PNode, field: PIdent): PSym
proc mustRehash*(length, counter: int): bool
proc nextTry*(h, maxHash: Hash): Hash {.inline.}
# ------------- table[int, int] ---------------------------------------------
const
@@ -214,6 +216,10 @@ proc getNamedParamFromList*(list: PNode, ident: PIdent): PSym =
proc hashNode(p: RootRef): Hash =
result = hash(cast[pointer](p))
proc mustRehash(length, counter: int): bool =
assert(length > counter)
result = (length * 2 < counter * 3) or (length - counter < 4)
import std/tables
const backrefStyle = "\e[90m"
@@ -478,6 +484,12 @@ proc debug(n: PNode; conf: ConfigRef) =
this.value(n)
echo($this.res)
proc nextTry(h, maxHash: Hash): Hash {.inline.} =
result = ((5 * h) + 1) and maxHash
# For any initial h in range(maxHash), repeating that maxHash times
# generates each int in range(maxHash) exactly once (see any text on
# random-number generation for proof).
proc objectSetContains*(t: TObjectSet, obj: RootRef): bool =
# returns true whether n is in t
var h: Hash = hashNode(obj) and high(t.data) # start with real hash value
@@ -525,6 +537,95 @@ proc objectSetContainsOrIncl*(t: var TObjectSet, obj: RootRef): bool =
inc(t.counter)
result = false
proc strTableContains*(t: TStrTable, n: PSym): bool =
var h: Hash = n.name.h and high(t.data) # start with real hash value
while t.data[h] != nil:
if (t.data[h] == n):
return true
h = nextTry(h, high(t.data))
result = false
proc strTableRawInsert(data: var seq[PSym], n: PSym) =
var h: Hash = n.name.h and high(data)
while data[h] != nil:
if data[h] == n:
# allowed for 'export' feature:
#InternalError(n.info, "StrTableRawInsert: " & n.name.s)
return
h = nextTry(h, high(data))
assert(data[h] == nil)
data[h] = n
proc symTabReplaceRaw(data: var seq[PSym], prevSym: PSym, newSym: PSym) =
assert prevSym.name.h == newSym.name.h
var h: Hash = prevSym.name.h and high(data)
while data[h] != nil:
if data[h] == prevSym:
data[h] = newSym
return
h = nextTry(h, high(data))
assert false
proc symTabReplace*(t: var TStrTable, prevSym: PSym, newSym: PSym) =
symTabReplaceRaw(t.data, prevSym, newSym)
proc strTableEnlarge(t: var TStrTable) =
var n: seq[PSym]
newSeq(n, t.data.len * GrowthFactor)
for i in 0..high(t.data):
if t.data[i] != nil: strTableRawInsert(n, t.data[i])
swap(t.data, n)
proc strTableAdd*(t: var TStrTable, n: PSym) =
if mustRehash(t.data.len, t.counter): strTableEnlarge(t)
strTableRawInsert(t.data, n)
inc(t.counter)
proc strTableInclReportConflict*(t: var TStrTable, n: PSym;
onConflictKeepOld = false): PSym =
# if `t` has a conflicting symbol (same identifier as `n`), return it
# otherwise return `nil`. Incl `n` to `t` unless `onConflictKeepOld = true`
# and a conflict was found.
assert n.name != nil
var h: Hash = n.name.h and high(t.data)
var replaceSlot = -1
while true:
var it = t.data[h]
if it == nil: break
# Semantic checking can happen multiple times thanks to templates
# and overloading: (var x=@[]; x).mapIt(it).
# So it is possible the very same sym is added multiple
# times to the symbol table which we allow here with the 'it == n' check.
if it.name.id == n.name.id:
if it == n: return nil
replaceSlot = h
h = nextTry(h, high(t.data))
if replaceSlot >= 0:
result = t.data[replaceSlot] # found it
if not onConflictKeepOld:
t.data[replaceSlot] = n # overwrite it with newer definition!
return result # but return the old one
elif mustRehash(t.data.len, t.counter):
strTableEnlarge(t)
strTableRawInsert(t.data, n)
else:
assert(t.data[h] == nil)
t.data[h] = n
inc(t.counter)
result = nil
proc strTableIncl*(t: var TStrTable, n: PSym;
onConflictKeepOld = false): bool {.discardable.} =
result = strTableInclReportConflict(t, n, onConflictKeepOld) != nil
proc strTableGet*(t: TStrTable, name: PIdent): PSym =
var h: Hash = name.h and high(t.data)
while true:
result = t.data[h]
if result == nil: break
if result.name.id == name.id: break
h = nextTry(h, high(t.data))
type
TIdentIter* = object # iterator over all syms with same identifier

File diff suppressed because it is too large Load Diff

View File

@@ -69,7 +69,7 @@ proc copyHalf[Key, Val](h, result: Node[Key, Val]) =
result.links[j] = h.links[Mhalf + j]
else:
for j in 0..<Mhalf:
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc) or defined(gcYrc):
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
result.vals[j] = move h.vals[Mhalf + j]
else:
shallowCopy(result.vals[j], h.vals[Mhalf + j])
@@ -92,7 +92,7 @@ proc insert[Key, Val](h: Node[Key, Val], key: Key, val: Val): Node[Key, Val] =
if less(key, h.keys[j]): break
inc j
for i in countdown(h.entries, j+1):
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc) or defined(gcYrc):
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
h.vals[i] = move h.vals[i-1]
else:
shallowCopy(h.vals[i], h.vals[i-1])

View File

@@ -154,14 +154,14 @@ template addField(builder: var Builder, constr: var StructInitializer, name: str
# no name, can just add value
valueBody
of siOrderedStruct:
# positional init - name not used in output (empty allowed for anonymous unions)
# no name, can just add value on C
assert name.len != 0, "name has to be given for struct initializer field"
valueBody
of siNamedStruct:
# designated init - empty name for anonymous unions (skips .name = prefix)
if name.len != 0:
builder.add(".")
builder.add(name)
builder.add(" = ")
assert name.len != 0, "name has to be given for struct initializer field"
builder.add(".")
builder.add(name)
builder.add(" = ")
valueBody
proc finishStructInitializer(builder: var Builder, constr: StructInitializer) =

View File

@@ -331,7 +331,7 @@ proc withTmpIfNeeded(p: BProc, a: TLoc, needsTmp: bool): TLoc =
# Bug https://github.com/status-im/nimbus-eth2/issues/1549
# Aliasing is preferred over stack overflows.
# Also don't regress for non ARC-builds, too risky.
if needsTmp and a.lode.typ != nil and p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc, gcYrc} and
if needsTmp and a.lode.typ != nil and p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc} and
getSize(p.config, a.lode.typ) < 1024:
result = getTemp(p, a.lode.typ, needsInit=false)
genAssignment(p, result, a, {})
@@ -368,8 +368,8 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Builder; n
# variable. Thus, we create a temporary pointer variable instead.
let needsIndirect = mapType(p.config, n[0].typ, mapTypeChooser(n[0]) == skParam) != ctArray
if needsIndirect:
n.typ = n.typ.exactReplica
n.typ.incl tfVarIsPtr
n.typ() = n.typ.exactReplica
n.typ.flags.incl tfVarIsPtr
a = initLocExprSingleUse(p, n)
a = withTmpIfNeeded(p, a, needsTmp)
if needsIndirect: a.flags.incl lfIndirect
@@ -498,7 +498,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
else:
cCall(p, params, e)
cIfExpr(e,
eCall,
eCall,
cCall(cCast(pTyp, p), params))
template callIter(rp, params: Snippet): Snippet =

View File

@@ -170,7 +170,7 @@ proc canMove(p: BProc, n: PNode; dest: TLoc): bool =
template simpleAsgn(builder: var Builder, dest, src: TLoc) =
let rd = rdLoc(dest)
let rs = rdLoc(src)
builder.addAssignment(rd, rs)
builder.addAssignment(rd, rs)
proc genRefAssign(p: BProc, dest, src: TLoc) =
if (dest.storage == OnStack and p.config.selectedGC != gcGo) or not usesWriteBarrier(p.config):
@@ -416,7 +416,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
else:
simpleAsgn(p.s(cpsStmts), dest, src)
of tyArray:
if containsGarbageCollectedRef(dest.t) and p.config.selectedGC notin {gcArc, gcAtomicArc, gcOrc, gcYrc, gcHooks}:
if containsGarbageCollectedRef(dest.t) and p.config.selectedGC notin {gcArc, gcAtomicArc, gcOrc, gcHooks}:
genGenericAsgn(p, dest, src, flags)
else:
let rd = rdLoc(dest)
@@ -675,7 +675,7 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
if e[2].kind in {nkIntLit..nkInt64Lit}:
needsOverflowCheck = e[2].intVal == -1
if canBeZero:
# remove extra paren from `==` op here to avoid Wparentheses-equality:
# remove extra paren from `==` op here to avoid Wparentheses-equality:
p.s(cpsStmts).addSingleIfStmt(removeSinglePar(cOp(Equal, rdLoc(b), cIntValue(0)))):
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "raiseDivByZero"))
raiseInstr(p, p.s(cpsStmts))
@@ -696,7 +696,7 @@ proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
let ra = rdLoc(a)
if optOverflowCheck in p.options:
let first = cIntLiteral(firstOrd(p.config, t))
# remove extra paren from `==` op here to avoid Wparentheses-equality:
# remove extra paren from `==` op here to avoid Wparentheses-equality:
p.s(cpsStmts).addSingleIfStmt(removeSinglePar(cOp(Equal, ra, first))):
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "raiseOverflow"))
raiseInstr(p, p.s(cpsStmts))
@@ -749,16 +749,16 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
let t = getType()
let at = cUintType(k)
let bt = cUintType(s)
res = cCast(t, cOp(Shr, at, cCast(at, ra), cOp(BitAnd, at, cCast(bt, rb), cIntLiteral(k - 1))))
res = cCast(t, cOp(Shr, at, cCast(at, ra), cCast(bt, rb)))
of mShlI:
let t = getType()
let at = cUintType(s)
res = cCast(t, cOp(Shl, at, cCast(at, ra), cOp(BitAnd, at, cCast(at, rb), cIntLiteral(k - 1))))
res = cCast(t, cOp(Shl, at, cCast(at, ra), cCast(at, rb)))
of mAshrI:
let t = getType()
let at = cIntType(s)
let bt = cUintType(s)
res = cCast(t, cOp(Shr, at, cCast(at, ra), cOp(BitAnd, at, cCast(bt, rb), cIntLiteral(k - 1))))
res = cCast(t, cOp(Shr, at, cCast(at, ra), cCast(bt, rb)))
of mBitandI:
let t = getType()
res = cCast(t, cOp(BitAnd, t, ra, rb))
@@ -919,10 +919,6 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) =
return
else:
a = initLocExprSingleUse(p, e[0])
if e.typ != nil and e.typ.kind == tyObject:
# bug #23453 #25265
discard getTypeDesc(p.module, e.typ)
if d.k == locNone:
# dest = *a; <-- We do not know that 'dest' is on the heap!
# It is completely wrong to set 'd.storage' here, unless it's not yet
@@ -1006,7 +1002,7 @@ proc genTupleElem(p: BProc, e: PNode, d: var TLoc) =
var
i: int = 0
var a: TLoc = initLocExpr(p, e[0])
let tupType = a.t.skipTypes(abstractInst+{tyVar}+tyUserTypeClasses) # ref #25227
let tupType = a.t.skipTypes(abstractInst+{tyVar})
assert tupType.kind == tyTuple
d.inheritLocation(a)
discard getTypeDesc(p.module, a.t) # fill the record's fields.loc
@@ -1832,7 +1828,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
var tmp: TLoc = default(TLoc)
var r: Rope
let needsZeroMem = p.config.selectedGC notin {gcArc, gcAtomicArc, gcOrc, gcYrc} or nfAllFieldsSet notin e.flags
let needsZeroMem = p.config.selectedGC notin {gcArc, gcAtomicArc, gcOrc} or nfAllFieldsSet notin e.flags
if useTemp:
tmp = getTemp(p, t)
r = rdLoc(tmp)
@@ -1916,7 +1912,7 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) =
proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
var elem, arr: TLoc
if n[1].kind == nkBracket:
n[1].typ = n.typ
n[1].typ() = n.typ
genSeqConstr(p, n[1], d)
return
if d.k == locNone:
@@ -2751,7 +2747,7 @@ proc genMove(p: BProc; n: PNode; d: var TLoc) =
p.s(cpsStmts).addFieldAssignment(destVal, "p", dotField(srcVal, "p"))
else:
if d.k == locNone: d = getTemp(p, n.typ)
if p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc, gcYrc}:
if p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
genAssignment(p, d, a, {})
var op = getAttachedOp(p.module.g.graph, n.typ, attachedWasMoved)
if op == nil:
@@ -2835,7 +2831,7 @@ proc genSlice(p: BProc; e: PNode; d: var TLoc) =
let (x, y) = genOpenArraySlice(p, e, e.typ, e.typ.elementType,
prepareForMutation = e[1].kind == nkHiddenDeref and
e[1].typ.skipTypes(abstractInst).kind == tyString and
p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc, gcYrc})
p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc})
if d.k == locNone: d = getTemp(p, e.typ)
let dest = rdLoc(d)
p.s(cpsStmts).addFieldAssignment(dest, "Field0", x)
@@ -3039,7 +3035,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
let n = semparallel.liftParallel(p.module.g.graph, p.module.idgen, p.module.module, e)
expr(p, n, d)
of mDeepCopy:
if p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc, gcYrc} and optEnableDeepCopy notin p.config.globalOptions:
if p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc} and optEnableDeepCopy notin p.config.globalOptions:
localError(p.config, e.info,
"for --mm:arc|atomicArc|orc 'deepcopy' support has to be enabled with --deepcopy:on")
@@ -3271,11 +3267,7 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "raiseObjectConversionError"))
raiseInstr(p, p.s(cpsStmts))
# skip cast when types map to the same C type
# this avoids invalid C code like `*(T*)&x` for types that can't have their address taken (e.g., WASM __externref_t)
if getTypeDesc(p.module, n.typ) == getTypeDesc(p.module, n[0].typ):
expr(p, n[0], d)
elif n[0].typ.kind != tyObject:
if n[0].typ.kind != tyObject:
let destTyp = getTypeDesc(p.module, n.typ)
let val = rdLoc(a)
if n.isLValue:
@@ -3321,7 +3313,7 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) =
cCast(ptrType(destType),
wrapPar(cAddr(wrapPar(val))))),
a.storage)
elif p.module.compileToCpp or isImportedType(src):
elif p.module.compileToCpp:
# C++ implicitly downcasts for us
expr(p, arg, d)
else:
@@ -3367,9 +3359,8 @@ proc genConstSetup(p: BProc; sym: PSym): bool =
useHeader(m, sym)
if sym.loc.k == locNone:
fillBackendName(p.module, sym)
backendEnsureMutable sym
fillLoc(sym.locImpl, locData, sym.astdef, OnStatic)
if m.hcrOn: incl(sym, lfIndirect)
fillLoc(sym.loc, locData, sym.astdef, OnStatic)
if m.hcrOn: incl(sym.loc.flags, lfIndirect)
result = lfNoDecl notin sym.loc.flags
proc genConstHeader(m, q: BModule; p: BProc, sym: PSym) =
@@ -3439,7 +3430,7 @@ proc genConstDefinition(q: BModule; p: BProc; sym: PSym) =
proc genConstStmt(p: BProc, n: PNode) =
# This code is only used in the new DCE implementation.
assert delayedCodegen(p.module)
assert useAliveDataFromDce in p.module.flags
let m = p.module
for it in n:
if it[0].kind == nkSym:
@@ -3457,7 +3448,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
var sym = n.sym
case sym.kind
of skMethod:
if delayedCodegen(p.module) or {sfDispatcher, sfForward} * sym.flags != {}:
if useAliveDataFromDce in p.module.flags or {sfDispatcher, sfForward} * sym.flags != {}:
# we cannot produce code for the dispatcher yet:
fillProcLoc(p.module, n)
genProcPrototype(p.module, sym)
@@ -3470,15 +3461,11 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
if sfCompileTime in sym.flags:
localError(p.config, n.info, "request to generate code for .compileTime proc: " &
sym.name.s)
if delayedCodegen(p.module) and sym.typ.callConv != ccInline:
if useAliveDataFromDce in p.module.flags and sym.typ.callConv != ccInline:
fillProcLoc(p.module, n)
genProcPrototype(p.module, sym)
else:
genProc(p.module, sym)
# For cross-module inline procs with optCompress, ensure prototype is emitted
if sym.typ.callConv == ccInline and optCompress in p.config.globalOptions and
sym.itemId.module != p.module.module.position:
genProcPrototype(p.module, sym)
if sym.loc.snippet == "" or sym.loc.lode == nil:
internalError(p.config, n.info, "expr: proc not init " & sym.name.s)
putLocIntoDest(p, d, sym.loc)
@@ -3487,13 +3474,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
var lit = newBuilder("")
genLiteral(p, sym.astdef, sym.typ, lit)
putIntoDest(p, d, n, extract(lit), OnStatic)
elif optCompress in p.config.globalOptions:
# With delayed codegen, we need to ensure the definition is generated
# not just the extern header declaration
requestConstImpl(p, sym)
assert((sym.loc.snippet != "") and (sym.loc.t != nil))
putLocIntoDest(p, d, sym.loc)
elif delayedCodegen(p.module):
elif useAliveDataFromDce in p.module.flags:
genConstHeader(p.module, p.module, p, sym)
assert((sym.loc.snippet != "") and (sym.loc.t != nil))
putLocIntoDest(p, d, sym.loc)
@@ -3625,7 +3606,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
of nkWhileStmt: genWhileStmt(p, n)
of nkVarSection, nkLetSection: genVarStmt(p, n)
of nkConstSection:
if delayedCodegen(p.module):
if useAliveDataFromDce in p.module.flags:
genConstStmt(p, n)
else: # enforce addressable consts for exportc
let m = p.module
@@ -3691,10 +3672,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
of nkProcDef, nkFuncDef, nkMethodDef, nkConverterDef:
if n[genericParamsPos].kind == nkEmpty:
var prc = n[namePos].sym
if optCompress in p.config.globalOptions:
if prc.magic in generatedMagics:
genProc(p.module, prc)
elif delayedCodegen(p.module):
if useAliveDataFromDce in p.module.flags:
if p.module.alive.contains(prc.itemId.item) and
prc.magic in generatedMagics:
genProc(p.module, prc)
@@ -3714,67 +3692,9 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
inc p.splitDecls
genGotoState(p, n)
of nkBreakState: genBreakState(p, n, d)
of nkMixinStmt, nkBindStmt, nkReplayAction: discard
of nkMixinStmt, nkBindStmt: discard
else: internalError(p.config, n.info, "expr(" & $n.kind & "); unknown node kind")
proc isOpaqueImportcType(t: PType): bool =
# importc type without completeStruct that can't use aggregate init (e.g. C11 _Atomic)
if t.sym != nil and sfImportc in t.sym.flags:
if tfCompleteStruct notin t.flags:
if tfIncompleteStruct in t.flags:
return true
if t.kind == tyObject and (t.n == nil or t.n.len == 0):
return true
return false
proc containsOpaqueImportcField(typ: PType): bool
proc containsOpaqueImportcFieldAux(t: PType; n: PNode): bool =
if n == nil: return false
case n.kind
of nkRecList:
for child in n.sons:
if containsOpaqueImportcFieldAux(t, child):
return true
of nkRecCase:
if containsOpaqueImportcFieldAux(t, n[0]):
return true
for i in 1..<n.len:
let branch = n[i]
if branch.kind == nkOfBranch or branch.kind == nkElse:
if containsOpaqueImportcFieldAux(t, branch.lastSon):
return true
of nkSym:
if containsOpaqueImportcField(n.sym.typ):
return true
else:
discard
return false
proc containsOpaqueImportcField(typ: PType): bool =
# Check if type contains opaque importc fields that need designated initializers
if typ == nil: return false
let t = skipTypes(typ, abstractRange+{tyOwned}-{tyTypeDesc})
if isOpaqueImportcType(t):
return true
case t.kind
of tyObject:
if t.baseClass != nil:
if containsOpaqueImportcField(t.baseClass):
return true
if containsOpaqueImportcFieldAux(t, t.n):
return true
of tyTuple:
for i, a in t.ikids:
if containsOpaqueImportcField(a):
return true
of tyArray:
if containsOpaqueImportcField(t.elementType):
return true
else:
discard
return false
proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo; result: var Builder) =
var t = skipTypes(typ, abstractRange+{tyOwned}-{tyTypeDesc})
case t.kind
@@ -3805,34 +3725,24 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo; result: var Builder)
result.addField(closureInit, name = "ClE_0"):
result.add(NimNil)
of tyObject:
# Use designated initializers when opaque importc fields present
var objInit: StructInitializer
let initKind = if containsOpaqueImportcField(t): siNamedStruct else: siOrderedStruct
result.addStructInitializer(objInit, kind = initKind):
result.addStructInitializer(objInit, kind = siOrderedStruct):
getNullValueAuxT(p, t, t, t.n, nil, result, objInit, true, info)
of tyTuple:
# Use designated initializers when opaque importc fields present
var tupleInit: StructInitializer
let initKind = if containsOpaqueImportcField(t): siNamedStruct else: siOrderedStruct
result.addStructInitializer(tupleInit, kind = initKind):
result.addStructInitializer(tupleInit, kind = siOrderedStruct):
if p.vccAndC and t.isEmptyTupleType:
result.addField(tupleInit, name = "dummy"):
result.addIntValue(0)
for i, a in t.ikids:
let elemTyp = skipTypes(a, abstractRange+{tyOwned}-{tyTypeDesc})
if not isOpaqueImportcType(elemTyp):
result.addField(tupleInit, name = "Field" & $i):
getDefaultValue(p, a, info, result)
result.addField(tupleInit, name = "Field" & $i):
getDefaultValue(p, a, info, result)
of tyArray:
let elemTyp = skipTypes(t.elementType, abstractRange+{tyOwned}-{tyTypeDesc})
if isOpaqueImportcType(elemTyp):
result.add "{0}"
else:
var arrInit: StructInitializer
result.addStructInitializer(arrInit, kind = siArray):
for i in 0..<toInt(lengthOrd(p.config, t.indexType)):
result.addField(arrInit, name = ""):
getDefaultValue(p, t.elementType, info, result)
var arrInit: StructInitializer
result.addStructInitializer(arrInit, kind = siArray):
for i in 0..<toInt(lengthOrd(p.config, t.indexType)):
result.addField(arrInit, name = ""):
getDefaultValue(p, t.elementType, info, result)
#result = rope"{}"
of tyOpenArray, tyVarargs:
var openArrInit: StructInitializer
@@ -3887,7 +3797,8 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode,
var fieldName: string = ""
if b.kind == nkRecList and not isEmptyCaseObjectBranch(b):
fieldName = "_" & mangleRecFieldName(p.module, obj[0].sym) & "_" & $selectedBranch
result.addField(init, name = ""): # anonymous union
result.addField(init, name = "<anonymous union>"):
# XXX figure out name for the union, see use of `addAnonUnion`
var branchInit: StructInitializer
result.addStructInitializer(branchInit, kind = siNamedStruct):
result.addField(branchInit, name = fieldName):
@@ -3896,7 +3807,8 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode,
getNullValueAux(p, t, b, constOrNil, result, branchObjInit, isConst, info)
elif b.kind == nkSym:
fieldName = mangleRecFieldName(p.module, b.sym)
result.addField(init, name = ""): # anonymous union
result.addField(init, name = "<anonymous union>"):
# XXX figure out name for the union, see use of `addAnonUnion`
var branchInit: StructInitializer
result.addStructInitializer(branchInit, kind = siNamedStruct):
result.addField(branchInit, name = fieldName):
@@ -3911,9 +3823,6 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode,
of nkSym:
let field = obj.sym
let fieldTyp = skipTypes(field.typ, abstractRange+{tyOwned}-{tyTypeDesc})
if isOpaqueImportcType(fieldTyp):
return # C zero-initializes omitted fields
let sname = mangleRecFieldName(p.module, field)
result.addField(init, name = sname):
block fieldInit:
@@ -3958,10 +3867,11 @@ proc getNullValueAuxT(p: BProc; orig, t: PType; obj, constOrNil: PNode,
proc genConstObjConstr(p: BProc; n: PNode; isConst: bool; result: var Builder) =
let t = n.typ.skipTypes(abstractInstOwned)
# Use designated initializers when opaque importc fields present
#if not isObjLackingTypeField(t) and not p.module.compileToCpp:
# result.addf("{$1}", [genTypeInfo(p.module, t)])
# inc count
var objInit: StructInitializer
let initKind = if t.kind == tyObject and containsOpaqueImportcField(t): siNamedStruct else: siOrderedStruct
result.addStructInitializer(objInit, kind = initKind):
result.addStructInitializer(objInit, kind = siOrderedStruct):
if t.kind == tyObject:
getNullValueAuxT(p, t, t, t.n, n, result, objInit, isConst, n.info)

View File

@@ -16,10 +16,13 @@
## implementation.
template detectVersion(field, corename) =
if m.g.config.selectedGC in {gcArc, gcOrc, gcYrc, gcAtomicArc, gcHooks}:
result = 2
else:
result = 1
if m.g.field == 0:
let core = getCompilerProc(m.g.graph, corename)
if core == nil or core.kind != skConst:
m.g.field = 1
else:
m.g.field = toInt(ast.getInt(core.astdef))
result = m.g.field
proc detectStrVersion(m: BModule): int =
detectVersion(strVersion, "nimStrVersion")

View File

@@ -126,26 +126,25 @@ proc genVarTuple(p: BProc, n: PNode) =
let vn = n[i]
let v = vn.sym
if sfCompileTime in v.flags: continue
backendEnsureMutable v
if sfGlobal in v.flags:
assignGlobalVar(p, vn, "")
genObjectInit(p, cpsInit, v.typ, v.locImpl, constructObj)
genObjectInit(p, cpsInit, v.typ, v.loc, constructObj)
registerTraverseProc(p, v)
else:
assignLocalVar(p, vn)
initLocalVar(p, v, immediateAsgn=isAssignedImmediately(p.config, n[^1]))
var field = initLoc(locExpr, vn, tup.storage)
let rtup = rdLoc(tup)
let fieldName =
let fieldName =
if t.kind == tyTuple:
"Field" & $i
else:
if t.n[i].kind != nkSym: internalError(p.config, n.info, "genVarTuple")
mangleRecFieldName(p.module, t.n[i].sym)
field.snippet = dotField(rtup, fieldName)
putLocIntoDest(p, v.locImpl, field)
putLocIntoDest(p, v.loc, field)
if forHcr or isGlobalInBlock:
hcrGlobals.add((loc: v.locImpl, tp: CNil))
hcrGlobals.add((loc: v.loc, tp: CNil))
if forHcr:
# end the block where the tuple gets initialized
@@ -226,7 +225,7 @@ proc genState(p: BProc, n: PNode) =
elif n0.kind == nkStrLit:
p.s(cpsStmts).addLabel(n0.strVal)
proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int, isReturnStmt = false) =
proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
# Called by return and break stmts.
# Deals with issues faced when jumping out of try/except/finally stmts.
@@ -258,7 +257,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int, isReturnStmt
# Pop exceptions that was handled by the
# except-blocks we are in
if noSafePoints notin p.flags and not (isReturnStmt and isClosureIterator(p.prc.typ)):
if noSafePoints notin p.flags:
for i in countdown(howManyExcepts-1, 0):
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "popCurrentException"))
@@ -366,7 +365,6 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
if v.flags * {sfImportc, sfExportc} == {sfImportc} and
value.kind == nkEmpty and
v.loc.flags * {lfHeader, lfNoDecl} != {}:
# IC XXX: this is bad, we should set v.loc regardless here
return
if sfPure in v.flags:
# v.owner.kind != skModule:
@@ -462,8 +460,7 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
if value.kind != nkEmpty and valueAsRope.len == 0:
genLineDir(targetProc, vn)
if not isCppCtorCall:
backendEnsureMutable v
loadInto(targetProc, vn, value, v.locImpl)
loadInto(targetProc, vn, value, v.loc)
if forHcr:
endBlockWith(targetProc):
finishBranch(p.s(cpsStmts), hcrInit)
@@ -490,17 +487,14 @@ proc genClosureVar(p: BProc, a: PNode) =
constructLoc(p, v)
proc genVarStmt(p: BProc, n: PNode) =
for it in n:
case it.kind
of nkCommentStmt: discard
of nkIdentDefs:
for it in n.sons:
if it.kind == nkCommentStmt: continue
if it.kind == nkIdentDefs:
# can be a lifted var nowadays ...
if it[0].kind == nkSym:
genSingleVar(p, it)
else:
genClosureVar(p, it)
of nkSym:
genSingleVar(p, it.sym, newSymNode(it.sym), it.sym.astdef)
else:
genVarTuple(p, it)
@@ -560,8 +554,7 @@ proc genReturnStmt(p: BProc, t: PNode) =
if (t[0].kind != nkEmpty): genStmts(p, t[0])
blockLeaveActions(p,
howManyTrys = p.nestedTryStmts.len,
howManyExcepts = p.inExceptBlockLen,
isReturnStmt = true)
howManyExcepts = p.inExceptBlockLen)
if (p.finallySafePoints.len > 0) and noSafePoints notin p.flags:
# If we're in a finally block, and we came here by exception
# consume it before we return.
@@ -743,10 +736,8 @@ proc genBlock(p: BProc, n: PNode, d: var TLoc) =
# named block?
assert(n[0].kind == nkSym)
var sym = n[0].sym
backendEnsureMutable sym
sym.locImpl.k = locOther
sym.positionImpl = p.breakIdx+1
# ^ IC: review this
sym.loc.k = locOther
sym.position = p.breakIdx+1
expr(p, n[1], d)
endSimpleBlock(p, scope)
@@ -1259,8 +1250,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
initElifBranch(p.s(cpsStmts), ifStmt, orExpr)
if exvar != nil:
fillLocalName(p, exvar.sym)
backendEnsureMutable exvar.sym
fillLoc(exvar.sym.locImpl, locTemp, exvar, OnStack)
fillLoc(exvar.sym.loc, locTemp, exvar, OnStack)
linefmt(p, cpsStmts, "$1 $2 = T$3_;$n", [getTypeDesc(p.module, exvar.sym.typ),
rdLoc(exvar.sym.loc), rope(etmp+1)])
# we handled the error:
@@ -1308,8 +1298,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
if isImportedException(typeNode.typ, p.config):
let exvar = t[i][j][2] # ex1 in `except ExceptType as ex1:`
fillLocalName(p, exvar.sym)
backendEnsureMutable exvar.sym
fillLoc(exvar.sym.locImpl, locTemp, exvar, OnStack)
fillLoc(exvar.sym.loc, locTemp, exvar, OnStack)
startBlockWith(p):
lineCg(p, cpsStmts, "catch ($1& $2) {$n", [getTypeDesc(p.module, typeNode.typ), rdLoc(exvar.sym.loc)])
genExceptBranchBody(t[i][^1]) # exception handler body will duplicated for every type
@@ -1400,8 +1389,7 @@ proc genTryCppOld(p: BProc, t: PNode, d: var TLoc) =
if t[i][j].isInfixAs():
let exvar = t[i][j][2] # ex1 in `except ExceptType as ex1:`
fillLocalName(p, exvar.sym)
backendEnsureMutable exvar.sym
fillLoc(exvar.sym.locImpl, locTemp, exvar, OnUnknown)
fillLoc(exvar.sym.loc, locTemp, exvar, OnUnknown)
startBlockWith(p):
lineCg(p, cpsStmts, "catch ($1& $2) {$n", [getTypeDesc(p.module, t[i][j][1].typ), rdLoc(exvar.sym.loc)])
else:

View File

@@ -11,7 +11,7 @@
# ------------------------- Name Mangling --------------------------------
import sighashes, std/strscans
import sighashes, modulegraphs, std/strscans
import ../dist/checksums/src/checksums/md5
import std/sequtils
@@ -75,7 +75,7 @@ proc mangleProc(m: BModule; s: PSym; makeUnique: bool): string =
proc fillBackendName(m: BModule; s: PSym) =
if s.loc.snippet == "":
var result: Rope
if s.kind in routineKinds and {optCDebug, optItaniumMangle} * m.g.config.globalOptions == {optCDebug, optItaniumMangle} and
if not m.compileToCpp and s.kind in routineKinds and optCDebug in m.g.config.globalOptions and
m.g.config.symbolFiles == disabledSf:
result = mangleProc(m, s, false).rope
else:
@@ -84,8 +84,7 @@ proc fillBackendName(m: BModule; s: PSym) =
if m.hcrOn:
result.add '_'
result.add(idOrSig(s, m.module.name.s.mangle, m.sigConflicts, m.config))
backendEnsureMutable s
s.locImpl.snippet = result
s.loc.snippet = result
proc fillParamName(m: BModule; s: PSym) =
if s.loc.snippet == "":
@@ -108,8 +107,7 @@ proc fillParamName(m: BModule; s: PSym) =
# and a function called in main or proxy uses `socket` as a parameter name.
# That would lead to either needing to reload `proxy` or to overwrite the
# executable file for the main module, which is running (or both!) -> error.
backendEnsureMutable s
s.locImpl.snippet = res.rope
s.loc.snippet = res.rope
proc fillLocalName(p: BProc; s: PSym) =
assert s.kind in skLocalVars+{skTemp}
@@ -124,8 +122,7 @@ proc fillLocalName(p: BProc; s: PSym) =
elif s.kind != skResult:
result.add "_" & rope(counter+1)
p.sigConflicts.inc(key)
backendEnsureMutable s
s.locImpl.snippet = result
s.loc.snippet = result
proc scopeMangledParam(p: BProc; param: PSym) =
## parameter generation only takes BModule, not a BProc, so we have to
@@ -159,9 +156,8 @@ proc getTypeName(m: BModule; typ: PType; sig: SigHash): Rope =
break
let typ = if typ.kind in {tyAlias, tySink, tyOwned}: typ.elementType else: typ
if typ.loc.snippet == "":
backendEnsureMutable typ
typ.typeName(typ.locImpl.snippet)
typ.locImpl.snippet.add $sig
typ.typeName(typ.loc.snippet)
typ.loc.snippet.add $sig
else:
when defined(debugSigHashes):
# check consistency:
@@ -242,6 +238,9 @@ proc mapReturnType(conf: ConfigRef; typ: PType): TCTypeKind =
proc isImportedType(t: PType): bool =
result = t.sym != nil and sfImportc in t.sym.flags
proc isNoDeclType(t: PType): bool =
result = t.sym != nil and {lfNoDecl, lfHeader} * t.sym.loc.flags != {}
proc isImportedCppType(t: PType): bool =
let x = t.skipTypes(irrelevantForBackend)
result = (t.sym != nil and sfInfixCall in t.sym.flags) or
@@ -251,7 +250,6 @@ proc isOrHasImportedCppType(typ: PType): bool =
searchTypeFor(typ.skipTypes({tyRef}), isImportedCppType)
proc hasNoInit(t: PType): bool =
let t = skipTypes(t, {tyGenericInst})
result = t.sym != nil and sfNoInit in t.sym.flags
proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDescKind): Rope
@@ -277,7 +275,7 @@ proc isInvalidReturnType(conf: ConfigRef; typ: PType, isProc = true): bool =
of ctStruct:
let t = skipTypes(rettype, typedescInst)
if rettype.isImportedCppType or t.isImportedCppType or
(typ.callConv == ccCDecl and conf.selectedGC in {gcArc, gcAtomicArc, gcOrc, gcYrc}):
(typ.callConv == ccCDecl and conf.selectedGC in {gcArc, gcAtomicArc, gcOrc}):
# prevents nrvo for cdecl procs; # bug #23401
result = false
else:
@@ -294,12 +292,7 @@ proc cacheGetType(tab: TypeCache; sig: SigHash): Rope =
result = tab.getOrDefault(sig)
proc addAbiCheck(m: BModule; t: PType, name: Rope) =
if isDefined(m.config, "checkAbi") and (let size = getSize(m.config, t); size != szUnknownSize) and
not (t.kind == tyObject and searchTypeFor(t, proc (t: PType): bool {.nimcall.} = t.kind == tyUncheckedArray)):
# `UncheckedArray`, not `ptr UncheckedArray` type field in object types is a flexible array.
# `sizeof` in C and Nim doesn't always return the same value for object types containing it.
# making `getSize` in Nim always returns the same value as `sizeof` in C from flexible arrays seems hard.
# See `SEQ_DECL_SIZE` in lib/nimbase.h
if isDefined(m.config, "checkAbi") and (let size = getSize(m.config, t); size != szUnknownSize):
var msg = "backend & Nim disagree on size for: "
msg.addTypeHeader(m.config, t)
var msg2 = ""
@@ -309,13 +302,12 @@ proc addAbiCheck(m: BModule; t: PType, name: Rope) =
proc fillResult(conf: ConfigRef; param: PNode, proctype: PType) =
ensureMutable param.sym
fillLoc(param.sym.locImpl, locParam, param, "Result",
fillLoc(param.sym.loc, locParam, param, "Result",
OnStack)
let t = param.sym.typ
if mapReturnType(conf, t) != ctArray and isInvalidReturnType(conf, proctype):
incl(param.sym.locImpl.flags, lfIndirect)
param.sym.locImpl.storage = OnUnknown
incl(param.sym.loc.flags, lfIndirect)
param.sym.loc.storage = OnUnknown
proc typeNameOrLiteral(m: BModule; t: PType, literal: string): Rope =
if t.sym != nil and sfImportc in t.sym.flags and t.sym.magic == mNone:
@@ -401,7 +393,7 @@ proc getTypeForward(m: BModule; typ: PType; sig: SigHash): Rope =
of tySequence, tyTuple, tyObject:
result = getTypeName(m, typ, sig)
m.forwTypeCache[sig] = result
if not isImportedType(concrete):
if not isNoDeclType(concrete):
addForwardStructFormat(m, structOrUnion(typ), result)
else:
pushType(m, concrete)
@@ -534,15 +526,14 @@ proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, name, params
var types, names, args: seq[string] = @[]
if not isCtor:
var this = t.n[1].sym
ensureMutable this
fillParamName(m, this)
fillLoc(this.locImpl, locParam, t.n[1],
fillLoc(this.loc, locParam, t.n[1],
this.paramStorageLoc)
if this.typ.kind == tyPtr:
this.locImpl.snippet = "this"
this.loc.snippet = "this"
else:
this.locImpl.snippet = "(*this)"
names.add this.locImpl.snippet
this.loc.snippet = "(*this)"
names.add this.loc.snippet
types.add getTypeDescWeak(m, this.typ, check, dkParam)
let firstParam = if isCtor: 1 else: 2
@@ -556,14 +547,13 @@ proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, name, params
else:
descKind = dkRefParam
var typ, name: string
ensureMutable param
fillParamName(m, param)
fillLoc(param.locImpl, locParam, t.n[i],
fillLoc(param.loc, locParam, t.n[i],
param.paramStorageLoc)
if ccgIntroducedPtr(m.config, param, t.returnType) and descKind == dkParam:
typ = getTypeDescWeak(m, param.typ, check, descKind) & "*"
incl(param.locImpl.flags, lfIndirect)
param.locImpl.storage = OnUnknown
incl(param.loc.flags, lfIndirect)
param.loc.storage = OnUnknown
elif weakDep:
typ = getTypeDescWeak(m, param.typ, check, descKind)
else:
@@ -571,7 +561,7 @@ proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, name, params
if sfNoalias in param.flags:
typ.add("NIM_NOALIAS ")
name = param.locImpl.snippet
name = param.loc.snippet
types.add typ
names.add name
if sfCodegenDecl notin param.flags:
@@ -613,15 +603,14 @@ proc genProcParams(m: BModule; t: PType, rettype: var Rope, params: var Builder,
else:
descKind = dkRefParam
if isCompileTimeOnly(param.typ): continue
backendEnsureMutable param
fillParamName(m, param)
fillLoc(param.locImpl, locParam, t.n[i],
fillLoc(param.loc, locParam, t.n[i],
param.paramStorageLoc)
var typ: Rope
if ccgIntroducedPtr(m.config, param, t.returnType) and descKind == dkParam:
typ = ptrType(getTypeDescWeak(m, param.typ, check, descKind))
incl(param.locImpl.flags, lfIndirect)
param.locImpl.storage = OnUnknown
incl(param.loc.flags, lfIndirect)
param.loc.storage = OnUnknown
elif weakDep:
typ = (getTypeDescWeak(m, param.typ, check, descKind))
else:
@@ -633,9 +622,9 @@ proc genProcParams(m: BModule; t: PType, rettype: var Rope, params: var Builder,
var j = 0
while arr.kind in {tyOpenArray, tyVarargs}:
# this fixes the 'sort' bug:
if param.typ.kind in {tyVar, tyLent}: param.locImpl.storage = OnUnknown
if param.typ.kind in {tyVar, tyLent}: param.loc.storage = OnUnknown
# need to pass hidden parameter:
params.addParam(paramBuilder, name = param.locImpl.snippet & "Len_" & $j, typ = NimInt)
params.addParam(paramBuilder, name = param.loc.snippet & "Len_" & $j, typ = NimInt)
inc(j)
arr = arr[0].skipTypes({tySink})
if t.returnType != nil and isInvalidReturnType(m.config, t):
@@ -720,13 +709,12 @@ proc genRecordFieldsAux(m: BModule; n: PNode,
if field.typ.kind == tyVoid: return
#assert(field.ast == nil)
let sname = mangleRecFieldName(m, field)
backendEnsureMutable field
fillLoc(field.locImpl, locField, n, unionPrefix & sname, OnUnknown)
fillLoc(field.loc, locField, n, unionPrefix & sname, OnUnknown)
# for importcpp'ed objects, we only need to set field.loc, but don't
# have to recurse via 'getTypeDescAux'. And not doing so prevents problems
# with heavily templatized C++ code:
if not isImportedCppType(rectype):
let fieldType = field.loc.t.skipTypes(abstractInst)
let fieldType = field.loc.lode.typ.skipTypes(abstractInst)
var typ: Rope = ""
var isFlexArray = false
var initializer = ""
@@ -849,54 +837,6 @@ proc getOpenArrayDesc(m: BModule; t: PType, check: var IntSet; kind: TypeDescKin
m.s[cfsTypes].addField(name = "Field0", typ = ptrType(elemType))
m.s[cfsTypes].addField(name = "Field1", typ = NimInt)
proc importedCppObject(m: BModule; t, tt: PType; check: var IntSet; kind: TypeDescKind; sig: SigHash; result: var Rope) =
let cppNameAsRope = getTypeName(m, t, sig)
let cppName = $cppNameAsRope
var i = 0
var chunkStart = 0
template addResultType(ty: untyped) =
if ty == nil or ty.kind == tyVoid:
result.add(CVoid)
elif ty.kind == tyStatic:
internalAssert m.config, ty.n != nil
result.add ty.n.renderTree
else:
result.add getTypeDescAux(m, ty, check, kind)
while i < cppName.len:
if cppName[i] == '\'':
var chunkEnd = i-1
var idx, stars: int = 0
if scanCppGenericSlot(cppName, i, idx, stars):
result.add cppName.substr(chunkStart, chunkEnd)
chunkStart = i
let typeInSlot = resolveStarsInCppType(tt, idx + 1, stars)
addResultType(typeInSlot)
else:
inc i
if chunkStart != 0:
result.add cppName.substr(chunkStart)
else:
result = cppNameAsRope & "<"
for needsComma, a in tt.genericInstParams:
if needsComma: result.add(" COMMA ")
addResultType(a)
result.add("> ")
# always call for sideeffects:
assert t.kind != tyTuple
discard getRecordDesc(m, t, result, check)
# The resulting type will include commas and these won't play well
# with the C macros for defining procs such as N_NIMCALL. We must
# create a typedef for the type and use it in the proc signature:
let typedefName = "TY" & $sig
m.s[cfsTypes].addTypedef(name = typedefName):
m.s[cfsTypes].add(result)
m.typeCache[sig] = typedefName
result = typedefName
proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDescKind): Rope =
# returns only the type's name
var t = origTyp.skipTypes(irrelevantForBackend-{tyOwned})
@@ -912,7 +852,7 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
# tyDistinct matters if it is an importc type
result = getTypePre(m, origTyp.skipTypes(irrelevantForBackend-{tyOwned, tyDistinct}), sig)
defer:
defer: # defer is the simplest in this case
if isImportedType(t) and not m.typeABICache.containsOrIncl(sig):
addAbiCheck(m, t, result)
@@ -1046,7 +986,7 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
m.s[cfsTypes].addArrayTypedef(name = result, len = 1):
m.s[cfsTypes].add(et)
of tyArray:
var n = toInt64(lengthOrd(m.config, t))
var n: BiggestInt = toInt64(lengthOrd(m.config, t))
if n <= 0: n = 1 # make an array of at least one element
result = getTypeName(m, origTyp, sig)
m.typeCache[sig] = result
@@ -1057,22 +997,66 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
of tyObject, tyTuple:
let tt = origTyp.skipTypes({tyDistinct})
if isImportedCppType(t) and tt.kind == tyGenericInst:
importedCppObject(m, t, tt, check, kind, sig, result)
let cppNameAsRope = getTypeName(m, t, sig)
let cppName = $cppNameAsRope
var i = 0
var chunkStart = 0
template addResultType(ty: untyped) =
if ty == nil or ty.kind == tyVoid:
result.add(CVoid)
elif ty.kind == tyStatic:
internalAssert m.config, ty.n != nil
result.add ty.n.renderTree
else:
result.add getTypeDescAux(m, ty, check, kind)
while i < cppName.len:
if cppName[i] == '\'':
var chunkEnd = i-1
var idx, stars: int = 0
if scanCppGenericSlot(cppName, i, idx, stars):
result.add cppName.substr(chunkStart, chunkEnd)
chunkStart = i
let typeInSlot = resolveStarsInCppType(tt, idx + 1, stars)
addResultType(typeInSlot)
else:
inc i
if chunkStart != 0:
result.add cppName.substr(chunkStart)
else:
result = cppNameAsRope & "<"
for needsComma, a in tt.genericInstParams:
if needsComma: result.add(" COMMA ")
addResultType(a)
result.add("> ")
# always call for sideeffects:
assert t.kind != tyTuple
discard getRecordDesc(m, t, result, check)
# The resulting type will include commas and these won't play well
# with the C macros for defining procs such as N_NIMCALL. We must
# create a typedef for the type and use it in the proc signature:
let typedefName = "TY" & $sig
m.s[cfsTypes].addTypedef(name = typedefName):
m.s[cfsTypes].add(result)
m.typeCache[sig] = typedefName
result = typedefName
else:
result = cacheGetType(m.forwTypeCache, sig)
if result == "":
result = getTypeName(m, origTyp, sig)
m.forwTypeCache[sig] = result
if not isImportedType(t):
if not isNoDeclType(t):
addForwardStructFormat(m, structOrUnion(t), result)
assert m.forwTypeCache[sig] == result
m.typeCache[sig] = result # always call for sideeffects:
if not incompleteType(t):
let recdesc = if t.kind != tyTuple: getRecordDesc(m, t, result, check)
else: getTupleDesc(m, t, result, check)
if not isImportedType(t):
if not isImportedType(t) and not isNoDeclType(t):
m.s[cfsTypes].add(recdesc)
addAbiCheck(m, t, result)
elif tfIncompleteStruct notin t.flags:
discard # addAbiCheck(m, t, result) # already handled elsewhere
of tySet:
@@ -1173,8 +1157,7 @@ proc genMemberProcHeader(m: BModule; prc: PSym; result: var Builder; asPtr: bool
let isCtor = sfConstructor in prc.flags
var check = initIntSet()
fillBackendName(m, prc)
ensureMutable prc
fillLoc(prc.locImpl, locProc, prc.ast[namePos], OnUnknown)
fillLoc(prc.loc, locProc, prc.ast[namePos], OnUnknown)
var memberOp = "#." #only virtual
var typ: PType
if isCtor:
@@ -1206,7 +1189,7 @@ proc genMemberProcHeader(m: BModule; prc: PSym; result: var Builder; asPtr: bool
superCall = ""
else:
if not isCtor:
prc.locImpl.snippet = "$1$2(@)" % [memberOp, name]
prc.loc.snippet = "$1$2(@)" % [memberOp, name]
elif superCall != "":
superCall = " : " & superCall
@@ -1221,15 +1204,14 @@ proc genProcHeader(m: BModule; prc: PSym; result: var Builder; visibility: var D
# using static is needed for inline procs
var check = initIntSet()
fillBackendName(m, prc)
backendEnsureMutable prc
fillLoc(prc.locImpl, locProc, prc.ast[namePos], OnUnknown)
fillLoc(prc.loc, locProc, prc.ast[namePos], OnUnknown)
var rettype: Snippet = ""
var desc = newBuilder("")
genProcParams(m, prc.typ, rettype, desc, check, true, false)
let params = extract(desc)
# handle the 2 options for hotcodereloading codegen - function pointer
# (instead of forward declaration) or header for function body with "_actual" postfix
var name = prc.locImpl.snippet
var name = prc.loc.snippet
if not asPtr and isReloadable(m, prc):
name.add("_actual")
# careful here! don't access ``prc.ast`` as that could reload large parts of
@@ -1469,7 +1451,7 @@ proc genObjectInfo(m: BModule; typ, origType: PType, name: Rope; info: TLineInfo
var t = typ.baseClass
while t != nil:
t = t.skipTypes(skipPtrs)
t.incl tfObjHasKids
t.flags.incl tfObjHasKids
t = t.baseClass
proc genTupleInfo(m: BModule; typ, origType: PType, name: Rope; info: TLineInfo) =
@@ -1665,8 +1647,8 @@ proc generateRttiDestructor(g: ModuleGraph; typ: PType; owner: PSym; kind: TType
n[bodyPos] = body
result.ast = n
incl result.flagsImpl, sfFromGeneric
incl result.flagsImpl, sfGeneratedOp
incl result.flags, sfFromGeneric
incl result.flags, sfGeneratedOp
proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp; result: var Builder) =
let theProc = getAttachedOp(m.g.graph, t, op)
@@ -1692,7 +1674,7 @@ proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp; result:
echo "ayclic but has this =trace ", t, " ", theProc.ast
else:
when false:
if op == attachedTrace and m.config.selectedGC in {gcOrc, gcYrc} and
if op == attachedTrace and m.config.selectedGC == gcOrc and
containsGarbageCollectedRef(t):
# unfortunately this check is wrong for an object type that only contains
# .cursor fields like 'Node' inside 'cycleleak'.
@@ -1871,12 +1853,6 @@ proc genTypeInfoV2Impl(m: BModule; t, origType: PType, name: Rope; info: TLineIn
if t.kind == tyObject and t.baseClass != nil and optEnableDeepCopy in m.config.globalOptions:
discard genTypeInfoV1(m, t, info)
proc myModuleOpenForCodegen(m: BModule; idx: FileIndex): bool {.inline.} =
if moduleOpenForCodegen(m.g.graph, idx):
result = idx.int < m.g.mods.len and m.g.mods[idx.int] != nil
else:
result = false
proc genTypeInfoV2(m: BModule; t: PType; info: TLineInfo): Rope =
let origType = t
# distinct types can have their own destructors
@@ -1905,9 +1881,9 @@ proc genTypeInfoV2(m: BModule; t: PType; info: TLineInfo): Rope =
m.typeInfoMarkerV2[sig] = result
let owner = t.skipTypes(typedescPtrs).itemId.module
if owner != m.module.position and myModuleOpenForCodegen(m, FileIndex owner):
if owner != m.module.position and moduleOpenForCodegen(m.g.graph, FileIndex owner):
# make sure the type info is created in the owner module
discard genTypeInfoV2(m.g.mods[owner], origType, info)
discard genTypeInfoV2(m.g.modules[owner], origType, info)
# reference the type info as extern here
cgsym(m, "TNimTypeV2")
declareNimType(m, "TNimTypeV2", result, owner)
@@ -1990,9 +1966,9 @@ proc genTypeInfoV1(m: BModule; t: PType; info: TLineInfo): Rope =
return prefixTI(result)
var owner = t.skipTypes(typedescPtrs).itemId.module
if owner != m.module.position and myModuleOpenForCodegen(m, FileIndex owner):
if owner != m.module.position and moduleOpenForCodegen(m.g.graph, FileIndex owner):
# make sure the type info is created in the owner module
discard genTypeInfoV1(m.g.mods[owner], origType, info)
discard genTypeInfoV1(m.g.modules[owner], origType, info)
# reference the type info as extern here
cgsym(m, "TNimType")
cgsym(m, "TNimNode")
@@ -2002,7 +1978,7 @@ proc genTypeInfoV1(m: BModule; t: PType; info: TLineInfo): Rope =
owner = m.module.position.int32
m.g.typeInfoMarker[sig] = (str: result, owner: owner)
#rememberEmittedTypeInfo(m.g.graph, FileIndex(owner), $result)
rememberEmittedTypeInfo(m.g.graph, FileIndex(owner), $result)
case t.kind
of tyEmpty, tyVoid: result = cIntValue(0)
@@ -2069,21 +2045,17 @@ proc genTypeInfo*(config: ConfigRef, m: BModule; t: PType; info: TLineInfo): Rop
else:
result = genTypeInfoV1(m, t, info)
proc retrieveSym(n: PNode): PSym =
case n.kind
of nkPostfix: result = retrieveSym(n[1])
of nkPragmaExpr, nkTypeDef: result = retrieveSym(n[0])
of nkSym: result = n.sym
else: result = nil
proc genTypeSection(m: BModule, n: PNode) =
var intSet = initIntSet()
let compress = optCompress in m.config.globalOptions
for typedef in n:
let s = retrieveSym(typedef)
if s != nil and ({sfExportc, sfCompilerProc} * s.flags == {sfExportc} or compress) and s.typ != nil and
not containsGenericType(s.typ) and
s.typ.kind notin {tyVoid, tyNot, tyAnything, tyOr, tyAnd, tyUntyped, tyTyped, tyNone, tyNil, tySink}:
discard getTypeDescAux(m, s.typ, intSet, descKindFromSymKind(s.kind))
if m.g.generatedHeader != nil:
discard getTypeDescAux(m.g.generatedHeader, s.typ, intSet, descKindFromSymKind(s.kind))
for i in 0..<n.len:
if len(n[i]) == 0: continue
if n[i][0].kind != nkPragmaExpr: continue
for p in 0..<n[i][0].len:
if (n[i][0][p].kind notin {nkSym, nkPostfix}): continue
var s = n[i][0][p]
if s.kind == nkPostfix:
s = n[i][0][p][1]
if {sfExportc, sfCompilerProc} * s.sym.flags == {sfExportc}:
discard getTypeDescAux(m, s.typ, intSet, descKindFromSymKind(s.sym.kind))
if m.g.generatedHeader != nil:
discard getTypeDescAux(m.g.generatedHeader, s.typ, intSet, descKindFromSymKind(s.sym.kind))

View File

@@ -16,7 +16,7 @@ import
rodutils, renderer, cgendata, aliases,
lowerings, lineinfos, pathutils, transf,
injectdestructors, astmsgs, modulepaths, pushpoppragmas,
mangleutils, cbuilderbase, modulegraphs
mangleutils, cbuilderbase
from expanddefaults import caseObjDefaultBranch
@@ -30,6 +30,7 @@ when not defined(leanCompiler):
import std/strutils except `%`, addf # collides with ropes.`%`
from ic / ic import ModuleBackendFlag
import std/[dynlib, math, tables, sets, os, intsets, hashes]
const
@@ -60,25 +61,14 @@ proc hcrOn(p: BProc): bool = p.module.config.hcrOn
proc addForwardedProc(m: BModule, prc: PSym) =
m.g.forwardedProcs.add(prc)
proc newModule*(g: BModuleList; module: PSym; conf: ConfigRef; idgen: IdGenerator): BModule
proc findPendingModule(m: BModule, s: PSym): BModule =
# TODO fixme
if m.config.symbolFiles == v2Sf or optCompress in m.config.globalOptions:
if m.config.symbolFiles == v2Sf:
let ms = s.itemId.module #getModule(s)
result = m.g.mods[ms]
elif m.config.cmd in {cmdNifC, cmdM}:
var ms = getModule(s)
registerModule m.g.graph, ms
if ms.position >= m.g.mods.len:
result = newModule(m.g, ms, m.config, idGeneratorFromModule(ms))
else:
result = m.g.mods[ms.position]
if result == nil:
result = newModule(m.g, ms, m.config, idGeneratorFromModule(ms))
result = m.g.modules[ms]
else:
var ms = getModule(s)
result = m.g.mods[ms.position]
result = m.g.modules[ms.position]
proc initLoc(k: TLocKind, lode: PNode, s: TStorageLoc, flags: TLocFlags = {}): TLoc =
result = TLoc(k: k, storage: s, lode: lode,
@@ -107,7 +97,7 @@ proc t(a: TLoc): PType {.inline.} =
proc lodeTyp(t: PType): PNode =
result = newNode(nkEmpty)
result.typ = t
result.typ() = t
proc isSimpleConst(typ: PType): bool =
let t = skipTypes(typ, abstractVar)
@@ -132,10 +122,10 @@ proc getModuleDllPath(m: BModule): Rope =
result = makeCString(dir.string & "/" & filename)
proc getModuleDllPath(m: BModule, module: int): Rope =
result = getModuleDllPath(m.g.mods[module])
result = getModuleDllPath(m.g.modules[module])
proc getModuleDllPath(m: BModule, s: PSym): Rope =
result = getModuleDllPath(m.g.mods[s.itemId.module])
result = getModuleDllPath(m.g.modules[s.itemId.module])
import std/macros
@@ -336,10 +326,7 @@ proc genLineDir(p: BProc, t: PNode) =
let line = t.info.safeLineNm
if optEmbedOrigSrc in p.config.globalOptions:
var code = sourceLine(p.config, t.info)
if code.endsWith('\\'):
code.add "#"
p.s(cpsStmts).add("// " & code & "\L")
p.s(cpsStmts).add("//" & sourceLine(p.config, t.info) & "\L")
let lastFileIndex = p.lastLineInfo.fileIndex
let freshLine = freshLineInfo(p, t.info)
if freshLine:
@@ -519,7 +506,7 @@ include ccgreset
proc resetLoc(p: BProc, loc: var TLoc) =
let containsGcRef = optSeqDestructors notin p.config.globalOptions and containsGarbageCollectedRef(loc.t)
let typ = skipTypes(loc.t, abstractVarRange)
if isImportedCppType(typ):
if isImportedCppType(typ):
var didGenTemp = false
let rl = rdLoc(loc)
let init = genCppInitializer(p.module, p, typ, didGenTemp)
@@ -613,8 +600,7 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
# ``var v = X()`` gets transformed into ``X(&v)``.
# Nowadays the logic in ccgcalls deals with this case however.
if not immediateAsgn:
backendEnsureMutable v
constructLoc(p, v.locImpl)
constructLoc(p, v.loc)
proc getTemp(p: BProc, t: PType, needsInit=false): TLoc =
inc(p.labels)
@@ -660,9 +646,8 @@ proc localVarDecl(res: var Builder, p: BProc; n: PNode,
let s = n.sym
if s.loc.k == locNone:
fillLocalName(p, s)
backendEnsureMutable s
fillLoc(s.locImpl, locLocalVar, n, OnStack)
if s.kind == skLet: incl(s, lfNoDeepCopy)
fillLoc(s.loc, locLocalVar, n, OnStack)
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
genCLineDir(res, p, n.info, p.config)
@@ -722,17 +707,15 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) =
let s = n.sym
if s.loc.k == locNone:
fillBackendName(p.module, s)
backendEnsureMutable s
fillLoc(s.locImpl, locGlobalVar, n, OnHeap)
if treatGlobalDifferentlyForHCR(p.module, s): incl(s, lfIndirect)
fillLoc(s.loc, locGlobalVar, n, OnHeap)
if treatGlobalDifferentlyForHCR(p.module, s): incl(s.loc.flags, lfIndirect)
if lfDynamicLib in s.loc.flags:
var q = findPendingModule(p.module, s)
if q != nil and not containsOrIncl(q.declaredThings, s.id):
varInDynamicLib(q, s)
else:
backendEnsureMutable s
s.locImpl.snippet = mangleDynLibProc(s)
s.loc.snippet = mangleDynLibProc(s)
if value != "":
internalError(p.config, n.info, ".dynlib variables cannot have a value")
return
@@ -772,14 +755,12 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) =
genGlobalVarDecl(p.module.s[cfsVars], p, n, td, initializer = initializer)
if p.withinLoop > 0 and value == "":
# fixes tests/run/tzeroarray:
backendEnsureMutable s
resetLoc(p, s.locImpl)
resetLoc(p, s.loc)
proc callGlobalVarCppCtor(p: BProc; v: PSym; vn, value: PNode; didGenTemp: var bool) =
let s = vn.sym
fillBackendName(p.module, s)
backendEnsureMutable s
fillLoc(s.locImpl, locGlobalVar, vn, OnHeap)
fillLoc(s.loc, locGlobalVar, vn, OnHeap)
let td = getTypeDesc(p.module, vn.sym.typ, dkVar)
var val = genCppParamsForCtor(p, value, didGenTemp)
if didGenTemp: return # generated in the caller
@@ -798,8 +779,7 @@ proc fillProcLoc(m: BModule; n: PNode) =
let sym = n.sym
if sym.loc.k == locNone:
fillBackendName(m, sym)
backendEnsureMutable sym
fillLoc(sym.locImpl, locProc, n, OnStack)
fillLoc(sym.loc, locProc, n, OnStack)
proc getLabel(p: BProc): TLabel =
inc(p.labels)
@@ -968,8 +948,7 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
var extname = sym.loc.snippet
if not isCall: loadDynamicLib(m, lib)
var tmp = mangleDynLibProc(sym)
backendEnsureMutable sym
sym.locImpl.snippet = tmp # from now on we only need the internal name
sym.loc.snippet = tmp # from now on we only need the internal name
sym.typ.sym = nil # generate a new name
inc(m.labels, 2)
if isCall:
@@ -1011,10 +990,9 @@ proc varInDynamicLib(m: BModule, sym: PSym) =
var lib = sym.annex
var extname = sym.loc.snippet
loadDynamicLib(m, lib)
incl(sym, lfIndirect)
incl(sym.loc.flags, lfIndirect)
var tmp = mangleDynLibProc(sym)
backendEnsureMutable sym
sym.locImpl.snippet = tmp # from now on we only need the internal name
sym.loc.snippet = tmp # from now on we only need the internal name
inc(m.labels, 2)
let t = ptrType(getTypeDesc(m, sym.typ, dkVar))
# cgsym has side effects, do it first:
@@ -1027,8 +1005,7 @@ proc varInDynamicLib(m: BModule, sym: PSym) =
m.s[cfsVars].addVar(name = sym.loc.snippet, typ = t)
proc symInDynamicLibPartial(m: BModule, sym: PSym) =
backendEnsureMutable sym
sym.locImpl.snippet = mangleDynLibProc(sym)
sym.loc.snippet = mangleDynLibProc(sym)
sym.typ.sym = nil # generate a new name
proc cgsymImpl(m: BModule; sym: PSym) {.inline.} =
@@ -1298,7 +1275,7 @@ proc genProcBody(p: BProc; procBody: PNode) =
p.blocks[0].sections[cpsInit].addAssignmentWithValue("nimErr_"):
p.blocks[0].sections[cpsInit].addCall(cgsymValue(p.module, "nimErrorFlag"))
proc genProcLvl3*(m: BModule, prc: PSym) =
proc genProcAux*(m: BModule, prc: PSym) =
var p = newProc(prc, m)
var header = newBuilder("")
let isCppMember = m.config.backend == backendCpp and sfCppMember * prc.flags != {}
@@ -1323,7 +1300,7 @@ proc genProcLvl3*(m: BModule, prc: PSym) =
let resNode = prc.ast[resultPos]
let res = resNode.sym # get result symbol
if not isInvalidReturnType(m.config, prc.typ) and sfConstructor notin prc.flags:
if sfNoInit in prc.flags: incl(res, sfNoInit)
if sfNoInit in prc.flags: incl(res.flags, sfNoInit)
if sfNoInit in prc.flags and p.module.compileToCpp and (let val = easyResultAsgn(procBody); val != nil):
var a: TLoc = initLocExprSingleUse(p, val)
let ra = rdLoc(a)
@@ -1332,7 +1309,7 @@ proc genProcLvl3*(m: BModule, prc: PSym) =
# declare the result symbol:
assignLocalVar(p, resNode)
assert(res.loc.snippet != "")
if p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc, gcYrc} and
if p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc} and
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.
@@ -1344,11 +1321,9 @@ proc genProcLvl3*(m: BModule, prc: PSym) =
returnBuilder.addReturn(rres)
returnStmt = extract(returnBuilder)
elif sfConstructor in prc.flags:
resNode.sym.incl lfIndirect
backendEnsureMutable resNode.sym
fillLoc(resNode.sym.locImpl, locParam, resNode, "this", OnHeap)
backendEnsureMutable prc
prc.locImpl.snippet = getTypeDesc(m, resNode.sym.locImpl.t, dkVar)
resNode.sym.loc.flags.incl lfIndirect
fillLoc(resNode.sym.loc, locParam, resNode, "this", OnHeap)
prc.loc.snippet = getTypeDesc(m, resNode.sym.loc.t, dkVar)
else:
fillResult(p.config, resNode, prc.typ)
assignParam(p, res, prc.typ.returnType)
@@ -1361,12 +1336,10 @@ proc genProcLvl3*(m: BModule, prc: PSym) =
if sfNoInit in prc.flags: discard
elif allPathsAsgnResult(p, procBody) == InitSkippable: discard
else:
backendEnsureMutable res
resetLoc(p, res.locImpl)
resetLoc(p, res.loc)
if skipTypes(res.typ, abstractInst).kind == tyArray:
#incl(res.loc.flags, lfIndirect)
backendEnsureMutable res
res.locImpl.storage = OnUnknown
res.loc.storage = OnUnknown
for i in 1..<prc.typ.n.len:
let param = prc.typ.n[i].sym
@@ -1375,8 +1348,7 @@ proc genProcLvl3*(m: BModule, prc: PSym) =
closureSetup(p, prc)
genProcBody(p, procBody)
# IC: spurious write, seems fine for now:
prc.infoImpl = tmpInfo
prc.info = tmpInfo
var generatedProc = newBuilder("")
generatedProc.genCLineDir prc.info, m.config
@@ -1459,8 +1431,6 @@ proc genProcPrototype(m: BModule, sym: PSym) =
getModuleDllPath(m, sym),
'"' & name & '"')
elif not containsOrIncl(m.declaredProtos, sym.id):
if optCompress in m.config.globalOptions:
m.queue.add(sym)
let asPtr = isReloadable(m, sym)
var header = newBuilder("")
var visibility: DeclVisibility = None
@@ -1480,9 +1450,8 @@ proc genProcPrototype(m: BModule, sym: PSym) =
m.s[cfsProcHeaders].add(extract(header))
m.s[cfsProcHeaders].finishProcHeaderAsProto()
include inliner
proc genProcLvl2(m: BModule, prc: PSym) =
# TODO: figure out how to rename this - it DOES generate a forward declaration
proc genProcNoForward(m: BModule, prc: PSym) =
if lfImportCompilerProc in prc.loc.flags:
fillProcLoc(m, prc.ast[namePos])
useHeader(m, prc)
@@ -1519,22 +1488,16 @@ proc genProcLvl2(m: BModule, prc: PSym) =
#if prc.loc.k == locNone:
# mangle the inline proc based on the module where it is defined -
# not on the first module that uses it
if m.module.itemId.module != prc.itemId.module and optCompress in m.config.globalOptions:
let prcCopy = prc # copyInlineProc(prc, m.idgen)
fillProcLoc(m, prcCopy.ast[namePos])
genProcPrototype(m, prcCopy)
genProcLvl3(m, prcCopy)
else:
let m2 = if m.config.symbolFiles != disabledSf: m
else: findPendingModule(m, prc)
fillProcLoc(m2, prc.ast[namePos])
#elif {sfExportc, sfImportc} * prc.flags == {}:
# # reset name to restore consistency in case of hashing collisions:
# #echo "resetting ", prc.id, " by ", m.module.name.s
# #prc.loc.snippet = nil
# #prc.loc.snippet = mangleName(m, prc)
genProcPrototype(m, prc)
genProcLvl3(m, prc)
let m2 = if m.config.symbolFiles != disabledSf: m
else: findPendingModule(m, prc)
fillProcLoc(m2, prc.ast[namePos])
#elif {sfExportc, sfImportc} * prc.flags == {}:
# # reset name to restore consistency in case of hashing collisions:
# echo "resetting ", prc.id, " by ", m.module.name.s
# prc.loc.snippet = nil
# prc.loc.snippet = mangleName(m, prc)
genProcPrototype(m, prc)
genProcAux(m, prc)
elif sfImportc notin prc.flags:
var q = findPendingModule(m, prc)
fillProcLoc(q, prc.ast[namePos])
@@ -1542,7 +1505,7 @@ proc genProcLvl2(m: BModule, prc: PSym) =
# externally-to-the-current-module defined proc, also important
# to do the declaredProtos check before the call to genProcPrototype
if isReloadable(m, prc) and prc.id notin m.declaredProtos and
q != nil and not sameModules(q.module, m.module):
q != nil and q.module.id != m.module.id:
m.s[cfsDynLibInit].add('\t')
m.s[cfsDynLibInit].addAssignment(prc.loc.snippet,
cCast(getProcTypeCast(m, prc),
@@ -1555,7 +1518,7 @@ proc genProcLvl2(m: BModule, prc: PSym) =
# which will actually become a function pointer
if isReloadable(m, prc):
genProcPrototype(q, prc)
genProcLvl3(q, prc)
genProcAux(q, prc)
else:
fillProcLoc(m, prc.ast[namePos])
useHeader(m, prc)
@@ -1581,26 +1544,25 @@ proc genProc(m: BModule, prc: PSym) =
addForwardedProc(m, prc)
fillProcLoc(m, prc.ast[namePos])
else:
genProcLvl2(m, prc)
genProcNoForward(m, prc)
if {sfExportc, sfCompilerProc} * prc.flags == {sfExportc} and
m.g.generatedHeader != nil and lfNoDecl notin prc.loc.flags:
genProcPrototype(m.g.generatedHeader, prc)
if prc.typ.callConv == ccInline:
if not containsOrIncl(m.g.generatedHeader.declaredThings, prc.id):
genProcLvl3(m.g.generatedHeader, prc)
genProcAux(m.g.generatedHeader, prc)
proc genVarPrototype(m: BModule, n: PNode) =
#assert(sfGlobal in sym.flags)
let sym = n.sym
useHeader(m, sym)
fillBackendName(m, sym)
backendEnsureMutable sym
fillLoc(sym.locImpl, locGlobalVar, n, OnHeap)
if treatGlobalDifferentlyForHCR(m, sym): incl(sym, lfIndirect)
fillLoc(sym.loc, locGlobalVar, n, OnHeap)
if treatGlobalDifferentlyForHCR(m, sym): incl(sym.loc.flags, lfIndirect)
if (lfNoDecl in sym.loc.flags) or contains(m.declaredThings, sym.id):
return
if not sameOwners(sym.owner, m.module):
if sym.owner.id != m.module.id:
# else we already have the symbol generated!
assert(sym.loc.snippet != "")
incl(m.declaredThings, sym.id)
@@ -1687,7 +1649,7 @@ proc hcrGetProcLoadCode(builder: var Builder, m: BModule, sym, prefix, handle, g
# prevents inlining of the NimMainInner function and dependent
# functions, which might otherwise merge their stack frames.
proc isInnerMainVolatile(m: BModule): bool =
m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc, gcYrc}
m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc}
proc genPreMain(m: BModule) =
m.s[cfsProcs].addDeclWithVisibility(Private):
@@ -1699,6 +1661,8 @@ proc genPreMain(m: BModule) =
m.s[cfsProcs].addVar(name = "cmdCount", typ = CInt)
m.s[cfsProcs].addDeclWithVisibility(Private):
m.s[cfsProcs].addVar(name = "cmdLine", typ = ptrType(ptrType(CChar)))
m.s[cfsProcs].addDeclWithVisibility(Private):
m.s[cfsProcs].addVar(name = "gEnv", typ = ptrType(ptrType(CChar)))
m.s[cfsProcs].addDeclWithVisibility(Private):
m.s[cfsProcs].addProcHeader(m.config.nimMainPrefix & "PreMain", CVoid, cProcParams())
m.s[cfsProcs].finishProcHeaderWithBody():
@@ -1717,12 +1681,9 @@ proc genMainProcs(m: BModule) =
proc genMainProcsWithResult(m: BModule) =
genMainProcs(m)
if m.config.cmd != cmdNifC:
var res = "nim_program_result"
if m.hcrOn: res = cDeref(res)
m.s[cfsProcs].addReturn(res)
else:
m.s[cfsProcs].addReturn(cIntValue(0))
var res = "nim_program_result"
if m.hcrOn: res = cDeref(res)
m.s[cfsProcs].addReturn(res)
proc genNimMainInner(m: BModule) =
m.s[cfsProcs].addDeclWithVisibility(Private):
@@ -1732,7 +1693,7 @@ proc genNimMainInner(m: BModule) =
m.s[cfsProcs].addNewline()
proc initStackBottom(m: BModule): bool =
not (m.config.target.targetOS == osStandalone or m.config.selectedGC in {gcNone, gcArc, gcAtomicArc, gcOrc, gcYrc})
not (m.config.target.targetOS == osStandalone or m.config.selectedGC in {gcNone, gcArc, gcAtomicArc, gcOrc})
proc genNimMainProc(m: BModule, preMainCode: Snippet) =
m.s[cfsProcs].addProcHeader(ccCDecl, m.config.nimMainPrefix & "NimMain", CVoid, cProcParams())
@@ -1759,10 +1720,12 @@ proc genNimMainBody(m: BModule, preMainCode: Snippet) =
proc genPosixCMain(m: BModule) =
m.s[cfsProcs].addProcHeader("main", CInt, cProcParams(
(name: "argc", typ: CInt),
(name: "args", typ: ptrType(ptrType(CChar)))))
(name: "args", typ: ptrType(ptrType(CChar))),
(name: "env", typ: ptrType(ptrType(CChar)))))
m.s[cfsProcs].finishProcHeaderWithBody():
m.s[cfsProcs].addAssignment("cmdLine", "args")
m.s[cfsProcs].addAssignment("cmdCount", "argc")
m.s[cfsProcs].addAssignment("gEnv", "env")
genMainProcsWithResult(m)
m.s[cfsProcs].addNewline()
@@ -1860,7 +1823,7 @@ proc genMainProc(m: BModule) =
builder.addCallStmt(cgsymValue(m, "nimLoadLibraryError"), strLit)
loadLib(preMainBuilder, "hcr_handle", "hcrGetProc")
if m.config.selectedGC in {gcArc, gcAtomicArc, gcOrc, gcYrc}:
if m.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
preMainBuilder.addCallStmt(m.config.nimMainPrefix & "PreMain")
else:
preMainBuilder.addVar(name = "rtl_handle", typ = CPointer)
@@ -1921,6 +1884,36 @@ proc genMainProc(m: BModule) =
if m.config.cppCustomNamespace.len > 0:
openNamespaceNim(m.config.cppCustomNamespace, m.s[cfsProcs])
proc registerInitProcs*(g: BModuleList; m: PSym; flags: set[ModuleBackendFlag]) =
## Called from the IC backend.
if HasDatInitProc in flags:
let datInit = getSomeNameForModule(g.config, g.config.toFullPath(m.info.fileIndex).AbsoluteFile) & "DatInit000"
g.mainModProcs.addDeclWithVisibility(Private):
g.mainModProcs.addProcHeader(ccNimCall, datInit, CVoid, cProcParams())
g.mainModProcs.finishProcHeaderAsProto()
g.mainDatInit.addCallStmt(datInit)
if HasModuleInitProc in flags:
let init = getSomeNameForModule(g.config, g.config.toFullPath(m.info.fileIndex).AbsoluteFile) & "Init000"
g.mainModProcs.addDeclWithVisibility(Private):
g.mainModProcs.addProcHeader(ccNimCall, init, CVoid, cProcParams())
g.mainModProcs.finishProcHeaderAsProto()
if sfMainModule in m.flags:
g.mainModInit.addCallStmt(init)
elif sfSystemModule in m.flags:
g.mainDatInit.addCallStmt(init) # systemInit must called right after systemDatInit if any
else:
g.otherModsInit.addCallStmt(init)
proc whichInitProcs*(m: BModule): set[ModuleBackendFlag] =
# called from IC.
result = {}
if m.hcrOn or m.preInitProc.s(cpsInit).buf.len > 0 or m.preInitProc.s(cpsStmts).buf.len > 0:
result.incl HasModuleInitProc
for i in cfsTypeInit1..cfsDynLibInit:
if m.s[i].buf.len != 0:
result.incl HasDatInitProc
break
proc registerModuleToMain(g: BModuleList; m: BModule) =
let
init = m.getInitName
@@ -1928,7 +1921,7 @@ proc registerModuleToMain(g: BModuleList; m: BModule) =
if m.hcrOn:
var hcrModuleMeta = newBuilder("")
let systemModulePath = getModuleDllPath(m, g.mods[g.graph.config.m.systemFileIdx.int].module)
let systemModulePath = getModuleDllPath(m, g.modules[g.graph.config.m.systemFileIdx.int].module)
let mainModulePath = getModuleDllPath(m, m.module)
hcrModuleMeta.addDeclWithVisibility(Private):
hcrModuleMeta.addArrayVarWithInitializer(kind = Local,
@@ -1945,7 +1938,7 @@ proc registerModuleToMain(g: BModuleList; m: BModule) =
g.graph.importDeps.withValue(FileIndex(m.module.position), deps):
for curr in deps[]:
hcrModuleMeta.addField(modules, ""):
hcrModuleMeta.add(getModuleDllPath(m, g.mods[curr.int].module))
hcrModuleMeta.add(getModuleDllPath(m, g.modules[curr.int].module))
hcrModuleMeta.addField(modules, ""):
hcrModuleMeta.add("\"\"")
hcrModuleMeta.addDeclWithVisibility(ExportLib):
@@ -2030,7 +2023,7 @@ proc registerModuleToMain(g: BModuleList; m: BModule) =
if sfSystemModule in m.module.flags:
if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone:
g.mainDatInit.addCallStmt(cgsymValue(m, "initThreadVarsEmulation"))
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc, gcYrc}:
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc}:
g.mainDatInit.addCallStmt(cgsymValue(m, "initStackBottomWith"),
cCast(CPointer, cAddr("inner")))
@@ -2081,8 +2074,7 @@ proc hcrGetProcLoadCode(builder: var Builder, m: BModule, sym, prefix, handle, g
var extname = prefix & sym
var tmp = mangleDynLibProc(prc)
backendEnsureMutable prc
prc.locImpl.snippet = tmp
prc.loc.snippet = tmp
prc.typ.sym = nil
if not containsOrIncl(m.declaredThings, prc.id):
@@ -2138,8 +2130,6 @@ proc genInitCode(m: BModule) =
else:
prcBody.add(extract(m.thing.s(section)))
#echo "PRE INIT PROC ", m.module.name.s, " ", m.s[cfsVars].buf.len
if m.preInitProc.s(cpsInit).buf.len > 0 or m.preInitProc.s(cpsStmts).buf.len > 0:
# Give this small function its own scope
prcBody.addScope():
@@ -2352,14 +2342,13 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: AbsoluteFile): BModule
proc rawNewModule(g: BModuleList; module: PSym; conf: ConfigRef): BModule =
result = rawNewModule(g, module, AbsoluteFile toFullPath(conf, module.position.FileIndex))
proc newModule(g: BModuleList; module: PSym; conf: ConfigRef; idgen: IdGenerator): BModule =
proc newModule*(g: BModuleList; module: PSym; conf: ConfigRef): BModule =
# we should create only one cgen module for each module sym
result = rawNewModule(g, module, conf)
result.idgen = idgen
if module.position >= g.mods.len:
setLen(g.mods, module.position + 1)
if module.position >= g.modules.len:
setLen(g.modules, module.position + 1)
#growCache g.modules, module.position
g.mods[module.position] = result
g.modules[module.position] = result
template injectG() {.dirty.} =
if graph.backend == nil:
@@ -2368,7 +2357,8 @@ template injectG() {.dirty.} =
proc setupCgen*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
injectG()
result = newModule(g, module, graph.config, idgen)
result = newModule(g, module, graph.config)
result.idgen = idgen
if optGenIndex in graph.config.globalOptions and g.generatedHeader == nil:
let f = if graph.config.headerFile.len > 0: AbsoluteFile graph.config.headerFile
else: graph.config.projectFull
@@ -2443,10 +2433,7 @@ proc handleProcGlobals(m: BModule) =
# fixes recursive calls #24997
swap stmts, m.preInitProc.s(cpsStmts)
var transformedN = procGlobals[i]
if sfInjectDestructors in m.module.flags:
transformedN = injectDestructorCalls(m.g.graph, m.idgen, m.module, transformedN)
genStmts(m.preInitProc, transformedN)
genStmts(m.preInitProc, procGlobals[i])
swap stmts, m.preInitProc.s(cpsStmts)
handleProcGlobals(m)
@@ -2493,15 +2480,16 @@ proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool =
rawMessage(m.config, errCannotOpenFile, cfile.cname.string)
result = true
proc writeModule(m: BModule) =
# We need 2 different logics here: pending modules (including
# 'nim__dat') may require file merging for the combination of dead code
# elimination and incremental compilation! Non pending modules need no
# such logic and in fact the logic hurts for the main module at least;
# it would generate multiple 'main' procs, for instance.
proc writeModule(m: BModule, pending: bool) =
let cfile = getCFile(m)
if moduleHasChanged(m.g.graph, m.module):
genInitCode(m)
while m.queue.len > 0:
let sym = m.queue.pop()
genProcLvl2(m, sym)
finishTypeDescriptions(m)
if sfMainModule in m.module.flags:
# generate main file:
@@ -2536,11 +2524,10 @@ proc generateLibraryDestroyGlobals(graph: ModuleGraph; m: BModule; body: PNode;
result = newSym(skProc, procname, m.idgen, m.module.owner, m.module.info)
result.typ = newProcType(m.module.info, m.idgen, m.module.owner)
result.typ.callConv = ccCDecl
backendEnsureMutable result
incl result.flagsImpl, sfExportc
result.locImpl.snippet = prefixedName
incl result.flags, sfExportc
result.loc.snippet = prefixedName
if isDynlib:
incl(result.locImpl.flags, lfExportLib)
incl(result.loc.flags, lfExportLib)
let theProc = newNodeI(nkProcDef, m.module.info, bodyPos+1)
for i in 0..<theProc.len: theProc[i] = newNodeI(nkEmpty, m.module.info)
@@ -2565,7 +2552,7 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
body.add graph.globalDestructors[i]
body.flags.incl nfTransf # should not be further transformed
let dtor = generateLibraryDestroyGlobals(graph, m, body, optGenDynLib in m.config.globalOptions)
genProcLvl3(m, dtor)
genProcAux(m, dtor)
if pipelineutils.skipCodegen(m.config, n): return
if moduleHasChanged(graph, m.module):
# if the module is cached, we don't regenerate the main proc
@@ -2599,7 +2586,7 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
cgsym(m, "rawWrite")
# raise dependencies on behalf of genMainProc
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc, gcYrc}:
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc}:
cgsym(m, "initStackBottomWith")
if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone:
cgsym(m, "initThreadVarsEmulation")
@@ -2607,7 +2594,7 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
if m.g.forwardedProcs.len == 0:
incl m.flags, objHasKidsValid
if optMultiMethods in m.g.config.globalOptions or
m.g.config.selectedGC notin {gcArc, gcOrc, gcAtomicArc, gcYrc} or
m.g.config.selectedGC notin {gcArc, gcOrc, gcAtomicArc} or
vtables notin m.g.config.features:
generateIfMethodDispatchers(graph, m.idgen)
@@ -2618,15 +2605,15 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
proc genForwardedProcs(g: BModuleList) =
# Forward declared proc:s lack bodies when first encountered, so they're given
# a second pass here
# Note: ``genProcLvl2`` may add to ``forwardedProcs``
# Note: ``genProcNoForward`` may add to ``forwardedProcs``
while g.forwardedProcs.len > 0:
let
prc = g.forwardedProcs.pop()
m = g.mods[prc.itemId.module]
m = g.modules[prc.itemId.module]
if sfForward in prc.flags:
internalError(m.config, prc.info, "still forwarded: " & prc.name.s)
genProcLvl2(m, prc)
genProcNoForward(m, prc)
proc cgenWriteModules*(backend: RootRef, config: ConfigRef) =
let g = BModuleList(backend)
@@ -2638,6 +2625,6 @@ proc cgenWriteModules*(backend: RootRef, config: ConfigRef) =
genForwardedProcs(g)
for m in cgenModules(g):
m.writeModule()
m.writeModule(pending=true)
writeMapping(config, g.mapping)
if g.generatedHeader != nil: writeHeader(g.generatedHeader)

View File

@@ -117,9 +117,9 @@ type
BModuleList* = ref object of RootObj
mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: Builder
mapping*: Rope # the generated mapping file (if requested)
mods*: seq[BModule] # list of all compiled modules
modules*: seq[BModule] # list of all compiled modules
modulesClosed*: seq[BModule] # list of the same compiled modules, but in the order they were closed
forwardedProcs*: seq[PSym] # procs that did not yet have a body
forwardedProcs*: seq[PSym] # proc:s that did not yet have a body
generatedHeader*: BModule
typeInfoMarker*: TypeCacheWithOwner
typeInfoMarkerV2*: TypeCacheWithOwner
@@ -155,7 +155,6 @@ type
forwTypeCache*: TypeCache # cache for forward declarations of types
declaredThings*: IntSet # things we have declared in this .c file
declaredProtos*: IntSet # prototypes we have declared in this .c file
queue*: seq[PSym] # queue of procs to generate
alive*: IntSet # symbol IDs of alive data as computed by `dce.nim`
headerFiles*: seq[string] # needed headers to include
typeInfoMarker*: TypeCache # needed for generating type information
@@ -179,9 +178,6 @@ template config*(m: BModule): ConfigRef = m.g.config
template config*(p: BProc): ConfigRef = p.module.g.config
template vccAndC*(p: BProc): bool = p.module.config.cCompiler == ccVcc and p.module.config.backend == backendC
proc delayedCodegen*(m: BModule): bool {.inline.} =
useAliveDataFromDce in m.flags or m.config.globalOptions.contains(optCompress)
proc includeHeader*(this: BModule; header: string) =
if not this.headerFiles.contains header:
this.headerFiles.add header

View File

@@ -55,7 +55,7 @@ proc methodCall*(n: PNode; conf: ConfigRef): PNode =
# replace ordinary method by dispatcher method:
let disp = getDispatcher(result[0].sym)
if disp != nil:
result[0].typ = disp.typ
result[0].typ() = disp.typ
result[0].sym = disp
# change the arguments to up/downcasts to fit the dispatcher's parameters:
for i in 1..<result.len:
@@ -123,8 +123,8 @@ proc attachDispatcher(s: PSym, dispatcher: PNode) =
proc createDispatcher(s: PSym; g: ModuleGraph; idgen: IdGenerator): PSym =
var disp = copySym(s, idgen)
incl(disp, sfDispatcher)
excl(disp, sfExported)
incl(disp.flags, sfDispatcher)
excl(disp.flags, sfExported)
let old = disp.typ
disp.typ = copyType(disp.typ, idgen, disp.typ.owner)
copyTypeProps(g, idgen.module, disp.typ, old)
@@ -133,7 +133,7 @@ proc createDispatcher(s: PSym; g: ModuleGraph; idgen: IdGenerator): PSym =
if disp.typ.callConv == ccInline: disp.typ.callConv = ccNimCall
disp.ast = copyTree(s.ast)
disp.ast[bodyPos] = newNodeI(nkEmpty, s.info)
disp.locImpl.snippet = ""
disp.loc.snippet = ""
if s.typ.returnType != nil:
if disp.ast.len > resultPos:
disp.ast[resultPos].sym = copySym(s.ast[resultPos].sym, idgen)

View File

@@ -64,8 +64,7 @@
# the target state is `except` block. For all states in `except` block
# the target state is `finally` block. For all other states there is no
# target state (0, as the first state can never be except nor finally).
# - env var :curExc is created, where "current" exception within the iterator is stored,
# also finallies use it to decide their exit logic
# - env var :curExcLevel is created, finallies use it to decide their exit logic
# - if there are finallies, env var :finallyPath is created. It contains exit state labels
# for every finally level, and is changed in runtime in try, except, break, and return
# nodes to control finally exit behavior.
@@ -112,6 +111,7 @@
# :state = 2 # And we continue to our finally
# break :stateLoop
# of 1: # Except
# inc(:curExcLevel, -1) # Exception is caught
# yield 1
# :tmpResult = 3 # Return
# :finalyPath[LEVEL] = 0 # Configure finally path.
@@ -123,7 +123,7 @@
# of 2: # Finally
# yield 2
# if :finallyPath[LEVEL] == 0: # This node is created by `newEndFinallyNode`
# if :curExc == nil:
# if :curExcLevel == 0:
# :state = -1
# return result = :tmpResult
# else:
@@ -139,7 +139,8 @@
import
ast, msgs, idents,
renderer, magicsys, lowerings, lambdalifting, modulegraphs, lineinfos
renderer, magicsys, lowerings, lambdalifting, modulegraphs, lineinfos,
options
import std/tables
@@ -164,8 +165,7 @@ type
fn: PSym
tmpResultSym: PSym # Used when we return, but finally has to interfere
finallyPathSym: PSym
curExcSym: PSym # Current exception
externExcSym: PSym # Extern exception: what would getCurrentException() return outside of closure iter
curExcLevelSym: PSym # Current exception level (because exceptions are stacked)
states: seq[State] # The resulting states. Label is int literal.
finallyPathStack: seq[FinallyTarget] # Stack of split blocks, whiles and finallies
@@ -178,9 +178,6 @@ type
varStates: Table[ItemId, int] # Used to detect if local variable belongs to multiple states
finallyPathLen: PNode # int literal
nullifyCurExc: PNode # Empty node, if no yields in tries
restoreExternExc: PNode # Empty node, id no yields in tries
const
nkSkip = {nkEmpty..nkNilLit, nkTemplateDef, nkTypeSection, nkStaticStmt,
nkCommentStmt, nkMixinStmt, nkBindStmt, nkTypeOfExpr} + procDefs
@@ -199,7 +196,7 @@ proc newStateAssgn(ctx: var Ctx, toValue: PNode): PNode =
proc newEnvVar(ctx: var Ctx, name: string, typ: PType): PSym =
result = newSym(skVar, getIdent(ctx.g.cache, name), ctx.idgen, ctx.fn, ctx.fn.info)
result.typ = typ
result.flagsImpl.incl sfNoInit
result.flags.incl sfNoInit
assert(not typ.isNil, "Env var needs a type")
let envParam = getEnvParam(ctx.fn)
@@ -245,11 +242,10 @@ proc newFinallyPathAssign(ctx: var Ctx, level: int, label: PNode, info: TLineInf
let fp = newFinallyPathAccess(ctx, level, info)
result = newTree(nkAsgn, fp, label)
proc newCurExcAccess(ctx: var Ctx): PNode =
if ctx.curExcSym.isNil:
let getCurExc = ctx.g.callCodegenProc("getCurrentException")
ctx.curExcSym = ctx.newEnvVar(":curExc", getCurExc.typ)
ctx.newEnvVarAccess(ctx.curExcSym)
proc newCurExcLevelAccess(ctx: var Ctx): PNode =
if ctx.curExcLevelSym.isNil:
ctx.curExcLevelSym = ctx.newEnvVar(":curExcLevel", ctx.g.getSysType(ctx.fn.info, tyInt16))
ctx.newEnvVarAccess(ctx.curExcLevelSym)
proc newStateLabel(ctx: Ctx): PNode =
ctx.g.newIntLit(TLineInfo(), 0)
@@ -288,15 +284,6 @@ proc newTempVar(ctx: var Ctx, typ: PType, parent: PNode, initialValue: PNode = n
assert(not typ.isNil, "Temp var needs a type")
parent.add(ctx.newTempVarDef(result, initialValue))
proc newExternExcAccess(ctx: var Ctx): PNode =
if ctx.externExcSym == nil:
ctx.externExcSym = newSym(skVar, getIdent(ctx.g.cache, ":externExc"), ctx.idgen, ctx.fn, ctx.fn.info)
ctx.externExcSym.typ = ctx.curExcSym.typ
newSymNode(ctx.externExcSym, ctx.fn.info)
proc newRestoreExternException(ctx: var Ctx): PNode =
ctx.g.callCodegenProc("closureIterSetExc", ctx.fn.info, ctx.newExternExcAccess())
proc hasYields(n: PNode): bool =
# TODO: This is very inefficient. It traverses the node, looking for nkYieldStmt.
case n.kind
@@ -311,13 +298,21 @@ proc hasYields(n: PNode): bool =
result = true
break
proc newNullifyCurExc(ctx: var Ctx, info: TLineInfo): PNode =
# :curExc = nil
let curExc = ctx.newCurExcAccess()
proc newNullifyCurExcLevel(ctx: var Ctx, info: TLineInfo, decrement = false): PNode =
# :curEcx = 0
let curExc = ctx.newCurExcLevelAccess()
curExc.info = info
let nilnode = newNodeIT(nkNilLit, info, getSysType(ctx.g, info, tyNil))
let nilnode = ctx.g.newIntLit(info, 0)
result = newTree(nkAsgn, curExc, nilnode)
proc newChangeCurExcLevel(ctx: var Ctx, info: TLineInfo, by: int): PNode =
# inc(:curEcxLevel, by)
let curExc = ctx.newCurExcLevelAccess()
curExc.info = info
result = newTreeIT(nkCall, info, ctx.g.getSysType(info, tyVoid),
newSymNode(ctx.g.getSysMagic(info, "inc", mInc)), curExc,
ctx.g.newIntLit(info, by))
proc newOr(g: ModuleGraph, a, b: PNode): PNode {.inline.} =
result = newTreeIT(nkCall, a.info, g.getSysType(a.info, tyBool),
newSymNode(g.getSysMagic(a.info, "or", mOr)), a, b)
@@ -349,7 +344,7 @@ proc collectExceptState(ctx: var Ctx, n: PNode): PNode {.inline.} =
else:
ifBranch = newNodeI(nkElse, c.info)
ifBranch.add(c[^1])
ifBranch.add(newTreeI(nkStmtList, c.info, ctx.newChangeCurExcLevel(c.info, -1), c[^1]))
ifStmt.add(ifBranch)
if ifStmt.len != 0:
@@ -357,10 +352,9 @@ proc collectExceptState(ctx: var Ctx, n: PNode): PNode {.inline.} =
else:
result = ctx.g.emptyNode
proc addElseToExcept(ctx: var Ctx, n, gotoOut: PNode): PNode =
proc addElseToExcept(ctx: var Ctx, n, gotoOut: PNode) =
# We should adjust finallyPath to gotoOut if exception is handled
# if there is no finally node next to this except, gotoOut must be nil
result = n
if n.kind == nkStmtList:
if n[0].kind == nkIfStmt and n[0][^1].kind != nkElse:
# Not all cases are covered, which means exception is not handled
@@ -383,7 +377,6 @@ proc addElseToExcept(ctx: var Ctx, n, gotoOut: PNode): PNode =
# raised one.
n.add newTree(nkCall,
newSymNode(ctx.g.getCompilerProc("popCurrentException")))
n.add ctx.newNullifyCurExc(n.info)
if gotoOut != nil:
# We have a finally node following this except block, and exception is handled
# Configure its path to continue normally
@@ -457,7 +450,7 @@ proc newNotCall(g: ModuleGraph; e: PNode): PNode =
proc boolLit(g: ModuleGraph; info: TLineInfo; value: bool): PNode =
result = newIntLit(g, info, ord value)
result.typ = getSysType(g, info, tyBool)
result.typ() = getSysType(g, info, tyBool)
proc captureVar(c: var Ctx, s: PSym) =
if c.varStates.getOrDefault(s.itemId) != localRequiresLifting:
@@ -818,7 +811,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
let (st, ex) = exprToStmtList(n[1])
n.transitionSonsKind(nkBlockStmt)
n.typ = nil
n.typ() = nil
n[1] = st
result.add(n)
result.add(ex)
@@ -830,7 +823,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
proc newEndFinallyNode(ctx: var Ctx, info: TLineInfo): PNode =
# Generate the following code:
# if :finallyPath[FINALLY_LEVEL] == 0:
# if :curExc == nil:
# if :curExcLevel == 0:
# :state = -1
# return result = :tmpResult
# else:
@@ -844,9 +837,9 @@ proc newEndFinallyNode(ctx: var Ctx, info: TLineInfo): PNode =
let excNilCmp = newTreeIT(nkCall,
info, ctx.g.getSysType(info, tyBool),
newSymNode(ctx.g.getSysMagic(info, "==", mEqRef), info),
ctx.newCurExcAccess(),
newNodeIT(nkNilLit, info, getSysType(ctx.g, info, tyNil)))
newSymNode(ctx.g.getSysMagic(info, "==", mEqI), info),
ctx.newCurExcLevelAccess(),
ctx.g.newIntLit(info, 0))
let retStmt =
block:
@@ -863,7 +856,7 @@ proc newEndFinallyNode(ctx: var Ctx, info: TLineInfo): PNode =
retStmt.flags.incl(nfNoRewrite)
let ifBody = newTree(nkIfStmt,
newTree(nkElifBranch, excNilCmp, newTree(nkStmtList, ctx.newRestoreExternException(), retStmt)),
newTree(nkElifBranch, excNilCmp, retStmt),
newTree(nkElse,
newTree(nkStmtList,
newTreeI(nkRaiseStmt, info, ctx.g.emptyNode))))
@@ -918,15 +911,14 @@ proc transformBreakStmt(ctx: var Ctx, n: PNode): PNode =
result = n
proc transformReturnStmt(ctx: var Ctx, n: PNode): PNode =
# "Returning" involves jumping along all the current finally path.
# "Returning" involves jumping along all the cureent finally path.
# The last finally should exit to state 0 which is a special case for last exit
# (either return or propagating exception to the caller).
# It is eccounted for in newEndFinallyNode.
result = newNodeI(nkStmtList, n.info)
# Returns prevent exception propagation
result.add(ctx.nullifyCurExc)
result.add(ctx.newNullifyCurExcLevel(n.info))
var finallyChain = newSeq[PNode]()
@@ -950,7 +942,6 @@ proc transformReturnStmt(ctx: var Ctx, n: PNode): PNode =
result.add(ctx.newJumpAlongFinallyChain(finallyChain, n.info))
else:
# There are no (split) finallies on the path, so we can return right away
result.add(ctx.restoreExternExc)
result.add(n)
proc transformBreaksAndReturns(ctx: var Ctx, n: PNode): PNode =
@@ -961,7 +952,7 @@ proc transformBreaksAndReturns(ctx: var Ctx, n: PNode): PNode =
# of nkContinueStmt: # By this point all relevant continues should be
# lowered to breaks in transf.nim.
of nkReturnStmt:
if nfNoRewrite notin n.flags:
if ctx.curFinallyLevel > 0 and nfNoRewrite notin n.flags:
result = ctx.transformReturnStmt(n)
else:
for i in 0..<n.len:
@@ -995,7 +986,6 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
of nkYieldStmt:
result = addGotoOut(result, gotoOut)
result = newTree(nkStmtList, ctx.restoreExternExc, result)
of nkElse, nkElseExpr:
result[0] = addGotoOut(result[0], gotoOut)
@@ -1065,7 +1055,7 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
result.add(tryLabel)
var tryBody = toStmtList(n[0])
var exceptBody = ctx.collectExceptState(n)
let exceptBody = ctx.collectExceptState(n)
var finallyBody = ctx.getFinallyNode(n)
var exceptLabel, finallyLabel = ctx.g.emptyNode
@@ -1104,7 +1094,8 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
inc ctx.curFinallyLevel
ctx.finallyPathStack.add(FinallyTarget(n: n[^1], label: finallyLabel))
tryBody = ctx.transformClosureIteratorBody(tryBody, tryOut)
if ctx.transformClosureIteratorBody(tryBody, tryOut) != tryBody:
internalError(ctx.g.config, "transformClosureIteratorBody != tryBody")
if exceptBody.kind != nkEmpty:
ctx.curExcLandingState = if finallyBody.kind != nkEmpty: finallyLabel
@@ -1112,9 +1103,10 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
discard ctx.newState(exceptBody, false, exceptLabel)
let normalOut = if finallyBody.kind != nkEmpty: gotoOut else: nil
exceptBody = ctx.addElseToExcept(exceptBody, normalOut)
ctx.addElseToExcept(exceptBody, normalOut)
# echo "EXCEPT: ", renderTree(exceptBody)
exceptBody = ctx.transformClosureIteratorBody(exceptBody, tryOut)
if ctx.transformClosureIteratorBody(exceptBody, tryOut) != exceptBody:
internalError(ctx.g.config, "transformClosureIteratorBody != exceptBody")
ctx.curExcLandingState = oldExcLandingState
@@ -1122,7 +1114,8 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
discard ctx.finallyPathStack.pop()
discard ctx.newState(finallyBody, false, finallyLabel)
let finallyExit = newTree(nkGotoState, ctx.newFinallyPathAccess(ctx.curFinallyLevel - 1, finallyBody.info))
finallyBody = ctx.transformClosureIteratorBody(finallyBody, finallyExit)
if ctx.transformClosureIteratorBody(finallyBody, finallyExit) != finallyBody:
internalError(ctx.g.config, "transformClosureIteratorBody != finallyBody")
dec ctx.curFinallyLevel
of nkGotoState, nkForStmt:
@@ -1208,6 +1201,34 @@ proc createExceptionTable(ctx: var Ctx): PNode {.inline.} =
for i in 0 .. ctx.states.high:
result.add(ctx.states[i].excLandingState)
proc newExceptBody(ctx: var Ctx, info: TLineInfo): PNode {.inline.} =
# Generates code:
# :state = exceptionTable[:state]
# if :state == 0:
# raise
result = newNodeI(nkStmtList, info)
let intTyp = ctx.g.getSysType(info, tyInt)
let boolTyp = ctx.g.getSysType(info, tyBool)
# :state = exceptionTable[:state]
result.add ctx.newStateAssgn(
newTreeIT(nkBracketExpr, info, intTyp,
ctx.createExceptionTable(),
ctx.newStateAccess()))
# if :state == 0: raise
block:
let cond = newTreeIT(nkCall, info, boolTyp,
ctx.g.getSysMagic(info, "==", mEqI).newSymNode(),
ctx.newStateAccess(),
newIntTypeNode(0, intTyp))
let raiseStmt = newTree(nkRaiseStmt, ctx.g.emptyNode)
let ifBranch = newTree(nkElifBranch, cond, raiseStmt)
let ifStmt = newTree(nkIfStmt, ifBranch)
result.add(ifStmt)
proc wrapIntoTryExcept(ctx: var Ctx, n: PNode): PNode {.inline.} =
# Generates code:
# var :tmp = nil
@@ -1215,45 +1236,24 @@ proc wrapIntoTryExcept(ctx: var Ctx, n: PNode): PNode {.inline.} =
# body
# except:
# :state = exceptionTable[:state]
# :curExc = getCurrentException()
# if :state == 0:
# closureIterSetExc(:externExc)
# raise
# if :state == 0:
# raise
# :tmp = getCurrentException()
#
# pushCurrentException(:curExc)
# pushCurrentException(:tmp)
let info = ctx.fn.info
let getCurExc = ctx.g.callCodegenProc("getCurrentException")
let exceptBody = newTreeI(nkStmtList, info,
ctx.newStateAssgn(
newTreeIT(nkBracketExpr, info, ctx.g.getSysType(info, tyInt),
ctx.createExceptionTable(),
ctx.newStateAccess())),
newTreeI(nkFastAsgn, info, ctx.newCurExcAccess(), getCurExc))
let tryBody = newTree(nkStmtList, n)
let exceptBody = ctx.newExceptBody(ctx.fn.info)
let exceptBranch = newTree(nkExceptBranch, exceptBody)
result = newTree(nkStmtList)
result.add newTree(nkTryStmt,
newTree(nkStmtList, n),
newTree(nkExceptBranch, exceptBody))
let getCurExc = ctx.g.callCodegenProc("getCurrentException")
let tempExc = ctx.newTempVar(getCurExc.typ, result)
result.add newTree(nkTryStmt, tryBody, exceptBranch)
exceptBody.add ctx.newTempVarAsgn(tempExc, getCurExc)
# if :state == 0:
# closureIterSetExc(:externExc)
# raise
block:
let boolTyp = ctx.g.getSysType(info, tyBool)
let intTyp = ctx.g.getSysType(info, tyInt)
let cond = newTreeIT(nkCall, info, boolTyp,
ctx.g.getSysMagic(info, "==", mEqI).newSymNode(),
ctx.newStateAccess(),
newIntTypeNode(0, intTyp))
let raiseStmt = newTree(nkRaiseStmt, ctx.newCurExcAccess())
let ifBody = newTree(nkStmtList, ctx.newRestoreExternException(), raiseStmt)
let ifBranch = newTree(nkElifBranch, cond, ifBody)
let ifStmt = newTree(nkIfStmt, ifBranch)
result.add(ifStmt)
result.add newTree(nkCall, newSymNode(ctx.g.getCompilerProc("pushCurrentException")), ctx.newCurExcAccess())
result.add newTree(nkCall, newSymNode(ctx.g.getCompilerProc("pushCurrentException")), ctx.newTempVarAccess(tempExc))
result.add ctx.newChangeCurExcLevel(n.info, 1)
proc wrapIntoStateLoop(ctx: var Ctx, n: PNode): PNode =
# while true:
@@ -1276,19 +1276,6 @@ proc wrapIntoStateLoop(ctx: var Ctx, n: PNode): PNode =
blockStmt.add(blockBody)
loopBody.add(blockStmt)
if ctx.hasExceptions:
# Since we have yields in tries, we must switch current exception
# between the iter and "outer world"
# var :externExc = getCurrentException()
# closureIterSetExc(:curExc)
let getCurExc = ctx.g.callCodegenProc("getCurrentException")
discard ctx.newExternExcAccess()
let setCurExc = ctx.g.callCodegenProc("closureIterSetExc", n.info, ctx.newCurExcAccess())
result = newTreeI(nkStmtList, n.info,
ctx.newTempVarDef(ctx.externExcSym, getCurExc),
setCurExc,
result)
proc countStateOccurences(ctx: var Ctx, n: PNode, stateOccurences: var openArray[int]) =
## Find all nkGotoState(stateIdx) nodes that do not follow nkYield.
## For every such node increment stateOccurences[stateIdx]
@@ -1306,15 +1293,16 @@ proc countStateOccurences(ctx: var Ctx, n: PNode, stateOccurences: var openArray
proc replaceDeletedStates(ctx: var Ctx, n: PNode): PNode =
result = n
if n.kind == nkIntLit:
let idx = n.intVal
if idx >= 0 and idx < ctx.states.len and ctx.states[idx].label == n and ctx.states[idx].deletable:
let gt = ctx.replaceDeletedStates(skipStmtList(ctx.states[idx].body))
assert(gt.kind == nkGotoState)
result = gt[0]
else:
for i in 0 ..< n.safeLen:
n[i] = ctx.replaceDeletedStates(n[i])
for i in 0 ..< n.safeLen:
let c = n[i]
if c.kind == nkIntLit:
let idx = c.intVal
if idx >= 0 and idx < ctx.states.len and ctx.states[idx].label == c and ctx.states[idx].deletable:
let gt = ctx.replaceDeletedStates(skipStmtList(ctx.states[idx].body))
assert(gt.kind == nkGotoState)
n[i] = gt[0]
else:
n[i] = ctx.replaceDeletedStates(c)
proc replaceInlinedStates(ctx: var Ctx, n: PNode): PNode =
## Find all nkGotoState(stateIdx) nodes that do not follow nkYield.
@@ -1345,7 +1333,6 @@ proc optimizeStates(ctx: var Ctx) =
# Replace deletable state labels to labels of respective non-empty states
for i in 0 .. ctx.states.high:
ctx.states[i].body = ctx.replaceDeletedStates(ctx.states[i].body)
ctx.states[i].excLandingState = ctx.replaceDeletedStates(ctx.states[i].excLandingState)
# Remove deletable states
var i = 0
@@ -1394,7 +1381,7 @@ proc detectCapturedVars(c: var Ctx, n: PNode, stateIdx: int) =
case n.kind
of nkSym:
let s = n.sym
if s.kind in {skResult, skVar, skLet, skForVar, skTemp} and sfGlobal notin s.flags and s.owner == c.fn and s != c.externExcSym:
if s.kind in {skResult, skVar, skLet, skForVar, skTemp} and sfGlobal notin s.flags and s.owner == c.fn:
let vs = c.varStates.getOrDefault(s.itemId, localNotSeen)
if vs == localNotSeen: # First seing this variable
c.varStates[s.itemId] = stateIdx
@@ -1467,16 +1454,10 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n:
ctx.curExcLandingState = ctx.newStateLabel()
ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), idgen, fn, fn.info)
ctx.nullifyCurExc = newTree(nkStmtList)
ctx.restoreExternExc = newTree(nkStmtList)
var n = n.toStmtList
# echo "transformed into ", n
discard ctx.newState(n, false, nil)
let gotoOut = newTree(nkGotoState, g.newIntLit(n.info, -1))
var ns = false
@@ -1489,10 +1470,6 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n:
# Splitting transformation
discard ctx.transformClosureIteratorBody(n, gotoOut)
if ctx.hasExceptions:
ctx.nullifyCurExc.add(ctx.newNullifyCurExc(fn.info))
ctx.restoreExternExc.add(ctx.newRestoreExternException())
# Assign state label indexes
for i in 0 .. ctx.states.high:
ctx.states[i].label.intVal = i
@@ -1510,9 +1487,7 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n:
let body = ctx.transformStateAssignments(s.body)
caseDispatcher.add newTreeI(nkOfBranch, body.info, s.label, body)
caseDispatcher.add newTreeI(nkElse, n.info,
newTree(nkStmtList, ctx.restoreExternExc,
newTreeI(nkReturnStmt, n.info, g.emptyNode)))
caseDispatcher.add newTreeI(nkElse, n.info, newTreeI(nkReturnStmt, n.info, g.emptyNode))
result = wrapIntoStateLoop(ctx, caseDispatcher)
result = liftLocals(ctx, result)

View File

@@ -118,7 +118,7 @@ const
errInvalidCmdLineOption = "invalid command line option: '$1'"
errOnOrOffExpectedButXFound = "'on' or 'off' expected, but '$1' found"
errOnOffOrListExpectedButXFound = "'on', 'off' or 'list' expected, but '$1' found"
errOffHintsError = "'off', 'hint', 'warning', 'error' or 'usages' expected, but '$1' found"
errOffHintsError = "'off', 'hint', 'error' or 'usages' expected, but '$1' found"
proc invalidCmdLineOption(conf: ConfigRef; pass: TCmdLinePass, switch: string, info: TLineInfo) =
if switch == " ": localError(conf, info, errInvalidCmdLineOption % "-")
@@ -245,7 +245,7 @@ proc processCompile(conf: ConfigRef; filename: string) =
extccomp.addExternalFileToCompile(conf, found)
const
errNoneBoehmRefcExpectedButXFound = "'arc', 'orc', 'yrc', 'atomicArc', 'markAndSweep', 'boehm', 'go', 'none', 'regions', or 'refc' expected, but '$1' found"
errNoneBoehmRefcExpectedButXFound = "'arc', 'orc', 'atomicArc', 'markAndSweep', 'boehm', 'go', 'none', 'regions', or 'refc' expected, but '$1' found"
errNoneSpeedOrSizeExpectedButXFound = "'none', 'speed' or 'size' expected, but '$1' found"
errGuiConsoleOrLibExpectedButXFound = "'gui', 'console', 'lib' or 'staticlib' expected, but '$1' found"
errInvalidExceptionSystem = "'goto', 'setjmp', 'cpp' or 'quirky' expected, but '$1' found"
@@ -266,7 +266,6 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo
of "markandsweep": result = conf.selectedGC == gcMarkAndSweep
of "destructors", "arc": result = conf.selectedGC == gcArc
of "orc": result = conf.selectedGC == gcOrc
of "yrc": result = conf.selectedGC == gcYrc
of "hooks": result = conf.selectedGC == gcHooks
of "go": result = conf.selectedGC == gcGo
of "none": result = conf.selectedGC == gcNone
@@ -365,7 +364,6 @@ proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool
result = false
of "panics": result = contains(conf.globalOptions, optPanics)
of "jsbigint64": result = contains(conf.globalOptions, optJsBigInt64)
of "mangle": result = contains(conf.globalOptions, optItaniumMangle)
else:
result = false
invalidCmdLineOption(conf, passCmd1, switch, info)
@@ -495,11 +493,10 @@ proc parseCommand*(command: string): Command =
of "gendepend": cmdGendepend
of "dump": cmdDump
of "parse": cmdParse
of "rod": cmdRod
of "secret": cmdInteractive
of "nop", "help": cmdNop
of "jsonscript": cmdJsonscript
of "nifc": cmdNifC # generate C from NIF files
of "ic": cmdIc # generate .build.nif for nifmake
else: cmdUnknown
proc setCmd*(conf: ConfigRef, cmd: Command) =
@@ -512,11 +509,6 @@ proc setCmd*(conf: ConfigRef, cmd: Command) =
of cmdCompileToOC: conf.backend = backendObjc
of cmdCompileToJS: conf.backend = backendJs
of cmdCompileToNif: conf.backend = backendNif
of cmdNifC:
conf.backend = backendC # NIF to C compilation
of cmdM:
# cmdM requires optCompress for proper IC handling (include files, etc.)
conf.globalOptions.incl optCompress
else: discard
proc setCommandEarly*(conf: ConfigRef, command: string) =
@@ -571,7 +563,6 @@ proc unregisterArcOrc*(conf: ConfigRef) =
undefSymbol(conf.symbols, "gcdestructors")
undefSymbol(conf.symbols, "gcarc")
undefSymbol(conf.symbols, "gcorc")
undefSymbol(conf.symbols, "gcyrc")
undefSymbol(conf.symbols, "gcatomicarc")
undefSymbol(conf.symbols, "nimSeqsV2")
undefSymbol(conf.symbols, "nimV2")
@@ -605,10 +596,6 @@ proc processMemoryManagementOption(switch, arg: string, pass: TCmdLinePass,
conf.selectedGC = gcOrc
defineSymbol(conf.symbols, "gcorc")
registerArcOrc(pass, conf)
of "yrc":
conf.selectedGC = gcYrc
defineSymbol(conf.symbols, "gcyrc")
registerArcOrc(pass, conf)
of "atomicarc":
conf.selectedGC = gcAtomicArc
defineSymbol(conf.symbols, "gcatomicarc")
@@ -775,16 +762,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
conf.globalOptions.excl optCDebug
else:
localError(conf, info, "expected native|gdb|on|off but found " & arg)
of "mangle":
case arg.normalize
of "nim":
conf.globalOptions.excl optItaniumMangle
of "cpp":
conf.globalOptions.incl optItaniumMangle
else:
localError(conf, info, "expected nim|cpp but found " & arg)
of "compress":
conf.globalOptions.incl optCompress
of "g": # alias for --debugger:native
conf.globalOptions.incl optCDebug
conf.options.incl optLineDir
@@ -907,19 +884,11 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
of "import":
expectArg(conf, switch, arg, pass, info)
if pass in {passCmd2, passPP}:
let m = findModule(conf, arg, toFullPath(conf, info)).string
if m.len == 0:
localError(conf, info, "Cannot resolve filename: " & arg)
else:
conf.implicitImports.add m
conf.implicitImports.add findModule(conf, arg, toFullPath(conf, info)).string
of "include":
expectArg(conf, switch, arg, pass, info)
if pass in {passCmd2, passPP}:
let m = findModule(conf, arg, toFullPath(conf, info)).string
if m.len == 0:
localError(conf, info, "Cannot resolve filename: " & arg)
else:
conf.implicitIncludes.add m
conf.implicitIncludes.add findModule(conf, arg, toFullPath(conf, info)).string
of "listcmd":
processOnOffSwitchG(conf, {optListCmd}, arg, pass, info)
of "asm":
@@ -1005,8 +974,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
# xxx maybe also ic, since not in help?
if pass in {passCmd2, passPP}:
case arg.normalize
of "on": conf.ic = true
of "legacy": conf.symbolFiles = v2Sf
of "on": conf.symbolFiles = v2Sf
of "off": conf.symbolFiles = disabledSf
of "writeonly": conf.symbolFiles = writeOnlySf
of "readonly": conf.symbolFiles = readOnlySf
@@ -1114,9 +1082,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
of "shownonexports":
expectNoArg(conf, switch, arg, pass, info)
showNonExportedFields(conf)
of "raw":
expectNoArg(conf, switch, arg, pass, info)
docRawOutput(conf)
of "exceptions":
case arg.normalize
of "cpp": conf.exc = excCpp
@@ -1148,10 +1113,9 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
defineSymbol(conf.symbols, "nimSeqsV2")
of "stylecheck":
case arg.normalize
of "off": conf.globalOptions = conf.globalOptions - {optStyleHint, optStyleError, optStyleWarning}
of "hint": conf.globalOptions = conf.globalOptions + {optStyleHint} - {optStyleError, optStyleWarning}
of "warning": conf.globalOptions = conf.globalOptions + {optStyleWarning} - {optStyleHint, optStyleError}
of "error": conf.globalOptions = conf.globalOptions + {optStyleError} - {optStyleHint, optStyleWarning}
of "off": conf.globalOptions = conf.globalOptions - {optStyleHint, optStyleError}
of "hint": conf.globalOptions = conf.globalOptions + {optStyleHint} - {optStyleError}
of "error": conf.globalOptions = conf.globalOptions + {optStyleError}
of "usages": conf.globalOptions.incl optStyleUsages
else: localError(conf, info, errOffHintsError % arg)
of "showallmismatches":

View File

@@ -11,9 +11,9 @@
## for details. Note this is a first implementation and only the "Concept matching"
## section has been implemented.
import ast, semdata, lookups, lineinfos, idents, msgs, renderer, types, layeredtable
import ast, astalgo, semdata, lookups, lineinfos, idents, msgs, renderer, types, layeredtable
import std/sets
import std/intsets
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -29,7 +29,7 @@ proc declareSelf(c: PContext; info: TLineInfo) =
let ow = getCurrOwner(c)
let s = newSym(skType, getIdent(c.cache, "Self"), c.idgen, ow, info)
s.typ = newType(tyTypeDesc, c.idgen, ow)
s.typ.incl {tfUnresolved, tfPacked}
s.typ.flags.incl {tfUnresolved, tfPacked}
s.typ.add newType(tyEmpty, c.idgen, ow)
addDecl(c, s, info)
@@ -73,20 +73,18 @@ type
MatchFlags* = enum
mfDontBind # Do not bind generic parameters
mfCheckGeneric # formal <- formal comparison as opposed to formal <- operand
ConceptTypePair = tuple[conceptId, typeId: ItemId]
## Pair of (concept type id, implementation type id) used for cycle detection
MatchCon = object ## Context we pass around during concept matching.
bindings: LayeredIdTable
marker: HashSet[ConceptTypePair] ## Tracks (concept, type) pairs being checked to detect cycles.
marker: IntSet ## Some protection against wild runaway recursions.
potentialImplementation: PType ## the concrete type that might match the concept we try to match.
magic: TMagic ## mArrGet and mArrPut is wrong in system.nim and
## cannot be fixed that easily.
## Thus we special case it here.
concpt: PType ## current concept being evaluated
depthCount = 0
flags: set[MatchFlags]
MatchKind = enum
mkNoMatch, mkSubset, mkSame
@@ -139,7 +137,7 @@ proc bindParam(c: PContext, m: var MatchCon; key, v: PType): bool {. discardable
# check previously bound value
if not matchType(c, old, value, m):
return false
elif key.hasElementType and not key.elementType.isNil and key.elementType.kind != tyNone:
elif key.hasElementType and key.elementType.kind != tyNone:
# check constaint
if matchType(c, unrollGenericParam(key), value, m) == false:
return false
@@ -190,48 +188,32 @@ iterator traverseTyOr(t: PType): PType {. closure .}=
proc matchConceptToImpl(c: PContext, f, potentialImpl: PType; m: var MatchCon): bool =
assert not(potentialImpl.reduceToBase.kind == tyConcept)
let concpt = f.reduceToBase
# Handle self-referential concepts: when a concept references itself in its body
# (e.g., `A = concept; proc test(x: Self, y: A)`), the inner type A has n=nil.
# We detect this by checking if the concept has the same symbol name as the
# one we're currently matching and has no body (n=nil).
if concpt.n.isNil:
if concpt.sym != nil and m.concpt.sym != nil and
concpt.sym == m.concpt.sym:
# Self-reference: check if potentialImpl matches what we're already checking
return potentialImpl.id == m.potentialImplementation.id
# Concept without body that's not a self-reference - cannot match
return false
# Cycle detection: track (concept, type) pairs to prevent infinite recursion.
# Returns true on cycle (coinductive semantics) to support co-dependent concepts.
let pair: ConceptTypePair = (concpt.itemId, potentialImpl.itemId)
if pair in m.marker:
if m.depthCount > 0:
# concepts that are more then 2 levels deep are treated like
# tyAnything to stop dependencies from getting out of control
return true
m.marker.incl pair
var efPot = potentialImpl
if potentialImpl.isSelf:
if m.concpt.n == concpt.n:
m.marker.excl pair
return true
efPot = m.potentialImplementation
var oldBindings = m.bindings
m.bindings = newTypeMapLayer(m.bindings)
let oldPotentialImplementation = m.potentialImplementation
m.potentialImplementation = efPot
let oldConcept = m.concpt
m.concpt = concpt
var invocation: PType = nil
if f.kind in {tyGenericInvocation, tyGenericInst}:
invocation = f
inc m.depthCount
result = processConcept(c, concpt, invocation, oldBindings, m)
dec m.depthCount
m.potentialImplementation = oldPotentialImplementation
m.concpt = oldConcept
m.bindings = oldBindings
m.marker.excl pair
proc cmpConceptDefs(c: PContext, fn, an: PNode, m: var MatchCon): bool=
if fn.kind != an.kind:
@@ -281,22 +263,6 @@ proc conceptsMatch(c: PContext, fc, ac: PType; m: var MatchCon): MatchKind =
return mkNoMatch
return mkSubset
proc isObjectSubtype(f, a: PType): bool =
var t = a
result = false
while t != nil:
t = t.baseClass
if t == nil:
break
t = t.skipTypes({tyPtr,tyRef})
if t == nil:
break
if t.kind != tyObject:
break
if sameObjectTypes(f, t):
result = true
break
proc matchType(c: PContext; fo, ao: PType; m: var MatchCon): bool =
## The heart of the concept matching process. 'f' is the formal parameter of some
## routine inside the concept that we're looking for. 'a' is the formal parameter
@@ -361,8 +327,6 @@ proc matchType(c: PContext; fo, ao: PType; m: var MatchCon): bool =
result = a.base.sym == f.sym
else:
result = sameType(f, a)
if not result and f.kind == tyObject and a.kind == tyObject:
result = isObjectSubtype(f, a)
of tyEmpty, tyString, tyCstring, tyPointer, tyNil, tyUntyped, tyTyped, tyVoid:
result = a.skipTypes(ignorableForArgType).kind == f.kind
of tyBool, tyChar, tyInt..tyUInt64:
@@ -394,14 +358,6 @@ proc matchType(c: PContext; fo, ao: PType; m: var MatchCon): bool =
if not matchType(c, f[i], ea[i], m):
result = false
break
elif f.kind == tyGenericInvocation:
# bind potential generic constraints into body
let body = f.base
for i in 1 ..< len(f):
bindParam(c,m,body[i-1], f[i])
result = matchType(c, body, a, m)
else: # tyGenericInst
result = matchType(c, f.last, a, m)
of tyOrdinal:
result = isOrdinalType(a, allowEnumWithHoles = false) or a.kind == tyGenericParam
of tyStatic:
@@ -628,7 +584,7 @@ proc conceptMatch*(c: PContext; concpt, arg: PType; bindings: var LayeredIdTable
## `C[S, T]` parent type that we look for. We need this because we need to store bindings
## for 'S' and 'T' inside 'bindings' on a successful match. It is very important that
## we do not add any bindings at all on an unsuccessful match!
var m = MatchCon(bindings: bindings, potentialImplementation: arg, concpt: concpt, flags: flags, marker: initHashSet[ConceptTypePair]())
var m = MatchCon(bindings: bindings, potentialImplementation: arg, concpt: concpt, flags: flags)
if arg.isConcept:
result = conceptsMatch(c, concpt.reduceToBase, arg.reduceToBase, m) >= mkSubset
elif arg.acceptsAllTypes:

View File

@@ -175,5 +175,3 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimHasSetLengthSeqUninitMagic")
defineSymbol("nimHasPreviewDuplicateModuleError")
defineSymbol("nimHasImplicitRangeConversion")

View File

@@ -1,395 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2025 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Generate a .build.nif file for nifmake from a Nim project.
## This enables incremental and parallel compilation using the `m` switch.
import std / [os, tables, sets, times, osproc, strutils]
import options, msgs, lineinfos, pathutils
import "../dist/nimony/src/lib" / [nifstreams, nifcursors, bitabs, nifreader, nifbuilder]
import "../dist/nimony/src/gear2" / modnames
type
FilePair = object
nimFile: string
modname: string
Node = ref object
files: seq[FilePair] # main file + includes
deps: seq[int] # indices into DepContext.nodes
id: int
DepContext = object
config: ConfigRef
nifler: string
nodes: seq[Node]
processedModules: Table[string, int] # modname -> node index
includeStack: seq[string]
systemNodeId: int # ID of the system.nim node
proc toPair(c: DepContext; f: string): FilePair =
FilePair(nimFile: f, modname: moduleSuffix(f, cast[seq[string]](c.config.searchPaths)))
proc depsFile(c: DepContext; f: FilePair): string =
getNimcacheDir(c.config).string / f.modname & ".deps.nif"
proc parsedFile(c: DepContext; f: FilePair): string =
getNimcacheDir(c.config).string / f.modname & ".p.nif"
proc semmedFile(c: DepContext; f: FilePair): string =
getNimcacheDir(c.config).string / f.modname & ".nif"
proc findNifler(): string =
# Look for nifler in common locations
let nimDir = getAppDir()
result = nimDir / "nifler"
if not fileExists(result):
result = findExe("nifler")
proc findNifmake(): string =
# Look for nifmake in common locations
# Try relative to nim executable
let nimDir = getAppDir()
result = nimDir / "nifmake"
if not fileExists(result):
result = findExe("nifmake")
proc runNifler(c: DepContext; nimFile: string): bool =
## Run nifler deps on a file if needed. Returns true on success.
let pair = c.toPair(nimFile)
let depsPath = c.depsFile(pair)
# Check if deps file is up-to-date
if fileExists(depsPath) and fileExists(nimFile):
if getLastModificationTime(depsPath) > getLastModificationTime(nimFile):
return true # Already up-to-date
# Create output directory if needed
createDir(parentDir(depsPath))
# Run nifler deps
let cmd = quoteShell(c.nifler) & " deps " & quoteShell(nimFile) & " " & quoteShell(depsPath)
let exitCode = execShellCmd(cmd)
result = exitCode == 0
proc resolveFile(c: DepContext; origin, toResolve: string): string =
## Resolve an import path relative to origin file
# Handle std/ prefix
var path = toResolve
if path.startsWith("std/"):
path = path.substr(4)
# Try relative to origin first
let originDir = parentDir(origin)
result = originDir / path.addFileExt("nim")
if fileExists(result):
return result
# Try search paths
for searchPath in c.config.searchPaths:
result = searchPath.string / path.addFileExt("nim")
if fileExists(result):
return result
result = ""
proc traverseDeps(c: var DepContext; pair: FilePair; current: Node)
proc processInclude(c: var DepContext; includePath: string; current: Node) =
let resolved = resolveFile(c, current.files[current.files.len - 1].nimFile, includePath)
if resolved.len == 0 or not fileExists(resolved):
return
# Check for recursive includes
for s in c.includeStack:
if s == resolved:
return # Skip recursive include
c.includeStack.add resolved
current.files.add c.toPair(resolved)
traverseDeps(c, c.toPair(resolved), current)
discard c.includeStack.pop()
proc processImport(c: var DepContext; importPath: string; current: Node) =
let resolved = resolveFile(c, current.files[0].nimFile, importPath)
if resolved.len == 0 or not fileExists(resolved):
return
let pair = c.toPair(resolved)
let existingIdx = c.processedModules.getOrDefault(pair.modname, -1)
if existingIdx == -1:
# New module - create node and process it
let newNode = Node(files: @[pair], id: c.nodes.len)
current.deps.add newNode.id
# Every module depends on system.nim
if c.systemNodeId >= 0:
newNode.deps.add c.systemNodeId
c.processedModules[pair.modname] = newNode.id
c.nodes.add newNode
traverseDeps(c, pair, newNode)
else:
# Already processed - just add dependency
if existingIdx notin current.deps:
current.deps.add existingIdx
proc readDepsFile(c: var DepContext; pair: FilePair; current: Node) =
## Read a .deps.nif file and process imports/includes
let depsPath = c.depsFile(pair)
if not fileExists(depsPath):
return
var s = nifstreams.open(depsPath)
defer: nifstreams.close(s)
discard processDirectives(s.r)
var t = next(s)
if t.kind != ParLe:
return
# Skip to content (past stmts tag)
t = next(s)
while t.kind != EofToken:
if t.kind == ParLe:
let tag = pool.tags[t.tagId]
case tag
of "import", "fromimport":
# Read import path
t = next(s)
# Check for "when" marker (conditional import)
if t.kind == Ident and pool.strings[t.litId] == "when":
t = next(s) # skip it, still process the import
# Handle path expression (could be ident, string, or infix like std/foo)
var importPath = ""
if t.kind == Ident:
importPath = pool.strings[t.litId]
elif t.kind == StringLit:
importPath = pool.strings[t.litId]
elif t.kind == ParLe and pool.tags[t.tagId] == "infix":
# Handle std / foo style imports
t = next(s) # skip infix tag
if t.kind == Ident: # operator (/)
t = next(s)
if t.kind == Ident: # first part (std)
importPath = pool.strings[t.litId]
t = next(s)
if t.kind == Ident: # second part (foo)
importPath = importPath & "/" & pool.strings[t.litId]
if importPath.len > 0:
processImport(c, importPath, current)
# Skip to end of import node
var depth = 1
while depth > 0:
t = next(s)
if t.kind == ParLe: inc depth
elif t.kind == ParRi: dec depth
of "include":
# Read include path
t = next(s)
if t.kind == Ident and pool.strings[t.litId] == "when":
t = next(s) # skip conditional marker
var includePath = ""
if t.kind == Ident:
includePath = pool.strings[t.litId]
elif t.kind == StringLit:
includePath = pool.strings[t.litId]
if includePath.len > 0:
processInclude(c, includePath, current)
# Skip to end
var depth = 1
while depth > 0:
t = next(s)
if t.kind == ParLe: inc depth
elif t.kind == ParRi: dec depth
else:
# Skip unknown node
var depth = 1
while depth > 0:
t = next(s)
if t.kind == ParLe: inc depth
elif t.kind == ParRi: dec depth
t = next(s)
proc traverseDeps(c: var DepContext; pair: FilePair; current: Node) =
## Process a module: run nifler and read deps
if not runNifler(c, pair.nimFile):
rawMessage(c.config, errGenerated, "nifler failed for: " & pair.nimFile)
return
readDepsFile(c, pair, current)
proc generateBuildFile(c: DepContext): string =
## Generate the .build.nif file for nifmake
let nimcache = getNimcacheDir(c.config).string
createDir(nimcache)
result = nimcache / c.nodes[0].files[0].modname & ".build.nif"
var b = nifbuilder.open(result)
defer: b.close()
b.addHeader("nim ic", "nifmake")
b.addTree "stmts"
# Define nifler command
b.addTree "cmd"
b.addSymbolDef "nifler"
b.addStrLit c.nifler
b.addStrLit "parse"
b.addStrLit "--deps"
b.addTree "input"
b.endTree()
b.addTree "output"
b.endTree()
b.endTree()
# Define nim m command
b.addTree "cmd"
b.addSymbolDef "nim_m"
b.addStrLit getAppFilename()
b.addStrLit "m"
b.addStrLit "--nimcache:" & nimcache
# Add search paths
for p in c.config.searchPaths:
b.addStrLit "--path:" & p.string
b.addTree "args"
b.endTree()
b.withTree "input":
b.addIntLit 0 # main parsed file
b.endTree()
# Define nim nifc command
b.addTree "cmd"
b.addSymbolDef "nim_nifc"
b.addStrLit getAppFilename()
b.addStrLit "nifc"
b.addStrLit "--nimcache:" & nimcache
# Add search paths
for p in c.config.searchPaths:
b.addStrLit "--path:" & p.string
b.addTree "input"
b.addIntLit 0
b.endTree()
b.endTree()
# Build rules for parsing (nifler)
var seenFiles = initHashSet[string]()
for node in c.nodes:
for pair in node.files:
let parsed = c.parsedFile(pair)
if not seenFiles.containsOrIncl(parsed):
b.addTree "do"
b.addIdent "nifler"
b.addTree "input"
b.addStrLit pair.nimFile
b.endTree()
b.addTree "output"
b.addStrLit parsed
b.endTree()
b.addTree "output"
b.addStrLit c.depsFile(pair)
b.endTree()
b.endTree()
# Build rules for semantic checking (nim m)
for i in countdown(c.nodes.len - 1, 0):
let node = c.nodes[i]
let pair = node.files[0]
b.addTree "do"
b.addIdent "nim_m"
# Input: all parsed files for this module
b.withTree "input":
b.addStrLit node.files[0].nimFile
for f in node.files:
b.addTree "input"
b.addStrLit c.parsedFile(f)
b.endTree()
# Also depend on semmed files of dependencies
for depIdx in node.deps:
b.addTree "input"
b.addStrLit c.semmedFile(c.nodes[depIdx].files[0])
b.endTree()
# Output: semmed file
b.addTree "output"
b.addStrLit c.semmedFile(pair)
b.endTree()
b.endTree()
# Final compilation step: generate executable from main module
let mainNif = c.nodes[0].files[0].nimFile
let exeFile = changeFileExt(c.nodes[0].files[0].nimFile, ExeExt)
b.addTree "do"
b.addIdent "nim_nifc"
# Input: .nim file (expanded as argument) and .nif file (dependency)
b.addTree "input"
b.addStrLit mainNif
b.endTree()
b.addTree "output"
b.addStrLit exeFile
b.endTree()
b.endTree()
b.endTree() # stmts
proc commandIc*(conf: ConfigRef) =
## Main entry point for `nim ic`
when not defined(nimKochBootstrap):
let nifler = findNifler()
if nifler.len == 0:
rawMessage(conf, errGenerated, "nifler tool not found. Install nimony or add nifler to PATH.")
return
let projectFile = conf.projectFull.string
if not fileExists(projectFile):
rawMessage(conf, errGenerated, "project file not found: " & projectFile)
return
# Create nimcache directory
createDir(getNimcacheDir(conf).string)
var c = DepContext(
config: conf,
nifler: nifler,
nodes: @[],
processedModules: initTable[string, int](),
includeStack: @[],
systemNodeId: -1
)
# Create root node for main project file
let rootPair = c.toPair(projectFile)
let rootNode = Node(files: @[rootPair], id: 0)
c.nodes.add rootNode
c.processedModules[rootPair.modname] = 0
# model the system.nim dependency:
let sysNode = Node(files: @[toPair(c, (conf.libpath / RelativeFile"system.nim").string)], id: 1)
c.nodes.add sysNode
c.systemNodeId = sysNode.id
rootNode.deps.add sysNode.id
# Process dependencies
traverseDeps(c, rootPair, rootNode)
# Generate build file
let buildFile = generateBuildFile(c)
rawMessage(conf, hintSuccess, "generated: " & buildFile)
# Automatically run nifmake
let nifmake = findNifmake()
if nifmake.len == 0:
rawMessage(conf, hintSuccess, "run: nifmake run " & buildFile)
else:
let cmd = quoteShell(nifmake) & " run " & quoteShell(buildFile)
rawMessage(conf, hintExecuting, cmd)
let exitCode = execShellCmd(cmd)
if exitCode != 0:
rawMessage(conf, errGenerated, "nifmake failed with exit code: " & $exitCode)
else:
rawMessage(conf, errGenerated, "nim ic not available in bootstrap build")

View File

@@ -483,7 +483,7 @@ proc constructCfg*(s: PSym; body: PNode; root: PSym): ControlFlowGraph =
gen(c, body)
if root.kind == skResult:
genImplicitReturn(c)
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc) or defined(gcYrc):
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
result = c.code # will move
else:
shallowCopy(result, c.code)

View File

@@ -19,7 +19,7 @@ import
wordrecg, syntaxes, renderer, lexer,
packages/docutils/[rst, rstidx, rstgen, dochelpers],
trees, types,
typesrenderer, lineinfos,
typesrenderer, astalgo, lineinfos,
pathutils, nimpaths, renderverbatim, packages
import packages/docutils/rstast except FileIndex, TLineInfo
@@ -433,9 +433,6 @@ proc getVarIdx(varnames: openArray[string], id: string): int =
proc genComment(d: PDoc, n: PNode): PRstNode =
if n.comment.len > 0:
if optDocRaw in d.conf.globalOptions:
return newRstLeaf(n.comment)
d.sharedState.currFileIdx = addRstFileIndex(d, n.info)
try:
result = parseRst(n.comment,
@@ -1179,12 +1176,8 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind, nonExports = false):
"col": %n.info.col}
)
if comm != nil:
if optDocRaw in d.conf.globalOptions:
result.json["description"] = %comm.text
else:
result.rst = comm
result.rstField = "description"
result.rst = comm
result.rstField = "description"
if r.buf.len > 0:
result.json["code"] = %r.buf
if k in routineKinds:
@@ -1327,7 +1320,7 @@ proc documentEffect(cache: IdentCache; n, x: PNode, effectType: TSpecialWord, id
if t.startsWith("ref "): t = substr(t, 4)
effects[i] = newIdentNode(getIdent(cache, t), n.info)
# set the type so that the following analysis doesn't screw up:
effects[i].typ = real[i].typ
effects[i].typ() = real[i].typ
result = newTreeI(nkExprColonExpr, n.info,
newIdentNode(getIdent(cache, $effectType), n.info), effects)
@@ -1425,7 +1418,7 @@ proc generateDoc*(d: PDoc, n, orig: PNode, config: ConfigRef, docFlags: DocFlags
of nkExportExceptStmt: discard "transformed into nkExportStmt by semExportExcept"
of nkFromStmt, nkImportExceptStmt: traceDeps(d, n[0])
of nkCallKinds:
var comm = default(ItemPre)
var comm: ItemPre = default(ItemPre)
getAllRunnableExamples(d, n, comm)
if comm.len != 0: d.modDescPre.add(comm)
else: discard

View File

@@ -47,7 +47,8 @@ proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph; idgen: IdGener
n[bodyPos] = body
n[resultPos] = newSymNode(res)
result.ast = n
incl result.flagsImpl, {sfFromGeneric, sfNeverRaises}
incl result.flags, sfFromGeneric
incl result.flags, sfNeverRaises
proc searchObjCaseImpl(obj: PNode; field: PSym): PNode =
case obj.kind
@@ -109,4 +110,5 @@ proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGra
n[bodyPos] = body
n[resultPos] = newSymNode(res)
result.ast = n
incl result.flagsImpl, {sfFromGeneric, sfNeverRaises}
incl result.flags, sfFromGeneric
incl result.flags, sfNeverRaises

View File

@@ -275,7 +275,7 @@ proc unpackObject(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
# the nkPar node:
if n.isNil:
result = newNode(nkTupleConstr)
result.typ = typ
result.typ() = typ
if typ.n.isNil:
internalError(conf, "cannot unpack unnamed tuple")
unpackObjectAdd(conf, x, typ.n, result)
@@ -298,7 +298,7 @@ proc unpackObject(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
proc unpackArray(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
if n.isNil:
result = newNode(nkBracket)
result.typ = typ
result.typ() = typ
newSeq(result.sons, lengthOrd(conf, typ).toInt)
else:
result = n
@@ -319,7 +319,7 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
template aw(k, v, field: untyped): untyped =
if n.isNil:
result = newNode(k)
result.typ = typ
result.typ() = typ
else:
# check we have the right field:
result = n
@@ -333,12 +333,12 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
template setNil() =
if n.isNil:
result = newNode(nkNilLit)
result.typ = typ
result.typ() = typ
else:
reset n[]
result = n
result[] = TNode(kind: nkNilLit)
result.typ = typ
result.typ() = typ
template awi(kind, v: untyped): untyped = aw(kind, v, intVal)
template awf(kind, v: untyped): untyped = aw(kind, v, floatVal)
@@ -427,7 +427,7 @@ proc fficast*(conf: ConfigRef, x: PNode, destTyp: PType): PNode =
# cast through a pointer needs a new inner object:
let y = if x.kind == nkRefTy: newNodeI(nkRefTy, x.info, 1)
else: x.copyTree
y.typ = x.typ
y.typ() = x.typ
result = unpack(conf, a, destTyp, y)
dealloc a
@@ -481,7 +481,7 @@ proc callForeignFunction*(conf: ConfigRef, fn: PNode, fntyp: PType,
if aTyp.isNil:
internalAssert conf, i+1 < fntyp.len
aTyp = fntyp[i+1]
args[i+start].typ = aTyp
args[i+start].typ() = aTyp
sig[i] = mapType(conf, aTyp)
if sig[i].isNil: globalError(conf, info, "cannot map FFI type")

View File

@@ -182,7 +182,7 @@ proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode =
d.add newSymNode(sym, info)
result.add d
result.add res
result.typ = res.typ
result.typ() = res.typ
proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
conf: ConfigRef;

View File

@@ -1104,7 +1104,7 @@ proc settype(n: PNode): PType =
proc buildOf(it, loc: PNode; o: Operators): PNode =
var s = newNodeI(nkCurly, it.info, it.len-1)
s.typ = settype(loc)
s.typ() = settype(loc)
for i in 0..<it.len-1: s[i] = it[i]
result = newNodeI(nkCall, it.info, 3)
result[0] = newSymNode(o.opContains)
@@ -1170,7 +1170,7 @@ proc buildProperFieldCheck(access, check: PNode; o: Operators): PNode =
# set field name to discriminator field name
a[1] = check[2]
# set discriminator field type: important for `neg`
a.typ = check[2].typ
a.typ() = check[2].typ
result[2] = a
# 'access.kind != nkDotExpr' can happen for object constructors
# which we don't check yet

View File

@@ -10,7 +10,7 @@
# This include implements the high level optimization pass.
# included from sem.nim
proc hlo(c: PContext, n: PNode, loopDetector: int): PNode
proc hlo(c: PContext, n: PNode): PNode
proc evalPattern(c: PContext, n, orig: PNode): PNode =
internalAssert c.config, n.kind == nkCall and n[0].kind == nkSym
@@ -61,11 +61,10 @@ proc applyPatterns(c: PContext, n: PNode): PNode =
# activate this pattern again:
c.patterns[i] = pattern
proc hlo(c: PContext, n: PNode, loopDetector: int): PNode =
proc hlo(c: PContext, n: PNode): PNode =
inc(c.hloLoopDetector)
# simply stop and do not perform any further transformations:
if loopDetector > 300:
message(c.config, n.info, warnUser, "term rewrite macro instantiation too nested")
return n
if c.hloLoopDetector > 300: return n
case n.kind
of nkMacroDef, nkTemplateDef, procDefs:
# already processed (special cases in semstmts.nim)
@@ -81,7 +80,7 @@ proc hlo(c: PContext, n: PNode, loopDetector: int): PNode =
# no optimization applied, try subtrees:
for i in 0..<result.safeLen:
let a = result[i]
let h = hlo(c, a, loopDetector)
let h = hlo(c, a)
if h != a: result[i] = h
else:
# perform type checking, so that the replacement still fits:
@@ -91,15 +90,17 @@ proc hlo(c: PContext, n: PNode, loopDetector: int): PNode =
result = fitNode(c, n.typ, result, n.info)
# optimization has been applied so check again:
result = commonOptimizations(c.graph, c.idgen, c.module, result)
result = hlo(c, result, loopDetector + 1)
result = hlo(c, result)
result = commonOptimizations(c.graph, c.idgen, c.module, result)
proc hloBody(c: PContext, n: PNode): PNode =
# fast exit:
if c.patterns.len == 0 or optTrMacros notin c.config.options: return n
result = hlo(c, n, 0)
c.hloLoopDetector = 0
result = hlo(c, n)
proc hloStmt(c: PContext, n: PNode): PNode =
# fast exit:
if c.patterns.len == 0 or optTrMacros notin c.config.options: return n
result = hlo(c, n, 0)
c.hloLoopDetector = 0
result = hlo(c, n)

178
compiler/ic/bitabs.nim Normal file
View File

@@ -0,0 +1,178 @@
## A BiTable is a table that can be seen as an optimized pair
## of `(Table[LitId, Val], Table[Val, LitId])`.
import std/hashes
import rodfiles
when defined(nimPreviewSlimSystem):
import std/assertions
type
LitId* = distinct uint32
BiTable*[T] = object
vals: seq[T] # indexed by LitId
keys: seq[LitId] # indexed by hash(val)
proc initBiTable*[T](): BiTable[T] = BiTable[T](vals: @[], keys: @[])
proc nextTry(h, maxHash: Hash): Hash {.inline.} =
result = (h + 1) and maxHash
template maxHash(t): untyped = high(t.keys)
template isFilled(x: LitId): bool = x.uint32 > 0'u32
proc `$`*(x: LitId): string {.borrow.}
proc `<`*(x, y: LitId): bool {.borrow.}
proc `<=`*(x, y: LitId): bool {.borrow.}
proc `==`*(x, y: LitId): bool {.borrow.}
proc hash*(x: LitId): Hash {.borrow.}
proc len*[T](t: BiTable[T]): int = t.vals.len
proc mustRehash(length, counter: int): bool {.inline.} =
assert(length > counter)
result = (length * 2 < counter * 3) or (length - counter < 4)
const
idStart = 1
template idToIdx(x: LitId): int = x.int - idStart
proc hasLitId*[T](t: BiTable[T]; x: LitId): bool =
let idx = idToIdx(x)
result = idx >= 0 and idx < t.vals.len
proc enlarge[T](t: var BiTable[T]) =
var n: seq[LitId]
newSeq(n, len(t.keys) * 2)
swap(t.keys, n)
for i in 0..high(n):
let eh = n[i]
if isFilled(eh):
var j = hash(t.vals[idToIdx eh]) and maxHash(t)
while isFilled(t.keys[j]):
j = nextTry(j, maxHash(t))
t.keys[j] = move n[i]
proc getKeyId*[T](t: BiTable[T]; v: T): LitId =
let origH = hash(v)
var h = origH and maxHash(t)
if t.keys.len != 0:
while true:
let litId = t.keys[h]
if not isFilled(litId): break
if t.vals[idToIdx t.keys[h]] == v: return litId
h = nextTry(h, maxHash(t))
return LitId(0)
proc getOrIncl*[T](t: var BiTable[T]; v: T): LitId =
let origH = hash(v)
var h = origH and maxHash(t)
if t.keys.len != 0:
while true:
let litId = t.keys[h]
if not isFilled(litId): break
if t.vals[idToIdx t.keys[h]] == v: return litId
h = nextTry(h, maxHash(t))
# not found, we need to insert it:
if mustRehash(t.keys.len, t.vals.len):
enlarge(t)
# recompute where to insert:
h = origH and maxHash(t)
while true:
let litId = t.keys[h]
if not isFilled(litId): break
h = nextTry(h, maxHash(t))
else:
setLen(t.keys, 16)
h = origH and maxHash(t)
result = LitId(t.vals.len + idStart)
t.keys[h] = result
t.vals.add v
proc `[]`*[T](t: var BiTable[T]; litId: LitId): var T {.inline.} =
let idx = idToIdx litId
assert idx < t.vals.len
result = t.vals[idx]
proc `[]`*[T](t: BiTable[T]; litId: LitId): lent T {.inline.} =
let idx = idToIdx litId
assert idx < t.vals.len
result = t.vals[idx]
proc hash*[T](t: BiTable[T]): Hash =
## as the keys are hashes of the values, we simply use them instead
var h: Hash = 0
for i, n in pairs t.keys:
h = h !& hash((i, n))
result = !$h
proc store*[T](f: var RodFile; t: BiTable[T]) =
storeSeq(f, t.vals)
storeSeq(f, t.keys)
proc load*[T](f: var RodFile; t: var BiTable[T]) =
loadSeq(f, t.vals)
loadSeq(f, t.keys)
proc sizeOnDisc*(t: BiTable[string]): int =
result = 4
for x in t.vals:
result += x.len + 4
result += t.keys.len * sizeof(LitId)
when isMainModule:
var t: BiTable[string]
echo getOrIncl(t, "hello")
echo getOrIncl(t, "hello")
echo getOrIncl(t, "hello3")
echo getOrIncl(t, "hello4")
echo getOrIncl(t, "helloasfasdfdsa")
echo getOrIncl(t, "hello")
echo getKeyId(t, "hello")
echo getKeyId(t, "none")
for i in 0 ..< 100_000:
discard t.getOrIncl($i & "___" & $i)
for i in 0 ..< 100_000:
assert t.getOrIncl($i & "___" & $i).idToIdx == i + 4
echo "begin"
echo t.vals.len
echo t.vals[0]
echo t.vals[1004]
echo "middle"
var tf: BiTable[float]
discard tf.getOrIncl(0.4)
discard tf.getOrIncl(16.4)
discard tf.getOrIncl(32.4)
echo getKeyId(tf, 32.4)
var f2 = open("testblah.bin", fmWrite)
echo store(f2, tf)
f2.close
var f1 = open("testblah.bin", fmRead)
var t2: BiTable[float]
echo f1.load(t2)
echo t2.vals.len
echo getKeyId(t2, 32.4)
echo "end"
f1.close

180
compiler/ic/cbackend.nim Normal file
View File

@@ -0,0 +1,180 @@
#
#
# The Nim Compiler
# (c) Copyright 2021 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## New entry point into our C/C++ code generator. Ideally
## somebody would rewrite the old backend (which is 8000 lines of crufty Nim code)
## to work on packed trees directly and produce the C code as an AST which can
## then be rendered to text in a very simple manner. Unfortunately nobody wrote
## this code. So instead we wrap the existing cgen.nim and its friends so that
## we call directly into the existing code generation logic but avoiding the
## naive, outdated `passes` design. Thus you will see some
## `useAliveDataFromDce in flags` checks in the old code -- the old code is
## also doing cross-module dependency tracking and DCE that we don't need
## anymore. DCE is now done as prepass over the entire packed module graph.
import std/[packedsets, algorithm, tables]
when defined(nimPreviewSlimSystem):
import std/assertions
import ".."/[ast, options, lineinfos, modulegraphs, cgendata, cgen,
pathutils, extccomp, msgs, modulepaths]
import packed_ast, ic, dce, rodfiles
proc unpackTree(g: ModuleGraph; thisModule: int;
tree: PackedTree; n: NodePos): PNode =
var decoder = initPackedDecoder(g.config, g.cache)
result = loadNodes(decoder, g.packed, thisModule, tree, n)
proc setupBackendModule(g: ModuleGraph; m: var LoadedModule) =
if g.backend == nil:
g.backend = cgendata.newModuleList(g)
assert g.backend != nil
var bmod = cgen.newModule(BModuleList(g.backend), m.module, g.config)
bmod.idgen = idgenFromLoadedModule(m)
proc generateCodeForModule(g: ModuleGraph; m: var LoadedModule; alive: var AliveSyms) =
var bmod = BModuleList(g.backend).modules[m.module.position]
assert bmod != nil
bmod.flags.incl useAliveDataFromDce
bmod.alive = move alive[m.module.position]
for p in allNodes(m.fromDisk.topLevel):
let n = unpackTree(g, m.module.position, m.fromDisk.topLevel, p)
cgen.genTopLevelStmt(bmod, n)
finalCodegenActions(g, bmod, newNodeI(nkStmtList, m.module.info))
for disp in getDispatchers(g):
genProcAux(bmod, disp)
m.fromDisk.backendFlags = cgen.whichInitProcs(bmod)
proc replayTypeInfo(g: ModuleGraph; m: var LoadedModule; origin: FileIndex) =
for x in mitems(m.fromDisk.emittedTypeInfo):
#echo "found type ", x, " for file ", int(origin)
g.emittedTypeInfo[x] = origin
proc addFileToLink(config: ConfigRef; m: PSym) =
let filename = AbsoluteFile toFullPath(config, m.position.FileIndex)
let ext =
if config.backend == backendCpp: ".nim.cpp"
elif config.backend == backendObjc: ".nim.m"
else: ".nim.c"
let cfile = changeFileExt(completeCfilePath(config,
mangleModuleName(config, filename).AbsoluteFile), ext)
let objFile = completeCfilePath(config, toObjFile(config, cfile))
if fileExists(objFile):
var cf = Cfile(nimname: m.name.s, cname: cfile,
obj: objFile,
flags: {CfileFlag.Cached})
addFileToCompile(config, cf)
when defined(debugDce):
import os, std/packedsets
proc storeAliveSymsImpl(asymFile: AbsoluteFile; s: seq[int32]) =
var f = rodfiles.create(asymFile.string)
f.storeHeader()
f.storeSection aliveSymsSection
f.storeSeq(s)
close f
template prepare {.dirty.} =
let asymFile = toRodFile(config, AbsoluteFile toFullPath(config, position.FileIndex), ".alivesyms")
var s = newSeqOfCap[int32](alive[position].len)
for a in items(alive[position]): s.add int32(a)
sort(s)
proc storeAliveSyms(config: ConfigRef; position: int; alive: AliveSyms) =
prepare()
storeAliveSymsImpl(asymFile, s)
proc aliveSymsChanged(config: ConfigRef; position: int; alive: AliveSyms): bool =
prepare()
var f2 = rodfiles.open(asymFile.string)
f2.loadHeader()
f2.loadSection aliveSymsSection
var oldData: seq[int32] = @[]
f2.loadSeq(oldData)
f2.close
if f2.err == ok and oldData == s:
result = false
else:
when defined(debugDce):
let oldAsSet = toPackedSet[int32](oldData)
let newAsSet = toPackedSet[int32](s)
echo "set of live symbols changed ", asymFile.changeFileExt("rod"), " ", position, " ", f2.err
echo "in old but not in new ", oldAsSet.difference(newAsSet), " number of entries in old ", oldAsSet.len
echo "in new but not in old ", newAsSet.difference(oldAsSet), " number of entries in new ", newAsSet.len
#if execShellCmd(getAppFilename() & " rod " & quoteShell(asymFile.changeFileExt("rod"))) != 0:
# echo "command failed"
result = true
storeAliveSymsImpl(asymFile, s)
proc genPackedModule(g: ModuleGraph, i: int; alive: var AliveSyms) =
# case statement here to enforce exhaustive checks.
case g.packed[i].status
of undefined:
discard "nothing to do"
of loading, stored:
assert false
of storing, outdated:
storeAliveSyms(g.config, g.packed[i].module.position, alive)
generateCodeForModule(g, g.packed[i], alive)
closeRodFile(g, g.packed[i].module)
of loaded:
if g.packed[i].loadedButAliveSetChanged:
generateCodeForModule(g, g.packed[i], alive)
else:
addFileToLink(g.config, g.packed[i].module)
replayTypeInfo(g, g.packed[i], FileIndex(i))
if g.backend == nil:
g.backend = cgendata.newModuleList(g)
registerInitProcs(BModuleList(g.backend), g.packed[i].module, g.packed[i].fromDisk.backendFlags)
proc generateCode*(g: ModuleGraph) =
## The single entry point, generate C(++) code for the entire
## Nim program aka `ModuleGraph`.
resetForBackend(g)
var alive = computeAliveSyms(g.packed, g.config)
when false:
for i in 0..<len(g.packed):
echo i, " is of status ", g.packed[i].status, " ", toFullPath(g.config, FileIndex(i))
# First pass: Setup all the backend modules for all the modules that have
# changed:
for i in 0..<len(g.packed):
# case statement here to enforce exhaustive checks.
case g.packed[i].status
of undefined:
discard "nothing to do"
of loading, stored:
assert false
of storing, outdated:
setupBackendModule(g, g.packed[i])
of loaded:
# Even though this module didn't change, DCE might trigger a change.
# Consider this case: Module A uses symbol S from B and B does not use
# S itself. A is then edited not to use S either. Thus we have to
# recompile B in order to remove S from the final result.
if aliveSymsChanged(g.config, g.packed[i].module.position, alive):
g.packed[i].loadedButAliveSetChanged = true
setupBackendModule(g, g.packed[i])
# Second pass: Code generation.
let mainModuleIdx = g.config.projectMainIdx2.int
# We need to generate the main module last, because only then
# all init procs have been registered:
for i in 0..<len(g.packed):
if i != mainModuleIdx:
genPackedModule(g, i, alive)
if mainModuleIdx >= 0:
genPackedModule(g, mainModuleIdx, alive)

169
compiler/ic/dce.nim Normal file
View File

@@ -0,0 +1,169 @@
#
#
# The Nim Compiler
# (c) Copyright 2021 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Dead code elimination (=DCE) for IC.
import std/[intsets, tables]
when defined(nimPreviewSlimSystem):
import std/assertions
import ".." / [ast, options, lineinfos, types]
import packed_ast, ic, bitabs
type
AliveSyms* = seq[IntSet]
AliveContext* = object ## Purpose is to fill the 'alive' field.
stack: seq[(int, TOptions, NodePos)] ## A stack for marking symbols as alive.
decoder: PackedDecoder ## We need a PackedDecoder for module ID address translations.
thisModule: int ## The module we're currently analysing for DCE.
alive: AliveSyms ## The final result of our computation.
options: TOptions
compilerProcs: Table[string, (int, int32)]
proc isExportedToC(c: var AliveContext; g: PackedModuleGraph; symId: int32): bool =
## "Exported to C" procs are special (these are marked with '.exportc') because these
## must not be optimized away!
let symPtr = unsafeAddr g[c.thisModule].fromDisk.syms[symId]
let flags = symPtr.flags
# due to a bug/limitation in the lambda lifting, unused inner procs
# are not transformed correctly; issue (#411). However, the whole purpose here
# is to eliminate unused procs. So there is no special logic required for this case.
if sfCompileTime notin flags:
if ({sfExportc, sfCompilerProc} * flags != {}) or
(symPtr.kind == skMethod):
result = true
else:
result = false
# XXX: This used to be a condition to:
# (sfExportc in prc.flags and lfExportLib in prc.loc.flags) or
if sfCompilerProc in flags:
c.compilerProcs[g[c.thisModule].fromDisk.strings[symPtr.name]] = (c.thisModule, symId)
else:
result = false
template isNotGeneric(n: NodePos): bool = ithSon(tree, n, genericParamsPos).kind == nkEmpty
proc followLater(c: var AliveContext; g: PackedModuleGraph; module: int; item: int32) =
## Marks a symbol 'item' as used and later in 'followNow' the symbol's body will
## be analysed.
if not c.alive[module].containsOrIncl(item):
var body = g[module].fromDisk.syms[item].ast
if body != emptyNodeId:
let opt = g[module].fromDisk.syms[item].options
if g[module].fromDisk.syms[item].kind in routineKinds:
body = NodeId ithSon(g[module].fromDisk.bodies, NodePos body, bodyPos)
c.stack.add((module, opt, NodePos(body)))
when false:
let nid = g[module].fromDisk.syms[item].name
if nid != LitId(0):
let name = g[module].fromDisk.strings[nid]
if name in ["nimFrame", "callDepthLimitReached"]:
echo "I was called! ", name, " body exists: ", body != emptyNodeId, " ", module, " ", item
proc requestCompilerProc(c: var AliveContext; g: PackedModuleGraph; name: string) =
let (module, item) = c.compilerProcs[name]
followLater(c, g, module, item)
proc loadTypeKind(t: PackedItemId; c: AliveContext; g: PackedModuleGraph; toSkip: set[TTypeKind]): TTypeKind =
template kind(t: ItemId): TTypeKind = g[t.module].fromDisk.types[t.item].kind
var t2 = translateId(t, g, c.thisModule, c.decoder.config)
result = t2.kind
while result in toSkip:
t2 = translateId(g[t2.module].fromDisk.types[t2.item].types[^1], g, t2.module, c.decoder.config)
result = t2.kind
proc rangeCheckAnalysis(c: var AliveContext; g: PackedModuleGraph; tree: PackedTree; n: NodePos) =
## Replicates the logic of `ccgexprs.genRangeChck`.
## XXX Refactor so that the duplicated logic is avoided. However, for now it's not clear
## the approach has enough merit.
var dest = loadTypeKind(n.typ, c, g, abstractVar)
if optRangeCheck notin c.options or dest in {tyUInt..tyUInt64}:
discard "no need to generate a check because it was disabled"
else:
let n0t = loadTypeKind(n.firstSon.typ, c, g, {})
if n0t in {tyUInt, tyUInt64}:
c.requestCompilerProc(g, "raiseRangeErrorNoArgs")
else:
let raiser =
case loadTypeKind(n.typ, c, g, abstractVarRange)
of tyUInt..tyUInt64, tyChar: "raiseRangeErrorU"
of tyFloat..tyFloat128: "raiseRangeErrorF"
else: "raiseRangeErrorI"
c.requestCompilerProc(g, raiser)
proc aliveCode(c: var AliveContext; g: PackedModuleGraph; tree: PackedTree; n: NodePos) =
## Marks the symbols we encounter when we traverse the AST at `tree[n]` as alive, unless
## it is purely in a declarative context (type section etc.).
case n.kind
of nkNone..pred(nkSym), succ(nkSym)..nkNilLit:
discard "ignore non-sym atoms"
of nkSym:
# This symbol is alive and everything its body references.
followLater(c, g, c.thisModule, tree[n].soperand)
of nkModuleRef:
let (n1, n2) = sons2(tree, n)
assert n1.kind == nkNone
assert n2.kind == nkNone
let m = n1.litId
let item = tree[n2].soperand
let otherModule = toFileIndexCached(c.decoder, g, c.thisModule, m).int
followLater(c, g, otherModule, item)
of nkMacroDef, nkTemplateDef, nkTypeSection, nkTypeOfExpr,
nkCommentStmt, nkIncludeStmt,
nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
nkFromStmt, nkStaticStmt:
discard
of nkVarSection, nkLetSection, nkConstSection:
# XXX ignore the defining local variable name?
for son in sonsReadonly(tree, n):
aliveCode(c, g, tree, son)
of nkChckRangeF, nkChckRange64, nkChckRange:
rangeCheckAnalysis(c, g, tree, n)
of nkProcDef, nkConverterDef, nkMethodDef, nkFuncDef, nkIteratorDef:
if n.firstSon.kind == nkSym and isNotGeneric(n):
let item = tree[n.firstSon].soperand
if isExportedToC(c, g, item):
# This symbol is alive and everything its body references.
followLater(c, g, c.thisModule, item)
else:
for son in sonsReadonly(tree, n):
aliveCode(c, g, tree, son)
proc followNow(c: var AliveContext; g: PackedModuleGraph) =
## Mark all entries in the stack. Marking can add more entries
## to the stack but eventually we have looked at every alive symbol.
while c.stack.len > 0:
let (modId, opt, ast) = c.stack.pop()
c.thisModule = modId
c.options = opt
aliveCode(c, g, g[modId].fromDisk.bodies, ast)
proc computeAliveSyms*(g: PackedModuleGraph; conf: ConfigRef): AliveSyms =
## Entry point for our DCE algorithm.
var c = AliveContext(stack: @[], decoder: PackedDecoder(config: conf),
thisModule: -1, alive: newSeq[IntSet](g.len),
options: conf.options)
for i in countdown(len(g)-1, 0):
if g[i].status != undefined:
c.thisModule = i
for p in allNodes(g[i].fromDisk.topLevel):
aliveCode(c, g, g[i].fromDisk.topLevel, p)
followNow(c, g)
result = move(c.alive)
proc isAlive*(a: AliveSyms; module: int, item: int32): bool =
## Backends use this to query if a symbol is `alive` which means
## we need to produce (C/C++/etc) code for it.
result = a[module].contains(item)

56
compiler/ic/design.rst Normal file
View File

@@ -0,0 +1,56 @@
====================================
Incremental Recompilations
====================================
We split the Nim compiler into a frontend and a backend.
The frontend produces a set of `.rod` files. Every `.nim` module
produces its own `.rod` file.
- The IR must be a faithful representation of the AST in memory.
- The backend can do its own caching but doesn't have to. In the
current implementation the backend also caches its results.
Advantage of the "set of files" vs the previous global database:
- By construction, we either read from the `.rod` file or from the
`.nim` file, there can be no inconsistency. There can also be no
partial updates.
- No dependency to external packages (SQLite). SQLite simply is too
slow and the old way of serialization was too slow too. We use a
format designed for Nim and expect to base further tools on this
file format.
References to external modules must be (moduleId, symId) pairs.
The symbol IDs are module specific. This way no global ID increment
mechanism needs to be implemented that we could get wrong. ModuleIds
are rod-file specific too.
Global state
------------
There is no global state.
Rod File Format
---------------
It's a simple binary file format. `rodfiles.nim` contains some details.
Backend
-------
Nim programmers have to come to enjoy whole-program dead code elimination,
by default. Since this is a "whole program" optimization, it does break
modularity. However, thanks to the packed AST representation we can perform
this global analysis without having to unpack anything. This is basically
a mark&sweep GC algorithm:
- Start with the top level statements. Every symbol that is referenced
from a top level statement is not "dead" and needs to be compiled by
the backend.
- Every symbol referenced from a referenced symbol also has to be
compiled.
Caching logic: Only if the set of alive symbols is different from the
last run, the module has to be regenerated.

File diff suppressed because it is too large Load Diff

1343
compiler/ic/ic.nim Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,84 @@
#
#
# The Nim Compiler
# (c) Copyright 2024 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# For the line information we use 32 bits. They are used as follows:
# Bit 0 (AsideBit): If we have inline line information or not. If not, the
# remaining 31 bits are used as an index into a seq[(LitId, int, int)].
#
# We use 10 bits for the "file ID", this means a program can consist of as much
# as 1024 different files. (If it uses more files than that, the overflow bit
# would be set.)
# This means we have 21 bits left to encode the (line, col) pair. We use 7 bits for the column
# so 128 is the limit and 14 bits for the line number.
# The packed representation supports files with up to 16384 lines.
# Keep in mind that whenever any limit is reached the AsideBit is set and the real line
# information is kept in a side channel.
import std / assertions
const
AsideBit = 1
FileBits = 10
LineBits = 14
ColBits = 7
FileMax = (1 shl FileBits) - 1
LineMax = (1 shl LineBits) - 1
ColMax = (1 shl ColBits) - 1
static:
assert AsideBit + FileBits + LineBits + ColBits == 32
import .. / ic / [bitabs, rodfiles] # for LitId
type
PackedLineInfo* = distinct uint32
LineInfoManager* = object
aside: seq[(LitId, int32, int32)]
const
NoLineInfo* = PackedLineInfo(0'u32)
proc pack*(m: var LineInfoManager; file: LitId; line, col: int32): PackedLineInfo =
if file.uint32 <= FileMax.uint32 and line <= LineMax and col <= ColMax:
let col = if col < 0'i32: 0'u32 else: col.uint32
let line = if line < 0'i32: 0'u32 else: line.uint32
# use inline representation:
result = PackedLineInfo((file.uint32 shl 1'u32) or (line shl uint32(AsideBit + FileBits)) or
(col shl uint32(AsideBit + FileBits + LineBits)))
else:
result = PackedLineInfo((m.aside.len shl 1) or AsideBit)
m.aside.add (file, line, col)
proc unpack*(m: LineInfoManager; i: PackedLineInfo): (LitId, int32, int32) =
let i = i.uint32
if (i and 1'u32) == 0'u32:
# inline representation:
result = (LitId((i shr 1'u32) and FileMax.uint32),
int32((i shr uint32(AsideBit + FileBits)) and LineMax.uint32),
int32((i shr uint32(AsideBit + FileBits + LineBits)) and ColMax.uint32))
else:
result = m.aside[int(i shr 1'u32)]
proc getFileId*(m: LineInfoManager; i: PackedLineInfo): LitId =
result = unpack(m, i)[0]
proc store*(r: var RodFile; m: LineInfoManager) = storeSeq(r, m.aside)
proc load*(r: var RodFile; m: var LineInfoManager) = loadSeq(r, m.aside)
when isMainModule:
var m = LineInfoManager(aside: @[])
for i in 0'i32..<16388'i32:
for col in 0'i32..<100'i32:
let packed = pack(m, LitId(1023), i, col)
let u = unpack(m, packed)
assert u[0] == LitId(1023)
assert u[1] == i
assert u[2] == col
echo m.aside.len

155
compiler/ic/integrity.nim Normal file
View File

@@ -0,0 +1,155 @@
#
#
# The Nim Compiler
# (c) Copyright 2021 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Integrity checking for a set of .rod files.
## The set must cover a complete Nim project.
import std/[sets, tables]
when defined(nimPreviewSlimSystem):
import std/assertions
import ".." / [ast, modulegraphs]
import packed_ast, bitabs, ic
type
CheckedContext = object
g: ModuleGraph
thisModule: int32
checkedSyms: HashSet[ItemId]
checkedTypes: HashSet[ItemId]
proc checkType(c: var CheckedContext; typeId: PackedItemId)
proc checkForeignSym(c: var CheckedContext; symId: PackedItemId)
proc checkNode(c: var CheckedContext; tree: PackedTree; n: NodePos)
proc checkTypeObj(c: var CheckedContext; typ: PackedType) =
for child in typ.types:
checkType(c, child)
if typ.n != emptyNodeId:
checkNode(c, c.g.packed[c.thisModule].fromDisk.bodies, NodePos typ.n)
if typ.sym != nilItemId:
checkForeignSym(c, typ.sym)
if typ.owner != nilItemId:
checkForeignSym(c, typ.owner)
checkType(c, typ.typeInst)
proc checkType(c: var CheckedContext; typeId: PackedItemId) =
if typeId == nilItemId: return
let itemId = translateId(typeId, c.g.packed, c.thisModule, c.g.config)
if not c.checkedTypes.containsOrIncl(itemId):
let oldThisModule = c.thisModule
c.thisModule = itemId.module
checkTypeObj c, c.g.packed[itemId.module].fromDisk.types[itemId.item]
c.thisModule = oldThisModule
proc checkSym(c: var CheckedContext; s: PackedSym) =
if s.name != LitId(0):
assert c.g.packed[c.thisModule].fromDisk.strings.hasLitId s.name
checkType c, s.typ
if s.ast != emptyNodeId:
checkNode(c, c.g.packed[c.thisModule].fromDisk.bodies, NodePos s.ast)
if s.owner != nilItemId:
checkForeignSym(c, s.owner)
proc checkLocalSym(c: var CheckedContext; item: int32) =
let itemId = ItemId(module: c.thisModule, item: item)
if not c.checkedSyms.containsOrIncl(itemId):
checkSym c, c.g.packed[c.thisModule].fromDisk.syms[item]
proc checkForeignSym(c: var CheckedContext; symId: PackedItemId) =
let itemId = translateId(symId, c.g.packed, c.thisModule, c.g.config)
if not c.checkedSyms.containsOrIncl(itemId):
let oldThisModule = c.thisModule
c.thisModule = itemId.module
checkSym c, c.g.packed[itemId.module].fromDisk.syms[itemId.item]
c.thisModule = oldThisModule
proc checkNode(c: var CheckedContext; tree: PackedTree; n: NodePos) =
let t = findType(tree, n)
if t != nilItemId:
checkType(c, t)
case n.kind
of nkEmpty, nkNilLit, nkType, nkNilRodNode:
discard
of nkIdent:
assert c.g.packed[c.thisModule].fromDisk.strings.hasLitId n.litId
of nkSym:
checkLocalSym(c, tree[n].soperand)
of directIntLit:
discard
of externIntLit, nkFloatLit..nkFloat128Lit:
assert c.g.packed[c.thisModule].fromDisk.numbers.hasLitId n.litId
of nkStrLit..nkTripleStrLit:
assert c.g.packed[c.thisModule].fromDisk.strings.hasLitId n.litId
of nkModuleRef:
let (n1, n2) = sons2(tree, n)
assert n1.kind == nkNone
assert n2.kind == nkNone
checkForeignSym(c, PackedItemId(module: n1.litId, item: tree[n2].soperand))
else:
for n0 in sonsReadonly(tree, n):
checkNode(c, tree, n0)
proc checkTree(c: var CheckedContext; t: PackedTree) =
for p in allNodes(t): checkNode(c, t, p)
proc checkLocalSymIds(c: var CheckedContext; m: PackedModule; symIds: seq[int32]) =
for symId in symIds:
assert symId >= 0 and symId < m.syms.len, $symId & " " & $m.syms.len
proc checkModule(c: var CheckedContext; m: PackedModule) =
# We check that:
# - Every symbol references existing types and symbols.
# - Every tree node references existing types and symbols.
for _, v in pairs(m.syms):
checkLocalSym c, v.id
checkTree c, m.toReplay
checkTree c, m.topLevel
for e in m.exports:
#assert e[1] >= 0 and e[1] < m.syms.len
assert e[0] == m.syms[e[1]].name
for e in m.compilerProcs:
#assert e[1] >= 0 and e[1] < m.syms.len
assert e[0] == m.syms[e[1]].name
checkLocalSymIds c, m, m.converters
checkLocalSymIds c, m, m.methods
checkLocalSymIds c, m, m.trmacros
checkLocalSymIds c, m, m.pureEnums
#[
To do: Check all these fields:
reexports*: seq[(LitId, PackedItemId)]
macroUsages*: seq[(PackedItemId, PackedLineInfo)]
typeInstCache*: seq[(PackedItemId, PackedItemId)]
procInstCache*: seq[PackedInstantiation]
attachedOps*: seq[(TTypeAttachedOp, PackedItemId, PackedItemId)]
methodsPerGenericType*: seq[(PackedItemId, int, PackedItemId)]
enumToStringProcs*: seq[(PackedItemId, PackedItemId)]
methodsPerType*: seq[(PackedItemId, PackedItemId)]
dispatchers*: seq[PackedItemId]
]#
proc checkIntegrity*(g: ModuleGraph) =
var c = CheckedContext(g: g)
for i in 0..<len(g.packed):
# case statement here to enforce exhaustive checks.
case g.packed[i].status
of undefined:
discard "nothing to do"
of loading:
assert false, "cannot check integrity: Module still loading"
of stored, storing, outdated, loaded:
c.thisModule = int32 i
checkModule(c, g.packed[i].fromDisk)

183
compiler/ic/navigator.nim Normal file
View File

@@ -0,0 +1,183 @@
#
#
# The Nim Compiler
# (c) Copyright 2021 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Supports the "nim check --ic:on --defusages:FILE,LINE,COL"
## IDE-like features. It uses the set of .rod files to accomplish
## its task. The set must cover a complete Nim project.
import std/[sets, tables]
from std/os import nil
from std/private/miscdollars import toLocation
when defined(nimPreviewSlimSystem):
import std/assertions
import ".." / [ast, modulegraphs, msgs, options]
import iclineinfos
import packed_ast, bitabs, ic
type
UnpackedLineInfo = object
file: LitId
line, col: int
NavContext = object
g: ModuleGraph
thisModule: int32
trackPos: UnpackedLineInfo
alreadyEmitted: HashSet[string]
outputSep: char # for easier testing, use short filenames and spaces instead of tabs.
proc isTracked(man: LineInfoManager; current: PackedLineInfo, trackPos: UnpackedLineInfo, tokenLen: int): bool =
let (currentFile, currentLine, currentCol) = man.unpack(current)
if currentFile == trackPos.file and currentLine == trackPos.line:
let col = trackPos.col
if col >= currentCol and col < currentCol+tokenLen:
result = true
else:
result = false
else:
result = false
proc searchLocalSym(c: var NavContext; s: PackedSym; info: PackedLineInfo): bool =
result = s.name != LitId(0) and
isTracked(c.g.packed[c.thisModule].fromDisk.man, info, c.trackPos, c.g.packed[c.thisModule].fromDisk.strings[s.name].len)
proc searchForeignSym(c: var NavContext; s: ItemId; info: PackedLineInfo): bool =
let name = c.g.packed[s.module].fromDisk.syms[s.item].name
result = name != LitId(0) and
isTracked(c.g.packed[c.thisModule].fromDisk.man, info, c.trackPos, c.g.packed[s.module].fromDisk.strings[name].len)
const
EmptyItemId = ItemId(module: -1'i32, item: -1'i32)
proc search(c: var NavContext; tree: PackedTree): ItemId =
# We use the linear representation here directly:
for i in 0..<len(tree):
let i = NodePos(i)
case tree[i].kind
of nkSym:
let item = tree[i].soperand
if searchLocalSym(c, c.g.packed[c.thisModule].fromDisk.syms[item], tree[i].info):
return ItemId(module: c.thisModule, item: item)
of nkModuleRef:
let (currentFile, currentLine, currentCol) = c.g.packed[c.thisModule].fromDisk.man.unpack(tree[i].info)
if currentLine == c.trackPos.line and currentFile == c.trackPos.file:
let (n1, n2) = sons2(tree, i)
assert n1.kind == nkInt32Lit
assert n2.kind == nkInt32Lit
let pId = PackedItemId(module: n1.litId, item: tree[n2].soperand)
let itemId = translateId(pId, c.g.packed, c.thisModule, c.g.config)
if searchForeignSym(c, itemId, tree[i].info):
return itemId
else: discard
return EmptyItemId
proc isDecl(tree: PackedTree; n: NodePos): bool =
# XXX This is not correct yet.
const declarativeNodes = procDefs + {nkMacroDef, nkTemplateDef,
nkLetSection, nkVarSection, nkUsingStmt, nkConstSection, nkTypeSection,
nkIdentDefs, nkEnumTy, nkVarTuple}
result = n.int >= 0 and tree[n].kind in declarativeNodes
proc usage(c: var NavContext; info: PackedLineInfo; isDecl: bool) =
let (fileId, line, col) = unpack(c.g.packed[c.thisModule].fromDisk.man, info)
var m = ""
var file = c.g.packed[c.thisModule].fromDisk.strings[fileId]
if c.outputSep == ' ':
file = os.extractFilename file
toLocation(m, file, line, col + ColOffset)
if not c.alreadyEmitted.containsOrIncl(m):
msgWriteln c.g.config, (if isDecl: "def" else: "usage") & c.outputSep & m
proc list(c: var NavContext; tree: PackedTree; sym: ItemId) =
for i in 0..<len(tree):
let i = NodePos(i)
case tree[i].kind
of nkSym:
let item = tree[i].soperand
if sym.item == item and sym.module == c.thisModule:
usage(c, tree[i].info, isDecl(tree, parent(i)))
of nkModuleRef:
let (n1, n2) = sons2(tree, i)
assert n1.kind == nkNone
assert n2.kind == nkNone
let pId = PackedItemId(module: n1.litId, item: tree[n2].soperand)
let itemId = translateId(pId, c.g.packed, c.thisModule, c.g.config)
if itemId.item == sym.item and sym.module == itemId.module:
usage(c, tree[i].info, isDecl(tree, parent(i)))
else: discard
proc searchForIncludeFile(g: ModuleGraph; fullPath: string): int =
for i in 0..<len(g.packed):
for k in 1..high(g.packed[i].fromDisk.includes):
# we start from 1 because the first "include" file is
# the module's filename.
if os.cmpPaths(g.packed[i].fromDisk.strings[g.packed[i].fromDisk.includes[k][0]], fullPath) == 0:
return i
return -1
proc nav(g: ModuleGraph) =
# translate the track position to a packed position:
let unpacked = g.config.m.trackPos
var mid = unpacked.fileIndex.int
let fullPath = toFullPath(g.config, unpacked.fileIndex)
if g.packed[mid].status == undefined:
# check if 'mid' is an include file of some other module:
mid = searchForIncludeFile(g, fullPath)
if mid < 0:
localError(g.config, unpacked, "unknown file name: " & fullPath)
return
let fileId = g.packed[mid].fromDisk.strings.getKeyId(fullPath)
if fileId == LitId(0):
internalError(g.config, unpacked, "cannot find a valid file ID")
return
var c = NavContext(
g: g,
thisModule: int32 mid,
trackPos: UnpackedLineInfo(line: unpacked.line.int, col: unpacked.col.int, file: fileId),
outputSep: if isDefined(g.config, "nimIcNavigatorTests"): ' ' else: '\t'
)
var symId = search(c, g.packed[mid].fromDisk.topLevel)
if symId == EmptyItemId:
symId = search(c, g.packed[mid].fromDisk.bodies)
if symId == EmptyItemId:
localError(g.config, unpacked, "no symbol at this position")
return
for i in 0..<len(g.packed):
# case statement here to enforce exhaustive checks.
case g.packed[i].status
of undefined:
discard "nothing to do"
of loading:
assert false, "cannot check integrity: Module still loading"
of stored, storing, outdated, loaded:
c.thisModule = int32 i
list(c, g.packed[i].fromDisk.topLevel, symId)
list(c, g.packed[i].fromDisk.bodies, symId)
proc navDefinition*(g: ModuleGraph) = nav(g)
proc navUsages*(g: ModuleGraph) = nav(g)
proc navDefusages*(g: ModuleGraph) = nav(g)
proc writeRodFiles*(g: ModuleGraph) =
for i in 0..<len(g.packed):
case g.packed[i].status
of undefined, loading, stored, loaded:
discard "nothing to do"
of storing, outdated:
closeRodFile(g, g.packed[i].module)

367
compiler/ic/packed_ast.nim Normal file
View File

@@ -0,0 +1,367 @@
#
#
# The Nim Compiler
# (c) Copyright 2020 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Packed AST representation, mostly based on a seq of nodes.
## For IC support. Far future: Rewrite the compiler passes to
## use this representation directly in all the transformations,
## it is superior.
import std/[hashes, tables, strtabs]
import bitabs, rodfiles
import ".." / [ast, options]
import iclineinfos
when defined(nimPreviewSlimSystem):
import std/assertions
type
SymId* = distinct int32
ModuleId* = distinct int32
NodePos* = distinct int
NodeId* = distinct int32
PackedItemId* = object
module*: LitId # 0 if it's this module
item*: int32 # same as the in-memory representation
const
nilItemId* = PackedItemId(module: LitId(0), item: 0.int32)
const
emptyNodeId* = NodeId(-1)
type
PackedLib* = object
kind*: TLibKind
generated*: bool
isOverridden*: bool
name*: LitId
path*: NodeId
PackedSym* = object
id*: int32
kind*: TSymKind
name*: LitId
typ*: PackedItemId
flags*: TSymFlags
magic*: TMagic
info*: PackedLineInfo
ast*: NodeId
owner*: PackedItemId
guard*: PackedItemId
bitsize*: int
alignment*: int # for alignment
options*: TOptions
position*: int
offset*: int32
disamb*: int32
externalName*: LitId # instead of TLoc
locFlags*: TLocFlags
annex*: PackedLib
when hasFFI:
cname*: LitId
constraint*: NodeId
instantiatedFrom*: PackedItemId
PackedType* = object
id*: int32
kind*: TTypeKind
callConv*: TCallingConvention
#nodekind*: TNodeKind
flags*: TTypeFlags
types*: seq[PackedItemId]
n*: NodeId
#nodeflags*: TNodeFlags
sym*: PackedItemId
owner*: PackedItemId
size*: BiggestInt
align*: int16
paddingAtEnd*: int16
# not serialized: loc*: TLoc because it is backend-specific
typeInst*: PackedItemId
nonUniqueId*: int32
PackedNode* = object # 8 bytes
x: uint32
info*: PackedLineInfo
PackedTree* = object ## usually represents a full Nim module
nodes: seq[PackedNode]
withFlags: seq[(int32, TNodeFlags)]
withTypes: seq[(int32, PackedItemId)]
PackedInstantiation* = object
key*, sym*: PackedItemId
concreteTypes*: seq[PackedItemId]
const
NodeKindBits = 8'u32
NodeKindMask = (1'u32 shl NodeKindBits) - 1'u32
template kind*(n: PackedNode): TNodeKind = TNodeKind(n.x and NodeKindMask)
template uoperand*(n: PackedNode): uint32 = (n.x shr NodeKindBits)
template soperand*(n: PackedNode): int32 = int32(uoperand(n))
template toX(k: TNodeKind; operand: uint32): uint32 =
uint32(k) or (operand shl NodeKindBits)
template toX(k: TNodeKind; operand: LitId): uint32 =
uint32(k) or (operand.uint32 shl NodeKindBits)
template typeId*(n: PackedNode): PackedItemId = n.typ
proc `==`*(a, b: SymId): bool {.borrow.}
proc hash*(a: SymId): Hash {.borrow.}
proc `==`*(a, b: NodePos): bool {.borrow.}
#proc `==`*(a, b: PackedItemId): bool {.borrow.}
proc `==`*(a, b: NodeId): bool {.borrow.}
proc newTreeFrom*(old: PackedTree): PackedTree =
result = PackedTree(nodes: @[])
when false: result.sh = old.sh
proc addIdent*(tree: var PackedTree; s: LitId; info: PackedLineInfo) =
tree.nodes.add PackedNode(x: toX(nkIdent, uint32(s)), info: info)
proc addSym*(tree: var PackedTree; s: int32; info: PackedLineInfo) =
tree.nodes.add PackedNode(x: toX(nkSym, cast[uint32](s)), info: info)
proc addSymDef*(tree: var PackedTree; s: SymId; info: PackedLineInfo) =
tree.nodes.add PackedNode(x: toX(nkSym, cast[uint32](s)), info: info)
proc isAtom*(tree: PackedTree; pos: int): bool {.inline.} = tree.nodes[pos].kind <= nkNilLit
type
PatchPos = distinct int
proc addNode*(t: var PackedTree; kind: TNodeKind; operand: int32;
typeId: PackedItemId = nilItemId; info: PackedLineInfo;
flags: TNodeFlags = {}) =
t.nodes.add PackedNode(x: toX(kind, cast[uint32](operand)), info: info)
if flags != {}:
t.withFlags.add (t.nodes.len.int32 - 1, flags)
if typeId != nilItemId:
t.withTypes.add (t.nodes.len.int32 - 1, typeId)
proc prepare*(tree: var PackedTree; kind: TNodeKind; flags: TNodeFlags; typeId: PackedItemId; info: PackedLineInfo): PatchPos =
result = PatchPos tree.nodes.len
tree.addNode(kind = kind, flags = flags, operand = 0, info = info, typeId = typeId)
proc prepare*(dest: var PackedTree; source: PackedTree; sourcePos: NodePos): PatchPos =
result = PatchPos dest.nodes.len
dest.nodes.add source.nodes[sourcePos.int]
proc patch*(tree: var PackedTree; pos: PatchPos) =
let pos = pos.int
let k = tree.nodes[pos].kind
assert k > nkNilLit
let distance = int32(tree.nodes.len - pos)
assert distance > 0
tree.nodes[pos].x = toX(k, cast[uint32](distance))
proc len*(tree: PackedTree): int {.inline.} = tree.nodes.len
proc `[]`*(tree: PackedTree; i: NodePos): lent PackedNode {.inline.} =
tree.nodes[i.int]
template rawSpan(n: PackedNode): int = int(uoperand(n))
proc nextChild(tree: PackedTree; pos: var int) {.inline.} =
if tree.nodes[pos].kind > nkNilLit:
assert tree.nodes[pos].uoperand > 0
inc pos, tree.nodes[pos].rawSpan
else:
inc pos
iterator sonsReadonly*(tree: PackedTree; n: NodePos): NodePos =
var pos = n.int
assert tree.nodes[pos].kind > nkNilLit
let last = pos + tree.nodes[pos].rawSpan
inc pos
while pos < last:
yield NodePos pos
nextChild tree, pos
iterator sons*(dest: var PackedTree; tree: PackedTree; n: NodePos): NodePos =
let patchPos = prepare(dest, tree, n)
for x in sonsReadonly(tree, n): yield x
patch dest, patchPos
iterator isons*(dest: var PackedTree; tree: PackedTree;
n: NodePos): (int, NodePos) =
var i = 0
for ch0 in sons(dest, tree, n):
yield (i, ch0)
inc i
iterator sonsFrom1*(tree: PackedTree; n: NodePos): NodePos =
var pos = n.int
assert tree.nodes[pos].kind > nkNilLit
let last = pos + tree.nodes[pos].rawSpan
inc pos
if pos < last:
nextChild tree, pos
while pos < last:
yield NodePos pos
nextChild tree, pos
iterator sonsWithoutLast2*(tree: PackedTree; n: NodePos): NodePos =
var count = 0
for child in sonsReadonly(tree, n):
inc count
var pos = n.int
assert tree.nodes[pos].kind > nkNilLit
let last = pos + tree.nodes[pos].rawSpan
inc pos
while pos < last and count > 2:
yield NodePos pos
dec count
nextChild tree, pos
proc parentImpl(tree: PackedTree; n: NodePos): NodePos =
# finding the parent of a node is rather easy:
var pos = n.int - 1
while pos >= 0 and (isAtom(tree, pos) or (pos + tree.nodes[pos].rawSpan - 1 < n.int)):
dec pos
#assert pos >= 0, "node has no parent"
result = NodePos(pos)
template parent*(n: NodePos): NodePos = parentImpl(tree, n)
proc hasXsons*(tree: PackedTree; n: NodePos; x: int): bool =
var count = 0
if tree.nodes[n.int].kind > nkNilLit:
for child in sonsReadonly(tree, n): inc count
result = count == x
proc hasAtLeastXsons*(tree: PackedTree; n: NodePos; x: int): bool =
if tree.nodes[n.int].kind > nkNilLit:
var count = 0
for child in sonsReadonly(tree, n):
inc count
if count >= x: return true
return false
proc firstSon*(tree: PackedTree; n: NodePos): NodePos {.inline.} =
NodePos(n.int+1)
proc kind*(tree: PackedTree; n: NodePos): TNodeKind {.inline.} =
tree.nodes[n.int].kind
proc litId*(tree: PackedTree; n: NodePos): LitId {.inline.} =
LitId tree.nodes[n.int].uoperand
proc info*(tree: PackedTree; n: NodePos): PackedLineInfo {.inline.} =
tree.nodes[n.int].info
proc findType*(tree: PackedTree; n: NodePos): PackedItemId =
for x in tree.withTypes:
if x[0] == int32(n): return x[1]
if x[0] > int32(n): return nilItemId
return nilItemId
proc findFlags*(tree: PackedTree; n: NodePos): TNodeFlags =
for x in tree.withFlags:
if x[0] == int32(n): return x[1]
if x[0] > int32(n): return {}
return {}
template typ*(n: NodePos): PackedItemId =
tree.findType(n)
template flags*(n: NodePos): TNodeFlags =
tree.findFlags(n)
template uoperand*(n: NodePos): uint32 =
tree.nodes[n.int].uoperand
proc span*(tree: PackedTree; pos: int): int {.inline.} =
if isAtom(tree, pos): 1 else: tree.nodes[pos].rawSpan
proc sons2*(tree: PackedTree; n: NodePos): (NodePos, NodePos) =
assert(not isAtom(tree, n.int))
let a = n.int+1
let b = a + span(tree, a)
result = (NodePos a, NodePos b)
proc sons3*(tree: PackedTree; n: NodePos): (NodePos, NodePos, NodePos) =
assert(not isAtom(tree, n.int))
let a = n.int+1
let b = a + span(tree, a)
let c = b + span(tree, b)
result = (NodePos a, NodePos b, NodePos c)
proc ithSon*(tree: PackedTree; n: NodePos; i: int): NodePos =
result = default(NodePos)
if tree.nodes[n.int].kind > nkNilLit:
var count = 0
for child in sonsReadonly(tree, n):
if count == i: return child
inc count
assert false, "node has no i-th child"
when false:
proc `@`*(tree: PackedTree; lit: LitId): lent string {.inline.} =
tree.sh.strings[lit]
template kind*(n: NodePos): TNodeKind = tree.nodes[n.int].kind
template info*(n: NodePos): PackedLineInfo = tree.nodes[n.int].info
template litId*(n: NodePos): LitId = LitId tree.nodes[n.int].uoperand
template symId*(n: NodePos): SymId = SymId tree.nodes[n.int].soperand
proc firstSon*(n: NodePos): NodePos {.inline.} = NodePos(n.int+1)
const
externIntLit* = {nkCharLit,
nkIntLit,
nkInt8Lit,
nkInt16Lit,
nkInt32Lit,
nkInt64Lit,
nkUIntLit,
nkUInt8Lit,
nkUInt16Lit,
nkUInt32Lit,
nkUInt64Lit}
externSIntLit* = {nkIntLit, nkInt8Lit, nkInt16Lit, nkInt32Lit, nkInt64Lit}
externUIntLit* = {nkUIntLit, nkUInt8Lit, nkUInt16Lit, nkUInt32Lit, nkUInt64Lit}
directIntLit* = nkNone
template copyInto*(dest, n, body) =
let patchPos = prepare(dest, tree, n)
body
patch dest, patchPos
template copyIntoKind*(dest, kind, info, body) =
let patchPos = prepare(dest, kind, info)
body
patch dest, patchPos
proc getNodeId*(tree: PackedTree): NodeId {.inline.} = NodeId tree.nodes.len
iterator allNodes*(tree: PackedTree): NodePos =
var p = 0
while p < tree.len:
yield NodePos(p)
let s = span(tree, p)
inc p, s
proc toPackedItemId*(item: int32): PackedItemId {.inline.} =
PackedItemId(module: LitId(0), item: item)
proc load*(f: var RodFile; t: var PackedTree) =
loadSeq f, t.nodes
loadSeq f, t.withFlags
loadSeq f, t.withTypes
proc store*(f: var RodFile; t: PackedTree) =
storeSeq f, t.nodes
storeSeq f, t.withFlags
storeSeq f, t.withTypes

View File

@@ -19,6 +19,8 @@ import std/tables
when defined(nimPreviewSlimSystem):
import std/assertions
import packed_ast, ic, bitabs
proc replayStateChanges*(module: PSym; g: ModuleGraph) =
let list = module.ast
assert list != nil
@@ -86,3 +88,84 @@ proc replayStateChanges*(module: PSym; g: ModuleGraph) =
g.cacheSeqs[destKey].add val
else:
internalAssert g.config, false
proc replayBackendProcs*(g: ModuleGraph; module: int) =
for it in mitems(g.packed[module].fromDisk.attachedOps):
let key = translateId(it[0], g.packed, module, g.config)
let op = it[1]
let tmp = translateId(it[2], g.packed, module, g.config)
let symId = FullId(module: tmp.module, packed: it[2])
g.attachedOps[op][key] = LazySym(id: symId, sym: nil)
for it in mitems(g.packed[module].fromDisk.enumToStringProcs):
let key = translateId(it[0], g.packed, module, g.config)
let tmp = translateId(it[1], g.packed, module, g.config)
let symId = FullId(module: tmp.module, packed: it[1])
g.enumToStringProcs[key] = LazySym(id: symId, sym: nil)
for it in mitems(g.packed[module].fromDisk.methodsPerType):
let key = translateId(it[0], g.packed, module, g.config)
let tmp = translateId(it[1], g.packed, module, g.config)
let symId = FullId(module: tmp.module, packed: it[1])
g.methodsPerType.mgetOrPut(key, @[]).add LazySym(id: symId, sym: nil)
for it in mitems(g.packed[module].fromDisk.dispatchers):
let tmp = translateId(it, g.packed, module, g.config)
let symId = FullId(module: tmp.module, packed: it)
g.dispatchers.add LazySym(id: symId, sym: nil)
proc replayGenericCacheInformation*(g: ModuleGraph; module: int) =
## We remember the generic instantiations a module performed
## in order to to avoid the code bloat that generic code tends
## to imply. This is cheaper than deduplication of identical
## generic instantiations. However, deduplication is more
## powerful and general and I hope to implement it soon too
## (famous last words).
assert g.packed[module].status == loaded
for it in g.packed[module].fromDisk.typeInstCache:
let key = translateId(it[0], g.packed, module, g.config)
g.typeInstCache.mgetOrPut(key, @[]).add LazyType(id: FullId(module: module, packed: it[1]), typ: nil)
for it in mitems(g.packed[module].fromDisk.procInstCache):
let key = translateId(it.key, g.packed, module, g.config)
let sym = translateId(it.sym, g.packed, module, g.config)
var concreteTypes = newSeq[FullId](it.concreteTypes.len)
for i in 0..high(it.concreteTypes):
let tmp = translateId(it.concreteTypes[i], g.packed, module, g.config)
concreteTypes[i] = FullId(module: tmp.module, packed: it.concreteTypes[i])
g.procInstCache.mgetOrPut(key, @[]).add LazyInstantiation(
module: module, sym: FullId(module: sym.module, packed: it.sym),
concreteTypes: concreteTypes, inst: nil)
for it in mitems(g.packed[module].fromDisk.methodsPerGenericType):
let key = translateId(it[0], g.packed, module, g.config)
let col = it[1]
let tmp = translateId(it[2], g.packed, module, g.config)
let symId = FullId(module: tmp.module, packed: it[2])
g.methodsPerGenericType.mgetOrPut(key, @[]).add (col, LazySym(id: symId, sym: nil))
replayBackendProcs(g, module)
for it in mitems(g.packed[module].fromDisk.methods):
let sym = loadSymFromId(g.config, g.cache, g.packed, module,
PackedItemId(module: LitId(0), item: it))
methodDef(g, g.idgen, sym)
when false:
# not used anymore:
for it in mitems(g.packed[module].fromDisk.compilerProcs):
let symId = FullId(module: module, packed: PackedItemId(module: LitId(0), item: it[1]))
g.lazyCompilerprocs[g.packed[module].fromDisk.sh.strings[it[0]]] = symId
for it in mitems(g.packed[module].fromDisk.converters):
let symId = FullId(module: module, packed: PackedItemId(module: LitId(0), item: it))
g.ifaces[module].converters.add LazySym(id: symId, sym: nil)
for it in mitems(g.packed[module].fromDisk.trmacros):
let symId = FullId(module: module, packed: PackedItemId(module: LitId(0), item: it))
g.ifaces[module].patterns.add LazySym(id: symId, sym: nil)
for it in mitems(g.packed[module].fromDisk.pureEnums):
let symId = FullId(module: module, packed: PackedItemId(module: LitId(0), item: it))
g.ifaces[module].pureEnums.add LazySym(id: symId, sym: nil)

283
compiler/ic/rodfiles.nim Normal file
View File

@@ -0,0 +1,283 @@
#
#
# The Nim Compiler
# (c) Copyright 2020 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Low level binary format used by the compiler to store and load various AST
## and related data.
##
## NB: this is incredibly low level and if you're interested in how the
## compiler works and less a storage format, you're probably looking for
## the `ic` or `packed_ast` modules to understand the logical format.
from std/typetraits import supportsCopyMem
when defined(nimPreviewSlimSystem):
import std/[syncio, assertions]
import std / tables
## Overview
## ========
## `RodFile` represents a Rod File (versioned binary format), and the
## associated data for common interactions such as IO and error tracking
## (`RodFileError`). The file format broken up into sections (`RodSection`)
## and preceded by a header (see: `cookie`). The precise layout, section
## ordering and data following the section are determined by the user. See
## `ic.loadRodFile`.
##
## A basic but "wrong" example of the lifecycle:
## ---------------------------------------------
## 1. `create` or `open` - create a new one or open an existing
## 2. `storeHeader` - header info
## 3. `storePrim` or `storeSeq` - save your stuff
## 4. `close` - and we're done
##
## Now read the bits below to understand what's missing.
##
## ### Issues with the Example
## Missing Sections:
## This is a low level API, so headers and sections need to be stored and
## loaded by the user, see `storeHeader` & `loadHeader` and `storeSection` &
## `loadSection`, respectively.
##
## No Error Handling:
## The API is centered around IO and prone to error, each operation checks or
## sets the `RodFile.err` field. A user of this API needs to handle these
## appropriately.
##
## API Notes
## =========
##
## Valid inputs for Rod files
## --------------------------
## ASTs, hopes, dreams, and anything as long as it and any children it may have
## support `copyMem`. This means anything that is not a pointer and that does not contain a pointer. At a glance these are:
## * string
## * objects & tuples (fields are recursed)
## * sequences AKA `seq[T]`
##
## Note on error handling style
## ----------------------------
## A flag based approach is used where operations no-op in case of a
## preexisting error and set the flag if they encounter one.
##
## Misc
## ----
## * 'Prim' is short for 'primitive', as in a non-sequence type
type
RodSection* = enum
versionSection
configSection
stringsSection
checkSumsSection
depsSection
numbersSection
exportsSection
hiddenSection
reexportsSection
compilerProcsSection
trmacrosSection
convertersSection
methodsSection
pureEnumsSection
toReplaySection
topLevelSection
bodiesSection
symsSection
typesSection
typeInstCacheSection
procInstCacheSection
attachedOpsSection
methodsPerGenericTypeSection
enumToStringProcsSection
methodsPerTypeSection
dispatchersSection
typeInfoSection # required by the backend
backendFlagsSection
aliveSymsSection # beware, this is stored in a `.alivesyms` file.
sideChannelSection
namespaceSection
symnamesSection
RodFileError* = enum
ok, tooBig, cannotOpen, ioFailure, wrongHeader, wrongSection, configMismatch,
includeFileChanged
RodFile* = object
f*: File
currentSection*: RodSection # for error checking
err*: RodFileError # little experiment to see if this works
# better than exceptions.
const
RodVersion = 2
defaultCookie = [byte(0), byte('R'), byte('O'), byte('D'),
byte(sizeof(int)*8), byte(system.cpuEndian), byte(0), byte(RodVersion)]
proc setError(f: var RodFile; err: RodFileError) {.inline.} =
f.err = err
#raise newException(IOError, "IO error")
proc storePrim*(f: var RodFile; s: string) =
## Stores a string.
## The len is prefixed to allow for later retreival.
if f.err != ok: return
if s.len >= high(int32):
setError f, tooBig
return
var lenPrefix = int32(s.len)
if writeBuffer(f.f, addr lenPrefix, sizeof(lenPrefix)) != sizeof(lenPrefix):
setError f, ioFailure
else:
if s.len != 0:
if writeBuffer(f.f, unsafeAddr(s[0]), s.len) != s.len:
setError f, ioFailure
proc storePrim*[T](f: var RodFile; x: T) =
## Stores a non-sequence/string `T`.
## If `T` doesn't support `copyMem` and is an object or tuple then the fields
## are written -- the user from context will need to know which `T` to load.
if f.err != ok: return
when supportsCopyMem(T):
if writeBuffer(f.f, unsafeAddr(x), sizeof(x)) != sizeof(x):
setError f, ioFailure
elif T is tuple:
for y in fields(x):
storePrim(f, y)
elif T is object:
for y in fields(x):
when y is seq:
storeSeq(f, y)
else:
storePrim(f, y)
else:
{.error: "unsupported type for 'storePrim'".}
proc storeSeq*[T](f: var RodFile; s: seq[T]) =
## Stores a sequence of `T`s, with the len as a prefix for later retrieval.
if f.err != ok: return
if s.len >= high(int32):
setError f, tooBig
return
var lenPrefix = int32(s.len)
if writeBuffer(f.f, addr lenPrefix, sizeof(lenPrefix)) != sizeof(lenPrefix):
setError f, ioFailure
else:
for i in 0..<s.len:
storePrim(f, s[i])
proc storeOrderedTable*[K, T](f: var RodFile; s: OrderedTable[K, T]) =
if f.err != ok: return
if s.len >= high(int32):
setError f, tooBig
return
var lenPrefix = int32(s.len)
if writeBuffer(f.f, addr lenPrefix, sizeof(lenPrefix)) != sizeof(lenPrefix):
setError f, ioFailure
else:
for _, v in s:
storePrim(f, v)
proc loadPrim*(f: var RodFile; s: var string) =
## Read a string, the length was stored as a prefix
if f.err != ok: return
var lenPrefix = int32(0)
if readBuffer(f.f, addr lenPrefix, sizeof(lenPrefix)) != sizeof(lenPrefix):
setError f, ioFailure
else:
s = newString(lenPrefix)
if lenPrefix > 0:
if readBuffer(f.f, unsafeAddr(s[0]), s.len) != s.len:
setError f, ioFailure
proc loadPrim*[T](f: var RodFile; x: var T) =
## Load a non-sequence/string `T`.
if f.err != ok: return
when supportsCopyMem(T):
if readBuffer(f.f, unsafeAddr(x), sizeof(x)) != sizeof(x):
setError f, ioFailure
elif T is tuple:
for y in fields(x):
loadPrim(f, y)
elif T is object:
for y in fields(x):
when y is seq:
loadSeq(f, y)
else:
loadPrim(f, y)
else:
{.error: "unsupported type for 'loadPrim'".}
proc loadSeq*[T](f: var RodFile; s: var seq[T]) =
## `T` must be compatible with `copyMem`, see `loadPrim`
if f.err != ok: return
var lenPrefix = int32(0)
if readBuffer(f.f, addr lenPrefix, sizeof(lenPrefix)) != sizeof(lenPrefix):
setError f, ioFailure
else:
s = newSeq[T](lenPrefix)
for i in 0..<lenPrefix:
loadPrim(f, s[i])
proc loadOrderedTable*[K, T](f: var RodFile; s: var OrderedTable[K, T]) =
## `T` must be compatible with `copyMem`, see `loadPrim`
if f.err != ok: return
var lenPrefix = int32(0)
if readBuffer(f.f, addr lenPrefix, sizeof(lenPrefix)) != sizeof(lenPrefix):
setError f, ioFailure
else:
s = initOrderedTable[K, T](lenPrefix)
for i in 0..<lenPrefix:
var x = default T
loadPrim(f, x)
s[x.id] = x
proc storeHeader*(f: var RodFile; cookie = defaultCookie) =
## stores the header which is described by `cookie`.
if f.err != ok: return
if f.f.writeBytes(cookie, 0, cookie.len) != cookie.len:
setError f, ioFailure
proc loadHeader*(f: var RodFile; cookie = defaultCookie) =
## Loads the header which is described by `cookie`.
if f.err != ok: return
var thisCookie: array[cookie.len, byte] = default(array[cookie.len, byte])
if f.f.readBytes(thisCookie, 0, thisCookie.len) != thisCookie.len:
setError f, ioFailure
elif thisCookie != cookie:
setError f, wrongHeader
proc storeSection*(f: var RodFile; s: RodSection) =
## update `currentSection` and writes the bytes value of s.
if f.err != ok: return
assert f.currentSection < s
f.currentSection = s
storePrim(f, s)
proc loadSection*(f: var RodFile; expected: RodSection) =
## read the bytes value of s, sets and error if the section is incorrect.
if f.err != ok: return
var s: RodSection = default(RodSection)
loadPrim(f, s)
if expected != s and f.err == ok:
setError f, wrongSection
proc create*(filename: string): RodFile =
## create the file and open it for writing
result = default(RodFile)
if not open(result.f, filename, fmWrite):
setError result, cannotOpen
proc close*(f: var RodFile) = close(f.f)
proc open*(filename: string): RodFile =
## open the file for reading
result = default(RodFile)
if not open(result.f, filename, fmRead):
setError result, cannotOpen

View File

@@ -10,7 +10,7 @@
## This module implements the symbol importing mechanism.
import
ast, msgs, options, idents, lookups,
ast, astalgo, msgs, options, idents, lookups,
semdata, modulepaths, sigmatch, lineinfos,
modulegraphs, wordrecg
from std/strutils import `%`, startsWith
@@ -108,8 +108,8 @@ proc rawImportSymbol(c: PContext, s, origin: PSym; importSet: var IntSet) =
else:
importPureEnumField(c, e)
else:
if s.kind == skConverter: addConverter(c, s)
if hasPattern(s): addPattern(c, s)
if s.kind == skConverter: addConverter(c, LazySym(sym: s))
if hasPattern(s): addPattern(c, LazySym(sym: s))
if s.owner != origin:
c.exportIndirections.incl((origin.id, s.id))
@@ -190,19 +190,22 @@ proc addImport(c: PContext; im: sink ImportedModule) =
template addUnnamedIt(c: PContext, fromMod: PSym; filter: untyped) {.dirty.} =
for it in mitems c.graph.ifaces[fromMod.position].converters:
if filter:
if sfExported in it.flags:
loadPackedSym(c.graph, it)
if sfExported in it.sym.flags:
addConverter(c, it)
for it in mitems c.graph.ifaces[fromMod.position].patterns:
if filter:
if sfExported in it.flags:
loadPackedSym(c.graph, it)
if sfExported in it.sym.flags:
addPattern(c, it)
for it in mitems c.graph.ifaces[fromMod.position].pureEnums:
if filter:
importPureEnumFields(c, it, it.typ)
loadPackedSym(c.graph, it)
importPureEnumFields(c, it.sym, it.sym.typ)
proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) =
c.addImport ImportedModule(m: fromMod, mode: importExcept, exceptSet: exceptSet)
addUnnamedIt(c, fromMod, it.name.id notin exceptSet)
addUnnamedIt(c, fromMod, it.sym.name.id notin exceptSet)
proc importAllSymbols*(c: PContext, fromMod: PSym) =
c.addImport ImportedModule(m: fromMod, mode: importAll)
@@ -242,8 +245,7 @@ proc importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden, track
# avoids modifying `realModule`, see D20201209T194412 for `import {.all.}`
result = createModuleAliasImpl(realModule.name)
if importHidden:
ensureMutable result
result.optionsImpl.incl optImportHidden
result.options.incl optImportHidden
let moduleIdent = if n.kind in {nkInfix, nkImportAs}: n[^1] else: n
result.info = moduleIdent.info
if trackUnusedImport:
@@ -289,8 +291,9 @@ proc myImportModule(c: PContext, n: var PNode, importStmtResult: PNode): PSym =
c.recursiveDep = err
let trackUnusedImport = warnUnusedImportX in c.config.notes
var realModule: PSym
discard pushOptionEntry(c)
let realModule = c.graph.importModuleCallback(c.graph, c.module, f)
realModule = c.graph.importModuleCallback(c.graph, c.module, f)
result = importModuleAs(c, n, realModule, transf.importHidden, trackUnusedImport)
popOptionEntry(c)

View File

@@ -69,7 +69,7 @@ proc hasDestructor(c: Con; t: PType): bool {.inline.} =
result = ast.hasDestructor(t)
when toDebug.len > 0:
# for more effective debugging
if not result and c.graph.config.selectedGC in {gcArc, gcOrc, gcYrc, gcAtomicArc}:
if not result and c.graph.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
assert(not containsGarbageCollectedRef(t))
proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode =
@@ -165,7 +165,7 @@ proc isLastReadImpl(n: PNode; c: var Con; scope: var Scope): bool =
template hasDestructorOrAsgn(c: var Con, typ: PType): bool =
# bug #23354; an object type could have a non-trivial assignements when it is passed to a sink parameter
hasDestructor(c, typ) or (c.graph.config.selectedGC in {gcArc, gcOrc, gcYrc, gcAtomicArc} and
hasDestructor(c, typ) or (c.graph.config.selectedGC in {gcArc, gcOrc, gcAtomicArc} and
typ.kind == tyObject and not isTrivial(getAttachedOp(c.graph, typ, attachedAsgn)))
proc isLastRead(n: PNode; c: var Con; s: var Scope): bool =
@@ -329,21 +329,21 @@ proc isCriticalLink(dest: PNode): bool {.inline.} =
result = dest.kind != nkSym
proc finishCopy(c: var Con; result, dest: PNode; flags: set[MoveOrCopyFlag]; isFromSink: bool) =
if c.graph.config.selectedGC in {gcOrc, gcYrc} and IsExplicitSink notin flags:
if c.graph.config.selectedGC == gcOrc and IsExplicitSink notin flags:
# add cyclic flag, but not to sink calls, which IsExplicitSink generates
let t = dest.typ.skipTypes(tyUserTypeClasses + {tyGenericInst, tyAlias, tySink, tyDistinct})
if cyclicType(c.graph, t):
result.add boolLit(c.graph, result.info, isFromSink or isCriticalLink(dest))
proc genMarkCyclic(c: var Con; result, dest: PNode) =
if c.graph.config.selectedGC in {gcOrc, gcYrc}:
if c.graph.config.selectedGC == gcOrc:
let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink, tyDistinct})
if cyclicType(c.graph, t):
if t.kind == tyRef:
result.add callCodegenProc(c.graph, "nimMarkCyclic", dest.info, dest)
else:
let xenv = genBuiltin(c.graph, c.idgen, mAccessEnv, "accessEnv", dest)
xenv.typ = getSysType(c.graph, dest.info, tyPointer)
xenv.typ() = getSysType(c.graph, dest.info, tyPointer)
result.add callCodegenProc(c.graph, "nimMarkCyclic", dest.info, xenv)
proc genCopyNoCheck(c: var Con; dest, ri: PNode; a: TTypeAttachedOp): PNode =
@@ -419,7 +419,7 @@ proc genWasMoved(c: var Con, n: PNode): PNode =
proc genDefaultCall(t: PType; c: Con; info: TLineInfo): PNode =
result = newNodeI(nkCall, info)
result.add(newSymNode(createMagic(c.graph, c.idgen, "default", mDefault)))
result.typ = t
result.typ() = t
proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode =
# generate: (let tmp = v; reset(v); tmp)
@@ -495,7 +495,7 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
localError(c.graph.config, n.info, errFailedMove,
("cannot move '$1', passing '$1' to a sink parameter introduces an implicit copy") % $n)
else:
if c.graph.config.selectedGC in {gcArc, gcOrc, gcYrc, gcAtomicArc}:
if c.graph.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
assert(not containsManagedMemory(nTyp))
if nTyp.skipTypes(abstractInst).kind in {tyOpenArray, tyVarargs}:
localError(c.graph.config, n.info, "cannot create an implicit openArray copy to be passed to a sink parameter")
@@ -825,9 +825,9 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
n[1].typ.skipTypes(abstractInst-{tyOwned}).kind == tyOwned:
# allow conversions from owned to unowned via this little hack:
let nTyp = n[1].typ
n[1].typ = n.typ
n[1].typ() = n.typ
result[1] = p(n[1], c, s, sinkArg)
result[1].typ = nTyp
result[1].typ() = nTyp
else:
result[1] = p(n[1], c, s, sinkArg)
elif n.kind in {nkObjDownConv, nkObjUpConv}:
@@ -926,7 +926,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
if n[0].kind == nkSym and n[0].sym.magic in {mNew, mNewFinalize}:
result[0] = copyTree(n[0])
if c.graph.config.selectedGC in {gcHooks, gcArc, gcAtomicArc, gcOrc, gcYrc}:
if c.graph.config.selectedGC in {gcHooks, gcArc, gcAtomicArc, gcOrc}:
let destroyOld = c.genDestroy(result[1])
result = newTree(nkStmtList, destroyOld, result)
else:
@@ -964,14 +964,14 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
s.locals.add v.sym
pVarTopLevel(v, c, s, result)
if ri.kind != nkEmpty:
let isGlobalPragma = v.kind == nkSym and
let isGlobalPragma = v.kind == nkSym and
{sfPure, sfGlobal} <= v.sym.flags and
isInProc
let value = moveOrCopy(v, ri, c, s, if v.kind == nkSym: {IsDecl} else: {})
if isGlobalPragma:
c.graph.procGlobals.add newTree(nkFastAsgn, v, ri)
c.graph.procGlobals.add value
else:
let value = moveOrCopy(v, ri, c, s, if v.kind == nkSym: {IsDecl} else: {})
result.add value
elif ri.kind == nkEmpty and c.inLoop > 0:
let skipInit = v.kind == nkDotExpr and # Closure var
@@ -1036,9 +1036,9 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
n[1].typ.skipTypes(abstractInst-{tyOwned}).kind == tyOwned:
# allow conversions from owned to unowned via this little hack:
let nTyp = n[1].typ
n[1].typ = n.typ
n[1].typ() = n.typ
result[1] = p(n[1], c, s, mode)
result[1].typ = nTyp
result[1].typ() = nTyp
else:
result[1] = p(n[1], c, s, mode)
@@ -1155,7 +1155,7 @@ proc ownsData(c: var Con; s: var Scope; orig: PNode; flags: set[MoveOrCopyFlag])
if n.kind in nkCallKinds and n.typ != nil and hasDestructor(c, n.typ):
result = newNodeIT(nkStmtListExpr, orig.info, orig.typ)
let tmp = c.getTemp(s, n.typ, n.info)
tmp.sym.flagsImpl.incl sfSingleUsedTemp
tmp.sym.flags.incl sfSingleUsedTemp
result.add newTree(nkFastAsgn, tmp, copyTree(n))
s.final.add c.genDestroy(tmp)
n[] = tmp[]
@@ -1330,7 +1330,7 @@ proc addSinkCopy(c: var Con; s: var Scope; sinkParams: seq[PSym]; n: PNode): PNo
for param in sinkParams:
if param.id in mutatedSet:
let newSym = newSym(skTemp, getIdent(c.graph.cache, "sinkCopy"), c.idgen, param.owner, n.info)
newSym.flagsImpl.incl sfFromGeneric
newSym.flags.incl sfFromGeneric
newSym.typ = param.typ.elementType
mapping[param.id] = newSym
let v = newNodeI(nkVarSection, n.info)

View File

@@ -1,122 +0,0 @@
proc copySymdef(n: PNode; locals: var Table[int, PSym]; idgen: IdGenerator; owner: PSym): PNode =
case n.kind
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
result = n
of nkSym:
let oldSym = n.sym
let newSym = copySym(oldSym, idgen)
setOwner(newSym, owner)
locals[oldSym.id] = newSym
result = newSymNode(newSym, oldSym.info)
else:
result = shallowCopy(n)
for i in 0..<n.len:
result[i] = copySymdef(n[i], locals, idgen, owner)
proc copyInlineProcBody(n: PNode; locals: var Table[int, PSym]; idgen: IdGenerator; owner: PSym): PNode =
case n.kind
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
result = n
of nkSym:
let sym = locals.getOrDefault(n.sym.id)
if sym != nil:
result = newSymNode(sym, n.info)
else:
result = n
of nkLetSection, nkVarSection:
result = shallowCopy(n)
for i in 0..<n.len:
let it = n[i]
if it.kind == nkCommentStmt:
result[i] = it
elif it.kind in {nkIdentDefs, nkConstDef}:
result[i] = shallowCopy(it)
for j in 0..<it.len-2:
result[i][j] = copySymdef(it[j], locals, idgen, owner)
for j in it.len-2..<it.len:
result[i][j] = copyInlineProcBody(it[j], locals, idgen, owner)
else:
assert it.kind == nkVarTuple
result[i] = shallowCopy(it)
for j in 0..<it.len-2:
assert it[j].kind == nkSym
let oldSym = it[j].sym
let newSym = copySym(oldSym, idgen)
setOwner(newSym, owner)
locals[oldSym.id] = newSym
result[i][j] = newSymNode(newSym, oldSym.info)
for j in it.len-2..<it.len:
result[i][j] = copyInlineProcBody(it[j], locals, idgen, owner)
of nkForStmt, nkParForStmt:
result = shallowCopy(n)
for i in 0..<n.len-2:
assert n[i].kind == nkSym
let oldSym = n[i].sym
let newSym = copySym(oldSym, idgen)
setOwner(newSym, owner)
locals[oldSym.id] = newSym
result[i] = newSymNode(newSym, oldSym.info)
result[n.len-2] = copyInlineProcBody(n[n.len-2], locals, idgen, owner)
result[n.len-1] = copyInlineProcBody(n[n.len-1], locals, idgen, owner)
of routineDefs, nkTypeSection, nkTypeOfExpr, nkMixinStmt, nkBindStmt, nkConstSection:
result = n
else:
result = shallowCopy(n)
for i in 0..<n.len:
result[i] = copyInlineProcBody(n[i], locals, idgen, owner)
proc copyParams(n: PNode; locals: var Table[int, PSym]; idgen: IdGenerator; owner: PSym): PNode =
result = shallowCopy(n)
result[0] = n[0] # return type
for i in 1..<n.len:
let it = n[i]
assert it.kind == nkIdentDefs
result[i] = shallowCopy(it)
for j in 0..<it.len-2:
assert it[j].kind == nkSym
let oldSym = it[j].sym
let newSym = copySym(oldSym, idgen)
setOwner(newSym, owner)
locals[oldSym.id] = newSym
result[i][j] = newSymNode(newSym, oldSym.info)
owner.typ.addParam newSym
for j in it.len-2..<it.len:
result[i][j] = copyInlineProcBody(it[j], locals, idgen, owner)
proc copyInlineProc(prc: PSym; idgen: IdGenerator): PSym =
result = copySym(prc, idgen)
var locals = initTable[int, PSym]()
var a = shallowCopy(prc.ast)
if resultPos < prc.ast.len and prc.ast[resultPos].kind == nkSym:
let oldRes = prc.ast[resultPos].sym
let newRes = copySym(oldRes, idgen)
setOwner(newRes, result)
locals[oldRes.id] = newRes
a[resultPos] = newSymNode(newRes, oldRes.info)
result.typ = copyType(prc.typ, idgen, result)
result.typ.n = newNodeI(prc.typ.n.kind, prc.typ.n.info)
if prc.typ.n.len > 0:
result.typ.n.add copyNode(prc.typ.n[0])
for i in 1..<prc.typ.n.len:
let it = prc.typ.n[i]
assert it.kind == nkSym
let oldSym = it.sym
let newSym = copySym(oldSym, idgen)
setOwner(newSym, result)
locals[oldSym.id] = newSym
result.typ.addParam newSym
for i in 0..<prc.ast.len:
if i == paramsPos:
a[i] = copyTree(prc.ast[i])
elif i == resultPos and prc.ast[i].kind == nkSym:
discard "handled above"
else:
a[i] = copyInlineProcBody(prc.ast[i], locals, idgen, result)
result.ast = a
#echo "Produced: ", renderTree(result.ast, {renderIds})

View File

@@ -277,8 +277,7 @@ proc mangleName(m: BModule, s: PSym): Rope =
else:
result.add("_")
result.add(rope(s.id))
ensureMutable s
s.locImpl.snippet = result
s.loc.snippet = result
proc escapeJSString(s: string): string =
result = newStringOfCap(s.len + s.len shr 2)
@@ -729,47 +728,44 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
of mShrI:
let typ = n[1].typ.skipTypes(abstractVarRange)
if typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions:
applyFormat("BigInt.asIntN(64, BigInt.asUintN(64, $1) >> (BigInt($2) & 63n))")
applyFormat("BigInt.asIntN(64, BigInt.asUintN(64, $1) >> BigInt($2))")
elif typ.kind == tyUInt64 and optJsBigInt64 in p.config.globalOptions:
applyFormat("($1 >> (BigInt($2) & 63n))")
applyFormat("($1 >> BigInt($2))")
else:
let bitmask = typ.size * 8 - 1
if typ.kind in {tyInt..tyInt32}:
let trimmerU = unsignedTrimmer(typ.size)
let trimmerS = signedTrimmer(typ.size)
r.res = "((($1 $2) >>> ($3 & $5)) $4)" % [xLoc, trimmerU, yLoc, trimmerS, $bitmask]
r.res = "((($1 $2) >>> $3) $4)" % [xLoc, trimmerU, yLoc, trimmerS]
else:
r.res = "($1 >>> ($2 & $3))" % [xLoc, yLoc, $bitmask]
applyFormat("($1 >>> $2)")
of mShlI:
let typ = n[1].typ.skipTypes(abstractVarRange)
if typ.size == 8:
if typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions:
applyFormat("BigInt.asIntN(64, $1 << (BigInt($2) & 63n))")
applyFormat("BigInt.asIntN(64, $1 << BigInt($2))")
elif typ.kind == tyUInt64 and optJsBigInt64 in p.config.globalOptions:
applyFormat("BigInt.asUintN(64, $1 << (BigInt($2) & 63n))")
applyFormat("BigInt.asUintN(64, $1 << BigInt($2))")
else:
applyFormat("($1 * Math.pow(2, ($2 & 63)))")
applyFormat("($1 * Math.pow(2, $2))")
else:
let bitmask = typ.size * 8 - 1
if typ.kind in {tyUInt..tyUInt32}:
let trimmer = unsignedTrimmer(typ.size)
r.res = "(($1 << ($2 & $4)) $3)" % [xLoc, yLoc, trimmer, $bitmask]
r.res = "(($1 << $2) $3)" % [xLoc, yLoc, trimmer]
else:
let trimmer = signedTrimmer(typ.size)
r.res = "(($1 << ($2 & $4)) $3)" % [xLoc, yLoc, trimmer, $bitmask]
r.res = "(($1 << $2) $3)" % [xLoc, yLoc, trimmer]
of mAshrI:
let typ = n[1].typ.skipTypes(abstractVarRange)
if typ.size == 8:
if optJsBigInt64 in p.config.globalOptions:
applyFormat("($1 >> (BigInt($2) & 63n))")
applyFormat("($1 >> BigInt($2))")
else:
applyFormat("Math.floor($1 / Math.pow(2, ($2 & 63)))")
applyFormat("Math.floor($1 / Math.pow(2, $2))")
else:
let bitmask = typ.size * 8 - 1
if typ.kind in {tyUInt..tyUInt32}:
r.res = "($1 >>> ($2 & $3)))" % [xLoc, yLoc, $bitmask]
applyFormat("($1 >>> $2)")
else:
r.res = "($1 >> ($2 & $3))" % [xLoc, yLoc, $bitmask]
applyFormat("($1 >> $2)")
of mBitandI: bitwiseExpr("&")
of mBitorI: bitwiseExpr("|")
of mBitxorI: bitwiseExpr("^")
@@ -1006,8 +1002,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
# If some branch requires a local alias introduce it here. This is needed
# since JS cannot do ``catch x as y``.
if excAlias != nil:
ensureMutable excAlias.sym
excAlias.sym.locImpl.snippet = mangleName(p.module, excAlias.sym)
excAlias.sym.loc.snippet = mangleName(p.module, excAlias.sym)
lineF(p, "var $1 = lastJSError;$n", excAlias.sym.loc.snippet)
gen(p, n[i][^1], a)
moveInto(p, a, r)
@@ -1140,8 +1135,7 @@ proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
# named block?
if (n[0].kind != nkSym): internalError(p.config, n.info, "genBlock")
var sym = n[0].sym
ensureMutable sym
sym.locImpl.k = locOther
sym.loc.k = locOther
sym.position = idx+1
let labl = p.unique
lineF(p, "Label$1: {$n", [labl.rope])
@@ -1240,8 +1234,7 @@ proc generateHeader(p: PProc, prc: PSym): Rope =
# to keep it simple
let env = prc.ast[paramsPos].lastSon
assert env.kind == nkSym, "env is missing"
ensureMutable env.sym
env.sym.locImpl.snippet = "this"
env.sym.loc.snippet = "this"
for i in 1..<typ.n.len:
assert(typ.n[i].kind == nkSym)
@@ -1378,15 +1371,12 @@ proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
r.typ = etyBaseIndex
let b = if n.kind == nkHiddenAddr: n[0] else: n
gen(p, b[0], a)
if skipTypes(b[0].typ, abstractVarRange + tyTypeClasses).kind == tyTuple:
# ref #25227 about `+ tyTypeClasses`
if skipTypes(b[0].typ, abstractVarRange).kind == tyTuple:
r.res = makeJSString("Field" & $getFieldPosition(p, b[1]))
else:
if b[1].kind != nkSym: internalError(p.config, b[1].info, "genFieldAddr")
var f = b[1].sym
if f.loc.snippet == "":
ensureMutable f
f.locImpl.snippet = mangleName(p.module, f)
if f.loc.snippet == "": f.loc.snippet = mangleName(p.module, f)
r.res = makeJSString($f.loc.snippet)
internalAssert p.config, a.typ != etyBaseIndex
r.address = a.res
@@ -1414,9 +1404,7 @@ proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
else:
if n[1].kind != nkSym: internalError(p.config, n[1].info, "genFieldAccess")
var f = n[1].sym
if f.loc.snippet == "":
ensureMutable f
f.locImpl.snippet = mangleName(p.module, f)
if f.loc.snippet == "": f.loc.snippet = mangleName(p.module, f)
r.res = "$1.$2" % [r.res, f.loc.snippet]
mkTemp(1)
r.kind = resExpr
@@ -1437,15 +1425,11 @@ proc genCheckedFieldOp(p: PProc, n: PNode, addrTyp: PType, r: var TCompRes) =
# Field symbol
var field = accessExpr[1].sym
internalAssert p.config, field.kind == skField
if field.loc.snippet == "":
ensureMutable field
field.locImpl.snippet = mangleName(p.module, field)
if field.loc.snippet == "": field.loc.snippet = mangleName(p.module, field)
# Discriminant symbol
let disc = checkExpr[2].sym
internalAssert p.config, disc.kind == skField
if disc.loc.snippet == "":
ensureMutable disc
disc.locImpl.snippet = mangleName(p.module, disc)
if disc.loc.snippet == "": disc.loc.snippet = mangleName(p.module, disc)
var setx: TCompRes = default(TCompRes)
gen(p, checkExpr[1], setx)
@@ -1602,11 +1586,7 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
of nkObjDownConv:
gen(p, n[0], r)
of nkHiddenDeref, nkDerefExpr:
if n.kind in {nkAddr, nkHiddenAddr}:
# addr ( deref ( x )) --> x
gen(p, n[0][0], r)
else:
gen(p, n[0], r)
gen(p, n[0], r)
of nkHiddenAddr:
gen(p, n[0], r)
of nkConv:
@@ -1857,9 +1837,7 @@ proc genPatternCall(p: PProc; n: PNode; pat: string; typ: PType;
proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
# don't call '$' here for efficiency:
let f = n[0].sym
if f.loc.snippet == "":
ensureMutable f
f.locImpl.snippet = mangleName(p.module, f)
if f.loc.snippet == "": f.loc.snippet = mangleName(p.module, f)
if sfInfixCall in f.flags:
let pat = $n[0].sym.loc.snippet
internalAssert p.config, pat.len > 0
@@ -2351,8 +2329,8 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
r.res = "if (null != $1) { if (null == $2) $2 = $3; else $2 += $3; }" %
[b, lhs.rdLoc, tmp]
else:
useMagic(p, "nimAddStrStr")
r.res = "nimAddStrStr($1, $2);" % [lhs.rdLoc, rhs.rdLoc]
let (a, tmp) = maybeMakeTemp(p, n[1], lhs)
r.res = "$1.push.apply($3, $2);" % [a, rhs.rdLoc, tmp]
r.kind = resExpr
of mAppendSeqElem:
var x, y: TCompRes = default(TCompRes)
@@ -2595,9 +2573,7 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
let val = it[1]
gen(p, val, a)
var f = it[0].sym
if f.loc.snippet == "":
ensureMutable f
f.locImpl.snippet = mangleName(p.module, f)
if f.loc.snippet == "": f.loc.snippet = mangleName(p.module, f)
fieldIDs.incl(lookupFieldAgain(n.typ.skipTypes({tyDistinct}), f).id)
let typ = val.typ.skipTypes(abstractInst)
@@ -2899,8 +2875,6 @@ proc genCast(p: PProc, n: PNode, r: var TCompRes) =
elif dest.kind in tyFloat..tyFloat64:
if src.kind in {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions:
r.res = "Number($1)" % [r.res]
elif dest.kind == tyChar and (fromInt or fromUint):
r.res = "($1 & 255)" % [r.res]
elif (src.kind == tyPtr and mapType(p, src) == etyObject) and dest.kind == tyPointer:
r.address = r.res
r.res = "null"

View File

@@ -150,7 +150,6 @@ template isIterator*(owner: PSym): bool =
proc createEnvObj(g: ModuleGraph; idgen: IdGenerator; owner: PSym; info: TLineInfo): PType =
result = createObj(g, idgen, owner, info, final=false)
result.incl tfFinal
if owner.isIterator:
rawAddField(result, createStateField(g, owner, idgen))
@@ -161,7 +160,7 @@ proc getClosureIterResult*(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym
# XXX a bit hacky:
result = newSym(skResult, getIdent(g.cache, ":result"), idgen, iter, iter.info, {})
result.typ = iter.typ.returnType
incl(result.flagsImpl, sfUsed)
incl(result.flags, sfUsed)
iter.ast.add newSymNode(result)
proc addHiddenParam(routine: PSym, param: PSym) =
@@ -228,7 +227,7 @@ proc makeClosure*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; env: PNode; inf
#if isClosureIterator(result.typ):
createTypeBoundOps(g, nil, result.typ, info, idgen)
if tfHasAsgn in result.typ.flags or optSeqDestructors in g.config.globalOptions:
prc.incl sfInjectDestructors
prc.flags.incl sfInjectDestructors
template liftingHarmful(conf: ConfigRef; owner: PSym): bool =
## lambda lifting can be harmful for JS-like code generators.
@@ -240,7 +239,7 @@ proc createTypeBoundOpsLL(g: ModuleGraph; refType: PType; info: TLineInfo; idgen
createTypeBoundOps(g, nil, refType.elementType, info, idgen)
createTypeBoundOps(g, nil, refType, info, idgen)
if tfHasAsgn in refType.flags or optSeqDestructors in g.config.globalOptions:
owner.incl sfInjectDestructors
owner.flags.incl sfInjectDestructors
proc genCreateEnv(env: PNode): PNode =
var c = newNodeIT(nkObjConstr, env.info, env.typ)
@@ -290,7 +289,7 @@ proc markAsClosure(g: ModuleGraph; owner: PSym; n: PNode) =
elif not (owner.typ.isClosure or owner.isNimcall and not owner.isExplicitCallConv or isEnv):
localError(g.config, n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" %
[s.name.s, owner.name.s, $owner.typ.callConv])
incl(owner.typ, tfCapturesEnv)
incl(owner.typ.flags, tfCapturesEnv)
if not isEnv:
owner.typ.callConv = ccClosure
@@ -336,7 +335,7 @@ proc asOwnedRef(c: var DetectionPass; t: PType): PType =
if optOwnedRefs in c.graph.config.globalOptions:
assert t.kind == tyRef
result = newType(tyOwned, c.idgen, t.owner)
result.incl tfHasOwned
result.flags.incl tfHasOwned
result.rawAddSon t
else:
result = t
@@ -414,7 +413,7 @@ proc addClosureParam(c: var DetectionPass; fn: PSym; info: TLineInfo) =
let t = c.getEnvTypeForOwner(owner, info)
if cp == nil:
cp = newSym(skParam, getIdent(c.graph.cache, paramName), c.idgen, fn, fn.info)
incl(cp.flagsImpl, sfFromGeneric)
incl(cp.flags, sfFromGeneric)
cp.typ = t
addHiddenParam(fn, cp)
elif cp.typ != t and fn.kind != skIterator:
@@ -610,7 +609,7 @@ proc rawClosureCreation(owner: PSym;
let unowned = c.unownedEnvVars[owner.id]
assert unowned != nil
let env2 = copyTree(env)
env2.typ = unowned.typ
env2.typ() = unowned.typ
result.add newAsgnStmt(unowned, env2, env.info)
createTypeBoundOpsLL(d.graph, unowned.typ, env.info, d.idgen, owner)
@@ -624,7 +623,7 @@ proc rawClosureCreation(owner: PSym;
if owner.kind != skMacro:
createTypeBoundOps(d.graph, nil, fieldAccess.typ, env.info, d.idgen)
if tfHasAsgn in fieldAccess.typ.flags or optSeqDestructors in d.graph.config.globalOptions:
owner.incl sfInjectDestructors
owner.flags.incl sfInjectDestructors
let upField = lookupInRecord(env.typ.skipTypes({tyOwned, tyRef, tyPtr}).n, getIdent(d.graph.cache, upName))
if upField != nil:
@@ -666,7 +665,7 @@ proc closureCreationForIter(owner: PSym, iter: PNode;
result = newNodeIT(nkStmtListExpr, iter.info, iter.sym.typ)
let iterOwner = iter.sym.skipGenericOwner
var v = newSym(skVar, getIdent(d.graph.cache, envName), d.idgen, iterOwner, iter.info)
incl(v.flagsImpl, sfShadowed)
incl(v.flags, sfShadowed)
v.typ = asOwnedRef(d, getHiddenParam(d.graph, iter.sym).typ)
var vnode: PNode
if iterOwner.isIterator:
@@ -787,7 +786,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: var DetectionPass;
let oldInContainer = c.inContainer
c.inContainer = 0
let m = newSymNode(n[namePos].sym)
m.typ = n.typ
m.typ() = n.typ
result = liftCapturedVars(m, owner, d, c)
c.inContainer = oldInContainer
of nkHiddenStdConv:
@@ -975,20 +974,6 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; idgen: IdGenerator; owner: PSym):
for i in 0..<op.len-1:
result.add op[i]
elif op.kind != nkSym: # might have side effects
# bug #25046
# create a temp for the closure
# var :closureTemp
# :closureTemp = ...
let tempSym = newSym(skLet, getIdent(g.cache, ":closureTemp"), idgen, owner, body.info)
tempSym.typ = call[0].typ
let temp = newSymNode(tempSym)
var v = newNodeI(nkVarSection, body.info)
addVar(v, temp)
result.add(v)
result.add newAsgnStmt(temp, call[0], body.info)
call[0] = temp
var loopBody = newNodeI(nkStmtList, body.info, 3)
var whileLoop = newNodeI(nkWhileStmt, body.info, 2)
whileLoop[0] = newIntTypeNode(1, getSysType(g, body.info, tyBool))

View File

@@ -1,3 +1,4 @@
import std/[tables]
import ast, astalgo
type

View File

@@ -316,28 +316,6 @@ proc getNumber(L: var Lexer, result: var Token) =
L.bufpos = msgPos
lexMessage(L, msgKind, msg % t.literal)
proc checkBitWidth(L: var Lexer, base: NumericalBase, tokType: TokType,
numDigits: int, startpos: int) =
# Check bit width for non-base-10 literals
# Warn if the digit count exceeds what can fit in the target type
let bitsPerDigit = case base
of base2: 1
of base8: 3
of base16: 4
else: raiseAssert "unreachable"
let bitWidth = case tokType
of tkInt8Lit, tkUInt8Lit: 8
of tkInt16Lit, tkUInt16Lit: 16
of tkInt32Lit, tkUInt32Lit: 32
of tkInt64Lit, tkUIntLit, tkIntLit, tkUInt64Lit: 64
else: raiseAssert "unreachable"
# Maximum digits = ceil(bitWidth / bitsPerDigit) = (bitWidth + bitsPerDigit - 1) div bitsPerDigit
let maxDigits = (bitWidth + bitsPerDigit - 1) div bitsPerDigit
if numDigits > maxDigits:
lexMessageLitNum(L,
"number has " & $numDigits & " digits but type only supports " &
$maxDigits & " digits: '$1'", startpos, warnLongLiterals)
var
xi: BiggestInt
isBase10 = true
@@ -513,11 +491,6 @@ proc getNumber(L: var Lexer, result: var Token) =
setNumber result.fNumber, (cast[ptr float64](addr(xi)))[]
else: internalError(L.config, getLineInfo(L), "getNumber")
# Check bit width for non-base-10 literals
# Warn if the digit count exceeds what can fit in the target type
if result.base != base10 and result.tokType in {tkIntLit..tkUInt64Lit} and numDigits > 0:
checkBitWidth(L, result.base, result.tokType, numDigits, startpos)
# Bounds checks. Non decimal literals are allowed to overflow the range of
# the datatype as long as their pattern don't overflow _bitwise_, hence
# below checks of signed sizes against uint*.high is deliberate:
@@ -923,7 +896,7 @@ proc getSymbol(L: var Lexer, tok: var Token) =
tok.tokType = tkSymbol
else:
tok.tokType = TokType(tok.ident.id + ord(tkSymbol))
if suspicious and {optStyleHint, optStyleError, optStyleWarning} * L.config.globalOptions != {}:
if suspicious and {optStyleHint, optStyleError} * L.config.globalOptions != {}:
lintReport(L.config, getLineInfo(L), tok.ident.s.normalize, tok.ident.s)
L.bufpos = pos

View File

@@ -49,7 +49,7 @@ proc at(a, i: PNode, elemType: PType): PNode =
result = newNodeI(nkBracketExpr, a.info, 2)
result[0] = a
result[1] = i
result.typ = elemType
result.typ() = elemType
proc destructorOverridden(g: ModuleGraph; t: PType): bool =
let op = getAttachedOp(g, t, attachedDestructor)
@@ -68,7 +68,7 @@ proc dotField(x: PNode, f: PSym): PNode =
else:
result[0] = x
result[1] = newSymNode(f, x.info)
result.typ = f.typ
result.typ() = f.typ
proc newAsgnStmt(le, ri: PNode): PNode =
result = newNodeI(nkAsgn, le.info, 2)
@@ -88,7 +88,7 @@ proc defaultOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add newAsgnStmt(x, y)
elif c.kind == attachedDestructor and c.addMemReset:
let call = genBuiltin(c, mDefault, "default", x)
call.typ = t
call.typ() = t
body.add newAsgnStmt(x, call)
elif c.kind == attachedWasMoved:
body.add genBuiltin(c, mWasMoved, "wasMoved", x)
@@ -105,7 +105,7 @@ proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode =
result = newNodeI(nkWhileStmt, c.info, 2)
let cmp = genBuiltin(c, mLtI, "<", i)
cmp.add genLen(c.g, dest)
cmp.typ = getSysType(c.g, c.info, tyBool)
cmp.typ() = getSysType(c.g, c.info, tyBool)
result[0] = cmp
result[1] = newNodeI(nkStmtList, c.info)
@@ -127,10 +127,10 @@ proc genContainerOf(c: var TLiftCtx; objType: PType, field, x: PSym): PNode =
dotExpr.add newSymNode(field)
let offsetOf = genBuiltin(c, mOffsetOf, "offsetof", dotExpr)
offsetOf.typ = intType
offsetOf.typ() = intType
let minusExpr = genBuiltin(c, mSubI, "-", castExpr1)
minusExpr.typ = intType
minusExpr.typ() = intType
minusExpr.add offsetOf
let objPtr = makePtrType(objType.owner, objType, c.idgen)
@@ -163,7 +163,7 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool,
if c.filterDiscriminator != nil: return
let f = n.sym
let b = if c.kind == attachedTrace: y else: y.dotField(f)
if (sfCursor in f.flags and c.g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc, gcYrc, gcHooks}) or
if (sfCursor in f.flags and c.g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc, gcHooks}) or
enforceDefaultOp:
defaultOp(c, f.typ, body, x.dotField(f), b)
else:
@@ -280,11 +280,11 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
# because the wasMoved(dest) call would zero out src, if dest aliases src.
var cond = newTree(nkCall, newSymNode(c.g.getSysMagic(c.info, "==", mEqRef)),
newTreeIT(nkAddr, c.info, makePtrType(c.fn, x.typ, c.idgen), x), newTreeIT(nkAddr, c.info, makePtrType(c.fn, y.typ, c.idgen), y))
cond.typ = getSysType(c.g, x.info, tyBool)
cond.typ() = getSysType(c.g, x.info, tyBool)
body.add genIf(c, cond, newTreeI(nkReturnStmt, c.info, newNodeI(nkEmpty, c.info)))
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
temp.typ = x.typ
incl(temp, sfFromGeneric)
incl(temp.flags, sfFromGeneric)
var v = newNodeI(nkVarSection, c.info)
let blob = newSymNode(temp)
v.addVar(blob, x)
@@ -312,7 +312,7 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
proc boolLit*(g: ModuleGraph; info: TLineInfo; value: bool): PNode =
result = newIntLit(g, info, ord value)
result.typ = getSysType(g, info, tyBool)
result.typ() = getSysType(g, info, tyBool)
proc getCycleParam(c: TLiftCtx): PNode =
assert c.kind in {attachedAsgn, attachedDup}
@@ -380,10 +380,6 @@ proc requiresDestructor(c: TLiftCtx; t: PType): bool {.inline.} =
proc instantiateGeneric(c: var TLiftCtx; op: PSym; t, typeInst: PType): PSym =
if c.c != nil and typeInst != nil:
result = c.c.instTypeBoundOp(c.c, op, typeInst, c.info, attachedAsgn, 1)
elif typeInst != nil and getAttachedOp(c.g, typeInst, c.kind) != nil:
# c.c == nil in lambdalifting
# hooks are already insted
result = getAttachedOp(c.g, typeInst, c.kind)
else:
localError(c.g.config, c.info,
"cannot generate destructor for generic type: " & typeToString(t))
@@ -397,8 +393,7 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
if op != nil and op != c.fn and
(sfOverridden in op.flags or destructorOverridden):
if sfError in op.flags:
ensureMutable c.fn
incl c.fn.flagsImpl, sfError
incl c.fn.flags, sfError
#else:
# markUsed(c.g.config, c.info, op, c.g.usageSym)
onUse(c.info, op)
@@ -424,8 +419,7 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
if op == nil:
op = produceSym(c.g, c.c, t, c.kind, c.info, c.idgen)
if sfError in op.flags:
ensureMutable c.fn
incl c.fn.flagsImpl, sfError
incl c.fn.flags, sfError
#else:
# markUsed(c.g.config, c.info, op, c.g.usageSym)
onUse(c.info, op)
@@ -541,7 +535,7 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
temp.typ = getSysType(c.g, body.info, tyInt)
incl(temp.flagsImpl, sfFromGeneric)
incl(temp.flags, sfFromGeneric)
var v = newNodeI(nkVarSection, c.info)
result = newSymNode(temp)
@@ -551,29 +545,13 @@ proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
proc declareTempOf(c: var TLiftCtx; body: PNode; value: PNode): PNode =
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
temp.typ = value.typ
incl(temp.flagsImpl, sfFromGeneric)
incl(temp.flags, sfFromGeneric)
var v = newNodeI(nkVarSection, c.info)
result = newSymNode(temp)
v.addVar(result, value)
body.add v
proc considerInferDupFromCopy(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
## For `=dup`, if no explicit hook exists, try to infer from `=copy` hook
## to maintain backward compatibility. Returns true if inference was applied.
if c.kind == attachedDup:
var op2 = getAttachedOp(c.g, t, attachedAsgn)
if op2 != nil and sfOverridden in op2.flags:
#markUsed(c.g.config, c.info, op, c.g.usageSym)
onUse(c.info, op2)
body.add genBuiltin(c, mWasMoved, "wasMoved", x)
body.add newHookCall(c, op2, x, y)
result = true
else:
result = false
else:
result = false
proc addIncStmt(c: var TLiftCtx; body, i: PNode) =
let incCall = genBuiltin(c, mInc, "inc", i)
incCall.add lowerings.newIntLit(c.g, c.info, 1)
@@ -583,18 +561,18 @@ proc newSeqCall(c: var TLiftCtx; x, y: PNode): PNode =
# don't call genAddr(c, x) here:
result = genBuiltin(c, mNewSeq, "newSeq", x)
let lenCall = genBuiltin(c, mLengthSeq, "len", y)
lenCall.typ = getSysType(c.g, x.info, tyInt)
lenCall.typ() = getSysType(c.g, x.info, tyInt)
result.add lenCall
proc setLenStrCall(c: var TLiftCtx; x, y: PNode): PNode =
let lenCall = genBuiltin(c, mLengthStr, "len", y)
lenCall.typ = getSysType(c.g, x.info, tyInt)
lenCall.typ() = getSysType(c.g, x.info, tyInt)
result = genBuiltin(c, mSetLengthStr, "setLen", x) # genAddr(g, x))
result.add lenCall
proc setLenSeqCall(c: var TLiftCtx; t: PType; x, y: PNode): PNode =
let lenCall = genBuiltin(c, mLengthSeq, "len", y)
lenCall.typ = getSysType(c.g, x.info, tyInt)
lenCall.typ() = getSysType(c.g, x.info, tyInt)
var op = getSysMagic(c.g, x.info, "setLen", mSetLengthSeq)
op = instantiateGeneric(c, op, t, t)
result = newTree(nkCall, newSymNode(op, x.info), x, lenCall)
@@ -617,7 +595,7 @@ proc checkSelfAssignment(c: var TLiftCtx; t: PType; body, x, y: PNode) =
newTreeIT(nkAddr, c.info, makePtrType(c.fn, x.typ, c.idgen), x),
newTreeIT(nkAddr, c.info, makePtrType(c.fn, y.typ, c.idgen), y)
)
cond.typ = getSysType(c.g, c.info, tyBool)
cond.typ() = getSysType(c.g, c.info, tyBool)
body.add genIf(c, cond, newTreeI(nkReturnStmt, c.info, newNodeI(nkEmpty, c.info)))
proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
@@ -737,43 +715,14 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
dest[] = source
decRef tmp
For YRC the write barrier is more complicated still and must be:
let tmp = dest
# assignment must come first so that the collector sees the most-recent graph:
atomic: dest[] = source
# Then teach the cycle collector about the changes edge (these use locks, see yrc.nim):
incRef source
decRef tmp
This is implemented as a single runtime call (nimAsgnYrc / nimSinkYrc).
]#
var actions = newNodeI(nkStmtList, c.info)
let elemType = t.elementType
createTypeBoundOps(c.g, c.c, elemType, c.info, c.idgen)
let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(c.g, elemType)
# YRC uses dedicated runtime procs for the entire write barrier:
if c.g.config.selectedGC == gcYrc:
let desc =
if isFinal(elemType):
let ti = genBuiltin(c, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType))
ti.typ = getSysType(c.g, c.info, tyPointer)
ti
else:
newNodeIT(nkNilLit, c.info, getSysType(c.g, c.info, tyPointer))
case c.kind
of attachedAsgn, attachedDup:
body.add callCodegenProc(c.g, "nimAsgnYrc", c.info, genAddr(c, x), y, desc)
return
of attachedSink:
body.add callCodegenProc(c.g, "nimSinkYrc", c.info, genAddr(c, x), y, desc)
return
else: discard # fall through for destructor, trace, wasMoved
let isCyclic = c.g.config.selectedGC in {gcOrc, gcYrc} and types.canFormAcycle(c.g, elemType)
let isInheritableAcyclicRef = c.g.config.selectedGC in {gcOrc, gcYrc} and
let isInheritableAcyclicRef = c.g.config.selectedGC == gcOrc and
(not isPureObject(elemType)) and
tfAcyclic in skipTypes(elemType, abstractInst+{tyOwned}-{tyTypeDesc}).flags
# dynamic Acyclic refs need to use dyn decRef
@@ -787,7 +736,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if isFinal(elemType):
addDestructorCall(c, elemType, actions, genDeref(tmp, nkDerefExpr))
var alignOf = genBuiltin(c, mAlignOf, "alignof", newNodeIT(nkType, c.info, elemType))
alignOf.typ = getSysType(c.g, c.info, tyInt)
alignOf.typ() = getSysType(c.g, c.info, tyInt)
actions.add callCodegenProc(c.g, "nimRawDispose", c.info, tmp, alignOf)
else:
addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(tmp, nkDerefExpr))
@@ -797,7 +746,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if isCyclic:
if isFinal(elemType):
let typInfo = genBuiltin(c, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType))
typInfo.typ = getSysType(c.g, c.info, tyPointer)
typInfo.typ() = getSysType(c.g, c.info, tyPointer)
cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicStatic", c.info, tmp, typInfo)
else:
cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicDyn", c.info, tmp)
@@ -805,7 +754,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
cond = callCodegenProc(c.g, "nimDecRefIsLastDyn", c.info, x)
else:
cond = callCodegenProc(c.g, "nimDecRefIsLast", c.info, x)
cond.typ = getSysType(c.g, x.info, tyBool)
cond.typ() = getSysType(c.g, x.info, tyBool)
case c.kind
of attachedSink:
@@ -832,7 +781,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if isCyclic:
if isFinal(elemType):
let typInfo = genBuiltin(c, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType))
typInfo.typ = getSysType(c.g, c.info, tyPointer)
typInfo.typ() = getSysType(c.g, c.info, tyPointer)
body.add callCodegenProc(c.g, "nimTraceRef", c.info, genAddrOf(x, c.idgen), typInfo, y)
else:
# If the ref is polymorphic we have to account for this
@@ -853,28 +802,9 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
## Closures are really like refs except they always use a virtual destructor
## and we need to do the refcounting only on the ref field which we call 'xenv':
let xenv = genBuiltin(c, mAccessEnv, "accessEnv", x)
xenv.typ = getSysType(c.g, c.info, tyPointer)
xenv.typ() = getSysType(c.g, c.info, tyPointer)
# Closures are (fnPtr, env) pairs. nimAsgnYrc/nimSinkYrc handle the env pointer
# (atomic store + buffered inc/dec). We also need newAsgnStmt to copy the fnPtr.
if c.g.config.selectedGC == gcYrc:
let nilDesc = newNodeIT(nkNilLit, c.info, getSysType(c.g, c.info, tyPointer))
let yenv = genBuiltin(c, mAccessEnv, "accessEnv", y)
yenv.typ = getSysType(c.g, c.info, tyPointer)
case c.kind
of attachedAsgn, attachedDup:
# nimAsgnYrc: save old env, atomic store new env, inc new env, dec old env
body.add callCodegenProc(c.g, "nimAsgnYrc", c.info, genAddr(c, xenv), yenv, nilDesc)
# Raw struct copy to also update the function pointer (env write is redundant but benign)
body.add newAsgnStmt(x, y)
return
of attachedSink:
body.add callCodegenProc(c.g, "nimSinkYrc", c.info, genAddr(c, xenv), yenv, nilDesc)
body.add newAsgnStmt(x, y)
return
else: discard # fall through for destructor, trace, wasMoved
let isCyclic = c.g.config.selectedGC in {gcOrc, gcYrc}
let isCyclic = c.g.config.selectedGC == gcOrc
let tmp =
if isCyclic and c.kind in {attachedAsgn, attachedSink, attachedDup}:
declareTempOf(c, body, xenv)
@@ -888,7 +818,7 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if isCyclic: "nimDecRefIsLastCyclicDyn"
else: "nimDecRefIsLast"
let cond = callCodegenProc(c.g, decRefProc, c.info, tmp)
cond.typ = getSysType(c.g, x.info, tyBool)
cond.typ() = getSysType(c.g, x.info, tyBool)
case c.kind
of attachedSink:
@@ -900,18 +830,19 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add newAsgnStmt(x, y)
of attachedAsgn:
let yenv = genBuiltin(c, mAccessEnv, "accessEnv", y)
yenv.typ = getSysType(c.g, c.info, tyPointer)
yenv.typ() = getSysType(c.g, c.info, tyPointer)
if isCyclic:
body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRefCyclic", c.info, yenv, getCycleParam(c)))
body.add newAsgnStmt(x, y)
body.add genIf(c, cond, actions)
else:
body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRef", c.info, yenv))
body.add genIf(c, cond, actions)
body.add newAsgnStmt(x, y)
of attachedDup:
let yenv = genBuiltin(c, mAccessEnv, "accessEnv", y)
yenv.typ = getSysType(c.g, c.info, tyPointer)
yenv.typ() = getSysType(c.g, c.info, tyPointer)
if isCyclic:
body.add newAsgnStmt(x, y)
body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRefCyclic", c.info, yenv, getCycleParam(c)))
@@ -963,7 +894,7 @@ proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if isFinal(elemType):
addDestructorCall(c, elemType, actions, genDeref(x, nkDerefExpr))
var alignOf = genBuiltin(c, mAlignOf, "alignof", newNodeIT(nkType, c.info, elemType))
alignOf.typ = getSysType(c.g, c.info, tyInt)
alignOf.typ() = getSysType(c.g, c.info, tyInt)
actions.add callCodegenProc(c.g, "nimRawDispose", c.info, x, alignOf)
else:
addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(x, nkDerefExpr))
@@ -986,14 +917,14 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
# a big problem is that we don't know the environment's type here, so we
# have to go through some indirection; we delegate this to the codegen:
let call = newNodeI(nkCall, c.info, 2)
call.typ = t
call.typ() = t
call[0] = newSymNode(createMagic(c.g, c.idgen, "deepCopy", mDeepCopy))
call[1] = y
body.add newAsgnStmt(x, call)
elif (optOwnedRefs in c.g.config.globalOptions and
optRefCheck in c.g.config.options) or c.g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc, gcYrc}:
optRefCheck in c.g.config.options) or c.g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
let xx = genBuiltin(c, mAccessEnv, "accessEnv", x)
xx.typ = getSysType(c.g, c.info, tyPointer)
xx.typ() = getSysType(c.g, c.info, tyPointer)
case c.kind
of attachedSink:
# we 'nil' y out afterwards so we *need* to take over its reference
@@ -1002,13 +933,13 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add newAsgnStmt(x, y)
of attachedAsgn:
let yy = genBuiltin(c, mAccessEnv, "accessEnv", y)
yy.typ = getSysType(c.g, c.info, tyPointer)
yy.typ() = getSysType(c.g, c.info, tyPointer)
body.add genIf(c, yy, callCodegenProc(c.g, "nimIncRef", c.info, yy))
body.add genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx))
body.add newAsgnStmt(x, y)
of attachedDup:
let yy = genBuiltin(c, mAccessEnv, "accessEnv", y)
yy.typ = getSysType(c.g, c.info, tyPointer)
yy.typ() = getSysType(c.g, c.info, tyPointer)
body.add newAsgnStmt(x, y)
body.add genIf(c, yy, callCodegenProc(c.g, "nimIncRef", c.info, yy))
of attachedDestructor:
@@ -1023,7 +954,7 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
let xx = genBuiltin(c, mAccessEnv, "accessEnv", x)
xx.typ = getSysType(c.g, c.info, tyPointer)
xx.typ() = getSysType(c.g, c.info, tyPointer)
var actions = newNodeI(nkStmtList, c.info)
#discard addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(xx))
actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, xx)
@@ -1046,7 +977,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
tyPtr, tyUncheckedArray, tyVar, tyLent:
defaultOp(c, t, body, x, y)
of tyRef:
if c.g.config.selectedGC in {gcArc, gcOrc, gcYrc, gcAtomicArc}:
if c.g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
atomicRefOp(c, t, body, x, y)
elif (optOwnedRefs in c.g.config.globalOptions and
optRefCheck in c.g.config.options):
@@ -1055,7 +986,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
defaultOp(c, t, body, x, y)
of tyProc:
if t.callConv == ccClosure:
if c.g.config.selectedGC in {gcArc, gcOrc, gcYrc, gcAtomicArc}:
if c.g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
atomicClosureOp(c, t, body, x, y)
else:
closureOp(c, t, body, x, y)
@@ -1113,15 +1044,20 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add genBuiltin(c, mWasMoved, "wasMoved", x)
else:
fillBodyObjT(c, t, body, x, y)
elif tfUnion in t.flags: # bug #25236
defaultOp(c, t, body, x, y)
else:
if not considerInferDupFromCopy(c, t, body, x, y):
if c.kind == attachedDup:
var op2 = getAttachedOp(c.g, t, attachedAsgn)
if op2 != nil and sfOverridden in op2.flags:
#markUsed(c.g.config, c.info, op, c.g.usageSym)
onUse(c.info, op2)
body.add newHookCall(c, t.assignment, x, y)
else:
fillBodyObjT(c, t, body, x, y)
else:
fillBodyObjT(c, t, body, x, y)
of tyDistinct:
if not considerUserDefinedOp(c, t, body, x, y):
if not considerInferDupFromCopy(c, t, body, x, y):
fillBody(c, t.elementType, body, x, y)
fillBody(c, t.elementType, body, x, y)
of tyTuple:
fillBodyTup(c, t, body, x, y)
of tyVarargs, tyOpenArray:
@@ -1168,7 +1104,7 @@ proc symDupPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttache
result.typ.addParam src
if g.config.selectedGC in {gcOrc, gcYrc} and
if g.config.selectedGC == gcOrc and
cyclicType(g, typ.skipTypes(abstractInst)):
let cycleParam = newSym(skParam, getIdent(g.cache, "cyclic"),
idgen, result, info)
@@ -1182,7 +1118,8 @@ proc symDupPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttache
n[bodyPos] = newNodeI(nkStmtList, info)
n[resultPos] = newSymNode(res)
result.ast = n
incl result.flagsImpl, {sfFromGeneric, sfGeneratedOp}
incl result.flags, sfFromGeneric
incl result.flags, sfGeneratedOp
proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp;
info: TLineInfo; idgen: IdGenerator; isDiscriminant = false): PSym =
@@ -1195,7 +1132,7 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
let src = newSym(skParam, getIdent(g.cache, if kind == attachedTrace: "env" else: "src"),
idgen, result, info)
if kind == attachedDestructor and g.config.selectedGC in {gcArc, gcOrc, gcYrc, gcAtomicArc} and
if kind == attachedDestructor and g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc} and
((g.config.isDefined("nimPreviewNonVarDestructor") and not isDiscriminant) or (typ.kind in {tyRef, tyString, tySequence})):
dest.typ = typ
else:
@@ -1211,7 +1148,7 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
if kind notin {attachedDestructor, attachedWasMoved}:
result.typ.addParam src
if kind == attachedAsgn and g.config.selectedGC in {gcOrc, gcYrc} and
if kind == attachedAsgn and g.config.selectedGC == gcOrc and
cyclicType(g, typ.skipTypes(abstractInst)):
let cycleParam = newSym(skParam, getIdent(g.cache, "cyclic"),
idgen, result, info)
@@ -1224,33 +1161,23 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
n[paramsPos] = result.typ.n
n[bodyPos] = newNodeI(nkStmtList, info)
result.ast = n
incl result.flagsImpl, sfFromGeneric
incl result.flagsImpl, sfGeneratedOp
incl result.flags, sfFromGeneric
incl result.flags, sfGeneratedOp
if kind == attachedWasMoved:
incl result.flagsImpl, sfNoSideEffect
incl result.typ, tfNoSideEffect
incl result.flags, sfNoSideEffect
incl result.typ.flags, tfNoSideEffect
proc genTypeFieldCopy(c: var TLiftCtx; t: PType; body, x, y: PNode) =
let xx = genBuiltin(c, mAccessTypeField, "accessTypeField", x)
let yy = genBuiltin(c, mAccessTypeField, "accessTypeField", y)
xx.typ = getSysType(c.g, c.info, tyPointer)
yy.typ = xx.typ
xx.typ() = getSysType(c.g, c.info, tyPointer)
yy.typ() = xx.typ
body.add newAsgnStmt(xx, yy)
proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
info: TLineInfo; idgen: IdGenerator): PSym =
if typ.kind == tyDistinct:
# For =dup, if the distinct type has a user-defined =copy, don't delegate
# to the base type. Instead fall through to the normal produceSym logic
# so that fillBody -> considerInferDupFromCopy can synthesize =dup from =copy.
if kind == attachedDup:
let copyOp = getAttachedOp(g, typ, attachedAsgn)
if copyOp != nil and sfOverridden in copyOp.flags:
discard "fall through to normal produceSym logic"
else:
return produceSymDistinctType(g, c, typ, kind, info, idgen)
else:
return produceSymDistinctType(g, c, typ, kind, info, idgen)
return produceSymDistinctType(g, c, typ, kind, info, idgen)
result = getAttachedOp(g, typ, kind)
if result == nil:
@@ -1271,48 +1198,35 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
if kind == attachedSink and destructorOverridden(g, typ):
## compiler can use a combination of `=destroy` and memCopy for sink op
ensureMutable dest
dest.flagsImpl.incl sfCursor
dest.flags.incl sfCursor
let op = getAttachedOp(g, typ, attachedDestructor)
result.ast[bodyPos].add newOpCall(a, op, if op.typ.firstParamType.kind == tyVar: d[0] else: d)
result.ast[bodyPos].add newAsgnStmt(d, src)
else:
var tk: TTypeKind
var skipped: PType = nil
if g.config.selectedGC in {gcArc, gcOrc, gcYrc, gcHooks, gcAtomicArc}:
skipped = skipTypes(typ, {tyOrdinal, tyRange, tyInferred, tyGenericInst, tyStatic, tyAlias, tySink})
tk = skipped.kind
if g.config.selectedGC in {gcArc, gcOrc, gcHooks, gcAtomicArc}:
tk = skipTypes(typ, {tyOrdinal, tyRange, tyInferred, tyGenericInst, tyStatic, tyAlias, tySink}).kind
else:
tk = tyNone # no special casing for strings and seqs
case tk
of tySequence:
let needsYrcLock = g.config.selectedGC == gcYrc and
kind in {attachedDestructor, attachedSink, attachedAsgn, attachedDeepCopy, attachedDup} and
types.canFormAcycle(g, skipped.elementType)
# YRC: topology-changing seq ops must hold the mutator (read) lock
if needsYrcLock:
result.ast[bodyPos].add callCodegenProc(g, "acquireMutatorLock", info)
fillSeqOp(a, typ, result.ast[bodyPos], d, src)
if needsYrcLock:
result.ast[bodyPos].add callCodegenProc(g, "releaseMutatorLock", info)
of tyString:
fillStrOp(a, typ, result.ast[bodyPos], d, src)
else:
fillBody(a, typ, result.ast[bodyPos], d, src)
if tk == tyObject and a.kind in {attachedAsgn, attachedSink, attachedDeepCopy, attachedDup} and not isObjLackingTypeField(skipped):
if tk == tyObject and a.kind in {attachedAsgn, attachedSink, attachedDeepCopy, attachedDup} and not isObjLackingTypeField(typ):
# bug #19205: Do not forget to also copy the hidden type field:
genTypeFieldCopy(a, typ, result.ast[bodyPos], d, src)
if not a.canRaise:
ensureMutable result
incl result.flagsImpl, sfNeverRaises
incl result.flags, sfNeverRaises
result.ast[pragmasPos] = newNodeI(nkPragma, info)
result.ast[pragmasPos].add newTree(nkExprColonExpr,
newIdentNode(g.cache.getIdent("raises"), info), newNodeI(nkBracket, info))
if kind == attachedDestructor:
ensureMutable result
incl result.optionsImpl, optQuirky
incl result.options, optQuirky
completePartialOp(g, idgen.module, typ, kind, result)
@@ -1337,9 +1251,7 @@ proc produceDestructorForDiscriminator*(g: ModuleGraph; typ: PType; field: PSym,
result.ast[bodyPos].add v
let placeHolder = newNodeIT(nkSym, info, getSysType(g, info, tyPointer))
fillBody(a, typ, result.ast[bodyPos], d, placeHolder)
if not a.canRaise:
ensureMutable result
incl result.flagsImpl, sfNeverRaises
if not a.canRaise: incl result.flags, sfNeverRaises
template liftTypeBoundOps*(c: PContext; typ: PType; info: TLineInfo) =
@@ -1383,13 +1295,11 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf
## to ensure we lift assignment, destructors and moves properly.
## The later 'injectdestructors' pass depends on it.
if orig == nil or {tfCheckedForDestructor, tfHasMeta} * orig.flags != {}: return
# IC: review this solution again later
incl orig.flagsImpl, tfCheckedForDestructor
incl orig.flags, tfCheckedForDestructor
# for user defined generic destructors:
let origRoot = genericRoot(orig)
if origRoot != nil:
# IC: review this solution again later
incl origRoot.flagsImpl, tfGenericHasDestructor
incl origRoot.flags, tfGenericHasDestructor
let skipped = orig.skipTypes({tyGenericInst, tyAlias, tySink})
if isEmptyContainer(skipped) or skipped.kind == tyStatic: return
@@ -1409,13 +1319,13 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf
# we do not generate '=trace' procs if we
# have the cycle detection disabled, saves code size.
let lastAttached = if g.config.selectedGC in {gcOrc, gcYrc}: attachedTrace
let lastAttached = if g.config.selectedGC == gcOrc: attachedTrace
else: attachedSink
# bug #15122: We need to produce all prototypes before entering the
# mind boggling recursion. Hacks like these imply we should rewrite
# this module.
var generics = default(array[attachedWasMoved..attachedTrace, bool])
var generics: array[attachedWasMoved..attachedTrace, bool] = default(array[attachedWasMoved..attachedTrace, bool])
for k in attachedWasMoved..lastAttached:
generics[k] = getAttachedOp(g, canon, k) != nil
if not generics[k]:
@@ -1434,6 +1344,5 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf
if not isTrivial(getAttachedOp(g, orig, attachedDestructor)):
#or not isTrivial(orig.assignment) or
# not isTrivial(orig.sink):
# IC: review this solution again later
orig.flagsImpl.incl tfHasAsgn
orig.flags.incl tfHasAsgn
# ^ XXX Breaks IC!

View File

@@ -32,12 +32,12 @@ proc interestingVar(s: PSym): bool {.inline.} =
proc lookupOrAdd(c: var Ctx; s: PSym; info: TLineInfo): PNode =
let field = addUniqueField(c.objType, s, c.cache, c.idgen)
var deref = newNodeI(nkHiddenDeref, info)
deref.typ = c.objType
deref.typ() = c.objType
deref.add(newSymNode(c.partialParam, info))
result = newNodeI(nkDotExpr, info)
result.add(deref)
result.add(newSymNode(field))
result.typ = field.typ
result.typ() = field.typ
proc liftLocals(n: PNode; i: int; c: var Ctx) =
let it = n[i]

View File

@@ -93,13 +93,10 @@ type
warnBareExcept = "BareExcept",
warnImplicitDefaultValue = "ImplicitDefaultValue",
warnIgnoredSymbolInjection = "IgnoredSymbolInjection",
warnStdPrefix = "StdPrefix",
warnUnknownNotes = "UnknownNotes",
warnLongLiterals = "LongLiterals",
warnStdPrefix = "StdPrefix"
warnUnknownNotes = "UnknownNotes"
warnUser = "User",
warnGlobalVarConstructorTemporary = "GlobalVarConstructorTemporary",
warnImplicitRangeConversion = "ImplicitRangeConversion",
warnSystemRangeConversion = "SystemRangeConversion",
# hints
hintSuccess = "Success", hintSuccessX = "SuccessX",
hintCC = "CC",
@@ -205,11 +202,8 @@ const
warnIgnoredSymbolInjection: "$1",
warnStdPrefix: "$1 needs the 'std' prefix",
warnUnknownNotes: "$1",
warnLongLiterals: "$1",
warnUser: "$1",
warnGlobalVarConstructorTemporary: "global variable '$1' initialization requires a temporary variable",
warnImplicitRangeConversion: "implicit range conversion $1",
warnSystemRangeConversion: "implicit range conversion $1",
hintSuccess: "operation successful: $#",
# keep in sync with `testament.isSuccess`
hintSuccessX: "$build\n$loc lines; ${sec}s; $mem; proj: $project; out: $output",
@@ -264,7 +258,7 @@ type
proc computeNotesVerbosity(): array[0..3, TNoteKinds] =
result = default(array[0..3, TNoteKinds])
result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv, warnBareExcept, warnStdPrefix, warnSystemRangeConversion}
result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv, warnBareExcept, warnStdPrefix}
result[2] = result[3] - {hintStackTrace, hintExtendedContext, hintDeclaredLoc, hintProcessingStmt}
result[1] = result[2] - {warnProveField, warnProveIndex,
warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd,
@@ -279,10 +273,6 @@ const
errFloatToString* = "cannot convert '$1' to '$2'"
type
FileInfoKind* = enum
fikSource, ## A real source file path
fikNifModule ## A NIF module suffix (not a real path)
TFileInfo* = object
fullPath*: AbsoluteFile # This is a canonical full filesystem path
projPath*: RelativeFile # This is relative to the project's root
@@ -301,7 +291,6 @@ type
# for 'nimsuggest'
hash*: string # the checksum of the file
dirty*: bool # for 'nimpretty' like tooling
kind*: FileInfoKind # distinguishes real files from NIF suffixes
when defined(nimpretty):
fullContent*: string
FileIndex* = distinct int32

View File

@@ -95,7 +95,7 @@ proc nep1CheckDefImpl(conf: ConfigRef; info: TLineInfo; s: PSym; k: TSymKind) =
template styleCheckDef*(ctx: PContext; info: TLineInfo; sym: PSym; k: TSymKind) =
## Check symbol definitions adhere to NEP1 style rules.
if optStyleCheck in ctx.config.options and # ignore if styleChecks are off
{optStyleHint, optStyleError, optStyleWarning} * ctx.config.globalOptions != {} and # check only if hint/error/warning is enabled
{optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # check only if hint/error is enabled
hintName in ctx.config.notes and # ignore if name checks are not requested
ctx.config.belongsToProjectPackageMaybeNil(getModule(ctx.graph, info.fileIndex)) and # ignore foreign packages
optStyleUsages notin ctx.config.globalOptions and # ignore if requested to only check name usage
@@ -136,7 +136,7 @@ proc styleCheckUseImpl(conf: ConfigRef; info: TLineInfo; s: PSym) =
template styleCheckUse*(ctx: PContext; info: TLineInfo; sym: PSym) =
## Check symbol uses match their definition's style.
if {optStyleHint, optStyleError, optStyleWarning} * ctx.config.globalOptions != {} and # ignore if styleChecks are off
if {optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # ignore if styleChecks are off
hintName in ctx.config.notes and # ignore if name checks are not requested
ctx.config.belongsToProjectPackageMaybeNil(getModule(ctx.graph, info.fileIndex)) and # ignore foreign packages
sym.kind != skTemp and # ignore temporary variables created by the compiler
@@ -152,7 +152,7 @@ proc checkPragmaUseImpl(conf: ConfigRef; info: TLineInfo; w: TSpecialWord; pragm
template checkPragmaUse*(ctx: PContext; info: TLineInfo; w: TSpecialWord; pragmaName: string, sym: PSym) =
## Check builtin pragma uses match their definition's style.
## Note: This only applies to builtin pragmas, not user pragmas.
if {optStyleHint, optStyleError, optStyleWarning} * ctx.config.globalOptions != {} and # ignore if styleChecks are off
if {optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # ignore if styleChecks are off
hintName in ctx.config.notes and # ignore if name checks are not requested
ctx.config.belongsToProjectPackageMaybeNil(getModule(ctx.graph, info.fileIndex)): # ignore foreign packages
checkPragmaUseImpl(ctx.config, info, w, pragmaName)

View File

@@ -311,7 +311,7 @@ proc errorSym*(c: PContext, ident: PIdent, info: TLineInfo): PSym =
## creates an error symbol to avoid cascading errors (for IDE support)
result = newSym(skError, ident, c.idgen, getCurrOwner(c), info, {})
result.typ = errorType(c)
incl(result.flagsImpl, sfDiscardable)
incl(result.flags, sfDiscardable)
# pretend it's from the top level scope to prevent cascading errors:
if c.config.cmd != cmdInteractive and c.compilesContextId == 0:
c.moduleScope.addSym(result)
@@ -412,6 +412,8 @@ proc addDecl*(c: PContext, sym: PSym) {.inline.} =
proc addPrelimDecl*(c: PContext, sym: PSym) =
discard c.currentScope.addUniqueSym(sym)
from ic / ic import addHidden
proc addInterfaceDeclAux(c: PContext, sym: PSym) =
## adds symbol to the module for either private or public access.
if sfExported in sym.flags:
@@ -420,6 +422,8 @@ proc addInterfaceDeclAux(c: PContext, sym: PSym) =
else: internalError(c.config, sym.info, "addInterfaceDeclAux")
elif sym.kind in ExportableSymKinds and c.module != nil and isTopLevelInsideDeclaration(c, sym):
strTableAdd(semtabAll(c.graph, c.module), sym)
if c.config.symbolFiles != disabledSf:
addHidden(c.encoder, c.packedRepr, sym)
proc addInterfaceDeclAt*(c: PContext, scope: PScope, sym: PSym) =
## adds a symbol on the scope and the interface if appropriate

View File

@@ -82,7 +82,7 @@ proc lowerTupleUnpacking*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: P
var temp = newSym(skTemp, getIdent(g.cache, genPrefix), idgen,
owner, value.info, g.config.options)
temp.typ = skipTypes(value.typ, abstractInst)
incl(temp.flagsImpl, sfFromGeneric)
incl(temp.flags, sfFromGeneric)
tempAsNode = newSymNode(temp)
var v = newNodeI(nkVarSection, value.info)
@@ -103,7 +103,7 @@ proc evalOnce*(g: ModuleGraph; value: PNode; idgen: IdGenerator; owner: PSym): P
var temp = newSym(skTemp, getIdent(g.cache, genPrefix), idgen,
owner, value.info, g.config.options)
temp.typ = skipTypes(value.typ, abstractInst)
incl(temp.flagsImpl, sfFromGeneric)
incl(temp.flags, sfFromGeneric)
var v = newNodeI(nkLetSection, value.info)
let tempAsNode = newSymNode(temp)
@@ -127,8 +127,8 @@ proc lowerSwap*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNod
# note: cannot use 'skTemp' here cause we really need the copy for the VM :-(
var temp = newSym(skVar, getIdent(g.cache, genPrefix), idgen, owner, n.info, owner.options)
temp.typ = n[1].typ
incl(temp.flagsImpl, sfFromGeneric)
incl(temp.flagsImpl, sfGenSym)
incl(temp.flags, sfFromGeneric)
incl(temp.flags, sfGenSym)
var v = newNodeI(nkVarSection, n.info)
let tempAsNode = newSymNode(temp)
@@ -147,13 +147,13 @@ proc createObj*(g: ModuleGraph; idgen: IdGenerator; owner: PSym, info: TLineInfo
result = newType(tyObject, idgen, owner)
if final:
rawAddSon(result, nil)
incl result, tfFinal
incl result.flags, tfFinal
else:
rawAddSon(result, getCompilerProc(g, "RootObj").typ)
result.n = newNodeI(nkRecList, info)
let s = newSym(skType, getIdent(g.cache, "Env_" & toFilename(g.config, info) & "_" & $owner.name.s),
idgen, owner, info, owner.options)
incl s.flagsImpl, sfAnon
incl s.flags, sfAnon
s.typ = result
result.sym = s
@@ -174,12 +174,12 @@ proc rawIndirectAccess*(a: PNode; field: PSym; info: TLineInfo): PNode =
# returns a[].field as a node
assert field.kind == skField
var deref = newNodeI(nkHiddenDeref, info)
deref.typ = a.typ.skipTypes(abstractInst)[0]
deref.typ() = a.typ.skipTypes(abstractInst)[0]
deref.add a
result = newNodeI(nkDotExpr, info)
result.add deref
result.add newSymNode(field)
result.typ = field.typ
result.typ() = field.typ
proc rawDirectAccess*(obj, field: PSym): PNode =
# returns a.field as a node
@@ -187,7 +187,7 @@ proc rawDirectAccess*(obj, field: PSym): PNode =
result = newNodeI(nkDotExpr, field.info)
result.add newSymNode(obj)
result.add newSymNode(field)
result.typ = field.typ
result.typ() = field.typ
proc lookupInRecord(n: PNode, id: ItemId): PSym =
result = nil
@@ -250,12 +250,12 @@ proc newDotExpr*(obj, b: PSym): PNode =
assert field != nil, b.name.s
result.add newSymNode(obj)
result.add newSymNode(field)
result.typ = field.typ
result.typ() = field.typ
proc indirectAccess*(a: PNode, b: ItemId, info: TLineInfo): PNode =
# returns a[].b as a node
var deref = newNodeI(nkHiddenDeref, info)
deref.typ = a.typ.skipTypes(abstractInst).elementType
deref.typ() = a.typ.skipTypes(abstractInst).elementType
var t = deref.typ.skipTypes(abstractInst)
var field: PSym
while true:
@@ -273,12 +273,12 @@ proc indirectAccess*(a: PNode, b: ItemId, info: TLineInfo): PNode =
result = newNodeI(nkDotExpr, info)
result.add deref
result.add newSymNode(field)
result.typ = field.typ
result.typ() = field.typ
proc indirectAccess*(a: PNode, b: string, info: TLineInfo; cache: IdentCache): PNode =
# returns a[].b as a node
var deref = newNodeI(nkHiddenDeref, info)
deref.typ = a.typ.skipTypes(abstractInst).elementType
deref.typ() = a.typ.skipTypes(abstractInst).elementType
var t = deref.typ.skipTypes(abstractInst)
var field: PSym
let bb = getIdent(cache, b)
@@ -297,7 +297,7 @@ proc indirectAccess*(a: PNode, b: string, info: TLineInfo; cache: IdentCache): P
result = newNodeI(nkDotExpr, info)
result.add deref
result.add newSymNode(field)
result.typ = field.typ
result.typ() = field.typ
proc getFieldFromObj*(t: PType; v: PSym): PSym =
assert v.kind != skField
@@ -320,7 +320,7 @@ proc indirectAccess*(a, b: PSym, info: TLineInfo): PNode =
proc genAddrOf*(n: PNode; idgen: IdGenerator; typeKind = tyPtr): PNode =
result = newNodeI(nkAddr, n.info, 1)
result[0] = n
result.typ = newType(typeKind, idgen, n.typ.owner)
result.typ() = newType(typeKind, idgen, n.typ.owner)
result.typ.rawAddSon(n.typ)
proc genDeref*(n: PNode; k = nkHiddenDeref): PNode =
@@ -344,18 +344,18 @@ proc callCodegenProc*(g: ModuleGraph; name: string;
if optionalArgs != nil:
for i in 1..<optionalArgs.len-2:
result.add optionalArgs[i]
result.typ = sym.typ.returnType
result.typ() = sym.typ.returnType
proc newIntLit*(g: ModuleGraph; info: TLineInfo; value: BiggestInt): PNode =
result = nkIntLit.newIntNode(value)
result.typ = getSysType(g, info, tyInt)
result.typ() = getSysType(g, info, tyInt)
proc genHigh*(g: ModuleGraph; n: PNode): PNode =
if skipTypes(n.typ, abstractVar).kind == tyArray:
result = newIntLit(g, n.info, toInt64(lastOrd(g.config, skipTypes(n.typ, abstractVar))))
else:
result = newNodeI(nkCall, n.info, 2)
result.typ = getSysType(g, n.info, tyInt)
result.typ() = getSysType(g, n.info, tyInt)
result[0] = newSymNode(getSysMagic(g, n.info, "high", mHigh))
result[1] = n
@@ -364,7 +364,7 @@ proc genLen*(g: ModuleGraph; n: PNode): PNode =
result = newIntLit(g, n.info, toInt64(lastOrd(g.config, skipTypes(n.typ, abstractVar)) + 1))
else:
result = newNodeI(nkCall, n.info, 2)
result.typ = getSysType(g, n.info, tyInt)
result.typ() = getSysType(g, n.info, tyInt)
result[0] = newSymNode(getSysMagic(g, n.info, "len", mLengthSeq))
result[1] = n

View File

@@ -10,7 +10,7 @@
# Built-in types and compilerprocs are registered here.
import
ast, msgs, platform, idents,
ast, astalgo, msgs, platform, idents,
modulegraphs, lineinfos
export createMagic
@@ -166,4 +166,4 @@ proc makeAddr*(n: PNode; idgen: IdGenerator): PNode =
result = n
else:
result = newTree(nkHiddenAddr, n)
result.typ = makePtrType(n.typ.skipTypes({tySink}), idgen)
result.typ() = makePtrType(n.typ.skipTypes({tySink}), idgen)

View File

@@ -26,14 +26,12 @@ import
when defined(nimPreviewSlimSystem):
import std/[syncio, assertions]
import ic / [cbackend, integrity, navigator, ic]
import ../dist/checksums/src/checksums/sha1
import pipelines
when not defined(nimKochBootstrap):
import nifbackend
import deps
when not defined(leanCompiler):
import docgen
@@ -97,6 +95,14 @@ proc commandCheck(graph: ModuleGraph) =
setPipeLinePass(graph, SemPass)
compilePipelineProject(graph)
if conf.symbolFiles != disabledSf:
case conf.ideCmd
of ideDef: navDefinition(graph)
of ideUse: navUsages(graph)
of ideDus: navDefusages(graph)
else: discard
writeRodFiles(graph)
when not defined(leanCompiler):
proc commandDoc2(graph: ModuleGraph; ext: string) =
handleDocOutputOptions graph.config
@@ -127,22 +133,6 @@ proc commandCompileToNif(graph: ModuleGraph) =
setPipeLinePass(graph, NifgenPass)
compilePipelineProject(graph)
proc commandNifC(graph: ModuleGraph) =
## Generate C code from precompiled NIF files.
## This is the new IC approach: compile modules to NIF first with `nim m`,
## then generate C code from the entry.nif file with whole-program DCE.
when not defined(nimKochBootstrap):
let conf = graph.config
extccomp.initVars(conf)
if not extccomp.ccHasSaneOverflow(conf):
conf.symbols.defineSymbol("nimEmulateOverflowChecks")
# Use the NIF backend to generate C code
nifbackend.generateCode(graph, conf.projectMainIdx)
else:
rawMessage(graph.config, errGenerated, "NIF backend not available during bootstrap build")
proc commandCompileToC(graph: ModuleGraph) =
let conf = graph.config
extccomp.initVars(conf)
@@ -163,7 +153,15 @@ proc commandCompileToC(graph: ModuleGraph) =
compilePipelineProject(graph)
if graph.config.errorCounter > 0:
return # issue #9933
cgenWriteModules(graph.backend, conf)
if conf.symbolFiles == disabledSf:
cgenWriteModules(graph.backend, conf)
else:
if isDefined(conf, "nimIcIntegrityChecks"):
checkIntegrity(graph)
generateCode(graph)
# graph.backend can be nil under IC when nothing changed at all:
if graph.backend != nil:
cgenWriteModules(graph.backend, conf)
if conf.cmd != cmdTcc and graph.backend != nil:
extccomp.callCCompiler(conf)
# for now we do not support writing out a .json file with the build instructions when HCR is on
@@ -202,7 +200,7 @@ proc commandInteractive(graph: ModuleGraph) =
discard graph.compilePipelineModule(fileInfoIdx(graph.config, graph.config.projectFull), {})
else:
var m = graph.makeStdinModule()
incl(m, sfMainModule)
incl(m.flags, sfMainModule)
var idgen = IdGenerator(module: m.itemId.module, symId: m.itemId.item, typeId: 0)
let s = llStreamOpenStdIn(onPrompt = proc() = flushDot(graph.config))
discard processPipelineModule(graph, m, idgen, s)
@@ -223,6 +221,10 @@ proc commandScan(cache: IdentCache, config: ConfigRef) =
else:
rawMessage(config, errGenerated, "cannot open file: " & f.string)
proc commandView(graph: ModuleGraph) =
let f = toAbsolute(mainCommandArg(graph.config), AbsoluteDir getCurrentDir()).addFileExt(RodExt)
rodViewer(f, graph.config, graph.cache)
const
PrintRopeCacheStats = false
@@ -320,6 +322,8 @@ proc mainCommand*(graph: ModuleGraph) =
case conf.cmd
of cmdBackends:
compileToBackend()
when BenchIC:
echoTimes graph.packed
of cmdTcc:
when hasTinyCBackend:
extccomp.setCC(conf, "tcc", unknownLineInfo)
@@ -416,27 +420,16 @@ proc mainCommand*(graph: ModuleGraph) =
of cmdCheck:
commandCheck(graph)
of cmdM:
# cmdM uses NIF files, not ROD files
graph.config.symbolFiles = disabledSf
setUseIc(true)
graph.config.symbolFiles = v2Sf
setUseIc(graph.config.symbolFiles != disabledSf)
commandCheck(graph)
of cmdNifC:
setUseIc(true)
# Generate C code from NIF files
wantMainModule(conf)
setOutFile(conf)
commandNifC(graph)
of cmdIc:
# Generate .build.nif for nifmake
setUseIc(true)
wantMainModule(conf)
when not defined(nimKochBootstrap):
commandIc(conf)
else:
rawMessage(conf, errGenerated, "nim deps not available in bootstrap build")
of cmdParse:
wantMainModule(conf)
discard parseFile(conf.projectMainIdx, cache, conf)
of cmdRod:
wantMainModule(conf)
commandView(graph)
#msgWriteln(conf, "Beware: Indentation tokens depend on the parser's state!")
of cmdInteractive: commandInteractive(graph)
of cmdNimscript:
if conf.projectIsCmd or conf.projectIsStdin: discard

View File

@@ -11,15 +11,11 @@
## represents a complete Nim project. Single modules can either be kept in RAM
## or stored in a rod-file.
import std/[intsets, tables, hashes, strtabs, os, strutils, parseutils]
import std/[intsets, tables, hashes, strtabs, algorithm, os, strutils, parseutils]
import ../dist/checksums/src/checksums/md5
import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils, packages, suggestsymdb
import ic / [packed_ast, ic]
when not defined(nimKochBootstrap):
import ast2nif
import "../dist/nimony/src/lib" / [nifstreams, bitabs]
import typekeys
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -27,12 +23,16 @@ when defined(nimPreviewSlimSystem):
type
SigHash* = distinct MD5Digest
LazySym* = object
id*: FullId
sym*: PSym
Iface* = object ## data we don't want to store directly in the
## ast.PSym type for s.kind == skModule
module*: PSym ## module this "Iface" belongs to
converters*: seq[PSym]
patterns*: seq[PSym]
pureEnums*: seq[PSym]
converters*: seq[LazySym]
patterns*: seq[LazySym]
pureEnums*: seq[LazySym]
interf: TStrTable
interfHidden: TStrTable
uniqueName*: Rope
@@ -41,6 +41,20 @@ type
opNot*, opContains*, opLe*, opLt*, opAnd*, opOr*, opIsNil*, opEq*: PSym
opAdd*, opSub*, opMul*, opDiv*, opLen*: PSym
FullId* = object
module*: int
packed*: PackedItemId
LazyType* = object
id*: FullId
typ*: PType
LazyInstantiation* = object
module*: int
sym*: FullId
concreteTypes*: seq[FullId]
inst*: PInstantiation
PipelinePass* = enum
NonePass
SemPass
@@ -56,18 +70,19 @@ type
ModuleGraph* {.acyclic.} = ref object
ifaces*: seq[Iface] ## indexed by int32 fileIdx
packed*: PackedModuleGraph
encoders*: seq[PackedEncoder]
typeInstCache*: Table[ItemId, seq[PType]] # A symbol's ItemId.
procInstCache*: Table[ItemId, seq[PInstantiation]] # A symbol's ItemId.
attachedOps*: array[TTypeAttachedOp, Table[ItemId, PSym]] # Type ID, destructors, etc.
loadedOps: array[TTypeAttachedOp, Table[string, PSym]] # This can later by unified with `attachedOps` once it's stable
opsLog*: seq[LogEntry]
methodsPerGenericType*: Table[ItemId, seq[(int, PSym)]] # Type ID, attached methods
typeInstCache*: Table[ItemId, seq[LazyType]] # A symbol's ItemId.
procInstCache*: Table[ItemId, seq[LazyInstantiation]] # A symbol's ItemId.
attachedOps*: array[TTypeAttachedOp, Table[ItemId, LazySym]] # Type ID, destructors, etc.
methodsPerGenericType*: Table[ItemId, seq[(int, LazySym)]] # Type ID, attached methods
memberProcsPerType*: Table[ItemId, seq[PSym]] # Type ID, attached member procs (only c++, virtual,member and ctor so far).
initializersPerType*: Table[ItemId, PNode] # Type ID, AST call to the default ctor (c++ only)
enumToStringProcs*: Table[ItemId, PSym]
enumToStringProcs*: Table[ItemId, LazySym]
emittedTypeInfo*: Table[string, FileIndex]
startupPackedConfig*: PackedConfig
packageSyms*: TStrTable
deps*: IntSet # the dependency graph or potentially its transitive closure.
importDeps*: Table[FileIndex, seq[FileIndex]] # explicit import module dependencies
@@ -93,8 +108,8 @@ type
methods*: seq[tuple[methods: seq[PSym], dispatcher: PSym]] # needs serialization!
bucketTable*: CountTable[ItemId]
objectTree*: Table[ItemId, seq[tuple[depth: int, value: PType]]]
methodsPerType*: Table[ItemId, seq[PSym]]
dispatchers*: seq[PSym]
methodsPerType*: Table[ItemId, seq[LazySym]]
dispatchers*: seq[LazySym]
systemModule*: PSym
sysTypes*: array[TTypeKind, PType]
@@ -123,8 +138,6 @@ type
cachedFiles*: StringTableRef
procGlobals*: seq[PNode]
nifReplayActions*: Table[int32, seq[PNode]] # module position -> replay actions for NIF
cachedMods: IntSet
TPassContext* = object of RootObj # the pass's context
idgen*: IdGenerator
@@ -149,9 +162,6 @@ proc resetForBackend*(g: ModuleGraph) =
g.enumToStringProcs.clear()
g.dispatchers.setLen(0)
g.methodsPerType.clear()
for a in mitems(g.loadedOps):
a.clear()
g.opsLog.setLen(0)
const
cb64 = [
@@ -207,43 +217,85 @@ proc strTableAdds*(g: ModuleGraph, m: PSym, s: PSym) =
strTableAdd(semtabAll(g, m), s)
proc isCachedModule(g: ModuleGraph; module: int): bool {.inline.} =
result = module in g.cachedMods
result = module < g.packed.len and g.packed[module].status == loaded
proc isCachedModule*(g: ModuleGraph; m: PSym): bool {.inline.} =
isCachedModule(g, m.position)
proc simulateCachedModule(g: ModuleGraph; moduleSym: PSym; m: PackedModule) =
when false:
echo "simulating ", moduleSym.name.s, " ", moduleSym.position
simulateLoadedModule(g.packed, g.config, g.cache, moduleSym, m)
proc initEncoder*(g: ModuleGraph; module: PSym) =
let id = module.position
if id >= g.encoders.len:
setLen g.encoders, id+1
ic.initEncoder(g.encoders[id],
g.packed[id].fromDisk, module, g.config, g.startupPackedConfig)
type
ModuleIter* = object
fromRod: bool
modIndex: int
ti: TIdentIter
rodIt: RodIter
importHidden: bool
proc initModuleIter*(mi: var ModuleIter; g: ModuleGraph; m: PSym; name: PIdent): PSym =
assert m.kind == skModule
mi.modIndex = m.position
mi.fromRod = isCachedModule(g, mi.modIndex)
mi.importHidden = optImportHidden in m.options
result = initIdentIter(mi.ti, g.ifaces[mi.modIndex].interfSelect(mi.importHidden), name)
if mi.fromRod:
result = initRodIter(mi.rodIt, g.config, g.cache, g.packed, FileIndex mi.modIndex, name, mi.importHidden)
else:
result = initIdentIter(mi.ti, g.ifaces[mi.modIndex].interfSelect(mi.importHidden), name)
proc nextModuleIter*(mi: var ModuleIter; g: ModuleGraph): PSym =
result = nextIdentIter(mi.ti, g.ifaces[mi.modIndex].interfSelect(mi.importHidden))
if mi.fromRod:
result = nextRodIter(mi.rodIt, g.packed)
else:
result = nextIdentIter(mi.ti, g.ifaces[mi.modIndex].interfSelect(mi.importHidden))
iterator allSyms*(g: ModuleGraph; m: PSym): PSym =
let importHidden = optImportHidden in m.options
for s in g.ifaces[m.position].interfSelect(importHidden).data:
if s != nil:
yield s
if isCachedModule(g, m):
var rodIt: RodIter = default(RodIter)
var r = initRodIterAllSyms(rodIt, g.config, g.cache, g.packed, FileIndex m.position, importHidden)
while r != nil:
yield r
r = nextRodIter(rodIt, g.packed)
else:
for s in g.ifaces[m.position].interfSelect(importHidden).data:
if s != nil:
yield s
proc someSym*(g: ModuleGraph; m: PSym; name: PIdent): PSym =
let importHidden = optImportHidden in m.options
result = strTableGet(g.ifaces[m.position].interfSelect(importHidden), name)
if isCachedModule(g, m):
result = interfaceSymbol(g.config, g.cache, g.packed, FileIndex(m.position), name, importHidden)
else:
result = strTableGet(g.ifaces[m.position].interfSelect(importHidden), name)
proc someSymAmb*(g: ModuleGraph; m: PSym; name: PIdent; amb: var bool): PSym =
let importHidden = optImportHidden in m.options
var ti: TIdentIter = default(TIdentIter)
result = initIdentIter(ti, g.ifaces[m.position].interfSelect(importHidden), name)
if result != nil and nextIdentIter(ti, g.ifaces[m.position].interfSelect(importHidden)) != nil:
# another symbol exists with same name
amb = true
if isCachedModule(g, m):
result = nil
for s in interfaceSymbols(g.config, g.cache, g.packed, FileIndex(m.position), name, importHidden):
if result == nil:
# set result to the first symbol
result = s
else:
# another symbol found
amb = true
break
else:
var ti: TIdentIter = default(TIdentIter)
result = initIdentIter(ti, g.ifaces[m.position].interfSelect(importHidden), name)
if result != nil and nextIdentIter(ti, g.ifaces[m.position].interfSelect(importHidden)) != nil:
# another symbol exists with same name
amb = true
proc systemModuleSym*(g: ModuleGraph; name: PIdent): PSym =
result = someSym(g, g.systemModule, name)
@@ -255,110 +307,109 @@ iterator systemModuleSyms*(g: ModuleGraph; name: PIdent): PSym =
yield r
r = nextModuleIter(mi, g)
proc resolveType(g: ModuleGraph; t: var LazyType): PType =
result = t.typ
if result == nil and isCachedModule(g, t.id.module):
result = loadTypeFromId(g.config, g.cache, g.packed, t.id.module, t.id.packed)
t.typ = result
assert result != nil
proc resolveSym(g: ModuleGraph; t: var LazySym): PSym =
result = t.sym
if result == nil and isCachedModule(g, t.id.module):
result = loadSymFromId(g.config, g.cache, g.packed, t.id.module, t.id.packed)
t.sym = result
assert result != nil
proc resolveInst(g: ModuleGraph; t: var LazyInstantiation): PInstantiation =
result = t.inst
if result == nil and isCachedModule(g, t.module):
result = PInstantiation(sym: loadSymFromId(g.config, g.cache, g.packed, t.sym.module, t.sym.packed))
result.concreteTypes = newSeq[PType](t.concreteTypes.len)
for i in 0..high(result.concreteTypes):
result.concreteTypes[i] = loadTypeFromId(g.config, g.cache, g.packed,
t.concreteTypes[i].module, t.concreteTypes[i].packed)
t.inst = result
assert result != nil
proc resolveAttachedOp*(g: ModuleGraph; t: var LazySym): PSym =
result = t.sym
if result == nil:
result = loadSymFromId(g.config, g.cache, g.packed, t.id.module, t.id.packed)
t.sym = result
assert result != nil
iterator typeInstCacheItems*(g: ModuleGraph; s: PSym): PType =
if g.typeInstCache.contains(s.itemId):
let x = addr(g.typeInstCache[s.itemId])
for t in mitems(x[]):
yield t
yield resolveType(g, t)
iterator procInstCacheItems*(g: ModuleGraph; s: PSym): PInstantiation =
if g.procInstCache.contains(s.itemId):
let x = addr(g.procInstCache[s.itemId])
for t in mitems(x[]):
yield t
yield resolveInst(g, t)
proc getAttachedOp*(g: ModuleGraph; t: PType; op: TTypeAttachedOp): PSym =
## returns the requested attached operation for type `t`. Can return nil
## if no such operation exists.
if g.attachedOps[op].contains(t.itemId):
result = g.attachedOps[op][t.itemId]
elif g.config.cmd in {cmdNifC, cmdM}:
# Fall back to key-based lookup for NIF-loaded hooks
let key = typeKey(t, g.config, loadTypeCallback, loadSymCallback)
result = g.loadedOps[op].getOrDefault(key)
#echo "fallback ", key, " ", op, " ", result
result = resolveAttachedOp(g, g.attachedOps[op][t.itemId])
else:
result = nil
proc setAttachedOp*(g: ModuleGraph; module: int; t: PType; op: TTypeAttachedOp; value: PSym) =
## we also need to record this to the packed module.
if not g.attachedOps[op].contains(t.itemId):
let key = typeKey(t, g.config, loadTypeCallback, loadSymCallback)
# Use key-based deduplication for opsLog because different type objects
# (e.g. canon vs orig) can have different itemIds but same structural key
if key notin g.loadedOps[op]:
# Hooks should be written to the module where the type is defined,
# not the module that triggered the registration
let ownerModule = if t.sym != nil: t.sym.itemId.module.int else: module
g.opsLog.add LogEntry(kind: HookEntry, op: op, module: ownerModule, key: key, sym: value)
g.loadedOps[op][key] = value
g.attachedOps[op][t.itemId] = value
proc setAttachedOp*(g: ModuleGraph; module: int; typeId: ItemId; op: TTypeAttachedOp; value: PSym) =
## Overload that takes ItemId directly, useful for registering hooks from NIF index.
g.attachedOps[op][typeId] = value
g.attachedOps[op][t.itemId] = LazySym(sym: value)
proc setAttachedOpPartial*(g: ModuleGraph; module: int; t: PType; op: TTypeAttachedOp; value: PSym) =
## we also need to record this to the packed module.
g.attachedOps[op][t.itemId] = value
g.attachedOps[op][t.itemId] = LazySym(sym: value)
proc completePartialOp*(g: ModuleGraph; module: int; t: PType; op: TTypeAttachedOp; value: PSym) {.inline.} =
discard
proc completePartialOp*(g: ModuleGraph; module: int; t: PType; op: TTypeAttachedOp; value: PSym) =
if g.config.symbolFiles != disabledSf:
assert module < g.encoders.len
assert isActive(g.encoders[module])
toPackedGeneratedProcDef(value, g.encoders[module], g.packed[module].fromDisk)
#storeAttachedProcDef(t, op, value, g.encoders[module], g.packed[module].fromDisk)
iterator getDispatchers*(g: ModuleGraph): PSym =
for i in g.dispatchers.mitems:
yield i
yield resolveSym(g, i)
proc addDispatchers*(g: ModuleGraph, value: PSym) =
# TODO: add it for packed modules
g.dispatchers.add value
g.dispatchers.add LazySym(sym: value)
iterator resolveLazySymSeq(g: ModuleGraph, list: var seq[PSym]): PSym =
iterator resolveLazySymSeq(g: ModuleGraph, list: var seq[LazySym]): PSym =
for it in list.mitems:
yield it
yield resolveSym(g, it)
proc setMethodsPerType*(g: ModuleGraph; id: ItemId, methods: seq[PSym]) =
proc setMethodsPerType*(g: ModuleGraph; id: ItemId, methods: seq[LazySym]) =
# TODO: add it for packed modules
g.methodsPerType[id] = methods
proc addNifReplayAction*(g: ModuleGraph; module: int32; n: PNode) =
## Stores a replay action for NIF-based incremental compilation.
g.nifReplayActions.mgetOrPut(module, @[]).add n
iterator getMethodsPerType*(g: ModuleGraph; t: PType): PSym =
if g.methodsPerType.contains(t.itemId):
for it in mitems g.methodsPerType[t.itemId]:
yield it
yield resolveSym(g, it)
proc getToStringProc*(g: ModuleGraph; t: PType): PSym =
result = g.enumToStringProcs[t.itemId]
result = resolveSym(g, g.enumToStringProcs[t.itemId])
assert result != nil
proc setToStringProc*(g: ModuleGraph; t: PType; value: PSym) =
g.enumToStringProcs[t.itemId] = value
let key = typeKey(t, g.config, loadTypeCallback, loadSymCallback)
let ownerModule = if t.sym != nil: t.sym.itemId.module.int else: value.itemId.module.int
g.opsLog.add LogEntry(kind: EnumToStrEntry, module: ownerModule, key: key, sym: value)
g.enumToStringProcs[t.itemId] = LazySym(sym: value)
iterator methodsForGeneric*(g: ModuleGraph; t: PType): (int, PSym) =
if g.methodsPerGenericType.contains(t.itemId):
for it in mitems g.methodsPerGenericType[t.itemId]:
yield (it[0], it[1])
yield (it[0], resolveSym(g, it[1]))
proc addMethodToGeneric*(g: ModuleGraph; module: int; t: PType; col: int; m: PSym) =
g.methodsPerGenericType.mgetOrPut(t.itemId, @[]).add (col, m)
let key = typeKey(t, g.config, loadTypeCallback, loadSymCallback)
let ownerModule = if t.sym != nil: t.sym.itemId.module.int else: module
g.opsLog.add LogEntry(kind: MethodEntry, module: ownerModule, key: key, sym: m)
proc logGenericInstance*(g: ModuleGraph; inst: PSym) =
## Log a generic instance so it gets written to the NIF file.
## This is needed when generic instances are created during compile-time
## evaluation and may be referenced from other modules compiled in the same run.
if g.config.cmd in {cmdNifC, cmdM}:
let ownerModule = inst.itemId.module.int
g.opsLog.add LogEntry(kind: GenericInstEntry, module: ownerModule, sym: inst)
g.methodsPerGenericType.mgetOrPut(t.itemId, @[]).add (col, LazySym(sym: m))
proc hasDisabledAsgn*(g: ModuleGraph; t: PType): bool =
let op = getAttachedOp(g, t, attachedAsgn)
@@ -372,31 +423,21 @@ proc copyTypeProps*(g: ModuleGraph; module: int; dest, src: PType) =
proc loadCompilerProc*(g: ModuleGraph; name: string): PSym =
result = nil
if g.config.symbolFiles == disabledSf and optWithinConfigSystem notin g.config.globalOptions:
# For NIF-based compilation, search in loaded NIF modules
when not defined(nimKochBootstrap):
# Try to resolve from NIF for both cmdNifC and cmdM (which uses NIF files)
if g.config.cmd in {cmdNifC, cmdM}:
# First try system module (most compilerprocs are there)
let systemFileIdx = g.config.m.systemFileIdx
if systemFileIdx != InvalidFileIdx and not g.withinSystem:
# Only try to load from NIF if the file exists (it may not during initial ic build)
result = tryResolveCompilerProc(ast.program, name, systemFileIdx)
if result != nil:
strTableAdd(g.compilerprocs, result)
return result
if g.config.symbolFiles == disabledSf: return nil
# Try threadpool module (some compilerprocs like FlowVar are there)
# Find threadpool module by searching loaded modules
for moduleIdx in 0..<g.ifaces.len:
let module = g.ifaces[moduleIdx].module
if module != nil and module.name.s == "threadpool":
let threadpoolFileIdx = module.position.FileIndex
result = tryResolveCompilerProc(ast.program, name, threadpoolFileIdx)
if result != nil:
strTableAdd(g.compilerprocs, result)
return result
return nil
# slow, linear search, but the results are cached:
for module in 0..<len(g.packed):
#if isCachedModule(g, module):
let x = searchForCompilerproc(g.packed[module], name)
if x >= 0:
result = loadSymFromId(g.config, g.cache, g.packed, module, toPackedItemId(x))
if result != nil:
strTableAdd(g.compilerprocs, result)
return result
proc loadPackedSym*(g: ModuleGraph; s: var LazySym) =
if s.sym == nil:
s.sym = loadSymFromId(g.config, g.cache, g.packed, s.id.module, s.id.packed)
proc `$`*(u: SigHash): string =
toBase64a(cast[cstring](unsafeAddr u), sizeof(u))
@@ -484,13 +525,15 @@ proc registerModule*(g: ModuleGraph; m: PSym) =
if m.position >= g.ifaces.len:
setLen(g.ifaces, m.position + 1)
if g.ifaces[m.position].module == nil:
g.ifaces[m.position] = Iface(module: m, converters: @[], patterns: @[],
uniqueName: rope(uniqueModuleName(g.config, m)))
initStrTables(g, m)
if m.position >= g.packed.len:
setLen(g.packed.pm, m.position + 1)
g.ifaces[m.position] = Iface(module: m, converters: @[], patterns: @[],
uniqueName: rope(uniqueModuleName(g.config, m)))
initStrTables(g, m)
proc registerModuleById*(g: ModuleGraph; m: FileIndex) =
registerModule(g, g.ifaces[int m].module)
registerModule(g, g.packed[int m].module)
proc initOperators*(g: ModuleGraph): Operators =
# These are safe for IC.
@@ -537,14 +580,12 @@ proc initModuleGraphFields(result: ModuleGraph) =
result.operators = initOperators(result)
result.emittedTypeInfo = initTable[string, FileIndex]()
result.cachedFiles = newStringTable()
result.cachedMods = initIntSet()
proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
result = ModuleGraph()
result.config = config
result.cache = cache
initModuleGraphFields(result)
ast.setupProgram(config, cache)
proc resetAllModules*(g: ModuleGraph) =
g.packageSyms = initStrTable()
@@ -560,13 +601,49 @@ proc resetAllModules*(g: ModuleGraph) =
initModuleGraphFields(g)
proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym =
if fileIdx.int32 >= 0 and fileIdx.int32 < g.ifaces.len:
result = g.ifaces[fileIdx.int32].module
else:
result = nil
result = nil
if fileIdx.int32 >= 0:
if isCachedModule(g, fileIdx.int32):
result = g.packed[fileIdx.int32].module
elif fileIdx.int32 < g.ifaces.len:
result = g.ifaces[fileIdx.int32].module
proc moduleOpenForCodegen*(g: ModuleGraph; m: FileIndex): bool {.inline.} =
result = true
if g.config.symbolFiles == disabledSf:
result = true
else:
result = g.packed[m.int32].status notin {undefined, stored, loaded}
proc rememberEmittedTypeInfo*(g: ModuleGraph; m: FileIndex; ti: string) =
#assert(not isCachedModule(g, m.int32))
if g.config.symbolFiles != disabledSf:
#assert g.encoders[m.int32].isActive
assert g.packed[m.int32].status != stored
g.packed[m.int32].fromDisk.emittedTypeInfo.add ti
#echo "added typeinfo ", m.int32, " ", ti, " suspicious ", not g.encoders[m.int32].isActive
proc rememberFlag*(g: ModuleGraph; m: PSym; flag: ModuleBackendFlag) =
if g.config.symbolFiles != disabledSf:
#assert g.encoders[m.int32].isActive
assert g.packed[m.position].status != stored
g.packed[m.position].fromDisk.backendFlags.incl flag
proc closeRodFile*(g: ModuleGraph; m: PSym) =
if g.config.symbolFiles in {readOnlySf, v2Sf}:
# For stress testing we seek to reload the symbols from memory. This
# way much of the logic is tested but the test is reproducible as it does
# not depend on the hard disk contents!
let mint = m.position
saveRodFile(toRodFile(g.config, AbsoluteFile toFullPath(g.config, FileIndex(mint))),
g.encoders[mint], g.packed[mint].fromDisk)
g.packed[mint].status = stored
elif g.config.symbolFiles == stressTest:
# debug code, but maybe a good idea for production? Could reduce the compiler's
# memory consumption considerably at the cost of more loads from disk.
let mint = m.position
simulateCachedModule(g, m, g.packed[mint].fromDisk)
g.packed[mint].status = loaded
proc dependsOn(a, b: int): int {.inline.} = (a shl 15) + b
@@ -604,13 +681,13 @@ proc markDirty*(g: ModuleGraph; fileIdx: FileIndex) =
if m != nil:
g.suggestSymbols.del(fileIdx)
g.suggestErrors.del(fileIdx)
incl m.flagsImpl, sfDirty
incl m.flags, sfDirty
proc unmarkAllDirty*(g: ModuleGraph) =
for i in 0i32..<g.ifaces.len.int32:
let m = g.ifaces[i].module
if m != nil:
m.flagsImpl.excl sfDirty
m.flags.excl sfDirty
proc isDirty*(g: ModuleGraph; m: PSym): bool =
result = g.suggestMode and sfDirty in m.flags
@@ -650,59 +727,23 @@ proc needsCompilation*(g: ModuleGraph, fileIdx: FileIndex): bool =
proc getBody*(g: ModuleGraph; s: PSym): PNode {.inline.} =
result = s.ast[bodyPos]
if result == nil and g.config.symbolFiles in {readOnlySf, v2Sf, stressTest}:
result = loadProcBody(g.config, g.cache, g.packed, s)
s.ast[bodyPos] = result
assert result != nil
when not defined(nimKochBootstrap):
proc moduleFromNifFile*(g: ModuleGraph; fileIdx: FileIndex;
flags: set[LoadFlag] = {}): PrecompiledModule =
## Returns 'nil' if the module needs to be recompiled.
## Loads module from NIF file when optCompress is enabled.
## When loadFullAst is true, loads the complete module AST for code generation.
if not fileExists(toNifFilename(g.config, fileIdx)):
return PrecompiledModule(module: nil)
# Create module symbol
let filename = AbsoluteFile toFullPath(g.config, fileIdx)
let m = PSym(
kindImpl: skModule,
itemId: ItemId(module: int32(fileIdx), item: 0'i32),
name: getIdent(g.cache, splitFile(filename).name),
infoImpl: newLineInfo(fileIdx, 1, 1),
positionImpl: int(fileIdx))
setOwner(m, getPackage(g.config, g.cache, fileIdx))
# Register module in graph
registerModule(g, m)
result = loadNifModule(ast.program, fileIdx,
g.ifaces[fileIdx.int].interf,
g.ifaces[fileIdx.int].interfHidden, flags)
result.module = m
# Mark module as cached
g.cachedMods.incl fileIdx.int
# Register hooks from NIF index with the module graph
for x in result.logOps:
case x.kind
of HookEntry:
g.loadedOps[x.op][x.key] = x.sym
of ConverterEntry:
g.ifaces[fileIdx.int].converters.add x.sym
of MethodEntry:
discard "todo"
of EnumToStrEntry:
discard "todo"
of GenericInstEntry:
raiseAssert "GenericInstEntry should not be in the NIF index"
# Register methods per type from NIF index
discard "todo"
proc moduleFromRodFile*(g: ModuleGraph; fileIdx: FileIndex;
cachedModules: var seq[FileIndex]): PSym =
## Returns 'nil' if the module needs to be recompiled.
if g.config.symbolFiles in {readOnlySf, v2Sf, stressTest}:
result = moduleFromRodFile(g.packed, g.config, g.cache, fileIdx, cachedModules)
else:
result = nil
proc configComplete*(g: ModuleGraph) =
#rememberStartupConfig(g.startupPackedConfig, g.config)
discard
rememberStartupConfig(g.startupPackedConfig, g.config)
proc onProcessing*(graph: ModuleGraph, fileIdx: FileIndex, moduleStatus: string, fromModule: PSym) =
proc onProcessing*(graph: ModuleGraph, fileIdx: FileIndex, moduleStatus: string, fromModule: PSym, ) =
let conf = graph.config
let isNimscript = conf.isDefined("nimscript")
if (not isNimscript) or hintProcessing in conf.cmdlineNotes:
@@ -723,7 +764,7 @@ proc getPackage*(graph: ModuleGraph; fileIdx: FileIndex): PSym =
result = pkgSym
graph.packageSyms.strTableAdd(pkgSym)
proc belongsToStdlib*(graph: ModuleGraph, sym: PSym): bool =
func belongsToStdlib*(graph: ModuleGraph, sym: PSym): bool =
## Check if symbol belongs to the 'stdlib' package.
sym.getPackageSymbol.getPackageId == graph.systemModule.getPackageId

View File

@@ -109,11 +109,9 @@ proc mangleModuleName*(conf: ConfigRef; path: AbsoluteFile): string =
of FromSearchPath: "@p"
of FromNimblePath: "@n"
# Note: We encode ".." specially as "@d" to avoid issues with changeFileExt
# which would misinterpret ".." as "name.ext" and strip the second part.
prefix & best.multiReplace(
{"..": "@d", $os.DirSep: "@s", $os.AltSep: "@s", "#": "@h", "@": "@@", ":": "@c"})
{$os.DirSep: "@s", $os.AltSep: "@s", "#": "@h", "@": "@@", ":": "@c"})
proc demangleModuleName*(path: string): string =
## Demangle a relative module path.
result = path.multiReplace({"@@": "@", "@d": "..", "@h": "#", "@s": "/", "@m": "", "@p": "", "@n": "", "@c": ":"})
result = path.multiReplace({"@@": "@", "@h": "#", "@s": "/", "@m": "", "@p": "", "@n": "", "@c": ":"})

View File

@@ -32,9 +32,9 @@ proc newModule*(graph: ModuleGraph; fileIdx: FileIndex): PSym =
let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
# We cannot call ``newSym`` here, because we have to circumvent the ID
# mechanism, which we do in order to assign each module a persistent ID.
result = PSym(kindImpl: skModule, itemId: ItemId(module: int32(fileIdx), item: 0'i32),
result = PSym(kind: skModule, itemId: ItemId(module: int32(fileIdx), item: 0'i32),
name: getModuleIdent(graph, filename),
infoImpl: newLineInfo(fileIdx, 1, 1))
info: newLineInfo(fileIdx, 1, 1))
if not isNimIdentifier(result.name.s):
rawMessage(graph.config, errGenerated, "invalid module name: '" & result.name.s &
"'; a module name must be a valid Nim identifier.")

View File

@@ -30,6 +30,7 @@ proc toLowerAscii(a: var string) {.inline.} =
proc flushDot*(conf: ConfigRef) =
## safe to call multiple times
# xxx one edge case not yet handled is when `printf` is called at CT with `compiletimeFFI`.
let stdOrr = if optStdout in conf.globalOptions: stdout else: stderr
let stdOrrKind = toStdOrrKind(stdOrr)
if stdOrrKind in conf.lastMsgWasDot:
@@ -51,7 +52,7 @@ proc makeCString*(s: string): Rope =
result = newStringOfCap(int(s.len.toFloat * 1.1) + 1)
result.add("\"")
for i in 0..<s.len:
# line wrapping of string literals in cgen'd code was a bad idea, e.g. causes: bug #16265
# line wrapping of string litterals in cgen'd code was a bad idea, e.g. causes: bug #16265
# It also makes reading c sources or grepping harder, for zero benefit.
# const MaxLineLength = 64
# if (i + 1) mod MaxLineLength == 0:
@@ -59,12 +60,12 @@ proc makeCString*(s: string): Rope =
toCChar(s[i], result)
result.add('\"')
proc newFileInfo(fullPath: AbsoluteFile, projPath: RelativeFile; kind = fikSource): TFileInfo =
proc newFileInfo(fullPath: AbsoluteFile, projPath: RelativeFile): TFileInfo =
result = TFileInfo(fullPath: fullPath, projPath: projPath,
shortName: fullPath.extractFilename,
quotedFullName: fullPath.string.makeCString,
lines: @[],
kind: kind)
lines: @[]
)
result.quotedName = result.shortName.makeCString
when defined(nimpretty):
if not result.fullPath.isEmpty:
@@ -132,23 +133,6 @@ proc fileInfoIdx*(conf: ConfigRef; filename: RelativeFile): FileIndex =
var dummy: bool = false
fileInfoIdx(conf, AbsoluteFile expandFilename(filename.string), dummy)
proc registerNifSuffix*(conf: ConfigRef; suffix: string; isKnownFile: var bool): FileIndex =
result = conf.m.filenameToIndexTbl.getOrDefault(suffix, InvalidFileIdx)
if result == InvalidFileIdx:
isKnownFile = false
result = conf.m.fileInfos.len.FileIndex
conf.m.fileInfos.add(newFileInfo(AbsoluteFile suffix, RelativeFile suffix, fikNifModule))
conf.m.filenameToIndexTbl[suffix] = result
else:
isKnownFile = true
proc fileInfoKind*(conf: ConfigRef; fileIdx: FileIndex): FileInfoKind =
## Returns the kind of a FileIndex (source file or NIF module suffix).
if fileIdx.int >= 0 and fileIdx.int < conf.m.fileInfos.len:
result = conf.m.fileInfos[fileIdx.int].kind
else:
result = fikSource # Default to source for unknown indices
proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo =
result = TLineInfo(fileIndex: fileInfoIdx)
if line < int high(uint16):
@@ -240,7 +224,7 @@ proc setDirtyFile*(conf: ConfigRef; fileIdx: FileIndex; filename: AbsoluteFile)
proc setHash*(conf: ConfigRef; fileIdx: FileIndex; hash: string) =
assert fileIdx.int32 >= 0
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc) or defined(gcYrc):
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
conf.m.fileInfos[fileIdx.int32].hash = hash
else:
shallowCopy(conf.m.fileInfos[fileIdx.int32].hash, hash)
@@ -248,7 +232,7 @@ proc setHash*(conf: ConfigRef; fileIdx: FileIndex; hash: string) =
proc getHash*(conf: ConfigRef; fileIdx: FileIndex): string =
assert fileIdx.int32 >= 0
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc) or defined(gcYrc):
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
result = conf.m.fileInfos[fileIdx.int32].hash
else:
shallowCopy(result, conf.m.fileInfos[fileIdx.int32].hash)
@@ -664,9 +648,7 @@ template internalAssert*(conf: ConfigRef, e: bool) =
template lintReport*(conf: ConfigRef; info: TLineInfo, beau, got: string, extraMsg = "") =
let m = "'$1' should be: '$2'$3" % [got, beau, extraMsg]
let msg = if optStyleError in conf.globalOptions: errGenerated
elif optStyleWarning in conf.globalOptions: warnUser
else: hintName
let msg = if optStyleError in conf.globalOptions: errGenerated else: hintName
liMessage(conf, info, msg, m, doNothing, instLoc())
proc quotedFilename*(conf: ConfigRef; fi: FileIndex): Rope =

View File

@@ -1,154 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2025 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## NIF-based C/C++ code generator backend.
##
## This module implements C code generation from precompiled NIF files.
## It traverses the module dependency graph starting from the main module
## and generates C code for all reachable modules.
##
## Usage:
## 1. Compile modules to NIF: nim m mymodule.nim
## 2. Generate C from NIF: nim nifc myproject.nim
import std/[intsets, tables, sets, os]
when defined(nimPreviewSlimSystem):
import std/assertions
import ast, options, lineinfos, modulegraphs, cgendata, cgen,
pathutils, extccomp, msgs, modulepaths, idents, types, ast2nif
proc loadModuleDependencies(g: ModuleGraph; mainFileIdx: FileIndex): seq[PrecompiledModule] =
## Traverse the module dependency graph using a stack.
## Returns all modules that need code generation, in dependency order.
let mainModule = moduleFromNifFile(g, mainFileIdx, {LoadFullAst})
var stack: seq[ModuleSuffix] = @[]
result = @[]
if mainModule.module != nil:
incl mainModule.module.flagsImpl, sfMainModule
for dep in mainModule.deps:
stack.add dep
var visited = initHashSet[string]()
while stack.len > 0:
let suffix = stack.pop()
if not visited.containsOrIncl(suffix.string):
let nifFile = toGeneratedFile(g.config, AbsoluteFile(suffix.string), ".nif")
let fileIdx = msgs.fileInfoIdx(g.config, nifFile)
let precomp = moduleFromNifFile(g, fileIdx, {LoadFullAst})
if precomp.module != nil:
result.add precomp
for dep in precomp.deps:
if not visited.contains(dep.string):
stack.add dep
if mainModule.module != nil:
result.add mainModule
proc setupNifBackendModule(g: ModuleGraph; module: PSym): BModule =
## Set up a BModule for code generation from a NIF module.
if g.backend == nil:
g.backend = cgendata.newModuleList(g)
result = cgen.newModule(BModuleList(g.backend), module, g.config, idGeneratorFromModule(module))
proc finishModule(g: ModuleGraph; bmod: BModule) =
# Finalize the module (this adds it to modulesClosed)
# Create an empty stmt list as the init body - genInitCode in writeModule will set it up properly
let initStmt = newNode(nkStmtList)
finalCodegenActions(g, bmod, initStmt)
# Generate dispatcher methods
for disp in getDispatchers(g):
genProcLvl3(bmod, disp)
proc generateCodeForModule(g: ModuleGraph; precomp: PrecompiledModule) =
## Generate C code for a single module.
let moduleId = precomp.module.position
var bmod = BModuleList(g.backend).mods[moduleId]
if bmod == nil:
bmod = setupNifBackendModule(g, precomp.module)
# Generate code for the module's top-level statements
if precomp.topLevel != nil:
cgen.genTopLevelStmt(bmod, precomp.topLevel)
proc generateCode*(g: ModuleGraph; mainFileIdx: FileIndex) =
## Main entry point for NIF-based C code generation.
## Traverses the module dependency graph and generates C code.
# Reset backend state
resetForBackend(g)
var isKnownFile = false
let systemFileIdx = registerNifSuffix(g.config, "sysma2dyk", isKnownFile)
g.config.m.systemFileIdx = systemFileIdx
#msgs.fileInfoIdx(g.config,
# g.config.libpath / RelativeFile"system.nim")
# Load system module first - it's always needed and contains essential hooks
var precompSys = PrecompiledModule(module: nil)
precompSys = moduleFromNifFile(g, systemFileIdx, {LoadFullAst, AlwaysLoadInterface})
g.systemModule = precompSys.module
# Load all modules in dependency order using stack traversal
# This must happen BEFORE any code generation so that hooks are loaded into loadedOps
let modules = loadModuleDependencies(g, mainFileIdx)
if modules.len == 0:
rawMessage(g.config, errGenerated,
"Cannot load NIF file for main module: " & toFullPath(g.config, mainFileIdx))
return
# Set up backend modules for all modules that need code generation
for m in modules:
discard setupNifBackendModule(g, m.module)
# Also ensure system module is set up and generated first if it exists
if precompSys.module != nil:
discard setupNifBackendModule(g, precompSys.module)
generateCodeForModule(g, precompSys)
# Track which modules have been processed to avoid duplicates
var processed = initIntSet()
if precompSys.module != nil:
processed.incl precompSys.module.position
# Generate code for all modules (skip system since it's already processed)
for m in modules:
if not processed.containsOrIncl(m.module.position):
generateCodeForModule(g, m)
# during code generation of `main.nim` we can trigger the code generation
# of symbols in different modules so we need to finish these modules
# here later, after the above loop!
# Important: The main module must be finished LAST so that all other modules
# have registered their init procs before genMainProc uses them.
var mainModule: BModule = nil
for m in BModuleList(g.backend).mods:
if m != nil:
assert m.module != nil
if sfMainModule in m.module.flags:
mainModule = m
else:
finishModule g, m
if mainModule != nil:
finishModule g, mainModule
# Write C files
cgenWriteModules(g.backend, g.config)
# Run C compiler
if g.config.cmd != cmdTcc:
extccomp.callCCompiler(g.config)
if not g.config.hcrOn:
extccomp.writeJsonBuildInstructions(g.config, g.cachedFiles)

View File

@@ -983,7 +983,7 @@ proc genericParamToNif(n: PNode; parent: PNode; c: var TranslationContext) =
toNif n, parent, c
proc addExternName(sym: PSym; c: var TranslationContext) =
if sym.loc.snippet != "":
if sym.loc.snippet != nil:
c.b.addStrLit sym.loc.snippet
else:
c.b.addStrLit sym.name.s

View File

@@ -919,7 +919,7 @@ proc infix(ctx: NilCheckerContext, l: PNode, r: PNode, magic: TMagic): PNode =
newSymNode(op, r.info),
l,
r)
result.typ = newType(tyBool, ctx.idgen, nil)
result.typ() = newType(tyBool, ctx.idgen, nil)
proc prefixNot(ctx: NilCheckerContext, node: PNode): PNode =
var cache = newIdentCache()
@@ -929,7 +929,7 @@ proc prefixNot(ctx: NilCheckerContext, node: PNode): PNode =
result = nkPrefix.newTree(
newSymNode(op, node.info),
node)
result.typ = newType(tyBool, ctx.idgen, nil)
result.typ() = newType(tyBool, ctx.idgen, nil)
proc infixEq(ctx: NilCheckerContext, l: PNode, r: PNode): PNode =
infix(ctx, l, r, mEqRef)

View File

@@ -65,7 +65,3 @@ define:useStdoutAsStdmsg
@if nimHasVtables:
experimental:vtables
@end
@if nimHasImplicitRangeConversion:
warning[ImplicitRangeConversion]:off
@end

View File

@@ -118,7 +118,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
if conf.selectedGC == gcUnselected:
if conf.backend in {backendC, backendCpp, backendObjc} or
(conf.cmd in cmdDocLike and conf.backend != backendJs) or
conf.cmd in {cmdGendepend, cmdNifC, cmdIc, cmdM}:
conf.cmd == cmdGendepend:
initOrcDefines(conf)
mainCommand(graph)

View File

@@ -207,6 +207,7 @@ proc parseAssignment(L: var Lexer, tok: var Token;
checkSymbol(L, tok)
val.add($tok)
confTok(L, tok, config, condStack)
config.currentConfigDir = parentDir(filename.string)
if percent:
processSwitch(s, strtabs.`%`(val, config.configVars,
{useEnvironment, useEmpty}), passPP, info, config)
@@ -248,8 +249,6 @@ proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef; idgen:
setDefaultLibpath(conf)
template readConfigFile(path) =
let configPath = path
conf.currentConfigDir = configPath.splitFile.dir.string
setConfigVar(conf, "selfDir", conf.currentConfigDir)
if readConfigFile(configPath, cache, conf):
conf.configFiles.add(configPath)

View File

@@ -128,7 +128,7 @@ proc createInterpreter*(scriptName: string;
if conf.libpath.isEmpty: conf.libpath = AbsoluteDir p
var m = graph.makeModule(scriptName)
incl(m, sfMainModule)
incl(m.flags, sfMainModule)
var idgen = idGeneratorFromModule(m)
var vm = newCtx(m, cache, graph, idgen)
vm.mode = emRepl
@@ -168,7 +168,7 @@ proc runRepl*(r: TLLRepl;
if supportNimscript: defineSymbol(conf.symbols, "nimconfig")
when hasFFI: defineSymbol(graph.config.symbols, "nimffi")
var m = graph.makeStdinModule()
incl(m, sfMainModule)
incl(m.flags, sfMainModule)
var idgen = idGeneratorFromModule(m)
if supportNimscript: graph.vm = setupVM(m, cache, "stdin", graph, idgen)

View File

@@ -84,7 +84,7 @@ proc toTreeSet*(conf: ConfigRef; s: TBitSet, settype: PType, info: TLineInfo): P
elemType = settype[0]
first = firstOrd(conf, elemType).toInt64
result = newNodeI(nkCurly, info)
result.typ = settype
result.typ() = settype
result.info = info
e = 0
while e < s.len * ElemSize:
@@ -101,7 +101,7 @@ proc toTreeSet*(conf: ConfigRef; s: TBitSet, settype: PType, info: TLineInfo): P
result.add aa
else:
n = newNodeI(nkRange, info)
n.typ = elemType
n.typ() = elemType
n.add aa
let bb = newIntTypeNode(b + first, elemType)
bb.info = info

View File

@@ -25,7 +25,7 @@ const
useEffectSystem* = true
useWriteTracking* = false
hasFFI* = defined(nimHasLibFFI)
copyrightYear* = "2026"
copyrightYear* = "2025"
nimEnableCovariance* = defined(nimEnableCovariance)
@@ -68,7 +68,6 @@ type # please make sure we have under 32 options
optUseNimcache, # save artifacts (including binary) in $nimcache
optStyleHint, # check that the names adhere to NEP-1
optStyleError, # enforce that the names adhere to NEP-1
optStyleWarning, # emit style checks as warnings
optStyleUsages, # only enforce consistent **usages** of the symbol
optSkipSystemConfigFile, # skip the system's cfg/nims config file
optSkipProjConfigFile, # skip the project's cfg/nims config file
@@ -111,10 +110,6 @@ type # please make sure we have under 32 options
optEnableDeepCopy # ORC specific: enable 'deepcopy' for all types.
optShowNonExportedFields # for documentation: show fields that are not exported
optJsBigInt64 # use bigints for 64-bit integers in JS
optDocRaw # for documentation: Don't render markdown for JSON output
optItaniumMangle # mangling follows the Itanium spec
optCompress # turn on AST compression by converting it to NIF
optWithinConfigSystem # we still compile within the configuration system
TGlobalOptions* = set[TGlobalOption]
@@ -157,6 +152,7 @@ type
cmdCheck # semantic checking for whole project
cmdM # only compile a single
cmdParse # parse a single file (for debugging)
cmdRod # .rod to some text representation (for debugging)
cmdIdeTools # ide tools (e.g. nimsuggest)
cmdNimscript # evaluate nimscript
cmdDoc0
@@ -177,8 +173,6 @@ type
cmdJsonscript # compile a .json build file
# old unused: cmdInterpret, cmdDef: def feature (find definition for IDEs)
cmdCompileToNif
cmdNifC # generate C code from NIF files
cmdIc # generate .build.nif for nifmake
const
cmdBackends* = {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,
@@ -195,7 +189,6 @@ type
gcRegions = "regions"
gcArc = "arc"
gcOrc = "orc"
gcYrc = "yrc" # thread-safe ORC (concurrent cycle collector)
gcAtomicArc = "atomicArc"
gcMarkAndSweep = "markAndSweep"
gcHooks = "hooks"
@@ -371,7 +364,6 @@ type
numberOfProcessors*: int # number of processors
lastCmdTime*: float # when caas is enabled, we measure each command
symbolFiles*: SymbolFilesOption
ic*: bool # whether ic is enabled
spellSuggestMax*: int # max number of spelling suggestions for typos
cppDefines*: HashSet[string] # (*)
@@ -516,7 +508,7 @@ const
optHints, optStackTrace, optLineTrace, # consider adding `optStackTraceMsgs`
optTrMacros, optStyleCheck, optCursorInference}
DefaultGlobalOptions* = {optThreadAnalysis, optExcessiveStackTrace,
optJsBigInt64, optItaniumMangle}
optJsBigInt64}
proc getSrcTimestamp(): DateTime =
try:
@@ -1048,9 +1040,6 @@ proc isDynlibOverride*(conf: ConfigRef; lib: string): bool =
proc showNonExportedFields*(conf: ConfigRef) =
incl(conf.globalOptions, optShowNonExportedFields)
proc docRawOutput*(conf: ConfigRef) =
incl(conf.globalOptions, optDocRaw)
proc expandDone*(conf: ConfigRef): bool =
result = conf.ideCmd == ideExpand and conf.expandLevels == 0 and conf.expandProgress

View File

@@ -33,7 +33,7 @@ proc getPackage*(conf: ConfigRef; cache: IdentCache; fileIdx: FileIndex): PSym =
pkgIdent = getIdent(cache, pkgName)
newSym(skPackage, pkgIdent, idGeneratorForPackage(int32(fileIdx)), nil, info)
proc getPackageSymbol*(sym: PSym): PSym =
func getPackageSymbol*(sym: PSym): PSym =
## Return the owning package symbol.
assert sym != nil
result = sym
@@ -41,18 +41,18 @@ proc getPackageSymbol*(sym: PSym): PSym =
result = result.owner
assert result != nil, repr(sym.info)
proc getPackageId*(sym: PSym): int =
func getPackageId*(sym: PSym): int =
## Return the owning package ID.
sym.getPackageSymbol.id
proc belongsToProjectPackage*(conf: ConfigRef, sym: PSym): bool =
func belongsToProjectPackage*(conf: ConfigRef, sym: PSym): bool =
## Return whether the symbol belongs to the project's package.
##
## See Also:
## * `modulegraphs.belongsToStdlib`
conf.mainPackageId == sym.getPackageId
proc belongsToProjectPackageMaybeNil*(conf: ConfigRef, sym: PSym): bool =
func belongsToProjectPackageMaybeNil*(conf: ConfigRef, sym: PSym): bool =
## Return whether the symbol belongs to the project's package.
## Returns `false` if `sym` is nil.
##

View File

@@ -148,6 +148,11 @@ proc processModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator;
closeParser(p)
if s.kind != llsStdIn: break
closePasses(graph, a)
if graph.config.backend notin {backendC, backendCpp, backendObjc}:
# We only write rod files here if no C-like backend is active.
# The C-like backends have been patched to support the IC mechanism.
# They are responsible for closing the rod files. See `cbackend.nim`.
closeRodFile(graph, module)
result = true
proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags, fromModule: PSym = nil): PSym =
@@ -163,12 +168,24 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags, fr
elif graph.config.projectIsCmd: s = llStreamOpen(graph.config.cmdInput)
discard processModule(graph, result, idGeneratorFromModule(result), s)
if result == nil:
result = newModule(graph, fileIdx)
result.incl flags
registerModule(graph, result)
processModuleAux("import")
var cachedModules: seq[FileIndex] = @[]
result = moduleFromRodFile(graph, fileIdx, cachedModules)
let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
if result == nil:
result = newModule(graph, fileIdx)
result.flags.incl flags
registerModule(graph, result)
processModuleAux("import")
else:
if sfSystemModule in flags:
graph.systemModule = result
partialInitModule(result, graph, fileIdx, filename)
for m in cachedModules:
registerModuleById(graph, m)
replayStateChanges(graph.packed.pm[m.int].module, graph)
replayGenericCacheInformation(graph, m.int)
elif graph.isDirty(result):
result.excl sfDirty
result.flags.excl sfDirty
# reset module fields:
initStrTables(graph, result)
result.ast = nil

View File

@@ -3,11 +3,6 @@ import sem, cgen, modulegraphs, ast, llstream, parser, msgs,
packages, syntaxes, depends, vm, pragmas, idents, lookups, wordrecg,
liftdestructors, nifgen
when not defined(nimKochBootstrap):
import vmdef
import ast2nif
import "../dist/nimony/src/lib" / [nifstreams, bitabs]
import pipelineutils
import ../dist/checksums/src/checksums/sha1
@@ -40,12 +35,7 @@ proc processPipeline(graph: ModuleGraph; semNode: PNode; bModule: PPassContext):
of GenDependPass:
result = addDotDependency(bModule, semNode)
of SemPass:
# Return the semantic node for cmdM (NIF generation needs it)
# For regular check, we don't need the result
if graph.config.cmd == cmdM:
result = semNode
else:
result = graph.emptyNode
result = graph.emptyNode
of Docgen2Pass, Docgen2TexPass:
when not defined(leanCompiler):
result = processNode(bModule, semNode)
@@ -62,8 +52,7 @@ proc processPipeline(graph: ModuleGraph; semNode: PNode; bModule: PPassContext):
raiseAssert "use setPipeLinePass to set a proper PipelinePass"
proc processImplicitImports*(graph: ModuleGraph; implicits: seq[string], nodeKind: TNodeKind,
m: PSym, ctx: PContext, bModule: PPassContext, idgen: IdGenerator;
topLevelStmts: PNode) =
m: PSym, ctx: PContext, bModule: PPassContext, idgen: IdGenerator) =
# XXX fixme this should actually be relative to the config file!
let relativeTo = toFullPath(graph.config, m.info)
for module in items(implicits):
@@ -75,13 +64,8 @@ proc processImplicitImports*(graph: ModuleGraph; implicits: seq[string], nodeKin
importStmt.add str
message(graph.config, importStmt.info, hintProcessingStmt, $idgen[])
let semNode = semWithPContext(ctx, importStmt)
if semNode == nil:
if semNode == nil or processPipeline(graph, semNode, bModule) == nil:
break
let top = processPipeline(graph, semNode, bModule)
if top == nil:
break
if topLevelStmts != nil:
topLevelStmts.add top
proc prePass*(c: PContext; n: PNode) =
for son in n:
@@ -103,7 +87,7 @@ proc prePass*(c: PContext; n: PNode) =
let feature = parseEnum[Feature](name.strVal)
if feature == codeReordering:
c.features.incl feature
c.module.incl sfReorder
c.module.flags.incl sfReorder
except ValueError:
discard
else:
@@ -166,11 +150,6 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
else:
s = stream
graph.interactive = stream.kind == llsStdIn
var topLevelStmts =
if optCompress in graph.config.globalOptions or graph.config.cmd == cmdM:
newNodeI(nkStmtList, module.info)
else:
nil
while true:
syntaxes.openParser(p, fileIdx, s, graph.cache, graph.config)
@@ -180,8 +159,8 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
# in ROD files. I think we should enable this feature only
# for the interactive mode.
if module.name.s != "nimscriptapi":
processImplicitImports graph, graph.config.implicitImports, nkImportStmt, module, ctx, bModule, idgen, topLevelStmts
processImplicitImports graph, graph.config.implicitIncludes, nkIncludeStmt, module, ctx, bModule, idgen, topLevelStmts
processImplicitImports graph, graph.config.implicitImports, nkImportStmt, module, ctx, bModule, idgen
processImplicitImports graph, graph.config.implicitIncludes, nkIncludeStmt, module, ctx, bModule, idgen
checkFirstLineIndentation(p)
block processCode:
@@ -202,9 +181,7 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
if graph.pipelinePass != EvalPass:
message(graph.config, sl.info, hintProcessingStmt, $idgen[])
var semNode = semWithPContext(ctx, sl)
let top = processPipeline(graph, semNode, bModule)
if top != nil and topLevelStmts != nil:
topLevelStmts.add top
discard processPipeline(graph, semNode, bModule)
closeParser(p)
if s.kind != llsStdIn: break
@@ -221,7 +198,7 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
if retTyp != nil:
# TODO: properly semcheck the code of dispatcher?
createTypeBoundOps(graph, ctx, retTyp, disp.ast.info, idgen)
genProcLvl3(m, disp)
genProcAux(m, disp)
discard closePContext(graph, ctx, nil)
of JSgenPass:
when not defined(leanCompiler):
@@ -241,26 +218,11 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
of NonePass:
raiseAssert "use setPipeLinePass to set a proper PipelinePass"
when not defined(nimKochBootstrap):
# For cmdM: only write NIF for the main module, not for imported modules
# (imported modules should be loaded from existing NIF files)
let shouldWriteNif = (optCompress in graph.config.globalOptions) or
(graph.config.cmd == cmdM and sfMainModule in module.flags)
if shouldWriteNif and not graph.config.isDefined("nimscript"):
topLevelStmts.add finalNode
# Collect replay actions from both pragma computations and VM state diff
var replayActions: seq[PNode] = @[]
# Get pragma-recorded replay actions (compile, link, passC, passL, etc.)
if graph.nifReplayActions.hasKey(module.position.int32):
replayActions.add graph.nifReplayActions[module.position.int32]
# Also get VM state diff (macro cache operations)
if graph.vm != nil:
for (m, n) in PCtx(graph.vm).vmstateDiff:
if m == module:
replayActions.add n
writeNifModule(graph.config, module.position.int32, topLevelStmts, graph.opsLog, replayActions)
if graph.config.backend notin {backendC, backendCpp, backendObjc}:
# We only write rod files here if no C-like backend is active.
# The C-like backends have been patched to support the IC mechanism.
# They are responsible for closing the rod files. See `cbackend.nim`.
closeRodFile(graph, module)
result = true
proc compilePipelineModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags; fromModule: PSym = nil): PSym =
@@ -276,30 +238,8 @@ proc compilePipelineModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymF
elif graph.config.projectIsCmd: s = llStreamOpen(graph.config.cmdInput)
discard processPipelineModule(graph, result, idGeneratorFromModule(result), s)
if result == nil:
when not defined(nimKochBootstrap):
# For cmdM: load imports from NIF files (but compile the main module from source)
# Skip when withinSystem is true (compiling system.nim itself)
if graph.config.cmd == cmdM and
sfMainModule notin flags and
not graph.withinSystem and
not graph.config.isDefined("nimscript"):
let precomp = moduleFromNifFile(graph, fileIdx)
if precomp.module == nil:
let nifPath = toNifFilename(graph.config, fileIdx)
globalError(graph.config, unknownLineInfo,
"nim m requires precompiled NIF for import: " & toFullPath(graph.config, fileIdx) &
" (expected: " & nifPath & ")")
return nil # Don't fall through to compile from source
else:
# Module successfully loaded from NIF file - use it and skip processing
result = precomp.module
if sfSystemModule in flags:
graph.systemModule = result
partialInitModule(result, graph, fileIdx, AbsoluteFile(toFullPath(graph.config, fileIdx)))
# Replay state changes from the loaded NIF module
if result.ast != nil:
replayStateChanges(result, graph)
return result # Return early, don't process from source
var cachedModules: seq[FileIndex] = @[]
result = moduleFromRodFile(graph, fileIdx, cachedModules)
let path = toFullPath(graph.config, fileIdx)
let filename = AbsoluteFile path
# it could be a stdinfile/cmdfile
@@ -307,19 +247,26 @@ proc compilePipelineModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymF
graph.cachedFiles[path] = $secureHashFile(path)
if result == nil:
result = newModule(graph, fileIdx)
result.incl flags
result.flags.incl flags
registerModule(graph, result)
processModuleAux("import")
else:
if sfSystemModule in flags:
graph.systemModule = result
if sfMainModule in flags and graph.config.cmd == cmdM:
result.incl flags
result.flags.incl flags
registerModule(graph, result)
processModuleAux("import")
partialInitModule(result, graph, fileIdx, filename)
for m in cachedModules:
registerModuleById(graph, m)
if sfMainModule in flags and graph.config.cmd == cmdM:
discard
else:
replayStateChanges(graph.packed.pm[m.int].module, graph)
replayGenericCacheInformation(graph, m.int)
elif graph.isDirty(result):
result.excl sfDirty
result.flags.excl sfDirty
# reset module fields:
initStrTables(graph, result)
result.ast = nil
@@ -347,12 +294,10 @@ proc connectPipelineCallbacks*(graph: ModuleGraph) =
proc compilePipelineSystemModule*(graph: ModuleGraph) =
if graph.systemModule == nil:
graph.withinSystem = true
connectPipelineCallbacks(graph)
graph.config.m.systemFileIdx = fileInfoIdx(graph.config,
graph.config.libpath / RelativeFile"system.nim")
discard graph.compilePipelineModule(graph.config.m.systemFileIdx, {sfSystemModule})
graph.withinSystem = false
proc compilePipelineProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIdx) =
connectPipelineCallbacks(graph)
@@ -369,23 +314,7 @@ proc compilePipelineProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIdx
graph.importStack.add projectFile
if projectFile == systemFileIdx:
graph.withinSystem = true
discard graph.compilePipelineModule(projectFile, {sfMainModule, sfSystemModule})
graph.withinSystem = false
elif graph.config.cmd == cmdM:
# For cmdM: load system.nim from NIF first, then compile the main module
connectPipelineCallbacks(graph)
graph.config.m.systemFileIdx = fileInfoIdx(graph.config,
graph.config.libpath / RelativeFile"system.nim")
when not defined(nimKochBootstrap):
let precomp = moduleFromNifFile(graph, graph.config.m.systemFileIdx)
graph.systemModule = precomp.module
if graph.systemModule == nil:
let nifPath = toNifFilename(graph.config, graph.config.m.systemFileIdx)
localError(graph.config, unknownLineInfo,
"nim m requires precompiled NIF for system module (expected: " & nifPath & ")")
return
discard graph.compilePipelineModule(projectFile, {sfMainModule})
else:
graph.compilePipelineSystemModule()
discard graph.compilePipelineModule(projectFile, {sfMainModule})

View File

@@ -33,7 +33,7 @@ proc iterToProcImpl*(c: PContext, n: PNode): PNode =
let prc = newSym(skProc, n[3].ident, c.idgen, iter.sym.owner, iter.sym.info)
prc.typ = copyType(iter.sym.typ, c.idgen, prc)
excl prc.typ, tfCapturesEnv
excl prc.typ.flags, tfCapturesEnv
prc.typ.n.add newSymNode(getEnvParam(iter.sym))
prc.typ.rawAddSon t
let orig = iter.sym.ast

View File

@@ -21,6 +21,8 @@ import std/[os, math, strutils]
when defined(nimPreviewSlimSystem):
import std/assertions
from ic / ic import addCompilerProc
const
FirstCallConv* = wNimcall
LastCallConv* = wNoconv
@@ -146,7 +148,7 @@ proc pragmaEnsures(c: PContext, n: PNode) =
if o.kind in routineKinds and o.typ != nil and o.typ.returnType != nil:
var s = newSym(skResult, getIdent(c.cache, "result"), c.idgen, o, n.info)
s.typ = o.typ.returnType
incl(s.flagsImpl, sfUsed)
incl(s.flags, sfUsed)
addDecl(c, s)
n[1] = c.semExpr(c, n[1])
closeScope(c)
@@ -154,12 +156,12 @@ proc pragmaEnsures(c: PContext, n: PNode) =
proc setExternName(c: PContext; s: PSym, extname: string, info: TLineInfo) =
# special cases to improve performance:
if extname == "$1":
s.setSnippet(rope(s.name.s))
s.loc.snippet = rope(s.name.s)
elif '$' notin extname:
s.setSnippet(rope(extname))
s.loc.snippet = rope(extname)
else:
try:
s.setSnippet(rope(extname % s.name.s))
s.loc.snippet = rope(extname % s.name.s)
except ValueError:
localError(c.config, info, "invalid extern name: '" & extname & "'. (Forgot to escape '$'?)")
when hasFFI:
@@ -168,36 +170,36 @@ proc setExternName(c: PContext; s: PSym, extname: string, info: TLineInfo) =
proc makeExternImport(c: PContext; s: PSym, extname: string, info: TLineInfo) =
setExternName(c, s, extname, info)
s.incl(sfImportc)
s.excl(sfForward)
incl(s.flags, sfImportc)
excl(s.flags, sfForward)
proc makeExternExport(c: PContext; s: PSym, extname: string, info: TLineInfo) =
setExternName(c, s, extname, info)
s.incl(sfExportc)
incl(s.flags, sfExportc)
proc processImportCompilerProc(c: PContext; s: PSym, extname: string, info: TLineInfo) =
setExternName(c, s, extname, info)
s.incl(sfImportc)
s.excl(sfForward)
incl(s.locImpl.flags, lfImportCompilerProc)
incl(s.flags, sfImportc)
excl(s.flags, sfForward)
incl(s.loc.flags, lfImportCompilerProc)
proc processImportCpp(c: PContext; s: PSym, extname: string, info: TLineInfo) =
setExternName(c, s, extname, info)
s.incl(sfImportc)
incl(s.flagsImpl, sfInfixCall)
excl(s.flagsImpl, sfForward)
incl(s.flags, sfImportc)
incl(s.flags, sfInfixCall)
excl(s.flags, sfForward)
if c.config.backend == backendC:
let m = s.getModule()
incl(m.flagsImpl, sfCompileToCpp)
incl(m.flags, sfCompileToCpp)
incl c.config.globalOptions, optMixedMode
proc processImportObjC(c: PContext; s: PSym, extname: string, info: TLineInfo) =
setExternName(c, s, extname, info)
s.incl(sfImportc)
incl(s.flagsImpl, sfNamedParamCall)
excl(s.flagsImpl, sfForward)
incl(s.flags, sfImportc)
incl(s.flags, sfNamedParamCall)
excl(s.flags, sfForward)
let m = s.getModule()
m.incl(sfCompileToObjc)
incl(m.flags, sfCompileToObjc)
proc newEmptyStrNode(c: PContext; n: PNode, strVal: string = ""): PNode {.noinline.} =
result = newNodeIT(nkStrLit, n.info, getSysType(c.graph, n.info, tyString))
@@ -237,14 +239,14 @@ proc getOptionalStr(c: PContext, n: PNode, defaultStr: string): string =
proc processVirtual(c: PContext, n: PNode, s: PSym, flag: TSymFlag) =
s.constraint = newEmptyStrNode(c, n, getOptionalStr(c, n, "$1"))
s.constraint.strVal = s.constraint.strVal % s.name.s
s.flagsImpl.incl {flag, sfInfixCall, sfExportc, sfMangleCpp}
s.flags.incl {flag, sfInfixCall, sfExportc, sfMangleCpp}
s.typ.callConv = ccMember
incl c.config.globalOptions, optMixedMode
proc processCodegenDecl(c: PContext, n: PNode, sym: PSym) =
sym.constraint = getStrLitNode(c, n)
sym.flagsImpl.incl sfCodegenDecl
sym.flags.incl sfCodegenDecl
proc processMagic(c: PContext, n: PNode, s: PSym) =
#if sfSystemModule notin c.module.flags:
@@ -280,10 +282,10 @@ proc onOff(c: PContext, n: PNode, op: TOptions, resOptions: var TOptions) =
proc pragmaNoForward*(c: PContext, n: PNode; flag=sfNoForward) =
if isTurnedOn(c, n):
incl(c.module.flagsImpl, flag)
incl(c.module.flags, flag)
c.features.incl codeReordering
else:
excl(c.module.flagsImpl, flag)
excl(c.module.flags, flag)
# c.features.excl codeReordering
# deprecated as of 0.18.1
@@ -355,9 +357,9 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) =
var lib = getLib(c, libDynamic, expectDynlibNode(c, n))
if not lib.isOverridden:
addToLib(lib, sym)
sym.incl(lfDynamicLib)
incl(sym.loc.flags, lfDynamicLib)
else:
sym.incl(lfExportLib)
incl(sym.loc.flags, lfExportLib)
# since we'll be loading the dynlib symbols dynamically, we must use
# a calling convention that doesn't introduce custom name mangling
# cdecl is the default - the user can override this explicitly
@@ -433,7 +435,7 @@ proc processExperimental(c: PContext; n: PNode) =
if not isTopLevel(c):
localError(c.config, n.info,
"Code reordering experimental pragma only valid at toplevel")
c.module.flagsImpl.incl sfReorder
c.module.flags.incl sfReorder
except ValueError:
localError(c.config, n[1].info, "unknown experimental feature")
else:
@@ -567,7 +569,7 @@ proc processCompile(c: PContext, n: PNode) =
n[i] = c.semConstExpr(c, n[i])
case n[i].kind
of nkStrLit, nkRStrLit, nkTripleStrLit:
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc) or defined(gcYrc):
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
result = n[i].strVal
else:
shallowCopy(result, n[i].strVal)
@@ -634,7 +636,7 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
var e = searchInScopes(con, getIdent(con.cache, sub), amb)
# XXX what to do here if 'amb' is true?
if e != nil:
incl(e.flagsImpl, sfUsed)
incl(e.flags, sfUsed)
if isDefined(con.config, "nimPreviewAsmSemSymbol"):
result.add con.semExprWithType(con, newSymNode(e), {efTypeAllowed})
else:
@@ -723,12 +725,12 @@ proc processPragma(c: PContext, n: PNode, i: int) =
proc pragmaRaisesOrTags(c: PContext, n: PNode) =
proc processExc(c: PContext, x: PNode) =
if c.hasUnresolvedArgs(c, x):
x.typ = makeTypeFromExpr(c, x)
x.typ() = makeTypeFromExpr(c, x)
else:
var t = skipTypes(c.semTypeNode(c, x, nil), skipPtrs)
if t.kind notin {tyObject, tyOr}:
localError(c.config, x.info, errGenerated, "invalid type for raises/tags list")
x.typ = t
x.typ() = t
if n.kind in nkPragmaCallKinds and n.len == 2:
let it = n[1]
@@ -755,21 +757,23 @@ proc typeBorrow(c: PContext; sym: PSym, n: PNode) =
let it = n[1]
if it.kind != nkAccQuoted:
localError(c.config, n.info, "a type can only borrow `.` for now")
incl(sym.typ, tfBorrowDot)
incl(sym.typ.flags, tfBorrowDot)
proc markCompilerProc(c: PContext; s: PSym) =
# minor hack ahead: FlowVar is the only generic .compilerproc type which
# should not have an external name set:
if s.kind != skType or s.name.s != "FlowVar":
makeExternExport(c, s, "$1", s.info)
incl(s, sfCompilerProc)
incl(s.flagsImpl, sfUsed)
incl(s.flags, sfCompilerProc)
incl(s.flags, sfUsed)
registerCompilerProc(c.graph, s)
if c.config.symbolFiles != disabledSf:
addCompilerProc(c.encoder, c.packedRepr, s)
proc deprecatedStmt(c: PContext; outerPragma: PNode) =
let pragma = outerPragma[1]
if pragma.kind in {nkStrLit..nkTripleStrLit}:
incl(c.module, sfDeprecated)
incl(c.module.flags, sfDeprecated)
c.module.constraint = getStrLitNode(c, outerPragma)
return
if pragma.kind != nkBracket:
@@ -838,7 +842,7 @@ proc processEffectsOf(c: PContext, n: PNode; owner: PSym) =
let r = c.semExpr(c, n)
if r.kind == nkSym and r.sym.kind == skParam:
if r.sym.owner == owner:
incl r.sym, sfEffectsDelayed
incl r.sym.flags, sfEffectsDelayed
else:
localError(c.config, n.info, errGenerated, "parameter cannot be declared as .effectsOf")
else:
@@ -903,8 +907,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
if c.config.backend != backendCpp:
localError(c.config, it.info, "exportcpp requires `cpp` backend, got: " & $c.config.backend)
else:
incl(sym, sfMangleCpp)
incl(sym.flagsImpl, sfUsed) # avoid wrong hints
incl(sym.flags, sfMangleCpp)
incl(sym.flags, sfUsed) # avoid wrong hints
of wImportc:
let name = getOptionalStr(c, it, "$1")
cppDefine(c.config, name)
@@ -917,24 +921,24 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
processImportCompilerProc(c, sym, name, it.info)
of wExtern: setExternName(c, sym, expectStrLit(c, it), it.info)
of wDirty:
if sym.kind == skTemplate: incl(sym, sfDirty)
if sym.kind == skTemplate: incl(sym.flags, sfDirty)
else: invalidPragma(c, it)
of wRedefine:
if sym.kind == skTemplate: incl(sym, sfTemplateRedefinition)
if sym.kind == skTemplate: incl(sym.flags, sfTemplateRedefinition)
else: invalidPragma(c, it)
of wCallsite:
if sym.kind == skTemplate: incl(sym, sfCallsite)
if sym.kind == skTemplate: incl(sym.flags, sfCallsite)
else: invalidPragma(c, it)
of wImportCpp:
processImportCpp(c, sym, getOptionalStr(c, it, "$1"), it.info)
of wCppNonPod:
incl(sym, sfCppNonPod)
incl(sym.flags, sfCppNonPod)
of wImportJs:
if c.config.backend != backendJs:
localError(c.config, it.info, "`importjs` pragma requires the JavaScript target")
let name = getOptionalStr(c, it, "$1")
incl(sym, sfImportc)
incl(sym.flagsImpl, sfInfixCall)
incl(sym.flags, sfImportc)
incl(sym.flags, sfInfixCall)
if sym.kind in skProcKinds and {'(', '#', '@'} notin name:
localError(c.config, n.info, "`importjs` for routines requires a pattern")
setExternName(c, sym, name, it.info)
@@ -964,29 +968,29 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
localError(c.config, it.info, "power of two expected")
of wNodecl:
noVal(c, it)
sym.incl(lfNoDecl)
incl(sym.loc.flags, lfNoDecl)
of wPure, wAsmNoStackFrame:
noVal(c, it)
if sym != nil:
if k == wPure and sym.kind in routineKinds: invalidPragma(c, it)
else: incl(sym, sfPure)
else: incl(sym.flags, sfPure)
of wVolatile:
noVal(c, it)
incl(sym, sfVolatile)
incl(sym.flags, sfVolatile)
of wCursor:
noVal(c, it)
incl(sym, sfCursor)
incl(sym.flags, sfCursor)
of wRegister:
noVal(c, it)
incl(sym, sfRegister)
incl(sym.flags, sfRegister)
of wNoalias:
noVal(c, it)
incl(sym, sfNoalias)
incl(sym.flags, sfNoalias)
of wEffectsOf:
processEffectsOf(c, it, sym)
of wThreadVar:
noVal(c, it)
incl(sym, {sfThread, sfGlobal})
incl(sym.flags, {sfThread, sfGlobal})
of wDeadCodeElimUnused:
warningDeprecated(c.config, n.info, "'{.deadcodeelim: on.}' is deprecated, now a noop") # deprecated, dead code elim always on
of wNoForward: pragmaNoForward(c, it)
@@ -996,50 +1000,51 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
noVal(c, it)
if comesFromPush:
if sym.kind in {skProc, skFunc}:
incl(sym, sfCompileTime)
incl(sym.flags, sfCompileTime)
else:
incl(sym, sfCompileTime)
incl(sym.flags, sfCompileTime)
#incl(sym.loc.flags, lfNoDecl)
of wGlobal:
noVal(c, it)
incl(sym, {sfGlobal, sfPure})
incl(sym.flags, sfGlobal)
incl(sym.flags, sfPure)
of wConstructor:
incl(sym, sfConstructor)
incl(sym.flags, sfConstructor)
if sfImportc notin sym.flags:
sym.constraint = newEmptyStrNode(c, it, getOptionalStr(c, it, ""))
sym.constraint.strVal = sym.constraint.strVal
sym.flagsImpl.incl {sfExportc, sfMangleCpp}
sym.flags.incl {sfExportc, sfMangleCpp}
sym.typ.callConv = ccNoConvention
of wHeader:
var lib = getLib(c, libHeader, getStrLitNode(c, it))
addToLib(lib, sym)
incl(sym, sfImportc)
incl(sym.locImpl.flags, lfHeader)
incl(sym.locImpl.flags, lfNoDecl)
incl(sym.flags, sfImportc)
incl(sym.loc.flags, lfHeader)
incl(sym.loc.flags, lfNoDecl)
# implies nodecl, because otherwise header would not make sense
if sym.locImpl.snippet == "": sym.locImpl.snippet = rope(sym.name.s)
if sym.loc.snippet == "": sym.loc.snippet = rope(sym.name.s)
of wNoSideEffect:
noVal(c, it)
if sym != nil:
incl(sym, sfNoSideEffect)
if sym.typ != nil: incl(sym.typ, tfNoSideEffect)
incl(sym.flags, sfNoSideEffect)
if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect)
of wSideEffect:
noVal(c, it)
incl(sym, sfSideEffect)
incl(sym.flags, sfSideEffect)
of wNoreturn:
noVal(c, it)
# Disable the 'noreturn' annotation when in the "Quirky Exceptions" mode!
if c.config.exc != excQuirky:
incl(sym, sfNoReturn)
incl(sym.flags, sfNoReturn)
if sym.typ.returnType != nil:
localError(c.config, sym.ast[paramsPos][0].info,
".noreturn with return type not allowed")
of wNoDestroy:
noVal(c, it)
incl(sym, sfGeneratedOp)
incl(sym.flags, sfGeneratedOp)
of wNosinks:
noVal(c, it)
incl(sym, sfWasForwarded)
incl(sym.flags, sfWasForwarded)
of wDynlib:
processDynLib(c, it, sym)
of wCompilerProc, wCore:
@@ -1048,79 +1053,79 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
recordPragma(c, it, "cppdefine", sym.name.s)
if sfFromGeneric notin sym.flags: markCompilerProc(c, sym)
of wNonReloadable:
sym.incl sfNonReloadable
sym.flags.incl sfNonReloadable
of wProcVar:
# old procvar annotation, no longer needed
noVal(c, it)
of wExplain:
sym.incl sfExplain
sym.flags.incl sfExplain
of wDeprecated:
if sym != nil and sym.kind in routineKinds + {skType, skVar, skLet, skConst}:
if it.kind in nkPragmaCallKinds: discard getStrLitNode(c, it)
incl(sym, sfDeprecated)
incl(sym.flags, sfDeprecated)
elif sym != nil and sym.kind != skModule:
# We don't support the extra annotation field
if it.kind in nkPragmaCallKinds:
localError(c.config, it.info, "annotation to deprecated not supported here")
incl(sym, sfDeprecated)
incl(sym.flags, sfDeprecated)
# At this point we're quite sure this is a statement and applies to the
# whole module
elif it.kind in nkPragmaCallKinds: deprecatedStmt(c, it)
else: incl(c.module, sfDeprecated)
else: incl(c.module.flags, sfDeprecated)
of wVarargs:
noVal(c, it)
if sym.typ == nil: invalidPragma(c, it)
else: incl(sym.typ, tfVarargs)
else: incl(sym.typ.flags, tfVarargs)
of wBorrow:
if sym.kind == skType:
typeBorrow(c, sym, it)
else:
noVal(c, it)
incl(sym, sfBorrow)
incl(sym.flags, sfBorrow)
of wFinal:
noVal(c, it)
if sym.typ == nil: invalidPragma(c, it)
else: incl(sym.typ, tfFinal)
else: incl(sym.typ.flags, tfFinal)
of wInheritable:
noVal(c, it)
if sym.typ == nil or tfFinal in sym.typ.flags: invalidPragma(c, it)
else: incl(sym.typ, tfInheritable)
else: incl(sym.typ.flags, tfInheritable)
of wPackage:
noVal(c, it)
if sym.typ == nil: invalidPragma(c, it)
else: incl(sym, sfForward)
else: incl(sym.flags, sfForward)
of wAcyclic:
noVal(c, it)
if sym.typ == nil: invalidPragma(c, it)
else: incl(sym.typ, tfAcyclic)
else: incl(sym.typ.flags, tfAcyclic)
of wShallow:
noVal(c, it)
if sym.typ == nil: invalidPragma(c, it)
else: incl(sym.typ, tfShallow)
else: incl(sym.typ.flags, tfShallow)
of wThread:
noVal(c, it)
incl(sym, sfThread)
incl(sym.flags, sfThread)
if sym.typ != nil:
incl(sym.typ, tfThread)
incl(sym.typ.flags, tfThread)
if sym.typ.callConv == ccClosure: sym.typ.callConv = ccNimCall
of wSendable:
noVal(c, it)
if sym != nil and sym.typ != nil:
incl(sym.typ, tfSendable)
incl(sym.typ.flags, tfSendable)
else:
invalidPragma(c, it)
of wGcSafe:
noVal(c, it)
if sym != nil:
if sym.kind != skType: incl(sym, sfThread)
if sym.typ != nil: incl(sym.typ, tfGcSafe)
if sym.kind != skType: incl(sym.flags, sfThread)
if sym.typ != nil: incl(sym.typ.flags, tfGcSafe)
else: invalidPragma(c, it)
else:
discard "no checking if used as a code block"
of wPacked:
noVal(c, it)
if sym.typ == nil: invalidPragma(c, it)
else: incl(sym.typ, tfPacked)
else: incl(sym.typ.flags, tfPacked)
of wHint:
let s = expectStrLit(c, it)
recordPragma(c, it, "hint", s)
@@ -1136,8 +1141,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
# distinguish properly between
# ``proc p() {.error}`` and ``proc p() = {.error: "msg".}``
if it.kind in nkPragmaCallKinds: discard getStrLitNode(c, it)
incl(sym, sfError)
excl(sym, sfForward)
incl(sym.flags, sfError)
excl(sym.flags, sfForward)
else:
let s = expectStrLit(c, it)
recordPragma(c, it, "error", s)
@@ -1147,18 +1152,18 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
of wUndef: processUndef(c, it)
of wCompile:
let m = sym.getModule()
incl(m.flagsImpl, sfUsed)
incl(m.flags, sfUsed)
processCompile(c, it)
of wLink: processLink(c, it)
of wPassl:
let m = sym.getModule()
incl(m.flagsImpl, sfUsed)
incl(m.flags, sfUsed)
let s = expectStrLit(c, it)
extccomp.addLinkOption(c.config, s)
recordPragma(c, it, "passl", s)
of wPassc:
let m = sym.getModule()
incl(m.flagsImpl, sfUsed)
incl(m.flags, sfUsed)
let s = expectStrLit(c, it)
extccomp.addCompileOption(c.config, s)
recordPragma(c, it, "passc", s)
@@ -1176,16 +1181,16 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
result = true
of wPragma:
if not sym.isNil and sym.kind == skTemplate:
sym.incl sfCustomPragma
sym.flags.incl sfCustomPragma
else:
processPragma(c, n, i)
result = true
of wDiscardable:
noVal(c, it)
if sym != nil: incl(sym, sfDiscardable)
if sym != nil: incl(sym.flags, sfDiscardable)
of wNoInit:
noVal(c, it)
if sym != nil: incl(sym, sfNoInit)
if sym != nil: incl(sym.flags, sfNoInit)
of wCodegenDecl: processCodegenDecl(c, it, sym)
of wChecks, wObjChecks, wFieldChecks, wRangeChecks, wBoundChecks,
wOverflowChecks, wNilChecks, wAssertions, wWarnings, wHints,
@@ -1195,8 +1200,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
processOption(c, it, c.config.options)
of wStackTrace, wLineTrace:
if sym.kind in {skProc, skMethod, skConverter}:
ensureMutable sym
processOption(c, it, sym.optionsImpl)
processOption(c, it, sym.options)
else:
processOption(c, it, c.config.options)
of FirstCallConv..LastCallConv:
@@ -1204,7 +1208,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
if sym.typ == nil: invalidPragma(c, it)
else:
sym.typ.callConv = wordToCallConv(k)
sym.typ.incl tfExplicitCallConv
sym.typ.flags.incl tfExplicitCallConv
of wEmit: pragmaEmit(c, it)
of wUnroll: pragmaUnroll(c, it)
of wLinearScanEnd, wComputedGoto: noVal(c, it)
@@ -1214,11 +1218,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
of wIncompleteStruct:
noVal(c, it)
if sym.typ == nil: invalidPragma(c, it)
else: incl(sym.typ, tfIncompleteStruct)
else: incl(sym.typ.flags, tfIncompleteStruct)
of wCompleteStruct:
noVal(c, it)
if sym.typ == nil: invalidPragma(c, it)
else: incl(sym.typ, tfCompleteStruct)
else: incl(sym.typ.flags, tfCompleteStruct)
of wUnchecked:
noVal(c, it)
if sym.typ == nil or sym.typ.kind notin {tyArray, tyUncheckedArray}:
@@ -1231,35 +1235,34 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
else:
noVal(c, it)
if sym.typ == nil: invalidPragma(c, it)
else: incl(sym.typ, tfUnion)
else: incl(sym.typ.flags, tfUnion)
of wRequiresInit:
noVal(c, it)
if sym.kind == skField:
sym.incl sfRequiresInit
sym.flags.incl sfRequiresInit
elif sym.typ != nil:
incl(sym.typ, tfNeedsFullInit)
incl(sym.typ.flags, tfNeedsFullInit)
else:
invalidPragma(c, it)
of wByRef:
noVal(c, it)
if sym != nil and sym.kind == skParam:
ensureMutable sym
sym.optionsImpl.incl optByRef
sym.options.incl optByRef
elif sym == nil or sym.typ == nil:
processOption(c, it, c.config.options)
else:
incl(sym.typ, tfByRef)
incl(sym.typ.flags, tfByRef)
of wByCopy:
noVal(c, it)
if sym.kind == skParam:
incl(sym, sfByCopy)
incl(sym.flags, sfByCopy)
elif sym.kind != skType or sym.typ == nil: invalidPragma(c, it)
else: incl(sym.typ, tfByCopy)
else: incl(sym.typ.flags, tfByCopy)
of wPartial:
noVal(c, it)
if sym.kind != skType or sym.typ == nil: invalidPragma(c, it)
else:
incl(sym.typ, tfPartial)
incl(sym.typ.flags, tfPartial)
of wInject, wGensym:
# We check for errors, but do nothing with these pragmas otherwise
# as they are handled directly in 'evalTemplate'.
@@ -1287,7 +1290,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
if sym == nil or sym.kind notin {skVar, skLet}:
invalidPragma(c, it)
else:
sym.incl sfGoto
sym.flags.incl sfGoto
of wExportNims:
if sym == nil: invalidPragma(c, it)
else: magicsys.registerNimScriptSymbol(c.graph, sym)
@@ -1302,7 +1305,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
noVal(c, it)
of wBase:
noVal(c, it)
sym.incl sfBase
sym.flags.incl sfBase
of wIntDefine:
processDefineConst(c, n, sym, mIntDefine)
of wStrDefine:
@@ -1312,22 +1315,21 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
of wUsed:
noVal(c, it)
if sym == nil: invalidPragma(c, it)
else: sym.incl sfUsed
else: sym.flags.incl sfUsed
of wLiftLocals:
sym.incl(sfForceLift)
sym.flags.incl(sfForceLift)
of wRequires, wInvariant, wAssume, wAssert:
pragmaProposition(c, it)
of wEnsures:
pragmaEnsures(c, it)
of wEnforceNoRaises:
sym.incl sfNeverRaises
sym.flags.incl sfNeverRaises
of wQuirky:
sym.incl sfNeverRaises
sym.flags.incl sfNeverRaises
if sym.kind in {skProc, skMethod, skConverter, skFunc, skIterator}:
ensureMutable sym
sym.optionsImpl.incl optQuirky
sym.options.incl optQuirky
of wSystemRaisesDefect:
sym.incl sfSystemRaisesDefect
sym.flags.incl sfSystemRaisesDefect
of wVirtual:
processVirtual(c, it, sym, sfVirtual)
of wMember:
@@ -1384,9 +1386,9 @@ proc implicitPragmas*(c: PContext, sym: PSym, info: TLineInfo,
var lib = c.optionStack[^1].dynlib
if {lfDynamicLib, lfHeader} * sym.loc.flags == {} and
sfImportc in sym.flags and lib != nil:
incl(sym, lfDynamicLib)
incl(sym.loc.flags, lfDynamicLib)
addToLib(lib, sym)
if sym.locImpl.snippet == "": sym.locImpl.snippet = rope(sym.name.s)
if sym.loc.snippet == "": sym.loc.snippet = rope(sym.name.s)
proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
if n == nil: return false

View File

@@ -14,7 +14,7 @@
{.used.}
import
lexer, options, idents, ast, msgs, lineinfos, wordrecg, trees
lexer, options, idents, ast, msgs, lineinfos, wordrecg
import std/[strutils]
@@ -30,7 +30,7 @@ type
TRenderFlags* = set[TRenderFlag]
TRenderTok* = object
kind*: TokType
length*: int32
length*: int16
sym*: PSym
Section = enum
@@ -66,359 +66,6 @@ proc renderTree*(n: PNode, renderFlags: TRenderFlags = {}): string
# determines how long the subtree will likely be, the second
# phase appends to a buffer that will be the output.
type
TPreferedDesc* = enum
preferName, # default
preferDesc, # probably should become what preferResolved is
preferExported,
preferModuleInfo, # fully qualified
preferGenericArg,
preferTypeName,
preferResolved, # fully resolved symbols
preferMixed,
# most useful, shows: symbol + resolved symbols if it differs, e.g.:
# tuple[a: MyInt{int}, b: float]
preferInlayHint,
preferInferredEffects,
proc typeToString*(typ: PType; prefer: TPreferedDesc = preferName): string
template `$`*(typ: PType): string = typeToString(typ)
proc valueToString(a: PNode): string =
case a.kind
of nkCharLit, nkUIntLit..nkUInt64Lit:
result = $cast[uint64](a.intVal)
of nkIntLit..nkInt64Lit:
result = $a.intVal
of nkFloatLit..nkFloat128Lit: result = $a.floatVal
of nkStrLit..nkTripleStrLit: result = a.strVal
of nkStaticExpr: result = "static(" & a[0].renderTree & ")"
else: result = "<invalid value>"
proc rangeToStr(n: PNode): string =
assert(n.kind == nkRange)
result = valueToString(n[0]) & ".." & valueToString(n[1])
const preferToResolveSymbols = {preferName, preferTypeName, preferModuleInfo,
preferGenericArg, preferResolved, preferMixed, preferInlayHint, preferInferredEffects}
const
typeToStr: array[TTypeKind, string] = ["None", "bool", "char", "empty",
"Alias", "typeof(nil)", "untyped", "typed", "typeDesc",
# xxx typeDesc=>typedesc: typedesc is declared as such, and is 10x more common.
"GenericInvocation", "GenericBody", "GenericInst", "GenericParam",
"distinct $1", "enum", "ordinal[$1]", "array[$1, $2]", "object", "tuple",
"set[$1]", "range[$1]", "ptr ", "ref ", "var ", "seq[$1]", "proc",
"pointer", "OpenArray[$1]", "string", "cstring", "Forward",
"int", "int8", "int16", "int32", "int64",
"float", "float32", "float64", "float128",
"uint", "uint8", "uint16", "uint32", "uint64",
"owned", "sink",
"lent ", "varargs[$1]", "UncheckedArray[$1]", "Error Type",
"BuiltInTypeClass", "UserTypeClass",
"UserTypeClassInst", "CompositeTypeClass", "inferred",
"and", "or", "not", "any", "static", "TypeFromExpr", "concept", # xxx bugfix
"void", "iterable"]
proc addTypeFlags(name: var string, typ: PType) {.inline.} =
if tfNotNil in typ.flags: name.add(" not nil")
proc isIntLit*(t: PType): bool {.inline.} =
result = t.kind == tyInt and t.n != nil and t.n.kind == nkIntLit
proc isFloatLit*(t: PType): bool {.inline.} =
result = t.kind == tyFloat and t.n != nil and t.n.kind == nkFloatLit
# TODO: It would be a good idea to kill the special state of a resolved
# concept by switching to tyAlias within the instantiated procs.
# Currently, tyAlias is always skipped with skipModifier, which means that
# we can store information about the matched concept in another position.
# Then builtInFieldAccess can be modified to properly read the derived
# consts and types stored within the concept.
template isResolvedUserTypeClass*(t: PType): bool =
tfResolved in t.flags
proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
let preferToplevel = prefer
proc getPrefer(prefer: TPreferedDesc): TPreferedDesc =
if preferToplevel in {preferResolved, preferMixed}:
preferToplevel # sticky option
else:
prefer
proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
result = ""
let prefer = getPrefer(prefer)
let t = typ
if t == nil: return
if prefer in preferToResolveSymbols and t.sym != nil and
sfAnon notin t.sym.flags and t.kind notin {tySequence, tyInferred}:
if t.kind == tyInt and isIntLit(t):
if prefer == preferInlayHint:
result = t.sym.name.s
else:
result = t.sym.name.s & " literal(" & $t.n.intVal & ")"
elif t.kind == tyAlias and t.elementType.kind != tyAlias:
result = typeToString(t.elementType)
elif prefer in {preferResolved, preferMixed}:
case t.kind
of IntegralTypes + {tyFloat..tyFloat128} + {tyString, tyCstring}:
result = typeToStr[t.kind]
of tyGenericBody:
result = typeToString(t.last)
of tyCompositeTypeClass:
# avoids showing `A[any]` in `proc fun(a: A)` with `A = object[T]`
result = typeToString(t.last.last)
else:
result = t.sym.name.s
if prefer == preferMixed and result != t.sym.name.s:
result = t.sym.name.s & "{" & result & "}"
elif prefer in {preferName, preferTypeName, preferInlayHint, preferInferredEffects} or t.sym.owner.isNil:
# note: should probably be: {preferName, preferTypeName, preferGenericArg}
result = t.sym.name.s
if t.kind == tyGenericParam and t.genericParamHasConstraints:
result.add ": "
result.add t.elementType.typeToString
else:
result = t.sym.owner.name.s & '.' & t.sym.name.s
result.addTypeFlags(t)
return
case t.kind
of tyInt:
if not isIntLit(t) or prefer == preferExported:
result = typeToStr[t.kind]
else:
case prefer:
of preferGenericArg:
result = $t.n.intVal
of preferInlayHint:
result = "int"
else:
result = "int literal(" & $t.n.intVal & ")"
of tyGenericInst:
result = typeToString(t.genericHead) & '['
for needsComma, a in t.genericInstParams:
if needsComma: result.add(", ")
result.add(typeToString(a, preferGenericArg))
result.add(']')
of tyGenericInvocation:
result = typeToString(t.genericHead) & '['
for needsComma, a in t.genericInvocationParams:
if needsComma: result.add(", ")
result.add(typeToString(a, preferGenericArg))
result.add(']')
of tyGenericBody:
result = typeToString(t.typeBodyImpl) & '['
for i, a in t.genericBodyParams:
if i > 0: result.add(", ")
result.add(typeToString(a, preferTypeName))
result.add(']')
of tyTypeDesc:
if t.elementType.kind == tyNone: result = "typedesc"
else: result = "typedesc[" & typeToString(t.elementType) & "]"
of tyStatic:
if prefer == preferGenericArg and t.n != nil:
result = t.n.renderTree
else:
result = "static[" & (if t.hasElementType: typeToString(t.skipModifier) else: "") & "]"
if t.n != nil: result.add "(" & renderTree(t.n) & ")"
of tyUserTypeClass:
if t.sym != nil and t.sym.owner != nil:
if t.isResolvedUserTypeClass: return typeToString(t.last)
return t.sym.owner.name.s
else:
result = "<invalid tyUserTypeClass>"
of tyBuiltInTypeClass:
result =
case t.base.kind
of tyVar: "var"
of tyRef: "ref"
of tyPtr: "ptr"
of tySequence: "seq"
of tyArray: "array"
of tySet: "set"
of tyRange: "range"
of tyDistinct: "distinct"
of tyProc: "proc"
of tyObject: "object"
of tyTuple: "tuple"
of tyOpenArray: "openArray"
else: typeToStr[t.base.kind]
of tyInferred:
let concrete = t.previouslyInferred
if concrete != nil: result = typeToString(concrete)
else: result = "inferred[" & typeToString(t.base) & "]"
of tyUserTypeClassInst:
let body = t.base
result = body.sym.name.s & "["
for needsComma, a in t.userTypeClassInstParams:
if needsComma: result.add(", ")
result.add(typeToString(a))
result.add "]"
of tyAnd:
for i, son in t.ikids:
if i > 0: result.add(" and ")
result.add(typeToString(son))
of tyOr:
for i, son in t.ikids:
if i > 0: result.add(" or ")
result.add(typeToString(son))
of tyNot:
result = "not " & typeToString(t.elementType)
of tyUntyped:
#internalAssert t.len == 0
result = "untyped"
of tyFromExpr:
if t.n == nil:
result = "unknown"
else:
result = "typeof(" & renderTree(t.n) & ")"
of tyArray:
result = "array"
if t.hasElementType:
if t.indexType.kind == tyRange:
result &= "[" & rangeToStr(t.indexType.n) & ", " &
typeToString(t.elementType) & ']'
else:
result &= "[" & typeToString(t.indexType) & ", " &
typeToString(t.elementType) & ']'
of tyUncheckedArray:
result = "UncheckedArray"
if t.hasElementType:
result &= "[" & typeToString(t.elementType) & ']'
of tySequence:
if t.sym != nil and prefer != preferResolved:
result = t.sym.name.s
else:
result = "seq"
if t.hasElementType:
result &= "[" & typeToString(t.elementType) & ']'
of tyOrdinal:
result = "ordinal"
if t.hasElementType:
result &= "[" & typeToString(t.skipModifier) & ']'
of tySet:
result = "set"
if t.hasElementType:
result &= "[" & typeToString(t.elementType) & ']'
of tyOpenArray:
result = "openArray"
if t.hasElementType:
result &= "[" & typeToString(t.elementType) & ']'
of tyDistinct:
result = "distinct " & typeToString(t.elementType,
if prefer == preferModuleInfo: preferModuleInfo else: preferTypeName)
of tyIterable:
# xxx factor this pattern
result = "iterable"
if t.hasElementType:
result &= "[" & typeToString(t.skipModifier) & ']'
of tyTuple:
# we iterate over t.sons here, because t.n may be nil
if t.n != nil:
result = "tuple["
for i in 0..<t.n.len:
assert(t.n[i].kind == nkSym)
result.add(t.n[i].sym.name.s & ": " & typeToString(t.n[i].sym.typ))
if i < t.n.len - 1: result.add(", ")
result.add(']')
elif t.isEmptyTupleType:
result = "tuple[]"
elif t.isSingletonTupleType:
result = "("
for son in t.kids:
result.add(typeToString(son))
result.add(",)")
else:
result = "("
for i, son in t.ikids:
if i > 0: result.add ", "
result.add(typeToString(son))
result.add(')')
of tyPtr, tyRef, tyVar, tyLent:
result = if isOutParam(t): "out " else: typeToStr[t.kind]
result.add typeToString(t.elementType)
of tyRange:
result = "range "
if t.n != nil and t.n.kind == nkRange:
result.add rangeToStr(t.n)
if prefer != preferExported:
result.add("(" & typeToString(t.elementType) & ")")
of tyProc:
result = if tfIterator in t.flags: "iterator "
elif t.owner != nil:
case t.owner.kind
of skTemplate: "template "
of skMacro: "macro "
of skConverter: "converter "
else: "proc "
else:
"proc "
if tfUnresolved in t.flags: result.add "[*missing parameters*]"
result.add "("
for i, a in t.paramTypes:
if i > FirstParamAt: result.add(", ")
let j = paramTypeToNodeIndex(i)
if t.n != nil and j < t.n.len and t.n[j].kind == nkSym:
result.add(t.n[j].sym.name.s)
result.add(": ")
result.add(typeToString(a))
result.add(')')
if t.returnType != nil: result.add(": " & typeToString(t.returnType))
var prag = if t.callConv == ccNimCall and tfExplicitCallConv notin t.flags: "" else: $t.callConv
var hasImplicitRaises = false
if not isNil(t.owner) and not isNil(t.owner.ast) and (t.owner.ast.len - 1) >= pragmasPos:
let pragmasNode = t.owner.ast[pragmasPos]
let raisesSpec = effectSpec(pragmasNode, wRaises)
if not isNil(raisesSpec):
addSep(prag)
prag.add("raises: ")
prag.add(renderTree raisesSpec)
hasImplicitRaises = true
if tfNoSideEffect in t.flags:
addSep(prag)
prag.add("noSideEffect")
if tfThread in t.flags:
addSep(prag)
prag.add("gcsafe")
var effectsOfStr = ""
for i, a in t.paramTypes:
let j = paramTypeToNodeIndex(i)
if t.n != nil and j < t.n.len and t.n[j].kind == nkSym and t.n[j].sym.kind == skParam and sfEffectsDelayed in t.n[j].sym.flags:
addSep(effectsOfStr)
effectsOfStr.add(t.n[j].sym.name.s)
if effectsOfStr != "":
addSep(prag)
prag.add("effectsOf: ")
prag.add(effectsOfStr)
if not hasImplicitRaises and prefer == preferInferredEffects and not isNil(t.owner) and not isNil(t.owner.typ) and not isNil(t.owner.typ.n) and (t.owner.typ.n.len > 0):
let effects = t.n[0]
if effects.kind == nkEffectList and effects.len == effectListLen:
var inferredRaisesStr = ""
let effs = effects[exceptionEffects]
if not isNil(effs):
for eff in items(effs):
if not isNil(eff):
addSep(inferredRaisesStr)
inferredRaisesStr.add($eff.typ)
addSep(prag)
prag.add("raises: <inferred> [")
prag.add(inferredRaisesStr)
prag.add("]")
if prag.len != 0: result.add("{." & prag & ".}")
of tyVarargs:
result = typeToStr[t.kind] % typeToString(t.elementType)
of tySink:
result = "sink " & typeToString(t.skipModifier)
of tyOwned:
result = "owned " & typeToString(t.elementType)
else:
result = typeToStr[t.kind]
result.addTypeFlags(t)
result = typeToString(typ, prefer)
proc disamb(g: var TSrcGen; s: PSym): int =
# we group by 's.name.s' to compute the stable name ID.
result = 0
@@ -507,7 +154,7 @@ proc initSrcGen(renderFlags: TRenderFlags; config: ConfigRef): TSrcGen =
)
proc addTok(g: var TSrcGen, kind: TokType, s: string; sym: PSym = nil) =
g.tokens.add TRenderTok(kind: kind, length: int32(s.len), sym: sym)
g.tokens.add TRenderTok(kind: kind, length: int16(s.len), sym: sym)
g.buf.add(s)
if kind != tkSpaces:
inc g.col, s.len
@@ -680,10 +327,6 @@ proc pushCom(g: var TSrcGen, n: PNode) =
setLen(g.comStack, g.comStack.len + 1)
g.comStack[^1] = n
proc popCom(g: var TSrcGen): PNode =
result = g.comStack[^1]
setLen(g.comStack, g.comStack.len - 1)
proc popAllComs(g: var TSrcGen) =
setLen(g.comStack, 0)
@@ -1215,28 +858,10 @@ proc genSymSuffix(result: var string, s: PSym) {.inline.} =
result.add '_'
result.addInt s.id
proc gsemmedParams(g: var TSrcGen, n: PNode) =
put(g, tkParLe, "(")
for i in 1..<n.len:
if i > 1:
putWithSpace(g, tkComma, ";")
let x {.cursor.} = n[i]
if x.kind == nkSym:
put g, tkSymbol, renderDefinitionName(x.sym)
putWithSpace(g, tkColon, ":")
put g, tkSymbol, typeToString(x.sym.typ)
else:
gsub(g, x)
put(g, tkParRi, ")")
if not isEmptyType(n[0].typ):
putWithSpace(g, tkColon, ":")
gsub(g, n[0])
proc gproc(g: var TSrcGen, n: PNode) =
var c: TContext = initContext()
var s: PSym = nil
if n[namePos].kind == nkSym:
s = n[namePos].sym
let s = n[namePos].sym
var ret = renderDefinitionName(s)
ret.genSymSuffix(s)
put(g, tkSymbol, ret)
@@ -1251,10 +876,7 @@ proc gproc(g: var TSrcGen, n: PNode) =
gsub(g, n[miscPos][1])
else:
gsub(g, n[genericParamsPos])
if n[paramsPos].len == 0 and s != nil and s.typ != nil and s.typ.n != nil:
gsemmedParams(g, s.typ.n)
else:
gsub(g, n[paramsPos])
gsub(g, n[paramsPos])
if renderNoPragmas notin g.flags:
gsub(g, n[pragmasPos])
if renderNoBody notin g.flags:
@@ -1731,10 +1353,6 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
if not n[0].isExported() and renderNonExportedFields notin g.flags:
# Skip if this is a property in a type and its not exported
# (While also not allowing rendering of non exported fields)
if shouldRenderComment(g, n):
# `shouldRenderComment` indicts that we have comments to render
# but it's a non-exported field, so we just pop without rendering any comment
discard popCom(g)
return
# render postfix for object fields:
exclFlags = g.flags * {renderNoPostfix}
@@ -2210,9 +1828,6 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
putWithSpace(g, tkSymbol, "error")
#gcomma(g, n, c)
gsub(g, n[0], c)
of nkReplayAction:
put(g, tkSymbol, "replayaction")
#gsons(g, n, c, 0)
else:
#nkNone, nkExplicitTypeListCall:
internalError(g.config, n.info, "renderer.gsub(" & $n.kind & ')')

View File

@@ -213,10 +213,9 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
unregisterArcOrc(conf)
conf.globalOptions.excl optOwnedRefs
conf.selectedGC = gcUnselected
conf.globalOptions.incl optWithinConfigSystem
var m = graph.makeModule(scriptName)
incl(m, sfMainModule)
incl(m.flags, sfMainModule)
var vm = setupVM(m, cache, scriptName.string, graph, idgen)
graph.vm = vm
@@ -231,7 +230,7 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
if optOwnedRefs in oldGlobalOptions:
conf.globalOptions.incl {optTinyRtti, optOwnedRefs, optSeqDestructors}
defineSymbol(conf.symbols, "nimv2")
if conf.selectedGC in {gcArc, gcOrc, gcYrc, gcAtomicArc}:
if conf.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
conf.globalOptions.incl {optTinyRtti, optSeqDestructors}
defineSymbol(conf.symbols, "nimv2")
defineSymbol(conf.symbols, "gcdestructors")
@@ -241,8 +240,6 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
defineSymbol(conf.symbols, "gcarc")
of gcOrc:
defineSymbol(conf.symbols, "gcorc")
of gcYrc:
defineSymbol(conf.symbols, "gcyrc")
of gcAtomicArc:
defineSymbol(conf.symbols, "gcatomicarc")
else:
@@ -254,5 +251,4 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
#initDefines()
undefSymbol(conf.symbols, "nimscript")
undefSymbol(conf.symbols, "nimconfig")
conf.globalOptions.excl optWithinConfigSystem
conf.symbolFiles = oldSymbolFiles

View File

@@ -102,7 +102,7 @@ proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode =
renderTree(arg, {renderNoComments}))
# error correction:
result = copyTree(arg)
result.typ = formal
result.typ() = formal
elif arg.kind in nkSymChoices and formal.skipTypes(abstractInst).kind == tyEnum:
# Pick the right 'sym' from the sym choice by looking at 'formal' type:
result = nil
@@ -116,7 +116,7 @@ proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode =
typeMismatch(c.config, info, formal, arg.typ, arg)
# error correction:
result = copyTree(arg)
result.typ = formal
result.typ() = formal
else:
result = fitNodePostMatch(c, formal, result)
@@ -126,7 +126,7 @@ proc fitNodeConsiderViewType(c: PContext, formal: PType, arg: PNode; info: TLine
#classifyViewType(formal) != noView:
result = newNodeIT(nkHiddenAddr, a.info, formal)
result.add a
formal.incl tfVarIsPtr
formal.flags.incl tfVarIsPtr
else:
result = a
@@ -260,7 +260,7 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
else:
result = newSym(kind, considerQuotedIdent(c, n), c.idgen, getCurrOwner(c), n.info)
if find(result.name.s, '`') >= 0:
result.flagsImpl.incl sfWasGenSym
result.flags.incl sfWasGenSym
#if kind in {skForVar, skLet, skVar} and result.owner.kind == skModule:
# incl(result.flags, sfGlobal)
when defined(nimsuggest):
@@ -346,19 +346,6 @@ proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode; producedClosure: v
isArrayConstr(arg):
arg.typ = eOrig.typ
proc resetEvalPosition(n: PNode) =
# resets the eval position of variables because `tryConstExpr` may be
# called multiple times on the same node
case n.kind
of {nkNone..nkNilLit}-{nkSym}:
discard
of nkSym:
if n.sym.kind in {skVar, skLet} and sfGlobal notin n.sym.flags:
n.sym.position = 0
else:
for i in 0..<n.safeLen:
resetEvalPosition(n[i])
proc tryConstExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode =
var e = semExprWithType(c, n, expectedType = expectedType)
if e == nil: return
@@ -395,8 +382,6 @@ proc tryConstExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode =
# Restore the error hook
c.graph.config.structuredErrorHook = tempHook
resetEvalPosition(n)
c.config.errorCounter = oldErrorCount
c.config.errorMax = oldErrorMax
c.config.m.errorOutputs = oldErrorOutputs
@@ -491,7 +476,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
renderTree(result, {renderNoComments}))
result = newSymNode(errorSym(c, result))
else:
result.typ = makeTypeDesc(c, typ)
result.typ() = makeTypeDesc(c, typ)
#result = symNodeFromType(c, typ, n.info)
else:
if s.ast[genericParamsPos] != nil and retType.isMetaType:
@@ -650,7 +635,7 @@ proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool, ch
newNodeIT(nkType, recNode.info, asgnType)
)
asgnExpr.flags.incl nfSkipFieldChecking
asgnExpr.typ = recNode.typ
asgnExpr.typ() = recNode.typ
result.add newTree(nkExprColonExpr, recNode, asgnExpr)
else:
raiseAssert "unreachable"
@@ -672,7 +657,7 @@ proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode, checkDefault:
if checkDefault: # don't add defaults when checking whether a case branch has default fields
return
defaultValue = newIntNode(nkIntLit#[c.graph]#, 0)
defaultValue.typ = discriminator.typ
defaultValue.typ() = discriminator.typ
selectedBranch = recNode.pickCaseBranchIndex defaultValue
defaultValue.flags.incl nfSkipFieldChecking
result.add newTree(nkExprColonExpr, discriminator, defaultValue)
@@ -685,7 +670,7 @@ proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode, checkDefault:
elif recType.kind in {tyObject, tyArray, tyTuple}:
let asgnExpr = defaultNodeField(c, recNode, recNode.typ, checkDefault)
if asgnExpr != nil:
asgnExpr.typ = recNode.typ
asgnExpr.typ() = recNode.typ
asgnExpr.flags.incl nfSkipFieldChecking
result.add newTree(nkExprColonExpr, recNode, asgnExpr)
else:
@@ -698,7 +683,7 @@ proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, checkDefault: bool): P
let child = defaultFieldsForTheUninitialized(c, aTypSkip.n, checkDefault)
if child.len > 0:
var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, a.info, aTyp))
asgnExpr.typ = aTyp
asgnExpr.typ() = aTyp
asgnExpr.sons.add child
result = semExpr(c, asgnExpr)
else:
@@ -710,11 +695,11 @@ proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, checkDefault: bool): P
let node = newNode(nkIntLit)
node.intVal = toInt64(lengthOrd(c.graph.config, aTypSkip))
let typeNode = newNode(nkType)
typeNode.typ = makeTypeDesc(c, aTypSkip[1])
typeNode.typ() = makeTypeDesc(c, aTypSkip[1])
result = semExpr(c, newTree(nkCall, newTree(nkBracketExpr, newSymNode(getSysSym(c.graph, a.info, "arrayWithDefault"), a.info), typeNode),
node
))
result.typ = aTyp
result.typ() = aTyp
else:
result = nil
of tyTuple:
@@ -723,7 +708,7 @@ proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, checkDefault: bool): P
let children = defaultFieldsForTuple(c, aTypSkip.n, hasDefault, checkDefault)
if hasDefault and children.len > 0:
result = newNodeI(nkTupleConstr, a.info)
result.typ = aTyp
result.typ() = aTyp
result.sons.add children
result = semExpr(c, result)
else:
@@ -855,7 +840,7 @@ proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
appendToModule(c.module, result)
trackStmt(c, c.module, result, isTopLevel = true)
if optMultiMethods notin c.config.globalOptions and
c.config.selectedGC in {gcArc, gcOrc, gcAtomicArc, gcYrc} and
c.config.selectedGC in {gcArc, gcOrc, gcAtomicArc} and
Feature.vtables in c.config.features:
sortVTableDispatchers(c.graph)
@@ -889,6 +874,8 @@ proc semWithPContext*(c: PContext, n: PNode): PNode =
else:
result = newNodeI(nkEmpty, n.info)
#if c.config.cmd == cmdIdeTools: findSuggest(c, n)
storeRodNode(c, result)
proc reportUnusedModules(c: PContext) =
if c.config.cmd == cmdM: return

View File

@@ -695,7 +695,7 @@ proc instGenericConvertersArg*(c: PContext, a: PNode, x: TCandidate) =
internalError(c.config, a.info, "generic converter failed rematch")
let finalCallee = generateInstance(c, s, convMatch.bindings, a.info)
a[0].sym = finalCallee
a[0].typ = finalCallee.typ
a[0].typ() = finalCallee.typ
#a.typ = finalCallee.typ.returnType
proc instGenericConvertersSons*(c: PContext, n: PNode, x: TCandidate) =
@@ -730,13 +730,13 @@ proc inferWithMetatype(c: PContext, formal: PType,
# This almost exactly replicates the steps taken by the compiler during
# param matching. It performs an embarrassing amount of back-and-forth
# type jugling, but it's the price to pay for consistency and correctness
result.typ = generateTypeInstance(c, m.bindings, arg.info,
result.typ() = generateTypeInstance(c, m.bindings, arg.info,
formal.skipTypes({tyCompositeTypeClass}))
else:
typeMismatch(c.config, arg.info, formal, arg.typ, arg)
# error correction:
result = copyTree(arg)
result.typ = formal
result.typ() = formal
proc updateDefaultParams(c: PContext, call: PNode) =
# In generic procs, the default parameter may be unique for each
@@ -759,7 +759,7 @@ proc updateDefaultParams(c: PContext, call: PNode) =
pushInfoContext(c.config, call.info, call[0].sym.detailedInfo)
typeMismatch(c.config, def.info, formal.typ, def.typ, formal.ast)
popInfoContext(c.config)
def.typ = errorType(c)
def.typ() = errorType(c)
call[i] = def
proc getCallLineInfo(n: PNode): TLineInfo =
@@ -830,21 +830,6 @@ proc inheritBindings(c: PContext, x: var TCandidate, expectedType: PType) =
for i in 0 ..< flatUnbound.len():
x.bindings.put(flatUnbound[i], flatBound[i])
proc compactVoidArgs(n: PNode): PNode =
# deletes void args from the argument list, which are created by `setSon`
var hasNil = false
for i in 0..<n.len:
if n[i] == nil:
hasNil = true
break
if not hasNil:
result = n
else:
result = copyNode(n)
for i in 0..<n.len:
if n[i] != nil:
result.add n[i]
proc semResolvedCall(c: PContext, x: var TCandidate,
n: PNode, flags: TExprFlags;
expectedType: PType = nil): PNode =
@@ -861,8 +846,8 @@ proc semResolvedCall(c: PContext, x: var TCandidate,
result = x.call
result[0] = newSymNode(finalCallee, getCallLineInfo(result[0]))
if containsGenericType(result.typ):
result.typ = newTypeS(tyError, c)
incl result.typ, tfCheckedForDestructor
result.typ() = newTypeS(tyError, c)
incl result.typ.flags, tfCheckedForDestructor
return
let gp = finalCallee.ast[genericParamsPos]
if gp.isGenericParams:
@@ -888,19 +873,19 @@ proc semResolvedCall(c: PContext, x: var TCandidate,
# this node will be used in template substitution,
# pretend this is an untyped node and let regular sem handle the type
# to prevent problems where a generic parameter is treated as a value
tn.typ = nil
tn.typ() = nil
x.call.add tn
else:
internalAssert c.config, false
markUsed(c, info, finalCallee, isGenericInstance = true)
onUse(info, finalCallee, isGenericInstance = true)
result = compactVoidArgs(x.call)
result = x.call
instGenericConvertersSons(c, result, x)
markConvertersUsed(c, result)
result[0] = newSymNode(finalCallee, getCallLineInfo(result[0]))
if finalCallee.magic notin {mArrGet, mArrPut}:
result.typ = finalCallee.typ.returnType
result.typ() = finalCallee.typ.returnType
updateDefaultParams(c, result)
proc canDeref(n: PNode): bool {.inline.} =
@@ -909,7 +894,7 @@ proc canDeref(n: PNode): bool {.inline.} =
proc tryDeref(n: PNode): PNode =
result = newNodeI(nkHiddenDeref, n.info)
result.typ = n.typ.skipTypes(abstractInst)[0]
result.typ() = n.typ.skipTypes(abstractInst)[0]
result.add n
proc semOverloadedCall(c: PContext, n, nOrig: PNode,
@@ -928,7 +913,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
else:
if c.inGenericContext > 0 and c.matchedConcept == nil:
result = semGenericStmt(c, n)
result.typ = makeTypeFromExpr(c, result.copyTree)
result.typ() = makeTypeFromExpr(c, result.copyTree)
elif efNoUndeclared in flags:
result = nil
elif efExplain notin flags:
@@ -960,7 +945,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym, errors: var CandidateErr
diagnostics: m.diagnostics))
return nil
var newInst = generateInstance(c, s, m.bindings, n.info)
newInst.typ.excl tfUnresolved
newInst.typ.flags.excl tfUnresolved
let info = getCallLineInfo(n)
markUsed(c, info, s, isGenericInstance = false)
onUse(info, s, isGenericInstance = false)
@@ -979,9 +964,9 @@ proc setGenericParams(c: PContext, n, expectedParams: PNode) =
nil
e = semExprWithType(c, n[i], expectedType = constraint)
if e.typ == nil:
n[i].typ = errorType(c)
n[i].typ() = errorType(c)
else:
n[i].typ = e.typ
n[i].typ() = e.typ.skipTypes({tyTypeDesc})
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym, doError: bool): PNode =
assert n.kind == nkBracketExpr
@@ -998,7 +983,7 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym, doError: bool)
# same as in semOverloadedCall, make expression untyped,
# may have failed match due to unresolved types
result = semGenericStmt(c, n)
result.typ = makeTypeFromExpr(c, result.copyTree)
result.typ() = makeTypeFromExpr(c, result.copyTree)
elif doError:
notFoundError(c, n, errors)
elif a.kind in {nkClosedSymChoice, nkOpenSymChoice}:
@@ -1016,7 +1001,7 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym, doError: bool)
# any failing match stops building the symchoice for correctness,
# can also make it untyped from the start
result = semGenericStmt(c, n)
result.typ = makeTypeFromExpr(c, result.copyTree)
result.typ() = makeTypeFromExpr(c, result.copyTree)
return
# get rid of nkClosedSymChoice if not ambiguous:
if result.len == 0:

View File

@@ -19,6 +19,8 @@ import
magicsys, vmdef, modulegraphs, lineinfos, pathutils, layeredtable,
types, lowerings, trees, parampatterns, astalgo
import ic / ic
type
TOptionEntry* = object # entries to put on a stack for pragma parsing
options*: TOptions
@@ -151,6 +153,7 @@ type
generics*: seq[TInstantiationPair] # pending list of instantiated generics to compile
topStmts*: int # counts the number of encountered top level statements
lastGenericIdx*: int # used for the generics stack
hloLoopDetector*: int # used to prevent endless loops in the HLO
inParallelStmt*: int
instTypeBoundOp*: proc (c: PContext; dc: PSym; t: PType; info: TLineInfo;
op: TTypeAttachedOp; col: int): PSym {.nimcall.}
@@ -199,29 +202,29 @@ proc getIntLitType*(c: PContext; literal: PNode): PType =
proc setIntLitType*(c: PContext; result: PNode) =
let i = result.intVal
case c.config.target.intSize
of 8: result.typ = getIntLitType(c, result)
of 8: result.typ() = getIntLitType(c, result)
of 4:
if i >= low(int32) and i <= high(int32):
result.typ = getIntLitType(c, result)
result.typ() = getIntLitType(c, result)
else:
result.typ = getSysType(c.graph, result.info, tyInt64)
result.typ() = getSysType(c.graph, result.info, tyInt64)
of 2:
if i >= low(int16) and i <= high(int16):
result.typ = getIntLitType(c, result)
result.typ() = getIntLitType(c, result)
elif i >= low(int32) and i <= high(int32):
result.typ = getSysType(c.graph, result.info, tyInt32)
result.typ() = getSysType(c.graph, result.info, tyInt32)
else:
result.typ = getSysType(c.graph, result.info, tyInt64)
result.typ() = getSysType(c.graph, result.info, tyInt64)
of 1:
# 8 bit CPUs are insane ...
if i >= low(int8) and i <= high(int8):
result.typ = getIntLitType(c, result)
result.typ() = getIntLitType(c, result)
elif i >= low(int16) and i <= high(int16):
result.typ = getSysType(c.graph, result.info, tyInt16)
result.typ() = getSysType(c.graph, result.info, tyInt16)
elif i >= low(int32) and i <= high(int32):
result.typ = getSysType(c.graph, result.info, tyInt32)
result.typ() = getSysType(c.graph, result.info, tyInt32)
else:
result.typ = getSysType(c.graph, result.info, tyInt64)
result.typ() = getSysType(c.graph, result.info, tyInt64)
else:
internalError(c.config, result.info, "invalid int size")
@@ -334,17 +337,28 @@ proc newContext*(graph: ModuleGraph; module: PSym): PContext =
signatures: initStrTable(),
features: graph.config.features
)
if graph.config.symbolFiles != disabledSf:
let id = module.position
if graph.config.cmd != cmdM:
assert graph.packed[id].status in {undefined, outdated}
graph.packed[id].status = storing
graph.packed[id].module = module
initEncoder graph, module
template packedRepr*(c): untyped = c.graph.packed[c.module.position].fromDisk
template encoder*(c): untyped = c.graph.encoders[c.module.position]
proc addIncludeFileDep*(c: PContext; f: FileIndex) =
discard
if c.config.symbolFiles != disabledSf:
addIncludeFileDep(c.encoder, c.packedRepr, f)
proc addImportFileDep*(c: PContext; f: FileIndex) =
discard
if c.config.symbolFiles != disabledSf:
addImportFileDep(c.encoder, c.packedRepr, f)
proc addPragmaComputation*(c: PContext; n: PNode) =
# Also store for NIF-based IC (cmdM mode or optCompress)
if optCompress in c.config.globalOptions or c.config.cmd == cmdM:
addNifReplayAction(c.graph, c.module.position.int32, n)
if c.config.symbolFiles != disabledSf:
addPragmaComputation(c.encoder, c.packedRepr, n)
proc inclSym(sq: var seq[PSym], s: PSym): bool =
for i in 0..<sq.len:
@@ -352,28 +366,38 @@ proc inclSym(sq: var seq[PSym], s: PSym): bool =
sq.add s
result = true
proc addConverter*(c: PContext, conv: PSym) =
assert conv != nil
if inclSym(c.converters, conv):
proc addConverter*(c: PContext, conv: LazySym) =
assert conv.sym != nil
if inclSym(c.converters, conv.sym):
add(c.graph.ifaces[c.module.position].converters, conv)
proc addConverterDef*(c: PContext, conv: PSym) =
proc addConverterDef*(c: PContext, conv: LazySym) =
addConverter(c, conv)
if c.config.symbolFiles != disabledSf:
addConverter(c.encoder, c.packedRepr, conv.sym)
proc addPureEnum*(c: PContext, e: PSym) =
assert e != nil
proc addPureEnum*(c: PContext, e: LazySym) =
assert e.sym != nil
add(c.graph.ifaces[c.module.position].pureEnums, e)
if c.config.symbolFiles != disabledSf:
addPureEnum(c.encoder, c.packedRepr, e.sym)
proc addPattern*(c: PContext, p: PSym) =
assert p != nil
if inclSym(c.patterns, p):
proc addPattern*(c: PContext, p: LazySym) =
assert p.sym != nil
if inclSym(c.patterns, p.sym):
add(c.graph.ifaces[c.module.position].patterns, p)
if c.config.symbolFiles != disabledSf:
addTrmacro(c.encoder, c.packedRepr, p.sym)
proc exportSym*(c: PContext; s: PSym) =
strTableAdds(c.graph, c.module, s)
if c.config.symbolFiles != disabledSf:
addExported(c.encoder, c.packedRepr, s)
proc reexportSym*(c: PContext; s: PSym) =
strTableAdds(c.graph, c.module, s)
if c.config.symbolFiles != disabledSf:
addReexport(c.encoder, c.packedRepr, s)
proc newLib*(kind: TLibKind): PLib =
result = PLib(kind: kind) #result.syms = initObjectSet()
@@ -410,7 +434,7 @@ proc makeVarType*(c: PContext, baseType: PType; kind = tyVar): PType =
proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
let typedesc = newTypeS(tyTypeDesc, c)
incl typedesc.flagsImpl, tfCheckedForDestructor
incl typedesc.flags, tfCheckedForDestructor
internalAssert(c.config, typ != nil)
typedesc.addSonSkipIntLit(typ, c.idgen)
let sym = newSym(skType, c.cache.idAnon, c.idgen, getCurrOwner(c), info,
@@ -434,7 +458,7 @@ when false:
proc makeStaticExpr*(c: PContext, n: PNode): PNode =
result = newNodeI(nkStaticExpr, n.info)
result.sons = @[n]
result.typ = if n.typ != nil and n.typ.kind == tyStatic: n.typ
result.typ() = if n.typ != nil and n.typ.kind == tyStatic: n.typ
else: newTypeS(tyStatic, c, n.typ)
proc makeAndType*(c: PContext, t1, t2: PType): PType =
@@ -443,8 +467,8 @@ proc makeAndType*(c: PContext, t1, t2: PType): PType =
result.rawAddSon t2
propagateToOwner(result, t1)
propagateToOwner(result, t2)
result.flagsImpl.incl((t1.flags + t2.flags) * {tfHasStatic})
result.flagsImpl.incl tfHasMeta
result.flags.incl((t1.flags + t2.flags) * {tfHasStatic})
result.flags.incl tfHasMeta
proc makeOrType*(c: PContext, t1, t2: PType): PType =
if t1.kind != tyOr and t2.kind != tyOr:
@@ -462,14 +486,14 @@ proc makeOrType*(c: PContext, t1, t2: PType): PType =
addOr(t2)
propagateToOwner(result, t1)
propagateToOwner(result, t2)
result.incl((t1.flags + t2.flags) * {tfHasStatic})
result.incl tfHasMeta
result.flags.incl((t1.flags + t2.flags) * {tfHasStatic})
result.flags.incl tfHasMeta
proc makeNotType*(c: PContext, t1: PType): PType =
result = newTypeS(tyNot, c, son = t1)
propagateToOwner(result, t1)
result.flagsImpl.incl(t1.flags * {tfHasStatic})
result.flagsImpl.incl tfHasMeta
result.flags.incl(t1.flags * {tfHasStatic})
result.flags.incl tfHasMeta
proc nMinusOne(c: PContext; n: PNode): PNode =
result = newTreeI(nkCall, n.info, newSymNode(getSysMagic(c.graph, n.info, "pred", mPred)), n)
@@ -479,7 +503,7 @@ proc makeRangeWithStaticExpr*(c: PContext, n: PNode): PType =
let intType = getSysType(c.graph, n.info, tyInt)
result = newTypeS(tyRange, c, son = intType)
if n.typ != nil and n.typ.n == nil:
result.incl tfUnresolved
result.flags.incl tfUnresolved
result.n = newTreeI(nkRange, n.info, newIntTypeNode(0, intType),
makeStaticExpr(c, nMinusOne(c, n)))
@@ -489,11 +513,11 @@ template rangeHasUnresolvedStatic*(t: PType): bool =
proc errorType*(c: PContext): PType =
## creates a type representing an error state
result = newTypeS(tyError, c)
result.flagsImpl.incl tfCheckedForDestructor
result.flags.incl tfCheckedForDestructor
proc errorNode*(c: PContext, n: PNode): PNode =
result = newNodeI(nkEmpty, n.info)
result.typ = errorType(c)
result.typ() = errorType(c)
# These mimic localError
template localErrorNode*(c: PContext, n: PNode, info: TLineInfo, msg: TMsgKind, arg: string): PNode =
@@ -539,21 +563,21 @@ proc makeTypeDesc*(c: PContext, typ: PType): PType =
result = typ
else:
result = newTypeS(tyTypeDesc, c, skipIntLit(typ, c.idgen))
incl result, tfCheckedForDestructor
incl result.flags, tfCheckedForDestructor
proc symFromType*(c: PContext; t: PType, info: TLineInfo): PSym =
if t.sym != nil: return t.sym
result = newSym(skType, getIdent(c.cache, "AnonType"), c.idgen, t.owner, info)
result.flagsImpl.incl sfAnon
result.flags.incl sfAnon
result.typ = t
proc symNodeFromType*(c: PContext, t: PType, info: TLineInfo): PNode =
result = newSymNode(symFromType(c, t, info), info)
result.typ = makeTypeDesc(c, t)
result.typ() = makeTypeDesc(c, t)
proc markIndirect*(c: PContext, s: PSym) {.inline.} =
if s.kind in {skProc, skFunc, skConverter, skMethod, skIterator}:
incl(s.flagsImpl, sfAddrTaken)
incl(s.flags, sfAddrTaken)
# XXX add to 'c' for global analysis
proc illFormedAst*(n: PNode; conf: ConfigRef) =
@@ -588,11 +612,19 @@ template addExport*(c: PContext; s: PSym) =
## convenience to export a symbol from the current module
addExport(c.graph, c.module, s)
proc storeRodNode*(c: PContext, n: PNode) =
if c.config.symbolFiles != disabledSf:
toPackedNodeTopLevel(n, c.encoder, c.packedRepr)
proc addToGenericProcCache*(c: PContext; s: PSym; inst: PInstantiation) =
c.graph.procInstCache.mgetOrPut(s.itemId, @[]).add inst
c.graph.procInstCache.mgetOrPut(s.itemId, @[]).add LazyInstantiation(module: c.module.position, inst: inst)
if c.config.symbolFiles != disabledSf:
storeInstantiation(c.encoder, c.packedRepr, s, inst)
proc addToGenericCache*(c: PContext; s: PSym; inst: PType) =
c.graph.typeInstCache.mgetOrPut(s.itemId, @[]).add inst
c.graph.typeInstCache.mgetOrPut(s.itemId, @[]).add LazyType(typ: inst)
if c.config.symbolFiles != disabledSf:
storeTypeInst(c.encoder, c.packedRepr, s, inst)
proc sealRodFile*(c: PContext) =
if c.config.symbolFiles != disabledSf:
@@ -608,8 +640,9 @@ proc rememberExpansion*(c: PContext; info: TLineInfo; expandedSym: PSym) =
## in the sem'checked AST. This is very bad for IDE-like tooling
## ("find all usages of this template" would not work). We need special
## logic to remember macro/template expansions. This is done here and
## delegated to the "NIF" file mechanism.
discard "XXX To implement"
## delegated to the "rod" file mechanism.
if c.config.symbolFiles != disabledSf:
storeExpansion(c.encoder, c.packedRepr, info, expandedSym)
const
errVarForOutParamNeededX = "for a 'var' type a variable needs to be passed; but '$1' is immutable"
@@ -652,7 +685,7 @@ proc analyseIfAddressTaken(c: PContext, n: PNode, isOutParam: bool): PNode =
# n.sym.typ can be nil in 'check' mode ...
if n.sym.typ != nil and
skipTypes(n.sym.typ, abstractInst-{tyTypeDesc}).kind notin {tyVar, tyLent}:
incl(n.sym.flagsImpl, sfAddrTaken)
incl(n.sym.flags, sfAddrTaken)
result = newHiddenAddrTaken(c, n, isOutParam)
of nkDotExpr:
checkSonsLen(n, 2, c.config)
@@ -660,12 +693,12 @@ proc analyseIfAddressTaken(c: PContext, n: PNode, isOutParam: bool): PNode =
internalError(c.config, n.info, "analyseIfAddressTaken")
return
if skipTypes(n[1].sym.typ, abstractInst-{tyTypeDesc}).kind notin {tyVar, tyLent}:
incl(n[1].sym.flagsImpl, sfAddrTaken)
incl(n[1].sym.flags, sfAddrTaken)
result = newHiddenAddrTaken(c, n, isOutParam)
of nkBracketExpr:
checkMinSonsLen(n, 1, c.config)
if skipTypes(n[0].typ, abstractInst-{tyTypeDesc}).kind notin {tyVar, tyLent}:
if n[0].kind == nkSym: incl(n[0].sym.flagsImpl, sfAddrTaken)
if n[0].kind == nkSym: incl(n[0].sym.flags, sfAddrTaken)
result = newHiddenAddrTaken(c, n, isOutParam)
else:
result = newHiddenAddrTaken(c, n, isOutParam)
@@ -754,7 +787,7 @@ proc replaceHookMagic*(c: PContext, n: PNode, kind: TTypeAttachedOp): PNode =
result[0] = newSymNode(op)
if op.typ.len == 3:
let boolLit = newIntLit(c.graph, n.info, 1)
boolLit.typ = getSysType(c.graph, n.info, tyBool)
boolLit.typ() = getSysType(c.graph, n.info, tyBool)
result.add boolLit
of attachedWasMoved:
result = n

View File

@@ -55,11 +55,11 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
if result.typ != nil:
if result.typ.kind in {tyVar, tyLent}: result = newDeref(result)
elif {efWantStmt, efAllowStmt} * flags != {}:
result.typ = newTypeS(tyVoid, c)
result.typ() = newTypeS(tyVoid, c)
else:
localError(c.config, n.info, errExprXHasNoType %
renderTree(result, {renderNoComments}))
result.typ = errorType(c)
result.typ() = errorType(c)
proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType = nil): PNode =
rejectEmptyNode(n)
@@ -81,14 +81,14 @@ proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode =
result = semExprCheck(c, n, flags-{efTypeAllowed}, expectedType)
if result.typ == nil and efInTypeof in flags:
result.typ = c.voidType
result.typ() = c.voidType
elif result.typ == nil or result.typ == c.enforceVoidContext:
localError(c.config, n.info, errExprXHasNoType %
renderTree(result, {renderNoComments}))
result.typ = errorType(c)
result.typ() = errorType(c)
elif result.typ.kind == tyError:
# associates the type error to the current owner
result.typ = errorType(c)
result.typ() = errorType(c)
elif efTypeAllowed in flags and result.typ.kind == tyProc and
hasUnresolvedParams(result, {}):
# mirrored with semOperand but only on efTypeAllowed
@@ -100,7 +100,7 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType
else:
errProcHasNoConcreteType % n.renderTree
localError(c.config, n.info, err)
result.typ = errorType(c)
result.typ() = errorType(c)
else:
if result.typ.kind in {tyVar, tyLent}: result = newDeref(result)
@@ -109,7 +109,7 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
if result.typ == nil:
localError(c.config, n.info, errExprXHasNoType %
renderTree(result, {renderNoComments}))
result.typ = errorType(c)
result.typ() = errorType(c)
proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
result = symChoice(c, n, s, scClosed)
@@ -195,7 +195,7 @@ proc semOpenSym(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType,
result = nil
if not isSym:
# set symchoice node type back to None
n.typ = newTypeS(tyNone, c)
n.typ() = newTypeS(tyNone, c)
proc semSymChoice(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode =
if n.kind == nkOpenSymChoice:
@@ -217,7 +217,7 @@ proc semSymChoice(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: P
err.add " " & candidate.owner.name.s & "." & candidate.name.s
err.add ": " & typeToString(candidate.typ) & "\n"
localError(c.config, n.info, err)
n.typ = errorType(c)
n.typ() = errorType(c)
result = n
if result.kind == nkSym:
result = semSym(c, result, result.sym, flags)
@@ -228,7 +228,7 @@ proc inlineConst(c: PContext, n: PNode, s: PSym): PNode {.inline.} =
localError(c.config, n.info, "constant of type '" & typeToString(s.typ) & "' has no value")
result = newSymNode(s)
else:
result.typ = s.typ
result.typ() = s.typ
result.info = n.info
type
@@ -333,7 +333,7 @@ proc isCastable(c: PContext; dst, src: PType, info: TLineInfo): bool =
if skipTypes(dst, abstractInst).kind == tyBuiltInTypeClass:
return false
let conf = c.config
if conf.selectedGC in {gcArc, gcOrc, gcAtomicArc, gcYrc}:
if conf.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
let d = skipTypes(dst, abstractInst)
let s = skipTypes(src, abstractInst)
if d.kind == tyRef and s.kind == tyRef and s[0].isFinal != d[0].isFinal:
@@ -396,7 +396,7 @@ proc semConv(c: PContext, n: PNode; flags: TExprFlags = {}, expectedType: PType
var evaluated = semStaticExpr(c, n[1], expectedType)
if evaluated.kind == nkType or evaluated.typ.kind == tyTypeDesc:
result = n
result.typ = c.makeTypeDesc semStaticType(c, evaluated, nil)
result.typ() = c.makeTypeDesc semStaticType(c, evaluated, nil)
return
elif targetType.base.kind == tyNone:
return evaluated
@@ -412,9 +412,9 @@ proc semConv(c: PContext, n: PNode; flags: TExprFlags = {}, expectedType: PType
let baseType = semTypeNode(c, n[1], nil).skipTypes({tyTypeDesc})
let t = newTypeS(targetType.kind, c, baseType)
if targetType.kind == tyOwned:
t.incl tfHasOwned
t.flags.incl tfHasOwned
result = newNodeI(nkType, n.info)
result.typ = makeTypeDesc(c, t)
result.typ() = makeTypeDesc(c, t)
return
result.add copyTree(n[0])
@@ -430,10 +430,10 @@ proc semConv(c: PContext, n: PNode; flags: TExprFlags = {}, expectedType: PType
if targetType.kind != tyGenericParam and targetType.isMetaType:
let final = inferWithMetatype(c, targetType, op, true)
result.add final
result.typ = final.typ
result.typ() = final.typ
return
result.typ = targetType
result.typ() = targetType
# XXX op is overwritten later on, this is likely added too early
# here or needs to be overwritten too then.
result.add op
@@ -441,7 +441,7 @@ proc semConv(c: PContext, n: PNode; flags: TExprFlags = {}, expectedType: PType
if targetType.kind == tyGenericParam or
(op.typ != nil and op.typ.kind == tyFromExpr and c.inGenericContext > 0):
# expression is compiled early in a generic body
result.typ = makeTypeFromExpr(c, copyTree(result))
result.typ() = makeTypeFromExpr(c, copyTree(result))
return result
if not isSymChoice(op):
@@ -491,7 +491,7 @@ proc semCast(c: PContext, n: PNode): PNode =
if not isCastable(c, targetType, castedExpr.typ, n.info):
localError(c.config, n.info, "expression cannot be cast to '$1'" % $targetType)
result = newNodeI(nkCast, n.info)
result.typ = targetType
result.typ() = targetType
result.add copyTree(n[0])
result.add castedExpr
@@ -505,18 +505,18 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
var typ = skipTypes(n[1].typ, abstractVarRange + {tyTypeDesc, tyUserTypeClassInst})
case typ.kind
of tySequence, tyString, tyCstring, tyOpenArray, tyVarargs:
n.typ = getSysType(c.graph, n.info, tyInt)
n.typ() = getSysType(c.graph, n.info, tyInt)
of tyArray:
n.typ = typ.indexType
n.typ() = typ.indexType
if n.typ.kind == tyRange and emptyRange(n.typ.n[0], n.typ.n[1]): #Invalid range
n.typ = getSysType(c.graph, n.info, tyInt)
n.typ() = getSysType(c.graph, n.info, tyInt)
of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt..tyUInt64, tyFloat..tyFloat64:
n.typ = n[1].typ.skipTypes({tyTypeDesc})
n.typ() = n[1].typ.skipTypes({tyTypeDesc})
of tyGenericParam:
# prepare this for resolving in semtypinst:
# we must use copyTree here in order to avoid creating a cycle
# that could easily turn into an infinite recursion in semtypinst
n.typ = makeTypeFromExpr(c, n.copyTree)
n.typ() = makeTypeFromExpr(c, n.copyTree)
else:
localError(c.config, n.info, "invalid argument for: " & opToStr[m])
result = n
@@ -532,7 +532,7 @@ proc fixupStaticType(c: PContext, n: PNode) =
# apply this measure only in code that is enlightened to work
# with static types.
if n.typ.kind != tyStatic:
n.typ = newTypeS(tyStatic, c, n.typ)
n.typ() = newTypeS(tyStatic, c, n.typ)
n.typ.n = n # XXX: cycles like the one here look dangerous.
# Consider using `n.copyTree`
@@ -582,7 +582,7 @@ proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode =
# `res = sameType(t1, t2)` would be wrong, e.g. for `int is (int|float)`
result = newIntNode(nkIntLit, ord(res))
result.typ = n.typ
result.typ() = n.typ
proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode =
if n.len != 3 or n[2].kind == nkEmpty:
@@ -591,7 +591,7 @@ proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode =
let boolType = getSysType(c.graph, n.info, tyBool)
result = n
n.typ = boolType
n.typ() = boolType
var liftLhs = true
n[1] = semExprWithType(c, n[1], {efDetermineType, efWantIterator})
@@ -605,7 +605,7 @@ proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode =
n[1] = evaluated
else:
result = newIntNode(nkIntLit, 0)
result.typ = boolType
result.typ() = boolType
return
elif t2.kind == tyTypeDesc and
(t2.base.kind == tyNone or tfExplicit in t2.flags):
@@ -635,7 +635,7 @@ proc semOpAux(c: PContext, n: PNode) =
let info = a[0].info
a[0] = newIdentNode(considerQuotedIdent(c, a[0], a), info)
a[1] = semExprWithType(c, a[1], flags)
a.typ = a[1].typ
a.typ() = a[1].typ
else:
n[i] = semExprWithType(c, a, flags)
@@ -708,7 +708,7 @@ proc changeType(c: PContext; n: PNode, newType: PType, check: bool) =
localError(c.config, n.info, "cannot convert '" & n.sym.name.s &
"' to '" & typeNameAndDesc(newType) & "'")
else: discard
n.typ = newType
n.typ() = newType
proc arrayConstrType(c: PContext, n: PNode): PType =
var typ = newTypeS(tyArray, c)
@@ -730,12 +730,12 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PTyp
var expectedElementType, expectedIndexType: PType = nil
var expectedBase: PType = nil
if constructType:
result.typ = newTypeS(tyArray, c)
result.typ() = newTypeS(tyArray, c)
rawAddSon(result.typ, nil) # index type
if expectedType != nil:
expectedBase = expectedType.skipTypes(abstractRange-{tyDistinct})
else:
result.typ = n.typ
result.typ() = n.typ
expectedBase = n.typ.skipTypes(abstractRange) # include tyDistinct this time
if expectedBase != nil:
case expectedBase.kind
@@ -813,11 +813,11 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PTyp
inc(lastIndex)
if isGeneric:
for i in 0..<result.len:
if result[i].typ != nil and isIntLit(result[i].typ):
if isIntLit(result[i].typ):
# generic instantiation strips int lit type which makes conversions fail
result[i].typ = nil
result.typ = nil # current result.typ is invalid, index type is nil
result.typ = makeTypeFromExpr(c, result.copyTree)
result[i].typ() = nil
result.typ() = nil # current result.typ is invalid, index type is nil
result.typ() = makeTypeFromExpr(c, result.copyTree)
return
if constructType:
addSonSkipIntLit(result.typ, typ, c.idgen)
@@ -832,6 +832,9 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PTyp
proc fixAbstractType(c: PContext, n: PNode) =
for i in 1..<n.len:
let it = n[i]
if it == nil:
localError(c.config, n.info, "'$1' has nil child at index $2" % [renderTree(n, {renderNoComments}), $i])
return
# do not get rid of nkHiddenSubConv for OpenArrays, the codegen needs it:
if it.kind == nkHiddenSubConv and
skipTypes(it.typ, abstractVar).kind notin {tyOpenArray, tyVarargs}:
@@ -915,8 +918,8 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
if n[i].typ.isNil or n[i].typ.kind != tyStatic or
tfUnresolved notin n[i].typ.flags:
break maybeLabelAsStatic
n.typ = newTypeS(tyStatic, c, n.typ)
n.typ.incl tfUnresolved
n.typ() = newTypeS(tyStatic, c, n.typ)
n.typ.flags.incl tfUnresolved
# optimization pass: not necessary for correctness of the semantic pass
if (callee.kind == skConst or
@@ -1009,7 +1012,7 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
if efWantIterable in flags:
let typ = newTypeS(tyIterable, c)
rawAddSon(typ, result.typ)
result.typ = typ
result.typ() = typ
proc resolveIndirectCall(c: PContext; n, nOrig: PNode;
t: PType): TCandidate =
@@ -1096,7 +1099,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
elif n0.typ.kind == tyFromExpr and c.inGenericContext > 0:
# don't make assumptions, entire expression needs to be tyFromExpr
result = semGenericStmt(c, n)
result.typ = makeTypeFromExpr(c, result.copyTree)
result.typ() = makeTypeFromExpr(c, result.copyTree)
return
else:
n[0] = n0
@@ -1152,7 +1155,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
localError(c.config, n.info, msg)
return errorNode(c, n)
else:
result = compactVoidArgs(m.call)
result = m.call
instGenericConvertersSons(c, result, m)
markConvertersUsed(c, result)
@@ -1358,7 +1361,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
of tyStatic:
if typ.n != nil:
result = typ.n
result.typ = typ.base
result.typ() = typ.base
else:
result = newSymNode(s, n.info)
else:
@@ -1404,11 +1407,11 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
onUse(n.info, s)
if s.typ.kind == tyStatic:
result = newSymNode(s, n.info)
result.typ = s.typ
result.typ() = s.typ
elif s.ast != nil:
result = semExpr(c, s.ast)
else:
n.typ = s.typ
n.typ() = s.typ
return n
of skType:
if n.kind != nkDotExpr: # dotExpr is already checked by builtinFieldAccess
@@ -1419,7 +1422,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
if s.typ.kind == tyStatic and s.typ.base.kind != tyNone and s.typ.n != nil:
return s.typ.n
result = newSymNode(s, n.info)
result.typ = makeTypeDesc(c, s.typ)
result.typ() = makeTypeDesc(c, s.typ)
of skField:
# old code, not sure if it's live code:
markUsed(c, n.info, s)
@@ -1445,7 +1448,7 @@ proc tryReadingGenericParam(c: PContext, n: PNode, i: PIdent, t: PType): PNode =
if result == c.graph.emptyNode:
if c.inGenericContext > 0:
result = semGenericStmt(c, n)
result.typ = makeTypeFromExpr(c, result.copyTree)
result.typ() = makeTypeFromExpr(c, result.copyTree)
else:
result = nil
of tyUserTypeClasses:
@@ -1453,7 +1456,7 @@ proc tryReadingGenericParam(c: PContext, n: PNode, i: PIdent, t: PType): PNode =
result = readTypeParameter(c, t, i, n.info)
elif c.inGenericContext > 0:
result = semGenericStmt(c, n)
result.typ = makeTypeFromExpr(c, copyTree(result))
result.typ() = makeTypeFromExpr(c, copyTree(result))
else:
result = nil
of tyGenericBody, tyCompositeTypeClass:
@@ -1462,12 +1465,12 @@ proc tryReadingGenericParam(c: PContext, n: PNode, i: PIdent, t: PType): PNode =
if result != nil:
# generic parameter exists, stop here but delay until instantiation
result = semGenericStmt(c, n)
result.typ = makeTypeFromExpr(c, copyTree(result))
result.typ() = makeTypeFromExpr(c, copyTree(result))
else:
result = nil
elif c.inGenericContext > 0 and t.containsUnresolvedType:
result = semGenericStmt(c, n)
result.typ = makeTypeFromExpr(c, copyTree(result))
result.typ() = makeTypeFromExpr(c, copyTree(result))
else:
result = nil
@@ -1485,14 +1488,14 @@ proc tryReadingTypeField(c: PContext, n: PNode, i: PIdent, ty: PType): PNode =
if f != nil:
result = newSymNode(f)
result.info = n.info
result.typ = ty
result.typ() = ty
markUsed(c, n.info, f)
onUse(n.info, f)
of tyObject, tyTuple:
if ty.n != nil and ty.n.kind == nkRecList:
let field = lookupInRecord(ty.n, i)
if field != nil:
n.typ = makeTypeDesc(c, field.typ)
n.typ() = makeTypeDesc(c, field.typ)
result = n
of tyGenericInst:
result = tryReadingTypeField(c, n, i, ty.skipModifier)
@@ -1539,7 +1542,7 @@ proc builtinFieldAccess(c: PContext; n: PNode; flags: var TExprFlags): PNode =
# tyFromExpr, but when this happen in a macro this is not a built-in
# field access and we leave the compiler to compile a normal call:
if getCurrOwner(c).kind != skMacro:
n.typ = makeTypeFromExpr(c, n.copyTree)
n.typ() = makeTypeFromExpr(c, n.copyTree)
flags.incl efCannotBeDotCall
return n
else:
@@ -1579,12 +1582,12 @@ proc builtinFieldAccess(c: PContext; n: PNode; flags: var TExprFlags): PNode =
n[0] = makeDeref(n[0])
n[1] = newSymNode(f) # we now have the correct field
n[1].info = info # preserve the original info
n.typ = f.typ
n.typ() = f.typ
if check == nil:
result = n
else:
check[0] = n
check.typ = n.typ
check.typ() = n.typ
result = check
elif ty.kind == tyTuple and ty.n != nil:
f = getSymFromList(ty.n, i)
@@ -1593,7 +1596,7 @@ proc builtinFieldAccess(c: PContext; n: PNode; flags: var TExprFlags): PNode =
onUse(n[1].info, f)
n[0] = makeDeref(n[0])
n[1] = newSymNode(f)
n.typ = f.typ
n.typ() = f.typ
result = n
# we didn't find any field, let's look for a generic param
@@ -1658,13 +1661,10 @@ proc semDeref(c: PContext, n: PNode, flags: TExprFlags): PNode =
n[0] = a
result = n
var t = skipTypes(n[0].typ, {tyGenericInst, tyVar, tyLent, tyAlias, tySink, tyOwned})
if t.kind == tyTypeDesc:
localError(c.config, n.info, "missing generic parameter")
return nil
case t.kind
of tyRef, tyPtr: n.typ = t.elementType
of tyRef, tyPtr: n.typ() = t.elementType
of tyMetaTypes, tyFromExpr:
n.typ = makeTypeFromExpr(c, n.copyTree)
n.typ() = makeTypeFromExpr(c, n.copyTree)
else: result = nil
#GlobalError(n[0].info, errCircumNeedsPointer)
@@ -1697,7 +1697,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags, afterOverloading = f
if arr.kind == tyStatic:
if arr.base.kind == tyNone:
result = n
result.typ = semStaticType(c, n[1], nil)
result.typ() = semStaticType(c, n[1], nil)
return
elif arr.n != nil:
return semSubscript(c, arr.n, flags, afterOverloading)
@@ -1719,18 +1719,18 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags, afterOverloading = f
if arg != nil:
n[1] = arg
result = n
result.typ = elemType(arr)
result.typ() = elemType(arr)
# Other types have a bit more of leeway
elif n[1].typ.skipTypes(abstractRange-{tyDistinct}).kind in
{tyInt..tyInt64, tyUInt..tyUInt64}:
result = n
result.typ = elemType(arr)
result.typ() = elemType(arr)
of tyTypeDesc:
# The result so far is a tyTypeDesc bound
# a tyGenericBody. The line below will substitute
# it with the instantiated type.
result = n
result.typ = makeTypeDesc(c, semTypeNode(c, n, nil))
result.typ() = makeTypeDesc(c, semTypeNode(c, n, nil))
#result = symNodeFromType(c, semTypeNode(c, n, nil), n.info)
of tyTuple:
if n.len != 2: return nil
@@ -1740,7 +1740,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags, afterOverloading = f
if skipTypes(n[1].typ, {tyGenericInst, tyRange, tyOrdinal, tyAlias, tySink}).kind in
{tyInt..tyInt64}:
let idx = getOrdValue(n[1])
if idx >= 0 and idx < arr.len: n.typ = arr[toInt(idx)]
if idx >= 0 and idx < arr.len: n.typ() = arr[toInt(idx)]
else:
localError(c.config, n.info,
"invalid index $1 in subscript for tuple of length $2" %
@@ -1837,7 +1837,7 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode =
localError(c.config, n.info, errExprHasNoAddress)
result = newNodeIT(nkHiddenAddr, n.info, if n.typ.kind in {tyVar, tyLent}: n.typ else: makePtrType(c, n.typ))
if n.typ.kind in {tyVar, tyLent}:
n.typ = n.typ.elementType
n.typ() = n.typ.elementType
result.add(n)
proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} =
@@ -1847,10 +1847,10 @@ proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} =
if x.sym.kind == skResult and (x.typ.kind in {tyVar, tyLent} or classifyViewType(x.typ) != noView):
n[0] = x # 'result[]' --> 'result'
n[1] = takeImplicitAddr(c, ri, x.typ.kind == tyLent)
x.typ.incl tfVarIsPtr
x.typ.flags.incl tfVarIsPtr
#echo x.info, " setting it for this type ", typeToString(x.typ), " ", n.info
elif sfGlobal in x.sym.flags:
x.typ.incl tfVarIsPtr
x.typ.flags.incl tfVarIsPtr
proc borrowCheck(c: PContext, n, le, ri: PNode) =
const
@@ -1920,7 +1920,7 @@ proc makeTupleAssignments(c: PContext; n: PNode): PNode =
let temp = newSym(skTemp, getIdent(c.cache, "tmpTupleAsgn"), c.idgen, getCurrOwner(c), n.info)
temp.typ = value.typ
temp.flagsImpl.incl(sfGenSym)
temp.flags.incl(sfGenSym)
var v = newNodeI(nkLetSection, value.info)
let tempNode = newSymNode(temp) #newIdentNode(getIdent(genPrefix & $temp.id), value.info)
var vpart = newNodeI(nkIdentDefs, v.info, 3)
@@ -1937,7 +1937,7 @@ proc makeTupleAssignments(c: PContext; n: PNode): PNode =
# generate `let _ = temp[i]` which should generate a destructor
let utemp = newSym(skLet, lhs[i].ident, c.idgen, getCurrOwner(c), lhs[i].info)
utemp.typ = value.typ[i]
temp.flagsImpl.incl(sfGenSym)
temp.flags.incl(sfGenSym)
var uv = newNodeI(nkLetSection, lhs[i].info)
let utempNode = newSymNode(utemp)
var uvpart = newNodeI(nkIdentDefs, v.info, 3)
@@ -2031,7 +2031,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
let lhs = n[0]
let rhs = semExprWithType(c, n[1], {efTypeAllowed}, le)
if lhs.kind == nkSym and lhs.sym.kind == skResult:
n.typ = c.enforceVoidContext
n.typ() = c.enforceVoidContext
if c.p.owner.kind != skMacro and resultTypeIsInferrable(lhs.sym.typ):
var rhsTyp = rhs.typ
if rhsTyp.kind in tyUserTypeClasses and rhsTyp.isResolvedUserTypeClass:
@@ -2042,7 +2042,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
internalAssert c.config, c.p.resultSym != nil
# Make sure the type is valid for the result variable
typeAllowedCheck(c, n.info, rhsTyp, skResult)
lhs.typ = rhsTyp
lhs.typ() = rhsTyp
c.p.resultSym.typ = rhsTyp
c.p.owner.typ.setReturnType rhsTyp
else:
@@ -2090,7 +2090,7 @@ proc semProcBody(c: PContext, n: PNode; expectedType: PType = nil): PNode =
if result.kind == nkNilLit:
# or ImplicitlyDiscardable(result):
# new semantic: 'result = x' triggers the void context
result.typ = nil
result.typ() = nil
elif result.kind == nkStmtListExpr and result.typ.kind == tyNil:
# to keep backwards compatibility bodies like:
# nil
@@ -2124,7 +2124,7 @@ proc semYieldVarResult(c: PContext, n: PNode, restype: PType) =
var t = skipTypes(restype, {tyGenericInst, tyAlias, tySink})
case t.kind
of tyVar, tyLent:
t.incl tfVarIsPtr # bugfix for #4048, #4910, #6892
t.flags.incl tfVarIsPtr # bugfix for #4048, #4910, #6892
if n[0].kind in {nkHiddenStdConv, nkHiddenSubConv}:
n[0] = n[0][1]
n[0] = takeImplicitAddr(c, n[0], t.kind == tyLent)
@@ -2132,7 +2132,7 @@ proc semYieldVarResult(c: PContext, n: PNode, restype: PType) =
for i in 0..<t.len:
let e = skipTypes(t[i], {tyGenericInst, tyAlias, tySink})
if e.kind in {tyVar, tyLent}:
e.incl tfVarIsPtr # bugfix for #4048, #4910, #6892
e.flags.incl tfVarIsPtr # bugfix for #4048, #4910, #6892
let tupleConstr = if n[0].kind in {nkHiddenStdConv, nkHiddenSubConv}: n[0][1] else: n[0]
if tupleConstr.kind in {nkPar, nkTupleConstr}:
if tupleConstr[i].kind == nkExprColonExpr:
@@ -2193,7 +2193,7 @@ proc semDefined(c: PContext, n: PNode): PNode =
result = newIntNode(nkIntLit, 0)
result.intVal = ord isDefined(c.config, considerQuotedIdentOrDot(c, n[1], n).s)
result.info = n.info
result.typ = getSysType(c.graph, n.info, tyBool)
result.typ() = getSysType(c.graph, n.info, tyBool)
proc lookUpForDeclared(c: PContext, n: PNode, onlyCurrentScope: bool): PSym =
case n.kind
@@ -2229,7 +2229,7 @@ proc semDeclared(c: PContext, n: PNode, onlyCurrentScope: bool): PNode =
result = newIntNode(nkIntLit, 0)
result.intVal = ord lookUpForDeclared(c, n[1], onlyCurrentScope) != nil
result.info = n.info
result.typ = getSysType(c.graph, n.info, tyBool)
result.typ() = getSysType(c.graph, n.info, tyBool)
proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym =
## The argument to the proc should be nkCall(...) or similar
@@ -2302,10 +2302,10 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
localError(c.config, n.info, "getAst takes a call, but got " & n.renderTree)
# Preserve the magic symbol in order to be handled in evals.nim
internalAssert c.config, n[0].sym.magic == mExpandToAst
#n.typ = getSysSym("NimNode").typ # expandedSym.getReturnType
#n.typ() = getSysSym("NimNode").typ # expandedSym.getReturnType
if n.kind == nkStmtList and n.len == 1: result = n[0]
else: result = n
result.typ = sysTypeFromName(c.graph, n.info, "NimNode")
result.typ() = sysTypeFromName(c.graph, n.info, "NimNode")
proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym,
flags: TExprFlags = {}): PNode =
@@ -2376,7 +2376,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
processQuotations(c, quotedBlock, op, quotes, ids)
let dummyTemplateSym = newAnonSym(c, skTemplate, n.info)
incl(dummyTemplateSym.flagsImpl, sfTemplateRedefinition)
incl(dummyTemplateSym.flags, sfTemplateRedefinition)
var dummyTemplate = newProcNode(
nkTemplateDef, quotedBlock.info, body = quotedBlock,
params = c.graph.emptyNode,
@@ -2475,7 +2475,7 @@ proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = newIntNode(nkIntLit, ord(tryExpr(c, n[1], flags) != nil))
result.info = n.info
result.typ = getSysType(c.graph, n.info, tyBool)
result.typ() = getSysType(c.graph, n.info, tyBool)
proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode =
if n.len == 3:
@@ -2505,9 +2505,8 @@ proc instantiateCreateFlowVarCall(c: PContext; t: PType;
# since it's an instantiation, we unmark it as a compilerproc. Otherwise
# codegen would fail:
if sfCompilerProc in result.flags:
ensureMutable result
result.flagsImpl.excl {sfCompilerProc, sfExportc, sfImportc}
result.locImpl.snippet = ""
result.flags.excl {sfCompilerProc, sfExportc, sfImportc}
result.loc.snippet = ""
proc setMs(n: PNode, s: PSym): PNode =
result = n
@@ -2520,7 +2519,7 @@ proc semSizeof(c: PContext, n: PNode): PNode =
else:
n[1] = semExprWithType(c, n[1], {efDetermineType})
#restoreOldStyleType(n[1])
n.typ = getSysType(c.graph, n.info, tyInt)
n.typ() = getSysType(c.graph, n.info, tyInt)
result = foldSizeOf(c.config, n, n)
proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags; expectedType: PType = nil): PNode =
@@ -2562,7 +2561,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags; expectedType: P
markUsed(c, n.info, s)
checkSonsLen(n, 2, c.config)
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n, c.graph)
result.typ = getSysType(c.graph, n.info, tyString)
result.typ() = getSysType(c.graph, n.info, tyString)
of mParallel:
markUsed(c, n.info, s)
if parallel notin c.features:
@@ -2588,9 +2587,9 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags; expectedType: P
let typ = result[^1].typ
if not typ.isEmptyType:
if spawnResult(typ, c.inParallelStmt > 0) == srFlowVar:
result.typ = createFlowVar(c, typ, n.info)
result.typ() = createFlowVar(c, typ, n.info)
else:
result.typ = typ
result.typ() = typ
result.add instantiateCreateFlowVarCall(c, typ, n.info).newSymNode
else:
result.add c.graph.emptyNode
@@ -2598,7 +2597,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags; expectedType: P
markUsed(c, n.info, s)
result = setMs(n, s)
result[1] = semExpr(c, n[1])
result.typ = n[1].typ
result.typ() = n[1].typ
of mPlugin:
markUsed(c, n.info, s)
# semDirectOp with conditional 'afterCallActions':
@@ -2729,19 +2728,19 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
else: illFormedAst(n, c.config)
if cannotResolve:
result = semGenericStmt(c, n)
result.typ = makeTypeFromExpr(c, result.copyTree)
result.typ() = makeTypeFromExpr(c, result.copyTree)
return
if result == nil:
result = newNodeI(nkEmpty, n.info)
if whenNimvm:
result.typ = typ
result.typ() = typ
if n.len == 1:
result.add(newTree(nkElse, newNode(nkStmtList)))
proc semSetConstr(c: PContext, n: PNode, expectedType: PType = nil): PNode =
result = newNodeI(nkCurly, n.info)
result.typ = newTypeS(tySet, c)
result.typ.incl tfIsConstructor
result.typ() = newTypeS(tySet, c)
result.typ.flags.incl tfIsConstructor
var expectedElementType: PType = nil
if expectedType != nil and (
let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
@@ -2771,7 +2770,7 @@ proc semSetConstr(c: PContext, n: PNode, expectedType: PType = nil): PNode =
if doSetType:
typ = skipTypes(n[i][1].typ,
{tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
n[i].typ = n[i][2].typ # range node needs type too
n[i].typ() = n[i][2].typ # range node needs type too
elif n[i].kind == nkRange:
# already semchecked
if doSetType:
@@ -2800,11 +2799,11 @@ proc semSetConstr(c: PContext, n: PNode, expectedType: PType = nil): PNode =
expectedElementType = typ
if isGeneric:
for i in 0..<n.len:
if n[i].typ != nil and isIntLit(n[i].typ):
if isIntLit(n[i].typ):
# generic instantiation strips int lit type which makes conversions fail
n[i].typ = nil
n[i].typ() = nil
result.add n[i]
result.typ = makeTypeFromExpr(c, result.copyTree)
result.typ() = makeTypeFromExpr(c, result.copyTree)
return
addSonSkipIntLit(result.typ, typ, c.idgen)
for i in 0..<n.len:
@@ -2902,7 +2901,7 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType
if n[i][1].typ.kind == tyTypeDesc:
localError(c.config, n[i][1].info, "typedesc not allowed as tuple field.")
n[i][1].typ = errorType(c)
n[i][1].typ() = errorType(c)
var f = newSymS(skField, n[i][0], c)
f.typ = skipIntLit(n[i][1].typ.skipTypes({tySink}), c.idgen)
@@ -2913,19 +2912,19 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType
result.add n[i]
if isGeneric:
for i in 0..<result.len:
if result[i][1].typ != nil and isIntLit(result[i][1].typ):
if isIntLit(result[i][1].typ):
# generic instantiation strips int lit type which makes conversions fail
result[i][1].typ = nil
result.typ = makeTypeFromExpr(c, result.copyTree)
result[i][1].typ() = nil
result.typ() = makeTypeFromExpr(c, result.copyTree)
return
let oldType = n.typ
result.typ = typ
result.typ() = typ
if oldType != nil and not hasEmpty(oldType): # see hasEmpty comment above
# convert back to old type
let conversion = indexTypesMatch(c, oldType, typ, result)
# ignore matching error, the goal is just to keep the original type info
if conversion != nil:
result.typ = oldType
result.typ() = oldType
proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
result = n # we don't modify n, but compute the type:
@@ -2954,19 +2953,19 @@ proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedT
addSonSkipIntLit(typ, n[i].typ.skipTypes({tySink}), c.idgen)
if isGeneric:
for i in 0..<result.len:
if result[i].typ != nil and isIntLit(result[i].typ):
if isIntLit(result[i].typ):
# generic instantiation strips int lit type which makes conversions fail
result[i].typ = nil
result.typ = makeTypeFromExpr(c, result.copyTree)
result[i].typ() = nil
result.typ() = makeTypeFromExpr(c, result.copyTree)
return
let oldType = n.typ
result.typ = typ
result.typ() = typ
if oldType != nil and not hasEmpty(oldType): # see hasEmpty comment above
# convert back to old type
let conversion = indexTypesMatch(c, oldType, typ, result)
# ignore matching error, the goal is just to keep the original type info
if conversion != nil:
result.typ = oldType
result.typ() = oldType
include semobjconstr
@@ -2988,7 +2987,7 @@ proc semBlock(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = ni
styleCheckDef(c, labl)
onDef(n[0].info, labl)
n[1] = semExpr(c, n[1], flags, expectedType)
n.typ = n[1].typ
n.typ() = n[1].typ
if isEmptyType(n.typ): n.transitionSonsKind(nkBlockStmt)
else: n.transitionSonsKind(nkBlockExpr)
closeScope(c)
@@ -3013,9 +3012,9 @@ proc semExportExcept(c: PContext, n: PNode): PNode =
proc semExport(c: PContext, n: PNode): PNode =
proc specialSyms(c: PContext; s: PSym) {.inline.} =
if s.kind == skConverter: addConverter(c, s)
if s.kind == skConverter: addConverter(c, LazySym(sym: s))
elif s.kind == skType and s.typ != nil and s.typ.kind == tyEnum and sfPure in s.flags:
addPureEnum(c, s)
addPureEnum(c, LazySym(sym: s))
result = newNodeI(nkExportStmt, n.info)
for i in 0..<n.len:
@@ -3054,13 +3053,6 @@ proc semExport(c: PContext, n: PNode): PNode =
s = nextOverloadIter(o, c, a)
proc isTypeTupleField(n: PNode): bool {.inline.} =
result = n.typ.kind == tyTypeDesc or
(n.typ.kind == tyGenericParam and n.typ.sym.kind == skGenericParam)
# `skGenericParam` stays as `tyGenericParam` type rather than being wrapped in `tyTypeDesc`
# would check if `n` itself is an `skGenericParam` symbol, but these symbols semcheck to an ident
# maybe check if `n` is an ident to ensure this is not a value with the generic param type?
proc semTupleConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
result = semTuplePositionsConstr(c, n, flags, expectedType)
if result.typ.kind == tyFromExpr:
@@ -3071,15 +3063,15 @@ proc semTupleConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PTyp
var isTupleType: bool = false
if tupexp.len > 0: # don't interpret () as type
internalAssert c.config, tupexp.kind == nkTupleConstr
isTupleType = isTypeTupleField(tupexp[0])
isTupleType = tupexp[0].typ.kind == tyTypeDesc
# check if either everything or nothing is tyTypeDesc
for i in 1..<tupexp.len:
if isTupleType != isTypeTupleField(tupexp[i]):
if isTupleType != (tupexp[i].typ.kind == tyTypeDesc):
return localErrorNode(c, n, tupexp[i].info, "Mixing types and values in tuples is not allowed.")
if isTupleType: # expressions as ``(int, string)`` are reinterpret as type expressions
result = n
var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc})
result.typ = makeTypeDesc(c, typ)
result.typ() = makeTypeDesc(c, typ)
proc isExplicitGenericCall(c: PContext, n: PNode): bool =
## checks if a call node `n` is a routine call with explicit generic params
@@ -3224,7 +3216,7 @@ proc enumFieldSymChoice(c: PContext, n: PNode, s: PSym; flags: TExprFlags): PNod
a = initOverloadIter(o, c, n)
while a != nil:
if a.kind == skEnumField:
incl(a.flagsImpl, sfUsed)
incl(a.flags, sfUsed)
markOwnerModuleAsUsed(c, a)
result.add newSymNode(a, info)
onUse(info, a)
@@ -3299,10 +3291,10 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
if expectedType != nil and (
let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
expected.kind == typeKind):
result.typ = expected
result.typ() = expected
changeType(c, result, expectedType, check=true)
else:
result.typ = getSysType(c.graph, n.info, typeKind)
result.typ() = getSysType(c.graph, n.info, typeKind)
result = n
when defined(nimsuggest):
@@ -3338,7 +3330,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
# localError(c.config, n.info, errInstantiateXExplicitly, s.name.s)
# "procs literals" are 'owned'
if optOwnedRefs in c.config.globalOptions:
result.typ = makeVarType(c, result.typ, tyOwned)
result.typ() = makeVarType(c, result.typ, tyOwned)
of skEnumField:
result = enumFieldSymChoice(c, n, s, flags)
else:
@@ -3367,11 +3359,11 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
discard
of nkNilLit:
if result.typ == nil:
result.typ = getNilType(c)
result.typ() = getNilType(c)
if expectedType != nil and expectedType.kind notin {tyUntyped, tyTyped}:
var m = newCandidate(c, result.typ)
if typeRel(m, expectedType, result.typ) >= isSubtype:
result.typ = expectedType
result.typ() = expectedType
# or: result = fitNode(c, expectedType, result, n.info)
of nkIntLit:
if result.typ == nil:
@@ -3399,10 +3391,10 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
if expectedType != nil and (
let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
expected.kind in {tyFloat..tyFloat128}):
result.typ = expected
result.typ() = expected
changeType(c, result, expectedType, check=true)
else:
result.typ = getSysType(c.graph, n.info, tyFloat64)
result.typ() = getSysType(c.graph, n.info, tyFloat64)
of nkFloat32Lit: directLiteral(tyFloat32)
of nkFloat64Lit: directLiteral(tyFloat64)
of nkFloat128Lit: directLiteral(tyFloat128)
@@ -3411,9 +3403,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
if expectedType != nil and (
let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
expected.kind in {tyString, tyCstring}):
result.typ = expectedType
result.typ() = expectedType
else:
result.typ = getSysType(c.graph, n.info, tyString)
result.typ() = getSysType(c.graph, n.info, tyString)
of nkCharLit: directLiteral(tyChar)
of nkDotExpr:
result = semFieldAccess(c, n, flags)
@@ -3428,13 +3420,13 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
let modifier = n.modifierTypeKindOfNode
if modifier != tyNone:
var baseType = semExpr(c, n[0]).typ.skipTypes({tyTypeDesc})
result.typ = c.makeTypeDesc(newTypeS(modifier, c, baseType))
result.typ() = c.makeTypeDesc(newTypeS(modifier, c, baseType))
return
var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc})
result.typ = makeTypeDesc(c, typ)
result.typ() = makeTypeDesc(c, typ)
of nkStmtListType:
let typ = semTypeNode(c, n, nil)
result.typ = makeTypeDesc(c, typ)
result.typ() = makeTypeDesc(c, typ)
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
# check if it is an expression macro:
checkMinSonsLen(n, 1, c.config)

View File

@@ -24,7 +24,7 @@ proc wrapNewScope(c: PContext, n: PNode): PNode {.inline.} =
# a scope has to be opened in the codegen as well for reused
# template instantiations
let trueLit = newIntLit(c.graph, n.info, 1)
trueLit.typ = getSysType(c.graph, n.info, tyBool)
trueLit.typ() = getSysType(c.graph, n.info, tyBool)
result = newTreeI(nkIfStmt, n.info, newTreeI(nkElifBranch, n.info, trueLit, n))
proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =

View File

@@ -16,7 +16,7 @@ import
commands, magicsys, modulegraphs, lineinfos, wordrecg
import std/[strutils, math, strtabs]
#from system/memory import nimCStrLen
from system/memory import nimCStrLen
when defined(nimPreviewSlimSystem):
import std/[assertions, formatfloat]
@@ -24,7 +24,7 @@ when defined(nimPreviewSlimSystem):
proc errorType*(g: ModuleGraph): PType =
## creates a type representing an error state
result = newType(tyError, g.idgen, g.owners[^1])
result.flagsImpl.incl tfCheckedForDestructor
result.flags.incl tfCheckedForDestructor
proc getIntLitTypeG(g: ModuleGraph; literal: PNode; idgen: IdGenerator): PType =
# we cache some common integer literal types for performance:
@@ -38,7 +38,7 @@ proc newIntNodeT*(intVal: Int128, n: PNode; idgen: IdGenerator; g: ModuleGraph):
# original type was 'int', not a distinct int etc.
if n.typ.kind == tyInt:
# access cache for the int lit type
result.typ = getIntLitTypeG(g, result, idgen)
result.typ() = getIntLitTypeG(g, result, idgen)
result.info = n.info
proc newFloatNodeT*(floatVal: BiggestFloat, n: PNode; g: ModuleGraph): PNode =
@@ -46,12 +46,12 @@ proc newFloatNodeT*(floatVal: BiggestFloat, n: PNode; g: ModuleGraph): PNode =
result = newFloatNode(nkFloat32Lit, floatVal)
else:
result = newFloatNode(nkFloatLit, floatVal)
result.typ = n.typ
result.typ() = n.typ
result.info = n.info
proc newStrNodeT*(strVal: string, n: PNode; g: ModuleGraph): PNode =
result = newStrNode(nkStrLit, strVal)
result.typ = n.typ
result.typ() = n.typ
result.info = n.info
proc getConstExpr*(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
@@ -179,30 +179,29 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; idgen: IdGenerator; g: ModuleGraph): P
let argB = getInt(b)
result = newIntNodeT(if argA > argB: argA else: argB, n, idgen, g)
of mShlI:
let valueB = toInt64(getInt(b)) and (n.typ.size * 8 - 1)
case skipTypes(n.typ, abstractRange).kind
of tyInt8: result = newIntNodeT(toInt128(toInt8(getInt(a)) shl valueB), n, idgen, g)
of tyInt16: result = newIntNodeT(toInt128(toInt16(getInt(a)) shl valueB), n, idgen, g)
of tyInt32: result = newIntNodeT(toInt128(toInt32(getInt(a)) shl valueB), n, idgen, g)
of tyInt64: result = newIntNodeT(toInt128(toInt64(getInt(a)) shl valueB), n, idgen, g)
of tyInt8: result = newIntNodeT(toInt128(toInt8(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
of tyInt16: result = newIntNodeT(toInt128(toInt16(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
of tyInt32: result = newIntNodeT(toInt128(toInt32(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
of tyInt64: result = newIntNodeT(toInt128(toInt64(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
of tyInt:
if g.config.target.intSize == 4:
result = newIntNodeT(toInt128(toInt32(getInt(a)) shl valueB), n, idgen, g)
result = newIntNodeT(toInt128(toInt32(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
else:
result = newIntNodeT(toInt128(toInt64(getInt(a)) shl valueB), n, idgen, g)
of tyUInt8: result = newIntNodeT(toInt128(toUInt8(getInt(a)) shl valueB), n, idgen, g)
of tyUInt16: result = newIntNodeT(toInt128(toUInt16(getInt(a)) shl valueB), n, idgen, g)
of tyUInt32: result = newIntNodeT(toInt128(toUInt32(getInt(a)) shl valueB), n, idgen, g)
of tyUInt64: result = newIntNodeT(toInt128(toUInt64(getInt(a)) shl valueB), n, idgen, g)
result = newIntNodeT(toInt128(toInt64(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
of tyUInt8: result = newIntNodeT(toInt128(toUInt8(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
of tyUInt16: result = newIntNodeT(toInt128(toUInt16(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
of tyUInt32: result = newIntNodeT(toInt128(toUInt32(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
of tyUInt64: result = newIntNodeT(toInt128(toUInt64(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
of tyUInt:
if g.config.target.intSize == 4:
result = newIntNodeT(toInt128(toUInt32(getInt(a)) shl valueB), n, idgen, g)
result = newIntNodeT(toInt128(toUInt32(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
else:
result = newIntNodeT(toInt128(toUInt64(getInt(a)) shl valueB), n, idgen, g)
result = newIntNodeT(toInt128(toUInt64(getInt(a)) shl toInt64(getInt(b))), n, idgen, g)
else: internalError(g.config, n.info, "constant folding for shl")
of mShrI:
var a = castToUInt64(getInt(a))
let b = castToUInt64(getInt(b)) and cast[uint64](n.typ.size * 8 - 1)
var a = cast[uint64](getInt(a))
let b = cast[uint64](getInt(b))
# To support the ``-d:nimOldShiftRight`` flag, we need to mask the
# signed integers to cut off the extended sign bit in the internal
# representation.
@@ -221,13 +220,12 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; idgen: IdGenerator; g: ModuleGraph): P
let c = cast[BiggestInt](a shr b)
result = newIntNodeT(toInt128(c), n, idgen, g)
of mAshrI:
let valueB = toInt64(getInt(b)) and (n.typ.size * 8 - 1)
case skipTypes(n.typ, abstractRange).kind
of tyInt8: result = newIntNodeT(toInt128(ashr(toInt8(getInt(a)), valueB)), n, idgen, g)
of tyInt16: result = newIntNodeT(toInt128(ashr(toInt16(getInt(a)), valueB)), n, idgen, g)
of tyInt32: result = newIntNodeT(toInt128(ashr(toInt32(getInt(a)), valueB)), n, idgen, g)
of tyInt8: result = newIntNodeT(toInt128(ashr(toInt8(getInt(a)), toInt8(getInt(b)))), n, idgen, g)
of tyInt16: result = newIntNodeT(toInt128(ashr(toInt16(getInt(a)), toInt16(getInt(b)))), n, idgen, g)
of tyInt32: result = newIntNodeT(toInt128(ashr(toInt32(getInt(a)), toInt32(getInt(b)))), n, idgen, g)
of tyInt64, tyInt:
result = newIntNodeT(toInt128(ashr(toInt64(getInt(a)), valueB)), n, idgen, g)
result = newIntNodeT(toInt128(ashr(toInt64(getInt(a)), toInt64(getInt(b)))), n, idgen, g)
else: internalError(g.config, n.info, "constant folding for ashr")
of mDivI:
let argA = getInt(a)
@@ -321,7 +319,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; idgen: IdGenerator; g: ModuleGraph): P
of mEnumToStr: result = newStrNodeT(ordinalValToString(a, g), n, g)
of mArrToSeq:
result = copyTree(a)
result.typ = n.typ
result.typ() = n.typ
of mCompileOption:
result = newIntNodeT(toInt128(ord(commands.testCompileOption(g.config, a.getStr, n.info))), n, idgen, g)
of mCompileOptionArg:
@@ -416,7 +414,7 @@ proc foldConv(n, a: PNode; idgen: IdGenerator; g: ModuleGraph; check = false): P
result = newIntNodeT(toInt128(a.getOrdValue != 0), n, idgen, g)
of tyBool, tyEnum: # xxx shouldn't we disallow `tyEnum`?
result = a
result.typ = n.typ
result.typ() = n.typ
else:
raiseAssert $srcTyp.kind
of tyInt..tyInt64, tyUInt..tyUInt64:
@@ -433,7 +431,7 @@ proc foldConv(n, a: PNode; idgen: IdGenerator; g: ModuleGraph; check = false): P
result = newIntNodeT(val, n, idgen, g)
else:
result = a
result.typ = n.typ
result.typ() = n.typ
if check and result.kind in {nkCharLit..nkUInt64Lit} and
dstTyp.kind notin {tyUInt..tyUInt64}:
rangeCheck(n, getInt(result), g)
@@ -443,12 +441,12 @@ proc foldConv(n, a: PNode; idgen: IdGenerator; g: ModuleGraph; check = false): P
result = newFloatNodeT(toFloat64(getOrdValue(a)), n, g)
else:
result = a
result.typ = n.typ
result.typ() = n.typ
of tyOpenArray, tyVarargs, tyProc, tyPointer:
result = nil
else:
result = a
result.typ = n.typ
result.typ() = n.typ
proc getArrayConstr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
if n.kind == nkBracket:
@@ -520,10 +518,10 @@ proc foldConStrStr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
proc newSymNodeTypeDesc*(s: PSym; idgen: IdGenerator; info: TLineInfo): PNode =
result = newSymNode(s, info)
if s.typ.kind != tyTypeDesc:
result.typ = newType(tyTypeDesc, idgen, s.owner)
result.typ() = newType(tyTypeDesc, idgen, s.owner)
result.typ.addSonSkipIntLit(s.typ, idgen)
else:
result.typ = s.typ
result.typ() = s.typ
proc foldDefine(m, s: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
result = nil
@@ -642,7 +640,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
if s.typ.kind == tyStatic:
if s.typ.n != nil and tfUnresolved notin s.typ.flags:
result = s.typ.n
result.typ = s.typ.base
result.typ() = s.typ.base
elif s.typ.isIntLit:
result = s.typ.n
else:
@@ -755,7 +753,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
if a == nil: return
if leValueConv(n[1], a) and leValueConv(a, n[2]):
result = a # a <= x and x <= b
result.typ = n.typ
result.typ() = n.typ
elif n.typ.kind in {tyUInt..tyUInt64}:
discard "don't check uints"
else:
@@ -766,7 +764,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
var a = getConstExpr(m, n[0], idgen, g)
if a == nil: return
result = a
result.typ = n.typ
result.typ() = n.typ
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
var a = getConstExpr(m, n[1], idgen, g)
if a == nil: return
@@ -783,7 +781,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
not (n.typ.kind == tyProc and a.typ.kind == tyProc):
# we allow compile-time 'cast' for pointer types:
result = a
result.typ = n.typ
result.typ() = n.typ
of nkBracketExpr: result = foldArrayAccess(m, n, idgen, g)
of nkDotExpr: result = foldFieldAccess(m, n, idgen, g)
of nkCheckedFieldExpr:

View File

@@ -50,13 +50,13 @@ proc semGenericStmtScope(c: PContext, n: PNode,
result = semGenericStmt(c, n, flags, ctx)
closeScope(c)
template isMixedIn(sym): bool {.dirty.} =
template isMixedIn(sym): bool =
let s = sym
s.name.id in ctx.toMixin or (withinConcept in flags and
s.magic == mNone and
s.kind in OverloadableSyms)
template canOpenSym(s): bool {.dirty.} =
template canOpenSym(s): bool =
{withinMixin, withinConcept} * flags == {withinMixin} and s.id notin ctx.toBind
proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
@@ -65,7 +65,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
fromDotExpr=false): PNode =
result = nil
semIdeForTemplateOrGenericCheck(c.config, n, ctx.cursorInBody)
incl(s.flagsImpl, sfUsed)
incl(s.flags, sfUsed)
template maybeDotChoice(c: PContext, n: PNode, s: PSym, fromDotExpr: bool) =
if fromDotExpr:
result = symChoice(c, n, s, scForceOpen)
@@ -78,10 +78,10 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
if result.kind == nkSym:
result = newOpenSym(result)
else:
result.typ = nil
result.typ() = nil
else:
result.flags.incl nfDisabledOpenSym
result.typ = nil
result.typ() = nil
case s.kind
of skUnknown:
# Introduced in this pass! Leave it as an identifier.
@@ -116,7 +116,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
result.typ = nil
result.typ() = nil
else:
result = n
else:
@@ -126,7 +126,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
result.typ = nil
result.typ() = nil
onUse(n.info, s)
of skParam:
result = n
@@ -145,7 +145,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
result.typ = nil
result.typ() = nil
elif c.inGenericContext > 0 and withinConcept notin flags:
# don't leave generic param as identifier node in generic type,
# sigmatch will try to instantiate generic type AST without all params
@@ -157,7 +157,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
result.typ = nil
result.typ() = nil
else:
result = n
onUse(n.info, s)
@@ -168,7 +168,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
result.typ = nil
result.typ() = nil
onUse(n.info, s)
proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
@@ -248,13 +248,13 @@ proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =
onDef(n.info, s)
proc addTempDeclToIdents(c: PContext; n: PNode; kind: TSymKind; inCall: bool) =
case n.kind
case n.kind
of nkIdent:
if inCall:
addTempDecl(c, n, kind)
of nkCallKinds:
for s in n:
addTempDeclToIdents(c, s, kind, true)
addTempDeclToIdents(c, s, kind, true)
else:
for s in n:
addTempDeclToIdents(c, s, kind, inCall)
@@ -274,7 +274,7 @@ proc semGenericStmt(c: PContext, n: PNode,
result = lookup(c, n, flags, ctx)
if result != nil and result.kind == nkSym:
assert result.sym != nil
incl result.sym.flagsImpl, sfUsed
incl result.sym.flags, sfUsed
markOwnerModuleAsUsed(c, result.sym)
of nkDotExpr:
#let luf = if withinMixin notin flags: {checkUndeclared} else: {}
@@ -318,7 +318,7 @@ proc semGenericStmt(c: PContext, n: PNode,
var first = int ord(withinConcept in flags)
var mixinContext = false
if s != nil:
incl(s.flagsImpl, sfUsed)
incl(s.flags, sfUsed)
mixinContext = s.magic in {mDefined, mDeclared, mDeclaredInScope, mCompiles, mAstToStr}
let whichChoice = if s.id in ctx.toBind: scClosed
elif s.isMixedIn: scForceOpen
@@ -632,7 +632,7 @@ proc semGenericStmt(c: PContext, n: PNode,
# treat as mixin context for user pragmas & macro args
x[j] = semGenericStmt(c, x[j], flags+{withinMixin}, ctx)
elif prag == wInvalid:
# only sem if not a language-level pragma
# only sem if not a language-level pragma
# treat as mixin context for user pragmas & macro args
result[i] = semGenericStmt(c, x, flags+{withinMixin}, ctx)
of nkExprColonExpr, nkExprEqExpr:

View File

@@ -24,7 +24,7 @@ proc addObjFieldsToLocalScope(c: PContext; n: PNode) =
let f = n.sym
if f.kind == skField and fieldVisible(c, f):
c.currentScope.symbols.strTableIncl(f, onConflictKeepOld=true)
incl(f.flagsImpl, sfUsed)
incl(f.flags, sfUsed)
# it is not an error to shadow fields via parameters
else: discard
@@ -42,7 +42,7 @@ iterator instantiateGenericParamList(c: PContext, n: PNode, pt: LayeredIdTable):
if q.typ.kind in {tyTypeDesc, tyGenericParam, tyStatic, tyConcept}+tyTypeClasses:
let symKind = if q.typ.kind == tyStatic: skConst else: skType
var s = newSym(symKind, q.name, c.idgen, getCurrOwner(c), q.info)
s.flagsImpl.incl {sfUsed, sfFromGeneric}
s.flags.incl {sfUsed, sfFromGeneric}
var t = lookup(pt, q.typ)
if t == nil:
if tfRetType in q.typ.flags:
@@ -149,7 +149,7 @@ proc instantiateBody(c: PContext, n, params: PNode, result, orig: PSym) =
nil
b = semProcBody(c, b, resultType)
result.ast[bodyPos] = hloBody(c, b)
excl(result, sfForward)
excl(result.flags, sfForward)
trackProc(c, result, result.ast[bodyPos])
dec c.inGenericInst
@@ -208,7 +208,7 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
# this scope was not created by the user,
# unused params shouldn't be reported.
param.flagsImpl.incl sfUsed
param.flags.incl sfUsed
addDecl(c, param)
result = replaceTypeVarsT(cl, header)
@@ -244,8 +244,7 @@ proc instantiateProcType(c: PContext, pt: LayeredIdTable,
var result = instCopyType(cl, prc.typ)
let originalParams = result.n
result.n = originalParams.shallowCopy
for i in 1 ..< originalParams.len:
let resulti = originalParams[i].sym.typ
for i, resulti in paramTypes(result):
# twrong_field_caching requires these 'resetIdTable' calls:
if i > FirstParamAt:
resetIdTable(cl.symMap)
@@ -258,24 +257,24 @@ proc instantiateProcType(c: PContext, pt: LayeredIdTable,
let needsStaticSkipping = resulti.kind == tyFromExpr
let needsTypeDescSkipping = resulti.kind == tyTypeDesc and tfUnresolved in resulti.flags
if resulti.kind == tyFromExpr:
resulti.incl tfNonConstExpr
var paramType = replaceTypeVarsT(cl, resulti)
resulti.flags.incl tfNonConstExpr
result[i] = replaceTypeVarsT(cl, resulti)
if needsStaticSkipping:
paramType = paramType.skipTypes({tyStatic})
result[i] = result[i].skipTypes({tyStatic})
if needsTypeDescSkipping:
paramType = paramType.skipTypes({tyTypeDesc})
typeToFit = paramType
result[i] = result[i].skipTypes({tyTypeDesc})
typeToFit = result[i]
# ...otherwise, we use the instantiated type in `fitNode`
if (typeToFit.kind != tyTypeDesc or typeToFit.base.kind != tyNone) and
(typeToFit.kind != tyStatic):
typeToFit = paramType
typeToFit = result[i]
internalAssert c.config, originalParams[i].kind == nkSym
let oldParam = originalParams[i].sym
let param = copySym(oldParam, c.idgen)
setOwner(param, prc)
param.typ = paramType
param.typ = result[i]
# The default value is instantiated and fitted against the final
# concrete param type. We avoid calling `replaceTypeVarsN` on the
@@ -283,7 +282,7 @@ proc instantiateProcType(c: PContext, pt: LayeredIdTable,
if oldParam.ast != nil:
var def = oldParam.ast.copyTree
if def.typ.kind == tyFromExpr:
def.typ.incl tfNonConstExpr
def.typ.flags.incl tfNonConstExpr
if not isIntLit(def.typ):
def = prepareNode(cl, def)
@@ -303,15 +302,15 @@ proc instantiateProcType(c: PContext, pt: LayeredIdTable,
# the only way the default value might be inserted).
param.ast = errorNode(c, def)
# we know the node is empty, we need the actual type for error message
param.ast.typ = def.typ
param.ast.typ() = def.typ
else:
param.ast = fitNodePostMatch(c, typeToFit, converted)
param.typ = paramType
param.typ = result[i]
result.n[i] = newSymNode(param)
if isRecursiveStructuralType(paramType):
if isRecursiveStructuralType(result[i]):
localError(c.config, originalParams[i].sym.info, "illegal recursion in type '" & typeToString(result[i]) & "'")
propagateToOwner(result, paramType)
propagateToOwner(result, result[i])
addDecl(c, param)
resetIdTable(cl.symMap)
@@ -338,7 +337,7 @@ proc instantiateOnlyProcType(c: PContext, pt: LayeredIdTable, prc: PSym, info: T
# examples are in texplicitgenerics
# might be buggy, see rest of generateInstance if problems occur
let fakeSym = copySym(prc, c.idgen)
incl(fakeSym.flagsImpl, sfFromGeneric)
incl(fakeSym.flags, sfFromGeneric)
fakeSym.instantiatedFrom = prc
openScope(c)
for s in instantiateGenericParamList(c, prc.ast[genericParamsPos], pt):
@@ -394,7 +393,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: LayeredIdTable,
let oldScope = c.currentScope
while not isTopLevel(c): c.currentScope = c.currentScope.parent
result = copySym(fn, c.idgen)
incl(result, sfFromGeneric)
incl(result.flags, sfFromGeneric)
result.instantiatedFrom = fn
if sfGlobal in result.flags and c.config.symbolFiles != disabledSf:
let passc = getLocalPassC(c, producer)
@@ -439,7 +438,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: LayeredIdTable,
inc i
#echo "INSTAN ", fn.name.s, " ", typeToString(result.typ), " ", entry.concreteTypes.len
if tfTriggersCompileTime in result.typ.flags:
incl(result, sfCompileTime)
incl(result.flags, sfCompileTime)
n[genericParamsPos] = c.graph.emptyNode
var oldPrc = genericCacheGet(c.graph, fn, entry[], c.compilesContextId)
if oldPrc == nil:
@@ -451,10 +450,6 @@ proc generateInstance(c: PContext, fn: PSym, pt: LayeredIdTable,
entry.compilesId = c.compilesContextId
addToGenericProcCache(c, fn, entry)
c.generics.add(makeInstPair(fn, entry))
# Log the generic instance so it gets written to the NIF file.
# This is needed for cyclic module dependencies where generic instances
# may be created in one module but referenced from another.
logGenericInstance(c.graph, result)
# bug #12985 bug #22913
# TODO: use the context of the declaration of generic functions instead
# TODO: consider fixing options as well

View File

@@ -93,8 +93,8 @@ proc annotateType*(n: PNode, t: PType; conf: ConfigRef; producedClosure: var boo
case n.kind
of nkObjConstr:
let x = t.skipTypes(abstractPtrs)
n.typ = t
n[0].typ = t
n.typ() = t
n[0].typ() = t
for i in 1..<n.len:
var tracker = FieldTracker(index: i-1, remaining: i-1, constr: n, delete: false)
let field = x.ithField(tracker)
@@ -108,12 +108,12 @@ proc annotateType*(n: PNode, t: PType; conf: ConfigRef; producedClosure: var boo
incl(n[i].flags, nfPreventCg)
of nkPar, nkTupleConstr:
if x.kind == tyTuple:
n.typ = t
n.typ() = t
for i in 0..<n.len:
if i >= x.kidsLen: globalError conf, n.info, "invalid field at index " & $i
else: annotateType(n[i], x[i], conf, producedClosure)
elif x.kind == tyProc and x.callConv == ccClosure:
n.typ = t
n.typ() = t
if n.len > 1 and n[1].kind notin {nkEmpty, nkNilLit}:
producedClosure = true
elif x.kind == tyOpenArray: # `opcSlice` transforms slices into tuples
@@ -136,18 +136,18 @@ proc annotateType*(n: PNode, t: PType; conf: ConfigRef; producedClosure: var boo
globalError(conf, n.info, "Incorrectly generated tuple constr")
n[] = bracketExpr[]
n.typ = t
n.typ() = t
else:
globalError(conf, n.info, "() must have a tuple type")
of nkBracket:
if x.kind in {tyArray, tySequence, tyOpenArray}:
n.typ = t
n.typ() = t
for m in n: annotateType(m, x.elemType, conf, producedClosure)
else:
globalError(conf, n.info, "[] must have some form of array type")
of nkCurly:
if x.kind in {tySet}:
n.typ = t
n.typ() = t
for m in n:
if m.kind == nkRange:
annotateType(m[0], x.elemType, conf, producedClosure)
@@ -158,22 +158,22 @@ proc annotateType*(n: PNode, t: PType; conf: ConfigRef; producedClosure: var boo
globalError(conf, n.info, "{} must have the set type")
of nkFloatLit..nkFloat128Lit:
if x.kind in {tyFloat..tyFloat128}:
n.typ = t
n.typ() = t
else:
globalError(conf, n.info, "float literal must have some float type")
of nkCharLit..nkUInt64Lit:
if x.kind in {tyInt..tyUInt64, tyBool, tyChar, tyEnum}:
n.typ = t
n.typ() = t
else:
globalError(conf, n.info, "integer literal must have some int type")
of nkStrLit..nkTripleStrLit:
if x.kind in {tyString, tyCstring}:
n.typ = t
n.typ() = t
else:
globalError(conf, n.info, "string literal must be of some string type")
of nkNilLit:
if x.kind in NilableTypes+{tyString, tySequence}:
n.typ = t
n.typ() = t
else:
globalError(conf, n.info, "nil literal must be of some pointer type")
else: discard

View File

@@ -18,7 +18,7 @@ proc addDefaultFieldForNew(c: PContext, n: PNode): PNode =
let typ = result[1].typ # new(x)
if typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyRef and typ.skipTypes({tyGenericInst, tyAlias, tySink})[0].kind == tyObject:
var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, result[1].info, typ))
asgnExpr.typ = typ
asgnExpr.typ() = typ
var t = typ.skipTypes({tyGenericInst, tyAlias, tySink})[0]
while true:
asgnExpr.sons.add defaultFieldsForTheUninitialized(c, t.n, false)
@@ -34,11 +34,11 @@ proc semAddr(c: PContext; n: PNode): PNode =
result = newNodeI(nkAddr, n.info)
let x = semExprWithType(c, n)
if x.kind == nkSym:
x.sym.flagsImpl.incl(sfAddrTaken)
x.sym.flags.incl(sfAddrTaken)
if isAssignable(c, x) notin {arLValue, arLocalLValue, arAddressableConst, arLentValue}:
localError(c.config, n.info, errExprHasNoAddress)
result.add x
result.typ = makePtrType(c, x.typ.skipTypes({tySink}))
result.typ() = makePtrType(c, x.typ.skipTypes({tySink}))
proc semTypeOf(c: PContext; n: PNode): PNode =
var m = BiggestInt 1 # typeOfIter
@@ -54,16 +54,16 @@ proc semTypeOf(c: PContext; n: PNode): PNode =
let typExpr = semExprWithType(c, n[1], if m == 1: {efInTypeof} else: {})
result.add typExpr
if typExpr.typ.kind == tyFromExpr:
typExpr.typ.incl tfNonConstExpr
typExpr.typ.flags.incl tfNonConstExpr
var t = typExpr.typ
if t.kind == tyStatic:
let base = t.skipTypes({tyStatic})
if c.inGenericContext > 0 and base.containsGenericType:
t = makeTypeFromExpr(c, copyTree(typExpr))
t.incl tfNonConstExpr
t.flags.incl tfNonConstExpr
else:
t = base
result.typ = makeTypeDesc(c, t)
result.typ() = makeTypeDesc(c, t)
type
SemAsgnMode = enum asgnNormal, noOverloadedSubscript, noOverloadedAsgn
@@ -84,8 +84,8 @@ proc semArrGet(c: PContext; n: PNode; flags: TExprFlags): PNode =
if a.typ != nil and a.typ.kind in {tyGenericParam, tyFromExpr}:
# expression is compiled early in a generic body
result = semGenericStmt(c, x)
result.typ = makeTypeFromExpr(c, copyTree(result))
result.typ.incl tfNonConstExpr
result.typ() = makeTypeFromExpr(c, copyTree(result))
result.typ.flags.incl tfNonConstExpr
return
let s = # extract sym from first arg
if n.len > 1:
@@ -208,15 +208,15 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym)
let preferStr = traitCall[2].strVal
prefer = parseEnum[TPreferedDesc](preferStr)
result = newStrNode(nkStrLit, operand.typeToString(prefer))
result.typ = getSysType(c.graph, traitCall[1].info, tyString)
result.typ() = getSysType(c.graph, traitCall[1].info, tyString)
result.info = traitCall.info
of "name", "$":
result = newStrNode(nkStrLit, operand.typeToString(preferTypeName))
result.typ = getSysType(c.graph, traitCall[1].info, tyString)
result.typ() = getSysType(c.graph, traitCall[1].info, tyString)
result.info = traitCall.info
of "arity":
result = newIntNode(nkIntLit, operand.len - ord(operand.kind==tyProc))
result.typ = newType(tyInt, c.idgen, context)
result.typ() = newType(tyInt, c.idgen, context)
result.info = traitCall.info
of "genericHead":
var arg = operand
@@ -236,8 +236,6 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym)
let complexObj = containsGarbageCollectedRef(t) or
hasDestructor(t)
result = newIntNodeT(toInt128(ord(not complexObj)), traitCall, c.idgen, c.graph)
of "canFormCycles":
result = newIntNodeT(toInt128(ord(types.canFormAcycle(c.graph, operand))), traitCall, c.idgen, c.graph)
of "hasDefaultValue":
result = newIntNodeT(toInt128(ord(not operand.requiresInit)), traitCall, c.idgen, c.graph)
of "isNamedTuple":
@@ -245,7 +243,7 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym)
let cond = operand.kind == tyTuple and operand.n != nil
result = newIntNodeT(toInt128(ord(cond)), traitCall, c.idgen, c.graph)
of "tupleLen":
var operand = operand.skipTypes({tyGenericInst, tyAlias})
var operand = operand.skipTypes({tyGenericInst})
assert operand.kind == tyTuple, $operand.kind
result = newIntNodeT(toInt128(operand.len), traitCall, c.idgen, c.graph)
of "distinctBase":
@@ -288,7 +286,7 @@ proc semOrd(c: PContext, n: PNode): PNode =
discard
else:
localError(c.config, n.info, errOrdinalTypeExpected % typeToString(parType, preferDesc))
result.typ = errorType(c)
result.typ() = errorType(c)
proc semBindSym(c: PContext, n: PNode): PNode =
result = copyNode(n)
@@ -404,7 +402,7 @@ proc semOf(c: PContext, n: PNode): PNode =
message(c.config, n.info, hintConditionAlwaysTrue, renderTree(n))
result = newIntNode(nkIntLit, 1)
result.info = n.info
result.typ = getSysType(c.graph, n.info, tyBool)
result.typ() = getSysType(c.graph, n.info, tyBool)
return result
elif diff == high(int):
if commonSuperclass(a, b) == nil:
@@ -413,10 +411,10 @@ proc semOf(c: PContext, n: PNode): PNode =
message(c.config, n.info, hintConditionAlwaysFalse, renderTree(n))
result = newIntNode(nkIntLit, 0)
result.info = n.info
result.typ = getSysType(c.graph, n.info, tyBool)
result.typ() = getSysType(c.graph, n.info, tyBool)
else:
localError(c.config, n.info, "'of' takes 2 arguments")
n.typ = getSysType(c.graph, n.info, tyBool)
n.typ() = getSysType(c.graph, n.info, tyBool)
result = n
proc semUnown(c: PContext; n: PNode): PNode =
@@ -444,16 +442,16 @@ proc semUnown(c: PContext; n: PNode): PNode =
copyTypeProps(c.graph, c.idgen.module, result, t)
result[^1] = b
result.excl tfHasOwned
result.flags.excl tfHasOwned
else:
result = t
else:
result = t
result = copyTree(n[1])
result.typ = unownedType(c, result.typ)
result.typ() = unownedType(c, result.typ)
# little hack for injectdestructors.nim (see bug #11350):
#result[0].typ = nil
#result[0].typ() = nil
proc turnFinalizerIntoDestructor(c: PContext; orig: PSym; info: TLineInfo): PSym =
# We need to do 2 things: Replace n.typ which is a 'ref T' by a 'var T' type.
@@ -463,7 +461,7 @@ proc turnFinalizerIntoDestructor(c: PContext; orig: PSym; info: TLineInfo): PSym
proc transform(c: PContext; n: PNode; old, fresh: PType; oldParam, newParam: PSym): PNode =
result = shallowCopy(n)
if sameTypeOrNil(n.typ, old):
result.typ = fresh
result.typ() = fresh
if n.kind == nkSym and n.sym == oldParam:
result.sym = newParam
for i in 0 ..< safeLen(n):
@@ -473,7 +471,7 @@ proc turnFinalizerIntoDestructor(c: PContext; orig: PSym; info: TLineInfo): PSym
result = copySym(orig, c.idgen)
result.info = info
result.incl sfFromGeneric
result.flags.incl sfFromGeneric
setOwner(result, orig)
let origParamType = orig.typ.firstParamType
let newParamType = makeVarType(result, origParamType.skipTypes(abstractPtrs), c.idgen)
@@ -552,8 +550,8 @@ proc semNewFinalize(c: PContext; n: PNode): PNode =
else:
let wrapperSym = newSym(skProc, getIdent(c.graph.cache, fin.name.s & "FinalizerWrapper"), c.idgen, fin.owner, fin.info)
let selfSymNode = newSymNode(copySym(fin.ast[paramsPos][1][0].sym, c.idgen))
selfSymNode.typ = fin.typ.firstParamType
wrapperSym.flagsImpl.incl sfUsed
selfSymNode.typ() = fin.typ.firstParamType
wrapperSym.flags.incl sfUsed
let wrapper = c.semExpr(c, newProcNode(nkProcDef, fin.info, body = newTree(nkCall, newSymNode(fin), selfSymNode),
params = nkFormalParams.newTree(c.graph.emptyNode,
@@ -570,7 +568,7 @@ proc semNewFinalize(c: PContext; n: PNode): PNode =
let selfSymbolType = makePtrType(c, origParamType.skipTypes(abstractPtrs))
let selfPtr = newNodeI(nkHiddenAddr, transFormedSym.ast[bodyPos][1].info)
selfPtr.add transFormedSym.ast[bodyPos][1]
selfPtr.typ = selfSymbolType
selfPtr.typ() = selfSymbolType
transFormedSym.ast[bodyPos][1] = c.semExpr(c, selfPtr)
bindTypeHook(c, transFormedSym, n, attachedDestructor)
result = addDefaultFieldForNew(c, n)
@@ -625,7 +623,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
of mTypeTrait: result = semTypeTraits(c, n)
of mAstToStr:
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n, c.graph)
result.typ = getSysType(c.graph, n.info, tyString)
result.typ() = getSysType(c.graph, n.info, tyString)
of mInstantiationInfo: result = semInstantiationInfo(c, n)
of mOrd: result = semOrd(c, n)
of mOf: result = semOf(c, n)
@@ -638,7 +636,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
result = semDynamicBindSym(c, n)
of mProcCall:
result = n
result.typ = n[1].typ
result.typ() = n[1].typ
of mDotDot:
result = n
of mPlugin:
@@ -694,7 +692,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
result = n
if result.typ != nil and expectedType != nil and result.typ.kind == tySequence and
expectedType.kind == tySequence and result.typ.elementType.kind == tyEmpty:
result.typ = expectedType # type inference for empty sequence # bug #21377
result.typ() = expectedType # type inference for empty sequence # bug #21377
of mEnsureMove:
result = n
if n[1].kind in {nkStmtListExpr, nkBlockExpr,

View File

@@ -68,10 +68,6 @@ proc locateFieldInInitExpr(c: PContext, field: PSym, initExpr: PNode): PNode =
let assignment = initExpr[i]
if assignment.kind != nkExprColonExpr:
invalidObjConstr(c, assignment)
elif nfPreventCg in assignment.flags:
# this is an object constructor node generated by the VM and
# this field is in an inactive case branch, just ignore it
discard
elif fieldId == considerQuotedIdent(c, assignment[0]).id:
return assignment
@@ -192,7 +188,7 @@ proc collectOrAddMissingCaseFields(c: PContext, branchNode: PNode,
newNodeIT(nkType, constrCtx.initExpr.info, asgnType)
)
asgnExpr.flags.incl nfSkipFieldChecking
asgnExpr.typ = recTyp
asgnExpr.typ() = recTyp
defaults.add newTree(nkExprColonExpr, newSymNode(sym), asgnExpr)
proc collectBranchFields(c: PContext, n: PNode, discriminatorVal: PNode,
@@ -482,10 +478,10 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
if t.kind == tyRef:
t = skipTypes(t.elementType, {tyGenericInst, tyAlias, tySink, tyOwned})
if optOwnedRefs in c.config.globalOptions:
result.typ = makeVarType(c, result.typ, tyOwned)
result.typ() = makeVarType(c, result.typ, tyOwned)
# we have to watch out, there are also 'owned proc' types that can be used
# multiple times as long as they don't have closures.
result.typ.incl tfHasOwned
result.typ.flags.incl tfHasOwned
if t.kind != tyObject:
return localErrorNode(c, result, if t.kind != tyGenericBody:
"object constructor needs an object type".dup(addTypeNodeDeclaredLoc(c.config, t))
@@ -519,10 +515,6 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
invalidObjConstr(c, field)
hasError = true
continue
elif nfPreventCg in field.flags:
# this is an object constructor node generated by the VM and
# this field is in an inactive case branch, just ignore it
continue
let id = considerQuotedIdent(c, field[0])
# This node was not processed. There are two possible reasons:
# 1) It was shadowed by a field with the same name on the left

View File

@@ -407,9 +407,9 @@ proc transformSlices(g: ModuleGraph; idgen: IdGenerator; n: PNode): PNode =
result = copyNode(n)
var typ = newType(tyOpenArray, idgen, result.typ.owner)
typ.add result.typ.elementType
result.typ = typ
result.typ() = typ
let opSlice = newSymNode(createMagic(g, idgen, "slice", mSlice))
opSlice.typ = getSysType(g, n.info, tyInt)
opSlice.typ() = getSysType(g, n.info, tyInt)
result.add opSlice
result.add n[1]
let slice = n[2].skipStmtList
@@ -491,7 +491,7 @@ proc liftParallel*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; n: PNode): P
var varSection = newNodeI(nkVarSection, n.info)
var temp = newSym(skTemp, getIdent(g.cache, "barrier"), idgen, owner, n.info)
temp.typ = magicsys.getCompilerProc(g, "Barrier").typ
incl(temp.flagsImpl, sfFromGeneric)
incl(temp.flags, sfFromGeneric)
let tempNode = newSymNode(temp)
varSection.addVar tempNode

View File

@@ -11,7 +11,7 @@ import
ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
wordrecg, options, guards, lineinfos, semfold, semdata,
modulegraphs, varpartitions, typeallowed, nilcheck, errorhandling,
semstrictfuncs, suggestsymdb, pushpoppragmas
semstrictfuncs, suggestsymdb, pushpoppragmas, lowerings
import std/[tables, intsets, strutils, sequtils]
@@ -84,8 +84,6 @@ type
gcUnsafe, isRecursive, isTopLevel, hasSideEffect, inEnforcedGcSafe: bool
isInnerProc: bool
inEnforcedNoSideEffects: bool
isArrayIndexing: bool
currentExceptType: PType
unknownRaises: seq[(PSym, TLineInfo)]
currOptions: TOptions
optionsStack: seq[(TOptions, TNoteKinds)]
@@ -143,55 +141,12 @@ proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo; explicit
if tracked.config.selectedGC == gcRefc or
optSeqDestructors in tracked.config.globalOptions or
tfHasAsgn in typ.flags:
tracked.owner.incl sfInjectDestructors
tracked.owner.flags.incl sfInjectDestructors
proc isLocalSym(a: PEffects, s: PSym): bool =
s.typ != nil and (s.kind in {skLet, skVar, skResult} or (s.kind == skParam and isOutParam(s.typ))) and
sfGlobal notin s.flags and s.owner == a.owner
proc isRangeSupertype(conf: ConfigRef; wider, narrower: PType): bool =
## Check if `wider` type fully contains `narrower` type
## Returns true if narrower fits entirely within wider (safe conversion)
if wider.isOrdinalType:
let wideFirst = firstOrd(conf, wider)
let wideLast = lastOrd(conf, wider)
let narrowFirst = firstOrd(conf, narrower)
let narrowLast = lastOrd(conf, narrower)
result = narrowFirst >= wideFirst and narrowLast <= wideLast
elif not narrower.isOrdinalType:
let wideFirst = firstFloat(wider)
let wideLast = lastFloat(wider)
let narrowFirst = firstFloat(narrower)
let narrowLast = lastFloat(narrower)
result = narrowFirst >= wideFirst and narrowLast <= wideLast
else:
# int -> float ranges; warn
result = false
proc shouldWarnRangeConversion(conf: ConfigRef; info: TLineInfo; formalType, argType: PType): bool =
## Determine if an implicit range conversion should warn
## We warn on conversions that are likely to cause panics
let f = formalType.skipTypes({tyGenericInst, tyAlias, tySink, tyDistinct})
let a = argType.skipTypes({tyGenericInst, tyAlias, tySink, tyDistinct})
if f.kind == tyRange:
# Only warn if formal range doesn't fully contain argument range
# Check if the ranges don't perfectly overlap
if a.kind == tyInt and f.sym != nil and f.sym.owner != nil and
sfSystemModule in f.sym.owner.flags and
(f.sym.name.s == "Positive" or
f.sym.name.s == "Natural"):
# Positive and Natural are special cases that we do not warn on with
# ImplicitRangeConversion, but may warn on with systemRangeConversion
# if that warning is enabled.
if conf.hasWarn(warnSystemRangeConversion):
message(conf, info, warnSystemRangeConversion,
typeToString(argType) & " -> " & typeToString(formalType))
result = false
else:
result = not isRangeSupertype(conf, f, a)
else:
result = false
proc lockLocations(a: PEffects; pragma: PNode) =
if pragma.kind != nkExprColonExpr:
localError(a.config, pragma.info, "locks pragma without argument")
@@ -241,7 +196,7 @@ proc guardDotAccess(a: PEffects; n: PNode) =
let dot = newNodeI(nkDotExpr, n.info, 2)
dot[0] = n[0]
dot[1] = newSymNode(g)
dot.typ = g.typ
dot.typ() = g.typ
for L in a.locked:
#if a.guards.sameSubexprs(dot, L): return
if guards.sameTree(dot, L): return
@@ -251,7 +206,7 @@ proc guardDotAccess(a: PEffects; n: PNode) =
proc makeVolatile(a: PEffects; s: PSym) {.inline.} =
if a.inTryStmt > 0 and a.config.exc == excSetjmp:
incl(s, sfVolatile)
incl(s.flags, sfVolatile)
proc varDecl(a: PEffects; n: PNode) {.inline.} =
if n.kind == nkSym:
@@ -417,9 +372,9 @@ proc useVarNoInitCheck(a: PEffects; n: PNode; s: PSym) =
proc useVar(a: PEffects, n: PNode) =
let s = n.sym
if a.inExceptOrFinallyStmt > 0:
incl s.flags, sfUsedInFinallyOrExcept
if isLocalSym(a, s):
if a.inExceptOrFinallyStmt > 0:
incl s, sfUsedInFinallyOrExcept
if sfNoInit in s.flags:
# If the variable is explicitly marked as .noinit. do not emit any error
a.init.add s.id
@@ -462,7 +417,7 @@ proc throws(tracked, n, orig: PNode) =
if n.typ == nil or n.typ.kind != tyError:
if orig != nil:
let x = copyTree(orig)
x.typ = n.typ
x.typ() = n.typ
tracked.add x
else:
tracked.add n
@@ -477,12 +432,12 @@ proc excType(g: ModuleGraph; n: PNode): PType =
proc createRaise(g: ModuleGraph; n: PNode): PNode =
result = newNode(nkType)
result.typ = getEbase(g, n.info)
result.typ() = getEbase(g, n.info)
if not n.isNil: result.info = n.info
proc createTag(g: ModuleGraph; n: PNode): PNode =
result = newNode(nkType)
result.typ = g.sysTypeFromName(n.info, "RootEffect")
result.typ() = g.sysTypeFromName(n.info, "RootEffect")
if not n.isNil: result.info = n.info
proc addRaiseEffect(a: PEffects, e, comesFrom: PNode) =
@@ -622,25 +577,11 @@ proc trackTryStmt(tracked: PEffects, n: PNode) =
let b = n[i]
if b.kind == nkExceptBranch:
setLen(tracked.init, oldState)
# If this except branch catches exactly one type, record it so an
# empty `raise` inside the branch can be inferred as re-raising that
# specific exception type instead of the generic `Exception`.
var savedExcept: PType = tracked.currentExceptType
var inferredExcept: PType = nil
if b.len == 2:
if b[0].isInfixAs():
assert(b[0][1].kind == nkType)
inferredExcept = b[0][1].typ
else:
assert(b[0].kind == nkType)
inferredExcept = b[0].typ
tracked.currentExceptType = inferredExcept
for j in 0..<b.len - 1:
if b[j].isInfixAs(): # skips initialization checks
assert(b[j][2].kind == nkSym)
tracked.init.add b[j][2].sym.id
track(tracked, b[^1])
tracked.currentExceptType = savedExcept
for i in oldState..<tracked.init.len:
addToIntersection(inter, tracked.init[i], bsNone)
else:
@@ -1302,9 +1243,9 @@ proc track(tracked: PEffects, n: PNode) =
of nkSym:
useVar(tracked, n)
if n.sym.typ != nil and tfHasAsgn in n.sym.typ.flags:
tracked.owner.incl sfInjectDestructors
tracked.owner.flags.incl sfInjectDestructors
# bug #15038: ensure consistency
if n.typ == nil or (not hasDestructor(n.typ) and sameType(n.typ, n.sym.typ)): n.typ = n.sym.typ
if n.typ == nil or (not hasDestructor(n.typ) and sameType(n.typ, n.sym.typ)): n.typ() = n.sym.typ
of nkHiddenAddr, nkAddr:
if n[0].kind == nkSym and isLocalSym(tracked, n[0].sym) and
n.typ.kind notin {tyVar, tyLent}:
@@ -1323,14 +1264,7 @@ proc track(tracked: PEffects, n: PNode) =
# A `raise` with no arguments means we're going to re-raise the exception
# being handled or, if outside of an `except` block, a `ReraiseDefect`.
# Here we add a `Exception` tag in order to cover both the cases.
if tracked.currentExceptType != nil:
var en = newNode(nkType)
en.typ = tracked.currentExceptType
en.info = n.info
addRaiseEffect(tracked, en, nil)
createTypeBoundOps(tracked, tracked.currentExceptType, n.info)
else:
addRaiseEffect(tracked, createRaise(tracked.graph, n), nil)
addRaiseEffect(tracked, createRaise(tracked.graph, n), nil)
of nkCallKinds:
trackCall(tracked, n)
of nkDotExpr:
@@ -1548,12 +1482,6 @@ proc track(tracked: PEffects, n: PNode) =
message(tracked.config, n.info, warnPtrToCstringConv,
$n[1].typ)
# Check for implicit range conversions
if n.kind == nkHiddenStdConv and (not tracked.isArrayIndexing) and
n[1].kind notin {nkCharLit..nkUInt64Lit, nkFloatLit..nkFloat128Lit} and
shouldWarnRangeConversion(tracked.config, n.info, n.typ, n[1].typ):
message(tracked.config, n.info, warnImplicitRangeConversion,
typeToString(n[1].typ) & " -> " & typeToString(n.typ))
let t = n.typ.skipTypes(abstractInst)
if t.kind == tyEnum:
@@ -1592,12 +1520,7 @@ proc track(tracked: PEffects, n: PNode) =
checkBounds(tracked, n[0], n[1])
track(tracked, n[0])
dec tracked.leftPartOfAsgn
for i in 1 ..< n.len:
if i == 1:
tracked.isArrayIndexing = true
track(tracked, n[i])
if i == 1:
tracked.isArrayIndexing = false
for i in 1 ..< n.len: track(tracked, n[i])
inc tracked.leftPartOfAsgn
of nkError:
localError(tracked.config, n.info, errorToString(tracked.config, n))
@@ -1704,7 +1627,7 @@ proc setEffectsForProcType*(g: ModuleGraph; t: PType, n: PNode; s: PSym = nil) =
effects[pragmasEffects] = n
if s != nil and s.magic != mNone:
if s.magic != mEcho:
t.incl tfNoSideEffect
t.flags.incl tfNoSideEffect
proc rawInitEffects(g: ModuleGraph; effects: PNode) =
newSeq(effects.sons, effectListLen)
@@ -1759,7 +1682,7 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) =
t.scopes[res.id] = t.currentBlock
if sfNoInit in s.flags:
# marks result "noinit"
incl res, sfNoInit
incl res.flags, sfNoInit
track(t, body)
@@ -1769,7 +1692,7 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) =
let param = params[i].sym
let typ = param.typ
if isSinkTypeForParam(typ) or
(t.config.selectedGC in {gcArc, gcOrc, gcYrc, gcAtomicArc} and
(t.config.selectedGC in {gcArc, gcOrc, gcAtomicArc} and
(isClosure(typ.skipTypes(abstractInst)) or param.id in t.escapingParams)):
createTypeBoundOps(t, typ, param.info)
if isOutParam(typ) and param.id notin t.init and s.magic == mNone:
@@ -1846,9 +1769,9 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) =
else:
localError(g.config, s.info, "") # simple error for `system.compiles` context
if not t.gcUnsafe:
s.typ.incl tfGcSafe
s.typ.flags.incl tfGcSafe
if not t.hasSideEffect and sfSideEffect notin s.flags:
s.typ.incl tfNoSideEffect
s.typ.flags.incl tfNoSideEffect
when defined(drnim):
if c.graph.strongSemCheck != nil: c.graph.strongSemCheck(c.graph, s, body)
when defined(useDfa):

View File

@@ -79,7 +79,7 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode =
if s.kind == skLabel and s.owner.id == c.p.owner.id:
var x = newSymNode(s)
x.info = n.info
incl(s.flagsImpl, sfUsed)
incl(s.flags, sfUsed)
n[0] = x
suggestSym(c.graph, x.info, s, c.graph.usageSym)
onUse(x.info, s)
@@ -112,11 +112,11 @@ proc semWhile(c: PContext, n: PNode; flags: TExprFlags): PNode =
dec(c.p.nestedLoopCounter)
closeScope(c)
if n[1].typ == c.enforceVoidContext:
result.typ = c.enforceVoidContext
result.typ() = c.enforceVoidContext
elif efInTypeof in flags:
result.typ = n[1].typ
result.typ() = n[1].typ
elif implicitlyDiscardable(n[1]):
result[1].typ = c.enforceVoidContext
result[1].typ() = c.enforceVoidContext
proc semProc(c: PContext, n: PNode): PNode
@@ -275,7 +275,7 @@ proc fixNilType(c: PContext; n: PNode) =
elif n.kind in {nkStmtList, nkStmtListExpr}:
n.transitionSonsKind(nkStmtList)
for it in n: fixNilType(c, it)
n.typ = nil
n.typ() = nil
proc discardCheck(c: PContext, result: PNode, flags: TExprFlags) =
if c.matchedConcept != nil or efInTypeof in flags: return
@@ -331,14 +331,14 @@ proc semIf(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil):
for it in n: discardCheck(c, it.lastSon, flags)
result.transitionSonsKind(nkIfStmt)
# propagate any enforced VoidContext:
if typ == c.enforceVoidContext: result.typ = c.enforceVoidContext
if typ == c.enforceVoidContext: result.typ() = c.enforceVoidContext
else:
for it in n:
let j = it.len-1
if not endsInNoReturn(it[j]):
it[j] = fitNode(c, typ, it[j], it[j].info)
result.transitionSonsKind(nkIfExpr)
result.typ = typ
result.typ() = typ
proc semTry(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil): PNode =
var check = initIntSet()
@@ -394,9 +394,8 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil)
elif a.len == 1:
# count number of ``except: body`` blocks
inc catchAllExcepts
if noPanicOnExcept in c.graph.config.legacyFeatures:
message(c.config, a.info, warnBareExcept,
"The bare except clause is deprecated; use `except CatchableError:` instead")
message(c.config, a.info, warnBareExcept,
"The bare except clause is deprecated; use `except CatchableError:` instead")
else:
# support ``except KeyError, ValueError, ... : body``
if catchAllExcepts > 0:
@@ -439,7 +438,7 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil)
discardCheck(c, n[0], flags)
for i in 1..<n.len: discardCheck(c, n[i].lastSon, flags)
if typ == c.enforceVoidContext:
result.typ = c.enforceVoidContext
result.typ() = c.enforceVoidContext
else:
if n.lastSon.kind == nkFinally: discardCheck(c, n.lastSon.lastSon, flags)
if not endsInNoReturn(n[0]):
@@ -449,7 +448,7 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil)
let j = it.len-1
if not endsInNoReturn(it[j]):
it[j] = fitNode(c, typ, it[j], it[j].info)
result.typ = typ
result.typ() = typ
proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
result = fitNode(c, typ, n, n.info)
@@ -458,7 +457,7 @@ proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
if r1.kind in {nkCharLit..nkUInt64Lit} and typ.skipTypes(abstractRange).kind in {tyFloat..tyFloat128}:
result = newFloatNode(nkFloatLit, BiggestFloat r1.intVal)
result.info = n.info
result.typ = typ
result.typ() = typ
if not floatRangeCheck(result.floatVal, typ):
localError(c.config, n.info, errFloatToString % [$result.floatVal, typeToString(typ)])
elif r1.kind == nkSym and typ.skipTypes(abstractRange).kind == tyCstring:
@@ -484,13 +483,13 @@ proc identWithin(n: PNode, s: PIdent): bool =
proc semIdentDef(c: PContext, n: PNode, kind: TSymKind, reportToNimsuggest = true): PSym =
if isTopLevel(c):
result = semIdentWithPragma(c, kind, n, {sfExported}, fromTopLevel = true)
incl(result, sfGlobal)
incl(result.flags, sfGlobal)
#if kind in {skVar, skLet}:
# echo "global variable here ", n.info, " ", result.name.s
else:
result = semIdentWithPragma(c, kind, n, {})
if result.owner.kind == skModule:
incl(result, sfGlobal)
incl(result.flags, sfGlobal)
result.options = c.config.options
if reportToNimsuggest:
@@ -521,7 +520,7 @@ proc addToVarSection(c: PContext; result: var PNode; orig, identDefs: PNode) =
proc isDiscardUnderscore(v: PSym): bool =
if v.name.id == ord(wUnderscore):
v.incl(sfGenSym)
v.flags.incl(sfGenSym)
result = true
else:
result = false
@@ -595,7 +594,7 @@ proc fillPartialObject(c: PContext; n: PNode; typ: PType) =
obj.n.add newSymNode(field)
n[0] = makeDeref x
n[1] = newSymNode(field)
n.typ = field.typ
n.typ() = field.typ
else:
localError(c.config, n.info, "implicit object field construction " &
"requires a .partial object, but got " & typeToString(obj))
@@ -617,7 +616,7 @@ proc checkDefineType(c: PContext; v: PSym; t: PType) =
# no distinct types for generic define
skipped.excl tyDistinct
if t.skipTypes(skipped).kind notin typeKinds:
let name =
let name =
case v.magic
of mStrDefine: "strdefine"
of mIntDefine: "intdefine"
@@ -780,7 +779,7 @@ proc makeVarTupleSection(c: PContext, n, a, def: PNode, typ: PType, symkind: TSy
# use same symkind for compatibility with original section
let temp = newSym(symkind, getIdent(c.cache, "tmpTuple"), c.idgen, getCurrOwner(c), n.info)
temp.typ = typ
temp.flagsImpl.incl(sfGenSym)
temp.flags.incl(sfGenSym)
lastDef = newNodeI(defkind, a.info)
newSons(lastDef, 3)
lastDef[0] = newSymNode(temp)
@@ -938,11 +937,11 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
else:
if v.owner == nil: setOwner(v, c.p.owner)
when oKeepVariableNames:
if c.inUnrolledContext > 0: v.incl(sfShadowed)
if c.inUnrolledContext > 0: v.flags.incl(sfShadowed)
else:
let shadowed = findShadowedVar(c, v)
if shadowed != nil:
shadowed.incl(sfShadowed)
shadowed.flags.incl(sfShadowed)
if shadowed.kind == skResult and sfGenSym notin v.flags:
message(c.config, a.info, warnResultShadowed)
if def.kind != nkEmpty:
@@ -1114,13 +1113,13 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
for i in 0..<n[0].len-1:
var v = symForVar(c, n[0][i])
if getCurrOwner(c).kind == skModule: incl(v, sfGlobal)
if getCurrOwner(c).kind == skModule: incl(v.flags, sfGlobal)
case iter.kind
of tyVar, tyLent:
v.typ = newTypeS(iter.kind, c)
v.typ.add iterAfterVarLent[i]
if tfVarIsPtr in iter.flags:
v.typ.incl tfVarIsPtr
v.typ.flags.incl tfVarIsPtr
else:
v.typ = iter[i]
n[0][i] = newSymNode(v)
@@ -1128,7 +1127,7 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
elif v.owner == nil: setOwner(v, getCurrOwner(c))
else:
var v = symForVar(c, n[0])
if getCurrOwner(c).kind == skModule: incl(v, sfGlobal)
if getCurrOwner(c).kind == skModule: incl(v.flags, sfGlobal)
# BUGFIX: don't use `iter` here as that would strip away
# the ``tyGenericInst``! See ``tests/compile/tgeneric.nim``
# for an example:
@@ -1158,7 +1157,7 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
localError(c.config, n[i].info, errWrongNumberOfVariables)
for j in 0..<n[i].len-1:
var v = symForVar(c, n[i][j])
if getCurrOwner(c).kind == skModule: incl(v, sfGlobal)
if getCurrOwner(c).kind == skModule: incl(v.flags, sfGlobal)
if mutable:
v.typ = newTypeS(tyVar, c)
v.typ.add iter[i][j]
@@ -1172,13 +1171,13 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
elif v.owner == nil: setOwner(v, getCurrOwner(c))
else:
var v = symForVar(c, n[i])
if getCurrOwner(c).kind == skModule: incl(v, sfGlobal)
if getCurrOwner(c).kind == skModule: incl(v.flags, sfGlobal)
case iter.kind
of tyVar, tyLent:
v.typ = newTypeS(iter.kind, c)
v.typ.add iterAfterVarLent[i]
if tfVarIsPtr in iter.flags:
v.typ.incl tfVarIsPtr
v.typ.flags.incl tfVarIsPtr
else:
v.typ = iter[i]
n[i] = newSymNode(v)
@@ -1319,9 +1318,9 @@ proc semFor(c: PContext, n: PNode; flags: TExprFlags): PNode =
result = semForVars(c, n, flags)
# propagate any enforced VoidContext:
if n[^1].typ == c.enforceVoidContext:
result.typ = c.enforceVoidContext
result.typ() = c.enforceVoidContext
elif efInTypeof in flags:
result.typ = result.lastSon.typ
result.typ() = result.lastSon.typ
closeScope(c)
proc semCase(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil): PNode =
@@ -1401,14 +1400,14 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil
for i in 1..<n.len: discardCheck(c, n[i].lastSon, flags)
# propagate any enforced VoidContext:
if typ == c.enforceVoidContext:
result.typ = c.enforceVoidContext
result.typ() = c.enforceVoidContext
else:
for i in 1..<n.len:
var it = n[i]
let j = it.len-1
if not endsInNoReturn(it[j]):
it[j] = fitNode(c, typ, it[j], it[j].info)
result.typ = typ
result.typ() = typ
proc semRaise(c: PContext, n: PNode): PNode =
result = n
@@ -1459,7 +1458,7 @@ proc typeDefLeftSidePass(c: PContext, typeSection: PNode, i: int) =
onDef(name[1].info, s)
s.typ = newTypeS(tyObject, c)
s.typ.sym = s
s.incl sfForward
s.flags.incl sfForward
c.graph.packageTypes.strTableAdd s
addInterfaceDecl(c, s)
elif typsym.kind == skType and sfForward in typsym.flags:
@@ -1550,7 +1549,7 @@ proc checkCovariantParamsUsages(c: PContext; genericType: PType) =
case t.kind
of tyGenericParam:
t.incl tfWeakCovariant
t.flags.incl tfWeakCovariant
return true
of tyObject:
for field in t.n:
@@ -1576,7 +1575,7 @@ proc checkCovariantParamsUsages(c: PContext; genericType: PType) =
error("covariant param '" & param.sym.name.s &
"' used in a non-covariant position")
elif tfWeakCovariant in formalFlags:
param.incl tfWeakCovariant
param.flags.incl tfWeakCovariant
result = true
elif tfContravariant in param.flags:
let formalParam = targetBody[i-1].sym
@@ -1668,11 +1667,11 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
body.size = -1 # could not be computed properly
if body.kind == tyObject:
# add flags applied to generic type to object (nominal) type
incl(body, oldFlags)
incl(body.flags, oldFlags)
# {.inheritable, final.} is already disallowed, but
# object might have been assumed to be final
if tfInheritable in oldFlags and tfFinal in body.flags:
excl(body, tfFinal)
excl(body.flags, tfFinal)
s.typ[^1] = body
if tfCovariant in s.typ.flags:
checkCovariantParamsUsages(c, s.typ)
@@ -1721,7 +1720,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
# flag might be copied from alias/instantiation:
let t = body.skipTypes({tyAlias, tyGenericInst})
if not (t.kind == tyDistinct and tfBorrowDot in t.flags):
excl s.typ, tfBorrowDot
excl s.typ.flags, tfBorrowDot
localError(c.config, name.info, "only a 'distinct' type can borrow `.`")
let aa = a[2]
if aa.kind in {nkRefTy, nkPtrTy} and aa.len == 1 and
@@ -1731,17 +1730,17 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
if st.kind == tyGenericBody: st = st.typeBodyImpl
internalAssert c.config, st.kind in {tyPtr, tyRef}
internalAssert c.config, st.last.sym == nil
incl st, tfRefsAnonObj
incl st.flags, tfRefsAnonObj
let objTy = st.last
# add flags for `ref object` etc to underlying `object`
incl(objTy, oldFlags)
incl(objTy.flags, oldFlags)
# {.inheritable, final.} is already disallowed, but
# object might have been assumed to be final
if tfInheritable in oldFlags and tfFinal in objTy.flags:
excl(objTy, tfFinal)
excl(objTy.flags, tfFinal)
let obj = newSym(skType, getIdent(c.cache, s.name.s & ":ObjectType"),
c.idgen, getCurrOwner(c), s.info)
obj.flagsImpl.incl sfGeneratedType
obj.flags.incl sfGeneratedType
let symNode = newSymNode(obj)
obj.ast = a.shallowCopy
case a[0].kind
@@ -1763,7 +1762,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
obj.ast[1] = a[1]
obj.ast[2] = a[2][0]
if sfPure in s.flags:
obj.incl sfPure
obj.flags.incl sfPure
obj.typ = objTy
objTy.sym = obj
@@ -1845,13 +1844,6 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
let baseType = s.typ.safeSkipTypes(abstractPtrs)
if baseType.kind in {tyObject, tyTuple} and not baseType.n.isNil:
checkForMetaFields(c, baseType.n, hasError)
if s.typ.kind in {tySet, tyArray, tySequence, tyUncheckedArray} and s.typ.elementType.kind == tyNone:
# magic generics are not filled but tyNone is added to its elements by default,
# we lift them to tyBuiltInTypeClass here
s.typ = newTypeS(tyBuiltInTypeClass, c,
newTypeS(s.typ.kind, c))
if not hasError:
checkConstructedType(c.config, s.info, s.typ)
#instAllTypeBoundOp(c, n.info)
@@ -1961,7 +1953,7 @@ proc addResult(c: PContext, n: PNode, t: PType, owner: TSymKind) =
var s = newSym(skResult, getIdent(c.cache, "result"), c.idgen,
getCurrOwner(c), n.info)
s.typ = t
incl(s.flagsImpl, sfUsed)
incl(s.flags, sfUsed)
if owner == skMacro or t != nil:
if n.len > resultPos and n[resultPos] != nil:
@@ -2066,7 +2058,7 @@ proc semInferredLambda(c: PContext, pt: LayeredIdTable, n: PNode): PNode =
popOwner(c)
closeScope(c)
if optOwnedRefs in c.config.globalOptions and result.typ != nil:
result.typ = makeVarType(c, result.typ, tyOwned)
result.typ() = makeVarType(c, result.typ, tyOwned)
# alternative variant (not quite working):
# var prc = arg[0].sym
# let inferred = c.semGenerateInstance(c, prc, m.bindings, arg.info)
@@ -2137,7 +2129,7 @@ proc bindDupHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
if cond:
var obj = t.firstParamType
while true:
incl(obj, tfHasAsgn)
incl(obj.flags, tfHasAsgn)
if obj.kind in {tyGenericBody, tyGenericInst}: obj = obj.skipModifier
elif obj.kind == tyGenericInvocation: obj = obj.genericHead
else: break
@@ -2166,8 +2158,8 @@ proc bindDupHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
localError(c.config, n.info, errGenerated,
"signature for '=dup' must be proc[T: object](x: T): T")
incl(s.flagsImpl, sfUsed)
incl(s, sfOverridden)
incl(s.flags, sfUsed)
incl(s.flags, sfOverridden)
proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
let t = s.typ
@@ -2175,7 +2167,7 @@ proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
template notRefc: bool =
# fixes refc with non-var destructor; cancel warnings (#23156)
c.config.backend == backendJs or
c.config.selectedGC in {gcArc, gcAtomicArc, gcOrc, gcYrc}
c.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}
let cond = case op
of attachedWasMoved:
t.len == 2 and t.returnType == nil and t.firstParamType.kind == tyVar
@@ -2192,7 +2184,7 @@ proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
if cond:
var obj = t.firstParamType.skipTypes({tyVar})
while true:
incl(obj, tfHasAsgn)
incl(obj.flags, tfHasAsgn)
if obj.kind in {tyGenericBody, tyGenericInst}: obj = obj.skipModifier
elif obj.kind == tyGenericInvocation: obj = obj.genericHead
else: break
@@ -2224,8 +2216,8 @@ proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
else:
localError(c.config, n.info, errGenerated,
"signature for '" & s.name.s & "' must be proc[T: object](x: var T)")
incl(s.flagsImpl, sfUsed)
incl(s, sfOverridden)
incl(s.flags, sfUsed)
incl(s.flags, sfOverridden)
proc semOverride(c: PContext, s: PSym, n: PNode) =
let name = s.name.s.normalize
@@ -2265,19 +2257,19 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
else:
localError(c.config, n.info, errGenerated,
"signature for 'deepCopy' must be proc[T: ptr|ref](x: T): T")
incl(s.flagsImpl, sfUsed)
incl(s, sfOverridden)
incl(s.flags, sfUsed)
incl(s.flags, sfOverridden)
of "=", "=copy", "=sink":
if s.magic == mAsgn: return
incl(s.flagsImpl, sfUsed)
incl(s, sfOverridden)
incl(s.flags, sfUsed)
incl(s.flags, sfOverridden)
if name == "=":
message(c.config, n.info, warnDeprecated, "Overriding `=` hook is deprecated; Override `=copy` hook instead")
let t = s.typ
if t.len == 3 and t.returnType == nil and t.firstParamType.kind == tyVar:
var obj = t.firstParamType.elementType
while true:
incl(obj, tfHasAsgn)
incl(obj.flags, tfHasAsgn)
if obj.kind == tyGenericBody: obj = obj.skipModifier
elif obj.kind == tyGenericInvocation: obj = obj.genericHead
else: break
@@ -2368,7 +2360,7 @@ proc semCppMember(c: PContext; s: PSym; n: PNode) =
typ = typ.elementType
if typ.kind != tyObject:
localError(c.config, n.info, pragmaName & " must be either ptr to object or object type.")
if sameOwners(typ.owner, s.owner) and sameOwners(c.module, s.owner):
if typ.owner.id == s.owner.id and c.module.id == s.owner.id:
c.graph.memberProcsPerType.mgetOrPut(typ.itemId, @[]).add s
else:
localError(c.config, n.info,
@@ -2436,8 +2428,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
case n[namePos].kind
of nkEmpty:
s = newSym(kind, c.cache.idAnon, c.idgen, c.getCurrOwner, n.info)
s.flagsImpl.incl sfUsed
s.incl sfGenSym
s.flags.incl sfUsed
s.flags.incl sfGenSym
n[namePos] = newSymNode(s)
of nkSym:
s = n[namePos].sym
@@ -2463,7 +2455,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
#s.scope = c.currentScope
if s.kind in {skMacro, skTemplate}:
# push noalias flag at first to prevent unwanted recursive calls:
incl(s, sfNoalias)
incl(s.flags, sfNoalias)
# before compiling the proc params & body, set as current the scope
# where the proc was declared
@@ -2501,14 +2493,14 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
n[genericParamsPos] = n[miscPos][1]
n[miscPos] = c.graph.emptyNode
if tfTriggersCompileTime in s.typ.flags: incl(s, sfCompileTime)
if tfTriggersCompileTime in s.typ.flags: incl(s.flags, sfCompileTime)
if n[patternPos].kind != nkEmpty:
n[patternPos] = semPattern(c, n[patternPos], s)
if s.kind == skIterator:
s.typ.incl(tfIterator)
s.typ.flags.incl(tfIterator)
elif s.kind == skFunc:
incl(s, sfNoSideEffect)
incl(s.typ, tfNoSideEffect)
incl(s.flags, sfNoSideEffect)
incl(s.typ.flags, tfNoSideEffect)
var (proto, comesFromShadowScope) =
if isAnon: (nil, false)
@@ -2554,7 +2546,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
if n[pragmasPos].kind != nkEmpty and sfBorrow notin s.flags:
setEffectsForProcType(c.graph, s.typ, n[pragmasPos], s)
s.typ.incl tfEffectSystemWorkaround
s.typ.flags.incl tfEffectSystemWorkaround
# To ease macro generation that produce forwarded .async procs we now
# allow a bit redundancy in the pragma declarations. The rule is
@@ -2581,8 +2573,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
if sfForward notin proto.flags and proto.magic == mNone:
wrongRedefinition(c, n.info, proto.name.s, proto.info)
if not comesFromShadowScope:
excl(proto, sfForward)
incl(proto, sfWasForwarded)
excl(proto.flags, sfForward)
incl(proto.flags, sfWasForwarded)
suggestSym(c.graph, s.info, proto, c.graph.usageSym)
closeScope(c) # close scope with wrong parameter symbols
openScope(c) # open scope for old (correct) parameter symbols
@@ -2663,7 +2655,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
# we need to add a result symbol for them
maybeAddResult(c, s, n)
trackProc(c, s, s.ast[bodyPos])
else:
if (s.typ.returnType != nil and s.kind != skIterator):
@@ -2684,8 +2676,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
if s.kind in {skProc, skFunc} and s.typ.returnType != nil and s.typ.returnType.kind == tyAnything:
localError(c.config, n[paramsPos][0].info, "return type 'auto' cannot be used in forward declarations")
incl(s, sfForward)
incl(s, sfWasForwarded)
incl(s.flags, sfForward)
incl(s.flags, sfWasForwarded)
elif sfBorrow in s.flags: semBorrow(c, n, s)
sideEffectsCheck(c, s)
@@ -2696,9 +2688,9 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
c.patterns.add(s)
if isAnon:
n.transitionSonsKind(nkLambda)
result.typ = s.typ
result.typ() = s.typ
if optOwnedRefs in c.config.globalOptions:
result.typ = makeVarType(c, result.typ, tyOwned)
result.typ() = makeVarType(c, result.typ, tyOwned)
elif isTopLevel(c) and s.kind != skIterator and s.typ.callConv == ccClosure:
localError(c.config, s.info, "'.closure' calling convention for top level routines is invalid")
@@ -2732,13 +2724,13 @@ proc semIterator(c: PContext, n: PNode): PNode =
# we require first class iterators to be marked with 'closure' explicitly
# -- at least for 0.9.2.
if s.typ.callConv == ccClosure:
incl(s.typ, tfCapturesEnv)
incl(s.typ.flags, tfCapturesEnv)
else:
s.typ.callConv = ccInline
if result[bodyPos].kind == nkEmpty and s.magic == mNone and c.inConceptDecl == 0:
localError(c.config, n.info, errImplOfXexpected % s.name.s)
if optOwnedRefs in c.config.globalOptions and result.typ != nil:
result.typ = makeVarType(c, result.typ, tyOwned)
result.typ() = makeVarType(c, result.typ, tyOwned)
result.typ.callConv = ccClosure
proc semProc(c: PContext, n: PNode): PNode =
@@ -2783,7 +2775,7 @@ proc semConverterDef(c: PContext, n: PNode): PNode =
var t = s.typ
if t.returnType == nil: localError(c.config, n.info, errXNeedsReturnType % "converter")
if t.len != 2: localError(c.config, n.info, "a converter takes exactly one argument")
addConverterDef(c, s)
addConverterDef(c, LazySym(sym: s))
proc semMacroDef(c: PContext, n: PNode): PNode =
result = semProcAux(c, n, skMacro, macroPragmas)
@@ -2802,14 +2794,14 @@ proc semMacroDef(c: PContext, n: PNode): PNode =
if param.typ.kind != tyUntyped: allUntyped = false
# no default value, parameters required in call
if param.ast == nil: nullary = false
if allUntyped: incl(s, sfAllUntyped)
if allUntyped: incl(s.flags, sfAllUntyped)
if nullary and n[genericParamsPos].kind == nkEmpty:
# macro can be called with alias syntax, remove pushed noalias flag
excl(s, sfNoalias)
excl(s.flags, sfNoalias)
if n[bodyPos].kind == nkEmpty:
localError(c.config, n.info, errImplOfXexpected % s.name.s)
proc incMod(c: PContext, n: PNode, it: PNode, includeStmtResult, resolvedIncStmt: PNode) =
proc incMod(c: PContext, n: PNode, it: PNode, includeStmtResult: PNode) =
var f = checkModuleName(c.config, it)
if f != InvalidFileIdx:
addIncludeFileDep(c, f)
@@ -2817,22 +2809,12 @@ proc incMod(c: PContext, n: PNode, it: PNode, includeStmtResult, resolvedIncStmt
if containsOrIncl(c.includedFiles, f.int):
localError(c.config, n.info, errRecursiveDependencyX % toMsgFilename(c.config, f))
else:
if resolvedIncStmt != nil:
resolvedIncStmt.add newStrNode(toFullPath(c.config, f), it.info)
includeStmtResult.add semStmt(c, c.graph.includeFileCallback(c.graph, c.module, f), {})
excl(c.includedFiles, f.int)
proc evalInclude(c: PContext, n: PNode): PNode =
result = newNodeI(nkStmtList, n.info)
var resolvedIncStmt: PNode = nil
if optCompress in c.config.globalOptions:
# New resolve the include filenames to string literals that contain absolute paths,
# nicer for IC:
resolvedIncStmt = newNodeI(nkIncludeStmt, n.info)
result.add resolvedIncStmt
else:
# Legacy: Keep `include` statement as is:
result.add n
result.add n
template checkAs(it: PNode) =
if it.kind == nkInfix and it.len == 3:
let op = it[0].getPIdent
@@ -2850,9 +2832,9 @@ proc evalInclude(c: PContext, n: PNode): PNode =
for x in it[lastPos]:
checkAs(x)
imp[lastPos] = x
incMod(c, n, imp, result, resolvedIncStmt)
incMod(c, n, imp, result)
else:
incMod(c, n, it, result, resolvedIncStmt)
incMod(c, n, it, result)
proc recursiveSetFlag(n: PNode, flag: TNodeFlag) =
if n != nil:
@@ -2894,7 +2876,7 @@ proc semPragmaBlock(c: PContext, n: PNode; expectedType: PType = nil): PNode =
n[1] = semExpr(c, n[1], expectedType = expectedType)
dec c.inUncheckedAssignSection, inUncheckedAssignSection
result = n
result.typ = n[1].typ
result.typ() = n[1].typ
for i in 0..<pragmaList.len:
case whichPragma(pragmaList[i])
of wLine: setInfoRecursive(result, pragmaList[i].info)
@@ -2981,14 +2963,14 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType =
else: discard
if n[i].typ == c.enforceVoidContext: #or usesResult(n[i]):
voidContext = true
n.typ = c.enforceVoidContext
n.typ() = c.enforceVoidContext
if i == last and (n.len == 1 or ({efWantValue, efInTypeof} * flags != {})):
n.typ = n[i].typ
n.typ() = n[i].typ
if not isEmptyType(n.typ): n.transitionSonsKind(nkStmtListExpr)
elif i != last or voidContext:
discardCheck(c, n[i], flags)
else:
n.typ = n[i].typ
n.typ() = n[i].typ
if not isEmptyType(n.typ): n.transitionSonsKind(nkStmtListExpr)
var m = n[i]
while m.kind in {nkStmtListExpr, nkStmtList} and m.len > 0: # from templates

View File

@@ -68,7 +68,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule;
if not isField or sfGenSym notin s.flags:
result = newSymNode(s, info)
# possibly not final field sym
incl(s.flagsImpl, sfUsed)
incl(s.flags, sfUsed)
markOwnerModuleAsUsed(c, s)
onUse(info, s)
else:
@@ -85,7 +85,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule;
a = initOverloadIter(o, c, n)
while a != nil:
if a.kind != skModule and (not isField or sfGenSym notin a.flags):
incl(a.flagsImpl, sfUsed)
incl(a.flags, sfUsed)
markOwnerModuleAsUsed(c, a)
result.add newSymNode(a, info)
onUse(info, a)
@@ -180,7 +180,8 @@ proc semTemplBodyScope(c: var TemplCtx, n: PNode): PNode =
proc newGenSym(kind: TSymKind, n: PNode, c: var TemplCtx): PSym =
result = newSym(kind, considerQuotedIdent(c.c, n), c.c.idgen, c.owner, n.info)
incl(result.flagsImpl, {sfGenSym, sfShadowed})
incl(result.flags, sfGenSym)
incl(result.flags, sfShadowed)
proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
# locals default to 'gensym', fields default to 'inject':
@@ -217,10 +218,10 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
onDef(n.info, local)
replaceIdentBySym(c.c, n, newSymNode(local, n.info))
if k == skParam and c.inTemplateHeader > 0:
local.incl sfTemplateParam
local.flags.incl sfTemplateParam
proc semTemplSymbol(c: var TemplCtx, n: PNode, s: PSym; isField, isAmbiguous: bool): PNode =
incl(s.flagsImpl, sfUsed)
incl(s.flags, sfUsed)
# bug #12885; ideally sem'checking is performed again afterwards marking
# the symbol as used properly, but the nfSem mechanism currently prevents
# that from happening, so we mark the module as used here already:
@@ -238,10 +239,10 @@ proc semTemplSymbol(c: var TemplCtx, n: PNode, s: PSym; isField, isAmbiguous: bo
if result.kind == nkSym:
result = newOpenSym(result)
else:
result.typ = nil
result.typ() = nil
else:
result.flags.incl nfDisabledOpenSym
result.typ = nil
result.typ() = nil
of skGenericParam:
if isField and sfGenSym in s.flags: result = n
else:
@@ -251,7 +252,7 @@ proc semTemplSymbol(c: var TemplCtx, n: PNode, s: PSym; isField, isAmbiguous: bo
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
result.typ = nil
result.typ() = nil
of skParam:
result = n
of skType:
@@ -269,10 +270,10 @@ proc semTemplSymbol(c: var TemplCtx, n: PNode, s: PSym; isField, isAmbiguous: bo
if result.kind == nkSym:
result = newOpenSym(result)
else:
result.typ = nil
result.typ() = nil
else:
result.flags.incl nfDisabledOpenSym
result.typ = nil
result.typ() = nil
else:
if isField and sfGenSym in s.flags: result = n
else:
@@ -282,7 +283,7 @@ proc semTemplSymbol(c: var TemplCtx, n: PNode, s: PSym; isField, isAmbiguous: bo
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
result.typ = nil
result.typ() = nil
# Issue #12832
when defined(nimsuggest):
suggestSym(c.c.graph, n.info, s, c.c.graph.usageSym, false)
@@ -297,7 +298,7 @@ proc semRoutineInTemplName(c: var TemplCtx, n: PNode, explicitInject: bool): PNo
if s != nil:
if s.owner == c.owner and (s.kind == skParam or
(sfGenSym in s.flags and not explicitInject)):
incl(s.flagsImpl, sfUsed)
incl(s.flags, sfUsed)
result = newSymNode(s, n.info)
onUse(n.info, s)
else:
@@ -383,7 +384,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
let s = qualifiedLookUp(c.c, n, {})
if s != nil:
if s.owner == c.owner and s.kind == skParam and sfTemplateParam in s.flags:
incl(s.flagsImpl, sfUsed)
incl(s.flags, sfUsed)
result = newSymNode(s, n.info)
onUse(n.info, s)
elif contains(c.toBind, s.id):
@@ -393,7 +394,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
elif s.owner == c.owner and sfGenSym in s.flags and c.noGenSym == 0:
# template tmp[T](x: var seq[T]) =
# var yz: T
incl(s.flagsImpl, sfUsed)
incl(s.flags, sfUsed)
result = newSymNode(s, n.info)
onUse(n.info, s)
else:
@@ -544,7 +545,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
let x = n[i]
let prag = whichPragma(x)
if prag == wInvalid:
# only sem if not a language-level pragma
# only sem if not a language-level pragma
result[i] = semTemplBody(c, x)
elif x.kind in nkPragmaCallKinds:
# is pragma, but value still needs to be checked
@@ -607,7 +608,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
# do not symchoice a quoted template parameter (bug #2390):
if s.owner == c.owner and s.kind == skParam and
n.kind == nkAccQuoted and n.len == 1:
incl(s.flagsImpl, sfUsed)
incl(s.flags, sfUsed)
onUse(n.info, s)
return newSymNode(s, n.info)
elif contains(c.toBind, s.id):
@@ -687,7 +688,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
var s: PSym
if isTopLevel(c):
s = semIdentVis(c, skTemplate, n[namePos], {sfExported})
incl(s, sfGlobal)
incl(s.flags, sfGlobal)
else:
s = semIdentVis(c, skTemplate, n[namePos], {})
assert s.kind == skTemplate
@@ -700,7 +701,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
# check parameter list:
#s.scope = c.currentScope
# push noalias flag at first to prevent unwanted recursive calls:
incl(s, sfNoalias)
incl(s.flags, sfNoalias)
pushOwner(c, s)
openScope(c)
n[namePos] = newSymNode(s)
@@ -723,8 +724,8 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
for i in 1..<s.typ.n.len:
let param = s.typ.n[i].sym
if param.name.id != ord(wUnderscore):
param.incl sfTemplateParam
param.excl sfGenSym
param.flags.incl sfTemplateParam
param.flags.excl sfGenSym
if param.typ.kind != tyUntyped: allUntyped = false
# no default value, parameters required in call
if param.ast == nil: nullary = false
@@ -738,12 +739,12 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
# restore original generic type params as no explicit or implicit were found
n[genericParamsPos] = n[miscPos][1]
n[miscPos] = c.graph.emptyNode
if allUntyped: incl(s, sfAllUntyped)
if allUntyped: incl(s.flags, sfAllUntyped)
if nullary and
n[genericParamsPos].kind == nkEmpty and
n[bodyPos].kind != nkEmpty:
# template can be called with alias syntax, remove pushed noalias flag
excl(s, sfNoalias)
excl(s.flags, sfNoalias)
if n[patternPos].kind != nkEmpty:
n[patternPos] = semPattern(c, n[patternPos], s)
@@ -800,7 +801,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
# macros because they have a shadowed param of type 'PNimNode' (see
# semtypes.addParamOrResult). Within the pattern we have to ensure
# to use the param with the proper type though:
incl(s.flagsImpl, sfUsed)
incl(s.flags, sfUsed)
onUse(n.info, s)
let x = c.owner.typ.n[s.position+1].sym
assert x.name == s.name
@@ -925,4 +926,4 @@ proc semPattern(c: PContext, n: PNode; s: PSym): PNode =
elif result.len == 0:
localError(c.config, n.info, "a pattern cannot be empty")
closeScope(c)
addPattern(c, s)
addPattern(c, LazySym(sym: s))

View File

@@ -62,7 +62,7 @@ proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType =
proc newConstraint(c: PContext, k: TTypeKind): PType =
result = newTypeS(tyBuiltInTypeClass, c)
result.incl tfCheckedForDestructor
result.flags.incl tfCheckedForDestructor
result.addSonSkipIntLit(newTypeS(k, c), c.idgen)
proc skipGenericPrev(prev: PType): PType =
@@ -151,7 +151,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
if i != 1:
if x != counter:
needsReorder = true
incl(result, tfEnumHasHoles)
incl(result.flags, tfEnumHasHoles)
e.ast = strVal # might be nil
counter = x
of nkSym:
@@ -184,7 +184,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
identToReplace[] = symNode
if e.position == 0: hasNull = true
if result.sym != nil and sfExported in result.sym.flags:
e.incl {sfUsed, sfExported}
e.flags.incl {sfUsed, sfExported}
result.n.add symNode
styleCheckDef(c, e)
@@ -210,9 +210,9 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
)
if isPure and sfExported in result.sym.flags:
addPureEnum(c, result.sym)
addPureEnum(c, LazySym(sym: result.sym))
if tfNotNil in e.typ.flags and not hasNull:
result.incl tfRequiresInit
result.flags.incl tfRequiresInit
setToStringProc(c.graph, result, genEnumToStrProc(result, n.info, c.graph, c.idgen))
proc semSet(c: PContext, n: PNode, prev: PType): PType =
@@ -378,7 +378,7 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
for i in 0..1:
if hasUnresolvedArgs(c, range[i]):
result.n.add makeStaticExpr(c, range[i])
result.incl tfUnresolved
result.flags.incl tfUnresolved
else:
result.n.add semConstExpr(c, range[i])
@@ -398,15 +398,15 @@ proc semRange(c: PContext, n: PNode, prev: PType): PType =
if not isDefined(c.config, "nimPreviewRangeDefault"):
let n = result.n
if n[0].kind in {nkCharLit..nkUInt64Lit} and n[0].intVal > 0:
incl(result, tfRequiresInit)
incl(result.flags, tfRequiresInit)
elif n[1].kind in {nkCharLit..nkUInt64Lit} and n[1].intVal < 0:
incl(result, tfRequiresInit)
incl(result.flags, tfRequiresInit)
elif n[0].kind in {nkFloatLit..nkFloat64Lit} and
n[0].floatVal > 0.0:
incl(result, tfRequiresInit)
incl(result.flags, tfRequiresInit)
elif n[1].kind in {nkFloatLit..nkFloat64Lit} and
n[1].floatVal < 0.0:
incl(result, tfRequiresInit)
incl(result.flags, tfRequiresInit)
else:
if n[1].kind == nkInfix and considerQuotedIdent(c, n[1][0]).s == "..<":
localError(c.config, n[0].info, "range types need to be constructed with '..', '..<' is not supported")
@@ -453,10 +453,10 @@ proc semArrayIndex(c: PContext, n: PNode): PType =
let info = if n.safeLen > 1: n[1].info else: n.info
localError(c.config, info, errOrdinalTypeExpected % typeToString(e.typ, preferDesc))
result = makeRangeWithStaticExpr(c, e)
if c.inGenericContext > 0: result.incl tfUnresolved
if c.inGenericContext > 0: result.flags.incl tfUnresolved
else:
result = e.typ.skipTypes({tyTypeDesc})
result.incl tfImplicitStatic
result.flags.incl tfImplicitStatic
elif e.kind in (nkCallKinds + {nkBracketExpr}) and hasUnresolvedArgs(c, e):
if not isOrdinalType(e.typ.skipTypes({tyStatic, tyAlias, tyGenericInst, tySink})):
localError(c.config, n[1].info, errOrdinalTypeExpected % typeToString(e.typ, preferDesc))
@@ -535,7 +535,7 @@ proc firstRange(config: ConfigRef, t: PType): PNode =
result = newFloatNode(nkFloatLit, firstFloat(t))
else:
result = newIntNode(nkIntLit, firstOrd(config, t))
result.typ = t
result.typ() = t
proc semTuple(c: PContext, n: PNode, prev: PType): PType =
var typ: PType
@@ -556,7 +556,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
typ = a[^1].typ
else:
fitDefaultNode(c, a[^1], typ)
typ = a[^1].typ.skipIntLit(c.idgen)
typ = a[^1].typ
elif a[^2].kind != nkEmpty:
typ = semTypeNode(c, a[^2], nil)
if c.graph.config.isDefined("nimPreviewRangeDefault") and typ.skipTypes(abstractInst).kind == tyRange:
@@ -595,7 +595,7 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
result = newSymG(kind, n[1], c)
var v = considerQuotedIdent(c, n[0])
if sfExported in allowed and v.id == ord(wStar):
incl(result, sfExported)
incl(result.flags, sfExported)
else:
if not (sfExported in allowed):
localError(c.config, n[0].info, errXOnlyAtModuleScope % "export")
@@ -805,7 +805,7 @@ proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
if a[0].kind != nkSym:
internalError(c.config, "semRecordCase: discriminant is no symbol")
return
incl(a[0].sym, sfDiscriminant)
incl(a[0].sym.flags, sfDiscriminant)
var covered = toInt128(0)
var chckCovered = false
var typ = skipTypes(a[0].typ, abstractVar-{tyTypeDesc})
@@ -928,7 +928,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
typ = n[^1].typ
else:
fitDefaultNode(c, n[^1], typ)
typ = n[^1].typ.skipIntLit(c.idgen)
typ = n[^1].typ
propagateToOwner(rectype, typ)
elif n[^2].kind == nkEmpty:
localError(c.config, n.info, errTypeExpected)
@@ -958,9 +958,8 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
if fieldOwner != nil and
{sfImportc, sfExportc} * fieldOwner.flags != {} and
not hasCaseFields and f.loc.snippet == "":
ensureMutable f
f.locImpl.snippet = rope(f.name.s)
f.incl {sfImportc, sfExportc} * fieldOwner.flags
f.loc.snippet = rope(f.name.s)
f.flags.incl {sfImportc, sfExportc} * fieldOwner.flags
inc(pos)
if containsOrIncl(check, f.name.id):
localError(c.config, info, "attempt to redefine: '" & f.name.s & "'")
@@ -1014,7 +1013,7 @@ proc skipGenericInvocation(t: PType): PType {.inline.} =
proc tryAddInheritedFields(c: PContext, check: var IntSet, pos: var int,
obj: PType, n: PNode, isPartial = false, innerObj: PType = nil): bool =
if ((not isPartial) and (obj.kind notin {tyObject, tyGenericParam} or tfFinal in obj.flags)) or
(innerObj != nil and obj.id == innerObj.id):
(innerObj != nil and obj.sym.id == innerObj.sym.id):
localError(c.config, n.info, "Cannot inherit from: '" & $obj & "'")
result = false
elif obj.kind == tyObject:
@@ -1075,8 +1074,8 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType; flags: TTypeFlags): PType
c.forwardTypeUpdates.add (result, n) # we retry in the final pass
rawAddSon(result, realBase)
if realBase == nil and tfInheritable in flags:
result.incl tfInheritable
if tfAcyclic in flags: result.incl tfAcyclic
result.flags.incl tfInheritable
if tfAcyclic in flags: result.flags.incl tfAcyclic
if result.n.isNil:
result.n = newNodeI(nkRecList, n.info)
else:
@@ -1091,9 +1090,9 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType; flags: TTypeFlags): PType
s.typ = result
pragma(c, s, n[0], typePragmas)
if base == nil and tfInheritable notin result.flags:
incl(result, tfFinal)
incl(result.flags, tfFinal)
if c.inGenericContext == 0 and computeRequiresInit(c, result):
result.incl tfRequiresInit
result.flags.incl tfRequiresInit
proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
if n.len < 1:
@@ -1136,22 +1135,22 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
addSonSkipIntLit(result, region, c.idgen)
addSonSkipIntLit(result, t, c.idgen)
if tfPartial in result.flags:
if result.elementType.kind == tyObject: incl(result.elementType, tfPartial)
if result.elementType.kind == tyObject: incl(result.elementType.flags, tfPartial)
# if not isNilable: result.flags.incl tfNotNil
case wrapperKind
of tyOwned:
if optOwnedRefs in c.config.globalOptions:
let t = newTypeS(tyOwned, c, result)
t.incl tfHasOwned
t.flags.incl tfHasOwned
result = t
of tySink:
let t = newTypeS(tySink, c, result)
result = t
else: discard
if result.kind == tyRef and
c.config.selectedGC in {gcArc, gcOrc, gcAtomicArc, gcYrc} and
if result.kind == tyRef and
c.config.selectedGC in {gcArc, gcOrc, gcAtomicArc} and
tfTriggersCompileTime notin result.flags:
result.incl tfHasAsgn
result.flags.incl tfHasAsgn
proc findEnforcedStaticType(t: PType): PType =
# This handles types such as `static[T] and Foo`,
@@ -1203,23 +1202,15 @@ proc addImplicitGeneric(c: PContext; typeClass: PType, typId: PIdent;
# is this a bindOnce type class already present in the param list?
for i in 0..<genericParams.len:
if genericParams[i].sym.name.id == finalTypId.id:
if typeClass.kind == tyStatic and genericParams[i].typ.kind != tyStatic:
# The base type (e.g. from `auto`) was already added as a generic param,
# but `static[auto]` requires upgrading it to a `tyStatic` wrapper so
# it is instantiated as a compile-time value (`skConst`).
genericParams[i].sym.linkTo(typeClass)
typeClass.incl tfImplicitTypeParam
return typeClass
else:
return genericParams[i].typ
return genericParams[i].typ
let owner = if typeClass.sym != nil: typeClass.sym
else: getCurrOwner(c)
var s = newSym(skType, finalTypId, c.idgen, owner, info)
if sfExplain in owner.flags: s.incl sfExplain
if typId == nil: s.incl(sfAnon)
if sfExplain in owner.flags: s.flags.incl sfExplain
if typId == nil: s.flags.incl(sfAnon)
s.linkTo(typeClass)
typeClass.incl tfImplicitTypeParam
typeClass.flags.incl tfImplicitTypeParam
s.position = genericParams.len
genericParams.add newSymNode(s)
result = typeClass
@@ -1252,7 +1243,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
localError(c.config, info, errMacroBodyDependsOnGenericTypes % paramName)
result = addImplicitGeneric(c, newTypeS(tyStatic, c, base),
paramTypId, info, genericParams, paramName)
if result != nil: result.incl({tfHasStatic, tfUnresolved})
if result != nil: result.flags.incl({tfHasStatic, tfUnresolved})
of tyTypeDesc:
if tfUnresolved notin paramType.flags:
@@ -1263,7 +1254,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
# XXX Why doesn't this check for tyTypeDesc instead?
paramTypId = nil
let t = newTypeS(tyTypeDesc, c, paramType.base)
incl t, tfCheckedForDestructor
incl t.flags, tfCheckedForDestructor
result = addImplicitGeneric(c, t, paramTypId, info, genericParams, paramName)
else:
result = nil
@@ -1313,7 +1304,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
for i in 0..<paramType.len - 1:
if paramType[i].kind == tyStatic:
var staticCopy = paramType[i].exactReplica
staticCopy.incl tfInferrableStatic
staticCopy.flags.incl tfInferrableStatic
result.rawAddSon staticCopy
else:
result.rawAddSon newTypeS(tyAnything, c)
@@ -1351,7 +1342,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
let liftBody = recurse(paramType.skipModifier, true)
if liftBody != nil:
result = liftBody
result.incl tfHasMeta
result.flags.incl tfHasMeta
#result.shouldHaveMeta
of tyGenericInvocation:
@@ -1382,7 +1373,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
markUsed(c, paramType.sym.info, paramType.sym)
onUse(paramType.sym.info, paramType.sym)
if tfWildcard in paramType.flags:
paramType.excl tfWildcard
paramType.flags.excl tfWildcard
paramType.sym.transitionGenericParamToType()
else: result = nil
@@ -1478,7 +1469,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
elif hasUnresolvedArgs(c, def):
# template default value depends on other parameter
# don't do any typechecking
def.typ = makeTypeFromExpr(c, def.copyTree)
def.typ() = makeTypeFromExpr(c, def.copyTree)
break determineType
elif typ != nil and typ.kind == tyTyped:
canBeVoid = true
@@ -1505,7 +1496,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
# surprising behavior. We must instead fix the expected type of
# the proc to be the unbound typedesc type:
typ = newTypeS(tyTypeDesc, c, newTypeS(tyNone, c))
typ.incl tfCheckedForDestructor
typ.flags.incl tfCheckedForDestructor
elif def.typ != nil and def.typ.kind != tyFromExpr: # def.typ can be void
# if def.typ != nil and def.typ.kind != tyNone:
@@ -1530,7 +1521,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
for j in 0..<a.len-2:
var arg = newSymG(skParam, if a[j].kind == nkPragmaExpr: a[j][0] else: a[j], c)
if arg.name.id == ord(wUnderscore):
arg.incl(sfGenSym)
arg.flags.incl(sfGenSym)
elif containsOrIncl(check, arg.name.id):
localError(c.config, a[j].info, "attempt to redefine: '" & arg.name.s & "'")
if a[j].kind == nkPragmaExpr:
@@ -1596,7 +1587,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
# 'auto' as a return type does not imply a generic:
elif r.kind == tyAnything:
r = copyType(r, c.idgen, r.owner)
r.incl tfRetType
r.flags.incl tfRetType
elif r.kind == tyStatic:
# type allowed should forbid this type
discard
@@ -1608,13 +1599,13 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
r = lifted
#if r.kind != tyGenericParam:
#echo "came here for ", typeToString(r)
r.incl tfRetType
r.flags.incl tfRetType
r = skipIntLit(r, c.idgen)
if kind == skIterator:
# see tchainediterators
# in cases like iterator foo(it: iterator): typeof(it)
# we don't need to change the return type to iter[T]
result.incl tfIterator
result.flags.incl tfIterator
# XXX Would be nice if we could get rid of this
result[0] = r
let oldFlags = result.flags
@@ -1622,17 +1613,17 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
if oldFlags != result.flags:
# XXX This rather hacky way keeps 'tflatmap' compiling:
if tfHasMeta notin oldFlags:
result.excl tfHasMeta
result.n.typ = r
result.flags.excl tfHasMeta
result.n.typ() = r
if isCurrentlyGeneric():
for n in genericParams:
if {sfUsed, sfAnon} * n.sym.flags == {}:
result.incl tfUnresolved
result.flags.incl tfUnresolved
if tfWildcard in n.sym.typ.flags:
n.sym.transitionGenericParamToType()
n.sym.typ.excl tfWildcard
n.sym.typ.flags.excl tfWildcard
proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
checkMinSonsLen(n, 1, c.config)
@@ -1640,8 +1631,8 @@ proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
n[i] = semStmt(c, n[i], {})
if n.len > 0:
result = semTypeNode(c, n[^1], prev)
n.typ = result
n[^1].typ = result
n.typ() = result
n[^1].typ() = result
else:
result = nil
@@ -1654,15 +1645,15 @@ proc semBlockType(c: PContext, n: PNode, prev: PType): PType =
if n[0].kind notin {nkEmpty, nkSym}:
addDecl(c, newSymS(skLabel, n[0], c))
result = semStmtListType(c, n[1], prev)
n[1].typ = result
n.typ = result
n[1].typ() = result
n.typ() = result
closeScope(c)
c.p.breakInLoop = oldBreakInLoop
dec(c.p.nestedBlockCounter)
proc semGenericParamInInvocation(c: PContext, n: PNode): PType =
result = semTypeNode(c, n, nil)
n.typ = makeTypeDesc(c, result)
n.typ() = makeTypeDesc(c, result)
proc trySemObjectTypeForInheritedGenericInst(c: PContext, n: PNode, t: PType): bool =
var
@@ -1747,7 +1738,6 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
var isConcrete = true
let rType = m.call[0].typ
let mIndex = if rType != nil: rType.len - 1 else: -1
var hasForwardTypeParam = false
for i in 1..<m.call.len:
var typ = m.call[i].typ
# is this a 'typedesc' *parameter*? If so, use the typedesc type,
@@ -1764,36 +1754,13 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
skip = false
addToResult(typ, skip)
if typ.kind == tyForward:
hasForwardTypeParam = true
if isConcrete:
if s.ast == nil and s.typ.kind != tyCompositeTypeClass:
# XXX: What kind of error is this? is it still relevant?
localError(c.config, n.info, errCannotInstantiateX % s.name.s)
result = newOrPrevType(tyError, prev, c)
elif containsGenericInvocationWithForward(n[0]) or hasForwardTypeParam:
# isConcrete == false means this generic type is not instanciated here because it invoked with generic parameters.
# Even if isConcrete == true, don't instanciate it now if there are any `tyForward` type params.
# Such `tyForward` type params will be semchecked later and we can instanciate this next time.
# Some generic types like std/options.Option[T] needs a type kinds of the given type argument.
# return `tyForward` instead of `tyGenericInvocation` because:
# ```nim
# type Foo = object
# x: Option[Foo]
# ```
# returning `tyGenericInvocation` makes `Option[Foo]` to `tyGenericInvocation` and
# next time `semGeneric` is called with `Option[Foo]`, containsGenericType(typeof(`Foo`)) == true
# and `isConcrete == false`.
if prev == nil:
result = newTypeS(tyForward, c)
result.sym = s
else:
assignType(result, newTypeS(tyForward, c))
result.sym = s
elif containsGenericInvocationWithForward(n[0]):
c.forwardTypeUpdates.add (result, n) #fixes 1500
return
else:
result = instGenericContainer(c, n.info, result,
allowMetaTypes = false)
@@ -1809,10 +1776,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
if not trySemObjectTypeForInheritedGenericInst(c, n, tx):
return newOrPrevType(tyError, prev, c)
var position = 0
# it can be that we cached this generic instance. In this case, we don't have to
# recompute the field positions:
if tx.state != Sealed:
recomputeFieldPositions(tx, tx.n, position)
recomputeFieldPositions(tx, tx.n, position)
proc maybeAliasType(c: PContext; typeExpr, prev: PType): PType =
if prev != nil and (prev.kind == tyGenericBody or
@@ -1882,7 +1846,7 @@ proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
# if n.len == 0: return newConstraint(c, tyTypeClass)
if isNewStyleConcept(n):
result = newOrPrevType(tyConcept, prev, c)
result.incl tfCheckedForDestructor
result.flags.incl tfCheckedForDestructor
result.n = semConceptDeclaration(c, n)
return result
@@ -1893,7 +1857,7 @@ proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
var owner = getCurrOwner(c)
var candidateTypeSlot = newTypeS(tyAlias, c, c.errorType)
result = newOrPrevType(tyUserTypeClass, prev, c, son = candidateTypeSlot)
result.incl tfCheckedForDestructor
result.flags.incl tfCheckedForDestructor
result.n = n
if inherited.kind != nkEmpty:
@@ -1915,8 +1879,8 @@ proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
# if modifier == tyRef:
# dummyType.flags.incl tfNotNil
if modifier == tyTypeDesc:
dummyType.incl tfConceptMatchedTypeSym
dummyType.incl tfCheckedForDestructor
dummyType.flags.incl tfConceptMatchedTypeSym
dummyType.flags.incl tfCheckedForDestructor
else:
dummyName = param
dummyType = candidateTypeSlot
@@ -1929,7 +1893,7 @@ proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
var dummyParam = newSym(if modifier == tyTypeDesc: skType else: skVar,
dummyName.ident, c.idgen, owner, param.info)
dummyParam.typ = dummyType
incl dummyParam.flagsImpl, sfUsed
incl dummyParam.flags, sfUsed
addDecl(c, dummyParam)
result.n[3] = semConceptBody(c, n[3])
@@ -2014,7 +1978,7 @@ proc semStaticType(c: PContext, childNode: PNode, prev: PType): PType =
result = newOrPrevType(tyStatic, prev, c)
var base = semTypeNode(c, childNode, nil).skipTypes({tyTypeDesc, tyAlias})
result.rawAddSon(base)
result.incl tfHasStatic
result.flags.incl tfHasStatic
proc semTypeOf(c: PContext; n: PNode; prev: PType): PType =
openScope(c)
@@ -2024,12 +1988,12 @@ proc semTypeOf(c: PContext; n: PNode; prev: PType): PType =
closeScope(c)
result = ex.typ
if result.kind == tyFromExpr:
result.incl tfNonConstExpr
result.flags.incl tfNonConstExpr
elif result.kind == tyStatic:
let base = result.skipTypes({tyStatic})
if c.inGenericContext > 0 and base.containsGenericType:
result = makeTypeFromExpr(c, copyTree(ex))
result.incl tfNonConstExpr
result.flags.incl tfNonConstExpr
else:
result = base
fixupTypeOf(c, prev, result)
@@ -2049,12 +2013,12 @@ proc semTypeOf2(c: PContext; n: PNode; prev: PType): PType =
closeScope(c)
result = ex.typ
if result.kind == tyFromExpr:
result.incl tfNonConstExpr
result.flags.incl tfNonConstExpr
elif result.kind == tyStatic:
let base = result.skipTypes({tyStatic})
if c.inGenericContext > 0 and base.containsGenericType:
result = makeTypeFromExpr(c, copyTree(ex))
result.incl tfNonConstExpr
result.flags.incl tfNonConstExpr
else:
result = base
fixupTypeOf(c, prev, result)
@@ -2081,23 +2045,21 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
# proc signature for example
if c.inGenericInst > 0:
let bound = result.typ.elementType.sym
# the symbol may still point to the uninstantiated generic body type
if bound != nil and bound.typ == result.typ.elementType:
return bound
if bound != nil: return bound
return result
if result.typ.sym == nil:
localError(c.config, n.info, errTypeExpected)
return errorSym(c, n)
result = result.typ.sym.copySym(c.idgen)
result.typ = exactReplica(result.typ)
result.typ.incl tfUnresolved
result.typ.flags.incl tfUnresolved
if result.kind == skGenericParam:
if result.typ.kind == tyGenericParam and result.typ.len == 0 and
tfWildcard in result.typ.flags:
# collapse the wild-card param to a type
result.transitionGenericParamToType()
result.typ.excl tfWildcard
result.typ.flags.excl tfWildcard
return
else:
localError(c.config, n.info, errTypeExpected)
@@ -2123,7 +2085,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
n.transitionNoneToSym()
n.sym = result
n.info = oldInfo
n.typ = result.typ
n.typ() = result.typ
else:
localError(c.config, n.info, "identifier expected")
result = errorSym(c, n)
@@ -2139,7 +2101,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
# for ``typeof(countup(1,3))``, see ``tests/ttoseq``.
checkSonsLen(n, 1, c.config)
result = semTypeOf(c, n[0], prev)
if result.kind == tyTypeDesc: result.incl tfExplicit
if result.kind == tyTypeDesc: result.flags.incl tfExplicit
of nkPar:
if n.len == 1: result = semTypeNode(c, n[0], prev)
else:
@@ -2159,7 +2121,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
if result.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).kind in NilableTypes+GenericTypes:
if tfNotNil in result.flags:
result = freshType(c, result, prev)
result.excl(tfNotNil)
result.flags.excl(tfNotNil)
else:
localError(c.config, n.info, errGenerated, "invalid type")
elif n[0].kind notin nkIdentKinds:
@@ -2222,7 +2184,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result = makeTypeFromExpr(c, newTree(nkStmtListType, n.copyTree))
of NilableTypes + {tyGenericInvocation, tyForward}:
result = freshType(c, result, prev)
result.incl(tfNotNil)
result.flags.incl(tfNotNil)
else:
localError(c.config, n.info, errGenerated, "invalid type")
of 2:
@@ -2253,8 +2215,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
else:
result = semTypeNode(c, whenResult, prev)
of nkBracketExpr:
# Actually len >= 2 is required, but it doesn't print errors nicely with empty brackets
checkMinSonsLen(n, 1, c.config)
checkMinSonsLen(n, 2, c.config)
var head = n[0]
var s = if head.kind notin nkCallKinds: semTypeIdent(c, head)
else: symFromExpectedTypeNode(c, semExpr(c, head))
@@ -2269,24 +2230,13 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
of mSeq:
result = semContainer(c, n, tySequence, "seq", prev)
if optSeqDestructors in c.config.globalOptions:
incl result, tfHasAsgn
incl result.flags, tfHasAsgn
of mVarargs: result = semVarargs(c, n, prev)
of mTypeDesc, mType, mTypeOf:
if n.len != 2:
let name = case s.magic:
of mTypeDesc: "typedesc"
of mType: "type"
of mTypeOf: "typeof"
else: ""
localError(c.config, n.info, errXExpectsOneTypeParam % name)
else:
result = makeTypeDesc(c, semTypeNode(c, n[1], nil))
result.incl tfExplicit
result = makeTypeDesc(c, semTypeNode(c, n[1], nil))
result.flags.incl tfExplicit
of mStatic:
if n.len != 2:
localError(c.config, n.info, errXExpectsOneTypeParam % "static")
else:
result = semStaticType(c, n[1], prev)
result = semStaticType(c, n[1], prev)
of mExpr:
result = semTypeNode(c, n[0], nil)
if result != nil:
@@ -2296,11 +2246,9 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
for i in 1..<n.len:
result.rawAddSon(semTypeNode(c, n[i], nil))
of mDistinct:
checkSonsLen(n, 2, c.config)
result = newOrPrevType(tyDistinct, prev, c)
addSonSkipIntLit(result, semTypeNode(c, n[1], nil), c.idgen)
of mVar:
checkSonsLen(n, 2, c.config)
result = newOrPrevType(tyVar, prev, c)
var base = semTypeNode(c, n[1], nil)
if base.kind in {tyVar, tyLent}:
@@ -2405,7 +2353,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result = newTypeS(tyBuiltInTypeClass, c)
let child = newTypeS(tyProc, c)
if n.kind == nkIteratorTy:
child.incl tfIterator
child.flags.incl tfIterator
if n.len > 0 and n[1].kind != nkEmpty and n[1].len > 0:
# typeclass with pragma
let symKind = if n.kind == nkIteratorTy: skIterator else: skProc
@@ -2423,9 +2371,9 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result = newOrPrevType(tyError, prev, c)
if n.kind == nkIteratorTy and result.kind == tyProc:
result.incl(tfIterator)
if result.callConv == ccClosure and c.config.selectedGC in {gcArc, gcOrc, gcAtomicArc, gcYrc}:
result.incl tfHasAsgn
result.flags.incl(tfIterator)
if result.callConv == ccClosure and c.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
result.flags.incl tfHasAsgn
of nkEnumTy: result = semEnum(c, n, prev)
of nkType: result = n.typ
of nkStmtListType: result = semStmtListType(c, n, prev)
@@ -2436,7 +2384,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
when false:
localError(c.config, n.info, "type expected, but got: " & renderTree(n))
result = newOrPrevType(tyError, prev, c)
n.typ = result
n.typ() = result
dec c.inTypeContext
proc setMagicType(conf: ConfigRef; m: PSym, kind: TTypeKind, size: int) =
@@ -2455,7 +2403,7 @@ proc setMagicType(conf: ConfigRef; m: PSym, kind: TTypeKind, size: int) =
proc setMagicIntegral(conf: ConfigRef; m: PSym, kind: TTypeKind, size: int) =
setMagicType(conf, m, kind, size)
incl m.typ, tfCheckedForDestructor
incl m.typ.flags, tfCheckedForDestructor
proc processMagicType(c: PContext, m: PSym) =
case m.magic
@@ -2479,7 +2427,7 @@ proc processMagicType(c: PContext, m: PSym) =
setMagicType(c.config, m, tyString, szUncomputedSize)
rawAddSon(m.typ, getSysType(c.graph, m.info, tyChar))
if optSeqDestructors in c.config.globalOptions:
incl m.typ, tfHasAsgn
incl m.typ.flags, tfHasAsgn
of mCstring:
setMagicIntegral(c.config, m, tyCstring, c.config.target.ptrSize)
rawAddSon(m.typ, getSysType(c.graph, m.info, tyChar))
@@ -2516,7 +2464,7 @@ proc processMagicType(c: PContext, m: PSym) =
of mSeq:
setMagicType(c.config, m, tySequence, szUncomputedSize)
if optSeqDestructors in c.config.globalOptions:
incl m.typ, tfHasAsgn
incl m.typ.flags, tfHasAsgn
if defined(nimsuggest) or c.config.cmd == cmdCheck: # bug #18985
discard
else:
@@ -2529,8 +2477,8 @@ proc processMagicType(c: PContext, m: PSym) =
setMagicIntegral(c.config, m, tyIterable, 0)
rawAddSon(m.typ, newTypeS(tyNone, c))
of mPNimrodNode:
incl m.typ, tfTriggersCompileTime
incl m.typ, tfCheckedForDestructor
incl m.typ.flags, tfTriggersCompileTime
incl m.typ.flags, tfCheckedForDestructor
of mException: discard
of mBuiltinType:
case m.name.s
@@ -2538,7 +2486,7 @@ proc processMagicType(c: PContext, m: PSym) =
of "sink": setMagicType(c.config, m, tySink, szUncomputedSize)
of "owned":
setMagicType(c.config, m, tyOwned, c.config.target.ptrSize)
incl m.typ, tfHasOwned
incl m.typ.flags, tfHasOwned
else: localError(c.config, m.info, errTypeExpected)
else: localError(c.config, m.info, errTypeExpected)
@@ -2571,7 +2519,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
if typ.kind == tyTypeDesc:
if typ.elementType.kind == tyNone:
typ = newTypeS(tyTypeDesc, c, newTypeS(tyNone, c))
incl typ, tfCheckedForDestructor
incl typ.flags, tfCheckedForDestructor
else:
typ = semGenericConstraints(c, typ)
@@ -2583,15 +2531,15 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
else:
# the following line fixes ``TV2*[T:SomeNumber=TR] = array[0..1, T]``
# from manyloc/named_argument_bug/triengine:
def.typ = def.typ.skipTypes({tyTypeDesc})
def.typ() = def.typ.skipTypes({tyTypeDesc})
if not containsGenericType(def.typ):
def = fitNode(c, typ, def, def.info)
if typ == nil:
typ = newTypeS(tyGenericParam, c)
if father == nil: typ.incl tfWildcard
if father == nil: typ.flags.incl tfWildcard
typ.incl tfGenericTypeParam
typ.flags.incl tfGenericTypeParam
for j in 0..<a.len-2:
var finalType: PType
@@ -2613,7 +2561,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
localError(c.config, paramName.info, errInOutFlagNotExtern % $paramName[0])
covarianceFlag = if paramName[0].ident.s == "in": tfContravariant
else: tfCovariant
if father != nil: father.incl tfCovariant
if father != nil: father.flags.incl tfCovariant
paramName = paramName[1]
var s = if finalType.kind == tyStatic or tfWildcard in typ.flags:
@@ -2621,7 +2569,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
else:
newSymG(skType, paramName, c).linkTo(finalType)
if covarianceFlag != tfUnresolved: s.typ.incl(covarianceFlag)
if covarianceFlag != tfUnresolved: s.typ.flags.incl(covarianceFlag)
if def.kind != nkEmpty: s.ast = def
s.position = result.len
result.addSym(s)

View File

@@ -110,7 +110,7 @@ proc prepareNode*(cl: var TReplTypeVars, n: PNode): PNode =
return if tfUnresolved in t.flags: prepareNode(cl, t.n)
else: t.n
result = copyNode(n)
result.typ = t
result.typ() = t
if result.kind == nkSym:
result.sym =
if n.typ != nil and n.typ == n.sym.typ:
@@ -249,24 +249,13 @@ proc hasValuelessStatics(n: PNode): bool =
a
proc doThing(_: MyThing)
]#
result = false
if n.safeLen == 0 and n.kind != nkEmpty: # Some empty nodes can get in here
if n.typ == nil:
result = true
elif n.typ.kind == tyStatic:
result = true
elif n.typ.kind == tyTypeDesc:
# Check if the base type is an unresolved generic parameter.
# This handles cases where a template containing sizeof(T) is called
# inside a generic object's when clause - the T needs to be resolved
# before we can evaluate the condition.
let base = n.typ.skipTypes({tyTypeDesc})
if base.kind == tyGenericParam:
result = true
n.typ == nil or n.typ.kind == tyStatic
else:
for x in n:
if hasValuelessStatics(x):
return true
false
proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0; expectedType: PType = nil): PNode =
if n == nil: return
@@ -274,8 +263,8 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0; expectedType: PT
if n.typ != nil:
if n.typ.kind == tyFromExpr:
# type of node should not be evaluated as a static value
n.typ.incl tfNonConstExpr
result.typ = replaceTypeVarsT(cl, n.typ)
n.typ.flags.incl tfNonConstExpr
result.typ() = replaceTypeVarsT(cl, n.typ)
checkMetaInvariants(cl, result.typ)
case n.kind
of nkNone..pred(nkSym), succ(nkSym)..nkNilLit:
@@ -290,10 +279,8 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0; expectedType: PT
if result.sym.kind == skField and result.sym.ast != nil and
(cl.owner == nil or result.sym.owner == cl.owner):
# instantiate default value of object/tuple field
var n = result.sym.ast
cl.c.fitDefaultNode(cl.c, n, result.sym.typ)
result.sym.ast = n
result.sym.typ = n.typ.skipIntLit(cl.c.idgen)
cl.c.fitDefaultNode(cl.c, result.sym.ast, result.sym.typ)
result.sym.typ = result.sym.ast.typ
# sym type can be nil if was gensym created by macro, see #24048
if result.sym.typ != nil and result.sym.typ.kind == tyVoid:
# don't add the 'void' field
@@ -373,9 +360,8 @@ proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym, t: PType): PSym =
var g: G[string]
]#
# XXX FIXME This causes system.Natural to be duplicated during compilation of system.nim as cl.owner == nil!
result = copySym(s, cl.c.idgen)
incl(result.flagsImpl, sfFromGeneric)
incl(result.flags, sfFromGeneric)
#idTablePut(cl.symMap, s, result)
setOwner(result, s.owner)
result.typ = t
@@ -408,12 +394,12 @@ proc instCopyType*(cl: var TReplTypeVars, t: PType): PType =
#cl.typeMap.topLayer.idTablePut(result, t)
if cl.allowMetaTypes: return
result.incl tfFromGeneric
result.flags.incl tfFromGeneric
if not (t.kind in tyMetaTypes or
(t.kind == tyStatic and t.n == nil)):
result.excl tfInstClearedFlags
result.flags.excl tfInstClearedFlags
else:
result.excl tfHasAsgn
result.flags.excl tfHasAsgn
when false:
if newDestructors:
result.assignment = nil
@@ -538,13 +524,13 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
let mm = skipTypes(bbody, abstractPtrs)
if tfFromGeneric notin mm.flags:
# bug #5479, prevent endless recursions here:
incl mm.flagsImpl, tfFromGeneric
incl mm.flags, tfFromGeneric
for col, meth in methodsForGeneric(cl.c.graph, mm):
# we instantiate the known methods belonging to that type, this causes
# them to be registered and that's enough, so we 'discard' the result.
discard cl.c.instTypeBoundOp(cl.c, meth, result, cl.info,
attachedAsgn, col)
excl mm.flagsImpl, tfFromGeneric
excl mm.flags, tfFromGeneric
proc eraseVoidParams*(t: PType) =
# transform '(): void' into '()' because old parts of the compiler really
@@ -554,33 +540,15 @@ proc eraseVoidParams*(t: PType) =
for i in FirstParamAt..<t.signatureLen:
# don't touch any memory unless necessary
if t.n[i].kind == nkRecList or t[i].kind == tyVoid:
if t[i].kind == tyVoid:
var pos = i
for j in i+1..<t.signatureLen:
if t[j].kind != tyVoid:
t.n[pos] = t.n[j]
inc pos
setLen t.n.sons, pos
break
proc eraseTupleVoidFields*(t: PType) =
## Remove void fields from a named tuple type, compacting both `t.n`
## (the field symbol nodes) and `t.sonsImpl` (the child types).
if t.n == nil: return # anonymous tuple, nothing to compact
for i in 0..<t.kidsLen:
if t.n[i].kind == nkRecList or t[i].kind == tyVoid:
# found first void field, compact from here
var pos = i
for j in i+1..<t.kidsLen:
if t[j].kind != tyVoid and j < t.n.len and t.n[j].kind != nkRecList:
t.n[pos] = t.n[j]
t[pos] = t[j]
if t.n[pos].kind == nkSym:
t.n[pos].sym.position = pos
t.n[pos] = t.n[j]
inc pos
# else: skip void entries
newSons t, pos
setLen t.n.sons, pos
t.setSonsLen pos
break
proc skipIntLiteralParams*(t: PType; idgen: IdGenerator) =
@@ -714,7 +682,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType, isInstValue = false):
of tyUserTypeClass:
result = t
of tyStatic:
if cl.c.matchedConcept != nil:
# allow concepts to not instantiate statics for now
@@ -736,7 +704,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType, isInstValue = false):
if not cl.allowMetaTypes and result.n != nil and
result.base.kind != tyNone:
result.n = cl.c.semConstExpr(cl.c, result.n)
result.n.typ = result.base
result.n.typ() = result.base
of tyGenericInst, tyUserTypeClassInst:
bailout()
@@ -773,8 +741,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType, isInstValue = false):
let r2 = r.skipTypes({tyAlias, tySink, tyOwned})
if r2.kind in {tyPtr, tyRef}:
r = skipTypes(r2, {tyPtr, tyRef})
if result.kind != tyProc or i == 0:
result[i] = r
result[i] = r
if result.kind != tyArray or i != 0:
propagateToOwner(result, r)
# bug #4677: Do not instantiate effect lists
@@ -787,9 +754,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType, isInstValue = false):
of tyObject, tyTuple:
propagateFieldFlags(result, result.n)
if result.kind == tyObject and cl.c.computeRequiresInit(cl.c, result):
result.incl tfRequiresInit
if result.kind == tyTuple:
eraseTupleVoidFields(result)
result.flags.incl tfRequiresInit
of tyProc:
eraseVoidParams(result)

View File

@@ -41,7 +41,6 @@ type
CoType
CoOwnerSig
CoIgnoreRange
CoIgnoreRangeInArray
CoConsiderOwned
CoDistinct
CoHashTypeInsideNode
@@ -107,10 +106,6 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi
c &= "\254"
return
# Ensure type is fully loaded before hashing to avoid hash changing
# as properties are accessed and trigger lazy loading.
backendEnsureMutable(t)
case t.kind
of tyGenericInvocation:
for a in t.kids:
@@ -148,15 +143,15 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi
if t.sym != nil and {sfImportc, sfExportc} * t.sym.flags != {}:
c.hashSym(t.sym)
of tyObject, tyEnum:
if t.typeInstImpl != nil:
if t.typeInst != nil:
# prevent against infinite recursions here, see bug #8883:
let inst = t.typeInstImpl
t.typeInstImpl = nil # IC: spurious writes are ok since we set it back immediately
let inst = t.typeInst
t.typeInst = nil
assert inst.kind == tyGenericInst
c.hashType inst.genericHead, flags, conf
for _, a in inst.genericInstParams:
c.hashType a, flags+{CoDistinct}, conf
t.typeInstImpl = inst
c.hashType a, flags, conf
t.typeInst = inst
return
c &= char(t.kind)
# Every cyclic type in Nim need to be constructed via some 't.sym', so this
@@ -185,9 +180,9 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi
# Hack to prevent endless recursion
# xxx instead, use a hash table to indicate we've already visited a type, which
# would also be more efficient.
symWithFlags.flagsImpl.excl {sfAnon, sfGenSym}
symWithFlags.flags.excl {sfAnon, sfGenSym}
hashTree(c, t.n, flags + {CoHashTypeInsideNode}, conf)
symWithFlags.flagsImpl = oldFlags
symWithFlags.flags = oldFlags
else:
# The object has no fields: we _must_ add something here in order to
# make the hash different from the one we produce by hashing only the
@@ -221,17 +216,10 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi
else:
for a in t.kids: c.hashType a, flags+{CoIgnoreRange}, conf
of tyRange:
if {CoIgnoreRange, CoIgnoreRangeInArray} * flags == {}:
if CoIgnoreRange notin flags:
c &= char(t.kind)
c.hashTree(t.n, {}, conf)
c.hashType(t.elementType, flags, conf)
elif CoIgnoreRangeInArray in flags:
# include only the length of the range (not its specific bounds)
c &= char(t.kind)
let l = lengthOrd(conf, t)
lowlevel l
else:
c.hashType(t.elementType, flags, conf)
c.hashType(t.elementType, flags, conf)
of tyStatic:
c &= char(t.kind)
c.hashTree(t.n, {}, conf)
@@ -261,7 +249,7 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi
if tfVarargs in t.flags: c &= ".varargs"
of tyArray:
c &= char(t.kind)
c.hashType(t.indexType, flags-{CoIgnoreRange}+{CoIgnoreRangeInArray}, conf)
c.hashType(t.indexType, flags-{CoIgnoreRange}, conf)
c.hashType(t.elementType, flags-{CoIgnoreRange}, conf)
else:
c &= char(t.kind)

Some files were not shown because too many files have changed in this diff Show More