integrity.nim 4.9 KB

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