mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-04 12:07:51 +00:00
Make {.requiresInit.} to work for distinct types (#15869)
Make `requiresInit` pragma to work for distinct types in addition to
objects. Tagging of distinct types with `requiresInit` pragma was
already supported, but its impact wasn't applied. Now its behavior when
applied on distinct types is as follows.
Given the following distinct type definitions:
```nim
type
DistinctObject {.requiresInit, borrow: `.`.} = distinct MyObject
DistinctString {.requiresInit.} = distinct string
```
The following code blocks will fail to compile:
```nim
var foo: DistinctFoo
foo.x = "test"
doAssert foo.x == "test"
```
```nim
var s: DistinctString
s = "test"
doAssert s == "test"
```
But these ones will compile successfully:
```nim
let foo = DistinctFoo(Foo(x: "test"))
doAssert foo.x == "test"
```
```nim
let s = "test"
doAssert s == "test"
```
This commit is contained in:
@@ -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`.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
-------------
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user