mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 00:24:34 +00:00
Condition derive tests on derived method
This commit is contained in:
parent
c3383da994
commit
6f06a59cdf
2 changed files with 90 additions and 47 deletions
|
@ -149,9 +149,11 @@ fn immediates() {
|
||||||
check_immediate(v!(STR), Symbol::ENCODE_STRING);
|
check_immediate(v!(STR), Symbol::ENCODE_STRING);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use crate::util::DeriveBuiltin::ToEncoder;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn empty_record() {
|
fn empty_record() {
|
||||||
derive_test(v!(EMPTY_RECORD), |golden| {
|
derive_test(ToEncoder, v!(EMPTY_RECORD), |golden| {
|
||||||
assert_snapshot!(golden, @r###"
|
assert_snapshot!(golden, @r###"
|
||||||
# derived for {}
|
# derived for {}
|
||||||
# {} -[[toEncoder_{}(0)]]-> Encoder fmt | fmt has EncoderFormatting
|
# {} -[[toEncoder_{}(0)]]-> Encoder fmt | fmt has EncoderFormatting
|
||||||
|
@ -171,7 +173,7 @@ fn empty_record() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn zero_field_record() {
|
fn zero_field_record() {
|
||||||
derive_test(v!({}), |golden| {
|
derive_test(ToEncoder, v!({}), |golden| {
|
||||||
assert_snapshot!(golden, @r###"
|
assert_snapshot!(golden, @r###"
|
||||||
# derived for {}
|
# derived for {}
|
||||||
# {} -[[toEncoder_{}(0)]]-> Encoder fmt | fmt has EncoderFormatting
|
# {} -[[toEncoder_{}(0)]]-> Encoder fmt | fmt has EncoderFormatting
|
||||||
|
@ -191,7 +193,7 @@ fn zero_field_record() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn one_field_record() {
|
fn one_field_record() {
|
||||||
derive_test(v!({ a: v!(U8), }), |golden| {
|
derive_test(ToEncoder, v!({ a: v!(U8), }), |golden| {
|
||||||
assert_snapshot!(golden, @r###"
|
assert_snapshot!(golden, @r###"
|
||||||
# derived for { a : U8 }
|
# derived for { a : U8 }
|
||||||
# { a : val } -[[toEncoder_{a}(0)]]-> Encoder fmt | fmt has EncoderFormatting, val has Encoding
|
# { a : val } -[[toEncoder_{a}(0)]]-> Encoder fmt | fmt has EncoderFormatting, val has Encoding
|
||||||
|
@ -218,7 +220,7 @@ fn one_field_record() {
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore = "TODO #3421 unification of unspecialized variables in lambda sets currently causes this to be derived incorrectly"]
|
#[ignore = "TODO #3421 unification of unspecialized variables in lambda sets currently causes this to be derived incorrectly"]
|
||||||
fn two_field_record() {
|
fn two_field_record() {
|
||||||
derive_test(v!({ a: v!(U8), b: v!(STR), }), |golden| {
|
derive_test(ToEncoder, v!({ a: v!(U8), b: v!(STR), }), |golden| {
|
||||||
assert_snapshot!(golden, @r###"
|
assert_snapshot!(golden, @r###"
|
||||||
# derived for { a : U8, b : Str }
|
# derived for { a : U8, b : Str }
|
||||||
# { a : val, b : a } -[[toEncoder_{a,b}(0)]]-> Encoder fmt | a has Encoding, fmt has EncoderFormatting, val has Encoding
|
# { a : val, b : a } -[[toEncoder_{a,b}(0)]]-> Encoder fmt | a has Encoding, fmt has EncoderFormatting, val has Encoding
|
||||||
|
@ -242,7 +244,7 @@ fn two_field_record() {
|
||||||
#[ignore = "NOTE: this would never actually happen, because [] is uninhabited, and hence toEncoder can never be called with a value of []!
|
#[ignore = "NOTE: this would never actually happen, because [] is uninhabited, and hence toEncoder can never be called with a value of []!
|
||||||
Rightfully it induces broken assertions in other parts of the compiler, so we ignore it."]
|
Rightfully it induces broken assertions in other parts of the compiler, so we ignore it."]
|
||||||
fn empty_tag_union() {
|
fn empty_tag_union() {
|
||||||
derive_test(v!(EMPTY_TAG_UNION), |golden| {
|
derive_test(ToEncoder, v!(EMPTY_TAG_UNION), |golden| {
|
||||||
assert_snapshot!(
|
assert_snapshot!(
|
||||||
golden,
|
golden,
|
||||||
@r#"
|
@r#"
|
||||||
|
@ -253,7 +255,7 @@ fn empty_tag_union() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn tag_one_label_zero_args() {
|
fn tag_one_label_zero_args() {
|
||||||
derive_test(v!([A]), |golden| {
|
derive_test(ToEncoder, v!([A]), |golden| {
|
||||||
assert_snapshot!(golden, @r###"
|
assert_snapshot!(golden, @r###"
|
||||||
# derived for [A]
|
# derived for [A]
|
||||||
# [A] -[[toEncoder_[A 0](0)]]-> Encoder fmt | fmt has EncoderFormatting
|
# [A] -[[toEncoder_[A 0](0)]]-> Encoder fmt | fmt has EncoderFormatting
|
||||||
|
@ -277,7 +279,7 @@ fn tag_one_label_zero_args() {
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore = "TODO #3421 unification of unspecialized variables in lambda sets currently causes this to be derived incorrectly"]
|
#[ignore = "TODO #3421 unification of unspecialized variables in lambda sets currently causes this to be derived incorrectly"]
|
||||||
fn tag_one_label_two_args() {
|
fn tag_one_label_two_args() {
|
||||||
derive_test(v!([A v!(U8) v!(STR)]), |golden| {
|
derive_test(ToEncoder, v!([A v!(U8) v!(STR)]), |golden| {
|
||||||
assert_snapshot!(golden, @r###"
|
assert_snapshot!(golden, @r###"
|
||||||
# derived for [A U8 Str]
|
# derived for [A U8 Str]
|
||||||
# [A val a] -[[toEncoder_[A 2](0)]]-> Encoder fmt | a has Encoding, fmt has EncoderFormatting, val has Encoding
|
# [A val a] -[[toEncoder_[A 2](0)]]-> Encoder fmt | a has Encoding, fmt has EncoderFormatting, val has Encoding
|
||||||
|
@ -302,8 +304,11 @@ fn tag_one_label_two_args() {
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore = "TODO #3421 unification of unspecialized variables in lambda sets currently causes this to be derived incorrectly"]
|
#[ignore = "TODO #3421 unification of unspecialized variables in lambda sets currently causes this to be derived incorrectly"]
|
||||||
fn tag_two_labels() {
|
fn tag_two_labels() {
|
||||||
derive_test(v!([A v!(U8) v!(STR) v!(U16), B v!(STR)]), |golden| {
|
derive_test(
|
||||||
assert_snapshot!(golden, @r###"
|
ToEncoder,
|
||||||
|
v!([A v!(U8) v!(STR) v!(U16), B v!(STR)]),
|
||||||
|
|golden| {
|
||||||
|
assert_snapshot!(golden, @r###"
|
||||||
# derived for [A U8 Str U16, B Str]
|
# derived for [A U8 Str U16, B Str]
|
||||||
# [A val a b, B c] -[[toEncoder_[A 3,B 1](0)]]-> Encoder fmt | a has Encoding, b has Encoding, c has Encoding, fmt has EncoderFormatting, val has Encoding
|
# [A val a b, B c] -[[toEncoder_[A 3,B 1](0)]]-> Encoder fmt | a has Encoding, b has Encoding, c has Encoding, fmt has EncoderFormatting, val has Encoding
|
||||||
# [A val a b, B c] -[[toEncoder_[A 3,B 1](0)]]-> (List U8, fmt -[[custom(6) [A val a b, B c]]]-> List U8) | a has Encoding, b has Encoding, c has Encoding, fmt has EncoderFormatting, val has Encoding
|
# [A val a b, B c] -[[toEncoder_[A 3,B 1](0)]]-> (List U8, fmt -[[custom(6) [A val a b, B c]]]-> List U8) | a has Encoding, b has Encoding, c has Encoding, fmt has EncoderFormatting, val has Encoding
|
||||||
|
@ -323,15 +328,19 @@ fn tag_two_labels() {
|
||||||
B #Derived.5 -> Encode.tag "B" [Encode.toEncoder #Derived.5])
|
B #Derived.5 -> Encode.tag "B" [Encode.toEncoder #Derived.5])
|
||||||
#Derived.fmt
|
#Derived.fmt
|
||||||
"###
|
"###
|
||||||
)
|
)
|
||||||
})
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore = "TODO #3421 unification of unspecialized variables in lambda sets currently causes this to be derived incorrectly"]
|
#[ignore = "TODO #3421 unification of unspecialized variables in lambda sets currently causes this to be derived incorrectly"]
|
||||||
fn recursive_tag_union() {
|
fn recursive_tag_union() {
|
||||||
derive_test(v!([Nil, Cons v!(U8) v!(*lst) ] as lst), |golden| {
|
derive_test(
|
||||||
assert_snapshot!(golden, @r###"
|
ToEncoder,
|
||||||
|
v!([Nil, Cons v!(U8) v!(*lst) ] as lst),
|
||||||
|
|golden| {
|
||||||
|
assert_snapshot!(golden, @r###"
|
||||||
# derived for [Cons U8 $rec, Nil] as $rec
|
# derived for [Cons U8 $rec, Nil] as $rec
|
||||||
# [Cons val a, Nil] -[[toEncoder_[Cons 2,Nil 0](0)]]-> Encoder fmt | a has Encoding, fmt has EncoderFormatting, val has Encoding
|
# [Cons val a, Nil] -[[toEncoder_[Cons 2,Nil 0](0)]]-> Encoder fmt | a has Encoding, fmt has EncoderFormatting, val has Encoding
|
||||||
# [Cons val a, Nil] -[[toEncoder_[Cons 2,Nil 0](0)]]-> (List U8, fmt -[[custom(4) [Cons val a, Nil]]]-> List U8) | a has Encoding, fmt has EncoderFormatting, val has Encoding
|
# [Cons val a, Nil] -[[toEncoder_[Cons 2,Nil 0](0)]]-> (List U8, fmt -[[custom(4) [Cons val a, Nil]]]-> List U8) | a has Encoding, fmt has EncoderFormatting, val has Encoding
|
||||||
|
@ -349,13 +358,14 @@ fn recursive_tag_union() {
|
||||||
]
|
]
|
||||||
Nil -> Encode.tag "Nil" []) #Derived.fmt
|
Nil -> Encode.tag "Nil" []) #Derived.fmt
|
||||||
"###
|
"###
|
||||||
)
|
)
|
||||||
})
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn list() {
|
fn list() {
|
||||||
derive_test(v!(Symbol::LIST_LIST v!(STR)), |golden| {
|
derive_test(ToEncoder, v!(Symbol::LIST_LIST v!(STR)), |golden| {
|
||||||
assert_snapshot!(golden, @r###"
|
assert_snapshot!(golden, @r###"
|
||||||
# derived for List Str
|
# derived for List Str
|
||||||
# List val -[[toEncoder_list(0)]]-> Encoder fmt | fmt has EncoderFormatting, val has Encoding
|
# List val -[[toEncoder_list(0)]]-> Encoder fmt | fmt has EncoderFormatting, val has Encoding
|
||||||
|
|
|
@ -30,13 +30,30 @@ use roc_types::{
|
||||||
|
|
||||||
const DERIVED_MODULE: ModuleId = ModuleId::DERIVED_SYNTH;
|
const DERIVED_MODULE: ModuleId = ModuleId::DERIVED_SYNTH;
|
||||||
|
|
||||||
fn encode_path() -> PathBuf {
|
#[derive(Clone, Copy)]
|
||||||
let repo_root = std::env::var("ROC_WORKSPACE_DIR").expect("are you running with `cargo test`?");
|
pub(crate) enum DeriveBuiltin {
|
||||||
PathBuf::from(repo_root)
|
ToEncoder,
|
||||||
.join("compiler")
|
}
|
||||||
.join("builtins")
|
|
||||||
.join("roc")
|
impl DeriveBuiltin {
|
||||||
.join("Encode.roc")
|
fn module_source_and_path(&self) -> (ModuleId, &'static str, PathBuf) {
|
||||||
|
use roc_builtins::roc::module_source;
|
||||||
|
|
||||||
|
let repo_root =
|
||||||
|
std::env::var("ROC_WORKSPACE_DIR").expect("are you running with `cargo test`?");
|
||||||
|
let builtins_path = PathBuf::from(repo_root)
|
||||||
|
.join("compiler")
|
||||||
|
.join("builtins")
|
||||||
|
.join("roc");
|
||||||
|
|
||||||
|
match self {
|
||||||
|
DeriveBuiltin::ToEncoder => (
|
||||||
|
ModuleId::ENCODE,
|
||||||
|
module_source(ModuleId::ENCODE),
|
||||||
|
builtins_path.join("Encode.roc"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writing out the types into content is inconvenient, so we use a DSL for testing.
|
/// Writing out the types into content is inconvenient, so we use a DSL for testing.
|
||||||
|
@ -185,14 +202,20 @@ fn assemble_derived_golden(
|
||||||
pretty_buf
|
pretty_buf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The environment of the module containing the builtin ability we're deriving for a type.
|
||||||
|
struct DeriveBuiltinEnv {
|
||||||
|
module_id: ModuleId,
|
||||||
|
exposed_types: ExposedTypesStorageSubs,
|
||||||
|
abilities_store: AbilitiesStore,
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn check_derived_typechecks_and_golden(
|
fn check_derived_typechecks_and_golden(
|
||||||
derived_def: Def,
|
derived_def: Def,
|
||||||
test_module: ModuleId,
|
test_module: ModuleId,
|
||||||
mut test_subs: Subs,
|
mut test_subs: Subs,
|
||||||
interns: &Interns,
|
interns: &Interns,
|
||||||
exposed_encode_types: ExposedTypesStorageSubs,
|
derive_builtin_env: DeriveBuiltinEnv,
|
||||||
encode_abilities_store: AbilitiesStore,
|
|
||||||
source_var: Variable,
|
source_var: Variable,
|
||||||
derived_program: &str,
|
derived_program: &str,
|
||||||
specialization_lsets: SpecializationLambdaSets,
|
specialization_lsets: SpecializationLambdaSets,
|
||||||
|
@ -205,25 +228,30 @@ fn check_derived_typechecks_and_golden(
|
||||||
decls.push_def(derived_def);
|
decls.push_def(derived_def);
|
||||||
let constr = constrain_decls(&mut constraints, test_module, &decls);
|
let constr = constrain_decls(&mut constraints, test_module, &decls);
|
||||||
|
|
||||||
// the derived depends on stuff from Encode, so
|
// the derived implementation on stuff from the builtin module, so
|
||||||
// - we need to add those dependencies as imported on the constraint
|
// - we need to add those dependencies as imported on the constraint
|
||||||
// - we need to add Encode ability info to a local abilities store
|
// - we need to add the builtin ability info to a local abilities store
|
||||||
let encode_values_to_import = exposed_encode_types
|
let values_to_import_from_builtin_module = derive_builtin_env
|
||||||
|
.exposed_types
|
||||||
.stored_vars_by_symbol
|
.stored_vars_by_symbol
|
||||||
.keys()
|
.keys()
|
||||||
.copied()
|
.copied()
|
||||||
.collect::<VecSet<_>>();
|
.collect::<VecSet<_>>();
|
||||||
let pending_abilities = encode_abilities_store.closure_from_imported(&encode_values_to_import);
|
let pending_abilities = derive_builtin_env
|
||||||
|
.abilities_store
|
||||||
|
.closure_from_imported(&values_to_import_from_builtin_module);
|
||||||
let mut exposed_by_module = ExposedByModule::default();
|
let mut exposed_by_module = ExposedByModule::default();
|
||||||
exposed_by_module.insert(
|
exposed_by_module.insert(
|
||||||
ModuleId::ENCODE,
|
derive_builtin_env.module_id,
|
||||||
ExposedModuleTypes {
|
ExposedModuleTypes {
|
||||||
exposed_types_storage_subs: exposed_encode_types,
|
exposed_types_storage_subs: derive_builtin_env.exposed_types,
|
||||||
resolved_implementations: ResolvedImplementations::default(),
|
resolved_implementations: ResolvedImplementations::default(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
let exposed_for_module =
|
let exposed_for_module = ExposedForModule::new(
|
||||||
ExposedForModule::new(encode_values_to_import.iter(), exposed_by_module);
|
values_to_import_from_builtin_module.iter(),
|
||||||
|
exposed_by_module,
|
||||||
|
);
|
||||||
let mut def_types = Default::default();
|
let mut def_types = Default::default();
|
||||||
let mut rigid_vars = Default::default();
|
let mut rigid_vars = Default::default();
|
||||||
let (import_variables, abilities_store) = add_imports(
|
let (import_variables, abilities_store) = add_imports(
|
||||||
|
@ -303,32 +331,34 @@ fn check_derived_typechecks_and_golden(
|
||||||
check_golden(&golden)
|
check_golden(&golden)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_key(subs: &Subs, var: Variable) -> DeriveKey {
|
fn get_key(derive: DeriveBuiltin, subs: &Subs, var: Variable) -> DeriveKey {
|
||||||
match Derived::encoding(subs, var) {
|
match derive {
|
||||||
Ok(Derived::Key(key)) => key,
|
DeriveBuiltin::ToEncoder => match Derived::encoding(subs, var) {
|
||||||
_ => unreachable!(),
|
Ok(Derived::Key(key)) => key,
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn derive_test<S>(synth_input: S, check_golden: impl Fn(&str))
|
pub(crate) fn derive_test<S>(derive: DeriveBuiltin, synth_input: S, check_golden: impl Fn(&str))
|
||||||
where
|
where
|
||||||
S: FnOnce(&mut Subs) -> Variable,
|
S: FnOnce(&mut Subs) -> Variable,
|
||||||
{
|
{
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let source = roc_builtins::roc::module_source(ModuleId::ENCODE);
|
let (builtin_module, source, path) = derive.module_source_and_path();
|
||||||
let target_info = roc_target::TargetInfo::default_x86_64();
|
let target_info = roc_target::TargetInfo::default_x86_64();
|
||||||
|
|
||||||
let LoadedModule {
|
let LoadedModule {
|
||||||
mut interns,
|
mut interns,
|
||||||
exposed_types_storage: exposed_encode_types,
|
exposed_types_storage,
|
||||||
abilities_store,
|
abilities_store,
|
||||||
resolved_implementations,
|
resolved_implementations,
|
||||||
..
|
..
|
||||||
} = roc_load_internal::file::load_and_typecheck_str(
|
} = roc_load_internal::file::load_and_typecheck_str(
|
||||||
&arena,
|
&arena,
|
||||||
encode_path().file_name().unwrap().into(),
|
path.file_name().unwrap().into(),
|
||||||
source,
|
source,
|
||||||
encode_path().parent().unwrap().to_path_buf(),
|
path.parent().unwrap().to_path_buf(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
target_info,
|
target_info,
|
||||||
roc_reporting::report::RenderTarget::ColorTerminal,
|
roc_reporting::report::RenderTarget::ColorTerminal,
|
||||||
|
@ -339,15 +369,15 @@ where
|
||||||
let mut subs = Subs::new();
|
let mut subs = Subs::new();
|
||||||
let ident_ids = IdentIds::default();
|
let ident_ids = IdentIds::default();
|
||||||
let source_var = synth_input(&mut subs);
|
let source_var = synth_input(&mut subs);
|
||||||
let key = get_key(&subs, source_var);
|
let key = get_key(derive, &subs, source_var);
|
||||||
|
|
||||||
let mut derived_module = unsafe { DerivedModule::from_components(subs, ident_ids) };
|
let mut derived_module = unsafe { DerivedModule::from_components(subs, ident_ids) };
|
||||||
|
|
||||||
let mut exposed_by_module = ExposedByModule::default();
|
let mut exposed_by_module = ExposedByModule::default();
|
||||||
exposed_by_module.insert(
|
exposed_by_module.insert(
|
||||||
ModuleId::ENCODE,
|
builtin_module,
|
||||||
ExposedModuleTypes {
|
ExposedModuleTypes {
|
||||||
exposed_types_storage_subs: exposed_encode_types.clone(),
|
exposed_types_storage_subs: exposed_types_storage.clone(),
|
||||||
resolved_implementations,
|
resolved_implementations,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -370,8 +400,11 @@ where
|
||||||
DERIVED_MODULE,
|
DERIVED_MODULE,
|
||||||
subs,
|
subs,
|
||||||
&interns,
|
&interns,
|
||||||
exposed_encode_types,
|
DeriveBuiltinEnv {
|
||||||
abilities_store,
|
module_id: builtin_module,
|
||||||
|
exposed_types: exposed_types_storage,
|
||||||
|
abilities_store,
|
||||||
|
},
|
||||||
source_var,
|
source_var,
|
||||||
&derived_program,
|
&derived_program,
|
||||||
specialization_lsets,
|
specialization_lsets,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue