Fix package module resolution in inline imports

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.
This commit is contained in:
Agus Zubiaga 2024-03-31 21:10:14 -03:00
parent 842a256907
commit 1f347f6ca1
No known key found for this signature in database
13 changed files with 398 additions and 309 deletions

View file

@ -11,7 +11,7 @@ use roc_can::scope::Scope;
use roc_collections::all::{ImMap, MutMap, SendSet};
use roc_constrain::expr::constrain_expr;
use roc_derive::SharedDerivedModule;
use roc_module::symbol::{IdentIds, Interns, ModuleId, ModuleIds};
use roc_module::symbol::{IdentIds, Interns, ModuleId, ModuleIds, PQModuleName, PackageModuleIds};
use roc_parse::parser::{SourceError, SyntaxError};
use roc_problem::can::Problem;
use roc_region::all::Loc;
@ -154,10 +154,10 @@ pub fn can_expr_with<'a>(
let var = var_store.fresh();
let var_index = constraints.push_variable(var);
let expected = constraints.push_expected_type(Expected::NoExpectation(var_index));
let mut module_ids = ModuleIds::default();
let mut module_ids = PackageModuleIds::default();
// ensure the Test module is accessible in our tests
module_ids.get_or_insert(&"Test".into());
module_ids.get_or_insert(&PQModuleName::Unqualified("Test".into()));
// Desugar operators (convert them to Apply calls, taking into account
// operator precedence and associativity rules), before doing other canonicalization.
@ -174,10 +174,15 @@ pub fn can_expr_with<'a>(
arena.alloc("TestPath"),
);
let mut scope = Scope::new(home, IdentIds::default(), Default::default());
let mut scope = Scope::new(
home,
"TestPath".into(),
IdentIds::default(),
Default::default(),
);
let dep_idents = IdentIds::exposed_builtins(0);
let mut env = Env::new(arena, home, &dep_idents, &module_ids);
let mut env = Env::new(arena, home, &dep_idents, &module_ids, None);
let (loc_expr, output) = canonicalize_expr(
&mut env,
&mut var_store,
@ -204,7 +209,7 @@ pub fn can_expr_with<'a>(
all_ident_ids.insert(home, scope.locals.ident_ids);
let interns = Interns {
module_ids: env.module_ids.clone(),
module_ids: env.qualified_module_ids.clone().into_module_ids(),
all_ident_ids,
};

View file

@ -4921,19 +4921,21 @@ mod test_reporting {
r#"
app "dict" imports [ Dict ] provides [main] to "./platform"
import Dict
myDict : Dict.Dict Num.I64 Str
myDict = Dict.insert (Dict.empty {}) "foo" 42
main = myDict
"#
),
@r#"
@r###"
TYPE MISMATCH in /code/proj/Main.roc
Something is off with the body of the `myDict` definition:
3 myDict : Dict.Dict Num.I64 Str
4 myDict = Dict.insert (Dict.empty {}) "foo" 42
5 myDict : Dict.Dict Num.I64 Str
6 myDict = Dict.insert (Dict.empty {}) "foo" 42
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This `insert` call produces:
@ -4943,7 +4945,7 @@ mod test_reporting {
But the type annotation on `myDict` says it should be:
Dict I64 Str
"#
"###
);
test_report!(
@ -10898,7 +10900,9 @@ In roc, functions are always written as a lambda, like{}
function_cannot_derive_encoding,
indoc!(
r#"
app "test" imports [Decode.{decoder}] provides [main] to "./platform"
app "test" imports [] provides [main] to "./platform"
import Decode exposing [decoder]
main =
myDecoder : Decoder (a -> a) fmt where fmt implements DecoderFormatting
@ -10907,12 +10911,12 @@ In roc, functions are always written as a lambda, like{}
myDecoder
"#
),
@r"
@r###"
TYPE MISMATCH in /code/proj/Main.roc
This expression has a type that does not implement the abilities it's expected to:
5 myDecoder = decoder
7 myDecoder = decoder
^^^^^^^
I can't generate an implementation of the `Decoding` ability for
@ -10920,14 +10924,16 @@ In roc, functions are always written as a lambda, like{}
a -> a
Note: `Decoding` cannot be generated for functions.
"
"###
);
test_report!(
nested_opaque_cannot_derive_encoding,
indoc!(
r#"
app "test" imports [Decode.{decoder}] provides [main] to "./platform"
app "test" imports [] provides [main] to "./platform"
import Decode exposing [decoder]
A := {}
@ -10938,12 +10944,12 @@ In roc, functions are always written as a lambda, like{}
myDecoder
"#
),
@r"
@r###"
TYPE MISMATCH in /code/proj/Main.roc
This expression has a type that does not implement the abilities it's expected to:
7 myDecoder = decoder
9 myDecoder = decoder
^^^^^^^
I can't generate an implementation of the `Decoding` ability for
@ -10958,7 +10964,7 @@ In roc, functions are always written as a lambda, like{}
Tip: `A` does not implement `Decoding`. Consider adding a custom
implementation or `implements Decode.Decoding` to the definition of `A`.
"
"###
);
test_report!(
@ -11119,7 +11125,9 @@ In roc, functions are always written as a lambda, like{}
infer_decoded_record_error_with_function_field,
indoc!(
r#"
app "test" imports [TotallyNotJson] provides [main] to "./platform"
app "test" imports [] provides [main] to "./platform"
import TotallyNotJson
main =
decoded = Str.toUtf8 "{\"first\":\"ab\",\"second\":\"cd\"}" |> Decode.fromBytes TotallyNotJson.json
@ -11128,12 +11136,12 @@ In roc, functions are always written as a lambda, like{}
_ -> "something went wrong"
"#
),
@r"
@r###"
TYPE MISMATCH in /code/proj/Main.roc
This expression has a type that does not implement the abilities it's expected to:
6 Ok rcd -> rcd.first rcd.second
8 Ok rcd -> rcd.first rcd.second
^^^^^^^^^
I can't generate an implementation of the `Decoding` ability for
@ -11141,14 +11149,16 @@ In roc, functions are always written as a lambda, like{}
* -> *
Note: `Decoding` cannot be generated for functions.
"
"###
);
test_report!(
record_with_optional_field_types_cannot_derive_decoding,
indoc!(
r#"
app "test" imports [Decode.{decoder}] provides [main] to "./platform"
app "test" imports [] provides [main] to "./platform"
import Decode exposing [decoder]
main =
myDecoder : Decoder {x : Str, y ? Str} fmt where fmt implements DecoderFormatting
@ -11157,12 +11167,12 @@ In roc, functions are always written as a lambda, like{}
myDecoder
"#
),
@r"
@r###"
TYPE MISMATCH in /code/proj/Main.roc
This expression has a type that does not implement the abilities it's expected to:
5 myDecoder = decoder
7 myDecoder = decoder
^^^^^^^
I can't generate an implementation of the `Decoding` ability for
@ -11177,7 +11187,7 @@ In roc, functions are always written as a lambda, like{}
over records that may or may not contain them at compile time, but are
not a concept that extends to runtime!
Maybe you wanted to use a `Result`?
"
"###
);
test_report!(
@ -11359,21 +11369,23 @@ In roc, functions are always written as a lambda, like{}
unused_value_import,
indoc!(
r#"
app "test" imports [List.{ concat }] provides [main] to "./platform"
app "test" imports [] provides [main] to "./platform"
import List exposing [concat]
main = ""
"#
),
@r#"
@r###"
UNUSED IMPORT in /code/proj/Main.roc
`List.concat` is not used in this module.
List is imported but not used.
1 app "test" imports [List.{ concat }] provides [main] to "./platform"
^^^^^^
3 import List exposing [concat]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Since `List.concat` isn't used, you don't need to import it.
"#
Since List isn't used, you don't need to import it.
"###
);
test_report!(
@ -11395,7 +11407,9 @@ In roc, functions are always written as a lambda, like{}
unnecessary_builtin_type_import,
indoc!(
r#"
app "test" imports [Decode.{ DecodeError }] provides [main, E] to "./platform"
app "test" imports [] provides [main, E] to "./platform"
import Decode exposing [DecodeError]
E : DecodeError
@ -13664,7 +13678,9 @@ In roc, functions are always written as a lambda, like{}
derive_decoding_for_tuple,
indoc!(
r#"
app "test" imports [Decode.{decoder}] provides [main] to "./platform"
app "test" imports [] provides [main] to "./platform"
import Decode exposing [decoder]
main =
myDecoder : Decoder (U32, Str) fmt where fmt implements DecoderFormatting
@ -13679,7 +13695,9 @@ In roc, functions are always written as a lambda, like{}
cannot_decode_tuple_with_non_decode_element,
indoc!(
r#"
app "test" imports [Decode.{decoder}] provides [main] to "./platform"
app "test" imports [] provides [main] to "./platform"
import Decode exposing [decoder]
main =
myDecoder : Decoder (U32, {} -> {}) fmt where fmt implements DecoderFormatting
@ -13688,12 +13706,12 @@ In roc, functions are always written as a lambda, like{}
myDecoder
"#
),
@r"
@r###"
TYPE MISMATCH in /code/proj/Main.roc
This expression has a type that does not implement the abilities it's expected to:
5 myDecoder = decoder
7 myDecoder = decoder
^^^^^^^
I can't generate an implementation of the `Decoding` ability for
@ -13701,7 +13719,7 @@ In roc, functions are always written as a lambda, like{}
U32, {} -> {}
Note: `Decoding` cannot be generated for functions.
"
"###
);
test_no_problem!(