semmacrosanity.nim 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2015 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## Implements type sanity checking for ASTs resulting from macros. Lots of
  10. ## room for improvement here.
  11. import ast, msgs, types, options, trees, nimsets
  12. type
  13. FieldTracker = object
  14. index: int
  15. remaining: int
  16. constr: PNode
  17. delete: bool # to delete fields from inactive case branches
  18. FieldInfo = ref object
  19. sym: PSym
  20. delete: bool
  21. proc caseBranchMatchesExpr(branch, matched: PNode): bool =
  22. # copied from sem
  23. result = false
  24. for i in 0 ..< branch.len-1:
  25. if branch[i].kind == nkRange:
  26. if overlap(branch[i], matched): return true
  27. elif exprStructuralEquivalent(branch[i], matched):
  28. return true
  29. proc ithField(n: PNode, field: var FieldTracker): FieldInfo =
  30. result = nil
  31. case n.kind
  32. of nkRecList:
  33. for i in 0..<n.len:
  34. result = ithField(n[i], field)
  35. if result != nil: return
  36. of nkRecCase:
  37. if n[0].kind != nkSym: return
  38. result = ithField(n[0], field)
  39. if result != nil: return
  40. # value of the discriminator field, from (index - remaining - 1 + 1):
  41. # - 1 because the `ithField` call above decreased it by 1,
  42. # + 1 because the constructor node has an initial type child
  43. let val = field.constr[field.index - field.remaining][1]
  44. var branchFound = false
  45. for i in 1..<n.len:
  46. let previousDelete = field.delete
  47. case n[i].kind
  48. of nkOfBranch:
  49. if branchFound or previousDelete or
  50. not caseBranchMatchesExpr(n[i], val):
  51. # if this is not the active case branch,
  52. # mark all fields inside as deleted
  53. field.delete = true
  54. else:
  55. branchFound = true
  56. result = ithField(lastSon(n[i]), field)
  57. if result != nil: return
  58. field.delete = previousDelete
  59. of nkElse:
  60. if branchFound:
  61. # if this is not the active case branch,
  62. # mark all fields inside as deleted
  63. field.delete = true
  64. result = ithField(lastSon(n[i]), field)
  65. if result != nil: return
  66. field.delete = previousDelete
  67. else: discard
  68. of nkSym:
  69. if field.remaining == 0:
  70. result = FieldInfo(sym: n.sym, delete: field.delete)
  71. else:
  72. dec(field.remaining)
  73. else: discard
  74. proc ithField(t: PType, field: var FieldTracker): FieldInfo =
  75. var base = t.baseClass
  76. while base != nil:
  77. let b = skipTypes(base, skipPtrs)
  78. result = ithField(b.n, field)
  79. if result != nil: return result
  80. base = b.baseClass
  81. result = ithField(t.n, field)
  82. proc annotateType*(n: PNode, t: PType; conf: ConfigRef) =
  83. let x = t.skipTypes(abstractInst+{tyRange})
  84. # Note: x can be unequal to t and we need to be careful to use 't'
  85. # to not to skip tyGenericInst
  86. case n.kind
  87. of nkObjConstr:
  88. let x = t.skipTypes(abstractPtrs)
  89. n.typ() = t
  90. n[0].typ() = t
  91. for i in 1..<n.len:
  92. var tracker = FieldTracker(index: i-1, remaining: i-1, constr: n, delete: false)
  93. let field = x.ithField(tracker)
  94. if field.isNil:
  95. globalError conf, n.info, "invalid field at index " & $i
  96. else:
  97. internalAssert(conf, n[i].kind == nkExprColonExpr)
  98. annotateType(n[i][1], field.sym.typ, conf)
  99. if field.delete:
  100. # only codegen fields from active case branches
  101. incl(n[i].flags, nfPreventCg)
  102. of nkPar, nkTupleConstr:
  103. if x.kind == tyTuple:
  104. n.typ() = t
  105. for i in 0..<n.len:
  106. if i >= x.kidsLen: globalError conf, n.info, "invalid field at index " & $i
  107. else: annotateType(n[i], x[i], conf)
  108. elif x.kind == tyProc and x.callConv == ccClosure:
  109. n.typ() = t
  110. elif x.kind == tyOpenArray: # `opcSlice` transforms slices into tuples
  111. if n.kind == nkTupleConstr:
  112. let
  113. bracketExpr = newNodeI(nkBracket, n.info)
  114. left = int n[1].intVal
  115. right = int n[2].intVal
  116. bracketExpr.flags = n.flags
  117. case n[0].kind # is this a string slice or a array slice
  118. of nkStrKinds:
  119. for i in left..right:
  120. bracketExpr.add newIntNode(nkCharLit, BiggestInt n[0].strVal[i])
  121. annotateType(bracketExpr[^1], x.elementType, conf)
  122. of nkBracket:
  123. for i in left..right:
  124. bracketExpr.add n[0][i]
  125. annotateType(bracketExpr[^1], x.elementType, conf)
  126. else:
  127. globalError(conf, n.info, "Incorrectly generated tuple constr")
  128. n[] = bracketExpr[]
  129. n.typ() = t
  130. else:
  131. globalError(conf, n.info, "() must have a tuple type")
  132. of nkBracket:
  133. if x.kind in {tyArray, tySequence, tyOpenArray}:
  134. n.typ() = t
  135. for m in n: annotateType(m, x.elemType, conf)
  136. else:
  137. globalError(conf, n.info, "[] must have some form of array type")
  138. of nkCurly:
  139. if x.kind in {tySet}:
  140. n.typ() = t
  141. for m in n: annotateType(m, x.elemType, conf)
  142. else:
  143. globalError(conf, n.info, "{} must have the set type")
  144. of nkFloatLit..nkFloat128Lit:
  145. if x.kind in {tyFloat..tyFloat128}:
  146. n.typ() = t
  147. else:
  148. globalError(conf, n.info, "float literal must have some float type")
  149. of nkCharLit..nkUInt64Lit:
  150. if x.kind in {tyInt..tyUInt64, tyBool, tyChar, tyEnum}:
  151. n.typ() = t
  152. else:
  153. globalError(conf, n.info, "integer literal must have some int type")
  154. of nkStrLit..nkTripleStrLit:
  155. if x.kind in {tyString, tyCstring}:
  156. n.typ() = t
  157. else:
  158. globalError(conf, n.info, "string literal must be of some string type")
  159. of nkNilLit:
  160. if x.kind in NilableTypes+{tyString, tySequence}:
  161. n.typ() = t
  162. else:
  163. globalError(conf, n.info, "nil literal must be of some pointer type")
  164. else: discard