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

error type unification when using an opaque type #5660

Open
Anton-4 opened this issue Jul 12, 2023 · 0 comments
Open

error type unification when using an opaque type #5660

Anton-4 opened this issue Jul 12, 2023 · 0 comments

Comments

@Anton-4
Copy link
Contributor

Anton-4 commented Jul 12, 2023

This error is from a while ago but we forgot to make an issue for it

app "command-line-args"
    packages {
        pf: "https://github.com/roc-lang/basic-cli/releases/download/0.4.0/DI4lqn7LIZs8ZrCDUgLK-tHHpQmxGF1ZrlevRKq5LXk.tar.br",
    }
    imports [
        pf.Stdout,
        pf.Stderr,
        pf.File,
        pf.Path,
        pf.Task,
        pf.Arg,
    ]
    provides [main] to pf

main : Task.Task {} U32
main =
    finalTask =
        # try to read the first command line argument
        pathArg <- Task.await readFirstArgT

        readFileToStr (Path.fromStr pathArg)

    finalResult <- Task.attempt finalTask

    when finalResult is

        Err ZeroArgsGiven ->
            {} <- Stderr.line "Error ZeroArgsGiven:\n\tI expected one argument, but I got none.\n\tRun the app like this: `roc command-line-args.roc -- path/to/input.txt`" |> Task.await

            Task.fail 1

        Err (ReadFileErr errMsg) ->
            indentedErrMsg = indentLines errMsg
            {} <- Stderr.line "Error ReadFileErr:\n\(indentedErrMsg)" |> Task.await

            Task.fail 1

        Ok fileContentStr ->
            Stdout.line "file content: \(fileContentStr)"

# Task to read the first CLI arg (= Str)
readFirstArgT : Task.Task Str [ZeroArgsGiven]
readFirstArgT =
    # read all command line arguments
    args <- Arg.list |> Task.await

    # get the second argument, the first is the executable's path
    List.get args 1 |> Result.mapErr (\_ -> ZeroArgsGiven) |> Task.fromResult

# reads a file and puts all lines in one Str
readFileToStr : Path.Path -> Task.Task Str [ReadFileErr Str]
readFileToStr = \path ->
    path
    |> File.readUtf8
    # Make a nice error message 
    |> Task.mapFail
        (\fileReadErr ->
            pathStr = Path.display path
            # TODO use FileReadErrToErrMsg when it is implemented: https://github.com/roc-lang/basic-cli/issues/44
            when fileReadErr is
                FileReadErr _ readErr ->
                    readErrStr = File.readErrToStr readErr
                    ReadFileErr "Failed to read file at:\n\t\(pathStr)\n\(readErrStr)"

                FileReadUtf8Err _ _ ->
                    ReadFileErr "I could not read the file:\n\t\(pathStr)\nIt contains charcaters that are not valid UTF-8:\n\t- Check if the file is encoded using a different format and convert it to UTF-8.\n\t- Check if the file is corrupted.\n\t- Find the characters that are not valid UTF-8 and fix or remove them."
        )

# indent all lines in a Str with a single tab
indentLines: Str -> Str
indentLines = \inputStr ->
    Str.split inputStr "\n"
    |> List.map (\line -> Str.concat "\t" line)
    |> Str.joinWith "\n

Results in:

❯ ./roc_nightly/roc check examples/CommandLineArgs/main.roc 

── TYPE MISMATCH ─────────────────────────── examples/CommandLineArgs/main.roc ─

This 2nd argument to await has an unexpected type:

20│>          pathArg <- Task.await readFirstArgT
21│>
22│>          readFileToStr (Path.fromStr pathArg)

The argument is an anonymous function of type:

    Str -> Task Str [ReadFileErr Str]

But await needs its 2nd argument to be:

    Str -> Task Str [ZeroArgsGiven]


── TYPE MISMATCH ─────────────────────────── examples/CommandLineArgs/main.roc ─

This 2nd argument to attempt has an unexpected type:

24│>      finalResult <- Task.attempt finalTask
25│>
26│>      when finalResult is
27│>
28│>          Err ZeroArgsGiven ->
29│>              {} <- Stderr.line "Error ZeroArgsGiven:\n\tI expected one argument, but I got none.\n\tRun the app like this: `roc command-line-args.roc -- path/to/input.txt`" |> Task.await
30│>
31│>              Task.fail 1
32│>
33│>          Err (ReadFileErr errMsg) ->
34│>              indentedErrMsg = indentLines errMsg
35│>              {} <- Stderr.line "Error ReadFileErr:\n\(indentedErrMsg)" |> Task.await
36│>
37│>              Task.fail 1
38│>
39│>          Ok fileContentStr ->
40│>              Stdout.line "file content: \(fileContentStr)"

The argument is an anonymous function of type:

    [
        Err [
            ReadFileErr Str,
            ZeroArgsGiven,
        ],
        Ok Str,
    ] -> Task {} (Num *)

But attempt needs its 2nd argument to be:

    Result Str [ZeroArgsGiven]* -> Task {} (Num *)

────────────────────────────────────────────────────────────────────────────────

2 errors and 0 warnings found in 40 ms.

Using roc from commit 8a3d07c

No errors should be returned here.

Explanation and workaround by Ayaz:

it's because Task.Task is an opaque type, and not all tag unions can be open-by-default-in-output position under an opaque type (but type parameters like the tags here should be). I'll file an issue, but in the meantime you can work around this by saying [ZeroArgsGiven]_ and [ReadFileErr Str]_.

zulip conversation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant