From 04b38ef4a21eeb135783bfc2fac61401d749f0e9 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 26 May 2021 12:46:13 -0700 Subject: [PATCH 1/4] close #18092 [skip ci] document elif in case statements --- doc/manual.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/manual.rst b/doc/manual.rst index 6a0dec120d73b..4824080f3e0cf 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -2985,6 +2985,7 @@ Example: of "delete-everything", "restart-computer": echo "permission denied" of "go-for-a-walk": echo "please yourself" + elif defined(windows): echo "bsod" else: echo "unknown command" # indentation of the branches is also allowed; and so is an optional colon From 86b3b210a635b42c1047a33dbd75b0091698dad0 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 26 May 2021 12:57:24 -0700 Subject: [PATCH 2/4] fixup --- doc/manual.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 4824080f3e0cf..43bc469b3421c 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -2985,8 +2985,8 @@ Example: of "delete-everything", "restart-computer": echo "permission denied" of "go-for-a-walk": echo "please yourself" - elif defined(windows): echo "bsod" - else: echo "unknown command" + elif defined(windows): echo "bsod" # optional `elif` must come after `of` branches + else: echo "unknown command" # ditto # indentation of the branches is also allowed; and so is an optional colon # after the selecting expression: From f137037bbd4ee0115be0795d82c61702f0b7c04c Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 26 May 2021 15:22:07 -0700 Subject: [PATCH 3/4] clarify spec; mention special rule for string in case statements --- doc/manual.rst | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 43bc469b3421c..6974d37c9d971 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -2997,19 +2997,22 @@ Example: else: echo "unknown command" -The `case` statement is similar to the if statement, but it represents +The `case` statement is similar to the `if` statement, but it represents a multi-branch selection. The expression after the keyword `case` is evaluated and if its value is in a *slicelist* the corresponding statements (after the `of` keyword) are executed. If the value is not in any -given *slicelist* the `else` part is executed. If there is no `else` -part and not all possible values that `expr` can hold occur in a -*slicelist*, a static error occurs. This holds only for expressions of -ordinal types. "All possible values" of `expr` are determined by `expr`'s -type. To suppress the static error an `else` part with an -empty `discard` statement should be used. +given *slicelist*, trailing `elif` and `else` parts are executed using same +semantics as for `if` statement. If there are no `else` or `elif` parts and not +all possible values that `expr` can hold occur in a *slicelist*, a static error occurs. +This holds only for expressions of ordinal types. +"All possible values" of `expr` are determined by `expr`'s type. +To suppress the static error an `else: discard` should be used. For non-ordinal types, it is not possible to list every possible value and so these always require an `else` part. +An exception to this rule is for the `string` type, which currently doesn't +require a trailing `else` or `elif` branch; it's unspecified whether this will +keep working in future versions. Because case statements are checked for exhaustiveness during semantic analysis, the value in every `of` branch must be a constant expression. @@ -3055,15 +3058,15 @@ won't work: var foo = Foo(x: @[]) foo.get_x().add("asd") -This can be fixed by explicitly using `return`: +This can be fixed by explicitly using `result` or `return`: .. code-block:: nim proc get_x(x: Foo): var seq[string] = case true of true: - return x.x + result = x.x else: - return x.x + result = x.x When statement From e4adccabac7d11c4a857429db1d219572046f3a5 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 31 May 2021 12:32:01 -0700 Subject: [PATCH 4/4] address comments --- doc/manual.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 6974d37c9d971..ff34b62ca1432 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -2981,11 +2981,12 @@ Example: .. code-block:: nim - case readline(stdin) + let line = readline(stdin) + case line of "delete-everything", "restart-computer": echo "permission denied" of "go-for-a-walk": echo "please yourself" - elif defined(windows): echo "bsod" # optional `elif` must come after `of` branches + elif line.len == 0: echo "empty" # optional, must come after `of` branches else: echo "unknown command" # ditto # indentation of the branches is also allowed; and so is an optional colon @@ -3002,7 +3003,8 @@ a multi-branch selection. The expression after the keyword `case` is evaluated and if its value is in a *slicelist* the corresponding statements (after the `of` keyword) are executed. If the value is not in any given *slicelist*, trailing `elif` and `else` parts are executed using same -semantics as for `if` statement. If there are no `else` or `elif` parts and not +semantics as for `if` statement, and `elif` is handled just like `else: if`. +If there are no `else` or `elif` parts and not all possible values that `expr` can hold occur in a *slicelist*, a static error occurs. This holds only for expressions of ordinal types. "All possible values" of `expr` are determined by `expr`'s type.