这是一个F#编译器错误吗?#2

con*_*low 2 compiler-construction ienumerable f# for-loop

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
Run Code Online (Sandbox Code Playgroud)

上面的代码产生以下编译错误:

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.

代码看起来完全合法,通用版本工作正常.这是一个F#编译器错误吗?

Tom*_*cek 5

我认为这是错误消息和规范之间的不匹配.正如kvb指出的那样,规范for ... in只允许两种情况:

  • 当类型实现通用IEnumerable<_>接口(又名seq<_>)
  • 当类型具有GetEnumerator返回具有某些属性的类型的方法时

如果类型实现非泛型IEnumerable接口,则它不匹配任何两个条件.但是,如果你把它投射到IEnumerable那么它实际上是IEnumerable类型,它匹配第二个条件.GetEnumerator直接在类型中有成员(如desco建议的那样)也是正确的,因为它也匹配第二种情况.

所以,我认为错误消息是不正确的,因为它表示实现非泛型IEnumerable就足够了,但实际上并非如此.

但是,似乎有一个与for循环相关的实际编译器错误.编写以下代码时会出现编译器"内部错误"(这是不正确的,因为推断的泛型返回类型没有实现IEnumerator):

 type Foo() =
   member x.GetEnumerator () = null
 for x in Foo() do ()  // Internal error here
Run Code Online (Sandbox Code Playgroud)


des*_*sco 5

您的样本可以简化为

type Foo() =
 interface Collections.IEnumerable with
     member x.GetEnumerator () = null

for x in Foo() do ()
Run Code Online (Sandbox Code Playgroud)

最初,F#编译器尝试断言源类型正在实现IEnumerable <_>在此断言失败后 - 它搜索可访问的GetEnumerator/0方法,该方法返回具有可访问的MoveNext()/ Current成员的类型.似乎来自IEnumerable的显式实现的方法在Foo类型中是不可见的,因为下面的代码是有效的:

open System
open System.Collections

type Foo() =
    member x.GetEnumerator () : IEnumerator = null

for x in Foo() do () // GetEnumerator is accessible in Foo
Run Code Online (Sandbox Code Playgroud)

要么

open System
open System.Collections

type Foo() =
    interface IEnumerable with
        member x.GetEnumerator () : IEnumerator = null

for x in (Foo() :> IEnumerable) do () // IEnumerable has accessible GetEnumerator
Run Code Online (Sandbox Code Playgroud)