mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-19 23:07:33 +03:00
Correct tests due to derived symbols
This commit is contained in:
parent
76a3772898
commit
19ea94bd43
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -4093,6 +4093,7 @@ dependencies = [
|
||||
"roc_can",
|
||||
"roc_collections",
|
||||
"roc_constrain",
|
||||
"roc_derive_key",
|
||||
"roc_exhaustive",
|
||||
"roc_load",
|
||||
"roc_module",
|
||||
|
@ -1,9 +1,10 @@
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_module::{
|
||||
ident::{Lowercase, TagName},
|
||||
symbol::Symbol,
|
||||
};
|
||||
use roc_types::subs::{Content, FlatType, GetSubsSlice, Subs, SubsFmtContent, Variable};
|
||||
use roc_types::subs::{Content, FlatType, GetSubsSlice, Subs, Variable};
|
||||
|
||||
use crate::DeriveError;
|
||||
|
||||
#[derive(Hash)]
|
||||
pub enum FlatEncodable {
|
||||
@ -55,32 +56,39 @@ impl FlatEncodableKey {
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! unexpected {
|
||||
($subs:expr, $var:expr) => {
|
||||
internal_error!(
|
||||
"Invalid content for toEncoder: {:?}",
|
||||
SubsFmtContent($subs.get_content_without_compacting($var), $subs)
|
||||
)
|
||||
};
|
||||
fn check_ext_var(
|
||||
subs: &Subs,
|
||||
ext_var: Variable,
|
||||
is_empty_ext: impl Fn(&Content) -> bool,
|
||||
) -> Result<(), DeriveError> {
|
||||
let ext_content = subs.get_content_without_compacting(ext_var);
|
||||
if is_empty_ext(ext_content) {
|
||||
Ok(())
|
||||
} else {
|
||||
match ext_content {
|
||||
Content::FlexVar(_) => Err(DeriveError::UnboundVar),
|
||||
_ => Err(DeriveError::Underivable),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FlatEncodable {
|
||||
pub(crate) fn from_var(subs: &Subs, var: Variable) -> FlatEncodable {
|
||||
pub(crate) fn from_var(subs: &Subs, var: Variable) -> Result<FlatEncodable, DeriveError> {
|
||||
use DeriveError::*;
|
||||
use FlatEncodable::*;
|
||||
match *subs.get_content_without_compacting(var) {
|
||||
Content::Structure(flat_type) => match flat_type {
|
||||
FlatType::Apply(sym, _) => match sym {
|
||||
Symbol::LIST_LIST => Key(FlatEncodableKey::List()),
|
||||
Symbol::SET_SET => Key(FlatEncodableKey::Set()),
|
||||
Symbol::DICT_DICT => Key(FlatEncodableKey::Dict()),
|
||||
Symbol::STR_STR => Immediate(Symbol::ENCODE_STRING),
|
||||
_ => unexpected!(subs, var),
|
||||
Symbol::LIST_LIST => Ok(Key(FlatEncodableKey::List())),
|
||||
Symbol::SET_SET => Ok(Key(FlatEncodableKey::Set())),
|
||||
Symbol::DICT_DICT => Ok(Key(FlatEncodableKey::Dict())),
|
||||
Symbol::STR_STR => Ok(Immediate(Symbol::ENCODE_STRING)),
|
||||
_ => Err(Underivable),
|
||||
},
|
||||
FlatType::Record(fields, ext) => {
|
||||
debug_assert!(matches!(
|
||||
subs.get_content_without_compacting(ext),
|
||||
Content::Structure(FlatType::EmptyRecord)
|
||||
));
|
||||
check_ext_var(subs, ext, |ext| {
|
||||
matches!(ext, Content::Structure(FlatType::EmptyRecord))
|
||||
})?;
|
||||
|
||||
let mut field_names: Vec<_> = subs
|
||||
.get_subs_slice(fields.field_names())
|
||||
@ -88,7 +96,8 @@ impl FlatEncodable {
|
||||
.cloned()
|
||||
.collect();
|
||||
field_names.sort();
|
||||
Key(FlatEncodableKey::Record(field_names))
|
||||
|
||||
Ok(Key(FlatEncodableKey::Record(field_names)))
|
||||
}
|
||||
FlatType::TagUnion(tags, ext) | FlatType::RecursiveTagUnion(_, tags, ext) => {
|
||||
// The recursion var doesn't matter, because the derived implementation will only
|
||||
@ -100,10 +109,10 @@ impl FlatEncodable {
|
||||
// [ A t1, B t1 t2 ] as R
|
||||
// look the same on the surface, because `R` is only somewhere inside of the
|
||||
// `t`-prefixed payload types.
|
||||
debug_assert!(matches!(
|
||||
subs.get_content_without_compacting(ext),
|
||||
Content::Structure(FlatType::EmptyTagUnion)
|
||||
));
|
||||
check_ext_var(subs, ext, |ext| {
|
||||
matches!(ext, Content::Structure(FlatType::EmptyTagUnion))
|
||||
})?;
|
||||
|
||||
let mut tag_names_and_payload_sizes: Vec<_> = tags
|
||||
.iter_all()
|
||||
.map(|(name_index, payload_slice_index)| {
|
||||
@ -114,44 +123,44 @@ impl FlatEncodable {
|
||||
})
|
||||
.collect();
|
||||
tag_names_and_payload_sizes.sort_by(|(t1, _), (t2, _)| t1.cmp(t2));
|
||||
Key(FlatEncodableKey::TagUnion(tag_names_and_payload_sizes))
|
||||
Ok(Key(FlatEncodableKey::TagUnion(tag_names_and_payload_sizes)))
|
||||
}
|
||||
FlatType::FunctionOrTagUnion(name_index, _, _) => Key(FlatEncodableKey::TagUnion(
|
||||
vec![(subs[name_index].clone(), 0)],
|
||||
FlatType::FunctionOrTagUnion(name_index, _, _) => Ok(Key(
|
||||
FlatEncodableKey::TagUnion(vec![(subs[name_index].clone(), 0)]),
|
||||
)),
|
||||
FlatType::EmptyRecord => Key(FlatEncodableKey::Record(vec![])),
|
||||
FlatType::EmptyTagUnion => Key(FlatEncodableKey::TagUnion(vec![])),
|
||||
FlatType::EmptyRecord => Ok(Key(FlatEncodableKey::Record(vec![]))),
|
||||
FlatType::EmptyTagUnion => Ok(Key(FlatEncodableKey::TagUnion(vec![]))),
|
||||
//
|
||||
FlatType::Erroneous(_) => unexpected!(subs, var),
|
||||
FlatType::Func(..) => unexpected!(subs, var),
|
||||
FlatType::Erroneous(_) => Err(Underivable),
|
||||
FlatType::Func(..) => Err(Underivable),
|
||||
},
|
||||
Content::Alias(sym, _, real_var, _) => match sym {
|
||||
Symbol::NUM_U8 => Immediate(Symbol::ENCODE_U8),
|
||||
Symbol::NUM_U16 => Immediate(Symbol::ENCODE_U16),
|
||||
Symbol::NUM_U32 => Immediate(Symbol::ENCODE_U32),
|
||||
Symbol::NUM_U64 => Immediate(Symbol::ENCODE_U64),
|
||||
Symbol::NUM_U128 => Immediate(Symbol::ENCODE_U128),
|
||||
Symbol::NUM_I8 => Immediate(Symbol::ENCODE_I8),
|
||||
Symbol::NUM_I16 => Immediate(Symbol::ENCODE_I16),
|
||||
Symbol::NUM_I32 => Immediate(Symbol::ENCODE_I32),
|
||||
Symbol::NUM_I64 => Immediate(Symbol::ENCODE_I64),
|
||||
Symbol::NUM_I128 => Immediate(Symbol::ENCODE_I128),
|
||||
Symbol::NUM_DEC => Immediate(Symbol::ENCODE_DEC),
|
||||
Symbol::NUM_F32 => Immediate(Symbol::ENCODE_F32),
|
||||
Symbol::NUM_F64 => Immediate(Symbol::ENCODE_F64),
|
||||
Symbol::NUM_U8 => Ok(Immediate(Symbol::ENCODE_U8)),
|
||||
Symbol::NUM_U16 => Ok(Immediate(Symbol::ENCODE_U16)),
|
||||
Symbol::NUM_U32 => Ok(Immediate(Symbol::ENCODE_U32)),
|
||||
Symbol::NUM_U64 => Ok(Immediate(Symbol::ENCODE_U64)),
|
||||
Symbol::NUM_U128 => Ok(Immediate(Symbol::ENCODE_U128)),
|
||||
Symbol::NUM_I8 => Ok(Immediate(Symbol::ENCODE_I8)),
|
||||
Symbol::NUM_I16 => Ok(Immediate(Symbol::ENCODE_I16)),
|
||||
Symbol::NUM_I32 => Ok(Immediate(Symbol::ENCODE_I32)),
|
||||
Symbol::NUM_I64 => Ok(Immediate(Symbol::ENCODE_I64)),
|
||||
Symbol::NUM_I128 => Ok(Immediate(Symbol::ENCODE_I128)),
|
||||
Symbol::NUM_DEC => Ok(Immediate(Symbol::ENCODE_DEC)),
|
||||
Symbol::NUM_F32 => Ok(Immediate(Symbol::ENCODE_F32)),
|
||||
Symbol::NUM_F64 => Ok(Immediate(Symbol::ENCODE_F64)),
|
||||
// TODO: I believe it is okay to unwrap opaques here because derivers are only used
|
||||
// by the backend, and the backend treats opaques like structural aliases.
|
||||
_ => Self::from_var(subs, real_var),
|
||||
},
|
||||
Content::RangedNumber(real_var, _) => Self::from_var(subs, real_var),
|
||||
//
|
||||
Content::RecursionVar { .. } => unexpected!(subs, var),
|
||||
Content::Error => unexpected!(subs, var),
|
||||
Content::RecursionVar { .. } => Err(Underivable),
|
||||
Content::Error => Err(Underivable),
|
||||
Content::FlexVar(_)
|
||||
| Content::RigidVar(_)
|
||||
| Content::FlexAbleVar(_, _)
|
||||
| Content::RigidAbleVar(_, _) => unexpected!(subs, var),
|
||||
Content::LambdaSet(_) => unexpected!(subs, var),
|
||||
| Content::RigidAbleVar(_, _) => Err(UnboundVar),
|
||||
Content::LambdaSet(_) => Err(Underivable),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,15 @@ use roc_collections::MutMap;
|
||||
use roc_module::symbol::{IdentIds, ModuleId, Symbol};
|
||||
use roc_types::subs::{Subs, Variable};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum DeriveError {
|
||||
/// Unbound variable present in the type-to-derive. It may be possible to derive for this type
|
||||
/// once the unbound variable is resolved.
|
||||
UnboundVar,
|
||||
/// The type is underivable for the given ability member.
|
||||
Underivable,
|
||||
}
|
||||
|
||||
#[derive(Hash, PartialEq, Eq, Debug)]
|
||||
#[repr(u8)]
|
||||
pub enum DeriveKey {
|
||||
@ -52,10 +61,10 @@ pub enum Derived {
|
||||
}
|
||||
|
||||
impl Derived {
|
||||
pub fn encoding(subs: &Subs, var: Variable) -> Self {
|
||||
match encoding::FlatEncodable::from_var(subs, var) {
|
||||
FlatEncodable::Immediate(imm) => Derived::Immediate(imm),
|
||||
FlatEncodable::Key(repr) => Derived::Key(DeriveKey::ToEncoder(repr)),
|
||||
pub fn encoding(subs: &Subs, var: Variable) -> Result<Self, DeriveError> {
|
||||
match encoding::FlatEncodable::from_var(subs, var)? {
|
||||
FlatEncodable::Immediate(imm) => Ok(Derived::Immediate(imm)),
|
||||
FlatEncodable::Key(repr) => Ok(Derived::Key(DeriveKey::ToEncoder(repr))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ use roc_collections::VecSet;
|
||||
use roc_debug_flags::dbg_do;
|
||||
#[cfg(debug_assertions)]
|
||||
use roc_debug_flags::ROC_VERIFY_RIGID_LET_GENERALIZED;
|
||||
use roc_derive_key::{Derived, GlobalDerivedSymbols};
|
||||
use roc_derive_key::{DeriveError, Derived, GlobalDerivedSymbols};
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_module::ident::TagName;
|
||||
use roc_module::symbol::{ModuleId, Symbol};
|
||||
@ -1804,29 +1804,44 @@ fn compact_lambda_set<P: Phase>(
|
||||
Structure(_) | Alias(_, _, _, AliasKind::Structural) => {
|
||||
// This is a structural type, find the name of the derived ability function it
|
||||
// should use.
|
||||
let specialization_symbol = match Derived::encoding(subs, var) {
|
||||
Derived::Immediate(symbol) => symbol,
|
||||
Derived::Key(derive_key) => {
|
||||
let mut derived_symbols = derived_symbols.write().unwrap();
|
||||
derived_symbols.get_or_insert(derive_key)
|
||||
match Derived::encoding(subs, var) {
|
||||
Ok(derived) => {
|
||||
let specialization_symbol = match derived {
|
||||
Derived::Immediate(symbol) => symbol,
|
||||
Derived::Key(derive_key) => {
|
||||
let mut derived_symbols = derived_symbols.write().unwrap();
|
||||
derived_symbols.get_or_insert(derive_key)
|
||||
}
|
||||
};
|
||||
|
||||
let specialization_symbol_slice = UnionLabels::insert_into_subs(
|
||||
subs,
|
||||
vec![(specialization_symbol, vec![])],
|
||||
);
|
||||
let lambda_set_for_derived = subs.fresh(Descriptor {
|
||||
content: LambdaSet(subs::LambdaSet {
|
||||
solved: specialization_symbol_slice,
|
||||
recursion_var: OptVariable::NONE,
|
||||
unspecialized: SubsSlice::default(),
|
||||
}),
|
||||
rank: target_rank,
|
||||
mark: Mark::NONE,
|
||||
copy: OptVariable::NONE,
|
||||
});
|
||||
|
||||
specialized_to_unify_with.push(lambda_set_for_derived);
|
||||
continue;
|
||||
}
|
||||
Err(DeriveError::UnboundVar) => {
|
||||
// not specialized yet
|
||||
new_unspecialized.push(uls);
|
||||
continue;
|
||||
}
|
||||
Err(DeriveError::Underivable) => {
|
||||
// we should have reported an error for this; drop the lambda set.
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let specialization_symbol_slice =
|
||||
UnionLabels::insert_into_subs(subs, vec![(specialization_symbol, vec![])]);
|
||||
let lambda_set_for_derived = subs.fresh(Descriptor {
|
||||
content: LambdaSet(subs::LambdaSet {
|
||||
solved: specialization_symbol_slice,
|
||||
recursion_var: OptVariable::NONE,
|
||||
unspecialized: SubsSlice::default(),
|
||||
}),
|
||||
rank: target_rank,
|
||||
mark: Mark::NONE,
|
||||
copy: OptVariable::NONE,
|
||||
});
|
||||
|
||||
specialized_to_unify_with.push(lambda_set_for_derived);
|
||||
continue;
|
||||
}
|
||||
Alias(opaque, _, _, AliasKind::Opaque) => opaque,
|
||||
Error => {
|
||||
|
@ -125,6 +125,7 @@ fn check_derived_typechecks(
|
||||
default_aliases(),
|
||||
abilities_store,
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
let subs = solved_subs.inner_mut();
|
||||
|
||||
@ -205,6 +206,7 @@ where
|
||||
subs: &mut test_subs,
|
||||
ident_ids: interns.all_ident_ids.get_mut(&test_module).unwrap(),
|
||||
exposed_encode_types: &mut exposed_encode_types,
|
||||
derived_symbols: &Default::default(),
|
||||
};
|
||||
|
||||
let derived = encoding::derive_to_encoder(&mut env, key);
|
||||
@ -227,7 +229,7 @@ where
|
||||
|
||||
fn get_key(subs: &Subs, var: Variable) -> FlatEncodableKey {
|
||||
match Derived::encoding(subs, var) {
|
||||
Derived::Key(DeriveKey::ToEncoder(repr)) => repr,
|
||||
Ok(Derived::Key(DeriveKey::ToEncoder(repr))) => repr,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
@ -260,7 +262,7 @@ where
|
||||
|
||||
let key = Derived::encoding(&subs, var);
|
||||
|
||||
assert_eq!(key, Derived::Immediate(immediate));
|
||||
assert_eq!(key, Ok(Derived::Immediate(immediate)));
|
||||
}
|
||||
|
||||
// Writing out the types into content is terrible, so let's use a DSL at least for testing
|
||||
|
@ -22,6 +22,7 @@ bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||
|
||||
[dev-dependencies]
|
||||
roc_constrain = { path = "../compiler/constrain" }
|
||||
roc_derive_key = { path = "../compiler/derive_key" }
|
||||
roc_builtins = { path = "../compiler/builtins" }
|
||||
roc_load = { path = "../compiler/load" }
|
||||
roc_problem = { path = "../compiler/problem" }
|
||||
|
@ -11,6 +11,7 @@ use roc_can::scope::Scope;
|
||||
use roc_collections::all::{ImMap, MutMap, SendSet};
|
||||
use roc_constrain::expr::constrain_expr;
|
||||
use roc_constrain::module::introduce_builtin_imports;
|
||||
use roc_derive_key::GlobalDerivedSymbols;
|
||||
use roc_module::symbol::{IdentIds, Interns, ModuleId, ModuleIds};
|
||||
use roc_parse::parser::{SourceError, SyntaxError};
|
||||
use roc_problem::can::Problem;
|
||||
@ -35,6 +36,7 @@ pub fn infer_expr(
|
||||
pending_derives: PendingDerives,
|
||||
aliases: &mut Aliases,
|
||||
abilities_store: &mut AbilitiesStore,
|
||||
derived_symbols: GlobalDerivedSymbols,
|
||||
expr_var: Variable,
|
||||
) -> (Content, Subs) {
|
||||
let (solved, _) = solve::run(
|
||||
@ -45,6 +47,7 @@ pub fn infer_expr(
|
||||
constraint,
|
||||
pending_derives,
|
||||
abilities_store,
|
||||
derived_symbols,
|
||||
);
|
||||
|
||||
let content = *solved.inner().get_content_without_compacting(expr_var);
|
||||
|
@ -234,6 +234,7 @@ mod test_reporting {
|
||||
PendingDerives::default(),
|
||||
&mut solve_aliases,
|
||||
&mut abilities_store,
|
||||
Default::default(),
|
||||
var,
|
||||
);
|
||||
|
||||
@ -1268,9 +1269,9 @@ mod test_reporting {
|
||||
r#"
|
||||
── CIRCULAR TYPE ───────────────────────────────────────── /code/proj/Main.roc ─
|
||||
|
||||
I'm inferring a weird self-referential type for `g`:
|
||||
I'm inferring a weird self-referential type for `f`:
|
||||
|
||||
2│ g = \x -> f [x]
|
||||
1│ f = \x -> g x
|
||||
^
|
||||
|
||||
Here is my best effort at writing down the type. You will see ∞ for
|
||||
@ -1281,9 +1282,9 @@ mod test_reporting {
|
||||
|
||||
── CIRCULAR TYPE ───────────────────────────────────────── /code/proj/Main.roc ─
|
||||
|
||||
I'm inferring a weird self-referential type for `f`:
|
||||
I'm inferring a weird self-referential type for `g`:
|
||||
|
||||
1│ f = \x -> g x
|
||||
2│ g = \x -> f [x]
|
||||
^
|
||||
|
||||
Here is my best effort at writing down the type. You will see ∞ for
|
||||
|
Loading…
Reference in New Issue
Block a user