[Mono-bugs] [Bug 591226] New: Using Reflection.Emit to generate a generic method may lead to invalid codegen

bugzilla_noreply at novell.com bugzilla_noreply at novell.com
Thu Mar 25 15:18:38 EDT 2010


http://bugzilla.novell.com/show_bug.cgi?id=591226

http://bugzilla.novell.com/show_bug.cgi?id=591226#c0


           Summary: Using Reflection.Emit to generate a generic method may
                    lead to invalid codegen
    Classification: Mono
           Product: Mono: Runtime
           Version: 2.6.x
          Platform: x86
        OS/Version: All
            Status: NEW
          Severity: Normal
          Priority: P5 - None
         Component: generics
        AssignedTo: mono-bugs at lists.ximian.com
        ReportedBy: joe at noteven.org
         QAContact: mono-bugs at lists.ximian.com
          Found By: ---
           Blocker: ---


User-Agent:       Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64;
Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729;
Media Center PC 6.0; MS-RTC LM 8; InfoPath.2; .NET4.0C; .NET4.0E)

It looks like if two non-generic classes are emitted into a module, with one
containing a specialized call to a generic method defined in the other, there’s
a problem with the code generated for the specialized call.  

Reproducible: Always

Steps to Reproduce:
1. Download the latest F# CTP
http://www.microsoft.com/downloads/details.aspx?FamilyID=b55f0532-ac3c-4106-918c-5586a953a7da&displaylang=en

2. Run FSI.exe through Mono

3. Enter the following code:
let myFunc x y = 
  if x > y then stdout.WriteLine("greater {0} {1}",x,y);
  if x < y then stdout.WriteLine("less {0} {1}",x,y);
  if x = y then stdout.WriteLine("equal {0} {1}",x,y);

myFunc 1 4;;

Actual Results:  
The above will yield the following output using Mono 2.6.3 (tested on both
Windows 7 and Mac OS X 10.5.8/Intel):

greater 1 4
less 1 4
equal 1 4

val myFunc : 'a -> 'a -> unit when 'a : comparison


Expected Results:  
The above is incorrect.  The output should be:

less 1 4
val myFunc : 'a -> 'a -> unit when 'a : comparison


Copy and paste the following code fragment into fsi.exe:

let myFunc x y = 
  if x > y then stdout.WriteLine("greater {0} {1}",x,y);
  if x < y then stdout.WriteLine("less {0} {1}",x,y);
  if x = y then stdout.WriteLine("equal {0} {1}",x,y);

myFunc 1 4;;

The above will yield the following output using Mono 2.6.3 (tested on both
Windows 7 and Mac OS X 10.5.8/Intel):

greater 1 4
less 1 4
equal 1 4

val myFunc : 'a -> 'a -> unit when 'a : comparison

The above is incorrect.  The output should be:

less 1 4
val myFunc : 'a -> 'a -> unit when 'a : comparison

On the Microsoft CLR, the correct output is generated.

It looks like if two non-generic classes are emitted into a module, with one
containing a specialized call to a generic method defined in the other, there’s
a problem with the code generated for the specialized call.  

(To be clear, in the example above, fsi.exe will emit two classes - one with
myFunc defined as a static method, and another with a static “main” method that
calls “myFunc 1 4”.  When the fragment is evaluated, the “main” method is
called.)  Here’s a clearer example that will produce the same incorrect output:

type A() =
  member a.Foo x y =
    if x > y then stdout.WriteLine("greater {0} {1}",x,y);
    if x < y then stdout.WriteLine("less {0} {1}",x,y);
    if x = y then stdout.WriteLine("equal {0} {1}",x,y);

and B() =
  member b.Bar x y = let a = A() in a.Foo x y

let _ = let b = B() in b.Bar 1 4

And one more sample, reported by a user:

let reduce gen = 
  match gen with 
  | [_; _] -> 
     printfn "path1"
     1
  | [_] -> 
     printfn "path2"
     2
  | _ -> 
     3

printfn "result = %A" (reduce  [1;2])

In this case, the expression “reduce [1;2]” will evaluate to “path2”, where it
should evaluate to “path1”.

It’s important to note that in all of these cases, if the “call” method is
emitted separately from the generic method (that is, as two separate evaluated
expressions), the correct code will be generated.  For example: 

// evaluate the definition of myFunc
let myFunc x y = 
  if x > y then stdout.WriteLine("greater {0} {1}",x,y);
  if x < y then stdout.WriteLine("less {0} {1}",x,y);
  if x = y then stdout.WriteLine("equal {0} {1}",x,y);;

val myFunc : 'a -> 'a -> unit when 'a : comparison

// Ok, fsi.exe has evaluated it - now call it
less 1 4
val it : unit = ()

// correct!

-- 
Configure bugmail: http://bugzilla.novell.com/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the QA contact for the bug.
You are the assignee for the bug.


More information about the mono-bugs mailing list