typeallowed.nim 9.8 KB

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