typeallowed.nim 10 KB

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