typeallowed.nim 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2020 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## This module contains 'typeAllowed' and friends which check
  10. ## for invalid types like 'openArray[var int]'.
  11. import
  12. intsets, ast, renderer, options, semdata, types
  13. type
  14. TTypeAllowedFlag* = enum
  15. taField,
  16. taHeap,
  17. taConcept,
  18. taIsOpenArray,
  19. taNoUntyped
  20. taIsTemplateOrMacro
  21. taProcContextIsNotMacro
  22. TTypeAllowedFlags* = set[TTypeAllowedFlag]
  23. proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind;
  24. c: PContext; flags: TTypeAllowedFlags = {}): PType
  25. proc typeAllowedNode(marker: var IntSet, n: PNode, kind: TSymKind,
  26. c: PContext; flags: TTypeAllowedFlags = {}): PType =
  27. if n != nil:
  28. result = typeAllowedAux(marker, n.typ, kind, c, flags)
  29. if result == nil:
  30. case n.kind
  31. of nkNone..nkNilLit:
  32. discard
  33. else:
  34. #if n.kind == nkRecCase and kind in {skProc, skFunc, skConst}:
  35. # return n[0].typ
  36. for i in 0..<n.len:
  37. let it = n[i]
  38. result = typeAllowedNode(marker, it, kind, c, flags)
  39. if result != nil: break
  40. proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
  41. c: PContext; flags: TTypeAllowedFlags = {}): PType =
  42. assert(kind in {skVar, skLet, skConst, skProc, skFunc, skParam, skResult})
  43. # if we have already checked the type, return true, because we stop the
  44. # evaluation if something is wrong:
  45. result = nil
  46. if typ == nil: return nil
  47. if containsOrIncl(marker, typ.id): return nil
  48. var t = skipTypes(typ, abstractInst-{tyTypeDesc, tySink})
  49. case t.kind
  50. of tyVar, tyLent:
  51. if kind in {skProc, skFunc, skConst} and (views notin c.features):
  52. result = t
  53. elif t.kind == tyLent and kind != skResult and (views notin c.features):
  54. result = t
  55. else:
  56. var t2 = skipTypes(t[0], abstractInst-{tyTypeDesc, tySink})
  57. case t2.kind
  58. of tyVar, tyLent:
  59. if taHeap notin flags: result = t2 # ``var var`` is illegal on the heap
  60. of tyOpenArray:
  61. if (kind != skParam and views notin c.features) or taIsOpenArray in flags: result = t
  62. else: result = typeAllowedAux(marker, t2[0], kind, c, flags+{taIsOpenArray})
  63. of tyUncheckedArray:
  64. if kind != skParam and views notin c.features: result = t
  65. else: result = typeAllowedAux(marker, t2[0], kind, c, flags)
  66. of tySink:
  67. result = t
  68. else:
  69. if kind notin {skParam, skResult} and views notin c.features: result = t
  70. else: result = typeAllowedAux(marker, t2, kind, c, flags)
  71. of tyProc:
  72. if kind in {skVar, skLet, skConst} and taIsTemplateOrMacro in flags:
  73. result = t
  74. else:
  75. if isInlineIterator(typ) and kind in {skVar, skLet, skConst, skParam, skResult}:
  76. # only closure iterators may be assigned to anything.
  77. result = t
  78. let f = if kind in {skProc, skFunc}: flags+{taNoUntyped} else: flags
  79. for i in 1..<t.len:
  80. if result != nil: break
  81. result = typeAllowedAux(marker, t[i], skParam, c, f-{taIsOpenArray})
  82. if result.isNil and t[0] != nil:
  83. result = typeAllowedAux(marker, t[0], skResult, c, flags)
  84. of tyTypeDesc:
  85. if kind in {skVar, skLet, skConst} and taProcContextIsNotMacro in flags:
  86. result = t
  87. else:
  88. # XXX: This is still a horrible idea...
  89. result = nil
  90. of tyUntyped, tyTyped:
  91. if kind notin {skParam, skResult} or taNoUntyped in flags: result = t
  92. of tyStatic:
  93. if kind notin {skParam}: result = t
  94. of tyVoid:
  95. if taField notin flags: result = t
  96. of tyTypeClasses:
  97. if tfGenericTypeParam in t.flags or taConcept in flags: #or taField notin flags:
  98. discard
  99. elif t.isResolvedUserTypeClass:
  100. result = typeAllowedAux(marker, t.lastSon, kind, c, flags)
  101. elif kind notin {skParam, skResult}:
  102. result = t
  103. of tyGenericBody, tyGenericParam, tyGenericInvocation,
  104. tyNone, tyForward, tyFromExpr:
  105. result = t
  106. of tyNil:
  107. if kind != skConst and kind != skParam: result = t
  108. of tyString, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString, tyPointer:
  109. result = nil
  110. of tyOrdinal:
  111. if kind != skParam: result = t
  112. of tyGenericInst, tyDistinct, tyAlias, tyInferred:
  113. result = typeAllowedAux(marker, lastSon(t), kind, c, flags)
  114. of tyRange:
  115. if skipTypes(t[0], abstractInst-{tyTypeDesc}).kind notin
  116. {tyChar, tyEnum, tyInt..tyFloat128, tyInt..tyUInt64}: result = t
  117. of tyOpenArray:
  118. # you cannot nest openArrays/sinks/etc.
  119. if (kind != skParam or taIsOpenArray in flags) and views notin c.features:
  120. result = t
  121. else:
  122. result = typeAllowedAux(marker, t[0], kind, c, flags+{taIsOpenArray})
  123. of tyVarargs:
  124. # you cannot nest openArrays/sinks/etc.
  125. if kind != skParam or taIsOpenArray in flags:
  126. result = t
  127. else:
  128. result = typeAllowedAux(marker, t[0], kind, c, flags+{taIsOpenArray})
  129. of tySink:
  130. # you cannot nest openArrays/sinks/etc.
  131. if kind != skParam or taIsOpenArray in flags or t[0].kind in {tySink, tyLent, tyVar}:
  132. result = t
  133. else:
  134. result = typeAllowedAux(marker, t[0], kind, c, flags)
  135. of tyUncheckedArray:
  136. if kind != skParam and taHeap notin flags:
  137. result = t
  138. else:
  139. result = typeAllowedAux(marker, lastSon(t), kind, c, flags-{taHeap})
  140. of tySequence:
  141. if t[0].kind != tyEmpty:
  142. result = typeAllowedAux(marker, t[0], kind, c, flags+{taHeap})
  143. elif kind in {skVar, skLet}:
  144. result = t[0]
  145. of tyArray:
  146. if t[1].kind == tyTypeDesc:
  147. result = t[1]
  148. elif t[1].kind != tyEmpty:
  149. result = typeAllowedAux(marker, t[1], kind, c, flags)
  150. elif kind in {skVar, skLet}:
  151. result = t[1]
  152. of tyRef:
  153. if kind == skConst: result = t
  154. else: result = typeAllowedAux(marker, t.lastSon, kind, c, flags+{taHeap})
  155. of tyPtr:
  156. result = typeAllowedAux(marker, t.lastSon, kind, c, flags+{taHeap})
  157. of tySet:
  158. for i in 0..<t.len:
  159. result = typeAllowedAux(marker, t[i], kind, c, flags)
  160. if result != nil: break
  161. of tyObject, tyTuple:
  162. if kind in {skProc, skFunc, skConst} and
  163. t.kind == tyObject and t[0] != nil:
  164. result = t
  165. else:
  166. let flags = flags+{taField}
  167. for i in 0..<t.len:
  168. result = typeAllowedAux(marker, t[i], kind, c, flags)
  169. if result != nil: break
  170. if result.isNil and t.n != nil:
  171. result = typeAllowedNode(marker, t.n, kind, c, flags)
  172. of tyEmpty:
  173. if kind in {skVar, skLet}: result = t
  174. of tyProxy:
  175. # for now same as error node; we say it's a valid type as it should
  176. # prevent cascading errors:
  177. result = nil
  178. of tyOwned:
  179. if t.len == 1 and t[0].skipTypes(abstractInst).kind in {tyRef, tyPtr, tyProc}:
  180. result = typeAllowedAux(marker, t.lastSon, kind, c, flags+{taHeap})
  181. else:
  182. result = t
  183. of tyOptDeprecated: doAssert false
  184. proc typeAllowed*(t: PType, kind: TSymKind; c: PContext; flags: TTypeAllowedFlags = {}): PType =
  185. # returns 'nil' on success and otherwise the part of the type that is
  186. # wrong!
  187. var marker = initIntSet()
  188. result = typeAllowedAux(marker, t, kind, c, flags)
  189. type
  190. ViewTypeKind* = enum
  191. noView, immutableView, mutableView
  192. proc combine(dest: var ViewTypeKind, b: ViewTypeKind) {.inline.} =
  193. case dest
  194. of noView, mutableView:
  195. dest = b
  196. of immutableView:
  197. if b == mutableView: dest = b
  198. proc classifyViewTypeAux(marker: var IntSet, t: PType): ViewTypeKind
  199. proc classifyViewTypeNode(marker: var IntSet, n: PNode): ViewTypeKind =
  200. case n.kind
  201. of nkSym:
  202. result = classifyViewTypeAux(marker, n.typ)
  203. of nkOfBranch:
  204. result = classifyViewTypeNode(marker, n.lastSon)
  205. else:
  206. result = noView
  207. for child in n:
  208. result.combine classifyViewTypeNode(marker, child)
  209. if result == mutableView: break
  210. proc classifyViewTypeAux(marker: var IntSet, t: PType): ViewTypeKind =
  211. if containsOrIncl(marker, t.id): return noView
  212. case t.kind
  213. of tyVar:
  214. result = mutableView
  215. of tyLent, tyOpenArray:
  216. result = immutableView
  217. of tyGenericInst, tyDistinct, tyAlias, tyInferred, tySink, tyOwned,
  218. tyUncheckedArray, tySequence, tyArray, tyRef, tyStatic:
  219. result = classifyViewTypeAux(marker, lastSon(t))
  220. of tyFromExpr:
  221. if t.len > 0:
  222. result = classifyViewTypeAux(marker, lastSon(t))
  223. else:
  224. result = noView
  225. of tyTuple:
  226. result = noView
  227. for i in 0..<t.len:
  228. result.combine classifyViewTypeAux(marker, t[i])
  229. if result == mutableView: break
  230. of tyObject:
  231. result = noView
  232. if t.n != nil:
  233. result = classifyViewTypeNode(marker, t.n)
  234. if t[0] != nil:
  235. result.combine classifyViewTypeAux(marker, t[0])
  236. else:
  237. # it doesn't matter what these types contain, 'ptr openArray' is not a
  238. # view type!
  239. result = noView
  240. proc classifyViewType*(t: PType): ViewTypeKind =
  241. var marker = initIntSet()
  242. result = classifyViewTypeAux(marker, t)
  243. proc directViewType*(t: PType): ViewTypeKind =
  244. # does classify 't' without looking recursively into 't'.
  245. case t.kind
  246. of tyVar:
  247. result = mutableView
  248. of tyLent, tyOpenArray:
  249. result = immutableView
  250. of abstractInst-{tyTypeDesc}:
  251. result = directViewType(t.lastSon)
  252. else:
  253. result = noView
  254. proc requiresInit*(t: PType): bool =
  255. (t.flags * {tfRequiresInit, tfNeedsFullInit, tfNotNil} != {}) or
  256. classifyViewType(t) != noView