Wrong type inference when using extension method for generic GetEnumerator
- Dominant language
- F#
- Stars
- 4.3k
- Forks
- 876
- Avg merge
- 4d 11h
- Merged PRs (30d)
- 131
Description
Given a generic type `GenericType<'T>` that supports the collection-pattern (`GetEnumerator` without `seq<_>`):
- using a generic enumerator (`Current` is `'T`)
- but defining `GetEnumerator` as an extension method,
iterating such collection with `for` causes the compiler to assign a fresh type to the extracted value, instead of inferring `'T`.
Both F#-style and C#-style extension methods fail the same way.
**Repro steps**
Minimal repro script:
```fsharp
type GenericType<'T> = { Value : 'T }
module OtherModule =
type Enumerator<'T>(gen : GenericType<'T>) =
member __.Current = gen.Value
member __.MoveNext() = true
type GenericType<'T> with
member this.GetEnumerator() = Enumerator(this)
// x should be int, but string is inferred
for x in { Value = 2 } do printfn "%s" x
```
**Expected behavior**
The extracted value `x` at the `for` should be inferred as the same type as the enumerator's `Current` property, `int`.
**Actual behavior**
The extracted value is inferred as a fresh type, allowing it to be constrained to the wrong type, `string`. According to the spec, this behaviour should only happen if `Current` has type `obj` and the collection type has an `Item` property of more specific type.
**Known workarounds**
Defining `GetEnumerator` as a non-extension method works correctly.
**Related information**
.NET Core SDK 3.0.100-preview5-011568
Found this while trying a proof of concept of Option enumerators, as an alternative to a closed language proposal.
Contributor guide
Assessment
This issue has not been assessed yet.