open System
type Foo() =
interface Collections.IEnumerable with
member x.GetEnumerator () = null
type Bar() =
interface Collections.IEnumerable with
member x.GetEnumerator () = null
interface Collections.Generic.IEnumerable<int> with
member x.GetEnumerator () = null
let xs, ys = Foo(), Bar()
for x in xs do () // <--
for y in ys do () // fine
The code above produces the following compilation error:
The type 'Foo' is not a type whose values can be enumerated with this syntax, i.e. is not compatible with either seq<_>, IEnumerable<_> or IEnumerable and does not have a GetEnumerator method.
The code looks perfectly legal and the generic version works fine. Is this an F# compiler bug?
I think this is a mismatch between the error message an the specification. As kvb points out, the specification allows for ... in
in only two cases:
IEnumerable<_>
interface (aka seq<_>
)GetEnumerator
method that returns type with certain propertiesIf the type implements a non-generic IEnumerable
interface then it doesn't match any of the two conditions. However, if you cast it to IEnumerable
then it will actually be the IEnumerable
type, which matches the second condition. Having a GetEnumerator
member directly in the type (as desco suggests) is also correct, because it also matches the second case.
So, I think that the error message is incorrect, because it says that implementing non-generic IEnumerable
is sufficient, but it is actually not.
However, there seems to be one actual compiler error related to the for
loop. You get a compiler "internal error" when you write the following code (which is not correct, because the inferred generic return type doesn't implement IEnumerator
):
type Foo() =
member x.GetEnumerator () = null
for x in Foo() do () // Internal error here