Skip to content

Commit

Permalink
fix #13502 a and b now short-circuits semcheck in VM
Browse files Browse the repository at this point in the history
  • Loading branch information
timotheecour committed Feb 29, 2020
1 parent 1056f9e commit b4b637a
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 0 deletions.
9 changes: 9 additions & 0 deletions compiler/semexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2153,6 +2153,15 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
result[0] = newSymNode(s, n[0].info)
result[1] = semAddrArg(c, n[1], s.name.s == "unsafeAddr")
result.typ = makePtrType(c, result[1].typ)
of mBitandI: # somehow, not mAnd
if c.inStaticContext > 0:
result = newTree(nkCall)
result.add newIdentNode(getIdent(c.cache, "nimInternalAndVM"), n.info)
result.add n[1]
result.add n[2]
result = semExpr(c, result)
else:
result = semDirectOp(c, n, flags)
of mTypeOf:
markUsed(c, n.info, s)
result = semTypeOf(c, n)
Expand Down
7 changes: 7 additions & 0 deletions lib/system/basic_types.nim
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ proc `and`*(x, y: bool): bool {.magic: "And", noSideEffect.}
## are true).
##
## Evaluation is lazy: if ``x`` is false, ``y`` will not even be evaluated.
## Semantic check is lazy in VM, to allow `when declared(Foo) and T is Foo`

template nimInternalAndVM*(x: bool, y: untyped): bool =
## Internal lowering used by `and` in VM to enable shortcuiting semcheck
when x: y
else: false

proc `or`*(x, y: bool): bool {.magic: "Or", noSideEffect.}
## Boolean ``or``; returns true if ``not (not x and not y)`` (if any of
## the arguments is true).
Expand Down
15 changes: 15 additions & 0 deletions tests/system/tsystem_misc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -210,3 +210,18 @@ block: # Ordinal
# doAssert enum is Ordinal # fails
# doAssert Ordinal is SomeOrdinal
# doAssert SomeOrdinal is Ordinal

block: # and VM shortcircuits semcheck
doAssert not compiles(nonexistant)
const a1 = false and nonexistant
doAssert not a1
const a2 = true and false
doAssert not a2
const a3 = true and true
doAssert a3

static:
const a4 = false and nonexistant
doAssert not a4
let a5 = false and nonexistant # still works, we're inside a static context
doAssert not a5

0 comments on commit b4b637a

Please sign in to comment.