tcovariancerules.nim 9.6 KB

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