Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Error Reporting: Make FS0072 less intimidating. #13013

Open
Tracked by #1103
isaacabraham opened this issue Apr 19, 2022 · 2 comments
Open
Tracked by #1103

Improve Error Reporting: Make FS0072 less intimidating. #13013

isaacabraham opened this issue Apr 19, 2022 · 2 comments
Labels
Area-Diagnostics mistakes and possible improvements to diagnostics Feature Request Theme-Simple-F# A cross-community initiative called "Simple F#", keeping people in the sweet spot of the language.
Milestone

Comments

@isaacabraham
Copy link
Contributor

isaacabraham commented Apr 19, 2022

What

The following code leads to the following error:

let bar foo =
    let age = foo.Bar + 99
    age * 2

Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.

Why

The message is overly verbose and complicated, using words like "indeterminate" and so on. In reality, all we're trying to say is: "I couldn't infer what this type is! Please add an annotation to tell me directly.". We could also provide some guidance to explain that the compiler cannot generally infer types from C#.

How

How about:

Unable to infer the type of foo. Please add a type annotation where foo is declared e.g. (foo:string).

or

It is unclear what type foo is. Please add a type annotation where foo is declared e.g. (foo:string).

We could also add some "background" information as well:

Unable to infer the type of foo. Please add a type annotation where foo is declared e.g. (foo:string). F# can only directly infer from member usage types that are defined in F#; if the type of foo is defined in a C# library (including anything from the Base Class Library e.g. string), F# will not be able to infer it based on a member access.

@dsyme dsyme added Area-Diagnostics mistakes and possible improvements to diagnostics Theme-Simple-F# A cross-community initiative called "Simple F#", keeping people in the sweet spot of the language. labels Apr 20, 2022
@vzarytovskii vzarytovskii moved this to Not Planned in F# Compiler and Tooling Jun 17, 2022
@pbachmann
Copy link

Yes.
I love type inferencing but I also love the intellisense you get with member access and I want to define types that support both. Now if I can't have both, the least the compiler can do is say so plainly so that I don't become confused and frustrated by the endless pursuit of a pipe dream.

@pbachmann
Copy link

@isaacabraham I agreed with you completely previously, but now I've changed my mind somewhat. The example code below seems it was misleading for you to suggest:

"F# can only directly infer from member usage types that are defined in F#; if the type of foo is defined in a C# library (including anything from the Base Class Library e.g. string), F# will not be able to infer it based on a member access."

ie. All the code below is in F# and still the type inferencing doesn’t work. Of course, your experience is much greater than mine and you may have other examples that invalidate my assessment.

I think the key to getting this error message right is prompting devs to stop wasting time pursuing the illusory goal of universal type inferencing.

How about:

“Due to limitations in F#’s type inferencing, especially when using member access, a type annotation may be needed prior to this point in the program.” ?

type Database = { Conn: SqliteConnection } with
    static member Init =
        let ret = { Conn = new SqliteConnection("Data Source=:memory:") }
        ret.Conn.Open()
        ret.Action "create table obs(ID int);"
        ret

    member this.Get sql =
        let cmd = this.Conn.CreateCommand()
        cmd.CommandText <- sql
        cmd.ExecuteScalar()

    member this.Action sql =
        let cmd = this.Conn.CreateCommand()
        cmd.CommandText <- sql
        let x = cmd.ExecuteNonQuery()
        ()

let SqlGet db sql =
    let cmd = db.Conn.CreateCommand()
    cmd.CommandText <- sql
    cmd.ExecuteScalar()

let SqlAction db sql =
    let cmd = db.Conn.CreateCommand()
    cmd.CommandText <- sql
    cmd.ExecuteNonQuery() |> ignore

let db = Database.Init

let TestDb db = 
    //db.Action "insert into obs values(1)" !!! only compiles with db parameter having type annotation (db:Database)
    //db.Get "select count(*) from obs"
    SqlAction db "insert into obs values(1)" // Works just fine
    SqlGet db "insert into obs values(1)"

printfn "result: %A"  (TestDb db)

@vzarytovskii vzarytovskii added this to the Backlog milestone Sep 21, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Diagnostics mistakes and possible improvements to diagnostics Feature Request Theme-Simple-F# A cross-community initiative called "Simple F#", keeping people in the sweet spot of the language.
Projects
Status: New
Development

No branches or pull requests

4 participants