summary refs log tree commit diff stats
path: root/tests/constructors
diff options
context:
space:
mode:
authorZahary Karadjov <zahary@gmail.com>2020-03-30 18:56:03 +0300
committerAndreas Rumpf <rumpf_a@web.de>2020-04-01 19:38:44 +0200
commitce9a4ed124d798d0287a62e4700a32f1d15878c9 (patch)
tree73a31457060d51b283be407c5cf37af20b6b0b1e /tests/constructors
parentd374c6373bed4d6807ff70b6179328e79fbe1ac8 (diff)
downloadNim-ce9a4ed124d798d0287a62e4700a32f1d15878c9.tar.gz
Replace tfHasRequiresInit with a more accurate mechanism
The new mechanism can deal with more complex scenarios such as
not nil field appearing in a non-default case object branch or
a field within a generic object that may depend on a when branch.

The commit also plugs another hole: the user is no longer able
to create illegal default values through seq.setLen(N).
Diffstat (limited to 'tests/constructors')
-rw-r--r--tests/constructors/tinvalid_construction.nim112
1 files changed, 112 insertions, 0 deletions
diff --git a/tests/constructors/tinvalid_construction.nim b/tests/constructors/tinvalid_construction.nim
index 6716bfb45..e98b530bb 100644
--- a/tests/constructors/tinvalid_construction.nim
+++ b/tests/constructors/tinvalid_construction.nim
@@ -10,6 +10,9 @@ type
   TRefObj = ref object
     x: int
 
+  IllegalToConstruct = object
+    x: cstring not nil
+
   THasNotNils = object of RootObj
     a: TRefObj not nil
     b: TRefObj not nil
@@ -89,6 +92,10 @@ proc userDefinedDefault(T: typedesc): T =
 proc genericDefault(T: typedesc): T =
   result = default(T)
 
+reject IllegalToConstruct()
+reject:
+  var x: IllegalToConstruct
+
 accept TObj()
 accept TObj(choice: A)
 reject TObj(choice: A, bc: 10)  # bc is in the wrong branch
@@ -256,6 +263,111 @@ reject TNestedChoices(outerChoice: false, innerChoice: C)
 accept TNestedChoices(outerChoice: false, innerChoice: C, notnil: notNilRef)
 reject TNestedChoices(outerChoice: false, innerChoice: C, notnil: nil)
 
+# Tests involving generics and sequences:
+#
+block:
+  # This test aims to show that it's possible to instantiate and
+  # use a sequence with a requiresInit type:
+
+  var legalSeq: seq[IllegalToConstruct]
+  legalSeq.add IllegalToConstruct(x: "one")
+  var two = IllegalToConstruct(x: "two")
+  legalSeq.add two
+  var one = legalSeq[0]
+  var twoAgain = legalSeq.pop
+
+  # It's not possible to tell the sequence to create elements
+  # for us though:
+  reject:
+    var illegalSeq = newSeq[IllegalToConstruct](10)
+
+  reject:
+    var illegalSeq: seq[IllegalToConstruct]
+    newSeq(illegalSeq, 10)
+
+  reject:
+    var illegalSeq: seq[IllegalToConstruct]
+    illegalSeq.setLen 10
+
+  # You can still use newSeqOfCap to write efficient code:
+  var anotherLegalSequence = newSeqOfCap[IllegalToConstruct](10)
+  for i in 0..9:
+    anotherLegalSequence.add IllegalToConstruct(x: "x")
+
+type DefaultConstructible[yesOrNo: static[bool]] = object
+  when yesOrNo:
+    x: string
+  else:
+    x: cstring not nil
+
+block:
+  # Constructability may also depend on the generic parameters of the type:
+  accept:
+    var a: DefaultConstructible[true]
+    var b = DefaultConstructible[true]()
+    var c = DefaultConstructible[true](x: "test")
+    var d = DefaultConstructible[false](x: "test")
+
+  reject:
+    var y: DefaultConstructible[false]
+
+  reject:
+    var y = DefaultConstructible[false]()
+
+block:
+  type
+    Hash = int
+
+    HashTableSlotType = enum
+      Free    = Hash(0)
+      Deleted = Hash(1)
+      HasKey  = Hash(2)
+
+    KeyValuePair[A, B] = object
+      key: A
+      case hash: HashTableSlotType
+      of Free, Deleted:
+        discard
+      else:
+        value: B
+
+  # The above KeyValuePair is an interesting type because it
+  # may become unconstructible depending on the generic parameters:
+  accept KeyValuePair[int, string](hash: Deleted)
+  accept KeyValuePair[int, IllegalToConstruct](hash: Deleted)
+
+  accept KeyValuePair[int, string](hash: HasKey)
+  reject KeyValuePair[int, IllegalToConstruct](hash: HasKey)
+
+  # Since all the above variations don't have a non-constructible
+  # field in the default branch of the case object, we can construct
+  # such values:
+  accept KeyValuePair[int, string]()
+  accept KeyValuePair[int, IllegalToConstruct]()
+  accept KeyValuePair[DefaultConstructible[true], string]()
+  accept KeyValuePair[DefaultConstructible[true], IllegalToConstruct]()
+
+  var a: KeyValuePair[int, string]
+  var b: KeyValuePair[int, IllegalToConstruct]
+  var c: KeyValuePair[DefaultConstructible[true], string]
+  var d: KeyValuePair[DefaultConstructible[true], IllegalToConstruct]
+  var s1 = newSeq[KeyValuePair[int, IllegalToConstruct]](10)
+  var s2 = newSeq[KeyValuePair[DefaultConstructible[true], IllegalToConstruct]](10)
+
+  # But let's put the non-constructible values as keys:
+  reject KeyValuePair[IllegalToConstruct, int](hash: Deleted)
+  reject KeyValuePair[IllegalToConstruct, int]()
+
+  type IllegalPair = KeyValuePair[DefaultConstructible[false], string]
+
+  reject:
+    var x: IllegalPair
+
+  reject:
+    var s = newSeq[IllegalPair](10)
+
+# Specific issues:
+#
 block:
   # https://github.com/nim-lang/Nim/issues/11428
   type