Compare commits

..

20 Commits

Author SHA1 Message Date
ringabout
112e274804 switch on 2023-12-11 14:12:55 +00:00
ringabout
f1a7bfce47 switch on 2023-12-11 14:12:47 +00:00
ringabout
68bf6c7f93 what's problem os cancelled CI 2023-12-11 11:00:02 +00:00
ringabout
7cd431804b test CI 2023-12-11 09:07:41 +00:00
ringabout
01388dc816 Merge branch 'devel' into pr_string_v3 2023-12-11 13:16:03 +08:00
ringabout
bee9baa8bf reprieve IC 2023-12-09 11:56:17 +00:00
ringabout
147621ec21 fixes a critical issue 2023-12-09 02:41:05 +00:00
ringabout
5bde480596 workaround a cstring conversion bug 2023-12-09 02:34:22 +00:00
ringabout
33f911e691 fixes C++ compilation 2023-12-08 14:13:21 +00:00
ringabout
ec03e476d5 fixes more problems 2023-12-08 08:41:16 +00:00
ringabout
4adb79f7cb a small fix 2023-12-08 07:29:36 +00:00
ringabout
1da417b818 tests nimSeqsV3 2023-12-08 07:26:32 +00:00
ringabout
7ef0f43f35 basic examples work now 2023-12-08 07:04:15 +00:00
ringabout
da277cf1b8 more fixes 2023-12-07 14:47:51 +00:00
ringabout
cb172328ba simple cases compile 2023-12-07 13:56:33 +00:00
ringabout
9af21cf719 progress 2023-12-07 12:53:06 +00:00
ringabout
f7bdec6f0d progress 2023-12-06 14:25:34 +00:00
ringabout
88c0ac44fc simple additions 2023-12-06 06:09:25 +00:00
ringabout
119cfe8bc8 some improvements 2023-12-06 02:27:05 +00:00
ringabout
ae99903236 wip: intern strings 2023-12-05 14:51:24 +00:00
408 changed files with 8936 additions and 13194 deletions

View File

@@ -45,7 +45,7 @@ jobs:
- target: windows
os: windows-2019
- target: osx
os: macos-12
os: macos-11
name: ${{ matrix.target }}
runs-on: ${{ matrix.os }}
@@ -109,7 +109,7 @@ jobs:
if: |
github.event_name == 'push' && github.ref == 'refs/heads/devel' &&
matrix.target == 'linux'
uses: crazy-max/ghaction-github-pages@v4
uses: crazy-max/ghaction-github-pages@v3
with:
build_dir: doc/html
env:

View File

@@ -17,7 +17,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, macos-12]
os: [ubuntu-20.04, macos-11]
cpu: [amd64]
batch: ["allowed_failures", "0_3", "1_3", "2_3"] # list of `index_num`
name: '${{ matrix.os }} (batch: ${{ matrix.batch }})'

View File

@@ -71,7 +71,7 @@ jobs:
run: nim c -r -d:release ci/action.nim
- name: 'Comment'
uses: actions/github-script@v7
uses: actions/github-script@v6
with:
script: |
const fs = require('fs');

View File

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

View File

@@ -29,10 +29,10 @@ jobs:
# vmImage: 'ubuntu-18.04'
# CPU: i386
OSX_amd64:
vmImage: 'macOS-12'
vmImage: 'macOS-11'
CPU: amd64
OSX_amd64_cpp:
vmImage: 'macOS-12'
vmImage: 'macOS-11'
CPU: amd64
NIM_COMPILE_TO_CPP: true
Windows_amd64_batch0_3:

View File

@@ -7,17 +7,6 @@
- The default user-agent in `std/httpclient` has been changed to `Nim-httpclient/<version>` instead of `Nim httpclient/<version>` which was incorrect according to the HTTP spec.
- Methods now support implementations based on a VTable by using `--experimental:vtables`. Methods are then confined to be in the same module where their type has been defined.
- With `-d:nimPreviewNonVarDestructor`, non-var destructors become the default.
- A bug where tuple unpacking assignment with a longer tuple on the RHS than the LHS was allowed has been fixed, i.e. code like:
```nim
var a, b: int
(a, b) = (1, 2, 3, 4)
```
will no longer compile.
- `internalNew` is removed from system, use `new` instead.
- `bindMethod` in `std/jsffi` is deprecated, don't use it with closures.
- JS backend now supports lambda lifting for closures. Use `--legacy:jsNoLambdaLifting` to emulate old behavior.
## Standard library additions and changes
@@ -34,14 +23,6 @@
slots when enlarging a sequence.
- Added `hasDefaultValue` to `std/typetraits` to check if a type has a valid default value.
- Added Viewport API for the JavaScript targets in the `dom` module.
- Added `toSinglyLinkedRing` and `toDoublyLinkedRing` to `std/lists` to convert from `openArray`s.
- ORC: To be enabled via `nimOrcStats` there is a new API called `GC_orcStats` that can be used to query how many
objects the cyclic collector did free. If the number is zero that is a strong indicator that you can use `--mm:arc`
instead of `--mm:orc`.
- A `$` template is provided for `Path` in `std/paths`.
- `nimPreviewHashFarm` has been added to `lib/pure/hashes.nim` to default to a
64-bit string `Hash` (based upon Google's Farm Hash) which is also faster than
the present one. At present, this is incompatible with `--jsbigint=off` mode.
[//]: # "Deprecations:"
@@ -52,59 +33,11 @@ the present one. At present, this is incompatible with `--jsbigint=off` mode.
## Language changes
- `noInit` can be used in types and fields to disable member initializers in the C++ backend.
- `noInit` can be used in types and fields to disable member initializers in the C++ backend.
- C++ custom constructors initializers see https://nim-lang.org/docs/manual_experimental.htm#constructor-initializer
- `member` can be used to attach a procedure to a C++ type.
- C++ `constructor` now reuses `result` instead creating `this`.
- Tuple unpacking changes:
- Tuple unpacking assignment now supports using underscores to discard values.
```nim
var a, c: int
(a, _, c) = (1, 2, 3)
```
- Tuple unpacking variable declarations now support type annotations, but
only for the entire tuple.
```nim
let (a, b): (int, int) = (1, 2)
let (a, (b, c)): (byte, (float, cstring)) = (1, (2, "abc"))
```
- An experimental option `genericsOpenSym` has been added to allow captured
symbols in generic routine bodies to be replaced by symbols injected locally
by templates/macros at instantiation time. `bind` may be used to keep the
captured symbols over the injected ones regardless of enabling the option.
Since this change may affect runtime behavior, the experimental switch
`genericsOpenSym` needs to be enabled, and a warning is given in the case
where an injected symbol would replace a captured symbol not bound by `bind`
and the experimental switch isn't enabled.
```nim
const value = "captured"
template foo(x: int, body: untyped) =
let value {.inject.} = "injected"
body
proc old[T](): string =
foo(123):
return value # warning: a new `value` has been injected, use `bind` or turn on `experimental:genericsOpenSym`
echo old[int]() # "captured"
{.experimental: "genericsOpenSym".}
proc bar[T](): string =
foo(123):
return value
assert bar[int]() == "injected" # previously it would be "captured"
proc baz[T](): string =
bind value
foo(123):
return value
assert baz[int]() == "captured"
```
## Compiler changes
- `--nimcache` using a relative path as the argument in a config file is now relative to the config file instead of the current directory.

View File

@@ -72,7 +72,7 @@
- `shallowCopy` and `shallow` are removed for ARC/ORC. Use `move` when possible or combine assignment and
`sink` for optimization purposes.
- The experimental `nimPreviewDotLikeOps` switch is going to be removed or deprecated because it didn't fulfill its promises.
- The experimental `nimPreviewDotLikeOps` switch is going to be removed or deprecated because it didn't fullfill its promises.
- The `{.this.}` pragma, deprecated since 0.19, has been removed.
- `nil` literals can no longer be directly assigned to variables or fields of `distinct` pointer types. They must be converted instead.

View File

@@ -51,16 +51,14 @@ proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult =
if compareTypes(a, b, dcEqIgnoreDistinct): return arYes
case a.kind
of tyObject:
if a.baseClass != nil:
result = isPartOfAux(a.baseClass.skipTypes(skipPtrs), b, marker)
if a[0] != nil:
result = isPartOfAux(a[0].skipTypes(skipPtrs), b, marker)
if result == arNo: result = isPartOfAux(a.n, b, marker)
of tyGenericInst, tyDistinct, tyAlias, tySink:
result = isPartOfAux(skipModifier(a), b, marker)
of tySet, tyArray:
result = isPartOfAux(a.elementType, b, marker)
of tyTuple:
for aa in a.kids:
result = isPartOfAux(aa, b, marker)
result = isPartOfAux(lastSon(a), b, marker)
of tyArray, tySet, tyTuple:
for i in 0..<a.len:
result = isPartOfAux(a[i], b, marker)
if result == arYes: return
else: discard

View File

@@ -20,9 +20,6 @@ when defined(nimPreviewSlimSystem):
export int128
import nodekinds
export nodekinds
type
TCallingConvention* = enum
ccNimCall = "nimcall" # nimcall, also the default
@@ -36,12 +33,207 @@ type
ccThisCall = "thiscall" # thiscall (parameters are pushed right-to-left)
ccClosure = "closure" # proc has a closure
ccNoConvention = "noconv" # needed for generating proper C procs sometimes
ccMember = "member" # proc is a (cpp) member
type
TNodeKind* = enum # order is extremely important, because ranges are used
# to check whether a node belongs to a certain class
nkNone, # unknown node kind: indicates an error
# Expressions:
# Atoms:
nkEmpty, # the node is empty
nkIdent, # node is an identifier
nkSym, # node is a symbol
nkType, # node is used for its typ field
nkCharLit, # a character literal ''
nkIntLit, # an integer literal
nkInt8Lit,
nkInt16Lit,
nkInt32Lit,
nkInt64Lit,
nkUIntLit, # an unsigned integer literal
nkUInt8Lit,
nkUInt16Lit,
nkUInt32Lit,
nkUInt64Lit,
nkFloatLit, # a floating point literal
nkFloat32Lit,
nkFloat64Lit,
nkFloat128Lit,
nkStrLit, # a string literal ""
nkRStrLit, # a raw string literal r""
nkTripleStrLit, # a triple string literal """
nkNilLit, # the nil literal
# end of atoms
nkComesFrom, # "comes from" template/macro information for
# better stack trace generation
nkDotCall, # used to temporarily flag a nkCall node;
# this is used
# for transforming ``s.len`` to ``len(s)``
nkCommand, # a call like ``p 2, 4`` without parenthesis
nkCall, # a call like p(x, y) or an operation like +(a, b)
nkCallStrLit, # a call with a string literal
# x"abc" has two sons: nkIdent, nkRStrLit
# x"""abc""" has two sons: nkIdent, nkTripleStrLit
nkInfix, # a call like (a + b)
nkPrefix, # a call like !a
nkPostfix, # something like a! (also used for visibility)
nkHiddenCallConv, # an implicit type conversion via a type converter
nkExprEqExpr, # a named parameter with equals: ''expr = expr''
nkExprColonExpr, # a named parameter with colon: ''expr: expr''
nkIdentDefs, # a definition like `a, b: typeDesc = expr`
# either typeDesc or expr may be nil; used in
# formal parameters, var statements, etc.
nkVarTuple, # a ``var (a, b) = expr`` construct
nkPar, # syntactic (); may be a tuple constructor
nkObjConstr, # object constructor: T(a: 1, b: 2)
nkCurly, # syntactic {}
nkCurlyExpr, # an expression like a{i}
nkBracket, # syntactic []
nkBracketExpr, # an expression like a[i..j, k]
nkPragmaExpr, # an expression like a{.pragmas.}
nkRange, # an expression like i..j
nkDotExpr, # a.b
nkCheckedFieldExpr, # a.b, but b is a field that needs to be checked
nkDerefExpr, # a^
nkIfExpr, # if as an expression
nkElifExpr,
nkElseExpr,
nkLambda, # lambda expression
nkDo, # lambda block appering as trailing proc param
nkAccQuoted, # `a` as a node
nkTableConstr, # a table constructor {expr: expr}
nkBind, # ``bind expr`` node
nkClosedSymChoice, # symbol choice node; a list of nkSyms (closed)
nkOpenSymChoice, # symbol choice node; a list of nkSyms (open)
nkHiddenStdConv, # an implicit standard type conversion
nkHiddenSubConv, # an implicit type conversion from a subtype
# to a supertype
nkConv, # a type conversion
nkCast, # a type cast
nkStaticExpr, # a static expr
nkAddr, # a addr expression
nkHiddenAddr, # implicit address operator
nkHiddenDeref, # implicit ^ operator
nkObjDownConv, # down conversion between object types
nkObjUpConv, # up conversion between object types
nkChckRangeF, # range check for floats
nkChckRange64, # range check for 64 bit ints
nkChckRange, # range check for ints
nkStringToCString, # string to cstring
nkCStringToString, # cstring to string
# end of expressions
nkAsgn, # a = b
nkFastAsgn, # internal node for a fast ``a = b``
# (no string copy)
nkGenericParams, # generic parameters
nkFormalParams, # formal parameters
nkOfInherit, # inherited from symbol
nkImportAs, # a 'as' b in an import statement
nkProcDef, # a proc
nkMethodDef, # a method
nkConverterDef, # a converter
nkMacroDef, # a macro
nkTemplateDef, # a template
nkIteratorDef, # an iterator
nkOfBranch, # used inside case statements
# for (cond, action)-pairs
nkElifBranch, # used in if statements
nkExceptBranch, # an except section
nkElse, # an else part
nkAsmStmt, # an assembler block
nkPragma, # a pragma statement
nkPragmaBlock, # a pragma with a block
nkIfStmt, # an if statement
nkWhenStmt, # a when expression or statement
nkForStmt, # a for statement
nkParForStmt, # a parallel for statement
nkWhileStmt, # a while statement
nkCaseStmt, # a case statement
nkTypeSection, # a type section (consists of type definitions)
nkVarSection, # a var section
nkLetSection, # a let section
nkConstSection, # a const section
nkConstDef, # a const definition
nkTypeDef, # a type definition
nkYieldStmt, # the yield statement as a tree
nkDefer, # the 'defer' statement
nkTryStmt, # a try statement
nkFinally, # a finally section
nkRaiseStmt, # a raise statement
nkReturnStmt, # a return statement
nkBreakStmt, # a break statement
nkContinueStmt, # a continue statement
nkBlockStmt, # a block statement
nkStaticStmt, # a static statement
nkDiscardStmt, # a discard statement
nkStmtList, # a list of statements
nkImportStmt, # an import statement
nkImportExceptStmt, # an import x except a statement
nkExportStmt, # an export statement
nkExportExceptStmt, # an 'export except' statement
nkFromStmt, # a from * import statement
nkIncludeStmt, # an include statement
nkBindStmt, # a bind statement
nkMixinStmt, # a mixin statement
nkUsingStmt, # an using statement
nkCommentStmt, # a comment statement
nkStmtListExpr, # a statement list followed by an expr; this is used
# to allow powerful multi-line templates
nkBlockExpr, # a statement block ending in an expr; this is used
# to allow powerful multi-line templates that open a
# temporary scope
nkStmtListType, # a statement list ending in a type; for macros
nkBlockType, # a statement block ending in a type; for macros
# types as syntactic trees:
nkWith, # distinct with `foo`
nkWithout, # distinct without `foo`
nkTypeOfExpr, # type(1+2)
nkObjectTy, # object body
nkTupleTy, # tuple body
nkTupleClassTy, # tuple type class
nkTypeClassTy, # user-defined type class
nkStaticTy, # ``static[T]``
nkRecList, # list of object parts
nkRecCase, # case section of object
nkRecWhen, # when section of object
nkRefTy, # ``ref T``
nkPtrTy, # ``ptr T``
nkVarTy, # ``var T``
nkConstTy, # ``const T``
nkOutTy, # ``out T``
nkDistinctTy, # distinct type
nkProcTy, # proc type
nkIteratorTy, # iterator type
nkSinkAsgn, # '=sink(x, y)'
nkEnumTy, # enum body
nkEnumFieldDef, # `ident = expr` in an enumeration
nkArgList, # argument list
nkPattern, # a special pattern; used for matching
nkHiddenTryStmt, # a hidden try statement
nkClosure, # (prc, env)-pair (internally used for code gen)
nkGotoState, # used for the state machine (for iterators)
nkState, # give a label to a code section (for iterators)
nkBreakState, # special break statement for easier code generation
nkFuncDef, # a func
nkTupleConstr # a tuple constructor
nkError # erroneous AST node
nkModuleRef # for .rod file support: A (moduleId, itemId) pair
nkReplayAction # for .rod file support: A replay action
nkNilRodNode # for .rod file support: a 'nil' PNode
TNodeKinds* = set[TNodeKind]
type
TSymFlag* = enum # 52 flags!
TSymFlag* = enum # 51 flags!
sfUsed, # read access of sym (for warnings) or simply used
sfExported, # symbol is exported from module
sfFromGeneric, # symbol is instantiation of a generic; this is needed
@@ -126,7 +318,6 @@ type
sfByCopy # param is marked as pass bycopy
sfMember # proc is a C++ member of a type
sfCodegenDecl # type, proc, global or proc param is marked as codegenDecl
sfWasGenSym # symbol was 'gensym'ed
TSymFlags* = set[TSymFlag]
@@ -243,9 +434,9 @@ type
tyInferred
# In the initial state `base` stores a type class constraining
# the types that can be inferred. After a candidate type is
# selected, it's stored in `last`. Between `base` and `last`
# selected, it's stored in `lastSon`. Between `base` and `lastSon`
# there may be 0, 2 or more types that were also considered as
# possible candidates in the inference process (i.e. last will
# possible candidates in the inference process (i.e. lastSon will
# be updated to store a type best conforming to all candidates)
tyAnd, tyOr, tyNot
@@ -329,7 +520,6 @@ type
nfFirstWrite # this node is a first write
nfHasComment # node has a comment
nfSkipFieldChecking # node skips field visable checking
nfOpenSym # node is a captured sym but can be overriden by local symbols
TNodeFlags* = set[TNodeFlag]
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 47)
@@ -362,7 +552,7 @@ type
tfIterator, # type is really an iterator, not a tyProc
tfPartial, # type is declared as 'partial'
tfNotNil, # type cannot be 'nil'
tfRequiresInit, # type contains a "not nil" constraint somewhere or
tfRequiresInit, # type constains a "not nil" constraint somewhere or
# a `requiresInit` field, so the default zero init
# is not appropriate
tfNeedsFullInit, # object type marked with {.requiresInit.}
@@ -489,6 +679,7 @@ type
mUnaryPlusI, mBitnotI,
mUnaryPlusF64, mUnaryMinusF64,
mCharToStr, mBoolToStr,
mIntToStr, mInt64ToStr, mFloatToStr, # for compiling nimStdlibVersion < 1.5.1 (not bootstrapping)
mCStrToStr,
mStrToStr, mEnumToStr,
mAnd, mOr,
@@ -505,7 +696,7 @@ type
mSwap, mIsNil, mArrToSeq, mOpenArrayToSeq,
mNewString, mNewStringOfCap, mParseBiggestFloat,
mMove, mEnsureMove, mWasMoved, mDup, mDestroy, mTrace,
mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mAccessTypeField,
mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mAccessTypeField, mReset,
mArray, mOpenArray, mRange, mSet, mSeq, mVarargs,
mRef, mPtr, mVar, mDistinct, mVoid, mTuple,
mOrdinal, mIterableType,
@@ -558,6 +749,7 @@ const
mUnaryMinusI, mUnaryMinusI64, mAbsI, mNot, mUnaryPlusI, mBitnotI,
mUnaryPlusF64, mUnaryMinusF64,
mCharToStr, mBoolToStr,
mIntToStr, mInt64ToStr, mFloatToStr,
mCStrToStr,
mStrToStr, mEnumToStr,
mAnd, mOr,
@@ -587,6 +779,10 @@ proc hash*(x: ItemId): Hash =
type
TIdObj* {.acyclic.} = object of RootObj
itemId*: ItemId
PIdObj* = ref TIdObj
PNode* = ref TNode
TNodeSeq* = seq[PNode]
PType* = ref TType
@@ -689,8 +885,7 @@ type
PScope* = ref TScope
PLib* = ref TLib
TSym* {.acyclic.} = object # Keep in sync with PackedSym
itemId*: ItemId
TSym* {.acyclic.} = object of TIdObj # Keep in sync with PackedSym
# proc and type instantiations are cached in the generic symbol
case kind*: TSymKind
of routineKinds:
@@ -759,12 +954,11 @@ type
attachedTrace,
attachedDeepCopy
TType* {.acyclic.} = object # \
TType* {.acyclic.} = object of TIdObj # \
# types are identical iff they have the
# same id; there may be multiple copies of a type
# in memory!
# Keep in sync with PackedType
itemId*: ItemId
kind*: TTypeKind # kind of type
callConv*: TCallingConvention # for procs
flags*: TTypeFlags # flags of the type
@@ -796,6 +990,24 @@ type
TPairSeq* = seq[TPair]
TIdPair* = object
key*: PIdObj
val*: RootRef
TIdPairSeq* = seq[TIdPair]
TIdTable* = object # the same as table[PIdent] of PObject
counter*: int
data*: TIdPairSeq
TIdNodePair* = object
key*: PIdObj
val*: PNode
TIdNodePairSeq* = seq[TIdNodePair]
TIdNodeTable* = object # the same as table[PIdObj] of PNode
counter*: int
data*: TIdNodePairSeq
TNodePair* = object
h*: Hash # because it is expensive to compute!
key*: PNode
@@ -883,8 +1095,7 @@ const
nfIsRef, nfIsPtr, nfPreventCg, nfLL,
nfFromTemplate, nfDefaultRefsParam,
nfExecuteOnReload, nfLastRead,
nfFirstWrite, nfSkipFieldChecking,
nfOpenSym}
nfFirstWrite, nfSkipFieldChecking}
namePos* = 0
patternPos* = 1 # empty except for term rewriting macros
genericParamsPos* = 2
@@ -897,6 +1108,8 @@ const
nfAllFieldsSet* = nfBase2
nkCallKinds* = {nkCall, nkInfix, nkPrefix, nkPostfix,
nkCommand, nkCallStrLit, nkHiddenCallConv}
nkIdentKinds* = {nkIdent, nkSym, nkAccQuoted, nkOpenSymChoice,
nkClosedSymChoice}
@@ -931,7 +1144,7 @@ proc getPIdent*(a: PNode): PIdent {.inline.} =
const
moduleShift = when defined(cpu32): 20 else: 24
template id*(a: PType | PSym): int =
template id*(a: PIdObj): int =
let x = a
(x.itemId.module.int shl moduleShift) + x.itemId.item.int
@@ -983,7 +1196,9 @@ proc isCallExpr*(n: PNode): bool =
proc discardSons*(father: PNode)
proc len*(n: PNode): int {.inline.} =
type Indexable = PNode | PType
proc len*(n: Indexable): int {.inline.} =
result = n.sons.len
proc safeLen*(n: PNode): int {.inline.} =
@@ -997,31 +1212,18 @@ proc safeArrLen*(n: PNode): int {.inline.} =
elif n.kind in {nkNone..nkFloat128Lit}: result = 0
else: result = n.len
proc add*(father, son: PNode) =
proc add*(father, son: Indexable) =
assert son != nil
father.sons.add(son)
proc addAllowNil*(father, son: PNode) {.inline.} =
proc addAllowNil*(father, son: Indexable) {.inline.} =
father.sons.add(son)
template `[]`*(n: PNode, i: int): PNode = n.sons[i]
template `[]=`*(n: PNode, i: int; x: PNode) = n.sons[i] = x
template `[]`*(n: Indexable, i: int): Indexable = n.sons[i]
template `[]=`*(n: Indexable, i: int; x: Indexable) = n.sons[i] = x
template `[]`*(n: PNode, i: BackwardsIndex): PNode = n[n.len - i.int]
template `[]=`*(n: PNode, i: BackwardsIndex; x: PNode) = n[n.len - i.int] = x
proc add*(father, son: PType) =
assert son != nil
father.sons.add(son)
proc addAllowNil*(father, son: PType) {.inline.} =
father.sons.add(son)
template `[]`*(n: PType, i: int): PType = n.sons[i]
template `[]=`*(n: PType, i: int; x: PType) = n.sons[i] = x
template `[]`*(n: PType, i: BackwardsIndex): PType = n[n.len - i.int]
template `[]=`*(n: PType, i: BackwardsIndex; x: PType) = n[n.len - i.int] = x
template `[]`*(n: Indexable, i: BackwardsIndex): Indexable = n[n.len - i.int]
template `[]=`*(n: Indexable, i: BackwardsIndex; x: Indexable) = n[n.len - i.int] = x
proc getDeclPragma*(n: PNode): PNode =
## return the `nkPragma` node for declaration `n`, or `nil` if no pragma was found.
@@ -1133,33 +1335,6 @@ proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode =
result.info = info
result.typ = typ
proc newNode*(kind: TNodeKind, info: TLineInfo): PNode =
## new node with line info, no type, and no children
newNodeImpl(info)
setIdMaybe()
proc newAtom*(ident: PIdent, info: TLineInfo): PNode =
result = newNode(nkIdent, info)
result.ident = ident
proc newAtom*(kind: TNodeKind, intVal: BiggestInt, info: TLineInfo): PNode =
result = newNode(kind, info)
result.intVal = intVal
proc newAtom*(kind: TNodeKind, floatVal: BiggestFloat, info: TLineInfo): PNode =
result = newNode(kind, info)
result.floatVal = floatVal
proc newAtom*(kind: TNodeKind; strVal: sink string; info: TLineInfo): PNode =
result = newNode(kind, info)
result.strVal = strVal
proc newTree*(kind: TNodeKind; info: TLineInfo; children: varargs[PNode]): PNode =
result = newNodeI(kind, info)
if children.len > 0:
result.info = children[0].info
result.sons = @children
proc newTree*(kind: TNodeKind; children: varargs[PNode]): PNode =
result = newNode(kind)
if children.len > 0:
@@ -1179,7 +1354,7 @@ proc newTreeIT*(kind: TNodeKind; info: TLineInfo; typ: PType; children: varargs[
result.sons = @children
template previouslyInferred*(t: PType): PType =
if t.sons.len > 1: t.last else: nil
if t.sons.len > 1: t.lastSon else: nil
when false:
import tables, strutils
@@ -1257,6 +1432,11 @@ proc copyStrTable*(dest: var TStrTable, src: TStrTable) =
setLen(dest.data, src.data.len)
for i in 0..high(src.data): dest.data[i] = src.data[i]
proc copyIdTable*(dest: var TIdTable, src: TIdTable) =
dest.counter = src.counter
newSeq(dest.data, src.data.len)
for i in 0..high(src.data): dest.data[i] = src.data[i]
proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) =
dest.counter = src.counter
setLen(dest.data, src.data.len)
@@ -1294,42 +1474,7 @@ proc newIntNode*(kind: TNodeKind, intVal: Int128): PNode =
result = newNode(kind)
result.intVal = castToInt64(intVal)
proc lastSon*(n: PNode): PNode {.inline.} = n.sons[^1]
template setLastSon*(n: PNode, s: PNode) = n.sons[^1] = s
template firstSon*(n: PNode): PNode = n.sons[0]
template secondSon*(n: PNode): PNode = n.sons[1]
template hasSon*(n: PNode): bool = n.len > 0
template has2Sons*(n: PNode): bool = n.len > 1
proc replaceFirstSon*(n, newson: PNode) {.inline.} =
n.sons[0] = newson
proc replaceSon*(n: PNode; i: int; newson: PNode) {.inline.} =
n.sons[i] = newson
proc last*(n: PType): PType {.inline.} = n.sons[^1]
proc elementType*(n: PType): PType {.inline.} = n.sons[^1]
proc skipModifier*(n: PType): PType {.inline.} = n.sons[^1]
proc indexType*(n: PType): PType {.inline.} = n.sons[0]
proc baseClass*(n: PType): PType {.inline.} = n.sons[0]
proc base*(t: PType): PType {.inline.} =
result = t.sons[0]
proc returnType*(n: PType): PType {.inline.} = n.sons[0]
proc setReturnType*(n, r: PType) {.inline.} = n.sons[0] = r
proc setIndexType*(n, idx: PType) {.inline.} = n.sons[0] = idx
proc firstParamType*(n: PType): PType {.inline.} = n.sons[1]
proc firstGenericParam*(n: PType): PType {.inline.} = n.sons[1]
proc typeBodyImpl*(n: PType): PType {.inline.} = n.sons[^1]
proc genericHead*(n: PType): PType {.inline.} = n.sons[0]
proc lastSon*(n: Indexable): Indexable = n.sons[^1]
proc skipTypes*(t: PType, kinds: TTypeKinds): PType =
## Used throughout the compiler code to test whether a type tree contains or
@@ -1337,7 +1482,7 @@ proc skipTypes*(t: PType, kinds: TTypeKinds): PType =
## last child nodes of a type tree need to be searched. This is a really hot
## path within the compiler!
result = t
while result.kind in kinds: result = last(result)
while result.kind in kinds: result = lastSon(result)
proc newIntTypeNode*(intVal: BiggestInt, typ: PType): PNode =
let kind = skipTypes(typ, abstractVarRange).kind
@@ -1396,120 +1541,31 @@ proc `$`*(s: PSym): string =
else:
result = "<nil>"
when false:
iterator items*(t: PType): PType =
for i in 0..<t.sons.len: yield t.sons[i]
iterator pairs*(n: PType): tuple[i: int, n: PType] =
for i in 0..<n.sons.len: yield (i, n.sons[i])
when true:
proc len*(n: PType): int {.inline.} =
result = n.sons.len
proc sameTupleLengths*(a, b: PType): bool {.inline.} =
result = a.sons.len == b.sons.len
iterator tupleTypePairs*(a, b: PType): (int, PType, PType) =
for i in 0 ..< a.sons.len:
yield (i, a.sons[i], b.sons[i])
iterator underspecifiedPairs*(a, b: PType; start = 0; without = 0): (PType, PType) =
# XXX Figure out with what typekinds this is called.
for i in start ..< min(a.sons.len, b.sons.len) + without:
yield (a.sons[i], b.sons[i])
proc signatureLen*(t: PType): int {.inline.} =
result = t.sons.len
proc paramsLen*(t: PType): int {.inline.} =
result = t.sons.len - 1
proc genericParamsLen*(t: PType): int {.inline.} =
assert t.kind == tyGenericInst
result = t.sons.len - 2 # without 'head' and 'body'
proc genericInvocationParamsLen*(t: PType): int {.inline.} =
assert t.kind == tyGenericInvocation
result = t.sons.len - 1 # without 'head'
proc kidsLen*(t: PType): int {.inline.} =
result = t.sons.len
proc genericParamHasConstraints*(t: PType): bool {.inline.} = t.sons.len > 0
proc hasElementType*(t: PType): bool {.inline.} = t.sons.len > 0
proc isEmptyTupleType*(t: PType): bool {.inline.} = t.sons.len == 0
proc isSingletonTupleType*(t: PType): bool {.inline.} = t.sons.len == 1
proc genericConstraint*(t: PType): PType {.inline.} = t.sons[0]
iterator genericInstParams*(t: PType): (bool, PType) =
for i in 1..<t.sons.len-1:
yield (i!=1, t.sons[i])
iterator genericInstParamPairs*(a, b: PType): (int, PType, PType) =
for i in 1..<min(a.sons.len, b.sons.len)-1:
yield (i-1, a.sons[i], b.sons[i])
iterator genericInvocationParams*(t: PType): (bool, PType) =
for i in 1..<t.sons.len:
yield (i!=1, t.sons[i])
iterator genericInvocationAndBodyElements*(a, b: PType): (PType, PType) =
for i in 1..<a.sons.len:
yield (a.sons[i], b.sons[i-1])
iterator genericInvocationParamPairs*(a, b: PType): (bool, PType, PType) =
for i in 1..<a.sons.len:
if i >= b.sons.len:
yield (false, nil, nil)
else:
yield (true, a.sons[i], b.sons[i])
iterator genericBodyParams*(t: PType): (int, PType) =
for i in 0..<t.sons.len-1:
yield (i, t.sons[i])
iterator userTypeClassInstParams*(t: PType): (bool, PType) =
for i in 1..<t.sons.len-1:
yield (i!=1, t.sons[i])
iterator ikids*(t: PType): (int, PType) =
for i in 0..<t.sons.len: yield (i, t.sons[i])
const
FirstParamAt* = 1
FirstGenericParamAt* = 1
iterator paramTypes*(t: PType): (int, PType) =
for i in FirstParamAt..<t.sons.len: yield (i, t.sons[i])
iterator paramTypePairs*(a, b: PType): (PType, PType) =
for i in FirstParamAt..<a.sons.len: yield (a.sons[i], b.sons[i])
template paramTypeToNodeIndex*(x: int): int = x
iterator kids*(t: PType): PType =
iterator items*(t: PType): PType =
for i in 0..<t.sons.len: yield t.sons[i]
iterator signature*(t: PType): PType =
# yields return type + parameter types
for i in 0..<t.sons.len: yield t.sons[i]
iterator pairs*(n: PType): tuple[i: int, n: PType] =
for i in 0..<n.sons.len: yield (i, n.sons[i])
proc newType*(kind: TTypeKind; idgen: IdGenerator; owner: PSym; son: sink PType = nil): PType =
proc newType*(kind: TTypeKind, idgen: IdGenerator; owner: PSym, sons: seq[PType] = @[]): PType =
let id = nextTypeId idgen
result = PType(kind: kind, owner: owner, size: defaultSize,
align: defaultAlignment, itemId: id,
uniqueId: id, sons: @[])
if son != nil: result.sons.add son
uniqueId: id, sons: sons)
when false:
if result.itemId.module == 55 and result.itemId.item == 2:
echo "KNID ", kind
writeStackTrace()
proc setSons*(dest: PType; sons: sink seq[PType]) {.inline.} = dest.sons = sons
proc setSon*(dest: PType; son: sink PType) {.inline.} = dest.sons = @[son]
template newType*(kind: TTypeKind, id: IdGenerator; owner: PSym, parent: PType): PType =
newType(kind, id, owner, parent.sons)
proc setSons*(dest: PType; sons: seq[PType]) {.inline.} = dest.sons = sons
when false:
proc newType*(prev: PType, sons: seq[PType]): PType =
result = prev
result.sons = sons
proc mergeLoc(a: var TLoc, b: TLoc) =
if a.k == low(typeof(a.k)): a.k = b.k
@@ -1518,17 +1574,9 @@ proc mergeLoc(a: var TLoc, b: TLoc) =
if a.lode == nil: a.lode = b.lode
if a.r == "": a.r = b.r
proc newSons*(father: PNode, length: int) =
proc newSons*(father: Indexable, length: int) =
setLen(father.sons, length)
proc newSons*(father: PType, length: int) =
setLen(father.sons, length)
proc truncateInferredTypeCandidates*(t: PType) {.inline.} =
assert t.kind == tyInferred
if t.sons.len > 1:
setLen(t.sons, 1)
proc assignType*(dest, src: PType) =
dest.kind = src.kind
dest.flags = src.flags
@@ -1544,8 +1592,8 @@ proc assignType*(dest, src: PType) =
mergeLoc(dest.sym.loc, src.sym.loc)
else:
dest.sym = src.sym
newSons(dest, src.sons.len)
for i in 0..<src.sons.len: dest[i] = src[i]
newSons(dest, src.len)
for i in 0..<src.len: dest[i] = src[i]
proc copyType*(t: PType, idgen: IdGenerator, owner: PSym): PType =
result = newType(t.kind, idgen, owner)
@@ -1591,10 +1639,24 @@ proc initStrTable*(): TStrTable =
result = TStrTable(counter: 0)
newSeq(result.data, StartSize)
proc initIdTable*(): TIdTable =
result = TIdTable(counter: 0)
newSeq(result.data, StartSize)
proc resetIdTable*(x: var TIdTable) =
x.counter = 0
# clear and set to old initial size:
setLen(x.data, 0)
setLen(x.data, StartSize)
proc initObjectSet*(): TObjectSet =
result = TObjectSet(counter: 0)
newSeq(result.data, StartSize)
proc initIdNodeTable*(): TIdNodeTable =
result = TIdNodeTable(counter: 0)
newSeq(result.data, StartSize)
proc initNodeTable*(): TNodeTable =
result = TNodeTable(counter: 0)
newSeq(result.data, StartSize)
@@ -1603,7 +1665,7 @@ proc skipTypes*(t: PType, kinds: TTypeKinds; maxIters: int): PType =
result = t
var i = maxIters
while result.kind in kinds:
result = last(result)
result = lastSon(result)
dec i
if i == 0: return nil
@@ -1611,8 +1673,8 @@ proc skipTypesOrNil*(t: PType, kinds: TTypeKinds): PType =
## same as skipTypes but handles 'nil'
result = t
while result != nil and result.kind in kinds:
if result.sons.len == 0: return nil
result = last(result)
if result.len == 0: return nil
result = lastSon(result)
proc isGCedMem*(t: PType): bool {.inline.} =
result = t.kind in {tyString, tyRef, tySequence} or
@@ -1879,15 +1941,13 @@ proc skipGenericOwner*(s: PSym): PSym =
## Generic instantiations are owned by their originating generic
## symbol. This proc skips such owners and goes straight to the owner
## of the generic itself (the module or the enclosing proc).
result = if s.kind == skModule:
s
elif s.kind in skProcKinds and sfFromGeneric in s.flags and s.owner.kind != skModule:
result = if s.kind in skProcKinds and sfFromGeneric in s.flags and s.owner.kind != skModule:
s.owner.owner
else:
s.owner
proc originatingModule*(s: PSym): PSym =
result = s
result = s.owner
while result.kind != skModule: result = result.owner
proc isRoutine*(s: PSym): bool {.inline.} =
@@ -1933,21 +1993,23 @@ proc toVar*(typ: PType; kind: TTypeKind; idgen: IdGenerator): PType =
## returned. Otherwise ``typ`` is simply returned as-is.
result = typ
if typ.kind != kind:
result = newType(kind, idgen, typ.owner, typ)
result = newType(kind, idgen, typ.owner)
rawAddSon(result, typ)
proc toRef*(typ: PType; idgen: IdGenerator): PType =
## If ``typ`` is a tyObject then it is converted into a `ref <typ>` and
## returned. Otherwise ``typ`` is simply returned as-is.
result = typ
if typ.skipTypes({tyAlias, tyGenericInst}).kind == tyObject:
result = newType(tyRef, idgen, typ.owner, typ)
result = newType(tyRef, idgen, typ.owner)
rawAddSon(result, typ)
proc toObject*(typ: PType): PType =
## If ``typ`` is a tyRef then its immediate son is returned (which in many
## cases should be a ``tyObject``).
## Otherwise ``typ`` is simply returned as-is.
let t = typ.skipTypes({tyAlias, tyGenericInst})
if t.kind == tyRef: t.elementType
if t.kind == tyRef: t.lastSon
else: typ
proc toObjectFromRefPtrGeneric*(typ: PType): PType =
@@ -1964,7 +2026,7 @@ proc toObjectFromRefPtrGeneric*(typ: PType): PType =
result = typ
while true:
case result.kind
of tyGenericBody: result = result.last
of tyGenericBody: result = result.lastSon
of tyRef, tyPtr, tyGenericInst, tyGenericInvocation, tyAlias: result = result[0]
# automatic dereferencing is deep, refs #18298.
else: break
@@ -1977,7 +2039,11 @@ proc isImportedException*(t: PType; conf: ConfigRef): bool =
return false
let base = t.skipTypes({tyAlias, tyPtr, tyDistinct, tyGenericInst})
result = base.sym != nil and {sfCompileToCpp, sfImportc} * base.sym.flags != {}
if base.sym != nil and {sfCompileToCpp, sfImportc} * base.sym.flags != {}:
result = true
else:
result = false
proc isInfixAs*(n: PNode): bool =
return n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.id == ord(wAs)
@@ -1992,7 +2058,7 @@ proc findUnresolvedStatic*(n: PNode): PNode =
return n
if n.typ != nil and n.typ.kind == tyTypeDesc:
let t = skipTypes(n.typ, {tyTypeDesc})
if t.kind == tyGenericParam and not t.genericParamHasConstraints:
if t.kind == tyGenericParam and t.len == 0:
return n
for son in n:
let n = son.findUnresolvedStatic
@@ -2053,7 +2119,7 @@ proc newProcType*(info: TLineInfo; idgen: IdGenerator; owner: PSym): PType =
result.n.add newNodeI(nkEffectList, info)
proc addParam*(procType: PType; param: PSym) =
param.position = procType.sons.len-1
param.position = procType.len-1
procType.n.add newSymNode(param)
rawAddSon(procType, param.typ)
@@ -2115,16 +2181,3 @@ const
proc isTrue*(n: PNode): bool =
n.kind == nkSym and n.sym.kind == skEnumField and n.sym.position != 0 or
n.kind == nkIntLit and n.intVal != 0
type
TypeMapping* = Table[ItemId, PType]
SymMapping* = Table[ItemId, PSym]
template idTableGet*(tab: typed; key: PSym | PType): untyped = tab.getOrDefault(key.itemId)
template idTablePut*(tab: typed; key, val: PSym | PType) = tab[key.itemId] = val
template initSymMapping*(): Table[ItemId, PSym] = initTable[ItemId, PSym]()
template initTypeMapping*(): Table[ItemId, PType] = initTable[ItemId, PType]()
template resetIdTable*(tab: Table[ItemId, PSym]) = tab.clear()
template resetIdTable*(tab: Table[ItemId, PType]) = tab.clear()

View File

@@ -12,18 +12,24 @@
# the data structures here are used in various places of the compiler.
import
ast, astyaml, options, lineinfos, idents, rodutils,
ast, options, lineinfos, ropes, idents, rodutils,
msgs
import std/[hashes, intsets]
import std/strutils except addf
export astyaml.treeToYaml, astyaml.typeToYaml, astyaml.symToYaml, astyaml.lineInfoToStr
when defined(nimPreviewSlimSystem):
import std/assertions
proc hashNode*(p: RootRef): Hash
proc treeToYaml*(conf: ConfigRef; n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope
# Convert a tree into its YAML representation; this is used by the
# YAML code generator and it is invaluable for debugging purposes.
# If maxRecDepht <> -1 then it won't print the whole graph.
proc typeToYaml*(conf: ConfigRef; n: PType, indent: int = 0, maxRecDepth: int = - 1): Rope
proc symToYaml*(conf: ConfigRef; n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope
proc lineInfoToStr*(conf: ConfigRef; info: TLineInfo): Rope
# these are for debugging only: They are not really deprecated, but I want
# the warning so that release versions do not contain debugging statements:
@@ -31,6 +37,15 @@ proc debug*(n: PSym; conf: ConfigRef = nil) {.exportc: "debugSym", deprecated.}
proc debug*(n: PType; conf: ConfigRef = nil) {.exportc: "debugType", deprecated.}
proc debug*(n: PNode; conf: ConfigRef = nil) {.exportc: "debugNode", deprecated.}
proc typekinds*(t: PType) {.deprecated.} =
var t = t
var s = ""
while t != nil and t.len > 0:
s.add $t.kind
s.add " "
t = t.lastSon
echo s
template debug*(x: PSym|PType|PNode) {.deprecated.} =
when compiles(c.config):
debug(c.config, x)
@@ -65,6 +80,16 @@ template mdbg*: bool {.deprecated.} =
else:
error()
# --------------------------- ident tables ----------------------------------
proc idTableGet*(t: TIdTable, key: PIdObj): RootRef
proc idTableGet*(t: TIdTable, key: int): RootRef
proc idTablePut*(t: var TIdTable, key: PIdObj, val: RootRef)
proc idTableHasObjectAsKey*(t: TIdTable, key: PIdObj): bool
# checks if `t` contains the `key` (compared by the pointer value, not only
# `key`'s id)
proc idNodeTableGet*(t: TIdNodeTable, key: PIdObj): PNode
proc idNodeTablePut*(t: var TIdNodeTable, key: PIdObj, val: PNode)
# ---------------------------------------------------------------------------
proc lookupInRecord*(n: PNode, field: PIdent): PSym
@@ -220,6 +245,170 @@ proc mustRehash(length, counter: int): bool =
assert(length > counter)
result = (length * 2 < counter * 3) or (length - counter < 4)
proc rspaces(x: int): Rope =
# returns x spaces
result = rope(spaces(x))
proc toYamlChar(c: char): string =
case c
of '\0'..'\x1F', '\x7F'..'\xFF': result = "\\u" & strutils.toHex(ord(c), 4)
of '\'', '\"', '\\': result = '\\' & c
else: result = $c
proc makeYamlString*(s: string): Rope =
# We have to split long strings into many ropes. Otherwise
# this could trigger InternalError(111). See the ropes module for
# further information.
const MaxLineLength = 64
result = ""
var res = "\""
for i in 0..<s.len:
if (i + 1) mod MaxLineLength == 0:
res.add('\"')
res.add("\n")
result.add(rope(res))
res = "\"" # reset
res.add(toYamlChar(s[i]))
res.add('\"')
result.add(rope(res))
proc flagsToStr[T](flags: set[T]): Rope =
if flags == {}:
result = rope("[]")
else:
result = ""
for x in items(flags):
if result != "": result.add(", ")
result.add(makeYamlString($x))
result = "[" & result & "]"
proc lineInfoToStr(conf: ConfigRef; info: TLineInfo): Rope =
result = "[$1, $2, $3]" % [makeYamlString(toFilename(conf, info)),
rope(toLinenumber(info)),
rope(toColumn(info))]
proc treeToYamlAux(conf: ConfigRef; n: PNode, marker: var IntSet,
indent, maxRecDepth: int): Rope
proc symToYamlAux(conf: ConfigRef; n: PSym, marker: var IntSet,
indent, maxRecDepth: int): Rope
proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet,
indent, maxRecDepth: int): Rope
proc symToYamlAux(conf: ConfigRef; n: PSym, marker: var IntSet, indent: int,
maxRecDepth: int): Rope =
if n == nil:
result = rope("null")
elif containsOrIncl(marker, n.id):
result = "\"$1\"" % [rope(n.name.s)]
else:
var ast = treeToYamlAux(conf, n.ast, marker, indent + 2, maxRecDepth - 1)
#rope("typ"), typeToYamlAux(conf, n.typ, marker,
# indent + 2, maxRecDepth - 1),
let istr = rspaces(indent + 2)
result = rope("{")
result.addf("$N$1\"kind\": $2", [istr, makeYamlString($n.kind)])
result.addf("$N$1\"name\": $2", [istr, makeYamlString(n.name.s)])
result.addf("$N$1\"typ\": $2", [istr, typeToYamlAux(conf, n.typ, marker, indent + 2, maxRecDepth - 1)])
if conf != nil:
# if we don't pass the config, we probably don't care about the line info
result.addf("$N$1\"info\": $2", [istr, lineInfoToStr(conf, n.info)])
if card(n.flags) > 0:
result.addf("$N$1\"flags\": $2", [istr, flagsToStr(n.flags)])
result.addf("$N$1\"magic\": $2", [istr, makeYamlString($n.magic)])
result.addf("$N$1\"ast\": $2", [istr, ast])
result.addf("$N$1\"options\": $2", [istr, flagsToStr(n.options)])
result.addf("$N$1\"position\": $2", [istr, rope(n.position)])
result.addf("$N$1\"k\": $2", [istr, makeYamlString($n.loc.k)])
result.addf("$N$1\"storage\": $2", [istr, makeYamlString($n.loc.storage)])
if card(n.loc.flags) > 0:
result.addf("$N$1\"flags\": $2", [istr, makeYamlString($n.loc.flags)])
result.addf("$N$1\"r\": $2", [istr, n.loc.r])
result.addf("$N$1\"lode\": $2", [istr, treeToYamlAux(conf, n.loc.lode, marker, indent + 2, maxRecDepth - 1)])
result.addf("$N$1}", [rspaces(indent)])
proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet, indent: int,
maxRecDepth: int): Rope =
var sonsRope: Rope
if n == nil:
result = ""
sonsRope = rope("null")
elif containsOrIncl(marker, n.id):
result = ""
sonsRope = "\"$1 @$2\"" % [rope($n.kind), rope(
strutils.toHex(cast[int](n), sizeof(n) * 2))]
else:
if n.len > 0:
sonsRope = rope("[")
for i in 0..<n.len:
if i > 0: sonsRope.add(",")
sonsRope.addf("$N$1$2", [rspaces(indent + 4), typeToYamlAux(conf, n[i],
marker, indent + 4, maxRecDepth - 1)])
sonsRope.addf("$N$1]", [rspaces(indent + 2)])
else:
sonsRope = rope("null")
let istr = rspaces(indent + 2)
result = rope("{")
result.addf("$N$1\"kind\": $2", [istr, makeYamlString($n.kind)])
result.addf("$N$1\"sym\": $2", [istr, symToYamlAux(conf, n.sym, marker, indent + 2, maxRecDepth - 1)])
result.addf("$N$1\"n\": $2", [istr, treeToYamlAux(conf, n.n, marker, indent + 2, maxRecDepth - 1)])
if card(n.flags) > 0:
result.addf("$N$1\"flags\": $2", [istr, flagsToStr(n.flags)])
result.addf("$N$1\"callconv\": $2", [istr, makeYamlString($n.callConv)])
result.addf("$N$1\"size\": $2", [istr, rope(n.size)])
result.addf("$N$1\"align\": $2", [istr, rope(n.align)])
result.addf("$N$1\"sons\": $2", [istr, sonsRope])
proc treeToYamlAux(conf: ConfigRef; n: PNode, marker: var IntSet, indent: int,
maxRecDepth: int): Rope =
if n == nil:
result = rope("null")
else:
var istr = rspaces(indent + 2)
result = "{$N$1\"kind\": $2" % [istr, makeYamlString($n.kind)]
if maxRecDepth != 0:
if conf != nil:
result.addf(",$N$1\"info\": $2", [istr, lineInfoToStr(conf, n.info)])
case n.kind
of nkCharLit..nkUInt64Lit:
result.addf(",$N$1\"intVal\": $2", [istr, rope(n.intVal)])
of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
result.addf(",$N$1\"floatVal\": $2",
[istr, rope(n.floatVal.toStrMaxPrecision)])
of nkStrLit..nkTripleStrLit:
result.addf(",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
of nkSym:
result.addf(",$N$1\"sym\": $2",
[istr, symToYamlAux(conf, n.sym, marker, indent + 2, maxRecDepth)])
of nkIdent:
if n.ident != nil:
result.addf(",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
else:
result.addf(",$N$1\"ident\": null", [istr])
else:
if n.len > 0:
result.addf(",$N$1\"sons\": [", [istr])
for i in 0..<n.len:
if i > 0: result.add(",")
result.addf("$N$1$2", [rspaces(indent + 4), treeToYamlAux(conf, n[i],
marker, indent + 4, maxRecDepth - 1)])
result.addf("$N$1]", [istr])
result.addf(",$N$1\"typ\": $2",
[istr, typeToYamlAux(conf, n.typ, marker, indent + 2, maxRecDepth)])
result.addf("$N$1}", [rspaces(indent)])
proc treeToYaml(conf: ConfigRef; n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope =
var marker = initIntSet()
result = treeToYamlAux(conf, n, marker, indent, maxRecDepth)
proc typeToYaml(conf: ConfigRef; n: PType, indent: int = 0, maxRecDepth: int = - 1): Rope =
var marker = initIntSet()
result = typeToYamlAux(conf, n, marker, indent, maxRecDepth)
proc symToYaml(conf: ConfigRef; n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope =
var marker = initIntSet()
result = symToYamlAux(conf, n, marker, indent, maxRecDepth)
import std/tables
const backrefStyle = "\e[90m"
@@ -384,12 +573,14 @@ proc value(this: var DebugPrinter; value: PType) =
this.key "n"
this.value value.n
this.key "sons"
this.openBracket
for i, a in value.ikids:
if i > 0: this.comma
this.value a
this.closeBracket
if value.len > 0:
this.key "sons"
this.openBracket
for i in 0..<value.len:
this.value value[i]
if i != value.len - 1:
this.comma
this.closeBracket
if value.n != nil:
this.key "n"
@@ -458,33 +649,30 @@ proc value(this: var DebugPrinter; value: PNode) =
proc debug(n: PSym; conf: ConfigRef) =
var this = DebugPrinter(
visited: initTable[pointer, int](),
renderSymType: true,
useColor: not defined(windows)
)
var this: DebugPrinter
this.visited = initTable[pointer, int]()
this.renderSymType = true
this.useColor = not defined(windows)
this.value(n)
echo($this.res)
proc debug(n: PType; conf: ConfigRef) =
var this = DebugPrinter(
visited: initTable[pointer, int](),
renderSymType: true,
useColor: not defined(windows)
)
var this: DebugPrinter
this.visited = initTable[pointer, int]()
this.renderSymType = true
this.useColor = not defined(windows)
this.value(n)
echo($this.res)
proc debug(n: PNode; conf: ConfigRef) =
var this = DebugPrinter(
visited: initTable[pointer, int](),
renderSymType: false,
useColor: not defined(windows)
)
var this: DebugPrinter
this.visited = initTable[pointer, int]()
#this.renderSymType = true
this.useColor = not defined(windows)
this.value(n)
echo($this.res)
proc nextTry(h, maxHash: Hash): Hash {.inline.} =
proc nextTry(h, maxHash: Hash): Hash =
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
@@ -707,12 +895,125 @@ proc initTabIter*(ti: var TTabIter, tab: TStrTable): PSym =
result = nextIter(ti, tab)
iterator items*(tab: TStrTable): PSym =
var it: TTabIter = default(TTabIter)
var it: TTabIter
var s = initTabIter(it, tab)
while s != nil:
yield s
s = nextIter(it, tab)
proc hasEmptySlot(data: TIdPairSeq): bool =
for h in 0..high(data):
if data[h].key == nil:
return true
result = false
proc idTableRawGet(t: TIdTable, key: int): int =
var h: Hash
h = key and high(t.data) # start with real hash value
while t.data[h].key != nil:
if t.data[h].key.id == key:
return h
h = nextTry(h, high(t.data))
result = - 1
proc idTableHasObjectAsKey(t: TIdTable, key: PIdObj): bool =
var index = idTableRawGet(t, key.id)
if index >= 0: result = t.data[index].key == key
else: result = false
proc idTableGet(t: TIdTable, key: PIdObj): RootRef =
var index = idTableRawGet(t, key.id)
if index >= 0: result = t.data[index].val
else: result = nil
proc idTableGet(t: TIdTable, key: int): RootRef =
var index = idTableRawGet(t, key)
if index >= 0: result = t.data[index].val
else: result = nil
iterator pairs*(t: TIdTable): tuple[key: int, value: RootRef] =
for i in 0..high(t.data):
if t.data[i].key != nil:
yield (t.data[i].key.id, t.data[i].val)
proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: RootRef) =
var h: Hash
h = key.id and high(data)
while data[h].key != nil:
assert(data[h].key.id != key.id)
h = nextTry(h, high(data))
assert(data[h].key == nil)
data[h].key = key
data[h].val = val
proc idTablePut(t: var TIdTable, key: PIdObj, val: RootRef) =
var
index: int
n: TIdPairSeq
index = idTableRawGet(t, key.id)
if index >= 0:
assert(t.data[index].key != nil)
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 t.data[i].key != nil:
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)
iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: RootRef] =
for i in 0..high(t.data):
if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
proc idNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int =
var h: Hash
h = key.id and high(t.data) # start with real hash value
while t.data[h].key != nil:
if t.data[h].key.id == key.id:
return h
h = nextTry(h, high(t.data))
result = - 1
proc idNodeTableGet(t: TIdNodeTable, key: PIdObj): PNode =
var index: int
index = idNodeTableRawGet(t, key)
if index >= 0: result = t.data[index].val
else: result = nil
proc idNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) =
var h: Hash
h = key.id and high(data)
while data[h].key != nil:
assert(data[h].key.id != key.id)
h = nextTry(h, high(data))
assert(data[h].key == nil)
data[h].key = key
data[h].val = val
proc idNodeTablePut(t: var TIdNodeTable, key: PIdObj, val: PNode) =
var index = idNodeTableRawGet(t, key)
if index >= 0:
assert(t.data[index].key != nil)
t.data[index].val = val
else:
if mustRehash(t.data.len, t.counter):
var n: TIdNodePairSeq
newSeq(n, t.data.len * GrowthFactor)
for i in 0..high(t.data):
if t.data[i].key != nil:
idNodeTableRawInsert(n, t.data[i].key, t.data[i].val)
swap(t.data, n)
idNodeTableRawInsert(t.data, key, val)
inc(t.counter)
iterator pairs*(t: TIdNodeTable): tuple[key: PIdObj, val: PNode] =
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)
@@ -758,6 +1059,14 @@ proc iiTablePut(t: var TIITable, key, val: int) =
iiTableRawInsert(t.data, key, val)
inc(t.counter)
proc isAddrNode*(n: PNode): bool =
case n.kind
of nkAddr, nkHiddenAddr: true
of nkCallKinds:
if n[0].kind == nkSym and n[0].sym.magic == mAddr: true
else: false
else: false
proc listSymbolNames*(symbols: openArray[PSym]): string =
result = ""
for sym in symbols:

View File

@@ -5,7 +5,7 @@ import options, ast, msgs
proc typSym*(t: PType): PSym =
result = t.sym
if result == nil and t.kind == tyGenericInst: # this might need to be refined
result = t.genericHead.sym
result = t[0].sym
proc addDeclaredLoc*(result: var string, conf: ConfigRef; sym: PSym) =
result.add " [$1 declared in $2]" % [sym.kind.toHumanStr, toFileLineCol(conf, sym.info)]
@@ -24,12 +24,6 @@ proc addDeclaredLoc*(result: var string, conf: ConfigRef; typ: PType) =
result.add " declared in " & toFileLineCol(conf, typ.sym.info)
result.add "]"
proc addTypeNodeDeclaredLoc*(result: var string, conf: ConfigRef; typ: PType) =
result.add " [$1" % typ.kind.toHumanStr
if typ.sym != nil:
result.add " declared in " & toFileLineCol(conf, typ.sym.info)
result.add "]"
proc addDeclaredLocMaybe*(result: var string, conf: ConfigRef; typ: PType) =
if optDeclaredLocs in conf.globalOptions: addDeclaredLoc(result, conf, typ)

View File

@@ -1,154 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# AST YAML printing
import "."/[ast, lineinfos, msgs, options, rodutils]
import std/[intsets, strutils]
proc addYamlString*(res: var string; s: string) =
res.add "\""
for c in s:
case c
of '\0' .. '\x1F', '\x7F' .. '\xFF':
res.add("\\u" & strutils.toHex(ord(c), 4))
of '\"', '\\':
res.add '\\' & c
else:
res.add c
res.add('\"')
proc makeYamlString(s: string): string =
result = ""
result.addYamlString(s)
proc flagsToStr[T](flags: set[T]): string =
if flags == {}:
result = "[]"
else:
result = ""
for x in items(flags):
if result != "":
result.add(", ")
result.addYamlString($x)
result = "[" & result & "]"
proc lineInfoToStr*(conf: ConfigRef; info: TLineInfo): string =
result = "["
result.addYamlString(toFilename(conf, info))
result.addf ", $1, $2]", [toLinenumber(info), toColumn(info)]
proc treeToYamlAux(res: var string; conf: ConfigRef; n: PNode; marker: var IntSet; indent, maxRecDepth: int)
proc symToYamlAux(res: var string; conf: ConfigRef; n: PSym; marker: var IntSet; indent, maxRecDepth: int)
proc typeToYamlAux(res: var string; conf: ConfigRef; n: PType; marker: var IntSet; indent, maxRecDepth: int)
proc symToYamlAux(res: var string; conf: ConfigRef; n: PSym; marker: var IntSet; indent: int; maxRecDepth: int) =
if n == nil:
res.add("null")
elif containsOrIncl(marker, n.id):
res.addYamlString(n.name.s)
else:
let istr = spaces(indent * 4)
res.addf("kind: $1", [makeYamlString($n.kind)])
res.addf("\n$1name: $2", [istr, makeYamlString(n.name.s)])
res.addf("\n$1typ: ", [istr])
res.typeToYamlAux(conf, n.typ, marker, indent + 1, maxRecDepth - 1)
if conf != nil:
# if we don't pass the config, we probably don't care about the line info
res.addf("\n$1info: $2", [istr, lineInfoToStr(conf, n.info)])
if card(n.flags) > 0:
res.addf("\n$1flags: $2", [istr, flagsToStr(n.flags)])
res.addf("\n$1magic: $2", [istr, makeYamlString($n.magic)])
res.addf("\n$1ast: ", [istr])
res.treeToYamlAux(conf, n.ast, marker, indent + 1, maxRecDepth - 1)
res.addf("\n$1options: $2", [istr, flagsToStr(n.options)])
res.addf("\n$1position: $2", [istr, $n.position])
res.addf("\n$1k: $2", [istr, makeYamlString($n.loc.k)])
res.addf("\n$1storage: $2", [istr, makeYamlString($n.loc.storage)])
if card(n.loc.flags) > 0:
res.addf("\n$1flags: $2", [istr, makeYamlString($n.loc.flags)])
res.addf("\n$1r: $2", [istr, n.loc.r])
res.addf("\n$1lode: $2", [istr])
res.treeToYamlAux(conf, n.loc.lode, marker, indent + 1, maxRecDepth - 1)
proc typeToYamlAux(res: var string; conf: ConfigRef; n: PType; marker: var IntSet; indent: int; maxRecDepth: int) =
if n == nil:
res.add("null")
elif containsOrIncl(marker, n.id):
res.addf "\"$1 @$2\"" % [$n.kind, strutils.toHex(cast[uint](n), sizeof(n) * 2)]
else:
let istr = spaces(indent * 4)
res.addf("kind: $2", [istr, makeYamlString($n.kind)])
res.addf("\n$1sym: ")
res.symToYamlAux(conf, n.sym, marker, indent + 1, maxRecDepth - 1)
res.addf("\n$1n: ")
res.treeToYamlAux(conf, n.n, marker, indent + 1, maxRecDepth - 1)
if card(n.flags) > 0:
res.addf("\n$1flags: $2", [istr, flagsToStr(n.flags)])
res.addf("\n$1callconv: $2", [istr, makeYamlString($n.callConv)])
res.addf("\n$1size: $2", [istr, $(n.size)])
res.addf("\n$1align: $2", [istr, $(n.align)])
if n.hasElementType:
res.addf("\n$1sons:")
for a in n.kids:
res.addf("\n - ")
res.typeToYamlAux(conf, a, marker, indent + 1, maxRecDepth - 1)
proc treeToYamlAux(res: var string; conf: ConfigRef; n: PNode; marker: var IntSet; indent: int;
maxRecDepth: int) =
if n == nil:
res.add("null")
else:
var istr = spaces(indent * 4)
res.addf("kind: $1" % [makeYamlString($n.kind)])
if maxRecDepth != 0:
if conf != nil:
res.addf("\n$1info: $2", [istr, lineInfoToStr(conf, n.info)])
case n.kind
of nkCharLit .. nkInt64Lit:
res.addf("\n$1intVal: $2", [istr, $(n.intVal)])
of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
res.addf("\n$1floatVal: $2", [istr, n.floatVal.toStrMaxPrecision])
of nkStrLit .. nkTripleStrLit:
res.addf("\n$1strVal: $2", [istr, makeYamlString(n.strVal)])
of nkSym:
res.addf("\n$1sym: ", [istr])
res.symToYamlAux(conf, n.sym, marker, indent + 1, maxRecDepth)
of nkIdent:
if n.ident != nil:
res.addf("\n$1ident: $2", [istr, makeYamlString(n.ident.s)])
else:
res.addf("\n$1ident: null", [istr])
else:
if n.len > 0:
res.addf("\n$1sons: ", [istr])
for i in 0 ..< n.len:
res.addf("\n$1 - ", [istr])
res.treeToYamlAux(conf, n[i], marker, indent + 1, maxRecDepth - 1)
if n.typ != nil:
res.addf("\n$1typ: ", [istr])
res.typeToYamlAux(conf, n.typ, marker, indent + 1, maxRecDepth)
proc treeToYaml*(conf: ConfigRef; n: PNode; indent: int = 0; maxRecDepth: int = -1): string =
var marker = initIntSet()
result = newStringOfCap(1024)
result.treeToYamlAux(conf, n, marker, indent, maxRecDepth)
proc typeToYaml*(conf: ConfigRef; n: PType; indent: int = 0; maxRecDepth: int = -1): string =
var marker = initIntSet()
result = newStringOfCap(1024)
result.typeToYamlAux(conf, n, marker, indent, maxRecDepth)
proc symToYaml*(conf: ConfigRef; n: PSym; indent: int = 0; maxRecDepth: int = -1): string =
var marker = initIntSet()
result = newStringOfCap(1024)
result.symToYamlAux(conf, n, marker, indent, maxRecDepth)

View File

@@ -76,23 +76,6 @@ proc isHarmlessStore(p: BProc; canRaise: bool; d: TLoc): bool =
else:
result = false
proc cleanupTemp(p: BProc; returnType: PType, tmp: TLoc): bool =
if returnType.kind in {tyVar, tyLent}:
# we don't need to worry about var/lent return types
result = false
elif hasDestructor(returnType) and getAttachedOp(p.module.g.graph, returnType, attachedDestructor) != nil:
let dtor = getAttachedOp(p.module.g.graph, returnType, attachedDestructor)
var op = initLocExpr(p, newSymNode(dtor))
var callee = rdLoc(op)
let destroy = if dtor.typ.firstParamType.kind == tyVar:
callee & "(&" & rdLoc(tmp) & ")"
else:
callee & "(" & rdLoc(tmp) & ")"
raiseExitCleanup(p, destroy)
result = true
else:
result = false
proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
callee, params: Rope) =
let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri[0])
@@ -100,17 +83,13 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
var pl = callee & "(" & params
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInst)
if typ.returnType != nil:
var flags: TAssignmentFlags = {}
if typ.returnType.kind in {tyOpenArray, tyVarargs}:
# perhaps generate no temp if the call doesn't have side effects
flags.incl needTempForOpenArray
if typ[0] != nil:
if isInvalidReturnType(p.config, typ):
if params.len != 0: pl.add(", ")
# beware of 'result = p(result)'. We may need to allocate a temporary:
if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri):
# Great, we can use 'd':
if d.k == locNone: d = getTemp(p, typ.returnType, needsInit=true)
if d.k == locNone: d = getTemp(p, typ[0], needsInit=true)
elif d.k notin {locTemp} and not hasNoInit(ri):
# reset before pass as 'result' var:
discard "resetLoc(p, d)"
@@ -118,7 +97,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
pl.add(");\n")
line(p, cpsStmts, pl)
else:
var tmp: TLoc = getTemp(p, typ.returnType, needsInit=true)
var tmp: TLoc = getTemp(p, typ[0], needsInit=true)
pl.add(addrLoc(p.config, tmp))
pl.add(");\n")
line(p, cpsStmts, pl)
@@ -136,34 +115,27 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
excl d.flags, lfSingleUse
else:
if d.k == locNone and p.splitDecls == 0:
d = getTempCpp(p, typ.returnType, pl)
d = getTempCpp(p, typ[0], pl)
else:
if d.k == locNone: d = getTemp(p, typ.returnType)
if d.k == locNone: d = getTemp(p, typ[0])
var list = initLoc(locCall, d.lode, OnUnknown)
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
if canRaise: raiseExit(p)
elif isHarmlessStore(p, canRaise, d):
var useTemp = false
if d.k == locNone:
useTemp = true
d = getTemp(p, typ.returnType)
if d.k == locNone: d = getTemp(p, typ[0])
assert(d.t != nil) # generate an assignment to d:
var list = initLoc(locCall, d.lode, OnUnknown)
list.r = pl
genAssignment(p, d, list, flags) # no need for deep copying
if canRaise:
if not (useTemp and cleanupTemp(p, typ.returnType, d)):
raiseExit(p)
genAssignment(p, d, list, {}) # no need for deep copying
if canRaise: raiseExit(p)
else:
var tmp: TLoc = getTemp(p, typ.returnType, needsInit=true)
var tmp: TLoc = getTemp(p, typ[0], needsInit=true)
var list = initLoc(locCall, d.lode, OnUnknown)
list.r = pl
genAssignment(p, tmp, list, flags) # no need for deep copying
if canRaise:
if not cleanupTemp(p, typ.returnType, tmp):
raiseExit(p)
genAssignment(p, tmp, list, {}) # no need for deep copying
if canRaise: raiseExit(p)
genAssignment(p, d, tmp, {})
else:
pl.add(");\n")
@@ -174,14 +146,8 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc)
proc reifiedOpenArray(n: PNode): bool {.inline.} =
var x = n
while true:
case x.kind
of {nkAddr, nkHiddenAddr, nkHiddenDeref}:
x = x[0]
of nkHiddenStdConv:
x = x[1]
else:
break
while x.kind in {nkAddr, nkHiddenAddr, nkHiddenStdConv, nkHiddenDeref}:
x = x[0]
if x.kind == nkSym and x.sym.kind == skParam:
result = false
else:
@@ -196,10 +162,7 @@ proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareF
genBoundsCheck(p, a, b, c)
if prepareForMutation:
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
# bug #23321: In the function mapType, ptrs (tyPtr, tyVar, tyLent, tyRef)
# are mapped into ctPtrToArray, the dereference of which is skipped
# in the `genref`. We need to skip these ptrs here
let ty = skipTypes(a.t, abstractVar+{tyPtr, tyRef})
let ty = skipTypes(a.t, abstractVar+{tyPtr})
let dest = getTypeDesc(p.module, destType)
let lengthExpr = "($1)-($2)+1" % [rdLoc(c), rdLoc(b)]
case ty.kind
@@ -231,11 +194,11 @@ proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareF
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
if atyp.kind in {tyVar} and not compileToCpp(p.module):
result = ("(($5) ? (($4*)(*$1)$3+($2)) : NIM_NIL)" %
[rdLoc(a), rdLoc(b), dataField(p), dest, dataFieldAccessor(p, "*" & rdLoc(a))],
[rdLoc(a), rdLoc(b), dataField(p, ty.kind == tyString), dest, dataFieldAccessor(p, "*" & rdLoc(a))],
lengthExpr)
else:
result = ("(($5) ? (($4*)$1$3+($2)) : NIM_NIL)" %
[rdLoc(a), rdLoc(b), dataField(p), dest, dataFieldAccessor(p, rdLoc(a))],
[rdLoc(a), rdLoc(b), dataField(p, ty.kind == tyString), dest, dataFieldAccessor(p, rdLoc(a))],
lengthExpr)
else:
result = ("", "")
@@ -255,11 +218,12 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) =
for i in 0..<q.len-1:
genStmts(p, q[i])
q = q.lastSon
let (x, y) = genOpenArraySlice(p, q, formalType, n.typ.elementType)
let (x, y) = genOpenArraySlice(p, q, formalType, n.typ[0])
result.add x & ", " & y
else:
var a = initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n)
case skipTypes(a.t, abstractVar+{tyStatic}).kind
let typKind = skipTypes(a.t, abstractVar+{tyStatic}).kind
case typKind
of tyOpenArray, tyVarargs:
if reifiedOpenArray(n):
if a.t.kind in {tyVar, tyLent}:
@@ -274,24 +238,26 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) =
optSeqDestructors in p.config.globalOptions:
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
if ntyp.kind in {tyVar} and not compileToCpp(p.module):
var t = TLoc(r: "(*$1)" % [a.rdLoc])
var t: TLoc
t.r = "(*$1)" % [a.rdLoc]
result.add "($4) ? ((*$1)$3) : NIM_NIL, $2" %
[a.rdLoc, lenExpr(p, t), dataField(p),
[a.rdLoc, lenExpr(p, t, typKind == tyString), dataField(p, typKind == tyString),
dataFieldAccessor(p, "*" & a.rdLoc)]
else:
result.add "($4) ? ($1$3) : NIM_NIL, $2" %
[a.rdLoc, lenExpr(p, a), dataField(p), dataFieldAccessor(p, a.rdLoc)]
[a.rdLoc, lenExpr(p, a, typKind == tyString), dataField(p, typKind == tyString), dataFieldAccessor(p, a.rdLoc)]
of tyArray:
result.add "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))]
of tyPtr, tyRef:
case elementType(a.t).kind
case lastSon(a.t).kind
of tyString, tySequence:
var t = TLoc(r: "(*$1)" % [a.rdLoc])
var t: TLoc
t.r = "(*$1)" % [a.rdLoc]
result.add "($4) ? ((*$1)$3) : NIM_NIL, $2" %
[a.rdLoc, lenExpr(p, t), dataField(p),
[a.rdLoc, lenExpr(p, t, typKind == tyString), dataField(p, typKind == tyString),
dataFieldAccessor(p, "*" & a.rdLoc)]
of tyArray:
result.add "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, elementType(a.t)))]
result.add "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, lastSon(a.t)))]
else:
internalError(p.config, "openArrayLoc: " & typeToString(a.t))
else: internalError(p.config, "openArrayLoc: " & typeToString(a.t))
@@ -322,7 +288,7 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; need
elif skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs}:
var n = if n.kind != nkHiddenAddr: n else: n[0]
openArrayLoc(p, param.typ, n, result)
elif ccgIntroducedPtr(p.config, param, call[0].typ.returnType) and
elif ccgIntroducedPtr(p.config, param, call[0].typ[0]) and
(optByRef notin param.options or not p.module.compileToCpp):
a = initLocExpr(p, n)
if n.kind in {nkCharLit..nkNilLit}:
@@ -343,11 +309,6 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; need
addRdLoc(a, result)
else:
a = initLocExprSingleUse(p, n)
if param.typ.kind in abstractPtrs:
let typ = skipTypes(param.typ, abstractPtrs)
if typ.sym != nil and sfImportc in typ.sym.flags:
a.r = "(($1) ($2))" %
[getTypeDesc(p.module, param.typ), rdCharLoc(a)]
addRdLoc(withTmpIfNeeded(p, a, needsTmp), result)
#assert result != nil
@@ -392,7 +353,7 @@ proc getPotentialWrites(n: PNode; mutate: bool; result: var seq[PNode]) =
of nkCallKinds:
case n.getMagic:
of mIncl, mExcl, mInc, mDec, mAppendStrCh, mAppendStrStr, mAppendSeqElem,
mAddr, mNew, mNewFinalize, mWasMoved, mDestroy:
mAddr, mNew, mNewFinalize, mWasMoved, mDestroy, mReset:
getPotentialWrites(n[1], true, result)
for i in 2..<n.len:
getPotentialWrites(n[i], mutate, result)
@@ -436,7 +397,7 @@ proc genParams(p: BProc, ri: PNode, typ: PType; result: var Rope) =
var oldLen = result.len
for i in 1..<ri.len:
if i < typ.n.len:
if i < typ.len:
assert(typ.n[i].kind == nkSym)
let paramType = typ.n[i]
if not paramType.typ.isCompileTimeOnly:
@@ -461,6 +422,7 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInstOwned)
assert(typ.kind == tyProc)
assert(typ.len == typ.n.len)
var params = newRopeAppender()
genParams(p, ri, typ, params)
@@ -483,6 +445,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInstOwned)
assert(typ.kind == tyProc)
assert(typ.len == typ.n.len)
var pl = newRopeAppender()
genParams(p, ri, typ, pl)
@@ -495,14 +458,14 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
let rawProc = getClosureType(p.module, typ, clHalf)
let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri[0])
if typ.returnType != nil:
if typ[0] != nil:
if isInvalidReturnType(p.config, typ):
if ri.len > 1: pl.add(", ")
# beware of 'result = p(result)'. We may need to allocate a temporary:
if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri):
# Great, we can use 'd':
if d.k == locNone:
d = getTemp(p, typ.returnType, needsInit=true)
d = getTemp(p, typ[0], needsInit=true)
elif d.k notin {locTemp} and not hasNoInit(ri):
# reset before pass as 'result' var:
discard "resetLoc(p, d)"
@@ -510,13 +473,13 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
genCallPattern()
if canRaise: raiseExit(p)
else:
var tmp: TLoc = getTemp(p, typ.returnType, needsInit=true)
var tmp: TLoc = getTemp(p, typ[0], needsInit=true)
pl.add(addrLoc(p.config, tmp))
genCallPattern()
if canRaise: raiseExit(p)
genAssignment(p, d, tmp, {}) # no need for deep copying
elif isHarmlessStore(p, canRaise, d):
if d.k == locNone: d = getTemp(p, typ.returnType)
if d.k == locNone: d = getTemp(p, typ[0])
assert(d.t != nil) # generate an assignment to d:
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
if tfIterator in typ.flags:
@@ -526,7 +489,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
genAssignment(p, d, list, {}) # no need for deep copying
if canRaise: raiseExit(p)
else:
var tmp: TLoc = getTemp(p, typ.returnType)
var tmp: TLoc = getTemp(p, typ[0])
assert(d.t != nil) # generate an assignment to d:
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
if tfIterator in typ.flags:
@@ -542,14 +505,14 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope;
argsCounter: var int) =
if i < typ.n.len:
if i < typ.len:
# 'var T' is 'T&' in C++. This means we ignore the request of
# any nkHiddenAddr when it's a 'var T'.
let paramType = typ.n[i]
assert(paramType.kind == nkSym)
if paramType.typ.isCompileTimeOnly:
discard
elif paramType.typ.kind in {tyVar} and ri[i].kind == nkHiddenAddr:
elif typ[i].kind in {tyVar} and ri[i].kind == nkHiddenAddr:
if argsCounter > 0: result.add ", "
genArgNoParam(p, ri[i][0], result)
inc argsCounter
@@ -624,7 +587,7 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope) =
# for better or worse c2nim translates the 'this' argument to a 'var T'.
# However manual wrappers may also use 'ptr T'. In any case we support both
# for convenience.
internalAssert p.config, i < typ.n.len
internalAssert p.config, i < typ.len
assert(typ.n[i].kind == nkSym)
# if the parameter is lying (tyVar) and thus we required an additional deref,
# skip the deref:
@@ -714,6 +677,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInst)
assert(typ.kind == tyProc)
assert(typ.len == typ.n.len)
# don't call '$' here for efficiency:
let pat = $ri[0].sym.loc.r
internalAssert p.config, pat.len > 0
@@ -722,7 +686,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
genPatternCall(p, ri, pat, typ, pl)
# simpler version of 'fixupCall' that works with the pl+params combination:
var typ = skipTypes(ri[0].typ, abstractInst)
if typ.returnType != nil:
if typ[0] != nil:
if p.module.compileToCpp and lfSingleUse in d.flags:
# do not generate spurious temporaries for C++! For C we're better off
# with them to prevent undefined behaviour and because the codegen
@@ -731,7 +695,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
d.r = pl
excl d.flags, lfSingleUse
else:
if d.k == locNone: d = getTemp(p, typ.returnType)
if d.k == locNone: d = getTemp(p, typ[0])
assert(d.t != nil) # generate an assignment to d:
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
list.r = pl
@@ -747,6 +711,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
pl.add(op.r)
var params = newRopeAppender()
for i in 2..<ri.len:
assert(typ.len == typ.n.len)
genOtherArg(p, ri, i, typ, params, argsCounter)
fixupCall(p, le, ri, d, pl, params)
@@ -757,6 +722,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInst)
assert(typ.kind == tyProc)
assert(typ.len == typ.n.len)
# don't call '$' here for efficiency:
let pat = $ri[0].sym.loc.r
@@ -778,7 +744,8 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
pl.add(": ")
genArg(p, ri[2], typ.n[2].sym, ri, pl)
for i in start..<ri.len:
if i >= typ.n.len:
assert(typ.len == typ.n.len)
if i >= typ.len:
internalError(p.config, ri.info, "varargs for objective C method?")
assert(typ.n[i].kind == nkSym)
var param = typ.n[i].sym
@@ -786,26 +753,26 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
pl.add(param.name.s)
pl.add(": ")
genArg(p, ri[i], param, ri, pl)
if typ.returnType != nil:
if typ[0] != nil:
if isInvalidReturnType(p.config, typ):
if ri.len > 1: pl.add(" ")
# beware of 'result = p(result)'. We always allocate a temporary:
if d.k in {locTemp, locNone}:
# We already got a temp. Great, special case it:
if d.k == locNone: d = getTemp(p, typ.returnType, needsInit=true)
if d.k == locNone: d = getTemp(p, typ[0], needsInit=true)
pl.add("Result: ")
pl.add(addrLoc(p.config, d))
pl.add("];\n")
line(p, cpsStmts, pl)
else:
var tmp: TLoc = getTemp(p, typ.returnType, needsInit=true)
var tmp: TLoc = getTemp(p, typ[0], needsInit=true)
pl.add(addrLoc(p.config, tmp))
pl.add("];\n")
line(p, cpsStmts, pl)
genAssignment(p, d, tmp, {}) # no need for deep copying
else:
pl.add("]")
if d.k == locNone: d = getTemp(p, typ.returnType)
if d.k == locNone: d = getTemp(p, typ[0])
assert(d.t != nil) # generate an assignment to d:
var list: TLoc = initLoc(locCall, ri, OnUnknown)
list.r = pl

View File

@@ -221,11 +221,10 @@ proc asgnComplexity(n: PNode): int =
proc optAsgnLoc(a: TLoc, t: PType, field: Rope): TLoc =
assert field != ""
result = TLoc(k: locField,
storage: a.storage,
lode: lodeTyp t,
r: rdLoc(a) & "." & field
)
result.k = locField
result.storage = a.storage
result.lode = lodeTyp t
result.r = rdLoc(a) & "." & field
proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
let newflags =
@@ -236,7 +235,8 @@ proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
else:
flags
let t = skipTypes(dest.t, abstractInst).getUniqueType()
for i, t in t.ikids:
for i in 0..<t.len:
let t = t[i]
let field = "Field$1" % [i.rope]
genAssignment(p, optAsgnLoc(dest, t, field),
optAsgnLoc(src, t, field), newflags)
@@ -285,22 +285,15 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
linefmt(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n",
[addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfoV1(p.module, dest.t, dest.lode.info)])
proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc; flags: TAssignmentFlags) =
proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc) =
assert d.k != locNone
# getTemp(p, d.t, d)
case a.t.skipTypes(abstractVar).kind
of tyOpenArray, tyVarargs:
if reifiedOpenArray(a.lode):
if needTempForOpenArray in flags:
var tmp: TLoc = getTemp(p, a.t)
linefmt(p, cpsStmts, "$2 = $1; $n",
[a.rdLoc, tmp.rdLoc])
linefmt(p, cpsStmts, "$1.Field0 = $2.Field0; $1.Field1 = $2.Field1;$n",
[rdLoc(d), tmp.rdLoc])
else:
linefmt(p, cpsStmts, "$1.Field0 = $2.Field0; $1.Field1 = $2.Field1;$n",
[rdLoc(d), a.rdLoc])
linefmt(p, cpsStmts, "$1.Field0 = $2.Field0; $1.Field1 = $2.Field1;$n",
[rdLoc(d), a.rdLoc])
else:
linefmt(p, cpsStmts, "$1.Field0 = $2; $1.Field1 = $2Len_0;$n",
[rdLoc(d), a.rdLoc])
@@ -316,7 +309,7 @@ proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc; flags: TAssignmentFlags) =
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
linefmt(p, cpsStmts, "$1.Field0 = ($5) ? ($2$3) : NIM_NIL; $1.Field1 = $4;$n",
[rdLoc(d), a.rdLoc, dataField(p), lenExpr(p, a), dataFieldAccessor(p, a.rdLoc)])
[rdLoc(d), a.rdLoc, dataField(p, isString = true), lenExpr(p, a, isString = true), dataFieldAccessor(p, a.rdLoc)])
else:
internalError(p.config, a.lode.info, "cannot handle " & $a.t.kind)
@@ -368,7 +361,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
of tyTuple:
if containsGarbageCollectedRef(dest.t):
if dest.t.kidsLen <= 4: genOptAsgnTuple(p, dest, src, flags)
if dest.t.len <= 4: genOptAsgnTuple(p, dest, src, flags)
else: genGenericAsgn(p, dest, src, flags)
else:
linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
@@ -398,7 +391,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
# open arrays are always on the stack - really? What if a sequence is
# passed to an open array?
if reifiedOpenArray(dest.lode):
genOpenArrayConv(p, dest, src, flags)
genOpenArrayConv(p, dest, src)
elif containsGarbageCollectedRef(dest.t):
linefmt(p, cpsStmts, # XXX: is this correct for arrays?
"#genericAssignOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n",
@@ -611,7 +604,7 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
if t.kind == tyInt64: prc64[m] else: prc[m])
putIntoDest(p, d, e, "($#)($#)" % [getTypeDesc(p.module, e.typ), res])
else:
let res = "($1)(($2) $3 ($4))" % [getTypeDesc(p.module, e.typ), rdLoc(a), rope(opr[m]), rdLoc(b)]
let res = "($1)($2 $3 $4)" % [getTypeDesc(p.module, e.typ), rdLoc(a), rope(opr[m]), rdLoc(b)]
putIntoDest(p, d, e, res)
proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
@@ -755,7 +748,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) =
var a: TLoc
var typ = e[0].typ
if typ.kind in {tyUserTypeClass, tyUserTypeClassInst} and typ.isResolvedUserTypeClass:
typ = typ.last
typ = typ.lastSon
typ = typ.skipTypes(abstractInstOwned)
if typ.kind in {tyVar} and tfVarIsPtr notin typ.flags and p.module.compileToCpp and e[0].kind == nkHiddenAddr:
d = initLocExprSingleUse(p, e[0][0])
@@ -860,7 +853,7 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
var a: TLoc = default(TLoc)
if p.module.compileToCpp and e.kind == nkDotExpr and e[1].kind == nkSym and e[1].typ.kind == tyPtr:
# special case for C++: we need to pull the type of the field as member and friends require the complete type.
let typ = e[1].typ.elementType
let typ = e[1].typ[0]
if typ.itemId in p.module.g.graph.memberProcsPerType:
discard getTypeDesc(p.module, typ)
@@ -1053,7 +1046,7 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) =
linefmt(p, cpsStmts,
"if ($2-$1 != -1 && " &
"($1 < 0 || $1 >= $3 || $2 < 0 || $2 >= $3)){ #raiseIndexError4($1, $2, $3); ",
[rdLoc(a), rdLoc(b), lenExpr(p, arr)])
[rdLoc(a), rdLoc(b), lenExpr(p, arr, ty.kind == tyString)])
raiseInstr(p, p.s(cpsStmts))
linefmt p, cpsStmts, "}$n", []
@@ -1089,12 +1082,11 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) =
var b = initLocExpr(p, y)
var ty = skipTypes(a.t, abstractVarRange)
if ty.kind in {tyRef, tyPtr}:
ty = skipTypes(ty.elementType, abstractVarRange)
# emit range check:
ty = skipTypes(ty.lastSon, abstractVarRange) # emit range check:
if optBoundsCheck in p.options:
linefmt(p, cpsStmts,
"if ($1 < 0 || $1 >= $2){ #raiseIndexError2($1,$2-1); ",
[rdCharLoc(b), lenExpr(p, a)])
[rdCharLoc(b), lenExpr(p, a, ty.kind == tyString)])
raiseInstr(p, p.s(cpsStmts))
linefmt p, cpsStmts, "}$n", []
@@ -1106,11 +1098,11 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) =
optSeqDestructors in p.config.globalOptions:
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
putIntoDest(p, d, n,
ropecg(p.module, "$1$3[$2]", [rdLoc(a), rdCharLoc(b), dataField(p)]), a.storage)
ropecg(p.module, "$1$3[$2]", [rdLoc(a), rdCharLoc(b), dataField(p, ty.kind == tyString)]), a.storage)
proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) =
var ty = skipTypes(n[0].typ, abstractVarRange + tyUserTypeClasses)
if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.elementType, abstractVarRange)
if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange)
case ty.kind
of tyUncheckedArray: genUncheckedArrayElem(p, n, n[0], n[1], d)
of tyArray: genArrayElem(p, n, n[0], n[1], d)
@@ -1207,6 +1199,7 @@ proc genEcho(p: BProc, n: PNode) =
a = initLocExpr(p, it)
if i > 0:
args.add(", ")
## TODO: fixme nimseqsv3 needs to be treated as well
case detectStrVersion(p.module)
of 2:
args.add(ropecg(p.module, "Genode::Cstring($1.p->data, $1.len)", [a.rdLoc]))
@@ -1268,7 +1261,7 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
if e[i + 1].kind in {nkStrLit..nkTripleStrLit}:
inc(L, e[i + 1].strVal.len)
else:
lens.add(lenExpr(p, a))
lens.add(lenExpr(p, a, isString = true))
lens.add(" + ")
appends.add(ropecg(p.module, "#appendString($1, $2);$n", [strLoc(p, tmp), rdLoc(a)]))
linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", [tmp.r, lens, L])
@@ -1308,7 +1301,7 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
if e[i + 2].kind in {nkStrLit..nkTripleStrLit}:
inc(L, e[i + 2].strVal.len)
else:
lens.add(lenExpr(p, a))
lens.add(lenExpr(p, a, isString = true))
lens.add(" + ")
appends.add(ropecg(p.module, "#appendString($1, $2);$n",
[strLoc(p, dest), rdLoc(a)]))
@@ -1352,6 +1345,14 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
genAssignment(p, dest, b, {needToCopy})
gcUsage(p.config, e)
proc genReset(p: BProc, n: PNode) =
var a: TLoc = initLocExpr(p, n[1])
specializeReset(p, a)
when false:
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
[addrLoc(p.config, a),
genTypeInfoV1(p.module, skipTypes(a.t, {tyVar}), n.info)])
proc genDefault(p: BProc; n: PNode; d: var TLoc) =
if d.k == locNone: d = getTemp(p, n.typ, needsInit=true)
else: resetLoc(p, d)
@@ -1362,7 +1363,7 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) =
var b: TLoc = initLoc(locExpr, a.lode, OnHeap)
let refType = typ.skipTypes(abstractInstOwned)
assert refType.kind == tyRef
let bt = refType.elementType
let bt = refType.lastSon
if sizeExpr == "":
sizeExpr = "sizeof($1)" % [getTypeDesc(p.module, bt)]
@@ -1452,7 +1453,7 @@ proc genNewSeq(p: BProc, e: PNode) =
let seqtype = skipTypes(e[1].typ, abstractVarRange)
linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n",
[a.rdLoc, b.rdLoc,
getTypeDesc(p.module, seqtype.elementType),
getTypeDesc(p.module, seqtype.lastSon),
getSeqPayloadType(p.module, seqtype)])
else:
let lenIsZero = e[2].kind == nkIntLit and e[2].intVal == 0
@@ -1465,7 +1466,7 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
if optSeqDestructors in p.config.globalOptions:
if d.k == locNone: d = getTemp(p, e.typ, needsInit=false)
linefmt(p, cpsStmts, "$1.len = 0; $1.p = ($4*) #newSeqPayloadUninit($2, sizeof($3), NIM_ALIGNOF($3));$n",
[d.rdLoc, a.rdLoc, getTypeDesc(p.module, seqtype.elementType),
[d.rdLoc, a.rdLoc, getTypeDesc(p.module, seqtype.lastSon),
getSeqPayloadType(p.module, seqtype),
])
else:
@@ -1484,13 +1485,9 @@ proc rawConstExpr(p: BProc, n: PNode; d: var TLoc) =
if id == p.module.labels:
# expression not found in the cache:
inc(p.module.labels)
var data = "static NIM_CONST $1 $2 = " % [getTypeDesc(p.module, t), d.r]
# bug #23627; when generating const object fields, it's likely that
# we need to generate type infos for the object, which may be an object with
# custom hooks. We need to generate potential consts in the hooks first.
genBracedInit(p, n, isConst = true, t, data)
data.addf(";$n", [])
p.module.s[cfsData].add data
p.module.s[cfsData].addf("static NIM_CONST $1 $2 = ", [getTypeDesc(p.module, t), d.r])
genBracedInit(p, n, isConst = true, t, p.module.s[cfsData])
p.module.s[cfsData].addf(";$n", [])
proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
if d.k == locNone and n.len > ord(n.kind == nkObjConstr) and n.isDeepConstExpr:
@@ -1501,7 +1498,8 @@ proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
proc genFieldObjConstr(p: BProc; ty: PType; useTemp, isRef: bool; nField, val, check: PNode; d: var TLoc; r: Rope; info: TLineInfo) =
var tmp2 = TLoc(r: r)
var tmp2: TLoc = default(TLoc)
tmp2.r = r
let field = lookupFieldAgain(p, ty, nField.sym, tmp2.r)
if field.loc.r == "": fillObjectFields(p.module, ty)
if field.loc.r == "": internalError(p.config, info, "genFieldObjConstr")
@@ -1516,12 +1514,7 @@ proc genFieldObjConstr(p: BProc; ty: PType; useTemp, isRef: bool; nField, val, c
tmp2.k = d.k
tmp2.storage = if isRef: OnHeap else: d.storage
tmp2.lode = val
if nField.typ.skipTypes(abstractVar).kind in {tyOpenArray, tyVarargs}:
var tmp3 = getTemp(p, val.typ)
expr(p, val, tmp3)
genOpenArrayConv(p, tmp2, tmp3, {})
else:
expr(p, val, tmp2)
expr(p, val, tmp2)
proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
# inheritance in C++ does not allow struct initialization so
@@ -1552,7 +1545,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
r = rdLoc(tmp)
if isRef:
rawGenNew(p, tmp, "", needsInit = nfAllFieldsSet notin e.flags)
t = t.elementType.skipTypes(abstractInstOwned)
t = t.lastSon.skipTypes(abstractInstOwned)
r = "(*$1)" % [r]
gcUsage(p.config, e)
elif needsZeroMem:
@@ -1598,7 +1591,7 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) =
if optSeqDestructors in p.config.globalOptions:
let seqtype = n.typ
linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n",
[rdLoc dest[], lit, getTypeDesc(p.module, seqtype.elementType),
[rdLoc dest[], lit, getTypeDesc(p.module, seqtype.lastSon),
getSeqPayloadType(p.module, seqtype)])
else:
# generate call to newSeq before adding the elements per hand:
@@ -1631,7 +1624,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
if optSeqDestructors in p.config.globalOptions:
let seqtype = n.typ
linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n",
[rdLoc d, L, getTypeDesc(p.module, seqtype.elementType),
[rdLoc d, L, getTypeDesc(p.module, seqtype.lastSon),
getSeqPayloadType(p.module, seqtype)])
else:
var lit = newRopeAppender()
@@ -1673,9 +1666,9 @@ proc genNewFinalize(p: BProc, e: PNode) =
p.module.s[cfsTypeInit3].addf("$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)])
b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", [
getTypeDesc(p.module, refType),
ti, getTypeDesc(p.module, skipTypes(refType.elementType, abstractRange))])
ti, getTypeDesc(p.module, skipTypes(refType.lastSon, abstractRange))])
genAssignment(p, a, b, {}) # set the object type:
bt = skipTypes(refType.elementType, abstractRange)
bt = skipTypes(refType.lastSon, abstractRange)
genObjectInit(p, cpsStmts, bt, a, constructRefObj)
gcUsage(p.config, e)
@@ -1707,12 +1700,12 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
if t.kind notin {tyVar, tyLent}: nilCheck = r
if t.kind notin {tyVar, tyLent} or not p.module.compileToCpp:
r = ropecg(p.module, "(*$1)", [r])
t = skipTypes(t.elementType, typedescInst+{tyOwned})
t = skipTypes(t.lastSon, typedescInst+{tyOwned})
discard getTypeDesc(p.module, t)
if not p.module.compileToCpp:
while t.kind == tyObject and t.baseClass != nil:
while t.kind == tyObject and t[0] != nil:
r.add(".Sup")
t = skipTypes(t.baseClass, skipPtrs)
t = skipTypes(t[0], skipPtrs)
if isObjLackingTypeField(t):
globalError(p.config, x.info,
"no 'of' operator available for pure objects")
@@ -1762,13 +1755,14 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
addrLoc(p.config, a), genTypeInfoV1(p.module, t, e.info)]), a.storage)
of tyOpenArray, tyVarargs:
var b: TLoc = default(TLoc)
case skipTypes(a.t, abstractVarRange).kind
let typKind = skipTypes(a.t, abstractVarRange).kind
case typKind
of tyOpenArray, tyVarargs:
putIntoDest(p, b, e, "$1, $1Len_0" % [rdLoc(a)], a.storage)
of tyString, tySequence:
putIntoDest(p, b, e,
"($4) ? ($1$3) : NIM_NIL, $2" %
[rdLoc(a), lenExpr(p, a), dataField(p), dataFieldAccessor(p, a.rdLoc)],
[rdLoc(a), lenExpr(p, a, typKind == tyString), dataField(p, typKind == tyString), dataFieldAccessor(p, a.rdLoc)],
a.storage)
of tyArray:
putIntoDest(p, b, e,
@@ -1796,13 +1790,13 @@ proc rdMType(p: BProc; a: TLoc; nilCheck: var Rope; result: var Rope; enforceV1
if t.kind notin {tyVar, tyLent}: nilCheck = derefs
if t.kind notin {tyVar, tyLent} or not p.module.compileToCpp:
derefs = "(*$1)" % [derefs]
t = skipTypes(t.elementType, abstractInst)
t = skipTypes(t.lastSon, abstractInst)
result.add derefs
discard getTypeDesc(p.module, t)
if not p.module.compileToCpp:
while t.kind == tyObject and t.baseClass != nil:
while t.kind == tyObject and t[0] != nil:
result.add(".Sup")
t = skipTypes(t.baseClass, skipPtrs)
t = skipTypes(t[0], skipPtrs)
result.add ".m_type"
if optTinyRtti in p.config.globalOptions and enforceV1:
result.add "->typeInfoV1"
@@ -1857,9 +1851,9 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
if optBoundsCheck in p.options:
genBoundsCheck(p, m, b, c)
if op == mHigh:
putIntoDest(p, d, e, ropecg(p.module, "(($2)-($1))", [rdLoc(b), rdLoc(c)]))
putIntoDest(p, d, e, ropecg(p.module, "($2)-($1)", [rdLoc(b), rdLoc(c)]))
else:
putIntoDest(p, d, e, ropecg(p.module, "(($2)-($1)+1)", [rdLoc(b), rdLoc(c)]))
putIntoDest(p, d, e, ropecg(p.module, "($2)-($1)+1", [rdLoc(b), rdLoc(c)]))
else:
if not reifiedOpenArray(a):
if op == mHigh: unaryExpr(p, e, d, "($1Len_0-1)")
@@ -1881,7 +1875,7 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
else: unaryExpr(p, e, d, "#nimCStrLen($1)")
of tyString:
var a: TLoc = initLocExpr(p, e[1])
var x = lenExpr(p, a)
var x = lenExpr(p, a, isString = true)
if op == mHigh: x = "($1-1)" % [x]
putIntoDest(p, d, e, x)
of tySequence:
@@ -2088,7 +2082,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mExcl: binaryStmtInExcl(p, e, d, "$1[(NU)($2)>>3] &= ~(1U<<($2&7U));$n")
of mCard:
var a: TLoc = initLocExpr(p, e[1])
putIntoDest(p, d, e, ropecg(p.module, "#cardSet($1, $2)", [rdCharLoc(a), size]))
putIntoDest(p, d, e, ropecg(p.module, "#cardSet($1, $2)", [addrLoc(p.config, a), size]))
of mLtSet, mLeSet:
i = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt)) # our counter
a = initLocExpr(p, e[1])
@@ -2250,15 +2244,9 @@ proc convStrToCStr(p: BProc, n: PNode, d: var TLoc) =
proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) =
var a: TLoc = initLocExpr(p, n[0])
if p.module.compileToCpp:
# fixes for const qualifier; bug #12703; bug #19588
putIntoDest(p, d, n,
ropecg(p.module, "#cstrToNimstr((NCSTRING) $1)", [rdLoc(a)]),
a.storage)
else:
putIntoDest(p, d, n,
ropecg(p.module, "#cstrToNimstr($1)", [rdLoc(a)]),
a.storage)
putIntoDest(p, d, n,
ropecg(p.module, "#cstrToNimstr($1)", [rdLoc(a)]),
a.storage)
gcUsage(p.config, n)
proc genStrEquals(p: BProc, e: PNode, d: var TLoc) =
@@ -2268,11 +2256,11 @@ proc genStrEquals(p: BProc, e: PNode, d: var TLoc) =
if a.kind in {nkStrLit..nkTripleStrLit} and a.strVal == "":
x = initLocExpr(p, e[2])
putIntoDest(p, d, e,
ropecg(p.module, "($1 == 0)", [lenExpr(p, x)]))
ropecg(p.module, "($1 == 0)", [lenExpr(p, x, isString = true)]))
elif b.kind in {nkStrLit..nkTripleStrLit} and b.strVal == "":
x = initLocExpr(p, e[1])
putIntoDest(p, d, e,
ropecg(p.module, "($1 == 0)", [lenExpr(p, x)]))
ropecg(p.module, "($1 == 0)", [lenExpr(p, x, isString = true)]))
else:
binaryExpr(p, e, d, "#eqStrings($1, $2)")
@@ -2317,7 +2305,11 @@ proc genMove(p: BProc; n: PNode; d: var TLoc) =
var src: TLoc = initLocExpr(p, n[2])
linefmt(p, cpsStmts, "if ($1.p != $2.p) {", [rdLoc(a), rdLoc(src)])
genStmts(p, n[3])
linefmt(p, cpsStmts, "}$n$1.len = $2.len; $1.p = $2.p;$n", [rdLoc(a), rdLoc(src)])
let typkind = skipTypes(a.t, abstractVar+{tyStatic}).kind
if typkind == tyString and p.config.isDefined("nimSeqsV3"):
linefmt(p, cpsStmts, "}$n$1.rawlen = $2.rawlen; $1.p = $2.p;$n", [rdLoc(a), rdLoc(src)])
else:
linefmt(p, cpsStmts, "}$n$1.len = $2.len; $1.p = $2.p;$n", [rdLoc(a), rdLoc(src)])
else:
if d.k == locNone: d = getTemp(p, n.typ)
if p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
@@ -2356,20 +2348,24 @@ proc genDestroy(p: BProc; n: PNode) =
case t.kind
of tyString:
var a: TLoc = initLocExpr(p, arg)
if optThreads in p.config.globalOptions:
linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" &
" #deallocShared($1.p);$n" &
"}$n", [rdLoc(a)])
if p.config.isDefined("nimSeqsV3"):
linefmt(p, cpsStmts, "#nimDestroyStrV1($1);$n",
[rdLoc(a)])
else:
linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" &
" #dealloc($1.p);$n" &
"}$n", [rdLoc(a)])
if optThreads in p.config.globalOptions:
linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" &
" #deallocShared($1.p);$n" &
"}$n", [rdLoc(a)])
else:
linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" &
" #dealloc($1.p);$n" &
"}$n", [rdLoc(a)])
of tySequence:
var a: TLoc = initLocExpr(p, arg)
linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" &
" #alignedDealloc($1.p, NIM_ALIGNOF($2));$n" &
"}$n",
[rdLoc(a), getTypeDesc(p.module, t.elementType)])
[rdLoc(a), getTypeDesc(p.module, t.lastSon)])
else: discard "nothing to do"
else:
let t = n[1].typ.skipTypes(abstractVar)
@@ -2380,7 +2376,7 @@ proc genDestroy(p: BProc; n: PNode) =
proc genDispose(p: BProc; n: PNode) =
when false:
let elemType = n[1].typ.skipTypes(abstractVar).elementType
let elemType = n[1].typ.skipTypes(abstractVar).lastSon
var a: TLoc = initLocExpr(p, n[1].skipAddr)
@@ -2395,7 +2391,7 @@ proc genDispose(p: BProc; n: PNode) =
lineCg(p, cpsStmts, ["#nimDestroyAndDispose($#)", rdLoc(a)])
proc genSlice(p: BProc; e: PNode; d: var TLoc) =
let (x, y) = genOpenArraySlice(p, e, e.typ, e.typ.elementType,
let (x, y) = genOpenArraySlice(p, e, e.typ, e.typ.lastSon,
prepareForMutation = e[1].kind == nkHiddenDeref and
e[1].typ.skipTypes(abstractInst).kind == tyString and
p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc})
@@ -2467,14 +2463,16 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mLeStr: binaryExpr(p, e, d, "(#cmpStrings($1, $2) <= 0)")
of mLtStr: binaryExpr(p, e, d, "(#cmpStrings($1, $2) < 0)")
of mIsNil: genIsNil(p, e, d)
of mIntToStr: genDollar(p, e, d, "#nimIntToStr($1)")
of mInt64ToStr: genDollar(p, e, d, "#nimInt64ToStr($1)")
of mBoolToStr: genDollar(p, e, d, "#nimBoolToStr($1)")
of mCharToStr: genDollar(p, e, d, "#nimCharToStr($1)")
of mCStrToStr:
if p.module.compileToCpp:
# fixes for const qualifier; bug #12703; bug #19588
genDollar(p, e, d, "#cstrToNimstr((NCSTRING) $1)")
of mFloatToStr:
if e[1].typ.skipTypes(abstractInst).kind == tyFloat32:
genDollar(p, e, d, "#nimFloat32ToStr($1)")
else:
genDollar(p, e, d, "#cstrToNimstr($1)")
genDollar(p, e, d, "#nimFloatToStr($1)")
of mCStrToStr: genDollar(p, e, d, "#cstrToNimstr($1)")
of mStrToStr, mUnown: expr(p, e[1], d)
of generatedMagics: genCall(p, e, d)
of mEnumToStr:
@@ -2562,6 +2560,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
[mangleDynLibProc(prc), getTypeDesc(p.module, prc.loc.t), getModuleDllPath(p.module, prc)])
genCall(p, e, d)
of mDefault, mZeroDefault: genDefault(p, e, d)
of mReset: genReset(p, e)
of mEcho: genEcho(p, e[1].skipConv)
of mArrToSeq: genArrToSeq(p, e, d)
of mNLen..mNError, mSlurp..mQuoteAst:
@@ -2597,8 +2596,6 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mTrace: discard "no code to generate"
of mEnsureMove:
expr(p, e[1], d)
of mDup:
expr(p, e[1], d)
else:
when defined(debugMagics):
echo p.prc.name.s, " ", p.prc.id, " ", p.prc.flags, " ", p.prc.ast[genericParamsPos].kind
@@ -3204,17 +3201,17 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo; result: var Rope) =
result.add "}"
of tyTuple:
result.add "{"
if p.vccAndC and t.isEmptyTupleType:
if p.vccAndC and t.len == 0:
result.add "0"
for i, a in t.ikids:
for i in 0..<t.len:
if i > 0: result.add ", "
getDefaultValue(p, a, info, result)
getDefaultValue(p, t[i], info, result)
result.add "}"
of tyArray:
result.add "{"
for i in 0..<toInt(lengthOrd(p.config, t.indexType)):
for i in 0..<toInt(lengthOrd(p.config, t[0])):
if i > 0: result.add ", "
getDefaultValue(p, t.elementType, info, result)
getDefaultValue(p, t[1], info, result)
result.add "}"
#result = rope"{}"
of tyOpenArray, tyVarargs:
@@ -3239,8 +3236,7 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode,
getNullValueAux(p, t, it, constOrNil, result, count, isConst, info)
of nkRecCase:
getNullValueAux(p, t, obj[0], constOrNil, result, count, isConst, info)
var res = ""
if count > 0: res.add ", "
if count > 0: result.add ", "
var branch = Zero
if constOrNil != nil:
## find kind value, default is zero if not specified
@@ -3254,21 +3250,18 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode,
break
let selectedBranch = caseObjDefaultBranch(obj, branch)
res.add "{"
result.add "{"
var countB = 0
let b = lastSon(obj[selectedBranch])
# designated initilization is the only way to init non first element of unions
# branches are allowed to have no members (b.len == 0), in this case they don't need initializer
if b.kind == nkRecList and not isEmptyCaseObjectBranch(b):
res.add "._" & mangleRecFieldName(p.module, obj[0].sym) & "_" & $selectedBranch & " = {"
getNullValueAux(p, t, b, constOrNil, res, countB, isConst, info)
res.add "}"
result.add "._" & mangleRecFieldName(p.module, obj[0].sym) & "_" & $selectedBranch & " = {"
getNullValueAux(p, t, b, constOrNil, result, countB, isConst, info)
result.add "}"
elif b.kind == nkSym:
res.add "." & mangleRecFieldName(p.module, b.sym) & " = "
getNullValueAux(p, t, b, constOrNil, res, countB, isConst, info)
else:
return
result.add res
result.add "." & mangleRecFieldName(p.module, b.sym) & " = "
getNullValueAux(p, t, b, constOrNil, result, countB, isConst, info)
result.add "}"
of nkSym:
@@ -3293,7 +3286,7 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode,
proc getNullValueAuxT(p: BProc; orig, t: PType; obj, constOrNil: PNode,
result: var Rope; count: var int;
isConst: bool, info: TLineInfo) =
var base = t.baseClass
var base = t[0]
let oldRes = result
let oldcount = count
if base != nil:
@@ -3325,7 +3318,7 @@ proc genConstObjConstr(p: BProc; n: PNode; isConst: bool; result: var Rope) =
proc genConstSimpleList(p: BProc, n: PNode; isConst: bool; result: var Rope) =
result.add "{"
if p.vccAndC and n.len == 0 and n.typ.kind == tyArray:
getDefaultValue(p, n.typ.elementType, n.info, result)
getDefaultValue(p, n.typ[1], n.info, result)
for i in 0..<n.len:
let it = n[i]
if i > 0: result.add ",\n"
@@ -3442,7 +3435,7 @@ proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType; resul
genConstSimpleList(p, n, isConst, data)
let payload = getTempName(p.module)
let ctype = getTypeDesc(p.module, typ.elementType)
let ctype = getTypeDesc(p.module, typ[0])
let arrLen = n.len
appcg(p.module, cfsStrData,
"static $5 $1 $3[$2] = $4;$n", [
@@ -3454,7 +3447,10 @@ proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType; resul
genConstObjConstr(p, n, isConst, result)
of tyString, tyCstring:
if optSeqDestructors in p.config.globalOptions and n.kind != nkNilLit and ty == tyString:
genStringLiteralV2Const(p.module, n, isConst, result)
if p.config.isDefined("nimSeqsV3"):
genStringLiteralV3Const(p.module, n, isConst, result)
else:
genStringLiteralV2Const(p.module, n, isConst, result)
else:
var d: TLoc = initLocExpr(p, n)
result.add rdLoc(d)

View File

@@ -94,6 +94,48 @@ proc genStringLiteralV2Const(m: BModule; n: PNode; isConst: bool; result: var Ro
pureLit = m.tmpBase & rope(id)
result.addf "{$1, (NimStrPayload*)&$2}", [rope(n.strVal.len), pureLit]
# ------ Version 3: destructor based strings and seqs -----------------------
# strings are enhanced by interned strings
proc toConstLenV3(len: int): string =
result = rope((len shl 1) or 1)
proc genStringLiteralDataOnlyV3(m: BModule, s: string; result: Rope; isConst: bool) =
# TODO: fixme: perhaps use makeCString for clarity for C
m.s[cfsStrData].addf("static $4 NIM_CHAR $1[$2] = $3;$n",
[result, rope(s.len), makeCCharArray(s),
rope(if isConst: "const" else: "")])
proc genStringLiteralV3(m: BModule; n: PNode; isConst: bool; result: var Rope) =
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
if id == m.labels:
let pureLit = getTempName(m)
genStringLiteralDataOnlyV3(m, n.strVal, pureLit, isConst)
let tmp = getTempName(m)
result.add tmp
cgsym(m, "NimStringV3")
# string literal not found in the cache:
m.s[cfsStrData].addf("static $4 NimStringV3 $1 = {$2, (NIM_CHAR*)&$3};$n",
[tmp, toConstLenV3(n.strVal.len), pureLit, rope(if isConst: "const" else: "")])
else:
let tmp = getTempName(m)
result.add tmp
m.s[cfsStrData].addf("static $4 NimStringV3 $1 = {$2, (NIM_CHAR*)&$3};$n",
[tmp, toConstLenV3(n.strVal.len), m.tmpBase & rope(id),
rope(if isConst: "const" else: "")])
proc genStringLiteralV3Const(m: BModule; n: PNode; isConst: bool; result: var Rope) =
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
var pureLit: Rope
if id == m.labels:
pureLit = getTempName(m)
cgsym(m, "NimStringV3")
# string literal not found in the cache:
genStringLiteralDataOnlyV3(m, n.strVal, pureLit, isConst)
else:
pureLit = m.tmpBase & rope(id)
result.addf "{$1, (NIM_CHAR*)&$2}", [toConstLenV3(n.strVal.len), pureLit]
# ------ Version selector ---------------------------------------------------
proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo;
@@ -104,6 +146,10 @@ proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo;
let tmp = getTempName(m)
genStringLiteralDataOnlyV2(m, s, tmp, isConst)
result.add tmp
of 3:
let tmp = getTempName(m)
genStringLiteralDataOnlyV3(m, s, tmp, isConst)
result.add tmp
else:
localError(m.config, info, "cannot determine how to produce code for string literal")
@@ -114,5 +160,6 @@ proc genStringLiteral(m: BModule; n: PNode; result: var Rope) =
case detectStrVersion(m)
of 0, 1: genStringLiteralV1(m, n, result)
of 2: genStringLiteralV2(m, n, isConst = true, result)
of 3: genStringLiteralV3(m, n, isConst = true, result)
else:
localError(m.config, n.info, "cannot determine how to produce code for string literal")

View File

@@ -54,23 +54,24 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
case typ.kind
of tyGenericInst, tyGenericBody, tyTypeDesc, tyAlias, tyDistinct, tyInferred,
tySink, tyOwned:
specializeResetT(p, accessor, skipModifier(typ))
specializeResetT(p, accessor, lastSon(typ))
of tyArray:
let arraySize = lengthOrd(p.config, typ.indexType)
let arraySize = lengthOrd(p.config, typ[0])
var i: TLoc = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt))
linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
[i.r, arraySize])
specializeResetT(p, ropecg(p.module, "$1[$2]", [accessor, i.r]), typ.elementType)
specializeResetT(p, ropecg(p.module, "$1[$2]", [accessor, i.r]), typ[1])
lineF(p, cpsStmts, "}$n", [])
of tyObject:
var x = typ.baseClass
if x != nil: x = x.skipTypes(skipPtrs)
specializeResetT(p, accessor.parentObj(p.module), x)
for i in 0..<typ.len:
var x = typ[i]
if x != nil: x = x.skipTypes(skipPtrs)
specializeResetT(p, accessor.parentObj(p.module), x)
if typ.n != nil: specializeResetN(p, accessor, typ.n, typ)
of tyTuple:
let typ = getUniqueType(typ)
for i, a in typ.ikids:
specializeResetT(p, ropecg(p.module, "$1.Field$2", [accessor, i]), a)
for i in 0..<typ.len:
specializeResetT(p, ropecg(p.module, "$1.Field$2", [accessor, i]), typ[i])
of tyString, tyRef, tySequence:
lineCg(p, cpsStmts, "#unsureAsgnRef((void**)&$1, NIM_NIL);$n", [accessor])
@@ -81,7 +82,7 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
lineCg(p, cpsStmts, "$1.ClP_0 = NIM_NIL;$n", [accessor])
else:
lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor])
of tyChar, tyBool, tyEnum, tyRange, tyInt..tyUInt64:
of tyChar, tyBool, tyEnum, tyInt..tyUInt64:
lineCg(p, cpsStmts, "$1 = 0;$n", [accessor])
of tyCstring, tyPointer, tyPtr, tyVar, tyLent:
lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor])
@@ -95,7 +96,7 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
else:
raiseAssert "unexpected set type kind"
of tyNone, tyEmpty, tyNil, tyUntyped, tyTyped, tyGenericInvocation,
tyGenericParam, tyOrdinal, tyOpenArray, tyForward, tyVarargs,
tyGenericParam, tyOrdinal, tyRange, tyOpenArray, tyForward, tyVarargs,
tyUncheckedArray, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot,
tyAnything, tyStatic, tyFromExpr, tyConcept, tyVoid, tyIterable:

View File

@@ -289,32 +289,22 @@ proc potentialValueInit(p: BProc; v: PSym; value: PNode; result: var Rope) =
#echo "New code produced for ", v.name.s, " ", p.config $ value.info
genBracedInit(p, value, isConst = false, v.typ, result)
proc genCppParamsForCtor(p: BProc; call: PNode; didGenTemp: var bool): string =
proc genCppParamsForCtor(p: BProc; call: PNode): string =
result = ""
var argsCounter = 0
let typ = skipTypes(call[0].typ, abstractInst)
assert(typ.kind == tyProc)
for i in 1..<call.len:
assert(typ.len == typ.n.len)
#if it's a type we can just generate here another initializer as we are in an initializer context
if call[i].kind == nkCall and call[i][0].kind == nkSym and call[i][0].sym.kind == skType:
if argsCounter > 0: result.add ","
result.add genCppInitializer(p.module, p, call[i][0].sym.typ, didGenTemp)
result.add genCppInitializer(p.module, p, call[i][0].sym.typ)
else:
#We need to test for temp in globals, see: #23657
let param =
if typ[i].kind in {tyVar} and call[i].kind == nkHiddenAddr:
call[i][0]
else:
call[i]
if param.kind != nkBracketExpr or param.typ.kind in
{tyRef, tyPtr, tyUncheckedArray, tyArray, tyOpenArray,
tyVarargs, tySequence, tyString, tyCstring, tyTuple}:
let tempLoc = initLocExprSingleUse(p, param)
didGenTemp = didGenTemp or tempLoc.k == locTemp
genOtherArg(p, call, i, typ, result, argsCounter)
proc genCppVarForCtor(p: BProc; call: PNode; decl: var Rope, didGenTemp: var bool) =
let params = genCppParamsForCtor(p, call, didGenTemp)
proc genCppVarForCtor(p: BProc; call: PNode; decl: var Rope) =
let params = genCppParamsForCtor(p, call)
if params.len == 0:
decl = runtimeFormat("$#;\n", [decl])
else:
@@ -341,14 +331,7 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
# v.owner.kind != skModule:
targetProc = p.module.preInitProc
if isCppCtorCall and not containsHiddenPointer(v.typ):
var didGenTemp = false
callGlobalVarCppCtor(targetProc, v, vn, value, didGenTemp)
if didGenTemp:
message(p.config, vn.info, warnGlobalVarConstructorTemporary, vn.sym.name.s)
#We fail to call the constructor in the global scope so we do the call inside the main proc
assignGlobalVar(targetProc, vn, valueAsRope)
var loc = initLocExprSingleUse(targetProc, value)
genAssignment(targetProc, v.loc, loc, {})
callGlobalVarCppCtor(targetProc, v, vn, value)
else:
assignGlobalVar(targetProc, vn, valueAsRope)
@@ -383,15 +366,11 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
var decl = localVarDecl(p, vn)
var tmp: TLoc
if isCppCtorCall:
var didGenTemp = false
genCppVarForCtor(p, value, decl, didGenTemp)
genCppVarForCtor(p, value, decl)
line(p, cpsStmts, decl)
else:
tmp = initLocExprSingleUse(p, value)
if value.kind == nkEmpty:
lineF(p, cpsStmts, "$#;\n", [decl])
else:
lineF(p, cpsStmts, "$# = $#;\n", [decl, tmp.rdLoc])
lineF(p, cpsStmts, "$# = $#;\n", [decl, tmp.rdLoc])
return
assignLocalVar(p, vn)
initLocalVar(p, v, imm)
@@ -755,18 +734,6 @@ proc raiseExit(p: BProc) =
lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) goto LA$1_;$n",
[p.nestedTryStmts[^1].label])
proc raiseExitCleanup(p: BProc, destroy: string) =
assert p.config.exc == excGoto
if nimErrorFlagDisabled notin p.flags:
p.flags.incl nimErrorFlagAccessed
if p.nestedTryStmts.len == 0:
p.flags.incl beforeRetNeeded
# easy case, simply goto 'ret':
lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) {$1; goto BeforeRet_;}$n", [destroy])
else:
lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) {$2; goto LA$1_;}$n",
[p.nestedTryStmts[^1].label, destroy])
proc finallyActions(p: BProc) =
if p.config.exc != excGoto and p.nestedTryStmts.len > 0 and p.nestedTryStmts[^1].inExcept:
# if the current try stmt have a finally block,
@@ -796,14 +763,10 @@ proc genRaiseStmt(p: BProc, t: PNode) =
var e = rdLoc(a)
discard getTypeDesc(p.module, t[0].typ)
var typ = skipTypes(t[0].typ, abstractPtrs)
case p.config.exc
of excCpp:
# XXX For reasons that currently escape me, this is only required by the new
# C++ based exception handling:
if p.config.exc == excCpp:
blockLeaveActions(p, howManyTrys = 0, howManyExcepts = p.inExceptBlockLen)
of excGoto:
blockLeaveActions(p, howManyTrys = 0,
howManyExcepts = (if p.nestedTryStmts.len > 0 and p.nestedTryStmts[^1].inExcept: 1 else: 0))
else:
discard
genLineDir(p, t)
if isImportedException(typ, p.config):
lineF(p, cpsStmts, "throw $1;$n", [e])
@@ -1075,8 +1038,8 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
inc(p.labels, 2)
let etmp = p.labels
#init on locals, fixes #23306
lineCg(p, cpsLocals, "std::exception_ptr T$1_;$n", [etmp])
lineCg(p, cpsStmts, "std::exception_ptr T$1_;$n", [etmp])
let fin = if t[^1].kind == nkFinally: t[^1] else: nil
p.nestedTryStmts.add((fin, false, 0.Natural))
@@ -1526,12 +1489,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) =
var res = ""
let offset =
if isAsmStmt: 1 # first son is pragmas
else: 0
for i in offset..<t.len:
let it = t[i]
for it in t.sons:
case it.kind
of nkStrLit..nkTripleStrLit:
res.add(it.strVal)
@@ -1575,21 +1533,6 @@ proc genAsmStmt(p: BProc, t: PNode) =
assert(t.kind == nkAsmStmt)
genLineDir(p, t)
var s = newRopeAppender()
var asmSyntax = ""
if (let p = t[0]; p.kind == nkPragma):
for i in p:
if whichPragma(i) == wAsmSyntax:
asmSyntax = i[1].strVal
if asmSyntax != "" and
not (
asmSyntax == "gcc" and hasGnuAsm in CC[p.config.cCompiler].props or
asmSyntax == "vcc" and hasGnuAsm notin CC[p.config.cCompiler].props):
localError(
p.config, t.info,
"Your compiler does not support the specified inline assembler")
genAsmOrEmitStmt(p, t, isAsmStmt=true, s)
# see bug #2362, "top level asm statements" seem to be a mis-feature
# but even if we don't do this, the example in #2362 cannot possibly

View File

@@ -71,36 +71,37 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
case typ.kind
of tyGenericInst, tyGenericBody, tyTypeDesc, tyAlias, tyDistinct, tyInferred,
tySink, tyOwned:
genTraverseProc(c, accessor, skipModifier(typ))
genTraverseProc(c, accessor, lastSon(typ))
of tyArray:
let arraySize = lengthOrd(c.p.config, typ.indexType)
let arraySize = lengthOrd(c.p.config, typ[0])
var i: TLoc = getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt))
var oldCode = p.s(cpsStmts)
freeze oldCode
linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
[i.r, arraySize])
let oldLen = p.s(cpsStmts).len
genTraverseProc(c, ropecg(c.p.module, "$1[$2]", [accessor, i.r]), typ.elementType)
genTraverseProc(c, ropecg(c.p.module, "$1[$2]", [accessor, i.r]), typ[1])
if p.s(cpsStmts).len == oldLen:
# do not emit dummy long loops for faster debug builds:
p.s(cpsStmts) = oldCode
else:
lineF(p, cpsStmts, "}$n", [])
of tyObject:
var x = typ.baseClass
if x != nil: x = x.skipTypes(skipPtrs)
genTraverseProc(c, accessor.parentObj(c.p.module), x)
for i in 0..<typ.len:
var x = typ[i]
if x != nil: x = x.skipTypes(skipPtrs)
genTraverseProc(c, accessor.parentObj(c.p.module), x)
if typ.n != nil: genTraverseProc(c, accessor, typ.n, typ)
of tyTuple:
let typ = getUniqueType(typ)
for i, a in typ.ikids:
genTraverseProc(c, ropecg(c.p.module, "$1.Field$2", [accessor, i]), a)
for i in 0..<typ.len:
genTraverseProc(c, ropecg(c.p.module, "$1.Field$2", [accessor, i]), typ[i])
of tyRef:
lineCg(p, cpsStmts, visitorFrmt, [accessor, c.visitorFrmt])
of tySequence:
if optSeqDestructors notin c.p.module.config.globalOptions:
lineCg(p, cpsStmts, visitorFrmt, [accessor, c.visitorFrmt])
elif containsGarbageCollectedRef(typ.elementType):
elif containsGarbageCollectedRef(typ.lastSon):
# destructor based seqs are themselves not traced but their data is, if
# they contain a GC'ed type:
lineCg(p, cpsStmts, "#nimGCvisitSeq((void*)$1, $2);$n", [accessor, c.visitorFrmt])
@@ -117,15 +118,15 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) =
var p = c.p
assert typ.kind == tySequence
var i = getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt))
var i: TLoc = getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt))
var oldCode = p.s(cpsStmts)
freeze oldCode
var a = TLoc(r: accessor)
var a: TLoc = TLoc(r: accessor)
lineF(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
[i.r, lenExpr(c.p, a)])
let oldLen = p.s(cpsStmts).len
genTraverseProc(c, "$1$3[$2]" % [accessor, i.r, dataField(c.p)], typ.elementType)
genTraverseProc(c, "$1$3[$2]" % [accessor, i.r, dataField(c.p)], typ[0])
if p.s(cpsStmts).len == oldLen:
# do not emit dummy long loops for faster debug builds:
p.s(cpsStmts) = oldCode
@@ -133,6 +134,7 @@ proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) =
lineF(p, cpsStmts, "}$n", [])
proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope =
var c: TTraversalClosure
var p = newProc(nil, m)
result = "Marker_" & getTypeName(m, origTyp, sig)
let
@@ -145,19 +147,18 @@ proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope =
lineF(p, cpsLocals, "$1 a;$n", [t])
lineF(p, cpsInit, "a = ($1)p;$n", [t])
var c = TTraversalClosure(p: p,
visitorFrmt: "op" # "#nimGCvisit((void*)$1, op);$n"
)
c.p = p
c.visitorFrmt = "op" # "#nimGCvisit((void*)$1, op);$n"
assert typ.kind != tyTypeDesc
if typ.kind == tySequence:
genTraverseProcSeq(c, "a".rope, typ)
else:
if skipTypes(typ.elementType, typedescInst+{tyOwned}).kind == tyArray:
if skipTypes(typ[0], typedescInst+{tyOwned}).kind == tyArray:
# C's arrays are broken beyond repair:
genTraverseProc(c, "a".rope, typ.elementType)
genTraverseProc(c, "a".rope, typ[0])
else:
genTraverseProc(c, "(*a)".rope, typ.elementType)
genTraverseProc(c, "(*a)".rope, typ[0])
let generatedProc = "$1 {$n$2$3$4}\n" %
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]
@@ -173,6 +174,7 @@ proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope =
proc genTraverseProcForGlobal(m: BModule, s: PSym; info: TLineInfo): Rope =
discard genTypeInfoV1(m, s.loc.t, info)
var c: TTraversalClosure
var p = newProc(nil, m)
var sLoc = rdLoc(s.loc)
result = getTempName(m)
@@ -181,10 +183,8 @@ proc genTraverseProcForGlobal(m: BModule, s: PSym; info: TLineInfo): Rope =
accessThreadLocalVar(p, s)
sLoc = "NimTV_->" & sLoc
var c = TTraversalClosure(p: p,
visitorFrmt: "0" # "#nimGCvisit((void*)$1, 0);$n"
)
c.visitorFrmt = "0" # "#nimGCvisit((void*)$1, 0);$n"
c.p = p
let header = "static N_NIMCALL(void, $1)(void)" % [result]
genTraverseProc(c, sLoc, s.loc.t)

View File

@@ -55,28 +55,13 @@ proc mangleField(m: BModule; name: PIdent): string =
if isKeyword(name):
result.add "_0"
proc mangleProc(m: BModule; s: PSym; makeUnique: bool): string =
result = "_Z" # Common prefix in Itanium ABI
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
result.add encodeType(m, s.typ[i])
if result in m.g.mangledPrcs:
result = mangleProc(m, s, true)
else:
m.g.mangledPrcs.incl(result)
proc fillBackendName(m: BModule; s: PSym) =
if s.loc.r == "":
var result: Rope
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:
result = s.name.s.mangle.rope
result.add mangleProcNameExt(m.g.graph, s)
var result = s.name.s.mangle.rope
result.add "__"
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
result.add "_u"
result.addInt s.itemId.item # s.disamb #
if m.hcrOn:
result.add '_'
result.add(idOrSig(s, m.module.name.s.mangle, m.sigConflicts, m.config))
@@ -86,7 +71,8 @@ proc fillBackendName(m: BModule; s: PSym) =
proc fillParamName(m: BModule; s: PSym) =
if s.loc.r == "":
var res = s.name.s.mangle
res.add mangleParamExt(s)
res.add "_p"
res.addInt s.position
#res.add idOrSig(s, res, m.sigConflicts, m.config)
# Take into account if HCR is on because of the following scenario:
# if a module gets imported and it has some more importc symbols in it,
@@ -150,10 +136,10 @@ proc getTypeName(m: BModule; typ: PType; sig: SigHash): Rope =
return t.sym.loc.r
if t.kind in irrelevantForBackend:
t = t.skipModifier
t = t.lastSon
else:
break
let typ = if typ.kind in {tyAlias, tySink, tyOwned}: typ.elementType else: typ
let typ = if typ.kind in {tyAlias, tySink, tyOwned}: typ.lastSon else: typ
if typ.loc.r == "":
typ.typeName(typ.loc.r)
typ.loc.r.add $sig
@@ -189,10 +175,10 @@ proc mapType(conf: ConfigRef; typ: PType; isParam: bool): TCTypeKind =
of tyObject, tyTuple: result = ctStruct
of tyUserTypeClasses:
doAssert typ.isResolvedUserTypeClass
result = mapType(conf, typ.skipModifier, isParam)
return mapType(conf, typ.lastSon, isParam)
of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal,
tyTypeDesc, tyAlias, tySink, tyInferred, tyOwned:
result = mapType(conf, skipModifier(typ), isParam)
result = mapType(conf, lastSon(typ), isParam)
of tyEnum:
if firstOrd(conf, typ) < 0:
result = ctInt32
@@ -203,9 +189,9 @@ proc mapType(conf: ConfigRef; typ: PType; isParam: bool): TCTypeKind =
of 4: result = ctInt32
of 8: result = ctInt64
else: result = ctInt32
of tyRange: result = mapType(conf, typ.elementType, isParam)
of tyRange: result = mapType(conf, typ[0], isParam)
of tyPtr, tyVar, tyLent, tyRef:
var base = skipTypes(typ.elementType, typedescInst)
var base = skipTypes(typ.lastSon, typedescInst)
case base.kind
of tyOpenArray, tyArray, tyVarargs, tyUncheckedArray: result = ctPtrToArray
of tySet:
@@ -220,7 +206,7 @@ proc mapType(conf: ConfigRef; typ: PType; isParam: bool): TCTypeKind =
of tyInt..tyUInt64:
result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt))
of tyStatic:
if typ.n != nil: result = mapType(conf, typ.skipModifier, isParam)
if typ.n != nil: result = mapType(conf, lastSon typ, isParam)
else:
result = ctVoid
doAssert(false, "mapType: " & $typ.kind)
@@ -245,14 +231,11 @@ proc isImportedCppType(t: PType): bool =
proc isOrHasImportedCppType(typ: PType): bool =
searchTypeFor(typ.skipTypes({tyRef}), isImportedCppType)
proc hasNoInit(t: PType): bool =
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))
(typ[0] == 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
@@ -274,15 +257,9 @@ proc isInvalidReturnType(conf: ConfigRef; typ: PType, isProc = true): bool =
{tyVar, tyLent, tyRef, tyPtr})
of ctStruct:
let t = skipTypes(rettype, typedescInst)
if rettype.isImportedCppType or t.isImportedCppType or
(typ.callConv == ccCDecl and conf.selectedGC in {gcArc, gcAtomicArc, gcOrc}):
# prevents nrvo for cdecl procs; # bug #23401
result = false
else:
result = containsGarbageCollectedRef(t) or
(t.kind == tyObject and not isObjLackingTypeField(t)) or
(getSize(conf, rettype) == szUnknownSize and (t.sym == nil or sfImportc notin t.sym.flags))
if rettype.isImportedCppType or t.isImportedCppType: return false
result = containsGarbageCollectedRef(t) or
(t.kind == tyObject and not isObjLackingTypeField(t))
else: result = false
const
@@ -290,9 +267,7 @@ const
"N_STDCALL", "N_CDECL", "N_SAFECALL",
"N_SYSCALL", # this is probably not correct for all platforms,
# but one can #define it to what one wants
"N_INLINE", "N_NOINLINE", "N_FASTCALL", "N_THISCALL", "N_CLOSURE", "N_NOCONV",
"N_NOCONV" #ccMember is N_NOCONV
]
"N_INLINE", "N_NOINLINE", "N_FASTCALL", "N_THISCALL", "N_CLOSURE", "N_NOCONV"]
proc cacheGetType(tab: TypeCache; sig: SigHash): Rope =
# returns nil if we need to declare this type
@@ -336,6 +311,9 @@ proc getSimpleTypeDesc(m: BModule; typ: PType): Rope =
result = typeNameOrLiteral(m, typ, "void*")
of tyString:
case detectStrVersion(m)
of 3:
cgsym(m, "NimStringV3")
result = typeNameOrLiteral(m, typ, "NimStringV3")
of 2:
cgsym(m, "NimStrPayload")
cgsym(m, "NimStringV2")
@@ -349,14 +327,14 @@ proc getSimpleTypeDesc(m: BModule; typ: PType): Rope =
of tyNil: result = typeNameOrLiteral(m, typ, "void*")
of tyInt..tyUInt64:
result = typeNameOrLiteral(m, typ, NumericalTypeToStr[typ.kind])
of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ.skipModifier)
of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ[0])
of tyStatic:
if typ.n != nil: result = getSimpleTypeDesc(m, skipModifier typ)
if typ.n != nil: result = getSimpleTypeDesc(m, lastSon typ)
else:
result = ""
internalError(m.config, "tyStatic for getSimpleTypeDesc")
of tyGenericInst, tyAlias, tySink, tyOwned:
result = getSimpleTypeDesc(m, skipModifier typ)
result = getSimpleTypeDesc(m, lastSon typ)
else: result = ""
if result != "" and typ.isImportedType():
@@ -377,9 +355,11 @@ proc getTypePre(m: BModule; typ: PType; sig: SigHash): Rope =
if result == "": result = cacheGetType(m.typeCache, sig)
proc structOrUnion(t: PType): Rope =
let cachedUnion = rope("union")
let cachedStruct = rope("struct")
let t = t.skipTypes({tyAlias, tySink})
if tfUnion in t.flags: "union"
else: "struct"
if tfUnion in t.flags: cachedUnion
else: cachedStruct
proc addForwardStructFormat(m: BModule; structOrUnion: Rope, typename: Rope) =
if m.compileToCpp:
@@ -479,8 +459,8 @@ macro unrollChars(x: static openArray[char], name, body: untyped) =
copy body
)))
proc multiFormat*(frmt: var string, chars: static openArray[char], args: openArray[seq[string]]) =
var res: string
proc multiFormat*(frmt: var string, chars : static openArray[char], args: openArray[seq[string]]) =
var res : string
unrollChars(chars, c):
res = ""
let arg = args[find(chars, c)]
@@ -522,16 +502,15 @@ proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, name, params
weakDep=false;) =
let t = prc.typ
let isCtor = sfConstructor in prc.flags
if isCtor or (name[0] == '~' and sfMember in prc.flags):
# destructors can't have void
if isCtor or (name[0] == '~' and sfMember in prc.flags): #destructors cant have void
rettype = ""
elif t.returnType == nil or isInvalidReturnType(m.config, t):
elif t[0] == nil or isInvalidReturnType(m.config, t):
rettype = "void"
else:
if rettype == "":
rettype = getTypeDescAux(m, t.returnType, check, dkResult)
rettype = getTypeDescAux(m, t[0], check, dkResult)
else:
rettype = runtimeFormat(rettype.replace("'0", "$1"), [getTypeDescAux(m, t.returnType, check, dkResult)])
rettype = runtimeFormat(rettype.replace("'0", "$1"), [getTypeDescAux(m, t[0], check, dkResult)])
var types, names, args: seq[string] = @[]
if not isCtor:
var this = t.n[1].sym
@@ -555,11 +534,11 @@ proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, name, params
descKind = dkRefGenericParam
else:
descKind = dkRefParam
var typ, name: string
var typ, name : string
fillParamName(m, param)
fillLoc(param.loc, locParam, t.n[i],
param.paramStorageLoc)
if ccgIntroducedPtr(m.config, param, t.returnType) and descKind == dkParam:
if ccgIntroducedPtr(m.config, param, t[0]) and descKind == dkParam:
typ = getTypeDescWeak(m, param.typ, check, descKind) & "*"
incl(param.loc.flags, lfIndirect)
param.loc.storage = OnUnknown
@@ -597,10 +576,10 @@ proc genProcParams(m: BModule; t: PType, rettype, params: var Rope,
check: var IntSet, declareEnvironment=true;
weakDep=false;) =
params = "("
if t.returnType == nil or isInvalidReturnType(m.config, t):
if t[0] == nil or isInvalidReturnType(m.config, t):
rettype = "void"
else:
rettype = getTypeDescAux(m, t.returnType, check, dkResult)
rettype = getTypeDescAux(m, t[0], check, dkResult)
for i in 1..<t.n.len:
if t.n[i].kind != nkSym: internalError(m.config, t.n.info, "genProcParams")
var param = t.n[i].sym
@@ -616,7 +595,7 @@ proc genProcParams(m: BModule; t: PType, rettype, params: var Rope,
fillLoc(param.loc, locParam, t.n[i],
param.paramStorageLoc)
var typ: Rope
if ccgIntroducedPtr(m.config, param, t.returnType) and descKind == dkParam:
if ccgIntroducedPtr(m.config, param, t[0]) and descKind == dkParam:
typ = (getTypeDescWeak(m, param.typ, check, descKind))
typ.add("*")
incl(param.loc.flags, lfIndirect)
@@ -635,7 +614,7 @@ proc genProcParams(m: BModule; t: PType, rettype, params: var Rope,
params.add runtimeFormat(param.cgDeclFrmt, [typ, param.loc.r])
# declare the len field for open arrays:
var arr = param.typ.skipTypes({tyGenericInst})
if arr.kind in {tyVar, tyLent, tySink}: arr = arr.elementType
if arr.kind in {tyVar, tyLent, tySink}: arr = arr.lastSon
var j = 0
while arr.kind in {tyOpenArray, tyVarargs}:
# this fixes the 'sort' bug:
@@ -644,10 +623,10 @@ proc genProcParams(m: BModule; t: PType, rettype, params: var Rope,
params.addf(", NI $1Len_$2", [param.loc.r, j.rope])
inc(j)
arr = arr[0].skipTypes({tySink})
if t.returnType != nil and isInvalidReturnType(m.config, t):
var arr = t.returnType
if t[0] != nil and isInvalidReturnType(m.config, t):
var arr = t[0]
if params != "(": params.add(", ")
if mapReturnType(m.config, arr) != ctArray:
if mapReturnType(m.config, t[0]) != ctArray:
if isHeaderFile in m.flags:
# still generates types for `--header`
params.add(getTypeDescAux(m, arr, check, dkResult))
@@ -681,9 +660,9 @@ proc hasCppCtor(m: BModule; typ: PType): bool =
if sfConstructor in prc.flags:
return true
proc genCppParamsForCtor(p: BProc; call: PNode; didGenTemp: var bool): string
proc genCppParamsForCtor(p: BProc; call: PNode): string
proc genCppInitializer(m: BModule, prc: BProc; typ: PType; didGenTemp: var bool): string =
proc genCppInitializer(m: BModule, prc: BProc; typ: PType): string =
#To avoid creating a BProc per test when called inside a struct nil BProc is allowed
result = "{}"
if typ.itemId in m.g.graph.initializersPerType:
@@ -692,7 +671,7 @@ proc genCppInitializer(m: BModule, prc: BProc; typ: PType; didGenTemp: var bool)
var p = prc
if p == nil:
p = BProc(module: m)
result = "{" & genCppParamsForCtor(p, call, didGenTemp) & "}"
result = "{" & genCppParamsForCtor(p, call) & "}"
if prc == nil:
assert p.blocks.len == 0, "BProc belongs to a struct doesnt have blocks"
@@ -762,8 +741,7 @@ proc genRecordFieldsAux(m: BModule; n: PNode,
# tyGenericInst for C++ template support
let noInit = sfNoInit in field.flags or (field.typ.sym != nil and sfNoInit in field.typ.sym.flags)
if not noInit and (fieldType.isOrHasImportedCppType() or hasCppCtor(m, field.owner.typ)):
var didGenTemp = false
var initializer = genCppInitializer(m, nil, fieldType, didGenTemp)
var initializer = genCppInitializer(m, nil, fieldType)
result.addf("\t$1$3 $2$4;$n", [getTypeDescAux(m, field.loc.t, check, dkField), sname, noAlias, initializer])
else:
result.addf("\t$1$3 $2;$n", [getTypeDescAux(m, field.loc.t, check, dkField), sname, noAlias])
@@ -787,7 +765,7 @@ proc getRecordFields(m: BModule; typ: PType, check: var IntSet): Rope =
genMemberProcHeader(m, prc, header, false, true)
result.addf "$1;$n", [header]
if isCtorGen and not isDefaultCtorGen:
var ch: IntSet = default(IntSet)
var ch: IntSet
result.addf "$1() = default;$n", [getTypeDescAux(m, typ, ch, dkOther)]
proc fillObjectFields*(m: BModule; typ: PType) =
@@ -802,7 +780,7 @@ proc getRecordDescAux(m: BModule; typ: PType, name, baseType: Rope,
check: var IntSet, hasField:var bool): Rope =
result = ""
if typ.kind == tyObject:
if typ.baseClass == nil:
if typ[0] == nil:
if lacksMTypeField(typ):
appcg(m, result, " {$n", [])
else:
@@ -842,8 +820,8 @@ proc getRecordDesc(m: BModule; typ: PType, name: Rope,
else:
structOrUnion = structOrUnion(typ)
var baseType: string = ""
if typ.baseClass != nil:
baseType = getTypeDescAux(m, typ.baseClass.skipTypes(skipPtrs), check, dkField)
if typ[0] != nil:
baseType = getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check, dkField)
if typ.sym == nil or sfCodegenDecl notin typ.sym.flags:
result = structOrUnion & " " & name
result.add(getRecordDescAux(m, typ, name, baseType, check, hasField))
@@ -851,7 +829,7 @@ proc getRecordDesc(m: BModule; typ: PType, name: Rope,
if not hasField and typ.itemId notin m.g.graph.memberProcsPerType:
if desc == "":
result.add("\tchar dummy;\n")
elif typ.n.len == 1 and typ.n[0].kind == nkSym:
elif typ.len == 1 and typ.n[0].kind == nkSym:
let field = typ.n[0].sym
let fieldType = field.typ.skipTypes(abstractInst)
if fieldType.kind == tyUncheckedArray:
@@ -870,9 +848,9 @@ proc getTupleDesc(m: BModule; typ: PType, name: Rope,
check: var IntSet): Rope =
result = "$1 $2 {$n" % [structOrUnion(typ), name]
var desc: Rope = ""
for i, a in typ.ikids:
for i in 0..<typ.len:
desc.addf("$1 Field$2;$n",
[getTypeDescAux(m, a, check, dkField), rope(i)])
[getTypeDescAux(m, typ[i], check, dkField), rope(i)])
if desc == "": result.add("char dummy;\L")
else: result.add(desc)
result.add("};\L")
@@ -897,25 +875,25 @@ proc scanCppGenericSlot(pat: string, cursor, outIdx, outStars: var int): bool =
proc resolveStarsInCppType(typ: PType, idx, stars: int): PType =
# Make sure the index refers to one of the generic params of the type.
# XXX: we should catch this earlier and report it as a semantic error.
if idx >= typ.kidsLen:
if idx >= typ.len:
raiseAssert "invalid apostrophe type parameter index"
result = typ[idx]
for i in 1..stars:
if result != nil and result.kidsLen > 0:
result = if result.kind == tyGenericInst: result[FirstGenericParamAt]
if result != nil and result.len > 0:
result = if result.kind == tyGenericInst: result[1]
else: result.elemType
proc getOpenArrayDesc(m: BModule; t: PType, check: var IntSet; kind: TypeDescKind): Rope =
let sig = hashType(t, m.config)
if kind == dkParam:
result = getTypeDescWeak(m, t.elementType, check, kind) & "*"
result = getTypeDescWeak(m, t[0], check, kind) & "*"
else:
result = cacheGetType(m.typeCache, sig)
if result == "":
result = getTypeName(m, t, sig)
m.typeCache[sig] = result
let elemType = getTypeDescWeak(m, t.elementType, check, kind)
let elemType = getTypeDescWeak(m, t[0], check, kind)
m.s[cfsTypes].addf("typedef struct {$n$2* Field0;$nNI Field1;$n} $1;$n",
[result, elemType])
@@ -947,7 +925,7 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
of tyRef, tyPtr, tyVar, tyLent:
var star = if t.kind in {tyVar} and tfVarIsPtr notin origTyp.flags and
compileToCpp(m): "&" else: "*"
var et = origTyp.skipTypes(abstractInst).elementType
var et = origTyp.skipTypes(abstractInst).lastSon
var etB = et.skipTypes(abstractInst)
if mapType(m.config, t, kind == dkParam) == ctPtrToArray and (etB.kind != tyOpenArray or kind == dkParam):
if etB.kind == tySet:
@@ -1039,7 +1017,7 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
assert(cacheGetType(m.typeCache, sig) == "")
m.typeCache[sig] = result & seqStar(m)
if not isImportedType(t):
if skipTypes(t.elementType, typedescInst).kind != tyEmpty:
if skipTypes(t[0], typedescInst).kind != tyEmpty:
const
cppSeq = "struct $2 : #TGenericSeq {$n"
cSeq = "struct $2 {$n" &
@@ -1047,11 +1025,11 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
if m.compileToCpp:
appcg(m, m.s[cfsSeqTypes],
cppSeq & " $1 data[SEQ_DECL_SIZE];$n" &
"};$n", [getTypeDescAux(m, t.elementType, check, kind), result])
"};$n", [getTypeDescAux(m, t[0], check, kind), result])
else:
appcg(m, m.s[cfsSeqTypes],
cSeq & " $1 data[SEQ_DECL_SIZE];$n" &
"};$n", [getTypeDescAux(m, t.elementType, check, kind), result])
"};$n", [getTypeDescAux(m, t[0], check, kind), result])
else:
result = rope("TGenericSeq")
result.add(seqStar(m))
@@ -1059,7 +1037,7 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
result = getTypeName(m, origTyp, sig)
m.typeCache[sig] = result
if not isImportedType(t):
let foo = getTypeDescAux(m, t.elementType, check, kind)
let foo = getTypeDescAux(m, t[0], check, kind)
m.s[cfsTypes].addf("typedef $1 $2[1];$n", [foo, result])
of tyArray:
var n: BiggestInt = toInt64(lengthOrd(m.config, t))
@@ -1067,9 +1045,9 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
result = getTypeName(m, origTyp, sig)
m.typeCache[sig] = result
if not isImportedType(t):
let e = getTypeDescAux(m, t.elementType, check, kind)
let foo = getTypeDescAux(m, t[1], check, kind)
m.s[cfsTypes].addf("typedef $1 $2[$3];$n",
[e, result, rope(n)])
[foo, result, rope(n)])
of tyObject, tyTuple:
let tt = origTyp.skipTypes({tyDistinct})
if isImportedCppType(t) and tt.kind == tyGenericInst:
@@ -1104,9 +1082,9 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
result.add cppName.substr(chunkStart)
else:
result = cppNameAsRope & "<"
for needsComma, a in tt.genericInstParams:
if needsComma: result.add(" COMMA ")
addResultType(a)
for i in 1..<tt.len-1:
if i > 1: result.add(" COMMA ")
addResultType(tt[i])
result.add("> ")
# always call for sideeffects:
assert t.kind != tyTuple
@@ -1137,8 +1115,8 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
of tySet:
# Don't use the imported name as it may be scoped: 'Foo::SomeKind'
result = rope("tySet_")
t.elementType.typeName(result)
result.add $t.elementType.hashType(m.config)
t.lastSon.typeName(result)
result.add $t.lastSon.hashType(m.config)
m.typeCache[sig] = result
if not isImportedType(t):
let s = int(getSize(m.config, t))
@@ -1148,7 +1126,7 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
[result, rope(getSize(m.config, t))])
of tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias, tySink, tyOwned,
tyUserTypeClass, tyUserTypeClassInst, tyInferred:
result = getTypeDescAux(m, skipModifier(t), check, kind)
result = getTypeDescAux(m, lastSon(t), check, kind)
else:
internalError(m.config, "getTypeDescAux(" & $t.kind & ')')
result = ""
@@ -1200,15 +1178,12 @@ proc isReloadable(m: BModule; prc: PSym): bool =
proc isNonReloadable(m: BModule; prc: PSym): bool =
return m.hcrOn and sfNonReloadable in prc.flags
proc parseVFunctionDecl(val: string; name, params, retType, superCall: var string; isFnConst, isOverride, isMemberVirtual, isStatic: var bool; isCtor: bool, isFunctor=false) =
proc parseVFunctionDecl(val: string; name, params, retType, superCall: var string; isFnConst, isOverride, isMemberVirtual: var bool; isCtor: bool, isFunctor=false) =
var afterParams: string = ""
if scanf(val, "$*($*)$s$*", name, params, afterParams):
if name.strip() == "operator" and params == "": #isFunctor?
parseVFunctionDecl(afterParams, name, params, retType, superCall, isFnConst, isOverride, isMemberVirtual, isStatic, isCtor, true)
parseVFunctionDecl(afterParams, name, params, retType, superCall, isFnConst, isOverride, isMemberVirtual, isCtor, true)
return
if name.find("static ") > -1:
isStatic = true
name = name.replace("static ", "")
isFnConst = afterParams.find("const") > -1
isOverride = afterParams.find("override") > -1
isMemberVirtual = name.find("virtual ") > -1
@@ -1223,7 +1198,7 @@ proc parseVFunctionDecl(val: string; name, params, retType, superCall: var strin
params = "(" & params & ")"
proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false, isFwdDecl: bool = false) =
proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false, isFwdDecl : bool = false) =
assert sfCppMember * prc.flags != {}
let isCtor = sfConstructor in prc.flags
var check = initIntSet()
@@ -1232,17 +1207,17 @@ proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool =
var memberOp = "#." #only virtual
var typ: PType
if isCtor:
typ = prc.typ.returnType
typ = prc.typ[0]
else:
typ = prc.typ.firstParamType
typ = prc.typ[1]
if typ.kind == tyPtr:
typ = typ.elementType
typ = typ[0]
memberOp = "#->"
var typDesc = getTypeDescWeak(m, typ, check, dkParam)
let asPtrStr = rope(if asPtr: "_PTR" else: "")
var name, params, rettype, superCall: string = ""
var isFnConst, isOverride, isMemberVirtual, isStatic: bool = false
parseVFunctionDecl(prc.constraint.strVal, name, params, rettype, superCall, isFnConst, isOverride, isMemberVirtual, isStatic, isCtor)
var isFnConst, isOverride, isMemberVirtual: bool = false
parseVFunctionDecl(prc.constraint.strVal, name, params, rettype, superCall, isFnConst, isOverride, isMemberVirtual, isCtor)
genMemberProcParams(m, prc, superCall, rettype, name, params, check, true, false)
let isVirtual = sfVirtual in prc.flags or isMemberVirtual
var fnConst, override: string = ""
@@ -1251,8 +1226,6 @@ proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool =
if isFnConst:
fnConst = " const"
if isFwdDecl:
if isStatic:
result.add "static "
if isVirtual:
rettype = "virtual " & rettype
if isOverride:
@@ -1363,8 +1336,8 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType;
proc genTypeInfoAux(m: BModule; typ, origType: PType, name: Rope;
info: TLineInfo) =
var base: Rope
if typ.hasElementType and typ.last != nil:
var x = typ.last
if typ.len > 0 and typ.lastSon != nil:
var x = typ.lastSon
if typ.kind == tyObject: x = x.skipTypes(skipPtrs)
if typ.kind == tyPtr and x.kind == tyObject and incompleteType(x):
base = rope("0")
@@ -1469,28 +1442,31 @@ proc genObjectFields(m: BModule; typ, origType: PType, n: PNode, expr: Rope;
else: internalError(m.config, n.info, "genObjectFields")
proc genObjectInfo(m: BModule; typ, origType: PType, name: Rope; info: TLineInfo) =
assert typ.kind == tyObject
if incompleteType(typ):
localError(m.config, info, "request for RTTI generation for incomplete object: " &
typeToString(typ))
genTypeInfoAux(m, typ, origType, name, info)
if typ.kind == tyObject:
if incompleteType(typ):
localError(m.config, info, "request for RTTI generation for incomplete object: " &
typeToString(typ))
genTypeInfoAux(m, typ, origType, name, info)
else:
genTypeInfoAuxBase(m, typ, origType, name, rope("0"), info)
var tmp = getNimNode(m)
if not isImportedType(typ):
genObjectFields(m, typ, origType, typ.n, tmp, info)
m.s[cfsTypeInit3].addf("$1.node = &$2;$n", [tiNameForHcr(m, name), tmp])
var t = typ.baseClass
var t = typ[0]
while t != nil:
t = t.skipTypes(skipPtrs)
t.flags.incl tfObjHasKids
t = t.baseClass
t = t[0]
proc genTupleInfo(m: BModule; typ, origType: PType, name: Rope; info: TLineInfo) =
genTypeInfoAuxBase(m, typ, typ, name, rope("0"), info)
var expr = getNimNode(m)
if not typ.isEmptyTupleType:
var tmp = getTempName(m) & "_" & $typ.kidsLen
genTNimNodeArray(m, tmp, rope(typ.kidsLen))
for i, a in typ.ikids:
if typ.len > 0:
var tmp = getTempName(m) & "_" & $typ.len
genTNimNodeArray(m, tmp, rope(typ.len))
for i in 0..<typ.len:
var a = typ[i]
var tmp2 = getNimNode(m)
m.s[cfsTypeInit3].addf("$1[$2] = &$3;$n", [tmp, rope(i), tmp2])
m.s[cfsTypeInit3].addf("$1.kind = 1;$n" &
@@ -1499,10 +1475,10 @@ proc genTupleInfo(m: BModule; typ, origType: PType, name: Rope; info: TLineInfo)
"$1.name = \"Field$3\";$n",
[tmp2, getTypeDesc(m, origType, dkVar), rope(i), genTypeInfoV1(m, a, info)])
m.s[cfsTypeInit3].addf("$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
[expr, rope(typ.kidsLen), tmp])
[expr, rope(typ.len), tmp])
else:
m.s[cfsTypeInit3].addf("$1.len = $2; $1.kind = 2;$n",
[expr, rope(typ.kidsLen)])
[expr, rope(typ.len)])
m.s[cfsTypeInit3].addf("$1.node = &$2;$n", [tiNameForHcr(m, name), expr])
proc genEnumInfo(m: BModule; typ: PType, name: Rope; info: TLineInfo) =
@@ -1547,14 +1523,14 @@ proc genEnumInfo(m: BModule; typ: PType, name: Rope; info: TLineInfo) =
m.s[cfsTypeInit3].addf("$1.flags = 1<<2;$n", [tiNameForHcr(m, name)])
proc genSetInfo(m: BModule; typ: PType, name: Rope; info: TLineInfo) =
assert(typ.elementType != nil)
assert(typ[0] != nil)
genTypeInfoAux(m, typ, typ, name, info)
var tmp = getNimNode(m)
m.s[cfsTypeInit3].addf("$1.len = $2; $1.kind = 0;$n$3.node = &$1;$n",
[tmp, rope(firstOrd(m.config, typ)), tiNameForHcr(m, name)])
proc genArrayInfo(m: BModule; typ: PType, name: Rope; info: TLineInfo) =
genTypeInfoAuxBase(m, typ, typ, name, genTypeInfoV1(m, typ.elementType, info), info)
genTypeInfoAuxBase(m, typ, typ, name, genTypeInfoV1(m, typ[1], info), info)
proc fakeClosureType(m: BModule; owner: PSym): PType =
# we generate the same RTTI as for a tuple[pointer, ref tuple[]]
@@ -1623,14 +1599,14 @@ proc generateRttiDestructor(g: ModuleGraph; typ: PType; owner: PSym; kind: TType
n[paramsPos] = result.typ.n
let body = newNodeI(nkStmtList, info)
let castType = makePtrType(typ, idgen)
if theProc.typ.firstParamType.kind != tyVar:
if theProc.typ[1].kind != tyVar:
body.add newTreeI(nkCall, info, newSymNode(theProc), newDeref(newTreeIT(
nkCast, info, castType, newNodeIT(nkType, info, castType),
newSymNode(dest)
))
)
else:
let addrOf = newNodeIT(nkHiddenAddr, info, theProc.typ.firstParamType)
let addrOf = newNodeIT(nkAddr, info, theProc.typ[1])
addrOf.add newDeref(newTreeIT(
nkCast, info, castType, newNodeIT(nkType, info, castType),
newSymNode(dest)
@@ -1758,7 +1734,7 @@ proc genTypeInfoV2OldImpl(m: BModule; t, origType: PType, name: Rope; info: TLin
m.s[cfsTypeInit3].add typeEntry
if t.kind == tyObject and t.baseClass != nil and optEnableDeepCopy in m.config.globalOptions:
if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions:
discard genTypeInfoV1(m, t, info)
proc genTypeInfoV2Impl(m: BModule; t, origType: PType, name: Rope; info: TLineInfo) =
@@ -1808,7 +1784,7 @@ proc genTypeInfoV2Impl(m: BModule; t, origType: PType, name: Rope; info: TLineIn
addf(typeEntry, ", .flags = $1};$n", [rope(flags)])
m.s[cfsVars].add typeEntry
if t.kind == tyObject and t.baseClass != nil and optEnableDeepCopy in m.config.globalOptions:
if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions:
discard genTypeInfoV1(m, t, info)
proc genTypeInfoV2(m: BModule; t: PType; info: TLineInfo): Rope =
@@ -1854,7 +1830,7 @@ proc openArrayToTuple(m: BModule; t: PType): PType =
result = newType(tyTuple, m.idgen, t.owner)
let p = newType(tyPtr, m.idgen, t.owner)
let a = newType(tyUncheckedArray, m.idgen, t.owner)
a.add t.elementType
a.add t.lastSon
p.add a
result.add p
result.add getSysType(m.g.graph, t.owner.info, tyInt)
@@ -1864,7 +1840,8 @@ proc typeToC(t: PType): string =
## to be unique.
let s = typeToString(t)
result = newStringOfCap(s.len)
for c in s:
for i in 0..<s.len:
let c = s[i]
case c
of 'a'..'z':
result.add c
@@ -1935,11 +1912,11 @@ proc genTypeInfoV1(m: BModule; t: PType; info: TLineInfo): Rope =
of tyPointer, tyBool, tyChar, tyCstring, tyString, tyInt..tyUInt64, tyVar, tyLent:
genTypeInfoAuxBase(m, t, t, result, rope"0", info)
of tyStatic:
if t.n != nil: result = genTypeInfoV1(m, skipModifier t, info)
if t.n != nil: result = genTypeInfoV1(m, lastSon t, info)
else: internalError(m.config, "genTypeInfoV1(" & $t.kind & ')')
of tyUserTypeClasses:
internalAssert m.config, t.isResolvedUserTypeClass
return genTypeInfoV1(m, t.skipModifier, info)
return genTypeInfoV1(m, t.lastSon, info)
of tyProc:
if t.callConv != ccClosure:
genTypeInfoAuxBase(m, t, t, result, rope"0", info)
@@ -1998,11 +1975,8 @@ proc genTypeSection(m: BModule, n: PNode) =
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 (n[i][0][p].kind != nkSym): continue
if sfExportc in n[i][0][p].sym.flags:
discard getTypeDescAux(m, n[i][0][p].typ, intSet, descKindFromSymKind(n[i][0][p].sym.kind))
if m.g.generatedHeader != nil:
discard getTypeDescAux(m.g.generatedHeader, s.typ, intSet, descKindFromSymKind(s.sym.kind))
discard getTypeDescAux(m.g.generatedHeader, n[i][0][p].typ, intSet, descKindFromSymKind(n[i][0][p].sym.kind))

View File

@@ -11,9 +11,9 @@
import
ast, types, msgs, wordrecg,
platform, trees, options, cgendata, mangleutils
platform, trees, options, cgendata
import std/[hashes, strutils, formatfloat]
import std/[hashes, strutils]
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -68,6 +68,53 @@ proc makeSingleLineCString*(s: string): string =
c.toCChar(result)
result.add('\"')
proc mangle*(name: string): string =
result = newStringOfCap(name.len)
var start = 0
if name[0] in Digits:
result.add("X" & name[0])
start = 1
var requiresUnderscore = false
template special(x) =
result.add x
requiresUnderscore = true
for i in start..<name.len:
let c = name[i]
case c
of 'a'..'z', '0'..'9', 'A'..'Z':
result.add(c)
of '_':
# we generate names like 'foo_9' for scope disambiguations and so
# disallow this here:
if i > 0 and i < name.len-1 and name[i+1] in Digits:
discard
else:
result.add(c)
of '$': special "dollar"
of '%': special "percent"
of '&': special "amp"
of '^': special "roof"
of '!': special "emark"
of '?': special "qmark"
of '*': special "star"
of '+': special "plus"
of '-': special "minus"
of '/': special "slash"
of '\\': special "backslash"
of '=': special "eq"
of '<': special "lt"
of '>': special "gt"
of '~': special "tilde"
of ':': special "colon"
of '.': special "dot"
of '@': special "at"
of '|': special "bar"
else:
result.add("X" & toHex(ord(c), 2))
requiresUnderscore = true
if requiresUnderscore:
result.add "_"
proc mapSetType(conf: ConfigRef; typ: PType): TCTypeKind =
case int(getSize(conf, typ))
of 1: result = ctInt8
@@ -79,10 +126,10 @@ proc mapSetType(conf: ConfigRef; typ: PType): TCTypeKind =
proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool =
var pt = skipTypes(s.typ, typedescInst)
assert skResult != s.kind
#note precedence: params override types
if optByRef in s.options: return true
elif sfByCopy in s.flags: return false
elif sfByCopy in s.flags: return false
elif tfByRef in pt.flags: return true
elif tfByCopy in pt.flags: return false
case pt.kind
@@ -90,9 +137,6 @@ 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):
@@ -109,62 +153,3 @@ proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool =
result = not (pt.kind in {tyVar, tyArray, tyOpenArray, tyVarargs, tyRef, tyPtr, tyPointer} or
pt.kind == tySet and mapSetType(conf, pt) == ctArray)
proc encodeName*(name: string): string =
result = mangle(name)
result = $result.len & result
proc makeUnique(m: BModule; s: PSym, name: string = ""): string =
result = if name == "": s.name.s else: name
result.add "__"
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
result.add "_u"
result.add $s.itemId.item
proc encodeSym*(m: BModule; s: PSym; makeUnique: bool = false): string =
#Module::Type
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): string =
result = ""
var kindName = ($t.kind)[2..^1]
kindName[0] = toLower($kindName[0])[0]
case t.kind
of tyObject, tyEnum, tyDistinct, tyUserTypeClass, tyGenericParam:
result = encodeSym(m, t.sym)
of tyGenericInst, tyUserTypeClassInst, tyGenericBody:
result = encodeName(t[0].sym.name.s)
result.add "I"
for i in 1..<t.len - 1:
result.add encodeType(m, t[i])
result.add "E"
of tySequence, tyOpenArray, tyArray, tyVarargs, tyTuple, tyProc, tySet, tyTypeDesc,
tyPtr, tyRef, tyVar, tyLent, tySink, tyStatic, tyUncheckedArray, tyOr, tyAnd, tyBuiltInTypeClass:
result =
case t.kind:
of tySequence: encodeName("seq")
else: encodeName(kindName)
result.add "I"
for i in 0..<t.len:
let s = t[i]
if s.isNil: continue
result.add encodeType(m, s)
result.add "E"
of tyRange:
var val = "range_"
if t.n[0].typ.kind in {tyFloat..tyFloat128}:
val.addFloat t.n[0].floatVal
val.add "_"
val.addFloat t.n[1].floatVal
else:
val.add $t.n[0].intVal & "_" & $t.n[1].intVal
result = encodeName(val)
of tyString..tyUInt64, tyPointer, tyBool, tyChar, tyVoid, tyAnything, tyNil, tyEmpty:
result = encodeName(kindName)
of tyAlias, tyInferred, tyOwned:
result = encodeType(m, t.elementType)
else:
assert false, "encodeType " & $t.kind

View File

@@ -15,8 +15,7 @@ import
ccgutils, ropes, wordrecg, treetab, cgmeth,
rodutils, renderer, cgendata, aliases,
lowerings, ndi, lineinfos, pathutils, transf,
injectdestructors, astmsgs, modulepaths, backendpragmas,
mangleutils
injectdestructors, astmsgs, modulepaths, backendpragmas
from expanddefaults import caseObjDefaultBranch
@@ -33,12 +32,6 @@ import std/strutils except `%`, addf # collides with ropes.`%`
from ic / ic import ModuleBackendFlag
import std/[dynlib, math, tables, sets, os, intsets, hashes]
const
# we use some ASCII control characters to insert directives that will be converted to real code in a postprocessing pass
postprocessDirStart = '\1'
postprocessDirSep = '\31'
postprocessDirEnd = '\23'
when not declared(dynlib.libCandidates):
proc libCandidates(s: string, dest: var seq[string]) =
## given a library name pattern `s` write possible library names to `dest`.
@@ -273,28 +266,24 @@ proc safeLineNm(info: TLineInfo): int =
result = toLinenumber(info)
if result < 0: result = 0 # negative numbers are not allowed in #line
proc genPostprocessDir(field1, field2, field3: string): string =
result = postprocessDirStart & field1 & postprocessDirSep & field2 & postprocessDirSep & field3 & postprocessDirEnd
proc genCLineDir(r: var Rope, fileIdx: FileIndex, line: int; conf: ConfigRef) =
proc genCLineDir(r: var Rope, filename: string, line: int; conf: ConfigRef) =
assert line >= 0
if optLineDir in conf.options and line > 0:
if fileIdx == InvalidFileIdx:
r.add(rope("\n#line " & $line & " \"generated_not_to_break_here\"\n"))
else:
r.add(rope("\n#line " & $line & " FX_" & $fileIdx.int32 & "\n"))
r.addf("\n#line $2 $1\n",
[rope(makeSingleLineCString(filename)), rope(line)])
proc genCLineDir(r: var Rope, fileIdx: FileIndex, line: int; p: BProc; info: TLineInfo; lastFileIndex: FileIndex) =
proc genCLineDir(r: var Rope, filename: string, line: int; p: BProc; info: TLineInfo; lastFileIndex: FileIndex) =
assert line >= 0
if optLineDir in p.config.options and line > 0:
if fileIdx == InvalidFileIdx:
r.add(rope("\n#line " & $line & " \"generated_not_to_break_here\"\n"))
if lastFileIndex == info.fileIndex:
r.addf("\n#line $1\n", [rope(line)])
else:
r.add(rope("\n#line " & $line & " FX_" & $fileIdx.int32 & "\n"))
r.addf("\n#line $2 $1\n",
[rope(makeSingleLineCString(filename)), rope(line)])
proc genCLineDir(r: var Rope, info: TLineInfo; conf: ConfigRef) =
if optLineDir in conf.options:
genCLineDir(r, info.fileIndex, info.safeLineNm, conf)
genCLineDir(r, toFullPath(conf, info), info.safeLineNm, conf)
proc freshLineInfo(p: BProc; info: TLineInfo): bool =
if p.lastLineInfo.line != info.line or
@@ -309,7 +298,7 @@ proc genCLineDir(r: var Rope, p: BProc, info: TLineInfo; conf: ConfigRef) =
if optLineDir in conf.options:
let lastFileIndex = p.lastLineInfo.fileIndex
if freshLineInfo(p, info):
genCLineDir(r, info.fileIndex, info.safeLineNm, p, info, lastFileIndex)
genCLineDir(r, toFullPath(conf, info), info.safeLineNm, p, info, lastFileIndex)
proc genLineDir(p: BProc, t: PNode) =
if p == p.module.preInitProc: return
@@ -320,11 +309,16 @@ proc genLineDir(p: BProc, t: PNode) =
let lastFileIndex = p.lastLineInfo.fileIndex
let freshLine = freshLineInfo(p, t.info)
if freshLine:
genCLineDir(p.s(cpsStmts), t.info.fileIndex, line, p, t.info, lastFileIndex)
genCLineDir(p.s(cpsStmts), toFullPath(p.config, t.info), line, p, t.info, lastFileIndex)
if ({optLineTrace, optStackTrace} * p.options == {optLineTrace, optStackTrace}) and
(p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex != InvalidFileIdx:
if freshLine:
line(p, cpsStmts, genPostprocessDir("nimln", $line, $t.info.fileIndex.int32))
if lastFileIndex == t.info.fileIndex:
linefmt(p, cpsStmts, "nimln_($1);",
[line])
else:
linefmt(p, cpsStmts, "nimlf_($1, $2);",
[line, quotedFilename(p.config, t.info)])
proc accessThreadLocalVar(p: BProc, s: PSym)
proc emulatedThreadVars(conf: ConfigRef): bool {.inline.}
@@ -354,9 +348,12 @@ proc addRdLoc(a: TLoc; result: var Rope) =
proc lenField(p: BProc): Rope {.inline.} =
result = rope(if p.module.compileToCpp: "len" else: "Sup.len")
proc lenExpr(p: BProc; a: TLoc): Rope =
proc lenExpr(p: BProc; a: TLoc; isString = false): Rope =
if optSeqDestructors in p.config.globalOptions:
result = rdLoc(a) & ".len"
if isString and p.config.isDefined("nimSeqsV3"):
result = ropecg(p.module, "(#nimStrLenV3($1))", [rdLoc(a)])
else:
result = rdLoc(a) & ".len"
else:
result = "($1 ? $1->$2 : 0)" % [rdLoc(a), lenField(p)]
@@ -366,9 +363,13 @@ proc dataFieldAccessor(p: BProc, sym: Rope): Rope =
else:
result = sym
proc dataField(p: BProc): Rope =
proc dataField(p: BProc; isString: bool = false): Rope =
# TODO: revisit this after unify strings and seqs
if optSeqDestructors in p.config.globalOptions:
result = rope".p->data"
if isString and p.config.isDefined("nimSeqsV3"):
result = rope".p"
else:
result = rope".p->data"
else:
result = rope"->data"
@@ -412,7 +413,6 @@ proc rdCharLoc(a: TLoc): Rope =
type
TAssignmentFlag = enum
needToCopy
needTempForOpenArray
TAssignmentFlags = set[TAssignmentFlag]
proc genObjConstr(p: BProc, e: PNode, d: var TLoc)
@@ -486,10 +486,16 @@ proc resetLoc(p: BProc, loc: var TLoc) =
assert loc.r != ""
let atyp = skipTypes(loc.t, abstractInst)
if atyp.kind in {tyVar, tyLent}:
linefmt(p, cpsStmts, "$1->len = 0; $1->p = NIM_NIL;$n", [rdLoc(loc)])
if p.config.isDefined("nimSeqsV3") and typ.kind == tyString:
if atyp.kind in {tyVar, tyLent}:
linefmt(p, cpsStmts, "$1->rawlen = 0; $1->p = NIM_NIL;$n", [rdLoc(loc)])
else:
linefmt(p, cpsStmts, "$1.rawlen = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
else:
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
if atyp.kind in {tyVar, tyLent}:
linefmt(p, cpsStmts, "$1->len = 0; $1->p = NIM_NIL;$n", [rdLoc(loc)])
else:
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
elif not isComplexValueType(typ):
if containsGcRef:
var nilLoc: TLoc = initLoc(locTemp, loc.lode, OnStack)
@@ -526,8 +532,12 @@ proc resetLoc(p: BProc, loc: var TLoc) =
proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) =
let typ = loc.t
if optSeqDestructors in p.config.globalOptions and skipTypes(typ, abstractInst + {tyStatic}).kind in {tyString, tySequence}:
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
let typKind = skipTypes(typ, abstractInst + {tyStatic}).kind
if optSeqDestructors in p.config.globalOptions and typKind in {tyString, tySequence}:
if typKind == tyString and p.config.isDefined("nimSeqsV3"):
linefmt(p, cpsStmts, "$1.rawlen = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
else:
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
elif not isComplexValueType(typ):
if containsGarbageCollectedRef(loc.t):
var nilLoc: TLoc = initLoc(locTemp, loc.lode, OnStack)
@@ -537,7 +547,7 @@ proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) =
linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc),
getTypeDesc(p.module, typ, descKindFromSymKind mapTypeChooser(loc))])
else:
if (not isTemp or containsGarbageCollectedRef(loc.t)) and not hasNoInit(loc.t):
if not isTemp or containsGarbageCollectedRef(loc.t):
# don't use nimZeroMem for temporary values for performance if we can
# avoid it:
if not isOrHasImportedCppType(typ):
@@ -562,9 +572,8 @@ proc getTemp(p: BProc, t: PType, needsInit=false): TLoc =
result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp, lode: lodeTyp t,
storage: OnStack, flags: {})
if p.module.compileToCpp and isOrHasImportedCppType(t):
var didGenTemp = false
linefmt(p, cpsLocals, "$1 $2$3;$n", [getTypeDesc(p.module, t, dkVar), result.r,
genCppInitializer(p.module, p, t, didGenTemp)])
genCppInitializer(p.module, p, t)])
else:
linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, dkVar), result.r])
constructLoc(p, result, not needsInit)
@@ -581,7 +590,7 @@ proc getTempCpp(p: BProc, t: PType, value: Rope): TLoc =
inc(p.labels)
result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp, lode: lodeTyp t,
storage: OnStack, flags: {})
linefmt(p, cpsStmts, "auto $1 = $2;$n", [result.r, value])
linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t, dkVar), result.r, value])
proc getIntTemp(p: BProc): TLoc =
inc(p.labels)
@@ -621,8 +630,7 @@ proc assignLocalVar(p: BProc, n: PNode) =
let nl = if optLineDir in p.config.options: "" else: "\n"
var decl = localVarDecl(p, n)
if p.module.compileToCpp and isOrHasImportedCppType(n.typ):
var didGenTemp = false
decl.add genCppInitializer(p.module, p, n.typ, didGenTemp)
decl.add genCppInitializer(p.module, p, n.typ)
decl.add ";" & nl
line(p, cpsLocals, decl)
@@ -657,7 +665,18 @@ proc genGlobalVarDecl(p: BProc, n: PNode; td, value: Rope; decl: var Rope) =
else:
decl = runtimeFormat(s.cgDeclFrmt & ";$n", [td, s.loc.r])
proc genCppVarForCtor(p: BProc; call: PNode; decl: var Rope; didGenTemp: var bool)
proc genCppVarForCtor(p: BProc; call: PNode; decl: var Rope)
proc callGlobalVarCppCtor(p: BProc; v: PSym; vn, value: PNode) =
let s = vn.sym
fillBackendName(p.module, s)
fillLoc(s.loc, locGlobalVar, vn, OnHeap)
var decl: Rope = ""
let td = getTypeDesc(p.module, vn.sym.typ, dkVar)
genGlobalVarDecl(p, vn, td, "", decl)
decl.add " " & $s.loc.r
genCppVarForCtor(p, value, decl)
p.module.s[cfsVars].add decl
proc assignGlobalVar(p: BProc, n: PNode; value: Rope) =
let s = n.sym
@@ -713,18 +732,6 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) =
# fixes tests/run/tzeroarray:
resetLoc(p, s.loc)
proc callGlobalVarCppCtor(p: BProc; v: PSym; vn, value: PNode; didGenTemp: var bool) =
let s = vn.sym
fillBackendName(p.module, s)
fillLoc(s.loc, locGlobalVar, vn, OnHeap)
var decl: Rope = ""
let td = getTypeDesc(p.module, vn.sym.typ, dkVar)
genGlobalVarDecl(p, vn, td, "", decl)
decl.add " " & $s.loc.r
genCppVarForCtor(p, value, decl, didGenTemp)
if didGenTemp: return # generated in the caller
p.module.s[cfsVars].add decl
proc assignParam(p: BProc, s: PSym, retType: PType) =
assert(s.loc.r != "")
scopeMangledParam(p, s)
@@ -752,7 +759,6 @@ proc intLiteral(i: BiggestInt; result: var Rope)
proc genLiteral(p: BProc, n: PNode; result: var Rope)
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope; argsCounter: var int)
proc raiseExit(p: BProc)
proc raiseExitCleanup(p: BProc, destroy: string)
proc initLocExpr(p: BProc, e: PNode, flags: TLocFlags = {}): TLoc =
result = initLoc(locNone, e, OnUnknown, flags)
@@ -1043,7 +1049,7 @@ proc easyResultAsgn(n: PNode): PNode =
type
InitResultEnum = enum Unknown, InitSkippable, InitRequired
proc allPathsAsgnResult(p: BProc; n: PNode): InitResultEnum =
proc allPathsAsgnResult(n: PNode): InitResultEnum =
# Exceptions coming from calls don't have not be considered here:
#
# proc bar(): string = raise newException(...)
@@ -1058,7 +1064,7 @@ proc allPathsAsgnResult(p: BProc; n: PNode): InitResultEnum =
# echo "a was not written to"
#
template allPathsInBranch(it) =
let a = allPathsAsgnResult(p, it)
let a = allPathsAsgnResult(it)
case a
of InitRequired: return InitRequired
of InitSkippable: discard
@@ -1070,20 +1076,14 @@ proc allPathsAsgnResult(p: BProc; n: PNode): InitResultEnum =
case n.kind
of nkStmtList, nkStmtListExpr:
for it in n:
result = allPathsAsgnResult(p, it)
result = allPathsAsgnResult(it)
if result != Unknown: return result
of nkAsgn, nkFastAsgn, nkSinkAsgn:
if n[0].kind == nkSym and n[0].sym.kind == skResult:
if not containsResult(n[1]):
if allPathsAsgnResult(p, n[1]) == InitRequired:
result = InitRequired
else:
result = InitSkippable
if not containsResult(n[1]): result = InitSkippable
else: result = InitRequired
elif containsResult(n):
result = InitRequired
else:
result = allPathsAsgnResult(p, n[1])
of nkReturnStmt:
if n.len > 0:
if n[0].kind == nkEmpty and result != InitSkippable:
@@ -1092,7 +1092,7 @@ proc allPathsAsgnResult(p: BProc; n: PNode): InitResultEnum =
# initialized. This avoids cases like #9286 where this heuristic lead to
# wrong code being generated.
result = InitRequired
else: result = allPathsAsgnResult(p, n[0])
else: result = allPathsAsgnResult(n[0])
of nkIfStmt, nkIfExpr:
var exhaustive = false
result = InitSkippable
@@ -1118,9 +1118,9 @@ proc allPathsAsgnResult(p: BProc; n: PNode): InitResultEnum =
of nkWhileStmt:
# some dubious code can assign the result in the 'while'
# condition and that would be fine. Everything else isn't:
result = allPathsAsgnResult(p, n[0])
result = allPathsAsgnResult(n[0])
if result == Unknown:
result = allPathsAsgnResult(p, n[1])
result = allPathsAsgnResult(n[1])
# we cannot assume that the 'while' loop is really executed at least once:
if result == InitSkippable: result = Unknown
of harmless:
@@ -1145,21 +1145,9 @@ proc allPathsAsgnResult(p: BProc; n: PNode): InitResultEnum =
allPathsInBranch(n[0])
for i in 1..<n.len:
if n[i].kind == nkFinally:
result = allPathsAsgnResult(p, n[i].lastSon)
result = allPathsAsgnResult(n[i].lastSon)
else:
allPathsInBranch(n[i].lastSon)
of nkCallKinds:
if canRaiseDisp(p, n[0]):
result = InitRequired
else:
for i in 0..<n.safeLen:
allPathsInBranch(n[i])
of nkRaiseStmt:
result = InitRequired
of nkChckRangeF, nkChckRange64, nkChckRange:
# TODO: more checks might need to be covered like overflow, indexDefect etc.
# bug #22852
result = InitRequired
else:
for i in 0..<n.safeLen:
allPathsInBranch(n[i])
@@ -1200,7 +1188,7 @@ proc genProcAux*(m: BModule, prc: PSym) =
let tmpInfo = prc.info
discard freshLineInfo(p, prc.info)
if sfPure notin prc.flags and prc.typ.returnType != nil:
if sfPure notin prc.flags and prc.typ[0] != nil:
if resultPos >= prc.ast.len:
internalError(m.config, prc.info, "proc has no result symbol")
let resNode = prc.ast[resultPos]
@@ -1216,7 +1204,7 @@ proc genProcAux*(m: BModule, prc: PSym) =
assignLocalVar(p, resNode)
assert(res.loc.r != "")
if p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc} and
allPathsAsgnResult(p, procBody) == InitSkippable:
allPathsAsgnResult(procBody) == InitSkippable:
# In an ideal world the codegen could rely on injectdestructors doing its job properly
# and then the analysis step would not be required.
discard "result init optimized out"
@@ -1226,10 +1214,9 @@ proc genProcAux*(m: BModule, prc: PSym) =
elif sfConstructor in prc.flags:
resNode.sym.loc.flags.incl lfIndirect
fillLoc(resNode.sym.loc, locParam, resNode, "this", OnHeap)
prc.loc.r = getTypeDesc(m, resNode.sym.loc.t, dkVar)
else:
fillResult(p.config, resNode, prc.typ)
assignParam(p, res, prc.typ.returnType)
assignParam(p, res, prc.typ[0])
# We simplify 'unsureAsgn(result, nil); unsureAsgn(result, x)'
# to 'unsureAsgn(result, x)'
# Sketch why this is correct: If 'result' points to a stack location
@@ -1237,7 +1224,7 @@ proc genProcAux*(m: BModule, prc: PSym) =
# global is either 'nil' or points to valid memory and so the RC operation
# succeeds without touching not-initialized memory.
if sfNoInit in prc.flags: discard
elif allPathsAsgnResult(p, procBody) == InitSkippable: discard
elif allPathsAsgnResult(procBody) == InitSkippable: discard
else:
resetLoc(p, res.loc)
if skipTypes(res.typ, abstractInst).kind == tyArray:
@@ -1247,7 +1234,7 @@ proc genProcAux*(m: BModule, prc: PSym) =
for i in 1..<prc.typ.n.len:
let param = prc.typ.n[i].sym
if param.typ.isCompileTimeOnly: continue
assignParam(p, param, prc.typ.returnType)
assignParam(p, param, prc.typ[0])
closureSetup(p, prc)
genProcBody(p, procBody)
@@ -1827,7 +1814,7 @@ proc genDatInitCode(m: BModule) =
# we don't want to break into such init code - could happen if a line
# directive from a function written by the user spills after itself
genCLineDir(prc, InvalidFileIdx, 999999, m.config)
genCLineDir(prc, "generated_not_to_break_here", 999999, m.config)
for i in cfsTypeInit1..cfsDynLibInit:
if m.s[i].len != 0:
@@ -1868,7 +1855,7 @@ proc genInitCode(m: BModule) =
[rope(if m.hcrOn: "N_LIB_EXPORT" else: "N_LIB_PRIVATE"), initname]
# we don't want to break into such init code - could happen if a line
# directive from a function written by the user spills after itself
genCLineDir(prc, InvalidFileIdx, 999999, m.config)
genCLineDir(prc, "generated_not_to_break_here", 999999, m.config)
if m.typeNodes > 0:
if m.hcrOn:
appcg(m, m.s[cfsTypeInit1], "\t#TNimNode* $1;$N", [m.typeNodesName])
@@ -1983,40 +1970,6 @@ proc genInitCode(m: BModule) =
registerModuleToMain(m.g, m)
proc postprocessCode(conf: ConfigRef, r: var Rope) =
# find the first directive
var f = r.find(postprocessDirStart)
if f == -1:
return
var
nimlnDirLastF = ""
var res: Rope = r.substr(0, f - 1)
while f != -1:
var
e = r.find(postprocessDirEnd, f + 1)
dir = r.substr(f + 1, e - 1).split(postprocessDirSep)
case dir[0]
of "nimln":
if dir[2] == nimlnDirLastF:
res.add("nimln_(" & dir[1] & ");")
else:
res.add("nimlf_(" & dir[1] & ", " & quotedFilename(conf, dir[2].parseInt.FileIndex) & ");")
nimlnDirLastF = dir[2]
else:
raiseAssert "unexpected postprocess directive"
# find the next directive
f = r.find(postprocessDirStart, e + 1)
# copy the code until the next directive
if f != -1:
res.add(r.substr(e + 1, f - 1))
else:
res.add(r.substr(e + 1))
r = res
proc genModule(m: BModule, cfile: Cfile): Rope =
var moduleIsEmpty = true
@@ -2045,17 +1998,9 @@ proc genModule(m: BModule, cfile: Cfile): Rope =
if m.config.cppCustomNamespace.len > 0:
closeNamespaceNim(result)
if optLineDir in m.config.options:
var srcFileDefs = ""
for fi in 0..m.config.m.fileInfos.high:
srcFileDefs.add("#define FX_" & $fi & " " & makeSingleLineCString(toFullPath(m.config, fi.FileIndex)) & "\n")
result = srcFileDefs & result
if moduleIsEmpty:
result = ""
postprocessCode(m.config, result)
proc initProcOptions(m: BModule): TOptions =
let opts = m.config.options
if sfSystemModule in m.module.flags: opts-{optStackTrace} else: opts
@@ -2255,22 +2200,6 @@ proc updateCachedModule(m: BModule) =
cf.flags = {CfileFlag.Cached}
addFileToCompile(m.config, cf)
proc generateLibraryDestroyGlobals(graph: ModuleGraph; m: BModule; body: PNode; isDynlib: bool): PSym =
let procname = getIdent(graph.cache, "NimDestroyGlobals")
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
incl result.flags, sfExportc
result.loc.r = "NimDestroyGlobals"
if isDynlib:
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)
theProc[namePos] = newSymNode(result)
theProc[bodyPos] = body
result.ast = theProc
proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
## Also called from IC.
if sfMainModule in m.module.flags:
@@ -2282,13 +2211,6 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
if {optGenStaticLib, optGenDynLib, optNoMain} * m.config.globalOptions == {}:
for i in countdown(high(graph.globalDestructors), 0):
n.add graph.globalDestructors[i]
else:
var body = newNodeI(nkStmtList, m.module.info)
for i in countdown(high(graph.globalDestructors), 0):
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)
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

View File

@@ -137,7 +137,6 @@ type
# unconditionally...
# nimtvDeps is VERY hard to cache because it's
# not a list of IDs nor can it be made to be one.
mangledPrcs*: HashSet[string]
TCGen = object of PPassContext # represents a C source file
s*: TCFileSections # sections of the C file
@@ -151,7 +150,7 @@ type
typeABICache*: HashSet[SigHash] # cache for ABI checks; reusing typeCache
# would be ideal but for some reason enums
# don't seem to get cached so it'd generate
# 1 ABI check per occurrence in code
# 1 ABI check per occurence in code
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

View File

@@ -69,23 +69,21 @@ type
proc sameMethodBucket(a, b: PSym; multiMethods: bool): MethodResult =
result = No
if a.name.id != b.name.id: return
if a.typ.signatureLen != b.typ.signatureLen:
if a.typ.len != b.typ.len:
return
var i = 0
for x, y in paramTypePairs(a.typ, b.typ):
inc i
var aa = x
var bb = y
for i in 1..<a.typ.len:
var aa = a.typ[i]
var bb = b.typ[i]
while true:
aa = skipTypes(aa, {tyGenericInst, tyAlias})
bb = skipTypes(bb, {tyGenericInst, tyAlias})
if aa.kind == bb.kind and aa.kind in {tyVar, tyPtr, tyRef, tyLent, tySink}:
aa = aa.elementType
bb = bb.elementType
aa = aa.lastSon
bb = bb.lastSon
else:
break
if sameType(x, y):
if sameType(a.typ[i], b.typ[i]):
if aa.kind == tyObject and result != Invalid:
result = Yes
elif aa.kind == tyObject and bb.kind == tyObject and (i == 1 or multiMethods):
@@ -104,10 +102,10 @@ proc sameMethodBucket(a, b: PSym; multiMethods: bool): MethodResult =
if result == Yes:
# check for return type:
# ignore flags of return types; # bug #22673
if not sameTypeOrNil(a.typ.returnType, b.typ.returnType, {IgnoreFlags}):
if b.typ.returnType != nil and b.typ.returnType.kind == tyUntyped:
if not sameTypeOrNil(a.typ[0], b.typ[0], {IgnoreFlags}):
if b.typ[0] != nil and b.typ[0].kind == tyUntyped:
# infer 'auto' from the base to make it consistent:
b.typ.setReturnType a.typ.returnType
b.typ[0] = a.typ[0]
else:
return No
@@ -134,7 +132,7 @@ proc createDispatcher(s: PSym; g: ModuleGraph; idgen: IdGenerator): PSym =
disp.ast = copyTree(s.ast)
disp.ast[bodyPos] = newNodeI(nkEmpty, s.info)
disp.loc.r = ""
if s.typ.returnType != nil:
if s.typ[0] != nil:
if disp.ast.len > resultPos:
disp.ast[resultPos].sym = copySym(s.ast[resultPos].sym, idgen)
else:
@@ -159,14 +157,9 @@ proc fixupDispatcher(meth, disp: PSym; conf: ConfigRef) =
proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) =
var witness: PSym = nil
if s.typ.firstParamType.owner.getModule != s.getModule and vtables in g.config.features and not
g.config.isDefined("nimInternalNonVtablesTesting"):
if s.typ[1].owner.getModule != s.getModule and vtables in g.config.features and not g.config.isDefined("nimInternalNonVtablesTesting"):
localError(g.config, s.info, errGenerated, "method `" & s.name.s &
"` can be defined only in the same module with its type (" & s.typ.firstParamType.typeToString() & ")")
if sfImportc in s.flags:
localError(g.config, s.info, errGenerated, "method `" & s.name.s &
"` is not allowed to have 'importc' pragmas")
"` can be defined only in the same module with its type (" & s.typ[1].typeToString() & ")")
for i in 0..<g.methods.len:
let disp = g.methods[i].dispatcher
case sameMethodBucket(disp, s, multimethods = optMultiMethods in g.config.globalOptions)
@@ -186,10 +179,10 @@ proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) =
if witness.isNil: witness = g.methods[i].methods[0]
# create a new dispatcher:
# stores the id and the position
if s.typ.firstParamType.skipTypes(skipPtrs).itemId notin g.bucketTable:
g.bucketTable[s.typ.firstParamType.skipTypes(skipPtrs).itemId] = 1
if s.typ[1].skipTypes(skipPtrs).itemId notin g.bucketTable:
g.bucketTable[s.typ[1].skipTypes(skipPtrs).itemId] = 1
else:
g.bucketTable.inc(s.typ.firstParamType.skipTypes(skipPtrs).itemId)
g.bucketTable.inc(s.typ[1].skipTypes(skipPtrs).itemId)
g.methods.add((methods: @[s], dispatcher: createDispatcher(s, g, idgen)))
#echo "adding ", s.info
if witness != nil:
@@ -210,7 +203,7 @@ proc relevantCol*(methods: seq[PSym], col: int): bool =
proc cmpSignatures(a, b: PSym, relevantCols: IntSet): int =
result = 0
for col in FirstParamAt..<a.typ.signatureLen:
for col in 1..<a.typ.len:
if contains(relevantCols, col):
var aa = skipTypes(a.typ[col], skipPtrs)
var bb = skipTypes(b.typ[col], skipPtrs)
@@ -240,13 +233,13 @@ proc sortBucket*(a: var seq[PSym], relevantCols: IntSet) =
proc genIfDispatcher*(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet; idgen: IdGenerator): PSym =
var base = methods[0].ast[dispatcherPos].sym
result = base
var paramLen = base.typ.signatureLen
var paramLen = base.typ.len
var nilchecks = newNodeI(nkStmtList, base.info)
var disp = newNodeI(nkIfStmt, base.info)
var ands = getSysMagic(g, unknownLineInfo, "and", mAnd)
var iss = getSysMagic(g, unknownLineInfo, "of", mOf)
let boolType = getSysType(g, unknownLineInfo, tyBool)
for col in FirstParamAt..<paramLen:
for col in 1..<paramLen:
if contains(relevantCols, col):
let param = base.typ.n[col].sym
if param.typ.skipTypes(abstractInst).kind in {tyRef, tyPtr}:
@@ -255,7 +248,7 @@ proc genIfDispatcher*(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet;
for meth in 0..high(methods):
var curr = methods[meth] # generate condition:
var cond: PNode = nil
for col in FirstParamAt..<paramLen:
for col in 1..<paramLen:
if contains(relevantCols, col):
var isn = newNodeIT(nkCall, base.info, boolType)
isn.add newSymNode(iss)
@@ -270,7 +263,7 @@ proc genIfDispatcher*(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet;
cond = a
else:
cond = isn
let retTyp = base.typ.returnType
let retTyp = base.typ[0]
let call = newNodeIT(nkCall, base.info, retTyp)
call.add newSymNode(curr)
for col in 1..<paramLen:
@@ -299,7 +292,7 @@ proc genIfDispatcher*(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet;
proc generateIfMethodDispatchers*(g: ModuleGraph, idgen: IdGenerator) =
for bucket in 0..<g.methods.len:
var relevantCols = initIntSet()
for col in FirstParamAt..<g.methods[bucket].methods[0].typ.signatureLen:
for col in 1..<g.methods[bucket].methods[0].typ.len:
if relevantCol(g.methods[bucket].methods, col): incl(relevantCols, col)
if optMultiMethods notin g.config.globalOptions:
# if multi-methods are not enabled, we are interested only in the first field

View File

@@ -18,8 +18,7 @@
# dec a
#
# Should be transformed to:
# case :state
# of 0:
# STATE0:
# if a > 0:
# echo "hi"
# :state = 1 # Next state
@@ -27,14 +26,12 @@
# else:
# :state = 2 # Next state
# break :stateLoop # Proceed to the next state
# of 1:
# STATE1:
# dec a
# :state = 0 # Next state
# break :stateLoop # Proceed to the next state
# of 2:
# STATE2:
# :state = -1 # End of execution
# else:
# return
# The transformation should play well with lambdalifting, however depending
# on situation, it can be called either before or after lambdalifting
@@ -107,13 +104,12 @@
# Is transformed to (yields are left in place for example simplicity,
# in reality the code is subdivided even more, as described above):
#
# case :state
# of 0: # Try
# STATE0: # Try
# yield 0
# raise ...
# :state = 2 # What would happen should we not raise
# break :stateLoop
# of 1: # Except
# STATE1: # Except
# yield 1
# :tmpResult = 3 # Return
# :unrollFinally = true # Return
@@ -121,7 +117,7 @@
# break :stateLoop
# :state = 2 # What would happen should we not return
# break :stateLoop
# of 2: # Finally
# STATE2: # Finally
# yield 2
# if :unrollFinally: # This node is created by `newEndFinallyNode`
# if :curExc.isNil:
@@ -134,8 +130,6 @@
# raise
# state = -1 # Goto next state. In this case we just exit
# break :stateLoop
# else:
# return
import
ast, msgs, idents,
@@ -156,7 +150,7 @@ type
unrollFinallySym: PSym # Indicates that we're unrolling finally states (either exception happened or premature return)
curExcSym: PSym # Current exception
states: seq[tuple[label: int, body: PNode]] # The resulting states.
states: seq[PNode] # The resulting states. Every state is an nkState node.
blockLevel: int # Temp used to transform break and continue stmts
stateLoopLabel: PSym # Label to break on, when jumping between states.
exitStateIdx: int # index of the last state
@@ -172,7 +166,6 @@ type
const
nkSkip = {nkEmpty..nkNilLit, nkTemplateDef, nkTypeSection, nkStaticStmt,
nkCommentStmt, nkMixinStmt, nkBindStmt} + procDefs
emptyStateLabel = -1
proc newStateAccess(ctx: var Ctx): PNode =
if ctx.stateVarSym.isNil:
@@ -194,7 +187,6 @@ proc newStateAssgn(ctx: var Ctx, stateNo: int = -2): PNode =
proc newEnvVar(ctx: var Ctx, name: string, typ: PType): PSym =
result = newSym(skVar, getIdent(ctx.g.cache, name), ctx.idgen, ctx.fn, ctx.fn.info)
result.typ = typ
result.flags.incl sfNoInit
assert(not typ.isNil)
if not ctx.stateVarSym.isNil:
@@ -206,7 +198,7 @@ proc newEnvVar(ctx: var Ctx, name: string, typ: PType): PSym =
else:
let envParam = getEnvParam(ctx.fn)
# let obj = envParam.typ.lastSon
result = addUniqueField(envParam.typ.elementType, result, ctx.g.cache, ctx.idgen)
result = addUniqueField(envParam.typ.lastSon, result, ctx.g.cache, ctx.idgen)
proc newEnvVarAccess(ctx: Ctx, s: PSym): PNode =
if ctx.stateVarSym.isNil:
@@ -216,7 +208,7 @@ proc newEnvVarAccess(ctx: Ctx, s: PSym): PNode =
proc newTmpResultAccess(ctx: var Ctx): PNode =
if ctx.tmpResultSym.isNil:
ctx.tmpResultSym = ctx.newEnvVar(":tmpResult", ctx.fn.typ.returnType)
ctx.tmpResultSym = ctx.newEnvVar(":tmpResult", ctx.fn.typ[0])
ctx.newEnvVarAccess(ctx.tmpResultSym)
proc newUnrollFinallyAccess(ctx: var Ctx, info: TLineInfo): PNode =
@@ -236,7 +228,10 @@ proc newState(ctx: var Ctx, n, gotoOut: PNode): int =
result = ctx.states.len
let resLit = ctx.g.newIntLit(n.info, result)
ctx.states.add((result, n))
let s = newNodeI(nkState, n.info)
s.add(resLit)
s.add(n)
ctx.states.add(s)
ctx.exceptionTable.add(ctx.curExcHandlingState)
if not gotoOut.isNil:
@@ -268,8 +263,8 @@ proc hasYields(n: PNode): bool =
result = false
else:
result = false
for i in ord(n.kind == nkCast)..<n.len:
if n[i].hasYields:
for c in n:
if c.hasYields:
result = true
break
@@ -418,7 +413,7 @@ proc hasYieldsInExpressions(n: PNode): bool =
proc exprToStmtList(n: PNode): tuple[s, res: PNode] =
assert(n.kind == nkStmtListExpr)
result = (newNodeI(nkStmtList, n.info), nil)
result.s = newNodeI(nkStmtList, n.info)
result.s.sons = @[]
var n = n
@@ -453,10 +448,6 @@ proc newNotCall(g: ModuleGraph; e: PNode): PNode =
result = newTree(nkCall, newSymNode(g.getSysMagic(e.info, "not", mNot), e.info), e)
result.typ = g.getSysType(e.info, tyBool)
proc boolLit(g: ModuleGraph; info: TLineInfo; value: bool): PNode =
result = newIntLit(g, info, ord value)
result.typ = getSysType(g, info, tyBool)
proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
result = n
case n.kind
@@ -788,7 +779,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
let check = newTree(nkIfStmt, branch)
let newBody = newTree(nkStmtList, st, check, n[1])
n[0] = ctx.g.boolLit(n[0].info, true)
n[0] = newSymNode(ctx.g.getSysSym(n[0].info, "true"))
n[1] = newBody
of nkDotExpr, nkCheckedFieldExpr:
@@ -840,7 +831,7 @@ proc newEndFinallyNode(ctx: var Ctx, info: TLineInfo): PNode =
let retStmt =
if ctx.nearestFinally == 0:
# last finally, we can return
let retValue = if ctx.fn.typ.returnType.isNil:
let retValue = if ctx.fn.typ[0].isNil:
ctx.g.emptyNode
else:
newTree(nkFastAsgn,
@@ -1142,10 +1133,10 @@ proc skipEmptyStates(ctx: Ctx, stateIdx: int): int =
let label = stateIdx
if label == ctx.exitStateIdx: break
var newLabel = label
if label == emptyStateLabel:
if label == -1:
newLabel = ctx.exitStateIdx
else:
let fs = skipStmtList(ctx, ctx.states[label].body)
let fs = skipStmtList(ctx, ctx.states[label][1])
if fs.kind == nkGotoState:
newLabel = fs[0].intVal.int
if label == newLabel: break
@@ -1154,7 +1145,7 @@ proc skipEmptyStates(ctx: Ctx, stateIdx: int): int =
if maxJumps == 0:
assert(false, "Internal error")
result = ctx.states[stateIdx].label
result = ctx.states[stateIdx][0].intVal.int
proc skipThroughEmptyStates(ctx: var Ctx, n: PNode): PNode=
result = n
@@ -1272,10 +1263,11 @@ proc wrapIntoTryExcept(ctx: var Ctx, n: PNode): PNode {.inline.} =
proc wrapIntoStateLoop(ctx: var Ctx, n: PNode): PNode =
# while true:
# block :stateLoop:
# gotoState :state
# local vars decl (if needed)
# body # Might get wrapped in try-except
let loopBody = newNodeI(nkStmtList, n.info)
result = newTree(nkWhileStmt, ctx.g.boolLit(n.info, true), loopBody)
result = newTree(nkWhileStmt, newSymNode(ctx.g.getSysSym(n.info, "true")), loopBody)
result.info = n.info
let localVars = newNodeI(nkStmtList, n.info)
@@ -1290,7 +1282,11 @@ proc wrapIntoStateLoop(ctx: var Ctx, n: PNode): PNode =
let blockStmt = newNodeI(nkBlockStmt, n.info)
blockStmt.add(newSymNode(ctx.stateLoopLabel))
var blockBody = newTree(nkStmtList, localVars, n)
let gs = newNodeI(nkGotoState, n.info)
gs.add(ctx.newStateAccess())
gs.add(ctx.g.newIntLit(n.info, ctx.states.len - 1))
var blockBody = newTree(nkStmtList, gs, localVars, n)
if ctx.hasExceptions:
blockBody = ctx.wrapIntoTryExcept(blockBody)
@@ -1303,28 +1299,29 @@ proc deleteEmptyStates(ctx: var Ctx) =
# Apply new state indexes and mark unused states with -1
var iValid = 0
for i, s in ctx.states.mpairs:
let body = skipStmtList(ctx, s.body)
for i, s in ctx.states:
let body = skipStmtList(ctx, s[1])
if body.kind == nkGotoState and i != ctx.states.len - 1 and i != 0:
# This is an empty state. Mark with -1.
s.label = emptyStateLabel
s[0].intVal = -1
else:
s.label = iValid
s[0].intVal = iValid
inc iValid
for i, s in ctx.states:
let body = skipStmtList(ctx, s.body)
let body = skipStmtList(ctx, s[1])
if body.kind != nkGotoState or i == 0:
discard ctx.skipThroughEmptyStates(s.body)
discard ctx.skipThroughEmptyStates(s)
let excHandlState = ctx.exceptionTable[i]
if excHandlState < 0:
ctx.exceptionTable[i] = -ctx.skipEmptyStates(-excHandlState)
elif excHandlState != 0:
ctx.exceptionTable[i] = ctx.skipEmptyStates(excHandlState)
var i = 1 # ignore the entry and the exit
var i = 0
while i < ctx.states.len - 1:
if ctx.states[i].label == emptyStateLabel:
let fs = skipStmtList(ctx, ctx.states[i][1])
if fs.kind == nkGotoState and i != 0:
ctx.states.delete(i)
ctx.exceptionTable.delete(i)
else:
@@ -1434,7 +1431,10 @@ proc preprocess(c: var PreprocessContext; n: PNode): PNode =
result[i] = preprocess(c, n[i])
proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n: PNode): PNode =
var ctx = Ctx(g: g, fn: fn, idgen: idgen)
var ctx: Ctx
ctx.g = g
ctx.fn = fn
ctx.idgen = idgen
if getEnvParam(fn).isNil:
# Lambda lifting was not done yet. Use temporary :state sym, which will
@@ -1463,16 +1463,17 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n:
# Optimize empty states away
ctx.deleteEmptyStates()
let caseDispatcher = newTreeI(nkCaseStmt, n.info,
ctx.newStateAccess())
# Make new body by concatenating the list of states
result = newNodeI(nkStmtList, n.info)
for s in ctx.states:
let body = ctx.transformStateAssignments(s.body)
caseDispatcher.add newTreeI(nkOfBranch, body.info, g.newIntLit(body.info, s.label), body)
assert(s.len == 2)
let body = s[1]
s.sons.del(1)
result.add(s)
result.add(body)
caseDispatcher.add newTreeI(nkElse, n.info, newTreeI(nkReturnStmt, n.info, g.emptyNode))
result = wrapIntoStateLoop(ctx, caseDispatcher)
result = ctx.transformStateAssignments(result)
result = ctx.wrapIntoStateLoop(result)
when false:
echo "TRANSFORM TO STATES: "

View File

@@ -57,11 +57,6 @@ proc loadConfigsAndProcessCmdLine*(self: NimProg, cache: IdentCache; conf: Confi
if conf.cmd == cmdNimscript:
incl(conf.globalOptions, optWasNimscript)
loadConfigs(DefaultConfig, cache, conf, graph.idgen) # load all config files
# restores `conf.notes` after loading config files
# because it has overwrites the notes when compiling the system module which
# is a foreign module compared to the project
if conf.cmd in cmdBackends:
conf.notes = conf.mainPackageNotes
if not self.suggestMode:
let scriptFile = conf.projectFull.changeFileExt("nims")

View File

@@ -96,7 +96,7 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
ignorableForArgType = {tyVar, tySink, tyLent, tyOwned, tyGenericInst, tyAlias, tyInferred}
case f.kind
of tyAlias:
result = matchType(c, f.skipModifier, a, m)
result = matchType(c, f.lastSon, a, m)
of tyTypeDesc:
if isSelf(f):
#let oldLen = m.inferred.len
@@ -105,19 +105,18 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
#m.inferred.setLen oldLen
#echo "A for ", result, " to ", typeToString(a), " to ", typeToString(m.potentialImplementation)
else:
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
if a.kind == tyTypeDesc and f.len == a.len:
for i in 0..<a.len:
if not matchType(c, f[i], a[i], m): return false
return true
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:
for i in FirstGenericParamAt ..< f.kidsLen:
if a.kind == tyGenericInst and a[0].kind == tyGenericBody:
if sameType(f[0], a[0]) and f.len == a.len-1:
for i in 1 ..< f.len:
if not matchType(c, f[i], a[i], m): return false
return true
of tyGenericParam:
@@ -127,17 +126,17 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
else:
let old = existingBinding(m, f)
if old == nil:
if f.hasElementType and f.elementType.kind != tyNone:
if f.len > 0 and f[0].kind != tyNone:
# also check the generic's constraints:
let oldLen = m.inferred.len
result = matchType(c, f.elementType, a, m)
result = matchType(c, f[0], 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, " ", lastSon ak
m.inferred.add((f, last ak))
m.inferred.add((f, lastSon ak))
result = true
else:
when logBindings: echo "C adding ", f, " ", ak
@@ -156,9 +155,9 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
# modifiers in the concept must be there in the actual implementation
# too but not vice versa.
if a.kind == f.kind:
result = matchType(c, f.elementType, a.elementType, m)
result = matchType(c, f[0], a[0], m)
elif m.magic == mArrPut:
result = matchType(c, f.elementType, a, m)
result = matchType(c, f[0], a, m)
else:
result = false
of tyEnum, tyObject, tyDistinct:
@@ -168,7 +167,7 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
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)
(ak.kind == tyGenericParam and ak.len > 0 and ak[0].kind == tyOrdinal)
of tyConcept:
let oldLen = m.inferred.len
let oldPotentialImplementation = m.potentialImplementation
@@ -179,11 +178,10 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
m.inferred.setLen oldLen
of tyArray, tyTuple, tyVarargs, tyOpenArray, tyRange, tySequence, tyRef, tyPtr,
tyGenericInst:
# ^ XXX Rewrite this logic, it's more complex than it needs to be.
result = false
let ak = a.skipTypes(ignorableForArgType - {f.kind})
if ak.kind == f.kind and f.kidsLen == ak.kidsLen:
for i in 0..<ak.kidsLen:
if ak.kind == f.kind and f.len == ak.len:
for i in 0..<ak.len:
if not matchType(c, f[i], ak[i], m): return false
return true
of tyOr:
@@ -192,30 +190,30 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
# 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:
for i in 0..<f.len:
for j in 0..<a.len:
let oldLenB = m.inferred.len
let r = matchType(c, ff, aa, m)
let r = matchType(c, f[i], a[j], m)
if r:
inc covered
break
m.inferred.setLen oldLenB
result = covered >= a.kidsLen
result = covered >= a.len
if not result:
m.inferred.setLen oldLen
else:
result = false
for ff in f.kids:
result = matchType(c, ff, a, m)
for i in 0..<f.len:
result = matchType(c, f[i], 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)
result = matchType(c, f[0], a[0], m)
else:
let oldLen = m.inferred.len
result = not matchType(c, f.elementType, a, m)
result = not matchType(c, f[0], a, m)
m.inferred.setLen oldLen
of tyAnything:
result = true
@@ -254,7 +252,7 @@ proc matchSym(c: PContext; candidate: PSym, n: PNode; m: var MatchCon): bool =
m.inferred.setLen oldLen
return false
if not matchReturnType(c, n[0].sym.typ.returnType, candidate.typ.returnType, m):
if not matchReturnType(c, n[0].sym.typ[0], candidate.typ[0], m):
m.inferred.setLen oldLen
return false
@@ -309,9 +307,9 @@ proc conceptMatchNode(c: PContext; n: PNode; m: var MatchCon): bool =
# error was reported earlier.
result = false
proc conceptMatch*(c: PContext; concpt, arg: PType; bindings: var TypeMapping; invocation: PType): bool =
proc conceptMatch*(c: PContext; concpt, arg: PType; bindings: var TIdTable; 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
## we extract its AST via 'concpt.n.lastSon'). 'arg' is the type that might fullfill the
## concept's requirements. If so, we return true and fill the 'bindings' with pairs of
## (typeVar, instance) pairs. ('typeVar' is usually simply written as a generic 'T'.)
## 'invocation' can be nil for atomic concepts. For non-atomic concepts, it contains the
@@ -336,8 +334,8 @@ proc conceptMatch*(c: PContext; concpt, arg: PType; bindings: var TypeMapping; i
# we have a match, so bind 'arg' itself to 'concpt':
bindings.idTablePut(concpt, arg)
# invocation != nil means we have a non-atomic concept:
if invocation != nil and arg.kind == tyGenericInst and invocation.kidsLen == arg.kidsLen-1:
if invocation != nil and arg.kind == tyGenericInst and invocation.len == arg.len-1:
# bind even more generic parameters
assert invocation.kind == tyGenericInvocation
for i in FirstGenericParamAt ..< invocation.kidsLen:
for i in 1 ..< invocation.len:
bindings.idTablePut(invocation[i], arg[i])

View File

@@ -157,7 +157,6 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimAllowNonVarDestructor")
defineSymbol("nimHasQuirky")
defineSymbol("nimHasEnsureMove")
defineSymbol("nimHasNoReturnError")
defineSymbol("nimUseStrictDefs")
defineSymbol("nimHasNolineTooLong")
@@ -166,4 +165,4 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimHasWarnStdPrefix")
defineSymbol("nimHasVtables")
defineSymbol("nimHasJsNoLambdaLifting")
defineSymbol("nimHasSeqsV3")

View File

@@ -46,10 +46,10 @@ type
case isTryBlock: bool
of false:
label: PSym
breakFixups: seq[(TPosition, seq[PNode])] # Contains the gotos for the breaks along with their pending finales
breakFixups: seq[(TPosition, seq[PNode])] #Contains the gotos for the breaks along with their pending finales
of true:
finale: PNode
raiseFixups: seq[TPosition] # Contains the gotos for the raises
raiseFixups: seq[TPosition] #Contains the gotos for the raises
Con = object
code: ControlFlowGraph
@@ -181,6 +181,14 @@ proc genIf(c: var Con, n: PNode) =
goto Lend3
L3:
D
goto Lend3 # not eliminated to simplify the join generation
Lend3:
join F3
Lend2:
join F2
Lend:
join F1
]#
var endings: seq[TPosition] = @[]
let oldInteresting = c.interestingInstructions
@@ -205,6 +213,7 @@ proc genAndOr(c: var Con; n: PNode) =
# fork lab1
# asgn dest, b
# lab1:
# join F1
c.gen(n[1])
forkT:
c.gen(n[2])
@@ -315,7 +324,7 @@ proc genRaise(c: var Con; n: PNode) =
if c.blocks[i].isTryBlock:
genBreakOrRaiseAux(c, i, n)
return
assert false # Unreachable
assert false #Unreachable
else:
genNoReturn(c)
@@ -371,7 +380,7 @@ proc genCall(c: var Con; n: PNode) =
if t != nil: t = t.skipTypes(abstractInst)
for i in 1..<n.len:
gen(c, n[i])
if t != nil and i < t.signatureLen and isOutParam(t[i]):
if t != nil and i < t.len and isOutParam(t[i]):
# Pass by 'out' is a 'must def'. Good enough for a move optimizer.
genDef(c, n[i])
# every call can potentially raise:
@@ -381,6 +390,7 @@ proc genCall(c: var Con; n: PNode) =
# fork lab1
# goto exceptionHandler (except or finally)
# lab1:
# join F1
forkT:
for i in countdown(c.blocks.high, 0):
if c.blocks[i].isTryBlock:

View File

@@ -289,7 +289,7 @@ template declareClosures(currentFilename: AbsoluteFile, destFile: string) =
let outDirPath: RelativeFile =
presentationPath(conf, AbsoluteFile(basedir / targetRelPath))
# use presentationPath because `..` path can be be mangled to `_._`
result = (string(conf.outDir / outDirPath), "")
result.targetPath = string(conf.outDir / outDirPath)
if not fileExists(result.targetPath):
# this can happen if targetRelPath goes to parent directory `OUTDIR/..`.
# Trying it, this may cause ambiguities, but allows us to insert
@@ -1000,9 +1000,8 @@ proc getTypeKind(n: PNode): string =
proc toLangSymbol(k: TSymKind, n: PNode, baseName: string): LangSymbol =
## Converts symbol info (names/types/parameters) in `n` into format
## `LangSymbol` convenient for ``rst.nim``/``dochelpers.nim``.
result = LangSymbol(name: baseName.nimIdentNormalize,
symKind: k.toHumanStr
)
result.name = baseName.nimIdentNormalize
result.symKind = k.toHumanStr
if k in routineKinds:
var
paramTypes: seq[string] = @[]
@@ -1031,7 +1030,7 @@ proc toLangSymbol(k: TSymKind, n: PNode, baseName: string): LangSymbol =
if genNode != nil:
var literal = ""
var r: TSrcGen = initTokRender(genNode, {renderNoBody, renderNoComments,
renderNoPragmas, renderNoProcDefs, renderExpandUsing, renderNoPostfix})
renderNoPragmas, renderNoProcDefs, renderExpandUsing})
var kind = tkEof
while true:
getNextTok(r, kind, literal)
@@ -1059,7 +1058,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx
# Obtain the plain rendered string for hyperlink titles.
var r: TSrcGen = initTokRender(n, {renderNoBody, renderNoComments, renderDocComments,
renderNoPragmas, renderNoProcDefs, renderExpandUsing, renderNoPostfix})
renderNoPragmas, renderNoProcDefs, renderExpandUsing})
while true:
getNextTok(r, kind, literal)
if kind == tkEof:
@@ -1086,9 +1085,6 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx
symbolOrIdEnc = encodeUrl(symbolOrId, usePlus = false)
deprecationMsg = genDeprecationMsg(d, pragmaNode)
rstLangSymbol = toLangSymbol(k, n, cleanPlainSymbol)
symNameNode =
if nameNode.kind == nkPostfix: nameNode[1]
else: nameNode
# we generate anchors automatically for subsequent use in doc comments
let lineinfo = rstast.TLineInfo(
@@ -1099,10 +1095,10 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx
priority = symbolPriority(k), info = lineinfo,
module = addRstFileIndex(d, FileIndex d.module.position))
var renderFlags = {renderNoBody, renderNoComments, renderDocComments,
renderSyms, renderExpandUsing, renderNoPostfix}
if nonExports:
renderFlags.incl renderNonExportedFields
let renderFlags =
if nonExports: {renderNoBody, renderNoComments, renderDocComments, renderSyms,
renderExpandUsing, renderNonExportedFields}
else: {renderNoBody, renderNoComments, renderDocComments, renderSyms, renderExpandUsing}
nodeToHighlightedHtml(d, n, result, renderFlags, symbolOrIdEnc)
let seeSrc = genSeeSrc(d, toFullPath(d.conf, n.info), n.info.line.int)
@@ -1125,19 +1121,18 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx
let external = d.destFile.AbsoluteFile.relativeTo(d.conf.outDir, '/').changeFileExt(HtmlExt).string
var attype = ""
if k in routineKinds and symNameNode.kind == nkSym:
if k in routineKinds and nameNode.kind == nkSym:
let att = attachToType(d, nameNode.sym)
if att != nil:
attype = esc(d.target, att.name.s)
elif k == skType and symNameNode.kind == nkSym and
symNameNode.sym.typ.kind in {tyEnum, tyBool}:
let etyp = symNameNode.sym.typ
elif k == skType and nameNode.kind == nkSym and nameNode.sym.typ.kind in {tyEnum, tyBool}:
let etyp = nameNode.sym.typ
for e in etyp.n:
if e.sym.kind != skEnumField: continue
let plain = renderPlainSymbolName(e)
let symbolOrId = d.newUniquePlainSymbol(plain)
setIndexTerm(d[], ieNim, htmlFile = external, id = symbolOrId,
term = plain, linkTitle = symNameNode.sym.name.s & '.' & plain,
term = plain, linkTitle = nameNode.sym.name.s & '.' & plain,
linkDesc = xmltree.escape(getPlainDocstring(e).docstringSummary),
line = n.info.line.int)
@@ -1158,8 +1153,8 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx
linkTitle = detailedName,
linkDesc = xmltree.escape(plainDocstring.docstringSummary),
line = n.info.line.int)
if k == skType and symNameNode.kind == nkSym:
d.types.strTableAdd symNameNode.sym
if k == skType and nameNode.kind == nkSym:
d.types.strTableAdd nameNode.sym
proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind, nonExports = false): JsonItem =
if not isVisible(d, nameNode): return
@@ -1167,14 +1162,12 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind, nonExports = false):
name = getNameEsc(d, nameNode)
comm = genRecComment(d, n)
r: TSrcGen
renderFlags = {renderNoBody, renderNoComments, renderDocComments,
renderExpandUsing, renderNoPostfix}
renderFlags = {renderNoBody, renderNoComments, renderDocComments, renderExpandUsing}
if nonExports:
renderFlags.incl renderNonExportedFields
r = initTokRender(n, renderFlags)
result = JsonItem(json: %{ "name": %name, "type": %($k), "line": %n.info.line.int,
result.json = %{ "name": %name, "type": %($k), "line": %n.info.line.int,
"col": %n.info.col}
)
if comm != nil:
result.rst = comm
result.rstField = "description"
@@ -1206,7 +1199,8 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind, nonExports = false):
var param = %{"name": %($genericParam)}
if genericParam.sym.typ.len > 0:
param["types"] = newJArray()
param["types"].add %($genericParam.sym.typ.elementType)
for kind in genericParam.sym.typ:
param["types"].add %($kind)
result.json["signature"]["genericParams"].add param
if optGenIndex in d.conf.globalOptions:
genItem(d, n, nameNode, k, kForceExport)
@@ -1406,8 +1400,7 @@ proc generateDoc*(d: PDoc, n, orig: PNode, config: ConfigRef, docFlags: DocFlags
for it in n: traceDeps(d, it)
of nkExportStmt:
for it in n:
# bug #23051; don't generate documentation for exported symbols again
if it.kind == nkSym and sfExported notin it.sym.flags:
if it.kind == nkSym:
if d.module != nil and d.module == it.sym.owner:
generateDoc(d, it.sym.ast, orig, config, kForceExport)
elif it.sym.ast != nil:

View File

@@ -63,8 +63,8 @@ proc searchObjCaseImpl(obj: PNode; field: PSym): PNode =
proc searchObjCase(t: PType; field: PSym): PNode =
result = searchObjCaseImpl(t.n, field)
if result == nil and t.baseClass != nil:
result = searchObjCase(t.baseClass.skipTypes({tyAlias, tyGenericInst, tyRef, tyPtr}), field)
if result == nil and t.len > 0:
result = searchObjCase(t[0].skipTypes({tyAlias, tyGenericInst, tyRef, tyPtr}), field)
doAssert result != nil
proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGraph; idgen: IdGenerator): PSym =

View File

@@ -99,7 +99,7 @@ proc mapType(conf: ConfigRef, t: ast.PType): ptr libffi.Type =
tyTyped, tyTypeDesc, tyProc, tyArray, tyStatic, tyNil:
result = addr libffi.type_pointer
of tyDistinct, tyAlias, tySink:
result = mapType(conf, t.skipModifier)
result = mapType(conf, t[0])
else:
result = nil
# too risky:
@@ -126,16 +126,16 @@ proc packSize(conf: ConfigRef, v: PNode, typ: PType): int =
if v.kind in {nkNilLit, nkPtrLit}:
result = sizeof(pointer)
else:
result = sizeof(pointer) + packSize(conf, v[0], typ.elementType)
result = sizeof(pointer) + packSize(conf, v[0], typ.lastSon)
of tyDistinct, tyGenericInst, tyAlias, tySink:
result = packSize(conf, v, typ.skipModifier)
result = packSize(conf, v, typ[0])
of tyArray:
# consider: ptr array[0..1000_000, int] which is common for interfacing;
# we use the real length here instead
if v.kind in {nkNilLit, nkPtrLit}:
result = sizeof(pointer)
elif v.len != 0:
result = v.len * packSize(conf, v[0], typ.elementType)
result = v.len * packSize(conf, v[0], typ[1])
else:
result = 0
else:
@@ -234,19 +234,19 @@ proc pack(conf: ConfigRef, v: PNode, typ: PType, res: pointer) =
packRecCheck = 0
globalError(conf, v.info, "cannot map value to FFI " & typeToString(v.typ))
inc packRecCheck
pack(conf, v[0], typ.elementType, res +! sizeof(pointer))
pack(conf, v[0], typ.lastSon, res +! sizeof(pointer))
dec packRecCheck
awr(pointer, res +! sizeof(pointer))
of tyArray:
let baseSize = getSize(conf, typ.elementType)
let baseSize = getSize(conf, typ[1])
for i in 0..<v.len:
pack(conf, v[i], typ.elementType, res +! i * baseSize)
pack(conf, v[i], typ[1], res +! i * baseSize)
of tyObject, tyTuple:
packObject(conf, v, typ, res)
of tyNil:
discard
of tyDistinct, tyGenericInst, tyAlias, tySink:
pack(conf, v, typ.skipModifier, res)
pack(conf, v, typ[0], res)
else:
globalError(conf, v.info, "cannot map value to FFI " & typeToString(v.typ))
@@ -304,9 +304,9 @@ proc unpackArray(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
result = n
if result.kind != nkBracket:
globalError(conf, n.info, "cannot map value from FFI")
let baseSize = getSize(conf, typ.elementType)
let baseSize = getSize(conf, typ[1])
for i in 0..<result.len:
result[i] = unpack(conf, x +! i * baseSize, typ.elementType, result[i])
result[i] = unpack(conf, x +! i * baseSize, typ[1], result[i])
proc canonNodeKind(k: TNodeKind): TNodeKind =
case k
@@ -387,7 +387,7 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
awi(nkPtrLit, cast[int](p))
elif n != nil and n.len == 1:
internalAssert(conf, n.kind == nkRefTy)
n[0] = unpack(conf, p, typ.elementType, n[0])
n[0] = unpack(conf, p, typ.lastSon, n[0])
result = n
else:
result = nil
@@ -405,7 +405,7 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
of tyNil:
setNil()
of tyDistinct, tyGenericInst, tyAlias, tySink:
result = unpack(conf, x, typ.skipModifier, n)
result = unpack(conf, x, typ.lastSon, n)
else:
# XXX what to do with 'array' here?
result = nil
@@ -434,7 +434,7 @@ proc fficast*(conf: ConfigRef, x: PNode, destTyp: PType): PNode =
proc callForeignFunction*(conf: ConfigRef, call: PNode): PNode =
internalAssert conf, call[0].kind == nkPtrLit
var cif: TCif = default(TCif)
var cif: TCif
var sig: ParamList = default(ParamList)
# use the arguments' types for varargs support:
for i in 1..<call.len:
@@ -444,7 +444,7 @@ proc callForeignFunction*(conf: ConfigRef, call: PNode): PNode =
let typ = call[0].typ
if prep_cif(cif, mapCallConv(conf, typ.callConv, call.info), cuint(call.len-1),
mapType(conf, typ.returnType), sig) != OK:
mapType(conf, typ[0]), sig) != OK:
globalError(conf, call.info, "error in FFI call")
var args: ArgList = default(ArgList)
@@ -453,15 +453,15 @@ proc callForeignFunction*(conf: ConfigRef, call: PNode): PNode =
var t = call[i].typ
args[i-1] = alloc0(packSize(conf, call[i], t))
pack(conf, call[i], t, args[i-1])
let retVal = if isEmptyType(typ.returnType): pointer(nil)
else: alloc(getSize(conf, typ.returnType).int)
let retVal = if isEmptyType(typ[0]): pointer(nil)
else: alloc(getSize(conf, typ[0]).int)
libffi.call(cif, fn, retVal, args)
if retVal.isNil:
result = newNode(nkEmpty)
else:
result = unpack(conf, retVal, typ.returnType, nil)
result = unpack(conf, retVal, typ[0], nil)
result.info = call.info
if retVal != nil: dealloc retVal
@@ -474,7 +474,7 @@ proc callForeignFunction*(conf: ConfigRef, fn: PNode, fntyp: PType,
info: TLineInfo): PNode =
internalAssert conf, fn.kind == nkPtrLit
var cif: TCif = default(TCif)
var cif: TCif
var sig: ParamList = default(ParamList)
for i in 0..len-1:
var aTyp = args[i+start].typ

View File

@@ -17,8 +17,8 @@ type
owner, genSymOwner: PSym
instLines: bool # use the instantiation lines numbers
isDeclarative: bool
mapping: SymMapping # every gensym'ed symbol needs to be mapped to some
# new symbol
mapping: TIdTable # every gensym'ed symbol needs to be mapped to some
# new symbol
config: ConfigRef
ic: IdentCache
instID: int
@@ -44,10 +44,10 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
handleParam actual[s.position]
elif (s.owner != nil) and (s.kind == skGenericParam or
s.kind == skType and s.typ != nil and s.typ.kind == tyGenericParam):
handleParam actual[s.owner.typ.signatureLen + s.position - 1]
handleParam actual[s.owner.typ.len + s.position - 1]
else:
internalAssert c.config, sfGenSym in s.flags or s.kind == skType
var x = idTableGet(c.mapping, s)
var x = PSym(idTableGet(c.mapping, s))
if x == nil:
x = copySym(s, c.idgen)
# sem'check needs to set the owner properly later, see bug #9476
@@ -56,7 +56,6 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
# internalAssert c.config, false
idTablePut(c.mapping, s, x)
if sfGenSym in s.flags:
# TODO: getIdent(c.ic, "`" & x.name.s & "`gensym" & $c.instID)
result.add newIdentNode(getIdent(c.ic, x.name.s & "`gensym" & $c.instID),
if c.instLines: actual.info else: templ.info)
else:
@@ -117,7 +116,7 @@ proc evalTemplateArgs(n: PNode, s: PSym; conf: ConfigRef; fromHlo: bool): PNode
# now that we have working untyped parameters.
genericParams = if fromHlo: 0
else: s.ast[genericParamsPos].len
expectedRegularParams = s.typ.paramsLen
expectedRegularParams = s.typ.len-1
givenRegularParams = totalParams - genericParams
if givenRegularParams < 0: givenRegularParams = 0
@@ -183,14 +182,14 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
# replace each param by the corresponding node:
var args = evalTemplateArgs(n, tmpl, conf, fromHlo)
var ctx = TemplCtx(owner: tmpl,
genSymOwner: genSymOwner,
config: conf,
ic: ic,
mapping: initSymMapping(),
instID: instID[],
idgen: idgen
)
var ctx: TemplCtx
ctx.owner = tmpl
ctx.genSymOwner = genSymOwner
ctx.config = conf
ctx.ic = ic
ctx.mapping = initIdTable()
ctx.instID = instID[]
ctx.idgen = idgen
let body = tmpl.ast[bodyPos]
#echo "instantion of ", renderTree(body, {renderIds})

View File

@@ -55,8 +55,8 @@ proc expandDefaultN(n: PNode; info: TLineInfo; res: PNode) =
discard
proc expandDefaultObj(t: PType; info: TLineInfo; res: PNode) =
if t.baseClass != nil:
expandDefaultObj(t.baseClass, info, res)
if t[0] != nil:
expandDefaultObj(t[0], info, res)
expandDefaultN(t.n, info, res)
proc expandDefault(t: PType; info: TLineInfo): PNode =
@@ -82,13 +82,13 @@ proc expandDefault(t: PType; info: TLineInfo): PNode =
result = newZero(t, info, nkIntLit)
of tyRange:
# Could use low(T) here to finally fix old language quirks
result = expandDefault(skipModifier t, info)
result = expandDefault(t[0], info)
of tyVoid: result = newZero(t, info, nkEmpty)
of tySink, tyGenericInst, tyDistinct, tyAlias, tyOwned:
result = expandDefault(t.skipModifier, info)
result = expandDefault(t.lastSon, info)
of tyOrdinal, tyGenericBody, tyGenericParam, tyInferred, tyStatic:
if t.hasElementType:
result = expandDefault(t.skipModifier, info)
if t.len > 0:
result = expandDefault(t.lastSon, info)
else:
result = newZero(t, info, nkEmpty)
of tyFromExpr:
@@ -100,16 +100,16 @@ proc expandDefault(t: PType; info: TLineInfo): PNode =
result = newZero(t, info, nkBracket)
let n = toInt64(lengthOrd(nil, t))
for i in 0..<n:
result.add expandDefault(t.elementType, info)
result.add expandDefault(t[1], info)
of tyPtr, tyRef, tyProc, tyPointer, tyCstring:
result = newZero(t, info, nkNilLit)
of tyVar, tyLent:
let e = t.elementType
let e = t.lastSon
if e.skipTypes(abstractInst).kind in {tyOpenArray, tyVarargs}:
# skip the modifier, `var openArray` is a (ptr, len) pair too:
result = expandDefault(e, info)
else:
result = newZero(e, info, nkNilLit)
result = newZero(t.lastSon, info, nkNilLit)
of tySet:
result = newZero(t, info, nkCurly)
of tyObject:
@@ -118,7 +118,7 @@ proc expandDefault(t: PType; info: TLineInfo): PNode =
expandDefaultObj(t, info, result)
of tyTuple:
result = newZero(t, info, nkTupleConstr)
for it in t.kids:
for it in t:
result.add expandDefault(it, info)
of tyVarargs, tyOpenArray, tySequence, tyUncheckedArray:
result = newZero(t, info, nkBracket)

View File

@@ -19,7 +19,7 @@ import std/[os, osproc, streams, sequtils, times, strtabs, json, jsonutils, suga
import std / strutils except addf
when defined(nimPreviewSlimSystem):
import std/[syncio, assertions]
import std/syncio
import ../dist/checksums/src/checksums/sha1
@@ -999,7 +999,7 @@ type BuildCache = object
depfiles: seq[(string, string)]
nimexe: string
proc writeJsonBuildInstructions*(conf: ConfigRef; deps: StringTableRef) =
proc writeJsonBuildInstructions*(conf: ConfigRef) =
var linkFiles = collect(for it in conf.externalToLink:
var it = it
if conf.noAbsolutePaths: it = it.extractFilename
@@ -1020,14 +1020,10 @@ proc writeJsonBuildInstructions*(conf: ConfigRef; deps: StringTableRef) =
currentDir: getCurrentDir())
if optRun in conf.globalOptions or isDefined(conf, "nimBetterRun"):
bcache.cmdline = conf.commandLine
for it in conf.m.fileInfos:
bcache.depfiles = collect(for it in conf.m.fileInfos:
let path = it.fullPath.string
if isAbsolute(path): # TODO: else?
if path in deps:
bcache.depfiles.add (path, deps[path])
else: # backup for configs etc.
bcache.depfiles.add (path, $secureHashFile(path))
(path, $secureHashFile(path)))
bcache.nimexe = hashNimExe()
conf.jsonBuildFile = conf.jsonBuildInstructionsFile
conf.jsonBuildFile.string.writeFile(bcache.toJson.pretty)

View File

@@ -1063,7 +1063,7 @@ proc pleViaModel(model: TModel; aa, bb: PNode): TImplication =
let b = fact[2]
if a.kind == nkSym: replacements.add((a,b))
else: replacements.add((b,a))
var m = TModel()
var m: TModel
var a = aa
var b = bb
if replacements.len > 0:

View File

@@ -33,7 +33,7 @@ type
HasDatInitProc
HasModuleInitProc
PackedModuleReader* = object ## the parts of a PackedEncoder that are part of the .rod file
PackedModule* = object ## the parts of a PackedEncoder that are part of the .rod file
definedSymbols: string
moduleFlags: TSymFlags
includes*: seq[(LitId, string)] # first entry is the module filename itself
@@ -59,43 +59,8 @@ type
emittedTypeInfo*: seq[string]
backendFlags*: set[ModuleBackendFlag]
syms*: OrderedTable[int32, PackedSym]
types*: OrderedTable[int32, PackedType]
strings*: BiTable[string] # we could share these between modules.
numbers*: BiTable[BiggestInt] # we also store floats in here so
# that we can assure that every bit is kept
man*: LineInfoManager
cfg: PackedConfig
PackedModuleWriter* = object ## the parts of a PackedEncoder that are part of the .rod file
definedSymbols: string
moduleFlags: TSymFlags
includes*: seq[(LitId, string)] # first entry is the module filename itself
imports: seq[LitId] # the modules this module depends on
toReplay*: PackedTree # pragmas and VM specific state to replay.
topLevel*: PackedTree # top level statements
bodies*: PackedTree # other trees. Referenced from typ.n and sym.ast by their position.
#producedGenerics*: Table[GenericKey, SymId]
exports*: seq[(LitId, int32)]
hidden: seq[(LitId, int32)]
reexports: seq[(LitId, PackedItemId)]
compilerProcs*: seq[(LitId, int32)]
converters*, methods*, trmacros*, pureEnums*: seq[int32]
typeInstCache*: seq[(PackedItemId, PackedItemId)]
procInstCache*: seq[PackedInstantiation]
attachedOps*: seq[(PackedItemId, TTypeAttachedOp, PackedItemId)]
methodsPerGenericType*: seq[(PackedItemId, int, PackedItemId)]
enumToStringProcs*: seq[(PackedItemId, PackedItemId)]
methodsPerType*: seq[(PackedItemId, PackedItemId)]
dispatchers*: seq[PackedItemId]
emittedTypeInfo*: seq[string]
backendFlags*: set[ModuleBackendFlag]
syms*: OrderedTable[int32, PackedSym]
types*: OrderedTable[int32, PackedType]
syms*: seq[PackedSym]
types*: seq[PackedType]
strings*: BiTable[string] # we could share these between modules.
numbers*: BiTable[BiggestInt] # we also store floats in here so
# that we can assure that every bit is kept
@@ -104,7 +69,7 @@ type
cfg: PackedConfig
PackedEncoder* = object
#m*: PackedModuleWriter
#m*: PackedModule
thisModule*: int32
lastFile*: FileIndex # remember the last lookup entry.
lastLit*: LitId
@@ -115,7 +80,7 @@ type
symMarker*: IntSet #Table[ItemId, SymId] # ItemId.item -> SymId
config*: ConfigRef
proc toString*(tree: PackedTree; pos: NodePos; m: PackedModuleWriter|PackedModuleReader; nesting: int;
proc toString*(tree: PackedTree; pos: NodePos; m: PackedModule; nesting: int;
result: var string) =
if result.len > 0 and result[^1] notin {' ', '\n'}:
result.add ' '
@@ -151,11 +116,11 @@ proc toString*(tree: PackedTree; pos: NodePos; m: PackedModuleWriter|PackedModul
result.add ")"
#for i in 1..nesting*2: result.add ' '
proc toString*(tree: PackedTree; n: NodePos; m: PackedModuleWriter|PackedModuleReader): string =
proc toString*(tree: PackedTree; n: NodePos; m: PackedModule): string =
result = ""
toString(tree, n, m, 0, result)
proc debug*(tree: PackedTree; m: PackedModuleWriter|PackedModuleReader) =
proc debug*(tree: PackedTree; m: PackedModule) =
stdout.write toString(tree, NodePos 0, m)
proc isActive*(e: PackedEncoder): bool = e.config != nil
@@ -175,7 +140,7 @@ proc definedSymbolsAsString(config: ConfigRef): string =
result.add ' '
result.add d
proc rememberConfig(c: var PackedEncoder; m: var PackedModuleWriter; config: ConfigRef; pc: PackedConfig) =
proc rememberConfig(c: var PackedEncoder; m: var PackedModule; config: ConfigRef; pc: PackedConfig) =
m.definedSymbols = definedSymbolsAsString(config)
#template rem(x) =
# c.m.cfg.x = config.x
@@ -188,7 +153,7 @@ const
when debugConfigDiff:
import hashes, tables, intsets, sha1, strutils, sets
proc configIdentical(m: PackedModuleReader; config: ConfigRef): bool =
proc configIdentical(m: PackedModule; config: ConfigRef): bool =
result = m.definedSymbols == definedSymbolsAsString(config)
when debugConfigDiff:
if not result:
@@ -218,7 +183,7 @@ proc hashFileCached(conf: ConfigRef; fileIdx: FileIndex): string =
result = $secureHashFile(fullpath)
msgs.setHash(conf, fileIdx, result)
proc toLitId(x: FileIndex; c: var PackedEncoder; m: var PackedModuleWriter): LitId =
proc toLitId(x: FileIndex; c: var PackedEncoder; m: var PackedModule): LitId =
## store a file index as a literal
if x == c.lastFile:
result = c.lastLit
@@ -232,16 +197,16 @@ proc toLitId(x: FileIndex; c: var PackedEncoder; m: var PackedModuleWriter): Lit
c.lastLit = result
assert result != LitId(0)
proc toFileIndex*(x: LitId; m: PackedModuleReader; config: ConfigRef): FileIndex =
proc toFileIndex*(x: LitId; m: PackedModule; config: ConfigRef): FileIndex =
result = msgs.fileInfoIdx(config, AbsoluteFile m.strings[x])
proc includesIdentical(m: var PackedModuleReader; config: ConfigRef): bool =
proc includesIdentical(m: var PackedModule; config: ConfigRef): bool =
for it in mitems(m.includes):
if hashFileCached(config, toFileIndex(it[0], m, config)) != it[1]:
return false
result = true
proc initEncoder*(c: var PackedEncoder; m: var PackedModuleWriter; moduleSym: PSym; config: ConfigRef; pc: PackedConfig) =
proc initEncoder*(c: var PackedEncoder; m: var PackedModule; moduleSym: PSym; config: ConfigRef; pc: PackedConfig) =
## setup a context for serializing to packed ast
c.thisModule = moduleSym.itemId.module
c.config = config
@@ -263,54 +228,54 @@ proc initEncoder*(c: var PackedEncoder; m: var PackedModuleWriter; moduleSym: PS
rememberConfig(c, m, config, pc)
proc addIncludeFileDep*(c: var PackedEncoder; m: var PackedModuleWriter; f: FileIndex) =
proc addIncludeFileDep*(c: var PackedEncoder; m: var PackedModule; f: FileIndex) =
m.includes.add((toLitId(f, c, m), hashFileCached(c.config, f)))
proc addImportFileDep*(c: var PackedEncoder; m: var PackedModuleWriter; f: FileIndex) =
proc addImportFileDep*(c: var PackedEncoder; m: var PackedModule; f: FileIndex) =
m.imports.add toLitId(f, c, m)
proc addHidden*(c: var PackedEncoder; m: var PackedModuleWriter; s: PSym) =
proc addHidden*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
assert s.kind != skUnknown
let nameId = getOrIncl(m.strings, s.name.s)
m.hidden.add((nameId, s.itemId.item))
assert s.itemId.module == c.thisModule
proc addExported*(c: var PackedEncoder; m: var PackedModuleWriter; s: PSym) =
proc addExported*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
assert s.kind != skUnknown
assert s.itemId.module == c.thisModule
let nameId = getOrIncl(m.strings, s.name.s)
m.exports.add((nameId, s.itemId.item))
proc addConverter*(c: var PackedEncoder; m: var PackedModuleWriter; s: PSym) =
proc addConverter*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
assert c.thisModule == s.itemId.module
m.converters.add(s.itemId.item)
proc addTrmacro*(c: var PackedEncoder; m: var PackedModuleWriter; s: PSym) =
proc addTrmacro*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
m.trmacros.add(s.itemId.item)
proc addPureEnum*(c: var PackedEncoder; m: var PackedModuleWriter; s: PSym) =
proc addPureEnum*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
assert s.kind == skType
m.pureEnums.add(s.itemId.item)
proc addMethod*(c: var PackedEncoder; m: var PackedModuleWriter; s: PSym) =
proc addMethod*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
m.methods.add s.itemId.item
proc addReexport*(c: var PackedEncoder; m: var PackedModuleWriter; s: PSym) =
proc addReexport*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
assert s.kind != skUnknown
if s.kind == skModule: return
let nameId = getOrIncl(m.strings, s.name.s)
m.reexports.add((nameId, PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m),
item: s.itemId.item)))
proc addCompilerProc*(c: var PackedEncoder; m: var PackedModuleWriter; s: PSym) =
proc addCompilerProc*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
let nameId = getOrIncl(m.strings, s.name.s)
m.compilerProcs.add((nameId, s.itemId.item))
proc toPackedNode*(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModuleWriter)
proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModuleWriter): PackedItemId
proc storeType(t: PType; c: var PackedEncoder; m: var PackedModuleWriter): PackedItemId
proc toPackedNode*(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModule)
proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId
proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemId
proc flush(c: var PackedEncoder; m: var PackedModuleWriter) =
proc flush(c: var PackedEncoder; m: var PackedModule) =
## serialize any pending types or symbols from the context
while true:
if c.pendingTypes.len > 0:
@@ -320,19 +285,19 @@ proc flush(c: var PackedEncoder; m: var PackedModuleWriter) =
else:
break
proc toLitId(x: string; m: var PackedModuleWriter): LitId =
proc toLitId(x: string; m: var PackedModule): LitId =
## store a string as a literal
result = getOrIncl(m.strings, x)
proc toLitId(x: BiggestInt; m: var PackedModuleWriter): LitId =
proc toLitId(x: BiggestInt; m: var PackedModule): LitId =
## store an integer as a literal
result = getOrIncl(m.numbers, x)
proc toPackedInfo(x: TLineInfo; c: var PackedEncoder; m: var PackedModuleWriter): PackedLineInfo =
proc toPackedInfo(x: TLineInfo; c: var PackedEncoder; m: var PackedModule): PackedLineInfo =
pack(m.man, toLitId(x.fileIndex, c, m), x.line.int32, x.col.int32)
#PackedLineInfo(line: x.line, col: x.col, file: toLitId(x.fileIndex, c, m))
proc safeItemId(s: PSym; c: var PackedEncoder; m: var PackedModuleWriter): PackedItemId {.inline.} =
proc safeItemId(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId {.inline.} =
## given a symbol, produce an ItemId with the correct properties
## for local or remote symbols, packing the symbol as necessary
if s == nil or s.kind == skPackage:
@@ -366,7 +331,7 @@ template storeNode(dest, src, field) =
nodeId = emptyNodeId
dest.field = nodeId
proc storeTypeLater(t: PType; c: var PackedEncoder; m: var PackedModuleWriter): PackedItemId =
proc storeTypeLater(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemId =
# We store multiple different trees in m.bodies. For this to work out, we
# cannot immediately store types/syms. We enqueue them instead to ensure
# we only write one tree into m.bodies after the other.
@@ -379,7 +344,7 @@ proc storeTypeLater(t: PType; c: var PackedEncoder; m: var PackedModuleWriter):
# the type belongs to this module, so serialize it here, eventually.
addMissing(c, t)
proc storeSymLater(s: PSym; c: var PackedEncoder; m: var PackedModuleWriter): PackedItemId =
proc storeSymLater(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId =
if s.isNil: return nilItemId
assert s.itemId.module >= 0
assert s.itemId.item >= 0
@@ -388,7 +353,7 @@ proc storeSymLater(s: PSym; c: var PackedEncoder; m: var PackedModuleWriter): Pa
# the sym belongs to this module, so serialize it here, eventually.
addMissing(c, s)
proc storeType(t: PType; c: var PackedEncoder; m: var PackedModuleWriter): PackedItemId =
proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemId =
## serialize a ptype
if t.isNil: return nilItemId
@@ -397,15 +362,15 @@ proc storeType(t: PType; c: var PackedEncoder; m: var PackedModuleWriter): Packe
result = PackedItemId(module: toLitId(t.uniqueId.module.FileIndex, c, m), item: t.uniqueId.item)
if t.uniqueId.module == c.thisModule and not c.typeMarker.containsOrIncl(t.uniqueId.item):
#if t.uniqueId.item >= m.types.len:
# setLen m.types, t.uniqueId.item+1
if t.uniqueId.item >= m.types.len:
setLen m.types, t.uniqueId.item+1
var p = PackedType(id: t.uniqueId.item, kind: t.kind, flags: t.flags, callConv: t.callConv,
var p = PackedType(kind: t.kind, flags: t.flags, callConv: t.callConv,
size: t.size, align: t.align, nonUniqueId: t.itemId.item,
paddingAtEnd: t.paddingAtEnd)
storeNode(p, t, n)
p.typeInst = t.typeInst.storeType(c, m)
for kid in kids t:
for kid in items t:
p.types.add kid.storeType(c, m)
c.addMissing t.sym
p.sym = t.sym.safeItemId(c, m)
@@ -415,15 +380,16 @@ proc storeType(t: PType; c: var PackedEncoder; m: var PackedModuleWriter): Packe
# fill the reserved slot, nothing else:
m.types[t.uniqueId.item] = p
proc toPackedLib(l: PLib; c: var PackedEncoder; m: var PackedModuleWriter): PackedLib =
proc toPackedLib(l: PLib; c: var PackedEncoder; m: var PackedModule): PackedLib =
## the plib hangs off the psym via the .annex field
if l.isNil: return
result = PackedLib(kind: l.kind, generated: l.generated,
isOverridden: l.isOverridden, name: toLitId($l.name, m)
)
result.kind = l.kind
result.generated = l.generated
result.isOverridden = l.isOverridden
result.name = toLitId($l.name, m)
storeNode(result, l, path)
proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModuleWriter): PackedItemId =
proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId =
## serialize a psym
if s.isNil: return nilItemId
@@ -431,12 +397,12 @@ proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModuleWriter): Packed
result = PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), item: s.itemId.item)
if s.itemId.module == c.thisModule and not c.symMarker.containsOrIncl(s.itemId.item):
#if s.itemId.item >= m.syms.len:
# setLen m.syms, s.itemId.item+1
if s.itemId.item >= m.syms.len:
setLen m.syms, s.itemId.item+1
assert sfForward notin s.flags
var p = PackedSym(id: s.itemId.item, kind: s.kind, flags: s.flags, info: s.info.toPackedInfo(c, m), magic: s.magic,
var p = PackedSym(kind: s.kind, flags: s.flags, info: s.info.toPackedInfo(c, m), magic: s.magic,
position: s.position, offset: s.offset, disamb: s.disamb, options: s.options,
name: s.name.s.toLitId(m))
@@ -463,22 +429,22 @@ proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModuleWriter): Packed
# fill the reserved slot, nothing else:
m.syms[s.itemId.item] = p
proc addModuleRef(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModuleWriter) =
proc addModuleRef(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModule) =
## add a remote symbol reference to the tree
let info = n.info.toPackedInfo(c, m)
if n.typ != n.sym.typ:
ir.addNode(kind = nkModuleRef, operand = 3.int32, # spans 3 nodes in total
info = info, flags = n.flags,
info = info,
typeId = storeTypeLater(n.typ, c, m))
else:
ir.addNode(kind = nkModuleRef, operand = 3.int32, # spans 3 nodes in total
info = info, flags = n.flags)
info = info)
ir.addNode(kind = nkNone, info = info,
operand = toLitId(n.sym.itemId.module.FileIndex, c, m).int32)
ir.addNode(kind = nkNone, info = info,
operand = n.sym.itemId.item)
proc toPackedNode*(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModuleWriter) =
proc toPackedNode*(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModule) =
## serialize a node into the tree
if n == nil:
ir.addNode(kind = nkNilRodNode, operand = 1, info = NoLineInfo)
@@ -526,13 +492,13 @@ proc toPackedNode*(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var Pa
toPackedNode(n[i], ir, c, m)
ir.patch patchPos
proc storeTypeInst*(c: var PackedEncoder; m: var PackedModuleWriter; s: PSym; inst: PType) =
proc storeTypeInst*(c: var PackedEncoder; m: var PackedModule; s: PSym; inst: PType) =
m.typeInstCache.add (storeSymLater(s, c, m), storeTypeLater(inst, c, m))
proc addPragmaComputation*(c: var PackedEncoder; m: var PackedModuleWriter; n: PNode) =
proc addPragmaComputation*(c: var PackedEncoder; m: var PackedModule; n: PNode) =
toPackedNode(n, m.toReplay, c, m)
proc toPackedProcDef(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModuleWriter) =
proc toPackedProcDef(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModule) =
let info = toPackedInfo(n.info, c, m)
let patchPos = ir.prepare(n.kind, n.flags,
storeTypeLater(n.typ, c, m), info)
@@ -547,7 +513,7 @@ proc toPackedProcDef(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var
typeId = nilItemId, info = info)
ir.patch patchPos
proc toPackedNodeIgnoreProcDefs(n: PNode, encoder: var PackedEncoder; m: var PackedModuleWriter) =
proc toPackedNodeIgnoreProcDefs(n: PNode, encoder: var PackedEncoder; m: var PackedModule) =
case n.kind
of routineDefs:
toPackedProcDef(n, m.topLevel, encoder, m)
@@ -569,11 +535,11 @@ proc toPackedNodeIgnoreProcDefs(n: PNode, encoder: var PackedEncoder; m: var Pac
else:
toPackedNode(n, m.topLevel, encoder, m)
proc toPackedNodeTopLevel*(n: PNode, encoder: var PackedEncoder; m: var PackedModuleWriter) =
proc toPackedNodeTopLevel*(n: PNode, encoder: var PackedEncoder; m: var PackedModule) =
toPackedNodeIgnoreProcDefs(n, encoder, m)
flush encoder, m
proc toPackedGeneratedProcDef*(s: PSym, encoder: var PackedEncoder; m: var PackedModuleWriter) =
proc toPackedGeneratedProcDef*(s: PSym, encoder: var PackedEncoder; m: var PackedModule) =
## Generic procs and generated `=hook`'s need explicit top-level entries so
## that the code generator can work without having to special case these. These
## entries will also be useful for other tools and are the cleanest design
@@ -583,7 +549,7 @@ proc toPackedGeneratedProcDef*(s: PSym, encoder: var PackedEncoder; m: var Packe
#flush encoder, m
proc storeAttachedProcDef*(t: PType; op: TTypeAttachedOp; s: PSym,
encoder: var PackedEncoder; m: var PackedModuleWriter) =
encoder: var PackedEncoder; m: var PackedModule) =
assert s.kind in routineKinds
assert isActive(encoder)
let tid = storeTypeLater(t, encoder, m)
@@ -591,7 +557,7 @@ proc storeAttachedProcDef*(t: PType; op: TTypeAttachedOp; s: PSym,
m.attachedOps.add (tid, op, sid)
toPackedGeneratedProcDef(s, encoder, m)
proc storeInstantiation*(c: var PackedEncoder; m: var PackedModuleWriter; s: PSym; i: PInstantiation) =
proc storeInstantiation*(c: var PackedEncoder; m: var PackedModule; s: PSym; i: PInstantiation) =
var t = newSeq[PackedItemId](i.concreteTypes.len)
for j in 0..high(i.concreteTypes):
t[j] = storeTypeLater(i.concreteTypes[j], c, m)
@@ -600,7 +566,7 @@ proc storeInstantiation*(c: var PackedEncoder; m: var PackedModuleWriter; s: PSy
concreteTypes: t)
toPackedGeneratedProcDef(i.sym, c, m)
proc storeExpansion*(c: var PackedEncoder; m: var PackedModuleWriter; info: TLineInfo; s: PSym) =
proc storeExpansion*(c: var PackedEncoder; m: var PackedModule; info: TLineInfo; s: PSym) =
toPackedNode(newSymNode(s, info), m.bodies, c, m)
proc loadError(err: RodFileError; filename: AbsoluteFile; config: ConfigRef;) =
@@ -631,7 +597,7 @@ when BenchIC:
else:
template bench(x, body) = body
proc loadRodFile*(filename: AbsoluteFile; m: var PackedModuleReader; config: ConfigRef;
proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef;
ignoreConfig = false): RodFileError =
var f = rodfiles.open(filename.string)
f.loadHeader()
@@ -648,10 +614,6 @@ proc loadRodFile*(filename: AbsoluteFile; m: var PackedModuleReader; config: Con
f.loadSection section
f.loadSeq data
template loadTableSection(section, data) {.dirty.} =
f.loadSection section
f.loadOrderedTable data
template loadTabSection(section, data) {.dirty.} =
f.loadSection section
f.load data
@@ -684,8 +646,8 @@ proc loadRodFile*(filename: AbsoluteFile; m: var PackedModuleReader; config: Con
loadTabSection topLevelSection, m.topLevel
loadTabSection bodiesSection, m.bodies
loadTableSection symsSection, m.syms
loadTableSection typesSection, m.types
loadSeqSection symsSection, m.syms
loadSeqSection typesSection, m.types
loadSeqSection typeInstCacheSection, m.typeInstCache
loadSeqSection procInstCacheSection, m.procInstCache
@@ -711,7 +673,7 @@ proc storeError(err: RodFileError; filename: AbsoluteFile) =
echo "Error: ", $err, "; couldn't write to ", filename.string
removeFile(filename.string)
proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder; m: var PackedModuleWriter) =
proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder; m: var PackedModule) =
flush encoder, m
#rememberConfig(encoder, encoder.config)
@@ -730,10 +692,6 @@ proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder; m: var Pac
f.storeSection section
f.store data
template storeTableSection(section, data) {.dirty.} =
f.storeSection section
f.storeOrderedTable data
storeTabSection stringsSection, m.strings
storeSeqSection checkSumsSection, m.includes
@@ -757,9 +715,9 @@ proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder; m: var Pac
storeTabSection topLevelSection, m.topLevel
storeTabSection bodiesSection, m.bodies
storeTableSection symsSection, m.syms
storeSeqSection symsSection, m.syms
storeTableSection typesSection, m.types
storeSeqSection typesSection, m.types
storeSeqSection typeInstCacheSection, m.typeInstCache
storeSeqSection procInstCacheSection, m.procInstCache
@@ -783,7 +741,7 @@ proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder; m: var Pac
when false:
# basic loader testing:
var m2: PackedModuleReader
var m2: PackedModule
discard loadRodFile(filename, m2, encoder.config)
echo "loaded ", filename.string
@@ -809,10 +767,9 @@ type
LoadedModule* = object
status*: ModuleStatus
symsInit, typesInit, loadedButAliveSetChanged*: bool
fromDisk*: PackedModuleReader
toDisk*: PackedModuleWriter
syms: OrderedTable[int32, PSym] # indexed by itemId
types: OrderedTable[int32, PType]
fromDisk*: PackedModule
syms: seq[PSym] # indexed by itemId
types: seq[PType]
module*: PSym # the one true module symbol.
iface, ifaceHidden: Table[PIdent, seq[PackedItemId]]
# PackedItemId so that it works with reexported symbols too
@@ -873,8 +830,7 @@ proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
result.ident = getIdent(c.cache, g[thisModule].fromDisk.strings[n.litId])
of nkSym:
result.sym = loadSym(c, g, thisModule, PackedItemId(module: LitId(0), item: tree[n].soperand))
if result.typ == nil and nfOpenSym notin result.flags:
result.typ = result.sym.typ
if result.typ == nil: result.typ = result.sym.typ
of externIntLit:
result.intVal = g[thisModule].fromDisk.numbers[n.litId]
of nkStrLit..nkTripleStrLit:
@@ -887,8 +843,7 @@ proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
assert n2.kind == nkNone
transitionNoneToSym(result)
result.sym = loadSym(c, g, thisModule, PackedItemId(module: n1.litId, item: tree[n2].soperand))
if result.typ == nil and nfOpenSym notin result.flags:
result.typ = result.sym.typ
if result.typ == nil: result.typ = result.sym.typ
else:
for n0 in sonsReadonly(tree, n):
result.addAllowNil loadNodes(c, g, thisModule, tree, n0)
@@ -1005,11 +960,11 @@ proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s:
loadToReplayNodes(g, c.config, c.cache, m, g[int m])
assert g[si].status in {loaded, storing, stored}
#if not g[si].symsInit:
# g[si].symsInit = true
# setLen g[si].syms, g[si].fromDisk.syms.len
if not g[si].symsInit:
g[si].symsInit = true
setLen g[si].syms, g[si].fromDisk.syms.len
if g[si].syms.getOrDefault(s.item) == nil:
if g[si].syms[s.item] == nil:
if g[si].fromDisk.syms[s.item].kind != skModule:
result = symHeaderFromPacked(c, g, g[si].fromDisk.syms[s.item], si, s.item)
# store it here early on, so that recursions work properly:
@@ -1056,11 +1011,11 @@ proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; t
assert g[si].status in {loaded, storing, stored}
assert t.item > 0
#if not g[si].typesInit:
# g[si].typesInit = true
# setLen g[si].types, g[si].fromDisk.types.len
if not g[si].typesInit:
g[si].typesInit = true
setLen g[si].types, g[si].fromDisk.types.len
if g[si].types.getOrDefault(t.item) == nil:
if g[si].types[t.item] == nil:
result = typeHeaderFromPacked(c, g, g[si].fromDisk.types[t.item], si, t.item)
# store it here early on, so that recursions work properly:
g[si].types[t.item] = result
@@ -1199,7 +1154,10 @@ proc loadProcBody*(config: ConfigRef, cache: IdentCache;
proc loadTypeFromId*(config: ConfigRef, cache: IdentCache;
g: var PackedModuleGraph; module: int; id: PackedItemId): PType =
bench g.loadType:
result = g[module].types.getOrDefault(id.item)
if id.item < g[module].types.len:
result = g[module].types[id.item]
else:
result = nil
if result == nil:
var decoder = PackedDecoder(
lastModule: int32(-1),
@@ -1212,7 +1170,10 @@ proc loadTypeFromId*(config: ConfigRef, cache: IdentCache;
proc loadSymFromId*(config: ConfigRef, cache: IdentCache;
g: var PackedModuleGraph; module: int; id: PackedItemId): PSym =
bench g.loadSym:
result = g[module].syms.getOrDefault(id.item)
if id.item < g[module].syms.len:
result = g[module].syms[id.item]
else:
result = nil
if result == nil:
var decoder = PackedDecoder(
lastModule: int32(-1),
@@ -1228,8 +1189,21 @@ proc translateId*(id: PackedItemId; g: PackedModuleGraph; thisModule: int; confi
else:
ItemId(module: toFileIndex(id.module, g[thisModule].fromDisk, config).int32, item: id.item)
proc checkForHoles(m: PackedModule; config: ConfigRef; moduleId: int) =
var bugs = 0
for i in 1 .. high(m.syms):
if m.syms[i].kind == skUnknown:
echo "EMPTY ID ", i, " module ", moduleId, " ", toFullPath(config, FileIndex(moduleId))
inc bugs
assert bugs == 0
when false:
var nones = 0
for i in 1 .. high(m.types):
inc nones, m.types[i].kind == tyNone
assert nones < 1
proc simulateLoadedModule*(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
moduleSym: PSym; m: PackedModuleWriter) =
moduleSym: PSym; m: PackedModule) =
# For now only used for heavy debugging. In the future we could use this to reduce the
# compiler's memory consumption.
let idx = moduleSym.position
@@ -1327,7 +1301,7 @@ proc searchForCompilerproc*(m: LoadedModule; name: string): int32 =
# ------------------------- .rod file viewer ---------------------------------
proc rodViewer*(rodfile: AbsoluteFile; config: ConfigRef, cache: IdentCache) =
var m: PackedModuleReader = PackedModuleReader()
var m: PackedModule = PackedModule()
let err = loadRodFile(rodfile, m, config, ignoreConfig=true)
if err != ok:
config.quitOrRaise "Error: could not load: " & $rodfile.string & " reason: " & $err

View File

@@ -10,7 +10,7 @@
## Integrity checking for a set of .rod files.
## The set must cover a complete Nim project.
import std/[sets, tables]
import std/sets
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -100,26 +100,26 @@ proc checkNode(c: var CheckedContext; tree: PackedTree; n: NodePos) =
proc checkTree(c: var CheckedContext; t: PackedTree) =
for p in allNodes(t): checkNode(c, t, p)
proc checkLocalSymIds(c: var CheckedContext; m: PackedModuleReader; symIds: seq[int32]) =
proc checkLocalSymIds(c: var CheckedContext; m: PackedModule; symIds: seq[int32]) =
for symId in symIds:
assert symId >= 0 and symId < m.syms.len, $symId & " " & $m.syms.len
proc checkModule(c: var CheckedContext; m: PackedModuleReader) =
proc checkModule(c: var CheckedContext; m: PackedModule) =
# We check that:
# - Every symbol references existing types and symbols.
# - Every tree node references existing types and symbols.
for _, v in pairs(m.syms):
checkLocalSym c, v.id
for i in 0..high(m.syms):
checkLocalSym c, int32(i)
checkTree c, m.toReplay
checkTree c, m.topLevel
for e in m.exports:
#assert e[1] >= 0 and e[1] < m.syms.len
assert e[1] >= 0 and e[1] < m.syms.len
assert e[0] == m.syms[e[1]].name
for e in m.compilerProcs:
#assert e[1] >= 0 and e[1] < m.syms.len
assert e[1] >= 0 and e[1] < m.syms.len
assert e[0] == m.syms[e[1]].name
checkLocalSymIds c, m, m.converters

View File

@@ -11,7 +11,7 @@
## IDE-like features. It uses the set of .rod files to accomplish
## its task. The set must cover a complete Nim project.
import std/[sets, tables]
import std/sets
from std/os import nil
from std/private/miscdollars import toLocation

View File

@@ -47,7 +47,6 @@ type
path*: NodeId
PackedSym* = object
id*: int32
kind*: TSymKind
name*: LitId
typ*: PackedItemId
@@ -72,7 +71,6 @@ type
instantiatedFrom*: PackedItemId
PackedType* = object
id*: int32
kind*: TTypeKind
callConv*: TCallingConvention
#nodekind*: TNodeKind
@@ -126,7 +124,7 @@ proc `==`*(a, b: NodePos): bool {.borrow.}
proc `==`*(a, b: NodeId): bool {.borrow.}
proc newTreeFrom*(old: PackedTree): PackedTree =
result = PackedTree(nodes: @[])
result.nodes = @[]
when false: result.sh = old.sh
proc addIdent*(tree: var PackedTree; s: LitId; info: PackedLineInfo) =

View File

@@ -19,8 +19,6 @@ from std/typetraits import supportsCopyMem
when defined(nimPreviewSlimSystem):
import std/[syncio, assertions]
import std / tables
## Overview
## ========
## `RodFile` represents a Rod File (versioned binary format), and the
@@ -172,18 +170,6 @@ proc storeSeq*[T](f: var RodFile; s: seq[T]) =
for i in 0..<s.len:
storePrim(f, s[i])
proc storeOrderedTable*[K, T](f: var RodFile; s: OrderedTable[K, T]) =
if f.err != ok: return
if s.len >= high(int32):
setError f, tooBig
return
var lenPrefix = int32(s.len)
if writeBuffer(f.f, addr lenPrefix, sizeof(lenPrefix)) != sizeof(lenPrefix):
setError f, ioFailure
else:
for _, v in s:
storePrim(f, v)
proc loadPrim*(f: var RodFile; s: var string) =
## Read a string, the length was stored as a prefix
if f.err != ok: return
@@ -225,19 +211,6 @@ proc loadSeq*[T](f: var RodFile; s: var seq[T]) =
for i in 0..<lenPrefix:
loadPrim(f, s[i])
proc loadOrderedTable*[K, T](f: var RodFile; s: var OrderedTable[K, T]) =
## `T` must be compatible with `copyMem`, see `loadPrim`
if f.err != ok: return
var lenPrefix = int32(0)
if readBuffer(f.f, addr lenPrefix, sizeof(lenPrefix)) != sizeof(lenPrefix):
setError f, ioFailure
else:
s = initOrderedTable[K, T](lenPrefix)
for i in 0..<lenPrefix:
var x = default T
loadPrim(f, x)
s[x.id] = x
proc storeHeader*(f: var RodFile; cookie = defaultCookie) =
## stores the header which is described by `cookie`.
if f.err != ok: return

View File

@@ -144,7 +144,7 @@ proc importSymbol(c: PContext, n: PNode, fromMod: PSym; importSet: var IntSet) =
# for an enumeration we have to add all identifiers
if multiImport:
# for a overloadable syms add all overloaded routines
var it: ModuleIter = default(ModuleIter)
var it: ModuleIter
var e = initModuleIter(it, c.graph, fromMod, s.name)
while e != nil:
if e.name.id != s.name.id: internalError(c.config, n.info, "importSymbol: 3")
@@ -251,8 +251,7 @@ proc importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden: bool)
c.importModuleLookup.mgetOrPut(result.name.id, @[]).addUnique realModule.id
proc transformImportAs(c: PContext; n: PNode): tuple[node: PNode, importHidden: bool] =
result = (nil, false)
var ret = default(typeof(result))
var ret: typeof(result)
proc processPragma(n2: PNode): PNode =
let (result2, kws) = splitPragmas(c, n2)
result = result2
@@ -307,15 +306,7 @@ proc myImportModule(c: PContext, n: var PNode, importStmtResult: PNode): PSym =
if belongsToStdlib(c.graph, result) and not startsWith(moduleName, stdPrefix) and
not startsWith(moduleName, "system/") and not startsWith(moduleName, "packages/"):
message(c.config, n.info, warnStdPrefix, realModule.name.s)
proc suggestMod(n: PNode; s: PSym) =
if n.kind == nkImportAs:
suggestMod(n[0], realModule)
elif n.kind == nkInfix:
suggestMod(n[2], s)
else:
suggestSym(c.graph, n.info, s, c.graph.usageSym, false)
suggestMod(n, result)
suggestSym(c.graph, n.info, result, c.graph.usageSym, false)
importStmtResult.add newSymNode(result, n.info)
#newStrNode(toFullPath(c.config, f), n.info)
else:

View File

@@ -163,8 +163,7 @@ proc isLastReadImpl(n: PNode; c: var Con; scope: var Scope): bool =
result = false
proc isLastRead(n: PNode; c: var Con; s: var Scope): bool =
# 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
if not hasDestructor(c, n.typ): return true
let m = skipConvDfa(n)
result = (m.kind == nkSym and sfSingleUsedTemp in m.sym.flags) or
@@ -222,7 +221,7 @@ proc makePtrType(c: var Con, baseType: PType): PType =
proc genOp(c: var Con; op: PSym; dest: PNode): PNode =
var addrExp: PNode
if op.typ != nil and op.typ.signatureLen > 1 and op.typ.firstParamType.kind != tyVar:
if op.typ != nil and op.typ.len > 1 and op.typ[1].kind != tyVar:
addrExp = dest
else:
addrExp = newNodeIT(nkHiddenAddr, dest.info, makePtrType(c, dest.typ))
@@ -300,7 +299,7 @@ proc genSink(c: var Con; s: var Scope; dest, ri: PNode; flags: set[MoveOrCopyFla
proc isCriticalLink(dest: PNode): bool {.inline.} =
#[
Lins's idea that only "critical" links can introduce a cycle. This is
critical for the performance guarantees that we strive for: If you
critical for the performance gurantees that we strive for: If you
traverse a data structure, no tracing will be performed at all.
ORC is about this promise: The GC only touches the memory that the
mutator touches too.
@@ -319,7 +318,7 @@ proc isCriticalLink(dest: PNode): bool {.inline.} =
proc finishCopy(c: var Con; result, dest: PNode; isFromSink: bool) =
if c.graph.config.selectedGC == gcOrc:
let t = dest.typ.skipTypes(tyUserTypeClasses + {tyGenericInst, tyAlias, tySink, tyDistinct})
let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink, tyDistinct})
if cyclicType(c.graph, t):
result.add boolLit(c.graph, result.info, isFromSink or isCriticalLink(dest))
@@ -412,10 +411,7 @@ proc genDefaultCall(t: PType; c: Con; info: TLineInfo): PNode =
proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode =
# generate: (let tmp = v; reset(v); tmp)
if (not hasDestructor(c, n.typ)) and c.inEnsureMove == 0:
assert n.kind != nkSym or not hasDestructor(c, n.sym.typ) or
(n.typ.kind == tyPtr and n.sym.typ.kind == tyRef)
# bug #23505; transformed by `transf`: addr (deref ref) -> ptr
# we know it's really a pointer; so here we assign it directly
assert n.kind != nkSym or not hasDestructor(c, n.sym.typ)
result = copyTree(n)
else:
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
@@ -446,19 +442,18 @@ proc isCapturedVar(n: PNode): bool =
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 hasDestructor(c, nTyp):
let typ = nTyp.skipTypes({tyGenericInst, tyAlias, tySink})
let tmp = c.getTemp(s, n.typ, n.info)
if hasDestructor(c, n.typ):
let typ = n.typ.skipTypes({tyGenericInst, tyAlias, tySink})
let op = getAttachedOp(c.graph, typ, attachedDup)
if op != nil and tfHasOwned notin typ.flags:
if sfError in op.flags:
c.checkForErrorPragma(nTyp, n, "=dup")
c.checkForErrorPragma(n.typ, n, "=dup")
else:
let copyOp = getAttachedOp(c.graph, typ, attachedAsgn)
if copyOp != nil and sfError in copyOp.flags and
sfOverridden notin op.flags:
c.checkForErrorPragma(nTyp, n, "=dup", inferredFromCopy = true)
c.checkForErrorPragma(n.typ, n, "=dup", inferredFromCopy = true)
let src = p(n, c, s, normal)
var newCall = newTreeIT(nkCall, src.info, src.typ,
@@ -475,7 +470,7 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
m.add p(n, c, s, normal)
c.finishCopy(m, n, isFromSink = true)
result.add m
if isLValue(n) and not isCapturedVar(n) and nTyp.skipTypes(abstractInst).kind != tyRef and c.inSpawn == 0:
if isLValue(n) and not isCapturedVar(n) and n.typ.skipTypes(abstractInst).kind != tyRef and c.inSpawn == 0:
message(c.graph.config, n.info, hintPerformance,
("passing '$1' to a sink parameter introduces an implicit copy; " &
"if possible, rearrange your program's control flow to prevent it") % $n)
@@ -484,8 +479,8 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
("cannot move '$1', passing '$1' to a sink parameter introduces an implicit copy") % $n)
else:
if c.graph.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
assert(not containsManagedMemory(nTyp))
if nTyp.skipTypes(abstractInst).kind in {tyOpenArray, tyVarargs}:
assert(not containsManagedMemory(n.typ))
if n.typ.skipTypes(abstractInst).kind in {tyOpenArray, tyVarargs}:
localError(c.graph.config, n.info, "cannot create an implicit openArray copy to be passed to a sink parameter")
result.add newTree(nkAsgn, tmp, p(n, c, s, normal))
# Since we know somebody will take over the produced copy, there is
@@ -494,7 +489,7 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
proc isDangerousSeq(t: PType): bool {.inline.} =
let t = t.skipTypes(abstractInst)
result = t.kind == tySequence and tfHasOwned notin t.elementType.flags
result = t.kind == tySequence and tfHasOwned notin t[0].flags
proc containsConstSeq(n: PNode): bool =
if n.kind == nkBracket and n.len > 0 and n.typ != nil and isDangerousSeq(n.typ):
@@ -599,9 +594,7 @@ template processScopeExpr(c: var Con; s: var Scope; ret: PNode, processCall: unt
# tricky because you would have to intercept moveOrCopy at a certain point
let tmp = c.getTemp(s.parent[], ret.typ, ret.info)
tmp.sym.flags = tmpFlags
let cpy = if hasDestructor(c, ret.typ) and
ret.typ.kind notin {tyOpenArray, tyVarargs}:
# bug #23247 we don't own the data, so it's harmful to destroy it
let cpy = if hasDestructor(c, ret.typ):
s.parent[].final.add c.genDestroy(tmp)
moveOrCopy(tmp, ret, c, s, {IsDecl})
else:
@@ -776,18 +769,6 @@ proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode =
result.add copyNode(n[0])
s.needsTry = true
template isCustomDestructor(c: Con, t: PType): bool =
hasDestructor(c, t) and
getAttachedOp(c.graph, t, attachedDestructor) != nil and
sfOverridden in getAttachedOp(c.graph, t, attachedDestructor).flags
proc hasCustomDestructor(c: Con, t: PType): bool =
result = isCustomDestructor(c, t)
var obj = t
while obj.baseClass != nil:
obj = skipTypes(obj.baseClass, abstractPtrs)
result = result or isCustomDestructor(c, obj)
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}; inReturn = false): PNode =
if n.kind in {nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkIfStmt,
nkIfExpr, nkCaseStmt, nkWhen, nkWhileStmt, nkParForStmt, nkTryStmt, nkPragmaBlock}:
@@ -872,14 +853,15 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
for i in 1..<n.len:
if n[i].kind == nkExprColonExpr:
let field = lookupFieldAgain(t, n[i][0].sym)
if field != nil and (sfCursor in field.flags or field.typ.kind in {tyOpenArray, tyVarargs}):
# don't sink fields with openarray types
if field != nil and sfCursor in field.flags:
result[i][1] = p(n[i][1], c, s, normal)
else:
result[i][1] = p(n[i][1], c, s, m)
else:
result[i] = p(n[i], c, s, m)
if mode == normal and (isRefConstr or hasCustomDestructor(c, t)):
if mode == normal and (isRefConstr or (hasDestructor(c, t) and
getAttachedOp(c.graph, t, attachedDestructor) != nil and
sfOverridden in getAttachedOp(c.graph, t, attachedDestructor).flags)):
result = ensureDestruction(result, n, c, s)
of nkCallKinds:
if n[0].kind == nkSym and n[0].sym.magic == mEnsureMove:
@@ -895,7 +877,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
c.inSpawn.dec
let parameters = n[0].typ
let L = if parameters != nil: parameters.signatureLen else: 0
let L = if parameters != nil: parameters.len else: 0
when false:
var isDangerous = false
@@ -925,10 +907,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
result[0] = p(n[0], c, s, normal)
if canRaise(n[0]): s.needsTry = true
if mode == normal:
if result.typ != nil and result.typ.kind notin {tyOpenArray, tyVarargs}:
# Returns of openarray types shouldn't be destroyed
# bug #19435; # bug #23247
result = ensureDestruction(result, n, c, s)
result = ensureDestruction(result, n, c, s)
of nkDiscardStmt: # Small optimization
result = shallowCopy(n)
if n[0].kind != nkEmpty:
@@ -1187,9 +1166,9 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
# Rule 3: `=sink`(x, z); wasMoved(z)
let snk = c.genSink(s, dest, ri, flags)
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
elif ri.sym.kind != skParam and
isAnalysableFieldAccess(ri, c.owner) and
isLastRead(ri, c, s) and canBeMoved(c, dest.typ):
elif ri.sym.kind != skParam and ri.sym.owner == c.owner and
isLastRead(ri, c, s) and canBeMoved(c, dest.typ) and not isCursor(ri) and
not ({sfGlobal, sfPure} <= ri.sym.flags):
# Rule 3: `=sink`(x, z); wasMoved(z)
let snk = c.genSink(s, dest, ri, flags)
result = newTree(nkStmtList, snk, c.genWasMoved(ri))

View File

@@ -6,11 +6,11 @@ Name: "Nim"
Version: "$version"
Platforms: """
windows: i386;amd64
linux: i386;hppa;ia64;alpha;amd64;powerpc64;arm;sparc;sparc64;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
macosx: i386;amd64;powerpc64;arm64
solaris: i386;amd64;sparc;sparc64
freebsd: i386;amd64;powerpc64;arm;arm64;riscv64;sparc64;mips;mipsel;mips64;mips64el;powerpc;powerpc64el
netbsd: i386;amd64;arm64
netbsd: i386;amd64
openbsd: i386;amd64;arm;arm64
dragonfly: i386;amd64
crossos: amd64
@@ -147,4 +147,4 @@ licenses: "bin/nim,MIT;lib/*,MIT;"
[nimble]
pkgName: "nim"
pkgFiles: "compiler/*;doc/basicopt.txt;doc/advopt.txt;doc/nimdoc.css;doc/nimdoc.cls"
pkgFiles: "compiler/*;doc/basicopt.txt;doc/advopt.txt;doc/nimdoc.css"

View File

@@ -34,7 +34,6 @@ proc `$`*(a: Int128): string
proc toInt128*[T: SomeInteger | bool](arg: T): Int128 =
{.noSideEffect.}:
result = Zero
when T is bool: result.sdata(0) = int32(arg)
elif T is SomeUnsignedInt:
when sizeof(arg) <= 4:
@@ -209,35 +208,30 @@ proc `==`*(a, b: Int128): bool =
return true
proc bitnot*(a: Int128): Int128 =
result = Zero
result.udata[0] = not a.udata[0]
result.udata[1] = not a.udata[1]
result.udata[2] = not a.udata[2]
result.udata[3] = not a.udata[3]
proc bitand*(a, b: Int128): Int128 =
result = Zero
result.udata[0] = a.udata[0] and b.udata[0]
result.udata[1] = a.udata[1] and b.udata[1]
result.udata[2] = a.udata[2] and b.udata[2]
result.udata[3] = a.udata[3] and b.udata[3]
proc bitor*(a, b: Int128): Int128 =
result = Zero
result.udata[0] = a.udata[0] or b.udata[0]
result.udata[1] = a.udata[1] or b.udata[1]
result.udata[2] = a.udata[2] or b.udata[2]
result.udata[3] = a.udata[3] or b.udata[3]
proc bitxor*(a, b: Int128): Int128 =
result = Zero
result.udata[0] = a.udata[0] xor b.udata[0]
result.udata[1] = a.udata[1] xor b.udata[1]
result.udata[2] = a.udata[2] xor b.udata[2]
result.udata[3] = a.udata[3] xor b.udata[3]
proc `shr`*(a: Int128, b: int): Int128 =
result = Zero
let b = b and 127
if b < 32:
result.sdata(3) = a.sdata(3) shr b
@@ -264,7 +258,6 @@ proc `shr`*(a: Int128, b: int): Int128 =
result.sdata(0) = a.sdata(3) shr (b and 31)
proc `shl`*(a: Int128, b: int): Int128 =
result = Zero
let b = b and 127
if b < 32:
result.udata[0] = a.udata[0] shl b
@@ -288,7 +281,6 @@ proc `shl`*(a: Int128, b: int): Int128 =
result.udata[3] = a.udata[0] shl (b and 31)
proc `+`*(a, b: Int128): Int128 =
result = Zero
let tmp0 = uint64(a.udata[0]) + uint64(b.udata[0])
result.udata[0] = cast[uint32](tmp0)
let tmp1 = uint64(a.udata[1]) + uint64(b.udata[1]) + (tmp0 shr 32)
@@ -321,7 +313,6 @@ proc abs(a: int32): int =
if a < 0: -a else: a
proc `*`(a: Int128, b: uint32): Int128 =
result = Zero
let tmp0 = uint64(a.udata[0]) * uint64(b)
let tmp1 = uint64(a.udata[1]) * uint64(b)
let tmp2 = uint64(a.udata[2]) * uint64(b)
@@ -344,7 +335,6 @@ proc `*=`(a: var Int128, b: int32) =
a = a * b
proc makeInt128(high, low: uint64): Int128 =
result = Zero
result.udata[0] = cast[uint32](low)
result.udata[1] = cast[uint32](low shr 32)
result.udata[2] = cast[uint32](high)
@@ -383,8 +373,6 @@ proc fastLog2*(a: Int128): int =
proc divMod*(dividend, divisor: Int128): tuple[quotient, remainder: Int128] =
assert(divisor != Zero)
result = (Zero, Zero)
let isNegativeA = isNegative(dividend)
let isNegativeB = isNegative(divisor)
@@ -551,28 +539,24 @@ proc toInt128*(arg: float64): Int128 =
return res
proc maskUInt64*(arg: Int128): Int128 {.noinit, inline.} =
result = Zero
result.udata[0] = arg.udata[0]
result.udata[1] = arg.udata[1]
result.udata[2] = 0
result.udata[3] = 0
proc maskUInt32*(arg: Int128): Int128 {.noinit, inline.} =
result = Zero
result.udata[0] = arg.udata[0]
result.udata[1] = 0
result.udata[2] = 0
result.udata[3] = 0
proc maskUInt16*(arg: Int128): Int128 {.noinit, inline.} =
result = Zero
result.udata[0] = arg.udata[0] and 0xffff
result.udata[1] = 0
result.udata[2] = 0
result.udata[3] = 0
proc maskUInt8*(arg: Int128): Int128 {.noinit, inline.} =
result = Zero
result.udata[0] = arg.udata[0] and 0xff
result.udata[1] = 0
result.udata[2] = 0

View File

@@ -54,18 +54,18 @@ proc canAlias(arg, ret: PType; marker: var IntSet): bool =
of tyObject:
if isFinal(ret):
result = canAliasN(arg, ret.n, marker)
if not result and ret.baseClass != nil:
result = canAlias(arg, ret.baseClass, marker)
if not result and ret.len > 0 and ret[0] != nil:
result = canAlias(arg, ret[0], marker)
else:
result = true
of tyTuple:
result = false
for r in ret.kids:
result = canAlias(arg, r, marker)
for i in 0..<ret.len:
result = canAlias(arg, ret[i], marker)
if result: break
of tyArray, tySequence, tyDistinct, tyGenericInst,
tyAlias, tyInferred, tySink, tyLent, tyOwned, tyRef:
result = canAlias(arg, ret.skipModifier, marker)
result = canAlias(arg, ret.lastSon, marker)
of tyProc:
result = ret.callConv == ccClosure
else:
@@ -119,16 +119,14 @@ proc containsDangerousRefAux(t: PType; marker: var IntSet): SearchResult =
if result != NotFound: return result
case t.kind
of tyObject:
if t.baseClass != nil:
result = containsDangerousRefAux(t.baseClass.skipTypes(skipPtrs), marker)
if t[0] != nil:
result = containsDangerousRefAux(t[0].skipTypes(skipPtrs), marker)
if result == NotFound: result = containsDangerousRefAux(t.n, marker)
of tyGenericInst, tyDistinct, tyAlias, tySink:
result = containsDangerousRefAux(skipModifier(t), marker)
of tyArray, tySet, tySequence:
result = containsDangerousRefAux(t.elementType, marker)
of tyTuple:
for a in t.kids:
result = containsDangerousRefAux(a, marker)
result = containsDangerousRefAux(lastSon(t), marker)
of tyArray, tySet, tyTuple, tySequence:
for i in 0..<t.len:
result = containsDangerousRefAux(t[i], marker)
if result == Found: return result
else:
discard

View File

@@ -31,10 +31,9 @@ implements the required case distinction.
import
ast, trees, magicsys, options,
nversion, msgs, idents, types,
ropes, wordrecg, renderer,
ropes, ccgutils, wordrecg, renderer,
cgmeth, lowerings, sighashes, modulegraphs, lineinfos,
transf, injectdestructors, sourcemap, astmsgs, backendpragmas,
mangleutils
transf, injectdestructors, sourcemap, astmsgs, backendpragmas
import pipelineutils
@@ -106,30 +105,26 @@ type
optionsStack: seq[TOptions]
module: BModule
g: PGlobals
generatedParamCopies: IntSet
beforeRetNeeded: bool
unique: int # for temp identifier generation
blocks: seq[TBlock]
extraIndent: int
previousFileName: string # For frameInfo inside templates.
# legacy: generatedParamCopies and up fields are used for jsNoLambdaLifting
generatedParamCopies: IntSet
up: PProc # up the call chain; required for closure support
declaredGlobals: IntSet
previousFileName: string # For frameInfo inside templates.
template config*(p: PProc): ConfigRef = p.module.config
proc indentLine(p: PProc, r: Rope): Rope =
var p = p
if jsNoLambdaLifting in p.config.legacyFeatures:
var ind = 0
while true:
inc ind, p.blocks.len + p.extraIndent
if p.up == nil or p.up.prc != p.prc.owner:
break
p = p.up
result = repeat(' ', ind*2) & r
else:
let ind = p.blocks.len + p.extraIndent
result = repeat(' ', ind*2) & r
var ind = 0
while true:
inc ind, p.blocks.len + p.extraIndent
if p.up == nil or p.up.prc != p.prc.owner:
break
p = p.up
result = repeat(' ', ind*2) & r
template line(p: PProc, added: string) =
p.body.add(indentLine(p, rope(added)))
@@ -180,6 +175,10 @@ proc initProcOptions(module: BModule): TOptions =
proc newInitProc(globals: PGlobals, module: BModule): PProc =
result = newProc(globals, module, nil, initProcOptions(module))
proc declareGlobal(p: PProc; id: int; r: Rope) =
if p.prc != nil and not p.declaredGlobals.containsOrIncl(id):
p.locals.addf("global $1;$n", [r])
const
MappedToObject = {tyObject, tyArray, tyTuple, tyOpenArray,
tySet, tyVarargs}
@@ -188,7 +187,7 @@ proc mapType(typ: PType): TJSTypeKind =
let t = skipTypes(typ, abstractInst)
case t.kind
of tyVar, tyRef, tyPtr:
if skipTypes(t.elementType, abstractInst).kind in MappedToObject:
if skipTypes(t.lastSon, abstractInst).kind in MappedToObject:
result = etyObject
else:
result = etyBaseIndex
@@ -197,7 +196,7 @@ proc mapType(typ: PType): TJSTypeKind =
result = etyBaseIndex
of tyRange, tyDistinct, tyOrdinal, tyProxy, tyLent:
# tyLent is no-op as JS has pass-by-reference semantics
result = mapType(skipModifier t)
result = mapType(t[0])
of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar: result = etyInt
of tyBool: result = etyBool
of tyFloat..tyFloat128: result = etyFloat
@@ -213,9 +212,9 @@ proc mapType(typ: PType): TJSTypeKind =
result = etyNone
of tyGenericInst, tyInferred, tyAlias, tyUserTypeClass, tyUserTypeClassInst,
tySink, tyOwned:
result = mapType(typ.skipModifier)
result = mapType(typ.lastSon)
of tyStatic:
if t.n != nil: result = mapType(skipModifier t)
if t.n != nil: result = mapType(lastSon t)
else: result = etyNone
of tyProc: result = etyProc
of tyCstring: result = etyString
@@ -270,10 +269,6 @@ proc mangleName(m: BModule, s: PSym): Rope =
# When hot reloading is enabled, we must ensure that the names
# of functions and types will be preserved across rebuilds:
result.add(idOrSig(s, m.module.name.s, m.sigConflicts, m.config))
elif s.kind == skParam:
result.add mangleParamExt(s)
elif s.kind in routineKinds:
result.add mangleProcNameExt(m.graph, s)
else:
result.add("_")
result.add(rope(s.id))
@@ -469,6 +464,9 @@ const # magic checked op; magic unchecked op;
mUnaryMinusF64: ["", ""],
mCharToStr: ["nimCharToStr", "nimCharToStr"],
mBoolToStr: ["nimBoolToStr", "nimBoolToStr"],
mIntToStr: ["cstrToNimstr", "cstrToNimstr"],
mInt64ToStr: ["cstrToNimstr", "cstrToNimstr"],
mFloatToStr: ["cstrToNimstr", "cstrToNimstr"],
mCStrToStr: ["cstrToNimstr", "cstrToNimstr"],
mStrToStr: ["", ""]]
@@ -518,7 +516,7 @@ proc maybeMakeTempAssignable(p: PProc, n: PNode; x: TCompRes): tuple[a, tmp: Rop
let (m1, tmp1) = maybeMakeTemp(p, n[0], address)
let typ = skipTypes(n[0].typ, abstractPtrs)
if typ.kind == tyArray:
first = firstOrd(p.config, typ.indexType)
first = firstOrd(p.config, typ[0])
if optBoundsCheck in p.options:
useMagic(p, "chckIndx")
if first == 0: # save a couple chars
@@ -790,13 +788,7 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
of mEqProc: applyFormat("($1 == $2)", "($1 == $2)")
of mUnaryMinusI: applyFormat("negInt($1)", "-($1)")
of mUnaryMinusI64: applyFormat("negInt64($1)", "-($1)")
of mAbsI:
let typ = n[1].typ.skipTypes(abstractVarRange)
if typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions:
useMagic(p, "absInt64")
applyFormat("absInt64($1)", "absInt64($1)")
else:
applyFormat("absInt($1)", "Math.abs($1)")
of mAbsI: applyFormat("absInt($1)", "Math.abs($1)")
of mNot: applyFormat("!($1)", "!($1)")
of mUnaryPlusI: applyFormat("+($1)", "+($1)")
of mBitnotI:
@@ -813,6 +805,8 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
of mUnaryMinusF64: applyFormat("-($1)", "-($1)")
of mCharToStr: applyFormat("nimCharToStr($1)", "nimCharToStr($1)")
of mBoolToStr: applyFormat("nimBoolToStr($1)", "nimBoolToStr($1)")
of mIntToStr: applyFormat("cstrToNimstr(($1) + \"\")", "cstrToNimstr(($1) + \"\")")
of mInt64ToStr: applyFormat("cstrToNimstr(($1) + \"\")", "cstrToNimstr(($1) + \"\")")
of mCStrToStr: applyFormat("cstrToNimstr($1)", "cstrToNimstr($1)")
of mStrToStr, mUnown, mIsolate, mFinished: applyFormat("$1", "$1")
else:
@@ -833,7 +827,7 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
arithAux(p, n, r, op)
of mModI:
arithAux(p, n, r, op)
of mCharToStr, mBoolToStr, mCStrToStr, mStrToStr, mEnumToStr:
of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mCStrToStr, mStrToStr, mEnumToStr:
arithAux(p, n, r, op)
of mEqRef:
if mapType(n[1].typ) != etyBaseIndex:
@@ -843,11 +837,6 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
gen(p, n[1], x)
gen(p, n[2], y)
r.res = "($# == $# && $# == $#)" % [x.address, y.address, x.res, y.res]
of mEqProc:
if skipTypes(n[1].typ, abstractInst).callConv == ccClosure:
binaryExpr(p, n, r, "cmpClosures", "cmpClosures($1, $2)")
else:
arithAux(p, n, r, op)
else:
arithAux(p, n, r, op)
r.kind = resExpr
@@ -937,7 +926,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
p.body.add("++excHandler;\L")
var tmpFramePtr = rope"F"
lineF(p, "try {$n", [])
var a: TCompRes = default(TCompRes)
var a: TCompRes
gen(p, n[0], a)
moveInto(p, a, r)
var generalCatchBranchExists = false
@@ -1030,7 +1019,7 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
a, b, cond, stmt: TCompRes = default(TCompRes)
genLineDir(p, n)
gen(p, n[0], cond)
let typeKind = skipTypes(n[0].typ, abstractVar+{tyRange}).kind
let typeKind = skipTypes(n[0].typ, abstractVar).kind
var transferRange = false
let anyString = typeKind in {tyString, tyCstring}
case typeKind
@@ -1147,14 +1136,10 @@ proc genBreakStmt(p: PProc, n: PNode) =
p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
lineF(p, "break Label$1;$n", [rope(p.blocks[idx].id)])
proc genAsmOrEmitStmt(p: PProc, n: PNode; isAsmStmt = false) =
proc genAsmOrEmitStmt(p: PProc, n: PNode) =
genLineDir(p, n)
p.body.add p.indentLine("")
let offset =
if isAsmStmt: 1 # first son is pragmas
else: 0
for i in offset..<n.len:
for i in 0..<n.len:
let it = n[i]
case it.kind
of nkStrLit..nkTripleStrLit:
@@ -1209,17 +1194,8 @@ proc genIf(p: PProc, n: PNode, r: var TCompRes) =
lineF(p, "}$n", [])
line(p, repeat('}', toClose) & "\L")
proc generateHeader(p: PProc, prc: PSym): Rope =
proc generateHeader(p: PProc, typ: PType): Rope =
result = ""
let typ = prc.typ
if jsNoLambdaLifting notin p.config.legacyFeatures:
if typ.callConv == ccClosure:
# we treat Env as the `this` parameter of the function
# to keep it simple
let env = prc.ast[paramsPos].lastSon
assert env.kind == nkSym, "env is missing"
env.sym.loc.r = "this"
for i in 1..<typ.n.len:
assert(typ.n[i].kind == nkSym)
var param = typ.n[i].sym
@@ -1252,10 +1228,9 @@ const
proc needsNoCopy(p: PProc; y: PNode): bool =
return y.kind in nodeKindsNeedNoCopy or
((mapType(y.typ) != etyBaseIndex or
(jsNoLambdaLifting in p.config.legacyFeatures and y.kind == nkSym and y.sym.kind == skParam)) and
((mapType(y.typ) != etyBaseIndex or (y.kind == nkSym and y.sym.kind == skParam)) and
(skipTypes(y.typ, abstractInst).kind in
{tyRef, tyPtr, tyLent, tyVar, tyCstring, tyProc, tyOwned, tyOpenArray} + IntegralTypes))
{tyRef, tyPtr, tyLent, tyVar, tyCstring, tyProc, tyOwned} + IntegralTypes))
proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
var a, b: TCompRes = default(TCompRes)
@@ -1282,7 +1257,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
lineF(p, "$1 = nimCopy(null, $2, $3);$n",
[a.rdLoc, b.res, genTypeInfo(p, y.typ)])
of etyObject:
if x.typ.kind in {tyVar, tyLent, tyOpenArray, tyVarargs} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
if x.typ.kind in {tyVar, tyLent} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
else:
useMagic(p, "nimCopy")
@@ -1337,10 +1312,19 @@ proc genFastAsgn(p: PProc, n: PNode) =
genAsgnAux(p, n[0], n[1], noCopyNeeded=noCopy)
proc genSwap(p: PProc, n: PNode) =
let stmtList = lowerSwap(p.module.graph, n, p.module.idgen, if p.prc != nil: p.prc else: p.module.module)
assert stmtList.kind == nkStmtList
for i in 0..<stmtList.len:
genStmt(p, stmtList[i])
var a, b: TCompRes = default(TCompRes)
gen(p, n[1], a)
gen(p, n[2], b)
var tmp = p.getTemp(false)
if mapType(p, skipTypes(n[1].typ, abstractVar)) == etyBaseIndex:
let tmp2 = p.getTemp(false)
if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
internalError(p.config, n.info, "genSwap")
lineF(p, "var $1 = $2; $2 = $3; $3 = $1;$n",
[tmp, a.address, b.address])
tmp = tmp2
lineF(p, "var $1 = $2; $2 = $3; $3 = $1;",
[tmp, a.res, b.res])
proc getFieldPosition(p: PProc; f: PNode): int =
case f.kind
@@ -1455,7 +1439,7 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
r.address = x
var typ = skipTypes(m[0].typ, abstractPtrs)
if typ.kind == tyArray:
first = firstOrd(p.config, typ.indexType)
first = firstOrd(p.config, typ[0])
if optBoundsCheck in p.options:
useMagic(p, "chckIndx")
if first == 0: # save a couple chars
@@ -1470,8 +1454,8 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
r.kind = resExpr
proc genArrayAccess(p: PProc, n: PNode, r: var TCompRes) =
var ty = skipTypes(n[0].typ, abstractVarRange+tyUserTypeClasses)
if ty.kind in {tyRef, tyPtr, tyLent, tyOwned}: ty = skipTypes(ty.elementType, abstractVarRange)
var ty = skipTypes(n[0].typ, abstractVarRange)
if ty.kind in {tyRef, tyPtr, tyLent, tyOwned}: ty = skipTypes(ty.lastSon, abstractVarRange)
case ty.kind
of tyArray, tyOpenArray, tySequence, tyString, tyCstring, tyVarargs:
genArrayAddr(p, n, r)
@@ -1558,7 +1542,7 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
if ty.kind in MappedToObject:
gen(p, n[0], r)
else:
let kindOfIndexedExpr = skipTypes(n[0][0].typ, abstractVarRange+tyUserTypeClasses).kind
let kindOfIndexedExpr = skipTypes(n[0][0].typ, abstractVarRange).kind
case kindOfIndexedExpr
of tyArray, tyOpenArray, tySequence, tyString, tyCstring, tyVarargs:
genArrayAddr(p, n[0], r)
@@ -1604,15 +1588,12 @@ proc attachProc(p: PProc; s: PSym) =
proc genProcForSymIfNeeded(p: PProc, s: PSym) =
if not p.g.generatedSyms.containsOrIncl(s.id):
if jsNoLambdaLifting in p.config.legacyFeatures:
let newp = genProc(p, s)
var owner = p
while owner != nil and owner.prc != s.owner:
owner = owner.up
if owner != nil: owner.locals.add(newp)
else: attachProc(p, newp, s)
else:
attachProc(p, s)
let newp = genProc(p, s)
var owner = p
while owner != nil and owner.prc != s.owner:
owner = owner.up
if owner != nil: owner.locals.add(newp)
else: attachProc(p, newp, s)
proc genCopyForParamIfNeeded(p: PProc, n: PNode) =
let s = n.sym
@@ -1639,7 +1620,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
internalError(p.config, n.info, "symbol has no generated name: " & s.name.s)
if sfCompileTime in s.flags:
genVarInit(p, s, if s.astdef != nil: s.astdef else: newNodeI(nkEmpty, s.info))
if jsNoLambdaLifting in p.config.legacyFeatures and s.kind == skParam:
if s.kind == skParam:
genCopyForParamIfNeeded(p, n)
let k = mapType(p, s.typ)
if k == etyBaseIndex:
@@ -1663,7 +1644,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
if s.loc.r == "":
internalError(p.config, n.info, "symbol has no generated name: " & s.name.s)
r.res = s.loc.r
of skProc, skFunc, skConverter, skMethod, skIterator:
of skProc, skFunc, skConverter, skMethod:
if sfCompileTime in s.flags:
localError(p.config, n.info, "request to generate code for .compileTime proc: " &
s.name.s)
@@ -1908,7 +1889,7 @@ proc createObjInitList(p: PProc, typ: PType, excludedFieldIDs: IntSet, output: v
while t != nil:
t = t.skipTypes(skipPtrs)
createRecordVarAux(p, t.n, excludedFieldIDs, output)
t = t.baseClass
t = t[0]
proc arrayTypeForElemType(conf: ConfigRef; typ: PType): string =
let typ = typ.skipTypes(abstractRange)
@@ -1957,7 +1938,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
of tyFloat..tyFloat128:
result = putToSeq("0.0", indirect)
of tyRange, tyGenericInst, tyAlias, tySink, tyOwned, tyLent:
result = createVar(p, skipModifier(typ), indirect)
result = createVar(p, lastSon(typ), indirect)
of tySet:
result = putToSeq("{}", indirect)
of tyBool:
@@ -2005,11 +1986,11 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
result = putToSeq("null", indirect)
of tySequence, tyString:
result = putToSeq("[]", indirect)
of tyCstring, tyProc, tyOpenArray:
of tyCstring, tyProc:
result = putToSeq("null", indirect)
of tyStatic:
if t.n != nil:
result = createVar(p, skipModifier t, indirect)
result = createVar(p, lastSon t, indirect)
else:
internalError(p.config, "createVar: " & $t.kind)
result = ""
@@ -2057,7 +2038,7 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
gen(p, n, a)
case mapType(p, v.typ)
of etyObject, etySeq:
if v.typ.kind in {tyOpenArray, tyVarargs} or needsNoCopy(p, n):
if needsNoCopy(p, n):
s = a.res
else:
useMagic(p, "nimCopy")
@@ -2094,17 +2075,6 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
dec p.extraIndent
lineF(p, "}$n")
proc genClosureVar(p: PProc, n: PNode) =
# assert n[2].kind != nkEmpty
# TODO: fixme transform `var env.x` into `var env.x = default()` after
# the order of transf and lambdalifting is fixed
if n[2].kind != nkEmpty:
genAsgnAux(p, n[0], n[2], false)
else:
var a: TCompRes = default(TCompRes)
gen(p, n[0], a)
line(p, runtimeFormat("$1 = $2;$n", [rdLoc(a), createVar(p, n[0].typ, false)]))
proc genVarStmt(p: PProc, n: PNode) =
for i in 0..<n.len:
var a = n[i]
@@ -2114,17 +2084,15 @@ proc genVarStmt(p: PProc, n: PNode) =
genStmt(p, unpacked)
else:
assert(a.kind == nkIdentDefs)
if a[0].kind == nkSym:
var v = a[0].sym
if lfNoDecl notin v.loc.flags and sfImportc notin v.flags:
genLineDir(p, a)
if sfCompileTime notin v.flags:
genVarInit(p, v, a[2])
else:
# lazy emit, done when it's actually used.
if v.ast == nil: v.ast = a[2]
else: # closure
genClosureVar(p, a)
assert(a[0].kind == nkSym)
var v = a[0].sym
if lfNoDecl notin v.loc.flags and sfImportc notin v.flags:
genLineDir(p, a)
if sfCompileTime notin v.flags:
genVarInit(p, v, a[2])
else:
# lazy emit, done when it's actually used.
if v.ast == nil: v.ast = a[2]
proc genConstant(p: PProc, c: PSym) =
if lfNoDecl notin c.loc.flags and not p.g.generatedSyms.containsOrIncl(c.id):
@@ -2171,20 +2139,20 @@ proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) =
if skipTypes(n[1].typ, abstractVarRange).kind == tyChar:
r.res.add("[$1].concat(" % [a.res])
else:
r.res.add("($1).concat(" % [a.res])
r.res.add("($1 || []).concat(" % [a.res])
for i in 2..<n.len - 1:
gen(p, n[i], a)
if skipTypes(n[i].typ, abstractVarRange).kind == tyChar:
r.res.add("[$1]," % [a.res])
else:
r.res.add("$1," % [a.res])
r.res.add("$1 || []," % [a.res])
gen(p, n[^1], a)
if skipTypes(n[^1].typ, abstractVarRange).kind == tyChar:
r.res.add("[$1])" % [a.res])
else:
r.res.add("$1)" % [a.res])
r.res.add("$1 || [])" % [a.res])
proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope = "") =
useMagic(p, magic)
@@ -2251,17 +2219,16 @@ proc genDefault(p: PProc, n: PNode; r: var TCompRes) =
r.res = createVar(p, n.typ, indirect = false)
r.kind = resExpr
proc genWasMoved(p: PProc, n: PNode) =
# TODO: it should be done by nir
proc genReset(p: PProc, n: PNode) =
var x: TCompRes = default(TCompRes)
useMagic(p, "genericReset")
gen(p, n[1], x)
if x.typ == etyBaseIndex:
lineF(p, "$1 = null, $2 = 0;$n", [x.address, x.res])
else:
var y: TCompRes = default(TCompRes)
genDefault(p, n[1], y)
let (a, _) = maybeMakeTempAssignable(p, n[1], x)
lineF(p, "$1 = $2;$n", [a, y.rdLoc])
let (a, tmp) = maybeMakeTempAssignable(p, n[1], x)
lineF(p, "$1 = genericReset($3, $2);$n", [a,
genTypeInfo(p, n[1].typ), tmp])
proc genMove(p: PProc; n: PNode; r: var TCompRes) =
var a: TCompRes = default(TCompRes)
@@ -2269,7 +2236,7 @@ proc genMove(p: PProc; n: PNode; r: var TCompRes) =
r.res = p.getTemp()
gen(p, n[1], a)
lineF(p, "$1 = $2;$n", [r.rdLoc, a.rdLoc])
genWasMoved(p, n)
genReset(p, n)
#lineF(p, "$1 = $2;$n", [dest.rdLoc, src.rdLoc])
proc genDup(p: PProc; n: PNode; r: var TCompRes) =
@@ -2450,7 +2417,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
of mNewSeqOfCap: unaryExpr(p, n, r, "", "[]")
of mOf: genOf(p, n, r)
of mDefault, mZeroDefault: genDefault(p, n, r)
of mWasMoved: genWasMoved(p, n)
of mReset, mWasMoved: genReset(p, n)
of mEcho: genEcho(p, n, r)
of mNLen..mNError, mSlurp, mStaticExec:
localError(p.config, n.info, errXMustBeCompileTime % n[0].sym.name.s)
@@ -2731,8 +2698,8 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
var returnStmt: Rope = ""
var resultAsgn: Rope = ""
var name = mangleName(p.module, prc)
let header = generateHeader(p, prc)
if prc.typ.returnType != nil and sfPure notin prc.flags:
let header = generateHeader(p, prc.typ)
if prc.typ[0] != nil and sfPure notin prc.flags:
resultSym = prc.ast[resultPos].sym
let mname = mangleName(p.module, resultSym)
# otherwise uses "fat pointers"
@@ -2950,18 +2917,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
genInfixCall(p, n, r)
else:
genCall(p, n, r)
of nkClosure:
if jsNoLambdaLifting in p.config.legacyFeatures:
gen(p, n[0], r)
else:
let tmp = getTemp(p)
var a: TCompRes = default(TCompRes)
var b: TCompRes = default(TCompRes)
gen(p, n[0], a)
gen(p, n[1], b)
lineF(p, "$1 = $2.bind($3); $1.ClP_0 = $2; $1.ClE_0 = $3;$n", [tmp, a.rdLoc, b.rdLoc])
r.res = tmp
r.kind = resVal
of nkClosure: gen(p, n[0], r)
of nkCurly: genSetConstr(p, n, r)
of nkBracket: genArrayConstr(p, n, r)
of nkPar, nkTupleConstr: genTupleConstr(p, n, r)
@@ -3024,16 +2980,17 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
if n[0].kind != nkEmpty:
genLineDir(p, n)
gen(p, n[0], r)
r.res = "(" & r.res & ")"
of nkAsmStmt:
warningDeprecated(p.config, n.info, "'asm' for the JS target is deprecated, use the 'emit' pragma")
genAsmOrEmitStmt(p, n, true)
r.res = "var _ = " & r.res
of nkAsmStmt: genAsmOrEmitStmt(p, n)
of nkTryStmt, nkHiddenTryStmt: genTry(p, n, r)
of nkRaiseStmt: genRaiseStmt(p, n)
of nkTypeSection, nkCommentStmt, nkIncludeStmt,
nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
nkFromStmt, nkTemplateDef, nkMacroDef, nkIteratorDef, nkStaticStmt,
nkFromStmt, nkTemplateDef, nkMacroDef, nkStaticStmt,
nkMixinStmt, nkBindStmt: discard
of nkIteratorDef:
if n[0].sym.typ.callConv == TCallingConvention.ccClosure:
globalError(p.config, n.info, "Closure iterators are not supported by JS backend!")
of nkPragma: genPragma(p, n)
of nkProcDef, nkFuncDef, nkMethodDef, nkConverterDef:
var s = n[namePos].sym
@@ -3041,18 +2998,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
genSym(p, n[namePos], r)
r.res = ""
of nkGotoState, nkState:
globalError(p.config, n.info, "not implemented")
of nkBreakState:
var a: TCompRes = default(TCompRes)
if n[0].kind == nkClosure:
gen(p, n[0][1], a)
let sym = n[0][1].typ[0].n[0].sym
r.res = "(($1).$2 < 0)" % [rdLoc(a), mangleName(p.module, sym)]
else:
gen(p, n[0], a)
let sym = n[0].typ[0].n[0].sym
r.res = "((($1.ClE_0).$2) < 0)" % [rdLoc(a), mangleName(p.module, sym)]
r.kind = resExpr
globalError(p.config, n.info, "First class iterators not implemented")
of nkPragmaBlock: gen(p, n.lastSon, r)
of nkComesFrom:
discard "XXX to implement for better stack traces"
@@ -3159,6 +3105,15 @@ proc wholeCode(graph: ModuleGraph; m: BModule): Rope =
result = globals.typeInfo & globals.constants & globals.code
proc getClassName(t: PType): Rope =
var s = t.sym
if s.isNil or sfAnon in s.flags:
s = skipTypes(t, abstractPtrs).sym
if s.isNil or sfAnon in s.flags:
doAssert(false, "cannot retrieve class name")
if s.loc.r != "": result = s.loc.r
else: result = rope(s.name.s)
proc finalJSCodeGen*(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
## Finalize JS code generation of a Nim module.
## Param `n` may contain nodes returned from the last module close call.

View File

@@ -69,7 +69,7 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
else: internalError(p.config, n.info, "genObjectFields")
proc objHasTypeField(t: PType): bool {.inline.} =
tfInheritable in t.flags or t.baseClass != nil
tfInheritable in t.flags or t[0] != nil
proc genObjectInfo(p: PProc, typ: PType, name: Rope) =
let kind = if objHasTypeField(typ): tyObject else: tyTuple
@@ -79,9 +79,9 @@ proc genObjectInfo(p: PProc, typ: PType, name: Rope) =
p.g.typeInfo.addf("var NNI$1 = $2;$n",
[rope(typ.id), genObjectFields(p, typ, typ.n)])
p.g.typeInfo.addf("$1.node = NNI$2;$n", [name, rope(typ.id)])
if (typ.kind == tyObject) and (typ.baseClass != nil):
if (typ.kind == tyObject) and (typ[0] != nil):
p.g.typeInfo.addf("$1.base = $2;$n",
[name, genTypeInfo(p, typ.baseClass.skipTypes(skipPtrs))])
[name, genTypeInfo(p, typ[0].skipTypes(skipPtrs))])
proc genTupleFields(p: PProc, typ: PType): Rope =
var s: Rope = ""
@@ -117,9 +117,9 @@ proc genEnumInfo(p: PProc, typ: PType, name: Rope) =
prepend(p.g.typeInfo, s)
p.g.typeInfo.add(n)
p.g.typeInfo.addf("$1.node = NNI$2;$n", [name, rope(typ.id)])
if typ.baseClass != nil:
if typ[0] != nil:
p.g.typeInfo.addf("$1.base = $2;$n",
[name, genTypeInfo(p, typ.baseClass)])
[name, genTypeInfo(p, typ[0])])
proc genTypeInfo(p: PProc, typ: PType): Rope =
let t = typ.skipTypes({tyGenericInst, tyDistinct, tyAlias, tySink, tyOwned})
@@ -127,7 +127,7 @@ proc genTypeInfo(p: PProc, typ: PType): Rope =
if containsOrIncl(p.g.typeInfoGenerated, t.id): return
case t.kind
of tyDistinct:
result = genTypeInfo(p, t.skipModifier)
result = genTypeInfo(p, t[0])
of tyPointer, tyProc, tyBool, tyChar, tyCstring, tyString, tyInt..tyUInt64:
var s =
"var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" %
@@ -139,18 +139,18 @@ proc genTypeInfo(p: PProc, typ: PType): Rope =
[result, rope(ord(t.kind))]
prepend(p.g.typeInfo, s)
p.g.typeInfo.addf("$1.base = $2;$n",
[result, genTypeInfo(p, t.elementType)])
[result, genTypeInfo(p, t.lastSon)])
of tyArray:
var s =
"var $1 = {size: 0, kind: $2, base: null, node: null, finalizer: null};$n" %
[result, rope(ord(t.kind))]
prepend(p.g.typeInfo, s)
p.g.typeInfo.addf("$1.base = $2;$n",
[result, genTypeInfo(p, t.elementType)])
[result, genTypeInfo(p, t[1])])
of tyEnum: genEnumInfo(p, t, result)
of tyObject: genObjectInfo(p, t, result)
of tyTuple: genTupleInfo(p, t, result)
of tyStatic:
if t.n != nil: result = genTypeInfo(p, skipModifier t)
if t.n != nil: result = genTypeInfo(p, lastSon t)
else: internalError(p.config, "genTypeInfo(" & $t.kind & ')')
else: internalError(p.config, "genTypeInfo(" & $t.kind & ')')

View File

@@ -157,7 +157,7 @@ proc getClosureIterResult*(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym
else:
# XXX a bit hacky:
result = newSym(skResult, getIdent(g.cache, ":result"), idgen, iter, iter.info, {})
result.typ = iter.typ.returnType
result.typ = iter.typ[0]
incl(result.flags, sfUsed)
iter.ast.add newSymNode(result)
@@ -239,14 +239,14 @@ proc interestingIterVar(s: PSym): bool {.inline.} =
template isIterator*(owner: PSym): bool =
owner.kind == skIterator and owner.typ.callConv == ccClosure
template liftingHarmful(conf: ConfigRef; owner: PSym): bool =
proc liftingHarmful(conf: ConfigRef; owner: PSym): bool {.inline.} =
## lambda lifting can be harmful for JS-like code generators.
let isCompileTime = sfCompileTime in owner.flags or owner.kind == skMacro
jsNoLambdaLifting in conf.legacyFeatures and conf.backend == backendJs and not isCompileTime
result = conf.backend == backendJs and not isCompileTime
proc createTypeBoundOpsLL(g: ModuleGraph; refType: PType; info: TLineInfo; idgen: IdGenerator; owner: PSym) =
if owner.kind != skMacro:
createTypeBoundOps(g, nil, refType.elementType, info, idgen)
createTypeBoundOps(g, nil, refType.lastSon, info, idgen)
createTypeBoundOps(g, nil, refType, info, idgen)
if tfHasAsgn in refType.flags or optSeqDestructors in g.config.globalOptions:
owner.flags.incl sfInjectDestructors
@@ -264,7 +264,8 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PN
let iter = n.sym
assert iter.isIterator
result = newNodeIT(nkStmtListExpr, n.info, iter.typ)
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
let hp = getHiddenParam(g, iter)
var env: PNode
if owner.isIterator:
@@ -466,7 +467,6 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
#let obj = c.getEnvTypeForOwner(s.owner).skipTypes({tyOwned, tyRef, tyPtr})
if s.name.id == getIdent(c.graph.cache, ":state").id:
obj.n[0].sym.flags.incl sfNoInit
obj.n[0].sym.itemId = ItemId(module: s.itemId.module, item: -s.itemId.item)
else:
discard addField(obj, s, c.graph.cache, c.idgen)
@@ -551,8 +551,8 @@ proc accessViaEnvParam(g: ModuleGraph; n: PNode; owner: PSym): PNode =
let envParam = getHiddenParam(g, owner)
if not envParam.isNil:
var access = newSymNode(envParam)
var obj = access.typ.elementType
while true:
let obj = access.typ[0]
assert obj.kind == tyObject
let field = getFieldFromObj(obj, s)
if field != nil:
@@ -560,7 +560,6 @@ proc accessViaEnvParam(g: ModuleGraph; n: PNode; owner: PSym): PNode =
let upField = lookupInRecord(obj.n, getIdent(g.cache, upName))
if upField == nil: break
access = rawIndirectAccess(access, upField, n.info)
obj = access.typ.baseClass
localError(g.config, n.info, "internal error: environment misses: " & s.name.s)
result = n
@@ -572,7 +571,7 @@ proc newEnvVar(cache: IdentCache; owner: PSym; typ: PType; info: TLineInfo; idge
when false:
if owner.kind == skIterator and owner.typ.callConv == ccClosure:
let it = getHiddenParam(owner)
addUniqueField(it.typ.elementType, v)
addUniqueField(it.typ[0], v)
result = indirectAccess(newSymNode(it), v, v.info)
else:
result = newSymNode(v)
@@ -883,9 +882,13 @@ proc liftIterToProc*(g: ModuleGraph; fn: PSym; body: PNode; ptrType: PType;
proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool;
idgen: IdGenerator; flags: TransformFlags): PNode =
# XXX backend == backendJs does not suffice! The compiletime stuff needs
# the transformation even when compiling to JS ...
# However we can do lifting for the stuff which is *only* compiletime.
let isCompileTime = sfCompileTime in fn.flags or fn.kind == skMacro
if body.kind == nkEmpty or (jsNoLambdaLifting in g.config.legacyFeatures and
if body.kind == nkEmpty or (
g.config.backend == backendJs and not isCompileTime) or
(fn.skipGenericOwner.kind != skModule and force notin flags):
@@ -990,15 +993,12 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; idgen: IdGenerator; owner: PSym):
# gather vars in a tuple:
var v2 = newNodeI(nkLetSection, body.info)
var vpart = newNodeI(if body.len == 3: nkIdentDefs else: nkVarTuple, body.info)
if body.len == 3 and body[0].kind == nkVarTuple:
vpart = body[0] # fixes for (i,j) in walk() # bug #15924
else:
for i in 0..<body.len-2:
if body[i].kind == nkSym:
body[i].sym.transitionToLet()
vpart.add body[i]
for i in 0..<body.len-2:
if body[i].kind == nkSym:
body[i].sym.transitionToLet()
vpart.add body[i]
vpart.add newNodeI(nkEmpty, body.info) # no explicit type
vpart.add newNodeI(nkEmpty, body.info) # no explicit type
if not env.isNil:
call[0] = makeClosure(g, idgen, call[0].sym, env.newSymNode, body.info)
vpart.add call

View File

@@ -9,7 +9,7 @@
## Layouter for nimpretty.
import idents, lexer, ast, lineinfos, llstream, options, msgs, strutils, pathutils
import idents, lexer, lineinfos, llstream, options, msgs, strutils, pathutils
const
MinLineLen = 15
@@ -243,28 +243,23 @@ proc renderTokens*(em: var Emitter): string =
return content
type
FinalCheck = proc (content: string; origAst: PNode): bool {.nimcall.}
proc writeOut*(em: Emitter; content: string; origAst: PNode; check: FinalCheck) =
proc writeOut*(em: Emitter, content: string) =
## Write to disk
let outFile = em.config.absOutFile
if fileExists(outFile) and readFile(outFile.string) == content:
discard "do nothing, see #9499"
return
var f = llStreamOpen(outFile, fmWrite)
if f == nil:
rawMessage(em.config, errGenerated, "cannot open file: " & outFile.string)
return
f.llStreamWrite content
llStreamClose(f)
if check(content, origAst):
var f = llStreamOpen(outFile, fmWrite)
if f == nil:
rawMessage(em.config, errGenerated, "cannot open file: " & outFile.string)
return
f.llStreamWrite content
llStreamClose(f)
proc closeEmitter*(em: var Emitter; origAst: PNode; check: FinalCheck) =
proc closeEmitter*(em: var Emitter) =
## Renders emitter tokens and write to a file
let content = renderTokens(em)
em.writeOut(content, origAst, check)
em.writeOut(content)
proc wr(em: var Emitter; x: string; lt: LayoutToken) =
em.tokens.add x

View File

@@ -300,7 +300,8 @@ proc getNumber(L: var Lexer, result: var Token) =
# Used to get slightly human friendlier err messages.
const literalishChars = {'A'..'Z', 'a'..'z', '0'..'9', '_', '.', '\''}
var msgPos = L.bufpos
var t = Token(literal: "")
var t: Token
t.literal = ""
L.bufpos = startpos # Use L.bufpos as pos because of matchChars
matchChars(L, t, literalishChars)
# We must verify +/- specifically so that we're not past the literal

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; isDistinct = false): PSym
info: TLineInfo; idgen: IdGenerator): PSym
proc createTypeBoundOps*(g: ModuleGraph; c: PContext; orig: PType; info: TLineInfo;
idgen: IdGenerator)
@@ -56,10 +56,10 @@ proc destructorOverridden(g: ModuleGraph; t: PType): bool =
op != nil and sfOverridden in op.flags
proc fillBodyTup(c: var TLiftCtx; t: PType; body, x, y: PNode) =
for i, a in t.ikids:
for i in 0..<t.len:
let lit = lowerings.newIntLit(c.g, x.info, i)
let b = if c.kind == attachedTrace: y else: y.at(lit, a)
fillBody(c, a, body, x.at(lit, a), b)
let b = if c.kind == attachedTrace: y else: y.at(lit, t[i])
fillBody(c, t[i], body, x.at(lit, t[i]), b)
proc dotField(x: PNode, f: PSym): PNode =
result = newNodeI(nkDotExpr, x.info, 2)
@@ -139,9 +139,9 @@ proc genContainerOf(c: var TLiftCtx; objType: PType, field, x: PSym): PNode =
result.add minusExpr
proc destructorCall(c: var TLiftCtx; op: PSym; x: PNode): PNode =
var destroy = newNodeIT(nkCall, x.info, op.typ.returnType)
var destroy = newNodeIT(nkCall, x.info, op.typ[0])
destroy.add(newSymNode(op))
if op.typ.firstParamType.kind != tyVar:
if op.typ[1].kind != tyVar:
destroy.add x
else:
destroy.add genAddr(c, x)
@@ -153,11 +153,11 @@ proc destructorCall(c: var TLiftCtx; op: PSym; x: PNode): PNode =
result = destroy
proc genWasMovedCall(c: var TLiftCtx; op: PSym; x: PNode): PNode =
result = newNodeIT(nkCall, x.info, op.typ.returnType)
result = newNodeIT(nkCall, x.info, op.typ[0])
result.add(newSymNode(op))
result.add genAddr(c, x)
proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool, enforceWasMoved = false) =
proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool) =
case n.kind
of nkSym:
if c.filterDiscriminator != nil: return
@@ -167,8 +167,6 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool,
enforceDefaultOp:
defaultOp(c, f.typ, body, x.dotField(f), b)
else:
if enforceWasMoved:
body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x.dotField(f))
fillBody(c, f.typ, body, x.dotField(f), b)
of nkNilLit: discard
of nkRecCase:
@@ -207,7 +205,7 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool,
branch[^1] = newNodeI(nkStmtList, c.info)
fillBodyObj(c, n[i].lastSon, branch[^1], x, y,
enforceDefaultOp = localEnforceDefaultOp, enforceWasMoved = c.kind == attachedAsgn)
enforceDefaultOp = localEnforceDefaultOp)
if branch[^1].len == 0: inc emptyBranches
caseStmt.add(branch)
if emptyBranches != n.len-1:
@@ -218,23 +216,20 @@ 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:
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)
else:
illFormedAstLocal(n, c.g.config)
proc fillBodyObjTImpl(c: var TLiftCtx; t: PType, body, x, y: PNode) =
if t.baseClass != nil:
let obj = newNodeIT(nkHiddenSubConv, c.info, t.baseClass)
obj.add newNodeI(nkEmpty, c.info)
obj.add x
fillBody(c, skipTypes(t.baseClass, abstractPtrs), body, obj, y)
if t.len > 0 and t[0] != nil:
fillBody(c, skipTypes(t[0], abstractPtrs), body, x, y)
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)
var obj = t
while obj.baseClass != nil:
obj = skipTypes(obj.baseClass, abstractPtrs)
while obj.len > 0 and obj[0] != nil:
obj = skipTypes(obj[0], abstractPtrs)
hasCase = hasCase or isCaseObj(obj.n)
if hasCase and c.kind in {attachedAsgn, attachedDeepCopy}:
@@ -284,7 +279,6 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
c.kind = attachedDestructor
fillBodyObjTImpl(c, t, body, blob, y)
c.kind = prevKind
else:
fillBodyObjTImpl(c, t, body, x, y)
@@ -294,7 +288,7 @@ proc boolLit*(g: ModuleGraph; info: TLineInfo; value: bool): PNode =
proc getCycleParam(c: TLiftCtx): PNode =
assert c.kind in {attachedAsgn, attachedDup}
if c.fn.typ.len == 3 + ord(c.kind == attachedAsgn):
if c.fn.typ.len == 4:
result = c.fn.typ.n.lastSon
assert result.kind == nkSym
assert result.sym.name.s == "cyclic"
@@ -308,35 +302,27 @@ proc newHookCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode =
result.add newSymNode(op)
if sfNeverRaises notin op.flags:
c.canRaise = true
if op.typ.firstParamType.kind == tyVar:
if op.typ[1].kind == tyVar:
result.add genAddr(c, x)
else:
result.add x
if y != nil:
result.add y
if op.typ.signatureLen == 4:
if op.typ.len == 4:
assert y != nil
if c.fn.typ.signatureLen == 4:
if c.fn.typ.len == 4:
result.add getCycleParam(c)
else:
# assume the worst: A cycle is created:
result.add boolLit(c.g, y.info, true)
proc newOpCall(c: var TLiftCtx; op: PSym; x: PNode): PNode =
result = newNodeIT(nkCall, x.info, op.typ.returnType)
result = newNodeIT(nkCall, x.info, op.typ[0])
result.add(newSymNode(op))
result.add x
if sfNeverRaises notin op.flags:
c.canRaise = true
if c.kind == attachedDup and op.typ.len == 3:
assert x != nil
if c.fn.typ.len == 3:
result.add getCycleParam(c)
else:
# assume the worst: A cycle is created:
result.add boolLit(c.g, x.info, true)
proc newDeepCopyCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode =
result = newAsgnStmt(x, newOpCall(c, op, y))
@@ -559,7 +545,7 @@ proc forallElements(c: var TLiftCtx; t: PType; body, x, y: PNode) =
let counterIdx = body.len
let i = declareCounter(c, body, toInt64(firstOrd(c.g.config, t)))
let whileLoop = genWhileLoop(c, i, x)
let elemType = t.elementType
let elemType = t.lastSon
let b = if c.kind == attachedTrace: y else: y.at(i, elemType)
fillBody(c, elemType, whileLoop[1], x.at(i, elemType), b)
if whileLoop[1].len > 0:
@@ -670,7 +656,7 @@ proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
proc cyclicType*(g: ModuleGraph, t: PType): bool =
case t.kind
of tyRef: result = types.canFormAcycle(g, t.elementType)
of tyRef: result = types.canFormAcycle(g, t.lastSon)
of tyProc: result = t.callConv == ccClosure
else: result = false
@@ -695,7 +681,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
]#
var actions = newNodeI(nkStmtList, c.info)
let elemType = t.elementType
let elemType = t.lastSon
createTypeBoundOps(c.g, c.c, elemType, c.info, c.idgen)
let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(c.g, elemType)
@@ -865,7 +851,7 @@ proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
var actions = newNodeI(nkStmtList, c.info)
let elemType = t.skipModifier
let elemType = t.lastSon
#fillBody(c, elemType, actions, genDeref(x), genDeref(y))
#var disposeCall = genBuiltin(c, mDispose, "dispose", x)
@@ -1031,7 +1017,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
fillBodyObjT(c, t, body, x, y)
of tyDistinct:
if not considerUserDefinedOp(c, t, body, x, y):
fillBody(c, t.elementType, body, x, y)
fillBody(c, t[0], body, x, y)
of tyTuple:
fillBodyTup(c, t, body, x, y)
of tyVarargs, tyOpenArray:
@@ -1048,18 +1034,16 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
discard
of tyOrdinal, tyRange, tyInferred,
tyGenericInst, tyAlias, tySink:
fillBody(c, skipModifier(t), body, x, y)
fillBody(c, lastSon(t), body, x, y)
of tyConcept, tyIterable: raiseAssert "unreachable"
proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType;
kind: TTypeAttachedOp; info: TLineInfo;
idgen: IdGenerator): PSym =
assert typ.kind == tyDistinct
let baseType = typ.elementType
let baseType = typ[0]
if getAttachedOp(g, baseType, kind) == nil:
# 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)
discard produceSym(g, c, baseType, kind, info, idgen)
result = getAttachedOp(g, baseType, kind)
setAttachedOp(g, idgen.module, typ, kind, result)
@@ -1098,7 +1082,7 @@ proc symDupPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttache
incl result.flags, sfGeneratedOp
proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp;
info: TLineInfo; idgen: IdGenerator; isDiscriminant = false; isDistinct = false): PSym =
info: TLineInfo; idgen: IdGenerator; isDiscriminant = false): PSym =
if kind == attachedDup:
return symDupPrototype(g, typ, owner, kind, info, idgen)
@@ -1109,7 +1093,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} and not isDistinct)):
((g.config.isDefined("nimPreviewNonVarDestructor") and not isDiscriminant) or typ.kind in {tyRef, tyString, tySequence}):
dest.typ = typ
else:
dest.typ = makeVarType(typ.owner, typ, idgen)
@@ -1151,19 +1135,19 @@ proc genTypeFieldCopy(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add newAsgnStmt(xx, yy)
proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
info: TLineInfo; idgen: IdGenerator; isDistinct = false): PSym =
info: TLineInfo; idgen: IdGenerator): 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, isDistinct = isDistinct)
result = symPrototype(g, typ, typ.owner, kind, info, idgen)
var a = TLiftCtx(info: info, g: g, kind: kind, c: c, asgnForType: typ, idgen: idgen,
fn: result)
let dest = if kind == attachedDup: result.ast[resultPos].sym else: result.typ.n[1].sym
let d = if result.typ.firstParamType.kind == tyVar: newDeref(newSymNode(dest)) else: newSymNode(dest)
let d = if result.typ[1].kind == tyVar: newDeref(newSymNode(dest)) else: newSymNode(dest)
let src = case kind
of {attachedDestructor, attachedWasMoved}: newNodeIT(nkSym, info, getSysType(g, info, tyPointer))
of attachedDup: newSymNode(result.typ.n[1].sym)
@@ -1176,7 +1160,7 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
## compiler can use a combination of `=destroy` and memCopy for sink op
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 newOpCall(a, op, if op.typ[1].kind == tyVar: d[0] else: d)
result.ast[bodyPos].add newAsgnStmt(d, src)
else:
var tk: TTypeKind
@@ -1195,12 +1179,7 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
# bug #19205: Do not forget to also copy the hidden type field:
genTypeFieldCopy(a, typ, result.ast[bodyPos], d, src)
if not a.canRaise:
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 not a.canRaise: incl result.flags, sfNeverRaises
completePartialOp(g, idgen.module, typ, kind, result)
@@ -1260,7 +1239,7 @@ proc inst(g: ModuleGraph; c: PContext; t: PType; kind: TTypeAttachedOp; idgen: I
else:
localError(g.config, info, "unresolved generic parameter")
proc isTrival*(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;

View File

@@ -92,10 +92,8 @@ type
warnStmtListLambda = "StmtListLambda",
warnBareExcept = "BareExcept",
warnImplicitDefaultValue = "ImplicitDefaultValue",
warnGenericsIgnoredInjection = "GenericsIgnoredInjection",
warnStdPrefix = "StdPrefix"
warnUser = "User",
warnGlobalVarConstructorTemporary = "GlobalVarConstructorTemporary",
# hints
hintSuccess = "Success", hintSuccessX = "SuccessX",
hintCC = "CC",
@@ -198,10 +196,8 @@ const
warnStmtListLambda: "statement list expression assumed to be anonymous proc; this is deprecated, use `do (): ...` or `proc () = ...` instead",
warnBareExcept: "$1",
warnImplicitDefaultValue: "$1",
warnGenericsIgnoredInjection: "$1",
warnStdPrefix: "$1 needs the 'std' prefix",
warnUser: "$1",
warnGlobalVarConstructorTemporary: "global variable '$1' initialization requires a temporary variable",
hintSuccess: "operation successful: $#",
# keep in sync with `testament.isSuccess`
hintSuccessX: "$build\n$loc lines; ${sec}s; $mem; proj: $project; out: $output",

View File

@@ -137,7 +137,7 @@ proc nextIdentIter(ti: var ModuleIter; marked: var IntSet; im: ImportedModule;
return result
iterator symbols(im: ImportedModule; marked: var IntSet; name: PIdent; g: ModuleGraph): PSym =
var ti: ModuleIter = default(ModuleIter)
var ti: ModuleIter
var candidate = initIdentIter(ti, marked, im, name, g)
while candidate != nil:
yield candidate
@@ -150,7 +150,7 @@ iterator importedItems*(c: PContext; name: PIdent): PSym =
yield s
proc allPureEnumFields(c: PContext; name: PIdent): seq[PSym] =
var ti: TIdentIter = default(TIdentIter)
var ti: TIdentIter
result = @[]
var res = initIdentIter(ti, c.pureEnumFields, name)
while res != nil:
@@ -222,7 +222,7 @@ proc debugScopes*(c: PContext; limit=0, max = int.high) {.deprecated.} =
proc searchInScopesAllCandidatesFilterBy*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSym] =
result = @[]
for scope in allScopes(c.currentScope):
var ti: TIdentIter = default(TIdentIter)
var ti: TIdentIter
var candidate = initIdentIter(ti, scope.symbols, s)
while candidate != nil:
if candidate.kind in filter:
@@ -240,7 +240,7 @@ proc searchInScopesFilterBy*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSy
result = @[]
block outer:
for scope in allScopes(c.currentScope):
var ti: TIdentIter = default(TIdentIter)
var ti: TIdentIter
var candidate = initIdentIter(ti, scope.symbols, s)
while candidate != nil:
if candidate.kind in filter:
@@ -256,23 +256,11 @@ proc searchInScopesFilterBy*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSy
if s.kind in filter:
result.add s
proc cmpScopes*(ctx: PContext, s: PSym): int =
# Do not return a negative number
if s.originatingModule == ctx.module:
result = 2
var owner = s
while true:
owner = owner.skipGenericOwner
if owner.kind == skModule: break
inc result
else:
result = 1
proc isAmbiguous*(c: PContext, s: PIdent, filter: TSymKinds, sym: var PSym): bool =
result = false
block outer:
for scope in allScopes(c.currentScope):
var ti: TIdentIter = default(TIdentIter)
var ti: TIdentIter
var candidate = initIdentIter(ti, scope.symbols, s)
var scopeHasCandidate = false
while candidate != nil:
@@ -303,16 +291,8 @@ proc isAmbiguous*(c: PContext, s: PIdent, filter: TSymKinds, sym: var PSym): boo
# imports had a candidate but wasn't ambiguous
return false
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.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)
proc errorSym*(c: PContext, n: PNode): PSym =
## creates an error symbol to avoid cascading errors (for IDE support)
var m = n
# ensure that 'considerQuotedIdent' can't fail:
if m.kind == nkDotExpr: m = m[1]
@@ -320,7 +300,12 @@ proc errorSym*(c: PContext, n: PNode): PSym =
considerQuotedIdent(c, m)
else:
getIdent(c.cache, "err:" & renderTree(m))
result = errorSym(c, ident, n.info)
result = newSym(skError, ident, c.idgen, getCurrOwner(c), n.info, {})
result.typ = errorType(c)
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)
type
TOverloadIterMode* = enum
@@ -347,7 +332,7 @@ proc getSymRepr*(conf: ConfigRef; s: PSym, getDeclarationPath = true): string =
proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) =
# check if all symbols have been used and defined:
var it: TTabIter = default(TTabIter)
var it: TTabIter
var s = initTabIter(it, scope.symbols)
var missingImpls = 0
var unusedSyms: seq[tuple[sym: PSym, key: string]] = @[]
@@ -502,7 +487,7 @@ proc mustFixSpelling(c: PContext): bool {.inline.} =
result = c.config.spellSuggestMax != 0 and c.compilesContextId == 0
# don't slowdown inside compiles()
proc fixSpelling(c: PContext, ident: PIdent, result: var string) =
proc fixSpelling(c: PContext, n: PNode, ident: PIdent, result: var string) =
## when we cannot find the identifier, suggest nearby spellings
var list = initHeapQueue[SpellCandidate]()
let name0 = ident.s.nimIdentNormalize
@@ -558,10 +543,10 @@ proc errorUseQualifier(c: PContext; info: TLineInfo; s: PSym; amb: var bool): PS
amb = false
proc errorUseQualifier*(c: PContext; info: TLineInfo; s: PSym) =
var amb: bool = false
var amb: bool
discard errorUseQualifier(c, info, s, amb)
proc errorUseQualifier*(c: PContext; info: TLineInfo; candidates: seq[PSym]; prefix = "use one of") =
proc errorUseQualifier(c: PContext; info: TLineInfo; candidates: seq[PSym]; prefix = "use one of") =
var err = "ambiguous identifier: '" & candidates[0].name.s & "'"
var i = 0
for candidate in candidates:
@@ -584,11 +569,7 @@ proc errorUndeclaredIdentifier*(c: PContext; info: TLineInfo; name: string, extr
if name == "_":
err = "the special identifier '_' is ignored in declarations and cannot be used"
else:
err = "undeclared identifier: '" & name & "'"
if "`gensym" in name:
err.add "; if declared in a template, this identifier may be inconsistently marked inject or gensym"
if extra.len != 0:
err.add extra
err = "undeclared identifier: '" & name & "'" & extra
if c.recursiveDep.len > 0:
err.add "\nThis might be caused by a recursive module dependency:\n"
err.add c.recursiveDep
@@ -596,11 +577,11 @@ proc errorUndeclaredIdentifier*(c: PContext; info: TLineInfo; name: string, extr
c.recursiveDep = ""
localError(c.config, info, errGenerated, err)
proc errorUndeclaredIdentifierHint*(c: PContext; ident: PIdent; info: TLineInfo): PSym =
proc errorUndeclaredIdentifierHint*(c: PContext; n: PNode, ident: PIdent): PSym =
var extra = ""
if c.mustFixSpelling: fixSpelling(c, ident, extra)
errorUndeclaredIdentifier(c, info, ident.s, extra)
result = errorSym(c, ident, info)
if c.mustFixSpelling: fixSpelling(c, n, ident, extra)
errorUndeclaredIdentifier(c, n.info, ident.s, extra)
result = errorSym(c, n)
proc lookUp*(c: PContext, n: PNode): PSym =
# Looks up a symbol. Generates an error in case of nil.
@@ -608,13 +589,13 @@ proc lookUp*(c: PContext, n: PNode): PSym =
case n.kind
of nkIdent:
result = searchInScopes(c, n.ident, amb)
if result == nil: result = errorUndeclaredIdentifierHint(c, n.ident, n.info)
if result == nil: result = errorUndeclaredIdentifierHint(c, n, n.ident)
of nkSym:
result = n.sym
of nkAccQuoted:
var ident = considerQuotedIdent(c, n)
result = searchInScopes(c, ident, amb)
if result == nil: result = errorUndeclaredIdentifierHint(c, ident, n.info)
if result == nil: result = errorUndeclaredIdentifierHint(c, n, ident)
else:
internalError(c.config, n.info, "lookUp")
return nil
@@ -628,29 +609,16 @@ type
TLookupFlag* = enum
checkAmbiguity, checkUndeclared, checkModule, checkPureEnumFields
const allExceptModule = {low(TSymKind)..high(TSymKind)} - {skModule, skPackage}
proc lookUpCandidates*(c: PContext, ident: PIdent, filter: set[TSymKind]): seq[PSym] =
result = searchInScopesFilterBy(c, ident, filter)
if result.len == 0:
result.add allPureEnumFields(c, ident)
proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
const allExceptModule = {low(TSymKind)..high(TSymKind)} - {skModule, skPackage}
case n.kind
of nkIdent, nkAccQuoted:
var amb = false
var ident = considerQuotedIdent(c, n)
if checkModule in flags:
result = searchInScopes(c, ident, amb)
if result == nil:
let candidates = allPureEnumFields(c, ident)
if candidates.len > 0:
result = candidates[0]
amb = candidates.len > 1
if amb and checkAmbiguity in flags:
errorUseQualifier(c, n.info, candidates)
else:
let candidates = lookUpCandidates(c, ident, allExceptModule)
let candidates = searchInScopesFilterBy(c, ident, allExceptModule)
if candidates.len > 0:
result = candidates[0]
amb = candidates.len > 1
@@ -658,8 +626,16 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
errorUseQualifier(c, n.info, candidates)
else:
result = nil
if result == nil:
let candidates = allPureEnumFields(c, ident)
if candidates.len > 0:
result = candidates[0]
amb = candidates.len > 1
if amb and checkAmbiguity in flags:
errorUseQualifier(c, n.info, candidates)
if result == nil and checkUndeclared in flags:
result = errorUndeclaredIdentifierHint(c, ident, n.info)
result = errorUndeclaredIdentifierHint(c, n, ident)
elif checkAmbiguity in flags and result != nil and amb:
result = errorUseQualifier(c, n.info, result, amb)
c.isAmbiguous = amb
@@ -679,17 +655,17 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
result = strTableGet(c.topLevelScope.symbols, ident)
else:
if c.importModuleLookup.getOrDefault(m.name.id).len > 1:
var amb: bool = false
var amb: bool
result = errorUseQualifier(c, n.info, m, amb)
else:
result = someSym(c.graph, m, ident)
if result == nil and checkUndeclared in flags:
result = errorUndeclaredIdentifierHint(c, ident, n[1].info)
result = errorUndeclaredIdentifierHint(c, n[1], ident)
elif n[1].kind == nkSym:
result = n[1].sym
if result.owner != nil and result.owner != m and checkUndeclared in flags:
# dotExpr in templates can end up here
result = errorUndeclaredIdentifierHint(c, result.name, n[1].info)
result = errorUndeclaredIdentifierHint(c, n[1], considerQuotedIdent(c, n[1]))
elif checkUndeclared in flags and
n[1].kind notin {nkOpenSymChoice, nkClosedSymChoice}:
localError(c.config, n[1].info, "identifier expected, but got: " &

View File

@@ -19,7 +19,7 @@ when defined(nimPreviewSlimSystem):
import std/assertions
proc newDeref*(n: PNode): PNode {.inline.} =
result = newNodeIT(nkHiddenDeref, n.info, n.typ.elementType)
result = newNodeIT(nkHiddenDeref, n.info, n.typ[0])
result.add n
proc newTupleAccess*(g: ModuleGraph; tup: PNode, i: int): PNode =
@@ -255,14 +255,14 @@ proc newDotExpr*(obj, b: PSym): PNode =
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)[0]
var t = deref.typ.skipTypes(abstractInst)
var field: PSym
while true:
assert t.kind == tyObject
field = lookupInRecord(t.n, b)
if field != nil: break
t = t.baseClass
t = t[0]
if t == nil: break
t = t.skipTypes(skipPtrs)
#if field == nil:
@@ -278,7 +278,7 @@ proc indirectAccess*(a: PNode, b: ItemId, info: TLineInfo): PNode =
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)[0]
var t = deref.typ.skipTypes(abstractInst)
var field: PSym
let bb = getIdent(cache, b)
@@ -286,7 +286,7 @@ proc indirectAccess*(a: PNode, b: string, info: TLineInfo; cache: IdentCache): P
assert t.kind == tyObject
field = getSymFromList(t.n, bb)
if field != nil: break
t = t.baseClass
t = t[0]
if t == nil: break
t = t.skipTypes(skipPtrs)
#if field == nil:
@@ -306,7 +306,7 @@ proc getFieldFromObj*(t: PType; v: PSym): PSym =
assert t.kind == tyObject
result = lookupInRecord(t.n, v.itemId)
if result != nil: break
t = t.baseClass
t = t[0]
if t == nil: break
t = t.skipTypes(skipPtrs)
@@ -325,7 +325,7 @@ proc genAddrOf*(n: PNode; idgen: IdGenerator; typeKind = tyPtr): PNode =
proc genDeref*(n: PNode; k = nkHiddenDeref): PNode =
result = newNodeIT(k, n.info,
n.typ.skipTypes(abstractInst).elementType)
n.typ.skipTypes(abstractInst)[0])
result.add n
proc callCodegenProc*(g: ModuleGraph; name: string;
@@ -344,7 +344,7 @@ 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[0]
proc newIntLit*(g: ModuleGraph; info: TLineInfo; value: BiggestInt): PNode =
result = nkIntLit.newIntNode(value)

View File

@@ -35,7 +35,7 @@ proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSy
for r in systemModuleSyms(g, id):
if r.magic == m:
# prefer the tyInt variant:
if r.typ.returnType != nil and r.typ.returnType.kind == tyInt: return r
if r.typ[0] != nil and r.typ[0].kind == tyInt: return r
result = r
if result != nil: return result
localError(g.config, info, "system module needs: " & name)

View File

@@ -155,7 +155,7 @@ proc commandCompileToC(graph: ModuleGraph) =
extccomp.callCCompiler(conf)
# for now we do not support writing out a .json file with the build instructions when HCR is on
if not conf.hcrOn:
extccomp.writeJsonBuildInstructions(conf, graph.cachedFiles)
extccomp.writeJsonBuildInstructions(conf)
if optGenScript in graph.config.globalOptions:
writeDepsFile(graph)
if optGenCDeps in graph.config.globalOptions:
@@ -222,7 +222,7 @@ proc commandScan(cache: IdentCache, config: ConfigRef) =
var stream = llStreamOpen(f, fmRead)
if stream != nil:
var
L: Lexer = default(Lexer)
L: Lexer
tok: Token = default(Token)
openLexer(L, f, stream, cache, config)
while true:
@@ -326,8 +326,7 @@ proc mainCommand*(graph: ModuleGraph) =
# so by default should not end up in $PWD nor in $projectPath.
var ret = if optUseNimcache in conf.globalOptions: getNimcacheDir(conf)
else: conf.projectPath
if not ret.string.isAbsolute: # `AbsoluteDir` is not a real guarantee
rawMessage(conf, errCannotOpenFile, ret.string & "/")
doAssert ret.string.isAbsolute # `AbsoluteDir` is not a real guarantee
if conf.cmd in cmdDocLike + {cmdRst2html, cmdRst2tex, cmdMd2html, cmdMd2tex}:
ret = ret / htmldocsDir
conf.outDir = ret

View File

@@ -1,59 +0,0 @@
import std/strutils
import ast, modulegraphs
proc mangle*(name: string): string =
result = newStringOfCap(name.len)
var start = 0
if name[0] in Digits:
result.add("X" & name[0])
start = 1
var requiresUnderscore = false
template special(x) =
result.add x
requiresUnderscore = true
for i in start..<name.len:
let c = name[i]
case c
of 'a'..'z', '0'..'9', 'A'..'Z':
result.add(c)
of '_':
# we generate names like 'foo_9' for scope disambiguations and so
# disallow this here:
if i > 0 and i < name.len-1 and name[i+1] in Digits:
discard
else:
result.add(c)
of '$': special "dollar"
of '%': special "percent"
of '&': special "amp"
of '^': special "roof"
of '!': special "emark"
of '?': special "qmark"
of '*': special "star"
of '+': special "plus"
of '-': special "minus"
of '/': special "slash"
of '\\': special "backslash"
of '=': special "eq"
of '<': special "lt"
of '>': special "gt"
of '~': special "tilde"
of ':': special "colon"
of '.': special "dot"
of '@': special "at"
of '|': special "bar"
else:
result.add("X" & toHex(ord(c), 2))
requiresUnderscore = true
if requiresUnderscore:
result.add "_"
proc mangleParamExt*(s: PSym): string =
result = "_p"
result.addInt s.position
proc mangleProcNameExt*(graph: ModuleGraph, s: PSym): string =
result = "__"
result.add graph.ifaces[s.itemId.module].uniqueName
result.add "_u"
result.addInt s.itemId.item # s.disamb #

View File

@@ -11,9 +11,9 @@
## 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, algorithm]
import std/[intsets, tables, hashes]
import ../dist/checksums/src/checksums/md5
import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils, packages, suggestsymdb
import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils, packages
import ic / [packed_ast, ic]
@@ -55,6 +55,11 @@ type
concreteTypes*: seq[FullId]
inst*: PInstantiation
SymInfoPair* = object
sym*: PSym
info*: TLineInfo
isDecl*: bool
PipelinePass* = enum
NonePass
SemPass
@@ -103,7 +108,7 @@ type
doStopCompile*: proc(): bool {.closure.}
usageSym*: PSym # for nimsuggest
owners*: seq[PSym]
suggestSymbols*: SuggestSymbolDatabase
suggestSymbols*: Table[FileIndex, seq[SymInfoPair]]
suggestErrors*: Table[FileIndex, seq[Suggest]]
methods*: seq[tuple[methods: seq[PSym], dispatcher: PSym]] # needs serialization!
bucketTable*: CountTable[ItemId]
@@ -135,8 +140,6 @@ type
idgen*: IdGenerator
operators*: Operators
cachedFiles*: StringTableRef
TPassContext* = object of RootObj # the pass's context
idgen*: IdGenerator
PPassContext* = ref TPassContext
@@ -220,7 +223,7 @@ proc isCachedModule(g: ModuleGraph; module: int): bool {.inline.} =
proc isCachedModule*(g: ModuleGraph; m: PSym): bool {.inline.} =
isCachedModule(g, m.position)
proc simulateCachedModule(g: ModuleGraph; moduleSym: PSym; m: PackedModuleWriter) =
proc simulateCachedModule(g: ModuleGraph; moduleSym: PSym; m: PackedModule) =
when false:
echo "simulating ", moduleSym.name.s, " ", moduleSym.position
simulateLoadedModule(g.packed, g.config, g.cache, moduleSym, m)
@@ -230,7 +233,7 @@ proc initEncoder*(g: ModuleGraph; module: PSym) =
if id >= g.encoders.len:
setLen g.encoders, id+1
ic.initEncoder(g.encoders[id],
g.packed[id].toDisk, module, g.config, g.startupPackedConfig)
g.packed[id].fromDisk, module, g.config, g.startupPackedConfig)
type
ModuleIter* = object
@@ -259,7 +262,7 @@ proc nextModuleIter*(mi: var ModuleIter; g: ModuleGraph): PSym =
iterator allSyms*(g: ModuleGraph; m: PSym): PSym =
let importHidden = optImportHidden in m.options
if isCachedModule(g, m):
var rodIt: RodIter = default(RodIter)
var rodIt: RodIter
var r = initRodIterAllSyms(rodIt, g.config, g.cache, g.packed, FileIndex m.position, importHidden)
while r != nil:
yield r
@@ -280,7 +283,7 @@ proc systemModuleSym*(g: ModuleGraph; name: PIdent): PSym =
result = someSym(g, g.systemModule, name)
iterator systemModuleSyms*(g: ModuleGraph; name: PIdent): PSym =
var mi: ModuleIter = default(ModuleIter)
var mi: ModuleIter
var r = initModuleIter(mi, g, g.systemModule, name)
while r != nil:
yield r
@@ -351,8 +354,8 @@ proc completePartialOp*(g: ModuleGraph; module: int; t: PType; op: TTypeAttached
if g.config.symbolFiles != disabledSf:
assert module < g.encoders.len
assert isActive(g.encoders[module])
toPackedGeneratedProcDef(value, g.encoders[module], g.packed[module].toDisk)
#storeAttachedProcDef(t, op, value, g.encoders[module], g.packed[module].toDisk)
toPackedGeneratedProcDef(value, g.encoders[module], g.packed[module].fromDisk)
#storeAttachedProcDef(t, op, value, g.encoders[module], g.packed[module].fromDisk)
iterator getDispatchers*(g: ModuleGraph): PSym =
for i in g.dispatchers.mitems:
@@ -474,21 +477,19 @@ proc registerModuleById*(g: ModuleGraph; m: FileIndex) =
proc initOperators*(g: ModuleGraph): Operators =
# These are safe for IC.
# Public because it's used by DrNim.
result = Operators(
opLe: createMagic(g, "<=", mLeI),
opLt: createMagic(g, "<", mLtI),
opAnd: createMagic(g, "and", mAnd),
opOr: createMagic(g, "or", mOr),
opIsNil: createMagic(g, "isnil", mIsNil),
opEq: createMagic(g, "==", mEqI),
opAdd: createMagic(g, "+", mAddI),
opSub: createMagic(g, "-", mSubI),
opMul: createMagic(g, "*", mMulI),
opDiv: createMagic(g, "div", mDivI),
opLen: createMagic(g, "len", mLengthSeq),
opNot: createMagic(g, "not", mNot),
opContains: createMagic(g, "contains", mInSet)
)
result.opLe = createMagic(g, "<=", mLeI)
result.opLt = createMagic(g, "<", mLtI)
result.opAnd = createMagic(g, "and", mAnd)
result.opOr = createMagic(g, "or", mOr)
result.opIsNil = createMagic(g, "isnil", mIsNil)
result.opEq = createMagic(g, "==", mEqI)
result.opAdd = createMagic(g, "+", mAddI)
result.opSub = createMagic(g, "-", mSubI)
result.opMul = createMagic(g, "*", mMulI)
result.opDiv = createMagic(g, "div", mDivI)
result.opLen = createMagic(g, "len", mLengthSeq)
result.opNot = createMagic(g, "not", mNot)
result.opContains = createMagic(g, "contains", mInSet)
proc initModuleGraphFields(result: ModuleGraph) =
# A module ID of -1 means that the symbol is not attached to a module at all,
@@ -501,7 +502,7 @@ proc initModuleGraphFields(result: ModuleGraph) =
result.importStack = @[]
result.inclToMod = initTable[FileIndex, FileIndex]()
result.owners = @[]
result.suggestSymbols = initTable[FileIndex, SuggestFileSymbolDatabase]()
result.suggestSymbols = initTable[FileIndex, seq[SymInfoPair]]()
result.suggestErrors = initTable[FileIndex, seq[Suggest]]()
result.methods = @[]
result.compilerprocs = initStrTable()
@@ -515,7 +516,6 @@ proc initModuleGraphFields(result: ModuleGraph) =
result.symBodyHashes = initTable[int, SigHash]()
result.operators = initOperators(result)
result.emittedTypeInfo = initTable[string, FileIndex]()
result.cachedFiles = newStringTable()
proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
result = ModuleGraph()
@@ -555,14 +555,14 @@ proc rememberEmittedTypeInfo*(g: ModuleGraph; m: FileIndex; ti: string) =
if g.config.symbolFiles != disabledSf:
#assert g.encoders[m.int32].isActive
assert g.packed[m.int32].status != stored
g.packed[m.int32].toDisk.emittedTypeInfo.add ti
g.packed[m.int32].fromDisk.emittedTypeInfo.add ti
#echo "added typeinfo ", m.int32, " ", ti, " suspicious ", not g.encoders[m.int32].isActive
proc rememberFlag*(g: ModuleGraph; m: PSym; flag: ModuleBackendFlag) =
if g.config.symbolFiles != disabledSf:
#assert g.encoders[m.int32].isActive
assert g.packed[m.position].status != stored
g.packed[m.position].toDisk.backendFlags.incl flag
g.packed[m.position].fromDisk.backendFlags.incl flag
proc closeRodFile*(g: ModuleGraph; m: PSym) =
if g.config.symbolFiles in {readOnlySf, v2Sf}:
@@ -571,14 +571,14 @@ proc closeRodFile*(g: ModuleGraph; m: PSym) =
# not depend on the hard disk contents!
let mint = m.position
saveRodFile(toRodFile(g.config, AbsoluteFile toFullPath(g.config, FileIndex(mint))),
g.encoders[mint], g.packed[mint].toDisk)
g.encoders[mint], g.packed[mint].fromDisk)
g.packed[mint].status = stored
elif g.config.symbolFiles == stressTest:
# debug code, but maybe a good idea for production? Could reduce the compiler's
# memory consumption considerably at the cost of more loads from disk.
let mint = m.position
simulateCachedModule(g, m, g.packed[mint].toDisk)
simulateCachedModule(g, m, g.packed[mint].fromDisk)
g.packed[mint].status = loaded
proc dependsOn(a, b: int): int {.inline.} = (a shl 15) + b
@@ -707,14 +707,16 @@ func belongsToStdlib*(graph: ModuleGraph, sym: PSym): bool =
## Check if symbol belongs to the 'stdlib' package.
sym.getPackageSymbol.getPackageId == graph.systemModule.getPackageId
proc fileSymbols*(graph: ModuleGraph, fileIdx: FileIndex): SuggestFileSymbolDatabase =
result = graph.suggestSymbols.getOrDefault(fileIdx, newSuggestFileSymbolDatabase(fileIdx, optIdeExceptionInlayHints in graph.config.globalOptions))
doAssert(result.fileIndex == fileIdx)
proc `==`*(a, b: SymInfoPair): bool =
result = a.sym == b.sym and a.info.exactEquals(b.info)
proc fileSymbols*(graph: ModuleGraph, fileIdx: FileIndex): seq[SymInfoPair] =
result = graph.suggestSymbols.getOrDefault(fileIdx, @[])
iterator suggestSymbolsIter*(g: ModuleGraph): SymInfoPair =
for xs in g.suggestSymbols.values:
for i in xs.lineInfo.low..xs.lineInfo.high:
yield xs.getSymInfoPair(i)
for x in xs:
yield x
iterator suggestErrorsIter*(g: ModuleGraph): Suggest =
for xs in g.suggestErrors.values:

View File

@@ -38,18 +38,11 @@ proc getModuleName*(conf: ConfigRef; n: PNode): string =
localError(n.info, "only '/' supported with $package notation")
result = ""
else:
if n0.kind in nkIdentKinds:
let ident = n0.getPIdent
if ident != nil and ident.s[0] == '/':
let modname = getModuleName(conf, n[2])
# hacky way to implement 'x / y /../ z':
result = getModuleName(conf, n1)
result.add renderTree(n0, {renderNoComments}).replace(" ")
result.add modname
else:
result = ""
else:
result = ""
let modname = getModuleName(conf, n[2])
# hacky way to implement 'x / y /../ z':
result = getModuleName(conf, n1)
result.add renderTree(n0, {renderNoComments}).replace(" ")
result.add modname
of nkPrefix:
when false:
if n[0].kind == nkIdent and n[0].ident.s == "$":

View File

@@ -14,9 +14,6 @@ import
idents, lexer, syntaxes, modulegraphs,
lineinfos, pathutils
import ../dist/checksums/src/checksums/sha1
import std/strtabs
proc resetSystemArtifacts*(g: ModuleGraph) =
magicsys.resetSysTypes(g)
@@ -45,8 +42,6 @@ proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PNode =
result = syntaxes.parseFile(fileIdx, graph.cache, graph.config)
graph.addDep(s, fileIdx)
graph.addIncludeDep(s.position.FileIndex, fileIdx)
let path = toFullPath(graph.config, fileIdx)
graph.cachedFiles[path] = $secureHashFile(path)
proc wantMainModule*(conf: ConfigRef) =
if conf.projectFull.isEmpty:

View File

@@ -60,13 +60,31 @@ proc makeCString*(s: string): Rope =
toCChar(s[i], result)
result.add('\"')
proc makeCCharArray*(s: string): Rope =
result = newStringOfCap(int(s.len.toFloat * 1.1) + 1)
result.add("{")
for i in 0..<s.len:
# 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:
# res.add("\"\L\"")
if i != 0:
result.add ", "
result.add '\''
toCChar(s[i], result)
result.add '\''
result.add('}')
proc newFileInfo(fullPath: AbsoluteFile, projPath: RelativeFile): TFileInfo =
result = TFileInfo(fullPath: fullPath, projPath: projPath,
shortName: fullPath.extractFilename,
quotedFullName: fullPath.string.makeCString,
lines: @[]
)
result.fullPath = fullPath
#shallow(result.fullPath)
result.projPath = projPath
#shallow(result.projPath)
result.shortName = fullPath.extractFilename
result.quotedName = result.shortName.makeCString
result.quotedFullName = fullPath.string.makeCString
result.lines = @[]
when defined(nimpretty):
if not result.fullPath.isEmpty:
try:
@@ -123,18 +141,18 @@ proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile; isKnownFile: var bool
conf.m.filenameToIndexTbl[canon2] = result
proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile): FileIndex =
var dummy: bool = false
var dummy: bool
result = fileInfoIdx(conf, filename, dummy)
proc fileInfoIdx*(conf: ConfigRef; filename: RelativeFile; isKnownFile: var bool): FileIndex =
fileInfoIdx(conf, AbsoluteFile expandFilename(filename.string), isKnownFile)
proc fileInfoIdx*(conf: ConfigRef; filename: RelativeFile): FileIndex =
var dummy: bool = false
var dummy: bool
fileInfoIdx(conf, AbsoluteFile expandFilename(filename.string), dummy)
proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo =
result = TLineInfo(fileIndex: fileInfoIdx)
result.fileIndex = fileInfoIdx
if line < int high(uint16):
result.line = uint16(line)
else:
@@ -429,8 +447,7 @@ To create a stacktrace, rerun compilation with './koch temp $1 <file>', see $2 f
proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string, ignoreMsg: bool) =
if msg in fatalMsgs:
if conf.cmd == cmdIdeTools: log(s)
if conf.cmd != cmdIdeTools or msg != errFatal:
quit(conf, msg)
quit(conf, msg)
if msg >= errMin and msg <= errMax or
(msg in warnMin..hintMax and msg in conf.warningAsErrors and not ignoreMsg):
inc(conf.errorCounter)
@@ -438,11 +455,7 @@ proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string,
if conf.errorCounter >= conf.errorMax:
# only really quit when we're not in the new 'nim check --def' mode:
if conf.ideCmd == ideNone:
when defined(nimsuggest):
#we need to inform the user that something went wrong when initializing NimSuggest
raiseRecoverableError(s)
else:
quit(conf, msg)
quit(conf, msg)
elif eh == doAbort and conf.cmd != cmdIdeTools:
quit(conf, msg)
elif eh == doRaise:
@@ -560,10 +573,9 @@ proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
ignoreMsg = not conf.hasHint(msg)
if not ignoreMsg and msg in conf.warningAsErrors:
title = ErrorTitle
color = ErrorColor
else:
title = HintTitle
color = HintColor
color = HintColor
inc(conf.hintCounter)
let s = if isRaw: arg else: getMessageStr(msg, arg)
@@ -651,16 +663,13 @@ template lintReport*(conf: ConfigRef; info: TLineInfo, beau, got: string, extraM
let msg = if optStyleError in conf.globalOptions: errGenerated else: hintName
liMessage(conf, info, msg, m, doNothing, instLoc())
proc quotedFilename*(conf: ConfigRef; fi: FileIndex): Rope =
if fi.int32 < 0:
proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope =
if i.fileIndex.int32 < 0:
result = makeCString "???"
elif optExcessiveStackTrace in conf.globalOptions:
result = conf.m.fileInfos[fi.int32].quotedFullName
result = conf.m.fileInfos[i.fileIndex.int32].quotedFullName
else:
result = conf.m.fileInfos[fi.int32].quotedName
proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope =
quotedFilename(conf, i.fileIndex)
result = conf.m.fileInfos[i.fileIndex.int32].quotedName
template listMsg(title, r) =
msgWriteln(conf, title, {msgNoUnitSep})

View File

@@ -498,7 +498,7 @@ proc checkCall(n, ctx, map): Check =
# check args and handle possible mutations
var isNew = false
result = Check(map: map)
result.map = map
for i, child in n:
discard check(child, ctx, map)
@@ -507,7 +507,7 @@ proc checkCall(n, ctx, map): Check =
# as it might have been mutated
# TODO similar for normal refs and fields: find dependent exprs: brackets
if child.kind == nkHiddenAddr and not child.typ.isNil and child.typ.kind == tyVar and child.typ.elementType.kind == tyRef:
if child.kind == nkHiddenAddr and not child.typ.isNil and child.typ.kind == tyVar and child.typ[0].kind == tyRef:
if not isNew:
result.map = newNilMap(map)
isNew = true
@@ -753,7 +753,6 @@ proc checkReturn(n, ctx, map): Check =
proc checkIf(n, ctx, map): Check =
## check branches based on condition
result = default(Check)
var mapIf: NilMap = map
# first visit the condition
@@ -826,7 +825,7 @@ proc checkFor(n, ctx, map): Check =
var check2 = check(n.sons[2], ctx, m)
var map2 = check2.map
result = Check(map: ctx.union(map0, m))
result.map = ctx.union(map0, m)
result.map = ctx.union(result.map, map2)
result.nilability = Safe
@@ -854,7 +853,7 @@ proc checkWhile(n, ctx, map): Check =
var check2 = check(n.sons[1], ctx, m)
var map2 = check2.map
result = Check(map: ctx.union(map0, map1))
result.map = ctx.union(map0, map1)
result.map = ctx.union(result.map, map2)
result.nilability = Safe
@@ -900,7 +899,7 @@ proc checkInfix(n, ctx, map): Check =
proc checkIsNil(n, ctx, map; isElse: bool = false): Check =
## check isNil calls
## update the map depending on if it is not isNil or isNil
result = Check(map: newNilMap(map))
result.map = newNilMap(map)
let value = n[1]
result.map.store(ctx, ctx.index(n[1]), if not isElse: Nil else: Safe, TArg, n.info, n)
@@ -948,7 +947,7 @@ proc checkCase(n, ctx, map): Check =
# c2
# also a == true is a , a == false is not a
let base = n[0]
result = Check(map: map.copyMap())
result.map = map.copyMap()
result.nilability = Safe
var a: PNode = nil
for child in n:
@@ -1220,7 +1219,7 @@ proc check(n: PNode, ctx: NilCheckerContext, map: NilMap): Check =
result = check(n.sons[1], ctx, map)
of nkStmtList, nkStmtListExpr, nkChckRangeF, nkChckRange64, nkChckRange,
nkBracket, nkCurly, nkPar, nkTupleConstr, nkClosure, nkObjConstr, nkElse:
result = Check(map: map)
result.map = map
if n.kind in {nkObjConstr, nkTupleConstr}:
# TODO deeper nested elements?
# A(field: B()) #
@@ -1247,10 +1246,10 @@ proc check(n: PNode, ctx: NilCheckerContext, map: NilMap): Check =
result = checkIf(n, ctx, map)
of nkAsgn, nkFastAsgn, nkSinkAsgn:
result = checkAsgn(n[0], n[1], ctx, map)
of nkVarSection, nkLetSection:
result = Check(map: map)
of nkVarSection:
result.map = map
for child in n:
result = checkAsgn(child[0].skipPragmaExpr, child[2], ctx, result.map)
result = checkAsgn(child[0], child[2], ctx, result.map)
of nkForStmt:
result = checkFor(n, ctx, map)
of nkCaseStmt:
@@ -1274,7 +1273,8 @@ proc check(n: PNode, ctx: NilCheckerContext, map: NilMap): Check =
else:
var elementMap = map.copyMap()
var elementCheck = Check(map: elementMap)
var elementCheck: Check
elementCheck.map = elementMap
for element in n:
elementCheck = check(element, ctx, elementCheck.map)
@@ -1367,7 +1367,7 @@ proc checkNil*(s: PSym; body: PNode; conf: ConfigRef, idgen: IdGenerator) =
continue
map.store(context, context.index(child), typeNilability(child.typ), TArg, child.info, child)
map.store(context, resultExprIndex, if not s.typ.returnType.isNil and s.typ.returnType.kind == tyRef: Nil else: Safe, TResult, s.ast.info)
map.store(context, resultExprIndex, if not s.typ[0].isNil and s.typ[0].kind == tyRef: Nil else: Safe, TResult, s.ast.info)
# echo "checking ", s.name.s, " ", filename
@@ -1383,5 +1383,5 @@ proc checkNil*(s: PSym; body: PNode; conf: ConfigRef, idgen: IdGenerator) =
# (ANotNil, BNotNil) :
# do we check on asgn nilability at all?
if not s.typ.returnType.isNil and s.typ.returnType.kind == tyRef and tfNotNil in s.typ.returnType.flags:
if not s.typ[0].isNil and s.typ[0].kind == tyRef and tfNotNil in s.typ[0].flags:
checkResult(s.ast, context, res.map)

View File

@@ -117,8 +117,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
if conf.selectedGC == gcUnselected:
if conf.backend in {backendC, backendCpp, backendObjc, backendNir} or
(conf.cmd == cmdInteractive and isDefined(conf, "nir")) or
(conf.cmd in cmdDocLike and conf.backend != backendJs):
(conf.cmd == cmdInteractive and isDefined(conf, "nir")):
initOrcDefines(conf)
mainCommand(graph)

View File

@@ -79,8 +79,6 @@ proc getPathVersionChecksum*(p: string): tuple[name, version, checksum: string]
## ``/home/user/.nimble/pkgs/package-0.1-febadeaea2345e777f0f6f8433f7f0a52edd5d1b`` into
## ``("/home/user/.nimble/pkgs/package", "0.1", "febadeaea2345e777f0f6f8433f7f0a52edd5d1b")``
result = ("", "", "")
const checksumSeparator = '-'
const versionSeparator = '-'
const specialVersionSepartator = "-#"

View File

@@ -223,7 +223,7 @@ proc readConfigFile*(filename: AbsoluteFile; cache: IdentCache;
stream = llStreamOpen(filename, fmRead)
if stream != nil:
openLexer(L, filename, stream, cache, config)
tok = Token(tokType: tkEof) # to avoid a pointless warning
tok.tokType = tkEof # to avoid a pointless warning
var condStack: seq[bool] = @[]
confTok(L, tok, config, condStack) # read in the first token
while tok.tokType != tkEof: parseAssignment(L, tok, config, filename, condStack)

View File

@@ -11,8 +11,8 @@
import
ast, modules, condsyms,
options, llstream, lineinfos, vm,
vmdef, modulegraphs, idents, pathutils,
scriptconfig, std/[compilesettings, tables, os]
vmdef, modulegraphs, idents, os, pathutils,
scriptconfig, std/[compilesettings, tables]
import pipelines
@@ -40,7 +40,7 @@ proc selectUniqueSymbol*(i: Interpreter; name: string;
assert i != nil
assert i.mainModule != nil, "no main module selected"
let n = getIdent(i.graph.cache, name)
var it: ModuleIter = default(ModuleIter)
var it: ModuleIter
var s = initModuleIter(it, i.graph, i.mainModule, n)
result = nil
while s != nil:

View File

@@ -65,7 +65,7 @@ proc toBitSet*(conf: ConfigRef; s: PNode): TBitSet =
result = @[]
var first: Int128 = Zero
var j: Int128 = Zero
first = firstOrd(conf, s.typ.elementType)
first = firstOrd(conf, s.typ[0])
bitSetInit(result, int(getSize(conf, s.typ)))
for i in 0..<s.len:
if s[i].kind == nkRange:

View File

@@ -586,7 +586,7 @@ proc genIndex(c: var ProcCon; n: PNode; arr: PType; d: var Value) =
proc rawGenNew(c: var ProcCon; d: Value; refType: PType; ninfo: TLineInfo; needsInit: bool) =
assert refType.kind == tyRef
let baseType = refType.elementType
let baseType = refType.lastSon
let info = toLineInfo(c, ninfo)
let codegenProc = magicsys.getCompilerProc(c.m.graph,
@@ -611,7 +611,7 @@ proc genNew(c: var ProcCon; n: PNode; needsInit: bool) =
proc genNewSeqOfCap(c: var ProcCon; n: PNode; d: var Value) =
let info = toLineInfo(c, n.info)
let seqtype = skipTypes(n.typ, abstractVarRange)
let baseType = seqtype.elementType
let baseType = seqtype.lastSon
var a = c.genx(n[1])
if isEmpty(d): d = getTemp(c, n)
# $1.len = 0
@@ -639,7 +639,7 @@ proc genNewSeqOfCap(c: var ProcCon; n: PNode; d: var Value) =
freeTemp c, a
proc genNewSeqPayload(c: var ProcCon; info: PackedLineInfo; d, b: Value; seqtype: PType) =
let baseType = seqtype.elementType
let baseType = seqtype.lastSon
# $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3))
let payloadPtr = seqPayloadPtrType(c.m.types, c.m.nirm.types, seqtype)[0]
@@ -1597,7 +1597,7 @@ proc genDestroySeq(c: var ProcCon; n: PNode; t: PType) =
let strLitFlag = 1 shl (c.m.graph.config.target.intSize * 8 - 2) # see also NIM_STRLIT_FLAG
let x = c.genx(n[1])
let baseType = t.elementType
let baseType = t.lastSon
let seqType = typeToIr(c.m, t)
let p = fieldAt(x, 0, seqType)
@@ -1655,7 +1655,7 @@ proc genIndexCheck(c: var ProcCon; n: PNode; a: Value; kind: IndexFor; arr: PTyp
proc addSliceFields(c: var ProcCon; target: var Tree; info: PackedLineInfo;
x: Value; n: PNode; arrType: PType) =
let elemType = arrayPtrTypeOf(c.m.nirm.types, typeToIr(c.m, arrType.elementType))
let elemType = arrayPtrTypeOf(c.m.nirm.types, typeToIr(c.m, arrType.lastSon))
case arrType.kind
of tyString, tySequence:
let checkKind = if arrType.kind == tyString: ForStr else: ForSeq
@@ -1819,8 +1819,15 @@ proc genMagic(c: var ProcCon; n: PNode; d: var Value; m: TMagic) =
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and size < 8):
c.gABC(n, opcNarrowU, d, TRegister(size*8))
of mStrToStr, mEnsureMove: c.gen n[1], d
of mIntToStr: genUnaryCp(c, n, d, "nimIntToStr")
of mInt64ToStr: genUnaryCp(c, n, d, "nimInt64ToStr")
of mBoolToStr: genUnaryCp(c, n, d, "nimBoolToStr")
of mCharToStr: genUnaryCp(c, n, d, "nimCharToStr")
of mFloatToStr:
if n[1].typ.skipTypes(abstractInst).kind == tyFloat32:
genUnaryCp(c, n, d, "nimFloat32ToStr")
else:
genUnaryCp(c, n, d, "nimFloatToStr")
of mCStrToStr: genUnaryCp(c, n, d, "cstrToNimstr")
of mEnumToStr: genEnumToStr(c, n, d)
@@ -1896,7 +1903,7 @@ proc genMagic(c: var ProcCon; n: PNode; d: var Value; m: TMagic) =
of mDefault, mZeroDefault:
genDefault c, n, d
of mMove: genMove(c, n, d)
of mWasMoved:
of mWasMoved, mReset:
unused(c, n, d)
genWasMoved(c, n)
of mDestroy: genDestroy(c, n)
@@ -1963,7 +1970,7 @@ proc genDeref(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) =
proc addAddrOfFirstElem(c: var ProcCon; target: var Tree; info: PackedLineInfo; tmp: Value; typ: PType) =
let arrType = typ.skipTypes(abstractVar)
let elemType = arrayPtrTypeOf(c.m.nirm.types, typeToIr(c.m, arrType.elementType))
let elemType = arrayPtrTypeOf(c.m.nirm.types, typeToIr(c.m, arrType.lastSon))
case arrType.kind
of tyString:
let t = typeToIr(c.m, typ)
@@ -2072,7 +2079,7 @@ proc genRefObjConstr(c: var ProcCon; n: PNode; d: var Value) =
if isEmpty(d): d = getTemp(c, n)
let info = toLineInfo(c, n.info)
let refType = n.typ.skipTypes(abstractInstOwned)
let objType = refType.elementType
let objType = refType.lastSon
rawGenNew(c, d, refType, n.info, needsInit = nfAllFieldsSet notin n.flags)
var deref = default(Value)
@@ -2085,7 +2092,7 @@ proc genSeqConstr(c: var ProcCon; n: PNode; d: var Value) =
let info = toLineInfo(c, n.info)
let seqtype = skipTypes(n.typ, abstractVarRange)
let baseType = seqtype.elementType
let baseType = seqtype.lastSon
var b = default(Value)
b.addIntVal c.lit.numbers, info, c.m.nativeIntId, n.len
@@ -2390,9 +2397,9 @@ proc genParams(c: var ProcCon; params: PNode; prc: PSym): PSym =
result = resNode.sym # get result symbol
c.code.addSummon toLineInfo(c, result.info), toSymId(c, result),
typeToIr(c.m, result.typ), SummonResult
elif prc.typ.len > 0 and not isEmptyType(prc.typ.returnType) and not isCompileTimeOnly(prc.typ.returnType):
elif prc.typ.len > 0 and not isEmptyType(prc.typ[0]) and not isCompileTimeOnly(prc.typ[0]):
# happens for procs without bodies:
let t = typeToIr(c.m, prc.typ.returnType)
let t = typeToIr(c.m, prc.typ[0])
let tmp = allocTemp(c, t)
c.code.addSummon toLineInfo(c, params.info), tmp, t, SummonResult
@@ -2416,7 +2423,7 @@ proc addCallConv(c: var ProcCon; info: PackedLineInfo; callConv: TCallingConvent
of ccInline: ann InlineCall
of ccNoInline: ann NoinlineCall
of ccThisCall: ann ThisCall
of ccNoConvention, ccMember: ann NoCall
of ccNoConvention: ann NoCall
proc genProc(cOuter: var ProcCon; prc: PSym) =
if prc.magic notin generatedMagics: return

View File

@@ -84,9 +84,9 @@ proc objectToIr(c: var TypesCon; g: var TypeGraph; n: PNode; fieldTypes: Table[I
assert false, "unknown node kind: " & $n.kind
proc objectToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
if t.baseClass != nil:
if t[0] != nil:
# ensure we emitted the base type:
discard typeToIr(c, g, t.baseClass)
discard typeToIr(c, g, t[0])
var unionId = 0
var fieldTypes = initTable[ItemId, TypeId]()
@@ -96,8 +96,8 @@ proc objectToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
g.addSize c.conf.getSize(t)
g.addAlign c.conf.getAlign(t)
if t.baseClass != nil:
g.addNominalType(ObjectTy, mangle(c, t.baseClass))
if t[0] != nil:
g.addNominalType(ObjectTy, mangle(c, t[0]))
else:
g.addBuiltinType VoidId # object does not inherit
if not lacksMTypeField(t):
@@ -150,7 +150,7 @@ proc procToIr(c: var TypesCon; g: var TypeGraph; t: PType; addEnv = false): Type
of ccInline: g.addAnnotation "__inline"
of ccNoInline: g.addAnnotation "__noinline"
of ccThisCall: g.addAnnotation "__thiscall"
of ccNoConvention, ccMember: g.addAnnotation ""
of ccNoConvention: g.addAnnotation ""
for i in 0..<fieldTypes.len:
g.addType fieldTypes[i]
@@ -171,7 +171,7 @@ proc nativeInt(c: TypesCon): TypeId =
else: result = Int64Id
proc openArrayPayloadType*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
let e = elementType(t)
let e = lastSon(t)
let elementType = typeToIr(c, g, e)
let arr = g.openType AArrayPtrTy
g.addType elementType
@@ -179,7 +179,7 @@ proc openArrayPayloadType*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId
proc openArrayToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
# object (a: ArrayPtr[T], len: int)
let e = elementType(t)
let e = lastSon(t)
let mangledBase = mangle(c, e)
let typeName = "NimOpenArray" & mangledBase
@@ -265,7 +265,7 @@ proc seqPayloadType(c: var TypesCon; g: var TypeGraph; t: PType): (string, TypeI
cap: int
data: UncheckedArray[T]
]#
let e = elementType(t)
let e = lastSon(t)
result = (mangle(c, e), TypeId(-1))
let payloadName = "NimSeqPayload" & result[0]
@@ -397,7 +397,7 @@ proc typeToIr*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
of tyChar: result = Char8Id
of tyVoid: result = VoidId
of tySink, tyGenericInst, tyDistinct, tyAlias, tyOwned, tyRange:
result = typeToIr(c, g, t.skipModifier)
result = typeToIr(c, g, t.lastSon)
of tyEnum:
if firstOrd(c.conf, t) < 0:
result = Int32Id
@@ -410,7 +410,7 @@ proc typeToIr*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
else: result = Int32Id
of tyOrdinal, tyGenericBody, tyGenericParam, tyInferred, tyStatic:
if t.len > 0:
result = typeToIr(c, g, t.skipModifier)
result = typeToIr(c, g, t.lastSon)
else:
result = TypeId(-1)
of tyFromExpr:
@@ -422,7 +422,7 @@ proc typeToIr*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
cached(c, t):
var n = toInt64(lengthOrd(c.conf, t))
if n <= 0: n = 1 # make an array of at least one element
let elemType = typeToIr(c, g, t.elementType)
let elemType = typeToIr(c, g, t[1])
let a = openType(g, ArrayTy)
g.addType(elemType)
g.addArrayLen n
@@ -430,20 +430,20 @@ proc typeToIr*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
result = finishType(g, a)
of tyPtr, tyRef:
cached(c, t):
let e = t.elementType
let e = t.lastSon
if e.kind == tyUncheckedArray:
let elemType = typeToIr(c, g, e.elementType)
let elemType = typeToIr(c, g, e.lastSon)
let a = openType(g, AArrayPtrTy)
g.addType(elemType)
result = finishType(g, a)
else:
let elemType = typeToIr(c, g, t.elementType)
let elemType = typeToIr(c, g, t.lastSon)
let a = openType(g, APtrTy)
g.addType(elemType)
result = finishType(g, a)
of tyVar, tyLent:
cached(c, t):
let e = t.elementType
let e = t.lastSon
if e.skipTypes(abstractInst).kind in {tyOpenArray, tyVarargs}:
# skip the modifier, `var openArray` is a (ptr, len) pair too:
result = typeToIr(c, g, e)
@@ -510,7 +510,7 @@ proc typeToIr*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
of tyUncheckedArray:
# We already handled the `ptr UncheckedArray` in a special way.
cached(c, t):
let elemType = typeToIr(c, g, t.elementType)
let elemType = typeToIr(c, g, t.lastSon)
let a = openType(g, LastArrayTy)
g.addType(elemType)
result = finishType(g, a)

View File

@@ -1,210 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2015 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## NodeKind enum.
type
TNodeKind* = enum # order is extremely important, because ranges are used
# to check whether a node belongs to a certain class
nkNone, # unknown node kind: indicates an error
# Expressions:
# Atoms:
nkEmpty, # the node is empty
nkIdent, # node is an identifier
nkSym, # node is a symbol
nkType, # node is used for its typ field
nkCharLit, # a character literal ''
nkIntLit, # an integer literal
nkInt8Lit,
nkInt16Lit,
nkInt32Lit,
nkInt64Lit,
nkUIntLit, # an unsigned integer literal
nkUInt8Lit,
nkUInt16Lit,
nkUInt32Lit,
nkUInt64Lit,
nkFloatLit, # a floating point literal
nkFloat32Lit,
nkFloat64Lit,
nkFloat128Lit,
nkStrLit, # a string literal ""
nkRStrLit, # a raw string literal r""
nkTripleStrLit, # a triple string literal """
nkNilLit, # the nil literal
# end of atoms
nkComesFrom, # "comes from" template/macro information for
# better stack trace generation
nkDotCall, # used to temporarily flag a nkCall node;
# this is used
# for transforming ``s.len`` to ``len(s)``
nkCommand, # a call like ``p 2, 4`` without parenthesis
nkCall, # a call like p(x, y) or an operation like +(a, b)
nkCallStrLit, # a call with a string literal
# x"abc" has two sons: nkIdent, nkRStrLit
# x"""abc""" has two sons: nkIdent, nkTripleStrLit
nkInfix, # a call like (a + b)
nkPrefix, # a call like !a
nkPostfix, # something like a! (also used for visibility)
nkHiddenCallConv, # an implicit type conversion via a type converter
nkExprEqExpr, # a named parameter with equals: ''expr = expr''
nkExprColonExpr, # a named parameter with colon: ''expr: expr''
nkIdentDefs, # a definition like `a, b: typeDesc = expr`
# either typeDesc or expr may be nil; used in
# formal parameters, var statements, etc.
nkVarTuple, # a ``var (a, b) = expr`` construct
nkPar, # syntactic (); may be a tuple constructor
nkObjConstr, # object constructor: T(a: 1, b: 2)
nkCurly, # syntactic {}
nkCurlyExpr, # an expression like a{i}
nkBracket, # syntactic []
nkBracketExpr, # an expression like a[i..j, k]
nkPragmaExpr, # an expression like a{.pragmas.}
nkRange, # an expression like i..j
nkDotExpr, # a.b
nkCheckedFieldExpr, # a.b, but b is a field that needs to be checked
nkDerefExpr, # a^
nkIfExpr, # if as an expression
nkElifExpr,
nkElseExpr,
nkLambda, # lambda expression
nkDo, # lambda block appering as trailing proc param
nkAccQuoted, # `a` as a node
nkTableConstr, # a table constructor {expr: expr}
nkBind, # ``bind expr`` node
nkClosedSymChoice, # symbol choice node; a list of nkSyms (closed)
nkOpenSymChoice, # symbol choice node; a list of nkSyms (open)
nkHiddenStdConv, # an implicit standard type conversion
nkHiddenSubConv, # an implicit type conversion from a subtype
# to a supertype
nkConv, # a type conversion
nkCast, # a type cast
nkStaticExpr, # a static expr
nkAddr, # a addr expression
nkHiddenAddr, # implicit address operator
nkHiddenDeref, # implicit ^ operator
nkObjDownConv, # down conversion between object types
nkObjUpConv, # up conversion between object types
nkChckRangeF, # range check for floats
nkChckRange64, # range check for 64 bit ints
nkChckRange, # range check for ints
nkStringToCString, # string to cstring
nkCStringToString, # cstring to string
# end of expressions
nkAsgn, # a = b
nkFastAsgn, # internal node for a fast ``a = b``
# (no string copy)
nkGenericParams, # generic parameters
nkFormalParams, # formal parameters
nkOfInherit, # inherited from symbol
nkImportAs, # a 'as' b in an import statement
nkProcDef, # a proc
nkMethodDef, # a method
nkConverterDef, # a converter
nkMacroDef, # a macro
nkTemplateDef, # a template
nkIteratorDef, # an iterator
nkOfBranch, # used inside case statements
# for (cond, action)-pairs
nkElifBranch, # used in if statements
nkExceptBranch, # an except section
nkElse, # an else part
nkAsmStmt, # an assembler block
nkPragma, # a pragma statement
nkPragmaBlock, # a pragma with a block
nkIfStmt, # an if statement
nkWhenStmt, # a when expression or statement
nkForStmt, # a for statement
nkParForStmt, # a parallel for statement
nkWhileStmt, # a while statement
nkCaseStmt, # a case statement
nkTypeSection, # a type section (consists of type definitions)
nkVarSection, # a var section
nkLetSection, # a let section
nkConstSection, # a const section
nkConstDef, # a const definition
nkTypeDef, # a type definition
nkYieldStmt, # the yield statement as a tree
nkDefer, # the 'defer' statement
nkTryStmt, # a try statement
nkFinally, # a finally section
nkRaiseStmt, # a raise statement
nkReturnStmt, # a return statement
nkBreakStmt, # a break statement
nkContinueStmt, # a continue statement
nkBlockStmt, # a block statement
nkStaticStmt, # a static statement
nkDiscardStmt, # a discard statement
nkStmtList, # a list of statements
nkImportStmt, # an import statement
nkImportExceptStmt, # an import x except a statement
nkExportStmt, # an export statement
nkExportExceptStmt, # an 'export except' statement
nkFromStmt, # a from * import statement
nkIncludeStmt, # an include statement
nkBindStmt, # a bind statement
nkMixinStmt, # a mixin statement
nkUsingStmt, # an using statement
nkCommentStmt, # a comment statement
nkStmtListExpr, # a statement list followed by an expr; this is used
# to allow powerful multi-line templates
nkBlockExpr, # a statement block ending in an expr; this is used
# to allow powerful multi-line templates that open a
# temporary scope
nkStmtListType, # a statement list ending in a type; for macros
nkBlockType, # a statement block ending in a type; for macros
# types as syntactic trees:
nkWith, # distinct with `foo`
nkWithout, # distinct without `foo`
nkTypeOfExpr, # type(1+2)
nkObjectTy, # object body
nkTupleTy, # tuple body
nkTupleClassTy, # tuple type class
nkTypeClassTy, # user-defined type class
nkStaticTy, # ``static[T]``
nkRecList, # list of object parts
nkRecCase, # case section of object
nkRecWhen, # when section of object
nkRefTy, # ``ref T``
nkPtrTy, # ``ptr T``
nkVarTy, # ``var T``
nkConstTy, # ``const T``
nkOutTy, # ``out T``
nkDistinctTy, # distinct type
nkProcTy, # proc type
nkIteratorTy, # iterator type
nkSinkAsgn, # '=sink(x, y)'
nkEnumTy, # enum body
nkEnumFieldDef, # `ident = expr` in an enumeration
nkArgList, # argument list
nkPattern, # a special pattern; used for matching
nkHiddenTryStmt, # a hidden try statement
nkClosure, # (prc, env)-pair (internally used for code gen)
nkGotoState, # used for the state machine (for iterators)
nkState, # give a label to a code section (for iterators)
nkBreakState, # special break statement for easier code generation
nkFuncDef, # a func
nkTupleConstr # a tuple constructor
nkError # erroneous AST node
nkModuleRef # for .rod file support: A (moduleId, itemId) pair
nkReplayAction # for .rod file support: A replay action
nkNilRodNode # for .rod file support: a 'nil' PNode
const
nkCallKinds* = {nkCall, nkInfix, nkPrefix, nkPostfix,
nkCommand, nkCallStrLit, nkHiddenCallConv}

View File

@@ -280,7 +280,7 @@ proc optimize*(n: PNode): PNode =
Now assume 'use' raises, then we shouldn't do the 'wasMoved(s)'
]#
var c: Con = Con()
var b: BasicBlock = default(BasicBlock)
var b: BasicBlock
analyse(c, b, n)
if c.somethingTodo:
result = shallowCopy(n)

View File

@@ -25,7 +25,7 @@ const
useEffectSystem* = true
useWriteTracking* = false
hasFFI* = defined(nimHasLibFFI)
copyrightYear* = "2024"
copyrightYear* = "2023"
nimEnableCovariance* = defined(nimEnableCovariance)
@@ -86,7 +86,6 @@ type # please make sure we have under 32 options
# also: generate header file
optIdeDebug # idetools: debug mode
optIdeTerse # idetools: use terse descriptions
optIdeExceptionInlayHints
optExcessiveStackTrace # fully qualified module filenames
optShowAllMismatches # show all overloading resolution candidates
optWholeProject # for 'doc': output any dependency
@@ -228,7 +227,6 @@ type
strictDefs,
strictCaseObjects,
inferGenericTypes,
genericsOpenSym,
vtables
LegacyFeature* = enum
@@ -246,8 +244,6 @@ type
emitGenerics
## generics are emitted in the module that contains them.
## Useful for libraries that rely on local passC
jsNoLambdaLifting
## Old transformation for closures in JS backend
SymbolFilesOption* = enum
disabledSf, writeOnlySf, readOnlySf, v2Sf, stressTest
@@ -301,7 +297,6 @@ type
SuggestInlayHintKind* = enum
sihkType = "Type",
sihkParameter = "Parameter"
sihkException = "Exception"
SuggestInlayHint* = ref object
kind*: SuggestInlayHintKind

View File

@@ -49,14 +49,9 @@ when isMainModule or defined(nimTestGrammar):
checkGrammarFile()
import
llstream, lexer, idents, msgs, options, lineinfos,
llstream, lexer, idents, ast, msgs, options, lineinfos,
pathutils
when not defined(nimCustomAst):
import ast
else:
import plugins / customast
import std/strutils
when defined(nimpretty):
@@ -78,8 +73,7 @@ type
bufposPrevious*: int
inPragma*: int # Pragma level
inSemiStmtList*: int
when not defined(nimCustomAst):
emptyNode: PNode
emptyNode: PNode
when defined(nimpretty):
em*: Emitter
@@ -89,10 +83,6 @@ type
PrimaryMode = enum
pmNormal, pmTypeDesc, pmTypeDef, pmTrySimple
when defined(nimCustomAst):
# For the `customast` version we cannot share nodes, not even empty nodes:
template emptyNode(p: Parser): PNode = newNode(nkEmpty)
# helpers for the other parsers
proc isOperator*(tok: Token): bool
proc getTok*(p: var Parser)
@@ -101,7 +91,7 @@ proc skipComment*(p: var Parser, node: PNode)
proc newNodeP*(kind: TNodeKind, p: Parser): PNode
proc newIntNodeP*(kind: TNodeKind, intVal: BiggestInt, p: Parser): PNode
proc newFloatNodeP*(kind: TNodeKind, floatVal: BiggestFloat, p: Parser): PNode
proc newStrNodeP*(kind: TNodeKind, strVal: sink string, p: Parser): PNode
proc newStrNodeP*(kind: TNodeKind, strVal: string, p: Parser): PNode
proc newIdentNodeP*(ident: PIdent, p: Parser): PNode
proc expectIdentOrKeyw*(p: Parser)
proc expectIdent*(p: Parser)
@@ -156,8 +146,7 @@ proc openParser*(p: var Parser, fileIdx: FileIndex, inputStream: PLLStream,
openEmitter(p.em, cache, config, fileIdx)
getTok(p) # read the first token
p.firstTok = true
when not defined(nimCustomAst):
p.emptyNode = newNode(nkEmpty)
p.emptyNode = newNode(nkEmpty)
proc openParser*(p: var Parser, filename: AbsoluteFile, inputStream: PLLStream,
cache: IdentCache; config: ConfigRef) =
@@ -166,6 +155,8 @@ proc openParser*(p: var Parser, filename: AbsoluteFile, inputStream: PLLStream,
proc closeParser*(p: var Parser) =
## Close a parser, freeing up its resources.
closeLexer(p.lex)
when defined(nimpretty):
closeEmitter(p.em)
proc parMessage(p: Parser, msg: TMsgKind, arg = "") =
## Produce and emit the parser message `arg` to output.
@@ -272,20 +263,24 @@ proc indAndComment(p: var Parser, n: PNode, maybeMissEquals = false) =
skipComment(p, n)
proc newNodeP(kind: TNodeKind, p: Parser): PNode =
result = newNode(kind, parLineInfo(p))
result = newNodeI(kind, parLineInfo(p))
proc newIntNodeP(kind: TNodeKind, intVal: BiggestInt, p: Parser): PNode =
result = newAtom(kind, intVal, parLineInfo(p))
result = newNodeP(kind, p)
result.intVal = intVal
proc newFloatNodeP(kind: TNodeKind, floatVal: BiggestFloat,
p: Parser): PNode =
result = newAtom(kind, floatVal, parLineInfo(p))
result = newNodeP(kind, p)
result.floatVal = floatVal
proc newStrNodeP(kind: TNodeKind, strVal: sink string, p: Parser): PNode =
result = newAtom(kind, strVal, parLineInfo(p))
proc newStrNodeP(kind: TNodeKind, strVal: string, p: Parser): PNode =
result = newNodeP(kind, p)
result.strVal = strVal
proc newIdentNodeP(ident: PIdent, p: Parser): PNode =
result = newAtom(ident, parLineInfo(p))
result = newNodeP(nkIdent, p)
result.ident = ident
proc parseExpr(p: var Parser): PNode
proc parseStmt(p: var Parser): PNode
@@ -388,7 +383,7 @@ proc parseSymbol(p: var Parser, mode = smNormal): PNode =
while true:
case p.tok.tokType
of tkAccent:
if not result.hasSon:
if result.len == 0:
parMessage(p, errIdentifierExpected, p.tok)
break
of tkOpr, tkDot, tkDotDot, tkEquals, tkParLe..tkParDotRi:
@@ -398,7 +393,8 @@ proc parseSymbol(p: var Parser, mode = smNormal): PNode =
tkParLe..tkParDotRi}:
accm.add($p.tok)
getTok(p)
let node = newAtom(p.lex.cache.getIdent(accm), lineinfo)
let node = newNodeI(nkIdent, lineinfo)
node.ident = p.lex.cache.getIdent(accm)
result.add(node)
of tokKeywordLow..tokKeywordHigh, tkSymbol, tkIntLit..tkCustomLit:
result.add(newIdentNodeP(p.lex.cache.getIdent($p.tok), p))
@@ -515,26 +511,26 @@ proc exprColonEqExprList(p: var Parser, kind: TNodeKind,
proc dotExpr(p: var Parser, a: PNode): PNode =
var info = p.parLineInfo
getTok(p)
result = newNode(nkDotExpr, info)
result = newNodeI(nkDotExpr, info)
optInd(p, result)
result.add(a)
result.add(parseSymbol(p, smAfterDot))
if p.tok.tokType == tkBracketLeColon and tsLeading notin p.tok.spacing:
var x = newNode(nkBracketExpr, p.parLineInfo)
var x = newNodeI(nkBracketExpr, p.parLineInfo)
# rewrite 'x.y[:z]()' to 'y[z](x)'
x.add result.secondSon
x.add result[1]
exprList(p, tkBracketRi, x)
eat(p, tkBracketRi)
var y = newNode(nkCall, p.parLineInfo)
var y = newNodeI(nkCall, p.parLineInfo)
y.add x
y.add result.firstSon
y.add result[0]
if p.tok.tokType == tkParLe and tsLeading notin p.tok.spacing:
exprColonEqExprListAux(p, tkParRi, y)
result = y
proc dotLikeExpr(p: var Parser, a: PNode): PNode =
var info = p.parLineInfo
result = newNode(nkInfix, info)
result = newNodeI(nkInfix, info)
optInd(p, result)
var opNode = newIdentNodeP(p.tok.ident, p)
getTok(p)
@@ -590,18 +586,12 @@ proc parseCast(p: var Parser): PNode =
eat(p, tkParRi)
setEndInfo()
template setNodeFlag(n: PNode; f: untyped) =
when defined(nimCustomAst):
discard
else:
incl n.flags, f
proc setBaseFlags(n: PNode, base: NumericalBase) =
case base
of base10: discard
of base2: setNodeFlag(n, nfBase2)
of base8: setNodeFlag(n, nfBase8)
of base16: setNodeFlag(n, nfBase16)
of base2: incl(n.flags, nfBase2)
of base8: incl(n.flags, nfBase8)
of base16: incl(n.flags, nfBase16)
proc parseGStrLit(p: var Parser, a: PNode): PNode =
case p.tok.tokType
@@ -897,7 +887,7 @@ proc primarySuffix(p: var Parser, r: PNode,
result = commandExpr(p, result, mode)
break
result = namedParams(p, result, nkCall, tkParRi)
if result.has2Sons and result.secondSon.kind == nkExprColonExpr:
if result.len > 1 and result[1].kind == nkExprColonExpr:
result.transitionSonsKind(nkObjConstr)
of tkDot:
# progress guaranteed
@@ -1168,7 +1158,7 @@ proc parseParamList(p: var Parser, retColon = true): PNode =
if hasRet and p.tok.indent < 0:
getTok(p)
optInd(p, result)
result.replaceFirstSon parseTypeDesc(p)
result[0] = parseTypeDesc(p)
elif not retColon and not hasParLe:
# Mark as "not there" in order to mark for deprecation in the semantic pass:
result = p.emptyNode
@@ -1213,9 +1203,9 @@ proc parseProcExpr(p: var Parser; isExpr: bool; kind: TNodeKind): PNode =
params = params, name = p.emptyNode, pattern = p.emptyNode,
genericParams = p.emptyNode, pragmas = pragmas, exceptions = p.emptyNode)
skipComment(p, result)
result.replaceSon bodyPos, parseStmt(p)
result[bodyPos] = parseStmt(p)
else:
result = newNode(if kind == nkIteratorDef: nkIteratorTy else: nkProcTy, info)
result = newNodeI(if kind == nkIteratorDef: nkIteratorTy else: nkProcTy, info)
if hasSignature or pragmas.kind != nkEmpty:
if hasSignature:
result.add(params)
@@ -1328,7 +1318,7 @@ proc parseExpr(p: var Parser): PNode =
result = parseFor(p)
of tkWhen:
nimprettyDontTouch:
result = parseIfOrWhenExpr(p, nkWhenStmt)
result = parseIfOrWhenExpr(p, nkWhenExpr)
of tkCase:
# Currently we think nimpretty is good enough with case expressions,
# so it is allowed to touch them:
@@ -1439,7 +1429,7 @@ proc parseTypeDesc(p: var Parser, fullExpr = false): PNode =
result = newNodeP(nkObjectTy, p)
getTok(p)
of tkConcept:
result = p.emptyNode
result = nil
parMessage(p, "the 'concept' keyword is only valid in 'type' sections")
of tkVar: result = parseTypeDescKAux(p, nkVarTy, pmTypeDesc)
of tkOut: result = parseTypeDescKAux(p, nkOutTy, pmTypeDesc)
@@ -1487,7 +1477,7 @@ proc makeCall(n: PNode): PNode =
if n.kind in nkCallKinds:
result = n
else:
result = newNode(nkCall, n.info)
result = newNodeI(nkCall, n.info)
result.add n
proc postExprBlocks(p: var Parser, x: PNode): PNode =
@@ -1518,9 +1508,9 @@ proc postExprBlocks(p: var Parser, x: PNode): PNode =
var stmtList = newNodeP(nkStmtList, p)
stmtList.add parseStmt(p)
# to keep backwards compatibility (see tests/vm/tstringnil)
if stmtList.firstSon.kind == nkStmtList: stmtList = stmtList.firstSon
if stmtList[0].kind == nkStmtList: stmtList = stmtList[0]
setNodeFlag stmtList, nfBlockArg
stmtList.flags.incl nfBlockArg
if openingParams.kind != nkEmpty or openingPragmas.kind != nkEmpty:
if openingParams.kind == nkEmpty:
openingParams = newNodeP(nkFormalParams, p)
@@ -1564,7 +1554,7 @@ proc postExprBlocks(p: var Parser, x: PNode): PNode =
eat(p, tkColon)
nextBlock.add parseStmt(p)
setNodeFlag nextBlock, nfBlockArg
nextBlock.flags.incl nfBlockArg
result.add nextBlock
if nextBlock.kind in {nkElse, nkFinally}: break
@@ -1590,7 +1580,7 @@ proc parseExprStmt(p: var Parser): PNode =
# if an expression is starting here, a simplePrimary was parsed and
# this is the start of a command
if p.tok.indent < 0 and isExprStart(p):
result = newTree(nkCommand, a.info, a)
result = newTreeI(nkCommand, a.info, a)
let baseIndent = p.currInd
while true:
result.add(commandParam(p, isFirstParam, pmNormal))
@@ -1981,13 +1971,13 @@ proc parseRoutine(p: var Parser, kind: TNodeKind): PNode =
else:
result.add(p.emptyNode)
indAndComment(p, result, maybeMissEquals)
let body = result.lastSon
if body.kind == nkStmtList and body.hasSon and body.firstSon.comment.len > 0 and body.firstSon.kind != nkCommentStmt:
let body = result[^1]
if body.kind == nkStmtList and body.len > 0 and body[0].comment.len > 0 and body[0].kind != nkCommentStmt:
if result.comment.len == 0:
# proc fn*(a: int): int = a ## foo
# => moves comment `foo` to `fn`
result.comment = body.firstSon.comment
body.firstSon.comment = ""
result.comment = body[0].comment
body[0].comment = ""
#else:
# assert false, p.lex.config$body.info # avoids hard to track bugs, fail early.
# Yeah, that worked so well. There IS a bug in this logic, now what?
@@ -2021,7 +2011,7 @@ proc parseSection(p: var Parser, kind: TNodeKind,
else:
parMessage(p, errIdentifierExpected, p.tok)
break
if not result.hasSon: parMessage(p, errIdentifierExpected, p.tok)
if result.len == 0: parMessage(p, errIdentifierExpected, p.tok)
elif p.tok.tokType in {tkSymbol, tkAccent, tkParLe} and p.tok.indent < 0:
# tkParLe is allowed for ``var (x, y) = ...`` tuple parsing
result.add(defparser(p))
@@ -2072,7 +2062,7 @@ proc parseEnum(p: var Parser): PNode =
if p.tok.indent >= 0 and p.tok.indent <= p.currInd or
p.tok.tokType == tkEof:
break
if not result.has2Sons:
if result.len <= 1:
parMessage(p, errIdentifierExpected, p.tok)
setEndInfo()
@@ -2201,8 +2191,7 @@ proc parseObject(p: var Parser): PNode =
proc parseTypeClassParam(p: var Parser): PNode =
let modifier =
case p.tok.tokType
of tkVar: nkVarTy
of tkOut: nkOutTy
of tkOut, tkVar: nkVarTy
of tkPtr: nkPtrTy
of tkRef: nkRefTy
of tkStatic: nkStaticTy
@@ -2218,7 +2207,7 @@ proc parseTypeClassParam(p: var Parser): PNode =
setEndInfo()
proc parseTypeClass(p: var Parser): PNode =
#| conceptParam = ('var' | 'out' | 'ptr' | 'ref' | 'static' | 'type')? symbol
#| conceptParam = ('var' | 'out')? symbol
#| conceptDecl = 'concept' conceptParam ^* ',' (pragma)? ('of' typeDesc ^* ',')?
#| &IND{>} stmt
result = newNodeP(nkTypeClassTy, p)
@@ -2332,7 +2321,7 @@ proc parseVariable(p: var Parser): PNode =
optInd(p, result)
result.add(parseExpr(p))
else: result = parseIdentColonEquals(p, {withPragma, withDot})
result.setLastSon postExprBlocks(p, result.lastSon)
result[^1] = postExprBlocks(p, result[^1])
indAndComment(p, result)
setEndInfo()
@@ -2351,8 +2340,8 @@ proc parseConstant(p: var Parser): PNode =
eat(p, tkEquals)
optInd(p, result)
#add(result, parseStmtListExpr(p))
let a = parseExpr(p)
result.add postExprBlocks(p, a)
result.add(parseExpr(p))
result[^1] = postExprBlocks(p, result[^1])
indAndComment(p, result)
setEndInfo()
@@ -2377,7 +2366,7 @@ proc parseStmtPragma(p: var Parser): PNode =
result = parsePragma(p)
if p.tok.tokType == tkColon and p.tok.indent < 0:
let a = result
result = newNode(nkPragmaBlock, a.info)
result = newNodeI(nkPragmaBlock, a.info)
getTok(p)
skipComment(p, result)
result.add a
@@ -2527,6 +2516,22 @@ proc parseStmt(p: var Parser): PNode =
if err and p.tok.tokType == tkEof: break
setEndInfo()
proc parseAll*(p: var Parser): PNode =
## Parses the rest of the input stream held by the parser into a PNode.
result = newNodeP(nkStmtList, p)
while p.tok.tokType != tkEof:
p.hasProgress = false
var a = complexOrSimpleStmt(p)
if a.kind != nkEmpty and p.hasProgress:
result.add(a)
else:
parMessage(p, errExprExpected, p.tok)
# bugfix: consume a token here to prevent an endless loop:
getTok(p)
if p.tok.indent != 0:
parMessage(p, errInvalidIndentation)
setEndInfo()
proc checkFirstLineIndentation*(p: var Parser) =
if p.tok.indent != 0 and tsLeading in p.tok.spacing:
parMessage(p, errInvalidIndentation)
@@ -2561,16 +2566,6 @@ proc parseTopLevelStmt*(p: var Parser): PNode =
break
setEndInfo()
proc parseAll*(p: var Parser): PNode =
## Parses the rest of the input stream held by the parser into a PNode.
result = newNodeP(nkStmtList, p)
while true:
let nextStmt = p.parseTopLevelStmt()
if nextStmt.kind == nkEmpty:
break
result &= nextStmt
setEndInfo()
proc parseString*(s: string; cache: IdentCache; config: ConfigRef;
filename: string = ""; line: int = 0;
errorHandler: ErrorHandler = nil): PNode =
@@ -2581,7 +2576,7 @@ proc parseString*(s: string; cache: IdentCache; config: ConfigRef;
var stream = llStreamOpen(s)
stream.lineOffset = line
var p = Parser()
var p: Parser
p.lex.errorHandler = errorHandler
openParser(p, AbsoluteFile filename, stream, cache, config)

View File

@@ -276,7 +276,10 @@ proc addToArgList(result, n: PNode) =
proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
## returns a tree to semcheck if the rule triggered; nil otherwise
var ctx = TPatternContext(owner: s, c: c, formals: s.typ.paramsLen)
var ctx: TPatternContext
ctx.owner = s
ctx.c = c
ctx.formals = s.typ.len-1
var m = matchStmtList(ctx, s.ast[patternPos], n)
if isNil(m): return nil
# each parameter should have been bound; we simply setup a call and

View File

@@ -5,12 +5,10 @@ import sem, cgen, modulegraphs, ast, llstream, parser, msgs,
import pipelineutils
import ../dist/checksums/src/checksums/sha1
when not defined(leanCompiler):
import jsgen, docgen2
import std/[syncio, objectdollar, assertions, tables, strutils, strtabs]
import std/[syncio, objectdollar, assertions, tables, strutils]
import renderer
import ic/replayer
import nir/nir
@@ -101,7 +99,7 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
stream: PLLStream): bool =
if graph.stopCompile(): return true
var
p: Parser = default(Parser)
p: Parser
s: PLLStream
fileIdx = module.fileIdx
@@ -198,7 +196,7 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
if graph.dispatchers.len > 0:
let ctx = preparePContext(graph, module, idgen)
for disp in getDispatchers(graph):
let retTyp = disp.typ.returnType
let retTyp = disp.typ[0]
if retTyp != nil:
# TODO: properly semcheck the code of dispatcher?
createTypeBoundOps(graph, ctx, retTyp, disp.ast.info, idgen)
@@ -246,10 +244,7 @@ proc compilePipelineModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymF
if result == nil:
var cachedModules: seq[FileIndex] = @[]
result = moduleFromRodFile(graph, fileIdx, cachedModules)
let path = toFullPath(graph.config, fileIdx)
let filename = AbsoluteFile path
if fileExists(filename): # it could be a stdinfile
graph.cachedFiles[path] = $secureHashFile(path)
let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
if result == nil:
result = newModule(graph, fileIdx)
result.flags.incl flags

View File

@@ -1,136 +0,0 @@
# This file exists to make it overridable via
# patchFile("plugins", "customast.nim", "customast.nim")
## This also serves as a blueprint for a possible implementation.
import "$nim" / compiler / [lineinfos, idents]
when defined(nimPreviewSlimSystem):
import std/assertions
import "$nim" / compiler / nodekinds
export nodekinds
type
PNode* = ref TNode
TNode*{.final, acyclic.} = object
case kind*: TNodeKind
of nkCharLit..nkUInt64Lit:
intVal: BiggestInt
of nkFloatLit..nkFloat128Lit:
floatVal: BiggestFloat
of nkStrLit..nkTripleStrLit:
strVal: string
of nkSym:
discard
of nkIdent:
ident: PIdent
else:
son, next, last: PNode # linked structure instead of a `seq`
info*: TLineInfo
const
bodyPos* = 6
paramsPos* = 3
proc comment*(n: PNode): string =
result = ""
proc `comment=`*(n: PNode, a: string) =
discard "XXX implement me"
proc add*(father, son: PNode) =
assert son != nil
if father.son == nil:
father.son = son
father.last = son
else:
father.last.next = son
father.last = son
template firstSon*(n: PNode): PNode = n.son
template secondSon*(n: PNode): PNode = n.son.next
proc replaceFirstSon*(n, newson: PNode) {.inline.} =
let old = n.son
n.son = newson
newson.next = old
proc replaceSon*(n: PNode; i: int; newson: PNode) =
assert i > 0
assert newson.next == nil
var i = i
var it = n.son
while i > 0:
it = it.next
dec i
let old = it.next
it.next = newson
newson.next = old
template newNodeImpl(info2) =
result = PNode(kind: kind, info: info2)
proc newNode*(kind: TNodeKind): PNode =
## new node with unknown line info, no type, and no children
newNodeImpl(unknownLineInfo)
proc newNode*(kind: TNodeKind, info: TLineInfo): PNode =
## new node with line info, no type, and no children
newNodeImpl(info)
proc newTree*(kind: TNodeKind; info: TLineInfo; child: PNode): PNode =
result = newNode(kind, info)
result.son = child
proc newAtom*(ident: PIdent, info: TLineInfo): PNode =
result = newNode(nkIdent)
result.ident = ident
result.info = info
proc newAtom*(kind: TNodeKind, intVal: BiggestInt, info: TLineInfo): PNode =
result = newNode(kind, info)
result.intVal = intVal
proc newAtom*(kind: TNodeKind, floatVal: BiggestFloat, info: TLineInfo): PNode =
result = newNode(kind, info)
result.floatVal = floatVal
proc newAtom*(kind: TNodeKind; strVal: sink string; info: TLineInfo): PNode =
result = newNode(kind, info)
result.strVal = strVal
proc lastSon*(n: PNode): PNode {.inline.} = n.last
proc setLastSon*(n: PNode, s: PNode) =
assert s.next == nil
n.last = s
if n.son == nil: n.son = s
proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode,
params,
name, pattern, genericParams,
pragmas, exceptions: PNode): PNode =
result = newNode(kind, info)
result.add name
result.add pattern
result.add genericParams
result.add params
result.add pragmas
result.add exceptions
result.add body
template transitionNodeKindCommon(k: TNodeKind) =
let obj {.inject.} = n[]
n[] = TNode(kind: k, info: obj.info)
# n.comment = obj.comment # shouldn't be needed, the address doesnt' change
proc transitionSonsKind*(n: PNode, kind: range[nkComesFrom..nkTupleConstr]) =
transitionNodeKindCommon(kind)
n.son = obj.son
template hasSon*(n: PNode): bool = n.son != nil
template has2Sons*(n: PNode): bool = n.son != nil and n.son.next != nil
proc isNewStyleConcept*(n: PNode): bool {.inline.} =
assert n.kind == nkTypeClassTy
result = n.firstSon.kind == nkEmpty

View File

@@ -25,7 +25,7 @@ proc iterToProcImpl*(c: PContext, n: PNode): PNode =
return
let t = n[2].typ.skipTypes({tyTypeDesc, tyGenericInst})
if t.kind notin {tyRef, tyPtr} or t.elementType.kind != tyObject:
if t.kind notin {tyRef, tyPtr} or t.lastSon.kind != tyObject:
localError(c.config, n[2].info,
"type must be a non-generic ref|ptr to object with state field")
return

View File

@@ -88,7 +88,7 @@ const
wGensym, wInject,
wIntDefine, wStrDefine, wBoolDefine, wDefine,
wCompilerProc, wCore}
paramPragmas* = {wNoalias, wInject, wGensym, wByRef, wByCopy, wCodegenDecl, wExportc, wExportCpp}
paramPragmas* = {wNoalias, wInject, wGensym, wByRef, wByCopy, wCodegenDecl}
letPragmas* = varPragmas
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNoSideEffect,
wThread, wRaises, wEffectsOf, wLocks, wTags, wForbids, wGcSafe,
@@ -145,14 +145,28 @@ proc pragmaEnsures(c: PContext, n: PNode) =
else:
openScope(c)
let o = getCurrOwner(c)
if o.kind in routineKinds and o.typ != nil and o.typ.returnType != nil:
if o.kind in routineKinds and o.typ != nil and o.typ[0] != nil:
var s = newSym(skResult, getIdent(c.cache, "result"), c.idgen, o, n.info)
s.typ = o.typ.returnType
s.typ = o.typ[0]
incl(s.flags, sfUsed)
addDecl(c, s)
n[1] = c.semExpr(c, n[1])
closeScope(c)
proc pragmaAsm*(c: PContext, n: PNode): char =
result = '\0'
if n != nil:
for i in 0..<n.len:
let it = n[i]
if it.kind in nkPragmaCallKinds and it.len == 2 and it[0].kind == nkIdent:
case whichKeyword(it[0].ident)
of wSubsChar:
if it[1].kind == nkCharLit: result = chr(int(it[1].intVal))
else: invalidPragma(c, it)
else: invalidPragma(c, it)
else:
invalidPragma(c, it)
proc setExternName(c: PContext; s: PSym, extname: string, info: TLineInfo) =
# special cases to improve performance:
if extname == "$1":
@@ -241,7 +255,7 @@ proc processVirtual(c: PContext, n: PNode, s: PSym, flag: TSymFlag) =
s.constraint.strVal = s.constraint.strVal % s.name.s
s.flags.incl {flag, sfInfixCall, sfExportc, sfMangleCpp}
s.typ.callConv = ccMember
s.typ.callConv = ccNoConvention
incl c.config.globalOptions, optMixedMode
proc processCodegenDecl(c: PContext, n: PNode, sym: PSym) =
@@ -293,24 +307,6 @@ proc pragmaNoForward*(c: PContext, n: PNode; flag=sfNoForward) =
"use {.experimental: \"codeReordering\".} instead; " &
(if flag == sfNoForward: "{.noForward.}" else: "{.reorder.}") & " is deprecated")
proc pragmaAsm*(c: PContext, n: PNode): char =
## Checks asm pragmas and get's the asm subschar (default: '`').
result = '\0'
if n != nil:
for i in 0..<n.len:
let it = n[i]
if it.kind in nkPragmaCallKinds and it.len == 2 and it[0].kind == nkIdent:
case whichKeyword(it[0].ident)
of wSubsChar:
if it[1].kind == nkCharLit: result = chr(int(it[1].intVal))
else: invalidPragma(c, it)
of wAsmSyntax:
let s = expectStrLit(c, it)
if s notin ["gcc", "vcc"]: invalidPragma(c, it)
else: invalidPragma(c, it)
else:
invalidPragma(c, it)
proc processCallConv(c: PContext, n: PNode) =
if n.kind in nkPragmaCallKinds and n.len == 2 and n[1].kind == nkIdent:
let sw = whichKeyword(n[1].ident)
@@ -480,18 +476,6 @@ proc processOption(c: PContext, n: PNode, resOptions: var TOptions) =
# calling conventions (boring...):
localError(c.config, n.info, "option expected")
proc checkPushedPragma(c: PContext, n: PNode) =
let keyDeep = n.kind in nkPragmaCallKinds and n.len > 1
var key = if keyDeep: n[0] else: n
if key.kind in nkIdentKinds:
let ident = considerQuotedIdent(c, key)
var userPragma = strTableGet(c.userPragmas, ident)
if userPragma == nil:
let k = whichKeyword(ident)
# TODO: might as well make a list which is not accepted by `push`: emit, cast etc.
if k == wEmit:
localError(c.config, n.info, "an 'emit' pragma cannot be pushed")
proc processPush(c: PContext, n: PNode, start: int) =
if n[start-1].kind in nkPragmaCallKinds:
localError(c.config, n.info, "'push' cannot have arguments")
@@ -499,7 +483,6 @@ proc processPush(c: PContext, n: PNode, start: int) =
for i in start..<n.len:
if not tryProcessOption(c, n[i], c.config.options):
# simply store it somewhere:
checkPushedPragma(c, n[i])
if x.otherPragmas.isNil:
x.otherPragmas = newNodeI(nkPragma, n.info)
x.otherPragmas.add n[i]
@@ -616,7 +599,6 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
case n[1].kind
of nkStrLit, nkRStrLit, nkTripleStrLit:
result = newNodeI(if n.kind == nkAsmStmt: nkAsmStmt else: nkArgList, n.info)
if n.kind == nkAsmStmt: result.add n[0] # save asm pragmas for NIR
var str = n[1].strVal
if str == "":
localError(con.config, n.info, "empty 'asm' statement")
@@ -648,7 +630,6 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
else:
illFormedAstLocal(n, con.config)
result = newNodeI(nkAsmStmt, n.info)
if n.kind == nkAsmStmt: result.add n[0]
proc pragmaEmit(c: PContext, n: PNode) =
if n.kind notin nkPragmaCallKinds or n.len != 2:
@@ -1028,7 +1009,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
# Disable the 'noreturn' annotation when in the "Quirky Exceptions" mode!
if c.config.exc != excQuirky:
incl(sym.flags, sfNoReturn)
if sym.typ.returnType != nil:
if sym.typ[0] != nil:
localError(c.config, sym.ast[paramsPos][0].info,
".noreturn with return type not allowed")
of wNoDestroy:
@@ -1142,20 +1123,13 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
of wFatal: fatal(c.config, it.info, expectStrLit(c, it))
of wDefine: processDefine(c, it, sym)
of wUndef: processUndef(c, it)
of wCompile:
let m = sym.getModule()
incl(m.flags, sfUsed)
processCompile(c, it)
of wCompile: processCompile(c, it)
of wLink: processLink(c, it)
of wPassl:
let m = sym.getModule()
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.flags, sfUsed)
let s = expectStrLit(c, it)
extccomp.addCompileOption(c.config, s)
recordPragma(c, it, "passc", s)

View File

@@ -33,7 +33,7 @@ proc equalGenericParams(procA, procB: PNode): bool =
proc searchForProcAux(c: PContext, scope: PScope, fn: PSym): PSym =
const flags = {ExactGenericParams, ExactTypeDescValues,
ExactConstraints, IgnoreCC}
var it: TIdentIter = default(TIdentIter)
var it: TIdentIter
result = initIdentIter(it, scope.symbols, fn.name)
while result != nil:
if result.kind == fn.kind: #and sameType(result.typ, fn.typ, flags):
@@ -54,7 +54,7 @@ proc searchForProcAux(c: PContext, scope: PScope, fn: PSym): PSym =
proc searchForProc*(c: PContext, scope: PScope, fn: PSym): tuple[proto: PSym, comesFromShadowScope: bool] =
var scope = scope
result = (searchForProcAux(c, scope, fn), false)
result.proto = searchForProcAux(c, scope, fn)
while result.proto == nil and scope.isShadowScope:
scope = scope.parent
result.proto = searchForProcAux(c, scope, fn)
@@ -76,7 +76,7 @@ when false:
proc searchForBorrowProc*(c: PContext, startScope: PScope, fn: PSym): PSym =
# Searches for the fn in the symbol table. If the parameter lists are suitable
# for borrowing the sym in the symbol table is returned, else nil.
var it: TIdentIter = default(TIdentIter)
var it: TIdentIter
for scope in walkScopes(startScope):
result = initIdentIter(it, scope.symbols, fn.Name)
while result != nil:

View File

@@ -25,7 +25,7 @@ type
TRenderFlag* = enum
renderNone, renderNoBody, renderNoComments, renderDocComments,
renderNoPragmas, renderIds, renderNoProcDefs, renderSyms, renderRunnableExamples,
renderIr, renderNonExportedFields, renderExpandUsing, renderNoPostfix
renderIr, renderNonExportedFields, renderExpandUsing
TRenderFlags* = set[TRenderFlag]
TRenderTok* = object
@@ -366,7 +366,7 @@ proc litAux(g: TSrcGen; n: PNode, x: BiggestInt, size: int): string =
result = t
while result != nil and result.kind in {tyGenericInst, tyRange, tyVar,
tyLent, tyDistinct, tyOrdinal, tyAlias, tySink}:
result = skipModifier(result)
result = lastSon(result)
result = ""
let typ = n.typ.skip
@@ -546,11 +546,7 @@ proc lsub(g: TSrcGen; n: PNode): int =
of nkInfix: result = lsons(g, n) + 2
of nkPrefix:
result = lsons(g, n)+1+(if n.len > 0 and n[1].kind == nkInfix: 2 else: 0)
of nkPostfix:
if renderNoPostfix notin g.flags:
result = lsons(g, n)
else:
result = lsub(g, n[1])
of nkPostfix: result = lsons(g, n)
of nkCallStrLit: result = lsons(g, n)
of nkPragmaExpr: result = lsub(g, n[0]) + lcomma(g, n, 1)
of nkRange: result = lsons(g, n) + 2
@@ -1334,20 +1330,14 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
put(g, tkColon, ":")
gsub(g, n, bodyPos)
of nkIdentDefs:
var exclFlags: TRenderFlags = {}
if ObjectDef in g.inside:
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)
return
# render postfix for object fields:
exclFlags = g.flags * {renderNoPostfix}
# Skip if this is a property in a type and its not exported
# (While also not allowing rendering of non exported fields)
if ObjectDef in g.inside and (not n[0].isExported() and renderNonExportedFields notin g.flags):
return
# We render the identDef without being inside the section incase we render something like
# y: proc (x: string) # (We wouldn't want to check if x is exported)
g.outside(ObjectDef):
g.flags.excl(exclFlags)
gcomma(g, n, 0, -3)
g.flags.incl(exclFlags)
if n.len >= 2 and n[^2].kind != nkEmpty:
putWithSpace(g, tkColon, ":")
gsub(g, n[^2], c)
@@ -1426,8 +1416,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
postStatements(g, n, i, fromStmtList)
of nkPostfix:
gsub(g, n, 1)
if renderNoPostfix notin g.flags:
gsub(g, n, 0)
gsub(g, n, 0)
of nkRange:
gsub(g, n, 0)
put(g, tkDotDot, "..")
@@ -1531,16 +1520,17 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
gsub(g, n[0])
gsub(g, n[1])
gcoms(g)
indentNL(g)
gsub(g, n[2])
dedent(g)
else:
put(g, tkObject, "object")
of nkRecList:
indentNL(g)
for i in 0..<n.len:
optNL(g)
gsub(g, n[i], c)
gcoms(g)
dedent(g)
putNL(g)
of nkOfInherit:
putWithSpace(g, tkOf, "of")
gsub(g, n, 0)

View File

@@ -397,7 +397,7 @@ proc getStrongComponents(g: var DepG): seq[seq[DepN]] =
## Tarjan's algorithm. Performs a topological sort
## and detects strongly connected components.
result = @[]
var s: seq[DepN] = @[]
var s: seq[DepN]
var idx = 0
for v in g.mitems:
if v.idx < 0:

View File

@@ -21,7 +21,7 @@ import
extccomp
import vtables
import std/[strtabs, math, tables, intsets, strutils, packedsets]
import std/[strtabs, math, tables, intsets, strutils]
when not defined(leanCompiler):
import spawn
@@ -144,7 +144,7 @@ proc commonType*(c: PContext; x, y: PType): PType =
elif b.kind == tyTyped: result = b
elif a.kind == tyTypeDesc:
# turn any concrete typedesc into the abstract typedesc type
if not a.hasElementType: result = a
if a.len == 0: result = a
else:
result = newType(tyTypeDesc, c.idgen, a.owner)
rawAddSon(result, newType(tyNone, c.idgen, a.owner))
@@ -153,17 +153,17 @@ proc commonType*(c: PContext; x, y: PType): PType =
# check for seq[empty] vs. seq[int]
let idx = ord(b.kind == tyArray)
if a[idx].kind == tyEmpty: return y
elif a.kind == tyTuple and b.kind == tyTuple and sameTupleLengths(a, b):
elif a.kind == tyTuple and b.kind == tyTuple and a.len == b.len:
var nt: PType = nil
for i, aa, bb in tupleTypePairs(a, b):
let aEmpty = isEmptyContainer(aa)
let bEmpty = isEmptyContainer(bb)
for i in 0..<a.len:
let aEmpty = isEmptyContainer(a[i])
let bEmpty = isEmptyContainer(b[i])
if aEmpty != bEmpty:
if nt.isNil:
nt = copyType(a, c.idgen, a.owner)
copyTypeProps(c.graph, c.idgen.module, nt, a)
nt[i] = if aEmpty: bb else: aa
nt[i] = if aEmpty: b[i] else: a[i]
if not nt.isNil: result = nt
#elif b[idx].kind == tyEmpty: return x
elif a.kind == tyRange and b.kind == tyRange:
@@ -196,8 +196,8 @@ proc commonType*(c: PContext; x, y: PType): PType =
k = a.kind
if b.kind != a.kind: return x
# bug #7601, array construction of ptr generic
a = a.elementType.skipTypes({tyGenericInst})
b = b.elementType.skipTypes({tyGenericInst})
a = a.lastSon.skipTypes({tyGenericInst})
b = b.lastSon.skipTypes({tyGenericInst})
if a.kind == tyObject and b.kind == tyObject:
result = commonSuperclass(a, b)
# this will trigger an error later:
@@ -222,7 +222,66 @@ proc shouldCheckCaseCovered(caseTyp: PType): bool =
else:
discard
proc endsInNoReturn(n: PNode): bool
proc endsInNoReturn(n: PNode): bool =
## check if expr ends the block like raising or call of noreturn procs do
result = false # assume it does return
template checkBranch(branch) =
if not endsInNoReturn(branch):
# proved a branch returns
return false
var it = n
# skip these beforehand, no special handling needed
while it.kind in {nkStmtList, nkStmtListExpr} and it.len > 0:
it = it.lastSon
case it.kind
of nkIfStmt:
var hasElse = false
for branch in it:
checkBranch:
if branch.len == 2:
branch[1]
elif branch.len == 1:
hasElse = true
branch[0]
else:
raiseAssert "Malformed `if` statement during endsInNoReturn"
# none of the branches returned
result = hasElse # Only truly a no-return when it's exhaustive
of nkCaseStmt:
let caseTyp = skipTypes(it[0].typ, abstractVar-{tyTypeDesc})
# semCase should already have checked for exhaustiveness in this case
# effectively the same as having an else
var hasElse = caseTyp.shouldCheckCaseCovered()
# actual noreturn checks
for i in 1 ..< it.len:
let branch = it[i]
checkBranch:
case branch.kind
of nkOfBranch:
branch[^1]
of nkElifBranch:
branch[1]
of nkElse:
hasElse = true
branch[0]
else:
raiseAssert "Malformed `case` statement in endsInNoReturn"
# Can only guarantee a noreturn if there is an else or it's exhaustive
result = hasElse
of nkTryStmt:
checkBranch(it[0])
for i in 1 ..< it.len:
let branch = it[i]
checkBranch(branch[^1])
# none of the branches returned
result = true
else:
result = it.kind in nkLastBlockStmts or
it.kind in nkCallKinds and it[0].kind == nkSym and sfNoReturn in it[0].sym.flags
proc commonType*(c: PContext; x: PType, y: PNode): PType =
# ignore exception raising branches in case/if expressions
@@ -254,8 +313,6 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
result.owner = getCurrOwner(c)
else:
result = newSym(kind, considerQuotedIdent(c, n), c.idgen, getCurrOwner(c), n.info)
if find(result.name.s, '`') >= 0:
result.flags.incl sfWasGenSym
#if kind in {skForVar, skLet, skVar} and result.owner.kind == skModule:
# incl(result.flags, sfGlobal)
when defined(nimsuggest):
@@ -265,7 +322,7 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym
# identifier with visibility
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags, fromTopLevel = false): PSym
allowed: TSymFlags): PSym
proc typeAllowedCheck(c: PContext; info: TLineInfo; typ: PType; kind: TSymKind;
flags: TTypeAllowedFlags = {}) =
@@ -441,15 +498,15 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
c.friendModules.add(s.owner.getModule)
result = macroResult
resetSemFlag result
if s.typ.returnType == nil:
if s.typ[0] == nil:
result = semStmt(c, result, flags)
else:
var retType = s.typ.returnType
var retType = s.typ[0]
if retType.kind == tyTypeDesc and tfUnresolved in retType.flags and
retType.hasElementType:
retType.len == 1:
# bug #11941: template fails(T: type X, v: auto): T
# does not mean we expect a tyTypeDesc.
retType = retType.skipModifier
retType = retType[0]
case retType.kind
of tyUntyped, tyAnything:
# Not expecting a type here allows templates like in ``tmodulealias.in``.
@@ -473,7 +530,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
# e.g. template foo(T: typedesc): seq[T]
# We will instantiate the return type here, because
# we now know the supplied arguments
var paramTypes = initTypeMapping()
var paramTypes = initIdTable()
for param, value in genericParamsInMacroCall(s, call):
var givenType = value.typ
# the sym nodes used for the supplied generic arguments for
@@ -491,7 +548,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
else:
result = semExpr(c, result, flags, expectedType)
result = fitNode(c, retType, result, result.info)
#globalError(s.info, errInvalidParamKindX, typeToString(s.typ.returnType))
#globalError(s.info, errInvalidParamKindX, typeToString(s.typ[0]))
dec(c.config.evalTemplateCounter)
discard c.friendModules.pop()

View File

@@ -49,18 +49,6 @@ proc initCandidateSymbols(c: PContext, headSymbol: PNode,
while symx != nil:
if symx.kind in filter:
result.add((symx, o.lastOverloadScope))
elif symx.kind == skGenericParam:
#[
This code handles looking up a generic parameter when it's a static callable.
For instance:
proc name[T: static proc()]() = T()
name[proc() = echo"hello"]()
]#
for paramSym in searchInScopesAllCandidatesFilterBy(c, symx.name, {skConst}):
let paramTyp = paramSym.typ
if paramTyp.n.kind == nkSym and paramTyp.n.sym.kind in filter:
result.add((paramTyp.n.sym, o.lastOverloadScope))
symx = nextOverloadIter(o, c, headSymbol)
if result.len > 0:
best = initCandidate(c, result[0].s, initialBinding,
@@ -80,7 +68,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
# `matches` may find new symbols, so keep track of count
var symCount = c.currentScope.symbols.counter
var o: TOverloadIter = default(TOverloadIter)
var o: TOverloadIter
# https://github.com/nim-lang/Nim/issues/21272
# prevent mutation during iteration by storing them in a seq
# luckily `initCandidateSymbols` does just that
@@ -248,89 +236,44 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
candidates.add("\n")
let nArg = if err.firstMismatch.arg < n.len: n[err.firstMismatch.arg] else: nil
let nameParam = if err.firstMismatch.formal != nil: err.firstMismatch.formal.name.s else: ""
if n.len > 1:
if verboseTypeMismatch notin c.config.legacyFeatures:
case err.firstMismatch.kind
of kUnknownNamedParam:
if nArg == nil:
candidates.add(" unknown named parameter")
else:
candidates.add(" unknown named parameter: " & $nArg[0])
candidates.add "\n"
of kAlreadyGiven:
candidates.add(" named param already provided: " & $nArg[0])
candidates.add "\n"
of kPositionalAlreadyGiven:
candidates.add(" positional param was already given as named param")
candidates.add "\n"
of kExtraArg:
candidates.add(" extra argument given")
candidates.add "\n"
of kMissingParam:
candidates.add(" missing parameter: " & nameParam)
candidates.add "\n"
of kVarNeeded:
doAssert nArg != nil
doAssert err.firstMismatch.formal != nil
candidates.add " expression '"
if n.len > 1 and verboseTypeMismatch in c.config.legacyFeatures:
candidates.add(" first type mismatch at position: " & $err.firstMismatch.arg)
# candidates.add "\n reason: " & $err.firstMismatch.kind # for debugging
case err.firstMismatch.kind
of kUnknownNamedParam:
if nArg == nil:
candidates.add("\n unknown named parameter")
else:
candidates.add("\n unknown named parameter: " & $nArg[0])
of kAlreadyGiven: candidates.add("\n named param already provided: " & $nArg[0])
of kPositionalAlreadyGiven: candidates.add("\n positional param was already given as named param")
of kExtraArg: candidates.add("\n extra argument given")
of kMissingParam: candidates.add("\n missing parameter: " & nameParam)
of kTypeMismatch, kVarNeeded:
doAssert nArg != nil
let wanted = err.firstMismatch.formal.typ
doAssert err.firstMismatch.formal != nil
candidates.add("\n required type for " & nameParam & ": ")
candidates.addTypeDeclVerboseMaybe(c.config, wanted)
candidates.add "\n but expression '"
if err.firstMismatch.kind == kVarNeeded:
candidates.add renderNotLValue(nArg)
candidates.add "' is immutable, not 'var'"
candidates.add "\n"
of kTypeMismatch:
doAssert nArg != nil
let wanted = err.firstMismatch.formal.typ
doAssert err.firstMismatch.formal != nil
doAssert wanted != nil
else:
candidates.add renderTree(nArg)
candidates.add "' is of type: "
let got = nArg.typ
if got != nil and got.kind == tyProc and wanted.kind == tyProc:
# These are proc mismatches so,
# add the extra explict detail of the mismatch
candidates.add " expression '"
candidates.add renderTree(nArg)
candidates.add "' is of type: "
candidates.addTypeDeclVerboseMaybe(c.config, got)
candidates.addPragmaAndCallConvMismatch(wanted, got, c.config)
candidates.addTypeDeclVerboseMaybe(c.config, got)
doAssert wanted != nil
if got != nil:
if got.kind == tyProc and wanted.kind == tyProc:
# These are proc mismatches so,
# add the extra explict detail of the mismatch
candidates.addPragmaAndCallConvMismatch(wanted, got, c.config)
effectProblem(wanted, got, candidates, c)
candidates.add "\n"
of kUnknown: discard "do not break 'nim check'"
else:
candidates.add(" first type mismatch at position: " & $err.firstMismatch.arg)
# candidates.add "\n reason: " & $err.firstMismatch.kind # for debugging
case err.firstMismatch.kind
of kUnknownNamedParam:
if nArg == nil:
candidates.add("\n unknown named parameter")
else:
candidates.add("\n unknown named parameter: " & $nArg[0])
of kAlreadyGiven: candidates.add("\n named param already provided: " & $nArg[0])
of kPositionalAlreadyGiven: candidates.add("\n positional param was already given as named param")
of kExtraArg: candidates.add("\n extra argument given")
of kMissingParam: candidates.add("\n missing parameter: " & nameParam)
of kTypeMismatch, kVarNeeded:
doAssert nArg != nil
let wanted = err.firstMismatch.formal.typ
doAssert err.firstMismatch.formal != nil
candidates.add("\n required type for " & nameParam & ": ")
candidates.addTypeDeclVerboseMaybe(c.config, wanted)
candidates.add "\n but expression '"
if err.firstMismatch.kind == kVarNeeded:
candidates.add renderNotLValue(nArg)
candidates.add "' is immutable, not 'var'"
else:
candidates.add renderTree(nArg)
candidates.add "' is of type: "
let got = nArg.typ
candidates.addTypeDeclVerboseMaybe(c.config, got)
doAssert wanted != nil
if got != nil:
if got.kind == tyProc and wanted.kind == tyProc:
# These are proc mismatches so,
# add the extra explict detail of the mismatch
candidates.addPragmaAndCallConvMismatch(wanted, got, c.config)
effectProblem(wanted, got, candidates, c)
of kUnknown: discard "do not break 'nim check'"
candidates.add "\n"
of kUnknown: discard "do not break 'nim check'"
candidates.add "\n"
if err.firstMismatch.arg == 1 and nArg.kind == nkTupleConstr and
n.kind == nkCommand:
maybeWrongSpace = true
@@ -411,7 +354,7 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
proc bracketNotFoundError(c: PContext; n: PNode) =
var errors: CandidateErrors = @[]
var o: TOverloadIter = default(TOverloadIter)
var o: TOverloadIter
let headSymbol = n[0]
var symx = initOverloadIter(o, c, headSymbol)
while symx != nil:
@@ -434,7 +377,7 @@ proc getMsgDiagnostic(c: PContext, flags: TExprFlags, n, f: PNode): string =
# also avoid slowdowns in evaluating `compiles(expr)`.
discard
else:
var o: TOverloadIter = default(TOverloadIter)
var o: TOverloadIter
var sym = initOverloadIter(o, c, f)
while sym != nil:
result &= "\n found $1" % [getSymRepr(c.config, sym)]
@@ -479,7 +422,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
filter, result, alt, errors, efExplain in flags,
errorsEnabled, flags)
var dummyErrors: CandidateErrors = @[]
var dummyErrors: CandidateErrors
template pickSpecialOp(headSymbol) =
pickBestCandidate(c, headSymbol, n, orig, initialBinding,
filter, result, alt, dummyErrors, efExplain in flags,
@@ -562,7 +505,7 @@ proc instGenericConvertersArg*(c: PContext, a: PNode, x: TCandidate) =
let finalCallee = generateInstance(c, s, x.bindings, a.info)
a[0].sym = finalCallee
a[0].typ = finalCallee.typ
#a.typ = finalCallee.typ.returnType
#a.typ = finalCallee.typ[0]
proc instGenericConvertersSons*(c: PContext, n: PNode, x: TCandidate) =
assert n.kind in nkCallKinds
@@ -625,7 +568,7 @@ proc inheritBindings(c: PContext, x: var TCandidate, expectedType: PType) =
## Helper proc to inherit bound generic parameters from expectedType into x.
## Does nothing if 'inferGenericTypes' isn't in c.features.
if inferGenericTypes notin c.features: return
if expectedType == nil or x.callee.returnType == nil: return # required for inference
if expectedType == nil or x.callee[0] == nil: return # required for inference
var
flatUnbound: seq[PType] = @[]
@@ -637,14 +580,14 @@ proc inheritBindings(c: PContext, x: var TCandidate, expectedType: PType) =
## skips types and puts the skipped version on stack
# It might make sense to skip here one by one. It's not part of the main
# type reduction because the right side normally won't be skipped
const toSkip = {tyVar, tyLent, tyStatic, tyCompositeTypeClass, tySink}
const toSkip = { tyVar, tyLent, tyStatic, tyCompositeTypeClass, tySink }
let
x = a.skipTypes(toSkip)
y = if a.kind notin toSkip: b
else: b.skipTypes(toSkip)
typeStack.add((x, y))
stackPut(x.callee.returnType, expectedType)
stackPut(x.callee[0], expectedType)
while typeStack.len() > 0:
let (t, u) = typeStack.pop()
@@ -652,18 +595,17 @@ proc inheritBindings(c: PContext, x: var TCandidate, expectedType: PType) =
continue
case t.kind
of ConcreteTypes, tyGenericInvocation, tyUncheckedArray:
# XXX This logic makes no sense for `tyUncheckedArray`
# nested, add all the types to stack
let
startIdx = if u.kind in ConcreteTypes: 0 else: 1
endIdx = min(u.kidsLen() - startIdx, t.kidsLen())
endIdx = min(u.len() - startIdx, t.len())
for i in startIdx ..< endIdx:
# early exit with current impl
if t[i] == nil or u[i] == nil: return
stackPut(t[i], u[i])
of tyGenericParam:
let prebound = x.bindings.idTableGet(t)
let prebound = x.bindings.idTableGet(t).PType
if prebound != nil:
continue # Skip param, already bound
@@ -725,7 +667,7 @@ proc semResolvedCall(c: PContext, x: var TCandidate,
result = x.call
instGenericConvertersSons(c, result, x)
result[0] = newSymNode(finalCallee, getCallLineInfo(result[0]))
result.typ = finalCallee.typ.returnType
result.typ = finalCallee.typ[0]
updateDefaultParams(result)
proc canDeref(n: PNode): bool {.inline.} =
@@ -778,9 +720,9 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
# try transforming the argument into a static one before feeding it into
# typeRel
if formal.kind == tyStatic and arg.kind != tyStatic:
let evaluated = c.semTryConstExpr(c, n[i], n[i].typ)
let evaluated = c.semTryConstExpr(c, n[i])
if evaluated != nil:
arg = newTypeS(tyStatic, c, son = evaluated.typ)
arg = newTypeS(tyStatic, c, sons = @[evaluated.typ])
arg.n = evaluated
let tm = typeRel(m, formal, arg)
if tm in {isNone, isConvertible}: return nil
@@ -791,16 +733,10 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
onUse(info, s)
result = newSymNode(newInst, info)
proc setGenericParams(c: PContext, n, expectedParams: PNode) =
proc setGenericParams(c: PContext, n: PNode) =
## sems generic params in subscript expression
for i in 1..<n.len:
let
constraint =
if expectedParams != nil and i <= expectedParams.len:
expectedParams[i - 1].typ
else:
nil
e = semExprWithType(c, n[i], expectedType = constraint)
let e = semExprWithType(c, n[i])
if e.typ == nil:
n[i].typ = errorType(c)
else:
@@ -808,7 +744,7 @@ proc setGenericParams(c: PContext, n, expectedParams: PNode) =
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
assert n.kind == nkBracketExpr
setGenericParams(c, n, s.ast[genericParamsPos])
setGenericParams(c, n)
var s = s
var a = n[0]
if a.kind == nkSym:
@@ -872,7 +808,7 @@ proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): tuple[s: PS
]#
t = skipTypes(param.typ, desiredTypes)
isDistinct = t.kind == tyDistinct or param.typ.kind == tyDistinct
if t.kind == tyGenericInvocation and t.genericHead.last.kind == tyDistinct:
if t.kind == tyGenericInvocation and t[0].lastSon.kind == tyDistinct:
result.state = bsGeneric
return
if isDistinct: hasDistinct = true
@@ -891,7 +827,7 @@ proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): tuple[s: PS
if resolved != nil:
result.s = resolved[0].sym
result.state = bsMatch
if not compareTypes(result.s.typ.returnType, fn.typ.returnType, dcEqIgnoreDistinct, {IgnoreFlags}):
if not compareTypes(result.s.typ[0], fn.typ[0], dcEqIgnoreDistinct, {IgnoreFlags}):
result.state = bsReturnNotMatch
elif result.s.magic in {mArrPut, mArrGet}:
# cannot borrow these magics for now

View File

@@ -41,7 +41,7 @@ type
breakInLoop*: bool # whether we are in a loop without block
next*: PProcCon # used for stacking procedure contexts
mappingExists*: bool
mapping*: Table[ItemId, PSym]
mapping*: TIdTable
caseContext*: seq[tuple[n: PNode, idx: int]]
localBindStmts*: seq[PNode]
@@ -122,6 +122,8 @@ type
converters*: seq[PSym]
patterns*: seq[PSym] # sequence of pattern matchers
optionStack*: seq[POptionEntry]
symMapping*: TIdTable # every gensym'ed symbol needs to be mapped
# to some new symbol in a generic instantiation
libs*: seq[PLib] # all libs used by this module
semConstExpr*: proc (c: PContext, n: PNode; expectedType: PType = nil): PNode {.nimcall.} # for the pragmas
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode {.nimcall.}
@@ -136,8 +138,8 @@ type
semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
filter: TSymKinds, flags: TExprFlags, expectedType: PType = nil): PNode {.nimcall.}
semTypeNode*: proc(c: PContext, n: PNode, prev: PType): PType {.nimcall.}
semInferredLambda*: proc(c: PContext, pt: Table[ItemId, PType], n: PNode): PNode
semGenerateInstance*: proc (c: PContext, fn: PSym, pt: Table[ItemId, PType],
semInferredLambda*: proc(c: PContext, pt: TIdTable, n: PNode): PNode
semGenerateInstance*: proc (c: PContext, fn: PSym, pt: TIdTable,
info: TLineInfo): PSym
includedFiles*: IntSet # used to detect recursive include files
pureEnumFields*: TStrTable # pure enum fields that can be used unambiguously
@@ -249,14 +251,14 @@ proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next
proc put*(p: PProcCon; key, val: PSym) =
if not p.mappingExists:
p.mapping = initTable[ItemId, PSym]()
p.mapping = initIdTable()
p.mappingExists = true
#echo "put into table ", key.info
p.mapping[key.itemId] = val
p.mapping.idTablePut(key, val)
proc get*(p: PProcCon; key: PSym): PSym =
if not p.mappingExists: return nil
result = p.mapping.getOrDefault(key.itemId)
result = PSym(p.mapping.idTableGet(key))
proc getGenSym*(c: PContext; s: PSym): PSym =
if sfGenSym notin s.flags: return s
@@ -331,7 +333,7 @@ proc newContext*(graph: ModuleGraph; module: PSym): PContext =
graph.packed[id].module = module
initEncoder graph, module
template packedRepr*(c): untyped = c.graph.packed[c.module.position].toDisk
template packedRepr*(c): untyped = c.graph.packed[c.module.position].fromDisk
template encoder*(c): untyped = c.graph.encoders[c.module.position]
proc addIncludeFileDep*(c: PContext; f: FileIndex) =
@@ -394,11 +396,12 @@ proc addToLib*(lib: PLib, sym: PSym) =
# LocalError(sym.info, errInvalidPragma)
sym.annex = lib
proc newTypeS*(kind: TTypeKind; c: PContext; son: sink PType = nil): PType =
result = newType(kind, c.idgen, getCurrOwner(c), son = son)
proc newTypeS*(kind: TTypeKind, c: PContext, sons: seq[PType] = @[]): PType =
result = newType(kind, c.idgen, getCurrOwner(c), sons = sons)
proc makePtrType*(owner: PSym, baseType: PType; idgen: IdGenerator): PType =
result = newType(tyPtr, idgen, owner, skipIntLit(baseType, idgen))
result = newType(tyPtr, idgen, owner)
addSonSkipIntLit(result, baseType, idgen)
proc makePtrType*(c: PContext, baseType: PType): PType =
makePtrType(getCurrOwner(c), baseType, c.idgen)
@@ -411,13 +414,15 @@ proc makeTypeWithModifier*(c: PContext,
if modifier in {tyVar, tyLent, tyTypeDesc} and baseType.kind == modifier:
result = baseType
else:
result = newTypeS(modifier, c, skipIntLit(baseType, c.idgen))
result = newTypeS(modifier, c)
addSonSkipIntLit(result, baseType, c.idgen)
proc makeVarType*(c: PContext, baseType: PType; kind = tyVar): PType =
if baseType.kind == kind:
result = baseType
else:
result = newTypeS(kind, c, skipIntLit(baseType, c.idgen))
result = newTypeS(kind, c)
addSonSkipIntLit(result, baseType, c.idgen)
proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
let typedesc = newTypeS(tyTypeDesc, c)
@@ -433,40 +438,40 @@ proc makeTypeFromExpr*(c: PContext, n: PNode): PType =
assert n != nil
result.n = n
when false:
proc newTypeWithSons*(owner: PSym, kind: TTypeKind, sons: seq[PType];
idgen: IdGenerator): PType =
result = newType(kind, idgen, owner, sons = sons)
proc newTypeWithSons*(owner: PSym, kind: TTypeKind, sons: seq[PType];
idgen: IdGenerator): PType =
result = newType(kind, idgen, owner, sons = sons)
proc newTypeWithSons*(c: PContext, kind: TTypeKind,
sons: seq[PType]): PType =
result = newType(kind, c.idgen, getCurrOwner(c), sons = sons)
proc newTypeWithSons*(c: PContext, kind: TTypeKind,
sons: seq[PType]): PType =
result = newType(kind, c.idgen, getCurrOwner(c), sons = sons)
proc newTypeWithSons*(c: PContext, kind: TTypeKind,
parent: PType): PType =
result = newType(kind, c.idgen, getCurrOwner(c), parent = parent)
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
else: newTypeS(tyStatic, c, n.typ)
else: newTypeWithSons(c, tyStatic, @[n.typ])
proc makeAndType*(c: PContext, t1, t2: PType): PType =
result = newTypeS(tyAnd, c)
result.rawAddSon t1
result.rawAddSon t2
result = newTypeS(tyAnd, c, sons = @[t1, t2])
propagateToOwner(result, t1)
propagateToOwner(result, t2)
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:
result = newTypeS(tyOr, c)
result.rawAddSon t1
result.rawAddSon t2
result = newTypeS(tyOr, c, sons = @[t1, t2])
else:
result = newTypeS(tyOr, c)
template addOr(t1) =
if t1.kind == tyOr:
for x in t1.kids: result.rawAddSon x
for x in t1: result.rawAddSon x
else:
result.rawAddSon t1
addOr(t1)
@@ -477,7 +482,7 @@ proc makeOrType*(c: PContext, t1, t2: PType): PType =
result.flags.incl tfHasMeta
proc makeNotType*(c: PContext, t1: PType): PType =
result = newTypeS(tyNot, c, son = t1)
result = newTypeS(tyNot, c, sons = @[t1])
propagateToOwner(result, t1)
result.flags.incl(t1.flags * {tfHasStatic})
result.flags.incl tfHasMeta
@@ -488,7 +493,7 @@ proc nMinusOne(c: PContext; n: PNode): PNode =
# Remember to fix the procs below this one when you make changes!
proc makeRangeWithStaticExpr*(c: PContext, n: PNode): PType =
let intType = getSysType(c.graph, n.info, tyInt)
result = newTypeS(tyRange, c, son = intType)
result = newTypeS(tyRange, c, sons = @[intType])
if n.typ != nil and n.typ.n == nil:
result.flags.incl tfUnresolved
result.n = newTreeI(nkRange, n.info, newIntTypeNode(0, intType),
@@ -548,8 +553,9 @@ proc makeTypeDesc*(c: PContext, typ: PType): PType =
if typ.kind == tyTypeDesc and not isSelf(typ):
result = typ
else:
result = newTypeS(tyTypeDesc, c, skipIntLit(typ, c.idgen))
result = newTypeS(tyTypeDesc, c)
incl result.flags, tfCheckedForDestructor
result.addSonSkipIntLit(typ, c.idgen)
proc symFromType*(c: PContext; t: PType, info: TLineInfo): PSym =
if t.sym != nil: return t.sym

View File

@@ -54,6 +54,17 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
# same as 'semExprWithType' but doesn't check for proc vars
result = semExpr(c, n, flags + {efOperand, efAllowSymChoice})
if result.typ != nil:
# XXX tyGenericInst here?
if result.typ.kind == tyProc and hasUnresolvedParams(result, {efOperand}):
#and tfUnresolved in result.typ.flags:
let owner = result.typ.owner
let err =
# consistent error message with evaltempl/semMacroExpr
if owner != nil and owner.kind in {skTemplate, skMacro}:
errMissingGenericParamsForTemplate % n.renderTree
else:
errProcHasNoConcreteType % n.renderTree
localError(c.config, n.info, err)
if result.typ.kind in {tyVar, tyLent}: result = newDeref(result)
elif {efWantStmt, efAllowStmt} * flags != {}:
result.typ = newTypeS(tyVoid, c)
@@ -120,13 +131,11 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode
proc isSymChoice(n: PNode): bool {.inline.} =
result = n.kind in nkSymChoices
proc resolveSymChoice(c: PContext, n: var PNode, flags: TExprFlags = {}, expectedType: PType = nil) =
## Attempts to resolve a symchoice `n`, `n` remains a symchoice if
## it cannot be resolved (this is the case even when `n.len == 1`).
proc semSymChoice(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode =
result = n
if expectedType != nil:
# resolve from type inference, see paramTypesMatch
n = fitNode(c, expectedType, n, n.info)
if isSymChoice(n) and efAllowSymChoice notin flags:
result = fitNode(c, expectedType, result, n.info)
if isSymChoice(result) and efAllowSymChoice notin flags:
# some contexts might want sym choices preserved for later disambiguation
# in general though they are ambiguous
let first = n[0].sym
@@ -136,24 +145,17 @@ proc resolveSymChoice(c: PContext, n: var PNode, flags: TExprFlags = {}, expecte
foundSym == first:
# choose the first resolved enum field, i.e. the latest in scope
# to mirror behavior before overloadable enums
n = n[0]
proc semSymChoice(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode =
result = n
resolveSymChoice(c, result, flags, expectedType)
if isSymChoice(result) and result.len == 1:
# resolveSymChoice can leave 1 sym
result = result[0]
if isSymChoice(result) and efAllowSymChoice notin flags:
var err = "ambiguous identifier: '" & result[0].sym.name.s &
"' -- use one of the following:\n"
for child in n:
let candidate = child.sym
err.add " " & candidate.owner.name.s & "." & candidate.name.s
err.add ": " & typeToString(candidate.typ) & "\n"
localError(c.config, n.info, err)
n.typ = errorType(c)
result = n
result = n[0]
else:
var err = "ambiguous identifier '" & first.name.s &
"' -- use one of the following:\n"
for child in n:
let candidate = child.sym
err.add " " & candidate.owner.name.s & "." & candidate.name.s
err.add ": " & typeToString(candidate.typ) & "\n"
localError(c.config, n.info, err)
n.typ = errorType(c)
result = n
if result.kind == nkSym:
result = semSym(c, result, result.sym, flags)
@@ -194,19 +196,19 @@ proc checkConvertible(c: PContext, targetTyp: PType, src: PNode): TConvStatus =
var d = skipTypes(targetTyp, abstractVar)
var s = srcTyp
if s.kind in tyUserTypeClasses and s.isResolvedUserTypeClass:
s = s.last
s = s.lastSon
s = skipTypes(s, abstractVar-{tyTypeDesc, tyOwned})
if s.kind == tyOwned and d.kind != tyOwned:
s = s.skipModifier
s = s.lastSon
var pointers = 0
while (d != nil) and (d.kind in {tyPtr, tyRef, tyOwned}):
if s.kind == tyOwned and d.kind != tyOwned:
s = s.skipModifier
s = s.lastSon
elif d.kind != s.kind:
break
else:
d = d.elementType
s = s.elementType
d = d.lastSon
s = s.lastSon
inc pointers
let targetBaseTyp = skipTypes(targetTyp, abstractVarRange)
@@ -343,7 +345,7 @@ proc semConv(c: PContext, n: PNode; flags: TExprFlags = {}, expectedType: PType
if targetType.kind in {tySink, tyLent} or isOwnedSym(c, n[0]):
let baseType = semTypeNode(c, n[1], nil).skipTypes({tyTypeDesc})
let t = newTypeS(targetType.kind, c, baseType)
let t = newTypeS(targetType.kind, c, @[baseType])
if targetType.kind == tyOwned:
t.flags.incl tfHasOwned
result = newNodeI(nkType, n.info)
@@ -440,7 +442,7 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
of tySequence, tyString, tyCstring, tyOpenArray, tyVarargs:
n.typ = getSysType(c.graph, n.info, tyInt)
of tyArray:
n.typ = typ.indexType
n.typ = typ[0] # indextype
if n.typ.kind == tyRange and emptyRange(n.typ.n[0], n.typ.n[1]): #Invalid range
n.typ = getSysType(c.graph, n.info, tyInt)
of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt..tyUInt64, tyFloat..tyFloat64:
@@ -465,7 +467,7 @@ proc fixupStaticType(c: PContext, n: PNode) =
# apply this measure only in code that is enlightened to work
# with static types.
if n.typ.kind != tyStatic:
n.typ = newTypeS(tyStatic, c, n.typ)
n.typ = newTypeWithSons(getCurrOwner(c), tyStatic, @[n.typ], c.idgen)
n.typ.n = n # XXX: cycles like the one here look dangerous.
# Consider using `n.copyTree`
@@ -518,9 +520,8 @@ proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode =
result.typ = n.typ
proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode =
if n.len != 3 or n[2].kind == nkEmpty:
if n.len != 3:
localError(c.config, n.info, "'is' operator takes 2 arguments")
return errorNode(c, n)
let boolType = getSysType(c.graph, n.info, tyBool)
result = n
@@ -620,7 +621,7 @@ proc changeType(c: PContext; n: PNode, newType: PType, check: bool) =
a.add m
changeType(m, tup[i], check)
of nkCharLit..nkUInt64Lit:
if check and n.kind != nkUInt64Lit and not sameTypeOrNil(n.typ, newType):
if check and n.kind != nkUInt64Lit and not sameType(n.typ, newType):
let value = n.intVal
if value < firstOrd(c.config, newType) or value > lastOrd(c.config, newType):
localError(c.config, n.info, "cannot convert " & $value &
@@ -639,7 +640,7 @@ proc arrayConstrType(c: PContext, n: PNode): PType =
else:
var t = skipTypes(n[0].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
addSonSkipIntLit(typ, t, c.idgen)
typ.setIndexType makeRangeType(c, 0, n.len - 1, n.info)
typ[0] = makeRangeType(c, 0, n.len - 1, n.info)
result = typ
proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
@@ -712,7 +713,7 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PTyp
addSonSkipIntLit(result.typ, typ, c.idgen)
for i in 0..<result.len:
result[i] = fitNode(c, typ, result[i], result[i].info)
result.typ.setIndexType makeRangeType(c, toInt64(firstIndex), toInt64(lastIndex), n.info,
result.typ[0] = makeRangeType(c, toInt64(firstIndex), toInt64(lastIndex), n.info,
indexType)
proc fixAbstractType(c: PContext, n: PNode) =
@@ -815,7 +816,7 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode, isConverter = false) =
const
FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl,
mSetLengthStr, mSetLengthSeq, mAppendStrCh, mAppendStrStr, mSwap,
mAppendSeqElem, mNewSeq, mShallowCopy, mDeepCopy, mMove,
mAppendSeqElem, mNewSeq, mReset, mShallowCopy, mDeepCopy, mMove,
mWasMoved}
template checkIfConverterCalled(c: PContext, n: PNode) =
@@ -900,7 +901,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
if n[i].typ.isNil or n[i].typ.kind != tyStatic or
tfUnresolved notin n[i].typ.flags:
break maybeLabelAsStatic
n.typ = newTypeS(tyStatic, c, n.typ)
n.typ = newTypeWithSons(c, tyStatic, @[n.typ])
n.typ.flags.incl tfUnresolved
# optimization pass: not necessary for correctness of the semantic pass
@@ -1003,34 +1004,6 @@ proc bracketedMacro(n: PNode): PSym =
else:
result = nil
proc finishOperand(c: PContext, a: PNode): PNode =
if a.typ.isNil:
result = c.semOperand(c, a, {efDetermineType})
else:
result = a
# XXX tyGenericInst here?
if result.typ.kind == tyProc and hasUnresolvedParams(result, {efOperand}):
#and tfUnresolved in result.typ.flags:
let owner = result.typ.owner
let err =
# consistent error message with evaltempl/semMacroExpr
if owner != nil and owner.kind in {skTemplate, skMacro}:
errMissingGenericParamsForTemplate % a.renderTree
else:
errProcHasNoConcreteType % a.renderTree
localError(c.config, a.info, err)
considerGenSyms(c, result)
proc semFinishOperands(c: PContext; n: PNode; isBracketExpr = false) =
# this needs to be called to ensure that after overloading resolution every
# argument has been sem'checked
# skip the first argument for operands of `[]` since it may be an unresolved
# generic proc, which is handled in semMagic
let start = 1 + ord(isBracketExpr)
for i in start..<n.len:
n[i] = finishOperand(c, n[i])
proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
if efNoSemCheck notin flags and n.typ != nil and n.typ.kind == tyError:
return errorNode(c, n)
@@ -1051,7 +1024,7 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags; expectedTy
of skMacro: result = semMacroExpr(c, result, orig, callee, flags, expectedType)
of skTemplate: result = semTemplateExpr(c, result, callee, flags, expectedType)
else:
semFinishOperands(c, result, isBracketExpr = callee.magic in {mArrGet, mArrPut})
semFinishOperands(c, result)
activate(c, result)
fixAbstractType(c, result)
analyseIfAddressTakenInCall(c, result)
@@ -1059,7 +1032,7 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags; expectedTy
result = magicsAfterOverloadResolution(c, result, flags, expectedType)
when false:
if result.typ != nil and
not (result.typ.kind == tySequence and result.elementType.kind == tyEmpty):
not (result.typ.kind == tySequence and result.typ[0].kind == tyEmpty):
liftTypeBoundOps(c, result.typ, n.info)
#result = patchResolvedTypeBoundOp(c, result)
if c.matchedConcept == nil:
@@ -1089,7 +1062,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
elif n[0].kind == nkBracketExpr:
let s = bracketedMacro(n[0])
if s != nil:
setGenericParams(c, n[0], s.ast[genericParamsPos])
setGenericParams(c, n[0])
return semDirectOp(c, n, flags, expectedType)
elif isSymChoice(n[0]) and nfDotField notin n.flags:
# overloaded generic procs e.g. newSeq[int] can end up here
@@ -1290,7 +1263,7 @@ proc readTypeParameter(c: PContext, typ: PType,
discard
if typ.kind != tyUserTypeClass:
let ty = if typ.kind == tyCompositeTypeClass: typ.firstGenericParam.skipGenericAlias
let ty = if typ.kind == tyCompositeTypeClass: typ[1].skipGenericAlias
else: typ.skipGenericAlias
let tbody = ty[0]
for s in 0..<tbody.len-1:
@@ -1319,7 +1292,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
onUse(n.info, s)
let typ = skipTypes(s.typ, abstractInst-{tyTypeDesc})
case typ.kind
of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
tyTuple, tySet, tyUInt..tyUInt64:
if s.magic == mNone: result = inlineConst(c, n, s)
else: result = newSymNode(s, n.info)
@@ -1460,7 +1433,7 @@ proc tryReadingTypeField(c: PContext, n: PNode, i: PIdent, ty: PType): PNode =
n.typ = makeTypeDesc(c, field.typ)
result = n
of tyGenericInst:
result = tryReadingTypeField(c, n, i, ty.skipModifier)
result = tryReadingTypeField(c, n, i, ty.lastSon)
if result == nil:
result = tryReadingGenericParam(c, n, i, ty)
else:
@@ -1520,7 +1493,7 @@ proc builtinFieldAccess(c: PContext; n: PNode; flags: var TExprFlags): PNode =
return nil
if ty.kind in tyUserTypeClasses and ty.isResolvedUserTypeClass:
ty = ty.last
ty = ty.lastSon
ty = skipTypes(ty, {tyGenericInst, tyVar, tyLent, tyPtr, tyRef, tyOwned, tyAlias, tySink, tyStatic})
while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct, tyGenericInst, tyAlias})
var check: PNode = nil
@@ -1607,7 +1580,7 @@ proc semDeref(c: PContext, n: PNode): PNode =
result = n
var t = skipTypes(n[0].typ, {tyGenericInst, tyVar, tyLent, tyAlias, tySink, tyOwned})
case t.kind
of tyRef, tyPtr: n.typ = t.elementType
of tyRef, tyPtr: n.typ = t.lastSon
else: result = nil
#GlobalError(n[0].info, errCircumNeedsPointer)
@@ -1956,7 +1929,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
if c.p.owner.kind != skMacro and resultTypeIsInferrable(lhs.sym.typ):
var rhsTyp = rhs.typ
if rhsTyp.kind in tyUserTypeClasses and rhsTyp.isResolvedUserTypeClass:
rhsTyp = rhsTyp.last
rhsTyp = rhsTyp.lastSon
if lhs.sym.typ.kind == tyAnything:
rhsTyp = rhsTyp.skipIntLit(c.idgen)
if cmpTypes(c, lhs.typ, rhsTyp) in {isGeneric, isEqual}:
@@ -1965,7 +1938,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
typeAllowedCheck(c, n.info, rhsTyp, skResult)
lhs.typ = rhsTyp
c.p.resultSym.typ = rhsTyp
c.p.owner.typ.setReturnType rhsTyp
c.p.owner.typ[0] = rhsTyp
else:
typeMismatch(c.config, n.info, lhs.typ, rhsTyp, rhs)
borrowCheck(c, n, lhs, rhs)
@@ -2031,12 +2004,12 @@ proc semProcBody(c: PContext, n: PNode; expectedType: PType = nil): PNode =
if isEmptyType(result.typ):
# we inferred a 'void' return type:
c.p.resultSym.typ = errorType(c)
c.p.owner.typ.setReturnType nil
c.p.owner.typ[0] = nil
else:
localError(c.config, c.p.resultSym.info, errCannotInferReturnType %
c.p.owner.name.s)
if isIterator(c.p.owner.typ) and c.p.owner.typ.returnType != nil and
c.p.owner.typ.returnType.kind == tyAnything:
if isIterator(c.p.owner.typ) and c.p.owner.typ[0] != nil and
c.p.owner.typ[0].kind == tyAnything:
localError(c.config, c.p.owner.info, errCannotInferReturnType %
c.p.owner.name.s)
closeScope(c)
@@ -2076,10 +2049,12 @@ proc semYield(c: PContext, n: PNode): PNode =
if c.p.owner == nil or c.p.owner.kind != skIterator:
localError(c.config, n.info, errYieldNotAllowedHere)
elif n[0].kind != nkEmpty:
n[0] = semExprWithType(c, n[0]) # check for type compatibility:
var iterType = c.p.owner.typ
let restype = iterType[0]
n[0] = semExprWithType(c, n[0], {}, restype) # check for type compatibility:
if restype != nil:
if restype.kind != tyUntyped:
n[0] = fitNode(c, restype, n[0], n.info)
if n[0].typ == nil: internalError(c.config, n.info, "semYield")
if resultTypeIsInferrable(restype):
@@ -2087,13 +2062,11 @@ proc semYield(c: PContext, n: PNode): PNode =
iterType[0] = inferred
if c.p.resultSym != nil:
c.p.resultSym.typ = inferred
else:
n[0] = fitNode(c, restype, n[0], n.info)
semYieldVarResult(c, n, restype)
else:
localError(c.config, n.info, errCannotReturnExpr)
elif c.p.owner.typ.returnType != nil:
elif c.p.owner.typ[0] != nil:
localError(c.config, n.info, errGenerated, "yield statement must yield a value")
proc considerQuotedIdentOrDot(c: PContext, n: PNode, origin: PNode = nil): PIdent =
@@ -2200,7 +2173,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
let headSymbol = macroCall[0]
var cands = 0
var cand: PSym = nil
var o: TOverloadIter = default(TOverloadIter)
var o: TOverloadIter
var symx = initOverloadIter(o, c, headSymbol)
while symx != nil:
if symx.kind in {skTemplate, skMacro} and symx.typ.len == macroCall.len:
@@ -2420,7 +2393,7 @@ proc instantiateCreateFlowVarCall(c: PContext; t: PType;
let sym = magicsys.getCompilerProc(c.graph, "nimCreateFlowVar")
if sym == nil:
localError(c.config, info, "system needs: nimCreateFlowVar")
var bindings = initTypeMapping()
var bindings: TIdTable = initIdTable()
bindings.idTablePut(sym.ast[genericParamsPos][0].typ, t)
result = c.semGenerateInstance(c, sym, bindings, info)
# since it's an instantiation, we unmark it as a compilerproc. Otherwise
@@ -2450,7 +2423,9 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags; expectedType: P
of mAddr:
markUsed(c, n.info, s)
checkSonsLen(n, 2, c.config)
result = semAddr(c, n[1])
result[0] = newSymNode(s, n[0].info)
result[1] = semAddrArg(c, n[1])
result.typ = makePtrType(c, result[1].typ)
of mTypeOf:
markUsed(c, n.info, s)
result = semTypeOf(c, n)
@@ -2577,10 +2552,9 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
# If semCheck is set to false, ``when`` will return the verbatim AST of
# the correct branch. Otherwise the AST will be passed through semStmt.
result = nil
let flags = if semCheck: {efWantStmt} else: {}
template setResult(e: untyped) =
if semCheck: result = semExpr(c, e, flags) # do not open a new scope!
if semCheck: result = semExpr(c, e) # do not open a new scope!
else: result = e
# Check if the node is "when nimvm"
@@ -2606,7 +2580,7 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
checkSonsLen(it, 2, c.config)
if whenNimvm:
if semCheck:
it[1] = semExpr(c, it[1], flags)
it[1] = semExpr(c, it[1])
typ = commonType(c, typ, it[1].typ)
result = n # when nimvm is not elimited until codegen
else:
@@ -2622,7 +2596,7 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
checkSonsLen(it, 1, c.config)
if result == nil or whenNimvm:
if semCheck:
it[0] = semExpr(c, it[0], flags)
it[0] = semExpr(c, it[0])
typ = commonType(c, typ, it[0].typ)
if result == nil:
result = it[0]
@@ -2768,12 +2742,6 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType
# can check if field name matches expected type here
let expectedElemType = if expected != nil: expected[i] else: nil
n[i][1] = semExprWithType(c, n[i][1], {}, expectedElemType)
if expectedElemType != nil and
(expectedElemType.kind != tyNil and not hasEmpty(expectedElemType)):
# hasEmpty/nil check is to not break existing code like
# `const foo = [(1, {}), (2, {false})]`,
# `const foo = if true: (0, nil) else: (1, new(int))`
n[i][1] = fitNode(c, expectedElemType, n[i][1], n[i][1].info)
if n[i][1].typ.kind == tyTypeDesc:
localError(c.config, n[i][1].info, "typedesc not allowed as tuple field.")
@@ -2800,12 +2768,6 @@ proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedT
for i in 0..<n.len:
let expectedElemType = if expected != nil: expected[i] else: nil
n[i] = semExprWithType(c, n[i], {}, expectedElemType)
if expectedElemType != nil and
(expectedElemType.kind != tyNil and not hasEmpty(expectedElemType)):
# hasEmpty/nil check is to not break existing code like
# `const foo = [(1, {}), (2, {false})]`,
# `const foo = if true: (0, nil) else: (1, new(int))`
n[i] = fitNode(c, expectedElemType, n[i], n[i].info)
addSonSkipIntLit(typ, n[i].typ, c.idgen)
result.typ = typ
@@ -2861,7 +2823,7 @@ proc semExport(c: PContext, n: PNode): PNode =
result = newNodeI(nkExportStmt, n.info)
for i in 0..<n.len:
let a = n[i]
var o: TOverloadIter = default(TOverloadIter)
var o: TOverloadIter
var s = initOverloadIter(o, c, a)
if s == nil:
localError(c.config, a.info, errGenerated, "cannot export: " & renderTree(a))
@@ -2944,18 +2906,6 @@ proc asBracketExpr(c: PContext; n: PNode): PNode =
return result
return nil
proc isOpenArraySym(x: PNode): bool =
var x = x
while true:
case x.kind
of {nkAddr, nkHiddenAddr}:
x = x[0]
of {nkHiddenStdConv, nkHiddenDeref}:
x = x[1]
else:
break
result = x.kind == nkSym
proc hoistParamsUsedInDefault(c: PContext, call, letSection, defExpr: var PNode) =
# This takes care of complicated signatures such as:
# proc foo(a: int, b = a)
@@ -2976,10 +2926,7 @@ proc hoistParamsUsedInDefault(c: PContext, call, letSection, defExpr: var PNode)
if defExpr.kind == nkSym and defExpr.sym.kind == skParam and defExpr.sym.owner == call[0].sym:
let paramPos = defExpr.sym.position + 1
if call[paramPos].skipAddr.kind != nkSym and not (
skipTypes(call[paramPos].typ, abstractVar).kind in {tyOpenArray, tyVarargs} and
isOpenArraySym(call[paramPos])
):
if call[paramPos].skipAddr.kind != nkSym:
let hoistedVarSym = newSym(skLet, getIdent(c.graph.cache, genPrefix), c.idgen,
c.p.owner, letSection.info, c.p.owner.options)
hoistedVarSym.typ = call[paramPos].typ
@@ -3005,8 +2952,8 @@ proc getNilType(c: PContext): PType =
result.align = c.config.target.ptrSize.int16
c.nilTypeCache = result
proc enumFieldSymChoice(c: PContext, n: PNode, s: PSym; flags: TExprFlags): PNode =
var o: TOverloadIter = default(TOverloadIter)
proc enumFieldSymChoice(c: PContext, n: PNode, s: PSym): PNode =
var o: TOverloadIter
var i = 0
var a = initOverloadIter(o, c, n)
while a != nil:
@@ -3018,7 +2965,7 @@ proc enumFieldSymChoice(c: PContext, n: PNode, s: PSym; flags: TExprFlags): PNod
if i <= 1:
if sfGenSym notin s.flags:
result = newSymNode(s, info)
markUsed(c, info, s, efInCall notin flags)
markUsed(c, info, s)
onUse(info, s)
else:
result = n
@@ -3039,48 +2986,6 @@ proc semPragmaStmt(c: PContext; n: PNode) =
else:
pragma(c, c.p.owner, n, stmtPragmas, true)
proc resolveIdentToSym(c: PContext, n: PNode, resultNode: var PNode,
flags: TExprFlags, expectedType: PType): PSym =
# result is nil on error or if a node that can't produce a sym is resolved
let ident = considerQuotedIdent(c, n)
var filter = {low(TSymKind)..high(TSymKind)}
if efNoEvaluateGeneric in flags or expectedType != nil:
# `a[...]` where `a` is a module or package is not possible
filter.excl {skModule, skPackage}
let candidates = lookUpCandidates(c, ident, filter)
if candidates.len == 0:
result = errorUndeclaredIdentifierHint(c, ident, n.info)
elif candidates.len == 1 or {efNoEvaluateGeneric, efInCall} * flags != {}:
# unambiguous, or we don't care about ambiguity
result = candidates[0]
else:
# ambiguous symbols have 1 last chance as a symchoice,
# but type symbols cannot participate in symchoices
var choice = newNodeIT(nkClosedSymChoice, n.info, newTypeS(tyNone, c))
for c in candidates:
if c.kind notin {skType, skModule, skPackage}:
choice.add newSymNode(c, n.info)
if choice.len == 0:
# we know candidates.len > 1, we just couldn't put any in a symchoice
errorUseQualifier(c, n.info, candidates)
return nil
resolveSymChoice(c, choice, flags, expectedType)
# choice.len == 1 can be true here but as long as it's a symchoice
# it's still not resolved
if isSymChoice(choice):
result = nil
if efAllowSymChoice in flags:
resultNode = choice
else:
errorUseQualifier(c, n.info, candidates)
else:
if choice.kind == nkSym:
result = choice.sym
else:
# resolution could have generated nkHiddenStdConv etc
resultNode = semExpr(c, choice, flags, expectedType)
result = nil
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode =
when defined(nimCompilerStacktraceHints):
setFrameMsg c.config$n.info & " " & $n.kind
@@ -3118,10 +3023,25 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
if nfSem in n.flags: return
case n.kind
of nkIdent, nkAccQuoted:
let s = resolveIdentToSym(c, n, result, flags, expectedType)
var s: PSym = nil
if expectedType != nil and (
let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
expected.kind == tyEnum):
let nameId = considerQuotedIdent(c, n).id
for f in expected.n:
if f.kind == nkSym and f.sym.name.id == nameId:
s = f.sym
break
if s == nil:
# resolveIdentToSym either errored or gave a result node
return
let checks = if efNoEvaluateGeneric in flags:
{checkUndeclared, checkPureEnumFields}
elif efInCall in flags:
{checkUndeclared, checkModule, checkPureEnumFields}
else:
{checkUndeclared, checkModule, checkAmbiguity, checkPureEnumFields}
s = qualifiedLookUp(c, n, checks)
if s == nil:
return
if c.matchedConcept == nil: semCaptureSym(s, c.p.owner)
case s.kind
of skProc, skFunc, skMethod, skConverter, skIterator:
@@ -3135,7 +3055,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
if optOwnedRefs in c.config.globalOptions:
result.typ = makeVarType(c, result.typ, tyOwned)
of skEnumField:
result = enumFieldSymChoice(c, n, s, flags)
result = enumFieldSymChoice(c, n, s)
else:
result = semSym(c, n, s, flags)
if isSymChoice(result):
@@ -3143,32 +3063,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
of nkClosedSymChoice, nkOpenSymChoice:
result = semSymChoice(c, result, flags, expectedType)
of nkSym:
let s = n.sym
if nfOpenSym in n.flags:
let id = newIdentNode(s.name, n.info)
c.isAmbiguous = false
let s2 = qualifiedLookUp(c, id, {})
if s2 != nil and s2 != s and not c.isAmbiguous:
# only consider symbols defined under current proc:
var o = s2.owner
while o != nil:
if o == c.p.owner:
if genericsOpenSym in c.features:
result = semExpr(c, id, flags, expectedType)
return
else:
message(c.config, n.info, warnGenericsIgnoredInjection,
"a new symbol '" & s.name.s & "' has been injected during " &
"instantiation of " & c.p.owner.name.s & ", " &
"however " & getSymRepr(c.config, s) & " captured at " &
"the proc declaration will be used instead; " &
"either enable --experimental:genericsOpenSym to use the " &
"injected symbol or `bind` this captured symbol explicitly")
break
o = o.owner
# because of the changed symbol binding, this does not mean that we
# don't have to check the symbol for semantics here again!
result = semSym(c, n, s, flags)
result = semSym(c, n, n.sym, flags)
of nkEmpty, nkNone, nkCommentStmt, nkType:
discard
of nkNilLit:
@@ -3186,6 +3083,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
expected.kind in {tyInt..tyInt64,
tyUInt..tyUInt64,
tyFloat..tyFloat128}):
result.typ = expected
if expected.kind in {tyFloat..tyFloat128}:
n.transitionIntToFloatKind(nkFloatLit)
changeType(c, result, expectedType, check=true)
@@ -3234,7 +3132,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
let modifier = n.modifierTypeKindOfNode
if modifier != tyNone:
var baseType = semExpr(c, n[0]).typ.skipTypes({tyTypeDesc})
result.typ = c.makeTypeDesc(newTypeS(modifier, c, baseType))
result.typ = c.makeTypeDesc(c.newTypeWithSons(modifier, @[baseType]))
return
var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc})
result.typ = makeTypeDesc(c, typ)
@@ -3274,7 +3172,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
isSymChoice(n[0][0]):
# indirectOp can deal with explicit instantiations; the fixes
# the 'newSeq[T](x)' bug
setGenericParams(c, n[0], nil)
setGenericParams(c, n[0])
result = semDirectOp(c, n, flags, expectedType)
elif nfDotField in n.flags:
result = semDirectOp(c, n, flags, expectedType)
@@ -3343,7 +3241,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
of nkAddr:
result = n
checkSonsLen(n, 1, c.config)
result = semAddr(c, n[0])
result[0] = semAddrArg(c, n[0])
result.typ = makePtrType(c, result[0].typ)
of nkHiddenAddr, nkHiddenDeref:
checkSonsLen(n, 1, c.config)
n[0] = semExpr(c, n[0], flags, expectedType)

View File

@@ -64,12 +64,10 @@ type
proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) =
case typ.kind
of nkSym:
# either 'tup[i]' or 'field' is valid
var fc = TFieldInstCtx(
c: c.c,
field: typ.sym,
replaceByFieldName: c.m == mFieldPairs
)
var fc: TFieldInstCtx # either 'tup[i]' or 'field' is valid
fc.c = c.c
fc.field = typ.sym
fc.replaceByFieldName = c.m == mFieldPairs
openScope(c.c)
inc c.c.inUnrolledContext
let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop)
@@ -141,24 +139,25 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
var loopBody = n[^1]
for i in 0..<tupleTypeA.len:
openScope(c)
var fc = TFieldInstCtx(
tupleType: tupleTypeA,
tupleIndex: i,
c: c,
replaceByFieldName: m == mFieldPairs
)
var fc: TFieldInstCtx
fc.tupleType = tupleTypeA
fc.tupleIndex = i
fc.c = c
fc.replaceByFieldName = m == mFieldPairs
var body = instFieldLoopBody(fc, loopBody, n)
inc c.inUnrolledContext
stmts.add(semStmt(c, body, {}))
dec c.inUnrolledContext
closeScope(c)
else:
var fc = TFieldsCtx(m: m, c: c)
var fc: TFieldsCtx
fc.m = m
fc.c = c
var t = tupleTypeA
while t.kind == tyObject:
semForObjectFields(fc, t.n, n, stmts)
if t.baseClass == nil: break
t = skipTypes(t.baseClass, skipPtrs)
if t[0] == nil: break
t = skipTypes(t[0], skipPtrs)
c.p.breakInLoop = oldBreakInLoop
dec(c.p.nestedLoopCounter)
# for TR macros this 'while true: ...; break' loop is pretty bad, so

View File

@@ -122,10 +122,10 @@ proc ordinalValToString*(a: PNode; g: ModuleGraph): string =
result = $x
proc isFloatRange(t: PType): bool {.inline.} =
result = t.kind == tyRange and t.elementType.kind in {tyFloat..tyFloat128}
result = t.kind == tyRange and t[0].kind in {tyFloat..tyFloat128}
proc isIntRange(t: PType): bool {.inline.} =
result = t.kind == tyRange and t.elementType.kind in {
result = t.kind == tyRange and t[0].kind in {
tyInt..tyInt64, tyUInt8..tyUInt32}
proc pickIntRange(a, b: PType): PType =
@@ -307,9 +307,11 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; idgen: IdGenerator; g: ModuleGraph): P
of mRepr:
# BUGFIX: we cannot eval mRepr here for reasons that I forgot.
discard
of mIntToStr, mInt64ToStr: result = newStrNodeT($(getOrdValue(a)), n, g)
of mBoolToStr:
if getOrdValue(a) == 0: result = newStrNodeT("false", n, g)
else: result = newStrNodeT("true", n, g)
of mFloatToStr: result = newStrNodeT($getFloat(a), n, g)
of mCStrToStr, mCharToStr:
result = newStrNodeT(getStrOrChar(a), n, g)
of mStrToStr: result = newStrNodeT(getStrOrChar(a), n, g)
@@ -771,8 +773,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
of nkCast:
var a = getConstExpr(m, n[1], idgen, g)
if a == nil: return
if n.typ != nil and n.typ.kind in NilableTypes and
not (n.typ.kind == tyProc and a.typ.kind == tyProc):
if n.typ != nil and n.typ.kind in NilableTypes:
# we allow compile-time 'cast' for pointer types:
result = a
result.typ = n.typ

View File

@@ -56,9 +56,6 @@ template isMixedIn(sym): bool =
s.magic == mNone and
s.kind in OverloadableSyms)
template canOpenSym(s): bool =
{withinMixin, withinConcept} * flags == {withinMixin} and s.id notin ctx.toBind
proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
ctx: var GenericCtx; flags: TSemGenericFlags,
fromDotExpr=false): PNode =
@@ -72,9 +69,6 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
result.transitionSonsKind(nkClosedSymChoice)
else:
result = symChoice(c, n, s, scOpen)
if result.kind == nkSym and canOpenSym(result.sym):
result.flags.incl nfOpenSym
result.typ = nil
case s.kind
of skUnknown:
# Introduced in this pass! Leave it as an identifier.
@@ -102,9 +96,6 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
result = n
else:
result = newSymNodeTypeDesc(s, c.idgen, n.info)
if canOpenSym(result.sym):
result.flags.incl nfOpenSym
result.typ = nil
onUse(n.info, s)
of skParam:
result = n
@@ -113,17 +104,11 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
if (s.typ != nil) and
(s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} == {}):
result = newSymNodeTypeDesc(s, c.idgen, n.info)
if canOpenSym(result.sym):
result.flags.incl nfOpenSym
result.typ = nil
else:
result = n
onUse(n.info, s)
else:
result = newSymNode(s, n.info)
if canOpenSym(result.sym):
result.flags.incl nfOpenSym
result.typ = nil
onUse(n.info, s)
proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
@@ -163,7 +148,6 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
var s = qualifiedLookUp(c, n, luf)
if s != nil:
isMacro = s.kind in {skTemplate, skMacro}
result = semGenericStmtSymbol(c, n, s, ctx, flags)
else:
n[0] = semGenericStmt(c, n[0], flags, ctx)
@@ -237,7 +221,7 @@ proc semGenericStmt(c: PContext, n: PNode,
#var s = qualifiedLookUp(c, n, luf)
#if s != nil: result = semGenericStmtSymbol(c, n, s)
# XXX for example: ``result.add`` -- ``add`` needs to be looked up here...
var dummy: bool = false
var dummy: bool
result = fuzzyLookup(c, n, flags, ctx, dummy)
of nkSym:
let a = n.sym
@@ -591,18 +575,16 @@ proc semGenericStmt(c: PContext, n: PNode,
if withinTypeDesc in flags: dec c.inTypeContext
proc semGenericStmt(c: PContext, n: PNode): PNode =
var ctx = GenericCtx(
toMixin: initIntSet(),
toBind: initIntSet()
)
var ctx: GenericCtx
ctx.toMixin = initIntSet()
ctx.toBind = initIntSet()
result = semGenericStmt(c, n, {}, ctx)
semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)
proc semConceptBody(c: PContext, n: PNode): PNode =
var ctx = GenericCtx(
toMixin: initIntSet(),
toBind: initIntSet()
)
var ctx: GenericCtx
ctx.toMixin = initIntSet()
ctx.toBind = initIntSet()
result = semGenericStmt(c, n, {withinConcept}, ctx)
semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)

View File

@@ -34,7 +34,7 @@ proc pushProcCon*(c: PContext; owner: PSym) =
const
errCannotInstantiateX = "cannot instantiate: '$1'"
iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TypeMapping): PSym =
iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym =
internalAssert c.config, n.kind == nkGenericParams
for a in n.items:
internalAssert c.config, a.kind == nkSym
@@ -43,7 +43,7 @@ iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TypeMapping): PS
let symKind = if q.typ.kind == tyStatic: skConst else: skType
var s = newSym(symKind, q.name, c.idgen, getCurrOwner(c), q.info)
s.flags.incl {sfUsed, sfFromGeneric}
var t = idTableGet(pt, q.typ)
var t = PType(idTableGet(pt, q.typ))
if t == nil:
if tfRetType in q.typ.flags:
# keep the generic type and allow the return type to be bound
@@ -56,15 +56,6 @@ iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TypeMapping): PS
elif t.kind in {tyGenericParam, tyConcept}:
localError(c.config, a.info, errCannotInstantiateX % q.name.s)
t = errorType(c)
elif isUnresolvedStatic(t) and (q.typ.kind == tyStatic or
(q.typ.kind == tyGenericParam and
q.typ.genericParamHasConstraints and
q.typ.genericConstraint.kind == tyStatic)) and
c.inGenericContext == 0 and c.matchedConcept == nil:
# generic/concept type bodies will try to instantiate static values but
# won't actually use them
localError(c.config, a.info, errCannotInstantiateX % q.name.s)
t = errorType(c)
elif t.kind == tyGenericInvocation:
#t = instGenericContainer(c, a, t)
t = generateTypeInstance(c, pt, a, t)
@@ -95,7 +86,7 @@ when false:
proc `$`(x: PSym): string =
result = x.name.s & " " & " id " & $x.id
proc freshGenSyms(c: PContext; n: PNode, owner, orig: PSym, symMap: var SymMapping) =
proc freshGenSyms(c: PContext; n: PNode, owner, orig: PSym, symMap: var TIdTable) =
# we need to create a fresh set of gensym'ed symbols:
#if n.kind == nkSym and sfGenSym in n.sym.flags:
# if n.sym.owner != orig:
@@ -103,7 +94,7 @@ proc freshGenSyms(c: PContext; n: PNode, owner, orig: PSym, symMap: var SymMappi
if n.kind == nkSym and sfGenSym in n.sym.flags: # and
# (n.sym.owner == orig or n.sym.owner.kind in {skPackage}):
let s = n.sym
var x = idTableGet(symMap, s)
var x = PSym(idTableGet(symMap, s))
if x != nil:
n.sym = x
elif s.owner == nil or s.owner.kind == skPackage:
@@ -127,7 +118,7 @@ proc instantiateBody(c: PContext, n, params: PNode, result, orig: PSym) =
inc c.inGenericInst
# add it here, so that recursive generic procs are possible:
var b = n[bodyPos]
var symMap = initSymMapping()
var symMap: TIdTable = initIdTable()
if params != nil:
for i in 1..<params.len:
let param = params[i].sym
@@ -142,7 +133,7 @@ proc instantiateBody(c: PContext, n, params: PNode, result, orig: PSym) =
if result.kind == skMacro:
sysTypeFromName(c.graph, n.info, "NimNode")
elif not isInlineIterator(result.typ):
result.typ.returnType
result.typ[0]
else:
nil
b = semProcBody(c, b, resultType)
@@ -177,12 +168,12 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
allowMetaTypes = false): PType =
internalAssert c.config, header.kind == tyGenericInvocation
var cl: TReplTypeVars = TReplTypeVars(symMap: initSymMapping(),
localCache: initTypeMapping(), typeMap: LayeredIdTable(),
var cl: TReplTypeVars = TReplTypeVars(symMap: initIdTable(),
localCache: initIdTable(), typeMap: LayeredIdTable(),
info: info, c: c, allowMetaTypes: allowMetaTypes
)
cl.typeMap.topLayer = initTypeMapping()
cl.typeMap.topLayer = initIdTable()
# We must add all generic params in scope, because the generic body
# may include tyFromExpr nodes depending on these generic params.
@@ -190,7 +181,8 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
# perhaps the code can be extracted in a shared function.
openScope(c)
let genericTyp = header.base
for i, genParam in genericBodyParams(genericTyp):
for i in 0..<genericTyp.len - 1:
let genParam = genericTyp[i]
var param: PSym
template paramSym(kind): untyped =
@@ -220,7 +212,7 @@ proc referencesAnotherParam(n: PNode, p: PSym): bool =
if referencesAnotherParam(n[i], p): return true
return false
proc instantiateProcType(c: PContext, pt: TypeMapping,
proc instantiateProcType(c: PContext, pt: TIdTable,
prc: PSym, info: TLineInfo) =
# XXX: Instantiates a generic proc signature, while at the same
# time adding the instantiated proc params into the current scope.
@@ -242,18 +234,18 @@ proc instantiateProcType(c: PContext, pt: TypeMapping,
var result = instCopyType(cl, prc.typ)
let originalParams = result.n
result.n = originalParams.shallowCopy
for i, resulti in paramTypes(result):
for i in 1..<result.len:
# twrong_field_caching requires these 'resetIdTable' calls:
if i > FirstParamAt:
if i > 1:
resetIdTable(cl.symMap)
resetIdTable(cl.localCache)
# take a note of the original type. If't a free type or static parameter
# we'll need to keep it unbound for the `fitNode` operation below...
var typeToFit = resulti
var typeToFit = result[i]
let needsStaticSkipping = resulti.kind == tyFromExpr
result[i] = replaceTypeVarsT(cl, resulti)
let needsStaticSkipping = result[i].kind == tyFromExpr
result[i] = replaceTypeVarsT(cl, result[i])
if needsStaticSkipping:
result[i] = result[i].skipTypes({tyStatic})
@@ -303,7 +295,7 @@ proc instantiateProcType(c: PContext, pt: TypeMapping,
resetIdTable(cl.symMap)
resetIdTable(cl.localCache)
cl.isReturnType = true
result.setReturnType replaceTypeVarsT(cl, result.returnType)
result[0] = replaceTypeVarsT(cl, result[0])
cl.isReturnType = false
result.n[0] = originalParams[0].copyTree
if result[0] != nil:
@@ -323,9 +315,8 @@ proc fillMixinScope(c: PContext) =
addSym(c.currentScope, n.sym)
p = p.next
proc getLocalPassC(c: PContext, s: PSym): string =
when defined(nimsuggest): return ""
if s.ast == nil or s.ast.len == 0: return ""
proc getLocalPassC(c: PContext, s: PSym): string =
if s.ast == nil or s.ast.len == 0: return ""
result = ""
template extractPassc(p: PNode) =
if p.kind == nkPragma and p[0][0].ident == c.cache.getIdent"localpassc":
@@ -334,8 +325,8 @@ proc getLocalPassC(c: PContext, s: PSym): string =
for n in s.ast:
for p in n:
extractPassc(p)
proc generateInstance(c: PContext, fn: PSym, pt: TypeMapping,
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
info: TLineInfo): PSym =
## Generates a new instance of a generic procedure.
## The `pt` parameter is a type-unsafe mapping table used to link generic
@@ -363,7 +354,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TypeMapping,
let passc = getLocalPassC(c, producer)
if passc != "": #pass the local compiler options to the consumer module too
extccomp.addLocalCompileOption(c.config, passc, toFullPathConsiderDirty(c.config, c.module.info.fileIndex))
result.owner = c.module
result.owner = c.module
else:
result.owner = fn
result.ast = n
@@ -386,20 +377,16 @@ proc generateInstance(c: PContext, fn: PSym, pt: TypeMapping,
# generic[void](), generic[int]()
# see ttypeor.nim test.
var i = 0
newSeq(entry.concreteTypes, fn.typ.paramsLen+gp.len)
# let param instantiation know we are in a concept for unresolved statics:
c.matchedConcept = oldMatchedConcept
newSeq(entry.concreteTypes, fn.typ.len+gp.len-1)
for s in instantiateGenericParamList(c, gp, pt):
addDecl(c, s)
entry.concreteTypes[i] = s.typ
inc i
c.matchedConcept = nil
pushProcCon(c, result)
instantiateProcType(c, pt, result, info)
for _, param in paramTypes(result.typ):
entry.concreteTypes[i] = param
for j in 1..<result.typ.len:
entry.concreteTypes[i] = result.typ[j]
inc i
#echo "INSTAN ", fn.name.s, " ", typeToString(result.typ), " ", entry.concreteTypes.len
if tfTriggersCompileTime in result.typ.flags:
incl(result.flags, sfCompileTime)
n[genericParamsPos] = c.graph.emptyNode
@@ -428,9 +415,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TypeMapping,
if result.magic notin {mSlice, mTypeOf}:
# 'toOpenArray' is special and it is allowed to return 'openArray':
paramsTypeCheck(c, result.typ)
#echo "INSTAN ", fn.name.s, " ", typeToString(result.typ), " <-- NEW PROC!", " ", entry.concreteTypes.len
else:
#echo "INSTAN ", fn.name.s, " ", typeToString(result.typ), " <-- CACHED! ", typeToString(oldPrc.typ), " ", entry.concreteTypes.len
result = oldPrc
popProcCon(c)
popInfoContext(c.config)

View File

@@ -35,12 +35,12 @@ proc ithField(n: PNode, field: var int): PSym =
else: discard
proc ithField(t: PType, field: var int): PSym =
var base = t.baseClass
var base = t[0]
while base != nil:
let b = skipTypes(base, skipPtrs)
result = ithField(b.n, field)
if result != nil: return result
base = b.baseClass
base = b[0]
result = ithField(t.n, field)
proc annotateType*(n: PNode, t: PType; conf: ConfigRef) =
@@ -63,7 +63,7 @@ proc annotateType*(n: PNode, t: PType; conf: ConfigRef) =
if x.kind == tyTuple:
n.typ = t
for i in 0..<n.len:
if i >= x.kidsLen: globalError conf, n.info, "invalid field at index " & $i
if i >= x.len: globalError conf, n.info, "invalid field at index " & $i
else: annotateType(n[i], x[i], conf)
elif x.kind == tyProc and x.callConv == ccClosure:
n.typ = t
@@ -78,11 +78,11 @@ proc annotateType*(n: PNode, t: PType; conf: ConfigRef) =
of nkStrKinds:
for i in left..right:
bracketExpr.add newIntNode(nkCharLit, BiggestInt n[0].strVal[i])
annotateType(bracketExpr[^1], x.elementType, conf)
annotateType(bracketExpr[^1], t[0], conf)
of nkBracket:
for i in left..right:
bracketExpr.add n[0][i]
annotateType(bracketExpr[^1], x.elementType, conf)
annotateType(bracketExpr[^1], t[0], conf)
else:
globalError(conf, n.info, "Incorrectly generated tuple constr")
n[] = bracketExpr[]

View File

@@ -22,7 +22,7 @@ proc addDefaultFieldForNew(c: PContext, n: PNode): PNode =
var t = typ.skipTypes({tyGenericInst, tyAlias, tySink})[0]
while true:
asgnExpr.sons.add defaultFieldsForTheUninitialized(c, t.n, false)
let base = t.baseClass
let base = t[0]
if base == nil:
break
t = skipTypes(base, skipPtrs)
@@ -30,15 +30,13 @@ proc addDefaultFieldForNew(c: PContext, n: PNode): PNode =
if asgnExpr.sons.len > 1:
result = newTree(nkAsgn, result[1], asgnExpr)
proc semAddr(c: PContext; n: PNode): PNode =
result = newNodeI(nkAddr, n.info)
proc semAddrArg(c: PContext; n: PNode): PNode =
let x = semExprWithType(c, n)
if x.kind == nkSym:
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)
result = x
proc semTypeOf(c: PContext; n: PNode): PNode =
var m = BiggestInt 1 # typeOfIter
@@ -73,7 +71,7 @@ proc semArrGet(c: PContext; n: PNode; flags: TExprFlags): PNode =
proc semArrPut(c: PContext; n: PNode; flags: TExprFlags): PNode =
# rewrite `[]=`(a, i, x) back to ``a[i] = x``.
let b = newNodeI(nkBracketExpr, n.info)
b.add(n[1].skipHiddenAddr)
b.add(n[1].skipAddr)
for i in 2..<n.len-1: b.add(n[i])
result = newNodeI(nkAsgn, n.info, 2)
result[0] = b
@@ -134,7 +132,7 @@ proc uninstantiate(t: PType): PType =
result = case t.kind
of tyMagicGenerics: t
of tyUserDefinedGenerics: t.base
of tyCompositeTypeClass: uninstantiate t.firstGenericParam
of tyCompositeTypeClass: uninstantiate t[1]
else: t
proc getTypeDescNode(c: PContext; typ: PType, sym: PSym, info: TLineInfo): PNode =
@@ -142,14 +140,6 @@ proc getTypeDescNode(c: PContext; typ: PType, sym: PSym, info: TLineInfo): PNode
rawAddSon(resType, typ)
result = toNode(resType, info)
proc buildBinaryPredicate(kind: TTypeKind; c: PContext; context: PSym; a, b: sink PType): PType =
result = newType(kind, c.idgen, context)
result.rawAddSon a
result.rawAddSon b
proc buildNotPredicate(c: PContext; context: PSym; a: sink PType): PType =
result = newType(tyNot, c.idgen, context, a)
proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym): PNode =
const skippedTypes = {tyTypeDesc, tyAlias, tySink}
let trait = traitCall[0]
@@ -159,17 +149,20 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym)
template operand2: PType =
traitCall[2].typ.skipTypes({tyTypeDesc})
template typeWithSonsResult(kind, sons): PNode =
newTypeWithSons(context, kind, sons, c.idgen).toNode(traitCall.info)
if operand.kind == tyGenericParam or (traitCall.len > 2 and operand2.kind == tyGenericParam):
return traitCall ## too early to evaluate
let s = trait.sym.name.s
case s
of "or", "|":
return buildBinaryPredicate(tyOr, c, context, operand, operand2).toNode(traitCall.info)
return typeWithSonsResult(tyOr, @[operand, operand2])
of "and":
return buildBinaryPredicate(tyAnd, c, context, operand, operand2).toNode(traitCall.info)
return typeWithSonsResult(tyAnd, @[operand, operand2])
of "not":
return buildNotPredicate(c, context, operand).toNode(traitCall.info)
return typeWithSonsResult(tyNot, @[operand])
of "typeToString":
var prefer = preferTypeName
if traitCall.len >= 2:
@@ -237,7 +230,7 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym)
proc semTypeTraits(c: PContext, n: PNode): PNode =
checkMinSonsLen(n, 2, c.config)
let t = n[1].typ
internalAssert c.config, t != nil and t.skipTypes({tyAlias}).kind == tyTypeDesc
internalAssert c.config, t != nil and t.kind == tyTypeDesc
if t.len > 0:
# This is either a type known to sem or a typedesc
# param to a regular proc (again, known at instantiation)
@@ -400,7 +393,7 @@ proc semUnown(c: PContext; n: PNode): PNode =
for e in elems: result.rawAddSon(e)
else:
result = t
of tyOwned: result = t.elementType
of tyOwned: result = t[0]
of tySequence, tyOpenArray, tyArray, tyVarargs, tyVar, tyLent,
tyGenericInst, tyAlias:
let b = unownedType(c, t[^1])
@@ -440,7 +433,7 @@ proc turnFinalizerIntoDestructor(c: PContext; orig: PSym; info: TLineInfo): PSym
result.info = info
result.flags.incl sfFromGeneric
result.owner = orig
let origParamType = orig.typ.firstParamType
let origParamType = orig.typ[1]
let newParamType = makeVarType(result, origParamType.skipTypes(abstractPtrs), c.idgen)
let oldParam = orig.typ.n[1].sym
let newParam = newSym(skParam, oldParam.name, c.idgen, result, result.info)
@@ -504,7 +497,7 @@ proc semNewFinalize(c: PContext; n: PNode): PNode =
localError(c.config, n.info, "finalizer must be a direct reference to a proc")
# check if we converted this finalizer into a destructor already:
let t = whereToBindTypeHook(c, fin.typ.firstParamType.skipTypes(abstractInst+{tyRef}))
let t = whereToBindTypeHook(c, fin.typ[1].skipTypes(abstractInst+{tyRef}))
if t != nil and getAttachedOp(c.graph, t, attachedDestructor) != nil and
getAttachedOp(c.graph, t, attachedDestructor).owner == fin:
discard "already turned this one into a finalizer"
@@ -513,13 +506,13 @@ proc semNewFinalize(c: PContext; n: PNode): PNode =
fin.owner = fin.instantiatedFrom
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
selfSymNode.typ = fin.typ[1]
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,
newTree(nkIdentDefs, selfSymNode, newNodeIT(nkType,
fin.ast[paramsPos][1][1].info, fin.typ.firstParamType), c.graph.emptyNode)
fin.ast[paramsPos][1][1].info, fin.typ[1]), c.graph.emptyNode)
),
name = newSymNode(wrapperSym), pattern = fin.ast[patternPos],
genericParams = fin.ast[genericParamsPos], pragmas = fin.ast[pragmasPos], exceptions = fin.ast[miscPos]), {})
@@ -539,7 +532,7 @@ proc semNewFinalize(c: PContext; n: PNode): PNode =
result = addDefaultFieldForNew(c, n)
proc semPrivateAccess(c: PContext, n: PNode): PNode =
let t = n[1].typ.elementType.toObjectFromRefPtrGeneric
let t = n[1].typ[0].toObjectFromRefPtrGeneric
if t.kind == tyObject:
assert t.sym != nil
c.currentScope.allowPrivateAccess.add t.sym
@@ -563,7 +556,9 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
case n[0].sym.magic
of mAddr:
checkSonsLen(n, 2, c.config)
result = semAddr(c, n[1])
result = n
result[1] = semAddrArg(c, n[1])
result.typ = makePtrType(c, result[1].typ)
of mTypeOf:
result = semTypeOf(c, n)
of mSizeOf:
@@ -623,7 +618,8 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
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 op.typ != nil and op.typ.len == 2 and op.typ[1].kind != tyVar:
if n[1].kind == nkSym and n[1].sym.kind == skParam and
n[1].typ.kind == tyVar:
result[1] = genDeref(n[1])
@@ -635,16 +631,6 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
let op = getAttachedOp(c.graph, t, attachedTrace)
if op != nil:
result[0] = newSymNode(op)
of mDup:
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 = n
let t = n[1].typ.skipTypes(abstractVar)
@@ -683,8 +669,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
result = semPrivateAccess(c, n)
of mArrToSeq:
result = n
if result.typ != nil and expectedType != nil and result.typ.kind == tySequence and
expectedType.kind == tySequence and result.typ.elementType.kind == tyEmpty:
if result.typ != nil and expectedType != nil and result.typ.kind == tySequence and expectedType.kind == tySequence and result.typ[0].kind == tyEmpty:
result.typ = expectedType # type inference for empty sequence # bug #21377
of mEnsureMove:
result = n

View File

@@ -405,7 +405,7 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
proc semConstructTypeAux(c: PContext,
constrCtx: var ObjConstrContext,
flags: TExprFlags): tuple[status: InitStatus, defaults: seq[PNode]] =
result = (initUnknown, @[])
result.status = initUnknown
var t = constrCtx.typ
while true:
let (status, defaults) = semConstructFields(c, t.n, constrCtx, flags)
@@ -413,10 +413,10 @@ proc semConstructTypeAux(c: PContext,
result.defaults.add defaults
if status in {initPartial, initNone, initUnknown}:
discard collectMissingFields(c, t.n, constrCtx, result.defaults)
let base = t.baseClass
let base = t[0]
if base == nil or base.id == t.id or
base.kind in {tyRef, tyPtr} and base.elementType.id == t.id:
break
base.kind in {tyRef, tyPtr} and base[0].id == t.id:
break
t = skipTypes(base, skipPtrs)
if t.kind != tyObject:
# XXX: This is not supposed to happen, but apparently
@@ -439,7 +439,7 @@ proc computeRequiresInit(c: PContext, t: PType): bool =
proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) =
var objType = t
while objType.kind notin {tyObject, tyDistinct}:
objType = objType.last
objType = objType.lastSon
assert objType != nil
if objType.kind == tyObject:
var constrCtx = initConstrContext(objType, newNodeI(nkObjConstr, info))
@@ -470,7 +470,7 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
t = skipTypes(t, {tyGenericInst, tyAlias, tySink, tyOwned})
if t.kind == tyRef:
t = skipTypes(t.elementType, {tyGenericInst, tyAlias, tySink, tyOwned})
t = skipTypes(t[0], {tyGenericInst, tyAlias, tySink, tyOwned})
if optOwnedRefs in c.config.globalOptions:
result.typ = makeVarType(c, result.typ, tyOwned)
# we have to watch out, there are also 'owned proc' types that can be used
@@ -478,7 +478,7 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
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))
"object constructor needs an object type".dup(addDeclaredLoc(c.config, t))
else: "cannot instantiate: '" &
typeToString(t, preferDesc) &
"'; the object's generic parameters cannot be inferred and must be explicitly given"

View File

@@ -77,12 +77,12 @@ type
graph: ModuleGraph
proc initAnalysisCtx(g: ModuleGraph): AnalysisCtx =
result = AnalysisCtx(locals: @[],
slices: @[],
args: @[],
graph: g)
result.locals = @[]
result.slices = @[]
result.args = @[]
result.guards.s = @[]
result.guards.g = g
result.graph = g
proc lookupSlot(c: AnalysisCtx; s: PSym): int =
for i in 0..<c.locals.len:
@@ -406,7 +406,7 @@ proc transformSlices(g: ModuleGraph; idgen: IdGenerator; n: PNode): PNode =
if op.name.s == "[]" and op.fromSystem:
result = copyNode(n)
var typ = newType(tyOpenArray, idgen, result.typ.owner)
typ.add result.typ.elementType
typ.add result.typ[0]
result.typ = typ
let opSlice = newSymNode(createMagic(g, idgen, "slice", mSlice))
opSlice.typ = getSysType(g, n.info, tyInt)
@@ -441,7 +441,7 @@ proc transformSpawn(g: ModuleGraph; idgen: IdGenerator; owner: PSym; n, barrier:
if result.isNil:
result = newNodeI(nkStmtList, n.info)
result.add n
let t = b[1][0].typ.returnType
let t = b[1][0].typ[0]
if spawnResult(t, true) == srByVar:
result.add wrapProcForSpawn(g, idgen, owner, m, b.typ, barrier, it[0])
it[^1] = newNodeI(nkEmpty, it.info)
@@ -450,7 +450,7 @@ proc transformSpawn(g: ModuleGraph; idgen: IdGenerator; owner: PSym; n, barrier:
if result.isNil: result = n
of nkAsgn, nkFastAsgn, nkSinkAsgn:
let b = n[1]
if getMagic(b) == mSpawn and (let t = b[1][0].typ.returnType;
if getMagic(b) == mSpawn and (let t = b[1][0].typ[0];
spawnResult(t, true) == srByVar):
let m = transformSlices(g, idgen, b)
return wrapProcForSpawn(g, idgen, owner, m, b.typ, barrier, n[0])

View File

@@ -11,9 +11,9 @@ import
ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
wordrecg, options, guards, lineinfos, semfold, semdata,
modulegraphs, varpartitions, typeallowed, nilcheck, errorhandling,
semstrictfuncs, suggestsymdb
semstrictfuncs
import std/[tables, intsets, strutils, sequtils]
import std/[tables, intsets, strutils]
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -24,6 +24,9 @@ when defined(useDfa):
import liftdestructors
include sinkparameter_inference
import std/options as opt
#[ Second semantic checking pass over the AST. Necessary because the old
way had some inherent problems. Performs:
@@ -66,12 +69,8 @@ discard """
"""
type
CaughtExceptionsStack = object
nodes: seq[seq[PType]]
TEffects = object
exc: PNode # stack of exceptions
when defined(nimsuggest):
caughtExceptions: CaughtExceptionsStack
tags: PNode # list of tags
forbids: PNode # list of tags
bottom, inTryStmt, inExceptOrFinallyStmt, leftPartOfAsgn, inIfStmt, currentBlock: int
@@ -95,26 +94,29 @@ const
errXCannotBeAssignedTo = "'$1' cannot be assigned to"
errLetNeedsInit = "'let' symbol requires an initialization"
proc getObjDepth(t: PType): (int, ItemId) =
proc getObjDepth(t: PType): Option[tuple[depth: int, root: ItemId]] =
var x = t
result = (-1, default(ItemId))
var res: tuple[depth: int, root: ItemId]
res.depth = -1
var stack = newSeq[ItemId]()
while x != nil:
x = skipTypes(x, skipPtrs)
if x.kind != tyObject:
return (-3, default(ItemId))
return none(tuple[depth: int, root: ItemId])
stack.add x.itemId
x = x.baseClass
inc(result[0])
result[1] = stack[^2]
x = x[0]
inc(res.depth)
res.root = stack[^2]
result = some(res)
proc collectObjectTree(graph: ModuleGraph, n: PNode) =
for section in n:
if section.kind == nkTypeDef and section[^1].kind in {nkObjectTy, nkRefTy, nkPtrTy} and section[^1].typ != nil:
if section.kind == nkTypeDef and section[^1].kind in {nkObjectTy, nkRefTy, nkPtrTy}:
let typ = section[^1].typ.skipTypes(skipPtrs)
if typ.kind == tyObject and typ.baseClass != nil:
let (depthLevel, root) = getObjDepth(typ)
if depthLevel != -3:
if typ.len > 0 and typ[0] != nil:
let depthItem = getObjDepth(typ)
if isSome(depthItem):
let (depthLevel, root) = depthItem.unsafeGet
if depthLevel == 1:
graph.objectTree[root] = @[]
else:
@@ -415,7 +417,7 @@ proc throws(tracked, n, orig: PNode) =
else:
tracked.add n
proc getEbase*(g: ModuleGraph; info: TLineInfo): PType =
proc getEbase(g: ModuleGraph; info: TLineInfo): PType =
result = g.sysTypeFromName(info, "Exception")
proc excType(g: ModuleGraph; n: PNode): PType =
@@ -496,18 +498,6 @@ proc catchesAll(tracked: PEffects) =
if tracked.exc.len > 0:
setLen(tracked.exc.sons, tracked.bottom)
proc push(s: var CaughtExceptionsStack) =
s.nodes.add(@[])
proc pop(s: var CaughtExceptionsStack) =
s.nodes.del(high(s.nodes))
proc addCatch(s: var CaughtExceptionsStack, e: PType) =
s.nodes[high(s.nodes)].add(e)
proc addCatchAll(s: var CaughtExceptionsStack) =
s.nodes[high(s.nodes)].add(nil)
proc track(tracked: PEffects, n: PNode)
proc trackTryStmt(tracked: PEffects, n: PNode) =
let oldBottom = tracked.bottom
@@ -516,33 +506,12 @@ proc trackTryStmt(tracked: PEffects, n: PNode) =
let oldState = tracked.init.len
var inter: TIntersection = @[]
when defined(nimsuggest):
tracked.caughtExceptions.push
for i in 1..<n.len:
let b = n[i]
if b.kind == nkExceptBranch:
if b.len == 1:
tracked.caughtExceptions.addCatchAll
else:
for j in 0..<b.len - 1:
if b[j].isInfixAs():
assert(b[j][1].kind == nkType)
tracked.caughtExceptions.addCatch(b[j][1].typ)
else:
assert(b[j].kind == nkType)
tracked.caughtExceptions.addCatch(b[j].typ)
else:
assert b.kind == nkFinally
inc tracked.inTryStmt
track(tracked, n[0])
dec tracked.inTryStmt
for i in oldState..<tracked.init.len:
addToIntersection(inter, tracked.init[i], bsNone)
when defined(nimsuggest):
tracked.caughtExceptions.pop
var branches = 1
var hasFinally = false
inc tracked.inExceptOrFinallyStmt
@@ -656,7 +625,7 @@ proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
if paramType != nil and tfNotNil in paramType.flags and n.typ != nil:
let ntyp = n.typ.skipTypesOrNil({tyVar, tyLent, tySink})
if ntyp != nil and tfNotNil notin ntyp.flags:
if n.kind in {nkAddr, nkHiddenAddr}:
if isAddrNode(n):
# addr(x[]) can't be proven, but addr(x) can:
if not containsNode(n, {nkDerefExpr, nkHiddenDeref}): return
elif (n.kind == nkSym and n.sym.kind in routineKinds) or
@@ -697,7 +666,7 @@ proc isTrival(caller: PNode): bool {.inline.} =
proc trackOperandForIndirectCall(tracked: PEffects, n: PNode, formals: PType; argIndex: int; caller: PNode) =
let a = skipConvCastAndClosure(n)
let op = a.typ
let param = if formals != nil and formals.n != nil and argIndex < formals.n.len: formals.n[argIndex].sym else: nil
let param = if formals != nil and argIndex < formals.len and formals.n != nil: 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 isTrival(caller) and
@@ -732,7 +701,7 @@ proc trackOperandForIndirectCall(tracked: PEffects, n: PNode, formals: PType; ar
markGcUnsafe(tracked, a)
elif tfNoSideEffect notin op.flags:
markSideEffect(tracked, a, n.info)
let paramType = if formals != nil and argIndex < formals.signatureLen: formals[argIndex] else: nil
let paramType = if formals != nil and argIndex < formals.len: formals[argIndex] else: nil
if paramType != nil and paramType.kind in {tyVar}:
invalidateFacts(tracked.guards, n)
if n.kind == nkSym and isLocalSym(tracked, n.sym):
@@ -788,7 +757,7 @@ proc addIdToIntersection(tracked: PEffects, inter: var TIntersection, resCounter
template hasResultSym(s: PSym): bool =
s != nil and s.kind in {skProc, skFunc, skConverter, skMethod} and
not isEmptyType(s.typ.returnType)
not isEmptyType(s.typ[0])
proc trackCase(tracked: PEffects, n: PNode) =
track(tracked, n[0])
@@ -954,19 +923,6 @@ proc checkForSink(tracked: PEffects; n: PNode) =
if tracked.inIfStmt == 0 and optSinkInference in tracked.config.options:
checkForSink(tracked.config, tracked.c.idgen, tracked.owner, n)
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)
if si != -1:
q.caughtExceptionsSet[si] = true
for w1 in tracked.caughtExceptions.nodes:
for w2 in w1:
q.caughtExceptions[si].add(w2)
if optIdeExceptionInlayHints in tracked.config.globalOptions:
internalMarkCaughtExceptions(tracked, g.suggestSymbols.mgetOrPut(info.fileIndex, newSuggestFileSymbolDatabase(info.fileIndex, true)), info)
proc trackCall(tracked: PEffects; n: PNode) =
template gcsafeAndSideeffectCheck() =
if notGcSafe(op) and not importedFromC(a):
@@ -987,13 +943,6 @@ proc trackCall(tracked: PEffects; n: PNode) =
if tracked.owner.kind != skMacro and n.typ.skipTypes(abstractVar).kind != tyOpenArray:
createTypeBoundOps(tracked, n.typ, n.info)
when defined(nimsuggest):
var actualLoc = a.info
if n.kind == nkHiddenCallConv:
actualLoc = n.info
if a.kind == nkSym:
markCaughtExceptions(tracked, tracked.graph, actualLoc, a.sym, tracked.graph.usageSym)
let notConstExpr = getConstExpr(tracked.ownerModule, n, tracked.c.idgen, tracked.graph) == nil
if notConstExpr:
if a.kind == nkCast and a[1].typ.kind == tyProc:
@@ -1036,7 +985,7 @@ proc trackCall(tracked: PEffects; n: PNode) =
# may not look like an assignment, but it is:
let arg = n[1]
initVarViaNew(tracked, arg)
if arg.typ.hasElementType and {tfRequiresInit} * arg.typ.elementType.flags != {}:
if arg.typ.len != 0 and {tfRequiresInit} * arg.typ.lastSon.flags != {}:
if a.sym.magic == mNewSeq and n[2].kind in {nkCharLit..nkUInt64Lit} and
n[2].intVal == 0:
# var s: seq[notnil]; newSeq(s, 0) is a special case!
@@ -1045,8 +994,8 @@ proc trackCall(tracked: PEffects; n: PNode) =
message(tracked.config, arg.info, warnProveInit, $arg)
# check required for 'nim check':
if n[1].typ.hasElementType:
createTypeBoundOps(tracked, n[1].typ.elementType, n.info)
if n[1].typ.len > 0:
createTypeBoundOps(tracked, n[1].typ.lastSon, n.info)
createTypeBoundOps(tracked, n[1].typ, n.info)
# new(x, finalizer): Problem: how to move finalizer into 'createTypeBoundOps'?
@@ -1069,11 +1018,11 @@ proc trackCall(tracked: PEffects; n: PNode) =
n[0].sym = op
if op != nil and op.kind == tyProc:
for i in 1..<min(n.safeLen, op.signatureLen):
for i in 1..<min(n.safeLen, op.len):
let paramType = op[i]
case paramType.kind
of tySink:
createTypeBoundOps(tracked, paramType.elementType, n.info)
createTypeBoundOps(tracked, paramType[0], n.info)
checkForSink(tracked, n[i])
of tyVar:
if isOutParam(paramType):
@@ -1204,8 +1153,7 @@ proc track(tracked: PEffects, n: PNode) =
# bug #15038: ensure consistency
if 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}:
if n[0].kind == nkSym and isLocalSym(tracked, n[0].sym):
useVarNoInitCheck(tracked, n[0], n[0].sym)
else:
track(tracked, n[0])
@@ -1226,10 +1174,7 @@ proc track(tracked: PEffects, n: PNode) =
trackCall(tracked, n)
of nkDotExpr:
guardDotAccess(tracked, n)
let oldLeftPartOfAsgn = tracked.leftPartOfAsgn
tracked.leftPartOfAsgn = 0
for i in 0..<n.len: track(tracked, n[i])
tracked.leftPartOfAsgn = oldLeftPartOfAsgn
of nkCheckedFieldExpr:
track(tracked, n[0])
if tracked.config.hasWarn(warnProveField) or strictCaseObjects in tracked.c.features:
@@ -1377,7 +1322,7 @@ proc track(tracked: PEffects, n: PNode) =
if tracked.owner.kind != skMacro:
# XXX n.typ can be nil in runnableExamples, we need to do something about it.
if n.typ != nil and n.typ.skipTypes(abstractInst).kind == tyRef:
createTypeBoundOps(tracked, n.typ.elementType, n.info)
createTypeBoundOps(tracked, n.typ.lastSon, n.info)
createTypeBoundOps(tracked, n.typ, n.info)
of nkTupleConstr:
for i in 0..<n.len:
@@ -1482,7 +1427,7 @@ proc track(tracked: PEffects, n: PNode) =
proc subtypeRelation(g: ModuleGraph; spec, real: PNode): bool =
if spec.typ.kind == tyOr:
result = false
for t in spec.typ.kids:
for t in spec.typ:
if safeInheritanceDiff(g.excType(real), t) <= 0:
return true
else:
@@ -1626,7 +1571,7 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) =
var t: TEffects = initEffects(g, inferredEffects, s, c)
rawInitEffects g, effects
if not isEmptyType(s.typ.returnType) and
if not isEmptyType(s.typ[0]) and
s.kind in {skProc, skFunc, skConverter, skMethod}:
var res = s.ast[resultPos].sym # get result symbol
t.scopes[res.id] = t.currentBlock
@@ -1645,13 +1590,13 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) =
if isOutParam(typ) and param.id notin t.init:
message(g.config, param.info, warnProveInit, param.name.s)
if not isEmptyType(s.typ.returnType) and
(s.typ.returnType.requiresInit or s.typ.returnType.skipTypes(abstractInst).kind == tyVar or
if not isEmptyType(s.typ[0]) and
(s.typ[0].requiresInit or s.typ[0].skipTypes(abstractInst).kind == tyVar or
strictDefs in c.features) and
s.kind in {skProc, skFunc, skConverter, skMethod} and s.magic == mNone:
var res = s.ast[resultPos].sym # get result symbol
if res.id notin t.init and breaksBlock(body) != bsNoReturn:
if tfRequiresInit in s.typ.returnType.flags:
if tfRequiresInit in s.typ[0].flags:
localError(g.config, body.info, "'$1' requires explicit initialization" % "result")
else:
message(g.config, body.info, warnProveInit, "result")
@@ -1725,7 +1670,7 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) =
dataflowAnalysis(s, body)
when false: trackWrites(s, body)
if strictNotNil in c.features and s.kind in {skProc, skFunc, skMethod, skConverter}:
if strictNotNil in c.features and s.kind == skProc:
checkNil(s, body, g.config, c.idgen)
proc trackStmt*(c: PContext; module: PSym; n: PNode, isTopLevel: bool) =

View File

@@ -42,10 +42,10 @@ proc implicitlyDiscardable(n: PNode): bool
proc hasEmpty(typ: PType): bool =
if typ.kind in {tySequence, tyArray, tySet}:
result = typ.elementType.kind == tyEmpty
result = typ.lastSon.kind == tyEmpty
elif typ.kind == tyTuple:
result = false
for s in typ.kids:
for s in typ:
result = result or hasEmpty(s)
else:
result = false
@@ -132,140 +132,17 @@ proc semExprBranchScope(c: PContext, n: PNode; expectedType: PType = nil): PNode
closeScope(c)
const
skipForDiscardable = {nkStmtList, nkStmtListExpr,
nkOfBranch, nkElse, nkFinally, nkExceptBranch,
skipForDiscardable = {nkIfStmt, nkIfExpr, nkCaseStmt, nkOfBranch,
nkElse, nkStmtListExpr, nkTryStmt, nkFinally, nkExceptBranch,
nkElifBranch, nkElifExpr, nkElseExpr, nkBlockStmt, nkBlockExpr,
nkHiddenStdConv, nkHiddenDeref}
proc implicitlyDiscardable(n: PNode): bool =
# same traversal as endsInNoReturn
template checkBranch(branch) =
if not implicitlyDiscardable(branch):
return false
var it = n
# skip these beforehand, no special handling needed
while it.kind in skipForDiscardable and it.len > 0:
it = it.lastSon
case it.kind
of nkIfExpr, nkIfStmt:
for branch in it:
checkBranch:
if branch.len == 2:
branch[1]
elif branch.len == 1:
branch[0]
else:
raiseAssert "Malformed `if` statement during implicitlyDiscardable"
# all branches are discardable
result = true
of nkCaseStmt:
for i in 1 ..< it.len:
let branch = it[i]
checkBranch:
case branch.kind
of nkOfBranch:
branch[^1]
of nkElifBranch:
branch[1]
of nkElse:
branch[0]
else:
raiseAssert "Malformed `case` statement in endsInNoReturn"
# all branches are discardable
result = true
of nkTryStmt:
checkBranch(it[0])
for i in 1 ..< it.len:
let branch = it[i]
if branch.kind != nkFinally:
checkBranch(branch[^1])
# all branches are discardable
result = true
of nkCallKinds:
result = it[0].kind == nkSym and {sfDiscardable, sfNoReturn} * it[0].sym.flags != {}
of nkLastBlockStmts:
result = true
else:
result = false
proc endsInNoReturn(n: PNode, returningNode: var PNode): bool =
## check if expr ends the block like raising or call of noreturn procs do
result = false # assume it does return
template checkBranch(branch) =
if not endsInNoReturn(branch, returningNode):
# proved a branch returns
return false
var it = n
# skip these beforehand, no special handling needed
while it.kind in skipForDiscardable and it.len > 0:
it = it.lastSon
case it.kind
of nkIfExpr, nkIfStmt:
var hasElse = false
for branch in it:
checkBranch:
if branch.len == 2:
branch[1]
elif branch.len == 1:
hasElse = true
branch[0]
else:
raiseAssert "Malformed `if` statement during endsInNoReturn"
# none of the branches returned
result = hasElse # Only truly a no-return when it's exhaustive
of nkCaseStmt:
let caseTyp = skipTypes(it[0].typ, abstractVar-{tyTypeDesc})
# semCase should already have checked for exhaustiveness in this case
# effectively the same as having an else
var hasElse = caseTyp.shouldCheckCaseCovered()
# actual noreturn checks
for i in 1 ..< it.len:
let branch = it[i]
checkBranch:
case branch.kind
of nkOfBranch:
branch[^1]
of nkElifBranch:
branch[1]
of nkElse:
hasElse = true
branch[0]
else:
raiseAssert "Malformed `case` statement in endsInNoReturn"
# Can only guarantee a noreturn if there is an else or it's exhaustive
result = hasElse
of nkTryStmt:
checkBranch(it[0])
var lastIndex = it.len - 1
if it[lastIndex].kind == nkFinally:
# if finally is noreturn, then the entire statement is noreturn
if endsInNoReturn(it[lastIndex][^1], returningNode):
return true
dec lastIndex
for i in 1 .. lastIndex:
let branch = it[i]
checkBranch(branch[^1])
# none of the branches returned
result = true
of nkLastBlockStmts:
result = true
of nkCallKinds:
result = it[0].kind == nkSym and sfNoReturn in it[0].sym.flags
if not result:
returningNode = it
else:
result = false
returningNode = it
proc endsInNoReturn(n: PNode): bool =
var dummy: PNode = nil
result = endsInNoReturn(n, dummy)
var n = n
while n.kind in skipForDiscardable: n = n.lastSon
result = n.kind in nkLastBlockStmts or
(isCallExpr(n) and n[0].kind == nkSym and
sfDiscardable in n[0].sym.flags)
proc fixNilType(c: PContext; n: PNode) =
if isAtom(n):
@@ -288,11 +165,10 @@ proc discardCheck(c: PContext, result: PNode, flags: TExprFlags) =
localError(c.config, result.info, "expression has no type: " &
renderTree(result, {renderNoComments}))
else:
# Ignore noreturn procs since they don't have a type
var n = result
if result.endsInNoReturn(n):
return
while n.kind in skipForDiscardable:
if n.kind == nkTryStmt: n = n[0]
else: n = n.lastSon
var s = "expression '" & $n & "' is of type '" &
result.typ.typeToString & "' and has to be used (or discarded)"
if result.info.line != n.info.line or
@@ -458,8 +334,6 @@ proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
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:
discard "keep nkHiddenStdConv for cstring conversions"
else:
changeType(c, r1, typ, check=true)
result = r1
@@ -480,7 +354,7 @@ 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)
result = semIdentWithPragma(c, kind, n, {sfExported})
incl(result.flags, sfGlobal)
#if kind in {skVar, skLet}:
# echo "global variable here ", n.info, " ", result.name.s
@@ -577,16 +451,16 @@ proc hasUnresolvedParams(n: PNode; flags: TExprFlags): bool =
proc makeDeref(n: PNode): PNode =
var t = n.typ
if t.kind in tyUserTypeClasses and t.isResolvedUserTypeClass:
t = t.last
t = t.lastSon
t = skipTypes(t, {tyGenericInst, tyAlias, tySink, tyOwned})
result = n
if t.kind in {tyVar, tyLent}:
result = newNodeIT(nkHiddenDeref, n.info, t.elementType)
result = newNodeIT(nkHiddenDeref, n.info, t[0])
result.add n
t = skipTypes(t.elementType, {tyGenericInst, tyAlias, tySink, tyOwned})
t = skipTypes(t[0], {tyGenericInst, tyAlias, tySink, tyOwned})
while t.kind in {tyPtr, tyRef}:
var a = result
let baseTyp = t.elementType
let baseTyp = t.lastSon
result = newNodeIT(nkHiddenDeref, n.info, baseTyp)
result.add a
t = skipTypes(baseTyp, {tyGenericInst, tyAlias, tySink, tyOwned})
@@ -788,24 +662,6 @@ proc makeVarTupleSection(c: PContext, n, a, def: PNode, typ: PType, symkind: TSy
proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
var b: PNode
result = copyNode(n)
# transform var x, y = 12 into var x = 12; var y = 12
# bug #18104; transformation should be finished before templates expansion
# TODO: move warnings for tuple here
var transformed = copyNode(n)
for i in 0..<n.len:
var a = n[i]
if a.kind == nkIdentDefs and a.len > 3 and a[^1].kind != nkEmpty:
for j in 0..<a.len-2:
var b = newNodeI(nkIdentDefs, a.info)
b.add a[j]
b.add a[^2]
b.add copyTree(a[^1])
transformed.add b
else:
transformed.add a
let n = transformed
for i in 0..<n.len:
var a = n[i]
if c.config.cmd == cmdIdeTools: suggestStmt(c, a)
@@ -847,7 +703,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
else:
typ = def.typ.skipTypes({tyStatic, tySink}).skipIntLit(c.idgen)
if typ.kind in tyUserTypeClasses and typ.isResolvedUserTypeClass:
typ = typ.last
typ = typ.lastSon
if hasEmpty(typ):
localError(c.config, def.info, errCannotInferTypeOfTheLiteral % typ.kind.toHumanStr)
elif typ.kind == tyProc and def.kind == nkSym and isGenericRoutine(def.sym.ast):
@@ -1069,10 +925,7 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
if iterAfterVarLent.kind != tyTuple or n.len == 3:
if n.len == 3:
if n[0].kind == nkVarTuple:
if iterAfterVarLent.kind != tyTuple:
return localErrorNode(c, n, n[0].info, errTupleUnpackingTupleExpected %
[typeToString(n[1].typ, preferDesc)])
elif n[0].len-1 != iterAfterVarLent.len:
if n[0].len-1 != iterAfterVarLent.len:
return localErrorNode(c, n, n[0].info, errWrongNumberOfVariables)
for i in 0..<n[0].len-1:
@@ -1185,12 +1038,12 @@ proc handleStmtMacro(c: PContext; n, selector: PNode; magicType: string;
if maType == nil: return
let headSymbol = selector[0]
var o: TOverloadIter = default(TOverloadIter)
var o: TOverloadIter
var match: PSym = nil
var symx = initOverloadIter(o, c, headSymbol)
while symx != nil:
if symx.kind in {skTemplate, skMacro}:
if symx.typ.len == 2 and symx.typ.firstParamType == maType.typ:
if symx.typ.len == 2 and symx.typ[1] == maType.typ:
if match == nil:
match = symx
else:
@@ -1221,7 +1074,7 @@ proc handleCaseStmtMacro(c: PContext; n: PNode; flags: TExprFlags): PNode =
toResolve.add newIdentNode(getIdent(c.cache, "case"), n.info)
toResolve.add n[0]
var errors: CandidateErrors = @[]
var errors: CandidateErrors
var r = resolveOverloads(c, toResolve, toResolve, {skTemplate, skMacro}, {efNoDiagnostics},
errors, false)
if r.state == csMatch:
@@ -1385,7 +1238,7 @@ proc semRaise(c: PContext, n: PNode): PNode =
typ = typ.skipTypes({tyAlias, tyGenericInst, tyOwned})
if typ.kind != tyRef:
localError(c.config, n.info, errExprCannotBeRaised)
if typ.len > 0 and not isException(typ.elementType):
if typ.len > 0 and not isException(typ.lastSon):
localError(c.config, n.info, "raised object of type $1 does not inherit from Exception" % typeToString(typ))
proc addGenericParamListToScope(c: PContext, n: PNode) =
@@ -1401,9 +1254,6 @@ proc typeSectionTypeName(c: PContext; n: PNode): PNode =
result = n[0]
else:
result = n
if result.kind == nkPostfix:
if result.len != 2: illFormedAst(n, c.config)
result = result[1]
if result.kind != nkSym: illFormedAst(n, c.config)
proc typeDefLeftSidePass(c: PContext, typeSection: PNode, i: int) =
@@ -1471,15 +1321,9 @@ proc typeDefLeftSidePass(c: PContext, typeSection: PNode, i: int) =
elif s.owner == nil: s.owner = getCurrOwner(c)
if name.kind == nkPragmaExpr:
if name[0].kind == nkPostfix:
typeDef[0][0][1] = newSymNode(s)
else:
typeDef[0][0] = newSymNode(s)
typeDef[0][0] = newSymNode(s)
else:
if name.kind == nkPostfix:
typeDef[0][1] = newSymNode(s)
else:
typeDef[0] = newSymNode(s)
typeDef[0] = newSymNode(s)
proc typeSectionLeftSidePass(c: PContext, n: PNode) =
# process the symbols on the left side for the whole type section, before
@@ -1499,7 +1343,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
inc i
proc checkCovariantParamsUsages(c: PContext; genericType: PType) =
var body = genericType.typeBodyImpl
var body = genericType[^1]
proc traverseSubTypes(c: PContext; t: PType): bool =
template error(msg) = localError(c.config, genericType.sym.info, msg)
@@ -1516,17 +1360,17 @@ proc checkCovariantParamsUsages(c: PContext; genericType: PType) =
for field in t.n:
subresult traverseSubTypes(c, field.typ)
of tyArray:
return traverseSubTypes(c, t.elementType)
return traverseSubTypes(c, t[1])
of tyProc:
for subType in t.signature:
for subType in t:
if subType != nil:
subresult traverseSubTypes(c, subType)
if result:
error("non-invariant type param used in a proc type: " & $t)
of tySequence:
return traverseSubTypes(c, t.elementType)
return traverseSubTypes(c, t[0])
of tyGenericInvocation:
let targetBody = t.genericHead
let targetBody = t[0]
for i in 1..<t.len:
let param = t[i]
if param.kind == tyGenericParam:
@@ -1551,13 +1395,13 @@ proc checkCovariantParamsUsages(c: PContext; genericType: PType) =
of tyUserTypeClass, tyUserTypeClassInst:
error("non-invariant type parameters are not supported in concepts")
of tyTuple:
for fieldType in t.kids:
for fieldType in t:
subresult traverseSubTypes(c, fieldType)
of tyPtr, tyRef, tyVar, tyLent:
if t.elementType.kind == tyGenericParam: return true
return traverseSubTypes(c, t.elementType)
if t.base.kind == tyGenericParam: return true
return traverseSubTypes(c, t.base)
of tyDistinct, tyAlias, tySink, tyOwned:
return traverseSubTypes(c, t.skipModifier)
return traverseSubTypes(c, t.lastSon)
of tyGenericInst:
internalAssert c.config, false
else:
@@ -1595,11 +1439,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
# we fill it out later. For magic generics like 'seq', it won't be filled
# so we use tyNone instead of nil to not crash for strange conversions
# like: mydata.seq
if s.typ.kind in {tyOpenArray, tyVarargs} and s.typ.len == 1:
# XXX investigate why `tySequence` cannot be added here for now.
discard
else:
rawAddSon(s.typ, newTypeS(tyNone, c))
rawAddSon(s.typ, newTypeS(tyNone, c))
s.ast = a
inc c.inGenericContext
var body = semTypeNode(c, a[2], s.typ)
@@ -1626,7 +1466,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
# possibilities such as instantiating C++ generic types with
# garbage collected Nim types.
if sfImportc in s.flags:
var body = s.typ.last
var body = s.typ.lastSon
if body.kind == tyObject:
# erases all declared fields
body.n.sons = @[]
@@ -1669,11 +1509,11 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
aa[0].kind == nkObjectTy:
# give anonymous object a dummy symbol:
var st = s.typ
if st.kind == tyGenericBody: st = st.typeBodyImpl
if st.kind == tyGenericBody: st = st.lastSon
internalAssert c.config, st.kind in {tyPtr, tyRef}
internalAssert c.config, st.last.sym == nil
internalAssert c.config, st.lastSon.sym == nil
incl st.flags, tfRefsAnonObj
let objTy = st.last
let objTy = st.lastSon
# add flags for `ref object` etc to underlying `object`
incl(objTy.flags, oldFlags)
# {.inheritable, final.} is already disallowed, but
@@ -1686,19 +1526,12 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
let symNode = newSymNode(obj)
obj.ast = a.shallowCopy
case a[0].kind
of nkSym: obj.ast[0] = symNode
of nkPragmaExpr:
obj.ast[0] = a[0].shallowCopy
if a[0][0].kind == nkPostfix:
obj.ast[0][0] = a[0][0].shallowCopy
obj.ast[0][0][1] = symNode
else:
of nkSym: obj.ast[0] = symNode
of nkPragmaExpr:
obj.ast[0] = a[0].shallowCopy
obj.ast[0][0] = symNode
obj.ast[0][1] = a[0][1]
of nkPostfix:
obj.ast[0] = a[0].shallowCopy
obj.ast[0][1] = symNode
else: assert(false)
obj.ast[0][1] = a[0][1]
else: assert(false)
obj.ast[1] = a[1]
obj.ast[2] = a[2][0]
if sfPure in s.flags:
@@ -1708,27 +1541,21 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
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) =
if t != nil and (t.isMetaType or t.kind == tyNone) and tfGenericTypeParam notin t.flags:
if t.kind == tyBuiltInTypeClass and t.len == 1 and t.elementType.kind == tyProc:
proc checkForMetaFields(c: PContext; n: PNode) =
proc checkMeta(c: PContext; n: PNode; t: PType) =
if t != nil and t.isMetaType and tfGenericTypeParam notin t.flags:
if t.kind == tyBuiltInTypeClass and t.len == 1 and t[0].kind == tyProc:
localError(c.config, n.info, ("'$1' is not a concrete type; " &
"for a callback without parameters use 'proc()'") % t.typeToString)
elif t.kind == tyNone and parent != nil:
# TODO: openarray has the `tfGenericTypeParam` flag & generics
# TODO: handle special cases (sink etc.) and views
localError(c.config, n.info, errTIsNotAConcreteType % parent.typeToString)
else:
localError(c.config, n.info, errTIsNotAConcreteType % t.typeToString)
hasError = true
if n.isNil: return
case n.kind
of nkRecList, nkRecCase:
for s in n: checkForMetaFields(c, s, hasError)
for s in n: checkForMetaFields(c, s)
of nkOfBranch, nkElse:
checkForMetaFields(c, n.lastSon, hasError)
checkForMetaFields(c, n.lastSon)
of nkSym:
let t = n.sym.typ
case t.kind
@@ -1736,9 +1563,9 @@ proc checkForMetaFields(c: PContext; n: PNode; hasError: var bool) =
tyProc, tyGenericInvocation, tyGenericInst, tyAlias, tySink, tyOwned:
let start = ord(t.kind in {tyGenericInvocation, tyGenericInst})
for i in start..<t.len:
checkMeta(c, n, t[i], hasError, t)
checkMeta(c, n, t[i])
else:
checkMeta(c, n, t, hasError, nil)
checkMeta(c, n, t)
else:
internalAssert c.config, false
@@ -1773,11 +1600,9 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
assert s.typ != nil
assignType(s.typ, t)
s.typ.itemId = t.itemId # same id
var hasError = false
checkConstructedType(c.config, s.info, s.typ)
if s.typ.kind in {tyObject, tyTuple} and not s.typ.n.isNil:
checkForMetaFields(c, s.typ.n, hasError)
if not hasError:
checkConstructedType(c.config, s.info, s.typ)
checkForMetaFields(c, s.typ.n)
# fix bug #5170, bug #17162, bug #15526: ensure locally scoped types get a unique name:
if s.typ.kind in {tyEnum, tyRef, tyObject} and not isTopLevel(c):
@@ -1857,25 +1682,25 @@ proc semBorrow(c: PContext, n: PNode, s: PSym) =
# search for the correct alias:
var (b, state) = searchForBorrowProc(c, c.currentScope.parent, s)
case state
of bsMatch:
# store the alias:
n[bodyPos] = newSymNode(b)
# Carry over the original symbol magic, this is necessary in order to ensure
# the semantic pass is correct
s.magic = b.magic
if b.typ != nil and b.typ.len > 0:
s.typ.n[0] = b.typ.n[0]
s.typ.flags = b.typ.flags
of bsNoDistinct:
localError(c.config, n.info, "borrow proc without distinct type parameter is meaningless")
of bsReturnNotMatch:
localError(c.config, n.info, "borrow from proc return type mismatch: '$1'" % typeToString(b.typ.returnType))
of bsGeneric:
localError(c.config, n.info, "borrow with generic parameter is not supported")
of bsNotSupported:
localError(c.config, n.info, "borrow from '$1' is not supported" % $b.name.s)
else:
localError(c.config, n.info, errNoSymbolToBorrowFromFound)
of bsMatch:
# store the alias:
n[bodyPos] = newSymNode(b)
# Carry over the original symbol magic, this is necessary in order to ensure
# the semantic pass is correct
s.magic = b.magic
if b.typ != nil and b.typ.len > 0:
s.typ.n[0] = b.typ.n[0]
s.typ.flags = b.typ.flags
of bsNoDistinct:
localError(c.config, n.info, "borrow proc without distinct type parameter is meaningless")
of bsReturnNotMatch:
localError(c.config, n.info, "borrow from proc return type mismatch: '$1'" % typeToString(b.typ[0]))
of bsGeneric:
localError(c.config, n.info, "borrow with generic parameter is not supported")
of bsNotSupported:
localError(c.config, n.info, "borrow from '$1' is not supported" % $b.name.s)
else:
localError(c.config, n.info, errNoSymbolToBorrowFromFound)
proc swapResult(n: PNode, sRes: PSym, dNode: PNode) =
## Swap nodes that are (skResult) symbols to d(estination)Node.
@@ -1961,7 +1786,7 @@ proc semProcAnnotation(c: PContext, prc: PNode;
return result
proc semInferredLambda(c: PContext, pt: TypeMapping, n: PNode): PNode =
proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
## used for resolving 'auto' in lambdas based on their callsite
var n = n
let original = n[namePos].sym
@@ -1976,6 +1801,7 @@ proc semInferredLambda(c: PContext, pt: TypeMapping, n: PNode): PNode =
n[genericParamsPos] = c.graph.emptyNode
# for LL we need to avoid wrong aliasing
let params = copyTree n.typ.n
n[paramsPos] = params
s.typ = n.typ
for i in 1..<params.len:
if params[i].typ.kind in {tyTypeDesc, tyGenericParam,
@@ -1987,8 +1813,8 @@ proc semInferredLambda(c: PContext, pt: TypeMapping, n: PNode): PNode =
pushOwner(c, s)
addParams(c, params, skProc)
pushProcCon(c, s)
addResult(c, n, n.typ.returnType, skProc)
s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos], n.typ.returnType))
addResult(c, n, n.typ[0], skProc)
s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos], n.typ[0]))
trackProc(c, s, s.ast[bodyPos])
popProcCon(c)
popOwner(c)
@@ -2018,8 +1844,8 @@ proc maybeAddResult(c: PContext, s: PSym, n: PNode) =
if s.kind == skMacro:
let resultType = sysTypeFromName(c.graph, n.info, "NimNode")
addResult(c, n, resultType, s.kind)
elif s.typ.returnType != nil and not isInlineIterator(s.typ):
addResult(c, n, s.typ.returnType, s.kind)
elif s.typ[0] != nil and not isInlineIterator(s.typ):
addResult(c, n, s.typ[0], s.kind)
proc canonType(c: PContext, t: PType): PType =
if t.kind == tySequence:
@@ -2038,7 +1864,7 @@ proc prevDestructor(c: PContext; prevOp: PSym; obj: PType; info: TLineInfo) =
proc whereToBindTypeHook(c: PContext; t: PType): PType =
result = t
while true:
if result.kind in {tyGenericBody, tyGenericInst}: result = result.skipModifier
if result.kind in {tyGenericBody, tyGenericInst}: result = result.lastSon
elif result.kind == tyGenericInvocation: result = result[0]
else: break
if result.kind in {tyObject, tyDistinct, tySequence, tyString}:
@@ -2047,20 +1873,20 @@ proc whereToBindTypeHook(c: PContext; t: PType): PType =
proc bindDupHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
let t = s.typ
var noError = false
let cond = t.len == 2 and t.returnType != nil
let cond = t.len == 2 and t[0] != nil
if cond:
var obj = t.firstParamType
var obj = t[1]
while true:
incl(obj.flags, tfHasAsgn)
if obj.kind in {tyGenericBody, tyGenericInst}: obj = obj.skipModifier
elif obj.kind == tyGenericInvocation: obj = obj.genericHead
if obj.kind in {tyGenericBody, tyGenericInst}: obj = obj.lastSon
elif obj.kind == tyGenericInvocation: obj = obj[0]
else: break
var res = t.returnType
var res = t[0]
while true:
if res.kind in {tyGenericBody, tyGenericInst}: res = res.skipModifier
elif res.kind == tyGenericInvocation: res = res.genericHead
if res.kind in {tyGenericBody, tyGenericInst}: res = res.lastSon
elif res.kind == tyGenericInvocation: res = res[0]
else: break
if obj.kind in {tyObject, tyDistinct, tySequence, tyString} and sameType(obj, res):
@@ -2089,27 +1915,21 @@ proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp; suppressV
var noError = false
let cond = case op
of attachedWasMoved:
t.len == 2 and t.returnType == nil and t.firstParamType.kind == tyVar
t.len == 2 and t[0] == nil and t[1].kind == tyVar
of attachedTrace:
t.len == 3 and t.returnType == nil and t.firstParamType.kind == tyVar and t[2].kind == tyPointer
of attachedDestructor:
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
t.len == 3 and t[0] == nil and t[1].kind == tyVar and t[2].kind == tyPointer
else:
t.len >= 2 and t.returnType == nil
t.len >= 2 and t[0] == nil
if cond:
var obj = t.firstParamType.skipTypes({tyVar})
var obj = t[1].skipTypes({tyVar})
while true:
incl(obj.flags, tfHasAsgn)
if obj.kind in {tyGenericBody, tyGenericInst}: obj = obj.skipModifier
elif obj.kind == tyGenericInvocation: obj = obj.genericHead
if obj.kind in {tyGenericBody, tyGenericInst}: obj = obj.lastSon
elif obj.kind == tyGenericInvocation: obj = obj[0]
else: break
if obj.kind in {tyObject, tyDistinct, tySequence, tyString}:
if (not suppressVarDestructorWarning) and op == attachedDestructor and t.firstParamType.kind == tyVar and
c.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
if (not suppressVarDestructorWarning) and op == attachedDestructor and t[1].kind == tyVar:
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)
@@ -2129,12 +1949,8 @@ proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp; suppressV
localError(c.config, n.info, errGenerated,
"signature for '=trace' must be proc[T: object](x: var T; env: pointer)")
of attachedDestructor:
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:
localError(c.config, n.info, errGenerated,
"signature for '=destroy' must be proc[T: object](x: var T)")
localError(c.config, n.info, errGenerated,
"signature for '=destroy' must be proc[T: object](x: var T) or proc[T: object](x: T)")
else:
localError(c.config, n.info, errGenerated,
"signature for '" & s.name.s & "' must be proc[T: object](x: var T)")
@@ -2153,14 +1969,14 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
newIdentNode(c.cache.getIdent("raises"), s.info), newNodeI(nkBracket, s.info))
of "deepcopy", "=deepcopy":
if s.typ.len == 2 and
s.typ.firstParamType.skipTypes(abstractInst).kind in {tyRef, tyPtr} and
sameType(s.typ.firstParamType, s.typ.returnType):
s.typ[1].skipTypes(abstractInst).kind in {tyRef, tyPtr} and
sameType(s.typ[1], s.typ[0]):
# Note: we store the deepCopy in the base of the pointer to mitigate
# the problem that pointers are structural types:
var t = s.typ.firstParamType.skipTypes(abstractInst).elementType.skipTypes(abstractInst)
var t = s.typ[1].skipTypes(abstractInst).lastSon.skipTypes(abstractInst)
while true:
if t.kind == tyGenericBody: t = t.typeBodyImpl
elif t.kind == tyGenericInvocation: t = t.genericHead
if t.kind == tyGenericBody: t = t.lastSon
elif t.kind == tyGenericInvocation: t = t[0]
else: break
if t.kind in {tyObject, tyDistinct, tyEnum, tySequence, tyString}:
if getAttachedOp(c.graph, t, attachedDeepCopy).isNil:
@@ -2188,18 +2004,18 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
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
if t.len == 3 and t[0] == nil and t[1].kind == tyVar:
var obj = t[1][0]
while true:
incl(obj.flags, tfHasAsgn)
if obj.kind == tyGenericBody: obj = obj.skipModifier
elif obj.kind == tyGenericInvocation: obj = obj.genericHead
if obj.kind == tyGenericBody: obj = obj.lastSon
elif obj.kind == tyGenericInvocation: obj = obj[0]
else: break
var objB = t[2]
while true:
if objB.kind == tyGenericBody: objB = objB.skipModifier
if objB.kind == tyGenericBody: objB = objB.lastSon
elif objB.kind in {tyGenericInvocation, tyGenericInst}:
objB = objB.genericHead
objB = objB[0]
else: break
if obj.kind in {tyObject, tyDistinct, tySequence, tyString} and sameType(obj, objB):
# attach these ops to the canonical tySequence
@@ -2266,20 +2082,20 @@ proc semCppMember(c: PContext; s: PSym; n: PNode) =
if c.config.backend == backendCpp:
if s.typ.len < 2 and not isCtor:
localError(c.config, n.info, pragmaName & " must have at least one parameter")
for son in s.typ.signature:
for son in s.typ:
if son!=nil and son.isMetaType:
localError(c.config, n.info, pragmaName & " unsupported for generic routine")
var typ: PType
if isCtor:
typ = s.typ.returnType
typ = s.typ[0]
if typ == nil or typ.kind != tyObject:
localError(c.config, n.info, "constructor must return an object")
if sfImportc in typ.sym.flags:
localError(c.config, n.info, "constructor in an imported type needs importcpp pragma")
else:
typ = s.typ.firstParamType
typ = s.typ[1]
if typ.kind == tyPtr and not isCtor:
typ = typ.elementType
typ = typ[0]
if typ.kind != tyObject:
localError(c.config, n.info, pragmaName & " must be either ptr to object or object type.")
if typ.owner.id == s.owner.id and c.module.id == s.owner.id:
@@ -2290,7 +2106,7 @@ proc semCppMember(c: PContext; s: PSym; n: PNode) =
else:
localError(c.config, n.info, pragmaName & " procs are only supported in C++")
else:
var typ = s.typ.returnType
var typ = s.typ[0]
if typ != nil and typ.kind == tyObject and typ.itemId notin c.graph.initializersPerType:
var initializerCall = newTree(nkCall, newSymNode(s))
var isInitializer = n[paramsPos].len > 1
@@ -2316,7 +2132,7 @@ proc semMethodPrototype(c: PContext; s: PSym; n: PNode) =
for col in 1..<tt.len:
let t = tt[col]
if t != nil and t.kind == tyGenericInvocation:
var x = skipTypes(t.genericHead, {tyVar, tyLent, tyPtr, tyRef, tyGenericInst,
var x = skipTypes(t[0], {tyVar, tyLent, tyPtr, tyRef, tyGenericInst,
tyGenericInvocation, tyGenericBody,
tyAlias, tySink, tyOwned})
if x.kind == tyObject and t.len-1 == n[genericParamsPos].len:
@@ -2529,7 +2345,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
if sfBorrow in s.flags and c.config.cmd notin cmdDocLike:
result[bodyPos] = c.graph.emptyNode
if sfCppMember * s.flags != {} and sfWasForwarded notin s.flags:
if sfCppMember * s.flags != {}:
semCppMember(c, s, n)
if n[bodyPos].kind != nkEmpty and sfError notin s.flags:
@@ -2544,8 +2360,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
# absolutely no generics (empty) or a single generic return type are
# allowed, everything else, including a nullary generic is an error.
pushProcCon(c, s)
addResult(c, n, s.typ.returnType, skProc)
s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos], s.typ.returnType))
addResult(c, n, s.typ[0], skProc)
s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos], s.typ[0]))
trackProc(c, s, s.ast[bodyPos])
popProcCon(c)
elif efOperand notin flags:
@@ -2561,7 +2377,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
if s.kind == skMacro:
sysTypeFromName(c.graph, n.info, "NimNode")
elif not isInlineIterator(s.typ):
s.typ.returnType
s.typ[0]
else:
nil
# semantic checking also needed with importc in case used in VM
@@ -2570,7 +2386,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
# context as it may even be evaluated in 'system.compiles':
trackProc(c, s, s.ast[bodyPos])
else:
if (s.typ.returnType != nil and s.kind != skIterator):
if (s.typ[0] != nil and s.kind != skIterator):
addDecl(c, newSym(skUnknown, getIdent(c.cache, "result"), c.idgen, s, n.info))
openScope(c)
@@ -2585,7 +2401,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
if hasProto: localError(c.config, n.info, errImplOfXexpected % proto.name.s)
if {sfImportc, sfBorrow, sfError} * s.flags == {} and s.magic == mNone:
# this is a forward declaration and we're building the prototype
if s.kind in {skProc, skFunc} and s.typ.returnType != nil and s.typ.returnType.kind == tyAnything:
if s.kind in {skProc, skFunc} and s.typ[0] != nil and s.typ[0].kind == tyAnything:
localError(c.config, n[paramsPos][0].info, "return type 'auto' cannot be used in forward declarations")
incl(s.flags, sfForward)
@@ -2630,7 +2446,7 @@ proc semIterator(c: PContext, n: PNode): PNode =
if result.kind != n.kind: return
var s = result[namePos].sym
var t = s.typ
if t.returnType == nil and s.typ.callConv != ccClosure:
if t[0] == nil and s.typ.callConv != ccClosure:
localError(c.config, n.info, "iterator needs a return type")
# iterators are either 'inline' or 'closure'; for backwards compatibility,
# we require first class iterators to be marked with 'closure' explicitly
@@ -2667,9 +2483,9 @@ proc semMethod(c: PContext, n: PNode): PNode =
# test case):
let disp = getDispatcher(s)
# auto return type?
if disp != nil and disp.typ.returnType != nil and disp.typ.returnType.kind == tyUntyped:
let ret = s.typ.returnType
disp.typ.setReturnType ret
if disp != nil and disp.typ[0] != nil and disp.typ[0].kind == tyUntyped:
let ret = s.typ[0]
disp.typ[0] = ret
if disp.ast[resultPos].kind == nkSym:
if isEmptyType(ret): disp.ast[resultPos] = c.graph.emptyNode
else: disp.ast[resultPos].sym.typ = ret
@@ -2685,7 +2501,7 @@ proc semConverterDef(c: PContext, n: PNode): PNode =
if result.kind != nkConverterDef: return
var s = result[namePos].sym
var t = s.typ
if t.returnType == nil: localError(c.config, n.info, errXNeedsReturnType % "converter")
if t[0] == nil: localError(c.config, n.info, errXNeedsReturnType % "converter")
if t.len != 2: localError(c.config, n.info, "a converter takes exactly one argument")
addConverterDef(c, LazySym(sym: s))

View File

@@ -52,7 +52,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule;
isField = false): PNode =
var
a: PSym
o: TOverloadIter = default(TOverloadIter)
o: TOverloadIter
var i = 0
a = initOverloadIter(o, c, n)
while a != nil:
@@ -261,7 +261,7 @@ proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
if n.kind == nkIdent:
let s = qualifiedLookUp(c.c, n, {})
if s != nil:
if s.owner == c.owner and s.kind == skParam:
if s.owner == c.owner and (s.kind == skParam or sfGenSym in s.flags):
incl(s.flags, sfUsed)
result = newSymNode(s, n.info)
onUse(n.info, s)
@@ -507,21 +507,14 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
if x.kind == nkExprColonExpr:
x[1] = semTemplBody(c, x[1])
of nkBracketExpr:
if n.typ == nil:
# if a[b] is nested inside a typed expression, don't convert it
# back to `[]`(a, b), prepareOperand will not typecheck it again
# and so `[]` will not be resolved
# checking if a[b] is typed should be enough to cover this case
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "[]"), n.info)
for i in 0..<n.len: result.add(n[i])
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "[]"), n.info)
for i in 0..<n.len: result.add(n[i])
result = semTemplBodySons(c, result)
of nkCurlyExpr:
if n.typ == nil:
# see nkBracketExpr case for explanation
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "{}"), n.info)
for i in 0..<n.len: result.add(n[i])
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "{}"), n.info)
for i in 0..<n.len: result.add(n[i])
result = semTemplBodySons(c, result)
of nkAsgn, nkFastAsgn, nkSinkAsgn:
checkSonsLen(n, 2, c.c.config)
@@ -531,21 +524,17 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
let k = a.kind
case k
of nkBracketExpr:
if a.typ == nil:
# see nkBracketExpr case above for explanation
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "[]="), n.info)
for i in 0..<a.len: result.add(a[i])
result.add(b)
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "[]="), n.info)
for i in 0..<a.len: result.add(a[i])
result.add(b)
let a0 = semTemplBody(c, a[0])
result = semTemplBodySons(c, result)
of nkCurlyExpr:
if a.typ == nil:
# see nkBracketExpr case above for explanation
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "{}="), n.info)
for i in 0..<a.len: result.add(a[i])
result.add(b)
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "{}="), n.info)
for i in 0..<a.len: result.add(a[i])
result.add(b)
result = semTemplBodySons(c, result)
else:
result = semTemplBodySons(c, n)
@@ -668,7 +657,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
# a template's parameters are not gensym'ed even if that was originally the
# case as we determine whether it's a template parameter in the template
# body by the absence of the sfGenSym flag:
let retType = s.typ.returnType
let retType = s.typ[0]
if retType != nil and retType.kind != tyUntyped:
allUntyped = false
for i in 1..<s.typ.n.len:
@@ -684,7 +673,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
# XXX why do we need tyTyped as a return type again?
s.typ.n = newNodeI(nkFormalParams, n.info)
rawAddSon(s.typ, newTypeS(tyTyped, c))
s.typ.n.add newNodeIT(nkType, n.info, s.typ.returnType)
s.typ.n.add newNodeIT(nkType, n.info, s.typ[0])
if n[genericParamsPos].safeLen == 0:
# restore original generic type params as no explicit or implicit were found
n[genericParamsPos] = n[miscPos][1]
@@ -699,13 +688,12 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
if n[patternPos].kind != nkEmpty:
n[patternPos] = semPattern(c, n[patternPos], s)
var ctx = TemplCtx(
toBind: initIntSet(),
toMixin: initIntSet(),
toInject: initIntSet(),
c: c,
owner: s
)
var ctx: TemplCtx
ctx.toBind = initIntSet()
ctx.toMixin = initIntSet()
ctx.toInject = initIntSet()
ctx.c = c
ctx.owner = s
if sfDirty in s.flags:
n[bodyPos] = semTemplBodyDirty(ctx, n[bodyPos])
else:
@@ -856,13 +844,12 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
proc semPattern(c: PContext, n: PNode; s: PSym): PNode =
openScope(c)
var ctx = TemplCtx(
toBind: initIntSet(),
toMixin: initIntSet(),
toInject: initIntSet(),
c: c,
owner: getCurrOwner(c)
)
var ctx: TemplCtx
ctx.toBind = initIntSet()
ctx.toMixin = initIntSet()
ctx.toInject = initIntSet()
ctx.c = c
ctx.owner = getCurrOwner(c)
result = flattenStmts(semPatternBody(ctx, n))
if result.kind in {nkStmtList, nkStmtListExpr}:
if result.len == 1:

View File

@@ -15,7 +15,7 @@ const
errStringLiteralExpected = "string literal expected"
errIntLiteralExpected = "integer literal expected"
errWrongNumberOfVariables = "wrong number of variables"
errDuplicateAliasInEnumX = "duplicate value in enum '$1'"
errInvalidOrderInEnumX = "invalid order in enum '$1'"
errOverflowInEnumX = "The enum '$1' exceeds its maximum value ($2)"
errOrdinalTypeExpected = "ordinal type expected; given: $1"
errSetTooBig = "set is too large; use `std/sets` for ordinal types with more than 2^16 elements"
@@ -38,12 +38,12 @@ const
errNoGenericParamsAllowedForX = "no generic parameters allowed for $1"
errInOutFlagNotExtern = "the '$1' modifier can be used only with imported types"
proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext, son: sink PType): PType =
proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext, sons: seq[PType]): PType =
if prev == nil or prev.kind == tyGenericBody:
result = newTypeS(kind, c, son)
result = newTypeS(kind, c, sons = sons)
else:
result = prev
result.setSon(son)
result.setSons(sons)
if result.kind == tyForward: result.kind = kind
#if kind == tyError: result.flags.incl tfCheckedForDestructor
@@ -69,7 +69,6 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
e: PSym = nil
base: PType = nil
identToReplace: ptr PNode = nil
counterSet = initPackedSet[BiggestInt]()
counter = 0
base = nil
result = newOrPrevType(tyEnum, prev, c)
@@ -86,7 +85,6 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
var hasNull = false
for i in 1..<n.len:
if n[i].kind == nkEmpty: continue
var useAutoCounter = false
case n[i].kind
of nkEnumFieldDef:
if n[i][0].kind == nkPragmaExpr:
@@ -114,7 +112,6 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
of tyString, tyCstring:
strVal = v
x = counter
useAutoCounter = true
else:
if isOrdinalType(v.typ, allowEnumWithHoles=true):
x = toInt64(getOrdValue(v))
@@ -123,30 +120,22 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
localError(c.config, v.info, errOrdinalTypeExpected % typeToString(v.typ, preferDesc))
if i != 1:
if x != counter: incl(result.flags, tfEnumHasHoles)
if x < counter:
localError(c.config, n[i].info, errInvalidOrderInEnumX % e.name.s)
x = counter
e.ast = strVal # might be nil
counter = x
of nkSym:
e = n[i].sym
useAutoCounter = true
of nkIdent, nkAccQuoted:
e = newSymS(skEnumField, n[i], c)
identToReplace = addr n[i]
useAutoCounter = true
of nkPragmaExpr:
e = newSymS(skEnumField, n[i][0], c)
pragma(c, e, n[i][1], enumFieldPragmas)
identToReplace = addr n[i][0]
useAutoCounter = true
else:
illFormedAst(n[i], c.config)
if useAutoCounter:
while counter in counterSet and counter != high(typeof(counter)):
inc counter
counterSet.incl counter
elif counterSet.containsOrIncl(counter):
localError(c.config, n[i].info, errDuplicateAliasInEnumX % e.name.s)
e.typ = result
e.position = int(counter)
let symNode = newSymNode(e)
@@ -184,7 +173,7 @@ proc semSet(c: PContext, n: PNode, prev: PType): PType =
if n.len == 2 and n[1].kind != nkEmpty:
var base = semTypeNode(c, n[1], nil)
addSonSkipIntLit(result, base, c.idgen)
if base.kind in {tyGenericInst, tyAlias, tySink}: base = skipModifier(base)
if base.kind in {tyGenericInst, tyAlias, tySink}: base = lastSon(base)
if base.kind notin {tyGenericParam, tyGenericInvocation}:
if base.kind == tyForward:
c.skipTypes.add n
@@ -243,7 +232,7 @@ proc isRecursiveType(t: PType, cycleDetector: var IntSet): bool =
return true
case t.kind
of tyAlias, tyGenericInst, tyDistinct:
return isRecursiveType(t.skipModifier, cycleDetector)
return isRecursiveType(t.lastSon, cycleDetector)
else:
return false
@@ -390,11 +379,11 @@ proc semArrayIndex(c: PContext, n: PNode): PType =
localError(c.config, n.info,
"Array length can't be negative, but was " & $e.intVal)
result = makeRangeType(c, 0, e.intVal-1, n.info, e.typ)
elif e.kind == nkSym and (e.typ.kind == tyStatic or e.typ.kind == tyTypeDesc):
elif e.kind == nkSym and (e.typ.kind == tyStatic or e.typ.kind == tyTypeDesc) :
if e.typ.kind == tyStatic:
if e.sym.ast != nil:
return semArrayIndex(c, e.sym.ast)
if e.typ.skipModifier.kind != tyGenericParam and not isOrdinalType(e.typ.skipModifier):
if e.typ.lastSon.kind != tyGenericParam and not isOrdinalType(e.typ.lastSon):
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)
@@ -423,24 +412,21 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
# 3 = length(array indx base)
let indx = semArrayIndex(c, n[1])
var indxB = indx
if indxB.kind in {tyGenericInst, tyAlias, tySink}: indxB = skipModifier(indxB)
if indxB.kind in {tyGenericInst, tyAlias, tySink}: indxB = lastSon(indxB)
if indxB.kind notin {tyGenericParam, tyStatic, tyFromExpr} and
tfUnresolved notin indxB.flags:
if not isOrdinalType(indxB):
if indxB.skipTypes({tyRange}).kind in {tyUInt, tyUInt64}:
discard
elif not isOrdinalType(indxB):
localError(c.config, n[1].info, errOrdinalTypeExpected % typeToString(indxB, preferDesc))
elif enumHasHoles(indxB):
localError(c.config, n[1].info, "enum '$1' has holes" %
typeToString(indxB.skipTypes({tyRange})))
elif indxB.kind != tyRange and
lengthOrd(c.config, indxB) > high(uint16).int:
# assume range type is intentional
localError(c.config, n[1].info,
"index type '$1' for array is too large" % typeToString(indxB))
base = semTypeNode(c, n[2], nil)
# ensure we only construct a tyArray when there was no error (bug #3048):
# bug #6682: Do not propagate initialization requirements etc for the
# index type:
result = newOrPrevType(tyArray, prev, c, indx)
result = newOrPrevType(tyArray, prev, c, @[indx])
addSonSkipIntLit(result, base, c.idgen)
else:
localError(c.config, n.info, errArrayExpectsTwoTypeParams)
@@ -540,7 +526,7 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
result = newSymG(kind, n, c)
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags, fromTopLevel = false): PSym =
allowed: TSymFlags): PSym =
if n.kind == nkPragmaExpr:
checkSonsLen(n, 2, c.config)
result = semIdentVis(c, kind, n[0], allowed)
@@ -555,15 +541,11 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
else: discard
else:
result = semIdentVis(c, kind, n, allowed)
let invalidPragmasForPush = if fromTopLevel and sfWasGenSym notin result.flags:
{}
else:
{wExportc, wExportCpp, wDynlib}
case kind
of skField: implicitPragmas(c, result, n.info, fieldPragmas)
of skVar: implicitPragmas(c, result, n.info, varPragmas-invalidPragmasForPush)
of skLet: implicitPragmas(c, result, n.info, letPragmas-invalidPragmasForPush)
of skConst: implicitPragmas(c, result, n.info, constPragmas-invalidPragmasForPush)
of skVar: implicitPragmas(c, result, n.info, varPragmas)
of skLet: implicitPragmas(c, result, n.info, letPragmas)
of skConst: implicitPragmas(c, result, n.info, constPragmas)
else: discard
proc checkForOverlap(c: PContext, t: PNode, currentEx, branchIndex: int) =
@@ -574,14 +556,14 @@ proc checkForOverlap(c: PContext, t: PNode, currentEx, branchIndex: int) =
if overlap(t[i][j].skipConv, ex):
localError(c.config, ex.info, errDuplicateCaseLabel)
proc semBranchRange(c: PContext, n, a, b: PNode, covered: var Int128): PNode =
checkMinSonsLen(n, 1, c.config)
proc semBranchRange(c: PContext, t, a, b: PNode, covered: var Int128): PNode =
checkMinSonsLen(t, 1, c.config)
let ac = semConstExpr(c, a)
let bc = semConstExpr(c, b)
if ac.kind in {nkStrLit..nkTripleStrLit} or bc.kind in {nkStrLit..nkTripleStrLit}:
localError(c.config, b.info, "range of string is invalid")
let at = fitNode(c, n[0].typ, ac, ac.info).skipConvTakeType
let bt = fitNode(c, n[0].typ, bc, bc.info).skipConvTakeType
let at = fitNode(c, t[0].typ, ac, ac.info).skipConvTakeType
let bt = fitNode(c, t[0].typ, bc, bc.info).skipConvTakeType
result = newNodeI(nkRange, a.info)
result.add(at)
@@ -594,19 +576,19 @@ proc semCaseBranchRange(c: PContext, t, b: PNode,
checkSonsLen(b, 3, c.config)
result = semBranchRange(c, t, b[1], b[2], covered)
proc semCaseBranchSetElem(c: PContext, n, b: PNode,
proc semCaseBranchSetElem(c: PContext, t, b: PNode,
covered: var Int128): PNode =
if isRange(b):
checkSonsLen(b, 3, c.config)
result = semBranchRange(c, n, b[1], b[2], covered)
result = semBranchRange(c, t, b[1], b[2], covered)
elif b.kind == nkRange:
checkSonsLen(b, 2, c.config)
result = semBranchRange(c, n, b[0], b[1], covered)
result = semBranchRange(c, t, b[0], b[1], covered)
else:
result = fitNode(c, n[0].typ, b, b.info)
result = fitNode(c, t[0].typ, b, b.info)
inc(covered)
proc semCaseBranch(c: PContext, n, branch: PNode, branchIndex: int,
proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
covered: var Int128) =
let lastIndex = branch.len - 2
for i in 0..lastIndex:
@@ -614,22 +596,22 @@ proc semCaseBranch(c: PContext, n, branch: PNode, branchIndex: int,
if b.kind == nkRange:
branch[i] = b
elif isRange(b):
branch[i] = semCaseBranchRange(c, n, b, covered)
branch[i] = semCaseBranchRange(c, t, b, covered)
else:
# constant sets and arrays are allowed:
# set expected type to selector type for type inference
# even if it can be a different type like a set or array
var r = semConstExpr(c, b, expectedType = n[0].typ)
var r = semConstExpr(c, b, expectedType = t[0].typ)
if r.kind in {nkCurly, nkBracket} and r.len == 0 and branch.len == 2:
# discarding ``{}`` and ``[]`` branches silently
delSon(branch, 0)
return
elif r.kind notin {nkCurly, nkBracket} or r.len == 0:
checkMinSonsLen(n, 1, c.config)
var tmp = fitNode(c, n[0].typ, r, r.info)
checkMinSonsLen(t, 1, c.config)
var tmp = fitNode(c, t[0].typ, r, r.info)
# the call to fitNode may introduce a call to a converter
if tmp.kind == nkHiddenCallConv or
(tmp.kind == nkHiddenStdConv and n[0].typ.kind == tyCstring):
(tmp.kind == nkHiddenStdConv and t[0].typ.kind == tyCstring):
tmp = semConstExpr(c, tmp)
branch[i] = skipConv(tmp)
inc(covered)
@@ -638,18 +620,18 @@ proc semCaseBranch(c: PContext, n, branch: PNode, branchIndex: int,
r = deduplicate(c.config, r)
# first element is special and will overwrite: branch[i]:
branch[i] = semCaseBranchSetElem(c, n, r[0], covered)
branch[i] = semCaseBranchSetElem(c, t, r[0], covered)
# other elements have to be added to ``branch``
for j in 1..<r.len:
branch.add(semCaseBranchSetElem(c, n, r[j], covered))
branch.add(semCaseBranchSetElem(c, t, r[j], covered))
# caution! last son of branch must be the actions to execute:
swap(branch[^2], branch[^1])
checkForOverlap(c, n, i, branchIndex)
checkForOverlap(c, t, i, branchIndex)
# Elements added above needs to be checked for overlaps.
for i in lastIndex.succ..<branch.len - 1:
checkForOverlap(c, n, i, branchIndex)
checkForOverlap(c, t, i, branchIndex)
proc toCover(c: PContext, t: PType): Int128 =
let t2 = skipTypes(t, abstractVarRange-{tyTypeDesc})
@@ -741,7 +723,7 @@ proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
of tyFloat..tyFloat128, tyError:
discard
of tyRange:
if skipTypes(typ.elementType, abstractInst).kind in shouldChckCovered:
if skipTypes(typ[0], abstractInst).kind in shouldChckCovered:
chckCovered = true
of tyForward:
errorUndeclaredIdentifier(c, n[0].info, typ.sym.name.s)
@@ -915,7 +897,7 @@ proc skipGenericInvocation(t: PType): PType {.inline.} =
if result.kind == tyGenericInvocation:
result = result[0]
while result.kind in {tyGenericInst, tyGenericBody, tyRef, tyPtr, tyAlias, tySink, tyOwned}:
result = skipModifier(result)
result = lastSon(result)
proc tryAddInheritedFields(c: PContext, check: var IntSet, pos: var int,
obj: PType, n: PNode, isPartial = false, innerObj: PType = nil): bool =
@@ -1031,16 +1013,16 @@ 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.flags, tfPartial)
if result.lastSon.kind == tyObject: incl(result.lastSon.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)
let t = newTypeS(tyOwned, c, @[result])
t.flags.incl tfHasOwned
result = t
of tySink:
let t = newTypeS(tySink, c, result)
let t = newTypeS(tySink, c, @[result])
result = t
else: discard
if result.kind == tyRef and c.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
@@ -1054,7 +1036,7 @@ proc findEnforcedStaticType(t: PType): PType =
if t == nil: return nil
if t.kind == tyStatic: return t
if t.kind == tyAnd:
for s in t.kids:
for s in t:
let t = findEnforcedStaticType(s)
if t != nil: return t
@@ -1135,7 +1117,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
let base = (if lifted != nil: lifted else: paramType.base)
if base.isMetaType and procKind == skMacro:
localError(c.config, info, errMacroBodyDependsOnGenericTypes % paramName)
result = addImplicitGeneric(c, newTypeS(tyStatic, c, base),
result = addImplicitGeneric(c, c.newTypeWithSons(tyStatic, @[base]),
paramTypId, info, genericParams, paramName)
if result != nil: result.flags.incl({tfHasStatic, tfUnresolved})
@@ -1147,7 +1129,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
paramTypId.id == getIdent(c.cache, "type").id):
# XXX Why doesn't this check for tyTypeDesc instead?
paramTypId = nil
let t = newTypeS(tyTypeDesc, c, paramType.base)
let t = c.newTypeWithSons(tyTypeDesc, @[paramType.base])
incl t.flags, tfCheckedForDestructor
result = addImplicitGeneric(c, t, paramTypId, info, genericParams, paramName)
else:
@@ -1177,9 +1159,9 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
# like: type myseq = distinct seq.
# Maybe there is another better place to associate
# the seq type class with the seq identifier.
if paramType.kind == tySequence and paramType.elementType.kind == tyNone:
let typ = newTypeS(tyBuiltInTypeClass, c,
newTypeS(paramType.kind, c))
if paramType.kind == tySequence and paramType.lastSon.kind == tyNone:
let typ = c.newTypeWithSons(tyBuiltInTypeClass,
@[newTypeS(paramType.kind, c)])
result = addImplicitGeneric(c, typ, paramTypId, info, genericParams, paramName)
else:
result = nil
@@ -1203,21 +1185,21 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
else:
result.rawAddSon newTypeS(tyAnything, c)
if paramType.typeBodyImpl.kind == tyUserTypeClass:
if paramType.lastSon.kind == tyUserTypeClass:
result.kind = tyUserTypeClassInst
result.rawAddSon paramType.typeBodyImpl
result.rawAddSon paramType.lastSon
return addImplicitGeneric(c, result, paramTypId, info, genericParams, paramName)
let x = instGenericContainer(c, paramType.sym.info, result,
allowMetaTypes = true)
result = newTypeS(tyCompositeTypeClass, c)
result.rawAddSon paramType
result.rawAddSon x
result = newTypeWithSons(c, tyCompositeTypeClass, @[paramType, x])
#result = newTypeS(tyCompositeTypeClass, c)
#for i in 0..<x.len: result.rawAddSon(x[i])
result = addImplicitGeneric(c, result, paramTypId, info, genericParams, paramName)
of tyGenericInst:
result = nil
if paramType.skipModifier.kind == tyUserTypeClass:
if paramType.lastSon.kind == tyUserTypeClass:
var cp = copyType(paramType, c.idgen, getCurrOwner(c))
copyTypeProps(c.graph, c.idgen.module, cp, paramType)
@@ -1229,9 +1211,9 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
if lifted != nil:
paramType[i] = lifted
result = paramType
result.last.shouldHaveMeta
result.lastSon.shouldHaveMeta
let liftBody = recurse(paramType.skipModifier, true)
let liftBody = recurse(paramType.lastSon, true)
if liftBody != nil:
result = liftBody
result.flags.incl tfHasMeta
@@ -1250,7 +1232,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
# before one of its param types
return
if body.last.kind == tyUserTypeClass:
if body.lastSon.kind == tyUserTypeClass:
let expanded = instGenericContainer(c, info, paramType,
allowMetaTypes = true)
result = recurse(expanded, true)
@@ -1371,7 +1353,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
# which will prevent other types from matching - clearly a very
# 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 = newTypeWithSons(c, tyTypeDesc, @[newTypeS(tyNone, c)])
typ.flags.incl tfCheckedForDestructor
else:
@@ -1454,8 +1436,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
"' 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.flags.incl tfRetType
discard
elif r.kind == tyStatic:
# type allowed should forbid this type
discard
@@ -1528,7 +1509,7 @@ proc trySemObjectTypeForInheritedGenericInst(c: PContext, n: PNode, t: PType): b
check = initIntSet()
pos = 0
let
realBase = t.baseClass
realBase = t[0]
base = skipTypesOrNil(realBase, skipPtrs)
result = true
if base.isNil:
@@ -1712,8 +1693,8 @@ proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
inherited = n[2]
var owner = getCurrOwner(c)
var candidateTypeSlot = newTypeS(tyAlias, c, c.errorType)
result = newOrPrevType(tyUserTypeClass, prev, c, son = candidateTypeSlot)
var candidateTypeSlot = newTypeWithSons(owner, tyAlias, @[c.errorType], c.idgen)
result = newOrPrevType(tyUserTypeClass, prev, c, sons = @[candidateTypeSlot])
result.flags.incl tfCheckedForDestructor
result.n = n
@@ -1876,7 +1857,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
# it's not bound when it's used multiple times in the
# proc signature for example
if c.inGenericInst > 0:
let bound = result.typ.elementType.sym
let bound = result.typ[0].sym
if bound != nil: return bound
return result
if result.typ.sym == nil:
@@ -1898,7 +1879,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
return errorSym(c, n)
if result.kind != skType and result.magic notin {mStatic, mType, mTypeOf}:
# this implements the wanted ``var v: V, x: V`` feature ...
var ov: TOverloadIter = default(TOverloadIter)
var ov: TOverloadIter
var amb = initOverloadIter(ov, c, n)
while amb != nil and amb.kind != skType:
amb = nextOverloadIter(ov, c, n)
@@ -2195,10 +2176,6 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
else:
let symKind = if n.kind == nkIteratorTy: skIterator else: skProc
result = semProcTypeWithScope(c, n, prev, symKind)
if result == nil:
localError(c.config, n.info, "type expected, but got: " & renderTree(n))
result = newOrPrevType(tyError, prev, c)
if n.kind == nkIteratorTy and result.kind == tyProc:
result.flags.incl(tfIterator)
if result.callConv == ccClosure and c.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
@@ -2319,7 +2296,7 @@ proc processMagicType(c: PContext, m: PSym) =
else: localError(c.config, m.info, errTypeExpected)
proc semGenericConstraints(c: PContext, x: PType): PType =
result = newTypeS(tyGenericParam, c, x)
result = newTypeWithSons(c, tyGenericParam, @[x])
proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
@@ -2345,8 +2322,8 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
typ = semTypeNode(c, constraint, nil)
if typ.kind != tyStatic or typ.len == 0:
if typ.kind == tyTypeDesc:
if typ.elementType.kind == tyNone:
typ = newTypeS(tyTypeDesc, c, newTypeS(tyNone, c))
if typ[0].kind == tyNone:
typ = newTypeWithSons(c, tyTypeDesc, @[newTypeS(tyNone, c)])
incl typ.flags, tfCheckedForDestructor
else:
typ = semGenericConstraints(c, typ)
@@ -2355,7 +2332,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
def = semConstExpr(c, def)
if typ == nil:
if def.typ.kind != tyTypeDesc:
typ = newTypeS(tyStatic, c, def.typ)
typ = newTypeWithSons(c, tyStatic, @[def.typ])
else:
# the following line fixes ``TV2*[T:SomeNumber=TR] = array[0..1, T]``
# from manyloc/named_argument_bug/triengine:

View File

@@ -9,8 +9,6 @@
# This module does the instantiation of generic types.
import std / tables
import ast, astalgo, msgs, types, magicsys, semdata, renderer, options,
lineinfos, modulegraphs
@@ -20,16 +18,20 @@ when defined(nimPreviewSlimSystem):
const tfInstClearedFlags = {tfHasMeta, tfUnresolved}
proc checkPartialConstructedType(conf: ConfigRef; info: TLineInfo, t: PType) =
if t.kind in {tyVar, tyLent} and t.elementType.kind in {tyVar, tyLent}:
if t.kind in {tyVar, tyLent} and t[0].kind in {tyVar, tyLent}:
localError(conf, info, "type 'var var' is not allowed")
proc checkConstructedType*(conf: ConfigRef; info: TLineInfo, typ: PType) =
var t = typ.skipTypes({tyDistinct})
if t.kind in tyTypeClasses: discard
elif t.kind in {tyVar, tyLent} and t.elementType.kind in {tyVar, tyLent}:
elif t.kind in {tyVar, tyLent} and t[0].kind in {tyVar, tyLent}:
localError(conf, info, "type 'var var' is not allowed")
elif computeSize(conf, t) == szIllegalRecursion or isTupleRecursive(t):
localError(conf, info, "illegal recursion in type '" & typeToString(t) & "'")
when false:
if t.kind == tyObject and t[0] != nil:
if t[0].kind != tyObject or tfFinal in t[0].flags:
localError(info, errInheritanceOnlyWithNonFinalObjects)
proc searchInstTypes*(g: ModuleGraph; key: PType): PType =
result = nil
@@ -39,7 +41,7 @@ proc searchInstTypes*(g: ModuleGraph; key: PType): PType =
for inst in typeInstCacheItems(g, genericTyp.sym):
if inst.id == key.id: return inst
if inst.kidsLen < key.kidsLen:
if inst.len < key.len:
# XXX: This happens for prematurely cached
# types such as Channel[empty]. Why?
# See the notes for PActor in handleGenericInvocation
@@ -49,7 +51,7 @@ proc searchInstTypes*(g: ModuleGraph; key: PType): PType =
continue
block matchType:
for j in FirstGenericParamAt..<key.kidsLen:
for j in 1..<len(key):
# XXX sameType is not really correct for nested generics?
if not compareTypes(inst[j], key[j],
flags = {ExactGenericParams, PickyCAliases}):
@@ -59,21 +61,21 @@ proc searchInstTypes*(g: ModuleGraph; key: PType): PType =
proc cacheTypeInst(c: PContext; inst: PType) =
let gt = inst[0]
let t = if gt.kind == tyGenericBody: gt.typeBodyImpl else: gt
let t = if gt.kind == tyGenericBody: gt.lastSon else: gt
if t.kind in {tyStatic, tyError, tyGenericParam} + tyTypeClasses:
return
addToGenericCache(c, gt.sym, inst)
type
LayeredIdTable* {.acyclic.} = ref object
topLayer*: TypeMapping
topLayer*: TIdTable
nextLayer*: LayeredIdTable
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*: TIdTable # map PSym to PSym
localCache*: TIdTable # local cache for remembering already replaced
# types during instantiation of meta types
# (they are not stored in the global cache)
info*: TLineInfo
@@ -85,26 +87,26 @@ type
recursionLimit: int
proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType
proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym, t: PType): PSym
proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
proc replaceTypeVarsN*(cl: var TReplTypeVars, n: PNode; start=0; expectedType: PType = nil): PNode
proc initLayeredTypeMap*(pt: sink TypeMapping): LayeredIdTable =
proc initLayeredTypeMap*(pt: TIdTable): LayeredIdTable =
result = LayeredIdTable()
result.topLayer = pt
copyIdTable(result.topLayer, pt)
proc newTypeMapLayer*(cl: var TReplTypeVars): LayeredIdTable =
result = LayeredIdTable(nextLayer: cl.typeMap, topLayer: initTable[ItemId, PType]())
result = LayeredIdTable(nextLayer: cl.typeMap, topLayer: initIdTable())
proc lookup(typeMap: LayeredIdTable, key: PType): PType =
result = nil
var tm = typeMap
while tm != nil:
result = getOrDefault(tm.topLayer, key.itemId)
result = PType(idTableGet(tm.topLayer, key))
if result != nil: return
tm = tm.nextLayer
template put(typeMap: LayeredIdTable, key, value: PType) =
typeMap.topLayer[key.itemId] = value
idTablePut(typeMap.topLayer, key, value)
template checkMetaInvariants(cl: TReplTypeVars, t: PType) = # noop code
when false:
@@ -125,12 +127,7 @@ proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode =
else: t.n
result = copyNode(n)
result.typ = t
if result.kind == nkSym:
result.sym =
if n.typ != nil and n.typ == n.sym.typ:
replaceTypeVarsS(cl, n.sym, result.typ)
else:
replaceTypeVarsS(cl, n.sym, replaceTypeVarsT(cl, n.sym.typ))
if result.kind == nkSym: result.sym = replaceTypeVarsS(cl, n.sym)
let isCall = result.kind in nkCallKinds
for i in 0..<n.safeLen:
# XXX HACK: ``f(a, b)``, avoid to instantiate `f`
@@ -225,11 +222,7 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0; expectedType: PT
discard
of nkOpenSymChoice, nkClosedSymChoice: result = n
of nkSym:
result.sym =
if n.typ != nil and n.typ == n.sym.typ:
replaceTypeVarsS(cl, n.sym, result.typ)
else:
replaceTypeVarsS(cl, n.sym, replaceTypeVarsT(cl, n.sym.typ))
result.sym = replaceTypeVarsS(cl, n.sym)
if result.sym.typ.kind == tyVoid:
# don't add the 'void' field
result = newNodeI(nkRecList, n.info)
@@ -271,7 +264,7 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0; expectedType: PT
for i in start..<n.len:
result[i] = replaceTypeVarsN(cl, n[i])
proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym, t: PType): PSym =
proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
if s == nil: return nil
# symbol is not our business:
if cl.owner != nil and s.owner != cl.owner:
@@ -312,14 +305,11 @@ proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym, t: PType): PSym =
incl(result.flags, sfFromGeneric)
#idTablePut(cl.symMap, s, result)
result.owner = s.owner
result.typ = t
result.typ = replaceTypeVarsT(cl, s.typ)
if result.kind != skType:
result.ast = replaceTypeVarsN(cl, s.ast)
proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
if tfRetType in t.flags and t.kind == tyAnything:
# don't bind `auto` return type to a previous binding of `auto`
return nil
result = cl.typeMap.lookup(t)
if result == nil:
if cl.allowMetaTypes or tfRetType in t.flags: return
@@ -357,13 +347,13 @@ proc instCopyType*(cl: var TReplTypeVars, t: PType): PType =
proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
# tyGenericInvocation[A, tyGenericInvocation[A, B]]
# is difficult to handle:
var body = t.genericHead
var body = t[0]
if body.kind != tyGenericBody:
internalError(cl.c.config, cl.info, "no generic body")
var header = t
# search for some instantiation here:
if cl.allowMetaTypes:
result = getOrDefault(cl.localCache, t.itemId)
result = PType(idTableGet(cl.localCache, t))
else:
result = searchInstTypes(cl.c.graph, t)
@@ -371,7 +361,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
when defined(reportCacheHits):
echo "Generic instantiation cached ", typeToString(result), " for ", typeToString(t)
return
for i in FirstGenericParamAt..<t.kidsLen:
for i in 1..<t.len:
var x = t[i]
if x.kind in {tyGenericParam}:
x = lookupTypeVar(cl, x)
@@ -393,7 +383,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
else:
header = instCopyType(cl, t)
result = newType(tyGenericInst, cl.c.idgen, t.genericHead.owner, son = header.genericHead)
result = newType(tyGenericInst, cl.c.idgen, t[0].owner, sons = @[header[0]])
result.flags = header.flags
# be careful not to propagate unnecessary flags here (don't use rawAddSon)
# ugh need another pass for deeply recursive generic types (e.g. PActor)
@@ -402,14 +392,14 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
if not cl.allowMetaTypes:
cacheTypeInst(cl.c, result)
else:
cl.localCache[t.itemId] = result
idTablePut(cl.localCache, t, result)
let oldSkipTypedesc = cl.skipTypedesc
cl.skipTypedesc = true
cl.typeMap = newTypeMapLayer(cl)
for i in FirstGenericParamAt..<t.kidsLen:
for i in 1..<t.len:
var x = replaceTypeVarsT(cl):
if header[i].kind == tyGenericInst:
t[i]
@@ -420,7 +410,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
propagateToOwner(header, x)
cl.typeMap.put(body[i-1], x)
for i in FirstGenericParamAt..<t.kidsLen:
for i in 1..<t.len:
# if one of the params is not concrete, we cannot do anything
# but we already raised an error!
rawAddSon(result, header[i], propagateHasAsgn = false)
@@ -428,7 +418,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
if body.kind == tyError:
return
let bbody = last body
let bbody = lastSon body
var newbody = replaceTypeVarsT(cl, bbody)
cl.skipTypedesc = oldSkipTypedesc
newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags)
@@ -459,11 +449,11 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
# can come here for tyGenericInst too, see tests/metatype/ttypeor.nim
# need to look into this issue later
assert newbody.kind in {tyRef, tyPtr}
if newbody.last.typeInst != nil:
if newbody.lastSon.typeInst != nil:
#internalError(cl.c.config, cl.info, "ref already has a 'typeInst' field")
discard
else:
newbody.last.typeInst = result
newbody.lastSon.typeInst = result
# DESTROY: adding object|opt for opt[topttree.Tree]
# sigmatch: Formal opt[=destroy.T] real opt[topttree.Tree]
# adding myseq for myseq[system.int]
@@ -483,14 +473,14 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
proc eraseVoidParams*(t: PType) =
# transform '(): void' into '()' because old parts of the compiler really
# don't deal with '(): void':
if t.returnType != nil and t.returnType.kind == tyVoid:
t.setReturnType nil
if t[0] != nil and t[0].kind == tyVoid:
t[0] = nil
for i in FirstParamAt..<t.signatureLen:
for i in 1..<t.len:
# don't touch any memory unless necessary
if t[i].kind == tyVoid:
var pos = i
for j in i+1..<t.signatureLen:
for j in i+1..<t.len:
if t[j].kind != tyVoid:
t[pos] = t[j]
t.n[pos] = t.n[j]
@@ -500,7 +490,8 @@ proc eraseVoidParams*(t: PType) =
break
proc skipIntLiteralParams*(t: PType; idgen: IdGenerator) =
for i, p in t.ikids:
for i in 0..<t.len:
let p = t[i]
if p == nil: continue
let skipped = p.skipIntLit(idgen)
if skipped != p:
@@ -509,8 +500,8 @@ proc skipIntLiteralParams*(t: PType; idgen: IdGenerator) =
# when the typeof operator is used on a static input
# param, the results gets infected with static as well:
if t.returnType != nil and t.returnType.kind == tyStatic:
t.setReturnType t.returnType.skipModifier
if t[0] != nil and t[0].kind == tyStatic:
t[0] = t[0].base
proc propagateFieldFlags(t: PType, n: PNode) =
# This is meant for objects and tuples
@@ -549,23 +540,21 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
# type
# Vector[N: static[int]] = array[N, float64]
# TwoVectors[Na, Nb: static[int]] = (Vector[Na], Vector[Nb])
result = getOrDefault(cl.localCache, t.itemId)
result = PType(idTableGet(cl.localCache, t))
if result != nil: return result
inc cl.recursionLimit
result = t
if t == nil: return
const lookupMetas = {tyStatic, tyGenericParam, tyConcept} + tyTypeClasses - {tyAnything}
if t.kind in lookupMetas or
(t.kind == tyAnything and tfRetType notin t.flags):
if t.kind in {tyStatic, tyGenericParam, tyConcept} + tyTypeClasses:
let lookup = cl.typeMap.lookup(t)
if lookup != nil: return lookup
case t.kind
of tyGenericInvocation:
result = handleGenericInvocation(cl, t)
if result.last.kind == tyUserTypeClass:
if result.lastSon.kind == tyUserTypeClass:
result.kind = tyUserTypeClassInst
of tyGenericBody:
@@ -600,7 +589,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
# return tyStatic values to let anyone make
# use of this knowledge. The patching here
# won't be necessary then.
result = newTypeS(tyStatic, cl.c, son = n.typ)
result = newTypeS(tyStatic, cl.c, sons = @[n.typ])
result.n = n
else:
result = n.typ
@@ -616,8 +605,8 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
result = makeTypeDesc(cl.c, result)
elif tfUnresolved in t.flags or cl.skipTypedesc:
result = result.base
elif t.elementType.kind != tyNone:
result = makeTypeDesc(cl.c, replaceTypeVarsT(cl, t.elementType))
elif t[0].kind != tyNone:
result = makeTypeDesc(cl.c, replaceTypeVarsT(cl, t[0]))
of tyUserTypeClass, tyStatic:
result = t
@@ -625,10 +614,10 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
of tyGenericInst, tyUserTypeClassInst:
bailout()
result = instCopyType(cl, t)
cl.localCache[t.itemId] = result
for i in FirstGenericParamAt..<result.kidsLen:
idTablePut(cl.localCache, t, result)
for i in 1..<result.len:
result[i] = replaceTypeVarsT(cl, result[i])
propagateToOwner(result, result.last)
propagateToOwner(result, result.lastSon)
else:
if containsGenericType(t):
@@ -637,17 +626,17 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
result = instCopyType(cl, t)
result.size = -1 # needs to be recomputed
#if not cl.allowMetaTypes:
cl.localCache[t.itemId] = result
idTablePut(cl.localCache, t, result)
for i, resulti in result.ikids:
if resulti != nil:
if resulti.kind == tyGenericBody:
for i in 0..<result.len:
if result[i] != nil:
if result[i].kind == tyGenericBody:
localError(cl.c.config, if t.sym != nil: t.sym.info else: cl.info,
"cannot instantiate '" &
typeToString(result[i], preferDesc) &
"' inside of type definition: '" &
t.owner.name.s & "'; Maybe generic arguments are missing?")
var r = replaceTypeVarsT(cl, resulti)
var r = replaceTypeVarsT(cl, result[i])
if result.kind == tyObject:
# carefully coded to not skip the precious tyGenericInst:
let r2 = r.skipTypes({tyAlias, tySink, tyOwned})
@@ -660,7 +649,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
result.n = replaceTypeVarsN(cl, result.n, ord(result.kind==tyProc))
case result.kind
of tyArray:
let idx = result.indexType
let idx = result[0]
internalAssert cl.c.config, idx.kind != tyStatic
of tyObject, tyTuple:
@@ -673,7 +662,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
skipIntLiteralParams(result, cl.c.idgen)
of tyRange:
result.setIndexType result.indexType.skipTypes({tyStatic, tyDistinct})
result[0] = result[0].skipTypes({tyStatic, tyDistinct})
else: discard
else:
@@ -682,8 +671,8 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
result = t
# Slow path, we have some work to do
if t.kind == tyRef and t.hasElementType and t.elementType.kind == tyObject and t.elementType.n != nil:
discard replaceObjBranches(cl, t.elementType.n)
if t.kind == tyRef and t.len > 0 and t[0].kind == tyObject and t[0].n != nil:
discard replaceObjBranches(cl, t[0].n)
elif result.n != nil and t.kind == tyObject:
# Invalidate the type size as we may alter its structure
@@ -692,11 +681,11 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
proc initTypeVars*(p: PContext, typeMap: LayeredIdTable, info: TLineInfo;
owner: PSym): TReplTypeVars =
result = TReplTypeVars(symMap: initSymMapping(),
localCache: initTypeMapping(), typeMap: typeMap,
result = TReplTypeVars(symMap: initIdTable(),
localCache: initIdTable(), typeMap: typeMap,
info: info, c: p, owner: owner)
proc replaceTypesInBody*(p: PContext, pt: TypeMapping, n: PNode;
proc replaceTypesInBody*(p: PContext, pt: TIdTable, n: PNode;
owner: PSym, allowMetaTypes = false,
fromStaticExpr = false, expectedType: PType = nil): PNode =
var typeMap = initLayeredTypeMap(pt)
@@ -718,8 +707,8 @@ when false:
popInfoContext(p.config)
proc recomputeFieldPositions*(t: PType; obj: PNode; currPosition: var int) =
if t != nil and t.baseClass != nil:
let b = skipTypes(t.baseClass, skipPtrs)
if t != nil and t.len > 0 and t[0] != nil:
let b = skipTypes(t[0], skipPtrs)
recomputeFieldPositions(b, b.n, currPosition)
case obj.kind
of nkRecList:
@@ -733,7 +722,7 @@ proc recomputeFieldPositions*(t: PType; obj: PNode; currPosition: var int) =
inc currPosition
else: discard "cannot happen"
proc generateTypeInstance*(p: PContext, pt: TypeMapping, info: TLineInfo,
proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo,
t: PType): PType =
# Given `t` like Foo[T]
# pt: Table with type mappings: T -> int
@@ -749,7 +738,7 @@ proc generateTypeInstance*(p: PContext, pt: TypeMapping, info: TLineInfo,
var position = 0
recomputeFieldPositions(objType, objType.n, position)
proc prepareMetatypeForSigmatch*(p: PContext, pt: TypeMapping, info: TLineInfo,
proc prepareMetatypeForSigmatch*(p: PContext, pt: TIdTable, info: TLineInfo,
t: PType): PType =
var typeMap = initLayeredTypeMap(pt)
var cl = initTypeVars(p, typeMap, info, nil)
@@ -758,6 +747,6 @@ proc prepareMetatypeForSigmatch*(p: PContext, pt: TypeMapping, info: TLineInfo,
result = replaceTypeVarsT(cl, t)
popInfoContext(p.config)
template generateTypeInstance*(p: PContext, pt: TypeMapping, arg: PNode,
template generateTypeInstance*(p: PContext, pt: TIdTable, arg: PNode,
t: PType): untyped =
generateTypeInstance(p, pt, arg.info, t)

View File

@@ -104,15 +104,15 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi
case t.kind
of tyGenericInvocation:
for a in t.kids:
c.hashType a, flags, conf
for i in 0..<t.len:
c.hashType t[i], flags, conf
of tyDistinct:
if CoDistinct in flags:
if t.sym != nil: c.hashSym(t.sym)
if t.sym == nil or tfFromGeneric in t.flags:
c.hashType t.elementType, flags, conf
c.hashType t.lastSon, flags, conf
elif CoType in flags or t.sym == nil:
c.hashType t.elementType, flags, conf
c.hashType t.lastSon, flags, conf
else:
c.hashSym(t.sym)
of tyGenericInst:
@@ -121,17 +121,16 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi
# We cannot trust the `lastSon` to hold a properly populated and unique
# value for each instantiation, so we hash the generic parameters here:
let normalizedType = t.skipGenericAlias
c.hashType normalizedType.genericHead, flags, conf
for _, a in normalizedType.genericInstParams:
c.hashType a, flags, conf
for i in 0..<normalizedType.len - 1:
c.hashType t[i], flags, conf
else:
c.hashType t.skipModifier, flags, conf
c.hashType t.lastSon, flags, conf
of tyAlias, tySink, tyUserTypeClasses, tyInferred:
c.hashType t.skipModifier, flags, conf
c.hashType t.lastSon, flags, conf
of tyOwned:
if CoConsiderOwned in flags:
c &= char(t.kind)
c.hashType t.skipModifier, flags, conf
c.hashType t.lastSon, flags, conf
of tyBool, tyChar, tyInt..tyUInt64:
# no canonicalization for integral types, so that e.g. ``pid_t`` is
# produced instead of ``NI``:
@@ -144,9 +143,8 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi
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
for i in 0..<inst.len - 1:
c.hashType inst[i], flags, conf
t.typeInst = inst
return
c &= char(t.kind)
@@ -186,40 +184,37 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi
c &= ".empty"
else:
c &= t.id
if t.hasElementType and t.baseClass != nil:
hashType c, t.baseClass, flags, conf
of tyRef, tyPtr, tyVar:
if t.len > 0 and t[0] != nil:
hashType c, t[0], flags, conf
of tyRef, tyPtr, tyGenericBody, tyVar:
c &= char(t.kind)
if t.hasElementType:
c.hashType t.elementType, flags, conf
if t.len > 0:
c.hashType t.lastSon, flags, conf
if tfVarIsPtr in t.flags: c &= ".varisptr"
of tyGenericBody:
c &= char(t.kind)
if t.hasElementType:
c.hashType t.typeBodyImpl, flags, conf
of tyFromExpr:
c &= char(t.kind)
c.hashTree(t.n, {}, conf)
of tyTuple:
c &= char(t.kind)
if t.n != nil and CoType notin flags:
assert(t.n.len == t.len)
for i in 0..<t.n.len:
assert(t.n[i].kind == nkSym)
c &= t.n[i].sym.name.s
c &= ':'
c.hashType(t.n[i].sym.typ, flags+{CoIgnoreRange}, conf)
c.hashType(t[i], flags+{CoIgnoreRange}, conf)
c &= ','
else:
for a in t.kids: c.hashType a, flags+{CoIgnoreRange}, conf
for i in 0..<t.len: c.hashType t[i], flags+{CoIgnoreRange}, conf
of tyRange:
if CoIgnoreRange notin flags:
c &= char(t.kind)
c.hashTree(t.n, {}, conf)
c.hashType(t.elementType, flags, conf)
c.hashType(t[0], flags, conf)
of tyStatic:
c &= char(t.kind)
c.hashTree(t.n, {}, conf)
c.hashType(t.skipModifier, flags, conf)
c.hashType(t[0], flags, conf)
of tyProc:
c &= char(t.kind)
c &= (if tfIterator in t.flags: "iterator " else: "proc ")
@@ -231,9 +226,9 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi
c &= ':'
c.hashType(param.typ, flags, conf)
c &= ','
c.hashType(t.returnType, flags, conf)
c.hashType(t[0], flags, conf)
else:
for a in t.signature: c.hashType(a, flags, conf)
for i in 0..<t.len: c.hashType(t[i], flags, conf)
c &= char(t.callConv)
# purity of functions doesn't have to affect the mangling (which is in fact
# problematic for HCR - someone could have cached a pointer to another
@@ -245,11 +240,10 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi
if tfVarargs in t.flags: c &= ".varargs"
of tyArray:
c &= char(t.kind)
c.hashType(t.indexType, flags-{CoIgnoreRange}, conf)
c.hashType(t.elementType, flags-{CoIgnoreRange}, conf)
for i in 0..<t.len: c.hashType(t[i], flags-{CoIgnoreRange}, conf)
else:
c &= char(t.kind)
for a in t.kids: c.hashType(a, flags, conf)
for i in 0..<t.len: c.hashType(t[i], flags, conf)
if tfNotNil in t.flags and CoType notin flags: c &= "not nil"
when defined(debugSigHashes):
@@ -268,7 +262,7 @@ when defined(debugSigHashes):
proc hashType*(t: PType; conf: ConfigRef; flags: set[ConsiderFlag] = {CoType}): SigHash =
result = default(SigHash)
var c: MD5Context = default(MD5Context)
var c: MD5Context
md5Init c
hashType c, t, flags+{CoOwnerSig}, conf
md5Final c, result.MD5Digest
@@ -278,7 +272,7 @@ proc hashType*(t: PType; conf: ConfigRef; flags: set[ConsiderFlag] = {CoType}):
proc hashProc(s: PSym; conf: ConfigRef): SigHash =
result = default(SigHash)
var c: MD5Context = default(MD5Context)
var c: MD5Context
md5Init c
hashType c, s.typ, {CoProc}, conf
@@ -299,7 +293,7 @@ proc hashProc(s: PSym; conf: ConfigRef): SigHash =
proc hashNonProc*(s: PSym): SigHash =
result = default(SigHash)
var c: MD5Context = default(MD5Context)
var c: MD5Context
md5Init c
hashSym(c, s)
var it = s
@@ -316,7 +310,7 @@ proc hashNonProc*(s: PSym): SigHash =
proc hashOwner*(s: PSym): SigHash =
result = default(SigHash)
var c: MD5Context = default(MD5Context)
var c: MD5Context
md5Init c
var m = s
while m.kind != skModule: m = m.owner
@@ -389,7 +383,7 @@ proc symBodyDigest*(graph: ModuleGraph, sym: PSym): SigHash =
graph.symBodyHashes.withValue(sym.id, value):
return value[]
var c: MD5Context = default(MD5Context)
var c: MD5Context
md5Init(c)
c.hashType(sym.typ, {CoProc}, graph.config)
c &= char(sym.kind)

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