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 std/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. let t = findType(tree, n)
  64. if t != nilItemId:
  65. checkType(c, t)
  66. case n.kind
  67. of nkEmpty, nkNilLit, nkType, nkNilRodNode:
  68. discard
  69. of nkIdent:
  70. assert c.g.packed[c.thisModule].fromDisk.strings.hasLitId n.litId
  71. of nkSym:
  72. checkLocalSym(c, tree[n].soperand)
  73. of directIntLit:
  74. discard
  75. of externIntLit, nkFloatLit..nkFloat128Lit:
  76. assert c.g.packed[c.thisModule].fromDisk.numbers.hasLitId n.litId
  77. of nkStrLit..nkTripleStrLit:
  78. assert c.g.packed[c.thisModule].fromDisk.strings.hasLitId n.litId
  79. of nkModuleRef:
  80. let (n1, n2) = sons2(tree, n)
  81. assert n1.kind == nkNone
  82. assert n2.kind == nkNone
  83. checkForeignSym(c, PackedItemId(module: n1.litId, item: tree[n2].soperand))
  84. else:
  85. for n0 in sonsReadonly(tree, n):
  86. checkNode(c, tree, n0)
  87. proc checkTree(c: var CheckedContext; t: PackedTree) =
  88. for p in allNodes(t): checkNode(c, t, p)
  89. proc checkLocalSymIds(c: var CheckedContext; m: PackedModule; symIds: seq[int32]) =
  90. for symId in symIds:
  91. assert symId >= 0 and symId < m.syms.len, $symId & " " & $m.syms.len
  92. proc checkModule(c: var CheckedContext; m: PackedModule) =
  93. # We check that:
  94. # - Every symbol references existing types and symbols.
  95. # - Every tree node references existing types and symbols.
  96. for i in 0..high(m.syms):
  97. checkLocalSym c, int32(i)
  98. checkTree c, m.toReplay
  99. checkTree c, m.topLevel
  100. for e in m.exports:
  101. assert e[1] >= 0 and e[1] < m.syms.len
  102. assert e[0] == m.syms[e[1]].name
  103. for e in m.compilerProcs:
  104. assert e[1] >= 0 and e[1] < m.syms.len
  105. assert e[0] == m.syms[e[1]].name
  106. checkLocalSymIds c, m, m.converters
  107. checkLocalSymIds c, m, m.methods
  108. checkLocalSymIds c, m, m.trmacros
  109. checkLocalSymIds c, m, m.pureEnums
  110. #[
  111. To do: Check all these fields:
  112. reexports*: seq[(LitId, PackedItemId)]
  113. macroUsages*: seq[(PackedItemId, PackedLineInfo)]
  114. typeInstCache*: seq[(PackedItemId, PackedItemId)]
  115. procInstCache*: seq[PackedInstantiation]
  116. attachedOps*: seq[(TTypeAttachedOp, PackedItemId, PackedItemId)]
  117. methodsPerType*: seq[(PackedItemId, int, PackedItemId)]
  118. enumToStringProcs*: seq[(PackedItemId, PackedItemId)]
  119. ]#
  120. proc checkIntegrity*(g: ModuleGraph) =
  121. var c = CheckedContext(g: g)
  122. for i in 0..<len(g.packed):
  123. # case statement here to enforce exhaustive checks.
  124. case g.packed[i].status
  125. of undefined:
  126. discard "nothing to do"
  127. of loading:
  128. assert false, "cannot check integrity: Module still loading"
  129. of stored, storing, outdated, loaded:
  130. c.thisModule = int32 i
  131. checkModule(c, g.packed[i].fromDisk)