summary refs log tree commit diff stats
path: root/tests/cpp
diff options
context:
space:
mode:
authorZahary Karadjov <zahary@gmail.com>2017-05-13 15:46:47 +0300
committerZahary Karadjov <zahary@gmail.com>2017-05-13 15:46:47 +0300
commitcdb011afdcef5c9f634403cc121f1ae1d4dccafb (patch)
tree5a74ba38de4baf414549b4914c3af0c24d28b925 /tests/cpp
parentb428da2cc2e7785ed9cb9a7efa1d2fa219603b59 (diff)
downloadNim-cdb011afdcef5c9f634403cc121f1ae1d4dccafb.tar.gz
attempt to fix a compilation problem caused by nimcache
Diffstat (limited to 'tests/cpp')
-rw-r--r--tests/cpp/tcovariancerules.nim424
1 files changed, 424 insertions, 0 deletions
diff --git a/tests/cpp/tcovariancerules.nim b/tests/cpp/tcovariancerules.nim
new file mode 100644
index 000000000..dfe4cb941
--- /dev/null
+++ b/tests/cpp/tcovariancerules.nim
@@ -0,0 +1,424 @@
+discard """
+cmd: "nim cpp $file"
+output: '''
+cat
+cat
+dog
+dog
+cat
+cat
+dog
+dog X
+cat
+cat
+dog
+dog
+dog value
+cat value
+dog value
+cat value
+dog
+dog
+dog value
+cat value
+dog 1
+dog 2
+'''
+"""
+
+template accept(x) =
+  static: assert(compiles(x))
+
+template reject(x) =
+  static: assert(not compiles(x))
+
+import macros
+
+macro skipElse(n: untyped): typed = n[0]
+
+template acceptWithCovariance(x, otherwise): typed =
+  when nimEnableCovariance:
+    x
+  else:
+    reject(x)
+    skipElse(otherwise)
+
+type
+  Animal = object of RootObj
+    x: string
+
+  Dog = object of Animal
+    y: int
+
+  Cat = object of Animal
+    z: int
+
+  AnimalRef = ref Animal
+  AnimalPtr = ptr Animal
+
+  RefAlias[T] = ref T
+
+var dog = new(Dog)
+dog.x = "dog"
+
+var cat = new(Cat)
+cat.x = "cat"
+
+proc makeDerivedRef(x: string): ref Dog =
+  new(result)
+  result.x = x
+
+proc makeDerived(x: string): Dog =
+  result.x = x
+
+var covariantSeq = @[makeDerivedRef("dog 1"), makeDerivedRef("dog 2")]
+var nonCovariantSeq = @[makeDerived("dog 1"), makeDerived("dog 2")]
+var covariantArr = [makeDerivedRef("dog 1"), makeDerivedRef("dog 2")]
+var nonCovariantArr = [makeDerived("dog 1"), makeDerived("dog 2")]
+
+proc wantsCovariantSeq1(s: seq[ref Animal]) =
+  for a in s: echo a.x
+
+proc wantsCovariantSeq2(s: seq[AnimalRef]) =
+  for a in s: echo a.x
+
+proc wantsCovariantSeq3(s: seq[RefAlias[Animal]]) =
+  for a in s: echo a.x
+
+proc wantsCovariantOperArray(s: openarray[ref Animal]) =
+  for a in s: echo a.x
+
+proc modifiesCovariantOperArray(s: var openarray[ref Animal]) =
+  for a in s: echo a.x
+
+proc modifiesDerivedOperArray(s: var openarray[ref Dog]) =
+  for a in s: echo a.x
+
+proc wantsNonCovariantOperArray(s: openarray[Animal]) =
+  for a in s: echo a.x
+
+proc wantsCovariantArray(s: array[2, ref Animal]) =
+  for a in s: echo a.x
+
+proc wantsNonCovariantSeq(s: seq[Animal]) =
+  for a in s: echo a.x
+
+proc wantsNonCovariantArray(s: array[2, Animal]) =
+  for a in s: echo a.x
+
+proc modifiesCovariantSeq(s: var seq[ref Animal]) =
+  for a in s: echo a.x
+
+proc modifiesCovariantArray(s: var array[2, ref Animal]) =
+  for a in s: echo a.x
+
+proc modifiesCovariantSeq(s: ptr seq[ref Animal]) =
+  for a in s[]: echo a.x
+
+proc modifiesCovariantArray(s: ptr array[2, ref Animal]) =
+  for a in s[]: echo a.x
+
+proc modifiesDerivedSeq(s: var seq[ref Dog]) =
+  for a in s: echo a.x
+
+proc modifiesDerivedArray(s: var array[2, ref Dog]) =
+  for a in s: echo a.x
+
+proc modifiesDerivedSeq(s: ptr seq[ref Dog]) =
+  for a in s[]: echo a.x
+
+proc modifiesDerivedArray(s: ptr array[2, ref Dog]) =
+  for a in s[]: echo a.x
+
+accept:
+  wantsCovariantArray([AnimalRef(dog), AnimalRef(dog)])
+  wantsCovariantArray([AnimalRef(cat), AnimalRef(dog)])
+  wantsCovariantArray([AnimalRef(cat), dog])
+
+  # there is a special rule that detects the base
+  # type of polymorphic arrays
+  wantsCovariantArray([cat, dog])
+
+acceptWithCovariance:
+  wantsCovariantArray([cat, cat])
+else:
+  echo "cat"
+  echo "cat"
+
+var animalRefArray: array[2, ref Animal]
+
+accept:
+  animalRefArray = [AnimalRef(dog), AnimalRef(dog)]
+  animalRefArray = [AnimalRef(cat), dog]
+
+acceptWithCovariance:
+  animalRefArray = [dog, dog]
+  wantsCovariantArray animalRefArray
+else:
+  echo "dog"
+  echo "dog"
+
+accept:
+  var animal: AnimalRef = dog
+  animal = cat
+
+var vdog: Dog
+vdog.x = "dog value"
+var vcat: Cat
+vcat.x = "cat value"
+
+reject:
+  vcat = vdog
+
+# XXX: The next two cases seem incosistent, perhaps we should change the rules
+accept:
+  # truncating copies are allowed
+  var vanimal: Animal = vdog
+  vanimal = vdog
+
+reject:
+  # truncating copies are not allowed with arrays
+  var vanimalArray: array[2, Animal]
+  var vdogArray = [vdog, vdog]
+  vanimalArray = vdogArray
+
+accept:
+  # a more explicit version of a truncating copy that
+  # should probably always remain allowed
+  var vnextnimal: Animal = Animal(vdog)
+
+proc wantsRefSeq(x: seq[AnimalRef]) = discard
+
+accept:
+  wantsCovariantSeq1(@[AnimalRef(dog), AnimalRef(dog)])
+  wantsCovariantSeq1(@[AnimalRef(cat), AnimalRef(dog)])
+  wantsCovariantSeq1(@[AnimalRef(cat), dog])
+  wantsCovariantSeq1(@[cat, dog])
+
+  wantsCovariantSeq2(@[AnimalRef(dog), AnimalRef(dog)])
+  wantsCovariantSeq2(@[AnimalRef(cat), AnimalRef(dog)])
+  wantsCovariantSeq2(@[AnimalRef(cat), dog])
+  wantsCovariantSeq2(@[cat, dog])
+
+  wantsCovariantSeq3(@[AnimalRef(dog), AnimalRef(dog)])
+  wantsCovariantSeq3(@[AnimalRef(cat), AnimalRef(dog)])
+  wantsCovariantSeq3(@[AnimalRef(cat), dog])
+  wantsCovariantSeq3(@[cat, dog])
+
+  wantsCovariantOperArray([cat, dog])
+
+acceptWithCovariance:
+  wantsCovariantSeq1(@[cat, cat])
+  wantsCovariantSeq2(@[dog, makeDerivedRef("dog X")])
+  # XXX: wantsCovariantSeq3(@[cat, cat])
+
+  wantsCovariantOperArray(@[cat, cat])
+  wantsCovariantOperArray([dog, dog])
+else:
+  echo "cat"
+  echo "cat"
+  echo "dog"
+  echo "dog X"
+  echo "cat"
+  echo "cat"
+  echo "dog"
+  echo "dog"
+
+var dogRefs = @[dog, dog]
+var dogRefsArray = [dog, dog]
+var animalRefs = @[dog, cat]
+
+accept:
+  modifiesDerivedArray(dogRefsArray)
+  modifiesDerivedSeq(dogRefs)
+
+reject modifiesCovariantSeq(dogRefs)
+reject modifiesCovariantSeq(addr(dogRefs))
+reject modifiesCovariantSeq(dogRefs.addr)
+
+reject modifiesCovariantArray([dog, dog])
+reject modifiesCovariantArray(dogRefsArray)
+reject modifiesCovariantArray(addr(dogRefsArray))
+reject modifiesCovariantArray(dogRefsArray.addr)
+
+var dogValues = @[vdog, vdog]
+var dogValuesArray = [vdog, vdog]
+var animalValues = @[Animal(vdog), Animal(vcat)]
+var animalValuesArray = [Animal(vdog), Animal(vcat)]
+
+wantsNonCovariantSeq animalValues
+wantsNonCovariantArray animalValuesArray
+
+reject wantsNonCovariantSeq(dogRefs)
+reject modifiesCovariantOperArray(dogRefs)
+reject wantsNonCovariantArray(dogRefsArray)
+reject wantsNonCovariantSeq(dogValues)
+reject wantsNonCovariantArray(dogValuesArray)
+reject modifiesValueArray()
+
+modifiesDerivedOperArray dogRefs
+reject modifiesDerivedOperArray(dogValues)
+reject modifiesDerivedOperArray(animalRefs)
+
+wantsNonCovariantOperArray animalValues
+reject wantsNonCovariantOperArray(animalRefs)
+reject wantsNonCovariantOperArray(dogRefs)
+reject wantsNonCovariantOperArray(dogValues)
+
+var animalRefSeq: seq[ref Animal]
+
+accept:
+  animalRefSeq = @[AnimalRef(dog), AnimalRef(dog)]
+  animalRefSeq = @[AnimalRef(cat), dog]
+
+acceptWithCovariance:
+  animalRefSeq = @[makeDerivedRef("dog 1"), makeDerivedRef("dog 2")]
+  wantsCovariantSeq1(animalRefSeq)
+else:
+  echo "dog 1"
+  echo "dog 2"
+
+var pdog: ptr Dog
+var pcat: ptr Cat
+
+proc wantsPointer(x: ptr Animal) =
+  discard
+
+accept:
+  wantsPointer pdog
+  wantsPointer pcat
+
+# covariance should be disabled when var is involved
+proc wantsVarPointer1(x: var ptr Animal) =
+  discard
+
+proc wantsVarPointer2(x: var AnimalPtr) =
+  discard
+
+reject wantsVarPointer1(pdog)
+reject wantsVarPointer2(pcat)
+
+# covariance may be allowed for certain extern types
+
+{.emit: """
+template <class T> struct FN { typedef void (*type)(T); };
+template <class T> struct ARR { typedef T DataType[2]; DataType data; };
+""".}
+
+type
+  MyPtr {.importcpp: "'0 *"} [out T] = object
+
+  MySeq {.importcpp: "ARR<'0>", nodecl} [out T] = object
+    data: array[2, T]
+
+  MyAction {.importcpp: "FN<'0>::type"} [in T] = object
+
+var
+  cAnimal: MyPtr[Animal]
+  cDog: MyPtr[Dog]
+  cCat: MyPtr[Cat]
+
+  cAnimalFn: MyAction[Animal]
+  cCatFn: MyAction[Cat]
+  cDogFn: MyAction[Dog]
+
+  cRefAnimalFn: MyAction[ref Animal]
+  cRefCatFn: MyAction[ref Cat]
+  cRefDogFn: MyAction[ref Dog]
+
+accept:
+  cAnimal = cDog
+  cAnimal = cCat
+
+  cDogFn = cAnimalFn
+  cCatFn = cAnimalFn
+
+  cRefDogFn = cRefAnimalFn
+  cRefCatFn = cRefAnimalFn
+
+reject: cDogFn = cRefAnimalFn
+reject: cCatFn = cRefAnimalFn
+
+reject: cCat = cDog
+reject: cAnimalFn = cDogFn
+reject: cAnimalFn = cCatFn
+reject: cRefAnimalFn = cRefDogFn
+reject: cRefAnimalFn = cRefCatFn
+reject: cRefAnimalFn = cDogFn
+
+var
+  ptrPtrDog: ptr ptr Dog
+  ptrPtrAnimal: ptr ptr Animal
+
+reject: ptrPtrDog = ptrPtrAnimal
+
+# Try to break the rules by introducing some tricky
+# double indirection types:
+var
+  cPtrRefAnimal: MyPtr[ref Animal]
+  cPtrRefDog: MyPtr[ref Dog]
+
+  cPtrAliasRefAnimal: MyPtr[RefAlias[Animal]]
+  cPtrAliasRefDog: MyPtr[RefAlias[Dog]]
+
+  cDoublePtrAnimal: MyPtr[MyPtr[Animal]]
+  cDoublePtrDog: MyPtr[MyPtr[Dog]]
+
+reject: cPtrRefAnimal = cPtrRefDog
+reject: cDoublePtrAnimal = cDoublePtrDog
+reject: cRefAliasPtrAnimal = cRefAliasPtrDog
+reject: cPtrRefAnimal = cRefAliasPtrDog
+reject: cPtrAliasRefAnimal = cPtrRefDog
+
+var
+  # Array and Sequence types are covariant only
+  # when instantiated with ref or ptr types:
+  cAnimals: MySeq[ref Animal]
+  cDogs: MySeq[ref Dog]
+
+  # "User-defined" pointer types should be OK too:
+  cAnimalPtrSeq: MySeq[MyPtr[Animal]]
+  cDogPtrSeq: MySeq[MyPtr[Dog]]
+
+  # Value types shouldn't work:
+  cAnimalValues: MySeq[Animal]
+  cDogValues: MySeq[Dog]
+
+  # Double pointer types should not work either:
+  cAnimalRefPtrSeq: MySeq[ref MyPtr[Animal]]
+  cDogRefPtrSeq: MySeq[ref MyPtr[Dog]]
+  cAnimalPtrPtrSeq: MySeq[ptr ptr Animal]
+  cDogPtrPtrSeq: MySeq[ptr ptr Dog]
+
+accept:
+  cAnimals = cDogs
+  cAnimalPtrSeq = cDogPtrSeq
+
+reject: cAnimalValues = cDogValues
+reject: cAnimalRefPtrSeq = cDogRefPtrSeq
+reject: cAnimalPtrPtrSeq = cDogPtrPtrSeq
+
+proc wantsAnimalSeq(x: MySeq[Animal]) = discard
+proc wantsAnimalRefSeq(x: MySeq[ref Animal]) = discard
+proc modifiesAnimalRefSeq(x: var MySeq[ref Animal]) = discard
+proc usesAddressOfAnimalRefSeq(x: ptr MySeq[ref Animal]) = discard
+
+accept wantsAnimalSeq(cAnimalValues)
+reject wantsAnimalSeq(cDogValues)
+reject wantsAnimalSeq(cAnimals)
+
+reject wantsAnimalRefSeq(cAnimalValues)
+reject wantsAnimalRefSeq(cDogValues)
+accept wantsAnimalRefSeq(cAnimals)
+accept wantsAnimalRefSeq(cDogs)
+
+reject modifiesAnimalRefSeq(cAnimalValues)
+reject modifiesAnimalRefSeq(cDogValues)
+accept modifiesAnimalRefSeq(cAnimals)
+reject modifiesAnimalRefSeq(cDogs)
+
+reject usesAddressOfAnimalRefSeq(addr cAnimalValues)
+reject usesAddressOfAnimalRefSeq(addr cDogValues)
+accept usesAddressOfAnimalRefSeq(addr cAnimals)
+reject usesAddressOfAnimalRefSeq(addr cDogs)
+