Skip to content

Commit

Permalink
generate tyFromExpr for when in generics (nim-lang#24066)
Browse files Browse the repository at this point in the history
fixes nim-lang#22342, fixes nim-lang#22607

Another followup of nim-lang#22029, `when` expressions in general in generic
type bodies now behave like `nkRecWhen` does since nim-lang#24042, leaving them
as `tyFromExpr` if a condition is uncertain. The tests for the issues
were originally added but left disabled in nim-lang#24005.
  • Loading branch information
metagn authored Sep 6, 2024
1 parent a93c5d7 commit 7cd1777
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 4 deletions.
23 changes: 22 additions & 1 deletion compiler/semexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2685,6 +2685,7 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
whenNimvm = exprNode.sym.magic == mNimvm
if whenNimvm: n.flags.incl nfLL

var cannotResolve = false
for i in 0..<n.len:
var it = n[i]
case it.kind
Expand All @@ -2695,6 +2696,20 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
it[1] = semExpr(c, it[1], flags)
typ = commonType(c, typ, it[1].typ)
result = n # when nimvm is not elimited until codegen
elif c.inGenericContext > 0:
let e = semExprWithType(c, it[0])
if e.typ.kind == tyFromExpr:
it[0] = makeStaticExpr(c, e)
cannotResolve = true
else:
it[0] = forceBool(c, e)
let val = getConstExpr(c.module, it[0], c.idgen, c.graph)
if val == nil or val.kind != nkIntLit:
cannotResolve = true
elif not cannotResolve and val.intVal != 0 and result == nil:
setResult(it[1])
return # we're not in nimvm and we already have a result
it[1] = semGenericStmt(c, it[1])
else:
let e = forceBool(c, semConstExpr(c, it[0]))
if e.kind != nkIntLit:
Expand All @@ -2706,7 +2721,9 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
return # we're not in nimvm and we already have a result
of nkElse, nkElseExpr:
checkSonsLen(it, 1, c.config)
if result == nil or whenNimvm:
if cannotResolve:
it[0] = semGenericStmt(c, it[0])
elif result == nil or whenNimvm:
if semCheck:
it[0] = semExpr(c, it[0], flags)
typ = commonType(c, typ, it[0].typ)
Expand All @@ -2715,6 +2732,10 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
if result == nil:
result = it[0]
else: illFormedAst(n, c.config)
if cannotResolve:
result = n
result.typ = makeTypeFromExpr(c, result.copyTree)
return
if result == nil:
result = newNodeI(nkEmpty, n.info)
if whenNimvm:
Expand Down
5 changes: 4 additions & 1 deletion compiler/semtypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2068,7 +2068,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
of nkWhenStmt:
var whenResult = semWhen(c, n, false)
if whenResult.kind == nkStmtList: whenResult.transitionSonsKind(nkStmtListType)
result = semTypeNode(c, whenResult, prev)
if whenResult.kind == nkWhenStmt:
result = whenResult.typ
else:
result = semTypeNode(c, whenResult, prev)
of nkBracketExpr:
checkMinSonsLen(n, 2, c.config)
var head = n[0]
Expand Down
39 changes: 38 additions & 1 deletion tests/generics/tuninstantiatedgenericcalls.nim
Original file line number Diff line number Diff line change
Expand Up @@ -333,10 +333,47 @@ block: # issue #24044
type MyBuf[I] = ArrayBuf[maxLen(I)]
var v: MyBuf[int]

when false: # issue #22342, type section version of #22607
block: # issue #22342, type section version of #22607
type GenAlias[isInt: static bool] = (
when isInt:
int
else:
float
)
doAssert GenAlias[true] is int
doAssert GenAlias[false] is float
proc foo(T: static bool): GenAlias[T] = discard
doAssert foo(true) is int
doAssert foo(false) is float
proc foo[T: static bool](v: var GenAlias[T]) =
v += 1
var x: int
foo[true](x)
doAssert not compiles(foo[false](x))
foo[true](x)
doAssert x == 2
var y: float
foo[false](y)
doAssert not compiles(foo[true](y))
foo[false](y)
doAssert y == 2

block: # `when`, test no constant semchecks
type Foo[T] = (
when false:
{.error: "bad".}
elif defined(neverDefined):
{.error: "bad 2".}
else:
T
)
var x: Foo[int]
type Bar[T] = (
when true:
T
elif defined(js):
{.error: "bad".}
else:
{.error: "bad 2".}
)
var y: Bar[int]
2 changes: 1 addition & 1 deletion tests/proc/tstaticsignature.nim
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ block: # issue #7547
let z = initContainsFoo(5) # Error: undeclared identifier: 'N'
doAssert z.Ffoo is int

when false: # issue #22607, needs nkWhenStmt to be handled like nkRecWhen
block: # issue #22607, needs nkWhenStmt to be handled like nkRecWhen
proc test[x: static bool](
t: (
when x:
Expand Down

0 comments on commit 7cd1777

Please sign in to comment.