123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- #
- #
- # The Nim Compiler
- # (c) Copyright 2021 Andreas Rumpf
- #
- # See the file "copying.txt", included in this
- # distribution, for details about the copyright.
- #
- ## Integrity checking for a set of .rod files.
- ## The set must cover a complete Nim project.
- import sets
- when defined(nimPreviewSlimSystem):
- import std/assertions
- import ".." / [ast, modulegraphs]
- import packed_ast, bitabs, ic
- type
- CheckedContext = object
- g: ModuleGraph
- thisModule: int32
- checkedSyms: HashSet[ItemId]
- checkedTypes: HashSet[ItemId]
- proc checkType(c: var CheckedContext; typeId: PackedItemId)
- proc checkForeignSym(c: var CheckedContext; symId: PackedItemId)
- proc checkNode(c: var CheckedContext; tree: PackedTree; n: NodePos)
- proc checkTypeObj(c: var CheckedContext; typ: PackedType) =
- for child in typ.types:
- checkType(c, child)
- if typ.n != emptyNodeId:
- checkNode(c, c.g.packed[c.thisModule].fromDisk.bodies, NodePos typ.n)
- if typ.sym != nilItemId:
- checkForeignSym(c, typ.sym)
- if typ.owner != nilItemId:
- checkForeignSym(c, typ.owner)
- checkType(c, typ.typeInst)
- proc checkType(c: var CheckedContext; typeId: PackedItemId) =
- if typeId == nilItemId: return
- let itemId = translateId(typeId, c.g.packed, c.thisModule, c.g.config)
- if not c.checkedTypes.containsOrIncl(itemId):
- let oldThisModule = c.thisModule
- c.thisModule = itemId.module
- checkTypeObj c, c.g.packed[itemId.module].fromDisk.types[itemId.item]
- c.thisModule = oldThisModule
- proc checkSym(c: var CheckedContext; s: PackedSym) =
- if s.name != LitId(0):
- assert c.g.packed[c.thisModule].fromDisk.strings.hasLitId s.name
- checkType c, s.typ
- if s.ast != emptyNodeId:
- checkNode(c, c.g.packed[c.thisModule].fromDisk.bodies, NodePos s.ast)
- if s.owner != nilItemId:
- checkForeignSym(c, s.owner)
- proc checkLocalSym(c: var CheckedContext; item: int32) =
- let itemId = ItemId(module: c.thisModule, item: item)
- if not c.checkedSyms.containsOrIncl(itemId):
- checkSym c, c.g.packed[c.thisModule].fromDisk.syms[item]
- proc checkForeignSym(c: var CheckedContext; symId: PackedItemId) =
- let itemId = translateId(symId, c.g.packed, c.thisModule, c.g.config)
- if not c.checkedSyms.containsOrIncl(itemId):
- let oldThisModule = c.thisModule
- c.thisModule = itemId.module
- checkSym c, c.g.packed[itemId.module].fromDisk.syms[itemId.item]
- c.thisModule = oldThisModule
- proc checkNode(c: var CheckedContext; tree: PackedTree; n: NodePos) =
- if tree[n.int].typeId != nilItemId:
- checkType(c, tree[n.int].typeId)
- case n.kind
- of nkEmpty, nkNilLit, nkType, nkNilRodNode:
- discard
- of nkIdent:
- assert c.g.packed[c.thisModule].fromDisk.strings.hasLitId n.litId
- of nkSym:
- checkLocalSym(c, tree.nodes[n.int].operand)
- of directIntLit:
- discard
- of externIntLit, nkFloatLit..nkFloat128Lit:
- assert c.g.packed[c.thisModule].fromDisk.numbers.hasLitId n.litId
- of nkStrLit..nkTripleStrLit:
- assert c.g.packed[c.thisModule].fromDisk.strings.hasLitId n.litId
- of nkModuleRef:
- let (n1, n2) = sons2(tree, n)
- assert n1.kind == nkInt32Lit
- assert n2.kind == nkInt32Lit
- checkForeignSym(c, PackedItemId(module: n1.litId, item: tree.nodes[n2.int].operand))
- else:
- for n0 in sonsReadonly(tree, n):
- checkNode(c, tree, n0)
- proc checkTree(c: var CheckedContext; t: PackedTree) =
- for p in allNodes(t): checkNode(c, t, p)
- proc checkLocalSymIds(c: var CheckedContext; m: PackedModule; symIds: seq[int32]) =
- for symId in symIds:
- assert symId >= 0 and symId < m.syms.len, $symId & " " & $m.syms.len
- proc checkModule(c: var CheckedContext; m: PackedModule) =
- # We check that:
- # - Every symbol references existing types and symbols.
- # - Every tree node references existing types and symbols.
- for i in 0..high(m.syms):
- checkLocalSym c, int32(i)
- checkTree c, m.toReplay
- checkTree c, m.topLevel
- for e in m.exports:
- assert e[1] >= 0 and e[1] < m.syms.len
- assert e[0] == m.syms[e[1]].name
- for e in m.compilerProcs:
- assert e[1] >= 0 and e[1] < m.syms.len
- assert e[0] == m.syms[e[1]].name
- checkLocalSymIds c, m, m.converters
- checkLocalSymIds c, m, m.methods
- checkLocalSymIds c, m, m.trmacros
- checkLocalSymIds c, m, m.pureEnums
- #[
- To do: Check all these fields:
- reexports*: seq[(LitId, PackedItemId)]
- macroUsages*: seq[(PackedItemId, PackedLineInfo)]
- typeInstCache*: seq[(PackedItemId, PackedItemId)]
- procInstCache*: seq[PackedInstantiation]
- attachedOps*: seq[(TTypeAttachedOp, PackedItemId, PackedItemId)]
- methodsPerType*: seq[(PackedItemId, int, PackedItemId)]
- enumToStringProcs*: seq[(PackedItemId, PackedItemId)]
- ]#
- proc checkIntegrity*(g: ModuleGraph) =
- var c = CheckedContext(g: g)
- for i in 0..high(g.packed):
- # case statement here to enforce exhaustive checks.
- case g.packed[i].status
- of undefined:
- discard "nothing to do"
- of loading:
- assert false, "cannot check integrity: Module still loading"
- of stored, storing, outdated, loaded:
- c.thisModule = int32 i
- checkModule(c, g.packed[i].fromDisk)
|