[ 
https://issues.apache.org/jira/browse/GROOVY-6844?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Eric Milles updated GROOVY-6844:
--------------------------------
    Description: 
I've seen in groovy _the break statement with named label is only allowed 
inside loops_, in fact executing the following snippet from groovyConsole
{code:groovy}
foo: {
    println "foo"
    break foo
}
{code}
I get this output {quote}
2 compilation errors:

the break statement with named label is only allowed inside loops
 at line: 5, column: 13

break to missing label
 at line: 5, column: 13
{quote}

But this morning a colleague of mine discovered that if you combine *old-school 
label definition* with a *break label used within two nested loops* you obtain 
no compile/runtime errors. Instead the executed logic is not the expected one, 
at least not what you would expect when you write that kind of code.
It seems that the _break label_ instruction simply breaks the innermost loop 
execution, continuing with the outer one (hence ignoring the label).

Follows a test based on the example took from 
http://docs.codehaus.org/display/GROOVY/JN2535-Control:
Its output shows how the labeled code block  is *re-executed after the 
{{break}}*

{code:title=Foo.groovy}
def i=0, j=0
outer: {
  println "executing outer block"
  while( i<5 ){ //labelling a while loop is especially useful...
    j= 0
    i++
  println "executing outer while, i: $i, j: $j"
    while( j<5 ){
      j++
  println "executing inner while, i: $i, j: $j"
      if( i==3 && j==2 ) break outer
            //...because we can break out of a specified labelled while loop
    }
  }
}
assert i==3 && j==2
{code}

This is its execution output:
{quote}
executing outer block
executing outer while, i: 1, j: 0
executing inner while, i: 1, j: 1
executing inner while, i: 1, j: 2
executing inner while, i: 1, j: 3
executing inner while, i: 1, j: 4
executing inner while, i: 1, j: 5
executing outer while, i: 2, j: 0
executing inner while, i: 2, j: 1
executing inner while, i: 2, j: 2
executing inner while, i: 2, j: 3
executing inner while, i: 2, j: 4
executing inner while, i: 2, j: 5
executing outer while, i: 3, j: 0
executing inner while, i: 3, j: 1
executing inner while, i: 3, j: 2
executing outer while, i: 4, j: 0
executing inner while, i: 4, j: 1
executing inner while, i: 4, j: 2
executing inner while, i: 4, j: 3
executing inner while, i: 4, j: 4
executing inner while, i: 4, j: 5
executing outer while, i: 5, j: 0
executing inner while, i: 5, j: 1
executing inner while, i: 5, j: 2
executing inner while, i: 5, j: 3
executing inner while, i: 5, j: 4
executing inner while, i: 5, j: 5
{code}
Exception in thread "main" Assertion failed: 
assert i==3 && j==2
       ||   |
       5|   false
        false

        at 
org.codehaus.groovy.runtime.InvokerHelper.assertFailed(InvokerHelper.java:398)
        at 
org.codehaus.groovy.runtime.ScriptBytecodeAdapter.assertFailed(ScriptBytecodeAdapter.java:646)
        at Bar.main(Bar.groovy:27)
{code}
{quote}

Follows the java counterpart, whose output shows how the labeled code block  is 
not executed after the {{break}}

{code:title=Foo.java}
public class Foo {
    public static void main(String[] args) {
        int i = 0, j = 0;
        outer: {
            println("executing outer block");
            while (i < 5) { // labelling a while loop is especially useful...
                j = 0;
                i++;
                println("executing outer while, i: " + i + ", j: " + j);
                while (j < 5) {
                    j++;
                    println("executing inner while, i: " + i + ", j: " + j);
                    if (i == 3 && j == 2)
                        break outer;
                    // ...because we can break out of a specified labelled 
while loop
                }
            }
        }
        assert i == 3 && j == 2;
    }

    static void println(String s) {
        System.out.println(s);
    }
}
{code}

And this is its execution output
{quote}
executing outer block
executing outer while, i: 1, j: 0
executing inner while, i: 1, j: 1
executing inner while, i: 1, j: 2
executing inner while, i: 1, j: 3
executing inner while, i: 1, j: 4
executing inner while, i: 1, j: 5
executing outer while, i: 2, j: 0
executing inner while, i: 2, j: 1
executing inner while, i: 2, j: 2
executing inner while, i: 2, j: 3
executing inner while, i: 2, j: 4
executing inner while, i: 2, j: 5
executing outer while, i: 3, j: 0
executing inner while, i: 3, j: 1
executing inner while, i: 3, j: 2
{quote}
(even running it with assertions enabled through the {{-ea}} switch)

  was:
I've seen in groovy _the break statement with named label is only allowed 
inside loops_, in fact executing the following snippet from groovyConsole
{code}
foo: {
    println "foo"
    break foo
}
{code}
I get this output {quote}
2 compilation errors:

the break statement with named label is only allowed inside loops
 at line: 5, column: 13

break to missing label
 at line: 5, column: 13
{quote}

But this morning a colleague of mine discovered that if you combine *old-school 
label definition* with a *break label used within two nested loops* you obtain 
no compile/runtime errors. Instead the executed logic is not the expected one, 
at least not what you would expect when you write that kind of code.
It seems that the _break label_ instruction simply breaks the innermost loop 
execution, continuing with the outer one (hence ignoring the label).

Follows a test based on the example took from 
http://docs.codehaus.org/display/GROOVY/JN2535-Control:
Its output shows how the labeled code block  is *re-executed after the 
{{break}}*

{code:title=Foo.groovy}
def i=0, j=0
outer: {
  println "executing outer block"
  while( i<5 ){ //labelling a while loop is especially useful...
    j= 0
    i++
  println "executing outer while, i: $i, j: $j"
    while( j<5 ){
      j++
  println "executing inner while, i: $i, j: $j"
      if( i==3 && j==2 ) break outer
            //...because we can break out of a specified labelled while loop
    }
  }
}
assert i==3 && j==2
{code}
This is its execution output:
{quote}
executing outer block
executing outer while, i: 1, j: 0
executing inner while, i: 1, j: 1
executing inner while, i: 1, j: 2
executing inner while, i: 1, j: 3
executing inner while, i: 1, j: 4
executing inner while, i: 1, j: 5
executing outer while, i: 2, j: 0
executing inner while, i: 2, j: 1
executing inner while, i: 2, j: 2
executing inner while, i: 2, j: 3
executing inner while, i: 2, j: 4
executing inner while, i: 2, j: 5
executing outer while, i: 3, j: 0
executing inner while, i: 3, j: 1
executing inner while, i: 3, j: 2
executing outer while, i: 4, j: 0
executing inner while, i: 4, j: 1
executing inner while, i: 4, j: 2
executing inner while, i: 4, j: 3
executing inner while, i: 4, j: 4
executing inner while, i: 4, j: 5
executing outer while, i: 5, j: 0
executing inner while, i: 5, j: 1
executing inner while, i: 5, j: 2
executing inner while, i: 5, j: 3
executing inner while, i: 5, j: 4
executing inner while, i: 5, j: 5
Exception in thread "main" Assertion failed: 

assert i==3 && j==2
       ||   |
       5|   false
        false

        at 
org.codehaus.groovy.runtime.InvokerHelper.assertFailed(InvokerHelper.java:398)
        at 
org.codehaus.groovy.runtime.ScriptBytecodeAdapter.assertFailed(ScriptBytecodeAdapter.java:646)
        at Bar.main(Bar.groovy:27)
{quote}

Follows the java counterpart, whose output shows how the labeled code block  is 
not executed after the {{break}}
{code:title=Foo.java}
public class Foo {
    public static void main(String[] args) {
        int i = 0, j = 0;
        outer: {
            println("executing outer block");
            while (i < 5) { // labelling a while loop is especially useful...
                j = 0;
                i++;
                println("executing outer while, i: " + i + ", j: " + j);
                while (j < 5) {
                    j++;
                    println("executing inner while, i: " + i + ", j: " + j);
                    if (i == 3 && j == 2)
                        break outer;
                    // ...because we can break out of a specified labelled 
while loop
                }
            }
        }
        assert i == 3 && j == 2;
    }

    static void println(String s) {
        System.out.println(s);
    }
}
{code}
And this is its execution output {quote}executing outer block
executing outer while, i: 1, j: 0
executing inner while, i: 1, j: 1
executing inner while, i: 1, j: 2
executing inner while, i: 1, j: 3
executing inner while, i: 1, j: 4
executing inner while, i: 1, j: 5
executing outer while, i: 2, j: 0
executing inner while, i: 2, j: 1
executing inner while, i: 2, j: 2
executing inner while, i: 2, j: 3
executing inner while, i: 2, j: 4
executing inner while, i: 2, j: 5
executing outer while, i: 3, j: 0
executing inner while, i: 3, j: 1
executing inner while, i: 3, j: 2
{quote}
(even running it with assertions enabled through the {{-ea}} switch)


> "Break label" instruction broken when combining nested loops with 
> "old-school" labeled code blocks
> --------------------------------------------------------------------------------------------------
>
>                 Key: GROOVY-6844
>                 URL: https://issues.apache.org/jira/browse/GROOVY-6844
>             Project: Groovy
>          Issue Type: Bug
>          Components: Compiler
>    Affects Versions: 2.3.2
>            Reporter: Davide Cavestro
>            Assignee: Eric Milles
>            Priority: Major
>
> I've seen in groovy _the break statement with named label is only allowed 
> inside loops_, in fact executing the following snippet from groovyConsole
> {code:groovy}
> foo: {
>     println "foo"
>     break foo
> }
> {code}
> I get this output {quote}
> 2 compilation errors:
> the break statement with named label is only allowed inside loops
>  at line: 5, column: 13
> break to missing label
>  at line: 5, column: 13
> {quote}
> But this morning a colleague of mine discovered that if you combine 
> *old-school label definition* with a *break label used within two nested 
> loops* you obtain no compile/runtime errors. Instead the executed logic is 
> not the expected one, at least not what you would expect when you write that 
> kind of code.
> It seems that the _break label_ instruction simply breaks the innermost loop 
> execution, continuing with the outer one (hence ignoring the label).
> Follows a test based on the example took from 
> http://docs.codehaus.org/display/GROOVY/JN2535-Control:
> Its output shows how the labeled code block  is *re-executed after the 
> {{break}}*
> {code:title=Foo.groovy}
> def i=0, j=0
> outer: {
>   println "executing outer block"
>   while( i<5 ){ //labelling a while loop is especially useful...
>     j= 0
>     i++
>   println "executing outer while, i: $i, j: $j"
>     while( j<5 ){
>       j++
>   println "executing inner while, i: $i, j: $j"
>       if( i==3 && j==2 ) break outer
>             //...because we can break out of a specified labelled while loop
>     }
>   }
> }
> assert i==3 && j==2
> {code}
> This is its execution output:
> {quote}
> executing outer block
> executing outer while, i: 1, j: 0
> executing inner while, i: 1, j: 1
> executing inner while, i: 1, j: 2
> executing inner while, i: 1, j: 3
> executing inner while, i: 1, j: 4
> executing inner while, i: 1, j: 5
> executing outer while, i: 2, j: 0
> executing inner while, i: 2, j: 1
> executing inner while, i: 2, j: 2
> executing inner while, i: 2, j: 3
> executing inner while, i: 2, j: 4
> executing inner while, i: 2, j: 5
> executing outer while, i: 3, j: 0
> executing inner while, i: 3, j: 1
> executing inner while, i: 3, j: 2
> executing outer while, i: 4, j: 0
> executing inner while, i: 4, j: 1
> executing inner while, i: 4, j: 2
> executing inner while, i: 4, j: 3
> executing inner while, i: 4, j: 4
> executing inner while, i: 4, j: 5
> executing outer while, i: 5, j: 0
> executing inner while, i: 5, j: 1
> executing inner while, i: 5, j: 2
> executing inner while, i: 5, j: 3
> executing inner while, i: 5, j: 4
> executing inner while, i: 5, j: 5
> {code}
> Exception in thread "main" Assertion failed: 
> assert i==3 && j==2
>        ||   |
>        5|   false
>         false
>       at 
> org.codehaus.groovy.runtime.InvokerHelper.assertFailed(InvokerHelper.java:398)
>       at 
> org.codehaus.groovy.runtime.ScriptBytecodeAdapter.assertFailed(ScriptBytecodeAdapter.java:646)
>       at Bar.main(Bar.groovy:27)
> {code}
> {quote}
> Follows the java counterpart, whose output shows how the labeled code block  
> is not executed after the {{break}}
> {code:title=Foo.java}
> public class Foo {
>     public static void main(String[] args) {
>         int i = 0, j = 0;
>         outer: {
>             println("executing outer block");
>             while (i < 5) { // labelling a while loop is especially useful...
>                 j = 0;
>                 i++;
>                 println("executing outer while, i: " + i + ", j: " + j);
>                 while (j < 5) {
>                     j++;
>                     println("executing inner while, i: " + i + ", j: " + j);
>                     if (i == 3 && j == 2)
>                         break outer;
>                     // ...because we can break out of a specified labelled 
> while loop
>                 }
>             }
>         }
>         assert i == 3 && j == 2;
>     }
>     static void println(String s) {
>         System.out.println(s);
>     }
> }
> {code}
> And this is its execution output
> {quote}
> executing outer block
> executing outer while, i: 1, j: 0
> executing inner while, i: 1, j: 1
> executing inner while, i: 1, j: 2
> executing inner while, i: 1, j: 3
> executing inner while, i: 1, j: 4
> executing inner while, i: 1, j: 5
> executing outer while, i: 2, j: 0
> executing inner while, i: 2, j: 1
> executing inner while, i: 2, j: 2
> executing inner while, i: 2, j: 3
> executing inner while, i: 2, j: 4
> executing inner while, i: 2, j: 5
> executing outer while, i: 3, j: 0
> executing inner while, i: 3, j: 1
> executing inner while, i: 3, j: 2
> {quote}
> (even running it with assertions enabled through the {{-ea}} switch)



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to