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:
parent
60c364fb22
commit
3c85aa9e53
6 changed files with 82 additions and 9 deletions
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
## Standard library additions and changes
|
## Standard library additions and changes
|
||||||
|
|
||||||
|
- Make `{.requiresInit.}` pragma to work for `distinct` types.
|
||||||
|
|
||||||
- `prelude` now works with the JavaScript target.
|
- `prelude` now works with the JavaScript target.
|
||||||
|
|
||||||
- Added `ioutils` module containing `duplicate` and `duplicateTo` to duplicate `FileHandle` using C function `dup` and `dup2`.
|
- 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) =
|
proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) =
|
||||||
var objType = t
|
var objType = t
|
||||||
while objType.kind != tyObject:
|
while objType.kind notin {tyObject, tyDistinct}:
|
||||||
objType = objType.lastSon
|
objType = objType.lastSon
|
||||||
assert objType != nil
|
assert objType != nil
|
||||||
var constrCtx = initConstrContext(objType, newNodeI(nkObjConstr, info))
|
if objType.kind == tyObject:
|
||||||
let initResult = semConstructTypeAux(c, constrCtx, {})
|
var constrCtx = initConstrContext(objType, newNodeI(nkObjConstr, info))
|
||||||
assert constrCtx.missingFields.len > 0
|
let initResult = semConstructTypeAux(c, constrCtx, {})
|
||||||
localError(c.config, info,
|
assert constrCtx.missingFields.len > 0
|
||||||
"The $1 type doesn't have a default value. The following fields must be initialized: $2.",
|
localError(c.config, info,
|
||||||
[typeToString(t), listSymbolNames(constrCtx.missingFields)])
|
"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 =
|
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
var t = semTypeNode(c, n[0], nil)
|
var t = semTypeNode(c, n[0], nil)
|
||||||
|
|
|
||||||
|
|
@ -611,7 +611,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
if def.kind == nkEmpty:
|
if def.kind == nkEmpty:
|
||||||
let actualType = v.typ.skipTypes({tyGenericInst, tyAlias,
|
let actualType = v.typ.skipTypes({tyGenericInst, tyAlias,
|
||||||
tyUserTypeClassInst})
|
tyUserTypeClassInst})
|
||||||
if actualType.kind == tyObject and actualType.requiresInit:
|
if actualType.kind in {tyObject, tyDistinct} and
|
||||||
|
actualType.requiresInit:
|
||||||
defaultConstructionError(c, v.typ, v.info)
|
defaultConstructionError(c, v.typ, v.info)
|
||||||
else:
|
else:
|
||||||
checkNilable(c, v)
|
checkNilable(c, v)
|
||||||
|
|
|
||||||
|
|
@ -260,4 +260,5 @@ proc directViewType*(t: PType): ViewTypeKind =
|
||||||
result = noView
|
result = noView
|
||||||
|
|
||||||
proc requiresInit*(t: PType): bool =
|
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()
|
x = a()
|
||||||
# use x
|
# 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
|
Let statement
|
||||||
-------------
|
-------------
|
||||||
|
|
|
||||||
|
|
@ -106,3 +106,35 @@ type FooD = distinct int
|
||||||
proc `<=`(a, b: FooD): bool {.borrow.}
|
proc `<=`(a, b: FooD): bool {.borrow.}
|
||||||
|
|
||||||
for f in [FooD(0): "Foo"]: echo f
|
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"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue