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 ... inin only two cases:IEnumerable<_>interface (akaseq<_>)GetEnumeratormethod that returns type with certain propertiesIf the type implements a non-generic
IEnumerableinterface then it doesn’t match any of the two conditions. However, if you cast it toIEnumerablethen it will actually be theIEnumerabletype, which matches the second condition. Having aGetEnumeratormember 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
IEnumerableis sufficient, but it is actually not.However, there seems to be one actual compiler error related to the
forloop. You get a compiler “internal error” when you write the following code (which is not correct, because the inferred generic return type doesn’t implementIEnumerator):