Mark macros.error as .noreturn. (#23081)

Closes #14329 

Marks `macros.error` as `.noreturn` so that it can be used in
expressions. This also fixes the issue that occurred in #19659 where a
stmt that could be an expression (Due to having `discardable` procs at
the end of other branches) would believe a `noreturn` proc is returning
the same type e.g.
```nim
 proc bar(): int {.discardable.} = discard

if true: bar()
else: quit(0) # Says that quit is of type `int` and needs to be used/discarded except it actually has no return type
```
This commit is contained in:
Jake Leahy
2023-12-17 22:29:46 +11:00
committed by GitHub
parent 0bd4d80238
commit b3b87f0f8a
5 changed files with 30 additions and 1 deletions

View File

@@ -157,6 +157,7 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimAllowNonVarDestructor")
defineSymbol("nimHasQuirky")
defineSymbol("nimHasEnsureMove")
defineSymbol("nimHasNoReturnError")
defineSymbol("nimUseStrictDefs")
defineSymbol("nimHasNolineTooLong")

View File

@@ -169,6 +169,11 @@ proc discardCheck(c: PContext, result: PNode, flags: TExprFlags) =
while n.kind in skipForDiscardable:
if n.kind == nkTryStmt: n = n[0]
else: n = n.lastSon
# Ignore noreturn procs since they don't have a type
if n.endsInNoReturn:
return
var s = "expression '" & $n & "' is of type '" &
result.typ.typeToString & "' and has to be used (or discarded)"
if result.info.line != n.info.line or

View File

@@ -427,7 +427,12 @@ proc copyNimTree*(n: NimNode): NimNode {.magic: "NCopyNimTree", noSideEffect.} =
let x = 12
echo x
proc error*(msg: string, n: NimNode = nil) {.magic: "NError", benign.}
when defined(nimHasNoReturnError):
{.pragma: errorNoReturn, noreturn.}
else:
{.pragma: errorNoReturn.}
proc error*(msg: string, n: NimNode = nil) {.magic: "NError", benign, errorNoReturn.}
## Writes an error message at compile time. The optional `n: NimNode`
## parameter is used as the source for file and line number information in
## the compilation error message.

View File

@@ -298,3 +298,17 @@ proc main(a: uint64) =
static:
main(10)
main(10)
block:
# Just needs to compile
proc bar(): int {.discardable.} = discard
proc foo() {.noreturn.} = discard
case "*"
of "*":
bar()
else:
# Make sure this noreturn doesn't
# cause the discardable to not discard
foo()

4
tests/macros/t14329.nim Normal file
View File

@@ -0,0 +1,4 @@
import macros
macro myMacro(n) =
let x = if true: newLit"test" else: error "error", n