summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--changelog.md2
-rw-r--r--compiler/semobjconstr.nim21
-rw-r--r--compiler/semstmts.nim3
-rw-r--r--compiler/typeallowed.nim3
-rw-r--r--doc/manual.rst30
-rw-r--r--tests/distinct/tdistinct.nim32
6 files changed, 82 insertions, 9 deletions
diff --git a/changelog.md b/changelog.md
index 871fb229d..53730ecc5 100644
--- a/changelog.md
+++ b/changelog.md
@@ -4,6 +4,8 @@
 
 ## Standard library additions and changes
 
+- Make `{.requiresInit.}` pragma to work for `distinct` types.
+
 - `prelude` now works with the JavaScript target.
 
 - Added `ioutils` module containing `duplicate` and `duplicateTo` to duplicate `FileHandle` using C function `dup` and `dup2`.
diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim
index 64a27d1db..42529e1e5 100644
--- a/compiler/semobjconstr.nim
+++ b/compiler/semobjconstr.nim
@@ -355,15 +355,22 @@ proc computeRequiresInit(c: PContext, t: PType): bool =
 
 proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) =
   var objType = t
-  while objType.kind != tyObject:
+  while objType.kind notin {tyObject, tyDistinct}:
     objType = objType.lastSon
     assert objType != nil
-  var constrCtx = initConstrContext(objType, newNodeI(nkObjConstr, info))
-  let initResult = semConstructTypeAux(c, constrCtx, {})
-  assert constrCtx.missingFields.len > 0
-  localError(c.config, info,
-    "The $1 type doesn't have a default value. The following fields must be initialized: $2.",
-    [typeToString(t), listSymbolNames(constrCtx.missingFields)])
+  if objType.kind == tyObject:
+    var constrCtx = initConstrContext(objType, newNodeI(nkObjConstr, info))
+    let initResult = semConstructTypeAux(c, constrCtx, {})
+    assert constrCtx.missingFields.len > 0
+    localError(c.config, info,
+      "The $1 type doesn't have a default value. The following fields must " &
+      "be initialized: $2.",
+      [typeToString(t), listSymbolNames(constrCtx.missingFields)])
+  elif objType.kind == tyDistinct:
+    localError(c.config, info,
+      "The $1 distinct type doesn't have a default value.", [typeToString(t)])
+  else:
+    assert false, "Must not enter here."
 
 proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
   var t = semTypeNode(c, n[0], nil)
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 2a058eee2..4b79cd546 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -611,7 +611,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
       if def.kind == nkEmpty:
         let actualType = v.typ.skipTypes({tyGenericInst, tyAlias,
                                           tyUserTypeClassInst})
-        if actualType.kind == tyObject and actualType.requiresInit:
+        if actualType.kind in {tyObject, tyDistinct} and
+           actualType.requiresInit:
           defaultConstructionError(c, v.typ, v.info)
         else:
           checkNilable(c, v)
diff --git a/compiler/typeallowed.nim b/compiler/typeallowed.nim
index a8210508c..e163b914a 100644
--- a/compiler/typeallowed.nim
+++ b/compiler/typeallowed.nim
@@ -260,4 +260,5 @@ proc directViewType*(t: PType): ViewTypeKind =
     result = noView
 
 proc requiresInit*(t: PType): bool =
-  (t.flags * {tfRequiresInit, tfNotNil} != {}) or classifyViewType(t) != noView
+  (t.flags * {tfRequiresInit, tfNeedsFullInit, tfNotNil} != {}) or
+  classifyViewType(t) != noView
diff --git a/doc/manual.rst b/doc/manual.rst
index d9f9cc9b9..4e5b861b1 100644
--- a/doc/manual.rst
+++ b/doc/manual.rst
@@ -2697,6 +2697,36 @@ the variable has been initialized and does not rely on syntactic properties:
       x = a()
     # use x
 
+`requiresInit` pragma can also be applyied to `distinct` types.
+
+Given the following distinct type definitions:
+
+.. code-block:: nim
+  type
+    DistinctObject {.requiresInit, borrow: `.`.} = distinct MyObject
+    DistinctString {.requiresInit.} = distinct string
+
+The following code blocks will fail to compile:
+
+.. code-block:: nim
+  var foo: DistinctFoo
+  foo.x = "test"
+  doAssert foo.x == "test"
+
+.. code-block:: nim
+  var s: DistinctString
+  s = "test"
+  doAssert s == "test"
+
+But these ones will compile successfully:
+
+.. code-block:: nim
+  let foo = DistinctFoo(Foo(x: "test"))
+  doAssert foo.x == "test"
+
+.. code-block:: nim
+  let s = "test"
+  doAssert s == "test"
 
 Let statement
 -------------
diff --git a/tests/distinct/tdistinct.nim b/tests/distinct/tdistinct.nim
index 2c0196745..d64f33443 100644
--- a/tests/distinct/tdistinct.nim
+++ b/tests/distinct/tdistinct.nim
@@ -106,3 +106,35 @@ type FooD = distinct int
 proc `<=`(a, b: FooD): bool {.borrow.}
 
 for f in [FooD(0): "Foo"]: echo f
+
+block tRequiresInit:
+  template accept(x) =
+    static: doAssert compiles(x)
+
+  template reject(x) =
+    static: doAssert not compiles(x)
+
+  type
+    Foo = object
+      x: string
+
+    DistinctFoo {.requiresInit, borrow: `.`.} = distinct Foo
+    DistinctString {.requiresInit.} = distinct string
+
+  reject:
+    var foo: DistinctFoo
+    foo.x = "test"
+    doAssert foo.x == "test"
+
+  accept:
+    let foo = DistinctFoo(Foo(x: "test"))
+    doAssert foo.x == "test"
+
+  reject:
+    var s: DistinctString
+    s = "test"
+    doAssert s == "test"
+
+  accept:
+    let s = "test"
+    doAssert s == "test"