From 7cd17772181a8577a79ee166f4dc96b396dd59d2 Mon Sep 17 00:00:00 2001 From: metagn Date: Fri, 6 Sep 2024 12:46:17 +0300 Subject: [PATCH] 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. --- compiler/semexprs.nim | 23 ++++++++++- compiler/semtypes.nim | 5 ++- .../generics/tuninstantiatedgenericcalls.nim | 39 ++++++++++++++++++- tests/proc/tstaticsignature.nim | 2 +- 4 files changed, 65 insertions(+), 4 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index bb82a7cd7a897..737a846c06659 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -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.. 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: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 4c7affd277beb..d51cafe0c168e 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -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] diff --git a/tests/generics/tuninstantiatedgenericcalls.nim b/tests/generics/tuninstantiatedgenericcalls.nim index 45de244597206..edce48aef9317 100644 --- a/tests/generics/tuninstantiatedgenericcalls.nim +++ b/tests/generics/tuninstantiatedgenericcalls.nim @@ -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] diff --git a/tests/proc/tstaticsignature.nim b/tests/proc/tstaticsignature.nim index 17b7d006176a0..3c6d66b2bd92e 100644 --- a/tests/proc/tstaticsignature.nim +++ b/tests/proc/tstaticsignature.nim @@ -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: