Implements the new app header syntax as discussed in Zulip [1].
app [main] {
cli: platform "../platform/main.roc",
json: "../json/main.roc"
}
Old headers still parse and are automatically upgraded to the new
syntax by the formatter.
[1] 418444862
We will now show a warning if a builtin is imported explicitly,
since this is unncessary.
We will not show the warning if they expose functions from the builtin:
import Dict exposing [isEmpty]
However, we will show a special warning if they expose types from it:
import Dict exposing [Dict, isEmpty]
If we exposed a symbol in an import and used it both unqualified
and qualified, we'd produce an unused warning false positive.
This happened because we were using a single bit flag to determine
whether a value was used qualified or unqualified.
We were still passing `ModuleIds` from `load` to `can`, but now
that imports can appear in any scope, we don't know which package
an unqualified module name belongs to from the top level.
We now pass `PackageModuleIds` instead and keep a Map of `ModuleName` to
`ModuleId` in `Scope`.
This also allow us to import multiple modules with the same name from different
packages as long as a unique alias is provided.
Allows a module to be imported with an alias:
import JsonDecode as JD
Import aliases must be unique and they cannot have the same name
as an imported module.
Moves handling of ingested file imports from load to can, so that they
can be properly introduced in the scope they appear.
Example:
import "input.txt" as input : Str
image =
import "image.png" as bytes : List U8
# `bytes` is only available under `image`
decodePng bytes
...
Now that imports can be limited to smaller scopes than the entire module,
unused import warnings need to work like unused def warnings.
This commit moves unused import warnings discovery and reporting from load
to canonicalization where we can track their usage per scope.
This also fixes a longstanding bug where unused exposed names from an import
were not reported if they were only used in a qualified manner.
After parsing a module, we now recursively traverse the tree to find
all imports inside Defs, not just the top-level ones.
Previously, imported modules were available in the entire file,
but that's no longer the case. Therefore, Scope now keeps track of
imported modules and Env::qualified_lookup checks whether a module
is available in the provided scope.
Note: Unused import warnings are still global and need to be updated.
Previously, all imports were available in the header, so we could start
processing dependencies as soon as we parsed it. However, the new imports
are treated as defs, so we have to parse the whole module to find them.
This commit essentially moves the dependency resolution from the `LoadHeader`
phase to the `Parse` phase, and it updates canonicalization to introduce
module symbols into scope when a `ValueDef::ModuleImport` is encountered.
NOTE:
- The `imports` header still parses, but it's no longer wired up. I will remove
it in an upcoming commit.
- Ingested files and imports that appear in nested expressions are not
yet supported by load