tcovariancerules.nim 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. discard """
  2. cmd: "nim cpp $file"
  3. output: '''
  4. cat
  5. cat
  6. dog
  7. dog
  8. cat
  9. cat
  10. dog
  11. dog X
  12. cat
  13. cat
  14. dog
  15. dog
  16. dog value
  17. cat value
  18. dog value
  19. cat value
  20. dog
  21. dog
  22. dog value
  23. cat value
  24. dog 1
  25. dog 2
  26. '''
  27. """
  28. template accept(x) =
  29. static: assert(compiles(x))
  30. template reject(x) =
  31. static: assert(not compiles(x))
  32. import macros
  33. macro skipElse(n: untyped): typed = n[0]
  34. template acceptWithCovariance(x, otherwise): typed =
  35. when nimEnableCovariance:
  36. x
  37. else:
  38. reject(x)
  39. skipElse(otherwise)
  40. type
  41. Animal = object of RootObj
  42. x: string
  43. Dog = object of Animal
  44. y: int
  45. Cat = object of Animal
  46. z: int
  47. AnimalRef = ref Animal
  48. AnimalPtr = ptr Animal
  49. RefAlias[T] = ref T
  50. var dog = new(Dog)
  51. dog.x = "dog"
  52. var cat = new(Cat)
  53. cat.x = "cat"
  54. proc makeDerivedRef(x: string): ref Dog =
  55. new(result)
  56. result.x = x
  57. proc makeDerived(x: string): Dog =
  58. result.x = x
  59. var covariantSeq = @[makeDerivedRef("dog 1"), makeDerivedRef("dog 2")]
  60. var nonCovariantSeq = @[makeDerived("dog 1"), makeDerived("dog 2")]
  61. var covariantArr = [makeDerivedRef("dog 1"), makeDerivedRef("dog 2")]
  62. var nonCovariantArr = [makeDerived("dog 1"), makeDerived("dog 2")]
  63. proc wantsCovariantSeq1(s: seq[ref Animal]) =
  64. for a in s: echo a.x
  65. proc wantsCovariantSeq2(s: seq[AnimalRef]) =
  66. for a in s: echo a.x
  67. proc wantsCovariantSeq3(s: seq[RefAlias[Animal]]) =
  68. for a in s: echo a.x
  69. proc wantsCovariantOperArray(s: openarray[ref Animal]) =
  70. for a in s: echo a.x
  71. proc modifiesCovariantOperArray(s: var openarray[ref Animal]) =
  72. for a in s: echo a.x
  73. proc modifiesDerivedOperArray(s: var openarray[ref Dog]) =
  74. for a in s: echo a.x
  75. proc wantsNonCovariantOperArray(s: openarray[Animal]) =
  76. for a in s: echo a.x
  77. proc wantsCovariantArray(s: array[2, ref Animal]) =
  78. for a in s: echo a.x
  79. proc wantsNonCovariantSeq(s: seq[Animal]) =
  80. for a in s: echo a.x
  81. proc wantsNonCovariantArray(s: array[2, Animal]) =
  82. for a in s: echo a.x
  83. proc modifiesCovariantSeq(s: var seq[ref Animal]) =
  84. for a in s: echo a.x
  85. proc modifiesCovariantArray(s: var array[2, ref Animal]) =
  86. for a in s: echo a.x
  87. proc modifiesCovariantSeq(s: ptr seq[ref Animal]) =
  88. for a in s[]: echo a.x
  89. proc modifiesCovariantArray(s: ptr array[2, ref Animal]) =
  90. for a in s[]: echo a.x
  91. proc modifiesDerivedSeq(s: var seq[ref Dog]) =
  92. for a in s: echo a.x
  93. proc modifiesDerivedArray(s: var array[2, ref Dog]) =
  94. for a in s: echo a.x
  95. proc modifiesDerivedSeq(s: ptr seq[ref Dog]) =
  96. for a in s[]: echo a.x
  97. proc modifiesDerivedArray(s: ptr array[2, ref Dog]) =
  98. for a in s[]: echo a.x
  99. accept:
  100. wantsCovariantArray([AnimalRef(dog), AnimalRef(dog)])
  101. wantsCovariantArray([AnimalRef(cat), AnimalRef(dog)])
  102. wantsCovariantArray([AnimalRef(cat), dog])
  103. # there is a special rule that detects the base
  104. # type of polymorphic arrays
  105. wantsCovariantArray([cat, dog])
  106. acceptWithCovariance:
  107. wantsCovariantArray([cat, cat])
  108. else:
  109. echo "cat"
  110. echo "cat"
  111. var animalRefArray: array[2, ref Animal]
  112. accept:
  113. animalRefArray = [AnimalRef(dog), AnimalRef(dog)]
  114. animalRefArray = [AnimalRef(cat), dog]
  115. acceptWithCovariance:
  116. animalRefArray = [dog, dog]
  117. wantsCovariantArray animalRefArray
  118. else:
  119. echo "dog"
  120. echo "dog"
  121. accept:
  122. var animal: AnimalRef = dog
  123. animal = cat
  124. var vdog: Dog
  125. vdog.x = "dog value"
  126. var vcat: Cat
  127. vcat.x = "cat value"
  128. reject:
  129. vcat = vdog
  130. # XXX: The next two cases seem incosistent, perhaps we should change the rules
  131. accept:
  132. # truncating copies are allowed
  133. var vanimal: Animal = vdog
  134. vanimal = vdog
  135. reject:
  136. # truncating copies are not allowed with arrays
  137. var vanimalArray: array[2, Animal]
  138. var vdogArray = [vdog, vdog]
  139. vanimalArray = vdogArray
  140. accept:
  141. # a more explicit version of a truncating copy that
  142. # should probably always remain allowed
  143. var vnextnimal: Animal = Animal(vdog)
  144. proc wantsRefSeq(x: seq[AnimalRef]) = discard
  145. accept:
  146. wantsCovariantSeq1(@[AnimalRef(dog), AnimalRef(dog)])
  147. wantsCovariantSeq1(@[AnimalRef(cat), AnimalRef(dog)])
  148. wantsCovariantSeq1(@[AnimalRef(cat), dog])
  149. wantsCovariantSeq1(@[cat, dog])
  150. wantsCovariantSeq2(@[AnimalRef(dog), AnimalRef(dog)])
  151. wantsCovariantSeq2(@[AnimalRef(cat), AnimalRef(dog)])
  152. wantsCovariantSeq2(@[AnimalRef(cat), dog])
  153. wantsCovariantSeq2(@[cat, dog])
  154. wantsCovariantSeq3(@[AnimalRef(dog), AnimalRef(dog)])
  155. wantsCovariantSeq3(@[AnimalRef(cat), AnimalRef(dog)])
  156. wantsCovariantSeq3(@[AnimalRef(cat), dog])
  157. wantsCovariantSeq3(@[cat, dog])
  158. wantsCovariantOperArray([cat, dog])
  159. acceptWithCovariance:
  160. wantsCovariantSeq1(@[cat, cat])
  161. wantsCovariantSeq2(@[dog, makeDerivedRef("dog X")])
  162. # XXX: wantsCovariantSeq3(@[cat, cat])
  163. wantsCovariantOperArray(@[cat, cat])
  164. wantsCovariantOperArray([dog, dog])
  165. else:
  166. echo "cat"
  167. echo "cat"
  168. echo "dog"
  169. echo "dog X"
  170. echo "cat"
  171. echo "cat"
  172. echo "dog"
  173. echo "dog"
  174. var dogRefs = @[dog, dog]
  175. var dogRefsArray = [dog, dog]
  176. var animalRefs = @[dog, cat]
  177. accept:
  178. modifiesDerivedArray(dogRefsArray)
  179. modifiesDerivedSeq(dogRefs)
  180. reject modifiesCovariantSeq(dogRefs)
  181. reject modifiesCovariantSeq(addr(dogRefs))
  182. reject modifiesCovariantSeq(dogRefs.addr)
  183. reject modifiesCovariantArray([dog, dog])
  184. reject modifiesCovariantArray(dogRefsArray)
  185. reject modifiesCovariantArray(addr(dogRefsArray))
  186. reject modifiesCovariantArray(dogRefsArray.addr)
  187. var dogValues = @[vdog, vdog]
  188. var dogValuesArray = [vdog, vdog]
  189. var animalValues = @[Animal(vdog), Animal(vcat)]
  190. var animalValuesArray = [Animal(vdog), Animal(vcat)]
  191. wantsNonCovariantSeq animalValues
  192. wantsNonCovariantArray animalValuesArray
  193. reject wantsNonCovariantSeq(dogRefs)
  194. reject modifiesCovariantOperArray(dogRefs)
  195. reject wantsNonCovariantArray(dogRefsArray)
  196. reject wantsNonCovariantSeq(dogValues)
  197. reject wantsNonCovariantArray(dogValuesArray)
  198. reject modifiesValueArray()
  199. modifiesDerivedOperArray dogRefs
  200. reject modifiesDerivedOperArray(dogValues)
  201. reject modifiesDerivedOperArray(animalRefs)
  202. wantsNonCovariantOperArray animalValues
  203. reject wantsNonCovariantOperArray(animalRefs)
  204. reject wantsNonCovariantOperArray(dogRefs)
  205. reject wantsNonCovariantOperArray(dogValues)
  206. var animalRefSeq: seq[ref Animal]
  207. accept:
  208. animalRefSeq = @[AnimalRef(dog), AnimalRef(dog)]
  209. animalRefSeq = @[AnimalRef(cat), dog]
  210. acceptWithCovariance:
  211. animalRefSeq = @[makeDerivedRef("dog 1"), makeDerivedRef("dog 2")]
  212. wantsCovariantSeq1(animalRefSeq)
  213. else:
  214. echo "dog 1"
  215. echo "dog 2"
  216. var pdog: ptr Dog
  217. var pcat: ptr Cat
  218. proc wantsPointer(x: ptr Animal) =
  219. discard
  220. accept:
  221. wantsPointer pdog
  222. wantsPointer pcat
  223. # covariance should be disabled when var is involved
  224. proc wantsVarPointer1(x: var ptr Animal) =
  225. discard
  226. proc wantsVarPointer2(x: var AnimalPtr) =
  227. discard
  228. reject wantsVarPointer1(pdog)
  229. reject wantsVarPointer2(pcat)
  230. # covariance may be allowed for certain extern types
  231. {.emit: """
  232. template <class T> struct FN { typedef void (*type)(T); };
  233. template <class T> struct ARR { typedef T DataType[2]; DataType data; };
  234. """.}
  235. type
  236. MyPtr {.importcpp: "'0 *"} [out T] = object
  237. MySeq {.importcpp: "ARR<'0>", nodecl} [out T] = object
  238. data: array[2, T]
  239. MyAction {.importcpp: "FN<'0>::type"} [in T] = object
  240. var
  241. cAnimal: MyPtr[Animal]
  242. cDog: MyPtr[Dog]
  243. cCat: MyPtr[Cat]
  244. cAnimalFn: MyAction[Animal]
  245. cCatFn: MyAction[Cat]
  246. cDogFn: MyAction[Dog]
  247. cRefAnimalFn: MyAction[ref Animal]
  248. cRefCatFn: MyAction[ref Cat]
  249. cRefDogFn: MyAction[ref Dog]
  250. accept:
  251. cAnimal = cDog
  252. cAnimal = cCat
  253. cDogFn = cAnimalFn
  254. cCatFn = cAnimalFn
  255. cRefDogFn = cRefAnimalFn
  256. cRefCatFn = cRefAnimalFn
  257. reject: cDogFn = cRefAnimalFn
  258. reject: cCatFn = cRefAnimalFn
  259. reject: cCat = cDog
  260. reject: cAnimalFn = cDogFn
  261. reject: cAnimalFn = cCatFn
  262. reject: cRefAnimalFn = cRefDogFn
  263. reject: cRefAnimalFn = cRefCatFn
  264. reject: cRefAnimalFn = cDogFn
  265. var
  266. ptrPtrDog: ptr ptr Dog
  267. ptrPtrAnimal: ptr ptr Animal
  268. reject: ptrPtrDog = ptrPtrAnimal
  269. # Try to break the rules by introducing some tricky
  270. # double indirection types:
  271. var
  272. cPtrRefAnimal: MyPtr[ref Animal]
  273. cPtrRefDog: MyPtr[ref Dog]
  274. cPtrAliasRefAnimal: MyPtr[RefAlias[Animal]]
  275. cPtrAliasRefDog: MyPtr[RefAlias[Dog]]
  276. cDoublePtrAnimal: MyPtr[MyPtr[Animal]]
  277. cDoublePtrDog: MyPtr[MyPtr[Dog]]
  278. reject: cPtrRefAnimal = cPtrRefDog
  279. reject: cDoublePtrAnimal = cDoublePtrDog
  280. reject: cRefAliasPtrAnimal = cRefAliasPtrDog
  281. reject: cPtrRefAnimal = cRefAliasPtrDog
  282. reject: cPtrAliasRefAnimal = cPtrRefDog
  283. var
  284. # Array and Sequence types are covariant only
  285. # when instantiated with ref or ptr types:
  286. cAnimals: MySeq[ref Animal]
  287. cDogs: MySeq[ref Dog]
  288. # "User-defined" pointer types should be OK too:
  289. cAnimalPtrSeq: MySeq[MyPtr[Animal]]
  290. cDogPtrSeq: MySeq[MyPtr[Dog]]
  291. # Value types shouldn't work:
  292. cAnimalValues: MySeq[Animal]
  293. cDogValues: MySeq[Dog]
  294. # Double pointer types should not work either:
  295. cAnimalRefPtrSeq: MySeq[ref MyPtr[Animal]]
  296. cDogRefPtrSeq: MySeq[ref MyPtr[Dog]]
  297. cAnimalPtrPtrSeq: MySeq[ptr ptr Animal]
  298. cDogPtrPtrSeq: MySeq[ptr ptr Dog]
  299. accept:
  300. cAnimals = cDogs
  301. cAnimalPtrSeq = cDogPtrSeq
  302. reject: cAnimalValues = cDogValues
  303. reject: cAnimalRefPtrSeq = cDogRefPtrSeq
  304. reject: cAnimalPtrPtrSeq = cDogPtrPtrSeq
  305. proc wantsAnimalSeq(x: MySeq[Animal]) = discard
  306. proc wantsAnimalRefSeq(x: MySeq[ref Animal]) = discard
  307. proc modifiesAnimalRefSeq(x: var MySeq[ref Animal]) = discard
  308. proc usesAddressOfAnimalRefSeq(x: ptr MySeq[ref Animal]) = discard
  309. accept wantsAnimalSeq(cAnimalValues)
  310. reject wantsAnimalSeq(cDogValues)
  311. reject wantsAnimalSeq(cAnimals)
  312. reject wantsAnimalRefSeq(cAnimalValues)
  313. reject wantsAnimalRefSeq(cDogValues)
  314. accept wantsAnimalRefSeq(cAnimals)
  315. accept wantsAnimalRefSeq(cDogs)
  316. reject modifiesAnimalRefSeq(cAnimalValues)
  317. reject modifiesAnimalRefSeq(cDogValues)
  318. accept modifiesAnimalRefSeq(cAnimals)
  319. reject modifiesAnimalRefSeq(cDogs)
  320. reject usesAddressOfAnimalRefSeq(addr cAnimalValues)
  321. reject usesAddressOfAnimalRefSeq(addr cDogValues)
  322. accept usesAddressOfAnimalRefSeq(addr cAnimals)
  323. reject usesAddressOfAnimalRefSeq(addr cDogs)