123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644 |
- #
- #
- # The Nim Compiler
- # (c) Copyright 2017 Andreas Rumpf
- #
- # See the file "copying.txt", included in this
- # distribution, for details about the copyright.
- #
- ## This module contains the data structures for the semantic checking phase.
- import tables
- when defined(nimPreviewSlimSystem):
- import std/assertions
- import
- intsets, options, ast, astalgo, msgs, idents, renderer,
- magicsys, vmdef, modulegraphs, lineinfos, sets, pathutils
- import ic / ic
- type
- TOptionEntry* = object # entries to put on a stack for pragma parsing
- options*: TOptions
- defaultCC*: TCallingConvention
- dynlib*: PLib
- notes*: TNoteKinds
- features*: set[Feature]
- otherPragmas*: PNode # every pragma can be pushed
- warningAsErrors*: TNoteKinds
- POptionEntry* = ref TOptionEntry
- PProcCon* = ref TProcCon
- TProcCon* {.acyclic.} = object # procedure context; also used for top-level
- # statements
- owner*: PSym # the symbol this context belongs to
- resultSym*: PSym # the result symbol (if we are in a proc)
- nestedLoopCounter*: int # whether we are in a loop or not
- nestedBlockCounter*: int # whether we are in a block or not
- breakInLoop*: bool # whether we are in a loop without block
- next*: PProcCon # used for stacking procedure contexts
- mappingExists*: bool
- mapping*: TIdTable
- caseContext*: seq[tuple[n: PNode, idx: int]]
- localBindStmts*: seq[PNode]
- TMatchedConcept* = object
- candidateType*: PType
- prev*: ptr TMatchedConcept
- depth*: int
- TInstantiationPair* = object
- genericSym*: PSym
- inst*: PInstantiation
- TExprFlag* = enum
- efLValue, efWantIterator, efWantIterable, efInTypeof,
- efNeedStatic,
- # Use this in contexts where a static value is mandatory
- efPreferStatic,
- # Use this in contexts where a static value could bring more
- # information, but it's not strictly mandatory. This may become
- # the default with implicit statics in the future.
- efPreferNilResult,
- # Use this if you want a certain result (e.g. static value),
- # but you don't want to trigger a hard error. For example,
- # you may be in position to supply a better error message
- # to the user.
- efWantStmt, efAllowStmt, efDetermineType, efExplain,
- efWantValue, efOperand, efNoSemCheck,
- efNoEvaluateGeneric, efInCall, efFromHlo, efNoSem2Check,
- efNoUndeclared, efIsDotCall, efCannotBeDotCall,
- # Use this if undeclared identifiers should not raise an error during
- # overload resolution.
- efNoDiagnostics,
- efTypeAllowed # typeAllowed will be called after
- efWantNoDefaults
- TExprFlags* = set[TExprFlag]
- ImportMode* = enum
- importAll, importSet, importExcept
- ImportedModule* = object
- m*: PSym
- case mode*: ImportMode
- of importAll: discard
- of importSet:
- imported*: IntSet # of PIdent.id
- of importExcept:
- exceptSet*: IntSet # of PIdent.id
- PContext* = ref TContext
- TContext* = object of TPassContext # a context represents the module
- # that is currently being compiled
- enforceVoidContext*: PType
- # for `if cond: stmt else: foo`, `foo` will be evaluated under
- # enforceVoidContext != nil
- voidType*: PType # for typeof(stmt)
- module*: PSym # the module sym belonging to the context
- currentScope*: PScope # current scope
- moduleScope*: PScope # scope for modules
- imports*: seq[ImportedModule] # scope for all imported symbols
- topLevelScope*: PScope # scope for all top-level symbols
- p*: PProcCon # procedure context
- intTypeCache*: array[-5..32, PType] # cache some common integer types
- # to avoid type allocations
- nilTypeCache*: PType
- matchedConcept*: ptr TMatchedConcept # the current concept being matched
- friendModules*: seq[PSym] # friend modules; may access private data;
- # this is used so that generic instantiations
- # can access private object fields
- instCounter*: int # to prevent endless instantiations
- templInstCounter*: ref int # gives every template instantiation a unique id
- inGenericContext*: int # > 0 if we are in a generic type
- inStaticContext*: int # > 0 if we are inside a static: block
- inUnrolledContext*: int # > 0 if we are unrolling a loop
- compilesContextId*: int # > 0 if we are in a ``compiles`` magic
- compilesContextIdGenerator*: int
- inGenericInst*: int # > 0 if we are instantiating a generic
- 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.}
- semExprWithType*: proc (c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode {.nimcall.}
- semTryExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
- semTryConstExpr*: proc (c: PContext, n: PNode; expectedType: PType = nil): PNode {.nimcall.}
- computeRequiresInit*: proc (c: PContext, t: PType): bool {.nimcall.}
- hasUnresolvedArgs*: proc (c: PContext, n: PNode): bool
- semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
- semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet
- 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: 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
- userPragmas*: TStrTable
- evalContext*: PEvalContext
- unknownIdents*: IntSet # ids of all unknown identifiers to prevent
- # naming it multiple times
- generics*: seq[TInstantiationPair] # pending list of instantiated generics to compile
- topStmts*: int # counts the number of encountered top level statements
- lastGenericIdx*: int # used for the generics stack
- hloLoopDetector*: int # used to prevent endless loops in the HLO
- inParallelStmt*: int
- instTypeBoundOp*: proc (c: PContext; dc: PSym; t: PType; info: TLineInfo;
- op: TTypeAttachedOp; col: int): PSym {.nimcall.}
- cache*: IdentCache
- graph*: ModuleGraph
- signatures*: TStrTable
- recursiveDep*: string
- suggestionsMade*: bool
- isAmbiguous*: bool # little hack
- features*: set[Feature]
- inTypeContext*, inConceptDecl*: int
- unusedImports*: seq[(PSym, TLineInfo)]
- exportIndirections*: HashSet[(int, int)] # (module.id, symbol.id)
- importModuleMap*: Table[int, int] # (module.id, module.id)
- lastTLineInfo*: TLineInfo
- sideEffects*: Table[int, seq[(TLineInfo, PSym)]] # symbol.id index
- inUncheckedAssignSection*: int
- importModuleLookup*: Table[int, seq[int]] # (module.ident.id, [module.id])
- skipTypes*: seq[PNode] # used to skip types between passes in type section. So far only used for inheritance, sets and generic bodies.
- TBorrowState* = enum
- bsNone, bsReturnNotMatch, bsNoDistinct, bsGeneric, bsNotSupported, bsMatch
- template config*(c: PContext): ConfigRef = c.graph.config
- proc getIntLitType*(c: PContext; literal: PNode): PType =
- # we cache some common integer literal types for performance:
- let value = literal.intVal
- if value >= low(c.intTypeCache) and value <= high(c.intTypeCache):
- result = c.intTypeCache[value.int]
- if result == nil:
- let ti = getSysType(c.graph, literal.info, tyInt)
- result = copyType(ti, nextTypeId(c.idgen), ti.owner)
- result.n = literal
- c.intTypeCache[value.int] = result
- else:
- let ti = getSysType(c.graph, literal.info, tyInt)
- result = copyType(ti, nextTypeId(c.idgen), ti.owner)
- result.n = literal
- proc setIntLitType*(c: PContext; result: PNode) =
- let i = result.intVal
- case c.config.target.intSize
- of 8: result.typ = getIntLitType(c, result)
- of 4:
- if i >= low(int32) and i <= high(int32):
- result.typ = getIntLitType(c, result)
- else:
- result.typ = getSysType(c.graph, result.info, tyInt64)
- of 2:
- if i >= low(int16) and i <= high(int16):
- result.typ = getIntLitType(c, result)
- elif i >= low(int32) and i <= high(int32):
- result.typ = getSysType(c.graph, result.info, tyInt32)
- else:
- result.typ = getSysType(c.graph, result.info, tyInt64)
- of 1:
- # 8 bit CPUs are insane ...
- if i >= low(int8) and i <= high(int8):
- result.typ = getIntLitType(c, result)
- elif i >= low(int16) and i <= high(int16):
- result.typ = getSysType(c.graph, result.info, tyInt16)
- elif i >= low(int32) and i <= high(int32):
- result.typ = getSysType(c.graph, result.info, tyInt32)
- else:
- result.typ = getSysType(c.graph, result.info, tyInt64)
- else:
- internalError(c.config, result.info, "invalid int size")
- proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
- result.genericSym = s
- result.inst = inst
- proc filename*(c: PContext): string =
- # the module's filename
- return toFilename(c.config, FileIndex c.module.position)
- proc scopeDepth*(c: PContext): int {.inline.} =
- result = if c.currentScope != nil: c.currentScope.depthLevel
- else: 0
- proc getCurrOwner*(c: PContext): PSym =
- # owner stack (used for initializing the
- # owner field of syms)
- # the documentation comment always gets
- # assigned to the current owner
- result = c.graph.owners[^1]
- proc pushOwner*(c: PContext; owner: PSym) =
- c.graph.owners.add(owner)
- proc popOwner*(c: PContext) =
- if c.graph.owners.len > 0: setLen(c.graph.owners, c.graph.owners.len - 1)
- else: internalError(c.config, "popOwner")
- proc lastOptionEntry*(c: PContext): POptionEntry =
- result = c.optionStack[^1]
- proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next
- proc put*(p: PProcCon; key, val: PSym) =
- if not p.mappingExists:
- p.mapping = initIdTable()
- p.mappingExists = true
- #echo "put into table ", key.info
- p.mapping.idTablePut(key, val)
- proc get*(p: PProcCon; key: PSym): PSym =
- if not p.mappingExists: return nil
- result = PSym(p.mapping.idTableGet(key))
- proc getGenSym*(c: PContext; s: PSym): PSym =
- if sfGenSym notin s.flags: return s
- var it = c.p
- while it != nil:
- result = get(it, s)
- if result != nil:
- #echo "got from table ", result.name.s, " ", result.info
- return result
- it = it.next
- result = s
- proc considerGenSyms*(c: PContext; n: PNode) =
- if n == nil:
- discard "can happen for nkFormalParams/nkArgList"
- elif n.kind == nkSym:
- let s = getGenSym(c, n.sym)
- if n.sym != s:
- n.sym = s
- else:
- for i in 0..<n.safeLen:
- considerGenSyms(c, n[i])
- proc newOptionEntry*(conf: ConfigRef): POptionEntry =
- new(result)
- result.options = conf.options
- result.defaultCC = ccNimCall
- result.dynlib = nil
- result.notes = conf.notes
- result.warningAsErrors = conf.warningAsErrors
- proc pushOptionEntry*(c: PContext): POptionEntry =
- new(result)
- var prev = c.optionStack[^1]
- result.options = c.config.options
- result.defaultCC = prev.defaultCC
- result.dynlib = prev.dynlib
- result.notes = c.config.notes
- result.warningAsErrors = c.config.warningAsErrors
- result.features = c.features
- c.optionStack.add(result)
- proc popOptionEntry*(c: PContext) =
- c.config.options = c.optionStack[^1].options
- c.config.notes = c.optionStack[^1].notes
- c.config.warningAsErrors = c.optionStack[^1].warningAsErrors
- c.features = c.optionStack[^1].features
- c.optionStack.setLen(c.optionStack.len - 1)
- proc newContext*(graph: ModuleGraph; module: PSym): PContext =
- new(result)
- result.optionStack = @[newOptionEntry(graph.config)]
- result.libs = @[]
- result.module = module
- result.friendModules = @[module]
- result.converters = @[]
- result.patterns = @[]
- result.includedFiles = initIntSet()
- result.pureEnumFields = initStrTable()
- result.userPragmas = initStrTable()
- result.generics = @[]
- result.unknownIdents = initIntSet()
- result.cache = graph.cache
- result.graph = graph
- result.signatures = initStrTable()
- result.features = graph.config.features
- if graph.config.symbolFiles != disabledSf:
- let id = module.position
- assert graph.packed[id].status in {undefined, outdated}
- graph.packed[id].status = storing
- graph.packed[id].module = module
- initEncoder graph, module
- template packedRepr*(c): untyped = c.graph.packed[c.module.position].fromDisk
- template encoder*(c): untyped = c.graph.encoders[c.module.position]
- proc addIncludeFileDep*(c: PContext; f: FileIndex) =
- if c.config.symbolFiles != disabledSf:
- addIncludeFileDep(c.encoder, c.packedRepr, f)
- proc addImportFileDep*(c: PContext; f: FileIndex) =
- if c.config.symbolFiles != disabledSf:
- addImportFileDep(c.encoder, c.packedRepr, f)
- proc addPragmaComputation*(c: PContext; n: PNode) =
- if c.config.symbolFiles != disabledSf:
- addPragmaComputation(c.encoder, c.packedRepr, n)
- proc inclSym(sq: var seq[PSym], s: PSym): bool =
- for i in 0..<sq.len:
- if sq[i].id == s.id: return false
- sq.add s
- result = true
- proc addConverter*(c: PContext, conv: LazySym) =
- assert conv.sym != nil
- if inclSym(c.converters, conv.sym):
- add(c.graph.ifaces[c.module.position].converters, conv)
- proc addConverterDef*(c: PContext, conv: LazySym) =
- addConverter(c, conv)
- if c.config.symbolFiles != disabledSf:
- addConverter(c.encoder, c.packedRepr, conv.sym)
- proc addPureEnum*(c: PContext, e: LazySym) =
- assert e.sym != nil
- add(c.graph.ifaces[c.module.position].pureEnums, e)
- if c.config.symbolFiles != disabledSf:
- addPureEnum(c.encoder, c.packedRepr, e.sym)
- proc addPattern*(c: PContext, p: LazySym) =
- assert p.sym != nil
- if inclSym(c.patterns, p.sym):
- add(c.graph.ifaces[c.module.position].patterns, p)
- if c.config.symbolFiles != disabledSf:
- addTrmacro(c.encoder, c.packedRepr, p.sym)
- proc exportSym*(c: PContext; s: PSym) =
- strTableAdds(c.graph, c.module, s)
- if c.config.symbolFiles != disabledSf:
- addExported(c.encoder, c.packedRepr, s)
- proc reexportSym*(c: PContext; s: PSym) =
- strTableAdds(c.graph, c.module, s)
- if c.config.symbolFiles != disabledSf:
- addReexport(c.encoder, c.packedRepr, s)
- proc newLib*(kind: TLibKind): PLib =
- new(result)
- result.kind = kind #result.syms = initObjectSet()
- proc addToLib*(lib: PLib, sym: PSym) =
- #if sym.annex != nil and not isGenericRoutine(sym):
- # LocalError(sym.info, errInvalidPragma)
- sym.annex = lib
- proc newTypeS*(kind: TTypeKind, c: PContext, sons: seq[PType] = @[]): PType =
- result = newType(kind, nextTypeId(c.idgen), getCurrOwner(c), sons = sons)
- proc makePtrType*(owner: PSym, baseType: PType; idgen: IdGenerator): PType =
- result = newType(tyPtr, nextTypeId(idgen), owner)
- addSonSkipIntLit(result, baseType, idgen)
- proc makePtrType*(c: PContext, baseType: PType): PType =
- makePtrType(getCurrOwner(c), baseType, c.idgen)
- proc makeTypeWithModifier*(c: PContext,
- modifier: TTypeKind,
- baseType: PType): PType =
- assert modifier in {tyVar, tyLent, tyPtr, tyRef, tyStatic, tyTypeDesc}
- if modifier in {tyVar, tyLent, tyTypeDesc} and baseType.kind == modifier:
- result = baseType
- else:
- 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)
- addSonSkipIntLit(result, baseType, c.idgen)
- proc makeVarType*(owner: PSym, baseType: PType; idgen: IdGenerator; kind = tyVar): PType =
- if baseType.kind == kind:
- result = baseType
- else:
- result = newType(kind, nextTypeId(idgen), owner)
- addSonSkipIntLit(result, baseType, idgen)
- proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
- let typedesc = newTypeS(tyTypeDesc, c)
- incl typedesc.flags, tfCheckedForDestructor
- internalAssert(c.config, typ != nil)
- typedesc.addSonSkipIntLit(typ, c.idgen)
- let sym = newSym(skType, c.cache.idAnon, c.idgen, getCurrOwner(c), info,
- c.config.options).linkTo(typedesc)
- result = newSymNode(sym, info)
- proc makeTypeFromExpr*(c: PContext, n: PNode): PType =
- result = newTypeS(tyFromExpr, c)
- assert n != nil
- result.n = n
- proc newTypeWithSons*(owner: PSym, kind: TTypeKind, sons: seq[PType];
- idgen: IdGenerator): PType =
- result = newType(kind, nextTypeId(idgen), owner, sons = sons)
- proc newTypeWithSons*(c: PContext, kind: TTypeKind,
- sons: seq[PType]): PType =
- result = newType(kind, nextTypeId(c.idgen), getCurrOwner(c), sons = sons)
- proc newTypeWithSons*(c: PContext, kind: TTypeKind,
- parent: PType): PType =
- result = newType(kind, nextTypeId(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: newTypeWithSons(c, tyStatic, @[n.typ])
- proc makeAndType*(c: PContext, t1, t2: PType): PType =
- 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, sons = @[t1, t2])
- else:
- result = newTypeS(tyOr, c)
- template addOr(t1) =
- if t1.kind == tyOr:
- for x in t1: result.rawAddSon x
- else:
- result.rawAddSon t1
- addOr(t1)
- addOr(t2)
- propagateToOwner(result, t1)
- propagateToOwner(result, t2)
- result.flags.incl((t1.flags + t2.flags) * {tfHasStatic})
- result.flags.incl tfHasMeta
- proc makeNotType*(c: PContext, t1: PType): PType =
- result = newTypeS(tyNot, c, sons = @[t1])
- propagateToOwner(result, t1)
- result.flags.incl(t1.flags * {tfHasStatic})
- result.flags.incl tfHasMeta
- proc nMinusOne(c: PContext; n: PNode): PNode =
- result = newTreeI(nkCall, n.info, newSymNode(getSysMagic(c.graph, n.info, "pred", mPred)), n)
- # 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, sons = @[intType])
- if n.typ != nil and n.typ.n == nil:
- result.flags.incl tfUnresolved
- result.n = newTreeI(nkRange, n.info, newIntTypeNode(0, intType),
- makeStaticExpr(c, nMinusOne(c, n)))
- template rangeHasUnresolvedStatic*(t: PType): bool =
- tfUnresolved in t.flags
- proc errorType*(c: PContext): PType =
- ## creates a type representing an error state
- result = newTypeS(tyError, c)
- result.flags.incl tfCheckedForDestructor
- proc errorNode*(c: PContext, n: PNode): PNode =
- result = newNodeI(nkEmpty, n.info)
- result.typ = errorType(c)
- # These mimic localError
- template localErrorNode*(c: PContext, n: PNode, info: TLineInfo, msg: TMsgKind, arg: string): PNode =
- liMessage(c.config, info, msg, arg, doNothing, instLoc())
- errorNode(c, n)
- template localErrorNode*(c: PContext, n: PNode, info: TLineInfo, arg: string): PNode =
- liMessage(c.config, info, errGenerated, arg, doNothing, instLoc())
- errorNode(c, n)
- template localErrorNode*(c: PContext, n: PNode, msg: TMsgKind, arg: string): PNode =
- let n2 = n
- liMessage(c.config, n2.info, msg, arg, doNothing, instLoc())
- errorNode(c, n2)
- template localErrorNode*(c: PContext, n: PNode, arg: string): PNode =
- let n2 = n
- liMessage(c.config, n2.info, errGenerated, arg, doNothing, instLoc())
- errorNode(c, n2)
- proc fillTypeS*(dest: PType, kind: TTypeKind, c: PContext) =
- dest.kind = kind
- dest.owner = getCurrOwner(c)
- dest.size = - 1
- proc makeRangeType*(c: PContext; first, last: BiggestInt;
- info: TLineInfo; intType: PType = nil): PType =
- let intType = if intType != nil: intType else: getSysType(c.graph, info, tyInt)
- var n = newNodeI(nkRange, info)
- n.add newIntTypeNode(first, intType)
- n.add newIntTypeNode(last, intType)
- result = newTypeS(tyRange, c)
- result.n = n
- addSonSkipIntLit(result, intType, c.idgen) # basetype of range
- proc isSelf*(t: PType): bool {.inline.} =
- ## Is this the magical 'Self' type from concepts?
- t.kind == tyTypeDesc and tfPacked in t.flags
- proc makeTypeDesc*(c: PContext, typ: PType): PType =
- if typ.kind == tyTypeDesc and not isSelf(typ):
- result = typ
- else:
- 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
- result = newSym(skType, getIdent(c.cache, "AnonType"), c.idgen, t.owner, info)
- result.flags.incl sfAnon
- result.typ = t
- proc symNodeFromType*(c: PContext, t: PType, info: TLineInfo): PNode =
- result = newSymNode(symFromType(c, t, info), info)
- result.typ = makeTypeDesc(c, t)
- proc markIndirect*(c: PContext, s: PSym) {.inline.} =
- if s.kind in {skProc, skFunc, skConverter, skMethod, skIterator}:
- incl(s.flags, sfAddrTaken)
- # XXX add to 'c' for global analysis
- proc illFormedAst*(n: PNode; conf: ConfigRef) =
- globalError(conf, n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
- proc illFormedAstLocal*(n: PNode; conf: ConfigRef) =
- localError(conf, n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
- proc checkSonsLen*(n: PNode, length: int; conf: ConfigRef) =
- if n.len != length: illFormedAst(n, conf)
- proc checkMinSonsLen*(n: PNode, length: int; conf: ConfigRef) =
- if n.len < length: illFormedAst(n, conf)
- proc isTopLevel*(c: PContext): bool {.inline.} =
- result = c.currentScope.depthLevel <= 2
- proc isTopLevelInsideDeclaration*(c: PContext, sym: PSym): bool {.inline.} =
- # for routeKinds the scope isn't closed yet:
- c.currentScope.depthLevel <= 2 + ord(sym.kind in routineKinds)
- proc pushCaseContext*(c: PContext, caseNode: PNode) =
- c.p.caseContext.add((caseNode, 0))
- proc popCaseContext*(c: PContext) =
- discard pop(c.p.caseContext)
- proc setCaseContextIdx*(c: PContext, idx: int) =
- c.p.caseContext[^1].idx = idx
- template addExport*(c: PContext; s: PSym) =
- ## convenience to export a symbol from the current module
- addExport(c.graph, c.module, s)
- proc storeRodNode*(c: PContext, n: PNode) =
- if c.config.symbolFiles != disabledSf:
- toPackedNodeTopLevel(n, c.encoder, c.packedRepr)
- proc addToGenericProcCache*(c: PContext; s: PSym; inst: PInstantiation) =
- c.graph.procInstCache.mgetOrPut(s.itemId, @[]).add LazyInstantiation(module: c.module.position, inst: inst)
- if c.config.symbolFiles != disabledSf:
- storeInstantiation(c.encoder, c.packedRepr, s, inst)
- proc addToGenericCache*(c: PContext; s: PSym; inst: PType) =
- c.graph.typeInstCache.mgetOrPut(s.itemId, @[]).add LazyType(typ: inst)
- if c.config.symbolFiles != disabledSf:
- storeTypeInst(c.encoder, c.packedRepr, s, inst)
- proc sealRodFile*(c: PContext) =
- if c.config.symbolFiles != disabledSf:
- if c.graph.vm != nil:
- for (m, n) in PCtx(c.graph.vm).vmstateDiff:
- if m == c.module:
- addPragmaComputation(c, n)
- c.idgen.sealed = true # no further additions are allowed
- proc rememberExpansion*(c: PContext; info: TLineInfo; expandedSym: PSym) =
- ## Templates and macros are very special in Nim; these have
- ## inlining semantics so after semantic checking they leave no trace
- ## in the sem'checked AST. This is very bad for IDE-like tooling
- ## ("find all usages of this template" would not work). We need special
- ## logic to remember macro/template expansions. This is done here and
- ## delegated to the "rod" file mechanism.
- if c.config.symbolFiles != disabledSf:
- storeExpansion(c.encoder, c.packedRepr, info, expandedSym)
|