Repository: fredrikekre/Runic.jl
Pull request #70 (2024-10-19 20:46:35)

Don't add explicit returns in `do` blocks


Patch:
diff --git a/README.md b/README.md
index 0978e90..b9342e3 100644
--- a/README.md
+++ b/README.md
@@ -411,9 +411,8 @@ x = a + b *
 
 ### Explicit `return`
 
-Explicit `return` statements are ensured in function/macro definitions as well as in
-`do`-blocks by adding `return` in front of the last expression, with some exceptions listed
-below.
+Explicit `return` statements are ensured in function and macro definitions by adding
+`return` in front of the last expression, with some exceptions listed below.
 
  - If the last expression is a `for` or `while` loop (which both always evaluate to
    `nothing`) `return` is added *after* the loop.
@@ -423,6 +422,8 @@ below.
    there is no `return` inside the block.
  - If the last expression is a macro call, the `return` is only added in case there is no
    `return` inside the macro.
+ - No `return` is added in short form functions (`f(...) = ...`), short form anonymous
+   functions (`(...) -> ...`), and `do`-blocks (`f(...) do ...; ...; end`).
  - If the last expression is a function call, and the function name is (or contains) `throw`
    or `error`, no `return` is added. This is because it is already obvious that these calls
    terminate the function and don't return any value.
@@ -449,14 +450,6 @@ Examples:
 -    :(generate_expr(args...))
 +    return :(generate_expr(args...))
  end
-
- function g()
--    open("/dev/random", "r") do f
--        read(f, 8)
-+    return open("/dev/random", "r") do f
-+        return read(f, 8)
-     end
- end
 ```
 
 #### Potential changes
diff --git a/src/runestone.jl b/src/runestone.jl
index fe77730..e343894 100644
--- a/src/runestone.jl
+++ b/src/runestone.jl
@@ -3584,7 +3584,7 @@ function explicit_return_block(ctx, node)
 end
 
 function explicit_return(ctx::Context, node::Node)
-    if !(!is_leaf(node) && kind(node) in KSet"function macro do")
+    if !(!is_leaf(node) && kind(node) in KSet"function macro")
         return nothing
     end
     if !safe_to_insert_return(ctx, node)


Test patch:
diff --git a/test/runtests.jl b/test/runtests.jl
index 85293e5..1a4fece 100644
--- a/test/runtests.jl
+++ b/test/runtests.jl
@@ -487,9 +487,9 @@ end
         @test format_string("try\nerror()\ncatch$(sp)e\nend") == "try\n    error()\ncatch e\nend"
         @test format_string("A$(sp)where$(sp){T}") == "A where {T}"
         @test format_string("A$(sp)where$(sp){T}$(sp)where$(sp){S}") == "A where {T} where {S}"
-        @test format_string("f()$(sp)do$(sp)x\ny\nend") == "f() do x\n    return y\nend"
-        @test format_string("f()$(sp)do\ny\nend") == "f() do\n    return y\nend"
-        @test format_string("f()$(sp)do; y end") == "f() do;\n    return y\nend"
+        @test format_string("f()$(sp)do$(sp)x\ny\nend") == "f() do x\n    y\nend"
+        @test format_string("f()$(sp)do\ny\nend") == "f() do\n    y\nend"
+        @test format_string("f()$(sp)do; y end") == "f() do;\n    y\nend"
         # After `where` (anywhere else?) a newline can be used instead of a space
         @test format_string("A$(sp)where$(sp)\n{A}") == "A where\n{A}"
     end
@@ -647,8 +647,8 @@ end
             "try\n$(sp)x\n$(sp)catch err\n$(sp)y\n$(sp)else\n$(sp)z\n$(sp)finally\n$(sp)z\n$(sp)end"
         ) == "try\n    x\ncatch err\n    y\nelse\n    z\nfinally\n    z\nend"
         # do-end
-        @test format_string("open() do\n$(sp)a\n$(sp)end") == "open() do\n    return a\nend"
-        @test format_string("open() do io\n$(sp)a\n$(sp)end") == "open() do io\n    return a\nend"
+        @test format_string("open() do\n$(sp)a\n$(sp)end") == "open() do\n    a\nend"
+        @test format_string("open() do io\n$(sp)a\n$(sp)end") == "open() do io\n    a\nend"
         # module-end, baremodule-end
         for b in ("", "bare")
             # Just a module
@@ -1082,11 +1082,11 @@ end
         @test format_string("try$(d)x$(d)catch err$(d)y$(d)else$(d)z$(d)finally$(d)z$(d)end") ==
             "try\n    x\ncatch err\n    y\nelse\n    z\nfinally\n    z\nend"
         # do-end
-        @test format_string("open() do\na$(d)end") == "open() do\n    return a\nend"
+        @test format_string("open() do\na$(d)end") == "open() do\n    a\nend"
         @test format_string("open() do\nend") == "open() do\nend"
         @test_broken format_string("open() do;a$(d)end") == "open() do\n    a\nend"
         @test_broken format_string("open() do ;a$(d)end") == "open() do\n    a\nend"
-        @test format_string("open() do io$(d)a end") == "open() do io\n    return a\nend"
+        @test format_string("open() do io$(d)a end") == "open() do io\n    a\nend"
         # let-end
         @test format_string("let a = 1\nx$(d)end") == "let a = 1\n    x\nend"
         @test format_string("let\nx$(d)end") == "let\n    x\nend"
@@ -1216,7 +1216,7 @@ end
             "begin", "quote", "for i in I", "let", "let x = 1", "while cond",
             "if cond", "macro f()", "function f()", "f() do", "f() do x",
         )
-        rx = prefix in ("function f()", "macro f()", "f() do", "f() do x") ? "    return x\n" : ""
+        rx = prefix in ("function f()", "macro f()") ? "    return x\n" : ""
         @test format_string("$(prefix)\n$(body)$(rx)\nend") == "$prefix\n$(bodyfmt)$(rx)\nend"
     end
     @test format_string(
@@ -1255,7 +1255,7 @@ end
 end
 
 @testset "explicit return" begin
-    for f in ("function f()", "function ()", "f() do", "macro m()")
+    for f in ("function f()", "function ()", "macro m()")
         # Simple cases just prepend `return`
         for r in (
                 "x", "*", "x, y", "(x, y)", "f()", "[1, 2]", "Int[1, 2]", "[1 2]", "Int[1 2]",
@@ -1265,7 +1265,7 @@ end
                 "a.b", "a.b.c", "x -> x^2", "[x for x in X]", "Int[x for x in X]",
                 "A{T} where {T}", "(@m a, b)", "A{T}",
                 "r\"foo\"", "r\"foo\"m", "`foo`", "```foo```", "r`foo`",
-                "f() do\n        return x\n    end", "f() do x\n        return x\n    end",
+                "f() do\n        x\n    end", "f() do x\n        x\n    end",
                 "function f()\n        return x\n    end",
                 "function ()\n        return x\n    end",
                 "quote\n        x\n    end", "begin\n        x\n    end",