diff --git a/doc/manual.rst b/doc/manual.rst index 3933a92974..f1b0ae77aa 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -2568,7 +2568,8 @@ Example: discard p(3, 4) # discard the return value of `p` The ``discard`` statement evaluates its expression for side-effects and -throws the expression's resulting value away. +throws the expression's resulting value away, and should only be used +when ignoring this value is known not to cause problems. Ignoring the return value of a procedure without using a discard statement is a static error. diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index 9b05c65dcc..afc28bbdf0 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -112,7 +112,7 @@ proc getName(node: NimNode): string {.compileTime.} = of nnkEmpty: return "anonymous" else: - error("Unknown name.") + error("Unknown name.", node) proc getFutureVarIdents(params: NimNode): seq[NimNode] {.compileTime.} = result = @[] @@ -125,10 +125,10 @@ proc getFutureVarIdents(params: NimNode): seq[NimNode] {.compileTime.} = proc isInvalidReturnType(typeName: string): bool = return typeName notin ["Future"] #, "FutureStream"] -proc verifyReturnType(typeName: string) {.compileTime.} = +proc verifyReturnType(typeName: string, node: NimNode = nil) {.compileTime.} = if typeName.isInvalidReturnType: error("Expected return type of 'Future' got '$1'" % - typeName) + typeName, node) proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = ## This macro transforms a single procedure into a closure iterator. @@ -141,7 +141,13 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = if prc.kind notin {nnkProcDef, nnkLambda, nnkMethodDef, nnkDo}: error("Cannot transform this node kind into an async proc." & - " proc/method definition or lambda node expected.") + " proc/method definition or lambda node expected.", prc) + + if prc[4].kind != nnkEmpty: + for prag in prc[4]: + if prag.eqIdent("discardable"): + error("Cannot make async proc discardable. Futures have to be " & + "checked with `asyncCheck` instead of discarded", prag) let prcName = prc.name.getName @@ -153,16 +159,16 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = # Verify that the return type is a Future[T] if returnType.kind == nnkBracketExpr: let fut = repr(returnType[0]) - verifyReturnType(fut) + verifyReturnType(fut, returnType[0]) baseType = returnType[1] elif returnType.kind in nnkCallKinds and returnType[0].eqIdent("[]"): let fut = repr(returnType[1]) - verifyReturnType(fut) + verifyReturnType(fut, returnType[0]) baseType = returnType[2] elif returnType.kind == nnkEmpty: baseType = returnType else: - verifyReturnType(repr(returnType)) + verifyReturnType(repr(returnType), returntype) let subtypeIsVoid = returnType.kind == nnkEmpty or (baseType.kind == nnkIdent and returnType[1].eqIdent("void")) @@ -303,7 +309,7 @@ proc stripReturnType(returnType: NimNode): NimNode = result = returnType if returnType.kind == nnkBracketExpr: let fut = repr(returnType[0]) - verifyReturnType(fut) + verifyReturnType(fut, returnType) result = returnType[1] proc splitProc(prc: NimNode): (NimNode, NimNode) = diff --git a/tests/async/tdiscardableproc.nim b/tests/async/tdiscardableproc.nim new file mode 100644 index 0000000000..80286ece0e --- /dev/null +++ b/tests/async/tdiscardableproc.nim @@ -0,0 +1,9 @@ +discard """ + errmsg: "Cannot make async proc discardable. Futures have to be checked with `asyncCheck` instead of discarded" +""" + +import async + +proc foo {.async, discardable.} = discard + +foo() diff --git a/tests/vm/tslow_tables.nim b/tests/vm/tslow_tables.nim index a933021e0f..37351bfe2e 100644 --- a/tests/vm/tslow_tables.nim +++ b/tests/vm/tslow_tables.nim @@ -26,5 +26,5 @@ proc hop(): bool = echo "done" -const r = hop() +const r {.used.} = hop()