Skip to content

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

@anton-pt

Description

@anton-pt

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

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

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 accare not marked as inline

Actual behavior

Compiler infers type ^U as obj without warnings or errors.

Example 3

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'.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Feature ImprovementTheme-Simple-F#A cross-community initiative called "Simple F#", keeping people in the sweet spot of the language.

    Type

    No type

    Projects

    Status

    In Progress

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions