diff --git a/crates/compiler/test_derive/src/encoding.rs b/crates/compiler/test_derive/src/encoding.rs index 0272951aa3..adbeede886 100644 --- a/crates/compiler/test_derive/src/encoding.rs +++ b/crates/compiler/test_derive/src/encoding.rs @@ -149,9 +149,11 @@ fn immediates() { check_immediate(v!(STR), Symbol::ENCODE_STRING); } +use crate::util::DeriveBuiltin::ToEncoder; + #[test] fn empty_record() { - derive_test(v!(EMPTY_RECORD), |golden| { + derive_test(ToEncoder, v!(EMPTY_RECORD), |golden| { assert_snapshot!(golden, @r###" # derived for {} # {} -[[toEncoder_{}(0)]]-> Encoder fmt | fmt has EncoderFormatting @@ -171,7 +173,7 @@ fn empty_record() { #[test] fn zero_field_record() { - derive_test(v!({}), |golden| { + derive_test(ToEncoder, v!({}), |golden| { assert_snapshot!(golden, @r###" # derived for {} # {} -[[toEncoder_{}(0)]]-> Encoder fmt | fmt has EncoderFormatting @@ -191,7 +193,7 @@ fn zero_field_record() { #[test] fn one_field_record() { - derive_test(v!({ a: v!(U8), }), |golden| { + derive_test(ToEncoder, v!({ a: v!(U8), }), |golden| { assert_snapshot!(golden, @r###" # derived for { a : U8 } # { a : val } -[[toEncoder_{a}(0)]]-> Encoder fmt | fmt has EncoderFormatting, val has Encoding @@ -218,7 +220,7 @@ fn one_field_record() { #[test] #[ignore = "TODO #3421 unification of unspecialized variables in lambda sets currently causes this to be derived incorrectly"] 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###" # 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 @@ -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 []! Rightfully it induces broken assertions in other parts of the compiler, so we ignore it."] fn empty_tag_union() { - derive_test(v!(EMPTY_TAG_UNION), |golden| { + derive_test(ToEncoder, v!(EMPTY_TAG_UNION), |golden| { assert_snapshot!( golden, @r#" @@ -253,7 +255,7 @@ fn empty_tag_union() { #[test] fn tag_one_label_zero_args() { - derive_test(v!([A]), |golden| { + derive_test(ToEncoder, v!([A]), |golden| { assert_snapshot!(golden, @r###" # derived for [A] # [A] -[[toEncoder_[A 0](0)]]-> Encoder fmt | fmt has EncoderFormatting @@ -277,7 +279,7 @@ fn tag_one_label_zero_args() { #[test] #[ignore = "TODO #3421 unification of unspecialized variables in lambda sets currently causes this to be derived incorrectly"] 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###" # derived for [A U8 Str] # [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] #[ignore = "TODO #3421 unification of unspecialized variables in lambda sets currently causes this to be derived incorrectly"] fn tag_two_labels() { - derive_test(v!([A v!(U8) v!(STR) v!(U16), B v!(STR)]), |golden| { - assert_snapshot!(golden, @r###" + derive_test( + 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] # [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 @@ -323,15 +328,19 @@ fn tag_two_labels() { B #Derived.5 -> Encode.tag "B" [Encode.toEncoder #Derived.5]) #Derived.fmt "### - ) - }) + ) + }, + ) } #[test] #[ignore = "TODO #3421 unification of unspecialized variables in lambda sets currently causes this to be derived incorrectly"] fn recursive_tag_union() { - derive_test(v!([Nil, Cons v!(U8) v!(*lst) ] as lst), |golden| { - assert_snapshot!(golden, @r###" + derive_test( + ToEncoder, + v!([Nil, Cons v!(U8) v!(*lst) ] as lst), + |golden| { + assert_snapshot!(golden, @r###" # 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)]]-> (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 "### - ) - }) + ) + }, + ) } #[test] 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###" # derived for List Str # List val -[[toEncoder_list(0)]]-> Encoder fmt | fmt has EncoderFormatting, val has Encoding diff --git a/crates/compiler/test_derive/src/util.rs b/crates/compiler/test_derive/src/util.rs index ffe468d4a5..58a90db8a6 100644 --- a/crates/compiler/test_derive/src/util.rs +++ b/crates/compiler/test_derive/src/util.rs @@ -30,13 +30,30 @@ use roc_types::{ const DERIVED_MODULE: ModuleId = ModuleId::DERIVED_SYNTH; -fn encode_path() -> PathBuf { - let repo_root = std::env::var("ROC_WORKSPACE_DIR").expect("are you running with `cargo test`?"); - PathBuf::from(repo_root) - .join("compiler") - .join("builtins") - .join("roc") - .join("Encode.roc") +#[derive(Clone, Copy)] +pub(crate) enum DeriveBuiltin { + ToEncoder, +} + +impl DeriveBuiltin { + 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. @@ -185,14 +202,20 @@ fn assemble_derived_golden( 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)] fn check_derived_typechecks_and_golden( derived_def: Def, test_module: ModuleId, mut test_subs: Subs, interns: &Interns, - exposed_encode_types: ExposedTypesStorageSubs, - encode_abilities_store: AbilitiesStore, + derive_builtin_env: DeriveBuiltinEnv, source_var: Variable, derived_program: &str, specialization_lsets: SpecializationLambdaSets, @@ -205,25 +228,30 @@ fn check_derived_typechecks_and_golden( decls.push_def(derived_def); 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 Encode ability info to a local abilities store - let encode_values_to_import = exposed_encode_types + // - we need to add the builtin ability info to a local abilities store + let values_to_import_from_builtin_module = derive_builtin_env + .exposed_types .stored_vars_by_symbol .keys() .copied() .collect::>(); - 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(); exposed_by_module.insert( - ModuleId::ENCODE, + derive_builtin_env.module_id, ExposedModuleTypes { - exposed_types_storage_subs: exposed_encode_types, + exposed_types_storage_subs: derive_builtin_env.exposed_types, resolved_implementations: ResolvedImplementations::default(), }, ); - let exposed_for_module = - ExposedForModule::new(encode_values_to_import.iter(), exposed_by_module); + let exposed_for_module = ExposedForModule::new( + values_to_import_from_builtin_module.iter(), + exposed_by_module, + ); let mut def_types = Default::default(); let mut rigid_vars = Default::default(); let (import_variables, abilities_store) = add_imports( @@ -303,32 +331,34 @@ fn check_derived_typechecks_and_golden( check_golden(&golden) } -fn get_key(subs: &Subs, var: Variable) -> DeriveKey { - match Derived::encoding(subs, var) { - Ok(Derived::Key(key)) => key, - _ => unreachable!(), +fn get_key(derive: DeriveBuiltin, subs: &Subs, var: Variable) -> DeriveKey { + match derive { + DeriveBuiltin::ToEncoder => match Derived::encoding(subs, var) { + Ok(Derived::Key(key)) => key, + _ => unreachable!(), + }, } } -pub(crate) fn derive_test(synth_input: S, check_golden: impl Fn(&str)) +pub(crate) fn derive_test(derive: DeriveBuiltin, synth_input: S, check_golden: impl Fn(&str)) where S: FnOnce(&mut Subs) -> Variable, { 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 LoadedModule { mut interns, - exposed_types_storage: exposed_encode_types, + exposed_types_storage, abilities_store, resolved_implementations, .. } = roc_load_internal::file::load_and_typecheck_str( &arena, - encode_path().file_name().unwrap().into(), + path.file_name().unwrap().into(), source, - encode_path().parent().unwrap().to_path_buf(), + path.parent().unwrap().to_path_buf(), Default::default(), target_info, roc_reporting::report::RenderTarget::ColorTerminal, @@ -339,15 +369,15 @@ where let mut subs = Subs::new(); let ident_ids = IdentIds::default(); 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 exposed_by_module = ExposedByModule::default(); exposed_by_module.insert( - ModuleId::ENCODE, + builtin_module, ExposedModuleTypes { - exposed_types_storage_subs: exposed_encode_types.clone(), + exposed_types_storage_subs: exposed_types_storage.clone(), resolved_implementations, }, ); @@ -370,8 +400,11 @@ where DERIVED_MODULE, subs, &interns, - exposed_encode_types, - abilities_store, + DeriveBuiltinEnv { + module_id: builtin_module, + exposed_types: exposed_types_storage, + abilities_store, + }, source_var, &derived_program, specialization_lsets,