fixes #1940; code breakage! stricter template evaluation
This commit is contained in:
parent
c914532c26
commit
d58212ccc5
6 changed files with 479 additions and 435 deletions
383
compiler/ast.nim
383
compiler/ast.nim
|
|
@ -9,12 +9,12 @@
|
|||
|
||||
# abstract syntax tree + symbol table
|
||||
|
||||
import
|
||||
msgs, hashes, nversion, options, strutils, crc, ropes, idents, lists,
|
||||
import
|
||||
msgs, hashes, nversion, options, strutils, crc, ropes, idents, lists,
|
||||
intsets, idgen
|
||||
|
||||
type
|
||||
TCallingConvention* = enum
|
||||
TCallingConvention* = enum
|
||||
ccDefault, # proc has no explicit calling convention
|
||||
ccStdCall, # procedure is stdcall
|
||||
ccCDecl, # cdecl
|
||||
|
|
@ -26,12 +26,12 @@ type
|
|||
ccClosure, # proc has a closure
|
||||
ccNoConvention # needed for generating proper C procs sometimes
|
||||
|
||||
const
|
||||
CallingConvToStr*: array[TCallingConvention, string] = ["", "stdcall",
|
||||
const
|
||||
CallingConvToStr*: array[TCallingConvention, string] = ["", "stdcall",
|
||||
"cdecl", "safecall", "syscall", "inline", "noinline", "fastcall",
|
||||
"closure", "noconv"]
|
||||
|
||||
type
|
||||
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
|
||||
|
|
@ -64,13 +64,13 @@ type
|
|||
# end of atoms
|
||||
nkMetaNode_Obsolete, # difficult to explain; represents itself
|
||||
# (used for macros)
|
||||
nkDotCall, # used to temporarily flag a nkCall node;
|
||||
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
|
||||
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)
|
||||
|
|
@ -126,7 +126,7 @@ type
|
|||
|
||||
nkAsgn, # a = b
|
||||
nkFastAsgn, # internal node for a fast ``a = b``
|
||||
# (no string copy)
|
||||
# (no string copy)
|
||||
nkGenericParams, # generic parameters
|
||||
nkFormalParams, # formal parameters
|
||||
nkOfInherit, # inherited from symbol
|
||||
|
|
@ -192,7 +192,7 @@ type
|
|||
|
||||
nkWith, # distinct with `foo`
|
||||
nkWithout, # distinct without `foo`
|
||||
|
||||
|
||||
nkTypeOfExpr, # type(1+2)
|
||||
nkObjectTy, # object body
|
||||
nkTupleTy, # tuple body
|
||||
|
|
@ -226,7 +226,7 @@ type
|
|||
TSymFlag* = enum # already 32 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
|
||||
sfFromGeneric, # symbol is instantiation of a generic; this is needed
|
||||
# for symbol file generation; such symbols should always
|
||||
# be written into the ROD file
|
||||
sfGlobal, # symbol is at global scope
|
||||
|
|
@ -284,9 +284,9 @@ const
|
|||
|
||||
sfAnon* = sfDiscardable
|
||||
# symbol name that was generated by the compiler
|
||||
# the compiler will avoid printing such names
|
||||
# the compiler will avoid printing such names
|
||||
# in user messages.
|
||||
|
||||
|
||||
sfNoForward* = sfRegister
|
||||
# forward declarations are not required (per module)
|
||||
|
||||
|
|
@ -300,7 +300,7 @@ const
|
|||
# getting ready for the future expr/stmt merge
|
||||
nkWhen* = nkWhenStmt
|
||||
nkWhenExpr* = nkWhenStmt
|
||||
nkEffectList* = nkArgList
|
||||
nkEffectList* = nkArgList
|
||||
# hacks ahead: an nkEffectList is a node with 4 children:
|
||||
exceptionEffects* = 0 # exceptions at position 0
|
||||
usesEffects* = 1 # read effects at position 1
|
||||
|
|
@ -321,7 +321,7 @@ type
|
|||
# unless this is an instance of a generic alias type.
|
||||
# then realInstance will be the tyGenericInst of the
|
||||
# completely (recursively) resolved alias.
|
||||
|
||||
|
||||
tyGenericParam, # ``a`` in the above patterns
|
||||
tyDistinct,
|
||||
tyEnum,
|
||||
|
|
@ -340,14 +340,14 @@ type
|
|||
tyInt, tyInt8, tyInt16, tyInt32, tyInt64, # signed integers
|
||||
tyFloat, tyFloat32, tyFloat64, tyFloat128,
|
||||
tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64,
|
||||
tyBigNum,
|
||||
tyConst, tyMutable, tyVarargs,
|
||||
tyBigNum,
|
||||
tyConst, tyMutable, tyVarargs,
|
||||
tyIter, # unused
|
||||
tyProxy # used as errornous type (for idetools)
|
||||
|
||||
|
||||
tyBuiltInTypeClass #\
|
||||
# Type such as the catch-all object, tuple, seq, etc
|
||||
|
||||
|
||||
tyUserTypeClass #\
|
||||
# the body of a user-defined type class
|
||||
|
||||
|
|
@ -357,24 +357,24 @@ type
|
|||
# tyGenericInst represents concrete types, while
|
||||
# this is still a "generic param" that will bind types
|
||||
# and resolves them during sigmatch and instantiation.
|
||||
|
||||
|
||||
tyCompositeTypeClass #\
|
||||
# Type such as seq[Number]
|
||||
# The notes for tyUserTypeClassInst apply here as well
|
||||
# The notes for tyUserTypeClassInst apply here as well
|
||||
# sons[0]: the original expression used by the user.
|
||||
# sons[1]: fully expanded and instantiated meta type
|
||||
# (potentially following aliases)
|
||||
|
||||
|
||||
tyAnd, tyOr, tyNot #\
|
||||
# boolean type classes such as `string|int`,`not seq`,
|
||||
# `Sortable and Enumable`, etc
|
||||
|
||||
|
||||
tyAnything #\
|
||||
# a type class matching any type
|
||||
|
||||
|
||||
tyStatic #\
|
||||
# a value known at compile type (the underlying type is .base)
|
||||
|
||||
|
||||
tyFromExpr #\
|
||||
# This is a type representing an expression that depends
|
||||
# on generic parameters (the expression is stored in t.n)
|
||||
|
|
@ -390,7 +390,7 @@ type
|
|||
# sons[0]: type of containing object or tuple
|
||||
# sons[1]: field type
|
||||
# .n: nkDotExpr storing the field name
|
||||
|
||||
|
||||
static:
|
||||
# remind us when TTypeKind stops to fit in a single 64-bit word
|
||||
assert TTypeKind.high.ord <= 63
|
||||
|
|
@ -408,7 +408,7 @@ const
|
|||
tyAnd, tyOr, tyNot, tyAnything}
|
||||
|
||||
tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyExpr} + tyTypeClasses
|
||||
|
||||
|
||||
type
|
||||
TTypeKinds* = set[TTypeKind]
|
||||
|
||||
|
|
@ -429,7 +429,7 @@ type
|
|||
nfExprCall # this is an attempt to call a regular expression
|
||||
nfIsRef # this node is a 'ref' node; used for the VM
|
||||
nfIsCursor # this node is attached a cursor; used for idetools
|
||||
|
||||
|
||||
TNodeFlags* = set[TNodeFlag]
|
||||
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 28)
|
||||
tfVarargs, # procedure has C styled varargs
|
||||
|
|
@ -448,7 +448,7 @@ type
|
|||
# proc foo(L: static[int]): array[L, int]
|
||||
# can be attached to ranges to indicate that the range
|
||||
# depends on unresolved static params.
|
||||
tfRetType, # marks return types in proc (used to detect type classes
|
||||
tfRetType, # marks return types in proc (used to detect type classes
|
||||
# used as return types for return type inference)
|
||||
tfCapturesEnv, # whether proc really captures some environment
|
||||
tfByCopy, # pass object/tuple by copy (C backend)
|
||||
|
|
@ -456,7 +456,7 @@ type
|
|||
tfIterator, # type is really an iterator, not a tyProc
|
||||
tfShared, # type is 'shared'
|
||||
tfNotNil, # type cannot be 'nil'
|
||||
|
||||
|
||||
tfNeedsInit, # type constains a "not nil" constraint somewhere or some
|
||||
# other type so that it requires inititalization
|
||||
tfVarIsPtr, # 'var' type is translated like 'ptr' even in C++ mode
|
||||
|
|
@ -520,7 +520,7 @@ const
|
|||
tfGcSafe* = tfThread
|
||||
tfObjHasKids* = tfEnumHasHoles
|
||||
skError* = skUnknown
|
||||
|
||||
|
||||
# type flags that are essential for type equality:
|
||||
eqTypeFlags* = {tfIterator, tfShared, tfNotNil, tfVarIsPtr}
|
||||
|
||||
|
|
@ -531,29 +531,29 @@ type
|
|||
mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf,
|
||||
mEcho, mShallowCopy, mSlurp, mStaticExec,
|
||||
mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst,
|
||||
mUnaryLt, mSucc,
|
||||
mPred, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray,
|
||||
mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr, mGCref,
|
||||
mGCunref, mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
|
||||
mUnaryLt, mSucc,
|
||||
mPred, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray,
|
||||
mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr, mGCref,
|
||||
mGCunref, mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
|
||||
mDivI64, mModI64,
|
||||
mAddF64, mSubF64, mMulF64, mDivF64,
|
||||
mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI,
|
||||
mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI,
|
||||
mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64, mMinI64, mMaxI64,
|
||||
mMinF64, mMaxF64, mAddU, mSubU, mMulU,
|
||||
mMinF64, mMaxF64, mAddU, mSubU, mMulU,
|
||||
mDivU, mModU, mEqI, mLeI,
|
||||
mLtI,
|
||||
mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64,
|
||||
mLeU, mLtU, mLeU64, mLtU64,
|
||||
mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
|
||||
mLtI,
|
||||
mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64,
|
||||
mLeU, mLtU, mLeU64, mLtU64,
|
||||
mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
|
||||
mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mEqProc, mUnaryMinusI,
|
||||
mUnaryMinusI64, mAbsI, mAbsI64, mNot,
|
||||
mUnaryPlusI, mBitnotI, mUnaryPlusI64,
|
||||
mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
|
||||
mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
|
||||
mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
|
||||
mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
|
||||
mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
|
||||
mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT,
|
||||
mUnaryMinusI64, mAbsI, mAbsI64, mNot,
|
||||
mUnaryPlusI, mBitnotI, mUnaryPlusI64,
|
||||
mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
|
||||
mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
|
||||
mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
|
||||
mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
|
||||
mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
|
||||
mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT,
|
||||
mConTArr, mConTT, mSlice,
|
||||
mFields, mFieldPairs, mOmpParFor,
|
||||
mAppendStrCh, mAppendStrStr, mAppendSeqElem,
|
||||
|
|
@ -584,36 +584,36 @@ type
|
|||
|
||||
# things that we can evaluate safely at compile time, even if not asked for it:
|
||||
const
|
||||
ctfeWhitelist* = {mNone, mUnaryLt, mSucc,
|
||||
mPred, mInc, mDec, mOrd, mLengthOpenArray,
|
||||
mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr,
|
||||
mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
|
||||
ctfeWhitelist* = {mNone, mUnaryLt, mSucc,
|
||||
mPred, mInc, mDec, mOrd, mLengthOpenArray,
|
||||
mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr,
|
||||
mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
|
||||
mDivI64, mModI64, mAddF64, mSubF64, mMulF64, mDivF64,
|
||||
mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI,
|
||||
mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI,
|
||||
mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64, mMinI64, mMaxI64,
|
||||
mMinF64, mMaxF64, mAddU, mSubU, mMulU,
|
||||
mMinF64, mMaxF64, mAddU, mSubU, mMulU,
|
||||
mDivU, mModU, mEqI, mLeI,
|
||||
mLtI,
|
||||
mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64,
|
||||
mLeU, mLtU, mLeU64, mLtU64,
|
||||
mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
|
||||
mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mUnaryMinusI,
|
||||
mUnaryMinusI64, mAbsI, mAbsI64, mNot,
|
||||
mUnaryPlusI, mBitnotI, mUnaryPlusI64,
|
||||
mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
|
||||
mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
|
||||
mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
|
||||
mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
|
||||
mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
|
||||
mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT,
|
||||
mLtI,
|
||||
mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64,
|
||||
mLeU, mLtU, mLeU64, mLtU64,
|
||||
mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
|
||||
mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mUnaryMinusI,
|
||||
mUnaryMinusI64, mAbsI, mAbsI64, mNot,
|
||||
mUnaryPlusI, mBitnotI, mUnaryPlusI64,
|
||||
mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
|
||||
mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
|
||||
mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
|
||||
mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
|
||||
mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
|
||||
mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT,
|
||||
mConTArr, mConTT,
|
||||
mAppendStrCh, mAppendStrStr, mAppendSeqElem,
|
||||
mAppendStrCh, mAppendStrStr, mAppendSeqElem,
|
||||
mInRange, mInSet, mRepr,
|
||||
mCopyStr, mCopyStrLast}
|
||||
# magics that require special semantic checking and
|
||||
# thus cannot be overloaded (also documented in the spec!):
|
||||
SpecialSemMagics* = {
|
||||
mDefined, mDefinedInScope, mCompiles, mLow, mHigh, mSizeOf, mIs, mOf,
|
||||
mDefined, mDefinedInScope, mCompiles, mLow, mHigh, mSizeOf, mIs, mOf,
|
||||
mEcho, mShallowCopy, mExpandToAst, mParallel, mSpawn, mAstToStr}
|
||||
|
||||
type
|
||||
|
|
@ -634,21 +634,21 @@ type
|
|||
floatVal*: BiggestFloat
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
strVal*: string
|
||||
of nkSym:
|
||||
of nkSym:
|
||||
sym*: PSym
|
||||
of nkIdent:
|
||||
of nkIdent:
|
||||
ident*: PIdent
|
||||
else:
|
||||
sons*: TNodeSeq
|
||||
comment*: string
|
||||
|
||||
|
||||
TSymSeq* = seq[PSym]
|
||||
TStrTable* = object # a table[PIdent] of PSym
|
||||
counter*: int
|
||||
data*: TSymSeq
|
||||
|
||||
|
||||
# -------------- backend information -------------------------------
|
||||
TLocKind* = enum
|
||||
TLocKind* = enum
|
||||
locNone, # no location
|
||||
locTemp, # temporary location
|
||||
locLocalVar, # location is a local variable
|
||||
|
|
@ -660,7 +660,7 @@ type
|
|||
locData, # location is a constant
|
||||
locCall, # location is a call expression
|
||||
locOther # location is something other
|
||||
TLocFlag* = enum
|
||||
TLocFlag* = enum
|
||||
lfIndirect, # backend introduced a pointer
|
||||
lfParamCopy, # backend introduced a parameter copy (LLVM)
|
||||
lfNoDeepCopy, # no need for a deep copy
|
||||
|
|
@ -670,13 +670,13 @@ type
|
|||
lfHeader, # include header file for symbol
|
||||
lfImportCompilerProc, # ``importc`` of a compilerproc
|
||||
lfSingleUse # no location yet and will only be used once
|
||||
TStorageLoc* = enum
|
||||
TStorageLoc* = enum
|
||||
OnUnknown, # location is unknown (stack, heap or static)
|
||||
OnStack, # location is on hardware stack
|
||||
OnHeap # location is on heap or global
|
||||
# (reference counting needed)
|
||||
TLocFlags* = set[TLocFlag]
|
||||
TLoc* = object
|
||||
TLoc* = object
|
||||
k*: TLocKind # kind of location
|
||||
s*: TStorageLoc
|
||||
flags*: TLocFlags # location's flags
|
||||
|
|
@ -688,7 +688,7 @@ type
|
|||
|
||||
# ---------------- end of backend information ------------------------------
|
||||
|
||||
TLibKind* = enum
|
||||
TLibKind* = enum
|
||||
libHeader, libDynamic
|
||||
TLib* = object of lists.TListEntry # also misused for headers!
|
||||
kind*: TLibKind
|
||||
|
|
@ -696,17 +696,17 @@ type
|
|||
isOverriden*: bool
|
||||
name*: PRope
|
||||
path*: PNode # can be a string literal!
|
||||
|
||||
|
||||
TInstantiation* = object
|
||||
sym*: PSym
|
||||
concreteTypes*: seq[PType]
|
||||
usedBy*: seq[int32] # list of modules using the generic
|
||||
# needed in caas mode for purging the cache
|
||||
# XXX: it's possible to switch to a
|
||||
# XXX: it's possible to switch to a
|
||||
# simple ref count here
|
||||
|
||||
|
||||
PInstantiation* = ref TInstantiation
|
||||
|
||||
|
||||
TScope* = object
|
||||
depthLevel*: int
|
||||
symbols*: TStrTable
|
||||
|
|
@ -773,7 +773,7 @@ type
|
|||
constraint*: PNode # additional constraints like 'lit|result'; also
|
||||
# misused for the codegenDecl pragma in the hope
|
||||
# it won't cause problems
|
||||
|
||||
|
||||
TTypeSeq* = seq[PType]
|
||||
TLockLevel* = distinct int16
|
||||
TType* {.acyclic.} = object of TIdObj # \
|
||||
|
|
@ -806,7 +806,7 @@ type
|
|||
lockLevel*: TLockLevel # lock level as required for deadlock checking
|
||||
loc*: TLoc
|
||||
|
||||
TPair*{.final.} = object
|
||||
TPair*{.final.} = object
|
||||
key*, val*: RootRef
|
||||
|
||||
TPairSeq* = seq[TPair]
|
||||
|
|
@ -814,7 +814,7 @@ type
|
|||
counter*: int
|
||||
data*: TPairSeq
|
||||
|
||||
TIdPair*{.final.} = object
|
||||
TIdPair*{.final.} = object
|
||||
key*: PIdObj
|
||||
val*: RootRef
|
||||
|
||||
|
|
@ -823,7 +823,7 @@ type
|
|||
counter*: int
|
||||
data*: TIdPairSeq
|
||||
|
||||
TIdNodePair*{.final.} = object
|
||||
TIdNodePair*{.final.} = object
|
||||
key*: PIdObj
|
||||
val*: PNode
|
||||
|
||||
|
|
@ -832,7 +832,7 @@ type
|
|||
counter*: int
|
||||
data*: TIdNodePairSeq
|
||||
|
||||
TNodePair*{.final.} = object
|
||||
TNodePair*{.final.} = object
|
||||
h*: THash # because it is expensive to compute!
|
||||
key*: PNode
|
||||
val*: int
|
||||
|
|
@ -844,7 +844,7 @@ type
|
|||
data*: TNodePairSeq
|
||||
|
||||
TObjectSeq* = seq[RootRef]
|
||||
TObjectSet*{.final.} = object
|
||||
TObjectSet*{.final.} = object
|
||||
counter*: int
|
||||
data*: TObjectSeq
|
||||
|
||||
|
|
@ -855,27 +855,27 @@ type
|
|||
# same name as an imported module. This is necessary because of
|
||||
# the poor naming choices in the standard library.
|
||||
|
||||
const
|
||||
const
|
||||
OverloadableSyms* = {skProc, skMethod, skIterator, skClosureIterator,
|
||||
skConverter, skModule, skTemplate, skMacro}
|
||||
|
||||
GenericTypes*: TTypeKinds = {tyGenericInvocation, tyGenericBody,
|
||||
GenericTypes*: TTypeKinds = {tyGenericInvocation, tyGenericBody,
|
||||
tyGenericParam}
|
||||
|
||||
StructuralEquivTypes*: TTypeKinds = {tyArrayConstr, tyNil, tyTuple, tyArray,
|
||||
|
||||
StructuralEquivTypes*: TTypeKinds = {tyArrayConstr, tyNil, tyTuple, tyArray,
|
||||
tySet, tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc, tyOpenArray,
|
||||
tyVarargs}
|
||||
|
||||
|
||||
ConcreteTypes*: TTypeKinds = { # types of the expr that may occur in::
|
||||
# var x = expr
|
||||
tyBool, tyChar, tyEnum, tyArray, tyObject,
|
||||
tyBool, tyChar, tyEnum, tyArray, tyObject,
|
||||
tySet, tyTuple, tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc,
|
||||
tyPointer,
|
||||
tyPointer,
|
||||
tyOpenArray, tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128,
|
||||
tyUInt..tyUInt64}
|
||||
IntegralTypes* = {tyBool, tyChar, tyEnum, tyInt..tyInt64,
|
||||
tyFloat..tyFloat128, tyUInt..tyUInt64}
|
||||
ConstantDataTypes*: TTypeKinds = {tyArrayConstr, tyArray, tySet,
|
||||
ConstantDataTypes*: TTypeKinds = {tyArrayConstr, tyArray, tySet,
|
||||
tyTuple, tySequence}
|
||||
NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, tySequence,
|
||||
tyProc, tyString, tyError}
|
||||
|
|
@ -926,17 +926,17 @@ proc discardSons*(father: PNode)
|
|||
proc len*(n: PNode): int {.inline.} =
|
||||
if isNil(n.sons): result = 0
|
||||
else: result = len(n.sons)
|
||||
|
||||
|
||||
proc safeLen*(n: PNode): int {.inline.} =
|
||||
## works even for leaves.
|
||||
if n.kind in {nkNone..nkNilLit} or isNil(n.sons): result = 0
|
||||
else: result = len(n.sons)
|
||||
|
||||
|
||||
proc add*(father, son: PNode) =
|
||||
assert son != nil
|
||||
if isNil(father.sons): father.sons = @[]
|
||||
add(father.sons, son)
|
||||
|
||||
|
||||
proc `[]`*(n: PNode, i: int): PNode {.inline.} =
|
||||
result = n.sons[i]
|
||||
|
||||
|
|
@ -946,13 +946,10 @@ template `{}=`*(n: PNode, i: int, s: PNode): stmt =
|
|||
n.sons[i -| n] = s
|
||||
|
||||
when defined(useNodeIds):
|
||||
const nodeIdToDebug* = -1 # 884953 # 612794
|
||||
#612840 # 612905 # 614635 # 614637 # 614641
|
||||
# 423408
|
||||
#429107 # 430443 # 441048 # 441090 # 441153
|
||||
const nodeIdToDebug* = -1 # 299750 # 300761 #300863 # 300879
|
||||
var gNodeId: int
|
||||
|
||||
proc newNode*(kind: TNodeKind): PNode =
|
||||
proc newNode*(kind: TNodeKind): PNode =
|
||||
new(result)
|
||||
result.kind = kind
|
||||
#result.info = UnknownLineInfo() inlined:
|
||||
|
|
@ -966,24 +963,24 @@ proc newNode*(kind: TNodeKind): PNode =
|
|||
writeStackTrace()
|
||||
inc gNodeId
|
||||
|
||||
proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode =
|
||||
proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode =
|
||||
result = newNode(kind)
|
||||
result.intVal = intVal
|
||||
|
||||
proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode =
|
||||
proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode =
|
||||
result = newIntNode(kind, intVal)
|
||||
result.typ = typ
|
||||
|
||||
proc newFloatNode*(kind: TNodeKind, floatVal: BiggestFloat): PNode =
|
||||
proc newFloatNode*(kind: TNodeKind, floatVal: BiggestFloat): PNode =
|
||||
result = newNode(kind)
|
||||
result.floatVal = floatVal
|
||||
|
||||
proc newStrNode*(kind: TNodeKind, strVal: string): PNode =
|
||||
proc newStrNode*(kind: TNodeKind, strVal: string): PNode =
|
||||
result = newNode(kind)
|
||||
result.strVal = strVal
|
||||
|
||||
proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
|
||||
info: TLineInfo): PSym =
|
||||
info: TLineInfo): PSym =
|
||||
# generates a symbol and initializes the hash field too
|
||||
new(result)
|
||||
result.name = name
|
||||
|
|
@ -994,7 +991,7 @@ proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
|
|||
result.owner = owner
|
||||
result.offset = - 1
|
||||
result.id = getID()
|
||||
when debugIds:
|
||||
when debugIds:
|
||||
registerId(result)
|
||||
#if result.id < 2000:
|
||||
# MessageOut(name.s & " has id: " & toString(result.id))
|
||||
|
|
@ -1036,54 +1033,54 @@ proc appendToModule*(m: PSym, n: PNode) =
|
|||
else:
|
||||
assert m.ast.kind == nkStmtList
|
||||
m.ast.sons.add(n)
|
||||
|
||||
|
||||
const # for all kind of hash tables:
|
||||
GrowthFactor* = 2 # must be power of 2, > 0
|
||||
StartSize* = 8 # must be power of 2, > 0
|
||||
|
||||
proc copyStrTable*(dest: var TStrTable, src: TStrTable) =
|
||||
proc copyStrTable*(dest: var TStrTable, src: TStrTable) =
|
||||
dest.counter = src.counter
|
||||
if isNil(src.data): return
|
||||
if isNil(src.data): return
|
||||
setLen(dest.data, len(src.data))
|
||||
for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
|
||||
|
||||
proc copyIdTable*(dest: var TIdTable, src: TIdTable) =
|
||||
|
||||
proc copyIdTable*(dest: var TIdTable, src: TIdTable) =
|
||||
dest.counter = src.counter
|
||||
if isNil(src.data): return
|
||||
if isNil(src.data): return
|
||||
newSeq(dest.data, len(src.data))
|
||||
for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
|
||||
|
||||
proc copyTable*(dest: var TTable, src: TTable) =
|
||||
|
||||
proc copyTable*(dest: var TTable, src: TTable) =
|
||||
dest.counter = src.counter
|
||||
if isNil(src.data): return
|
||||
if isNil(src.data): return
|
||||
setLen(dest.data, len(src.data))
|
||||
for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
|
||||
|
||||
proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) =
|
||||
|
||||
proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) =
|
||||
dest.counter = src.counter
|
||||
if isNil(src.data): return
|
||||
if isNil(src.data): return
|
||||
setLen(dest.data, len(src.data))
|
||||
for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
|
||||
|
||||
proc discardSons*(father: PNode) =
|
||||
|
||||
proc discardSons*(father: PNode) =
|
||||
father.sons = nil
|
||||
|
||||
proc withInfo*(n: PNode, info: TLineInfo): PNode =
|
||||
n.info = info
|
||||
return n
|
||||
|
||||
proc newIdentNode*(ident: PIdent, info: TLineInfo): PNode =
|
||||
proc newIdentNode*(ident: PIdent, info: TLineInfo): PNode =
|
||||
result = newNode(nkIdent)
|
||||
result.ident = ident
|
||||
result.info = info
|
||||
|
||||
proc newSymNode*(sym: PSym): PNode =
|
||||
proc newSymNode*(sym: PSym): PNode =
|
||||
result = newNode(nkSym)
|
||||
result.sym = sym
|
||||
result.typ = sym.typ
|
||||
result.info = sym.info
|
||||
|
||||
proc newSymNode*(sym: PSym, info: TLineInfo): PNode =
|
||||
proc newSymNode*(sym: PSym, info: TLineInfo): PNode =
|
||||
result = newNode(nkSym)
|
||||
result.sym = sym
|
||||
result.typ = sym.typ
|
||||
|
|
@ -1128,12 +1125,12 @@ proc newNode*(kind: TNodeKind, info: TLineInfo, sons: TNodeSeq = @[],
|
|||
writeStackTrace()
|
||||
inc gNodeId
|
||||
|
||||
proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode =
|
||||
proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode =
|
||||
result = newNode(kind)
|
||||
result.info = info
|
||||
result.typ = typ
|
||||
|
||||
proc addSon*(father, son: PNode) =
|
||||
proc addSon*(father, son: PNode) =
|
||||
assert son != nil
|
||||
if isNil(father.sons): father.sons = @[]
|
||||
add(father.sons, son)
|
||||
|
|
@ -1159,7 +1156,7 @@ proc `$`*(x: TLockLevel): string =
|
|||
elif x.ord == UnknownLockLevel.ord: result = "<unknown>"
|
||||
else: result = $int16(x)
|
||||
|
||||
proc newType*(kind: TTypeKind, owner: PSym): PType =
|
||||
proc newType*(kind: TTypeKind, owner: PSym): PType =
|
||||
new(result)
|
||||
result.kind = kind
|
||||
result.owner = owner
|
||||
|
|
@ -1171,7 +1168,7 @@ proc newType*(kind: TTypeKind, owner: PSym): PType =
|
|||
registerId(result)
|
||||
#if result.id < 2000:
|
||||
# messageOut(typeKindToStr[kind] & ' has id: ' & toString(result.id))
|
||||
|
||||
|
||||
proc mergeLoc(a: var TLoc, b: TLoc) =
|
||||
if a.k == low(a.k): a.k = b.k
|
||||
if a.s == low(a.s): a.s = b.s
|
||||
|
|
@ -1180,37 +1177,37 @@ proc mergeLoc(a: var TLoc, b: TLoc) =
|
|||
if a.r == nil: a.r = b.r
|
||||
#if a.a == 0: a.a = b.a
|
||||
|
||||
proc newSons*(father: PNode, length: int) =
|
||||
if isNil(father.sons):
|
||||
proc newSons*(father: PNode, length: int) =
|
||||
if isNil(father.sons):
|
||||
newSeq(father.sons, length)
|
||||
else:
|
||||
setLen(father.sons, length)
|
||||
|
||||
proc newSons*(father: PType, length: int) =
|
||||
if isNil(father.sons):
|
||||
proc newSons*(father: PType, length: int) =
|
||||
if isNil(father.sons):
|
||||
newSeq(father.sons, length)
|
||||
else:
|
||||
setLen(father.sons, length)
|
||||
|
||||
proc sonsLen*(n: PType): int =
|
||||
proc sonsLen*(n: PType): int =
|
||||
if isNil(n.sons): result = 0
|
||||
else: result = len(n.sons)
|
||||
|
||||
proc len*(n: PType): int =
|
||||
proc len*(n: PType): int =
|
||||
if isNil(n.sons): result = 0
|
||||
else: result = len(n.sons)
|
||||
|
||||
proc sonsLen*(n: PNode): int =
|
||||
|
||||
proc sonsLen*(n: PNode): int =
|
||||
if isNil(n.sons): result = 0
|
||||
else: result = len(n.sons)
|
||||
|
||||
proc lastSon*(n: PNode): PNode =
|
||||
|
||||
proc lastSon*(n: PNode): PNode =
|
||||
result = n.sons[sonsLen(n) - 1]
|
||||
|
||||
proc lastSon*(n: PType): PType =
|
||||
proc lastSon*(n: PType): PType =
|
||||
result = n.sons[sonsLen(n) - 1]
|
||||
|
||||
proc assignType*(dest, src: PType) =
|
||||
proc assignType*(dest, src: PType) =
|
||||
dest.kind = src.kind
|
||||
dest.flags = src.flags
|
||||
dest.callConv = src.callConv
|
||||
|
|
@ -1230,23 +1227,23 @@ proc assignType*(dest, src: PType) =
|
|||
dest.sym = src.sym
|
||||
newSons(dest, sonsLen(src))
|
||||
for i in countup(0, sonsLen(src) - 1): dest.sons[i] = src.sons[i]
|
||||
|
||||
proc copyType*(t: PType, owner: PSym, keepId: bool): PType =
|
||||
|
||||
proc copyType*(t: PType, owner: PSym, keepId: bool): PType =
|
||||
result = newType(t.kind, owner)
|
||||
assignType(result, t)
|
||||
if keepId:
|
||||
if keepId:
|
||||
result.id = t.id
|
||||
else:
|
||||
else:
|
||||
when debugIds: registerId(result)
|
||||
result.sym = t.sym # backend-info should not be copied
|
||||
|
||||
proc copySym*(s: PSym, keepId: bool = false): PSym =
|
||||
|
||||
proc copySym*(s: PSym, keepId: bool = false): PSym =
|
||||
result = newSym(s.kind, s.name, s.owner, s.info)
|
||||
#result.ast = nil # BUGFIX; was: s.ast which made problems
|
||||
result.typ = s.typ
|
||||
if keepId:
|
||||
result.id = s.id
|
||||
else:
|
||||
else:
|
||||
result.id = getID()
|
||||
when debugIds: registerId(result)
|
||||
result.flags = s.flags
|
||||
|
|
@ -1273,19 +1270,19 @@ proc createModuleAlias*(s: PSym, newIdent: PIdent, info: TLineInfo): PSym =
|
|||
result.annex = s.annex
|
||||
# XXX once usedGenerics is used, ensure module aliases keep working!
|
||||
assert s.usedGenerics == nil
|
||||
|
||||
proc initStrTable*(x: var TStrTable) =
|
||||
|
||||
proc initStrTable*(x: var TStrTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
proc newStrTable*: TStrTable =
|
||||
initStrTable(result)
|
||||
|
||||
proc initTable(x: var TTable) =
|
||||
proc initTable(x: var TTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
proc initIdTable*(x: var TIdTable) =
|
||||
proc initIdTable*(x: var TIdTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
|
|
@ -1295,15 +1292,15 @@ proc resetIdTable*(x: var TIdTable) =
|
|||
setLen(x.data, 0)
|
||||
setLen(x.data, StartSize)
|
||||
|
||||
proc initObjectSet*(x: var TObjectSet) =
|
||||
proc initObjectSet*(x: var TObjectSet) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
proc initIdNodeTable*(x: var TIdNodeTable) =
|
||||
proc initIdNodeTable*(x: var TIdNodeTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
proc initNodeTable*(x: var TNodeTable) =
|
||||
proc initNodeTable*(x: var TNodeTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
|
|
@ -1327,11 +1324,11 @@ proc propagateToOwner*(owner, elem: PType) =
|
|||
owner.flags.incl tfNotNil
|
||||
elif owner.kind notin HaveTheirOwnEmpty:
|
||||
owner.flags.incl tfNeedsInit
|
||||
|
||||
|
||||
if tfNeedsInit in elem.flags:
|
||||
if owner.kind in HaveTheirOwnEmpty: discard
|
||||
else: owner.flags.incl tfNeedsInit
|
||||
|
||||
|
||||
if elem.isMetaType:
|
||||
owner.flags.incl tfHasMeta
|
||||
|
||||
|
|
@ -1348,15 +1345,15 @@ proc addSonNilAllowed*(father, son: PNode) =
|
|||
if isNil(father.sons): father.sons = @[]
|
||||
add(father.sons, son)
|
||||
|
||||
proc delSon*(father: PNode, idx: int) =
|
||||
if isNil(father.sons): return
|
||||
proc delSon*(father: PNode, idx: int) =
|
||||
if isNil(father.sons): return
|
||||
var length = sonsLen(father)
|
||||
for i in countup(idx, length - 2): father.sons[i] = father.sons[i + 1]
|
||||
setLen(father.sons, length - 1)
|
||||
|
||||
proc copyNode*(src: PNode): PNode =
|
||||
proc copyNode*(src: PNode): PNode =
|
||||
# does not copy its sons!
|
||||
if src == nil:
|
||||
if src == nil:
|
||||
return nil
|
||||
result = newNode(src.kind)
|
||||
result.info = src.info
|
||||
|
|
@ -1373,7 +1370,7 @@ proc copyNode*(src: PNode): PNode =
|
|||
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
|
||||
else: discard
|
||||
|
||||
proc shallowCopy*(src: PNode): PNode =
|
||||
proc shallowCopy*(src: PNode): PNode =
|
||||
# does not copy its sons, but provides space for them:
|
||||
if src == nil: return nil
|
||||
result = newNode(src.kind)
|
||||
|
|
@ -1391,9 +1388,9 @@ proc shallowCopy*(src: PNode): PNode =
|
|||
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
|
||||
else: newSeq(result.sons, sonsLen(src))
|
||||
|
||||
proc copyTree*(src: PNode): PNode =
|
||||
proc copyTree*(src: PNode): PNode =
|
||||
# copy a whole syntax tree; performs deep copying
|
||||
if src == nil:
|
||||
if src == nil:
|
||||
return nil
|
||||
result = newNode(src.kind)
|
||||
result.info = src.info
|
||||
|
|
@ -1408,20 +1405,20 @@ proc copyTree*(src: PNode): PNode =
|
|||
of nkSym: result.sym = src.sym
|
||||
of nkIdent: result.ident = src.ident
|
||||
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
|
||||
else:
|
||||
else:
|
||||
newSeq(result.sons, sonsLen(src))
|
||||
for i in countup(0, sonsLen(src) - 1):
|
||||
for i in countup(0, sonsLen(src) - 1):
|
||||
result.sons[i] = copyTree(src.sons[i])
|
||||
|
||||
proc hasSonWith*(n: PNode, kind: TNodeKind): bool =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if n.sons[i].kind == kind:
|
||||
proc hasSonWith*(n: PNode, kind: TNodeKind): bool =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if n.sons[i].kind == kind:
|
||||
return true
|
||||
result = false
|
||||
|
||||
proc hasNilSon*(n: PNode): bool =
|
||||
for i in countup(0, safeLen(n) - 1):
|
||||
if n.sons[i] == nil:
|
||||
proc hasNilSon*(n: PNode): bool =
|
||||
for i in countup(0, safeLen(n) - 1):
|
||||
if n.sons[i] == nil:
|
||||
return true
|
||||
elif hasNilSon(n.sons[i]):
|
||||
return true
|
||||
|
|
@ -1435,47 +1432,47 @@ proc containsNode*(n: PNode, kinds: TNodeKinds): bool =
|
|||
for i in countup(0, sonsLen(n) - 1):
|
||||
if n.kind in kinds or containsNode(n.sons[i], kinds): return true
|
||||
|
||||
proc hasSubnodeWith*(n: PNode, kind: TNodeKind): bool =
|
||||
proc hasSubnodeWith*(n: PNode, kind: TNodeKind): bool =
|
||||
case n.kind
|
||||
of nkEmpty..nkNilLit: result = n.kind == kind
|
||||
else:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if (n.sons[i].kind == kind) or hasSubnodeWith(n.sons[i], kind):
|
||||
else:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if (n.sons[i].kind == kind) or hasSubnodeWith(n.sons[i], kind):
|
||||
return true
|
||||
result = false
|
||||
|
||||
proc replaceSons(n: PNode, oldKind, newKind: TNodeKind) =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
proc replaceSons(n: PNode, oldKind, newKind: TNodeKind) =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if n.sons[i].kind == oldKind: n.sons[i].kind = newKind
|
||||
|
||||
proc sonsNotNil(n: PNode): bool =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if n.sons[i] == nil:
|
||||
|
||||
proc sonsNotNil(n: PNode): bool =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if n.sons[i] == nil:
|
||||
return false
|
||||
result = true
|
||||
|
||||
proc getInt*(a: PNode): BiggestInt =
|
||||
proc getInt*(a: PNode): BiggestInt =
|
||||
case a.kind
|
||||
of nkIntLit..nkUInt64Lit: result = a.intVal
|
||||
else:
|
||||
else:
|
||||
internalError(a.info, "getInt")
|
||||
result = 0
|
||||
|
||||
proc getFloat*(a: PNode): BiggestFloat =
|
||||
proc getFloat*(a: PNode): BiggestFloat =
|
||||
case a.kind
|
||||
of nkFloatLit..nkFloat128Lit: result = a.floatVal
|
||||
else:
|
||||
else:
|
||||
internalError(a.info, "getFloat")
|
||||
result = 0.0
|
||||
|
||||
proc getStr*(a: PNode): string =
|
||||
proc getStr*(a: PNode): string =
|
||||
case a.kind
|
||||
of nkStrLit..nkTripleStrLit: result = a.strVal
|
||||
else:
|
||||
else:
|
||||
internalError(a.info, "getStr")
|
||||
result = ""
|
||||
|
||||
proc getStrOrChar*(a: PNode): string =
|
||||
proc getStrOrChar*(a: PNode): string =
|
||||
case a.kind
|
||||
of nkStrLit..nkTripleStrLit: result = a.strVal
|
||||
of nkCharLit..nkUInt64Lit: result = $chr(int(a.intVal))
|
||||
|
|
@ -1483,7 +1480,7 @@ proc getStrOrChar*(a: PNode): string =
|
|||
internalError(a.info, "getStrOrChar")
|
||||
result = ""
|
||||
|
||||
proc isGenericRoutine*(s: PSym): bool =
|
||||
proc isGenericRoutine*(s: PSym): bool =
|
||||
case s.kind
|
||||
of skProcKinds:
|
||||
result = sfFromGeneric in s.flags or
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue