Correct tests due to derived symbols

This commit is contained in:
Ayaz Hafiz 2022-06-21 11:45:57 -04:00
parent 76a3772898
commit 19ea94bd43
No known key found for this signature in database
GPG Key ID: 0E2A37416A25EF58
8 changed files with 121 additions and 80 deletions

1
Cargo.lock generated
View File

@ -4093,6 +4093,7 @@ dependencies = [
"roc_can",
"roc_collections",
"roc_constrain",
"roc_derive_key",
"roc_exhaustive",
"roc_load",
"roc_module",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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