integrity.nim 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2021 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## Integrity checking for a set of .rod files.
  10. ## The set must cover a complete Nim project.
  11. import sets
  12. when defined(nimPreviewSlimSystem):
  13. import std/assertions
  14. import ".." / [ast, modulegraphs]
  15. import packed_ast, bitabs, ic
  16. type
  17. CheckedContext = object
  18. g: ModuleGraph
  19. thisModule: int32
  20. checkedSyms: HashSet[ItemId]
  21. checkedTypes: HashSet[ItemId]
  22. proc checkType(c: var CheckedContext; typeId: PackedItemId)
  23. proc checkForeignSym(c: var CheckedContext; symId: PackedItemId)
  24. proc checkNode(c: var CheckedContext; tree: PackedTree; n: NodePos)
  25. proc checkTypeObj(c: var CheckedContext; typ: PackedType) =
  26. for child in typ.types:
  27. checkType(c, child)
  28. if typ.n != emptyNodeId:
  29. checkNode(c, c.g.packed[c.thisModule].fromDisk.bodies, NodePos typ.n)
  30. if typ.sym != nilItemId:
  31. checkForeignSym(c, typ.sym)
  32. if typ.owner != nilItemId:
  33. checkForeignSym(c, typ.owner)
  34. checkType(c, typ.typeInst)
  35. proc checkType(c: var CheckedContext; typeId: PackedItemId) =
  36. if typeId == nilItemId: return
  37. let itemId = translateId(typeId, c.g.packed, c.thisModule, c.g.config)
  38. if not c.checkedTypes.containsOrIncl(itemId):
  39. let oldThisModule = c.thisModule
  40. c.thisModule = itemId.module
  41. checkTypeObj c, c.g.packed[itemId.module].fromDisk.types[itemId.item]
  42. c.thisModule = oldThisModule
  43. proc checkSym(c: var CheckedContext; s: PackedSym) =
  44. if s.name != LitId(0):
  45. assert c.g.packed[c.thisModule].fromDisk.strings.hasLitId s.name
  46. checkType c, s.typ
  47. if s.ast != emptyNodeId:
  48. checkNode(c, c.g.packed[c.thisModule].fromDisk.bodies, NodePos s.ast)
  49. if s.owner != nilItemId:
  50. checkForeignSym(c, s.owner)
  51. proc checkLocalSym(c: var CheckedContext; item: int32) =
  52. let itemId = ItemId(module: c.thisModule, item: item)
  53. if not c.checkedSyms.containsOrIncl(itemId):
  54. checkSym c, c.g.packed[c.thisModule].fromDisk.syms[item]
  55. proc checkForeignSym(c: var CheckedContext; symId: PackedItemId) =
  56. let itemId = translateId(symId, c.g.packed, c.thisModule, c.g.config)
  57. if not c.checkedSyms.containsOrIncl(itemId):
  58. let oldThisModule = c.thisModule
  59. c.thisModule = itemId.module
  60. checkSym c, c.g.packed[itemId.module].fromDisk.syms[itemId.item]
  61. c.thisModule = oldThisModule
  62. proc checkNode(c: var CheckedContext; tree: PackedTree; n: NodePos) =
  63. if tree[n.int].typeId != nilItemId:
  64. checkType(c, tree[n.int].typeId)
  65. case n.kind
  66. of nkEmpty, nkNilLit, nkType, nkNilRodNode:
  67. discard
  68. of nkIdent:
  69. assert c.g.packed[c.thisModule].fromDisk.strings.hasLitId n.litId
  70. of nkSym:
  71. checkLocalSym(c, tree.nodes[n.int].operand)
  72. of directIntLit:
  73. discard
  74. of externIntLit, nkFloatLit..nkFloat128Lit:
  75. assert c.g.packed[c.thisModule].fromDisk.numbers.hasLitId n.litId
  76. of nkStrLit..nkTripleStrLit:
  77. assert c.g.packed[c.thisModule].fromDisk.strings.hasLitId n.litId
  78. of nkModuleRef:
  79. let (n1, n2) = sons2(tree, n)
  80. assert n1.kind == nkInt32Lit
  81. assert n2.kind == nkInt32Lit
  82. checkForeignSym(c, PackedItemId(module: n1.litId, item: tree.nodes[n2.int].operand))
  83. else:
  84. for n0 in sonsReadonly(tree, n):
  85. checkNode(c, tree, n0)
  86. proc checkTree(c: var CheckedContext; t: PackedTree) =
  87. for p in allNodes(t): checkNode(c, t, p)
  88. proc checkLocalSymIds(c: var CheckedContext; m: PackedModule; symIds: seq[int32]) =
  89. for symId in symIds:
  90. assert symId >= 0 and symId < m.syms.len, $symId & " " & $m.syms.len
  91. proc checkModule(c: var CheckedContext; m: PackedModule) =
  92. # We check that:
  93. # - Every symbol references existing types and symbols.
  94. # - Every tree node references existing types and symbols.
  95. for i in 0..high(m.syms):
  96. checkLocalSym c, int32(i)
  97. checkTree c, m.toReplay
  98. checkTree c, m.topLevel
  99. for e in m.exports:
  100. assert e[1] >= 0 and e[1] < m.syms.len
  101. assert e[0] == m.syms[e[1]].name
  102. for e in m.compilerProcs:
  103. assert e[1] >= 0 and e[1] < m.syms.len
  104. assert e[0] == m.syms[e[1]].name
  105. checkLocalSymIds c, m, m.converters
  106. checkLocalSymIds c, m, m.methods
  107. checkLocalSymIds c, m, m.trmacros
  108. checkLocalSymIds c, m, m.pureEnums
  109. #[
  110. To do: Check all these fields:
  111. reexports*: seq[(LitId, PackedItemId)]
  112. macroUsages*: seq[(PackedItemId, PackedLineInfo)]
  113. typeInstCache*: seq[(PackedItemId, PackedItemId)]
  114. procInstCache*: seq[PackedInstantiation]
  115. attachedOps*: seq[(TTypeAttachedOp, PackedItemId, PackedItemId)]
  116. methodsPerType*: seq[(PackedItemId, int, PackedItemId)]
  117. enumToStringProcs*: seq[(PackedItemId, PackedItemId)]
  118. ]#
  119. proc checkIntegrity*(g: ModuleGraph) =
  120. var c = CheckedContext(g: g)
  121. for i in 0..high(g.packed):
  122. # case statement here to enforce exhaustive checks.
  123. case g.packed[i].status
  124. of undefined:
  125. discard "nothing to do"
  126. of loading:
  127. assert false, "cannot check integrity: Module still loading"
  128. of stored, storing, outdated, loaded:
  129. c.thisModule = int32 i
  130. checkModule(c, g.packed[i].fromDisk)