fsharp icon indicating copy to clipboard operation
fsharp copied to clipboard

One of our negative test cases had an error that changed from attractive to spaghetti

Open KevinRansom opened this issue 2 years ago • 1 comments

The error produced by:

module Applicatives =
    open System

    type Ap = Ap with
        static member inline Invoke (x:'T) : '``Applicative<'T>`` =
            let inline call (mthd : ^M, output : ^R) = ((^M or ^R) : (static member Return: _*_ -> _) output, mthd)
            call (Ap, Unchecked.defaultof<'``Applicative<'T>``>) x 
        static member inline InvokeOnInstance (x:'T) = (^``Applicative<'T>`` : (static member Return: ^T -> ^``Applicative<'T>``) x)
        static member inline Return (r:'R       , _:obj) = Ap.InvokeOnInstance      :_ -> 'R
        static member        Return (_:seq<'a>  , Ap   ) = fun x -> Seq.singleton x : seq<'a>
        static member        Return (_:Tuple<'a>, Ap   ) = fun x -> Tuple x         : Tuple<'a>
        static member        Return (_:'r -> 'a , Ap   ) = fun k _ -> k             : 'a  -> 'r -> _

    let inline result (x:'T) = Ap.Invoke x

    let inline (<*>) (f:'``Applicative<'T->'U>``) (x:'``Applicative<'T>``) : '``Applicative<'U>`` = 
        (( ^``Applicative<'T->'U>`` or ^``Applicative<'T>`` or ^``Applicative<'U>``) : (static member (<*>): _*_ -> _) f, x)

    let inline (+) (a:'Num) (b:'Num) :'Num = a + b

    type ZipList<'s> = ZipList of 's seq with
        static member Return (x:'a)                              = ZipList (Seq.initInfinite (fun _ -> x))
        static member (<*>) (ZipList (f:seq<'a->'b>), ZipList x) = ZipList (Seq.zip f x |> Seq.map (fun (f, x) -> f x)) :ZipList<'b>

    type Ii = Ii
    type Idiomatic = Idiomatic with
        static member inline ($) (Idiomatic, si) = fun sfi x -> (Idiomatic $ x) (sfi <*> si)
        static member        ($) (Idiomatic, Ii) = id
    let inline idiomatic a b = (Idiomatic $ b) a
    let inline iI x = (idiomatic << result) x

    let res1n2n3 = iI (+) (result          0M                  ) (ZipList [1M;2M;3M]) Ii
    let res2n3n4 = iI (+) (result LanguagePrimitives.GenericOne) (ZipList [1 ;2 ;3 ]) Ii

repro:

c:\kevinransom\fsharp>fsc C:\kevinransom\fsharp\tests\fsharp\typecheck\sigs\neg119a.fs --langversion:6.0
Microsoft (R) F# Compiler version 12.0.6.0 for F# 6.0
Copyright (c) Microsoft Corporation. All Rights Reserved.

C:\kevinransom\fsharp\tests\fsharp\typecheck\sigs\neg119.fs(40,20): error FS0071: Type constraint mismatch when applying the default type 'obj' for a type inference variable. No overloads match for method 'Return'.

Known return type: ((int -> int -> int) -> obj)

Known type parameters: < obj , Applicatives.Ap >

Available overloads:
 - static member Applicatives.Ap.Return: ('r -> 'a) * Ap: Applicatives.Ap -> (('a -> 'r -> 'a2) -> 'a3 -> 'a -> 'r -> 'a2) // Argument at index 1 doesn't match
 - static member Applicatives.Ap.Return: System.Tuple<'a> * Ap: Applicatives.Ap -> ('a -> System.Tuple<'a>) // Argument at index 1 doesn't match
 - static member Applicatives.Ap.Return: r: ^R * obj -> ('a1 -> ^R) when ^R: (static member Return: 'a1 -> ^R) // Argument 'r' doesn't match
 - static member Applicatives.Ap.Return: seq<'a> * Ap: Applicatives.Ap -> ('a -> seq<'a>) // Argument at index 1 doesn't match Consider adding further type constraints
c:\kevinransom\fsharp>fsc C:\kevinransom\fsharp\tests\fsharp\typecheck\sigs\neg119.fs --langversion:preview
Microsoft (R) F# Compiler version 12.0.6.0 for F# 6.0
Copyright (c) Microsoft Corporation. All Rights Reserved.

C:\kevinransom\fsharp\tests\fsharp\typecheck\sigs\neg119.fs(40,9): error FS0030: Value restriction. The value 'res2n3n4' has been inferred to have generic type
    val res2n3n4: ^_a when (^_b or Applicatives.ZipList<int> or ^_a) : (static member (<*>) : ^_b * Applicatives.ZipList<int> -> ^_a) and (^_c or obj or ^_b) : (static member (<*>) : ^_c * obj -> ^_b) and (Applicatives.Ap or ^_c) : (static member Return: ^_c * Applicatives.Ap -> ((int -> int -> int) -> ^_c))
Either define 'res2n3n4' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation.

Do you see what I mean? The error may be more accurate, but probably needs formatting to make it readable by a tiny brain like myself.

neg119.fs is being renamed to neg119a.fs in a forthcoming pr, so, try that if you get file not found.

KevinRansom avatar Aug 15 '22 22:08 KevinRansom

How do you like this formatting?

Value restriction. The value 'res2n3n4' has been inferred to have generic type
    val res2n3n4: ^_a when (^_b or Applicatives.ZipList<int> or ^_a) : (static member (<*>) : ^_b * Applicatives.ZipList<int> -> ^_a)
                  and (^_c or obj or ^_b) : (static member (<*>) : ^_c * obj -> ^_b)
                  and (Applicatives.Ap or ^_c) : (static member Return: ^_c * Applicatives.Ap -> ((int -> int -> int) -> ^_c))    
Either define 'res2n3n4' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation.

https://github.com/dotnet/fsharp/pull/13727

0101 avatar Aug 18 '22 13:08 0101