mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 08:54:53 +00:00
generate tyFromExpr for when in generics (#24066)
fixes #22342, fixes #22607 Another followup of #22029, `when` expressions in general in generic type bodies now behave like `nkRecWhen` does since #24042, leaving them as `tyFromExpr` if a condition is uncertain. The tests for the issues were originally added but left disabled in #24005.
This commit is contained in:
@@ -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
|
||||
@@ -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:
|
||||
@@ -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)
|
||||
@@ -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:
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user