1#
2#
3#           The Nim Compiler
4#        (c) Copyright 2017 Andreas Rumpf
5#
6#    See the file "copying.txt", included in this
7#    distribution, for details about the copyright.
8#
9
10## This module contains the data structures for the semantic checking phase.
11
12import tables
13
14import
15  intsets, options, ast, astalgo, msgs, idents, renderer,
16  magicsys, vmdef, modulegraphs, lineinfos, sets, pathutils
17
18import ic / ic
19
20type
21  TOptionEntry* = object      # entries to put on a stack for pragma parsing
22    options*: TOptions
23    defaultCC*: TCallingConvention
24    dynlib*: PLib
25    notes*: TNoteKinds
26    features*: set[Feature]
27    otherPragmas*: PNode      # every pragma can be pushed
28    warningAsErrors*: TNoteKinds
29
30  POptionEntry* = ref TOptionEntry
31  PProcCon* = ref TProcCon
32  TProcCon* {.acyclic.} = object # procedure context; also used for top-level
33                                 # statements
34    owner*: PSym              # the symbol this context belongs to
35    resultSym*: PSym          # the result symbol (if we are in a proc)
36    selfSym*: PSym            # the 'self' symbol (if available)
37    nestedLoopCounter*: int   # whether we are in a loop or not
38    nestedBlockCounter*: int  # whether we are in a block or not
39    next*: PProcCon           # used for stacking procedure contexts
40    mappingExists*: bool
41    mapping*: TIdTable
42    caseContext*: seq[tuple[n: PNode, idx: int]]
43    localBindStmts*: seq[PNode]
44
45  TMatchedConcept* = object
46    candidateType*: PType
47    prev*: ptr TMatchedConcept
48    depth*: int
49
50  TInstantiationPair* = object
51    genericSym*: PSym
52    inst*: PInstantiation
53
54  TExprFlag* = enum
55    efLValue, efWantIterator, efWantIterable, efInTypeof,
56    efNeedStatic,
57      # Use this in contexts where a static value is mandatory
58    efPreferStatic,
59      # Use this in contexts where a static value could bring more
60      # information, but it's not strictly mandatory. This may become
61      # the default with implicit statics in the future.
62    efPreferNilResult,
63      # Use this if you want a certain result (e.g. static value),
64      # but you don't want to trigger a hard error. For example,
65      # you may be in position to supply a better error message
66      # to the user.
67    efWantStmt, efAllowStmt, efDetermineType, efExplain,
68    efWantValue, efOperand, efNoSemCheck,
69    efNoEvaluateGeneric, efInCall, efFromHlo, efNoSem2Check,
70    efNoUndeclared
71      # Use this if undeclared identifiers should not raise an error during
72      # overload resolution.
73
74  TExprFlags* = set[TExprFlag]
75
76  ImportMode* = enum
77    importAll, importSet, importExcept
78  ImportedModule* = object
79    m*: PSym
80    case mode*: ImportMode
81    of importAll: discard
82    of importSet:
83      imported*: IntSet          # of PIdent.id
84    of importExcept:
85      exceptSet*: IntSet         # of PIdent.id
86
87  PContext* = ref TContext
88  TContext* = object of TPassContext # a context represents the module
89                                     # that is currently being compiled
90    enforceVoidContext*: PType
91      # for `if cond: stmt else: foo`, `foo` will be evaluated under
92      # enforceVoidContext != nil
93    voidType*: PType # for typeof(stmt)
94    module*: PSym              # the module sym belonging to the context
95    currentScope*: PScope      # current scope
96    moduleScope*: PScope       # scope for modules
97    imports*: seq[ImportedModule] # scope for all imported symbols
98    topLevelScope*: PScope     # scope for all top-level symbols
99    p*: PProcCon               # procedure context
100    intTypeCache*: array[-5..32, PType] # cache some common integer types
101                                        # to avoid type allocations
102    nilTypeCache*: PType
103    matchedConcept*: ptr TMatchedConcept # the current concept being matched
104    friendModules*: seq[PSym]  # friend modules; may access private data;
105                               # this is used so that generic instantiations
106                               # can access private object fields
107    instCounter*: int          # to prevent endless instantiations
108    templInstCounter*: ref int # gives every template instantiation a unique id
109    inGenericContext*: int     # > 0 if we are in a generic type
110    inStaticContext*: int      # > 0 if we are inside a static: block
111    inUnrolledContext*: int    # > 0 if we are unrolling a loop
112    compilesContextId*: int    # > 0 if we are in a ``compiles`` magic
113    compilesContextIdGenerator*: int
114    inGenericInst*: int        # > 0 if we are instantiating a generic
115    converters*: seq[PSym]
116    patterns*: seq[PSym]       # sequence of pattern matchers
117    optionStack*: seq[POptionEntry]
118    symMapping*: TIdTable      # every gensym'ed symbol needs to be mapped
119                               # to some new symbol in a generic instantiation
120    libs*: seq[PLib]           # all libs used by this module
121    semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
122    semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
123    semTryExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
124    semTryConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.}
125    computeRequiresInit*: proc (c: PContext, t: PType): bool {.nimcall.}
126    hasUnresolvedArgs*: proc (c: PContext, n: PNode): bool
127
128    semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
129    semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet
130    semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
131                              filter: TSymKinds, flags: TExprFlags): PNode {.nimcall.}
132    semTypeNode*: proc(c: PContext, n: PNode, prev: PType): PType {.nimcall.}
133    semInferredLambda*: proc(c: PContext, pt: TIdTable, n: PNode): PNode
134    semGenerateInstance*: proc (c: PContext, fn: PSym, pt: TIdTable,
135                                info: TLineInfo): PSym
136    includedFiles*: IntSet    # used to detect recursive include files
137    pureEnumFields*: TStrTable   # pure enum fields that can be used unambiguously
138    userPragmas*: TStrTable
139    evalContext*: PEvalContext
140    unknownIdents*: IntSet     # ids of all unknown identifiers to prevent
141                               # naming it multiple times
142    generics*: seq[TInstantiationPair] # pending list of instantiated generics to compile
143    topStmts*: int # counts the number of encountered top level statements
144    lastGenericIdx*: int      # used for the generics stack
145    hloLoopDetector*: int     # used to prevent endless loops in the HLO
146    inParallelStmt*: int
147    instTypeBoundOp*: proc (c: PContext; dc: PSym; t: PType; info: TLineInfo;
148                            op: TTypeAttachedOp; col: int): PSym {.nimcall.}
149    selfName*: PIdent
150    cache*: IdentCache
151    graph*: ModuleGraph
152    signatures*: TStrTable
153    recursiveDep*: string
154    suggestionsMade*: bool
155    isAmbiguous*: bool # little hack
156    features*: set[Feature]
157    inTypeContext*, inConceptDecl*: int
158    unusedImports*: seq[(PSym, TLineInfo)]
159    exportIndirections*: HashSet[(int, int)] # (module.id, symbol.id)
160    importModuleMap*: Table[int, int] # (module.id, module.id)
161    lastTLineInfo*: TLineInfo
162    sideEffects*: Table[int, seq[(TLineInfo, PSym)]] # symbol.id index
163    inUncheckedAssignSection*: int
164
165template config*(c: PContext): ConfigRef = c.graph.config
166
167proc getIntLitType*(c: PContext; literal: PNode): PType =
168  # we cache some common integer literal types for performance:
169  let value = literal.intVal
170  if value >= low(c.intTypeCache) and value <= high(c.intTypeCache):
171    result = c.intTypeCache[value.int]
172    if result == nil:
173      let ti = getSysType(c.graph, literal.info, tyInt)
174      result = copyType(ti, nextTypeId(c.idgen), ti.owner)
175      result.n = literal
176      c.intTypeCache[value.int] = result
177  else:
178    let ti = getSysType(c.graph, literal.info, tyInt)
179    result = copyType(ti, nextTypeId(c.idgen), ti.owner)
180    result.n = literal
181
182proc setIntLitType*(c: PContext; result: PNode) =
183  let i = result.intVal
184  case c.config.target.intSize
185  of 8: result.typ = getIntLitType(c, result)
186  of 4:
187    if i >= low(int32) and i <= high(int32):
188      result.typ = getIntLitType(c, result)
189    else:
190      result.typ = getSysType(c.graph, result.info, tyInt64)
191  of 2:
192    if i >= low(int16) and i <= high(int16):
193      result.typ = getIntLitType(c, result)
194    elif i >= low(int32) and i <= high(int32):
195      result.typ = getSysType(c.graph, result.info, tyInt32)
196    else:
197      result.typ = getSysType(c.graph, result.info, tyInt64)
198  of 1:
199    # 8 bit CPUs are insane ...
200    if i >= low(int8) and i <= high(int8):
201      result.typ = getIntLitType(c, result)
202    elif i >= low(int16) and i <= high(int16):
203      result.typ = getSysType(c.graph, result.info, tyInt16)
204    elif i >= low(int32) and i <= high(int32):
205      result.typ = getSysType(c.graph, result.info, tyInt32)
206    else:
207      result.typ = getSysType(c.graph, result.info, tyInt64)
208  else:
209    internalError(c.config, result.info, "invalid int size")
210
211proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
212  result.genericSym = s
213  result.inst = inst
214
215proc filename*(c: PContext): string =
216  # the module's filename
217  return toFilename(c.config, FileIndex c.module.position)
218
219proc scopeDepth*(c: PContext): int {.inline.} =
220  result = if c.currentScope != nil: c.currentScope.depthLevel
221           else: 0
222
223proc getCurrOwner*(c: PContext): PSym =
224  # owner stack (used for initializing the
225  # owner field of syms)
226  # the documentation comment always gets
227  # assigned to the current owner
228  result = c.graph.owners[^1]
229
230proc pushOwner*(c: PContext; owner: PSym) =
231  c.graph.owners.add(owner)
232
233proc popOwner*(c: PContext) =
234  if c.graph.owners.len > 0: setLen(c.graph.owners, c.graph.owners.len - 1)
235  else: internalError(c.config, "popOwner")
236
237proc lastOptionEntry*(c: PContext): POptionEntry =
238  result = c.optionStack[^1]
239
240proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next
241
242proc put*(p: PProcCon; key, val: PSym) =
243  if not p.mappingExists:
244    initIdTable(p.mapping)
245    p.mappingExists = true
246  #echo "put into table ", key.info
247  p.mapping.idTablePut(key, val)
248
249proc get*(p: PProcCon; key: PSym): PSym =
250  if not p.mappingExists: return nil
251  result = PSym(p.mapping.idTableGet(key))
252
253proc getGenSym*(c: PContext; s: PSym): PSym =
254  if sfGenSym notin s.flags: return s
255  var it = c.p
256  while it != nil:
257    result = get(it, s)
258    if result != nil:
259      #echo "got from table ", result.name.s, " ", result.info
260      return result
261    it = it.next
262  result = s
263
264proc considerGenSyms*(c: PContext; n: PNode) =
265  if n == nil:
266    discard "can happen for nkFormalParams/nkArgList"
267  elif n.kind == nkSym:
268    let s = getGenSym(c, n.sym)
269    if n.sym != s:
270      n.sym = s
271  else:
272    for i in 0..<n.safeLen:
273      considerGenSyms(c, n[i])
274
275proc newOptionEntry*(conf: ConfigRef): POptionEntry =
276  new(result)
277  result.options = conf.options
278  result.defaultCC = ccNimCall
279  result.dynlib = nil
280  result.notes = conf.notes
281  result.warningAsErrors = conf.warningAsErrors
282
283proc pushOptionEntry*(c: PContext): POptionEntry =
284  new(result)
285  var prev = c.optionStack[^1]
286  result.options = c.config.options
287  result.defaultCC = prev.defaultCC
288  result.dynlib = prev.dynlib
289  result.notes = c.config.notes
290  result.warningAsErrors = c.config.warningAsErrors
291  result.features = c.features
292  c.optionStack.add(result)
293
294proc popOptionEntry*(c: PContext) =
295  c.config.options = c.optionStack[^1].options
296  c.config.notes = c.optionStack[^1].notes
297  c.config.warningAsErrors = c.optionStack[^1].warningAsErrors
298  c.features = c.optionStack[^1].features
299  c.optionStack.setLen(c.optionStack.len - 1)
300
301proc newContext*(graph: ModuleGraph; module: PSym): PContext =
302  new(result)
303  result.optionStack = @[newOptionEntry(graph.config)]
304  result.libs = @[]
305  result.module = module
306  result.friendModules = @[module]
307  result.converters = @[]
308  result.patterns = @[]
309  result.includedFiles = initIntSet()
310  initStrTable(result.pureEnumFields)
311  initStrTable(result.userPragmas)
312  result.generics = @[]
313  result.unknownIdents = initIntSet()
314  result.cache = graph.cache
315  result.graph = graph
316  initStrTable(result.signatures)
317  result.features = graph.config.features
318  if graph.config.symbolFiles != disabledSf:
319    let id = module.position
320    assert graph.packed[id].status in {undefined, outdated}
321    graph.packed[id].status = storing
322    graph.packed[id].module = module
323    initEncoder graph, module
324
325template packedRepr*(c): untyped = c.graph.packed[c.module.position].fromDisk
326template encoder*(c): untyped = c.graph.encoders[c.module.position]
327
328proc addIncludeFileDep*(c: PContext; f: FileIndex) =
329  if c.config.symbolFiles != disabledSf:
330    addIncludeFileDep(c.encoder, c.packedRepr, f)
331
332proc addImportFileDep*(c: PContext; f: FileIndex) =
333  if c.config.symbolFiles != disabledSf:
334    addImportFileDep(c.encoder, c.packedRepr, f)
335
336proc addPragmaComputation*(c: PContext; n: PNode) =
337  if c.config.symbolFiles != disabledSf:
338    addPragmaComputation(c.encoder, c.packedRepr, n)
339
340proc inclSym(sq: var seq[PSym], s: PSym): bool =
341  for i in 0..<sq.len:
342    if sq[i].id == s.id: return false
343  sq.add s
344  result = true
345
346proc addConverter*(c: PContext, conv: LazySym) =
347  assert conv.sym != nil
348  if inclSym(c.converters, conv.sym):
349    add(c.graph.ifaces[c.module.position].converters, conv)
350
351proc addConverterDef*(c: PContext, conv: LazySym) =
352  addConverter(c, conv)
353  if c.config.symbolFiles != disabledSf:
354    addConverter(c.encoder, c.packedRepr, conv.sym)
355
356proc addPureEnum*(c: PContext, e: LazySym) =
357  assert e.sym != nil
358  add(c.graph.ifaces[c.module.position].pureEnums, e)
359  if c.config.symbolFiles != disabledSf:
360    addPureEnum(c.encoder, c.packedRepr, e.sym)
361
362proc addPattern*(c: PContext, p: LazySym) =
363  assert p.sym != nil
364  if inclSym(c.patterns, p.sym):
365    add(c.graph.ifaces[c.module.position].patterns, p)
366  if c.config.symbolFiles != disabledSf:
367    addTrmacro(c.encoder, c.packedRepr, p.sym)
368
369proc exportSym*(c: PContext; s: PSym) =
370  strTableAdds(c.graph, c.module, s)
371  if c.config.symbolFiles != disabledSf:
372    addExported(c.encoder, c.packedRepr, s)
373
374proc reexportSym*(c: PContext; s: PSym) =
375  strTableAdds(c.graph, c.module, s)
376  if c.config.symbolFiles != disabledSf:
377    addReexport(c.encoder, c.packedRepr, s)
378
379proc newLib*(kind: TLibKind): PLib =
380  new(result)
381  result.kind = kind          #initObjectSet(result.syms)
382
383proc addToLib*(lib: PLib, sym: PSym) =
384  #if sym.annex != nil and not isGenericRoutine(sym):
385  #  LocalError(sym.info, errInvalidPragma)
386  sym.annex = lib
387
388proc newTypeS*(kind: TTypeKind, c: PContext): PType =
389  result = newType(kind, nextTypeId(c.idgen), getCurrOwner(c))
390
391proc makePtrType*(owner: PSym, baseType: PType; idgen: IdGenerator): PType =
392  result = newType(tyPtr, nextTypeId(idgen), owner)
393  addSonSkipIntLit(result, baseType, idgen)
394
395proc makePtrType*(c: PContext, baseType: PType): PType =
396  makePtrType(getCurrOwner(c), baseType, c.idgen)
397
398proc makeTypeWithModifier*(c: PContext,
399                           modifier: TTypeKind,
400                           baseType: PType): PType =
401  assert modifier in {tyVar, tyLent, tyPtr, tyRef, tyStatic, tyTypeDesc}
402
403  if modifier in {tyVar, tyLent, tyTypeDesc} and baseType.kind == modifier:
404    result = baseType
405  else:
406    result = newTypeS(modifier, c)
407    addSonSkipIntLit(result, baseType, c.idgen)
408
409proc makeVarType*(c: PContext, baseType: PType; kind = tyVar): PType =
410  if baseType.kind == kind:
411    result = baseType
412  else:
413    result = newTypeS(kind, c)
414    addSonSkipIntLit(result, baseType, c.idgen)
415
416proc makeVarType*(owner: PSym, baseType: PType; idgen: IdGenerator; kind = tyVar): PType =
417  if baseType.kind == kind:
418    result = baseType
419  else:
420    result = newType(kind, nextTypeId(idgen), owner)
421    addSonSkipIntLit(result, baseType, idgen)
422
423proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
424  let typedesc = newTypeS(tyTypeDesc, c)
425  incl typedesc.flags, tfCheckedForDestructor
426  internalAssert(c.config, typ != nil)
427  typedesc.addSonSkipIntLit(typ, c.idgen)
428  let sym = newSym(skType, c.cache.idAnon, nextSymId(c.idgen), getCurrOwner(c), info,
429                   c.config.options).linkTo(typedesc)
430  result = newSymNode(sym, info)
431
432proc makeTypeFromExpr*(c: PContext, n: PNode): PType =
433  result = newTypeS(tyFromExpr, c)
434  assert n != nil
435  result.n = n
436
437proc newTypeWithSons*(owner: PSym, kind: TTypeKind, sons: seq[PType];
438                      idgen: IdGenerator): PType =
439  result = newType(kind, nextTypeId(idgen), owner)
440  result.sons = sons
441
442proc newTypeWithSons*(c: PContext, kind: TTypeKind,
443                      sons: seq[PType]): PType =
444  result = newType(kind, nextTypeId(c.idgen), getCurrOwner(c))
445  result.sons = sons
446
447proc makeStaticExpr*(c: PContext, n: PNode): PNode =
448  result = newNodeI(nkStaticExpr, n.info)
449  result.sons = @[n]
450  result.typ = if n.typ != nil and n.typ.kind == tyStatic: n.typ
451               else: newTypeWithSons(c, tyStatic, @[n.typ])
452
453proc makeAndType*(c: PContext, t1, t2: PType): PType =
454  result = newTypeS(tyAnd, c)
455  result.sons = @[t1, t2]
456  propagateToOwner(result, t1)
457  propagateToOwner(result, t2)
458  result.flags.incl((t1.flags + t2.flags) * {tfHasStatic})
459  result.flags.incl tfHasMeta
460
461proc makeOrType*(c: PContext, t1, t2: PType): PType =
462  result = newTypeS(tyOr, c)
463  if t1.kind != tyOr and t2.kind != tyOr:
464    result.sons = @[t1, t2]
465  else:
466    template addOr(t1) =
467      if t1.kind == tyOr:
468        for x in t1.sons: result.rawAddSon x
469      else:
470        result.rawAddSon t1
471    addOr(t1)
472    addOr(t2)
473  propagateToOwner(result, t1)
474  propagateToOwner(result, t2)
475  result.flags.incl((t1.flags + t2.flags) * {tfHasStatic})
476  result.flags.incl tfHasMeta
477
478proc makeNotType*(c: PContext, t1: PType): PType =
479  result = newTypeS(tyNot, c)
480  result.sons = @[t1]
481  propagateToOwner(result, t1)
482  result.flags.incl(t1.flags * {tfHasStatic})
483  result.flags.incl tfHasMeta
484
485proc nMinusOne(c: PContext; n: PNode): PNode =
486  result = newTreeI(nkCall, n.info, newSymNode(getSysMagic(c.graph, n.info, "pred", mPred)), n)
487
488# Remember to fix the procs below this one when you make changes!
489proc makeRangeWithStaticExpr*(c: PContext, n: PNode): PType =
490  let intType = getSysType(c.graph, n.info, tyInt)
491  result = newTypeS(tyRange, c)
492  result.sons = @[intType]
493  if n.typ != nil and n.typ.n == nil:
494    result.flags.incl tfUnresolved
495  result.n = newTreeI(nkRange, n.info, newIntTypeNode(0, intType),
496    makeStaticExpr(c, nMinusOne(c, n)))
497
498template rangeHasUnresolvedStatic*(t: PType): bool =
499  tfUnresolved in t.flags
500
501proc errorType*(c: PContext): PType =
502  ## creates a type representing an error state
503  result = newTypeS(tyError, c)
504  result.flags.incl tfCheckedForDestructor
505
506proc errorNode*(c: PContext, n: PNode): PNode =
507  result = newNodeI(nkEmpty, n.info)
508  result.typ = errorType(c)
509
510# These mimic localError
511template localErrorNode*(c: PContext, n: PNode, info: TLineInfo, msg: TMsgKind, arg: string): PNode =
512  liMessage(c.config, info, msg, arg, doNothing, instLoc())
513  errorNode(c, n)
514
515template localErrorNode*(c: PContext, n: PNode, info: TLineInfo, arg: string): PNode =
516  liMessage(c.config, info, errGenerated, arg, doNothing, instLoc())
517  errorNode(c, n)
518
519template localErrorNode*(c: PContext, n: PNode, msg: TMsgKind, arg: string): PNode =
520  let n2 = n
521  liMessage(c.config, n2.info, msg, arg, doNothing, instLoc())
522  errorNode(c, n2)
523
524template localErrorNode*(c: PContext, n: PNode, arg: string): PNode =
525  let n2 = n
526  liMessage(c.config, n2.info, errGenerated, arg, doNothing, instLoc())
527  errorNode(c, n2)
528
529proc fillTypeS*(dest: PType, kind: TTypeKind, c: PContext) =
530  dest.kind = kind
531  dest.owner = getCurrOwner(c)
532  dest.size = - 1
533
534proc makeRangeType*(c: PContext; first, last: BiggestInt;
535                    info: TLineInfo; intType: PType = nil): PType =
536  let intType = if intType != nil: intType else: getSysType(c.graph, info, tyInt)
537  var n = newNodeI(nkRange, info)
538  n.add newIntTypeNode(first, intType)
539  n.add newIntTypeNode(last, intType)
540  result = newTypeS(tyRange, c)
541  result.n = n
542  addSonSkipIntLit(result, intType, c.idgen) # basetype of range
543
544proc markIndirect*(c: PContext, s: PSym) {.inline.} =
545  if s.kind in {skProc, skFunc, skConverter, skMethod, skIterator}:
546    incl(s.flags, sfAddrTaken)
547    # XXX add to 'c' for global analysis
548
549proc illFormedAst*(n: PNode; conf: ConfigRef) =
550  globalError(conf, n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
551
552proc illFormedAstLocal*(n: PNode; conf: ConfigRef) =
553  localError(conf, n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
554
555proc checkSonsLen*(n: PNode, length: int; conf: ConfigRef) =
556  if n.len != length: illFormedAst(n, conf)
557
558proc checkMinSonsLen*(n: PNode, length: int; conf: ConfigRef) =
559  if n.len < length: illFormedAst(n, conf)
560
561proc isTopLevel*(c: PContext): bool {.inline.} =
562  result = c.currentScope.depthLevel <= 2
563
564proc isTopLevelInsideDeclaration*(c: PContext, sym: PSym): bool {.inline.} =
565  # for routeKinds the scope isn't closed yet:
566  c.currentScope.depthLevel <= 2 + ord(sym.kind in routineKinds)
567
568proc pushCaseContext*(c: PContext, caseNode: PNode) =
569  c.p.caseContext.add((caseNode, 0))
570
571proc popCaseContext*(c: PContext) =
572  discard pop(c.p.caseContext)
573
574proc setCaseContextIdx*(c: PContext, idx: int) =
575  c.p.caseContext[^1].idx = idx
576
577template addExport*(c: PContext; s: PSym) =
578  ## convenience to export a symbol from the current module
579  addExport(c.graph, c.module, s)
580
581proc storeRodNode*(c: PContext, n: PNode) =
582  if c.config.symbolFiles != disabledSf:
583    toPackedNodeTopLevel(n, c.encoder, c.packedRepr)
584
585proc addToGenericProcCache*(c: PContext; s: PSym; inst: PInstantiation) =
586  c.graph.procInstCache.mgetOrPut(s.itemId, @[]).add LazyInstantiation(module: c.module.position, inst: inst)
587  if c.config.symbolFiles != disabledSf:
588    storeInstantiation(c.encoder, c.packedRepr, s, inst)
589
590proc addToGenericCache*(c: PContext; s: PSym; inst: PType) =
591  c.graph.typeInstCache.mgetOrPut(s.itemId, @[]).add LazyType(typ: inst)
592  if c.config.symbolFiles != disabledSf:
593    storeTypeInst(c.encoder, c.packedRepr, s, inst)
594
595proc sealRodFile*(c: PContext) =
596  if c.config.symbolFiles != disabledSf:
597    if c.graph.vm != nil:
598      for (m, n) in PCtx(c.graph.vm).vmstateDiff:
599        if m == c.module:
600          addPragmaComputation(c, n)
601    c.idgen.sealed = true # no further additions are allowed
602
603proc rememberExpansion*(c: PContext; info: TLineInfo; expandedSym: PSym) =
604  ## Templates and macros are very special in Nim; these have
605  ## inlining semantics so after semantic checking they leave no trace
606  ## in the sem'checked AST. This is very bad for IDE-like tooling
607  ## ("find all usages of this template" would not work). We need special
608  ## logic to remember macro/template expansions. This is done here and
609  ## delegated to the "rod" file mechanism.
610  if c.config.symbolFiles != disabledSf:
611    storeExpansion(c.encoder, c.packedRepr, info, expandedSym)
612