nemerle icon indicating copy to clipboard operation
nemerle copied to clipboard

Компиляция с включенной оптимизацией выносит промежуточную переменную за тело цикла

Open DarthSidius opened this issue 10 years ago • 5 comments

using System;
using System.Console;

class cls
{
    public Value : string
    {
        get { "aaaaa!" }
    }
}

class cls1
{
    public Item[num : int] : cls
    {
        get { if( num == 1 ) cls() else null }
    }
}

module Program
{
    Main() : void
    {
        def o = cls1();
        foreach( i in array[1, 2] ) {
            WriteLine(o[i]?.Value); 
        }
    }
}

The output should be:

aaaaa!

Got in release:

aaaaa!
aaaaa!

In debug the output is correct.

DarthSidius avatar Mar 24 '14 22:03 DarthSidius

Using reflector, it seems that in RELEASE mode the variable str is moved to FUNCTION scope instead of local loop scope. This is the cause of the error. So it must be a bug in Nemerle compiler or ?. macro

private static void Main()
{
    string str = null;  //<---- ERROR this variable should be LOCAL in LOOP
    Program.cls1 cls2 = new Program.cls1();
    for (list<int> tl = new list<int>.Cons(1, new list<int>.Cons(2, new list<int>.Cons(3, new list<int>.Cons(4, list<int>.Nil._N_constant_object)))); tl is list<int>.Cons; tl = tl)
    {
        int hd = ((list<int>.Cons) tl).hd;
        tl = ((list<int>.Cons) tl).tl;
        Program.cls cls = cls2[hd];
        if (cls != null)
        {
            str = cls.Value;
        }
        Console.WriteLine(str);
    }
}

liviuu avatar Mar 25 '14 07:03 liviuu

This is how the program look correctly in DEBUG mode. The str variable is loop local. This issue is very troubling, what is the stability of the Nemerle compiler is someone decides to use it for production code?

private static void Main()
{
    list<int> tl;
    Program.cls1 cls = new Program.cls1();
    for (list<int> list = new list<int>.Cons(1, new list<int>.Cons(2, new list<int>.Cons(3, new list<int>.Cons(4, list<int>.Nil._N_constant_object)))); list is list<int>.Cons; list = tl)
    {
        int hd = ((list<int>.Cons) list).hd;
        tl = ((list<int>.Cons) list).tl;
        int num2 = hd;
        Program.cls cls2 = cls[num2];
        string str2 = null;
        if (cls2 != null)
        {
            str2 = cls2.Value;
        }
        string str = str2;
        Console.WriteLine(str);
    }
}


liviuu avatar Mar 25 '14 07:03 liviuu

Release:

  private static void Main()
  {
    string str = (string) null;  // Release (!)
    cls1 cls1 = new cls1();
    int[] numArray1 = new int[2];
    int index1 = 0;
    int num1 = 1;
    numArray1[index1] = num1;
    int index2 = 1;
    int num2 = 2;
    numArray1[index2] = num2;
    int[] numArray2 = numArray1;
    int index3 = 0;
    while (index3 < numArray2.Length)
    {
      int index4 = numArray2[index3];
      cls cls = cls1[index4];
      if (cls != null)
        str = cls.Value;
      Console.WriteLine(str);
      checked { ++index3; }
    }
  }

Debug:

  private static void Main()
  {
    cls1 cls1 = new cls1();
    int[] numArray1 = new int[2];
    int index1 = 0;
    int num1 = 1;
    numArray1[index1] = num1;
    int index2 = 1;
    int num2 = 2;
    numArray1[index2] = num2;
    int[] numArray2 = numArray1;
    int index3 = 0;
    while (index3 < numArray2.Length)
    {
      int index4 = numArray2[index3];
      cls cls = cls1[index4];
      string str = (string) null;  // OK
      if (cls != null)
        str = cls.Value;
      Console.WriteLine(str);
      checked { ++index3; }
    }
  }

DarthSidius avatar Mar 25 '14 07:03 DarthSidius

liviuu, don't panic, this is work correct

    Main() : void
    {
        def o = cls1();
        foreach( i in array[1, 2] ) {
            def temp = o[i];
            when( temp != null ) {
                WriteLine(temp.Value); 
            }
        }
    }

I think, bug will fixed soon

DarthSidius avatar Mar 25 '14 08:03 DarthSidius

So, the problem is the ?. macro that creates the temporary variable in wrong scope?

liviuu avatar Mar 25 '14 08:03 liviuu