diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/cpp/tcovariancerules.nim | 424 | ||||
-rw-r--r-- | tests/errmsgs/tinvalidinout.nim | 26 | ||||
-rw-r--r-- | tests/generics/tfakecovariance.nim | 78 | ||||
-rw-r--r-- | tests/generics/tgenericconst.nim | 39 | ||||
-rw-r--r-- | tests/generics/tptrinheritance.nim | 2 | ||||
-rw-r--r-- | tests/stdlib/tmarshal.nim | 24 | ||||
-rw-r--r-- | tests/template/tgenerictemplates.nim | 13 |
7 files changed, 604 insertions, 2 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) + diff --git a/tests/errmsgs/tinvalidinout.nim b/tests/errmsgs/tinvalidinout.nim new file mode 100644 index 000000000..ce7eb6022 --- /dev/null +++ b/tests/errmsgs/tinvalidinout.nim @@ -0,0 +1,26 @@ +discard """ +cmd: "nim check $file" +errormsg: "The `in` modifier can be used only with imported types" +nimout: ''' +tinvalidinout.nim(14, 7) Error: The `out` modifier can be used only with imported types +tinvalidinout.nim(17, 9) Error: The `in` modifier can be used only with imported types +tinvalidinout.nim(18, 9) Error: The `in` modifier can be used only with imported types +''' +""" + +type + Foo {.header: "foo.h", importcpp.} [in T] = object + + Bar[out X] = object + x: int + +proc f1[in T](x: T) = discard +proc f2[in T](x: T) {.importc: "f", header: "foo.h"} + +var + f: Foo[int] + b: Bar[string] + +f1 f +f2 b + diff --git a/tests/generics/tfakecovariance.nim b/tests/generics/tfakecovariance.nim new file mode 100644 index 000000000..0920cb504 --- /dev/null +++ b/tests/generics/tfakecovariance.nim @@ -0,0 +1,78 @@ +template accept(x) = + static: assert(compiles(x)) + +template reject(x) = + static: assert(not compiles(x)) + +type + BaseObj = object of RootObj + DerivedObj = object of BaseObj + NonDerivedObj = object + + Container[T] = object + +var base: BaseObj +var derived: DerivedObj +var nonDerived: NonDerivedObj + +var baseContainer: Container[BaseObj] +var derivedContainer: Container[DerivedObj] +var nonDerivedContainer: Container[NonDerivedObj] + +# We can fake covariance by listing some specific derived types that +# will be allowed with our overload. This is not a real covariance, +# because there will be multiple instantiations of the proc, but for +# many purposes, it will suffice: + +proc wantsSpecificContainers(c: Container[BaseObj or DerivedObj]) = discard + +accept wantsSpecificContainers(baseContainer) +accept wantsSpecificContainers(derivedContainer) + +reject wantsSpecificContainers(nonDerivedContainer) +reject wantsSpecificContainers(derived) + +# Now, let's make a more general solution able to catch all derived types: + +type + DerivedFrom[T] = concept type D + var derived: ref D + var base: ref T = derived + +proc wantsDerived(x: DerivedFrom[BaseObj]) = discard + +accept wantsDerived(base) +accept wantsDerived(derived) + +reject wantsDerived(nonDerived) +reject wantsDerived(baseContainer) + +proc wantsDerivedContainer(c: Container[DerivedFrom[BaseObj]]) = discard + +accept wantsDerivedContainer(baseContainer) +accept wantsDerivedContainer(derivedContainer) + +reject wantsDerivedContainer(nonDerivedContainer) + +# The previous solutions were solving the problem for a single overload. +# Let's solve it for multiple overloads by introducing a converter: + +type + OtherContainer[T] = object + +proc wantsBaseContainer1(c: OtherContainer[BaseObj]) = discard +proc wantsBaseContainer2(c: OtherContainer[BaseObj]) = discard + +converter derivedToBase(c: OtherContainer[DerivedFrom[BaseObj]]): OtherContainer[BaseObj] = discard + +block: + var baseContainer: OtherContainer[BaseObj] + var derivedContainer: OtherContainer[DerivedObj] + var nonDerivedContainer: OtherContainer[NonDerivedObj] + + accept wantsBaseContainer1(derivedContainer) + reject wantsBaseContainer1(nonDerivedContainer) + + accept wantsBaseContainer2(derivedContainer) + reject wantsBaseContainer2(nonDerivedContainer) + diff --git a/tests/generics/tgenericconst.nim b/tests/generics/tgenericconst.nim new file mode 100644 index 000000000..3c86888df --- /dev/null +++ b/tests/generics/tgenericconst.nim @@ -0,0 +1,39 @@ +discard """ +output: ''' +@[1, 2] +@[3, 4] +1 +''' +""" + +# https://github.com/nim-lang/Nim/issues/5756 + +type + Vec*[N : static[int]] = object + x: int + arr*: array[N, int32] + + Mat*[M,N: static[int]] = object + x: int + arr*: array[M, Vec[N]] + +proc vec2*(x,y:int32) : Vec[2] = + result.arr = [x,y] + result.x = 10 + +proc mat2*(a,b: Vec[2]): Mat[2,2] = + result.arr = [a,b] + result.x = 20 + +const M = mat2(vec2(1, 2), vec2(3, 4)) + +let m1 = M +echo @(m1.arr[0].arr) +echo @(m1.arr[1].arr) + +proc foo = + let m2 = M + echo m1.arr[0].arr[0] + +foo() + diff --git a/tests/generics/tptrinheritance.nim b/tests/generics/tptrinheritance.nim index 1e1115fa5..221b8777b 100644 --- a/tests/generics/tptrinheritance.nim +++ b/tests/generics/tptrinheritance.nim @@ -10,7 +10,7 @@ proc newMutableArrayAbstract*(): NSMutableArrayAbstract = discard template newMutableArray*(T: typedesc): NSMutableArray[T] = cast[NSMutableArray[T]](newMutableArrayAbstract()) -proc writeObjects*(p: NSPasteboard, o: ptr NSArray[NSPasteboardItem]) = discard +proc writeObjects*(p: NSPasteboard, o: NSArray[NSPasteboardItem]) = discard let a = newMutableArray NSPasteboardItem var x: NSMutableArray[NSPasteboardItem] diff --git a/tests/stdlib/tmarshal.nim b/tests/stdlib/tmarshal.nim index b05cb5a10..6a53a2964 100644 --- a/tests/stdlib/tmarshal.nim +++ b/tests/stdlib/tmarshal.nim @@ -1,7 +1,10 @@ discard """ output: '''{"age": 12, "bio": "\u042F Cletus", "blob": [65, 66, 67, 128], "name": "Cletus"} true -true''' +true +alpha 100 +omega 200 +''' """ import marshal @@ -83,3 +86,22 @@ var instance1 = Person(name: "Cletus", age: 12, echo($$instance1) echo(to[Person]($$instance1).bio == instance1.bio) echo(to[Person]($$instance1).blob == instance1.blob) + +# bug 5757 + +type + Something = object + x: string + y: int + +var data1 = """{"x": "alpha", "y": 100}""" +var data2 = """{"x": "omega", "y": 200}""" + +var r = to[Something](data1) + +echo r.x, " ", r.y + +r = to[Something](data2) + +echo r.x, " ", r.y + diff --git a/tests/template/tgenerictemplates.nim b/tests/template/tgenerictemplates.nim new file mode 100644 index 000000000..2c83bc0ec --- /dev/null +++ b/tests/template/tgenerictemplates.nim @@ -0,0 +1,13 @@ +type + SomeObj = object of RootObj + + Foo[T, U] = object + x: T + y: U + +template someTemplate[T](): tuple[id: int32, obj: T] = + var result: tuple[id: int32, obj: T] = (0'i32, T()) + result + +let ret = someTemplate[SomeObj]() + |