diff options
-rw-r--r-- | changelog.md | 2 | ||||
-rw-r--r-- | compiler/condsyms.nim | 1 | ||||
-rw-r--r-- | compiler/sem.nim | 1 | ||||
-rw-r--r-- | compiler/semdata.nim | 3 | ||||
-rw-r--r-- | compiler/semexprs.nim | 4 | ||||
-rw-r--r-- | lib/js/asyncjs.nim | 7 | ||||
-rw-r--r-- | testament/lib/stdtest/testutils.nim | 11 | ||||
-rw-r--r-- | tests/typerel/tvoid.nim | 61 |
8 files changed, 78 insertions, 12 deletions
diff --git a/changelog.md b/changelog.md index 7b4a2438a..d7b568aa0 100644 --- a/changelog.md +++ b/changelog.md @@ -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. diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index bdecd7e53..6a49584c8 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -133,3 +133,4 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasCustomLiterals") defineSymbol("nimHasUnifiedTuple") defineSymbol("nimHasIterable") + defineSymbol("nimHasTypeofVoid") diff --git a/compiler/sem.nim b/compiler/sem.nim index 4020fc4d6..b80795354 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -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 diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 1c1a5159c..082a4813e 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -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 diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 97f88869e..2e229d861 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -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) diff --git a/lib/js/asyncjs.nim b/lib/js/asyncjs.nim index c62ac633f..861fe3fe2 100644 --- a/lib/js/asyncjs.nim +++ b/lib/js/asyncjs.nim @@ -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))) diff --git a/testament/lib/stdtest/testutils.nim b/testament/lib/stdtest/testutils.nim index 44048adbd..241ab1770 100644 --- a/testament/lib/stdtest/testutils.nim +++ b/testament/lib/stdtest/testutils.nim @@ -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 diff --git a/tests/typerel/tvoid.nim b/tests/typerel/tvoid.nim index 1e46d016e..0b7b525cc 100644 --- a/tests/typerel/tvoid.nim +++ b/tests/typerel/tvoid.nim @@ -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()) |