-
Notifications
You must be signed in to change notification settings - Fork 832
Open
Labels
Area-Compiler-SRTPbugs in SRTP inference, resolution, witness passing, code genbugs in SRTP inference, resolution, witness passing, code genBugImpact-Low(Internal MS Team use only) Describes an issue with limited impact on existing code.(Internal MS Team use only) Describes an issue with limited impact on existing code.
Milestone
Description
By accident I discovered a situation where a dynamic invocation error is thrown at run-time, instead of failing compilation.
Repro steps
type Default1 = obj
type Map =
static member Map ((x: option<_>, f: 'T->'U), _mthd: Map) = Option.map f x
static member Map ((x: list<_> , f: 'T->'U), _mthd: Map) = List.map f x : list<'U>
static member inline Invoke (mapping: 'T->'U) (source: '``Functor<'T>``) : '``Functor<'U>`` =
let inline call (mthd: ^M, source: ^I, _output: ^R) = ((^M or ^I or ^R) : (static member Map : (_*_)*_ -> _) (source, mapping), mthd)
call (Unchecked.defaultof<Map>, source, Unchecked.defaultof<'``Functor<'U>``>)
type Bimap =
static member Bimap (x: Result<'T2, 'T1>, f: 'T1->'U1, g: 'T2->'U2, _mthd: Bimap) = match x with Ok x -> Ok (g x) | Error x -> Error (f x)
static member Bimap (x: Choice<'T2, 'T1>, f: 'T1->'U1, g: 'T2->'U2, _mthd: Bimap) = match x with Choice1Of2 x -> Choice1Of2 (g x) | Choice2Of2 x -> Choice2Of2 (f x)
static member inline Invoke (f: 'T->'U) (g: 'V->'W) (source: '``Bifunctor<'T,'V>``) : '``Bifunctor<'U,'W>`` =
let inline call (mthd: ^M, source: ^I, _output: ^R) = ((^M or ^I or ^R) : (static member Bimap : _*_*_*_ -> _) source, f, g, mthd)
call (Unchecked.defaultof<Bimap>, source, Unchecked.defaultof<'``Bifunctor<'U,'W>``>)
type Bitraverse =
static member inline Bitraverse (x: Result<'T1,'Error1>, f: 'Error1->'``Functor<'Error2>``, g: 'T1->'``Functor<'T2>``, _impl: Bitraverse) : '``Functor<Result<'Error2,'T2>>`` = match x with Ok a -> Map.Invoke Result<'Error2,'T2>.Ok (g a) | Error e -> Map.Invoke Result<'Error2,'T2>.Error (f e)
static member inline Bitraverse (x: Choice<'T1,'Error1>, f: 'Error1->'``Functor<'Error2>``, g: 'T1->'``Functor<'T2>``, _impl: Bitraverse) : '``Functor<Choice<'Error2,'T2>>`` = match x with Choice1Of2 a -> Map.Invoke Choice<'Error2,'T2>.Choice1Of2 (g a) | Choice2Of2 e -> Map.Invoke Choice<'Error2,'T2>.Choice2Of2 (f e)
static member inline Invoke (f: 'T1->'``Functor<'T2>``) (g: 'U1->'``Functor<'U2>``) (source: '``Bitraversable<'T1,'U1>``) : '``Functor<'Bitraversable<'T2,'U2>>`` =
let inline call (a: ^a, b: ^b, _: 'r) = ((^a or ^b or ^r) : (static member Bitraverse : _*_*_*_ -> _) b,f,g,a)
call (Unchecked.defaultof<Bitraverse>, source, Unchecked.defaultof<'``Functor<'Bitraversable<'T2,'U2>>``>)
type Bisequence =
static member inline Bisequence (x: Result<'``Functor<'Error>``, '``Functor<'T>``>, _impl: Bisequence) : '``Functor<Result<'Error,'T>>`` = match x with Ok a -> Map.Invoke Result<'Error,'T>.Ok a | Error e -> Map.Invoke Result<'Error,'T>.Error e
static member inline Bisequence (x: Choice<'``Functor<'Error>``, '``Functor<'T>``>, _impl: Bisequence) : '``Functor<Choice<'Error,'T>>`` = match x with Choice1Of2 a -> Map.Invoke Choice<'Error,'T>.Choice1Of2 a | Choice2Of2 e -> Map.Invoke Choice<'Error,'T>.Choice2Of2 e
static member inline Invoke (source: '``Bitraversable<'Functor<'T>,'Functor<'U>>``) : '``Functor<'Bitraversable<'T,'U>>`` =
let inline call (a: ^a, b: ^b, _: 'r) = ((^a or ^b or ^r) : (static member Bisequence : _*_ -> _) b, a)
call (Unchecked.defaultof<Bisequence>, source, Unchecked.defaultof<'``Functor<'Bitraversable<'T,'U>>``>)
static member inline InvokeOnInstance (source: '``Bitraversable<'Functor<'T>,'Functor<'U>>``) : '``Functor<'Bitraversable<'T,'U>>`` =
(^``Bitraversable<'Functor<'T>,'Functor<'U>>`` : (static member Bisequence : _ -> _) source)
type Bitraverse with
static member inline Bitraverse (x: '``Bitraversable<'T1,'U1>``, f: 'T1->'``Functor<'T2>``, g: 'U1->'``Functor<'U2>``, _impl: Default1) =
printfn "Using Default"
Bimap.Invoke f g x |> Bisequence.InvokeOnInstance : '``Functor<'Bitraversable<'T2,'U2>>``
type Either<'left,'right> = Left of 'left | Right of 'right with
static member inline Bisequence x = match x with Right a -> Map.Invoke Either<'Left,'Right>.Right a | Left e -> Map.Invoke Either<'Left,'Right>.Left e
static member inline Bimap (x, f, g) = match x with Right a -> Right (f a) | Left e -> Left (g e)
let _failureBad: Either<string, int> list = Bitraverse.Invoke id id (Left ["Bad"])
// this gives a better error
// let _failureBad: Either<string, int> list = Bimap.Invoke id id (Left ["Bad"]) |> Bisequence.InvokeOnInstance
Expected behavior
Either to fail compilation, or succeed but without run-time errors.
I understand that maybe type inference is not able to solve in some cases like this, but if that's the case, it should fail at compiler-time.
Also, I don't understand why there's a dynamic invocation involved in these static calls.
Actual behavior
Compiles but fails at run-time with
>
Using Default
> System.NotSupportedException: Dynamic invocation of Bisequence is not supported
at <StartupCode$FSI_0005>.$FSI_0005.main@() in C:\Users\gmpl2\AppData\Local\Temp\~vs7011.fsx:line 51
Stopped due to error
Known workarounds
There are many workarounds, just change a bit the code, for instance invoking the Bimap member directly on instances, avoiding the or constraint.
Related information
F# Interactive version 10.7.0.0 for F# 4.7
abelbraaksma
Metadata
Metadata
Assignees
Labels
Area-Compiler-SRTPbugs in SRTP inference, resolution, witness passing, code genbugs in SRTP inference, resolution, witness passing, code genBugImpact-Low(Internal MS Team use only) Describes an issue with limited impact on existing code.(Internal MS Team use only) Describes an issue with limited impact on existing code.
Type
Projects
Status
New