fix(binding): if + binding statement list expressions is broken in nim 2.2.8

Requires change in the nim compiler to work: https://github.com/nim-lang/Nim/pull/25761
This commit is contained in:
E M 2026-04-22 19:05:19 +10:00
parent 2906828765
commit 34aa579af4
No known key found for this signature in database
7 changed files with 239 additions and 1 deletions

3
.gitignore vendored
View File

@ -4,3 +4,6 @@
nimbledeps nimbledeps
nimble.develop nimble.develop
nimble.paths nimble.paths
nimbledeps
.claude
nimcache

View File

@ -4,7 +4,7 @@ description = "Elegant optional types"
license = "MIT" license = "MIT"
task test, "Runs the test suite": task test, "Runs the test suite":
for module in ["options", "results", "stew"]: for module in ["options", "results", "stew", "async"]:
withDir "testmodules/" & module: withDir "testmodules/" & module:
delEnv "NIMBLE_DIR" # use nimbledeps dir delEnv "NIMBLE_DIR" # use nimbledeps dir
exec "nimble install -d -y" exec "nimble install -d -y"

View File

@ -0,0 +1,3 @@
--path:"../.."
--threads:on
import "../../config.nims"

View File

@ -0,0 +1,2 @@
import ./testChronos
import ./testAsyncDispatch

View File

@ -0,0 +1,16 @@
version = "0.1.0"
author = "Questionable Authors"
description = "Questionable tests for pkg/chronos"
license = "MIT"
requires "chronos >= 4.2.2"
requires "asynctest >= 0.5.4"
let nimBin = getEnv("NIM_PATH", "nim")
when (NimMajor, NimMinor) >= (1, 6):
task test, "Runs the test suite":
exec nimBin & " c -f -r --skipParentCfg --nimcache:./nimcache test.nim"
else:
task test, "Runs the test suite":
echo "Warning: Skipping test with chronos on Nim < 1.6"

View File

@ -0,0 +1,107 @@
import std/asyncdispatch
import pkg/questionable/results
import pkg/asynctest/asyncdispatch/unittest
{.experimental: "parallel".}
suite "chronos":
var asyncSuccessCalled: bool
var asyncFailureCalled: bool
var assignValueCalled: bool
var assignValueFailedCalled: bool
var returnBoolCalled: bool
setup:
asyncSuccessCalled = false
asyncFailureCalled = false
assignValueCalled = false
assignValueFailedCalled = false
returnBoolCalled = false
proc asyncSuccess(): Future[?!int] {.async.} =
asyncSuccessCalled = true
success 42
proc asyncFailure(): Future[?!int] {.async.} =
asyncFailureCalled = true
failure "failed to complete async operation"
proc assignValue(): ?!int =
assignValueCalled = true
success 43
proc assignValueFailed(): ?!int =
assignValueFailedCalled = true
failure "failed to assign value"
proc returnBool(val: bool): bool =
returnBoolCalled = true
return val
test "=? works with if + await":
if a =? (await asyncSuccess()):
check a == 42
else:
fail()
test "=? works with if + await + value binding (and)":
if a =? (await asyncSuccess()) and b =? assignValue():
check a == 42
check b == 43
else:
fail()
test "=? works with if + await failure + value binding -- short circuit doesn't works (and)":
if a =? (await asyncFailure()) and b =? assignValue():
fail()
check assignValueCalled # should not be called if short circuiting works for statement list expressions
test "=? works with if + await failure + non-statement list expression -- short circuit works (and)":
if a =? (await asyncFailure()) and returnBool(true):
fail()
check not returnBoolCalled
test "=? works with if + value binding + await (and)":
if a =? assignValue() and b =? (await asyncSuccess()):
check a == 43
check b == 42
else:
fail()
test "=? works with if + value binding + await -- short circuit works (and)":
if a =? assignValueFailed() and b =? (await asyncSuccess()):
fail()
check asyncSuccessCalled # should not be called if short circuiting works for statement list expressions
test "=? works with if + await + value binding (or)":
if a =? (await asyncSuccess()) or b =? assignValue():
check a == 42
check b == 43
else:
fail()
test "=? works with if + value binding + await -- short circuit doesn't work (or)":
if a =? assignValue() or b =? (await asyncSuccess()):
check a == 43
check b == 42
check asyncSuccessCalled # should not be called if short circuiting worked for statement list expressions
else:
fail()
test "=? works with if + value binding + non-statement list expression -- short circuit works (or)":
if a =? assignValue() or returnBool(true):
check a == 43
check not returnBoolCalled
else:
fail()
test "=? works with if + value binding failure + await (or)":
if a =? assignValueFailed() or b =? (await asyncSuccess()):
check a == default int
check b == 42
else:
fail()

View File

@ -0,0 +1,107 @@
import pkg/questionable/results
import pkg/chronos
import pkg/asynctest/chronos/unittest
{.experimental: "parallel".}
suite "chronos":
var asyncSuccessCalled: bool
var asyncFailureCalled: bool
var assignValueCalled: bool
var assignValueFailedCalled: bool
var returnBoolCalled: bool
setup:
asyncSuccessCalled = false
asyncFailureCalled = false
assignValueCalled = false
assignValueFailedCalled = false
returnBoolCalled = false
proc asyncSuccess(): Future[?!int] {.async.} =
asyncSuccessCalled = true
success 42
proc asyncFailure(): Future[?!int] {.async.} =
asyncFailureCalled = true
failure "failed to complete async operation"
proc assignValue(): ?!int =
assignValueCalled = true
success 43
proc assignValueFailed(): ?!int =
assignValueFailedCalled = true
failure "failed to assign value"
proc returnBool(val: bool): bool =
returnBoolCalled = true
return val
test "=? works with if + await":
if a =? (await asyncSuccess()):
check a == 42
else:
fail()
test "=? works with if + await + value binding (and)":
if a =? (await asyncSuccess()) and b =? assignValue():
check a == 42
check b == 43
else:
fail()
test "=? works with if + await failure + value binding -- short circuit doesn't works (and)":
if a =? (await asyncFailure()) and b =? assignValue():
fail()
check assignValueCalled # should not be called if short circuiting works for statement list expressions
test "=? works with if + await failure + non-statement list expression -- short circuit works (and)":
if a =? (await asyncFailure()) and returnBool(true):
fail()
check not returnBoolCalled
test "=? works with if + value binding + await (and)":
if a =? assignValue() and b =? (await asyncSuccess()):
check a == 43
check b == 42
else:
fail()
test "=? works with if + value binding + await -- short circuit works (and)":
if a =? assignValueFailed() and b =? (await asyncSuccess()):
fail()
check asyncSuccessCalled # should not be called if short circuiting works for statement list expressions
test "=? works with if + await + value binding (or)":
if a =? (await asyncSuccess()) or b =? assignValue():
check a == 42
check b == 43
else:
fail()
test "=? works with if + value binding + await -- short circuit doesn't work (or)":
if a =? assignValue() or b =? (await asyncSuccess()):
check a == 43
check b == 42
check asyncSuccessCalled # should not be called if short circuiting worked for statement list expressions
else:
fail()
test "=? works with if + value binding + non-statement list expression -- short circuit works (or)":
if a =? assignValue() or returnBool(true):
check a == 43
check not returnBoolCalled
else:
fail()
test "=? works with if + value binding failure + await (or)":
if a =? assignValueFailed() or b =? (await asyncSuccess()):
check a == default int
check b == 42
else:
fail()