Compare commits

..

8 Commits

Author SHA1 Message Date
ringabout
663f6c4365 revert #7343 2025-02-04 18:54:37 +08:00
ringabout
fb0d936801 Merge remote-tracking branch 'origin/devel' into pr_quote_do_r 2025-02-04 18:27:47 +08:00
ringabout
1a16f55948 fixes 2025-01-24 18:12:38 +08:00
ringabout
b66ff0b6ac Apply suggestions from code review 2025-01-24 17:34:58 +08:00
ringabout
1b004f1632 progress: skips the current routine scopes 2025-01-24 17:10:44 +08:00
ringabout
c70f67b0d6 uses topLevelScope 2025-01-24 15:25:10 +08:00
ringabout
7ce4433843 progress 2025-01-23 22:18:28 +08:00
ringabout
b550fb54d9 fixes #24641; quote do captures no variables under current macros 2025-01-23 21:45:31 +08:00
427 changed files with 5395 additions and 21293 deletions

View File

@@ -10,16 +10,6 @@ body:
Please provide a minimal code example that reproduces the bug if possible.
Reports with a reproducible example or detailed information will likely receive fixes faster.
- type: textarea
id: nim-version
attributes:
label: Nim Version
description: |
Can be obtained from `nim -v` on the command line along with the OS/architecture.
For development versions, including the commit hash may help.
validations:
required: true
- type: textarea
id: description
attributes:
@@ -29,6 +19,16 @@ body:
placeholder: Bug reports with reproducible code or detailed information will be fixed faster.
validations:
required: true
- type: textarea
id: nim-version
attributes:
label: Nim Version
description: |
Can be obtained from `nim -v` on the command line along with the OS/architecture.
For development versions, make sure to include the commit hash.
validations:
required: true
- type: textarea
id: current-logs

View File

@@ -15,16 +15,9 @@ jobs:
name: ${{ matrix.platform }}-bisects
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v5
- 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

@@ -43,9 +43,9 @@ jobs:
- target: linux
os: ubuntu-22.04
- target: windows
os: windows-latest
os: windows-2019
- target: osx
os: macos-15
os: macos-13
name: ${{ matrix.target }}
runs-on: ${{ matrix.os }}

View File

@@ -18,13 +18,9 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-14]
os: [ubuntu-22.04, macos-13]
cpu: [amd64]
batch: ["allowed_failures", "0_3", "1_3", "2_3"] # list of `index_num`
include:
- os: ubuntu-latest
cpu: amd64
- os: macos-14
cpu: arm64
name: '${{ matrix.os }} (batch: ${{ matrix.batch }})'
runs-on: ${{ matrix.os }}
timeout-minutes: 60 # refs bug #18178
@@ -45,11 +41,11 @@ jobs:
- name: 'Install dependencies (Linux amd64)'
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
run: |
sudo apt-get update -qq
sudo apt-fast update -qq
DEBIAN_FRONTEND='noninteractive' \
sudo apt-get install --no-install-recommends -yq \
sudo apt-fast install --no-install-recommends -yq \
libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev \
valgrind libc6-dbg libblas-dev liblapack-dev libpcre3 xorg-dev
valgrind libc6-dbg libblas-dev xorg-dev
- name: 'Install dependencies (macOS)'
if: runner.os == 'macOS'
run: brew install boehmgc make sfml gtk+3

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,24 +28,24 @@ 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'
vmImage: 'windows-2019'
CPU: amd64
# see also: `NIM_TEST_PACKAGES`
NIM_TESTAMENT_BATCH: "0_3"
Windows_amd64_batch1_3:
vmImage: 'windows-2025'
vmImage: 'windows-2019'
CPU: amd64
NIM_TESTAMENT_BATCH: "1_3"
Windows_amd64_batch2_3:
vmImage: 'windows-2025'
vmImage: 'windows-2019'
CPU: amd64
NIM_TESTAMENT_BATCH: "2_3"

View File

@@ -19,52 +19,15 @@ errors.
- With `-d:nimPreviewAsmSemSymbol`, backticked symbols are type checked in the `asm/emit` statements.
- 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 `!=`.
- `std/parsesql` has been moved to a nimble package, use `nimble` or `atlas` to install it.
- 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.
## Standard library additions and changes
[//]: # "Additions:"
- `setutils.symmetricDifference` along with its operator version
`` setutils.`-+-` `` and in-place version `setutils.toggle` have been added
to more efficiently calculate the symmetric difference of bitsets.
- `strutils.multiReplace` overload for character set replacements in a single pass.
Useful for string sanitation. Follows existing multiReplace semantics.
- `std/files` adds:
- Exports `CopyFlag` enum and `FilePermission` type for fine-grained control of file operations
- New file operation procs with `Path` support:
- `getFilePermissions`, `setFilePermissions` for managing permissions
- `tryRemoveFile` for file deletion
- `copyFile` with configurable buffer size and symlink handling
- `copyFileWithPermissions` to preserve file attributes
- `copyFileToDir` for copying files into directories
- `std/dirs` adds:
- New directory operation procs with `Path` support:
- `copyDir` with special file handling options
- `copyDirWithPermissions` to recursively preserve attributes
- `system.setLenUninit` now supports refc, JS and VM backends.
[//]: # "Changes:"
- `std/math` The `^` symbol now supports floating-point as exponent in addition to the Natural type.
- `min`, `max`, and `sequtils`' `minIndex`, `maxIndex` and `minmax` for `openArray`s now accept a comparison function.
- `system.substr` implementation now uses `copymem` (wrapped C `memcpy`) for copying data, if available at compilation.
- `system.newStringUninit` is now considered free of side-effects allowing it to be used with `--experimental:strictFuncs`.
## Language changes
@@ -105,15 +68,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 `--stdinfile` flag to name of the file used when running program from stdin (defaults to `stdinfile.nim`)
## 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
@@ -612,70 +713,6 @@ iterator items*(tab: TStrTable): PSym =
yield s
s = nextIter(it, tab)
proc isNil(x: ItemId): bool {.inline.} =
x.module == 0 and x.item == 0
proc hasEmptySlot[T](data: TIdPairSeq[T]): bool =
for h in 0..high(data):
if isNil(data[h].key):
return true
result = false
proc idTableRawGet[T](t: TIdTable[T], key: int): int =
var h: Hash
h = key and high(t.data) # start with real hash value
while not isNil(t.data[h].key):
if toId(t.data[h].key) == key:
return h
h = nextTry(h, high(t.data))
result = - 1
proc getOrDefault*[T](t: TIdTable[T], key: ItemId): T =
var index = idTableRawGet(t, toId(key))
if index >= 0: result = t.data[index].val
else: result = default(T)
template idTableGet*[T](t: TIdTable[T], key: PType | PSym): T =
getOrDefault(t, key.itemId)
proc idTableRawInsert[T](data: var TIdPairSeq[T], key: ItemId, val: T) =
var h: Hash
let keyId = toId(key)
h = keyId and high(data)
while not isNil(data[h].key):
assert(toId(data[h].key) != keyId)
h = nextTry(h, high(data))
assert(isNil(data[h].key))
data[h].key = key
data[h].val = val
proc `[]=`*[T](t: var TIdTable[T], key: ItemId, val: T) =
var
index: int
n: TIdPairSeq[T]
index = idTableRawGet(t, toId(key))
if index >= 0:
assert(not isNil(t.data[index].key))
t.data[index].val = val
else:
if mustRehash(t.data.len, t.counter):
newSeq(n, t.data.len * GrowthFactor)
for i in 0..high(t.data):
if not isNil(t.data[i].key):
idTableRawInsert(n, t.data[i].key, t.data[i].val)
assert(hasEmptySlot(n))
swap(t.data, n)
idTableRawInsert(t.data, key, val)
inc(t.counter)
template idTablePut*[T](t: var TIdTable[T], key: PType | PSym, val: T) =
t[key.itemId] = val
iterator idTablePairs*[T](t: TIdTable[T]): tuple[key: ItemId, val: T] =
for i in 0..high(t.data):
if not isNil(t.data[i].key):
yield (t.data[i].key, t.data[i].val)
proc initIITable(x: var TIITable) =
x.counter = 0
newSeq(x.data, StartSize)

File diff suppressed because it is too large Load Diff

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

@@ -338,7 +338,7 @@ proc withTmpIfNeeded(p: BProc, a: TLoc, needsTmp: bool): TLoc =
else:
result = a
proc expressionsNeedsTmp(p: BProc, a: TLoc): TLoc =
proc literalsNeedsTmp(p: BProc, a: TLoc): TLoc =
result = getTemp(p, a.lode.typ, needsInit=false)
genAssignment(p, result, a, {})
@@ -358,7 +358,7 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Builder; n
(optByRef notin param.options or not p.module.compileToCpp):
a = initLocExpr(p, n)
if n.kind in {nkCharLit..nkNilLit}:
addAddrLoc(p.config, expressionsNeedsTmp(p, a), result)
addAddrLoc(p.config, literalsNeedsTmp(p, a), result)
else:
addAddrLoc(p.config, withTmpIfNeeded(p, a, needsTmp), result)
elif p.module.compileToCpp and param.typ.kind in {tyVar} and
@@ -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
@@ -418,6 +418,35 @@ proc skipTrivialIndirections(n: PNode): PNode =
result = result[1]
else: break
proc getPotentialWrites(n: PNode; mutate: bool; result: var seq[PNode]) =
case n.kind:
of nkLiterals, nkIdent, nkFormalParams: discard
of nkSym:
if mutate: result.add n
of nkAsgn, nkFastAsgn, nkSinkAsgn:
getPotentialWrites(n[0], true, result)
getPotentialWrites(n[1], mutate, result)
of nkAddr, nkHiddenAddr:
getPotentialWrites(n[0], true, result)
of nkBracketExpr, nkDotExpr, nkCheckedFieldExpr:
getPotentialWrites(n[0], mutate, result)
of nkCallKinds:
case n.getMagic:
of mIncl, mExcl, mInc, mDec, mAppendStrCh, mAppendStrStr, mAppendSeqElem,
mAddr, mNew, mNewFinalize, mWasMoved, mDestroy:
getPotentialWrites(n[1], true, result)
for i in 2..<n.len:
getPotentialWrites(n[i], mutate, result)
of mSwap:
for i in 1..<n.len:
getPotentialWrites(n[i], true, result)
else:
for i in 1..<n.len:
getPotentialWrites(n[i], mutate, result)
else:
for s in n:
getPotentialWrites(s, mutate, result)
proc getPotentialReads(n: PNode; result: var seq[PNode]) =
case n.kind:
of nkLiterals, nkIdent, nkFormalParams: discard
@@ -498,7 +527,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):
@@ -357,7 +357,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
of tyString:
if optSeqDestructors in p.config.globalOptions:
genGenericAsgn(p, dest, src, flags)
elif (needToCopy notin flags and src.storage != OnStatic) or canMove(p, src.lode, dest):
elif ({needToCopy, needToCopySinkParam} * flags == {} and src.storage != OnStatic) or canMove(p, src.lode, dest):
genRefAssign(p, dest, src)
else:
if (dest.storage == OnStack and p.config.selectedGC != gcGo) or not usesWriteBarrier(p.config):
@@ -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
@@ -966,11 +962,6 @@ proc cowBracket(p: BProc; n: PNode) =
proc cow(p: BProc; n: PNode) {.inline.} =
if n.kind == nkHiddenAddr: cowBracket(p, n[0])
template ignoreConv(e: PNode): bool =
let destType = e.typ.skipTypes({tyVar, tyLent, tyGenericInst, tyAlias, tySink})
let srcType = e[1].typ.skipTypes({tyVar, tyLent, tyGenericInst, tyAlias, tySink})
sameBackendTypePickyAliases(destType, srcType)
proc genAddr(p: BProc, e: PNode, d: var TLoc) =
# careful 'addr(myptrToArray)' needs to get the ampersand:
if e[0].typ.skipTypes(abstractInstOwned).kind in {tyRef, tyPtr}:
@@ -983,15 +974,7 @@ proc genAddr(p: BProc, e: PNode, d: var TLoc) =
d.lode = e
else:
var a: TLoc = initLocExpr(p, e[0])
if e[0].kind in {nkHiddenStdConv, nkHiddenSubConv, nkConv} and not ignoreConv(e[0]):
# addr (conv x) introduces a temp because `conv x` is not a rvalue
# transform addr ( conv ( x ) ) -> conv ( addr ( x ) )
var exprLoc: TLoc = initLocExpr(p, e[0][1])
var tmp = getTemp(p, e.typ, needsInit=false)
putIntoDest(p, tmp, e, cCast(getTypeDesc(p.module, e.typ), addrLoc(p.config, exprLoc)))
putIntoDest(p, d, e, rdLoc(tmp))
else:
putIntoDest(p, d, e, addrLoc(p.config, a), a.storage)
putIntoDest(p, d, e, addrLoc(p.config, a), a.storage)
template inheritLocation(d: var TLoc, a: TLoc) =
if d.k == locNone: d.storage = a.storage
@@ -1006,7 +989,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
@@ -1916,7 +1899,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:
@@ -2215,14 +2198,7 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
else: putIntoDest(p, d, e, cIntValue(lengthOrd(p.config, typ)))
else: internalError(p.config, e.info, "genArrayLen()")
proc isTrivialTypesToSnippet(t: PType): Snippet =
if containsGarbageCollectedRef(t) or
hasDestructor(t):
result = NimFalse
else:
result = NimTrue
proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc, noinit = false) =
proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
if optSeqDestructors in p.config.globalOptions:
e[1] = makeAddr(e[1], p.module.idgen)
genCall(p, e, d)
@@ -2244,10 +2220,7 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc, noinit = false) =
pExpr = cIfExpr(ra, cAddr(derefField(ra, "Sup")), NimNil)
else:
pExpr = ra
let name = if noinit: "setLengthSeqUninit" else: "setLengthSeqV2"
call.snippet = cCast(rt, cgCall(p, name, pExpr, rti, rb,
isTrivialTypesToSnippet(t.skipTypes(abstractInst)[0])))
call.snippet = cCast(rt, cgCall(p, "setLengthSeqV2", pExpr, rti, rb))
genAssignment(p, a, call, {})
gcUsage(p.config, e)
@@ -2656,7 +2629,8 @@ proc genRangeChck(p: BProc, n: PNode, d: var TLoc) =
putIntoDest(p, d, n, cCast(destType, wrapPar(val)), a.storage)
proc genConv(p: BProc, e: PNode, d: var TLoc) =
if ignoreConv(e):
let destType = e.typ.skipTypes({tyVar, tyLent, tyGenericInst, tyAlias, tySink})
if sameBackendTypeIgnoreRange(destType, e[1].typ):
expr(p, e[1], d)
else:
genSomeCast(p, e, d)
@@ -2775,7 +2749,13 @@ proc genMove(p: BProc; n: PNode; d: var TLoc) =
let val = if p.module.compileToCpp: rdLoc(a) else: byRefLoc(p, a)
p.s(cpsStmts).addCallStmt(rdLoc(b), val)
else:
genAssignment(p, d, a, {})
if n[1].kind == nkSym and isSinkParam(n[1].sym):
var tmp = getTemp(p, n[1].typ.skipTypes({tySink}))
genAssignment(p, tmp, a, {needToCopySinkParam})
genAssignment(p, d, tmp, {})
resetLoc(p, tmp)
else:
genAssignment(p, d, a, {})
resetLoc(p, a)
proc genDestroy(p: BProc; n: PNode) =
@@ -2985,7 +2965,6 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimGCunref"), ra)
of mSetLengthStr: genSetLengthStr(p, e, d)
of mSetLengthSeq: genSetLengthSeq(p, e, d)
of mSetLengthSeqUninit: genSetLengthSeq(p, e, d, noinit = true)
of mIncl, mExcl, mCard, mLtSet, mLeSet, mEqSet, mMulSet, mPlusSet, mMinusSet,
mInSet, mXorSet:
genSetOp(p, e, d, op)
@@ -3363,9 +3342,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) =
@@ -3435,7 +3413,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:
@@ -3453,7 +3431,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)
@@ -3466,15 +3444,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)
@@ -3483,13 +3457,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)
@@ -3621,7 +3589,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
@@ -3687,10 +3655,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)
@@ -3710,67 +3675,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
@@ -3801,34 +3708,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
@@ -3883,7 +3780,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):
@@ -3892,7 +3790,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):
@@ -3907,9 +3806,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:
@@ -3954,10 +3850,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, 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

@@ -67,14 +67,7 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
var x = typ.baseClass
if x != nil: x = x.skipTypes(skipPtrs)
specializeResetT(p, accessor.parentObj(p.module), x)
if typ.n != nil:
if typ.sym != nil and sfImportc in typ.sym.flags:
# imported C struct, nimZeroMem
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimZeroMem"),
cCast(ptrType(CPointer), cAddr(accessor)),
cSizeof(getTypeDesc(p.module, typ)))
else:
specializeResetN(p, accessor, typ.n, typ)
if typ.n != nil: specializeResetN(p, accessor, typ.n, typ)
of tyTuple:
let typ = getUniqueType(typ)
for i, a in typ.ikids:

View File

@@ -18,7 +18,7 @@ proc registerTraverseProc(p: BProc, v: PSym) =
var traverseProc = ""
if p.config.selectedGC in {gcMarkAndSweep, gcHooks, gcRefc} and
optOwnedRefs notin p.config.globalOptions and
containsManagedMemory(v.loc.t):
containsGarbageCollectedRef(v.loc.t):
# we register a specialized marked proc here; this has the advantage
# that it works out of the box for thread local storage then :-)
traverseProc = genTraverseProcForGlobal(p.module, v, v.info)
@@ -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
@@ -57,15 +57,11 @@ proc mangleField(m: BModule; name: PIdent): string =
proc mangleProc(m: BModule; s: PSym; makeUnique: bool): string =
result = "_Z" # Common prefix in Itanium ABI
var params = ""
var staticLists = ""
result.add encodeSym(m, s, makeUnique)
if s.typ.len > 1: #we dont care about the return param
for i in 1..<s.typ.len:
if s.typ[i].isNil: continue
params.add encodeType(m, s.typ[i], staticLists)
result.add encodeSym(m, s, makeUnique, staticLists)
result.add params
result.add encodeType(m, s.typ[i])
if result in m.g.mangledPrcs:
result = mangleProc(m, s, true)
@@ -75,7 +71,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 +80,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 +103,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}
@@ -121,11 +115,10 @@ proc fillLocalName(p: BProc; s: PSym) =
if s.kind == skTemp:
# speed up conflict search for temps (these are quite common):
if counter != 0: result.add "_" & rope(counter+1)
elif s.kind != skResult:
elif counter != 0 or isKeyword(s.name) or p.module.g.config.cppDefines.contains(key):
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 +152,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:
@@ -251,11 +243,14 @@ 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
proc isObjLackingTypeField(typ: PType): bool {.inline.} =
result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
(typ.baseClass == nil) or isPureObject(typ))
proc isInvalidReturnType(conf: ConfigRef; typ: PType, isProc = true): bool =
# Arrays and sets cannot be returned by a C procedure, because C is
# such a poor programming language.
@@ -304,13 +299,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:
@@ -529,15 +523,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
@@ -551,14 +544,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:
@@ -566,7 +558,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:
@@ -595,7 +587,7 @@ proc genProcParams(m: BModule; t: PType, rettype: var Rope, params: var Builder,
if t.returnType == nil or isInvalidReturnType(m.config, t):
rettype = CVoid
else:
rettype = getTypeDescWeak(m, t.returnType, check, dkResult)
rettype = getTypeDescAux(m, t.returnType, check, dkResult)
var paramBuilder: ProcParamBuilder
params.addProcParams(paramBuilder):
for i in 1..<t.n.len:
@@ -608,15 +600,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:
@@ -628,9 +619,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):
@@ -715,13 +706,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 = ""
@@ -769,8 +759,6 @@ proc fillObjectFields*(m: BModule; typ: PType) =
var check = initIntSet()
var ignored = newBuilder("")
addRecordFields(ignored, m, typ, check)
if typ.baseClass != nil:
fillObjectFields(m, typ.baseClass.skipTypes(skipPtrs))
proc mangleDynLibProc(sym: PSym): Rope
@@ -844,54 +832,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})
@@ -907,7 +847,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)
@@ -1041,7 +981,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
@@ -1052,7 +992,52 @@ 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 == "":
@@ -1167,8 +1152,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:
@@ -1200,7 +1184,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
@@ -1215,15 +1199,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
@@ -1463,7 +1446,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) =
@@ -1659,8 +1642,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)
@@ -1865,12 +1848,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
@@ -1899,9 +1876,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)
@@ -1984,9 +1961,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")
@@ -2022,9 +1999,6 @@ proc genTypeInfoV1(m: BModule; t: PType; info: TLineInfo): Rope =
of tyRef:
genTypeInfoAux(m, t, t, result, info)
if m.config.selectedGC in {gcMarkAndSweep, gcRefc, gcGo}:
# it may not be used in other places except in `genTraverseProc`,
# we have to generate a typedesc for this case, not a weak one
discard getTypeDesc(m, origType.last)
let markerProc = genTraverseProc(m, origType, sig)
m.s[cfsTypeInit3].addFieldAssignment(tiNameForHcr(m, result), "marker", markerProc)
of tyPtr, tyRange, tyUncheckedArray: genTypeInfoAux(m, t, t, result, info)
@@ -2063,21 +2037,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

@@ -11,7 +11,7 @@
import
ast, types, msgs, wordrecg,
platform, trees, options, cgendata, mangleutils, renderer
platform, trees, options, cgendata, mangleutils
import std/[hashes, strutils, formatfloat]
@@ -90,6 +90,9 @@ proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool =
if s.typ.sym != nil and sfForward in s.typ.sym.flags:
# forwarded objects are *always* passed by pointers for consistency!
result = true
elif s.typ.kind == tySink and conf.selectedGC notin {gcArc, gcAtomicArc, gcOrc, gcHooks}:
# bug #23354:
result = false
elif (optByRef in s.options) or (getSize(conf, pt) > conf.target.floatSize * 3):
result = true # requested anyway
elif (tfFinal in pt.flags) and (pt[0] == nil):
@@ -117,14 +120,14 @@ proc makeUnique(m: BModule; s: PSym, name: string = ""): string =
result.add "_u"
result.add $s.itemId.item
proc encodeSym*(m: BModule; s: PSym; makeUnique: bool = false; extra: string = ""): string =
proc encodeSym*(m: BModule; s: PSym; makeUnique: bool = false): string =
#Module::Type
var name = s.name.s & extra
var name = s.name.s
if makeUnique:
name = makeUnique(m, s, name)
"N" & encodeName(s.skipGenericOwner.name.s) & encodeName(name) & "E"
proc encodeType*(m: BModule; t: PType; staticLists: var string): string =
proc encodeType*(m: BModule; t: PType): string =
result = ""
var kindName = ($t.kind)[2..^1]
kindName[0] = toLower($kindName[0])[0]
@@ -135,10 +138,10 @@ proc encodeType*(m: BModule; t: PType; staticLists: var string): string =
result = encodeName(t[0].sym.name.s)
result.add "I"
for i in 1..<t.len - 1:
result.add encodeType(m, t[i], staticLists)
result.add encodeType(m, t[i])
result.add "E"
of tySequence, tyOpenArray, tyArray, tyVarargs, tyTuple, tyProc, tySet, tyTypeDesc,
tyPtr, tyRef, tyVar, tyLent, tySink, tyUncheckedArray, tyOr, tyAnd, tyBuiltInTypeClass:
tyPtr, tyRef, tyVar, tyLent, tySink, tyStatic, tyUncheckedArray, tyOr, tyAnd, tyBuiltInTypeClass:
result =
case t.kind:
of tySequence: encodeName("seq")
@@ -147,13 +150,8 @@ proc encodeType*(m: BModule; t: PType; staticLists: var string): string =
for i in 0..<t.len:
let s = t[i]
if s.isNil: continue
result.add encodeType(m, s, staticLists)
result.add encodeType(m, s)
result.add "E"
of tyStatic:
if t.n != nil:
staticLists.add "_s" & renderTree(t.n)
else:
raiseAssert "unreachable"
of tyRange:
var val = "range_"
if t.n[0].typ.kind in {tyFloat..tyFloat128}:
@@ -166,7 +164,7 @@ proc encodeType*(m: BModule; t: PType; staticLists: var string): string =
of tyString..tyUInt64, tyPointer, tyBool, tyChar, tyVoid, tyAnything, tyNil, tyEmpty:
result = encodeName(kindName)
of tyAlias, tyInferred, tyOwned:
result = encodeType(m, t.elementType, staticLists)
result = encodeType(m, t.elementType)
else:
assert false, "encodeType " & $t.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
@@ -61,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,
@@ -108,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)
@@ -133,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
@@ -337,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:
@@ -444,6 +430,7 @@ proc rdCharLoc(a: TLoc): Rope =
type
TAssignmentFlag = enum
needToCopy
needToCopySinkParam
needTempForOpenArray
needAssignCall
TAssignmentFlags = set[TAssignmentFlag]
@@ -520,7 +507,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)
@@ -614,8 +601,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)
@@ -661,9 +647,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)
@@ -723,17 +708,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
@@ -773,14 +756,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
@@ -799,8 +780,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)
@@ -969,8 +949,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:
@@ -1012,10 +991,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:
@@ -1028,8 +1006,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.} =
@@ -1258,14 +1235,7 @@ proc allPathsAsgnResult(p: BProc; n: PNode): InitResultEnum =
else:
allPathsInBranch(n[i].lastSon)
of nkCallKinds:
if canRaiseDisp(p, n[0]) or
(n[0].kind == nkSym and sfNoReturn in n[0].sym.flags):
# requires initializations when encountering unreachable code
result = InitRequired
elif n[0].kind == nkSym and
n[0].sym.magic in {mUnaryMinusI..mAbsI, mAddI..mPred} and
optOverflowCheck in p.config.options:
# arithmetic operations may raise exceptions
if canRaiseDisp(p, n[0]):
result = InitRequired
else:
for i in 0..<n.safeLen:
@@ -1299,7 +1269,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 != {}
@@ -1324,7 +1294,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)
@@ -1345,11 +1315,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)
@@ -1362,12 +1330,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
@@ -1376,8 +1342,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
@@ -1460,8 +1425,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
@@ -1481,9 +1444,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)
@@ -1520,22 +1482,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])
@@ -1543,7 +1499,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),
@@ -1556,7 +1512,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)
@@ -1582,26 +1538,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)
@@ -1720,12 +1675,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):
@@ -1963,7 +1915,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,
@@ -1980,7 +1932,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):
@@ -2116,8 +2068,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):
@@ -2173,8 +2124,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():
@@ -2387,14 +2336,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:
@@ -2403,7 +2351,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
@@ -2470,23 +2419,6 @@ proc addHcrInitGuards(p: BProc, n: PNode, inInitGuard: var bool, init: var IfBui
genStmts(p, n)
proc handleProcGlobals(m: BModule) =
var procGlobals: seq[PNode] = move m.g.graph.procGlobals
for i in 0..<procGlobals.len:
var stmts = newBuilder("")
# 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)
swap stmts, m.preInitProc.s(cpsStmts)
handleProcGlobals(m)
m.preInitProc.s(cpsStmts).add stmts.extract()
proc genTopLevelStmt*(m: BModule; n: PNode) =
## Also called from `ic/cbackend.nim`.
if pipelineutils.skipCodegen(m.config, n): return
@@ -2502,8 +2434,6 @@ proc genTopLevelStmt*(m: BModule; n: PNode) =
else:
genProcBody(m.initProc, transformedN)
handleProcGlobals(m)
proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool =
if optForceFullMake notin m.config.globalOptions:
if not moduleHasChanged(m.g.graph, m.module):
@@ -2528,15 +2458,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:
@@ -2571,11 +2502,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)
@@ -2600,7 +2530,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
@@ -2653,15 +2583,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)
@@ -2673,6 +2603,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)

File diff suppressed because it is too large Load Diff

View File

@@ -364,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)
@@ -460,7 +459,7 @@ template handleStdinOrCmdInput =
conf.outDir = getNimcacheDir(conf)
proc handleStdinInput*(conf: ConfigRef) =
conf.projectName = conf.stdinFile.string
conf.projectName = "stdinfile"
conf.projectIsStdin = true
handleStdinOrCmdInput()
@@ -474,7 +473,6 @@ proc parseCommand*(command: string): Command =
of "cpp", "compiletocpp": cmdCompileToCpp
of "objc", "compiletooc": cmdCompileToOC
of "js", "compiletojs": cmdCompileToJS
of "nif": cmdCompileToNif
of "r": cmdCrun
of "m": cmdM
of "run": cmdTcc
@@ -498,8 +496,6 @@ proc parseCommand*(command: string): Command =
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) =
@@ -511,12 +507,6 @@ proc setCmd*(conf: ConfigRef, cmd: Command) =
of cmdCompileToCpp: conf.backend = backendCpp
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) =
@@ -770,16 +760,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
@@ -902,19 +882,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":
@@ -963,10 +935,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
var value: int = 0
discard parseSaturatedNatural(arg, value)
conf.errorMax = if value == 0: high(int) else: value
of "stdinfile":
expectArg(conf, switch, arg, pass, info)
conf.stdinFile = if os.isAbsolute(arg): AbsoluteFile(arg)
else: AbsoluteFile(getCurrentDir() / arg)
of "verbosity":
expectArg(conf, switch, arg, pass, info)
let verbosity = parseInt(arg)
@@ -1000,8 +968,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

View File

@@ -13,13 +13,13 @@
import ast, semdata, lookups, lineinfos, idents, msgs, renderer, types, layeredtable
import std/sets
import std/intsets
when defined(nimPreviewSlimSystem):
import std/assertions
const
logBindings = when defined(debugConcepts): true else: false
logBindings = false
## Code dealing with Concept declarations
## --------------------------------------
@@ -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)
@@ -70,89 +70,26 @@ proc semConceptDeclaration*(c: PContext; n: PNode): PNode =
## ----------------
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.
inferred: seq[(PType, PType)] ## we need a seq here so that we can easily undo inferences \
## that turned out to be wrong.
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
flags: set[MatchFlags]
MatchKind = enum
mkNoMatch, mkSubset, mkSame
const
asymmetricConceptParamMods = {tyVar, tySink, tyLent, tyOwned, tyAlias, tyInferred} # param modifiers that to not have to match implementation -> concept
bindableTypes = {tyGenericParam, tyOr, tyTypeDesc}
proc conceptMatchNode(c: PContext; n: PNode; m: var MatchCon): bool
proc matchType(c: PContext; fo, ao: PType; m: var MatchCon): bool
proc matchReturnType(c: PContext; f, a: PType; m: var MatchCon): bool
proc processConcept(c: PContext; concpt, invocation: PType, bindings: var LayeredIdTable; m: var MatchCon): bool
concpt: PType
proc existingBinding(m: MatchCon; key: PType): PType =
## checks if we bound the type variable 'key' already to some
## concrete type.
result = m.bindings.lookup(key)
if result == nil:
result = key
for i in 0..<m.inferred.len:
if m.inferred[i][0] == key: return m.inferred[i][1]
return nil
const
ignorableForArgType = {tyVar, tySink, tyLent, tyOwned, tyAlias, tyInferred}
proc conceptMatchNode(c: PContext; n: PNode; m: var MatchCon): bool
proc unrollGenericParam(param: PType): PType =
result = param.skipTypes(ignorableForArgType)
while result.kind in {tyGenericParam, tyTypeDesc} and result.hasElementType and result.elementType.kind != tyNone:
result = result.elementType
proc bindParam(c: PContext, m: var MatchCon; key, v: PType): bool {. discardable .} =
if v.kind == tyTypeDesc:
return false
var value = unrollGenericParam(v)
if value.kind == tyGenericParam:
value = existingBinding(m, value)
if value.kind == tyGenericParam:
if value.hasElementType:
value = value.elementType
else:
return true
if value.kind == tyStatic:
return false
if m.magic in {mArrPut, mArrGet} and value.kind in arrPutGetMagicApplies:
value = value.last
let old = existingBinding(m, key)
if old != key:
# 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:
# check constaint
if matchType(c, unrollGenericParam(key), value, m) == false:
return false
when logBindings: echo "bind table adding '", key, "', ", value
assert value != nil
assert value.kind != tyVoid
m.bindings.put(key, value)
return true
proc defSignatureType(n: PNode): PType = n[0].sym.typ
proc conceptBody*(n: PType): PNode = n.n.lastSon
proc matchType(c: PContext; f, ao: PType; m: var MatchCon): bool
proc acceptsAllTypes(t: PType): bool=
result = false
@@ -164,187 +101,84 @@ proc acceptsAllTypes(t: PType): bool=
if not t.hasElementType or t.elementType.kind == tyNone:
result = true
proc procDefSignature(s: PSym): PNode {. deprecated .} =
var nc = s.ast.copyNode()
for i in 0 .. 5:
nc.add s.ast[i]
nc
proc matchKids(c: PContext; f, a: PType; m: var MatchCon, start=0): bool=
result = true
for i in start ..< f.kidsLen - ord(f.kind in {tyGenericInst, tyGenericInvocation}):
for i in start..<f.kidsLen - ord(f.kind == tyGenericInst):
if not matchType(c, f[i], a[i], m): return false
iterator traverseTyOr(t: PType): PType {. closure .}=
for i in t.kids:
case i.kind:
of tyGenericParam:
if i.hasElementType:
for s in traverseTyOr(i.elementType):
yield s
else:
yield i
else:
yield i
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:
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
result = processConcept(c, concpt, invocation, oldBindings, m)
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:
return false
if fn[namePos].sym.name != an[namePos].sym.name:
return false
let
ft = fn.defSignatureType
at = an.defSignatureType
if ft.len != at.len:
return false
for i in 1 ..< ft.n.len:
m.bindings = m.bindings.newTypeMapLayer()
let aType = at.n[i].typ
let fType = ft.n[i].typ
if aType.isSelf and fType.isSelf:
continue
if not matchType(c, fType, aType, m):
m.bindings.setToPreviousLayer()
return false
result = true
if not matchReturnType(c, ft.returnType, at.returnType, m):
m.bindings.setToPreviousLayer()
result = false
proc conceptsMatch(c: PContext, fc, ac: PType; m: var MatchCon): MatchKind =
# XXX: In the future this may need extra parameters to carry info for container types
if fc.n == ac.n:
# This will have to take generic parameters into account at some point
return mkSame
let
fn = fc.conceptBody
an = ac.conceptBody
sameLen = fc.len == ac.len
var match = false
for fdef in fn:
var cmpResult = false
for ia, ndef in an:
match = cmpConceptDefs(c, fdef, ndef, m)
if match:
break
if not match:
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 =
proc matchType(c: PContext; f, 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
## of a routine that might match.
const
ignorableForArgType = {tyVar, tySink, tyLent, tyOwned, tyGenericInst, tyAlias, tyInferred}
var
a = ao
f = fo
if a.isSelf:
if m.magic in {mArrPut, mArrGet}:
return false
a = m.potentialImplementation
if a.kind in bindableTypes:
a = existingBinding(m, ao)
if a == ao and a.kind == tyGenericParam and a.hasElementType and a.elementType.kind != tyNone:
a = a.elementType
var a = ao
if f.isConcept:
if a.acceptsAllTypes:
return false
if a.skipTypes(ignorableForArgType).isConcept:
# if f is a subset of a then any match to a will also match f. Not the other way around
return conceptsMatch(c, a.reduceToBase, f.reduceToBase, m) >= mkSubset
else:
return matchConceptToImpl(c, f, a, m)
case a.kind
of tyGenericParam:
let binding = m.existingBinding(a)
if binding != nil:
a = binding
else:
discard
result = false
case f.kind
of tyAlias:
result = matchType(c, f.skipModifier, a, m)
of tyTypeDesc:
if isSelf(f):
let ua = a.skipTypes(asymmetricConceptParamMods)
if m.magic in {mArrPut, mArrGet}:
result = false
if m.potentialImplementation.reduceToBase.kind in arrPutGetMagicApplies:
bindParam(c, m, a, last m.potentialImplementation)
m.inferred.add((a, last m.potentialImplementation))
result = true
#elif ua.isConcept:
# result = matchType(c, m.concpt, ua, m)
else:
result = matchType(c, a.skipTypes(ignorableForArgType), m.potentialImplementation, m)
result = matchType(c, a, m.potentialImplementation, m)
else:
if a.kind == tyTypeDesc:
if not(a.hasElementType) or a.elementType.kind == tyNone:
result = true
elif f.hasElementType:
if a.kind == tyTypeDesc and f.hasElementType == a.hasElementType:
if f.hasElementType:
result = matchType(c, f.elementType, a.elementType, m)
else:
result = true # both lack it
else:
result = false
of tyGenericInvocation:
result = false
if a.kind == tyGenericInst and a.genericHead.kind == tyGenericBody:
if sameType(f.genericHead, a.genericHead) and f.kidsLen == a.kidsLen-1:
result = matchKids(c, f, a, m, start=FirstGenericParamAt)
of tyGenericParam:
let ak = a.skipTypes({tyVar, tySink, tyLent, tyOwned})
if ak.kind in {tyTypeDesc, tyStatic} and not isSelf(ak):
result = false
else:
let old = existingBinding(m, f)
if old == nil:
if f.hasElementType and f.elementType.kind != tyNone:
# also check the generic's constraints:
let oldLen = m.inferred.len
result = matchType(c, f.elementType, a, m)
m.inferred.setLen oldLen
if result:
when logBindings: echo "A adding ", f, " ", ak
m.inferred.add((f, ak))
elif m.magic == mArrGet and ak.kind in {tyArray, tyOpenArray, tySequence, tyVarargs, tyCstring, tyString}:
when logBindings: echo "B adding ", f, " ", last ak
m.inferred.add((f, last ak))
result = true
else:
when logBindings: echo "C adding ", f, " ", ak
m.inferred.add((f, ak))
#echo "binding ", typeToString(ak), " to ", typeToString(f)
result = true
elif not m.marker.containsOrIncl(old.id):
result = matchType(c, old, ak, m)
if m.magic == mArrPut and ak.kind == tyGenericParam:
result = true
else:
result = false
#echo "B for ", result, " to ", typeToString(a), " to ", typeToString(m.potentialImplementation)
of tyVar, tySink, tyLent, tyOwned:
# modifiers in the concept must be there in the actual implementation
# too but not vice versa.
@@ -352,59 +186,91 @@ proc matchType(c: PContext; fo, ao: PType; m: var MatchCon): bool =
result = matchType(c, f.elementType, a.elementType, m)
elif m.magic == mArrPut:
result = matchType(c, f.elementType, a, m)
of tyEnum, tyObject, tyDistinct:
if a.kind in ignorableForArgType:
result = matchType(c, f, a.skipTypes(ignorableForArgType), m)
else:
if a.kind == tyGenericInst:
# tyOr does this to generic typeclasses
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)
result = false
of tyEnum, tyObject, tyDistinct:
result = sameType(f, a)
of tyEmpty, tyString, tyCstring, tyPointer, tyNil, tyUntyped, tyTyped, tyVoid:
result = a.skipTypes(ignorableForArgType).kind == f.kind
of tyBool, tyChar, tyInt..tyUInt64:
let ak = a.skipTypes(ignorableForArgType)
result = ak.kind == f.kind or ak.kind == tyOrdinal or
(ak.kind == tyGenericParam and ak.hasElementType and ak.elementType.kind == tyOrdinal)
of tyArray, tyTuple, tyVarargs, tyOpenArray, tyRange, tySequence, tyRef, tyPtr:
if f.kind == tyArray and f.kidsLen == 3 and a.kind == tyArray:
(ak.kind == tyGenericParam and ak.hasElementType and ak.elementType.kind == tyOrdinal)
of tyConcept:
if a.kind == tyConcept and f.n == a.n:
result = true
elif m.concpt.size == szIllegalRecursion:
result = false
else:
let oldLen = m.inferred.len
let oldPotentialImplementation = m.potentialImplementation
m.potentialImplementation = a
m.concpt.size = szIllegalRecursion
let oldConcept = m.concpt
m.concpt = f
result = conceptMatchNode(c, f.n.lastSon, m)
m.potentialImplementation = oldPotentialImplementation
m.concpt = oldConcept
m.concpt.size = szUnknownSize
if not result:
m.inferred.setLen oldLen
of tyGenericBody:
var ak = a
if a.kind == tyGenericBody:
ak = last(a)
result = matchType(c, last(f), ak, m)
of tyCompositeTypeClass:
var ak = if a.kind == tyCompositeTypeClass: a.last else: a
result = matchType(c, last(f), ak, m)
of tyArray, tyTuple, tyVarargs, tyOpenArray, tyRange, tySequence, tyRef, tyPtr,
tyGenericInst:
# ^ XXX Rewrite this logic, it's more complex than it needs to be.
if f.kind == tyArray and f.kidsLen == 3:
# XXX: this is a work-around!
# system.nim creates these for the magic array typeclass
result = true
else:
result = false
let ak = a.skipTypes(ignorableForArgType - {f.kind})
if ak.kind == f.kind:
if f.base.kind == tyNone:
result = true
elif f.kidsLen == ak.kidsLen:
result = matchKids(c, f, ak, m)
of tyGenericInvocation, tyGenericInst:
result = false
let ea = a.skipTypes(ignorableForArgType)
if ea.kind in {tyGenericInst, tyGenericInvocation}:
var
k1 = f.kidsLen - ord(f.kind == tyGenericInst)
k2 = ea.kidsLen - ord(ea.kind == tyGenericInst)
if sameType(f.genericHead, ea.genericHead) and k1 == k2:
result = true
for i in 1 ..< k2:
if not matchType(c, f[i], ea[i], m):
result = false
if ak.kind == f.kind and f.kidsLen == ak.kidsLen:
result = matchKids(c, f, ak, m)
of tyOr:
let oldLen = m.inferred.len
if a.kind == tyOr:
# say the concept requires 'int|float|string' if the potentialImplementation
# says 'int|string' that is good enough.
var covered = 0
for ff in f.kids:
for aa in a.kids:
let oldLenB = m.inferred.len
let r = matchType(c, ff, aa, m)
if r:
inc covered
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)
m.inferred.setLen oldLenB
result = covered >= a.kidsLen
if not result:
m.inferred.setLen oldLen
else:
result = false
for ff in f.kids:
result = matchType(c, ff, a, m)
if result: break # and remember the binding!
m.inferred.setLen oldLen
of tyNot:
if a.kind == tyNot:
result = matchType(c, f.elementType, a.elementType, m)
else:
let oldLen = m.inferred.len
result = not matchType(c, f.elementType, a, m)
m.inferred.setLen oldLen
of tyAnything:
result = true
of tyOrdinal:
result = isOrdinalType(a, allowEnumWithHoles = false) or a.kind == tyGenericParam
of tyStatic:
result = false
var scomp = f.base
if scomp.kind == tyGenericParam:
if f.base.kidsLen > 0:
@@ -413,75 +279,8 @@ proc matchType(c: PContext; fo, ao: PType; m: var MatchCon): bool =
result = matchType(c, scomp, a.base, m)
else:
result = matchType(c, scomp, a, m)
of tyGenericParam:
if a.acceptsAllTypes:
discard bindParam(c, m, f, a)
result = f.acceptsAllTypes
else:
result = bindParam(c, m, f, a)
of tyAnything:
result = true
of tyNot:
if a.kind == tyNot:
result = matchType(c, f.elementType, a.elementType, m)
else:
m.bindings = m.bindings.newTypeMapLayer()
result = not matchType(c, f.elementType, a, m)
m.bindings.setToPreviousLayer()
of tyAnd:
m.bindings = m.bindings.newTypeMapLayer()
result = true
for ff in traverseTyOr(f):
let r = matchType(c, ff, a, m)
if not r:
m.bindings.setToPreviousLayer()
result = false
break
of tyGenericBody:
var ak = a
if a.kind == tyGenericBody:
ak = last(a)
result = matchType(c, last(f), ak, m)
of tyCompositeTypeClass:
if a.kind == tyCompositeTypeClass:
result = matchKids(c, f, a, m)
else:
result = matchType(c, last(f), a, m)
of tyBuiltInTypeClass:
let target = f.genericHead.kind
result = a.skipTypes(ignorableForArgType).reduceToBase.kind == target
of tyOr:
if a.kind == tyOr:
var covered = 0
for ff in traverseTyOr(f):
for aa in traverseTyOr(a):
m.bindings = m.bindings.newTypeMapLayer()
let r = matchType(c, ff, aa, m)
if r:
inc covered
break
m.bindings.setToPreviousLayer()
result = covered >= a.kidsLen
else:
for ff in f.kids:
m.bindings = m.bindings.newTypeMapLayer()
result = matchType(c, ff, a, m)
if result: break # and remember the binding!
m.bindings.setToPreviousLayer()
of tySet:
result = false
if a.kind == tySet:
result = matchType(c, f.elementType, a.elementType, m)
else:
result = false
if result and ao.kind == tyGenericParam:
let bf = if f.isSelf: m.potentialImplementation else: f
if bindParam(c, m, ao, bf):
when logBindings: echo " ^ reverse binding"
proc checkConstraint(c: PContext; f, a: PType; m: var MatchCon): bool =
result = matchType(c, f, a, m) or matchType(c, a, f, m)
proc matchReturnType(c: PContext; f, a: PType; m: var MatchCon): bool =
## Like 'matchType' but with extra logic dealing with proc return types
@@ -491,38 +290,30 @@ proc matchReturnType(c: PContext; f, a: PType; m: var MatchCon): bool =
elif a == nil:
result = false
else:
result = checkConstraint(c, f, a, m)
result = matchType(c, f, a, m)
proc matchSym(c: PContext; candidate: PSym, n: PNode; m: var MatchCon): bool =
## Checks if 'candidate' matches 'n' from the concept body. 'n' is a nkProcDef
## or similar.
# watch out: only add bindings after a completely successful match.
m.bindings = m.bindings.newTypeMapLayer()
let oldLen = m.inferred.len
let can = candidate.typ.n
let con = defSignatureType(n).n
let con = n[0].sym.typ.n
if can.len < con.len:
# too few arguments, cannot be a match:
return false
if can.len > con.len:
# too many arguments (not optional)
for i in con.len ..< can.len:
if can[i].sym.ast == nil:
return false
when defined(debugConcepts):
echo "considering: ", renderTree(candidate.procDefSignature), " ", candidate.magic
let common = min(can.len, con.len)
for i in 1 ..< common:
if not checkConstraint(c, con[i].typ, can[i].typ, m):
m.bindings.setToPreviousLayer()
if not matchType(c, con[i].typ, can[i].typ, m):
m.inferred.setLen oldLen
return false
if not matchReturnType(c, n.defSignatureType.returnType, candidate.typ.returnType, m):
m.bindings.setToPreviousLayer()
if not matchReturnType(c, n[0].sym.typ.returnType, candidate.typ.returnType, m):
m.inferred.setLen oldLen
return false
# all other parameters have to be optional parameters:
@@ -530,7 +321,7 @@ proc matchSym(c: PContext; candidate: PSym, n: PNode; m: var MatchCon): bool =
assert can[i].kind == nkSym
if can[i].sym.ast == nil:
# has too many arguments one of which is not optional:
m.bindings.setToPreviousLayer()
m.inferred.setLen oldLen
return false
return true
@@ -538,14 +329,13 @@ proc matchSym(c: PContext; candidate: PSym, n: PNode; m: var MatchCon): bool =
proc matchSyms(c: PContext, n: PNode; kinds: set[TSymKind]; m: var MatchCon): bool =
## Walk the current scope, extract candidates which the same name as 'n[namePos]',
## 'n' is the nkProcDef or similar from the concept that we try to match.
result = false
var candidates = searchScopes(c, n[namePos].sym.name, kinds)
searchImportsAll(c, n[namePos].sym.name, kinds, candidates)
for candidate in candidates:
#echo "considering ", typeToString(candidate.typ), " ", candidate.magic
m.magic = candidate.magic
if matchSym(c, candidate, n, m):
result = true
break
if matchSym(c, candidate, n, m): return true
result = false
proc conceptMatchNode(c: PContext; n: PNode; m: var MatchCon): bool =
## Traverse the concept's AST ('n') and see if every declaration inside 'n'
@@ -578,48 +368,7 @@ proc conceptMatchNode(c: PContext; n: PNode; m: var MatchCon): bool =
# error was reported earlier.
result = false
proc fixBindings(bindings: var LayeredIdTable; concpt: PType; invocation: PType; m: var MatchCon) =
# invocation != nil means we have a non-atomic concept:
if invocation != nil and invocation.kind == tyGenericInvocation:
assert concpt.sym.typ.kind == tyGenericBody
for i in 0 .. concpt.sym.typ.len - 1:
let thisSym = concpt.sym.typ[i]
if lookup(bindings, thisSym) != nil:
# dont trust the bindings over existing ones
continue
let found = m.bindings.lookup(thisSym)
if found != nil:
when logBindings: echo "Invocation bind: ", thisSym, " ", found
bindings.put(thisSym, found)
# bind even more generic parameters
let genBody = invocation.base
assert genBody.kind == tyGenericBody
for i in FirstGenericParamAt ..< invocation.kidsLen:
let bpram = genBody[i - 1]
if lookup(bindings, invocation[i]) != nil:
# dont trust the bindings over existing ones
continue
let boundV = lookup(bindings, bpram)
when logBindings: echo "generic body bind: '", invocation[i], "' '", boundV, "'"
if boundV != nil:
bindings.put(invocation[i], boundV)
bindings.put(concpt, m.potentialImplementation)
proc processConcept(c: PContext; concpt, invocation: PType, bindings: var LayeredIdTable; m: var MatchCon): bool =
m.bindings = m.bindings.newTypeMapLayer()
if invocation != nil and invocation.kind == tyGenericInst:
let genericBody = invocation.base
for i in 1..<invocation.kidsLen-1:
# instGenericContainer can bind `tyVoid`
if invocation[i].kind != tyVoid:
bindParam(c, m, genericBody[i-1], invocation[i])
result = conceptMatchNode(c, concpt.conceptBody, m)
if result and mfDontBind notin m.flags:
fixBindings(bindings, concpt, invocation, m)
proc conceptMatch*(c: PContext; concpt, arg: PType; bindings: var LayeredIdTable; invocation: PType, flags: set[MatchFlags] = {}): bool =
proc conceptMatch*(c: PContext; concpt, arg: PType; bindings: var LayeredIdTable; invocation: PType): bool =
## Entry point from sigmatch. 'concpt' is the concept we try to match (here still a PType but
## we extract its AST via 'concpt.n.lastSon'). 'arg' is the type that might fulfill the
## concept's requirements. If so, we return true and fill the 'bindings' with pairs of
@@ -628,16 +377,28 @@ 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]())
if arg.isConcept:
result = conceptsMatch(c, concpt.reduceToBase, arg.reduceToBase, m) >= mkSubset
elif arg.acceptsAllTypes:
# XXX: I think this is wrong, or at least partially wrong. Can still test ambiguous types
result = false
elif mfCheckGeneric in m.flags:
# prioritize concepts the least. Specifically if the arg is not a catch all as per above
result = true
else:
result = processConcept(c, concpt, invocation, bindings, m)
if arg.containsUnresolvedType:
return false
var m = MatchCon(inferred: @[], potentialImplementation: arg, concpt: concpt)
result = conceptMatchNode(c, concpt.n.lastSon, m)
if result:
for (a, b) in m.inferred:
if b.kind == tyGenericParam:
var dest = b
while true:
dest = existingBinding(m, dest)
if dest == nil or dest.kind != tyGenericParam: break
if dest != nil:
bindings.put(a, dest)
when logBindings: echo "A bind ", a, " ", dest
else:
bindings.put(a, b)
when logBindings: echo "B bind ", a, " ", b
# we have a match, so bind 'arg' itself to 'concpt':
bindings.put(concpt, arg)
# invocation != nil means we have a non-atomic concept:
if invocation != nil and arg.kind == tyGenericInst and invocation.kidsLen == arg.kidsLen-1:
# bind even more generic parameters
assert invocation.kind == tyGenericInvocation
for i in FirstGenericParamAt ..< invocation.kidsLen:
bindings.put(invocation[i], arg[i])

View File

@@ -172,6 +172,3 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimHasDefaultFloatRoundtrip")
defineSymbol("nimHasXorSet")
defineSymbol("nimHasSetLengthSeqUninitMagic")
defineSymbol("nimHasPreviewDuplicateModuleError")

View File

@@ -1,389 +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]
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
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
createDir("nifcache")
result = "nifcache" / c.nodes[0].files[0].modname & ".build.nif"
#getNimcacheDir(c.config).string / 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:nifcache"
# 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:nifcache"
# 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: @[]
)
# 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
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

@@ -439,8 +439,8 @@ proc gen(c: var Con; n: PNode) =
genUse(c, n)
of nkIfStmt, nkIfExpr: genIf(c, n)
of nkWhenStmt:
# This is "when nimvm" node. Chose the second branch.
gen(c, n[1][0])
# This is "when nimvm" node. Chose the first branch.
gen(c, n[0][1])
of nkCaseStmt: genCase(c, n)
of nkWhileStmt: genWhile(c, n)
of nkBlockExpr, nkBlockStmt: genBlock(c, n)

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
@@ -1320,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)
@@ -1406,14 +1406,11 @@ proc generateDoc*(d: PDoc, n, orig: PNode, config: ConfigRef, docFlags: DocFlags
for it in n: traceDeps(d, it)
of nkExportStmt:
for it in n:
if it.kind == nkSym:
if d.module != nil and d.module == it.sym.owner: # in current module
# bug #23051; don't generate documentation for exported symbols again
if sfExported notin it.sym.flags:
generateDoc(d, it.sym.ast, orig, config, kForceExport)
# else it's to be handled in `of XxxSection` branch
# bug #23051; don't generate documentation for exported symbols again
if it.kind == nkSym and sfExported notin it.sym.flags:
if d.module != nil and d.module == it.sym.owner:
generateDoc(d, it.sym.ast, orig, config, kForceExport)
elif it.sym.ast != nil:
# only export symbols in imported modules, not in current module
exportSym(d, it.sym)
of nkExportExceptStmt: discard "transformed into nkExportStmt by semExportExcept"
of nkFromStmt, nkImportExceptStmt: traceDeps(d, n[0])
@@ -1892,9 +1889,6 @@ proc commandJson*(cache: IdentCache, conf: ConfigRef) =
else:
#echo getOutFile(gProjectFull, JsonExt)
let filename = getOutFile(conf, RelativeFile conf.projectName, JsonExt)
conf.outFile = filename.relativeTo(conf.outDir)
let dir = filename.splitFile.dir
createDir(dir)
try:
writeFile(filename, content)
except IOError:
@@ -1915,10 +1909,8 @@ proc commandTags*(cache: IdentCache, conf: ConfigRef) =
if optStdout in d.conf.globalOptions:
write(stdout, content)
else:
#echo getOutFile(gProjectFull, TagsExt)
let filename = getOutFile(conf, RelativeFile conf.projectName, TagsExt)
conf.outFile = filename.relativeTo(conf.outDir)
let dir = filename.splitFile.dir
createDir(dir)
try:
writeFile(filename, content)
except IOError:

View File

@@ -33,10 +33,6 @@ proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph; idgen: IdGener
caseStmt.add newTree(nkOfBranch, newIntTypeNode(field.position, t),
newTree(nkStmtList, newTree(nkFastAsgn, newSymNode(res), newStrNode(val, info))))
#newIntTypeNode(nkIntLit, field.position, t)
# safety branch for invalid data:
caseStmt.add newTree(nkElse,
newTree(nkStmtList, newTree(nkFastAsgn, newSymNode(res),
newStrNode("", info))))
body.add(caseStmt)
@@ -47,7 +43,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 +106,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

@@ -257,8 +257,8 @@ compiler tcc:
linkerExe: "tcc",
linkTmpl: "-o $exefile $options $buildgui $builddll $objfiles",
includeCmd: " -I",
linkDirCmd: " -L",
linkLibCmd: " -l$1",
linkDirCmd: "", # XXX: not supported yet
linkLibCmd: "", # XXX: not supported yet
debug: " -g ",
pic: "",
asmStmtFrmt: "asm($1);$n",
@@ -341,7 +341,7 @@ proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string =
var fullSuffix = suffix
case conf.backend
of backendCpp, backendJs, backendObjc: fullSuffix = "." & $conf.backend & suffix
of backendC, backendNif: discard
of backendC: discard
of backendInvalid:
# during parsing of cfg files; we don't know the backend yet, no point in
# guessing wrong thing
@@ -474,11 +474,6 @@ proc noAbsolutePaths(conf: ConfigRef): bool {.inline.} =
proc cFileSpecificOptions(conf: ConfigRef; nimname, fullNimFile: string): string =
result = conf.compileOptions
if (conf.cCompiler == ccGcc or conf.cCompiler == ccCLang) and
conf.selectedGC == gcRefc:
# bug #10625
addOpt(result, "-fno-omit-frame-pointer")
for option in conf.compileOptionsCmd:
if strutils.find(result, option, 0) < 0:
addOpt(result, option)
@@ -810,59 +805,6 @@ template tryExceptOSErrorMessage(conf: ConfigRef; errorPrefix: string = "", body
(ose.msg & " " & $ose.errorCode))
raise
proc createMacAppBundle(conf: ConfigRef; exefile: AbsoluteFile) =
let (dir, name, _) = splitFile(exefile.string)
let appBundleName = name & ".app"
let appBundlePath = dir / appBundleName
let contentsPath = appBundlePath / "Contents"
let macosPath = contentsPath / "MacOS"
createDir(macosPath)
let bundleExePath = macosPath / name
copyFileWithPermissions(exefile.string, bundleExePath)
let infoPlistPath = contentsPath / "Info.plist"
proc xmlEscape(s: string): string =
result = newStringOfCap(s.len)
for c in items(s):
case c:
of '<': result.add("&lt;")
of '>': result.add("&gt;")
of '&': result.add("&amp;")
of '"': result.add("&quot;")
of '\'': result.add("&apos;")
else:
if ord(c) < 32:
result.add("&#" & $ord(c) & ';')
else:
result.add(c)
let escapedName = xmlEscape(name)
let infoPlistContent = """<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>$1</string>
<key>CFBundleIdentifier</key>
<string>com.nim.$1</string>
<key>CFBundleName</key>
<string>$1</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>LSUIElement</key>
<string>1</string>
</dict>
</plist>""" % [escapedName]
writeFile(infoPlistPath, infoPlistContent)
removeFile(exefile.string)
rawMessage(conf, hintUserRaw, "Created Mac app bundle: " & appBundlePath)
proc getExtraCmds(conf: ConfigRef; output: AbsoluteFile): seq[string] =
result = @[]
when defined(macosx):
@@ -1047,10 +989,6 @@ proc callCCompiler*(conf: ConfigRef) =
preventLinkCmdMaxCmdLen(conf, linkCmd)
for cmd in extraCmds:
execExternalProgram(conf, cmd, hintExecuting)
# create Mac app bundle for GUI apps on macOS
when defined(macosx):
if conf.globalOptions * {optGenGuiApp, optGenDynLib, optGenStaticLib} == {optGenGuiApp}:
createMacAppBundle(conf, mainOutput)
else:
linkCmd = ""
if optGenScript in conf.globalOptions:

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)

View File

@@ -37,10 +37,11 @@ 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, idgenFromLoadedModule(m))
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).mods[m.module.position]
var bmod = BModuleList(g.backend).modules[m.module.position]
assert bmod != nil
bmod.flags.incl useAliveDataFromDce
bmod.alive = move alive[m.module.position]
@@ -51,7 +52,7 @@ proc generateCodeForModule(g: ModuleGraph; m: var LoadedModule; alive: var Alive
finalCodegenActions(g, bmod, newNodeI(nkStmtList, m.module.info))
for disp in getDispatchers(g):
genProcLvl3(bmod, disp)
genProcAux(bmod, disp)
m.fromDisk.backendFlags = cgen.whichInitProcs(bmod)
proc replayTypeInfo(g: ModuleGraph; m: var LoadedModule; origin: FileIndex) =

File diff suppressed because it is too large Load Diff

View File

@@ -370,14 +370,8 @@ proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemI
paddingAtEnd: t.paddingAtEnd)
storeNode(p, t, n)
p.typeInst = t.typeInst.storeType(c, m)
if t.kind == tyProc and t.len > 0:
# if kind == tyProc, parameter types are stored in t.n
# and you can access them with `kits` iterator.
# return type is stored in t.sons[0].
p.types.add t[0].storeType(c, m)
else:
for kid in kids t:
p.types.add kid.storeType(c, m)
for kid in kids t:
p.types.add kid.storeType(c, m)
c.addMissing t.sym
p.sym = t.sym.safeItemId(c, m)
c.addMissing t.owner
@@ -844,7 +838,7 @@ proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
of nkSym:
result.sym = loadSym(c, g, thisModule, PackedItemId(module: LitId(0), item: tree[n].soperand))
if result.typ == nil:
result.typ = result.sym.typ
result.typ() = result.sym.typ
of externIntLit:
result.intVal = g[thisModule].fromDisk.numbers[n.litId]
of nkStrLit..nkTripleStrLit:
@@ -858,7 +852,7 @@ proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
transitionNoneToSym(result)
result.sym = loadSym(c, g, thisModule, PackedItemId(module: n1.litId, item: tree[n2].soperand))
if result.typ == nil:
result.typ = result.sym.typ
result.typ() = result.sym.typ
else:
for n0 in sonsReadonly(tree, n):
result.addAllowNil loadNodes(c, g, thisModule, tree, n0)
@@ -905,11 +899,11 @@ proc moduleIndex*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: in
proc symHeaderFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
s: PackedSym; si, item: int32): PSym =
result = PSym(itemId: ItemId(module: si, item: item),
kindImpl: s.kind, magicImpl: s.magic, flagsImpl: s.flags,
infoImpl: translateLineInfo(c, g, si, s.info),
optionsImpl: s.options,
positionImpl: if s.kind in {skForVar, skVar, skLet, skTemp}: 0 else: s.position,
offsetImpl: if s.kind in routineKinds: defaultOffset else: s.offset,
kind: s.kind, magic: s.magic, flags: s.flags,
info: translateLineInfo(c, g, si, s.info),
options: s.options,
position: if s.kind in {skForVar, skVar, skLet, skTemp}: 0 else: s.position,
offset: if s.kind in routineKinds: defaultOffset else: s.offset,
disamb: s.disamb,
name: getIdent(c.cache, g[si].fromDisk.strings[s.name])
)
@@ -951,8 +945,8 @@ proc symBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
setOwner(result, loadSym(c, g, si, s.owner))
let externalName = g[si].fromDisk.strings[s.externalName]
if externalName != "":
result.locImpl.snippet = externalName
result.locImpl.flags = s.locFlags
result.loc.snippet = externalName
result.loc.flags = s.locFlags
result.instantiatedFrom = loadSym(c, g, si, s.instantiatedFrom)
proc needsRecompile(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
@@ -996,10 +990,10 @@ proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s:
proc typeHeaderFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
t: PackedType; si, item: int32): PType =
result = PType(itemId: ItemId(module: si, item: t.nonUniqueId), kind: t.kind,
flagsImpl: t.flags, sizeImpl: t.size, alignImpl: t.align,
paddingAtEndImpl: t.paddingAtEnd,
flags: t.flags, size: t.size, align: t.align,
paddingAtEnd: t.paddingAtEnd,
uniqueId: ItemId(module: si, item: item),
callConvImpl: t.callConv)
callConv: t.callConv)
proc typeBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
t: PackedType; si, item: int32; result: PType) =
@@ -1064,12 +1058,12 @@ proc setupLookupTables(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCa
let filename = AbsoluteFile toFullPath(conf, 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.
m.module = PSym(kindImpl: skModule, itemId: ItemId(module: int32(fileIdx), item: 0'i32),
m.module = PSym(kind: skModule, itemId: ItemId(module: int32(fileIdx), item: 0'i32),
name: getIdent(cache, splitFile(filename).name),
infoImpl: newLineInfo(fileIdx, 1, 1),
positionImpl: int(fileIdx))
info: newLineInfo(fileIdx, 1, 1),
position: int(fileIdx))
setOwner(m.module, getPackage(conf, cache, fileIdx))
m.module.flagsImpl = m.fromDisk.moduleFlags
m.module.flags = m.fromDisk.moduleFlags
proc loadToReplayNodes(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
fileIdx: FileIndex; m: var LoadedModule) =

View File

@@ -7,7 +7,7 @@
# distribution, for details about the copyright.
#
## Supports the "nim check --ic:legacy --defusages:FILE,LINE,COL"
## 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.

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
@@ -245,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:

View File

@@ -24,7 +24,7 @@ import std/[strtabs, tables, strutils, intsets]
when defined(nimPreviewSlimSystem):
import std/assertions
from trees import exprStructuralEquivalent, getRoot, whichPragma, getPotentialWrites
from trees import exprStructuralEquivalent, getRoot, whichPragma
type
Con = object
@@ -100,7 +100,6 @@ when false:
proc isLastReadImpl(n: PNode; c: var Con; scope: var Scope): bool =
let root = parampatterns.exprRoot(n, allowCalls=false)
if root == nil: return false
elif sfSingleUsedTemp in root.flags: return true
var s = addr(scope)
while s != nil:
@@ -163,16 +162,13 @@ proc isLastReadImpl(n: PNode; c: var Con; scope: var Scope): bool =
else:
result = false
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, gcAtomicArc} and
typ.kind == tyObject and not isTrivial(getAttachedOp(c.graph, typ, attachedAsgn)))
proc isLastRead(n: PNode; c: var Con; s: var Scope): bool =
if not hasDestructorOrAsgn(c, n.typ): return true
# bug #23354; an object type could have a non-trival assignements when it is passed to a sink parameter
if not hasDestructor(c, n.typ) and (n.typ.kind != tyObject or isTrival(getAttachedOp(c.graph, n.typ, attachedAsgn))): return true
let m = skipConvDfa(n)
result = isLastReadImpl(n, c, s)
result = (m.kind == nkSym and sfSingleUsedTemp in m.sym.flags) or
isLastReadImpl(n, c, s)
proc isFirstWrite(n: PNode; c: var Con): bool =
let m = skipConvDfa(n)
@@ -189,11 +185,10 @@ proc isCursor(n: PNode): bool =
else:
false
template isFullyUnpackedTuple(n: PNode): bool =
template isUnpackedTuple(n: PNode): bool =
## we move out all elements of unpacked tuples,
## hence unpacked tuples themselves don't need to be destroyed
## except it's already a cursor
## restricted to `skTemp`, tuple temps where not every field is unpacked should not use `skTemp`
(n.kind == nkSym and n.sym.kind == skTemp and
n.sym.typ.kind == tyTuple and sfCursor notin n.sym.flags)
@@ -202,8 +197,7 @@ proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string; inferredFr
if inferredFromCopy:
m.add ", which is inferred from unavailable '=copy'"
if (opname == "=" or opname == "=copy" or opname == "=dup") and
ri != nil:
if (opname == "=" or opname == "=copy" or opname == "=dup") and ri != nil:
m.add "; requires a copy because it's not the last read of '"
m.add renderTree(ri)
m.add '\''
@@ -253,12 +247,7 @@ proc genOp(c: var Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode
dbg:
if kind == attachedDestructor:
echo "destructor is ", op.id, " ", op.ast
if sfError in op.flags:
if ri != nil:
checkForErrorPragma(c, t, ri, AttachedOpToStr[kind])
else:
# uses the lineinfos of `dest` is `ri` is not available
checkForErrorPragma(c, t, dest, AttachedOpToStr[kind])
if sfError in op.flags: checkForErrorPragma(c, t, ri, AttachedOpToStr[kind])
c.genOp(op, dest)
proc genDestroy(c: var Con; dest: PNode): PNode =
@@ -286,7 +275,7 @@ proc deepAliases(dest, ri: PNode): bool =
return aliases(dest, ri) != no
proc genSink(c: var Con; s: var Scope; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNode =
if (c.inLoopCond == 0 and (isFullyUnpackedTuple(dest) or IsDecl in flags or
if (c.inLoopCond == 0 and (isUnpackedTuple(dest) or IsDecl in flags or
(isAnalysableFieldAccess(dest, c.owner) and isFirstWrite(dest, c)))) or
isNoInit(dest) or IsReturn in flags:
# optimize sink call into a bitwise memcopy
@@ -343,7 +332,7 @@ proc genMarkCyclic(c: var Con; result, dest: PNode) =
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 =
@@ -411,7 +400,7 @@ proc genWasMoved(c: var Con, n: PNode): PNode =
result = genOp(c, op, n)
else:
result = newNodeI(nkCall, n.info)
result.add(newSymNode(createMagic(c.graph, c.idgen, "wasMoved", mWasMoved)))
result.add(newSymNode(createMagic(c.graph, c.idgen, "`=wasMoved`", mWasMoved)))
result.add copyTree(n) #mWasMoved does not take the address
#if n.kind != nkSym:
# message(c.graph.config, n.info, warnUser, "wasMoved(" & $n & ")")
@@ -419,7 +408,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)
@@ -460,7 +449,7 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
let nTyp = n.typ.skipTypes(tyUserTypeClasses)
let tmp = c.getTemp(s, nTyp, n.info)
if hasDestructorOrAsgn(c, nTyp):
if hasDestructor(c, nTyp):
let typ = nTyp.skipTypes({tyGenericInst, tyAlias, tySink})
let op = getAttachedOp(c.graph, typ, attachedDup)
if op != nil and tfHasOwned notin typ.flags:
@@ -570,7 +559,7 @@ proc cycleCheck(n: PNode; c: var Con) =
proc pVarTopLevel(v: PNode; c: var Con; s: var Scope; res: PNode) =
# move the variable declaration to the top of the frame:
s.vars.add v.sym
if isFullyUnpackedTuple(v):
if isUnpackedTuple(v):
if c.inLoop > 0:
# unpacked tuple needs reset at every loop iteration
res.add newTree(nkFastAsgn, v, genDefaultCall(v.typ, c, v.info))
@@ -825,9 +814,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}:
@@ -946,9 +935,6 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
of nkVarSection, nkLetSection:
# transform; var x = y to var x; x op y where op is a move or copy
result = newNodeI(nkStmtList, n.info)
let isInProc = c.owner.kind in {skProc, skFunc, skMethod, skIterator, skConverter}
for it in n:
var ri = it[^1]
if it.kind == nkVarTuple and hasDestructor(c, ri.typ):
@@ -964,15 +950,7 @@ 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
{sfPure, sfGlobal} <= v.sym.flags and
isInProc
if isGlobalPragma:
c.graph.procGlobals.add newTree(nkFastAsgn, v, ri)
else:
let value = moveOrCopy(v, ri, c, s, if v.kind == nkSym: {IsDecl} else: {})
result.add value
result.add moveOrCopy(v, ri, c, s, if v.kind == nkSym: {IsDecl} else: {})
elif ri.kind == nkEmpty and c.inLoop > 0:
let skipInit = v.kind == nkDotExpr and # Closure var
sfNoInit in v[1].sym.flags
@@ -1036,9 +1014,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)
@@ -1144,25 +1122,6 @@ proc genFieldAccessSideEffects(c: var Con; s: var Scope; dest, ri: PNode; flags:
var snk = c.genSink(s, dest, newAccess, flags)
result = newTree(nkStmtList, v, snk, c.genWasMoved(newAccess))
proc ownsData(c: var Con; s: var Scope; orig: PNode; flags: set[MoveOrCopyFlag]): PNode =
var n = orig
while true:
case n.kind
of nkDotExpr, nkCheckedFieldExpr, nkBracketExpr:
n = n[0]
else:
break
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
result.add newTree(nkFastAsgn, tmp, copyTree(n))
s.final.add c.genDestroy(tmp)
n[] = tmp[]
result.add copyTree(orig)
else:
result = nil
proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopyFlag] = {}): PNode =
var ri = ri
var isEnsureMove = 0
@@ -1189,7 +1148,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
of nkCallKinds:
result = c.genSink(s, dest, p(ri, c, s, consumed), flags)
of nkBracketExpr:
if isFullyUnpackedTuple(ri[0]):
if isUnpackedTuple(ri[0]):
# unpacking of tuple: take over the elements
result = c.genSink(s, dest, p(ri, c, s, consumed), flags)
elif isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c, s):
@@ -1238,22 +1197,15 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
result.add p(ri, c, s, consumed)
c.finishCopy(result, dest, flags, isFromSink = false)
of nkHiddenSubConv, nkHiddenStdConv, nkConv, nkObjDownConv, nkObjUpConv, nkCast:
if IsExplicitSink in flags:
result = c.genSink(s, dest, p(ri, c, s, consumed), flags)
else:
result = c.genSink(s, dest, p(ri, c, s, sinkArg), flags)
of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt, nkPragmaBlock:
result = c.genSink(s, dest, p(ri, c, s, sinkArg), flags)
of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt:
template process(child, s): untyped = moveOrCopy(dest, child, c, s, flags)
# We know the result will be a stmt so we use that fact to optimize
handleNestedTempl(ri, process, willProduceStmt = true)
of nkRaiseStmt:
result = pRaiseStmt(ri, c, s)
else:
let isOwnsData = ownsData(c, s, ri2, flags)
if isOwnsData != nil:
result = moveOrCopy(dest, isOwnsData, c, s, flags)
elif isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c, s) and
if isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c, s) and
canBeMoved(c, dest.typ):
# Rule 3: `=sink`(x, z); wasMoved(z)
let snk = c.genSink(s, dest, ri, flags)
@@ -1292,55 +1244,6 @@ when false:
for i in 0..<n.safeLen:
injectDefaultCalls(n[i], c)
proc replaceSinkParam(n: PNode, mapping: Table[int, PSym]): PNode =
case n.kind
of nkSym:
if n.sym.id in mapping:
result = newSymNode(mapping[n.sym.id])
else:
result = n
of nkVarSection, nkLetSection:
result = copyNode(n)
newSons(result, n.len)
for i in 0..<n.len:
result[i] = copyNode(n[i])
for j in 0..<n[i].len-1:
result[i].add n[i][j]
result[i].add replaceSinkParam(n[i][^1], mapping)
of {nkNone..nkNilLit}-{nkSym}, nkTypeSection, nkProcDef, nkConverterDef,
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
nkTypeOfExpr, nkMixinStmt, nkBindStmt:
result = n
else:
result = copyNode(n)
for i in 0..<n.len:
result.add replaceSinkParam(n[i], mapping)
proc addSinkCopy(c: var Con; s: var Scope; sinkParams: seq[PSym]; n: PNode): PNode =
result = newNodeI(nkStmtList, n.info)
var mapping = initTable[int, PSym]()
var mutated = newSeq[PNode]()
getPotentialWrites(n, false, mutated)
var mutatedSet = initIntSet()
for m in mutated:
mutatedSet.incl m.sym.id
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.typ = param.typ.elementType
mapping[param.id] = newSym
let v = newNodeI(nkVarSection, n.info)
v.addVar(newSymNode(newSym), newSymNode(param))
result.add v
if mapping.len > 0:
result.add replaceSinkParam(n, mapping)
else:
result = n
proc injectDestructorCalls*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; n: PNode): PNode =
when toDebug.len > 0:
shouldDebug = toDebug == owner.name.s or toDebug == "always"
@@ -1354,24 +1257,15 @@ proc injectDestructorCalls*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; n:
var scope = Scope(body: n)
let body = p(n, c, scope, normal)
var sinkParams = newSeq[PSym]()
if owner.kind in {skProc, skFunc, skMethod, skIterator, skConverter}:
let params = owner.typ.n
for i in 1..<params.len:
let t = params[i].sym.typ
if isSinkTypeForParam(t):
let baseType = t.skipTypes({tySink})
if baseType.kind in {tyString, tySequence, tyArray, tyTuple, tyObject}:
sinkParams.add params[i].sym
if hasDestructor(c, baseType):
scope.final.add c.genDestroy(params[i])
if isSinkTypeForParam(t) and hasDestructor(c, t.skipTypes({tySink})):
scope.final.add c.genDestroy(params[i])
#if optNimV2 in c.graph.config.globalOptions:
# injectDefaultCalls(n, c)
result = optimize processScope(c, scope, body)
if sinkParams.len > 0:
result = addSinkCopy(c, scope, sinkParams, result)
dbg:
echo ">---------transformed-to--------->"
echo renderTree(result, {renderIds})

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

@@ -6,7 +6,7 @@ Name: "Nim"
Version: "$version"
Platforms: """
windows: i386;amd64
linux: i386;hppa;ia64;alpha;amd64;powerpc64;arm;sparc;sparc64;s390x;m68k;mips;mipsel;mips64;mips64el;powerpc;powerpc64el;arm64;riscv32;riscv64;loongarch64
linux: i386;hppa;ia64;alpha;amd64;powerpc64;arm;sparc;sparc64;m68k;mips;mipsel;mips64;mips64el;powerpc;powerpc64el;arm64;riscv32;riscv64;loongarch64
macosx: i386;amd64;powerpc64;arm64
solaris: i386;amd64;sparc;sparc64
freebsd: i386;amd64;powerpc64;arm;arm64;riscv64;sparc64;mips;mipsel;mips64;mips64el;powerpc;powerpc64el
@@ -80,7 +80,6 @@ Files: "lib"
Files: "examples"
Files: "dist/nimble"
Files: "dist/checksums"
Files: "dist/nimony"
Files: "tests"

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)
@@ -2456,7 +2434,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
binaryExpr(p, n, r, "mnewString",
"""if ($1.length < $2) { for (var i = $3.length; i < $4; ++i) $3.push(0); }
else {$3.length = $4; }""")
of mSetLengthSeq, mSetLengthSeqUninit:
of mSetLengthSeq:
var x, y: TCompRes = default(TCompRes)
gen(p, n[1], x)
gen(p, n[2], y)
@@ -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

@@ -122,7 +122,7 @@ proc genEnumInfo(p: PProc, typ: PType, name: Rope) =
[name, genTypeInfo(p, typ.baseClass)])
proc genTypeInfo(p: PProc, typ: PType): Rope =
let t = typ.skipTypes({tyGenericInst, tyDistinct, tyAlias, tySink, tyOwned} + tyUserTypeClasses)
let t = typ.skipTypes({tyGenericInst, tyDistinct, tyAlias, tySink, tyOwned})
result = "NTI$1" % [rope(t.id)]
if containsOrIncl(p.g.typeInfoGenerated, t.id): return
case t.kind

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) =
@@ -200,7 +199,7 @@ proc interestingVar(s: PSym): bool {.inline.} =
proc illegalCapture(s: PSym): bool {.inline.} =
result = classifyViewType(s.typ) != noView or s.kind == skResult
proc isInnerProc*(s: PSym): bool =
proc isInnerProc(s: PSym): bool =
if s.kind in {skProc, skFunc, skMethod, skConverter, skIterator} and s.magic == mNone:
result = s.skipGenericOwner.kind in routineKinds
else:
@@ -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,4 +1,5 @@
import ast, astalgo
import std/tables
import ast
type
LayeredIdTableObj* {.acyclic.} = object
@@ -27,15 +28,14 @@ proc shallowCopy*(pt: LayeredIdTable): LayeredIdTable {.inline.} =
## copies only the type bindings of the current layer, but not any parent layers,
## useful for write-only bindings
result = LayeredIdTable(topLayer: pt.topLayer, nextLayer: pt.nextLayer, previousLen: pt.previousLen)
#copyIdTable(result.topLayer, pt.topLayer)
proc currentLen*(pt: LayeredIdTable): int =
## the sum of the cached total binding count of the parents and
## the current binding count, just used to track if bindings were added
pt.previousLen + pt.topLayer.counter
pt.previousLen + pt.topLayer.len
proc newTypeMapLayer*(pt: LayeredIdTable): LayeredIdTable =
result = LayeredIdTable(topLayer: initTypeMapping(), previousLen: pt.currentLen)
result = LayeredIdTable(topLayer: initTable[ItemId, PType](), previousLen: pt.currentLen)
when useRef:
result.nextLayer = pt
else:
@@ -53,15 +53,6 @@ proc setToPreviousLayer*(pt: var LayeredIdTable) {.inline.} =
let tmp = pt.nextLayer[]
pt = tmp
iterator pairs*(pt: LayeredIdTable): (ItemId, PType) =
var tm = pt
while true:
for (k, v) in idTablePairs(tm.topLayer):
yield (k, v)
if tm.nextLayer == nil:
break
tm.setToPreviousLayer
proc lookup(typeMap: ref LayeredIdTableObj, key: ItemId): PType =
result = nil
var tm = typeMap

View File

@@ -40,7 +40,7 @@ template asink*(t: PType): PSym = getAttachedOp(c.g, t, attachedSink)
proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode)
proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
info: TLineInfo; idgen: IdGenerator): PSym
info: TLineInfo; idgen: IdGenerator; isDistinct = false): PSym
proc createTypeBoundOps*(g: ModuleGraph; c: PContext; orig: PType; info: TLineInfo;
idgen: IdGenerator)
@@ -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,10 +88,10 @@ 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)
body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
proc genAddr(c: var TLiftCtx; x: PNode): PNode =
if x.kind == nkHiddenDeref:
@@ -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)
@@ -148,7 +148,7 @@ proc destructorCall(c: var TLiftCtx; op: PSym; x: PNode): PNode =
if sfNeverRaises notin op.flags:
c.canRaise = true
if c.addMemReset:
result = newTree(nkStmtList, destroy, genBuiltin(c, mWasMoved, "wasMoved", x))
result = newTree(nkStmtList, destroy, genBuiltin(c, mWasMoved, "`=wasMoved`", x))
else:
result = destroy
@@ -168,7 +168,7 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool,
defaultOp(c, f.typ, body, x.dotField(f), b)
else:
if enforceWasMoved:
body.add genBuiltin(c, mWasMoved, "wasMoved", x.dotField(f))
body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x.dotField(f))
fillBody(c, f.typ, body, x.dotField(f), b)
of nkNilLit: discard
of nkRecCase:
@@ -218,38 +218,23 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool,
fillBodyObj(c, n[0], body, x, y, enforceDefaultOp = false)
c.filterDiscriminator = oldfilterDiscriminator
of nkRecList:
# destroys in reverse order #24719
if c.kind == attachedDestructor:
for i in countdown(n.len-1, 0):
fillBodyObj(c, n[i], body, x, y, enforceDefaultOp, enforceWasMoved)
else:
for t in items(n): fillBodyObj(c, t, body, x, y, enforceDefaultOp, enforceWasMoved)
for t in items(n): fillBodyObj(c, t, body, x, y, enforceDefaultOp, enforceWasMoved)
else:
illFormedAstLocal(n, c.g.config)
proc fillBodyObjTImpl(c: var TLiftCtx; t: PType, body, x, y: PNode) =
template fillBase =
if t.baseClass != nil:
let dest = newNodeIT(nkHiddenSubConv, c.info, t.baseClass)
dest.add newNodeI(nkEmpty, c.info)
dest.add x
var src = y
if c.kind in {attachedAsgn, attachedDeepCopy, attachedSink}:
src = newNodeIT(nkHiddenSubConv, c.info, t.baseClass)
src.add newNodeI(nkEmpty, c.info)
src.add y
if t.baseClass != nil:
let dest = newNodeIT(nkHiddenSubConv, c.info, t.baseClass)
dest.add newNodeI(nkEmpty, c.info)
dest.add x
var src = y
if c.kind in {attachedAsgn, attachedDeepCopy, attachedSink}:
src = newNodeIT(nkHiddenSubConv, c.info, t.baseClass)
src.add newNodeI(nkEmpty, c.info)
src.add y
fillBody(c, skipTypes(t.baseClass, abstractPtrs), body, dest, src)
template fillFields =
fillBodyObj(c, t.n, body, x, y, enforceDefaultOp = false)
if c.kind == attachedDestructor:
# destroys in reverse order #24719
fillFields()
fillBase()
else:
fillBase()
fillFields()
fillBody(c, skipTypes(t.baseClass, abstractPtrs), body, dest, src)
fillBodyObj(c, t.n, body, x, y, enforceDefaultOp = false)
proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
var hasCase = isCaseObj(t.n)
@@ -280,11 +265,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)
@@ -292,8 +277,7 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
#body.add newAsgnStmt(blob, x)
var wasMovedCall = newNodeI(nkCall, c.info)
wasMovedCall.add(newSymNode(createMagic(c.g, c.idgen, "wasMoved", mWasMoved)))
wasMovedCall.add(newSymNode(createMagic(c.g, c.idgen, "`=wasMoved`", mWasMoved)))
wasMovedCall.add x # mWasMoved does not take the address
body.add wasMovedCall
@@ -312,7 +296,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 +364,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 +377,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 +403,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 +519,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,7 +529,7 @@ 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)
@@ -567,18 +545,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)
@@ -601,7 +579,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) =
@@ -634,7 +612,7 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if canFormAcycle(c.g, t.elemType):
# follow all elements:
forallElements(c, t, body, x, y)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
createTypeBoundOps(c.g, c.c, t, body.info, c.idgen)
@@ -672,7 +650,7 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if op == nil:
return # protect from recursion
body.add newHookCall(c, op, x, y)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
of attachedDup:
# XXX: replace these with assertions.
let op = getAttachedOp(c.g, t, c.kind)
@@ -694,7 +672,7 @@ proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add genBuiltin(c, mDestroy, "destroy", x)
of attachedTrace:
discard "strings are atomic and have no inner elements that are to trace"
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
proc cyclicType*(g: ModuleGraph, t: PType): bool =
case t.kind
@@ -742,7 +720,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))
@@ -752,7 +730,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)
@@ -760,7 +738,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:
@@ -787,13 +765,13 @@ 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
body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(x, c.idgen), y)
#echo "can follow ", elemType, " static ", isFinal(elemType)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
of attachedDup:
if isCyclic:
body.add newAsgnStmt(x, y)
@@ -808,7 +786,7 @@ 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)
let isCyclic = c.g.config.selectedGC == gcOrc
let tmp =
@@ -824,7 +802,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:
@@ -836,7 +814,7 @@ 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)
@@ -848,7 +826,7 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
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)))
@@ -860,7 +838,7 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace:
body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(xenv, c.idgen), y)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case c.kind
@@ -888,7 +866,7 @@ proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.sons.insert(des, 0)
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace: discard
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
var actions = newNodeI(nkStmtList, c.info)
@@ -900,7 +878,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))
@@ -916,21 +894,21 @@ proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add genIf(c, x, actions)
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace: discard
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if c.kind == attachedDeepCopy:
# 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}:
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
@@ -939,13 +917,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:
@@ -956,11 +934,11 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.sons.insert(des, 0)
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace: discard
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
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)
@@ -974,7 +952,7 @@ proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add genIf(c, xx, actions)
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace: discard
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case t.kind
@@ -1024,13 +1002,9 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
# 'selectedGC' here to determine if we have the new runtime.
discard considerUserDefinedOp(c, t, body, x, y)
elif tfHasAsgn in t.flags:
# seqs with elements using custom hooks in refc
if c.kind in {attachedAsgn, attachedSink, attachedDeepCopy}:
body.add newSeqCall(c, x, y)
if c.kind == attachedWasMoved:
body.add genBuiltin(c, mWasMoved, "wasMoved", x)
else:
forallElements(c, t, body, x, y)
forallElements(c, t, body, x, y)
else:
defaultOp(c, t, body, x, y)
of tyString:
@@ -1047,11 +1021,9 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
of {attachedAsgn, attachedSink, attachedDup}:
body.add newAsgnStmt(x, y)
of attachedWasMoved:
body.add genBuiltin(c, mWasMoved, "wasMoved", x)
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 c.kind == attachedDup:
var op2 = getAttachedOp(c.g, t, attachedAsgn)
@@ -1091,7 +1063,9 @@ proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType;
assert typ.kind == tyDistinct
let baseType = typ.elementType
if getAttachedOp(g, baseType, kind) == nil:
discard produceSym(g, c, baseType, kind, info, idgen)
# TODO: fixme `isDistinct` is a fix for #23552; remove it after
# `-d:nimPreviewNonVarDestructor` becomes the default
discard produceSym(g, c, baseType, kind, info, idgen, isDistinct = true)
result = getAttachedOp(g, baseType, kind)
setAttachedOp(g, idgen.module, typ, kind, result)
@@ -1126,10 +1100,11 @@ 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 =
info: TLineInfo; idgen: IdGenerator; isDiscriminant = false; isDistinct = false): PSym =
if kind == attachedDup:
return symDupPrototype(g, typ, owner, kind, info, idgen)
@@ -1140,7 +1115,7 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
idgen, result, info)
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})):
((g.config.isDefined("nimPreviewNonVarDestructor") and not isDiscriminant) or (typ.kind in {tyRef, tyString, tySequence} and not isDistinct)):
dest.typ = typ
else:
dest.typ = makeVarType(typ.owner, typ, idgen)
@@ -1168,27 +1143,27 @@ 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 =
info: TLineInfo; idgen: IdGenerator; isDistinct = false): PSym =
if typ.kind == tyDistinct:
return produceSymDistinctType(g, c, typ, kind, info, idgen)
result = getAttachedOp(g, typ, kind)
if result == nil:
result = symPrototype(g, typ, typ.owner, kind, info, idgen)
result = symPrototype(g, typ, typ.owner, kind, info, idgen, isDistinct = isDistinct)
var a = TLiftCtx(info: info, g: g, kind: kind, c: c, asgnForType: typ, idgen: idgen,
fn: result)
@@ -1205,17 +1180,14 @@ 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, gcHooks, gcAtomicArc}:
skipped = skipTypes(typ, {tyOrdinal, tyRange, tyInferred, tyGenericInst, tyStatic, tyAlias, tySink})
tk = skipped.kind
tk = skipTypes(typ, {tyOrdinal, tyRange, tyInferred, tyGenericInst, tyStatic, tyAlias, tySink}).kind
else:
tk = tyNone # no special casing for strings and seqs
case tk
@@ -1225,20 +1197,16 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
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 lacksMTypeField(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
completePartialOp(g, idgen.module, typ, kind, result)
@@ -1263,9 +1231,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) =
@@ -1300,7 +1266,7 @@ proc inst(g: ModuleGraph; c: PContext; t: PType; kind: TTypeAttachedOp; idgen: I
else:
localError(g.config, info, "unresolved generic parameter")
proc isTrivial*(s: PSym): bool {.inline.} =
proc isTrival*(s: PSym): bool {.inline.} =
s == nil or (s.ast != nil and s.ast[bodyPos].len == 0)
proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInfo;
@@ -1309,13 +1275,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
@@ -1341,7 +1305,7 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf
# 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]:
@@ -1357,9 +1321,8 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf
if canon != orig:
setAttachedOp(g, idgen.module, orig, k, getAttachedOp(g, canon, k))
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
if not isTrival(getAttachedOp(g, orig, attachedDestructor)):
#or not isTrival(orig.assignment) or
# not isTrival(orig.sink):
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

@@ -110,7 +110,6 @@ type
hintSource = "Source", hintPerformance = "Performance", hintStackTrace = "StackTrace",
hintGCStats = "GCStats", hintGlobalVar = "GlobalVar", hintExpandMacro = "ExpandMacro",
hintUser = "User", hintUserRaw = "UserRaw", hintExtendedContext = "ExtendedContext",
hintUnknownRaises = "UnknownRaises",
hintMsgOrigin = "MsgOrigin", # since 1.3.5
hintDeclaredLoc = "DeclaredLoc", # since 1.5.1
@@ -237,7 +236,6 @@ const
hintUser: "$1",
hintUserRaw: "$1",
hintExtendedContext: "$1",
hintUnknownRaises: "$1 is a forward declaration without explicit .raises, assuming it can raise anything",
hintMsgOrigin: "$1",
hintDeclaredLoc: "$1"
]
@@ -273,10 +271,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
@@ -295,7 +289,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

@@ -11,7 +11,7 @@
import
pathutils
import std/strutils
when defined(nimPreviewSlimSystem):
import std/syncio
@@ -86,47 +86,6 @@ const
LineContinuationOprs = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^',
'|', '%', '&', '$', '@', '~', ','}
AdditionalLineContinuationOprs = {'#', ':', '='}
LineContinuationTokens = [
"let", "var", "const", "type", # section
"object", "tuple",
# from ./layouter.oprSet
"div", "mod", "shl", "shr", "in", "notin", "is",
"isnot", "not", "of", "as", "from", "..", "and", "or", "xor",
] # must be all `nimIdentNormalized`-ed
proc eqIdent(a, bNormalized: string): bool =
a.nimIdentNormalize == bNormalized
proc endsWithIdent(s, subs: string): bool =
let le = subs.len
if le > s.len: return false
s[^le .. ^1].eqIdent subs
proc continuesWithIdent(s, subs: string, start: int): bool =
s.substr(start, start+subs.high).eqIdent subs
proc endsWithIdent(s, subs: string, endIdx: var int): bool =
endIdx.dec subs.len
result = s.continuesWithIdent(subs, endIdx+1)
proc containsObjectOf(x: string): bool =
const sep = ' '
var idx = x.rfind(sep)
if idx == -1: return
template eatWord(word) =
while x[idx] == sep: idx.dec
result = x.endsWithIdent(word, idx)
if not result: return
eatWord "of"
eatWord "object"
result = true
proc endsWithLineContinuationToken(x: string): bool =
result = false
for tok in LineContinuationTokens:
if x.endsWithIdent(tok):
return true
result = x.containsObjectOf
proc endsWithOpr*(x: string): bool =
result = x.endsWith(LineContinuationOprs)
@@ -134,9 +93,7 @@ proc endsWithOpr*(x: string): bool =
proc continueLine(line: string, inTripleString: bool): bool {.inline.} =
result = inTripleString or line.len > 0 and (
line[0] == ' ' or
line.endsWith(LineContinuationOprs+AdditionalLineContinuationOprs) or
line.endsWithLineContinuationToken()
)
line.endsWith(LineContinuationOprs+AdditionalLineContinuationOprs))
proc countTriples(s: string): int =
result = 0
@@ -152,10 +109,7 @@ proc llReadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int =
s.rd = 0
var line = newStringOfCap(120)
var triples = 0
while true:
if not readLineFromStdin(if s.s.len == 0: ">>> " else: "... ", line):
# now readLineFromStdin meets EOF (ctrl-D/Z) or ctrl-C
quit()
while readLineFromStdin(if s.s.len == 0: ">>> " else: "... ", line):
s.s.add(line)
s.s.add("\n")
inc triples, countTriples(line)

View File

@@ -58,11 +58,13 @@ proc considerQuotedIdent*(c: PContext; n: PNode, origin: PNode = nil): PIdent =
of nkLiterals - nkFloatLiterals: id.add(x.renderTree)
else: handleError(n, origin)
result = getIdent(c.cache, id)
of nkOpenSymChoice, nkClosedSymChoice, nkOpenSym:
of nkOpenSymChoice, nkClosedSymChoice:
if n[0].kind == nkSym:
result = n[0].sym.name
else:
handleError(n, origin)
of nkOpenSym:
result = considerQuotedIdent(c, n[0], origin)
else:
handleError(n, origin)
@@ -75,13 +77,10 @@ proc addUniqueSym*(scope: PScope, s: PSym): PSym =
proc openScope*(c: PContext): PScope {.discardable.} =
result = PScope(parent: c.currentScope,
symbols: initStrTable(),
depthLevel: c.scopeDepth + 1,
optionStackLen: c.optionStack.len)
depthLevel: c.scopeDepth + 1)
c.currentScope = result
proc rawCloseScope*(c: PContext) =
if c.currentScope.optionStackLen >= 1:
c.optionStack.setLen(c.currentScope.optionStackLen)
c.currentScope = c.currentScope.parent
proc closeScope*(c: PContext) =
@@ -311,7 +310,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)
@@ -388,7 +387,7 @@ proc addDeclAt*(c: PContext; scope: PScope, sym: PSym, info: TLineInfo) =
if sym.name.id == ord(wUnderscore): return
let conflict = scope.addUniqueSym(sym)
if conflict != nil:
if sym.kind == skModule and conflict.kind == skModule and not c.config.isDefined("nimPreviewDuplicateModuleError"):
if sym.kind == skModule and conflict.kind == skModule:
# e.g.: import foo; import foo
# xxx we could refine this by issuing a different hint for the case
# where a duplicate import happens inside an include.

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, idgen)

View File

@@ -32,10 +32,6 @@ import ../dist/checksums/src/checksums/sha1
import pipelines
when not defined(nimKochBootstrap):
import nifbackend
import deps
when not defined(leanCompiler):
import docgen
@@ -121,38 +117,6 @@ when not defined(leanCompiler):
else: raiseAssert $ext
compilePipelineProject(graph)
proc commandCompileToNif(graph: ModuleGraph) =
let conf = graph.config
extccomp.initVars(conf)
if conf.symbolFiles == disabledSf:
if {optRun, optForceFullMake} * conf.globalOptions == {optRun} or isDefined(conf, "nimBetterRun"):
if not changeDetectedViaJsonBuildInstructions(conf, conf.jsonBuildInstructionsFile):
# nothing changed
graph.config.notes = graph.config.mainPackageNotes
return
if not extccomp.ccHasSaneOverflow(conf):
conf.symbols.defineSymbol("nimEmulateOverflowChecks")
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)
@@ -220,7 +184,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)
@@ -293,7 +257,7 @@ proc mainCommand*(graph: ModuleGraph) =
if conf.exc == excNone: conf.exc = excSetjmp
of backendCpp:
if conf.exc == excNone: conf.exc = excCpp
of backendObjc, backendNif: discard
of backendObjc: discard
of backendJs:
if conf.hcrOn:
# XXX: At the moment, system.nim cannot be compiled in JS mode
@@ -311,7 +275,6 @@ proc mainCommand*(graph: ModuleGraph) =
of backendCpp: commandCompileToC(graph)
of backendObjc: commandCompileToC(graph)
of backendJs: commandCompileToJS(graph)
of backendNif: commandCompileToNif(graph)
of backendInvalid: raiseAssert "unreachable"
template docLikeCmd(body) =
@@ -440,24 +403,9 @@ 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)

View File

@@ -11,16 +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
@@ -65,7 +60,6 @@ type
SemPass
JSgenPass
CgenPass
NifgenPass
EvalPass
InterpreterPass
GenDependPass
@@ -81,8 +75,6 @@ type
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.
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, 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)
@@ -144,9 +136,6 @@ type
cachedFiles*: StringTableRef
procGlobals*: seq[PNode]
nifReplayActions*: Table[int32, seq[PNode]] # module position -> replay actions for NIF
TPassContext* = object of RootObj # the pass's context
idgen*: IdGenerator
PPassContext* = ref TPassContext
@@ -170,9 +159,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 = [
@@ -368,32 +354,13 @@ proc getAttachedOp*(g: ModuleGraph; t: PType; op: TTypeAttachedOp): PSym =
## if no such operation exists.
if g.attachedOps[op].contains(t.itemId):
result = resolveAttachedOp(g, 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
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] = LazySym(sym: 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] = 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] = LazySym(sym: value)
@@ -421,10 +388,6 @@ 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]:
@@ -436,9 +399,6 @@ proc getToStringProc*(g: ModuleGraph; t: PType): PSym =
proc setToStringProc*(g: ModuleGraph; t: PType; value: PSym) =
g.enumToStringProcs[t.itemId] = LazySym(sym: 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)
iterator methodsForGeneric*(g: ModuleGraph; t: PType): (int, PSym) =
if g.methodsPerGenericType.contains(t.itemId):
@@ -447,17 +407,6 @@ iterator methodsForGeneric*(g: ModuleGraph; t: PType): (int, PSym) =
proc addMethodToGeneric*(g: ModuleGraph; module: int; t: PType; col: int; m: PSym) =
g.methodsPerGenericType.mgetOrPut(t.itemId, @[]).add (col, LazySym(sym: 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)
proc hasDisabledAsgn*(g: ModuleGraph; t: PType): bool =
let op = getAttachedOp(g, t, attachedAsgn)
@@ -471,30 +420,7 @@ 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):
# Only try to resolve from NIF if we're actually using NIF files (cmdNifC)
if g.config.cmd == cmdNifC:
# First try system module (most compilerprocs are there)
let systemFileIdx = g.config.m.systemFileIdx
if systemFileIdx != InvalidFileIdx:
result = tryResolveCompilerProc(ast.program, name, systemFileIdx)
if result != nil:
strTableAdd(g.compilerprocs, result)
return result
# 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
if g.config.symbolFiles == disabledSf: return nil
# slow, linear search, but the results are cached:
for module in 0..<len(g.packed):
@@ -528,10 +454,10 @@ template getPContext(): untyped =
else: c.c
when defined(nimsuggest):
template onUse*(info: TLineInfo; s: PSym; isGenericInstance = false) = discard
template onUse*(info: TLineInfo; s: PSym) = discard
template onDefResolveForward*(info: TLineInfo; s: PSym) = discard
else:
template onUse*(info: TLineInfo; s: PSym; isGenericInstance = false) = discard
template onUse*(info: TLineInfo; s: PSym) = discard
template onDef*(info: TLineInfo; s: PSym) = discard
template onDefResolveForward*(info: TLineInfo; s: PSym) = discard
@@ -599,10 +525,9 @@ proc registerModule*(g: ModuleGraph; m: PSym) =
if m.position >= g.packed.len:
setLen(g.packed.pm, 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)
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.packed[int m].module)
@@ -658,7 +583,6 @@ proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
result.config = config
result.cache = cache
initModuleGraphFields(result)
ast.setupProgram(config, cache)
proc resetAllModules*(g: ModuleGraph) =
g.packageSyms = initStrTable()
@@ -754,13 +678,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
@@ -813,49 +737,6 @@ proc moduleFromRodFile*(g: ModuleGraph; fileIdx: FileIndex;
else:
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
# 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 LazySym(sym: 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 configComplete*(g: ModuleGraph) =
rememberStartupConfig(g.startupPackedConfig, g.config)
@@ -880,7 +761,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

@@ -79,10 +79,6 @@ proc checkModuleName*(conf: ConfigRef; n: PNode; doLocalError=true): FileIndex =
else:
result = fileInfoIdx(conf, fullPath)
type
SelectedBase = enum
FromProject, FromSearchPath, FromNimblePath
proc mangleModuleName*(conf: ConfigRef; path: AbsoluteFile): string =
## Mangle a relative module path to avoid path and symbol collisions.
##
@@ -91,27 +87,9 @@ proc mangleModuleName*(conf: ConfigRef; path: AbsoluteFile): string =
##
## Example:
## `foo-#head/../bar` becomes `@foo-@hhead@s..@sbar`
var best = relativeTo(path, conf.projectPath).string
var selectedBase = FromProject
for x in conf.searchPaths:
let other = relativeTo(path, x).string
if other.len < best.len:
best = other
selectedBase = FromSearchPath
for x in conf.nimblePaths:
let other = relativeTo(path, x).string
if other.len < best.len:
best = other
selectedBase = FromNimblePath
let prefix =
case selectedBase
of FromProject: "@m"
of FromSearchPath: "@p"
of FromNimblePath: "@n"
prefix & best.multiReplace(
"@m" & relativeTo(path, conf.projectPath).string.multiReplace(
{$os.DirSep: "@s", $os.AltSep: "@s", "#": "@h", "@": "@@", ":": "@c"})
proc demangleModuleName*(path: string): string =
## Demangle a relative module path.
result = path.multiReplace({"@@": "@", "@h": "#", "@s": "/", "@m": "", "@p": "", "@n": "", "@c": ":"})
result = path.multiReplace({"@@": "@", "@h": "#", "@s": "/", "@m": "", "@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):

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)

File diff suppressed because it is too large Load Diff

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

@@ -11,9 +11,6 @@ define:nimPreviewRangeDefault
define:nimPreviewNonVarDestructor
define:nimPreviewCheckedClose
define:nimPreviewAsmSemSymbol
define:nimPreviewCStringComparisons
define:nimPreviewDuplicateModuleError
threads:off
#import:"$projectpath/testability"

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

@@ -28,14 +28,11 @@ type
hasReturn, hasBreak: bool
label: PSym # can be nil
parent: ptr BasicBlock
symToDel: seq[PNode]
Con = object
somethingTodo: bool
inFinally: int
proc invalidateWasMoved(c: var BasicBlock; x: PNode)
proc nestedBlock(parent: var BasicBlock; kind: TNodeKind): BasicBlock =
BasicBlock(wasMovedLocs: @[], kind: kind, hasReturn: false, hasBreak: false,
label: nil, parent: addr(parent))
@@ -65,10 +62,6 @@ proc mergeBasicBlockInfo(parent: var BasicBlock; this: BasicBlock) {.inline.} =
if this.hasReturn:
parent.wasMovedLocs.setLen 0
parent.hasReturn = true
elif this.symToDel.len > 0:
parent.symToDel = this.symToDel
for i in this.symToDel:
invalidateWasMoved(parent, i)
proc wasMovedTarget(matches: var IntSet; branch: seq[PNode]; moveTarget: PNode): bool =
result = false
@@ -156,7 +149,6 @@ proc analyse(c: var Con; b: var BasicBlock; n: PNode) =
# any usage of the location before destruction implies we
# cannot elide the 'wasMoved(x)':
b.invalidateWasMoved n
b.symToDel.add n
of nkNone..pred(nkSym), succ(nkSym)..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef,
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,

View File

@@ -25,7 +25,7 @@ const
useEffectSystem* = true
useWriteTracking* = false
hasFFI* = defined(nimHasLibFFI)
copyrightYear* = "2026"
copyrightYear* = "2025"
nimEnableCovariance* = defined(nimEnableCovariance)
@@ -110,9 +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
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]
@@ -142,7 +139,6 @@ type
backendCpp = "cpp"
backendJs = "js"
backendObjc = "objc"
backendNif = "nif"
# backendNimscript = "nimscript" # this could actually work
# backendLlvm = "llvm" # probably not well supported; was cmdCompileToLLVM
@@ -175,13 +171,10 @@ type
cmdNop
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,
cmdCompileToJS, cmdCrun, cmdCompileToNif}
cmdCompileToJS, cmdCrun}
cmdDocLike* = {cmdDoc0, cmdDoc, cmdDoc2tex, cmdJsondoc0, cmdJsondoc,
cmdCtags, cmdBuildindex}
@@ -255,8 +248,6 @@ type
## Useful for libraries that rely on local passC
jsNoLambdaLifting
## Old transformation for closures in JS backend
noPanicOnExcept
## don't panic on bare except
SymbolFilesOption* = enum
disabledSf, writeOnlySf, readOnlySf, v2Sf, stressTest
@@ -369,7 +360,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] # (*)
@@ -412,7 +402,6 @@ type
projectPath*: AbsoluteDir # holds a path like /home/alice/projects/nim/compiler/
projectFull*: AbsoluteFile # projectPath/projectName
projectIsStdin*: bool # whether we're compiling from stdin
stdinFile*: AbsoluteFile # Filename to use in messages for stdin
lastMsgWasDot*: set[StdOrrKind] # the last compiler message was a single '.'
projectMainIdx*: FileIndex # the canonical path id of the main module
projectMainIdx2*: FileIndex # consider merging with projectMainIdx
@@ -514,7 +503,7 @@ const
optHints, optStackTrace, optLineTrace, # consider adding `optStackTraceMsgs`
optTrMacros, optStyleCheck, optCursorInference}
DefaultGlobalOptions* = {optThreadAnalysis, optExcessiveStackTrace,
optJsBigInt64, optItaniumMangle}
optJsBigInt64}
proc getSrcTimestamp(): DateTime =
try:
@@ -589,7 +578,6 @@ proc newConfigRef*(): ConfigRef =
projectPath: AbsoluteDir"", # holds a path like /home/alice/projects/nim/compiler/
projectFull: AbsoluteFile"", # projectPath/projectName
projectIsStdin: false, # whether we're compiling from stdin
stdinFile: AbsoluteFile"stdinfile",
projectMainIdx: FileIndex(0'i32), # the canonical path id of the main module
command: "", # the main command (e.g. cc, check, scan, etc)
commandArgs: @[], # any arguments after the main command

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

@@ -13,7 +13,7 @@
import ast, types, msgs, idents, renderer, wordrecg, trees,
options
import std/[strutils, assertions]
import std/strutils
# we precompile the pattern here for efficiency into some internal
# stack based VM :-) Why? Because it's fun; I did no benchmarks to see if that
@@ -216,11 +216,6 @@ proc exprRoot*(n: PNode; allowCalls = true): PSym =
else:
break
proc isAssignable*(owner: PSym, n: PNode): TAssignableResult
proc isLentableBranch(owner: PSym, n: PNode): bool =
result = isAssignable(owner, n) in {arLentValue, arAddressableConst, arLentValue}
proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
## 'owner' can be nil!
result = arNone
@@ -313,35 +308,6 @@ proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
# nkVarTy denotes an lvalue, but the example above is the only
# possible code which will get us here
result = arLValue
of nkIfExpr, nkIfStmt:
# allow 'if' expressions to be lent if all branches are lentable
for branch in n:
if branch.len == 2:
if not isLentableBranch(owner, branch[1]):
return
elif branch.len == 1:
if not isLentableBranch(owner, branch[0]):
return
else:
raiseAssert "Malformed `if` statement in isAssignable"
result = arLentValue
of nkCaseStmt:
# allow 'case' expressions to be lent if all branches are lentable
for i in 1 ..< n.len:
let branch = n[i]
case branch.kind
of nkOfBranch:
if not isLentableBranch(owner, branch[^1]):
return
of nkElifBranch:
if not isLentableBranch(owner, branch[1]):
return
of nkElse:
if not isLentableBranch(owner, branch[0]):
return
else:
raiseAssert "Malformed `case` statement in isAssignable"
result = arLentValue
else:
discard

View File

@@ -638,9 +638,8 @@ proc semiStmtList(p: var Parser, result: PNode) =
getTok(p)
if p.tok.tokType == tkParRi:
break
# ignore indent:
#elif not (sameOrNoInd(p) or realInd(p)):
# parMessage(p, errInvalidIndentation)
elif not (sameInd(p) or realInd(p)):
parMessage(p, errInvalidIndentation)
let a = complexOrSimpleStmt(p)
if a.kind == nkEmpty:
parMessage(p, errExprExpected, p.tok)
@@ -700,12 +699,10 @@ proc parsePar(p: var Parser): PNode =
asgn.add b
result.add(asgn)
if p.tok.tokType == tkSemiColon:
getTok(p)
semiStmtList(p, result)
elif p.tok.tokType == tkSemiColon:
# stmt context:
result.add(a)
getTok(p)
semiStmtList(p, result)
else:
a = colonOrEquals(p, a)
@@ -1156,10 +1153,7 @@ proc parseParamList(p: var Parser, retColon = true): PNode =
parMessage(p, errGenerated, "the syntax is 'parameter: var T', not 'var parameter: T'")
break
else:
if p.tok.tokType in tokKeywordLow..tokKeywordHigh:
parMessage(p, errGenerated, "'" & $p.tok.ident.s & "' is a keyword and cannot be used as a parameter name")
else:
parMessage(p, "expected closing ')'")
parMessage(p, "expected closing ')'")
break
result.add(a)
if p.tok.tokType notin {tkComma, tkSemiColon}: break
@@ -2113,28 +2107,12 @@ proc parseObjectCase(p: var Parser): PNode =
#| objectBranches = objectBranch (IND{=} objectBranch)*
#| (IND{=} 'elif' expr colcom objectPart)*
#| (IND{=} 'else' colcom objectPart)?
#| objectCase = 'case' (declColonEquals / pragma)? ':'? COMMENT?
#| objectCase = 'case' declColonEquals ':'? COMMENT?
#| (IND{>} objectBranches DED
#| | IND{=} objectBranches)
result = newNodeP(nkRecCase, p)
getTok(p)
if p.tok.tokType != tkOf:
# of case will be handled later
if p.tok.indent >= 0: parMessage(p, errInvalidIndentation)
var a: PNode
if p.tok.tokType in {tkSymbol, tkAccent}:
a = parseIdentColonEquals(p, {withPragma})
else:
a = newNodeP(nkIdentDefs, p)
if p.tok.tokType == tkCurlyDotLe:
var prag = newNodeP(nkPragmaExpr, p)
prag.add(p.emptyNode)
prag.add(parsePragma(p))
a.add(prag)
else:
a.add(p.emptyNode)
a.add(p.emptyNode)
a.add(p.emptyNode)
getTokNoInd(p)
var a = parseIdentColonEquals(p, {withPragma})
result.add(a)
if p.tok.tokType == tkColon: getTok(p)
flexComment(p, result)

View File

@@ -173,7 +173,7 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags, fr
let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
if result == nil:
result = newModule(graph, fileIdx)
result.incl flags
result.flags.incl flags
registerModule(graph, result)
processModuleAux("import")
else:
@@ -185,7 +185,7 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags, fr
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

@@ -77,7 +77,7 @@ proc inSymChoice(sc, x: PNode): bool =
result = false
for i in 0..<sc.len:
if sc[i].sym == x.sym: return true
elif sc.kind in {nkOpenSymChoice, nkOpenSym}:
elif sc.kind == nkOpenSymChoice:
# same name suffices for open sym choices!
result = sc[0].sym.name.id == x.sym.name.id
else:

View File

@@ -1,12 +1,7 @@
import sem, cgen, modulegraphs, ast, llstream, parser, msgs,
lineinfos, reorder, options, semdata, cgendata, modules, pathutils,
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]
liftdestructors
import pipelineutils
@@ -28,10 +23,6 @@ proc processPipeline(graph: ModuleGraph; semNode: PNode; bModule: PPassContext):
result = semNode
if bModule != nil:
genTopLevelStmt(BModule(bModule), result)
of NifgenPass:
result = semNode
if bModule != nil:
genTopLevelNif(bModule, result)
of JSgenPass:
when not defined(leanCompiler):
result = processJSCodeGen(bModule, semNode)
@@ -40,12 +31,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 +48,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 +60,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 +83,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:
@@ -151,8 +131,6 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
nil
of SemPass:
nil
of NifgenPass:
setupNifgen(graph, module, idgen)
of NonePass:
raiseAssert "use setPipeLinePass to set a proper PipelinePass"
@@ -166,11 +144,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 +153,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 +175,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 +192,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):
@@ -236,33 +207,13 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
of Docgen2JsonPass:
when not defined(leanCompiler):
discard closeJson(graph, bModule, finalNode)
of NifgenPass:
closeNif(graph, bModule, finalNode)
of NonePass:
raiseAssert "use setPipeLinePass to set a proper PipelinePass"
when not defined(nimKochBootstrap):
if (optCompress in graph.config.globalOptions or graph.config.cmd == cmdM) 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} and graph.config.cmd != cmdM:
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`.
# cmdM uses NIF files only, not ROD files.
closeRodFile(graph, module)
result = true
@@ -280,53 +231,33 @@ proc compilePipelineModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymF
discard processPipelineModule(graph, result, idGeneratorFromModule(result), s)
if result == nil:
var cachedModules: seq[FileIndex] = @[]
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)
localError(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
if result == nil and graph.config.cmd != cmdM:
# Fall back to ROD file loading (not used for cmdM which uses NIF only)
result = moduleFromRodFile(graph, fileIdx, cachedModules)
result = moduleFromRodFile(graph, fileIdx, cachedModules)
let path = toFullPath(graph.config, fileIdx)
let filename = AbsoluteFile path
# it could be a stdinfile/cmdfile
if fileExists(filename) and not graph.config.projectIsStdin:
if fileExists(filename): # it could be a stdinfile
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 graph.config.cmd == cmdM:
# cmdM uses NIF files - replay from module AST loaded by loadNifModule
let module = graph.getModule(m)
if module != nil and module.ast != nil:
replayStateChanges(module, graph)
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
@@ -354,12 +285,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)
@@ -376,24 +305,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")
var cachedModules: seq[FileIndex] = @[]
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

@@ -210,8 +210,8 @@ type
cpuNone, cpuI386, cpuM68k, cpuAlpha, cpuPowerpc, cpuPowerpc64,
cpuPowerpc64el, cpuSparc, cpuVm, cpuHppa, cpuIa64, cpuAmd64, cpuMips,
cpuMipsel, cpuArm, cpuArm64, cpuJS, cpuNimVM, cpuAVR, cpuMSP430,
cpuSparc64, cpuS390x, cpuMips64, cpuMips64el, cpuRiscV32, cpuRiscV64,
cpuEsp, cpuWasm32, cpuE2k, cpuLoongArch64
cpuSparc64, cpuMips64, cpuMips64el, cpuRiscV32, cpuRiscV64, cpuEsp, cpuWasm32,
cpuE2k, cpuLoongArch64
type
TInfoCPU* = tuple[name: string, intSize: int, endian: Endianness,
@@ -241,7 +241,6 @@ const
(name: "avr", intSize: 16, endian: littleEndian, floatSize: 32, bit: 16),
(name: "msp430", intSize: 16, endian: littleEndian, floatSize: 32, bit: 16),
(name: "sparc64", intSize: 64, endian: bigEndian, floatSize: 64, bit: 64),
(name: "s390x", intSize: 64, endian: bigEndian, floatSize: 64, bit: 64),
(name: "mips64", intSize: 64, endian: bigEndian, floatSize: 64, bit: 64),
(name: "mips64el", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
(name: "riscv32", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32),

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

@@ -107,7 +107,7 @@ proc getPragmaVal*(procAst: PNode; name: TSpecialWord): PNode =
return it[1]
proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords;
isStatement: bool = false; comesFromPush = false)
isStatement: bool = false)
proc recordPragma(c: PContext; n: PNode; args: varargs[string]) =
var recorded = newNodeI(nkReplayAction, n.info)
@@ -148,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)
@@ -156,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:
@@ -170,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))
@@ -239,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:
@@ -282,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
@@ -357,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
@@ -435,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:
@@ -636,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:
@@ -725,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]
@@ -757,15 +757,15 @@ 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)
@@ -773,7 +773,7 @@ proc markCompilerProc(c: PContext; s: PSym) =
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:
@@ -842,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:
@@ -893,7 +893,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
if keyDeep:
localError(c.config, it.info, "user pragma cannot have arguments")
pragma(c, sym, userPragma.ast, validPragmas, isStatement, comesFromPush)
pragma(c, sym, userPragma.ast, validPragmas, isStatement)
n.sons[i..i] = userPragma.ast.sons # expand user pragma with its content
i.inc(userPragma.ast.len - 1) # inc by -1 is ok, user pragmas was empty
else:
@@ -907,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)
@@ -921,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)
@@ -947,19 +947,15 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
of wSize:
if sym.typ == nil: invalidPragma(c, it)
var size = expectIntLit(c, it)
if sfImportc in sym.flags:
# no restrictions on size for imported types
setImportedTypeSize(c.config, sym.typ, size)
case size
of 1, 2, 4:
sym.typ.size = size
sym.typ.align = int16 size
of 8:
sym.typ.size = 8
sym.typ.align = floatInt64Align(c.config)
else:
case size
of 1, 2, 4:
sym.typ.size = size
sym.typ.align = int16 size
of 8:
sym.typ.size = 8
sym.typ.align = floatInt64Align(c.config)
else:
localError(c.config, it.info, "size may only be 1, 2, 4 or 8")
localError(c.config, it.info, "size may only be 1, 2, 4 or 8")
of wAlign:
let alignment = expectIntLit(c, it)
if isPowerOfTwo(alignment) and alignment > 0:
@@ -968,29 +964,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)
@@ -1000,50 +996,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:
@@ -1052,79 +1049,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)
@@ -1140,8 +1137,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)
@@ -1151,18 +1148,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)
@@ -1180,16 +1177,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,
@@ -1199,8 +1196,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:
@@ -1208,7 +1204,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)
@@ -1218,11 +1214,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}:
@@ -1235,35 +1231,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'.
@@ -1291,7 +1286,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)
@@ -1306,7 +1301,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:
@@ -1316,22 +1311,17 @@ 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
of wQuirky:
sym.incl sfNeverRaises
if sym.kind in {skProc, skMethod, skConverter, skFunc, skIterator}:
ensureMutable sym
sym.optionsImpl.incl optQuirky
of wEnforceNoRaises, wQuirky:
sym.flags.incl sfNeverRaises
of wSystemRaisesDefect:
sym.incl sfSystemRaisesDefect
sym.flags.incl sfSystemRaisesDefect
of wVirtual:
processVirtual(c, it, sym, sfVirtual)
of wMember:
@@ -1388,9 +1378,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
@@ -1411,12 +1401,11 @@ proc pragmaRec(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords;
inc i
proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords;
isStatement: bool; comesFromPush = false) =
isStatement: bool) =
if n == nil: return
pragmaRec(c, sym, n, validPragmas, isStatement)
# XXX: in the case of a callable def, this should use its info
if not comesFromPush:
implicitPragmas(c, sym, n.info, validPragmas)
implicitPragmas(c, sym, n.info, validPragmas)
proc pragmaCallable*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords,
isStatement: bool = false) =

View File

@@ -30,7 +30,7 @@ type
TRenderFlags* = set[TRenderFlag]
TRenderTok* = object
kind*: TokType
length*: int32
length*: int16
sym*: PSym
Section = enum
@@ -154,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
@@ -327,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)
@@ -414,7 +410,7 @@ proc atom(g: TSrcGen; n: PNode): string =
of nkEmpty: result = ""
of nkIdent: result = n.ident.s
of nkSym: result = n.sym.name.s
of nkClosedSymChoice, nkOpenSymChoice, nkOpenSym: result = n[0].sym.name.s
of nkClosedSymChoice, nkOpenSymChoice: result = n[0].sym.name.s
of nkStrLit: result = ""; result.addQuoted(n.strVal)
of nkRStrLit: result = "r\"" & replace(n.strVal, "\"", "\"\"") & '\"'
of nkTripleStrLit: result = "\"\"\"" & n.strVal & "\"\"\""
@@ -569,16 +565,8 @@ proc lsub(g: TSrcGen; n: PNode): int =
of nkIfExpr:
result = lsub(g, n[0][0]) + lsub(g, n[0][1]) + lsons(g, n, 1) +
len("if_:_")
of nkElifExpr, nkElifBranch:
if isEmptyType(n[1].typ):
result = lsons(g, n) + len("elif_:_")
else:
result = lsons(g, n) + len("_elif_:_")
of nkElseExpr, nkElse:
if isEmptyType(n[0].typ):
result = lsub(g, n[0]) + len("else:_")
else:
result = lsub(g, n[0]) + len("_else:_") # type descriptions
of nkElifExpr: result = lsons(g, n) + len("_elif_:_")
of nkElseExpr: result = lsub(g, n[0]) + len("_else:_") # type descriptions
of nkTypeOfExpr: result = (if n.len > 0: lsub(g, n[0]) else: 0)+len("typeof()")
of nkRefTy: result = (if n.len > 0: lsub(g, n[0])+1 else: 0) + len("ref")
of nkPtrTy: result = (if n.len > 0: lsub(g, n[0])+1 else: 0) + len("ptr")
@@ -621,6 +609,8 @@ proc lsub(g: TSrcGen; n: PNode): int =
of nkCommentStmt: result = n.comment.len
of nkOfBranch: result = lcomma(g, n, 0, - 2) + lsub(g, lastSon(n)) + len("of_:_")
of nkImportAs: result = lsub(g, n[0]) + len("_as_") + lsub(g, n[1])
of nkElifBranch: result = lsons(g, n) + len("elif_:_")
of nkElse: result = lsub(g, n[0]) + len("else:_")
of nkFinally: result = lsub(g, n[0]) + len("finally:_")
of nkGenericParams: result = lcomma(g, n) + 2
of nkFormalParams:
@@ -1012,7 +1002,7 @@ type
proc bracketKind*(g: TSrcGen, n: PNode): BracketKind =
if renderIds notin g.flags:
case n.kind
of nkClosedSymChoice, nkOpenSymChoice, nkOpenSym:
of nkClosedSymChoice, nkOpenSymChoice:
if n.len > 0: result = bracketKind(g, n[0])
else: result = bkNone
of nkSym:
@@ -1357,10 +1347,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}
@@ -1429,7 +1415,10 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
of nkPrefix:
gsub(g, n, 0)
if n.len > 1:
let opr = getPIdent(n[0])
let opr = if n[0].kind == nkIdent: n[0].ident
elif n[0].kind == nkSym: n[0].sym.name
elif n[0].kind in {nkOpenSymChoice, nkClosedSymChoice}: n[0][0].sym.name
else: nil
let nNext = skipHiddenNodes(n[1])
if nNext.kind == nkPrefix or (opr != nil and renderer.isKeyword(opr)):
put(g, tkSpaces, Space)
@@ -1480,30 +1469,15 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
putWithSpace(g, tkColon, ":")
if n.len > 0: gsub(g, n[0], 1)
gsons(g, n, emptyContext, 1)
of nkElifExpr, nkElifBranch:
if isEmptyType(n[1].typ):
optNL(g)
putWithSpace(g, tkElif, "elif")
gsub(g, n, 0)
putWithSpace(g, tkColon, ":")
gcoms(g)
gstmts(g, n[1], c)
else:
putWithSpace(g, tkElif, " elif")
gcond(g, n[0])
putWithSpace(g, tkColon, ":")
gsub(g, n, 1)
of nkElseExpr, nkElse:
if isEmptyType(n[0].typ):
optNL(g)
put(g, tkElse, "else")
putWithSpace(g, tkColon, ":")
gcoms(g)
gstmts(g, n[0], c)
else:
put(g, tkElse, " else")
putWithSpace(g, tkColon, ":")
gsub(g, n, 0)
of nkElifExpr:
putWithSpace(g, tkElif, " elif")
gcond(g, n[0])
putWithSpace(g, tkColon, ":")
gsub(g, n, 1)
of nkElseExpr:
put(g, tkElse, " else")
putWithSpace(g, tkColon, ":")
gsub(g, n, 0)
of nkTypeOfExpr:
put(g, tkType, "typeof")
put(g, tkParLe, "(")
@@ -1765,6 +1739,19 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
of nkMixinStmt:
putWithSpace(g, tkMixin, "mixin")
gcomma(g, n, c)
of nkElifBranch:
optNL(g)
putWithSpace(g, tkElif, "elif")
gsub(g, n, 0)
putWithSpace(g, tkColon, ":")
gcoms(g)
gstmts(g, n[1], c)
of nkElse:
optNL(g)
put(g, tkElse, "else")
putWithSpace(g, tkColon, ":")
gcoms(g)
gstmts(g, n[0], c)
of nkFinally, nkDefer:
optNL(g)
if n.kind == nkFinally:
@@ -1836,9 +1823,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

@@ -93,7 +93,7 @@ proc computeDeps(cache: IdentCache; n: PNode, declares, uses: var IntSet; topLev
of nkIdent: uses.incl n.ident.id
of nkSym: uses.incl n.sym.name.id
of nkAccQuoted: uses.incl accQuoted(cache, n).id
of nkOpenSymChoice, nkClosedSymChoice, nkOpenSym:
of nkOpenSymChoice, nkClosedSymChoice:
uses.incl n[0].sym.name.id
of nkStmtList, nkStmtListExpr, nkWhenStmt, nkElifBranch, nkElse, nkStaticStmt:
for i in 0..<n.len: computeDeps(cache, n[i], declares, uses, topLevel)

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
@@ -252,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):
@@ -321,7 +321,7 @@ proc hasCycle(n: PNode): bool =
break
excl n.flags, nfNone
proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode; producedClosure: var bool): PNode =
proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode =
# recompute the types as 'eval' isn't guaranteed to construct types nor
# that the types are sound:
when true:
@@ -333,7 +333,7 @@ proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode; producedClosure: v
if hasCycle(result):
result = localErrorNode(c, eOrig, "the resulting AST is cyclic and cannot be processed further")
else:
semmacrosanity.annotateType(result, expectedType, c.config, producedClosure)
semmacrosanity.annotateType(result, expectedType, c.config)
else:
result = semExprWithType(c, evaluated)
#result = fitNode(c, e.typ, result) inlined with special case:
@@ -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
@@ -383,10 +370,7 @@ proc tryConstExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode =
if result == nil or result.kind == nkEmpty:
result = nil
else:
var producedClosure = false
result = fixupTypeAfterEval(c, result, e, producedClosure)
if producedClosure:
result = nil
result = fixupTypeAfterEval(c, result, e)
except ERecoverableError:
result = nil
@@ -395,8 +379,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
@@ -425,10 +407,7 @@ proc semConstExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode =
# error correction:
result = e
else:
var producedClosure = false
result = fixupTypeAfterEval(c, result, e, producedClosure)
if producedClosure:
result = nil
result = fixupTypeAfterEval(c, result, e)
proc semExprFlagDispatched(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
if efNeedStatic in flags:
@@ -491,7 +470,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 +629,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 +651,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 +664,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 +677,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 +689,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 +702,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:
@@ -776,7 +755,6 @@ proc preparePContext*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PCo
result.semTypeNode = semTypeNode
result.instTypeBoundOp = sigmatch.instTypeBoundOp
result.hasUnresolvedArgs = hasUnresolvedArgs
result.semAsgnOpr = semAsgnOpr
result.templInstCounter = new int
pushProcCon(result, module)

View File

@@ -144,6 +144,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
while true:
determineType(c, sym)
z = initCandidate(c, sym, initialBinding, scope, diagnosticsFlag)
# this is kinda backwards as without a check here the described
# problems in recalc would not happen, but instead it 100%
# does check forever in some cases
@@ -183,7 +184,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
# 1) new symbols are discovered but the loop ends before we recalc
# 2) new symbols are discovered and resemmed forever
# not 100% sure if these are possible though as they would rely
# on somehow introducing a new overload during overload resolution
# on somehow introducing a new overload during overload resolution
# Symbol table has been modified. Restart and pre-calculate all syms
# before any further candidate init and compare. SLOW, but rare case.
@@ -244,6 +245,14 @@ proc effectProblem(f, a: PType; result: var string; c: PContext) =
if not c.graph.compatibleProps(c.graph, f, a):
result.add "\n The `.requires` or `.ensures` properties are incompatible."
proc renderNotLValue(n: PNode): string =
result = $n
let n = if n.kind == nkHiddenDeref: n[0] else: n
if n.kind == nkHiddenCallConv and n.len > 1:
result = $n[0] & "(" & result & ")"
elif n.kind in {nkHiddenStdConv, nkHiddenSubConv} and n.len == 2:
result = typeToString(n.typ.skipTypes(abstractVar)) & "(" & result & ")"
proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
(TPreferedDesc, string) =
var prefer = preferName
@@ -581,7 +590,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
let overloadsState = result.state
if overloadsState != csMatch:
if nfDotField in n.flags:
internalAssert c.config, f.kind in nkIdentKinds and n.len >= 2
internalAssert c.config, f.kind == nkIdent and n.len >= 2
# leave the op head symbol empty,
# we are going to try multiple variants
@@ -686,16 +695,9 @@ proc instGenericConvertersArg*(c: PContext, a: PNode, x: TCandidate) =
if a.kind == nkHiddenCallConv and a[0].kind == nkSym:
let s = a[0].sym
if s.isGenericRoutineStrict:
var src = s.typ.firstParamType
var convMatch = newCandidate(c, src)
var arg = a[1]
if arg.kind in {nkHiddenAddr, nkHiddenSubConv}: arg = arg[^1]
let srca = typeRel(convMatch, src, arg.typ)
if srca notin {isEqual, isGeneric, isSubtype}:
internalError(c.config, a.info, "generic converter failed rematch")
let finalCallee = generateInstance(c, s, convMatch.bindings, a.info)
let finalCallee = generateInstance(c, s, x.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 +732,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 +761,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 =
@@ -836,18 +838,15 @@ proc semResolvedCall(c: PContext, x: var TCandidate,
assert x.state == csMatch
var finalCallee = x.calleeSym
let info = getCallLineInfo(n)
markUsed(c, info, finalCallee, isGenericInstance = false)
onUse(info, finalCallee, isGenericInstance = false)
markUsed(c, info, finalCallee)
onUse(info, finalCallee)
assert finalCallee.ast != nil
if x.matchedErrorType:
markUsed(c, info, finalCallee, isGenericInstance = true)
onUse(info, finalCallee, isGenericInstance = true)
if x.matchedErrorType:
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:
@@ -873,19 +872,17 @@ 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 = 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.} =
@@ -894,7 +891,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,
@@ -913,16 +910,16 @@ 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)
elif efNoUndeclared in flags:
result = nil
result.typ() = makeTypeFromExpr(c, result.copyTree)
elif efExplain notin flags:
# repeat the overload resolution,
# this time enabling all the diagnostic output (this should fail again)
result = semOverloadedCall(c, n, nOrig, filter, flags + {efExplain})
else:
elif efNoUndeclared notin flags:
result = nil
notFoundError(c, n, errors)
else:
result = nil
proc explicitGenericInstError(c: PContext; n: PNode): PNode =
localError(c.config, getCallLineInfo(n), errCannotInstantiateX % renderTree(n))
@@ -945,12 +942,10 @@ 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)
markUsed(c, info, newInst, isGenericInstance = true)
onUse(info, newInst, isGenericInstance = true)
markUsed(c, info, s)
onUse(info, s)
result = newSymNode(newInst, info)
proc setGenericParams(c: PContext, n, expectedParams: PNode) =
@@ -964,9 +959,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.skipTypes({tyTypeDesc})
n[i].typ() = e.typ.skipTypes({tyTypeDesc})
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym, doError: bool): PNode =
assert n.kind == nkBracketExpr
@@ -983,7 +978,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}:
@@ -1001,7 +996,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

@@ -9,15 +9,14 @@
## This module contains the data structures for the semantic checking phase.
import std/[tables, intsets, sets, strutils]
import std/[tables, intsets, sets]
when defined(nimPreviewSlimSystem):
import std/assertions
import
options, ast, msgs, idents, renderer,
magicsys, vmdef, modulegraphs, lineinfos, pathutils, layeredtable,
types, lowerings, trees, parampatterns, astalgo
magicsys, vmdef, modulegraphs, lineinfos, pathutils, layeredtable
import ic / ic
@@ -42,7 +41,7 @@ type
breakInLoop*: bool # whether we are in a loop without block
next*: PProcCon # used for stacking procedure contexts
mappingExists*: bool
mapping*: SymMapping
mapping*: Table[ItemId, PSym]
caseContext*: seq[tuple[n: PNode, idx: int]]
localBindStmts*: seq[PNode]
@@ -153,6 +152,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.}
@@ -171,13 +171,8 @@ type
sideEffects*: Table[int, seq[(TLineInfo, PSym)]] # symbol.id index
inUncheckedAssignSection*: int
importModuleLookup*: Table[int, seq[int]] # (module.ident.id, [module.id])
forwardTypeUpdates*: seq[(PType, PNode)]
# types that need to be updated in a type section
# due to containing forward types, and their corresponding nodes
skipTypes*: seq[PNode] # used to skip types between passes in type section. So far only used for inheritance, sets and generic bodies.
inTypeofContext*: int
semAsgnOpr*: proc (c: PContext; n: PNode; k: TNodeKind): PNode {.nimcall.}
TBorrowState* = enum
bsNone, bsReturnNotMatch, bsNoDistinct, bsGeneric, bsNotSupported, bsMatch
@@ -201,29 +196,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")
@@ -259,7 +254,7 @@ proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next
proc put*(p: PProcCon; key, val: PSym) =
if not p.mappingExists:
p.mapping = initSymMapping()
p.mapping = initTable[ItemId, PSym]()
p.mappingExists = true
#echo "put into table ", key.info
p.mapping[key.itemId] = val
@@ -291,24 +286,22 @@ proc considerGenSyms*(c: PContext; n: PNode) =
considerGenSyms(c, n[i])
proc newOptionEntry*(conf: ConfigRef): POptionEntry =
result = POptionEntry(
options: conf.options,
defaultCC: ccNimCall,
dynlib: nil,
notes: conf.notes,
warningAsErrors: conf.warningAsErrors
)
new(result)
result.options = conf.options
result.defaultCC = ccNimCall
result.dynlib = nil
result.notes = conf.notes
result.warningAsErrors = conf.warningAsErrors
proc pushOptionEntry*(c: PContext): POptionEntry =
let prev = c.optionStack[^1]
result = POptionEntry(
options: c.config.options,
defaultCC: prev.defaultCC,
dynlib: prev.dynlib,
notes: c.config.notes,
warningAsErrors: c.config.warningAsErrors,
features: c.features
)
new(result)
var prev = c.optionStack[^1]
result.options = c.config.options
result.defaultCC = prev.defaultCC
result.dynlib = prev.dynlib
result.notes = c.config.notes
result.warningAsErrors = c.config.warningAsErrors
result.features = c.features
c.optionStack.add(result)
proc popOptionEntry*(c: PContext) =
@@ -319,23 +312,22 @@ proc popOptionEntry*(c: PContext) =
c.optionStack.setLen(c.optionStack.len - 1)
proc newContext*(graph: ModuleGraph; module: PSym): PContext =
result = PContext(
optionStack: @[newOptionEntry(graph.config)],
libs: @[],
module: module,
friendModules: @[module],
converters: @[],
patterns: @[],
includedFiles: initIntSet(),
pureEnumFields: initStrTable(),
userPragmas: initStrTable(),
generics: @[],
unknownIdents: initIntSet(),
cache: graph.cache,
graph: graph,
signatures: initStrTable(),
features: graph.config.features
)
new(result)
result.optionStack = @[newOptionEntry(graph.config)]
result.libs = @[]
result.module = module
result.friendModules = @[module]
result.converters = @[]
result.patterns = @[]
result.includedFiles = initIntSet()
result.pureEnumFields = initStrTable()
result.userPragmas = initStrTable()
result.generics = @[]
result.unknownIdents = initIntSet()
result.cache = graph.cache
result.graph = graph
result.signatures = initStrTable()
result.features = graph.config.features
if graph.config.symbolFiles != disabledSf:
let id = module.position
if graph.config.cmd != cmdM:
@@ -358,9 +350,6 @@ proc addImportFileDep*(c: PContext; f: FileIndex) =
proc addPragmaComputation*(c: PContext; n: PNode) =
if c.config.symbolFiles != disabledSf:
addPragmaComputation(c.encoder, c.packedRepr, n)
# 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)
proc inclSym(sq: var seq[PSym], s: PSym): bool =
for i in 0..<sq.len:
@@ -402,7 +391,8 @@ proc reexportSym*(c: PContext; s: PSym) =
addReexport(c.encoder, c.packedRepr, s)
proc newLib*(kind: TLibKind): PLib =
result = PLib(kind: kind) #result.syms = initObjectSet()
new(result)
result.kind = kind #result.syms = initObjectSet()
proc addToLib*(lib: PLib, sym: PSym) =
#if sym.annex != nil and not isGenericRoutine(sym):
@@ -436,7 +426,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,
@@ -460,7 +450,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 =
@@ -469,8 +459,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:
@@ -488,14 +478,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)
@@ -505,7 +495,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)))
@@ -515,11 +505,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 =
@@ -565,21 +555,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) =
@@ -645,166 +635,3 @@ proc rememberExpansion*(c: PContext; info: TLineInfo; expandedSym: PSym) =
## 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"
errXStackEscape = "address of '$1' may not escape its stack frame"
proc renderNotLValue*(n: PNode): string =
result = $n
let n = if n.kind == nkHiddenDeref: n[0] else: n
if n.kind == nkHiddenCallConv and n.len > 1:
result = $n[0] & "(" & result & ")"
elif n.kind in {nkHiddenStdConv, nkHiddenSubConv} and n.len == 2:
result = typeToString(n.typ.skipTypes(abstractVar)) & "(" & result & ")"
proc isAssignable(c: PContext, n: PNode): TAssignableResult =
result = parampatterns.isAssignable(c.p.owner, n)
proc newHiddenAddrTaken(c: PContext, n: PNode, isOutParam: bool): PNode =
if n.kind == nkHiddenDeref and not (c.config.backend == backendCpp or
sfCompileToCpp in c.module.flags):
checkSonsLen(n, 1, c.config)
result = n[0]
else:
result = newNodeIT(nkHiddenAddr, n.info, makeVarType(c, n.typ))
result.add n
let aa = isAssignable(c, n)
let sym = getRoot(n)
if aa notin {arLValue, arLocalLValue}:
if aa == arDiscriminant and c.inUncheckedAssignSection > 0:
discard "allow access within a cast(unsafeAssign) section"
elif strictDefs in c.features and aa == arAddressableConst and
sym != nil and sym.kind == skLet and isOutParam:
discard "allow let varaibles to be passed to out parameters"
else:
localError(c.config, n.info, errVarForOutParamNeededX % renderNotLValue(n))
proc analyseIfAddressTaken(c: PContext, n: PNode, isOutParam: bool): PNode =
result = n
case n.kind
of nkSym:
# 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)
result = newHiddenAddrTaken(c, n, isOutParam)
of nkDotExpr:
checkSonsLen(n, 2, c.config)
if n[1].kind != nkSym:
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)
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)
result = newHiddenAddrTaken(c, n, isOutParam)
else:
result = newHiddenAddrTaken(c, n, isOutParam)
proc analyseIfAddressTakenInCall*(c: PContext, n: PNode, isConverter = false) =
checkMinSonsLen(n, 1, c.config)
if n[0].typ == nil:
# n[0] might be erroring node in nimsuggest
return
const
FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl,
mSetLengthStr, mSetLengthSeq, mSetLengthSeqUninit, mAppendStrCh, mAppendStrStr, mSwap,
mAppendSeqElem, mNewSeq, mShallowCopy, mDeepCopy, mMove, mWasMoved}
template checkIfConverterCalled(c: PContext, n: PNode) =
## Checks if there is a converter call which wouldn't be checked otherwise
# Call can sometimes be wrapped in a deref
let node = if n.kind == nkHiddenDeref: n[0] else: n
if node.kind == nkHiddenCallConv:
analyseIfAddressTakenInCall(c, node, true)
# get the real type of the callee
# it may be a proc var with a generic alias type, so we skip over them
var t = n[0].typ.skipTypes({tyGenericInst, tyAlias, tySink})
if n[0].kind == nkSym and n[0].sym.magic in FakeVarParams:
# BUGFIX: check for L-Value still needs to be done for the arguments!
# note sometimes this is eval'ed twice so we check for nkHiddenAddr here:
for i in 1..<n.len:
if i < t.len and t[i] != nil and
skipTypes(t[i], abstractInst-{tyTypeDesc}).kind in {tyVar}:
let it = n[i]
let aa = isAssignable(c, it)
if aa notin {arLValue, arLocalLValue}:
if it.kind != nkHiddenAddr:
if aa == arDiscriminant and c.inUncheckedAssignSection > 0:
discard "allow access within a cast(unsafeAssign) section"
else:
localError(c.config, it.info, errVarForOutParamNeededX % $it)
# Make sure to still check arguments for converters
c.checkIfConverterCalled(n[i])
# bug #5113: disallow newSeq(result) where result is a 'var T':
if n[0].sym.magic in {mNew, mNewFinalize, mNewSeq}:
var arg = n[1] #.skipAddr
if arg.kind == nkHiddenDeref: arg = arg[0]
if arg.kind == nkSym and arg.sym.kind == skResult and
arg.typ.skipTypes(abstractInst).kind in {tyVar, tyLent}:
localError(c.config, n.info, errXStackEscape % renderTree(n[1], {renderNoComments}))
return
for i in 1..<n.len:
let n = if n.kind == nkHiddenDeref: n[0] else: n
c.checkIfConverterCalled(n[i])
if i < t.len and
skipTypes(t[i], abstractInst-{tyTypeDesc}).kind in {tyVar}:
# Converters wrap var parameters in nkHiddenAddr but they haven't been analysed yet.
# So we need to make sure we are checking them still when in a converter call
if n[i].kind != nkHiddenAddr or isConverter:
n[i] = analyseIfAddressTaken(c, n[i].skipAddr(), isOutParam(skipTypes(t[i], abstractInst-{tyTypeDesc})))
proc replaceHookMagic*(c: PContext, n: PNode, kind: TTypeAttachedOp): PNode =
## Replaces builtin generic hooks with lifted hooks.
case kind
of attachedDestructor:
result = n
let t = n[1].typ.skipTypes(abstractVar)
let op = getAttachedOp(c.graph, t, attachedDestructor)
if op != nil:
result[0] = newSymNode(op)
if op.typ != nil and op.typ.len == 2 and op.typ.firstParamType.kind != tyVar:
if n[1].kind == nkSym and n[1].sym.kind == skParam and
n[1].typ.kind == tyVar:
result[1] = genDeref(n[1])
else:
result[1] = skipAddr(n[1])
of attachedTrace:
result = n
let t = n[1].typ.skipTypes(abstractVar)
let op = getAttachedOp(c.graph, t, attachedTrace)
if op != nil:
result[0] = newSymNode(op)
of attachedDup:
result = n
let t = n[1].typ.skipTypes(abstractVar)
let op = getAttachedOp(c.graph, t, attachedDup)
if op != nil:
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)
result.add boolLit
of attachedWasMoved:
result = n
let t = n[1].typ.skipTypes(abstractVar)
let op = getAttachedOp(c.graph, t, attachedWasMoved)
if op != nil:
result[0] = newSymNode(op)
analyseIfAddressTakenInCall(c, result, false)
of attachedSink:
result = c.semAsgnOpr(c, n, nkSinkAsgn)
of attachedAsgn:
result = c.semAsgnOpr(c, n, nkAsgn)
of attachedDeepCopy:
result = n
let t = n[1].typ.skipTypes(abstractVar)
let op = getAttachedOp(c.graph, t, kind)
if op != nil:
result[0] = newSymNode(op)

File diff suppressed because it is too large Load Diff

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 =
@@ -36,8 +36,7 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
of nkIdent, nkSym:
result = n
let ident = considerQuotedIdent(c.c, n)
if c.replaceByFieldName and
ident.id != ord(wUnderscore):
if c.replaceByFieldName:
if ident.id == considerQuotedIdent(c.c, forLoop[0]).id:
let fieldName = if c.tupleType.isNil: c.field.name.s
elif c.tupleType.n.isNil: "Field" & $c.tupleIndex
@@ -46,8 +45,7 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
return
# other fields:
for i in ord(c.replaceByFieldName)..<forLoop.len-2:
if ident.id == considerQuotedIdent(c.c, forLoop[i]).id and
ident.id != ord(wUnderscore):
if ident.id == considerQuotedIdent(c.c, forLoop[i]).id:
var call = forLoop[^2]
var tupl = call[i+1-ord(c.replaceByFieldName)]
if c.field.isNil:

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:
@@ -473,20 +471,19 @@ proc foldArrayAccess(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNo
if result.kind == nkExprColonExpr: result = result[1]
else:
result = nil
#localError(g.config, n.info, formatErrorIndexBound(idx, x.len-1) & $n)
localError(g.config, n.info, formatErrorIndexBound(idx, x.len-1) & $n)
of nkBracket:
idx -= toInt64(firstOrd(g.config, x.typ))
if idx >= 0 and idx < x.len: result = x[int(idx)]
else:
result = nil
#localError(g.config, n.info, formatErrorIndexBound(idx, x.len-1) & $n)
localError(g.config, n.info, formatErrorIndexBound(idx, x.len-1) & $n)
of nkStrLit..nkTripleStrLit:
result = newNodeIT(nkCharLit, x.info, n.typ)
if idx >= 0 and idx < x.strVal.len:
result.intVal = ord(x.strVal[int(idx)])
else:
result = nil
#localError(g.config, n.info, formatErrorIndexBound(idx, x.strVal.len-1) & $n)
localError(g.config, n.info, formatErrorIndexBound(idx, x.strVal.len-1) & $n)
else: result = nil
proc foldFieldAccess(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
@@ -520,10 +517,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 +639,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 +752,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 +763,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 +780,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,8 +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
markOwnerModuleAsUsed(c, result.sym)
markUsed(c, n.info, result.sym)
of nkDotExpr:
#let luf = if withinMixin notin flags: {checkUndeclared} else: {}
#var s = qualifiedLookUp(c, n, luf)
@@ -318,7 +317,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 +631,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,13 @@ 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):
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)
@@ -321,8 +318,6 @@ proc instantiateProcType(c: PContext, pt: LayeredIdTable,
cl.isReturnType = false
result.n[0] = originalParams[0].copyTree
if result[0] != nil:
if isRecursiveStructuralType(result[0]):
localError(c.config, originalParams[0].info, "illegal recursion in type '" & typeToString(result[0]) & "'")
propagateToOwner(result, result[0])
eraseVoidParams(result)
@@ -338,7 +333,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 +389,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)
@@ -430,7 +425,6 @@ proc generateInstance(c: PContext, fn: PSym, pt: LayeredIdTable,
addDecl(c, s)
entry.concreteTypes[i] = s.typ
inc i
entry.genericParamsCount = i
c.matchedConcept = nil
pushProcCon(c, result)
instantiateProcType(c, pt, result, info)
@@ -439,7 +433,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 +445,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

@@ -86,15 +86,15 @@ proc ithField(t: PType, field: var FieldTracker): FieldInfo =
base = b.baseClass
result = ithField(t.n, field)
proc annotateType*(n: PNode, t: PType; conf: ConfigRef; producedClosure: var bool) =
proc annotateType*(n: PNode, t: PType; conf: ConfigRef) =
let x = t.skipTypes(abstractInst+{tyRange})
# Note: x can be unequal to t and we need to be careful to use 't'
# to not to skip tyGenericInst
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)
@@ -102,20 +102,18 @@ proc annotateType*(n: PNode, t: PType; conf: ConfigRef; producedClosure: var boo
globalError conf, n.info, "invalid field at index " & $i
else:
internalAssert(conf, n[i].kind == nkExprColonExpr)
annotateType(n[i][1], field.sym.typ, conf, producedClosure)
annotateType(n[i][1], field.sym.typ, conf)
if field.delete:
# only codegen fields from active case branches
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)
else: annotateType(n[i], x[i], conf)
elif x.kind == tyProc and x.callConv == ccClosure:
n.typ = t
if n.len > 1 and n[1].kind notin {nkEmpty, nkNilLit}:
producedClosure = true
n.typ() = t
elif x.kind == tyOpenArray: # `opcSlice` transforms slices into tuples
if n.kind == nkTupleConstr:
let
@@ -127,53 +125,48 @@ proc annotateType*(n: PNode, t: PType; conf: ConfigRef; producedClosure: var boo
of nkStrKinds:
for i in left..right:
bracketExpr.add newIntNode(nkCharLit, BiggestInt n[0].strVal[i])
annotateType(bracketExpr[^1], x.elementType, conf, producedClosure)
annotateType(bracketExpr[^1], x.elementType, conf)
of nkBracket:
for i in left..right:
bracketExpr.add n[0][i]
annotateType(bracketExpr[^1], x.elementType, conf, producedClosure)
annotateType(bracketExpr[^1], x.elementType, conf)
else:
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
for m in n: annotateType(m, x.elemType, conf, producedClosure)
n.typ() = t
for m in n: annotateType(m, x.elemType, conf)
else:
globalError(conf, n.info, "[] must have some form of array type")
of nkCurly:
if x.kind in {tySet}:
n.typ = t
for m in n:
if m.kind == nkRange:
annotateType(m[0], x.elemType, conf, producedClosure)
annotateType(m[1], x.elemType, conf, producedClosure)
else:
annotateType(m, x.elemType, conf, producedClosure)
n.typ() = t
for m in n: annotateType(m, x.elemType, conf)
else:
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)
proc semTypeOf(c: PContext; n: PNode): PNode =
var m = BiggestInt 1 # typeOfIter
@@ -54,16 +54,8 @@ 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
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
else:
t = base
result.typ = makeTypeDesc(c, t)
typExpr.typ.flags.incl tfNonConstExpr
result.typ() = makeTypeDesc(c, typExpr.typ)
type
SemAsgnMode = enum asgnNormal, noOverloadedSubscript, noOverloadedAsgn
@@ -84,8 +76,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 +200,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
@@ -243,7 +235,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":
@@ -286,7 +278,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)
@@ -402,7 +394,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:
@@ -411,10 +403,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 =
@@ -442,16 +434,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.
@@ -461,7 +453,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):
@@ -471,7 +463,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)
@@ -550,8 +542,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,
@@ -568,7 +560,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)
@@ -612,10 +604,9 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
of mArrPut:
result = semArrPut(c, n, flags)
of mAsgn:
case n[0].sym.name.s
of "=", "=copy":
if n[0].sym.name.s == "=":
result = semAsgnOpr(c, n, nkAsgn)
of "=sink":
elif n[0].sym.name.s == "=sink":
result = semAsgnOpr(c, n, nkSinkAsgn)
else:
result = semShallowCopy(c, n, flags)
@@ -623,7 +614,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)
@@ -636,7 +627,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:
@@ -654,20 +645,49 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
of mNewFinalize:
result = semNewFinalize(c, n)
of mDestroy:
result = replaceHookMagic(c, n, attachedDestructor)
result = n
let t = n[1].typ.skipTypes(abstractVar)
let op = getAttachedOp(c.graph, t, attachedDestructor)
if op != nil:
result[0] = newSymNode(op)
if op.typ != nil and op.typ.len == 2 and op.typ.firstParamType.kind != tyVar:
if n[1].kind == nkSym and n[1].sym.kind == skParam and
n[1].typ.kind == tyVar:
result[1] = genDeref(n[1])
else:
result[1] = skipAddr(n[1])
of mTrace:
result = replaceHookMagic(c, n, attachedTrace)
result = n
let t = n[1].typ.skipTypes(abstractVar)
let op = getAttachedOp(c.graph, t, attachedTrace)
if op != nil:
result[0] = newSymNode(op)
of mDup:
result = replaceHookMagic(c, n, attachedDup)
result = n
let t = n[1].typ.skipTypes(abstractVar)
let op = getAttachedOp(c.graph, t, attachedDup)
if op != nil:
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)
result.add boolLit
of mWasMoved:
result = replaceHookMagic(c, n, attachedWasMoved)
result = n
let t = n[1].typ.skipTypes(abstractVar)
let op = getAttachedOp(c.graph, t, attachedWasMoved)
if op != nil:
result[0] = newSymNode(op)
let addrExp = newNodeIT(nkHiddenAddr, result[1].info, makePtrType(c, t))
addrExp.add result[1]
result[1] = addrExp
of mUnown:
result = semUnown(c, n)
of mExists, mForall:
result = semQuantifier(c, n)
of mOld:
result = semOld(c, n)
of mSetLengthSeq, mSetLengthSeqUninit:
of mSetLengthSeq:
result = n
let seqType = result[1].typ.skipTypes({tyPtr, tyRef, # in case we had auto-dereferencing
tyVar, tyGenericInst, tyOwned, tySink,
@@ -692,7 +712,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,
@@ -240,7 +236,7 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
let prevFields = fieldsPresentInBranch(selectedBranch)
let currentFields = fieldsPresentInBranch(i)
localError(c.config, constrCtx.initExpr.info,
("The fields $1 and $2 cannot be initialized together, " &
("The fields '$1' and '$2' cannot be initialized together, " &
"because they are from conflicting branches in the case object.") %
[prevFields, currentFields])
result.status = initConflict
@@ -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

@@ -84,7 +84,6 @@ type
gcUnsafe, isRecursive, isTopLevel, hasSideEffect, inEnforcedGcSafe: bool
isInnerProc: bool
inEnforcedNoSideEffects: bool
unknownRaises: seq[(PSym, TLineInfo)]
currOptions: TOptions
optionsStack: seq[(TOptions, TNoteKinds)]
config: ConfigRef
@@ -138,10 +137,9 @@ proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo; explicit
createTypeBoundOps(tracked.graph, tracked.c, realType.lastSon, info)
createTypeBoundOps(tracked.graph, tracked.c, typ, info, tracked.c.idgen)
if tracked.config.selectedGC == gcRefc or
optSeqDestructors in tracked.config.globalOptions or
tfHasAsgn in typ.flags:
tracked.owner.incl sfInjectDestructors
if (tfHasAsgn in typ.flags) or
optSeqDestructors in tracked.config.globalOptions:
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
@@ -196,7 +194,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
@@ -206,7 +204,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:
@@ -372,16 +370,14 @@ 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
elif s.id notin a.init:
if s.kind == skResult and tfRequiresInit in s.typ.flags:
localError(a.config, n.info, "'result' requires explicit initialization")
elif s.typ.requiresInit:
if s.typ.requiresInit:
message(a.config, n.info, warnProveInit, s.name.s)
elif a.leftPartOfAsgn <= 0:
if strictDefs in a.c.features:
@@ -417,7 +413,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
@@ -432,12 +428,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) =
@@ -642,8 +638,6 @@ proc importedFromC(n: PNode): bool =
proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
let pragma = s.ast[pragmasPos]
let spec = effectSpec(pragma, wRaises)
if spec.isNil and sfForward in s.flags:
tracked.unknownRaises.add (s, n.info)
mergeRaises(tracked, spec, n)
let tagSpec = effectSpec(pragma, wTags)
@@ -707,7 +701,7 @@ proc isNoEffectList(n: PNode): bool {.inline.} =
assert n.kind == nkEffectList
n.len == 0 or (n[tagEffects] == nil and n[exceptionEffects] == nil and n[forbiddenEffects] == nil)
proc isTrivial(caller: PNode): bool {.inline.} =
proc isTrival(caller: PNode): bool {.inline.} =
result = caller.kind == nkSym and caller.sym.magic in {mEqProc, mIsNil, mMove, mWasMoved, mSwap}
proc trackOperandForIndirectCall(tracked: PEffects, n: PNode, formals: PType; argIndex: int; caller: PNode) =
@@ -716,7 +710,7 @@ proc trackOperandForIndirectCall(tracked: PEffects, n: PNode, formals: PType; ar
let param = if formals != nil and formals.n != nil and argIndex < formals.n.len: formals.n[argIndex].sym else: nil
# assume indirect calls are taken here:
if op != nil and op.kind == tyProc and n.skipConv.kind != nkNilLit and
not isTrivial(caller) and
not isTrival(caller) and
((param != nil and sfEffectsDelayed in param.flags) or laxEffects in tracked.c.config.legacyFeatures):
internalAssert tracked.config, op.n[0].kind == nkEffectList
@@ -888,9 +882,8 @@ proc trackIf(tracked: PEffects, n: PNode) =
setLen(tracked.guards.s, oldFacts)
dec tracked.inIfStmt
proc trackBlock(tracked: PEffects, n: PNode; typ: PType) =
proc trackBlock(tracked: PEffects, n: PNode) =
if n.kind in {nkStmtList, nkStmtListExpr}:
let myBlock = tracked.currentBlock
var oldState = -1
for i in 0..<n.len:
if hasSubnodeWith(n[i], nkBreakStmt):
@@ -902,14 +895,6 @@ proc trackBlock(tracked: PEffects, n: PNode; typ: PType) =
if oldState < 0: oldState = tracked.init.len
track(tracked, n[i])
if oldState > 0: setLen(tracked.init, oldState)
if typ != nil and typ.kind in {tyVar, tyLent, tyOpenArray, tyVarargs}:
let last = lastSon(n)
let root = getRoot(last)
if root != nil:
let owner = tracked.scopes.getOrDefault(root.id, -1)
if owner >= 0:
localError(tracked.config, last.info, "'" & renderTree(last) & "' borrows from location '" & root.name.s &
"' which does not live long enough")
else:
track(tracked, n)
@@ -982,7 +967,7 @@ proc checkForSink(tracked: PEffects; n: PNode) =
proc markCaughtExceptions(tracked: PEffects; g: ModuleGraph; info: TLineInfo; s: PSym; usageSym: var PSym) =
when defined(nimsuggest):
proc internalMarkCaughtExceptions(tracked: PEffects; q: var SuggestFileSymbolDatabase; info: TLineInfo) =
var si = q.findSymInfoIndex(info, true)
var si = q.findSymInfoIndex(info)
if si != -1:
q.caughtExceptionsSet[si] = true
for w1 in tracked.caughtExceptions.nodes:
@@ -992,25 +977,6 @@ proc markCaughtExceptions(tracked: PEffects; g: ModuleGraph; info: TLineInfo; s:
if optIdeExceptionInlayHints in tracked.config.globalOptions:
internalMarkCaughtExceptions(tracked, g.suggestSymbols.mgetOrPut(info.fileIndex, newSuggestFileSymbolDatabase(info.fileIndex, true)), info)
proc findHookKind(name: string): (bool, TTypeAttachedOp) =
case name.normalize
of "=wasmoved":
result = (true, attachedWasMoved)
of "=destroy":
result = (true, attachedDestructor)
of "=copy", "=":
result = (true, attachedAsgn)
of "=dup":
result = (true, attachedDup)
of "=sink":
result = (true, attachedSink)
of "=trace":
result = (true, attachedTrace)
of "=deepcopy":
result = (true, attachedDeepCopy)
else:
result = (false, attachedWasMoved)
proc trackCall(tracked: PEffects; n: PNode) =
template gcsafeAndSideeffectCheck() =
if notGcSafe(op) and not importedFromC(a):
@@ -1099,17 +1065,18 @@ proc trackCall(tracked: PEffects; n: PNode) =
checkBounds(tracked, n[1], n[2])
var n = n
if a.kind == nkSym and a.sym.name.s.len > 0 and a.sym.name.s[0] == '=' and
tracked.owner.kind != skMacro:
var (isHook, opKind) = findHookKind(a.sym.name.s)
if isHook:
var opKind = find(AttachedOpToStr, a.sym.name.s.normalize)
if a.sym.name.s == "=": opKind = attachedAsgn.int
if opKind != -1:
# rebind type bounds operations after createTypeBoundOps call
let t = n[1].typ.skipTypes({tyAlias, tyVar})
if a.sym != getAttachedOp(tracked.graph, t, opKind):
if a.sym != getAttachedOp(tracked.graph, t, TTypeAttachedOp(opKind)):
createTypeBoundOps(tracked, t, n.info, explicit = true)
# replace builtin hooks with lifted ones
n = replaceHookMagic(tracked.c, n, opKind)
let op = getAttachedOp(tracked.graph, t, TTypeAttachedOp(opKind))
if op != nil:
n[0].sym = op
if op != nil and op.kind == tyProc:
for i in 1..<min(n.safeLen, op.signatureLen):
@@ -1243,9 +1210,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}:
@@ -1342,12 +1309,12 @@ proc track(tracked: PEffects, n: PNode) =
tracked.init.setLen(oldState)
track(tracked, n[1][0])
of nkIfStmt, nkIfExpr: trackIf(tracked, n)
of nkBlockStmt, nkBlockExpr: trackBlock(tracked, n[1], n.typ)
of nkBlockStmt, nkBlockExpr: trackBlock(tracked, n[1])
of nkWhileStmt:
# 'while true' loop?
inc tracked.currentBlock
if isTrue(n[0]):
trackBlock(tracked, n[1], nil)
trackBlock(tracked, n[1])
else:
# loop may never execute:
let oldState = tracked.init.len
@@ -1538,7 +1505,7 @@ proc subtypeRelation(g: ModuleGraph; spec, real: PNode): bool =
proc checkRaisesSpec(g: ModuleGraph; emitWarnings: bool; spec, real: PNode, msg: string, hints: bool;
effectPredicate: proc (g: ModuleGraph; a, b: PNode): bool {.nimcall.};
hintsArg: PNode = nil; isForbids: bool = false; unknownRaises: seq[(PSym, TLineInfo)] = @[]) =
hintsArg: PNode = nil; isForbids: bool = false) =
# check that any real exception is listed in 'spec'; mark those as used;
# report any unused exception
var used = initIntSet()
@@ -1555,8 +1522,6 @@ proc checkRaisesSpec(g: ModuleGraph; emitWarnings: bool; spec, real: PNode, msg:
pushInfoContext(g.config, spec.info)
var rr = if r.kind == nkRaiseStmt: r[0] else: r
while rr.kind in {nkStmtList, nkStmtListExpr} and rr.len > 0: rr = rr.lastSon
for (s, info) in unknownRaises.items:
message(g.config, info, hintUnknownRaises, s.name.s)
message(g.config, r.info, if emitWarnings: warnEffect else: errGenerated,
renderTree(rr) & " " & msg & typeToString(r.typ))
popInfoContext(g.config)
@@ -1627,7 +1592,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)
@@ -1682,7 +1647,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)
@@ -1714,7 +1679,7 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) =
if not isNil(raisesSpec):
let useWarning = s.name.s == "=destroy"
checkRaisesSpec(g, useWarning, raisesSpec, t.exc, "can raise an unlisted exception: ",
hints=on, subtypeRelation, hintsArg=s.ast[0], unknownRaises = t.unknownRaises)
hints=on, subtypeRelation, hintsArg=s.ast[0])
# after the check, use the formal spec:
effects[exceptionEffects] = raisesSpec
else:
@@ -1769,9 +1734,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"
@@ -726,33 +725,22 @@ template isLocalSym(sym: PSym): bool =
sym.typ.kind == tyTypeDesc or
sfCompileTime in sym.flags) or
sym.kind in {skProc, skFunc, skIterator} and
sfGlobal notin sym.flags and sym.typ.callConv == ccClosure
sfGlobal notin sym.flags
template isLocalVarSym(n: PNode): bool =
n.kind == nkSym and isLocalSym(n.sym)
proc usesLocalVar(n: PNode): bool =
case n.kind
of nkSym:
result = isLocalSym(n.sym)
of nkCallKinds, nkObjConstr:
result = false
for i in 1 ..< n.len:
if usesLocalVar(n[i]):
result = false
for z in 1 ..< n.len:
if n[z].isLocalVarSym:
return true
elif n[z].kind in nkCallKinds:
if usesLocalVar(n[z]):
return true
of nkTupleConstr, nkPar, nkBracket, nkCurly:
result = false
for i in 0 ..< n.len:
if usesLocalVar(n[i]):
return true
of nkDotExpr, nkCheckedFieldExpr,
nkBracketExpr, nkAddr, nkHiddenAddr,
nkObjDownConv, nkObjUpConv:
result = usesLocalVar(n[0])
of nkHiddenStdConv, nkHiddenSubConv, nkCast, nkExprColonExpr:
result = usesLocalVar(n[1])
else:
result = false
proc globalVarInitCheck(c: PContext, n: PNode) =
if usesLocalVar(n):
if n.isLocalVarSym or n.kind in nkCallKinds and usesLocalVar(n):
localError(c.config, n.info, errCannotAssignToGlobal)
const
@@ -780,7 +768,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 +926,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 +1102,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 +1116,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 +1146,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 +1160,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 +1307,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 +1389,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 +1447,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:
@@ -1472,13 +1460,8 @@ proc typeDefLeftSidePass(c: PContext, typeSection: PNode, i: int) =
else:
s = semIdentDef(c, name, skType)
onDef(name.info, s)
if s.typ != nil:
# name node is a symbol with a type already, probably in resem, don't touch it
discard
else:
s.typ = newTypeS(tyForward, c)
s.typ.sym = s
# process pragmas:
s.typ = newTypeS(tyForward, c)
s.typ.sym = s # process pragmas:
if name.kind == nkPragmaExpr:
let rewritten = applyTypeSectionPragmas(c, name[1], typeDef)
if rewritten != nil:
@@ -1550,7 +1533,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 +1559,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
@@ -1616,26 +1599,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
localError(c.config, a.info, errImplOfXexpected % s.name.s)
if s.magic != mNone: processMagicType(c, s)
let oldFlags = s.typ.flags
let preserveSym = s.typ != nil and s.typ.kind != tyForward and sfForward notin s.flags and
s.magic == mNone # magic might have received type above but still needs processing
if preserveSym:
# symbol already has a type, probably in resem, do not modify it
# but still semcheck the RHS to handle any defined symbols
# nominal type nodes are still ignored in semtypes
if a[1].kind != nkEmpty:
openScope(c)
pushOwner(c, s)
a[1] = semGenericParamList(c, a[1], nil)
inc c.inGenericContext
discard semTypeNode(c, a[2], s.typ)
dec c.inGenericContext
popOwner(c)
closeScope(c)
elif a[2].kind != nkEmpty:
pushOwner(c, s)
discard semTypeNode(c, a[2], s.typ)
popOwner(c)
elif a[1].kind != nkEmpty:
if a[1].kind != nkEmpty:
# We have a generic type declaration here. In generic types,
# symbol lookup needs to be done here.
openScope(c)
@@ -1668,11 +1632,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,27 +1685,27 @@ 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
aa[0].kind == nkObjectTy and not preserveSym:
aa[0].kind == nkObjectTy:
# give anonymous object a dummy symbol:
var st = s.typ
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,9 +1727,12 @@ 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
for sk in c.skipTypes:
discard semTypeNode(c, sk, nil)
c.skipTypes = @[]
proc checkForMetaFields(c: PContext; n: PNode; hasError: var bool) =
proc checkMeta(c: PContext; n: PNode; t: PType; hasError: var bool; parent: PType) =
@@ -1801,15 +1768,6 @@ proc checkForMetaFields(c: PContext; n: PNode; hasError: var bool) =
internalAssert c.config, false
proc typeSectionFinalPass(c: PContext, n: PNode) =
for (typ, typeNode) in c.forwardTypeUpdates:
# types that need to be updated due to containing forward types
# and their corresponding type nodes
# for example generic invocations of forward types end up here
var reified = semTypeNode(c, typeNode, nil)
assert reified != nil
assignType(typ, reified)
typ.itemId = reified.itemId # same id
c.forwardTypeUpdates = @[]
for i in 0..<n.len:
var a = n[i]
if a.kind == nkCommentStmt: continue
@@ -1836,15 +1794,29 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
else:
while x.kind in {nkStmtList, nkStmtListExpr} and x.len > 0:
x = x.lastSon
# we need the 'safeSkipTypes' here because illegally recursive types
# can enter at this point, see bug #13763
if x.kind notin {nkObjectTy, nkDistinctTy, nkEnumTy, nkEmpty} and
s.typ.safeSkipTypes(abstractPtrs).kind notin {tyObject, tyEnum}:
# type aliases are hard:
var t = semTypeNode(c, x, nil)
assert t != nil
if s.typ != nil and s.typ.kind notin {tyAlias, tySink}:
if t.kind in {tyProc, tyGenericInst} and not t.isMetaType:
assignType(s.typ, t)
s.typ.itemId = t.itemId
elif t.kind in {tyObject, tyEnum, tyDistinct}:
assert s.typ != nil
assignType(s.typ, t)
s.typ.itemId = t.itemId # same id
var hasError = false
if x.kind in {nkObjectTy, nkTupleTy} or
let baseType = s.typ.safeSkipTypes(abstractPtrs)
if baseType.kind in {tyObject, tyTuple} and not baseType.n.isNil and
(x.kind in {nkObjectTy, nkTupleTy} or
(x.kind in {nkRefTy, nkPtrTy} and x.len == 1 and
x[0].kind in {nkObjectTy, nkTupleTy}):
# we need the 'safeSkipTypes' here because illegally recursive types
# can enter at this point, see bug #13763
let baseType = s.typ.safeSkipTypes(abstractPtrs)
if baseType.kind in {tyObject, tyTuple} and not baseType.n.isNil:
checkForMetaFields(c, baseType.n, hasError)
x[0].kind in {nkObjectTy, nkTupleTy})
):
checkForMetaFields(c, baseType.n, hasError)
if not hasError:
checkConstructedType(c.config, s.info, s.typ)
#instAllTypeBoundOp(c, n.info)
@@ -1954,7 +1926,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:
@@ -2059,7 +2031,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)
@@ -2130,7 +2102,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
@@ -2159,23 +2131,19 @@ 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
var noError = false
template notRefc: bool =
# fixes refc with non-var destructor; cancel warnings (#23156)
c.config.backend == backendJs or
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
of attachedTrace:
t.len == 3 and t.returnType == nil and t.firstParamType.kind == tyVar and t[2].kind == tyPointer
of attachedDestructor:
if notRefc:
if c.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
t.len == 2 and t.returnType == nil
else:
t.len == 2 and t.returnType == nil and t.firstParamType.kind == tyVar
@@ -2185,11 +2153,14 @@ 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
if obj.kind in {tyObject, tyDistinct, tySequence, tyString}:
if op == attachedDestructor and t.firstParamType.kind == tyVar and
c.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
message(c.config, n.info, warnDeprecated, "A custom '=destroy' hook which takes a 'var T' parameter is deprecated; it should take a 'T' parameter")
obj = canonType(c, obj)
let ao = getAttachedOp(c.graph, obj, op)
if ao == s:
@@ -2208,7 +2179,7 @@ proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
localError(c.config, n.info, errGenerated,
"signature for '=trace' must be proc[T: object](x: var T; env: pointer)")
of attachedDestructor:
if notRefc:
if c.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
localError(c.config, n.info, errGenerated,
"signature for '=destroy' must be proc[T: object](x: var T) or proc[T: object](x: T)")
else:
@@ -2217,8 +2188,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
@@ -2258,19 +2229,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
@@ -2361,7 +2332,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,
@@ -2429,8 +2400,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
@@ -2456,7 +2427,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
@@ -2494,14 +2465,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)
@@ -2547,7 +2518,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
@@ -2574,8 +2545,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
@@ -2645,18 +2616,9 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
else:
nil
# semantic checking also needed with importc in case used in VM
let isInlineIterator = isInlineIterator(s.typ)
s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos], resultType))
# unfortunately we cannot skip this step when in 'system.compiles'
# context as it may even be evaluated in 'system.compiles':
if isInlineIterator and s.typ.callConv == ccClosure:
# iterators without explicit callconvs are lifted to closure,
# 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):
@@ -2677,8 +2639,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)
@@ -2689,9 +2651,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")
@@ -2725,13 +2687,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 =
@@ -2795,14 +2757,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)
@@ -2810,22 +2772,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
@@ -2843,33 +2795,18 @@ 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:
for i in 0..<n.safeLen: recursiveSetFlag(n[i], flag)
incl(n.flags, flag)
proc enterPragmaBlock(c: PContext): POptionEntry =
result = POptionEntry(options: c.config.options,
notes: c.config.notes,
warningAsErrors: c.config.warningAsErrors,
features: c.features)
proc leavePragmaBlock(c: PContext, p: POptionEntry) =
c.config.options = p.options
c.config.notes = p.notes
c.config.warningAsErrors = p.warningAsErrors
c.features = p.features
proc semPragmaBlock(c: PContext, n: PNode; expectedType: PType = nil): PNode =
checkSonsLen(n, 2, c.config)
let pragmaList = n[0]
let oldOptionEntry = enterPragmaBlock(c)
pragma(c, nil, pragmaList, exprPragmas, isStatement = true)
var inUncheckedAssignSection = 0
@@ -2887,15 +2824,13 @@ 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)
of wNoRewrite: recursiveSetFlag(result, nfNoRewrite)
else: discard
leavePragmaBlock(c, oldOptionEntry)
proc semStaticStmt(c: PContext, n: PNode): PNode =
#echo "semStaticStmt"
#writeStackTrace()
@@ -2974,14 +2909,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

@@ -67,9 +67,12 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule;
# for instance 'nextTry' is both in tables.nim and astalgo.nim ...
if not isField or sfGenSym notin s.flags:
result = newSymNode(s, info)
# possibly not final field sym
incl(s.flagsImpl, sfUsed)
markOwnerModuleAsUsed(c, s)
if isField:
# possibly not final field sym
incl(s.flags, sfUsed)
markOwnerModuleAsUsed(c, s)
else:
markUsed(c, info, s)
onUse(info, s)
else:
result = n
@@ -85,7 +88,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 +183,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 +221,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 +242,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 +255,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 +273,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 +286,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 +301,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 +387,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 +397,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 +548,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 +611,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 +691,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 +704,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 +727,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 +742,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 +804,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

View File

@@ -38,58 +38,32 @@ const
errNoGenericParamsAllowedForX = "no generic parameters allowed for $1"
errInOutFlagNotExtern = "the '$1' modifier can be used only with imported types"
proc reusePrev(prev: PType): bool {.inline.} =
# only overwrite `prev` if it is a forward type, partial object or magic type
result = prev != nil and (prev.kind == tyForward or (prev.sym != nil and
# partial object marks sym as `sfForward`
(sfForward in prev.sym.flags or prev.sym.magic != mNone)))
proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext, son: sink PType): PType =
if reusePrev(prev):
if prev == nil or prev.kind == tyGenericBody:
result = newTypeS(kind, c, son)
else:
result = prev
result.setSon(son)
if result.kind == tyForward: result.kind = kind
else:
result = newTypeS(kind, c, son)
#if kind == tyError: result.flags.incl tfCheckedForDestructor
proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType =
if reusePrev(prev):
if prev == nil or prev.kind == tyGenericBody:
result = newTypeS(kind, c)
else:
result = prev
if result.kind == tyForward: result.kind = kind
else:
result = newTypeS(kind, c)
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 =
result = prev
if prev.kind == tyGenericBody and prev.last.kind != tyNone:
result = prev.last
proc prevIsKind(prev: PType, kind: TTypeKind): bool {.inline.} =
result = prev != nil and skipGenericPrev(prev).kind == kind
proc semEnum(c: PContext, n: PNode, prev: PType): PType =
if n.len == 0: return newConstraint(c, tyEnum)
elif n.len == 1:
# don't create an empty tyEnum; fixes #3052
return errorType(c)
if prevIsKind(prev, tyEnum):
# the symbol already has an enum type (likely resem), don't define a new enum
# but add the enum fields to scope from the original type
let isPure = sfPure in prev.sym.flags
for enumField in prev.n:
assert enumField.kind == nkSym
let e = enumField.sym
if not isPure:
addInterfaceOverloadableSymAt(c, c.currentScope, e)
else:
declarePureEnumField(c, e)
return prev
var
counter, x: BiggestInt = 0
e: PSym = nil
@@ -151,7 +125,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 +158,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)
@@ -212,7 +186,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
if isPure and sfExported in result.sym.flags:
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 =
@@ -223,7 +197,7 @@ proc semSet(c: PContext, n: PNode, prev: PType): PType =
if base.kind in {tyGenericInst, tyAlias, tySink}: base = skipModifier(base)
if base.kind notin {tyGenericParam, tyGenericInvocation}:
if base.kind == tyForward:
c.forwardTypeUpdates.add (base, n[1])
c.skipTypes.add n
elif not isOrdinalType(base, allowEnumWithHoles = true):
localError(c.config, n.info, errOrdinalTypeExpected % typeToString(base, preferDesc))
elif lengthOrd(c.config, base) > MaxSetElements:
@@ -333,9 +307,6 @@ proc addSonSkipIntLitChecked(c: PContext; father, son: PType; it: PNode, id: IdG
proc semDistinct(c: PContext, n: PNode, prev: PType): PType =
if n.len == 0: return newConstraint(c, tyDistinct)
if prevIsKind(prev, tyDistinct):
# the symbol already has a distinct type (likely resem), don't create a new type
return skipGenericPrev(prev)
result = newOrPrevType(tyDistinct, prev, c)
addSonSkipIntLitChecked(c, result, semTypeNode(c, n[0], nil), n[0], c.idgen)
if n.len > 1: result.n = n[1]
@@ -378,7 +349,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 +369,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 +424,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 +506,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 +527,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:
@@ -582,7 +553,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
styleCheckDef(c, a[j].info, field)
onDef(field.info, field)
if result.n.len == 0: result.n = nil
if isRecursiveStructuralType(result):
if isTupleRecursive(result):
localError(c.config, n.info, errIllegalRecursionInTypeX % typeToString(result))
proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
@@ -595,7 +566,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 +776,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})
@@ -813,7 +784,7 @@ proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
case typ.kind
of shouldChckCovered:
chckCovered = true
of tyError:
of tyFloat..tyFloat128, tyError:
discard
of tyRange:
if skipTypes(typ.elementType, abstractInst).kind in shouldChckCovered:
@@ -821,8 +792,7 @@ proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
of tyForward:
errorUndeclaredIdentifier(c, n[0].info, typ.sym.name.s)
elif not isOrdinalType(typ):
localError(c.config, n[0].info, "selector must be of an ordinal type")
localError(c.config, n[0].info, "selector must be of an ordinal type, float")
if firstOrd(c.config, typ) != 0:
localError(c.config, n.info, "low(" & $a[0].sym.name.s &
") must be 0 for discriminant")
@@ -928,7 +898,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)
@@ -948,19 +918,14 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
else:
n[i].info
suggestSym(c.graph, info, f, c.graph.usageSym)
# this must only be enabled for cmd == cmdNif as its a minor breaking
# change otherwise :-(
if c.config.cmd == cmdCompileToNif:
n[i] = newSymNode(f)
f.typ = typ
f.position = pos
f.options = c.config.options
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 & "'")
@@ -1029,15 +994,11 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType; flags: TTypeFlags): PType
result = nil
if n.len == 0:
return newConstraint(c, tyObject)
if prevIsKind(prev, tyObject) and sfForward notin prev.sym.flags:
# the symbol already has an object type (likely resem), don't create a new type
return skipGenericPrev(prev)
var check = initIntSet()
var pos = 0
var base, realBase: PType = nil
# n[0] contains the pragmas (if any). We process these later...
checkSonsLen(n, 3, c.config)
var needsForwardUpdate = false
if n[1].kind != nkEmpty:
realBase = semTypeNode(c, n[1][0], nil)
base = skipTypesOrNil(realBase, skipPtrs)
@@ -1059,7 +1020,7 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType; flags: TTypeFlags): PType
return newType(tyError, c.idgen, result.owner)
elif concreteBase.kind == tyForward:
needsForwardUpdate = true
c.skipTypes.add n #we retry in the final pass
else:
if concreteBase.kind != tyError:
localError(c.config, n[1].info, "inheritance only works with non-final objects; " &
@@ -1069,14 +1030,10 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType; flags: TTypeFlags): PType
realBase = nil
if n.kind != nkObjectTy: internalError(c.config, n.info, "semObjectNode")
result = newOrPrevType(tyObject, prev, c)
if needsForwardUpdate:
# if the inherited object is a forward type,
# the entire object needs to be checked again
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,17 +1048,14 @@ 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:
result = newConstraint(c, kind)
else:
if prevIsKind(prev, kind) and tfRefsAnonObj in prev.skipTypes({tyGenericBody}).flags:
# the symbol already has an object type (likely resem), don't create a new type
return skipGenericPrev(prev)
let isCall = int ord(n.kind in nkCallKinds+{nkBracketExpr})
let n = if n[0].kind == nkBracket: n[0] else: n
checkMinSonsLen(n, 1, c.config)
@@ -1136,22 +1090,20 @@ 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} and
tfTriggersCompileTime notin result.flags:
result.incl tfHasAsgn
if result.kind == tyRef and c.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
result.flags.incl tfHasAsgn
proc findEnforcedStaticType(t: PType): PType =
# This handles types such as `static[T] and Foo`,
@@ -1208,10 +1160,10 @@ proc addImplicitGeneric(c: PContext; typeClass: PType, typId: PIdent;
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
@@ -1244,7 +1196,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:
@@ -1255,7 +1207,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
@@ -1305,7 +1257,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)
@@ -1337,14 +1289,12 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
paramType[i] = lifted
result = paramType
result.last.shouldHaveMeta
if paramType.isConcept:
return addImplicitGeneric(c, paramType, paramTypId, info, genericParams, paramName)
else:
let liftBody = recurse(paramType.skipModifier, true)
if liftBody != nil:
result = liftBody
result.incl tfHasMeta
#result.shouldHaveMeta
let liftBody = recurse(paramType.skipModifier, true)
if liftBody != nil:
result = liftBody
result.flags.incl tfHasMeta
#result.shouldHaveMeta
of tyGenericInvocation:
result = nil
@@ -1358,6 +1308,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
# this may happen for proc type appearing in a type section
# before one of its param types
return
if body.last.kind == tyUserTypeClass:
let expanded = instGenericContainer(c, info, paramType,
allowMetaTypes = true)
@@ -1374,7 +1325,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
@@ -1470,7 +1421,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
@@ -1497,7 +1448,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:
@@ -1514,15 +1465,13 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
if isType: localError(c.config, a.info, "':' expected")
if kind in {skTemplate, skMacro}:
typ = newTypeS(tyUntyped, c)
elif isRecursiveStructuralType(typ):
localError(c.config, a[^2].info, errIllegalRecursionInTypeX % typeToString(typ))
elif skipTypes(typ, {tyGenericInst, tyAlias, tySink}).kind == tyVoid:
continue
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:
@@ -1552,10 +1501,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
addParamOrResult(c, arg, kind)
styleCheckDef(c, a[j].info, arg)
onDef(a[j].info, arg)
if a[j].kind == nkPragmaExpr:
a[j][0] = newSymNode(arg)
else:
a[j] = newSymNode(arg)
a[j] = newSymNode(arg)
var r: PType = nil
if n[0].kind != nkEmpty:
@@ -1579,16 +1525,14 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
if r != nil:
# turn explicit 'void' return type into 'nil' because the rest of the
# compiler only checks for 'nil':
if isRecursiveStructuralType(r):
localError(c.config, n.info, errIllegalRecursionInTypeX % typeToString(r))
elif skipTypes(r, {tyGenericInst, tyAlias, tySink}).kind != tyVoid:
if skipTypes(r, {tyGenericInst, tyAlias, tySink}).kind != tyVoid:
if kind notin {skMacro, skTemplate} and r.kind in {tyTyped, tyUntyped}:
localError(c.config, n[0].info, "return type '" & typeToString(r) &
"' is only valid for macros and templates")
# '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
@@ -1600,13 +1544,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
@@ -1614,17 +1558,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)
@@ -1632,8 +1576,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
@@ -1646,15 +1590,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
@@ -1712,7 +1656,6 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
for i in 1..<n.len:
var elem = semGenericParamInInvocation(c, n[i])
addToResult(elem, true)
c.forwardTypeUpdates.add (result, n)
return
elif t.kind != tyGenericBody:
# we likely got code of the form TypeA[TypeB] where TypeA is
@@ -1761,7 +1704,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
localError(c.config, n.info, errCannotInstantiateX % s.name.s)
result = newOrPrevType(tyError, prev, c)
elif containsGenericInvocationWithForward(n[0]):
c.forwardTypeUpdates.add (result, n) #fixes 1500
c.skipTypes.add n #fixes 1500
else:
result = instGenericContainer(c, n.info, result,
allowMetaTypes = false)
@@ -1769,7 +1712,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
# special check for generic object with
# generic/partial specialized parent
let tx = result.skipTypes(abstractPtrs, 50)
if tx.isNil or isRecursiveStructuralType(tx):
if tx.isNil or isTupleRecursive(tx):
localError(c.config, n.info, "illegal recursion in type '$1'" % typeToString(result[0]))
return errorType(c)
if tx != result and tx.kind == tyObject:
@@ -1777,10 +1720,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
@@ -1793,10 +1733,10 @@ proc maybeAliasType(c: PContext; typeExpr, prev: PType): PType =
else:
result = nil
proc fixupTypeOf(c: PContext, prev: PType, typ: PType) =
proc fixupTypeOf(c: PContext, prev: PType, typExpr: PNode) =
if prev != nil:
let result = newTypeS(tyAlias, c)
result.rawAddSon typ
result.rawAddSon typExpr.typ
result.sym = prev.sym
if prev.kind != tyGenericBody:
assignType(prev, result)
@@ -1850,7 +1790,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
@@ -1861,7 +1801,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:
@@ -1883,8 +1823,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
@@ -1897,7 +1837,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])
@@ -1982,25 +1922,18 @@ 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)
inc c.inTypeofContext
defer: dec c.inTypeofContext # compiles can raise an exception
let ex = semExprWithType(c, n, {efInTypeof})
let t = semExprWithType(c, n, {efInTypeof})
closeScope(c)
result = ex.typ
fixupTypeOf(c, prev, t)
result = t.typ
if result.kind == tyFromExpr:
result.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
else:
result = base
fixupTypeOf(c, prev, result)
result.flags.incl tfNonConstExpr
proc semTypeOf2(c: PContext; n: PNode; prev: PType): PType =
openScope(c)
@@ -2013,19 +1946,12 @@ proc semTypeOf2(c: PContext; n: PNode; prev: PType): PType =
m = mode.intVal
inc c.inTypeofContext
defer: dec c.inTypeofContext # compiles can raise an exception
let ex = semExprWithType(c, n[1], if m == 1: {efInTypeof} else: {})
let t = semExprWithType(c, n[1], if m == 1: {efInTypeof} else: {})
closeScope(c)
result = ex.typ
fixupTypeOf(c, prev, t)
result = t.typ
if result.kind == tyFromExpr:
result.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
else:
result = base
fixupTypeOf(c, prev, result)
result.flags.incl tfNonConstExpr
proc semTypeIdent(c: PContext, n: PNode): PSym =
if n.kind == nkSym:
@@ -2056,14 +1982,14 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
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)
@@ -2089,7 +2015,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)
@@ -2105,7 +2031,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:
@@ -2125,7 +2051,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:
@@ -2188,7 +2114,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:
@@ -2234,11 +2160,11 @@ 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:
result = makeTypeDesc(c, semTypeNode(c, n[1], nil))
result.incl tfExplicit
result.flags.incl tfExplicit
of mStatic:
result = semStaticType(c, n[1], prev)
of mExpr:
@@ -2357,7 +2283,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
@@ -2375,9 +2301,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)
result.flags.incl(tfIterator)
if result.callConv == ccClosure and c.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
result.incl tfHasAsgn
result.flags.incl tfHasAsgn
of nkEnumTy: result = semEnum(c, n, prev)
of nkType: result = n.typ
of nkStmtListType: result = semStmtListType(c, n, prev)
@@ -2388,7 +2314,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) =
@@ -2407,7 +2333,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
@@ -2431,7 +2357,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))
@@ -2468,7 +2394,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:
@@ -2481,8 +2407,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
@@ -2490,7 +2416,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)
@@ -2523,7 +2449,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)
@@ -2535,15 +2461,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
@@ -2565,7 +2491,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:
@@ -2573,7 +2499,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

@@ -28,7 +28,7 @@ proc checkConstructedType*(conf: ConfigRef; info: TLineInfo, typ: PType) =
if t.kind in tyTypeClasses: discard
elif t.kind in {tyVar, tyLent} and t.elementType.kind in {tyVar, tyLent}:
localError(conf, info, "type 'var var' is not allowed")
elif computeSize(conf, t) == szIllegalRecursion or isRecursiveStructuralType(t):
elif computeSize(conf, t) == szIllegalRecursion or isTupleRecursive(t):
localError(conf, info, "illegal recursion in type '" & typeToString(t) & "'")
proc searchInstTypes*(g: ModuleGraph; key: PType): PType =
@@ -68,8 +68,8 @@ type
TReplTypeVars* = object
c*: PContext
typeMap*: LayeredIdTable # map PType to PType
symMap*: SymMapping # map PSym to PSym
localCache*: TypeMapping # local cache for remembering already replaced
symMap*: SymMapping # map PSym to PSym
localCache*: TypeMapping # local cache for remembering already replaced
# types during instantiation of meta types
# (they are not stored in the global cache)
info*: TLineInfo
@@ -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
@@ -374,7 +361,7 @@ proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym, t: PType): PSym =
]#
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
@@ -407,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
@@ -537,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
@@ -553,12 +540,14 @@ 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[pos] = t[j]
t.n[pos] = t.n[j]
inc pos
newSons t, pos
setLen t.n.sons, pos
break
@@ -619,13 +608,10 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType, isInstValue = false):
result = t
if t == nil: return
var et = t
if t.isConcept:
et = t.reduceToBase
const lookupMetas = {tyStatic, tyGenericParam, tyConcept} + tyTypeClasses - {tyAnything}
if et.kind in lookupMetas or
(et.kind == tyAnything and tfRetType notin et.flags):
let lookup = cl.typeMap.lookup(et)
if t.kind in lookupMetas or
(t.kind == tyAnything and tfRetType notin t.flags):
let lookup = cl.typeMap.lookup(t)
if lookup != nil: return lookup
case t.kind
@@ -693,7 +679,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
@@ -715,7 +701,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()
@@ -752,8 +738,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
@@ -766,7 +751,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
result.flags.incl tfRequiresInit
of tyProc:
eraseVoidParams(result)

View File

@@ -106,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:
@@ -147,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, conf
t.typeInstImpl = inst
t.typeInst = inst
return
c &= char(t.kind)
# Every cyclic type in Nim need to be constructed via some 't.sym', so this
@@ -184,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

View File

@@ -20,7 +20,6 @@ import std/[intsets, strutils, tables]
when defined(nimPreviewSlimSystem):
import std/assertions
type
MismatchKind* = enum
kUnknown, kAlreadyGiven, kUnknownNamedParam, kTypeMismatch, kVarNeeded,
@@ -95,7 +94,6 @@ type
trNoCovariance
trBindGenericParam # bind tyGenericParam even with trDontBind
trIsOutParam
trCheckGeneric
TTypeRelFlags* = set[TTypeRelFlag]
@@ -104,7 +102,7 @@ const
isNilConversion = isConvertible # maybe 'isIntConv' fits better?
maxInheritancePenalty = high(int) div 2
proc markUsed*(c: PContext; info: TLineInfo, s: PSym; checkStyle = true; isGenericInstance = false)
proc markUsed*(c: PContext; info: TLineInfo, s: PSym; checkStyle = true)
proc markOwnerModuleAsUsed*(c: PContext; s: PSym)
proc initCandidateAux(ctx: PContext,
@@ -233,11 +231,13 @@ proc copyingEraseVoidParams(m: TCandidate, t: var PType) =
if not copied:
# keep first i children
t = copyType(original, m.c.idgen, t.owner)
t.setSonsLen(i)
t.n = copyNode(original.n)
t.n.sons = original.n.sons
t.n.sons.setLen(i)
copied = true
elif copied:
t.add(f)
t.n.add(original.n[i])
proc initCandidate*(ctx: PContext, callee: PSym,
@@ -297,9 +297,9 @@ proc checkGeneric(a, b: TCandidate): int =
var winner = 0
for aai, bbi in underspecifiedPairs(aa, bb, 1):
var ma = newCandidate(c, bbi)
let tra = typeRel(ma, bbi, aai, {trDontBind, trCheckGeneric})
let tra = typeRel(ma, bbi, aai, {trDontBind})
var mb = newCandidate(c, aai)
let trb = typeRel(mb, aai, bbi, {trDontBind, trCheckGeneric})
let trb = typeRel(mb, aai, bbi, {trDontBind})
if tra == isGeneric and trb in {isNone, isInferred, isInferredConvertible}:
if winner == -1: return 0
winner = 1
@@ -363,8 +363,6 @@ proc sumGeneric(t: PType): int =
result += sumGeneric(a)
break
else:
if t.isConcept:
result += t.reduceToBase.conceptBody.len
break
proc complexDisambiguation(a, b: PType): int =
@@ -452,11 +450,11 @@ template describeArgImpl(c: PContext, n: PNode, i: int, startIdx = 1; prefer = p
arg = c.semTryExpr(c, n[i][1])
if arg == nil:
arg = n[i][1]
arg.typ = newTypeS(tyUntyped, c)
arg.typ() = newTypeS(tyUntyped, c)
else:
if arg.typ == nil:
arg.typ = newTypeS(tyVoid, c)
n[i].typ = arg.typ
arg.typ() = newTypeS(tyVoid, c)
n[i].typ() = arg.typ
n[i][1] = arg
else:
if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo, nkElse,
@@ -465,10 +463,10 @@ template describeArgImpl(c: PContext, n: PNode, i: int, startIdx = 1; prefer = p
arg = c.semTryExpr(c, n[i])
if arg == nil:
arg = n[i]
arg.typ = newTypeS(tyUntyped, c)
arg.typ() = newTypeS(tyUntyped, c)
else:
if arg.typ == nil:
arg.typ = newTypeS(tyVoid, c)
arg.typ() = newTypeS(tyVoid, c)
n[i] = arg
if arg.typ != nil and arg.typ.kind == tyError: return
result.add argTypeToString(arg, prefer)
@@ -895,7 +893,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType =
param.typ = typ.exactReplica
#copyType(typ, c.idgen, typ.owner)
if typ.n == nil:
param.typ.incl tfInferrableStatic
param.typ.flags.incl tfInferrableStatic
else:
param.ast = typ.n
of tyFromExpr:
@@ -928,8 +926,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType =
diagnostics = @[]
flags = {efExplain}
m.c.config.writelnHook = proc (s: string) =
{.gcsafe.}:
if errorPrefix.len == 0: errorPrefix = typeClass.sym.name.s & ":"
if errorPrefix.len == 0: errorPrefix = typeClass.sym.name.s & ":"
let msg = s.replace("Error:", errorPrefix)
if oldWriteHook != nil: oldWriteHook msg
diagnostics.add msg
@@ -1141,24 +1138,6 @@ proc isCovariantPtr(c: var TCandidate, f, a: PType): bool =
else:
return false
proc enterConceptMatch(c: var TCandidate; f,a: PType, flags: TTypeRelFlags): TTypeRelation =
var
conceptFlags: set[MatchFlags] = {}
container: PType = nil
concpt = f
if concpt.kind != tyConcept:
container = concpt
concpt = container.reduceToBase
if trDontBind in flags:
conceptFlags.incl mfDontBind
if trCheckGeneric in flags:
conceptFlags.incl mfCheckGeneric
let mres = concepts.conceptMatch(c.c, concpt, a, c.bindings, container, flags = conceptFlags)
if mres:
isGeneric
else:
isNone
when false:
proc maxNumericType(prev, candidate: PType): PType =
let c = candidate.skipTypes({tyRange})
@@ -1233,10 +1212,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
else:
var candidate = f
let fType = f.skipTypes({tySink})
case fType.kind
case f.kind
of tyGenericParam:
var prev = lookup(c.bindings, fType)
var prev = lookup(c.bindings, f)
if prev != nil: candidate = prev
of tyFromExpr:
let computedType = tryResolvingStaticExpr(c, f.n).typ
@@ -1446,8 +1424,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
return isNone
if fRange.rangeHasUnresolvedStatic:
if (aRange.kind in {tyGenericParam} and aRange.reduceToBase() == aRange) or
(aRange.kind == tyRange and aRange.rangeHasUnresolvedStatic):
if aRange.kind in {tyGenericParam} and aRange.reduceToBase() == aRange:
return
return inferStaticsInRange(c, fRange, a)
elif c.c.matchedConcept != nil and aRange.rangeHasUnresolvedStatic:
@@ -1540,14 +1517,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
reduceToBase(a)
if effectiveArgType.kind == tyObject:
if sameObjectTypes(f, effectiveArgType):
if tfFinal notin f.flags:
inc c.inheritancePenalty, ord(c.inheritancePenalty < 0)
c.inheritancePenalty = if tfFinal in f.flags: -1 else: 0
result = isEqual
# elif tfHasMeta in f.flags: result = recordRel(c, f, a)
elif trIsOutParam notin flags:
let depth = isObjectSubtype(c, effectiveArgType, f, nil)
if depth > 0:
inc c.inheritancePenalty, depth + ord(c.inheritancePenalty < 0)
c.inheritancePenalty = isObjectSubtype(c, effectiveArgType, f, nil)
if c.inheritancePenalty > 0:
result = isSubtype
of tyDistinct:
a = a.skipTypes({tyOwned, tyGenericInst, tyRange})
@@ -1567,11 +1542,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
# set['a'..'z'] and set[char] have different representations
result = isNone
else:
if result >= isConvertible:
# but we can convert individual elements of the constructor
result = isConvertible
else:
result = isNone
# but we can convert individual elements of the constructor
result = isConvertible
of tyPtr, tyRef:
a = reduceToBase(a)
if a.kind == f.kind:
@@ -1671,9 +1643,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
let roota = if skipBoth or deptha > depthf: a.skipGenericAlias else: a
let rootf = if skipBoth or depthf > deptha: f.skipGenericAlias else: f
if f.isConcept:
result = enterConceptMatch(c, rootf, roota, flags)
elif a.kind == tyGenericInst:
if a.kind == tyGenericInst:
if roota.base == rootf.base:
let nextFlags = flags + {trNoCovariance}
var hasCovariance = false
@@ -1722,8 +1692,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
if aAsObject.kind == tyObject and trIsOutParam notin flags:
let baseType = aAsObject.base
if baseType != nil:
if tfFinal notin aAsObject.flags:
inc c.inheritancePenalty, 1 + int(c.inheritancePenalty < 0)
inc c.inheritancePenalty, 1 + int(c.inheritancePenalty < 0)
let ret = typeRel(c, f, baseType, flags)
return if ret in {isEqual,isGeneric}: isSubtype else: ret
@@ -1744,7 +1713,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
var x = a.skipGenericAlias
if x.kind == tyGenericParam and x.len > 0:
x = x.last
let concpt = f.reduceToBase
let concpt = f[0].skipTypes({tyGenericBody})
var preventHack = concpt.kind == tyConcept
if x.kind == tyOwned and f[0].kind != tyOwned:
preventHack = true
@@ -1764,10 +1733,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
let tr = typeRel(c, f[i], x[i], flags)
if tr <= isSubtype: return
result = isGeneric
let impl = last(f[0])
if impl.kind == tyObject and tfFinal notin impl.flags:
# match non-invocation case
inc c.inheritancePenalty, 0 + int(c.inheritancePenalty < 0)
elif x.kind == tyGenericInst and f[0] == x[0] and
x.len - 1 == f.len:
for i in 1..<f.len:
@@ -1777,8 +1742,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
# Workaround for regression #4589
if f[i].kind != tyTypeDesc: return
result = isGeneric
elif concpt.kind == tyConcept:
result = enterConceptMatch(c, f, x, flags)
elif x.kind == tyGenericInst and concpt.kind == tyConcept:
result = if concepts.conceptMatch(c.c, concpt, x, c.bindings, f): isGeneric
else: isNone
else:
let genericBody = f[0]
var askip = skippedNone
@@ -1786,7 +1752,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
let aobj = x.skipToObject(askip)
let fobj = genericBody.last.skipToObject(fskip)
result = typeRel(c, genericBody, x, flags)
if result != isNone and concpt.kind != tyConcept:
if result != isNone:
# see tests/generics/tgeneric3.nim for an example that triggers this
# piece of code:
#
@@ -1823,8 +1789,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
depth = -1
if depth >= 0:
if aobj.kind == tyObject and tfFinal notin aobj.flags:
inc c.inheritancePenalty, depth + int(c.inheritancePenalty < 0)
inc c.inheritancePenalty, depth + int(c.inheritancePenalty < 0)
# bug #4863: We still need to bind generic alias crap, so
# we cannot return immediately:
result = if depth == 0: isGeneric else: isSubtype
@@ -1850,10 +1815,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
if c.inheritancePenalty > -1:
minInheritance = min(minInheritance, c.inheritancePenalty)
result = x
c.inheritancePenalty = oldInheritancePenalty
if result >= isIntConv:
if minInheritance < maxInheritancePenalty:
inc c.inheritancePenalty, minInheritance + ord(c.inheritancePenalty < 0)
c.inheritancePenalty = oldInheritancePenalty + minInheritance
if result > isGeneric: result = isGeneric
bindingRet result
else:
@@ -1915,7 +1879,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
else:
result = isNone
of tyConcept:
result = enterConceptMatch(c, f, a, flags)
if a.kind == tyConcept and sameType(f, a):
result = isGeneric
else:
result = if concepts.conceptMatch(c.c, f, a, c.bindings, nil): isGeneric
else: isNone
of tyCompositeTypeClass:
considerPreviousT:
let roota = a.skipGenericAlias
@@ -1988,7 +1956,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
var concrete = a
if tfWildcard in a.flags:
a.sym.transitionGenericParamToType()
a.excl tfWildcard
a.flags.excl tfWildcard
elif doBind:
# careful: `trDontDont` (set by `checkGeneric`) is not always respected in this call graph.
# typRel having two different modes (binding and non-binding) can make things harder to
@@ -2179,18 +2147,16 @@ proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
result = newNodeI(kind, arg.info)
if containsGenericType(f):
if not m.matchedErrorType:
result.typ = getInstantiatedType(c, arg, m, f).skipTypes({tySink})
result.typ() = getInstantiatedType(c, arg, m, f).skipTypes({tySink})
else:
result.typ = errorType(c)
result.typ() = errorType(c)
else:
result.typ = f.skipTypes({tySink})
result.typ() = f.skipTypes({tySink})
# keep varness
if arg.typ != nil and arg.typ.kind == tyVar:
result.typ = toVar(result.typ, tyVar, c.idgen)
# copy the tfVarIsPtr flag
result.typ.flags = arg.typ.flags
result.typ() = toVar(result.typ, tyVar, c.idgen)
else:
result.typ = result.typ.skipTypes({tyVar})
result.typ() = result.typ.skipTypes({tyVar})
if result.typ == nil: internalError(c.graph.config, arg.info, "implicitConv")
result.add c.graph.emptyNode
@@ -2218,13 +2184,13 @@ proc convertLiteral(kind: TNodeKind, c: PContext, m: TCandidate; n: PNode, newTy
result.add x
else:
result.addConsiderNil convertLiteral(kind, c, m, n[i], elemType(newType))
result.typ = newType
result.typ() = newType
return
of nkBracket:
result = copyNode(n)
for i in 0..<n.len:
result.addConsiderNil convertLiteral(kind, c, m, n[i], elemType(newType))
result.typ = newType
result.typ() = newType
return
of nkPar, nkTupleConstr:
let tup = newType.skipTypes({tyGenericInst, tyAlias, tySink, tyDistinct})
@@ -2248,7 +2214,7 @@ proc convertLiteral(kind: TNodeKind, c: PContext, m: TCandidate; n: PNode, newTy
else:
for i in 0..<n.len:
result.addConsiderNil convertLiteral(kind, c, m, n[i], tup[i])
result.typ = newType
result.typ() = newType
return
of nkCharLit..nkUInt64Lit:
if n.kind != nkUInt64Lit and not sameTypeOrNil(n.typ, newType) and isOrdinalType(newType):
@@ -2256,14 +2222,14 @@ proc convertLiteral(kind: TNodeKind, c: PContext, m: TCandidate; n: PNode, newTy
if value < firstOrd(c.config, newType) or value > lastOrd(c.config, newType):
return nil
result = copyNode(n)
result.typ = newType
result.typ() = newType
return
of nkFloatLit..nkFloat64Lit:
if newType.skipTypes(abstractVarRange-{tyTypeDesc}).kind == tyFloat:
if not floatRangeCheck(n.floatVal, newType):
return nil
result = copyNode(n)
result.typ = newType
result.typ() = newType
return
of nkSym:
if n.sym.kind == skEnumField and not sameTypeOrNil(n.sym.typ, newType) and isOrdinalType(newType):
@@ -2271,7 +2237,7 @@ proc convertLiteral(kind: TNodeKind, c: PContext, m: TCandidate; n: PNode, newTy
if value < firstOrd(c.config, newType) or value > lastOrd(c.config, newType):
return nil
result = copyNode(n)
result.typ = newType
result.typ() = newType
return
else: discard
return implicitConv(kind, newType, n, m, c)
@@ -2298,8 +2264,7 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
# for generic type converters we need to check 'src <- a' before
# 'f <- dest' in order to not break the unification:
# see tests/tgenericconverter:
var convMatch = newCandidate(c, src)
let srca = typeRel(convMatch, src, a)
let srca = typeRel(m, src, a)
if srca notin {isEqual, isGeneric, isSubtype}: continue
# What's done below matches the logic in ``matchesAux``
@@ -2311,14 +2276,14 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
let destIsGeneric = containsGenericType(dest)
if destIsGeneric:
dest = generateTypeInstance(c, convMatch.bindings, arg, dest)
dest = generateTypeInstance(c, m.bindings, arg, dest)
let fdest = typeRel(m, f, dest)
if fdest in {isEqual, isGeneric} and not (dest.kind == tyLent and f.kind in {tyVar}):
# can't fully mark used yet, may not be used in final call
incl(c.converters[i].flagsImpl, sfUsed)
incl(c.converters[i].flags, sfUsed)
markOwnerModuleAsUsed(c, c.converters[i])
var s = newSymNode(c.converters[i])
s.typ = c.converters[i].typ
s.typ() = c.converters[i].typ
s.info = arg.info
result = newNodeIT(nkHiddenCallConv, arg.info, dest)
result.add s
@@ -2327,8 +2292,7 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
# it is correct
var param: PNode = nil
if srca == isSubtype:
# convMatch used here to use its bindings to instantiate subtype:
param = implicitConv(nkHiddenSubConv, src, copyTree(arg), convMatch, c)
param = implicitConv(nkHiddenSubConv, src, copyTree(arg), m, c)
elif src.kind in {tyVar}:
# Analyse the converter return type.
param = newNodeIT(nkHiddenAddr, arg.info, s.typ.firstParamType)
@@ -2338,7 +2302,7 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
result.add param
if dest.kind in {tyVar, tyLent}:
dest.incl tfVarIsPtr
dest.flags.incl tfVarIsPtr
result = newDeref(result)
inc(m.convMatches)
@@ -2372,7 +2336,7 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
if result.kind == nkCall: result.transitionSonsKind(nkHiddenCallConv)
inc(m.convMatches)
if r == isGeneric:
result.typ = getInstantiatedType(c, arg, m, base(f))
result.typ() = getInstantiatedType(c, arg, m, base(f))
m.baseTypeMatch = true
proc incMatches(m: var TCandidate; r: TTypeRelation; convMatch = 1) =
@@ -2428,18 +2392,19 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
let typ = newTypeS(tyStatic, c, son = evaluated.typ)
typ.n = evaluated
arg = copyTree(arg) # fix #12864
arg.typ = typ
arg.typ() = typ
a = typ
else:
if m.callee.kind == tyGenericBody:
if f.kind == tyStatic and typeRel(m, f.base, a) != isNone:
result = makeStaticExpr(m.c, arg)
result.typ.incl tfUnresolved
result.typ.flags.incl tfUnresolved
result.typ.n = arg
return
let oldInheritancePenalty = m.inheritancePenalty
var r = typeRel(m, f, a)
# This special typing rule for macros and templates is not documented
# anywhere and breaks symmetry. It's hard to get rid of though, my
# custom seqs example fails to compile without this:
@@ -2546,7 +2511,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
# doesn't work: `proc foo[T](): array[T, int] = ...; foo[3]()` (see #23204)
(arg.typ.isIntLit and not m.isNoCall):
result = arg.copyTree
result.typ = getInstantiatedType(c, arg, m, f).skipTypes({tySink})
result.typ() = getInstantiatedType(c, arg, m, f).skipTypes({tySink})
else:
result = arg
of isBothMetaConvertible:
@@ -2602,7 +2567,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
of isGeneric:
inc(m.convMatches)
result = copyTree(arg)
result.typ = getInstantiatedType(c, arg, m, base(f))
result.typ() = getInstantiatedType(c, arg, m, base(f))
m.baseTypeMatch = true
of isFromIntLit:
inc(m.intConvMatches, 256)
@@ -2628,7 +2593,7 @@ proc staticAwareTypeRel(m: var TCandidate, f: PType, arg: var PNode): TTypeRelat
# The ast of the type does not point to the symbol.
# Without this we will never resolve a `static proc` with overloads
let copiedNode = copyNode(arg)
copiedNode.typ = exactReplica(copiedNode.typ)
copiedNode.typ() = exactReplica(copiedNode.typ)
copiedNode.typ.n = arg
arg = copiedNode
typeRel(m, f, arg.typ)
@@ -2897,7 +2862,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int
var newlyTyped = false
n[a][1] = prepareOperand(c, formal.typ, n[a][1], newlyTyped)
if newlyTyped: m.newlyTypedOperands.add(a)
n[a].typ = n[a][1].typ
n[a].typ() = n[a][1].typ
arg = paramTypesMatch(m, formal.typ, n[a].typ,
n[a][1], n[a][1])
m.firstMismatch.kind = kTypeMismatch
@@ -2994,7 +2959,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int
#assert(container == nil)
if container.isNil:
container = newNodeIT(nkBracket, n[a].info, arrayConstr(c, arg))
container.typ.incl tfVarargs
container.typ.flags.incl tfVarargs
else:
incrIndexType(container.typ)
container.add arg
@@ -3077,7 +3042,7 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
if m.calleeSym != nil: m.calleeSym.detailedInfo else: "")
typeMismatch(c.config, formal.ast.info, formal.typ, formal.ast.typ, formal.ast)
popInfoContext(c.config)
formal.ast.typ = errorType(c)
formal.ast.typ() = errorType(c)
if nfDefaultRefsParam in formal.ast.flags:
m.call.flags.incl nfDefaultRefsParam
var defaultValue = copyTree(formal.ast)

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