Skip to content

The compiler infers the wrong type. #1287

@gusty

Description

@gusty

In some situations the compiler tries to unify a type argument contained in a generic type with the generic type itself.

Repro steps

open System
open System.Collections.Generic

let pInt = Int32.TryParse >> function (true, x) -> Some x | _ -> None 

let pString (x:string) = 
    match x.Trim() with
    | x when x.[0..0] = "\"" && x.[x.Length-1..x.Length-1] = "\"" -> Some x.[1..x.Length-2]
    | _ -> None 

let pTuple2 p1 p2 (x:string) =
    match x.Trim() with
    | x when x.[0..0] = "(" && x.[x.Length-1..x.Length-1] = ")" -> 
        let x = x.[1..x.Length-2]
        match x.Split(',') with
        | [|a; b|] -> match (p1 a, p2 b) with (Some a, Some b) -> Some (a, b) | _ -> None
        | _ -> None
    | _ -> None 

let pList (p:string -> 'a option) (x:string) =
    match x.Trim() with
    | x when x.[0..0] = "[" && x.[x.Length-1..x.Length-1] = "]" -> 
        let x = x.[1..x.Length-2]
        let x = x.Split(';') |> Array.map p
        if x |> Array.forall (fun x -> x.IsSome) then
            Some (Array.choose id x |> Array.toList)
        else None
    | _ -> None

type TryParseCs = TryParseCs with        
    static member TryParse (_: int   ) = pInt    
    static member TryParse (_: string) = pString

let inline iTryParse (a: ^a, b: ^b) =  ((^a or ^b) : (static member TryParse: ^b -> (string -> ^b option)) b)
let inline tryParse (x: string) : 'a option = iTryParse (TryParseCs, Unchecked.defaultof<'a>) x

type TryParseCs with
    static member inline TryParse (_: IDictionary<string, 'a>) : string -> option<IDictionary<string, 'a>> =
        pList (pTuple2 pString tryParse) >> function
        | Some x -> Some (dict x )
        | _ -> None

    static member inline TryParse (_: 'a ResizeArray) : string -> option<'a ResizeArray> = pList tryParse >> function
        | Some x -> Some (ResizeArray<_>(x))
        | _ -> None

Expected behavior

val inline tryParse :
  x:string ->  ^a option
    when (TryParseCs or  ^a) : (static member TryParse :  ^a ->
                                                       string ->
                                                          ^a option)

Actual behavior

It doesn't compile

~vs4AFB.fsx(43,98): error FS0043: Type mismatch. Expecting a
    string -> 'a option    
but given a
    string -> ResizeArray<'a> option    
The resulting type would be infinite when unifying ''a' and 'ResizeArray<'a>'

Known workarounds

At the end of the code add this overload:

static member TryParse (_: 'a Tuple) : string -> option<Tuple<'a>> = fun _ -> Some (Tuple<'a>(Unchecked.defaultof<'a>))

Related information

This was reported as a bug in Fleece.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Area-Compiler-SRTPbugs in SRTP inference, resolution, witness passing, code genBugImpact-Low(Internal MS Team use only) Describes an issue with limited impact on existing code.

    Type

    No fields configured for Bug.

    Projects

    Status

    In Progress

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions