123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418 |
- discard """
- targets: "cpp"
- output: '''
- cat
- cat
- dog
- dog
- cat
- cat
- dog
- dog X
- cat
- cat
- dog
- dog
- dog
- dog
- 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): untyped = n[0]
- template acceptWithCovariance(x, otherwise): untyped =
- 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 wantsCovariantOpenArray(s: openarray[ref Animal]) =
- for a in s: echo a.x
- proc modifiesCovariantOpenArray(s: var openarray[ref Animal]) =
- for a in s: echo a.x
- proc modifiesDerivedOpenArray(s: var openarray[ref Dog]) =
- for a in s: echo a.x
- proc wantsNonCovariantOpenArray(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 inconsistent, 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])
- wantsCovariantOpenArray([cat, dog])
- acceptWithCovariance:
- wantsCovariantSeq1(@[cat, cat])
- wantsCovariantSeq2(@[dog, makeDerivedRef("dog X")])
- # XXX: wantsCovariantSeq3(@[cat, cat])
- wantsCovariantOpenArray(@[cat, cat])
- wantsCovariantOpenArray([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 modifiesCovariantSeqd(ogRefs)
- 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]
- when false:
- var animalValues = @[Animal(vdog), Animal(vcat)]
- var animalValuesArray = [Animal(vdog), Animal(vcat)]
- wantsNonCovariantSeq animalValues
- wantsNonCovariantArray animalValuesArray
- reject wantsNonCovariantSeq(dogRefs)
- reject modifiesCovariantOpenArray(dogRefs)
- reject wantsNonCovariantArray(dogRefsArray)
- reject wantsNonCovariantSeq(dogValues)
- reject wantsNonCovariantArray(dogValuesArray)
- reject modifiesValueArray()
- modifiesDerivedOpenArray dogRefs
- reject modifiesDerivedOpenArray(dogValues)
- reject modifiesDerivedOpenArray(animalRefs)
- reject wantsNonCovariantOpenArray(animalRefs)
- reject wantsNonCovariantOpenArray(dogRefs)
- reject wantsNonCovariantOpenArray(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: """/*TYPESECTION*/
- template <class T> struct FN { typedef void (*type)(T); };
- template <class T> struct ARR { typedef T DataType[2]; DataType data; };
- """.}
- type
- MyPtr[out T] {.importcpp: "'0 *"} = object
- MySeq[out T] {.importcpp: "ARR<'0>", nodecl} = object
- data: array[2, T]
- MyAction[in T] {.importcpp: "FN<'0>::type"} = 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)
|