structf#warnings

Is this an F# compiler bug? #3


Signature file Foo.fsi:

namespace FooBarSoftware
open System.Collections.Generic

[<Struct>]
type Foo<'T> =
     new: unit -> 'T Foo
     new: 'T   -> 'T Foo

     // doesn't exists in implementation!
     member public GetEnumerator: unit -> IEnumerator<'T>
     interface IEnumerable<'T>

Implementation file Foo.fs:

namespace FooBarSoftware
open System.Collections
open System.Collections.Generic

[<Struct>]
type Foo<'T> =
     val offset: int
     new (x:'T) = { offset = 1 }

     interface IEnumerable<'T> with
        member this.GetEnumerator() = null :> IEnumerator<'T>
        member this.GetEnumerator() = null :> IEnumerator

This compiles fine, but with warning FS0314:

The type definitions in the signature and implementation are not compatible because the field offset was present in the implementation but not in the signature. Struct types must now reveal their fields in the signature for the type, though the fields may still be labelled 'private' or 'internal'.

When I run the code like that, I've got MethodMissingException:

let foo = FooBarSoftware.Foo<int>() // <==

// System.MethodMissingException:
// Method not found: 'Void FooBarSoftware.Foo~1..ctor()'

Also if I use other ctor and call GetEnumerator() method:

let foo = FooBarSoftware.Foo<int>(1)
let e = foo.GetEnumerator() // <==

// System.MethodMissingException:
// Method not found: 'System.Collections.Generic.IEnumerator`1<!0>
// FooBarSoftware.Foo`1.GetEnumerator()'.

Is this an compiler bug, that allows to compile interface without implementation after getting an FS0314 warning?

Microsoft (R) F# 2.0 build 4.0.30319.1

Solution

  • Looks like a bug to me. The following runs fine.

    Signature file Foo.fsi:

    namespace FooBarSoftware
    open System.Collections.Generic
    
    //[<Struct>]
    type Foo<'T> =
         new: unit -> 'T Foo
         new: 'T   -> 'T Foo
    
         // doesn't exists in implementation!
         //member public GetEnumerator: unit -> IEnumerator<'T>
    
         interface IEnumerable<'T>
    

    Implementation file Foo.fs:

    namespace FooBarSoftware
    open System.Collections
    open System.Collections.Generic
    
    //[<Struct>]
    type Foo<'T> =
        val offset: int
        new () = { offset = 1 }
        new (x:'T) = { offset = 1 }
    
        //member this.GetEnumerator() = null :> IEnumerator<'T>
    
        interface IEnumerable<'T> with
            member this.GetEnumerator() = null :> IEnumerator<'T>
            member this.GetEnumerator() = null :> IEnumerator
    

    Test file test.fs:

    module test
    
    let foo = FooBarSoftware.Foo<int>() 
    let bar = FooBarSoftware.Foo<int>(1)
    let e = foo :> seq<_>
    

    .

    Reflector also shows .ctor() missing from your code.

    Missing Default COnstructor