Why is is the compiler telling me "Type misMatch for App message" when they are the same type

75 Views Asked by At

So, I've been fighting with the compiler on a type error.

This code was working as of a couple days ago.

Type misMatch for App level message

App.fs snippets

module App =
    type Msg =
        | ConnectionPageMsg of ConnectionPage.Msg
        | CodeGenPageMsg of CodeGenPage.Msg
//...
    let update (msg : Msg) (model : Model) =
        match msg with
        | ConnectionPageMsg msg ->
            let m, cmd = ConnectionPage.update msg model.ConnectionPageModel
            { model with ConnectionPageModel = m }, cmd
        | CodeGenPageMsg msg ->
            let m, cmd = CodeGenPage.update msg model.CodeGenPageModel
            { model with CodeGenPageModel = m }, cmd
//...
    let runner =
        Program.mkProgram init update view
        |> Program.withConsoleTrace
        |> XamarinFormsProgram.run app

I've added explicit aliases and the original error :

Type mismatch. Expecting a
    'App.Msg -> App.Model -> App.Model * Cmd<App.Msg>'    
but given a
    'App.Msg -> App.Model -> App.Model * Cmd<Msg>'    
The type 'App.Msg' does not match the type 'Msg'

Became these:

App.fs(50,50): Error FS0001: The type 'PocoGen.Page.ConnectionPage.Msg' does not match the type 'PocoGen.Page.CodeGenPage.Msg' (FS0001) (PocoGen)
App.fs(32,32): Error FS0001: Type mismatch. 
Expecting a 'App.Msg -> App.Model -> App.Model * Cmd<App.Msg>'    
but given a 'App.Msg -> App.Model -> App.Model * Cmd<Msg>'    
The type 'App.Msg' does not match the type 'Msg' (FS0001) (PocoGen)

Other remarks

Right before these errors started appearing I was working on converting a blocking syncronous call to a async command in the ConnectionTestPage and removed the calling code for the cmd hoping that would fix it. (It did not)

ConnectionPage.fs Messages

type Msg =
    | UpdateConnectionStringValue of string
    | UpdateConnectionStringName of string
    | TestConnection
    | TestConnectionComplete of Model
    | SaveConnectionString of ConnectionStringItem
    | UpdateOutput of string

ConnectionPage.fs update

let update (msg : Msg) (m : Model) : Model * Cmd<Msg> =
    match msg with
    | UpdateConnectionStringValue conStringVal ->
        { m with
              ConnectionString =
                  { Id = m.ConnectionString.Id
                    Name = m.ConnectionString.Name
                    Value = conStringVal }
              CurrentFormState =
                  match hasRequredSaveFields m.ConnectionString with
                  | false -> MissingConnStrValue
                  | _ -> Valid }, Cmd.none

    | UpdateConnectionStringName conStringName ->
        { m with
              ConnectionString =
                  { Id = m.ConnectionString.Id
                    Name = conStringName
                    Value = m.ConnectionString.Value }
              CurrentFormState =
                  match hasRequredSaveFields m.ConnectionString with
                  | false -> MissingConnStrValue
                  | _ -> Valid }, Cmd.none

    | UpdateOutput output -> { m with Output = output }, Cmd.none
    | TestConnection -> m, Cmd.none
    | TestConnectionComplete testResult -> { m with Output = testResult.Output + "\r\n" }, Cmd.none
    | SaveConnectionString(_) -> saveConnection m, Cmd.none

I've played with the Fsharp Version (because incidentally I did update to 4.7.2 a bit before getting this error)

The Full Repo:

https://github.com/musicm122/PocoGen_Fsharp/tree/master/PocoGen

1

There are 1 best solutions below

1
On BEST ANSWER

The two branches of the match inside App.update have different types. The first branch has type App.Model * Cmd<ConnectionPage.Msg> and the second page has type App.Model * Cmd<CodeGenPage.Msg>.

You can't generally do that. This, for example, wouldn't compile:

let x = 
    match y with
    | true -> 42
    | false -> "foo"

What type is x here? Is it int or is it string? Doesn't compute. A match expression has to have all branches of the same type.


To convert Cmd<ConnectionPage.Msg> into a Cmd<App.Msg> (by wrapping the message in ConnectionPageMsg) you can use Cmd.map:

let update (msg : Msg) (model : Model) =
    match msg with
    | ConnectionPageMsg msg ->
        let m, cmd = ConnectionPage.update msg model.ConnectionPageModel
        { model with ConnectionPageModel = m }, Cmd.map ConnectionPageMsg cmd
    | CodeGenPageMsg msg ->
        let m, cmd = CodeGenPage.update msg model.CodeGenPageModel
        { model with CodeGenPageModel = m }, Cmd.map CodeGenPageMsg cmd