Condition derive tests on derived method

This commit is contained in:
Ayaz Hafiz 2022-08-01 13:50:29 -05:00
parent c3383da994
commit 6f06a59cdf
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
2 changed files with 90 additions and 47 deletions

View file

@ -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

View file

@ -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,