rsdn / nemerle

Nemerle language. Main repository.
http://nemerle.org
Other
618 stars 89 forks source link

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

Open DarthSidius opened 10 years ago

DarthSidius commented 10 years ago
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.

liviuu commented 10 years ago

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 commented 10 years ago

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);
    }
}
DarthSidius commented 10 years ago

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 commented 10 years ago

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

liviuu commented 10 years ago

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