From 56a3dd57fb038cab2d00f6415435e701d2273573 Mon Sep 17 00:00:00 2001 From: metagn Date: Fri, 27 Sep 2024 12:09:49 +0300 Subject: [PATCH] evaluate all hidden conversions in case branches (#24187) fixes #11422, refs #8336/#8333, refs #20130 The compiler generates conversion nodes *after* evaluating the branches of case statements as constants, the reasoning is that case branches accept constants of different types, like arrays or sets. But this means that conversion nodes that need to be evaluated like converter calls don't get evaluated as a constant for codegen. #8336 fixed this by re-evaluating the node if an `nkHiddenCallConv` was created, and in #20130 this logic also had to be added for `nkHiddenStdConv` for cstrings. This logic was only for single case elements, it has now been added to range elements as well to fix #11422. Additionally, all conversion nodes are now evaluated for simplicity, but maybe this won't pass CI. --- compiler/semtypes.nim | 15 ++++++++++----- tests/casestmt/tcasestmt.nim | 5 +++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 6fe921e8101e..25ce73b513e2 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -586,9 +586,14 @@ proc semBranchRange(c: PContext, n, a, b: PNode, covered: var Int128): PNode = let bc = semConstExpr(c, b) if ac.kind in {nkStrLit..nkTripleStrLit} or bc.kind in {nkStrLit..nkTripleStrLit}: localError(c.config, b.info, "range of string is invalid") - let at = fitNode(c, n[0].typ, ac, ac.info).skipConvTakeType - let bt = fitNode(c, n[0].typ, bc, bc.info).skipConvTakeType - + var at = fitNode(c, n[0].typ, ac, ac.info).skipConvTakeType + var bt = fitNode(c, n[0].typ, bc, bc.info).skipConvTakeType + # the calls to fitNode may introduce calls to converters + # mirrored with semCaseBranch for single elements + if at.kind in {nkHiddenCallConv, nkHiddenStdConv, nkHiddenSubConv}: + at = semConstExpr(c, at) + if bt.kind in {nkHiddenCallConv, nkHiddenStdConv, nkHiddenSubConv}: + bt = semConstExpr(c, bt) result = newNodeI(nkRange, a.info) result.add(at) result.add(bt) @@ -636,8 +641,8 @@ proc semCaseBranch(c: PContext, n, branch: PNode, branchIndex: int, checkMinSonsLen(n, 1, c.config) var tmp = fitNode(c, n[0].typ, r, r.info) # the call to fitNode may introduce a call to a converter - if tmp.kind == nkHiddenCallConv or - (tmp.kind == nkHiddenStdConv and n[0].typ.kind == tyCstring): + # mirrored with semBranchRange + if tmp.kind in {nkHiddenCallConv, nkHiddenStdConv, nkHiddenSubConv}: tmp = semConstExpr(c, tmp) branch[i] = skipConv(tmp) inc(covered) diff --git a/tests/casestmt/tcasestmt.nim b/tests/casestmt/tcasestmt.nim index aea0c96a42be..66de4183dd58 100644 --- a/tests/casestmt/tcasestmt.nim +++ b/tests/casestmt/tcasestmt.nim @@ -41,6 +41,11 @@ block t8333: case 0 of 'a': echo 0 else: echo 1 +block: # issue #11422 + var c: int = 5 + case c + of 'a' .. 'c': discard + else: discard block emptyset_when: