mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-04 09:04:33 +00:00
Add test module for derivers
This commit is contained in:
parent
f1fa29fcfc
commit
ccd78a560f
7 changed files with 329 additions and 70 deletions
22
Cargo.lock
generated
22
Cargo.lock
generated
|
@ -4797,6 +4797,28 @@ dependencies = [
|
||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "test_derivers"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bumpalo",
|
||||||
|
"indoc",
|
||||||
|
"lazy_static",
|
||||||
|
"roc_builtins",
|
||||||
|
"roc_can",
|
||||||
|
"roc_collections",
|
||||||
|
"roc_constrain",
|
||||||
|
"roc_load_internal",
|
||||||
|
"roc_module",
|
||||||
|
"roc_mono",
|
||||||
|
"roc_region",
|
||||||
|
"roc_reporting",
|
||||||
|
"roc_solve",
|
||||||
|
"roc_target",
|
||||||
|
"roc_types",
|
||||||
|
"ven_pretty",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "test_gen"
|
name = "test_gen"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
|
@ -18,6 +18,7 @@ members = [
|
||||||
"compiler/mono",
|
"compiler/mono",
|
||||||
"compiler/alias_analysis",
|
"compiler/alias_analysis",
|
||||||
"compiler/test_mono",
|
"compiler/test_mono",
|
||||||
|
"compiler/test_derivers",
|
||||||
"compiler/load",
|
"compiler/load",
|
||||||
"compiler/load_internal",
|
"compiler/load_internal",
|
||||||
"compiler/gen_llvm",
|
"compiler/gen_llvm",
|
||||||
|
|
|
@ -220,6 +220,73 @@ impl<Phase: ResolvePhase> IAbilitiesStore<Phase> {
|
||||||
self.next_specialization_id += 1;
|
self.next_specialization_id += 1;
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a store from [`self`] that closes over the abilities/members given by the
|
||||||
|
/// imported `symbols`, and their specializations (if any).
|
||||||
|
pub fn closure_from_imported(&self, symbols: &VecSet<Symbol>) -> PendingAbilitiesStore {
|
||||||
|
let Self {
|
||||||
|
members_of_ability,
|
||||||
|
ability_members,
|
||||||
|
declared_specializations,
|
||||||
|
|
||||||
|
// Covered by `declared_specializations`
|
||||||
|
specialization_to_root: _,
|
||||||
|
|
||||||
|
// Taking closure for a new module, so specialization IDs can be fresh
|
||||||
|
next_specialization_id: _,
|
||||||
|
resolved_specializations: _,
|
||||||
|
} = self;
|
||||||
|
|
||||||
|
let mut new = PendingAbilitiesStore::default();
|
||||||
|
|
||||||
|
// 1. Figure out the abilities we need to introduce.
|
||||||
|
let mut abilities_to_introduce = VecSet::with_capacity(2);
|
||||||
|
symbols.iter().for_each(|symbol| {
|
||||||
|
if let Some(member_data) = ability_members.get(symbol) {
|
||||||
|
// If the symbol is member of an ability, we need to capture the entire ability.
|
||||||
|
abilities_to_introduce.insert(member_data.parent_ability);
|
||||||
|
}
|
||||||
|
if members_of_ability.contains_key(symbol) {
|
||||||
|
abilities_to_introduce.insert(*symbol);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 2. Add each ability, and any specializations of its members we know about.
|
||||||
|
for ability in abilities_to_introduce.into_iter() {
|
||||||
|
let members = members_of_ability.get(&ability).unwrap();
|
||||||
|
let mut imported_member_data = Vec::with_capacity(members.len());
|
||||||
|
for member in members {
|
||||||
|
let AbilityMemberData {
|
||||||
|
parent_ability,
|
||||||
|
region,
|
||||||
|
typ: _,
|
||||||
|
} = ability_members.get(member).unwrap().clone();
|
||||||
|
// All external members need to be marked as imported. We'll figure out their real
|
||||||
|
// type variables when it comes time to solve the module we're currently importing
|
||||||
|
// into.
|
||||||
|
let imported_data = AbilityMemberData {
|
||||||
|
parent_ability,
|
||||||
|
region,
|
||||||
|
typ: PendingMemberType::Imported,
|
||||||
|
};
|
||||||
|
|
||||||
|
imported_member_data.push((*member, imported_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
new.register_ability(ability, imported_member_data);
|
||||||
|
|
||||||
|
// Add any specializations of the ability's members we know about.
|
||||||
|
declared_specializations
|
||||||
|
.iter()
|
||||||
|
.filter(|((member, _), _)| members.contains(member))
|
||||||
|
.for_each(|(&(member, typ), specialization)| {
|
||||||
|
new.register_specializing_symbol(specialization.symbol, member);
|
||||||
|
new.import_specialization(member, typ, specialization);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
new
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IAbilitiesStore<Resolved> {
|
impl IAbilitiesStore<Resolved> {
|
||||||
|
@ -326,73 +393,6 @@ impl IAbilitiesStore<Pending> {
|
||||||
debug_assert!(old_spec.is_none(), "Replacing existing specialization");
|
debug_assert!(old_spec.is_none(), "Replacing existing specialization");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a store from [`self`] that closes over the abilities/members given by the
|
|
||||||
/// imported `symbols`, and their specializations (if any).
|
|
||||||
pub fn closure_from_imported(&self, symbols: &VecSet<Symbol>) -> Self {
|
|
||||||
let Self {
|
|
||||||
members_of_ability,
|
|
||||||
ability_members,
|
|
||||||
declared_specializations,
|
|
||||||
|
|
||||||
// Covered by `declared_specializations`
|
|
||||||
specialization_to_root: _,
|
|
||||||
|
|
||||||
// Taking closure for a new module, so specialization IDs can be fresh
|
|
||||||
next_specialization_id: _,
|
|
||||||
resolved_specializations: _,
|
|
||||||
} = self;
|
|
||||||
|
|
||||||
let mut new = PendingAbilitiesStore::default();
|
|
||||||
|
|
||||||
// 1. Figure out the abilities we need to introduce.
|
|
||||||
let mut abilities_to_introduce = VecSet::with_capacity(2);
|
|
||||||
symbols.iter().for_each(|symbol| {
|
|
||||||
if let Some(member_data) = ability_members.get(symbol) {
|
|
||||||
// If the symbol is member of an ability, we need to capture the entire ability.
|
|
||||||
abilities_to_introduce.insert(member_data.parent_ability);
|
|
||||||
}
|
|
||||||
if members_of_ability.contains_key(symbol) {
|
|
||||||
abilities_to_introduce.insert(*symbol);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 2. Add each ability, and any specializations of its members we know about.
|
|
||||||
for ability in abilities_to_introduce.into_iter() {
|
|
||||||
let members = members_of_ability.get(&ability).unwrap();
|
|
||||||
let mut imported_member_data = Vec::with_capacity(members.len());
|
|
||||||
for member in members {
|
|
||||||
let AbilityMemberData {
|
|
||||||
parent_ability,
|
|
||||||
region,
|
|
||||||
typ: _,
|
|
||||||
} = ability_members.get(member).unwrap().clone();
|
|
||||||
// All external members need to be marked as imported. We'll figure out their real
|
|
||||||
// type variables when it comes time to solve the module we're currently importing
|
|
||||||
// into.
|
|
||||||
let imported_data = AbilityMemberData {
|
|
||||||
parent_ability,
|
|
||||||
region,
|
|
||||||
typ: PendingMemberType::Imported,
|
|
||||||
};
|
|
||||||
|
|
||||||
imported_member_data.push((*member, imported_data));
|
|
||||||
}
|
|
||||||
|
|
||||||
new.register_ability(ability, imported_member_data);
|
|
||||||
|
|
||||||
// Add any specializations of the ability's members we know about.
|
|
||||||
declared_specializations
|
|
||||||
.iter()
|
|
||||||
.filter(|((member, _), _)| members.contains(member))
|
|
||||||
.for_each(|(&(member, typ), specialization)| {
|
|
||||||
new.register_specializing_symbol(specialization.symbol, member);
|
|
||||||
new.import_specialization(member, typ, specialization);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
new
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn union(&mut self, other: Self) {
|
pub fn union(&mut self, other: Self) {
|
||||||
let Self {
|
let Self {
|
||||||
members_of_ability: other_members_of_ability,
|
members_of_ability: other_members_of_ability,
|
||||||
|
|
|
@ -46,7 +46,7 @@ use roc_solve::module::SolvedModule;
|
||||||
use roc_solve::solve;
|
use roc_solve::solve;
|
||||||
use roc_target::TargetInfo;
|
use roc_target::TargetInfo;
|
||||||
use roc_types::solved_types::Solved;
|
use roc_types::solved_types::Solved;
|
||||||
use roc_types::subs::{Subs, VarStore, Variable};
|
use roc_types::subs::{ExposedTypesStorageSubs, Subs, VarStore, Variable};
|
||||||
use roc_types::types::{Alias, AliasKind};
|
use roc_types::types::{Alias, AliasKind};
|
||||||
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
@ -510,6 +510,7 @@ pub struct LoadedModule {
|
||||||
pub dep_idents: IdentIdsByModule,
|
pub dep_idents: IdentIdsByModule,
|
||||||
pub exposed_aliases: MutMap<Symbol, Alias>,
|
pub exposed_aliases: MutMap<Symbol, Alias>,
|
||||||
pub exposed_values: Vec<Symbol>,
|
pub exposed_values: Vec<Symbol>,
|
||||||
|
pub exposed_types_storage: ExposedTypesStorageSubs,
|
||||||
pub sources: MutMap<ModuleId, (PathBuf, Box<str>)>,
|
pub sources: MutMap<ModuleId, (PathBuf, Box<str>)>,
|
||||||
pub timings: MutMap<ModuleId, ModuleTiming>,
|
pub timings: MutMap<ModuleId, ModuleTiming>,
|
||||||
pub documentation: MutMap<ModuleId, ModuleDocumentation>,
|
pub documentation: MutMap<ModuleId, ModuleDocumentation>,
|
||||||
|
@ -687,6 +688,7 @@ enum Msg<'a> {
|
||||||
solved_subs: Solved<Subs>,
|
solved_subs: Solved<Subs>,
|
||||||
exposed_vars_by_symbol: Vec<(Symbol, Variable)>,
|
exposed_vars_by_symbol: Vec<(Symbol, Variable)>,
|
||||||
exposed_aliases_by_symbol: MutMap<Symbol, (bool, Alias)>,
|
exposed_aliases_by_symbol: MutMap<Symbol, (bool, Alias)>,
|
||||||
|
exposed_types_storage: ExposedTypesStorageSubs,
|
||||||
dep_idents: IdentIdsByModule,
|
dep_idents: IdentIdsByModule,
|
||||||
documentation: MutMap<ModuleId, ModuleDocumentation>,
|
documentation: MutMap<ModuleId, ModuleDocumentation>,
|
||||||
abilities_store: AbilitiesStore,
|
abilities_store: AbilitiesStore,
|
||||||
|
@ -1404,6 +1406,7 @@ fn state_thread_step<'a>(
|
||||||
solved_subs,
|
solved_subs,
|
||||||
exposed_vars_by_symbol,
|
exposed_vars_by_symbol,
|
||||||
exposed_aliases_by_symbol,
|
exposed_aliases_by_symbol,
|
||||||
|
exposed_types_storage,
|
||||||
dep_idents,
|
dep_idents,
|
||||||
documentation,
|
documentation,
|
||||||
abilities_store,
|
abilities_store,
|
||||||
|
@ -1421,6 +1424,7 @@ fn state_thread_step<'a>(
|
||||||
solved_subs,
|
solved_subs,
|
||||||
exposed_aliases_by_symbol,
|
exposed_aliases_by_symbol,
|
||||||
exposed_vars_by_symbol,
|
exposed_vars_by_symbol,
|
||||||
|
exposed_types_storage,
|
||||||
dep_idents,
|
dep_idents,
|
||||||
documentation,
|
documentation,
|
||||||
abilities_store,
|
abilities_store,
|
||||||
|
@ -2209,6 +2213,7 @@ fn update<'a>(
|
||||||
solved_subs,
|
solved_subs,
|
||||||
exposed_vars_by_symbol: solved_module.exposed_vars_by_symbol,
|
exposed_vars_by_symbol: solved_module.exposed_vars_by_symbol,
|
||||||
exposed_aliases_by_symbol: solved_module.aliases,
|
exposed_aliases_by_symbol: solved_module.aliases,
|
||||||
|
exposed_types_storage: solved_module.exposed_types,
|
||||||
dep_idents,
|
dep_idents,
|
||||||
documentation,
|
documentation,
|
||||||
abilities_store,
|
abilities_store,
|
||||||
|
@ -2663,6 +2668,7 @@ fn finish(
|
||||||
solved: Solved<Subs>,
|
solved: Solved<Subs>,
|
||||||
exposed_aliases_by_symbol: MutMap<Symbol, Alias>,
|
exposed_aliases_by_symbol: MutMap<Symbol, Alias>,
|
||||||
exposed_vars_by_symbol: Vec<(Symbol, Variable)>,
|
exposed_vars_by_symbol: Vec<(Symbol, Variable)>,
|
||||||
|
exposed_types_storage: ExposedTypesStorageSubs,
|
||||||
dep_idents: IdentIdsByModule,
|
dep_idents: IdentIdsByModule,
|
||||||
documentation: MutMap<ModuleId, ModuleDocumentation>,
|
documentation: MutMap<ModuleId, ModuleDocumentation>,
|
||||||
abilities_store: AbilitiesStore,
|
abilities_store: AbilitiesStore,
|
||||||
|
@ -2697,6 +2703,7 @@ fn finish(
|
||||||
exposed_aliases: exposed_aliases_by_symbol,
|
exposed_aliases: exposed_aliases_by_symbol,
|
||||||
exposed_values,
|
exposed_values,
|
||||||
exposed_to_host: exposed_vars_by_symbol.into_iter().collect(),
|
exposed_to_host: exposed_vars_by_symbol.into_iter().collect(),
|
||||||
|
exposed_types_storage,
|
||||||
sources,
|
sources,
|
||||||
timings: state.timings,
|
timings: state.timings,
|
||||||
documentation,
|
documentation,
|
||||||
|
@ -3738,7 +3745,7 @@ impl<'a> BuildTask<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_imports(
|
pub fn add_imports(
|
||||||
my_module: ModuleId,
|
my_module: ModuleId,
|
||||||
subs: &mut Subs,
|
subs: &mut Subs,
|
||||||
mut pending_abilities: PendingAbilitiesStore,
|
mut pending_abilities: PendingAbilitiesStore,
|
||||||
|
@ -5013,7 +5020,7 @@ fn to_missing_platform_report(module_id: ModuleId, other: PlatformPath) -> Strin
|
||||||
/// Generic number types (Num, Int, Float, etc.) are treated as `DelayedAlias`es resolved during
|
/// Generic number types (Num, Int, Float, etc.) are treated as `DelayedAlias`es resolved during
|
||||||
/// type solving.
|
/// type solving.
|
||||||
/// All that remains are Signed8, Signed16, etc.
|
/// All that remains are Signed8, Signed16, etc.
|
||||||
fn default_aliases() -> roc_solve::solve::Aliases {
|
pub fn default_aliases() -> roc_solve::solve::Aliases {
|
||||||
use roc_types::types::Type;
|
use roc_types::types::Type;
|
||||||
|
|
||||||
let mut solve_aliases = roc_solve::solve::Aliases::default();
|
let mut solve_aliases = roc_solve::solve::Aliases::default();
|
||||||
|
|
28
compiler/test_derivers/Cargo.toml
Normal file
28
compiler/test_derivers/Cargo.toml
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
[package]
|
||||||
|
name = "test_derivers"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["The Roc Contributors"]
|
||||||
|
license = "UPL-1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "test_derives"
|
||||||
|
path = "src/tests.rs"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
roc_collections = { path = "../collections" }
|
||||||
|
roc_module = { path = "../module" }
|
||||||
|
roc_builtins = { path = "../builtins" }
|
||||||
|
roc_load_internal = { path = "../load_internal" }
|
||||||
|
roc_can = { path = "../can" }
|
||||||
|
roc_mono = { path = "../mono" }
|
||||||
|
roc_target = { path = "../roc_target" }
|
||||||
|
roc_types = { path = "../types" }
|
||||||
|
roc_reporting = { path = "../../reporting" }
|
||||||
|
roc_constrain = { path = "../constrain" }
|
||||||
|
roc_region = { path = "../region" }
|
||||||
|
roc_solve = { path = "../solve" }
|
||||||
|
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
indoc = "1.0.3"
|
||||||
|
ven_pretty = { path = "../../vendor/pretty" }
|
198
compiler/test_derivers/src/encoding.rs
Normal file
198
compiler/test_derivers/src/encoding.rs
Normal file
|
@ -0,0 +1,198 @@
|
||||||
|
#![cfg(test)]
|
||||||
|
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use bumpalo::Bump;
|
||||||
|
use roc_can::{
|
||||||
|
abilities::{AbilitiesStore, ResolvedSpecializations},
|
||||||
|
constraint::Constraints,
|
||||||
|
expected::Expected,
|
||||||
|
expr::Expr,
|
||||||
|
module::RigidVariables,
|
||||||
|
};
|
||||||
|
use roc_collections::VecSet;
|
||||||
|
use roc_constrain::{
|
||||||
|
expr::constrain_expr,
|
||||||
|
module::{ExposedByModule, ExposedForModule, ExposedModuleTypes},
|
||||||
|
};
|
||||||
|
use roc_load_internal::file::{add_imports, default_aliases, LoadedModule, Threading};
|
||||||
|
use roc_module::{
|
||||||
|
ident::ModuleName,
|
||||||
|
symbol::{IdentIds, Interns, ModuleId},
|
||||||
|
};
|
||||||
|
use roc_mono::derivers::encoding::Env;
|
||||||
|
use roc_region::all::{LineInfo, Region};
|
||||||
|
use roc_reporting::report::{type_problem, RocDocAllocator};
|
||||||
|
use roc_types::{
|
||||||
|
subs::{Content, ExposedTypesStorageSubs, FlatType, RecordFields, Subs, Variable},
|
||||||
|
types::{RecordField, Type},
|
||||||
|
};
|
||||||
|
use ven_pretty::DocAllocator;
|
||||||
|
|
||||||
|
use roc_mono::derivers::{encoding, synth_var};
|
||||||
|
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_derived_typechecks(
|
||||||
|
derived: Expr,
|
||||||
|
test_module: ModuleId,
|
||||||
|
mut test_subs: Subs,
|
||||||
|
interns: &Interns,
|
||||||
|
exposed_encode_types: ExposedTypesStorageSubs,
|
||||||
|
encode_abilities_store: AbilitiesStore,
|
||||||
|
) {
|
||||||
|
let mut constraints = Constraints::new();
|
||||||
|
let mut env = roc_constrain::expr::Env {
|
||||||
|
rigids: Default::default(),
|
||||||
|
resolutions_to_make: Default::default(),
|
||||||
|
home: test_module,
|
||||||
|
};
|
||||||
|
let constr = constrain_expr(
|
||||||
|
&mut constraints,
|
||||||
|
&mut env,
|
||||||
|
Region::zero(),
|
||||||
|
&derived,
|
||||||
|
Expected::NoExpectation(Type::Variable(test_subs.fresh_unnamed_flex_var())),
|
||||||
|
);
|
||||||
|
let encode_values_to_import = exposed_encode_types
|
||||||
|
.stored_vars_by_symbol
|
||||||
|
.keys()
|
||||||
|
.copied()
|
||||||
|
.collect::<VecSet<_>>();
|
||||||
|
let pending_abilities = encode_abilities_store.closure_from_imported(&encode_values_to_import);
|
||||||
|
let mut exposed_by_module = ExposedByModule::default();
|
||||||
|
exposed_by_module.insert(
|
||||||
|
ModuleId::ENCODE,
|
||||||
|
ExposedModuleTypes {
|
||||||
|
exposed_types_storage_subs: exposed_encode_types,
|
||||||
|
resolved_specializations: ResolvedSpecializations::default(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let exposed_for_module =
|
||||||
|
ExposedForModule::new(encode_values_to_import.iter(), exposed_by_module);
|
||||||
|
let mut def_types = Default::default();
|
||||||
|
let mut rigid_vars = Default::default();
|
||||||
|
let (import_variables, abilities_store) = add_imports(
|
||||||
|
test_module,
|
||||||
|
&mut test_subs,
|
||||||
|
pending_abilities,
|
||||||
|
exposed_for_module,
|
||||||
|
&mut def_types,
|
||||||
|
&mut rigid_vars,
|
||||||
|
);
|
||||||
|
let constr =
|
||||||
|
constraints.let_import_constraint(rigid_vars, def_types, constr, &import_variables);
|
||||||
|
|
||||||
|
let (_solved_subs, _, problems, _) = roc_solve::module::run_solve(
|
||||||
|
&constraints,
|
||||||
|
constr,
|
||||||
|
RigidVariables::default(),
|
||||||
|
test_subs,
|
||||||
|
default_aliases(),
|
||||||
|
abilities_store,
|
||||||
|
Default::default(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if !problems.is_empty() {
|
||||||
|
let filename = PathBuf::from("Test.roc");
|
||||||
|
let lines = LineInfo::new(" ");
|
||||||
|
let src_lines = vec![" "];
|
||||||
|
let mut reports = Vec::new();
|
||||||
|
let alloc = RocDocAllocator::new(&src_lines, test_module, &interns);
|
||||||
|
|
||||||
|
for problem in problems.into_iter() {
|
||||||
|
if let Some(report) = type_problem(&alloc, &lines, filename.clone(), problem.clone()) {
|
||||||
|
reports.push(report);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let has_reports = !reports.is_empty();
|
||||||
|
|
||||||
|
let doc = alloc
|
||||||
|
.stack(reports.into_iter().map(|v| v.pretty(&alloc)))
|
||||||
|
.append(if has_reports {
|
||||||
|
alloc.line()
|
||||||
|
} else {
|
||||||
|
alloc.nil()
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut buf = String::new();
|
||||||
|
doc.1
|
||||||
|
.render_raw(80, &mut roc_reporting::report::CiWrite::new(&mut buf))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
panic!("Derived does not typecheck:\n{}", buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn derive_test<S>(synth_input: S)
|
||||||
|
where
|
||||||
|
S: FnOnce(&mut Subs) -> Variable,
|
||||||
|
{
|
||||||
|
let arena = Bump::new();
|
||||||
|
let source = roc_builtins::roc::module_source(ModuleId::ENCODE);
|
||||||
|
let target_info = roc_target::TargetInfo::default_x86_64();
|
||||||
|
|
||||||
|
let LoadedModule {
|
||||||
|
mut interns,
|
||||||
|
exposed_types_storage: mut exposed_encode_types,
|
||||||
|
abilities_store,
|
||||||
|
..
|
||||||
|
} = roc_load_internal::file::load_and_typecheck_str(
|
||||||
|
&arena,
|
||||||
|
encode_path().file_name().unwrap().into(),
|
||||||
|
source,
|
||||||
|
&encode_path().parent().unwrap(),
|
||||||
|
Default::default(),
|
||||||
|
target_info,
|
||||||
|
roc_reporting::report::RenderTarget::ColorTerminal,
|
||||||
|
Threading::AllAvailable,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let test_module = interns.module_id(&ModuleName::from("Test"));
|
||||||
|
let mut test_subs = Subs::new();
|
||||||
|
let mut test_ident_ids = IdentIds::default();
|
||||||
|
|
||||||
|
let mut env = Env {
|
||||||
|
home: test_module,
|
||||||
|
arena: &arena,
|
||||||
|
subs: &mut test_subs,
|
||||||
|
ident_ids: &mut test_ident_ids,
|
||||||
|
exposed_encode_types: &mut exposed_encode_types,
|
||||||
|
};
|
||||||
|
|
||||||
|
let signature_var = synth_input(env.subs);
|
||||||
|
|
||||||
|
let derived = encoding::derive_to_encoder(&mut env, signature_var);
|
||||||
|
|
||||||
|
check_derived_typechecks(
|
||||||
|
derived,
|
||||||
|
test_module,
|
||||||
|
test_subs,
|
||||||
|
&interns,
|
||||||
|
exposed_encode_types,
|
||||||
|
abilities_store,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! synth {
|
||||||
|
(rcd{ $($field:literal: $typ:expr),* }) => {
|
||||||
|
|subs| {
|
||||||
|
let fields = RecordFields::insert_into_subs(subs, vec![ $( ($field.into(), RecordField::Required($typ)) ,)* ]);
|
||||||
|
synth_var(subs, Content::Structure(FlatType::Record(fields, Variable::EMPTY_RECORD)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn one_field_record() {
|
||||||
|
derive_test(synth!(rcd{ "a": Variable::U8 }))
|
||||||
|
}
|
3
compiler/test_derivers/src/tests.rs
Normal file
3
compiler/test_derivers/src/tests.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
#![cfg(test)]
|
||||||
|
|
||||||
|
mod encoding;
|
Loading…
Add table
Add a link
Reference in a new issue