typeof(voidStmt) now works (#17807)
* `typeof(voidStmt)` now works * remove typeOrVoid * add condsyms, and reference cligen https://github.com/c-blake/cligen/pull/193 * fixup * changelog [skip ci] * fixup
This commit is contained in:
parent
3516f57e17
commit
2abc936d51
8 changed files with 78 additions and 12 deletions
|
|
@ -331,6 +331,8 @@
|
||||||
- Added a new module `std/importutils`, and an API `privateAccess`, which allows access to private fields
|
- Added a new module `std/importutils`, and an API `privateAccess`, which allows access to private fields
|
||||||
for an object type in the current scope.
|
for an object type in the current scope.
|
||||||
|
|
||||||
|
- `typeof(voidStmt)` now works and returns `void`.
|
||||||
|
|
||||||
## Compiler changes
|
## Compiler changes
|
||||||
|
|
||||||
- Added `--declaredlocs` to show symbol declaration location in messages.
|
- Added `--declaredlocs` to show symbol declaration location in messages.
|
||||||
|
|
|
||||||
|
|
@ -133,3 +133,4 @@ proc initDefines*(symbols: StringTableRef) =
|
||||||
defineSymbol("nimHasCustomLiterals")
|
defineSymbol("nimHasCustomLiterals")
|
||||||
defineSymbol("nimHasUnifiedTuple")
|
defineSymbol("nimHasUnifiedTuple")
|
||||||
defineSymbol("nimHasIterable")
|
defineSymbol("nimHasIterable")
|
||||||
|
defineSymbol("nimHasTypeofVoid")
|
||||||
|
|
|
||||||
|
|
@ -525,6 +525,7 @@ proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext
|
||||||
var c = newContext(graph, module)
|
var c = newContext(graph, module)
|
||||||
c.idgen = idgen
|
c.idgen = idgen
|
||||||
c.enforceVoidContext = newType(tyTyped, nextTypeId(idgen), nil)
|
c.enforceVoidContext = newType(tyTyped, nextTypeId(idgen), nil)
|
||||||
|
c.voidType = newType(tyVoid, nextTypeId(idgen), nil)
|
||||||
|
|
||||||
if c.p != nil: internalError(graph.config, module.info, "sem.myOpen")
|
if c.p != nil: internalError(graph.config, module.info, "sem.myOpen")
|
||||||
c.semConstExpr = semConstExpr
|
c.semConstExpr = semConstExpr
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,9 @@ type
|
||||||
TContext* = object of TPassContext # a context represents the module
|
TContext* = object of TPassContext # a context represents the module
|
||||||
# that is currently being compiled
|
# that is currently being compiled
|
||||||
enforceVoidContext*: PType
|
enforceVoidContext*: PType
|
||||||
|
# for `if cond: stmt else: foo`, `foo` will be evaluated under
|
||||||
|
# enforceVoidContext != nil
|
||||||
|
voidType*: PType # for typeof(stmt)
|
||||||
module*: PSym # the module sym belonging to the context
|
module*: PSym # the module sym belonging to the context
|
||||||
currentScope*: PScope # current scope
|
currentScope*: PScope # current scope
|
||||||
moduleScope*: PScope # scope for modules
|
moduleScope*: PScope # scope for modules
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,9 @@ proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
|
|
||||||
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
result = semExprCheck(c, n, flags)
|
result = semExprCheck(c, n, flags)
|
||||||
if result.typ == nil or result.typ == c.enforceVoidContext:
|
if result.typ == nil and efInTypeof in flags:
|
||||||
|
result.typ = c.voidType
|
||||||
|
elif result.typ == nil or result.typ == c.enforceVoidContext:
|
||||||
localError(c.config, n.info, errExprXHasNoType %
|
localError(c.config, n.info, errExprXHasNoType %
|
||||||
renderTree(result, {renderNoComments}))
|
renderTree(result, {renderNoComments}))
|
||||||
result.typ = errorType(c)
|
result.typ = errorType(c)
|
||||||
|
|
|
||||||
|
|
@ -158,10 +158,6 @@ proc newPromise*(handler: proc(resolve: proc())): Future[void] {.importjs: "(new
|
||||||
## A helper for wrapping callback-based functions
|
## A helper for wrapping callback-based functions
|
||||||
## into promises and async procedures.
|
## into promises and async procedures.
|
||||||
|
|
||||||
template typeOrVoid[T](a: T): type =
|
|
||||||
# xxx this is useful, make it public in std/typetraits in future work
|
|
||||||
T
|
|
||||||
|
|
||||||
template maybeFuture(T): untyped =
|
template maybeFuture(T): untyped =
|
||||||
# avoids `Future[Future[T]]`
|
# avoids `Future[Future[T]]`
|
||||||
when T is Future: T
|
when T is Future: T
|
||||||
|
|
@ -221,7 +217,8 @@ when defined(nimExperimentalAsyncjsThen):
|
||||||
assert witness == 3
|
assert witness == 3
|
||||||
|
|
||||||
template impl(call): untyped =
|
template impl(call): untyped =
|
||||||
when typeOrVoid(call) is void:
|
# see D20210421T014713
|
||||||
|
when typeof(block: call) is void:
|
||||||
var ret: Future[void]
|
var ret: Future[void]
|
||||||
else:
|
else:
|
||||||
var ret = default(maybeFuture(typeof(call)))
|
var ret = default(maybeFuture(typeof(call)))
|
||||||
|
|
|
||||||
|
|
@ -91,10 +91,6 @@ template disableVm*(body) =
|
||||||
when nimvm: discard
|
when nimvm: discard
|
||||||
else: body
|
else: body
|
||||||
|
|
||||||
template typeOrVoid[T](a: T): type =
|
|
||||||
# FACTOR with asyncjs.typeOrVoid
|
|
||||||
T
|
|
||||||
|
|
||||||
macro assertAll*(body) =
|
macro assertAll*(body) =
|
||||||
## works in VM, unlike `check`, `require`
|
## works in VM, unlike `check`, `require`
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
|
|
@ -106,6 +102,9 @@ macro assertAll*(body) =
|
||||||
result = newStmtList()
|
result = newStmtList()
|
||||||
for a in body:
|
for a in body:
|
||||||
result.add genAst(a) do:
|
result.add genAst(a) do:
|
||||||
# better than: `when not compiles(typeof(a)):`
|
# D20210421T014713:here
|
||||||
when typeOrVoid(a) is void: a
|
# xxx pending https://github.com/nim-lang/Nim/issues/12030,
|
||||||
|
# `typeof` should introduce its own scope, so that this
|
||||||
|
# is sufficient: `typeof(a)` instead of `typeof(block: a)`
|
||||||
|
when typeof(block: a) is void: a
|
||||||
else: doAssert a
|
else: doAssert a
|
||||||
|
|
|
||||||
|
|
@ -35,3 +35,64 @@ ReturnT[void]()
|
||||||
echo ReturnT[string]("abc")
|
echo ReturnT[string]("abc")
|
||||||
nothing()
|
nothing()
|
||||||
|
|
||||||
|
block: # typeof(stmt)
|
||||||
|
proc fn1(): auto =
|
||||||
|
discard
|
||||||
|
proc fn2(): auto =
|
||||||
|
1
|
||||||
|
doAssert type(fn1()) is void
|
||||||
|
doAssert typeof(fn1()) is void
|
||||||
|
doAssert typeof(fn1()) isnot int
|
||||||
|
|
||||||
|
doAssert type(fn2()) isnot void
|
||||||
|
doAssert typeof(fn2()) isnot void
|
||||||
|
when typeof(fn1()) is void: discard
|
||||||
|
else: doAssert false
|
||||||
|
|
||||||
|
doAssert typeof(1+1) is int
|
||||||
|
doAssert typeof((discard)) is void
|
||||||
|
|
||||||
|
type A1 = typeof(fn1())
|
||||||
|
doAssert A1 is void
|
||||||
|
type A2 = type(fn1())
|
||||||
|
doAssert A2 is void
|
||||||
|
doAssert A2 is A1
|
||||||
|
|
||||||
|
when false:
|
||||||
|
# xxx: MCS/UFCS doesn't work here: Error: expression 'fn1()' has no type (or is ambiguous)
|
||||||
|
type A3 = fn1().type
|
||||||
|
proc bar[T](a: T): string = $T
|
||||||
|
doAssert bar(1) == "int"
|
||||||
|
doAssert bar(fn1()) == "void"
|
||||||
|
|
||||||
|
proc bar2[T](a: T): bool = T is void
|
||||||
|
doAssert not bar2(1)
|
||||||
|
doAssert bar2(fn1())
|
||||||
|
|
||||||
|
block:
|
||||||
|
proc bar3[T](a: T): T = a
|
||||||
|
let a1 = bar3(1)
|
||||||
|
doAssert compiles(block:
|
||||||
|
let a1 = bar3(fn2()))
|
||||||
|
doAssert not compiles(block:
|
||||||
|
let a2 = bar3(fn1()))
|
||||||
|
doAssert compiles(block: bar3(fn1()))
|
||||||
|
doAssert compiles(bar3(fn1()))
|
||||||
|
doAssert typeof(bar3(fn1())) is void
|
||||||
|
doAssert not compiles(sizeof(bar3(fn1())))
|
||||||
|
|
||||||
|
block:
|
||||||
|
var a = 1
|
||||||
|
doAssert typeof((a = 2)) is void
|
||||||
|
doAssert typeof((a = 2; a = 3)) is void
|
||||||
|
doAssert typeof(block:
|
||||||
|
a = 2; a = 3) is void
|
||||||
|
|
||||||
|
block:
|
||||||
|
var a = 1
|
||||||
|
template bad1 = echo (a; a = 2)
|
||||||
|
doAssert not compiles(bad1())
|
||||||
|
|
||||||
|
block:
|
||||||
|
template bad2 = echo (nonexistant; discard)
|
||||||
|
doAssert not compiles(bad2())
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue