mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 00:01:16 +00:00
add test for transitive alias import
This commit is contained in:
parent
984cf744e3
commit
cf80e2852f
9 changed files with 135 additions and 27 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -2524,6 +2524,7 @@ dependencies = [
|
||||||
"roc_solve",
|
"roc_solve",
|
||||||
"roc_types",
|
"roc_types",
|
||||||
"roc_unify",
|
"roc_unify",
|
||||||
|
"tempfile",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -227,19 +227,7 @@ fn can_annotation_help(
|
||||||
// instantiate variables
|
// instantiate variables
|
||||||
actual.substitute(&substitutions);
|
actual.substitute(&substitutions);
|
||||||
|
|
||||||
// Type::Alias(symbol, vars, Box::new(actual))
|
Type::Alias(symbol, vars, Box::new(actual))
|
||||||
if vars.is_empty() {
|
|
||||||
let actual_var = var_store.fresh();
|
|
||||||
introduced_variables.insert_host_exposed_alias(symbol, actual_var);
|
|
||||||
Type::HostExposedAlias {
|
|
||||||
name: symbol,
|
|
||||||
arguments: vars,
|
|
||||||
actual: Box::new(actual),
|
|
||||||
actual_var,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Type::Alias(symbol, vars, Box::new(actual))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let mut args = Vec::new();
|
let mut args = Vec::new();
|
||||||
|
@ -373,7 +361,7 @@ fn can_annotation_help(
|
||||||
|
|
||||||
// Type::Alias(symbol, vars, Box::new(alias.typ.clone()))
|
// Type::Alias(symbol, vars, Box::new(alias.typ.clone()))
|
||||||
|
|
||||||
if vars.is_empty() {
|
if vars.is_empty() && env.home == symbol.module_id() {
|
||||||
let actual_var = var_store.fresh();
|
let actual_var = var_store.fresh();
|
||||||
introduced_variables.insert_host_exposed_alias(symbol, actual_var);
|
introduced_variables.insert_host_exposed_alias(symbol, actual_var);
|
||||||
Type::HostExposedAlias {
|
Type::HostExposedAlias {
|
||||||
|
|
|
@ -25,6 +25,7 @@ crossbeam = "0.7"
|
||||||
num_cpus = "1"
|
num_cpus = "1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
tempfile = "3.1.0"
|
||||||
pretty_assertions = "0.5.1"
|
pretty_assertions = "0.5.1"
|
||||||
maplit = "1.0.1"
|
maplit = "1.0.1"
|
||||||
indoc = "0.3.3"
|
indoc = "0.3.3"
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
extern crate indoc;
|
||||||
|
#[macro_use]
|
||||||
extern crate pretty_assertions;
|
extern crate pretty_assertions;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate maplit;
|
extern crate maplit;
|
||||||
|
@ -28,6 +30,87 @@ mod test_load {
|
||||||
|
|
||||||
// HELPERS
|
// HELPERS
|
||||||
|
|
||||||
|
fn multiple_modules(files: Vec<(&str, &str)>) -> LoadedModule {
|
||||||
|
multiple_modules_help(files).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn multiple_modules_help(mut files: Vec<(&str, &str)>) -> Result<LoadedModule, std::io::Error> {
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use tempfile::tempdir;
|
||||||
|
|
||||||
|
let arena = Bump::new();
|
||||||
|
let arena = &arena;
|
||||||
|
|
||||||
|
let stdlib = roc_builtins::std::standard_stdlib();
|
||||||
|
|
||||||
|
let mut file_handles: Vec<_> = Vec::new();
|
||||||
|
let exposed_types = MutMap::default();
|
||||||
|
let loaded = {
|
||||||
|
// create a temporary directory
|
||||||
|
let dir = tempdir()?;
|
||||||
|
|
||||||
|
let app_module = files.pop().unwrap();
|
||||||
|
let interfaces = files;
|
||||||
|
|
||||||
|
debug_assert!(
|
||||||
|
app_module.1.starts_with("app"),
|
||||||
|
"The final module should be the application module"
|
||||||
|
);
|
||||||
|
|
||||||
|
for (name, source) in interfaces {
|
||||||
|
let mut filename = PathBuf::from(name);
|
||||||
|
filename.set_extension("roc");
|
||||||
|
let file_path = dir.path().join(filename.clone());
|
||||||
|
let mut file = File::create(file_path)?;
|
||||||
|
writeln!(file, "{}", source)?;
|
||||||
|
file_handles.push(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = {
|
||||||
|
let (name, source) = app_module;
|
||||||
|
|
||||||
|
let filename = PathBuf::from(name);
|
||||||
|
let file_path = dir.path().join(filename.clone());
|
||||||
|
let full_file_path = PathBuf::from(file_path.clone());
|
||||||
|
let mut file = File::create(file_path)?;
|
||||||
|
writeln!(file, "{}", source)?;
|
||||||
|
file_handles.push(file);
|
||||||
|
|
||||||
|
roc_load::file::load_and_typecheck(
|
||||||
|
arena,
|
||||||
|
full_file_path,
|
||||||
|
stdlib,
|
||||||
|
dir.path(),
|
||||||
|
exposed_types,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
dir.close()?;
|
||||||
|
|
||||||
|
result
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut loaded_module = loaded.expect("failed to load module");
|
||||||
|
|
||||||
|
let home = loaded_module.module_id;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
loaded_module.can_problems.remove(&home).unwrap_or_default(),
|
||||||
|
Vec::new()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
loaded_module
|
||||||
|
.type_problems
|
||||||
|
.remove(&home)
|
||||||
|
.unwrap_or_default(),
|
||||||
|
Vec::new()
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(loaded_module)
|
||||||
|
}
|
||||||
|
|
||||||
fn load_fixture(
|
fn load_fixture(
|
||||||
dir_name: &str,
|
dir_name: &str,
|
||||||
module_name: &str,
|
module_name: &str,
|
||||||
|
@ -146,6 +229,46 @@ mod test_load {
|
||||||
|
|
||||||
// TESTS
|
// TESTS
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn import_transitive_alias() {
|
||||||
|
// this had a bug where NodeColor was HostExposed, and it's `actual_var` conflicted
|
||||||
|
// with variables in the importee
|
||||||
|
let modules = vec![
|
||||||
|
(
|
||||||
|
"RBTree",
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
interface RBTree exposes [ Dict, empty ] imports []
|
||||||
|
|
||||||
|
# The color of a node. Leaves are considered Black.
|
||||||
|
NodeColor : [ Red, Black ]
|
||||||
|
|
||||||
|
Dict k v : [ Node NodeColor k v (Dict k v) (Dict k v), Empty ]
|
||||||
|
|
||||||
|
# Create an empty dictionary.
|
||||||
|
empty : Dict k v
|
||||||
|
empty =
|
||||||
|
Empty
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Main",
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
app Test provides [ main ] imports [ RBTree ]
|
||||||
|
|
||||||
|
empty : RBTree.Dict Int Int
|
||||||
|
empty = RBTree.empty
|
||||||
|
|
||||||
|
main = empty
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
multiple_modules(modules);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn interface_with_deps() {
|
fn interface_with_deps() {
|
||||||
let subs_by_module = MutMap::default();
|
let subs_by_module = MutMap::default();
|
||||||
|
|
|
@ -972,7 +972,7 @@ fn add_category<'b>(
|
||||||
this_is,
|
this_is,
|
||||||
alloc.text(" an uniqueness attribute of type:"),
|
alloc.text(" an uniqueness attribute of type:"),
|
||||||
]),
|
]),
|
||||||
Storage => alloc.concat(vec![this_is, alloc.text(" a value of type:")]),
|
Storage(_file, _line) => alloc.concat(vec![this_is, alloc.text(" a value of type:")]),
|
||||||
|
|
||||||
DefaultValue(_) => alloc.concat(vec![this_is, alloc.text(" a default field of type:")]),
|
DefaultValue(_) => alloc.concat(vec![this_is, alloc.text(" a default field of type:")]),
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,9 +154,6 @@ pub fn run(
|
||||||
constraint,
|
constraint,
|
||||||
);
|
);
|
||||||
|
|
||||||
//dbg!(&subs, &state.env.vars_by_symbol);
|
|
||||||
//panic!();
|
|
||||||
|
|
||||||
(Solved(subs), state.env)
|
(Solved(subs), state.env)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1007,7 +1007,7 @@ pub enum Category {
|
||||||
StrInterpolation,
|
StrInterpolation,
|
||||||
|
|
||||||
// storing variables in the ast
|
// storing variables in the ast
|
||||||
Storage,
|
Storage(&'static str, u32),
|
||||||
|
|
||||||
// control flow
|
// control flow
|
||||||
If,
|
If,
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
app Main provides [ main ] imports [ Effect, ConsList ]
|
app Main provides [ main ] imports [ Effect, RBTree ]
|
||||||
|
|
||||||
empty : ConsList.ConsList Int
|
foo : RBTree.Dict Int Int
|
||||||
empty = ConsList.empty
|
foo = Empty # RBTree.empty
|
||||||
|
|
||||||
main : Effect.Effect {} as Fx
|
main : Effect.Effect {} as Fx
|
||||||
main =
|
main =
|
||||||
# if ConsList.isEmpty empty then
|
# if RBTree.isEmpty empty then
|
||||||
if ConsList.len empty == 0 then
|
if RBTree.size foo == 0 then
|
||||||
Effect.putLine "Yay"
|
Effect.putLine "Yay"
|
||||||
|> Effect.after (\{} -> Effect.getLine)
|
|> Effect.after (\{} -> Effect.getLine)
|
||||||
|> Effect.after (\line -> Effect.putLine line)
|
|> Effect.after (\line -> Effect.putLine line)
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
interface RBTree exposes [ Dict, empty, singleton, size, isEmpty, insert, remove, balance ] imports []
|
interface RBTree exposes [ Dict, empty, size, singleton ] imports []
|
||||||
# TODO remove `balance` from the exposed list
|
|
||||||
# todo change `foobar` to `balance`
|
|
||||||
|
|
||||||
# The color of a node. Leaves are considered Black.
|
# The color of a node. Leaves are considered Black.
|
||||||
NodeColor : [ Red, Black ]
|
NodeColor : [ Red, Black ]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue