dotnet / dotnet/fsharp

Improve error reporting: suggest inlining when compiler constrains types to be less generic

Open
#1,160 6 comments 3 reactions 0 assignees View on GitHub
Feature Improvement Theme-Simple-F#
Dominant language
F#
Stars
4.3k
Forks
876
Avg merge
4d 11h
Merged PRs (30d)
131

Description

Error messages on functions with generic type constraints can be quite misleading, especially when the solution is to mark a function as inline. Three different (but related) cases of poor messages are shown below:
### Example 1

``` fsharp
let averageBy (f : 'T -> ^U) (source : seq<'T>) : ^U =
let inline acc (sum, count) el = (Checked.(+) sum (f el), count + 1)
let (sum, count) = Seq.fold acc ((LanguagePrimitives.GenericZero< (^U) >), 0) source
LanguagePrimitives.DivideByInt sum count
```
#### Expected behavior

Compiler warning: `Checked.(+)` is inferred to have default type of `int` rather than `^U` because `averageBy` is not marked as inline.
#### Actual behavior

Compiler error on `Checked.(+)`:

```
Type constraint mismatch when applying the default type 'int' for a type inference variable. The type 'int' does not support the operator 'DivideByInt' Consider adding further type constraints.
```
### Example 2

``` fsharp
let averageBy (f : 'T -> ^U) (source : seq<'T>) : ^U =
let acc (sum, count) el = (Checked.(+) sum (f el), count + 1)
let (sum, count) = Seq.fold acc ((LanguagePrimitives.GenericZero< (^U) >), 0) source
LanguagePrimitives.DivideByInt sum count
```
#### Expected behavior

Compiler warning: `Checked.(+)` is inferred to have default type of `int` rather than `^U` because `averageBy` and/or `acc`are not marked as inline
#### Actual behavior

Compiler infers type `^U` as `obj` without warnings or errors.
### Example 3

``` fsharp
let averageBy (f : 'T -> ^U) (source : seq<'T>) : ^U =
let inline acc (sum, count) el = (Checked.(+) sum (f el), count + 1)
let (sum, count) = Seq.fold acc ((LanguagePrimitives.GenericZero< (^U) >), 0) source
Unchecked.defaultof<_> // TODO: finish implementation
```
#### Expected behavior

Compiler warning: `Checked.(+)` is inferred to have default type of `int` rather than `^U` because `averageBy` and is not marked as inline
#### Actual behavior

Compiler warning on `Checked.(+)`:

```
This construct causes code to be less generic than indicated by the type annotations. The type variable 'U has been constrained to be type 'int'.
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.