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:
Timothee Cour
2021-04-23 05:36:38 -07:00
committed by GitHub
parent 3516f57e17
commit 2abc936d51
8 changed files with 78 additions and 12 deletions

View File

@@ -331,6 +331,8 @@
- Added a new module `std/importutils`, and an API `privateAccess`, which allows access to private fields
for an object type in the current scope.
- `typeof(voidStmt)` now works and returns `void`.
## Compiler changes
- Added `--declaredlocs` to show symbol declaration location in messages.

View File

@@ -133,3 +133,4 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimHasCustomLiterals")
defineSymbol("nimHasUnifiedTuple")
defineSymbol("nimHasIterable")
defineSymbol("nimHasTypeofVoid")

View File

@@ -525,6 +525,7 @@ proc myOpen(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext
var c = newContext(graph, module)
c.idgen = idgen
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")
c.semConstExpr = semConstExpr

View File

@@ -90,6 +90,9 @@ type
TContext* = object of TPassContext # a context represents the module
# that is currently being compiled
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
currentScope*: PScope # current scope
moduleScope*: PScope # scope for modules

View File

@@ -83,7 +83,9 @@ proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
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 %
renderTree(result, {renderNoComments}))
result.typ = errorType(c)

View File

@@ -158,10 +158,6 @@ proc newPromise*(handler: proc(resolve: proc())): Future[void] {.importjs: "(new
## A helper for wrapping callback-based functions
## 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 =
# avoids `Future[Future[T]]`
when T is Future: T
@@ -221,7 +217,8 @@ when defined(nimExperimentalAsyncjsThen):
assert witness == 3
template impl(call): untyped =
when typeOrVoid(call) is void:
# see D20210421T014713
when typeof(block: call) is void:
var ret: Future[void]
else:
var ret = default(maybeFuture(typeof(call)))

View File

@@ -91,10 +91,6 @@ template disableVm*(body) =
when nimvm: discard
else: body
template typeOrVoid[T](a: T): type =
# FACTOR with asyncjs.typeOrVoid
T
macro assertAll*(body) =
## works in VM, unlike `check`, `require`
runnableExamples:
@@ -106,6 +102,9 @@ macro assertAll*(body) =
result = newStmtList()
for a in body:
result.add genAst(a) do:
# better than: `when not compiles(typeof(a)):`
when typeOrVoid(a) is void: a
# D20210421T014713:here
# 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

View File

@@ -35,3 +35,64 @@ ReturnT[void]()
echo ReturnT[string]("abc")
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())