From 5a872a1bddc87b08ed5d576614b1332431938875 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Mon, 28 Aug 2023 21:45:01 -0400 Subject: [PATCH 01/40] Add Nat to Inspect ability --- crates/compiler/builtins/roc/Inspect.roc | 2 ++ crates/compiler/module/src/symbol.rs | 1 + 2 files changed, 3 insertions(+) diff --git a/crates/compiler/builtins/roc/Inspect.roc b/crates/compiler/builtins/roc/Inspect.roc index f4009f38fa..79103f4c2c 100644 --- a/crates/compiler/builtins/roc/Inspect.roc +++ b/crates/compiler/builtins/roc/Inspect.roc @@ -26,6 +26,7 @@ interface Inspect i64, u128, i128, + nat, f32, f64, dec, @@ -73,6 +74,7 @@ InspectFormatter implements i64 : I64 -> Inspector f where f implements InspectFormatter u128 : U128 -> Inspector f where f implements InspectFormatter i128 : I128 -> Inspector f where f implements InspectFormatter + nat : Nat -> Inspector f where f implements InspectFormatter f32 : F32 -> Inspector f where f implements InspectFormatter f64 : F64 -> Inspector f where f implements InspectFormatter dec : Dec -> Inspector f where f implements InspectFormatter diff --git a/crates/compiler/module/src/symbol.rs b/crates/compiler/module/src/symbol.rs index e4266a158c..8db42669aa 100644 --- a/crates/compiler/module/src/symbol.rs +++ b/crates/compiler/module/src/symbol.rs @@ -1625,6 +1625,7 @@ define_builtins! { 29 INSPECT_CUSTOM: "custom" 30 INSPECT_APPLY: "apply" 31 INSPECT_TO_INSPECTOR: "toInspector" + 32 INSPECT_NAT: "nat" } 15 JSON: "TotallyNotJson" => { 0 JSON_JSON: "TotallyNotJson" From fb9e0fc777990fa4a31992abe238d57b92efd3f0 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Mon, 28 Aug 2023 21:46:08 -0400 Subject: [PATCH 02/40] Add Inspect to obligation checker --- crates/compiler/solve/src/ability.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/crates/compiler/solve/src/ability.rs b/crates/compiler/solve/src/ability.rs index 83272ccd0f..5521e8e332 100644 --- a/crates/compiler/solve/src/ability.rs +++ b/crates/compiler/solve/src/ability.rs @@ -373,7 +373,11 @@ impl ObligationCache { let ImplKey { opaque, ability } = impl_key; - let has_declared_impl = abilities_store.has_declared_implementation(opaque, ability); + // Every type has the Inspect ability automatically, even opaques with no `implements` declaration. + // (Those opaques get a default implementation that returns something along the lines of "") + let is_inspect = ability == Symbol::INSPECT_INSPECT_ABILITY; + let has_known_impl = + is_inspect || abilities_store.has_declared_implementation(opaque, ability); // Some builtins, like Float32 and Bool, would have a cyclic dependency on Encode/Decode/etc. // if their Roc implementations explicitly defined some abilities they support. @@ -385,15 +389,13 @@ impl ObligationCache { _ => false, }; - let has_declared_impl = has_declared_impl || builtin_opaque_impl_ok(); - - let obligation_result = if !has_declared_impl { + let obligation_result = if has_known_impl || builtin_opaque_impl_ok() { + Ok(()) + } else { Err(Unfulfilled::OpaqueDoesNotImplement { typ: opaque, ability, }) - } else { - Ok(()) }; self.impl_cache.insert(impl_key, obligation_result); From d0841fb0189e106fe82236259288250a5eda629c Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Mon, 28 Aug 2023 21:46:17 -0400 Subject: [PATCH 03/40] Add derive key for Inspect --- crates/compiler/can/src/derive.rs | 40 +++++ crates/compiler/derive/src/lib.rs | 5 +- crates/compiler/derive_key/src/inspect.rs | 194 ++++++++++++++++++++++ crates/compiler/derive_key/src/lib.rs | 16 ++ crates/compiler/derive_key/src/util.rs | 4 + crates/compiler/module/src/symbol.rs | 1 + 6 files changed, 259 insertions(+), 1 deletion(-) create mode 100644 crates/compiler/derive_key/src/inspect.rs diff --git a/crates/compiler/can/src/derive.rs b/crates/compiler/can/src/derive.rs index fd85aaa514..09623703e7 100644 --- a/crates/compiler/can/src/derive.rs +++ b/crates/compiler/can/src/derive.rs @@ -213,6 +213,42 @@ fn is_eq<'a>(env: &mut Env<'a>, at_opaque: &'a str) -> ast::Expr<'a> { ) } +fn to_inspector<'a>(env: &mut Env<'a>, at_opaque: &'a str) -> ast::Expr<'a> { + let alloc_pat = |it| env.arena.alloc(Loc::at(DERIVED_REGION, it)); + let alloc_expr = |it| env.arena.alloc(Loc::at(DERIVED_REGION, it)); + + let payload = "#payload"; + + // \@Opaq payload + let opaque_ref = alloc_pat(ast::Pattern::OpaqueRef(at_opaque)); + let opaque_apply_pattern = ast::Pattern::Apply( + opaque_ref, + &*env + .arena + .alloc([Loc::at(DERIVED_REGION, ast::Pattern::Identifier(payload))]), + ); + + // Inspect.toInspector payload + let call_member = alloc_expr(ast::Expr::Apply( + alloc_expr(ast::Expr::Var { + module_name: "Inspect", + ident: "toInspector", + }), + &*env.arena.alloc([&*alloc_expr(ast::Expr::Var { + module_name: "", + ident: payload, + })]), + roc_module::called_via::CalledVia::Space, + )); + + // \@Opaq payload -> Inspect.toInspector payload + ast::Expr::Closure( + env.arena + .alloc([Loc::at(DERIVED_REGION, opaque_apply_pattern)]), + call_member, + ) +} + pub const DERIVED_REGION: Region = Region::zero(); pub(crate) fn synthesize_member_impl<'a>( @@ -232,6 +268,10 @@ pub(crate) fn synthesize_member_impl<'a>( Symbol::DECODE_DECODER => (format!("#{opaque_name}_decoder"), decoder(env, at_opaque)), Symbol::HASH_HASH => (format!("#{opaque_name}_hash"), hash(env, at_opaque)), Symbol::BOOL_IS_EQ => (format!("#{opaque_name}_isEq"), is_eq(env, at_opaque)), + Symbol::INSPECT_TO_INSPECTOR => ( + format!("#{opaque_name}_toInspector"), + to_inspector(env, at_opaque), + ), other => internal_error!("{:?} is not a derivable ability member!", other), }; diff --git a/crates/compiler/derive/src/lib.rs b/crates/compiler/derive/src/lib.rs index 43d547ddb5..a1cdb81cc3 100644 --- a/crates/compiler/derive/src/lib.rs +++ b/crates/compiler/derive/src/lib.rs @@ -8,7 +8,7 @@ use roc_can::expr::Expr; use roc_can::pattern::Pattern; use roc_can::{def::Def, module::ExposedByModule}; use roc_collections::{MutMap, VecMap}; -use roc_derive_key::DeriveKey; +use roc_derive_key::{inspect, DeriveKey}; use roc_module::symbol::{IdentIds, ModuleId, Symbol}; use roc_region::all::Loc; use roc_types::subs::{ @@ -79,6 +79,9 @@ fn build_derived_body( decoding::derive_decoder(&mut env, decoder_key, derived_symbol) } DeriveKey::Hash(hash_key) => hash::derive_hash(&mut env, hash_key, derived_symbol), + DeriveKey::ToInspector(to_inspector_key) => { + inspect::derive_to_inspector(&mut env, to_inspector_key, derived_symbol) + } }; let def = Def { diff --git a/crates/compiler/derive_key/src/inspect.rs b/crates/compiler/derive_key/src/inspect.rs new file mode 100644 index 0000000000..55045b9551 --- /dev/null +++ b/crates/compiler/derive_key/src/inspect.rs @@ -0,0 +1,194 @@ +use roc_module::{ + ident::{Lowercase, TagName}, + symbol::Symbol, +}; +use roc_types::subs::{Content, FlatType, GetSubsSlice, Subs, Variable}; + +use crate::{ + util::{ + check_derivable_ext_var, debug_name_fn, debug_name_record, debug_name_tag, debug_name_tuple, + }, + DeriveError, +}; + +#[derive(Hash)] +pub enum FlatInspectable { + Immediate(Symbol), + Key(FlatInspectableKey), +} + +#[derive(Hash, PartialEq, Eq, Debug, Clone)] +pub enum FlatInspectableKey { + List(/* takes one variable */), + Set(/* takes one variable */), + Dict(/* takes two variables */), + // Unfortunate that we must allocate here, c'est la vie + Record(Vec), + Tuple(u32), + TagUnion(Vec<(TagName, u16)>), + Function(u32 /* arity; +1 for return type */), + Error, + TypeVar(String), +} + +impl FlatInspectableKey { + pub(crate) fn debug_name(&self) -> String { + match self { + FlatInspectableKey::List() => "list".to_string(), + FlatInspectableKey::Set() => "set".to_string(), + FlatInspectableKey::Dict() => "dict".to_string(), + FlatInspectableKey::Record(fields) => debug_name_record(fields), + FlatInspectableKey::Tuple(arity) => debug_name_tuple(*arity), + FlatInspectableKey::TagUnion(tags) => debug_name_tag(tags), + FlatInspectableKey::Function(arity) => debug_name_fn(*arity), + FlatInspectableKey::Error => "error".to_string(), + FlatInspectableKey::TypeVar(name) => format!("typeVariable({name})"), + } + } +} + +impl FlatInspectable { + pub(crate) fn from_var(subs: &Subs, var: Variable) -> FlatInspectable { + use DeriveError::*; + use FlatInspectable::*; + match *subs.get_content_without_compacting(var) { + Content::Structure(flat_type) => match flat_type { + FlatType::Apply(sym, _) => match sym { + Symbol::LIST_LIST => Key(FlatInspectableKey::List()), + Symbol::SET_SET => Key(FlatInspectableKey::Set()), + Symbol::DICT_DICT => Key(FlatInspectableKey::Dict()), + Symbol::STR_STR => Immediate(Symbol::INSPECT_STR), + Symbol::NUM_NUM => { + todo!(); + // TODO need to match again to see what type of Num it was, then + // use Symbol::INSPECT_WHATEVERNUMBERTYPE + } + _ => Immediate(Symbol::INSPECT_OPAQUE), + }, + FlatType::Record(fields, ext) => { + let (fields_iter, ext) = fields.unsorted_iterator_and_ext(subs, ext); + + check_derivable_ext_var(subs, ext, |ext| { + todo!(); // TODO open records can still derive Inspect, but we need to decide how/if to render the ext var. + + // matches!(ext, Content::Structure(FlatType::EmptyRecord)) + }); + + let mut field_names = Vec::with_capacity(fields.len()); + for (field_name, _) in fields_iter { + field_names.push(field_name.clone()); + } + + field_names.sort(); + + Key(FlatInspectableKey::Record(field_names)) + } + FlatType::Tuple(elems, ext) => { + let (elems_iter, ext) = elems.sorted_iterator_and_ext(subs, ext); + + check_derivable_ext_var(subs, ext, |ext| { + todo!(); // TODO open tuples can still derive Inspect, but we need to decide how/if to render the ext var. + + // matches!(ext, Content::Structure(FlatType::EmptyTuple)) + }); + + Key(FlatInspectableKey::Tuple(elems_iter.count() as _)) + } + FlatType::TagUnion(tags, ext) | FlatType::RecursiveTagUnion(_, tags, ext) => { + // The recursion var doesn't matter, because the derived implementation will only + // look on the surface of the tag union type, and more over the payloads of the + // arguments will be left generic for the monomorphizer to fill in with the + // appropriate type. That is, + // [ A t1, B t1 t2 ] + // and + // [ 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. + let (tags_iter, ext) = tags.unsorted_tags_and_ext(subs, ext); + + check_derivable_ext_var(subs, ext.var(), |ext| { + todo!(); // TODO open tag unions can still derive Inspect, but we need to decide how/if to render the ext var. + + // matches!(ext, Content::Structure(FlatType::EmptyTagUnion)) + }); + + let mut tag_names_and_payload_sizes: Vec<_> = tags_iter + .tags + .into_iter() + .map(|(name, payload_slice)| { + let payload_size = payload_slice.len(); + (name.clone(), payload_size as _) + }) + .collect(); + + tag_names_and_payload_sizes.sort_by(|(t1, _), (t2, _)| t1.cmp(t2)); + + Key(FlatInspectableKey::TagUnion(tag_names_and_payload_sizes)) + } + FlatType::FunctionOrTagUnion(names_index, _, _) => { + Key(FlatInspectableKey::TagUnion( + subs.get_subs_slice(names_index) + .iter() + .map(|t| (t.clone(), 0)) + .collect(), + )) + } + FlatType::EmptyRecord => Key(FlatInspectableKey::Record(Vec::new())), + FlatType::EmptyTuple => todo!(), + FlatType::EmptyTagUnion => Key(FlatInspectableKey::TagUnion(Vec::new())), + // + FlatType::Func(slice, ..) => { + let arity = subs.get_subs_slice(slice).len(); + + Key(FlatInspectableKey::Function(arity as u32)) + } + }, + Content::Alias(sym, _, real_var, _) => match Self::from_builtin_alias(sym) { + Some(lambda) => lambda, + // 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(range) => { + Self::from_var(subs, range.default_compilation_variable()) + } + Content::RecursionVar { structure, .. } => Self::from_var(subs, structure), + Content::Error => Key(FlatInspectableKey::Error), + Content::FlexVar(_) + | Content::RigidVar(_) + | Content::FlexAbleVar(_, _) + | Content::RigidAbleVar(_, _) => { + let var_name: String = todo!(); + + Key(FlatInspectableKey::TypeVar(var_name)) + } + Content::LambdaSet(_) | Content::ErasedLambda => { + unreachable!(); + } + } + } + + pub(crate) const fn from_builtin_alias(symbol: Symbol) -> Option { + use FlatInspectable::*; + + match symbol { + Symbol::BOOL_BOOL => Some(Immediate(Symbol::ENCODE_BOOL)), + Symbol::NUM_U8 | Symbol::NUM_UNSIGNED8 => Some(Immediate(Symbol::INSPECT_U8)), + Symbol::NUM_U16 | Symbol::NUM_UNSIGNED16 => Some(Immediate(Symbol::INSPECT_U16)), + Symbol::NUM_U32 | Symbol::NUM_UNSIGNED32 => Some(Immediate(Symbol::INSPECT_U32)), + Symbol::NUM_U64 | Symbol::NUM_UNSIGNED64 => Some(Immediate(Symbol::INSPECT_U64)), + Symbol::NUM_U128 | Symbol::NUM_UNSIGNED128 => Some(Immediate(Symbol::INSPECT_U128)), + Symbol::NUM_I8 | Symbol::NUM_SIGNED8 => Some(Immediate(Symbol::INSPECT_I8)), + Symbol::NUM_I16 | Symbol::NUM_SIGNED16 => Some(Immediate(Symbol::INSPECT_I16)), + Symbol::NUM_I32 | Symbol::NUM_SIGNED32 => Some(Immediate(Symbol::INSPECT_I32)), + Symbol::NUM_I64 | Symbol::NUM_SIGNED64 => Some(Immediate(Symbol::INSPECT_I64)), + Symbol::NUM_I128 | Symbol::NUM_SIGNED128 => Some(Immediate(Symbol::INSPECT_I128)), + Symbol::NUM_DEC | Symbol::NUM_DECIMAL => Some(Immediate(Symbol::INSPECT_DEC)), + Symbol::NUM_F32 | Symbol::NUM_BINARY32 => Some(Immediate(Symbol::INSPECT_F32)), + Symbol::NUM_F64 | Symbol::NUM_BINARY64 => Some(Immediate(Symbol::INSPECT_F64)), + Symbol::NUM_NAT | Symbol::NUM_NATURAL => Some(Immediate(Symbol::INSPECT_NAT)), + // TODO List, Dict, Set, etc. + _ => None, + } + } +} diff --git a/crates/compiler/derive_key/src/lib.rs b/crates/compiler/derive_key/src/lib.rs index 8d122c2661..53db35816e 100644 --- a/crates/compiler/derive_key/src/lib.rs +++ b/crates/compiler/derive_key/src/lib.rs @@ -16,12 +16,14 @@ pub mod decoding; pub mod encoding; pub mod hash; +pub mod inspect; mod util; use decoding::{FlatDecodable, FlatDecodableKey}; use encoding::{FlatEncodable, FlatEncodableKey}; use hash::{FlatHash, FlatHashKey}; +use inspect::{FlatInspectable, FlatInspectableKey}; use roc_module::symbol::Symbol; use roc_types::subs::{Subs, Variable}; @@ -40,6 +42,7 @@ pub enum DeriveKey { ToEncoder(FlatEncodableKey), Decoder(FlatDecodableKey), Hash(FlatHashKey), + ToInspector(FlatInspectableKey), } impl DeriveKey { @@ -48,6 +51,7 @@ impl DeriveKey { DeriveKey::ToEncoder(key) => format!("toEncoder_{}", key.debug_name()), DeriveKey::Decoder(key) => format!("decoder_{}", key.debug_name()), DeriveKey::Hash(key) => format!("hash_{}", key.debug_name()), + DeriveKey::ToInspector(key) => format!("toInspector_{}", key.debug_name()), } } } @@ -77,6 +81,7 @@ pub enum DeriveBuiltin { Decoder, Hash, IsEq, + ToInspector, } impl TryFrom for DeriveBuiltin { @@ -88,6 +93,7 @@ impl TryFrom for DeriveBuiltin { Symbol::DECODE_DECODER => Ok(DeriveBuiltin::Decoder), Symbol::HASH_HASH => Ok(DeriveBuiltin::Hash), Symbol::BOOL_IS_EQ => Ok(DeriveBuiltin::IsEq), + Symbol::INSPECT_TO_INSPECTOR => Ok(DeriveBuiltin::ToInspector), _ => Err(value), } } @@ -121,6 +127,10 @@ impl Derived { Symbol::BOOL_STRUCTURAL_EQ, )) } + DeriveBuiltin::ToInspector => match FlatInspectable::from_var(subs, var) { + FlatInspectable::Immediate(imm) => Ok(Derived::Immediate(imm)), + FlatInspectable::Key(repr) => Ok(Derived::Key(DeriveKey::ToInspector(repr))), + }, } } @@ -151,6 +161,12 @@ impl Derived { Symbol::BOOL_STRUCTURAL_EQ, )) } + DeriveBuiltin::ToInspector => { + match inspect::FlatInspectable::from_builtin_alias(symbol).unwrap() { + FlatInspectable::Immediate(imm) => Ok(Derived::Immediate(imm)), + FlatInspectable::Key(repr) => Ok(Derived::Key(DeriveKey::ToInspector(repr))), + } + } } } } diff --git a/crates/compiler/derive_key/src/util.rs b/crates/compiler/derive_key/src/util.rs index 8fbab82957..a6229c3e25 100644 --- a/crates/compiler/derive_key/src/util.rs +++ b/crates/compiler/derive_key/src/util.rs @@ -60,3 +60,7 @@ pub(crate) fn debug_name_tag(tags: &[(TagName, u16)]) -> String { str.push(']'); str } + +pub(crate) fn debug_name_fn(arity: u32) -> String { + format!("(arity:{arity} -> _)") +} diff --git a/crates/compiler/module/src/symbol.rs b/crates/compiler/module/src/symbol.rs index 8db42669aa..2ba48416ad 100644 --- a/crates/compiler/module/src/symbol.rs +++ b/crates/compiler/module/src/symbol.rs @@ -53,6 +53,7 @@ pub const DERIVABLE_ABILITIES: &[(Symbol, &[Symbol])] = &[ (Symbol::DECODE_DECODING, &[Symbol::DECODE_DECODER]), (Symbol::HASH_HASH_ABILITY, &[Symbol::HASH_HASH]), (Symbol::BOOL_EQ, &[Symbol::BOOL_IS_EQ]), + (Symbol::INSPECT_INSPECT, &[Symbol::INSPECT_TO_INSPECTOR]), ]; /// In Debug builds only, Symbol has a name() method that lets From 00c27b087b88a2f63dbf431b576475cc57327143 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Fri, 1 Sep 2023 22:29:22 -0400 Subject: [PATCH 04/40] Add Inspect to builtin_module_with_unlisted_ability_impl --- crates/compiler/solve/src/ability.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/compiler/solve/src/ability.rs b/crates/compiler/solve/src/ability.rs index 5521e8e332..a29b98e6ef 100644 --- a/crates/compiler/solve/src/ability.rs +++ b/crates/compiler/solve/src/ability.rs @@ -1394,11 +1394,14 @@ impl AbilityResolver for AbilitiesStore { } } -/// Whether this a module whose types' ability implementations should be checked via derive_key, +/// Whether this is a module whose types' ability implementations should be checked via derive_key, /// because they do not explicitly list ability implementations due to circular dependencies. #[inline] pub(crate) fn builtin_module_with_unlisted_ability_impl(module_id: ModuleId) -> bool { - matches!(module_id, ModuleId::NUM | ModuleId::BOOL) + matches!( + module_id, + ModuleId::NUM | ModuleId::BOOL | ModuleId::INSPECT + ) } #[derive(Debug)] From 34148645ae72dfabfcf918e518c6e0b58527d320 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Wed, 6 Sep 2023 21:24:52 -0400 Subject: [PATCH 05/40] wip --- crates/compiler/builtins/roc/Inspect.roc | 22 +- crates/compiler/derive/src/inspect.rs | 1096 ++++++++++++++++++++ crates/compiler/derive/src/lib.rs | 4 +- crates/compiler/derive_key/src/encoding.rs | 8 +- crates/compiler/derive_key/src/inspect.rs | 53 +- crates/compiler/module/src/symbol.rs | 2 + 6 files changed, 1139 insertions(+), 46 deletions(-) create mode 100644 crates/compiler/derive/src/inspect.rs diff --git a/crates/compiler/builtins/roc/Inspect.roc b/crates/compiler/builtins/roc/Inspect.roc index 79103f4c2c..987a0eebce 100644 --- a/crates/compiler/builtins/roc/Inspect.roc +++ b/crates/compiler/builtins/roc/Inspect.roc @@ -33,6 +33,9 @@ interface Inspect custom, apply, toInspector, + # TODO don't expose these - there's some way to do this! + inspectFn, + inspectOpaque, ] imports [ Bool.{ Bool }, @@ -57,12 +60,11 @@ InspectFormatter implements set : set, ElemWalker state set elem, (elem -> Inspector f) -> Inspector f where f implements InspectFormatter dict : dict, KeyValWalker state dict key value, (key -> Inspector f), (value -> Inspector f) -> Inspector f where f implements InspectFormatter - # Note opaque is used for both opaque types and functions. - # The auto deriver for functions probably could put the function type. - # For regular opaque types, I think we can use the type name, though that may lead to some reflection related issues that still need to be discussed. - # As a simple baseline, it can just use the exact words `opaque` and `function` for now. - # In text, this would render as ``, ``, etc - opaque : Str -> Inspector f where f implements InspectFormatter + # In text, this would render as `` + opaque : Inspector f where f implements InspectFormatter + + # In text, this would render as `` + function : Inspector f where f implements InspectFormatter u8 : U8 -> Inspector f where f implements InspectFormatter i8 : I8 -> Inspector f where f implements InspectFormatter @@ -94,3 +96,11 @@ inspect : val -> f where val implements Inspect, f implements InspectFormatter inspect = \val -> (@Inspector valFn) = toInspector val valFn (init {}) + +## Should not be exposed, only used in auto-deriving +inspectFn : * -> Inspector f where f implements InspectFormatter +inspectFn = \_ -> function + +## Should not be exposed, only used in auto-deriving +inspectOpaque : * -> Inspector f where f implements InspectFormatter +inspectOpaque = \_ -> opaque diff --git a/crates/compiler/derive/src/inspect.rs b/crates/compiler/derive/src/inspect.rs new file mode 100644 index 0000000000..c8413fbad6 --- /dev/null +++ b/crates/compiler/derive/src/inspect.rs @@ -0,0 +1,1096 @@ +//! Derivers for the `Inspect` ability. + +use std::iter::once; + +use roc_can::expr::{ + AnnotatedMark, ClosureData, Expr, Field, Recursive, WhenBranch, WhenBranchPattern, +}; +use roc_can::pattern::Pattern; +use roc_collections::SendMap; +use roc_derive_key::inspect::FlatInspectableKey; +use roc_module::called_via::CalledVia; +use roc_module::ident::Lowercase; +use roc_module::symbol::Symbol; +use roc_region::all::{Loc, Region}; +use roc_types::subs::{ + Content, ExhaustiveMark, FlatType, GetSubsSlice, LambdaSet, OptVariable, RecordFields, + RedundantMark, SubsSlice, TagExt, TupleElems, UnionLambdas, UnionTags, Variable, + VariableSubsSlice, +}; +use roc_types::types::RecordField; + +use crate::util::Env; +use crate::{synth_var, DerivedBody}; + +pub(crate) fn derive_to_inspector( + env: &mut Env<'_>, + key: FlatInspectableKey, + def_symbol: Symbol, +) -> DerivedBody { + let (body, body_type) = match key { + FlatInspectableKey::List() => to_inspector_list(env, def_symbol), + FlatInspectableKey::Set() => todo!(), + FlatInspectableKey::Dict() => todo!(), + FlatInspectableKey::Record(fields) => { + // Generalized record var so we can reuse this impl between many records: + // if fields = { a, b }, this is { a: t1, b: t2 } for fresh t1, t2. + let flex_fields = fields + .into_iter() + .map(|name| { + ( + name, + RecordField::Required(env.subs.fresh_unnamed_flex_var()), + ) + }) + .collect::>(); + let fields = RecordFields::insert_into_subs(env.subs, flex_fields); + let record_var = synth_var( + env.subs, + Content::Structure(FlatType::Record(fields, Variable::EMPTY_RECORD)), + ); + + to_encoder_record(env, record_var, fields, def_symbol) + } + FlatInspectableKey::Tuple(arity) => { + // Generalized tuple var so we can reuse this impl between many tuples: + // if arity = n, this is (t1, ..., tn) for fresh t1, ..., tn. + let flex_elems = (0..arity) + .map(|idx| (idx as usize, env.subs.fresh_unnamed_flex_var())) + .collect::>(); + let elems = TupleElems::insert_into_subs(env.subs, flex_elems); + let tuple_var = synth_var( + env.subs, + Content::Structure(FlatType::Tuple(elems, Variable::EMPTY_TUPLE)), + ); + + to_encoder_tuple(env, tuple_var, elems, def_symbol) + } + FlatInspectableKey::TagUnion(tags) => { + // Generalized tag union var so we can reuse this impl between many unions: + // if tags = [ A arity=2, B arity=1 ], this is [ A t1 t2, B t3 ] for fresh t1, t2, t3 + let flex_tag_labels = tags + .into_iter() + .map(|(label, arity)| { + let variables_slice = + VariableSubsSlice::reserve_into_subs(env.subs, arity.into()); + for var_index in variables_slice { + env.subs[var_index] = env.subs.fresh_unnamed_flex_var(); + } + (label, variables_slice) + }) + .collect::>(); + let union_tags = UnionTags::insert_slices_into_subs(env.subs, flex_tag_labels); + let tag_union_var = synth_var( + env.subs, + Content::Structure(FlatType::TagUnion( + union_tags, + TagExt::Any(Variable::EMPTY_TAG_UNION), + )), + ); + + to_encoder_tag_union(env, tag_union_var, union_tags, def_symbol) + } + FlatInspectableKey::Function(_arity) => { + // Desired output: \x, y, z -> ... ===> "" + + todo!(); + } + FlatInspectableKey::Opaque => todo!(), + FlatInspectableKey::Error => todo!(), + }; + + let specialization_lambda_sets = + env.get_specialization_lambda_sets(body_type, Symbol::ENCODE_TO_ENCODER); + + DerivedBody { + body, + body_type, + specialization_lambda_sets, + } +} + +fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { + // Build \lst -> Encode.list lst (\elem -> Encode.toEncoder elem) + // + // TODO eta reduce this baby ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + use Expr::*; + + let lst_sym = env.new_symbol("lst"); + let elem_sym = env.new_symbol("elem"); + + // List elem + let elem_var = env.subs.fresh_unnamed_flex_var(); + let elem_var_slice = SubsSlice::insert_into_subs(env.subs, [elem_var]); + let list_var = synth_var( + env.subs, + Content::Structure(FlatType::Apply(Symbol::LIST_LIST, elem_var_slice)), + ); + + // build `toEncoder elem` type + // val -[uls]-> Encoder fmt where fmt implements EncoderFormatting + let to_encoder_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_TO_ENCODER); + + // elem -[clos]-> t1 + let to_encoder_clos_var = env.subs.fresh_unnamed_flex_var(); // clos + let elem_encoder_var = env.subs.fresh_unnamed_flex_var(); // t1 + let elem_to_encoder_fn_var = synth_var( + env.subs, + Content::Structure(FlatType::Func( + elem_var_slice, + to_encoder_clos_var, + elem_encoder_var, + )), + ); + + // val -[uls]-> Encoder fmt where fmt implements EncoderFormatting + // ~ elem -[clos]-> t1 + env.unify(to_encoder_fn_var, elem_to_encoder_fn_var); + + // toEncoder : (typeof rcd.a) -[clos]-> Encoder fmt where fmt implements EncoderFormatting + let to_encoder_var = AbilityMember(Symbol::ENCODE_TO_ENCODER, None, elem_to_encoder_fn_var); + let to_encoder_fn = Box::new(( + to_encoder_fn_var, + Loc::at_zero(to_encoder_var), + to_encoder_clos_var, + elem_encoder_var, + )); + + // toEncoder elem + let to_encoder_call = Call( + to_encoder_fn, + vec![(elem_var, Loc::at_zero(Var(elem_sym, elem_var)))], + CalledVia::Space, + ); + + // elem -[to_elem_encoder]-> toEncoder elem + let to_elem_encoder_sym = env.new_symbol("to_elem_encoder"); + + // Create fn_var for ambient capture; we fix it up below. + let to_elem_encoder_fn_var = synth_var(env.subs, Content::Error); + + // -[to_elem_encoder]-> + let to_elem_encoder_labels = + UnionLambdas::insert_into_subs(env.subs, once((to_elem_encoder_sym, vec![]))); + let to_elem_encoder_lset = synth_var( + env.subs, + Content::LambdaSet(LambdaSet { + solved: to_elem_encoder_labels, + recursion_var: OptVariable::NONE, + unspecialized: SubsSlice::default(), + ambient_function: to_elem_encoder_fn_var, + }), + ); + // elem -[to_elem_encoder]-> toEncoder elem + env.subs.set_content( + to_elem_encoder_fn_var, + Content::Structure(FlatType::Func( + elem_var_slice, + to_elem_encoder_lset, + elem_encoder_var, + )), + ); + + // \elem -> toEncoder elem + let to_elem_encoder = Closure(ClosureData { + function_type: to_elem_encoder_fn_var, + closure_type: to_elem_encoder_lset, + return_type: elem_encoder_var, + name: to_elem_encoder_sym, + captured_symbols: vec![], + recursive: Recursive::NotRecursive, + arguments: vec![( + elem_var, + AnnotatedMark::known_exhaustive(), + Loc::at_zero(Pattern::Identifier(elem_sym)), + )], + loc_body: Box::new(Loc::at_zero(to_encoder_call)), + }); + + // build `Encode.list lst (\elem -> Encode.toEncoder elem)` type + // List e, (e -> Encoder fmt) -[uls]-> Encoder fmt where fmt implements EncoderFormatting + let encode_list_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_LIST); + + // List elem, to_elem_encoder_fn_var -[clos]-> t1 + let this_encode_list_args_slice = + VariableSubsSlice::insert_into_subs(env.subs, [list_var, to_elem_encoder_fn_var]); + let this_encode_list_clos_var = env.subs.fresh_unnamed_flex_var(); // clos + let this_list_encoder_var = env.subs.fresh_unnamed_flex_var(); // t1 + let this_encode_list_fn_var = synth_var( + env.subs, + Content::Structure(FlatType::Func( + this_encode_list_args_slice, + this_encode_list_clos_var, + this_list_encoder_var, + )), + ); + + // List e, (e -> Encoder fmt) -[uls]-> Encoder fmt where fmt implements EncoderFormatting + // ~ List elem, to_elem_encoder_fn_var -[clos]-> t1 + env.unify(encode_list_fn_var, this_encode_list_fn_var); + + // Encode.list : List elem, to_elem_encoder_fn_var -[clos]-> Encoder fmt where fmt implements EncoderFormatting + let encode_list = AbilityMember(Symbol::ENCODE_LIST, None, this_encode_list_fn_var); + let encode_list_fn = Box::new(( + this_encode_list_fn_var, + Loc::at_zero(encode_list), + this_encode_list_clos_var, + this_list_encoder_var, + )); + + // Encode.list lst to_elem_encoder + let encode_list_call = Call( + encode_list_fn, + vec![ + (list_var, Loc::at_zero(Var(lst_sym, list_var))), + (to_elem_encoder_fn_var, Loc::at_zero(to_elem_encoder)), + ], + CalledVia::Space, + ); + + // Encode.custom \bytes, fmt -> Encode.appendWith bytes (Encode.list ..) fmt + let (body, this_encoder_var) = wrap_in_encode_custom( + env, + encode_list_call, + this_list_encoder_var, + lst_sym, + list_var, + ); + + // \lst -> Encode.list lst (\elem -> Encode.toEncoder elem) + // Create fn_var for ambient capture; we fix it up below. + let fn_var = synth_var(env.subs, Content::Error); + + // -[fn_name]-> + let fn_name_labels = UnionLambdas::insert_into_subs(env.subs, once((fn_name, vec![]))); + let fn_clos_var = synth_var( + env.subs, + Content::LambdaSet(LambdaSet { + solved: fn_name_labels, + recursion_var: OptVariable::NONE, + unspecialized: SubsSlice::default(), + ambient_function: fn_var, + }), + ); + // List elem -[fn_name]-> Encoder fmt + let list_var_slice = SubsSlice::insert_into_subs(env.subs, once(list_var)); + env.subs.set_content( + fn_var, + Content::Structure(FlatType::Func( + list_var_slice, + fn_clos_var, + this_encoder_var, + )), + ); + + // \lst -[fn_name]-> Encode.list lst (\elem -> Encode.toEncoder elem) + let clos = Closure(ClosureData { + function_type: fn_var, + closure_type: fn_clos_var, + return_type: this_encoder_var, + name: fn_name, + captured_symbols: vec![], + recursive: Recursive::NotRecursive, + arguments: vec![( + list_var, + AnnotatedMark::known_exhaustive(), + Loc::at_zero(Pattern::Identifier(lst_sym)), + )], + loc_body: Box::new(Loc::at_zero(body)), + }); + + (clos, fn_var) +} + +fn to_encoder_record( + env: &mut Env<'_>, + record_var: Variable, + fields: RecordFields, + fn_name: Symbol, +) -> (Expr, Variable) { + // Suppose rcd = { a: t1, b: t2 }. Build + // + // \rcd -> Encode.record [ + // { key: "a", value: Encode.toEncoder rcd.a }, + // { key: "b", value: Encode.toEncoder rcd.b }, + // ] + + let rcd_sym = env.new_symbol("rcd"); + let whole_rcd_var = env.subs.fresh_unnamed_flex_var(); // type of the { key, value } records in the list + + use Expr::*; + + let fields_list = fields + .iter_all() + .map(|(field_name_index, field_var_index, _)| { + let field_name = env.subs[field_name_index].clone(); + let field_var = env.subs[field_var_index]; + let field_var_slice = VariableSubsSlice::new(field_var_index.index, 1); + + // key: "a" + let key_field = Field { + var: Variable::STR, + region: Region::zero(), + loc_expr: Box::new(Loc::at_zero(Str(field_name.as_str().into()))), + }; + + // rcd.a + let field_access = RecordAccess { + record_var, + ext_var: env.subs.fresh_unnamed_flex_var(), + field_var, + loc_expr: Box::new(Loc::at_zero(Var( + rcd_sym, + env.subs.fresh_unnamed_flex_var(), + ))), + field: field_name, + }; + + // build `toEncoder rcd.a` type + // val -[uls]-> Encoder fmt where fmt implements EncoderFormatting + let to_encoder_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_TO_ENCODER); + + // (typeof rcd.a) -[clos]-> t1 + let to_encoder_clos_var = env.subs.fresh_unnamed_flex_var(); // clos + let encoder_var = env.subs.fresh_unnamed_flex_var(); // t1 + let this_to_encoder_fn_var = synth_var( + env.subs, + Content::Structure(FlatType::Func( + field_var_slice, + to_encoder_clos_var, + encoder_var, + )), + ); + + // val -[uls]-> Encoder fmt where fmt implements EncoderFormatting + // ~ (typeof rcd.a) -[clos]-> t1 + env.unify(to_encoder_fn_var, this_to_encoder_fn_var); + + // toEncoder : (typeof rcd.a) -[clos]-> Encoder fmt where fmt implements EncoderFormatting + let to_encoder_var = AbilityMember(Symbol::ENCODE_TO_ENCODER, None, to_encoder_fn_var); + let to_encoder_fn = Box::new(( + to_encoder_fn_var, + Loc::at_zero(to_encoder_var), + to_encoder_clos_var, + encoder_var, + )); + + // toEncoder rcd.a + let to_encoder_call = Call( + to_encoder_fn, + vec![(field_var, Loc::at_zero(field_access))], + CalledVia::Space, + ); + + // value: toEncoder rcd.a + let value_field = Field { + var: encoder_var, + region: Region::zero(), + loc_expr: Box::new(Loc::at_zero(to_encoder_call)), + }; + + // { key: "a", value: toEncoder rcd.a } + let mut kv = SendMap::default(); + kv.insert("key".into(), key_field); + kv.insert("value".into(), value_field); + + let this_record_fields = RecordFields::insert_into_subs( + env.subs, + (once(("key".into(), RecordField::Required(Variable::STR)))) + .chain(once(("value".into(), RecordField::Required(encoder_var)))), + ); + let this_record_var = synth_var( + env.subs, + Content::Structure(FlatType::Record(this_record_fields, Variable::EMPTY_RECORD)), + ); + // NOTE: must be done to unify the lambda sets under `encoder_var` + env.unify(this_record_var, whole_rcd_var); + + Loc::at_zero(Record { + record_var: whole_rcd_var, + fields: kv, + }) + }) + .collect::>(); + + // typeof [ { key: .., value: .. }, { key: .., value: .. } ] + let fields_rcd_var_slice = VariableSubsSlice::insert_into_subs(env.subs, once(whole_rcd_var)); + let fields_list_var = synth_var( + env.subs, + Content::Structure(FlatType::Apply(Symbol::LIST_LIST, fields_rcd_var_slice)), + ); + + // [ { key: .., value: ..}, .. ] + let fields_list = List { + elem_var: whole_rcd_var, + loc_elems: fields_list, + }; + + // build `Encode.record [ { key: .., value: ..}, .. ]` type + // List { key : Str, value : Encoder fmt } -[uls]-> Encoder fmt where fmt implements EncoderFormatting + let encode_record_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_RECORD); + + // fields_list_var -[clos]-> t1 + let fields_list_var_slice = + VariableSubsSlice::insert_into_subs(env.subs, once(fields_list_var)); + let encode_record_clos_var = env.subs.fresh_unnamed_flex_var(); // clos + let encoder_var = env.subs.fresh_unnamed_flex_var(); // t1 + let this_encode_record_fn_var = synth_var( + env.subs, + Content::Structure(FlatType::Func( + fields_list_var_slice, + encode_record_clos_var, + encoder_var, + )), + ); + + // List { key : Str, value : Encoder fmt } -[uls]-> Encoder fmt where fmt implements EncoderFormatting + // ~ fields_list_var -[clos]-> t1 + env.unify(encode_record_fn_var, this_encode_record_fn_var); + + // Encode.record : fields_list_var -[clos]-> Encoder fmt where fmt implements EncoderFormatting + let encode_record_var = AbilityMember(Symbol::ENCODE_RECORD, None, encode_record_fn_var); + let encode_record_fn = Box::new(( + encode_record_fn_var, + Loc::at_zero(encode_record_var), + encode_record_clos_var, + encoder_var, + )); + + // Encode.record [ { key: .., value: .. }, .. ] + let encode_record_call = Call( + encode_record_fn, + vec![(fields_list_var, Loc::at_zero(fields_list))], + CalledVia::Space, + ); + + // Encode.custom \bytes, fmt -> Encode.appendWith bytes (Encode.record ..) fmt + let (body, this_encoder_var) = + wrap_in_encode_custom(env, encode_record_call, encoder_var, rcd_sym, record_var); + + // Create fn_var for ambient capture; we fix it up below. + let fn_var = synth_var(env.subs, Content::Error); + + // -[fn_name]-> + let fn_name_labels = UnionLambdas::insert_into_subs(env.subs, once((fn_name, vec![]))); + let fn_clos_var = synth_var( + env.subs, + Content::LambdaSet(LambdaSet { + solved: fn_name_labels, + recursion_var: OptVariable::NONE, + unspecialized: SubsSlice::default(), + ambient_function: fn_var, + }), + ); + // typeof rcd -[fn_name]-> (typeof Encode.record [ .. ] = Encoder fmt) + let record_var_slice = SubsSlice::insert_into_subs(env.subs, once(record_var)); + env.subs.set_content( + fn_var, + Content::Structure(FlatType::Func( + record_var_slice, + fn_clos_var, + this_encoder_var, + )), + ); + + // \rcd -[fn_name]-> Encode.record [ { key: .., value: .. }, .. ] + let clos = Closure(ClosureData { + function_type: fn_var, + closure_type: fn_clos_var, + return_type: this_encoder_var, + name: fn_name, + captured_symbols: vec![], + recursive: Recursive::NotRecursive, + arguments: vec![( + record_var, + AnnotatedMark::known_exhaustive(), + Loc::at_zero(Pattern::Identifier(rcd_sym)), + )], + loc_body: Box::new(Loc::at_zero(body)), + }); + + (clos, fn_var) +} + +fn to_encoder_tuple( + env: &mut Env<'_>, + tuple_var: Variable, + elems: TupleElems, + fn_name: Symbol, +) -> (Expr, Variable) { + // Suppose tup = (t1, t2). Build + // + // \tup -> Encode.tuple [ + // Encode.toEncoder tup.0, + // Encode.toEncoder tup.1, + // ] + + let tup_sym = env.new_symbol("tup"); + let whole_encoder_in_list_var = env.subs.fresh_unnamed_flex_var(); // type of the encoder in the list + + use Expr::*; + + let elem_encoders_list = elems + .iter_all() + .map(|(elem_index, elem_var_index)| { + let index = env.subs[elem_index]; + let elem_var = env.subs[elem_var_index]; + let elem_var_slice = VariableSubsSlice::new(elem_var_index.index, 1); + + // tup.0 + let tuple_access = TupleAccess { + tuple_var, + ext_var: env.subs.fresh_unnamed_flex_var(), + elem_var, + loc_expr: Box::new(Loc::at_zero(Var( + tup_sym, + env.subs.fresh_unnamed_flex_var(), + ))), + index, + }; + + // build `toEncoder tup.0` type + // val -[uls]-> Encoder fmt where fmt implements EncoderFormatting + let to_encoder_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_TO_ENCODER); + + // (typeof tup.0) -[clos]-> t1 + let to_encoder_clos_var = env.subs.fresh_unnamed_flex_var(); // clos + let encoder_var = env.subs.fresh_unnamed_flex_var(); // t1 + let this_to_encoder_fn_var = synth_var( + env.subs, + Content::Structure(FlatType::Func( + elem_var_slice, + to_encoder_clos_var, + encoder_var, + )), + ); + + // val -[uls]-> Encoder fmt where fmt implements EncoderFormatting + // ~ (typeof tup.0) -[clos]-> t1 + env.unify(to_encoder_fn_var, this_to_encoder_fn_var); + + // toEncoder : (typeof tup.0) -[clos]-> Encoder fmt where fmt implements EncoderFormatting + let to_encoder_var = AbilityMember(Symbol::ENCODE_TO_ENCODER, None, to_encoder_fn_var); + let to_encoder_fn = Box::new(( + to_encoder_fn_var, + Loc::at_zero(to_encoder_var), + to_encoder_clos_var, + encoder_var, + )); + + // toEncoder tup.0 + let to_encoder_call = Call( + to_encoder_fn, + vec![(elem_var, Loc::at_zero(tuple_access))], + CalledVia::Space, + ); + + // NOTE: must be done to unify the lambda sets under `encoder_var` + env.unify(encoder_var, whole_encoder_in_list_var); + + Loc::at_zero(to_encoder_call) + }) + .collect::>(); + + // typeof [ toEncoder tup.0, toEncoder tup.1 ] + let whole_encoder_in_list_var_slice = + VariableSubsSlice::insert_into_subs(env.subs, once(whole_encoder_in_list_var)); + let elem_encoders_list_var = synth_var( + env.subs, + Content::Structure(FlatType::Apply( + Symbol::LIST_LIST, + whole_encoder_in_list_var_slice, + )), + ); + + // [ toEncoder tup.0, toEncoder tup.1 ] + let elem_encoders_list = List { + elem_var: whole_encoder_in_list_var, + loc_elems: elem_encoders_list, + }; + + // build `Encode.tuple [ toEncoder tup.0, toEncoder tup.1 ]` type + // List (Encoder fmt) -[uls]-> Encoder fmt where fmt implements EncoderFormatting + let encode_tuple_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_TUPLE); + + // elem_encoders_list_var -[clos]-> t1 + let elem_encoders_list_var_slice = + VariableSubsSlice::insert_into_subs(env.subs, once(elem_encoders_list_var)); + let encode_tuple_clos_var = env.subs.fresh_unnamed_flex_var(); // clos + let encoder_var = env.subs.fresh_unnamed_flex_var(); // t1 + let this_encode_tuple_fn_var = synth_var( + env.subs, + Content::Structure(FlatType::Func( + elem_encoders_list_var_slice, + encode_tuple_clos_var, + encoder_var, + )), + ); + + // List (Encoder fmt) -[uls]-> Encoder fmt where fmt implements EncoderFormatting + // ~ elem_encoders_list_var -[clos]-> t1 + env.unify(encode_tuple_fn_var, this_encode_tuple_fn_var); + + // Encode.tuple : elem_encoders_list_var -[clos]-> Encoder fmt where fmt implements EncoderFormatting + let encode_tuple_var = AbilityMember(Symbol::ENCODE_TUPLE, None, encode_tuple_fn_var); + let encode_tuple_fn = Box::new(( + encode_tuple_fn_var, + Loc::at_zero(encode_tuple_var), + encode_tuple_clos_var, + encoder_var, + )); + + // Encode.tuple [ { key: .., value: .. }, .. ] + let encode_tuple_call = Call( + encode_tuple_fn, + vec![(elem_encoders_list_var, Loc::at_zero(elem_encoders_list))], + CalledVia::Space, + ); + + // Encode.custom \bytes, fmt -> Encode.appendWith bytes (Encode.tuple_var ..) fmt + let (body, this_encoder_var) = + wrap_in_encode_custom(env, encode_tuple_call, encoder_var, tup_sym, tuple_var); + + // Create fn_var for ambient capture; we fix it up below. + let fn_var = synth_var(env.subs, Content::Error); + + // -[fn_name]-> + let fn_name_labels = UnionLambdas::insert_into_subs(env.subs, once((fn_name, vec![]))); + let fn_clos_var = synth_var( + env.subs, + Content::LambdaSet(LambdaSet { + solved: fn_name_labels, + recursion_var: OptVariable::NONE, + unspecialized: SubsSlice::default(), + ambient_function: fn_var, + }), + ); + // typeof tup -[fn_name]-> (typeof Encode.tuple [ .. ] = Encoder fmt) + let tuple_var_slice = SubsSlice::insert_into_subs(env.subs, once(tuple_var)); + env.subs.set_content( + fn_var, + Content::Structure(FlatType::Func( + tuple_var_slice, + fn_clos_var, + this_encoder_var, + )), + ); + + // \tup -[fn_name]-> Encode.tuple [ { key: .., value: .. }, .. ] + let clos = Closure(ClosureData { + function_type: fn_var, + closure_type: fn_clos_var, + return_type: this_encoder_var, + name: fn_name, + captured_symbols: vec![], + recursive: Recursive::NotRecursive, + arguments: vec![( + tuple_var, + AnnotatedMark::known_exhaustive(), + Loc::at_zero(Pattern::Identifier(tup_sym)), + )], + loc_body: Box::new(Loc::at_zero(body)), + }); + + (clos, fn_var) +} + +fn to_encoder_tag_union( + env: &mut Env<'_>, + tag_union_var: Variable, + tags: UnionTags, + fn_name: Symbol, +) -> (Expr, Variable) { + // Suppose tag = [ A t1 t2, B t3 ]. Build + // + // \tag -> when tag is + // A v1 v2 -> Encode.tag "A" [ Encode.toEncoder v1, Encode.toEncoder v2 ] + // B v3 -> Encode.tag "B" [ Encode.toEncoder v3 ] + + let tag_sym = env.new_symbol("tag"); + let whole_tag_encoders_var = env.subs.fresh_unnamed_flex_var(); // type of the Encode.tag ... calls in the branch bodies + + use Expr::*; + + let branches = tags + .iter_all() + .map(|(tag_name_index, tag_vars_slice_index)| { + // A + let tag_name = &env.subs[tag_name_index].clone(); + let vars_slice = env.subs[tag_vars_slice_index]; + // t1 t2 + let payload_vars = env.subs.get_subs_slice(vars_slice).to_vec(); + // v1 v2 + let payload_syms: Vec<_> = std::iter::repeat_with(|| env.unique_symbol()) + .take(payload_vars.len()) + .collect(); + + // `A v1 v2` pattern + let pattern = Pattern::AppliedTag { + whole_var: tag_union_var, + tag_name: tag_name.clone(), + ext_var: Variable::EMPTY_TAG_UNION, + // (t1, v1) (t2, v2) + arguments: (payload_vars.iter()) + .zip(payload_syms.iter()) + .map(|(var, sym)| (*var, Loc::at_zero(Pattern::Identifier(*sym)))) + .collect(), + }; + let branch_pattern = WhenBranchPattern { + pattern: Loc::at_zero(pattern), + degenerate: false, + }; + + // whole type of the elements in [ Encode.toEncoder v1, Encode.toEncoder v2 ] + let whole_payload_encoders_var = env.subs.fresh_unnamed_flex_var(); + // [ Encode.toEncoder v1, Encode.toEncoder v2 ] + let payload_to_encoders = (payload_syms.iter()) + .zip(payload_vars.iter()) + .map(|(&sym, &sym_var)| { + // build `toEncoder v1` type + // expected: val -[uls]-> Encoder fmt where fmt implements EncoderFormatting + let to_encoder_fn_var = + env.import_builtin_symbol_var(Symbol::ENCODE_TO_ENCODER); + + // wanted: t1 -[clos]-> t' + let var_slice_of_sym_var = + VariableSubsSlice::insert_into_subs(env.subs, [sym_var]); // [ t1 ] + let to_encoder_clos_var = env.subs.fresh_unnamed_flex_var(); // clos + let encoder_var = env.subs.fresh_unnamed_flex_var(); // t' + let this_to_encoder_fn_var = synth_var( + env.subs, + Content::Structure(FlatType::Func( + var_slice_of_sym_var, + to_encoder_clos_var, + encoder_var, + )), + ); + + // val -[uls]-> Encoder fmt where fmt implements EncoderFormatting + // ~ t1 -[clos]-> t' + env.unify(to_encoder_fn_var, this_to_encoder_fn_var); + + // toEncoder : t1 -[clos]-> Encoder fmt where fmt implements EncoderFormatting + let to_encoder_var = + AbilityMember(Symbol::ENCODE_TO_ENCODER, None, this_to_encoder_fn_var); + let to_encoder_fn = Box::new(( + this_to_encoder_fn_var, + Loc::at_zero(to_encoder_var), + to_encoder_clos_var, + encoder_var, + )); + + // toEncoder rcd.a + let to_encoder_call = Call( + to_encoder_fn, + vec![(sym_var, Loc::at_zero(Var(sym, sym_var)))], + CalledVia::Space, + ); + + // NOTE: must be done to unify the lambda sets under `encoder_var` + env.unify(encoder_var, whole_payload_encoders_var); + + Loc::at_zero(to_encoder_call) + }) + .collect(); + + // typeof [ Encode.toEncoder v1, Encode.toEncoder v2 ] + let whole_encoders_var_slice = + VariableSubsSlice::insert_into_subs(env.subs, [whole_payload_encoders_var]); + let payload_encoders_list_var = synth_var( + env.subs, + Content::Structure(FlatType::Apply(Symbol::LIST_LIST, whole_encoders_var_slice)), + ); + + // [ Encode.toEncoder v1, Encode.toEncoder v2 ] + let payload_encoders_list = List { + elem_var: whole_payload_encoders_var, + loc_elems: payload_to_encoders, + }; + + // build `Encode.tag "A" [ ... ]` type + // expected: Str, List (Encoder fmt) -[uls]-> Encoder fmt where fmt implements EncoderFormatting + let encode_tag_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_TAG); + + // wanted: Str, List whole_encoders_var -[clos]-> t' + let this_encode_tag_args_var_slice = VariableSubsSlice::insert_into_subs( + env.subs, + [Variable::STR, payload_encoders_list_var], + ); + let this_encode_tag_clos_var = env.subs.fresh_unnamed_flex_var(); // -[clos]-> + let this_encoder_var = env.subs.fresh_unnamed_flex_var(); // t' + let this_encode_tag_fn_var = synth_var( + env.subs, + Content::Structure(FlatType::Func( + this_encode_tag_args_var_slice, + this_encode_tag_clos_var, + this_encoder_var, + )), + ); + + // Str, List (Encoder fmt) -[uls]-> Encoder fmt where fmt implements EncoderFormatting + // ~ Str, List whole_encoders_var -[clos]-> t' + env.unify(encode_tag_fn_var, this_encode_tag_fn_var); + + // Encode.tag : Str, List whole_encoders_var -[clos]-> Encoder fmt where fmt implements EncoderFormatting + let encode_tag_var = AbilityMember(Symbol::ENCODE_TAG, None, this_encode_tag_fn_var); + let encode_tag_fn = Box::new(( + this_encode_tag_fn_var, + Loc::at_zero(encode_tag_var), + this_encode_tag_clos_var, + this_encoder_var, + )); + + // Encode.tag "A" [ Encode.toEncoder v1, Encode.toEncoder v2 ] + let encode_tag_call = Call( + encode_tag_fn, + vec![ + // (Str, "A") + (Variable::STR, Loc::at_zero(Str(tag_name.0.as_str().into()))), + // (List (Encoder fmt), [ Encode.toEncoder v1, Encode.toEncoder v2 ]) + ( + payload_encoders_list_var, + Loc::at_zero(payload_encoders_list), + ), + ], + CalledVia::Space, + ); + + // NOTE: must be done to unify the lambda sets under `encoder_var` + // Encode.tag "A" [ Encode.toEncoder v1, Encode.toEncoder v2 ] ~ whole_encoders + env.unify(this_encoder_var, whole_tag_encoders_var); + + WhenBranch { + patterns: vec![branch_pattern], + value: Loc::at_zero(encode_tag_call), + guard: None, + redundant: RedundantMark::known_non_redundant(), + } + }) + .collect::>(); + + // when tag is + // A v1 v2 -> Encode.tag "A" [ Encode.toEncoder v1, Encode.toEncoder v2 ] + // B v3 -> Encode.tag "B" [ Encode.toEncoder v3 ] + let when_branches = When { + loc_cond: Box::new(Loc::at_zero(Var(tag_sym, tag_union_var))), + cond_var: tag_union_var, + expr_var: whole_tag_encoders_var, + region: Region::zero(), + branches, + branches_cond_var: tag_union_var, + exhaustive: ExhaustiveMark::known_exhaustive(), + }; + + // Encode.custom \bytes, fmt -> Encode.appendWith bytes (when ..) fmt + let (body, this_encoder_var) = wrap_in_encode_custom( + env, + when_branches, + whole_tag_encoders_var, + tag_sym, + tag_union_var, + ); + + // Create fn_var for ambient capture; we fix it up below. + let fn_var = synth_var(env.subs, Content::Error); + + // -[fn_name]-> + let fn_name_labels = UnionLambdas::insert_into_subs(env.subs, once((fn_name, vec![]))); + let fn_clos_var = synth_var( + env.subs, + Content::LambdaSet(LambdaSet { + solved: fn_name_labels, + recursion_var: OptVariable::NONE, + unspecialized: SubsSlice::default(), + ambient_function: fn_var, + }), + ); + // tag_union_var -[fn_name]-> whole_tag_encoders_var + let tag_union_var_slice = SubsSlice::insert_into_subs(env.subs, once(tag_union_var)); + env.subs.set_content( + fn_var, + Content::Structure(FlatType::Func( + tag_union_var_slice, + fn_clos_var, + this_encoder_var, + )), + ); + + // \tag -> + // Encode.custom \bytes, fmt -> Encode.appendWith bytes ( + // when tag is + // A v1 v2 -> Encode.tag "A" [ Encode.toEncoder v1, Encode.toEncoder v2 ] + // B v3 -> Encode.tag "B" [ Encode.toEncoder v3 ]) + // fmt + let clos = Closure(ClosureData { + function_type: fn_var, + closure_type: fn_clos_var, + return_type: this_encoder_var, + name: fn_name, + captured_symbols: vec![], + recursive: Recursive::NotRecursive, + arguments: vec![( + tag_union_var, + AnnotatedMark::known_exhaustive(), + Loc::at_zero(Pattern::Identifier(tag_sym)), + )], + loc_body: Box::new(Loc::at_zero(body)), + }); + + (clos, fn_var) +} + +/// Lift `encoder` to `Encode.custom \bytes, fmt -> Encode.appendWith bytes encoder fmt` +/// +/// TODO: currently it appears that just `encoder` is not isomorphic to the lift, on the +/// monomorphization level, even though we would think it is. In particular, unspecialized lambda +/// sets fail to resolve when we use the non-lifted version. +/// More investigation is needed to figure out why. +fn wrap_in_encode_custom( + env: &mut Env, + encoder: Expr, + encoder_var: Variable, + captured_symbol: Symbol, + captured_var: Variable, +) -> (Expr, Variable) { + use Expr::*; + + let fn_name = env.new_symbol("custom"); + + // bytes: List U8 + let bytes_sym = env.new_symbol("bytes"); + let bytes_var = Variable::LIST_U8; + + // fmt: fmt where fmt implements EncoderFormatting + let fmt_sym = env.new_symbol("fmt"); + let fmt_var = env.subs.fresh_unnamed_flex_var(); + + // build `Encode.appendWith bytes encoder fmt` type + // expected: Encode.appendWith : List U8, Encoder fmt, fmt -[appendWith]-> List U8 where fmt implements EncoderFormatting + let append_with_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_APPEND_WITH); + + // wanted: Encode.appendWith : List U8, encoder_var, fmt -[clos]-> List U8 where fmt implements EncoderFormatting + let this_append_with_args_var_slice = + VariableSubsSlice::insert_into_subs(env.subs, [Variable::LIST_U8, encoder_var, fmt_var]); + let this_append_with_clos_var = env.subs.fresh_unnamed_flex_var(); // -[clos]-> + let this_append_with_fn_var = synth_var( + env.subs, + Content::Structure(FlatType::Func( + this_append_with_args_var_slice, + this_append_with_clos_var, + Variable::LIST_U8, + )), + ); + + // List U8, Encoder fmt, fmt -[appendWith]-> List U8 where fmt implements EncoderFormatting + // ~ List U8, encoder_var, fmt -[clos]-> List U8 where fmt implements EncoderFormatting + env.unify(append_with_fn_var, this_append_with_fn_var); + + // Encode.appendWith : List U8, encoder_var, fmt -[appendWith]-> List U8 where fmt implements EncoderFormatting + let append_with_fn = Box::new(( + this_append_with_fn_var, + Loc::at_zero(Var(Symbol::ENCODE_APPEND_WITH, this_append_with_fn_var)), + this_append_with_clos_var, + Variable::LIST_U8, + )); + + // Encode.appendWith bytes encoder fmt + let append_with_call = Call( + append_with_fn, + vec![ + // (bytes_var, bytes) + (bytes_var, Loc::at_zero(Var(bytes_sym, bytes_var))), + // (encoder_var, encoder) + (encoder_var, Loc::at_zero(encoder)), + // (fmt, fmt_var) + (fmt_var, Loc::at_zero(Var(fmt_sym, fmt_var))), + ], + CalledVia::Space, + ); + + // Create fn_var for ambient capture; we fix it up below. + let fn_var = synth_var(env.subs, Content::Error); + + // -[[FN_name captured_var]]-> + let fn_name_labels = + UnionLambdas::insert_into_subs(env.subs, once((fn_name, vec![captured_var]))); + let fn_clos_var = synth_var( + env.subs, + Content::LambdaSet(LambdaSet { + solved: fn_name_labels, + recursion_var: OptVariable::NONE, + unspecialized: SubsSlice::default(), + ambient_function: fn_var, + }), + ); + + // bytes, fmt -[[FN_name captured_var]]-> Encode.appendWith bytes encoder fmt + let args_slice = SubsSlice::insert_into_subs(env.subs, vec![bytes_var, fmt_var]); + env.subs.set_content( + fn_var, + Content::Structure(FlatType::Func(args_slice, fn_clos_var, Variable::LIST_U8)), + ); + + // \bytes, fmt -[[fn_name captured_var]]-> Encode.appendWith bytes encoder fmt + let clos = Closure(ClosureData { + function_type: fn_var, + closure_type: fn_clos_var, + return_type: Variable::LIST_U8, + name: fn_name, + captured_symbols: vec![(captured_symbol, captured_var)], + recursive: Recursive::NotRecursive, + arguments: vec![ + ( + bytes_var, + AnnotatedMark::known_exhaustive(), + Loc::at_zero(Pattern::Identifier(bytes_sym)), + ), + ( + fmt_var, + AnnotatedMark::known_exhaustive(), + Loc::at_zero(Pattern::Identifier(fmt_sym)), + ), + ], + loc_body: Box::new(Loc::at_zero(append_with_call)), + }); + + // Build + // Encode.custom \bytes, fmt -> Encode.appendWith bytes encoder fmt + // + // expected: Encode.custom : (List U8, fmt -> List U8) -> Encoder fmt where fmt implements EncoderFormatting + let custom_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_CUSTOM); + + // wanted: Encode.custom : fn_var -[clos]-> t' + let this_custom_args_var_slice = VariableSubsSlice::insert_into_subs(env.subs, [fn_var]); + let this_custom_clos_var = env.subs.fresh_unnamed_flex_var(); // -[clos]-> + let this_custom_encoder_var = env.subs.fresh_unnamed_flex_var(); // t' + let this_custom_fn_var = synth_var( + env.subs, + Content::Structure(FlatType::Func( + this_custom_args_var_slice, + this_custom_clos_var, + this_custom_encoder_var, + )), + ); + + // (List U8, fmt -> List U8) -[..]-> Encoder fmt where fmt implements EncoderFormatting + // ~ fn_var -[clos]-> t' + env.unify(custom_fn_var, this_custom_fn_var); + + // Encode.custom : (List U8, fmt -> List U8) -> Encoder fmt where fmt implements EncoderFormatting + let custom_fn = Box::new(( + this_custom_fn_var, + Loc::at_zero(Var(Symbol::ENCODE_CUSTOM, this_custom_fn_var)), + this_custom_clos_var, // -[clos]-> + this_custom_encoder_var, // t' ~ Encoder fmt + )); + + // Encode.custom \bytes, fmt -> Encode.appendWith bytes encoder fmt + let custom_call = Call( + custom_fn, + vec![(fn_var, Loc::at_zero(clos))], + CalledVia::Space, + ); + + (custom_call, this_custom_encoder_var) +} diff --git a/crates/compiler/derive/src/lib.rs b/crates/compiler/derive/src/lib.rs index a1cdb81cc3..fdb4679d6e 100644 --- a/crates/compiler/derive/src/lib.rs +++ b/crates/compiler/derive/src/lib.rs @@ -8,7 +8,7 @@ use roc_can::expr::Expr; use roc_can::pattern::Pattern; use roc_can::{def::Def, module::ExposedByModule}; use roc_collections::{MutMap, VecMap}; -use roc_derive_key::{inspect, DeriveKey}; +use roc_derive_key::DeriveKey; use roc_module::symbol::{IdentIds, ModuleId, Symbol}; use roc_region::all::Loc; use roc_types::subs::{ @@ -19,7 +19,7 @@ use util::Env; mod decoding; mod encoding; mod hash; - +mod inspect; mod util; pub(crate) const DERIVED_SYNTH: ModuleId = ModuleId::DERIVED_SYNTH; diff --git a/crates/compiler/derive_key/src/encoding.rs b/crates/compiler/derive_key/src/encoding.rs index 10211ea5b3..423941bc7d 100644 --- a/crates/compiler/derive_key/src/encoding.rs +++ b/crates/compiler/derive_key/src/encoding.rs @@ -55,6 +55,7 @@ impl FlatEncodable { FlatType::Record(fields, ext) => { let (fields_iter, ext) = fields.unsorted_iterator_and_ext(subs, ext); + // TODO someday we can put #[cfg(debug_assertions)] around this, but for now let's always do it. check_derivable_ext_var(subs, ext, |ext| { matches!(ext, Content::Structure(FlatType::EmptyRecord)) })?; @@ -71,6 +72,7 @@ impl FlatEncodable { FlatType::Tuple(elems, ext) => { let (elems_iter, ext) = elems.sorted_iterator_and_ext(subs, ext); + // TODO someday we can put #[cfg(debug_assertions)] around this, but for now let's always do it. check_derivable_ext_var(subs, ext, |ext| { matches!(ext, Content::Structure(FlatType::EmptyTuple)) })?; @@ -89,6 +91,7 @@ impl FlatEncodable { // `t`-prefixed payload types. let (tags_iter, ext) = tags.unsorted_tags_and_ext(subs, ext); + // TODO someday we can put #[cfg(debug_assertions)] around this, but for now let's always do it. check_derivable_ext_var(subs, ext.var(), |ext| { matches!(ext, Content::Structure(FlatType::EmptyTagUnion)) })?; @@ -115,10 +118,9 @@ impl FlatEncodable { ))) } FlatType::EmptyRecord => Ok(Key(FlatEncodableKey::Record(vec![]))), - FlatType::EmptyTuple => todo!(), FlatType::EmptyTagUnion => Ok(Key(FlatEncodableKey::TagUnion(vec![]))), - // FlatType::Func(..) => Err(Underivable), + FlatType::EmptyTuple => unreachable!("Somehow Encoding derivation got an expression that's an empty tuple, which shouldn't be possible!"), }, Content::Alias(sym, _, real_var, _) => match from_builtin_symbol(sym) { Some(lambda) => lambda, @@ -129,9 +131,7 @@ impl FlatEncodable { Content::RangedNumber(range) => { Self::from_var(subs, range.default_compilation_variable()) } - // Content::RecursionVar { structure, .. } => Self::from_var(subs, structure), - // Content::Error => Err(Underivable), Content::FlexVar(_) | Content::RigidVar(_) diff --git a/crates/compiler/derive_key/src/inspect.rs b/crates/compiler/derive_key/src/inspect.rs index 55045b9551..439033aee7 100644 --- a/crates/compiler/derive_key/src/inspect.rs +++ b/crates/compiler/derive_key/src/inspect.rs @@ -4,11 +4,8 @@ use roc_module::{ }; use roc_types::subs::{Content, FlatType, GetSubsSlice, Subs, Variable}; -use crate::{ - util::{ - check_derivable_ext_var, debug_name_fn, debug_name_record, debug_name_tag, debug_name_tuple, - }, - DeriveError, +use crate::util::{ + check_derivable_ext_var, debug_name_fn, debug_name_record, debug_name_tag, debug_name_tuple, }; #[derive(Hash)] @@ -27,8 +24,9 @@ pub enum FlatInspectableKey { Tuple(u32), TagUnion(Vec<(TagName, u16)>), Function(u32 /* arity; +1 for return type */), + /// This means specifically an opaque type where the author hasn't requested that it derive Inspect (or implemented it) + Opaque, Error, - TypeVar(String), } impl FlatInspectableKey { @@ -42,15 +40,15 @@ impl FlatInspectableKey { FlatInspectableKey::TagUnion(tags) => debug_name_tag(tags), FlatInspectableKey::Function(arity) => debug_name_fn(*arity), FlatInspectableKey::Error => "error".to_string(), - FlatInspectableKey::TypeVar(name) => format!("typeVariable({name})"), + FlatInspectableKey::Opaque => "opaque".to_string(), } } } impl FlatInspectable { pub(crate) fn from_var(subs: &Subs, var: Variable) -> FlatInspectable { - use DeriveError::*; use FlatInspectable::*; + match *subs.get_content_without_compacting(var) { Content::Structure(flat_type) => match flat_type { FlatType::Apply(sym, _) => match sym { @@ -58,21 +56,15 @@ impl FlatInspectable { Symbol::SET_SET => Key(FlatInspectableKey::Set()), Symbol::DICT_DICT => Key(FlatInspectableKey::Dict()), Symbol::STR_STR => Immediate(Symbol::INSPECT_STR), - Symbol::NUM_NUM => { - todo!(); - // TODO need to match again to see what type of Num it was, then - // use Symbol::INSPECT_WHATEVERNUMBERTYPE - } _ => Immediate(Symbol::INSPECT_OPAQUE), }, FlatType::Record(fields, ext) => { let (fields_iter, ext) = fields.unsorted_iterator_and_ext(subs, ext); + // TODO someday we can put #[cfg(debug_assertions)] around this, but for now let's always do it. check_derivable_ext_var(subs, ext, |ext| { - todo!(); // TODO open records can still derive Inspect, but we need to decide how/if to render the ext var. - - // matches!(ext, Content::Structure(FlatType::EmptyRecord)) - }); + matches!(ext, Content::Structure(FlatType::EmptyRecord)) + }).expect("Compiler error: unexpected nonempty ext var when deriving Inspect for record"); let mut field_names = Vec::with_capacity(fields.len()); for (field_name, _) in fields_iter { @@ -86,11 +78,10 @@ impl FlatInspectable { FlatType::Tuple(elems, ext) => { let (elems_iter, ext) = elems.sorted_iterator_and_ext(subs, ext); + // TODO someday we can put #[cfg(debug_assertions)] around this, but for now let's always do it. check_derivable_ext_var(subs, ext, |ext| { - todo!(); // TODO open tuples can still derive Inspect, but we need to decide how/if to render the ext var. - - // matches!(ext, Content::Structure(FlatType::EmptyTuple)) - }); + matches!(ext, Content::Structure(FlatType::EmptyTuple)) + }).expect("Compiler error: unexpected nonempty ext var when deriving Inspect for tuple"); Key(FlatInspectableKey::Tuple(elems_iter.count() as _)) } @@ -106,11 +97,10 @@ impl FlatInspectable { // `t`-prefixed payload types. let (tags_iter, ext) = tags.unsorted_tags_and_ext(subs, ext); + // TODO someday we can put #[cfg(debug_assertions)] around this, but for now let's always do it. check_derivable_ext_var(subs, ext.var(), |ext| { - todo!(); // TODO open tag unions can still derive Inspect, but we need to decide how/if to render the ext var. - - // matches!(ext, Content::Structure(FlatType::EmptyTagUnion)) - }); + matches!(ext, Content::Structure(FlatType::EmptyTagUnion)) + }).expect("Compiler error: unexpected nonempty ext var when deriving Inspect for tag union"); let mut tag_names_and_payload_sizes: Vec<_> = tags_iter .tags @@ -134,14 +124,13 @@ impl FlatInspectable { )) } FlatType::EmptyRecord => Key(FlatInspectableKey::Record(Vec::new())), - FlatType::EmptyTuple => todo!(), FlatType::EmptyTagUnion => Key(FlatInspectableKey::TagUnion(Vec::new())), - // FlatType::Func(slice, ..) => { let arity = subs.get_subs_slice(slice).len(); Key(FlatInspectableKey::Function(arity as u32)) } + FlatType::EmptyTuple => unreachable!("Somehow Inspect derivation got an expression that's an empty tuple, which shouldn't be possible!"), }, Content::Alias(sym, _, real_var, _) => match Self::from_builtin_alias(sym) { Some(lambda) => lambda, @@ -157,13 +146,9 @@ impl FlatInspectable { Content::FlexVar(_) | Content::RigidVar(_) | Content::FlexAbleVar(_, _) - | Content::RigidAbleVar(_, _) => { - let var_name: String = todo!(); - - Key(FlatInspectableKey::TypeVar(var_name)) - } - Content::LambdaSet(_) | Content::ErasedLambda => { - unreachable!(); + | Content::RigidAbleVar(_, _) + | Content::LambdaSet(_) | Content::ErasedLambda => { + unreachable!("There must have been a bug in the solver, because we're trying to derive Inspect on a non-concrete type."); } } } diff --git a/crates/compiler/module/src/symbol.rs b/crates/compiler/module/src/symbol.rs index 2ba48416ad..6465511b25 100644 --- a/crates/compiler/module/src/symbol.rs +++ b/crates/compiler/module/src/symbol.rs @@ -1627,6 +1627,8 @@ define_builtins! { 30 INSPECT_APPLY: "apply" 31 INSPECT_TO_INSPECTOR: "toInspector" 32 INSPECT_NAT: "nat" + 33 INSPECT_INSPECT_FN: "inspectFn" + 34 INSPECT_INSPECT_OPAQUE: "inspectOpaque" } 15 JSON: "TotallyNotJson" => { 0 JSON_JSON: "TotallyNotJson" From c87e3e7413d82a6b380c2a654af255db1efa41e1 Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Tue, 12 Sep 2023 11:49:26 -0500 Subject: [PATCH 06/40] TODO --- crates/compiler/can/src/derive.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crates/compiler/can/src/derive.rs b/crates/compiler/can/src/derive.rs index 09623703e7..fd51376919 100644 --- a/crates/compiler/can/src/derive.rs +++ b/crates/compiler/can/src/derive.rs @@ -241,6 +241,12 @@ fn to_inspector<'a>(env: &mut Env<'a>, at_opaque: &'a str) -> ast::Expr<'a> { roc_module::called_via::CalledVia::Space, )); + // TODO: change the derived implementation to be something that includes the opaque symbol in + // the derivation, e.g. something like + // + // \@Opaq payload -> + // Inspect.opaqueWrapper "toString symbol" payload + // \@Opaq payload -> Inspect.toInspector payload ast::Expr::Closure( env.arena From 5c805ce80f163e1d8639f44f447d54c69b42e543 Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Tue, 12 Sep 2023 12:11:36 -0500 Subject: [PATCH 07/40] Get first inspect for non-Inspect-implementing opaques specialized --- crates/compiler/builtins/roc/Inspect.roc | 18 ++------ crates/compiler/can/src/def.rs | 1 + crates/compiler/derive_key/src/inspect.rs | 44 +++++++++++++++---- crates/compiler/module/src/symbol.rs | 37 ++++++++-------- crates/compiler/solve/src/specialize.rs | 13 +++++- .../inspect/non_implementing_opaque.txt | 6 +++ 6 files changed, 75 insertions(+), 44 deletions(-) create mode 100644 crates/compiler/uitest/tests/ability/specialize/inspect/non_implementing_opaque.txt diff --git a/crates/compiler/builtins/roc/Inspect.roc b/crates/compiler/builtins/roc/Inspect.roc index 987a0eebce..615a5863aa 100644 --- a/crates/compiler/builtins/roc/Inspect.roc +++ b/crates/compiler/builtins/roc/Inspect.roc @@ -15,6 +15,7 @@ interface Inspect record, bool, str, + function, opaque, u8, i8, @@ -33,13 +34,10 @@ interface Inspect custom, apply, toInspector, - # TODO don't expose these - there's some way to do this! - inspectFn, - inspectOpaque, ] imports [ Bool.{ Bool }, - Num.{ U8, U16, U32, U64, U128, I8, I16, I32, I64, I128, F32, F64, Dec }, + Num.{ U8, U16, U32, U64, U128, I8, I16, I32, I64, I128, F32, F64, Dec, Nat }, List, Str, ] @@ -61,10 +59,10 @@ InspectFormatter implements dict : dict, KeyValWalker state dict key value, (key -> Inspector f), (value -> Inspector f) -> Inspector f where f implements InspectFormatter # In text, this would render as `` - opaque : Inspector f where f implements InspectFormatter + opaque : * -> Inspector f where f implements InspectFormatter # In text, this would render as `` - function : Inspector f where f implements InspectFormatter + function : * -> Inspector f where f implements InspectFormatter u8 : U8 -> Inspector f where f implements InspectFormatter i8 : I8 -> Inspector f where f implements InspectFormatter @@ -96,11 +94,3 @@ inspect : val -> f where val implements Inspect, f implements InspectFormatter inspect = \val -> (@Inspector valFn) = toInspector val valFn (init {}) - -## Should not be exposed, only used in auto-deriving -inspectFn : * -> Inspector f where f implements InspectFormatter -inspectFn = \_ -> function - -## Should not be exposed, only used in auto-deriving -inspectOpaque : * -> Inspector f where f implements InspectFormatter -inspectOpaque = \_ -> opaque diff --git a/crates/compiler/can/src/def.rs b/crates/compiler/can/src/def.rs index 2496689eb8..804665e3a9 100644 --- a/crates/compiler/can/src/def.rs +++ b/crates/compiler/can/src/def.rs @@ -718,6 +718,7 @@ fn canonicalize_opaque<'a>( let ability_region = ability.region; + // Op := {} has [Eq] let (ability, members) = match ability.value { ast::TypeAnnotation::Apply(module_name, ident, []) => { match make_apply_symbol(env, region, scope, module_name, ident) { diff --git a/crates/compiler/derive_key/src/inspect.rs b/crates/compiler/derive_key/src/inspect.rs index 439033aee7..0f71c854a9 100644 --- a/crates/compiler/derive_key/src/inspect.rs +++ b/crates/compiler/derive_key/src/inspect.rs @@ -2,7 +2,10 @@ use roc_module::{ ident::{Lowercase, TagName}, symbol::Symbol, }; -use roc_types::subs::{Content, FlatType, GetSubsSlice, Subs, Variable}; +use roc_types::{ + subs::{Content, FlatType, GetSubsSlice, Subs, Variable}, + types::AliasKind, +}; use crate::util::{ check_derivable_ext_var, debug_name_fn, debug_name_record, debug_name_tag, debug_name_tuple, @@ -125,18 +128,41 @@ impl FlatInspectable { } FlatType::EmptyRecord => Key(FlatInspectableKey::Record(Vec::new())), FlatType::EmptyTagUnion => Key(FlatInspectableKey::TagUnion(Vec::new())), - FlatType::Func(slice, ..) => { - let arity = subs.get_subs_slice(slice).len(); - - Key(FlatInspectableKey::Function(arity as u32)) + FlatType::Func(..) => { + Immediate(Symbol::INSPECT_FUNCTION) } FlatType::EmptyTuple => unreachable!("Somehow Inspect derivation got an expression that's an empty tuple, which shouldn't be possible!"), }, - Content::Alias(sym, _, real_var, _) => match Self::from_builtin_alias(sym) { + Content::Alias(sym, _, real_var, kind) => match Self::from_builtin_alias(sym) { Some(lambda) => lambda, - // 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), + + _ => { + match kind { + AliasKind::Structural => { + Self::from_var(subs, real_var) + } + AliasKind::Opaque => { + // There are two cases in which `Inspect` can be derived for an opaque + // type. + // 1. An opaque type claims to implement `Inspect` and asks us to + // auto-derive it. E.g. + // + // ```text + // Op := {} implements [Inspect] + // ``` + // + // In this case, we generate a synthetic implementation during + // canonicalization that defers to `inspect`ing the inner type. As + // such, this case is never reached in this branch. + // + // 2. An opaque type does not explicitly claim to implement + // `Inspect`. In this case, we print a default opaque string for + // the opaque type. + Immediate(Symbol::INSPECT_OPAQUE) + } + } + } + }, Content::RangedNumber(range) => { Self::from_var(subs, range.default_compilation_variable()) diff --git a/crates/compiler/module/src/symbol.rs b/crates/compiler/module/src/symbol.rs index 6465511b25..d86c117a32 100644 --- a/crates/compiler/module/src/symbol.rs +++ b/crates/compiler/module/src/symbol.rs @@ -1610,25 +1610,24 @@ define_builtins! { 13 INSPECT_BOOL: "bool" 14 INSPECT_STR: "str" 15 INSPECT_OPAQUE: "opaque" - 16 INSPECT_U8: "u8" - 17 INSPECT_I8: "i8" - 18 INSPECT_U16: "u16" - 19 INSPECT_I16: "i16" - 20 INSPECT_U32: "u32" - 21 INSPECT_I32: "i32" - 22 INSPECT_U64: "u64" - 23 INSPECT_I64: "i64" - 24 INSPECT_U128: "u128" - 25 INSPECT_I128: "i128" - 26 INSPECT_F32: "f32" - 27 INSPECT_F64: "f64" - 28 INSPECT_DEC: "dec" - 29 INSPECT_CUSTOM: "custom" - 30 INSPECT_APPLY: "apply" - 31 INSPECT_TO_INSPECTOR: "toInspector" - 32 INSPECT_NAT: "nat" - 33 INSPECT_INSPECT_FN: "inspectFn" - 34 INSPECT_INSPECT_OPAQUE: "inspectOpaque" + 16 INSPECT_FUNCTION: "function" + 17 INSPECT_U8: "u8" + 18 INSPECT_I8: "i8" + 19 INSPECT_U16: "u16" + 20 INSPECT_I16: "i16" + 21 INSPECT_U32: "u32" + 22 INSPECT_I32: "i32" + 23 INSPECT_U64: "u64" + 24 INSPECT_I64: "i64" + 25 INSPECT_U128: "u128" + 26 INSPECT_I128: "i128" + 27 INSPECT_F32: "f32" + 28 INSPECT_F64: "f64" + 29 INSPECT_DEC: "dec" + 30 INSPECT_CUSTOM: "custom" + 31 INSPECT_APPLY: "apply" + 32 INSPECT_TO_INSPECTOR: "toInspector" + 33 INSPECT_NAT: "nat" } 15 JSON: "TotallyNotJson" => { 0 JSON_JSON: "TotallyNotJson" diff --git a/crates/compiler/solve/src/specialize.rs b/crates/compiler/solve/src/specialize.rs index 2ccee11d50..7673eb5bd4 100644 --- a/crates/compiler/solve/src/specialize.rs +++ b/crates/compiler/solve/src/specialize.rs @@ -634,8 +634,17 @@ fn make_specialization_decision( }; match abilities_store.get_implementation(impl_key) { None => { - // Doesn't specialize; an error will already be reported for this. - SpecializeDecision::Drop + match ability_member { + // Inspect is special - if there is no implementation for the + // opaque type, we always emit a default implementation. + Symbol::INSPECT_TO_INSPECTOR => SpecializeDecision::Specialize( + Immediate(Symbol::INSPECT_OPAQUE), + ), + _ => { + // Doesn't specialize; an error will already be reported for this. + SpecializeDecision::Drop + } + } } Some(MemberImpl::Error) => { // TODO: probably not right, we may want to choose a derive decision! diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/non_implementing_opaque.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/non_implementing_opaque.txt new file mode 100644 index 0000000000..c0b907ae38 --- /dev/null +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/non_implementing_opaque.txt @@ -0,0 +1,6 @@ +app "test" provides [main] to "./platform" + +Op := {} + +main = Inspect.toInspector (@Op {}) +# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Op -[[] + f:Inspect.opaque(15):1]-> Inspector f where f implements InspectFormatter From d36eba98fcb9ffe21496fa3b68995517664007ad Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Tue, 12 Sep 2023 12:17:34 -0500 Subject: [PATCH 08/40] Add a few more opaque tests `specialize/inspect/opaque_derived` does not yet pass. --- .../ability/specialize/inspect/opaque_custom_impl.txt | 9 +++++++++ .../tests/ability/specialize/inspect/opaque_derived.txt | 6 ++++++ 2 files changed, 15 insertions(+) create mode 100644 crates/compiler/uitest/tests/ability/specialize/inspect/opaque_custom_impl.txt create mode 100644 crates/compiler/uitest/tests/ability/specialize/inspect/opaque_derived.txt diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_custom_impl.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_custom_impl.txt new file mode 100644 index 0000000000..2b5a4b1cfa --- /dev/null +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_custom_impl.txt @@ -0,0 +1,9 @@ +app "test" provides [main] to "./platform" + +Op := U8 implements [Inspect { toInspector: myToInspector }] + +myToInspector : Op -> Inspector f where f implements InspectFormatter +myToInspector = \@Op num -> Inspect.u8 num + +main = Inspect.toInspector (@Op 1u8) +# ^^^^^^^^^^^^^^^^^^^ Op#Inspect.toInspector(2): Op -[[myToInspector(2)]]-> Inspector f where f implements InspectFormatter diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_derived.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_derived.txt new file mode 100644 index 0000000000..cfe872a6bd --- /dev/null +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_derived.txt @@ -0,0 +1,6 @@ +app "test" provides [main] to "./platform" + +Op := U8 implements [Inspect] + +main = Inspect.toInspector (@Op 1u8) +# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Op -[[] + f:Inspect.opaque(15):1]-> Inspector f where f implements InspectFormatter From 443f6593c51fcf09670c3087d462fa4fea57c464 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Wed, 18 Oct 2023 08:04:58 -0400 Subject: [PATCH 09/40] Add Inspect.Inspect to subs and auto-derive --- crates/compiler/solve/src/ability.rs | 106 +++++++++++++++++++++++++++ crates/compiler/types/src/subs.rs | 3 + 2 files changed, 109 insertions(+) diff --git a/crates/compiler/solve/src/ability.rs b/crates/compiler/solve/src/ability.rs index a29b98e6ef..6ffa242ba1 100644 --- a/crates/compiler/solve/src/ability.rs +++ b/crates/compiler/solve/src/ability.rs @@ -386,6 +386,7 @@ impl ObligationCache { DeriveDecoding::ABILITY => DeriveDecoding::is_derivable_builtin_opaque(opaque), DeriveEq::ABILITY => DeriveEq::is_derivable_builtin_opaque(opaque), DeriveHash::ABILITY => DeriveHash::is_derivable_builtin_opaque(opaque), + DeriveInspect::ABILITY => DeriveInspect::is_derivable_builtin_opaque(opaque), _ => false, }; @@ -851,6 +852,111 @@ trait DerivableVisitor { } } +struct DeriveInspect; +impl DerivableVisitor for DeriveInspect { + const ABILITY: Symbol = Symbol::INSPECT_INSPECT; + const ABILITY_SLICE: SubsSlice = Subs::AB_INSPECT; + + #[inline(always)] + fn is_derivable_builtin_opaque(symbol: Symbol) -> bool { + (is_builtin_number_alias(symbol) && !is_builtin_nat_alias(symbol)) + || is_builtin_bool_alias(symbol) + } + + #[inline(always)] + fn visit_recursion(_var: Variable) -> Result { + Ok(Descend(true)) + } + + #[inline(always)] + fn visit_apply(var: Variable, symbol: Symbol) -> Result { + if matches!( + symbol, + Symbol::LIST_LIST | Symbol::SET_SET | Symbol::DICT_DICT | Symbol::STR_STR, + ) { + Ok(Descend(true)) + } else { + Err(NotDerivable { + var, + context: NotDerivableContext::NoContext, + }) + } + } + + #[inline(always)] + fn visit_record( + _subs: &Subs, + _var: Variable, + _fields: RecordFields, + ) -> Result { + Ok(Descend(true)) + } + + #[inline(always)] + fn visit_tuple( + _subs: &Subs, + _var: Variable, + _elems: TupleElems, + ) -> Result { + Ok(Descend(true)) + } + + #[inline(always)] + fn visit_tag_union(_var: Variable) -> Result { + Ok(Descend(true)) + } + + #[inline(always)] + fn visit_recursive_tag_union(_var: Variable) -> Result { + Ok(Descend(true)) + } + + #[inline(always)] + fn visit_function_or_tag_union(_var: Variable) -> Result { + Ok(Descend(true)) + } + + #[inline(always)] + fn visit_empty_record(_var: Variable) -> Result<(), NotDerivable> { + Ok(()) + } + + #[inline(always)] + fn visit_empty_tag_union(_var: Variable) -> Result<(), NotDerivable> { + Ok(()) + } + + #[inline(always)] + fn visit_alias(var: Variable, symbol: Symbol) -> Result { + if is_builtin_number_alias(symbol) { + if is_builtin_nat_alias(symbol) { + Err(NotDerivable { + var, + context: NotDerivableContext::Encode(NotDerivableEncode::Nat), + }) + } else { + Ok(Descend(false)) + } + } else { + Ok(Descend(true)) + } + } + + #[inline(always)] + fn visit_ranged_number(_var: Variable, _range: NumericRange) -> Result<(), NotDerivable> { + Ok(()) + } + + #[inline(always)] + fn visit_floating_point_content( + _var: Variable, + _subs: &mut Subs, + _content_var: Variable, + ) -> Result { + Ok(Descend(false)) + } +} + struct DeriveEncoding; impl DerivableVisitor for DeriveEncoding { const ABILITY: Symbol = Symbol::ENCODE_ENCODING; diff --git a/crates/compiler/types/src/subs.rs b/crates/compiler/types/src/subs.rs index 8a62e63650..07dda6b003 100644 --- a/crates/compiler/types/src/subs.rs +++ b/crates/compiler/types/src/subs.rs @@ -1726,6 +1726,8 @@ impl Subs { pub const AB_HASH: SubsSlice = SubsSlice::new(3, 1); #[rustfmt::skip] pub const AB_EQ: SubsSlice = SubsSlice::new(4, 1); + #[rustfmt::skip] + pub const AB_INSPECT: SubsSlice = SubsSlice::new(5, 1); // END INIT-SymbolSubsSlice pub fn new() -> Self { @@ -1754,6 +1756,7 @@ impl Subs { symbol_names.push(Symbol::HASH_HASHER); symbol_names.push(Symbol::HASH_HASH_ABILITY); symbol_names.push(Symbol::BOOL_EQ); + symbol_names.push(Symbol::INSPECT_INSPECT); // END INIT-SymbolNames // IFTTT INIT-VariableSubsSlice From 768b55b8c58af6accf279b019089d2ffaf681b9e Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Wed, 18 Oct 2023 16:01:27 -0400 Subject: [PATCH 10/40] Add some Inspect.inspect tests, fix a bug --- crates/compiler/derive_key/src/inspect.rs | 2 +- crates/compiler/test_gen/src/gen_abilities.rs | 109 +++++++++++++++++- 2 files changed, 104 insertions(+), 7 deletions(-) diff --git a/crates/compiler/derive_key/src/inspect.rs b/crates/compiler/derive_key/src/inspect.rs index 0f71c854a9..3bc5793c46 100644 --- a/crates/compiler/derive_key/src/inspect.rs +++ b/crates/compiler/derive_key/src/inspect.rs @@ -183,7 +183,7 @@ impl FlatInspectable { use FlatInspectable::*; match symbol { - Symbol::BOOL_BOOL => Some(Immediate(Symbol::ENCODE_BOOL)), + Symbol::BOOL_BOOL => Some(Immediate(Symbol::INSPECT_BOOL)), Symbol::NUM_U8 | Symbol::NUM_UNSIGNED8 => Some(Immediate(Symbol::INSPECT_U8)), Symbol::NUM_U16 | Symbol::NUM_UNSIGNED16 => Some(Immediate(Symbol::INSPECT_U16)), Symbol::NUM_U32 | Symbol::NUM_UNSIGNED32 => Some(Immediate(Symbol::INSPECT_U32)), diff --git a/crates/compiler/test_gen/src/gen_abilities.rs b/crates/compiler/test_gen/src/gen_abilities.rs index 218e8f6f79..4f45e5510c 100644 --- a/crates/compiler/test_gen/src/gen_abilities.rs +++ b/crates/compiler/test_gen/src/gen_abilities.rs @@ -2159,19 +2159,19 @@ fn issue_4772_weakened_monomorphic_destructure() { getNumber = { result, rest } = Decode.fromBytesPartial (Str.toUtf8 "\"1234\"") TotallyNotJson.json - - when result is - Ok val -> - when Str.toI64 val is + + when result is + Ok val -> + when Str.toI64 val is Ok number -> Ok {val : number, input : rest} Err InvalidNumStr -> Err (ParsingFailure "not a number") - Err _ -> + Err _ -> Err (ParsingFailure "not a number") - main = + main = getNumber |> Result.map .val |> Result.withDefault 0 "### ), @@ -2180,3 +2180,100 @@ fn issue_4772_weakened_monomorphic_destructure() { ) }) } + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +fn inspect_bool() { + assert_evals_to!( + indoc!( + r#" + app "test" provides [main] to "./platform" + + main = [ + Inspect.inspect Bool.true, + Inspect.inspect Bool.false, + ] |> Str.joinWith ", " + "# + ), + RocStr::from("Bool.true, Bool.false"), + RocStr + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +fn inspect_num() { + assert_evals_to!( + indoc!( + r#" + app "test" provides [main] to "./platform" + + main = [ + Inspect.inspect 42, # Num * + Inspect.inspect 0x5, # Int * + Inspect.inspect (0.1 + 0.2), # Frac * + Inspect.inspect 1u8, # U8 + Inspect.inspect 2i8, # I8 + Inspect.inspect 3u16, # U16 + Inspect.inspect 4i16, # I16 + Inspect.inspect 5u32, # U32 + Inspect.inspect 6i32, # I32 + Inspect.inspect 7u64, # U64 + Inspect.inspect 8i64, # I64 + Inspect.inspect 9u128, # U128 + Inspect.inspect 10i128, # I128 + Inspect.inspect 1.1f32, # F32 + Inspect.inspect 2.2f64, # F64 + Inspect.inspect (1.1dec + 2.2), # Dec + ] |> Str.joinWith ", " + "# + ), + RocStr::from("42, 5, 0.3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1.1, 2.2, 3.3"), + RocStr + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +fn inspect_list() { + assert_evals_to!( + indoc!( + r#" + app "test" provides [main] to "./platform" + + main = [ + Inspect.inspect [], # List * + Inspect.inspect [0, 1, 2], # List (Num *) + Inspect.inspect [1, 0x2, 3], # List (Int *) + Inspect.inspect [0.1 + 0.2, 0.4], # List (Frac *) + Inspect.inspect [1u8, 2u8], # List U8 + Inspect.inspect ["foo"], # List Str + ] |> Str.joinWith ", " + "# + ), + RocStr::from("[], [0, 1, 2], [1, 2, 3], [0.3, 0.4], [1, 2], [\"foo\"]"), + RocStr + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +fn inspect_str() { + assert_evals_to!( + indoc!( + r#" + app "test" provides [main] to "./platform" + + main = [ + Inspect.inspect "", + Inspect.inspect "a small string", + Inspect.inspect "an extraordinarily long string - so long it's on the heap!", + ] |> Str.joinWith ", " + "# + ), + RocStr::from( + r#""", "a small string", "an extraordinarily long string - so long it's on the heap!""# + ), + RocStr + ); +} From b8e644a1e399161e27cd1fae39861ebab593d143 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Mon, 27 Nov 2023 17:13:11 -0800 Subject: [PATCH 11/40] add DbgFormatter to inspect --- crates/compiler/builtins/roc/Inspect.roc | 258 +++++++++++++++++- crates/compiler/module/src/symbol.rs | 2 + crates/compiler/test_gen/src/gen_abilities.rs | 8 +- 3 files changed, 262 insertions(+), 6 deletions(-) diff --git a/crates/compiler/builtins/roc/Inspect.roc b/crates/compiler/builtins/roc/Inspect.roc index 615a5863aa..611fa04e00 100644 --- a/crates/compiler/builtins/roc/Inspect.roc +++ b/crates/compiler/builtins/roc/Inspect.roc @@ -34,6 +34,8 @@ interface Inspect custom, apply, toInspector, + DbgFormatter, + toDbgStr, ] imports [ Bool.{ Bool }, @@ -59,10 +61,12 @@ InspectFormatter implements dict : dict, KeyValWalker state dict key value, (key -> Inspector f), (value -> Inspector f) -> Inspector f where f implements InspectFormatter # In text, this would render as `` - opaque : * -> Inspector f where f implements InspectFormatter + # TODO: Pass the type name to opaque so that it can be displayed. + opaque : Inspector f where f implements InspectFormatter # In text, this would render as `` - function : * -> Inspector f where f implements InspectFormatter + # TODO: Maybe pass the the function name or signiture to function so that it can be displayed. + function : Inspector f where f implements InspectFormatter u8 : U8 -> Inspector f where f implements InspectFormatter i8 : I8 -> Inspector f where f implements InspectFormatter @@ -94,3 +98,253 @@ inspect : val -> f where val implements Inspect, f implements InspectFormatter inspect = \val -> (@Inspector valFn) = toInspector val valFn (init {}) + + +# The current default formatter for inspect. +# This just returns a simple string for debugging. +# More powerful formatters will likely be wanted in the future. +DbgFormatter := { data : Str } + implements [ + InspectFormatter { + init: dbgInit, + list: dbgList, + set: dbgSet, + dict: dbgDict, + tag: dbgTag, + tuple: dbgTuple, + record: dbgRecord, + bool: dbgBool, + str: dbgStr, + opaque: dbgOpaque, + function: dbgFunction, + u8: dbgU8, + i8: dbgI8, + u16: dbgU16, + i16: dbgI16, + u32: dbgU32, + i32: dbgI32, + u64: dbgU64, + i64: dbgI64, + u128: dbgU128, + i128: dbgI128, + nat: dbgNat, + f32: dbgF32, + f64: dbgF64, + dec: dbgDec, + }, + ] + +dbgInit : {} -> DbgFormatter +dbgInit = \{} -> @DbgFormatter { data: "" } + +dbgList : list, ElemWalker (DbgFormatter, Bool) list elem, (elem -> Inspector DbgFormatter) -> Inspector DbgFormatter +dbgList = \content, walkFn, toDbgInspector -> + f0 <- custom + dbgWrite f0 "[" + |> \f1 -> + (f2, prependSep), elem <- walkFn content (f1, Bool.false) + f3 = + if prependSep then + dbgWrite f2 ", " + else + f2 + + elem + |> toDbgInspector + |> apply f3 + |> \f4 -> (f4, Bool.true) + |> .0 + |> dbgWrite "]" + +dbgSet : set, ElemWalker (DbgFormatter, Bool) set elem, (elem -> Inspector DbgFormatter) -> Inspector DbgFormatter +dbgSet = \content, walkFn, toDbgInspector -> + f0 <- custom + dbgWrite f0 "{" + |> \f1 -> + (f2, prependSep), elem <- walkFn content (f1, Bool.false) + f3 = + if prependSep then + dbgWrite f2 ", " + else + f2 + + elem + |> toDbgInspector + |> apply f3 + |> \f4 -> (f4, Bool.true) + |> .0 + |> dbgWrite "}" + +dbgDict : dict, KeyValWalker (DbgFormatter, Bool) dict key value, (key -> Inspector DbgFormatter), (value -> Inspector DbgFormatter) -> Inspector DbgFormatter +dbgDict = \d, walkFn, keyToInspector, valueToInspector -> + f0 <- custom + dbgWrite f0 "{" + |> \f1 -> + (f2, prependSep), key, value <- walkFn d (f1, Bool.false) + f3 = + if prependSep then + dbgWrite f2 ", " + else + f2 + + apply (keyToInspector key) f3 + |> dbgWrite ": " + |> \x -> apply (valueToInspector value) x + |> \f4 -> (f4, Bool.true) + |> .0 + |> dbgWrite "}" + +dbgTag : Str, List (Inspector DbgFormatter) -> Inspector DbgFormatter +dbgTag = \name, fields -> + if List.isEmpty fields then + f0 <- custom + dbgWrite f0 name + else + f0 <- custom + dbgWrite f0 "(" + |> dbgWrite name + |> \f1 -> + f2, inspector <- List.walk fields f1 + dbgWrite f2 " " + |> \x -> apply inspector x + |> dbgWrite ")" + +dbgTuple : List (Inspector DbgFormatter) -> Inspector DbgFormatter +dbgTuple = \fields -> + f0 <- custom + dbgWrite f0 "(" + |> \f1 -> + (f2, prependSep), inspector <- List.walk fields (f1, Bool.false) + f3 = + if prependSep then + dbgWrite f2 ", " + else + f2 + + apply inspector f3 + |> \f4 -> (f4, Bool.true) + |> .0 + |> dbgWrite ")" + +dbgRecord : List { key : Str, value : Inspector DbgFormatter } -> Inspector DbgFormatter +dbgRecord = \fields -> + f0 <- custom + dbgWrite f0 "{" + |> \f1 -> + (f2, prependSep), { key, value } <- List.walk fields (f1, Bool.false) + f3 = + if prependSep then + dbgWrite f2 ", " + else + f2 + + dbgWrite f3 key + |> dbgWrite ": " + |> \x -> apply value x + |> \f4 -> (f4, Bool.true) + |> .0 + |> dbgWrite "}" + +dbgBool : Bool -> Inspector DbgFormatter +dbgBool = \b -> + if b then + f0 <- custom + dbgWrite f0 "true" + else + f0 <- custom + dbgWrite f0 "false" + +dbgStr : Str -> Inspector DbgFormatter +dbgStr = \s -> + f0 <- custom + f0 + |> dbgWrite "\"" + |> dbgWrite s + |> dbgWrite "\"" + +dbgOpaque : Inspector DbgFormatter +dbgOpaque = + f0 <- custom + dbgWrite f0 "" + +dbgFunction : Inspector DbgFormatter +dbgFunction = + f0 <- custom + dbgWrite f0 "" + +dbgU8 : U8 -> Inspector DbgFormatter +dbgU8 = \num -> + f0 <- custom + dbgWrite f0 (num |> Num.toStr) + +dbgI8 : I8 -> Inspector DbgFormatter +dbgI8 = \num -> + f0 <- custom + dbgWrite f0 (num |> Num.toStr) + +dbgU16 : U16 -> Inspector DbgFormatter +dbgU16 = \num -> + f0 <- custom + dbgWrite f0 (num |> Num.toStr) + +dbgI16 : I16 -> Inspector DbgFormatter +dbgI16 = \num -> + f0 <- custom + dbgWrite f0 (num |> Num.toStr) + +dbgU32 : U32 -> Inspector DbgFormatter +dbgU32 = \num -> + f0 <- custom + dbgWrite f0 (num |> Num.toStr) + +dbgI32 : I32 -> Inspector DbgFormatter +dbgI32 = \num -> + f0 <- custom + dbgWrite f0 (num |> Num.toStr) + +dbgU64 : U64 -> Inspector DbgFormatter +dbgU64 = \num -> + f0 <- custom + dbgWrite f0 (num |> Num.toStr) + +dbgI64 : I64 -> Inspector DbgFormatter +dbgI64 = \num -> + f0 <- custom + dbgWrite f0 (num |> Num.toStr) + +dbgU128 : U128 -> Inspector DbgFormatter +dbgU128 = \num -> + f0 <- custom + dbgWrite f0 (num |> Num.toStr) + +dbgI128 : I128 -> Inspector DbgFormatter +dbgI128 = \num -> + f0 <- custom + dbgWrite f0 (num |> Num.toStr) + +dbgNat : Nat -> Inspector DbgFormatter +dbgNat = \num -> + f0 <- custom + dbgWrite f0 (num |> Num.toStr) + +dbgF32 : F32 -> Inspector DbgFormatter +dbgF32 = \num -> + f0 <- custom + dbgWrite f0 (num |> Num.toStr) + +dbgF64 : F64 -> Inspector DbgFormatter +dbgF64 = \num -> + f0 <- custom + dbgWrite f0 (num |> Num.toStr) + +dbgDec : Dec -> Inspector DbgFormatter +dbgDec = \num -> + f0 <- custom + dbgWrite f0 (num |> Num.toStr) + +dbgWrite : DbgFormatter, Str -> DbgFormatter +dbgWrite = \@DbgFormatter { data }, added -> + @DbgFormatter { data: Str.concat data added } + +toDbgStr : DbgFormatter -> Str +toDbgStr = \@DbgFormatter { data } -> data diff --git a/crates/compiler/module/src/symbol.rs b/crates/compiler/module/src/symbol.rs index d86c117a32..bbd130d326 100644 --- a/crates/compiler/module/src/symbol.rs +++ b/crates/compiler/module/src/symbol.rs @@ -1628,6 +1628,8 @@ define_builtins! { 31 INSPECT_APPLY: "apply" 32 INSPECT_TO_INSPECTOR: "toInspector" 33 INSPECT_NAT: "nat" + 34 INSPECT_DBG_FORMATTER: "DbgFormatter" exposed_type=true + 35 INSPECT_TO_DBG_STR: "toDbgStr" } 15 JSON: "TotallyNotJson" => { 0 JSON_JSON: "TotallyNotJson" diff --git a/crates/compiler/test_gen/src/gen_abilities.rs b/crates/compiler/test_gen/src/gen_abilities.rs index 4f45e5510c..44c5e4b5f5 100644 --- a/crates/compiler/test_gen/src/gen_abilities.rs +++ b/crates/compiler/test_gen/src/gen_abilities.rs @@ -2192,7 +2192,7 @@ fn inspect_bool() { main = [ Inspect.inspect Bool.true, Inspect.inspect Bool.false, - ] |> Str.joinWith ", " + ] |> List.map Inspect.toDbgStr |> Str.joinWith ", " "# ), RocStr::from("Bool.true, Bool.false"), @@ -2225,7 +2225,7 @@ fn inspect_num() { Inspect.inspect 1.1f32, # F32 Inspect.inspect 2.2f64, # F64 Inspect.inspect (1.1dec + 2.2), # Dec - ] |> Str.joinWith ", " + ] |> List.map Inspect.toDbgStr |> Str.joinWith ", " "# ), RocStr::from("42, 5, 0.3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1.1, 2.2, 3.3"), @@ -2248,7 +2248,7 @@ fn inspect_list() { Inspect.inspect [0.1 + 0.2, 0.4], # List (Frac *) Inspect.inspect [1u8, 2u8], # List U8 Inspect.inspect ["foo"], # List Str - ] |> Str.joinWith ", " + ] |> List.map Inspect.toDbgStr |> Str.joinWith ", " "# ), RocStr::from("[], [0, 1, 2], [1, 2, 3], [0.3, 0.4], [1, 2], [\"foo\"]"), @@ -2268,7 +2268,7 @@ fn inspect_str() { Inspect.inspect "", Inspect.inspect "a small string", Inspect.inspect "an extraordinarily long string - so long it's on the heap!", - ] |> Str.joinWith ", " + ] |> List.map Inspect.toDbgStr |> Str.joinWith ", " "# ), RocStr::from( From 96b3cc300f353fea776cda3f49c91859915fd2c8 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Mon, 27 Nov 2023 17:29:44 -0800 Subject: [PATCH 12/40] encode/encoder to inspect/inspector --- crates/compiler/derive/src/inspect.rs | 873 +++++++++++++------------- 1 file changed, 440 insertions(+), 433 deletions(-) diff --git a/crates/compiler/derive/src/inspect.rs b/crates/compiler/derive/src/inspect.rs index c8413fbad6..1fd048c997 100644 --- a/crates/compiler/derive/src/inspect.rs +++ b/crates/compiler/derive/src/inspect.rs @@ -49,7 +49,7 @@ pub(crate) fn derive_to_inspector( Content::Structure(FlatType::Record(fields, Variable::EMPTY_RECORD)), ); - to_encoder_record(env, record_var, fields, def_symbol) + to_inspector_record(env, record_var, fields, def_symbol) } FlatInspectableKey::Tuple(arity) => { // Generalized tuple var so we can reuse this impl between many tuples: @@ -63,7 +63,7 @@ pub(crate) fn derive_to_inspector( Content::Structure(FlatType::Tuple(elems, Variable::EMPTY_TUPLE)), ); - to_encoder_tuple(env, tuple_var, elems, def_symbol) + to_inspector_tuple(env, tuple_var, elems, def_symbol) } FlatInspectableKey::TagUnion(tags) => { // Generalized tag union var so we can reuse this impl between many unions: @@ -88,7 +88,7 @@ pub(crate) fn derive_to_inspector( )), ); - to_encoder_tag_union(env, tag_union_var, union_tags, def_symbol) + to_inspector_tag_union(env, tag_union_var, union_tags, def_symbol) } FlatInspectableKey::Function(_arity) => { // Desired output: \x, y, z -> ... ===> "" @@ -100,7 +100,7 @@ pub(crate) fn derive_to_inspector( }; let specialization_lambda_sets = - env.get_specialization_lambda_sets(body_type, Symbol::ENCODE_TO_ENCODER); + env.get_specialization_lambda_sets(body_type, Symbol::INSPECT_TO_INSPECTOR); DerivedBody { body, @@ -110,7 +110,7 @@ pub(crate) fn derive_to_inspector( } fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { - // Build \lst -> Encode.list lst (\elem -> Encode.toEncoder elem) + // Build \lst -> Inspect.list lst (\elem -> Inspect.toInspector elem) // // TODO eta reduce this baby ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -127,76 +127,77 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { Content::Structure(FlatType::Apply(Symbol::LIST_LIST, elem_var_slice)), ); - // build `toEncoder elem` type - // val -[uls]-> Encoder fmt where fmt implements EncoderFormatting - let to_encoder_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_TO_ENCODER); + // build `toInspector elem` type + // val -[uls]-> Inspector fmt where fmt implements InspectorFormatting + let to_inspector_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_TO_INSPECTOR); // elem -[clos]-> t1 - let to_encoder_clos_var = env.subs.fresh_unnamed_flex_var(); // clos - let elem_encoder_var = env.subs.fresh_unnamed_flex_var(); // t1 - let elem_to_encoder_fn_var = synth_var( + let to_inspector_clos_var = env.subs.fresh_unnamed_flex_var(); // clos + let elem_inspector_var = env.subs.fresh_unnamed_flex_var(); // t1 + let elem_to_inspector_fn_var = synth_var( env.subs, Content::Structure(FlatType::Func( elem_var_slice, - to_encoder_clos_var, - elem_encoder_var, + to_inspector_clos_var, + elem_inspector_var, )), ); - // val -[uls]-> Encoder fmt where fmt implements EncoderFormatting + // val -[uls]-> Inspector fmt where fmt implements InspectorFormatting // ~ elem -[clos]-> t1 - env.unify(to_encoder_fn_var, elem_to_encoder_fn_var); + env.unify(to_inspector_fn_var, elem_to_inspector_fn_var); - // toEncoder : (typeof rcd.a) -[clos]-> Encoder fmt where fmt implements EncoderFormatting - let to_encoder_var = AbilityMember(Symbol::ENCODE_TO_ENCODER, None, elem_to_encoder_fn_var); - let to_encoder_fn = Box::new(( - to_encoder_fn_var, - Loc::at_zero(to_encoder_var), - to_encoder_clos_var, - elem_encoder_var, + // toInspector : (typeof rcd.a) -[clos]-> Inspector fmt where fmt implements InspectorFormatting + let to_inspector_var = + AbilityMember(Symbol::INSPECT_TO_INSPECTOR, None, elem_to_inspector_fn_var); + let to_inspector_fn = Box::new(( + to_inspector_fn_var, + Loc::at_zero(to_inspector_var), + to_inspector_clos_var, + elem_inspector_var, )); - // toEncoder elem - let to_encoder_call = Call( - to_encoder_fn, + // toInspector elem + let to_inspector_call = Call( + to_inspector_fn, vec![(elem_var, Loc::at_zero(Var(elem_sym, elem_var)))], CalledVia::Space, ); - // elem -[to_elem_encoder]-> toEncoder elem - let to_elem_encoder_sym = env.new_symbol("to_elem_encoder"); + // elem -[to_elem_inspector]-> toInspector elem + let to_elem_inspector_sym = env.new_symbol("to_elem_inspector"); // Create fn_var for ambient capture; we fix it up below. - let to_elem_encoder_fn_var = synth_var(env.subs, Content::Error); + let to_elem_inspector_fn_var = synth_var(env.subs, Content::Error); - // -[to_elem_encoder]-> - let to_elem_encoder_labels = - UnionLambdas::insert_into_subs(env.subs, once((to_elem_encoder_sym, vec![]))); - let to_elem_encoder_lset = synth_var( + // -[to_elem_inspector]-> + let to_elem_inspector_labels = + UnionLambdas::insert_into_subs(env.subs, once((to_elem_inspector_sym, vec![]))); + let to_elem_inspector_lset = synth_var( env.subs, Content::LambdaSet(LambdaSet { - solved: to_elem_encoder_labels, + solved: to_elem_inspector_labels, recursion_var: OptVariable::NONE, unspecialized: SubsSlice::default(), - ambient_function: to_elem_encoder_fn_var, + ambient_function: to_elem_inspector_fn_var, }), ); - // elem -[to_elem_encoder]-> toEncoder elem + // elem -[to_elem_inspector]-> toInspector elem env.subs.set_content( - to_elem_encoder_fn_var, + to_elem_inspector_fn_var, Content::Structure(FlatType::Func( elem_var_slice, - to_elem_encoder_lset, - elem_encoder_var, + to_elem_inspector_lset, + elem_inspector_var, )), ); - // \elem -> toEncoder elem - let to_elem_encoder = Closure(ClosureData { - function_type: to_elem_encoder_fn_var, - closure_type: to_elem_encoder_lset, - return_type: elem_encoder_var, - name: to_elem_encoder_sym, + // \elem -> toInspector elem + let to_elem_inspector = Closure(ClosureData { + function_type: to_elem_inspector_fn_var, + closure_type: to_elem_inspector_lset, + return_type: elem_inspector_var, + name: to_elem_inspector_sym, captured_symbols: vec![], recursive: Recursive::NotRecursive, arguments: vec![( @@ -204,60 +205,60 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { AnnotatedMark::known_exhaustive(), Loc::at_zero(Pattern::Identifier(elem_sym)), )], - loc_body: Box::new(Loc::at_zero(to_encoder_call)), + loc_body: Box::new(Loc::at_zero(to_inspector_call)), }); - // build `Encode.list lst (\elem -> Encode.toEncoder elem)` type - // List e, (e -> Encoder fmt) -[uls]-> Encoder fmt where fmt implements EncoderFormatting - let encode_list_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_LIST); + // build `Inspect.list lst (\elem -> Inspect.toInspector elem)` type + // List e, (e -> Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatting + let inspect_list_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_LIST); - // List elem, to_elem_encoder_fn_var -[clos]-> t1 - let this_encode_list_args_slice = - VariableSubsSlice::insert_into_subs(env.subs, [list_var, to_elem_encoder_fn_var]); - let this_encode_list_clos_var = env.subs.fresh_unnamed_flex_var(); // clos - let this_list_encoder_var = env.subs.fresh_unnamed_flex_var(); // t1 - let this_encode_list_fn_var = synth_var( + // List elem, to_elem_inspector_fn_var -[clos]-> t1 + let this_inspect_list_args_slice = + VariableSubsSlice::insert_into_subs(env.subs, [list_var, to_elem_inspector_fn_var]); + let this_inspect_list_clos_var = env.subs.fresh_unnamed_flex_var(); // clos + let this_list_inspector_var = env.subs.fresh_unnamed_flex_var(); // t1 + let this_inspect_list_fn_var = synth_var( env.subs, Content::Structure(FlatType::Func( - this_encode_list_args_slice, - this_encode_list_clos_var, - this_list_encoder_var, + this_inspect_list_args_slice, + this_inspect_list_clos_var, + this_list_inspector_var, )), ); - // List e, (e -> Encoder fmt) -[uls]-> Encoder fmt where fmt implements EncoderFormatting - // ~ List elem, to_elem_encoder_fn_var -[clos]-> t1 - env.unify(encode_list_fn_var, this_encode_list_fn_var); + // List e, (e -> Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // ~ List elem, to_elem_inspector_fn_var -[clos]-> t1 + env.unify(inspect_list_fn_var, this_inspect_list_fn_var); - // Encode.list : List elem, to_elem_encoder_fn_var -[clos]-> Encoder fmt where fmt implements EncoderFormatting - let encode_list = AbilityMember(Symbol::ENCODE_LIST, None, this_encode_list_fn_var); - let encode_list_fn = Box::new(( - this_encode_list_fn_var, - Loc::at_zero(encode_list), - this_encode_list_clos_var, - this_list_encoder_var, + // Inspect.list : List elem, to_elem_inspector_fn_var -[clos]-> Inspector fmt where fmt implements InspectorFormatting + let inspect_list = AbilityMember(Symbol::INSPECT_LIST, None, this_inspect_list_fn_var); + let inspect_list_fn = Box::new(( + this_inspect_list_fn_var, + Loc::at_zero(inspect_list), + this_inspect_list_clos_var, + this_list_inspector_var, )); - // Encode.list lst to_elem_encoder - let encode_list_call = Call( - encode_list_fn, + // Inspect.list lst to_elem_inspector + let inspect_list_call = Call( + inspect_list_fn, vec![ (list_var, Loc::at_zero(Var(lst_sym, list_var))), - (to_elem_encoder_fn_var, Loc::at_zero(to_elem_encoder)), + (to_elem_inspector_fn_var, Loc::at_zero(to_elem_inspector)), ], CalledVia::Space, ); - // Encode.custom \bytes, fmt -> Encode.appendWith bytes (Encode.list ..) fmt - let (body, this_encoder_var) = wrap_in_encode_custom( + // Inspect.custom \bytes, fmt -> Inspect.appendWith bytes (Inspect.list ..) fmt + let (body, this_inspector_var) = wrap_in_inspect_custom( env, - encode_list_call, - this_list_encoder_var, + inspect_list_call, + this_list_inspector_var, lst_sym, list_var, ); - // \lst -> Encode.list lst (\elem -> Encode.toEncoder elem) + // \lst -> Inspect.list lst (\elem -> Inspect.toInspector elem) // Create fn_var for ambient capture; we fix it up below. let fn_var = synth_var(env.subs, Content::Error); @@ -272,22 +273,22 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { ambient_function: fn_var, }), ); - // List elem -[fn_name]-> Encoder fmt + // List elem -[fn_name]-> Inspector fmt let list_var_slice = SubsSlice::insert_into_subs(env.subs, once(list_var)); env.subs.set_content( fn_var, Content::Structure(FlatType::Func( list_var_slice, fn_clos_var, - this_encoder_var, + this_inspector_var, )), ); - // \lst -[fn_name]-> Encode.list lst (\elem -> Encode.toEncoder elem) + // \lst -[fn_name]-> Inspect.list lst (\elem -> Inspect.toInspector elem) let clos = Closure(ClosureData { function_type: fn_var, closure_type: fn_clos_var, - return_type: this_encoder_var, + return_type: this_inspector_var, name: fn_name, captured_symbols: vec![], recursive: Recursive::NotRecursive, @@ -302,7 +303,7 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { (clos, fn_var) } -fn to_encoder_record( +fn to_inspector_record( env: &mut Env<'_>, record_var: Variable, fields: RecordFields, @@ -310,9 +311,9 @@ fn to_encoder_record( ) -> (Expr, Variable) { // Suppose rcd = { a: t1, b: t2 }. Build // - // \rcd -> Encode.record [ - // { key: "a", value: Encode.toEncoder rcd.a }, - // { key: "b", value: Encode.toEncoder rcd.b }, + // \rcd -> Inspect.record [ + // { key: "a", value: Inspect.toInspector rcd.a }, + // { key: "b", value: Inspect.toInspector rcd.b }, // ] let rcd_sym = env.new_symbol("rcd"); @@ -346,50 +347,51 @@ fn to_encoder_record( field: field_name, }; - // build `toEncoder rcd.a` type - // val -[uls]-> Encoder fmt where fmt implements EncoderFormatting - let to_encoder_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_TO_ENCODER); + // build `toInspector rcd.a` type + // val -[uls]-> Inspector fmt where fmt implements InspectorFormatting + let to_inspector_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_TO_INSPECTOR); // (typeof rcd.a) -[clos]-> t1 - let to_encoder_clos_var = env.subs.fresh_unnamed_flex_var(); // clos - let encoder_var = env.subs.fresh_unnamed_flex_var(); // t1 - let this_to_encoder_fn_var = synth_var( + let to_inspector_clos_var = env.subs.fresh_unnamed_flex_var(); // clos + let inspector_var = env.subs.fresh_unnamed_flex_var(); // t1 + let this_to_inspector_fn_var = synth_var( env.subs, Content::Structure(FlatType::Func( field_var_slice, - to_encoder_clos_var, - encoder_var, + to_inspector_clos_var, + inspector_var, )), ); - // val -[uls]-> Encoder fmt where fmt implements EncoderFormatting + // val -[uls]-> Inspector fmt where fmt implements InspectorFormatting // ~ (typeof rcd.a) -[clos]-> t1 - env.unify(to_encoder_fn_var, this_to_encoder_fn_var); + env.unify(to_inspector_fn_var, this_to_inspector_fn_var); - // toEncoder : (typeof rcd.a) -[clos]-> Encoder fmt where fmt implements EncoderFormatting - let to_encoder_var = AbilityMember(Symbol::ENCODE_TO_ENCODER, None, to_encoder_fn_var); - let to_encoder_fn = Box::new(( - to_encoder_fn_var, - Loc::at_zero(to_encoder_var), - to_encoder_clos_var, - encoder_var, + // toInspector : (typeof rcd.a) -[clos]-> Inspector fmt where fmt implements InspectorFormatting + let to_inspector_var = + AbilityMember(Symbol::INSPECT_TO_INSPECTOR, None, to_inspector_fn_var); + let to_inspector_fn = Box::new(( + to_inspector_fn_var, + Loc::at_zero(to_inspector_var), + to_inspector_clos_var, + inspector_var, )); - // toEncoder rcd.a - let to_encoder_call = Call( - to_encoder_fn, + // toInspector rcd.a + let to_inspector_call = Call( + to_inspector_fn, vec![(field_var, Loc::at_zero(field_access))], CalledVia::Space, ); - // value: toEncoder rcd.a + // value: toInspector rcd.a let value_field = Field { - var: encoder_var, + var: inspector_var, region: Region::zero(), - loc_expr: Box::new(Loc::at_zero(to_encoder_call)), + loc_expr: Box::new(Loc::at_zero(to_inspector_call)), }; - // { key: "a", value: toEncoder rcd.a } + // { key: "a", value: toInspector rcd.a } let mut kv = SendMap::default(); kv.insert("key".into(), key_field); kv.insert("value".into(), value_field); @@ -397,13 +399,13 @@ fn to_encoder_record( let this_record_fields = RecordFields::insert_into_subs( env.subs, (once(("key".into(), RecordField::Required(Variable::STR)))) - .chain(once(("value".into(), RecordField::Required(encoder_var)))), + .chain(once(("value".into(), RecordField::Required(inspector_var)))), ); let this_record_var = synth_var( env.subs, Content::Structure(FlatType::Record(this_record_fields, Variable::EMPTY_RECORD)), ); - // NOTE: must be done to unify the lambda sets under `encoder_var` + // NOTE: must be done to unify the lambda sets under `inspector_var` env.unify(this_record_var, whole_rcd_var); Loc::at_zero(Record { @@ -426,47 +428,47 @@ fn to_encoder_record( loc_elems: fields_list, }; - // build `Encode.record [ { key: .., value: ..}, .. ]` type - // List { key : Str, value : Encoder fmt } -[uls]-> Encoder fmt where fmt implements EncoderFormatting - let encode_record_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_RECORD); + // build `Inspect.record [ { key: .., value: ..}, .. ]` type + // List { key : Str, value : Inspector fmt } -[uls]-> Inspector fmt where fmt implements InspectorFormatting + let inspect_record_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_RECORD); // fields_list_var -[clos]-> t1 let fields_list_var_slice = VariableSubsSlice::insert_into_subs(env.subs, once(fields_list_var)); - let encode_record_clos_var = env.subs.fresh_unnamed_flex_var(); // clos - let encoder_var = env.subs.fresh_unnamed_flex_var(); // t1 - let this_encode_record_fn_var = synth_var( + let inspect_record_clos_var = env.subs.fresh_unnamed_flex_var(); // clos + let inspector_var = env.subs.fresh_unnamed_flex_var(); // t1 + let this_inspect_record_fn_var = synth_var( env.subs, Content::Structure(FlatType::Func( fields_list_var_slice, - encode_record_clos_var, - encoder_var, + inspect_record_clos_var, + inspector_var, )), ); - // List { key : Str, value : Encoder fmt } -[uls]-> Encoder fmt where fmt implements EncoderFormatting + // List { key : Str, value : Inspector fmt } -[uls]-> Inspector fmt where fmt implements InspectorFormatting // ~ fields_list_var -[clos]-> t1 - env.unify(encode_record_fn_var, this_encode_record_fn_var); + env.unify(inspect_record_fn_var, this_inspect_record_fn_var); - // Encode.record : fields_list_var -[clos]-> Encoder fmt where fmt implements EncoderFormatting - let encode_record_var = AbilityMember(Symbol::ENCODE_RECORD, None, encode_record_fn_var); - let encode_record_fn = Box::new(( - encode_record_fn_var, - Loc::at_zero(encode_record_var), - encode_record_clos_var, - encoder_var, + // Inspect.record : fields_list_var -[clos]-> Inspector fmt where fmt implements InspectorFormatting + let inspect_record_var = AbilityMember(Symbol::INSPECT_RECORD, None, inspect_record_fn_var); + let inspect_record_fn = Box::new(( + inspect_record_fn_var, + Loc::at_zero(inspect_record_var), + inspect_record_clos_var, + inspector_var, )); - // Encode.record [ { key: .., value: .. }, .. ] - let encode_record_call = Call( - encode_record_fn, + // Inspect.record [ { key: .., value: .. }, .. ] + let inspect_record_call = Call( + inspect_record_fn, vec![(fields_list_var, Loc::at_zero(fields_list))], CalledVia::Space, ); - // Encode.custom \bytes, fmt -> Encode.appendWith bytes (Encode.record ..) fmt - let (body, this_encoder_var) = - wrap_in_encode_custom(env, encode_record_call, encoder_var, rcd_sym, record_var); + // Inspect.custom \bytes, fmt -> Inspect.appendWith bytes (Inspect.record ..) fmt + let (body, this_inspector_var) = + wrap_in_inspect_custom(env, inspect_record_call, inspector_var, rcd_sym, record_var); // Create fn_var for ambient capture; we fix it up below. let fn_var = synth_var(env.subs, Content::Error); @@ -482,22 +484,22 @@ fn to_encoder_record( ambient_function: fn_var, }), ); - // typeof rcd -[fn_name]-> (typeof Encode.record [ .. ] = Encoder fmt) + // typeof rcd -[fn_name]-> (typeof Inspect.record [ .. ] = Inspector fmt) let record_var_slice = SubsSlice::insert_into_subs(env.subs, once(record_var)); env.subs.set_content( fn_var, Content::Structure(FlatType::Func( record_var_slice, fn_clos_var, - this_encoder_var, + this_inspector_var, )), ); - // \rcd -[fn_name]-> Encode.record [ { key: .., value: .. }, .. ] + // \rcd -[fn_name]-> Inspect.record [ { key: .., value: .. }, .. ] let clos = Closure(ClosureData { function_type: fn_var, closure_type: fn_clos_var, - return_type: this_encoder_var, + return_type: this_inspector_var, name: fn_name, captured_symbols: vec![], recursive: Recursive::NotRecursive, @@ -512,7 +514,7 @@ fn to_encoder_record( (clos, fn_var) } -fn to_encoder_tuple( +fn to_inspector_tuple( env: &mut Env<'_>, tuple_var: Variable, elems: TupleElems, @@ -520,17 +522,17 @@ fn to_encoder_tuple( ) -> (Expr, Variable) { // Suppose tup = (t1, t2). Build // - // \tup -> Encode.tuple [ - // Encode.toEncoder tup.0, - // Encode.toEncoder tup.1, + // \tup -> Inspect.tuple [ + // Inspect.toInspector tup.0, + // Inspect.toInspector tup.1, // ] let tup_sym = env.new_symbol("tup"); - let whole_encoder_in_list_var = env.subs.fresh_unnamed_flex_var(); // type of the encoder in the list + let whole_inspector_in_list_var = env.subs.fresh_unnamed_flex_var(); // type of the inspector in the list use Expr::*; - let elem_encoders_list = elems + let elem_inspectors_list = elems .iter_all() .map(|(elem_index, elem_var_index)| { let index = env.subs[elem_index]; @@ -549,107 +551,108 @@ fn to_encoder_tuple( index, }; - // build `toEncoder tup.0` type - // val -[uls]-> Encoder fmt where fmt implements EncoderFormatting - let to_encoder_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_TO_ENCODER); + // build `toInspector tup.0` type + // val -[uls]-> Inspector fmt where fmt implements InspectorFormatting + let to_inspector_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_TO_INSPECTOR); // (typeof tup.0) -[clos]-> t1 - let to_encoder_clos_var = env.subs.fresh_unnamed_flex_var(); // clos - let encoder_var = env.subs.fresh_unnamed_flex_var(); // t1 - let this_to_encoder_fn_var = synth_var( + let to_inspector_clos_var = env.subs.fresh_unnamed_flex_var(); // clos + let inspector_var = env.subs.fresh_unnamed_flex_var(); // t1 + let this_to_inspector_fn_var = synth_var( env.subs, Content::Structure(FlatType::Func( elem_var_slice, - to_encoder_clos_var, - encoder_var, + to_inspector_clos_var, + inspector_var, )), ); - // val -[uls]-> Encoder fmt where fmt implements EncoderFormatting + // val -[uls]-> Inspector fmt where fmt implements InspectorFormatting // ~ (typeof tup.0) -[clos]-> t1 - env.unify(to_encoder_fn_var, this_to_encoder_fn_var); + env.unify(to_inspector_fn_var, this_to_inspector_fn_var); - // toEncoder : (typeof tup.0) -[clos]-> Encoder fmt where fmt implements EncoderFormatting - let to_encoder_var = AbilityMember(Symbol::ENCODE_TO_ENCODER, None, to_encoder_fn_var); - let to_encoder_fn = Box::new(( - to_encoder_fn_var, - Loc::at_zero(to_encoder_var), - to_encoder_clos_var, - encoder_var, + // toInspector : (typeof tup.0) -[clos]-> Inspector fmt where fmt implements InspectorFormatting + let to_inspector_var = + AbilityMember(Symbol::INSPECT_TO_INSPECTOR, None, to_inspector_fn_var); + let to_inspector_fn = Box::new(( + to_inspector_fn_var, + Loc::at_zero(to_inspector_var), + to_inspector_clos_var, + inspector_var, )); - // toEncoder tup.0 - let to_encoder_call = Call( - to_encoder_fn, + // toInspector tup.0 + let to_inspector_call = Call( + to_inspector_fn, vec![(elem_var, Loc::at_zero(tuple_access))], CalledVia::Space, ); - // NOTE: must be done to unify the lambda sets under `encoder_var` - env.unify(encoder_var, whole_encoder_in_list_var); + // NOTE: must be done to unify the lambda sets under `inspector_var` + env.unify(inspector_var, whole_inspector_in_list_var); - Loc::at_zero(to_encoder_call) + Loc::at_zero(to_inspector_call) }) .collect::>(); - // typeof [ toEncoder tup.0, toEncoder tup.1 ] - let whole_encoder_in_list_var_slice = - VariableSubsSlice::insert_into_subs(env.subs, once(whole_encoder_in_list_var)); - let elem_encoders_list_var = synth_var( + // typeof [ toInspector tup.0, toInspector tup.1 ] + let whole_inspector_in_list_var_slice = + VariableSubsSlice::insert_into_subs(env.subs, once(whole_inspector_in_list_var)); + let elem_inspectors_list_var = synth_var( env.subs, Content::Structure(FlatType::Apply( Symbol::LIST_LIST, - whole_encoder_in_list_var_slice, + whole_inspector_in_list_var_slice, )), ); - // [ toEncoder tup.0, toEncoder tup.1 ] - let elem_encoders_list = List { - elem_var: whole_encoder_in_list_var, - loc_elems: elem_encoders_list, + // [ toInspector tup.0, toInspector tup.1 ] + let elem_inspectors_list = List { + elem_var: whole_inspector_in_list_var, + loc_elems: elem_inspectors_list, }; - // build `Encode.tuple [ toEncoder tup.0, toEncoder tup.1 ]` type - // List (Encoder fmt) -[uls]-> Encoder fmt where fmt implements EncoderFormatting - let encode_tuple_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_TUPLE); + // build `Inspect.tuple [ toInspector tup.0, toInspector tup.1 ]` type + // List (Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatting + let inspect_tuple_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_TUPLE); - // elem_encoders_list_var -[clos]-> t1 - let elem_encoders_list_var_slice = - VariableSubsSlice::insert_into_subs(env.subs, once(elem_encoders_list_var)); - let encode_tuple_clos_var = env.subs.fresh_unnamed_flex_var(); // clos - let encoder_var = env.subs.fresh_unnamed_flex_var(); // t1 - let this_encode_tuple_fn_var = synth_var( + // elem_inspectors_list_var -[clos]-> t1 + let elem_inspectors_list_var_slice = + VariableSubsSlice::insert_into_subs(env.subs, once(elem_inspectors_list_var)); + let inspect_tuple_clos_var = env.subs.fresh_unnamed_flex_var(); // clos + let inspector_var = env.subs.fresh_unnamed_flex_var(); // t1 + let this_inspect_tuple_fn_var = synth_var( env.subs, Content::Structure(FlatType::Func( - elem_encoders_list_var_slice, - encode_tuple_clos_var, - encoder_var, + elem_inspectors_list_var_slice, + inspect_tuple_clos_var, + inspector_var, )), ); - // List (Encoder fmt) -[uls]-> Encoder fmt where fmt implements EncoderFormatting - // ~ elem_encoders_list_var -[clos]-> t1 - env.unify(encode_tuple_fn_var, this_encode_tuple_fn_var); + // List (Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // ~ elem_inspectors_list_var -[clos]-> t1 + env.unify(inspect_tuple_fn_var, this_inspect_tuple_fn_var); - // Encode.tuple : elem_encoders_list_var -[clos]-> Encoder fmt where fmt implements EncoderFormatting - let encode_tuple_var = AbilityMember(Symbol::ENCODE_TUPLE, None, encode_tuple_fn_var); - let encode_tuple_fn = Box::new(( - encode_tuple_fn_var, - Loc::at_zero(encode_tuple_var), - encode_tuple_clos_var, - encoder_var, + // Inspect.tuple : elem_inspectors_list_var -[clos]-> Inspector fmt where fmt implements InspectorFormatting + let inspect_tuple_var = AbilityMember(Symbol::INSPECT_TUPLE, None, inspect_tuple_fn_var); + let inspect_tuple_fn = Box::new(( + inspect_tuple_fn_var, + Loc::at_zero(inspect_tuple_var), + inspect_tuple_clos_var, + inspector_var, )); - // Encode.tuple [ { key: .., value: .. }, .. ] - let encode_tuple_call = Call( - encode_tuple_fn, - vec![(elem_encoders_list_var, Loc::at_zero(elem_encoders_list))], + // Inspect.tuple [ { key: .., value: .. }, .. ] + let inspect_tuple_call = Call( + inspect_tuple_fn, + vec![(elem_inspectors_list_var, Loc::at_zero(elem_inspectors_list))], CalledVia::Space, ); - // Encode.custom \bytes, fmt -> Encode.appendWith bytes (Encode.tuple_var ..) fmt - let (body, this_encoder_var) = - wrap_in_encode_custom(env, encode_tuple_call, encoder_var, tup_sym, tuple_var); + // Inspect.custom \bytes, fmt -> Inspect.appendWith bytes (Inspect.tuple_var ..) fmt + let (body, this_inspector_var) = + wrap_in_inspect_custom(env, inspect_tuple_call, inspector_var, tup_sym, tuple_var); // Create fn_var for ambient capture; we fix it up below. let fn_var = synth_var(env.subs, Content::Error); @@ -665,22 +668,22 @@ fn to_encoder_tuple( ambient_function: fn_var, }), ); - // typeof tup -[fn_name]-> (typeof Encode.tuple [ .. ] = Encoder fmt) + // typeof tup -[fn_name]-> (typeof Inspect.tuple [ .. ] = Inspector fmt) let tuple_var_slice = SubsSlice::insert_into_subs(env.subs, once(tuple_var)); env.subs.set_content( fn_var, Content::Structure(FlatType::Func( tuple_var_slice, fn_clos_var, - this_encoder_var, + this_inspector_var, )), ); - // \tup -[fn_name]-> Encode.tuple [ { key: .., value: .. }, .. ] + // \tup -[fn_name]-> Inspect.tuple [ { key: .., value: .. }, .. ] let clos = Closure(ClosureData { function_type: fn_var, closure_type: fn_clos_var, - return_type: this_encoder_var, + return_type: this_inspector_var, name: fn_name, captured_symbols: vec![], recursive: Recursive::NotRecursive, @@ -695,7 +698,7 @@ fn to_encoder_tuple( (clos, fn_var) } -fn to_encoder_tag_union( +fn to_inspector_tag_union( env: &mut Env<'_>, tag_union_var: Variable, tags: UnionTags, @@ -704,11 +707,11 @@ fn to_encoder_tag_union( // Suppose tag = [ A t1 t2, B t3 ]. Build // // \tag -> when tag is - // A v1 v2 -> Encode.tag "A" [ Encode.toEncoder v1, Encode.toEncoder v2 ] - // B v3 -> Encode.tag "B" [ Encode.toEncoder v3 ] + // A v1 v2 -> Inspect.tag "A" [ Inspect.toInspector v1, Inspect.toInspector v2 ] + // B v3 -> Inspect.tag "B" [ Inspect.toInspector v3 ] let tag_sym = env.new_symbol("tag"); - let whole_tag_encoders_var = env.subs.fresh_unnamed_flex_var(); // type of the Encode.tag ... calls in the branch bodies + let whole_tag_inspectors_var = env.subs.fresh_unnamed_flex_var(); // type of the Inspect.tag ... calls in the branch bodies use Expr::*; @@ -741,128 +744,131 @@ fn to_encoder_tag_union( degenerate: false, }; - // whole type of the elements in [ Encode.toEncoder v1, Encode.toEncoder v2 ] - let whole_payload_encoders_var = env.subs.fresh_unnamed_flex_var(); - // [ Encode.toEncoder v1, Encode.toEncoder v2 ] - let payload_to_encoders = (payload_syms.iter()) + // whole type of the elements in [ Inspect.toInspector v1, Inspect.toInspector v2 ] + let whole_payload_inspectors_var = env.subs.fresh_unnamed_flex_var(); + // [ Inspect.toInspector v1, Inspect.toInspector v2 ] + let payload_to_inspectors = (payload_syms.iter()) .zip(payload_vars.iter()) .map(|(&sym, &sym_var)| { - // build `toEncoder v1` type - // expected: val -[uls]-> Encoder fmt where fmt implements EncoderFormatting - let to_encoder_fn_var = - env.import_builtin_symbol_var(Symbol::ENCODE_TO_ENCODER); + // build `toInspector v1` type + // expected: val -[uls]-> Inspector fmt where fmt implements InspectorFormatting + let to_inspector_fn_var = + env.import_builtin_symbol_var(Symbol::INSPECT_TO_INSPECTOR); // wanted: t1 -[clos]-> t' let var_slice_of_sym_var = VariableSubsSlice::insert_into_subs(env.subs, [sym_var]); // [ t1 ] - let to_encoder_clos_var = env.subs.fresh_unnamed_flex_var(); // clos - let encoder_var = env.subs.fresh_unnamed_flex_var(); // t' - let this_to_encoder_fn_var = synth_var( + let to_inspector_clos_var = env.subs.fresh_unnamed_flex_var(); // clos + let inspector_var = env.subs.fresh_unnamed_flex_var(); // t' + let this_to_inspector_fn_var = synth_var( env.subs, Content::Structure(FlatType::Func( var_slice_of_sym_var, - to_encoder_clos_var, - encoder_var, + to_inspector_clos_var, + inspector_var, )), ); - // val -[uls]-> Encoder fmt where fmt implements EncoderFormatting + // val -[uls]-> Inspector fmt where fmt implements InspectorFormatting // ~ t1 -[clos]-> t' - env.unify(to_encoder_fn_var, this_to_encoder_fn_var); + env.unify(to_inspector_fn_var, this_to_inspector_fn_var); - // toEncoder : t1 -[clos]-> Encoder fmt where fmt implements EncoderFormatting - let to_encoder_var = - AbilityMember(Symbol::ENCODE_TO_ENCODER, None, this_to_encoder_fn_var); - let to_encoder_fn = Box::new(( - this_to_encoder_fn_var, - Loc::at_zero(to_encoder_var), - to_encoder_clos_var, - encoder_var, + // toInspector : t1 -[clos]-> Inspector fmt where fmt implements InspectorFormatting + let to_inspector_var = + AbilityMember(Symbol::INSPECT_TO_INSPECTOR, None, this_to_inspector_fn_var); + let to_inspector_fn = Box::new(( + this_to_inspector_fn_var, + Loc::at_zero(to_inspector_var), + to_inspector_clos_var, + inspector_var, )); - // toEncoder rcd.a - let to_encoder_call = Call( - to_encoder_fn, + // toInspector rcd.a + let to_inspector_call = Call( + to_inspector_fn, vec![(sym_var, Loc::at_zero(Var(sym, sym_var)))], CalledVia::Space, ); - // NOTE: must be done to unify the lambda sets under `encoder_var` - env.unify(encoder_var, whole_payload_encoders_var); + // NOTE: must be done to unify the lambda sets under `inspector_var` + env.unify(inspector_var, whole_payload_inspectors_var); - Loc::at_zero(to_encoder_call) + Loc::at_zero(to_inspector_call) }) .collect(); - // typeof [ Encode.toEncoder v1, Encode.toEncoder v2 ] - let whole_encoders_var_slice = - VariableSubsSlice::insert_into_subs(env.subs, [whole_payload_encoders_var]); - let payload_encoders_list_var = synth_var( + // typeof [ Inspect.toInspector v1, Inspect.toInspector v2 ] + let whole_inspectors_var_slice = + VariableSubsSlice::insert_into_subs(env.subs, [whole_payload_inspectors_var]); + let payload_inspectors_list_var = synth_var( env.subs, - Content::Structure(FlatType::Apply(Symbol::LIST_LIST, whole_encoders_var_slice)), - ); - - // [ Encode.toEncoder v1, Encode.toEncoder v2 ] - let payload_encoders_list = List { - elem_var: whole_payload_encoders_var, - loc_elems: payload_to_encoders, - }; - - // build `Encode.tag "A" [ ... ]` type - // expected: Str, List (Encoder fmt) -[uls]-> Encoder fmt where fmt implements EncoderFormatting - let encode_tag_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_TAG); - - // wanted: Str, List whole_encoders_var -[clos]-> t' - let this_encode_tag_args_var_slice = VariableSubsSlice::insert_into_subs( - env.subs, - [Variable::STR, payload_encoders_list_var], - ); - let this_encode_tag_clos_var = env.subs.fresh_unnamed_flex_var(); // -[clos]-> - let this_encoder_var = env.subs.fresh_unnamed_flex_var(); // t' - let this_encode_tag_fn_var = synth_var( - env.subs, - Content::Structure(FlatType::Func( - this_encode_tag_args_var_slice, - this_encode_tag_clos_var, - this_encoder_var, + Content::Structure(FlatType::Apply( + Symbol::LIST_LIST, + whole_inspectors_var_slice, )), ); - // Str, List (Encoder fmt) -[uls]-> Encoder fmt where fmt implements EncoderFormatting - // ~ Str, List whole_encoders_var -[clos]-> t' - env.unify(encode_tag_fn_var, this_encode_tag_fn_var); + // [ Inspect.toInspector v1, Inspect.toInspector v2 ] + let payload_inspectors_list = List { + elem_var: whole_payload_inspectors_var, + loc_elems: payload_to_inspectors, + }; - // Encode.tag : Str, List whole_encoders_var -[clos]-> Encoder fmt where fmt implements EncoderFormatting - let encode_tag_var = AbilityMember(Symbol::ENCODE_TAG, None, this_encode_tag_fn_var); - let encode_tag_fn = Box::new(( - this_encode_tag_fn_var, - Loc::at_zero(encode_tag_var), - this_encode_tag_clos_var, - this_encoder_var, + // build `Inspect.tag "A" [ ... ]` type + // expected: Str, List (Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatting + let inspect_tag_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_TAG); + + // wanted: Str, List whole_inspectors_var -[clos]-> t' + let this_inspect_tag_args_var_slice = VariableSubsSlice::insert_into_subs( + env.subs, + [Variable::STR, payload_inspectors_list_var], + ); + let this_inspect_tag_clos_var = env.subs.fresh_unnamed_flex_var(); // -[clos]-> + let this_inspector_var = env.subs.fresh_unnamed_flex_var(); // t' + let this_inspect_tag_fn_var = synth_var( + env.subs, + Content::Structure(FlatType::Func( + this_inspect_tag_args_var_slice, + this_inspect_tag_clos_var, + this_inspector_var, + )), + ); + + // Str, List (Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // ~ Str, List whole_inspectors_var -[clos]-> t' + env.unify(inspect_tag_fn_var, this_inspect_tag_fn_var); + + // Inspect.tag : Str, List whole_inspectors_var -[clos]-> Inspector fmt where fmt implements InspectorFormatting + let inspect_tag_var = AbilityMember(Symbol::INSPECT_TAG, None, this_inspect_tag_fn_var); + let inspect_tag_fn = Box::new(( + this_inspect_tag_fn_var, + Loc::at_zero(inspect_tag_var), + this_inspect_tag_clos_var, + this_inspector_var, )); - // Encode.tag "A" [ Encode.toEncoder v1, Encode.toEncoder v2 ] - let encode_tag_call = Call( - encode_tag_fn, + // Inspect.tag "A" [ Inspect.toInspector v1, Inspect.toInspector v2 ] + let inspect_tag_call = Call( + inspect_tag_fn, vec![ // (Str, "A") (Variable::STR, Loc::at_zero(Str(tag_name.0.as_str().into()))), - // (List (Encoder fmt), [ Encode.toEncoder v1, Encode.toEncoder v2 ]) + // (List (Inspector fmt), [ Inspect.toInspector v1, Inspect.toInspector v2 ]) ( - payload_encoders_list_var, - Loc::at_zero(payload_encoders_list), + payload_inspectors_list_var, + Loc::at_zero(payload_inspectors_list), ), ], CalledVia::Space, ); - // NOTE: must be done to unify the lambda sets under `encoder_var` - // Encode.tag "A" [ Encode.toEncoder v1, Encode.toEncoder v2 ] ~ whole_encoders - env.unify(this_encoder_var, whole_tag_encoders_var); + // NOTE: must be done to unify the lambda sets under `inspector_var` + // Inspect.tag "A" [ Inspect.toInspector v1, Inspect.toInspector v2 ] ~ whole_inspectors + env.unify(this_inspector_var, whole_tag_inspectors_var); WhenBranch { patterns: vec![branch_pattern], - value: Loc::at_zero(encode_tag_call), + value: Loc::at_zero(inspect_tag_call), guard: None, redundant: RedundantMark::known_non_redundant(), } @@ -870,23 +876,23 @@ fn to_encoder_tag_union( .collect::>(); // when tag is - // A v1 v2 -> Encode.tag "A" [ Encode.toEncoder v1, Encode.toEncoder v2 ] - // B v3 -> Encode.tag "B" [ Encode.toEncoder v3 ] + // A v1 v2 -> Inspect.tag "A" [ Inspect.toInspector v1, Inspect.toInspector v2 ] + // B v3 -> Inspect.tag "B" [ Inspect.toInspector v3 ] let when_branches = When { loc_cond: Box::new(Loc::at_zero(Var(tag_sym, tag_union_var))), cond_var: tag_union_var, - expr_var: whole_tag_encoders_var, + expr_var: whole_tag_inspectors_var, region: Region::zero(), branches, branches_cond_var: tag_union_var, exhaustive: ExhaustiveMark::known_exhaustive(), }; - // Encode.custom \bytes, fmt -> Encode.appendWith bytes (when ..) fmt - let (body, this_encoder_var) = wrap_in_encode_custom( + // Inspect.custom \bytes, fmt -> Inspect.appendWith bytes (when ..) fmt + let (body, this_inspector_var) = wrap_in_inspect_custom( env, when_branches, - whole_tag_encoders_var, + whole_tag_inspectors_var, tag_sym, tag_union_var, ); @@ -905,27 +911,27 @@ fn to_encoder_tag_union( ambient_function: fn_var, }), ); - // tag_union_var -[fn_name]-> whole_tag_encoders_var + // tag_union_var -[fn_name]-> whole_tag_inspectors_var let tag_union_var_slice = SubsSlice::insert_into_subs(env.subs, once(tag_union_var)); env.subs.set_content( fn_var, Content::Structure(FlatType::Func( tag_union_var_slice, fn_clos_var, - this_encoder_var, + this_inspector_var, )), ); // \tag -> - // Encode.custom \bytes, fmt -> Encode.appendWith bytes ( + // Inspect.custom \bytes, fmt -> Inspect.appendWith bytes ( // when tag is - // A v1 v2 -> Encode.tag "A" [ Encode.toEncoder v1, Encode.toEncoder v2 ] - // B v3 -> Encode.tag "B" [ Encode.toEncoder v3 ]) + // A v1 v2 -> Inspect.tag "A" [ Inspect.toInspector v1, Inspect.toInspector v2 ] + // B v3 -> Inspect.tag "B" [ Inspect.toInspector v3 ]) // fmt let clos = Closure(ClosureData { function_type: fn_var, closure_type: fn_clos_var, - return_type: this_encoder_var, + return_type: this_inspector_var, name: fn_name, captured_symbols: vec![], recursive: Recursive::NotRecursive, @@ -940,157 +946,158 @@ fn to_encoder_tag_union( (clos, fn_var) } -/// Lift `encoder` to `Encode.custom \bytes, fmt -> Encode.appendWith bytes encoder fmt` +/// Lift `inspector` to `Inspect.custom \bytes, fmt -> Inspect.appendWith bytes inspector fmt` /// -/// TODO: currently it appears that just `encoder` is not isomorphic to the lift, on the +/// TODO: currently it appears that just `inspector` is not isomorphic to the lift, on the /// monomorphization level, even though we would think it is. In particular, unspecialized lambda /// sets fail to resolve when we use the non-lifted version. /// More investigation is needed to figure out why. -fn wrap_in_encode_custom( - env: &mut Env, - encoder: Expr, - encoder_var: Variable, - captured_symbol: Symbol, - captured_var: Variable, +fn wrap_in_inspect_custom( + _env: &mut Env, + _inspector: Expr, + _inspector_var: Variable, + _captured_symbol: Symbol, + _captured_var: Variable, ) -> (Expr, Variable) { - use Expr::*; + unimplemented!(); + // use Expr::*; - let fn_name = env.new_symbol("custom"); + // let fn_name = env.new_symbol("custom"); - // bytes: List U8 - let bytes_sym = env.new_symbol("bytes"); - let bytes_var = Variable::LIST_U8; + // // bytes: List U8 + // let bytes_sym = env.new_symbol("bytes"); + // let bytes_var = Variable::LIST_U8; - // fmt: fmt where fmt implements EncoderFormatting - let fmt_sym = env.new_symbol("fmt"); - let fmt_var = env.subs.fresh_unnamed_flex_var(); + // // fmt: fmt where fmt implements InspectorFormatting + // let fmt_sym = env.new_symbol("fmt"); + // let fmt_var = env.subs.fresh_unnamed_flex_var(); - // build `Encode.appendWith bytes encoder fmt` type - // expected: Encode.appendWith : List U8, Encoder fmt, fmt -[appendWith]-> List U8 where fmt implements EncoderFormatting - let append_with_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_APPEND_WITH); + // // build `Inspect.appendWith bytes inspector fmt` type + // // expected: Inspect.appendWith : List U8, Inspector fmt, fmt -[appendWith]-> List U8 where fmt implements InspectorFormatting + // let append_with_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_APPEND_WITH); - // wanted: Encode.appendWith : List U8, encoder_var, fmt -[clos]-> List U8 where fmt implements EncoderFormatting - let this_append_with_args_var_slice = - VariableSubsSlice::insert_into_subs(env.subs, [Variable::LIST_U8, encoder_var, fmt_var]); - let this_append_with_clos_var = env.subs.fresh_unnamed_flex_var(); // -[clos]-> - let this_append_with_fn_var = synth_var( - env.subs, - Content::Structure(FlatType::Func( - this_append_with_args_var_slice, - this_append_with_clos_var, - Variable::LIST_U8, - )), - ); + // // wanted: Inspect.appendWith : List U8, inspector_var, fmt -[clos]-> List U8 where fmt implements InspectorFormatting + // let this_append_with_args_var_slice = + // VariableSubsSlice::insert_into_subs(env.subs, [Variable::LIST_U8, inspector_var, fmt_var]); + // let this_append_with_clos_var = env.subs.fresh_unnamed_flex_var(); // -[clos]-> + // let this_append_with_fn_var = synth_var( + // env.subs, + // Content::Structure(FlatType::Func( + // this_append_with_args_var_slice, + // this_append_with_clos_var, + // Variable::LIST_U8, + // )), + // ); - // List U8, Encoder fmt, fmt -[appendWith]-> List U8 where fmt implements EncoderFormatting - // ~ List U8, encoder_var, fmt -[clos]-> List U8 where fmt implements EncoderFormatting - env.unify(append_with_fn_var, this_append_with_fn_var); + // // List U8, Inspector fmt, fmt -[appendWith]-> List U8 where fmt implements InspectorFormatting + // // ~ List U8, inspector_var, fmt -[clos]-> List U8 where fmt implements InspectorFormatting + // env.unify(append_with_fn_var, this_append_with_fn_var); - // Encode.appendWith : List U8, encoder_var, fmt -[appendWith]-> List U8 where fmt implements EncoderFormatting - let append_with_fn = Box::new(( - this_append_with_fn_var, - Loc::at_zero(Var(Symbol::ENCODE_APPEND_WITH, this_append_with_fn_var)), - this_append_with_clos_var, - Variable::LIST_U8, - )); + // // Inspect.appendWith : List U8, inspector_var, fmt -[appendWith]-> List U8 where fmt implements InspectorFormatting + // let append_with_fn = Box::new(( + // this_append_with_fn_var, + // Loc::at_zero(Var(Symbol::INSPECT_APPEND_WITH, this_append_with_fn_var)), + // this_append_with_clos_var, + // Variable::LIST_U8, + // )); - // Encode.appendWith bytes encoder fmt - let append_with_call = Call( - append_with_fn, - vec![ - // (bytes_var, bytes) - (bytes_var, Loc::at_zero(Var(bytes_sym, bytes_var))), - // (encoder_var, encoder) - (encoder_var, Loc::at_zero(encoder)), - // (fmt, fmt_var) - (fmt_var, Loc::at_zero(Var(fmt_sym, fmt_var))), - ], - CalledVia::Space, - ); + // // Inspect.appendWith bytes inspector fmt + // let append_with_call = Call( + // append_with_fn, + // vec![ + // // (bytes_var, bytes) + // (bytes_var, Loc::at_zero(Var(bytes_sym, bytes_var))), + // // (inspector_var, inspector) + // (inspector_var, Loc::at_zero(inspector)), + // // (fmt, fmt_var) + // (fmt_var, Loc::at_zero(Var(fmt_sym, fmt_var))), + // ], + // CalledVia::Space, + // ); - // Create fn_var for ambient capture; we fix it up below. - let fn_var = synth_var(env.subs, Content::Error); + // // Create fn_var for ambient capture; we fix it up below. + // let fn_var = synth_var(env.subs, Content::Error); - // -[[FN_name captured_var]]-> - let fn_name_labels = - UnionLambdas::insert_into_subs(env.subs, once((fn_name, vec![captured_var]))); - let fn_clos_var = synth_var( - env.subs, - Content::LambdaSet(LambdaSet { - solved: fn_name_labels, - recursion_var: OptVariable::NONE, - unspecialized: SubsSlice::default(), - ambient_function: fn_var, - }), - ); + // // -[[FN_name captured_var]]-> + // let fn_name_labels = + // UnionLambdas::insert_into_subs(env.subs, once((fn_name, vec![captured_var]))); + // let fn_clos_var = synth_var( + // env.subs, + // Content::LambdaSet(LambdaSet { + // solved: fn_name_labels, + // recursion_var: OptVariable::NONE, + // unspecialized: SubsSlice::default(), + // ambient_function: fn_var, + // }), + // ); - // bytes, fmt -[[FN_name captured_var]]-> Encode.appendWith bytes encoder fmt - let args_slice = SubsSlice::insert_into_subs(env.subs, vec![bytes_var, fmt_var]); - env.subs.set_content( - fn_var, - Content::Structure(FlatType::Func(args_slice, fn_clos_var, Variable::LIST_U8)), - ); + // // bytes, fmt -[[FN_name captured_var]]-> Inspect.appendWith bytes inspector fmt + // let args_slice = SubsSlice::insert_into_subs(env.subs, vec![bytes_var, fmt_var]); + // env.subs.set_content( + // fn_var, + // Content::Structure(FlatType::Func(args_slice, fn_clos_var, Variable::LIST_U8)), + // ); - // \bytes, fmt -[[fn_name captured_var]]-> Encode.appendWith bytes encoder fmt - let clos = Closure(ClosureData { - function_type: fn_var, - closure_type: fn_clos_var, - return_type: Variable::LIST_U8, - name: fn_name, - captured_symbols: vec![(captured_symbol, captured_var)], - recursive: Recursive::NotRecursive, - arguments: vec![ - ( - bytes_var, - AnnotatedMark::known_exhaustive(), - Loc::at_zero(Pattern::Identifier(bytes_sym)), - ), - ( - fmt_var, - AnnotatedMark::known_exhaustive(), - Loc::at_zero(Pattern::Identifier(fmt_sym)), - ), - ], - loc_body: Box::new(Loc::at_zero(append_with_call)), - }); + // // \bytes, fmt -[[fn_name captured_var]]-> Inspect.appendWith bytes inspector fmt + // let clos = Closure(ClosureData { + // function_type: fn_var, + // closure_type: fn_clos_var, + // return_type: Variable::LIST_U8, + // name: fn_name, + // captured_symbols: vec![(captured_symbol, captured_var)], + // recursive: Recursive::NotRecursive, + // arguments: vec![ + // ( + // bytes_var, + // AnnotatedMark::known_exhaustive(), + // Loc::at_zero(Pattern::Identifier(bytes_sym)), + // ), + // ( + // fmt_var, + // AnnotatedMark::known_exhaustive(), + // Loc::at_zero(Pattern::Identifier(fmt_sym)), + // ), + // ], + // loc_body: Box::new(Loc::at_zero(append_with_call)), + // }); - // Build - // Encode.custom \bytes, fmt -> Encode.appendWith bytes encoder fmt - // - // expected: Encode.custom : (List U8, fmt -> List U8) -> Encoder fmt where fmt implements EncoderFormatting - let custom_fn_var = env.import_builtin_symbol_var(Symbol::ENCODE_CUSTOM); + // // Build + // // Inspect.custom \bytes, fmt -> Inspect.appendWith bytes inspector fmt + // // + // // expected: Inspect.custom : (List U8, fmt -> List U8) -> Inspector fmt where fmt implements InspectorFormatting + // let custom_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_CUSTOM); - // wanted: Encode.custom : fn_var -[clos]-> t' - let this_custom_args_var_slice = VariableSubsSlice::insert_into_subs(env.subs, [fn_var]); - let this_custom_clos_var = env.subs.fresh_unnamed_flex_var(); // -[clos]-> - let this_custom_encoder_var = env.subs.fresh_unnamed_flex_var(); // t' - let this_custom_fn_var = synth_var( - env.subs, - Content::Structure(FlatType::Func( - this_custom_args_var_slice, - this_custom_clos_var, - this_custom_encoder_var, - )), - ); + // // wanted: Inspect.custom : fn_var -[clos]-> t' + // let this_custom_args_var_slice = VariableSubsSlice::insert_into_subs(env.subs, [fn_var]); + // let this_custom_clos_var = env.subs.fresh_unnamed_flex_var(); // -[clos]-> + // let this_custom_inspector_var = env.subs.fresh_unnamed_flex_var(); // t' + // let this_custom_fn_var = synth_var( + // env.subs, + // Content::Structure(FlatType::Func( + // this_custom_args_var_slice, + // this_custom_clos_var, + // this_custom_inspector_var, + // )), + // ); - // (List U8, fmt -> List U8) -[..]-> Encoder fmt where fmt implements EncoderFormatting - // ~ fn_var -[clos]-> t' - env.unify(custom_fn_var, this_custom_fn_var); + // // (List U8, fmt -> List U8) -[..]-> Inspector fmt where fmt implements InspectorFormatting + // // ~ fn_var -[clos]-> t' + // env.unify(custom_fn_var, this_custom_fn_var); - // Encode.custom : (List U8, fmt -> List U8) -> Encoder fmt where fmt implements EncoderFormatting - let custom_fn = Box::new(( - this_custom_fn_var, - Loc::at_zero(Var(Symbol::ENCODE_CUSTOM, this_custom_fn_var)), - this_custom_clos_var, // -[clos]-> - this_custom_encoder_var, // t' ~ Encoder fmt - )); + // // Inspect.custom : (List U8, fmt -> List U8) -> Inspector fmt where fmt implements InspectorFormatting + // let custom_fn = Box::new(( + // this_custom_fn_var, + // Loc::at_zero(Var(Symbol::INSPECT_CUSTOM, this_custom_fn_var)), + // this_custom_clos_var, // -[clos]-> + // this_custom_inspector_var, // t' ~ Inspector fmt + // )); - // Encode.custom \bytes, fmt -> Encode.appendWith bytes encoder fmt - let custom_call = Call( - custom_fn, - vec![(fn_var, Loc::at_zero(clos))], - CalledVia::Space, - ); + // // Inspect.custom \bytes, fmt -> Inspect.appendWith bytes inspector fmt + // let custom_call = Call( + // custom_fn, + // vec![(fn_var, Loc::at_zero(clos))], + // CalledVia::Space, + // ); - (custom_call, this_custom_encoder_var) + // (custom_call, this_custom_inspector_var) } From c57bc4db11a5b14372ce06569b35e18ec90cfba9 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Mon, 27 Nov 2023 17:46:27 -0800 Subject: [PATCH 13/40] add uitest to view bool inspect derive --- .../compiler/uitest/tests/ability/specialize/inspect/bool.txt | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 crates/compiler/uitest/tests/ability/specialize/inspect/bool.txt diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/bool.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/bool.txt new file mode 100644 index 0000000000..7b11b76012 --- /dev/null +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/bool.txt @@ -0,0 +1,4 @@ +app "test" provides [main] to "./platform" + +main = Inspect.toInspector Bool.true +# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Bool -[[] + f:Inspect.bool(13):1]-> Inspector f where f implements InspectFormatter From f0dee1f6e923543d35b0cc4973dab9f4b76ed99d Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Mon, 27 Nov 2023 17:59:41 -0800 Subject: [PATCH 14/40] add missing ToInspector case --- crates/compiler/test_derive/src/util.rs | 5 +++++ .../specialize/inspect/{bool.txt => bool_to_inspector.txt} | 0 2 files changed, 5 insertions(+) rename crates/compiler/uitest/tests/ability/specialize/inspect/{bool.txt => bool_to_inspector.txt} (100%) diff --git a/crates/compiler/test_derive/src/util.rs b/crates/compiler/test_derive/src/util.rs index bb5d7bb6dc..0f5cacd2e7 100644 --- a/crates/compiler/test_derive/src/util.rs +++ b/crates/compiler/test_derive/src/util.rs @@ -68,6 +68,11 @@ fn module_source_and_path(builtin: DeriveBuiltin) -> (ModuleId, &'static str, Pa module_source(ModuleId::BOOL), builtins_path.join("Bool.roc"), ), + DeriveBuiltin::ToInspector => ( + ModuleId::INSPECT, + module_source(ModuleId::INSPECT), + builtins_path.join("Inspect.roc"), + ), } } diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/bool.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/bool_to_inspector.txt similarity index 100% rename from crates/compiler/uitest/tests/ability/specialize/inspect/bool.txt rename to crates/compiler/uitest/tests/ability/specialize/inspect/bool_to_inspector.txt From 3434d3154aec8e5d4da391f22e2116998fda2e11 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Mon, 27 Nov 2023 22:15:09 -0800 Subject: [PATCH 15/40] Ayaz's fix and first passing inspect test --- crates/compiler/builtins/roc/Inspect.roc | 4 ++-- crates/compiler/solve/src/ability.rs | 5 +---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/crates/compiler/builtins/roc/Inspect.roc b/crates/compiler/builtins/roc/Inspect.roc index 611fa04e00..03e46e1b48 100644 --- a/crates/compiler/builtins/roc/Inspect.roc +++ b/crates/compiler/builtins/roc/Inspect.roc @@ -249,10 +249,10 @@ dbgBool : Bool -> Inspector DbgFormatter dbgBool = \b -> if b then f0 <- custom - dbgWrite f0 "true" + dbgWrite f0 "Bool.true" else f0 <- custom - dbgWrite f0 "false" + dbgWrite f0 "Bool.false" dbgStr : Str -> Inspector DbgFormatter dbgStr = \s -> diff --git a/crates/compiler/solve/src/ability.rs b/crates/compiler/solve/src/ability.rs index 6ffa242ba1..cce612453c 100644 --- a/crates/compiler/solve/src/ability.rs +++ b/crates/compiler/solve/src/ability.rs @@ -1504,10 +1504,7 @@ impl AbilityResolver for AbilitiesStore { /// because they do not explicitly list ability implementations due to circular dependencies. #[inline] pub(crate) fn builtin_module_with_unlisted_ability_impl(module_id: ModuleId) -> bool { - matches!( - module_id, - ModuleId::NUM | ModuleId::BOOL | ModuleId::INSPECT - ) + matches!(module_id, ModuleId::NUM | ModuleId::BOOL) } #[derive(Debug)] From 2e486953be6e64fa80974a8c6852131c898a0882 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Mon, 27 Nov 2023 22:21:10 -0800 Subject: [PATCH 16/40] put inspect tests in their own module --- crates/compiler/test_gen/src/gen_abilities.rs | 107 ++++++++++-------- 1 file changed, 59 insertions(+), 48 deletions(-) diff --git a/crates/compiler/test_gen/src/gen_abilities.rs b/crates/compiler/test_gen/src/gen_abilities.rs index 44c5e4b5f5..50fbbeb243 100644 --- a/crates/compiler/test_gen/src/gen_abilities.rs +++ b/crates/compiler/test_gen/src/gen_abilities.rs @@ -2181,12 +2181,25 @@ fn issue_4772_weakened_monomorphic_destructure() { }) } -#[test] -#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] -fn inspect_bool() { - assert_evals_to!( - indoc!( - r#" +mod inspect { + #[cfg(feature = "gen-llvm")] + use crate::helpers::llvm::assert_evals_to; + + #[cfg(feature = "gen-wasm")] + use crate::helpers::wasm::assert_evals_to; + + #[cfg(all(test, any(feature = "gen-llvm", feature = "gen-wasm")))] + use indoc::indoc; + + #[cfg(all(test, any(feature = "gen-llvm", feature = "gen-wasm")))] + use roc_std::RocStr; + + #[test] + #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] + fn bool() { + assert_evals_to!( + indoc!( + r#" app "test" provides [main] to "./platform" main = [ @@ -2194,24 +2207,21 @@ fn inspect_bool() { Inspect.inspect Bool.false, ] |> List.map Inspect.toDbgStr |> Str.joinWith ", " "# - ), - RocStr::from("Bool.true, Bool.false"), - RocStr - ); -} + ), + RocStr::from("Bool.true, Bool.false"), + RocStr + ); + } -#[test] -#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] -fn inspect_num() { - assert_evals_to!( - indoc!( - r#" + #[test] + #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] + fn num() { + assert_evals_to!( + indoc!( + r#" app "test" provides [main] to "./platform" main = [ - Inspect.inspect 42, # Num * - Inspect.inspect 0x5, # Int * - Inspect.inspect (0.1 + 0.2), # Frac * Inspect.inspect 1u8, # U8 Inspect.inspect 2i8, # I8 Inspect.inspect 3u16, # U16 @@ -2227,18 +2237,18 @@ fn inspect_num() { Inspect.inspect (1.1dec + 2.2), # Dec ] |> List.map Inspect.toDbgStr |> Str.joinWith ", " "# - ), - RocStr::from("42, 5, 0.3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1.1, 2.2, 3.3"), - RocStr - ); -} + ), + RocStr::from("42, 5, 0.3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1.1, 2.2, 3.3"), + RocStr + ); + } -#[test] -#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] -fn inspect_list() { - assert_evals_to!( - indoc!( - r#" + #[test] + #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] + fn list() { + assert_evals_to!( + indoc!( + r#" app "test" provides [main] to "./platform" main = [ @@ -2250,18 +2260,18 @@ fn inspect_list() { Inspect.inspect ["foo"], # List Str ] |> List.map Inspect.toDbgStr |> Str.joinWith ", " "# - ), - RocStr::from("[], [0, 1, 2], [1, 2, 3], [0.3, 0.4], [1, 2], [\"foo\"]"), - RocStr - ); -} + ), + RocStr::from("[], [0, 1, 2], [1, 2, 3], [0.3, 0.4], [1, 2], [\"foo\"]"), + RocStr + ); + } -#[test] -#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] -fn inspect_str() { - assert_evals_to!( - indoc!( - r#" + #[test] + #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] + fn str() { + assert_evals_to!( + indoc!( + r#" app "test" provides [main] to "./platform" main = [ @@ -2270,10 +2280,11 @@ fn inspect_str() { Inspect.inspect "an extraordinarily long string - so long it's on the heap!", ] |> List.map Inspect.toDbgStr |> Str.joinWith ", " "# - ), - RocStr::from( - r#""", "a small string", "an extraordinarily long string - so long it's on the heap!""# - ), - RocStr - ); + ), + RocStr::from( + r#""", "a small string", "an extraordinarily long string - so long it's on the heap!""# + ), + RocStr + ); + } } From a1a563074dc859956e7b66209ec05797f9d77892 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Mon, 27 Nov 2023 22:25:51 -0800 Subject: [PATCH 17/40] expand ui tests to numbers --- .../specialize/inspect/bool_to_inspector.txt | 4 ++-- .../specialize/inspect/num_a_to_inspector.txt | 4 ++++ .../ability/specialize/inspect/u8_to_inspector.txt | 4 ++++ .../generalization_among_large_recursive_group.txt | 14 +++++++------- 4 files changed, 17 insertions(+), 9 deletions(-) create mode 100644 crates/compiler/uitest/tests/ability/specialize/inspect/num_a_to_inspector.txt create mode 100644 crates/compiler/uitest/tests/ability/specialize/inspect/u8_to_inspector.txt diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/bool_to_inspector.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/bool_to_inspector.txt index 7b11b76012..50661600b3 100644 --- a/crates/compiler/uitest/tests/ability/specialize/inspect/bool_to_inspector.txt +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/bool_to_inspector.txt @@ -1,4 +1,4 @@ app "test" provides [main] to "./platform" -main = Inspect.toInspector Bool.true -# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Bool -[[] + f:Inspect.bool(13):1]-> Inspector f where f implements InspectFormatter +main = Inspect.toInspector Bool.true |> Inspect.apply (Inspect.init {}) |> Inspect.toDbgStr +# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Bool -[[Inspect.dbgBool(43)]]-> Inspector DbgFormatter diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/num_a_to_inspector.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/num_a_to_inspector.txt new file mode 100644 index 0000000000..7d6958d913 --- /dev/null +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/num_a_to_inspector.txt @@ -0,0 +1,4 @@ +app "test" provides [main] to "./platform" + +main = Inspect.toInspector 7 |> Inspect.apply (Inspect.init {}) |> Inspect.toDbgStr +# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Bool -[[Inspect.dbgBool(43)]]-> Inspector DbgFormatter diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/u8_to_inspector.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/u8_to_inspector.txt new file mode 100644 index 0000000000..346c608138 --- /dev/null +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/u8_to_inspector.txt @@ -0,0 +1,4 @@ +app "test" provides [main] to "./platform" + +main = Inspect.toInspector 7u8 |> Inspect.apply (Inspect.init {}) |> Inspect.toDbgStr +# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Bool -[[Inspect.dbgBool(43)]]-> Inspector DbgFormatter diff --git a/crates/compiler/uitest/tests/recursion/generalization_among_large_recursive_group.txt b/crates/compiler/uitest/tests/recursion/generalization_among_large_recursive_group.txt index 6238bd9ad1..5b89442a58 100644 --- a/crates/compiler/uitest/tests/recursion/generalization_among_large_recursive_group.txt +++ b/crates/compiler/uitest/tests/recursion/generalization_among_large_recursive_group.txt @@ -3,22 +3,22 @@ app "test" provides [main] to "./platform" f = \{} -> -#^{-1} <1874><117>{} -<120>[[f(1)]]-> <116>[Ok <1882>{}]<80>* +#^{-1} <2722><117>{} -<120>[[f(1)]]-> <116>[Ok <2730>{}]<80>* when g {} is -# ^ <1864><1882>{} -<1872>[[g(2)]]-> <72>[Ok <1882>{}]<102>* +# ^ <2712><2730>{} -<2720>[[g(2)]]-> <72>[Ok <2730>{}]<102>* _ -> Ok {} g = \{} -> -#^{-1} <1864><1882>{} -<1872>[[g(2)]]-> <72>[Ok <1882>{}]<102>* +#^{-1} <2712><2730>{} -<2720>[[g(2)]]-> <72>[Ok <2730>{}]<102>* when h {} is -# ^ <1869><1882>{} -<1877>[[h(3)]]-> <94>[Ok <1882>{}]<124>* +# ^ <2717><2730>{} -<2725>[[h(3)]]-> <94>[Ok <2730>{}]<124>* _ -> Ok {} h = \{} -> -#^{-1} <1869><1882>{} -<1877>[[h(3)]]-> <94>[Ok <1882>{}]<124>* +#^{-1} <2717><2730>{} -<2725>[[h(3)]]-> <94>[Ok <2730>{}]<124>* when f {} is -# ^ <1874><117>{} -<120>[[f(1)]]-> <116>[Ok <1882>{}]<80>* +# ^ <2722><117>{} -<120>[[f(1)]]-> <116>[Ok <2730>{}]<80>* _ -> Ok {} main = f {} -# ^ <1884><133>{} -<136>[[f(1)]]-> <138>[Ok <1882>{}]<1883>w_a +# ^ <2732><133>{} -<136>[[f(1)]]-> <138>[Ok <2730>{}]<2731>w_a From 35078a22952ddb4a2d05a0926c472f8e0ab3ce49 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 09:20:33 -0800 Subject: [PATCH 18/40] allow nat in DeriveInspect --- crates/compiler/solve/src/ability.rs | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/crates/compiler/solve/src/ability.rs b/crates/compiler/solve/src/ability.rs index cce612453c..36eac7736a 100644 --- a/crates/compiler/solve/src/ability.rs +++ b/crates/compiler/solve/src/ability.rs @@ -859,8 +859,8 @@ impl DerivableVisitor for DeriveInspect { #[inline(always)] fn is_derivable_builtin_opaque(symbol: Symbol) -> bool { - (is_builtin_number_alias(symbol) && !is_builtin_nat_alias(symbol)) - || is_builtin_bool_alias(symbol) + // TODO: Should this just be true? All values are always inspectable. + is_builtin_number_alias(symbol) || is_builtin_bool_alias(symbol) } #[inline(always)] @@ -927,16 +927,9 @@ impl DerivableVisitor for DeriveInspect { } #[inline(always)] - fn visit_alias(var: Variable, symbol: Symbol) -> Result { + fn visit_alias(_var: Variable, symbol: Symbol) -> Result { if is_builtin_number_alias(symbol) { - if is_builtin_nat_alias(symbol) { - Err(NotDerivable { - var, - context: NotDerivableContext::Encode(NotDerivableEncode::Nat), - }) - } else { - Ok(Descend(false)) - } + Ok(Descend(false)) } else { Ok(Descend(true)) } From f2ab6b54f3468e2601e0a3a8fcf0e43786f8e57d Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 09:33:11 -0800 Subject: [PATCH 19/40] correct Inspect.opaque and Inspect.function to be function calls --- crates/compiler/builtins/roc/Inspect.roc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/compiler/builtins/roc/Inspect.roc b/crates/compiler/builtins/roc/Inspect.roc index 03e46e1b48..64a5f8fcb3 100644 --- a/crates/compiler/builtins/roc/Inspect.roc +++ b/crates/compiler/builtins/roc/Inspect.roc @@ -62,11 +62,11 @@ InspectFormatter implements # In text, this would render as `` # TODO: Pass the type name to opaque so that it can be displayed. - opaque : Inspector f where f implements InspectFormatter + opaque : * -> Inspector f where f implements InspectFormatter # In text, this would render as `` # TODO: Maybe pass the the function name or signiture to function so that it can be displayed. - function : Inspector f where f implements InspectFormatter + function : * -> Inspector f where f implements InspectFormatter u8 : U8 -> Inspector f where f implements InspectFormatter i8 : I8 -> Inspector f where f implements InspectFormatter @@ -262,13 +262,13 @@ dbgStr = \s -> |> dbgWrite s |> dbgWrite "\"" -dbgOpaque : Inspector DbgFormatter -dbgOpaque = +dbgOpaque : * -> Inspector DbgFormatter +dbgOpaque = \_ -> f0 <- custom dbgWrite f0 "" -dbgFunction : Inspector DbgFormatter -dbgFunction = +dbgFunction : * -> Inspector DbgFormatter +dbgFunction = \_ -> f0 <- custom dbgWrite f0 "" From 796c2b1ded3df666d844118bddb0ffed8893c600 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 09:54:02 -0800 Subject: [PATCH 20/40] unwrap builtin opaques like NUM_NUM --- crates/compiler/derive_key/src/inspect.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/compiler/derive_key/src/inspect.rs b/crates/compiler/derive_key/src/inspect.rs index 3bc5793c46..18f67dec8e 100644 --- a/crates/compiler/derive_key/src/inspect.rs +++ b/crates/compiler/derive_key/src/inspect.rs @@ -141,6 +141,10 @@ impl FlatInspectable { AliasKind::Structural => { Self::from_var(subs, real_var) } + AliasKind::Opaque if sym.is_builtin() => { + // TODO: Is this correct for all builtins? It is at least required for the Num wrapper types. + Self::from_var(subs, real_var) + } AliasKind::Opaque => { // There are two cases in which `Inspect` can be derived for an opaque // type. From 6eedd08e5a77edc7ed0a3ad850a3112583d7f5cf Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 09:55:35 -0800 Subject: [PATCH 21/40] add Debug to FlatInspectable --- crates/compiler/derive_key/src/inspect.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/compiler/derive_key/src/inspect.rs b/crates/compiler/derive_key/src/inspect.rs index 18f67dec8e..1fa026863d 100644 --- a/crates/compiler/derive_key/src/inspect.rs +++ b/crates/compiler/derive_key/src/inspect.rs @@ -11,7 +11,7 @@ use crate::util::{ check_derivable_ext_var, debug_name_fn, debug_name_record, debug_name_tag, debug_name_tuple, }; -#[derive(Hash)] +#[derive(Hash, Debug)] pub enum FlatInspectable { Immediate(Symbol), Key(FlatInspectableKey), From 82cda1965c0e6e8a3141815bfd79648ac94c708c Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 10:05:25 -0800 Subject: [PATCH 22/40] use INSPECT_INSPECT_ABILITY instead of INSPECT_INSPECT --- crates/compiler/load/tests/test_reporting.rs | 2 +- crates/compiler/module/src/symbol.rs | 5 ++++- crates/compiler/solve/src/ability.rs | 2 +- crates/compiler/types/src/subs.rs | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/crates/compiler/load/tests/test_reporting.rs b/crates/compiler/load/tests/test_reporting.rs index 9cf2f4bccc..331eee480b 100644 --- a/crates/compiler/load/tests/test_reporting.rs +++ b/crates/compiler/load/tests/test_reporting.rs @@ -9798,7 +9798,7 @@ In roc, functions are always written as a lambda, like{} Only builtin abilities can be derived. - Note: The builtin abilities are `Encoding`, `Decoding`, `Hash`, `Eq` + Note: The builtin abilities are `Encoding`, `Decoding`, `Hash`, `Eq`, `Inspect` "### ); diff --git a/crates/compiler/module/src/symbol.rs b/crates/compiler/module/src/symbol.rs index bbd130d326..7fee728ad4 100644 --- a/crates/compiler/module/src/symbol.rs +++ b/crates/compiler/module/src/symbol.rs @@ -53,7 +53,10 @@ pub const DERIVABLE_ABILITIES: &[(Symbol, &[Symbol])] = &[ (Symbol::DECODE_DECODING, &[Symbol::DECODE_DECODER]), (Symbol::HASH_HASH_ABILITY, &[Symbol::HASH_HASH]), (Symbol::BOOL_EQ, &[Symbol::BOOL_IS_EQ]), - (Symbol::INSPECT_INSPECT, &[Symbol::INSPECT_TO_INSPECTOR]), + ( + Symbol::INSPECT_INSPECT_ABILITY, + &[Symbol::INSPECT_TO_INSPECTOR], + ), ]; /// In Debug builds only, Symbol has a name() method that lets diff --git a/crates/compiler/solve/src/ability.rs b/crates/compiler/solve/src/ability.rs index 36eac7736a..33de269a9f 100644 --- a/crates/compiler/solve/src/ability.rs +++ b/crates/compiler/solve/src/ability.rs @@ -854,7 +854,7 @@ trait DerivableVisitor { struct DeriveInspect; impl DerivableVisitor for DeriveInspect { - const ABILITY: Symbol = Symbol::INSPECT_INSPECT; + const ABILITY: Symbol = Symbol::INSPECT_INSPECT_ABILITY; const ABILITY_SLICE: SubsSlice = Subs::AB_INSPECT; #[inline(always)] diff --git a/crates/compiler/types/src/subs.rs b/crates/compiler/types/src/subs.rs index 07dda6b003..7b3f6abf28 100644 --- a/crates/compiler/types/src/subs.rs +++ b/crates/compiler/types/src/subs.rs @@ -1756,7 +1756,7 @@ impl Subs { symbol_names.push(Symbol::HASH_HASHER); symbol_names.push(Symbol::HASH_HASH_ABILITY); symbol_names.push(Symbol::BOOL_EQ); - symbol_names.push(Symbol::INSPECT_INSPECT); + symbol_names.push(Symbol::INSPECT_INSPECT_ABILITY); // END INIT-SymbolNames // IFTTT INIT-VariableSubsSlice From c443bdcf4f312bf366001d780ac88e24f5c1e080 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 10:17:09 -0800 Subject: [PATCH 23/40] check_adhoc for inspect --- crates/compiler/solve/src/ability.rs | 7 +++++++ .../ability/specialize/inspect/num_a_to_inspector.txt | 2 +- .../tests/ability/specialize/inspect/opaque_derived.txt | 2 +- .../tests/ability/specialize/inspect/u8_to_inspector.txt | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/crates/compiler/solve/src/ability.rs b/crates/compiler/solve/src/ability.rs index 33de269a9f..889e3d5425 100644 --- a/crates/compiler/solve/src/ability.rs +++ b/crates/compiler/solve/src/ability.rs @@ -304,6 +304,13 @@ impl ObligationCache { Symbol::BOOL_EQ => Some(DeriveEq::is_derivable(self, abilities_store, subs, var)), + Symbol::INSPECT_INSPECT_ABILITY => Some(DeriveInspect::is_derivable( + self, + abilities_store, + subs, + var, + )), + _ => None, }; diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/num_a_to_inspector.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/num_a_to_inspector.txt index 7d6958d913..e0112f852b 100644 --- a/crates/compiler/uitest/tests/ability/specialize/inspect/num_a_to_inspector.txt +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/num_a_to_inspector.txt @@ -1,4 +1,4 @@ app "test" provides [main] to "./platform" main = Inspect.toInspector 7 |> Inspect.apply (Inspect.init {}) |> Inspect.toDbgStr -# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Bool -[[Inspect.dbgBool(43)]]-> Inspector DbgFormatter +# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): I64 -[[Inspect.dbgI64(54)]]-> Inspector DbgFormatter diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_derived.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_derived.txt index cfe872a6bd..4aebca3440 100644 --- a/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_derived.txt +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_derived.txt @@ -3,4 +3,4 @@ app "test" provides [main] to "./platform" Op := U8 implements [Inspect] main = Inspect.toInspector (@Op 1u8) -# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Op -[[] + f:Inspect.opaque(15):1]-> Inspector f where f implements InspectFormatter +# ^^^^^^^^^^^^^^^^^^^ Op#Inspect.toInspector(3): Op -[[#Op_toInspector(3)]]-> Inspector f where f implements InspectFormatter diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/u8_to_inspector.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/u8_to_inspector.txt index 346c608138..59b9a84c1c 100644 --- a/crates/compiler/uitest/tests/ability/specialize/inspect/u8_to_inspector.txt +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/u8_to_inspector.txt @@ -1,4 +1,4 @@ app "test" provides [main] to "./platform" main = Inspect.toInspector 7u8 |> Inspect.apply (Inspect.init {}) |> Inspect.toDbgStr -# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Bool -[[Inspect.dbgBool(43)]]-> Inspector DbgFormatter +# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): U8 -[[Inspect.dbgU8(47)]]-> Inspector DbgFormatter From 4c25c60cdc191cbf331e76b5c500afaff79c8ff7 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 10:38:49 -0800 Subject: [PATCH 24/40] expand ui tests for inspect --- .../inspect/{bool_to_inspector.txt => bool.txt} | 0 .../uitest/tests/ability/specialize/inspect/dec.txt | 4 ++++ .../specialize/inspect/non_implementing_opaque.txt | 4 ++-- .../ability/specialize/inspect/opaque_custom_impl.txt | 4 ++-- .../tests/ability/specialize/inspect/opaque_derived.txt | 4 ++-- .../inspect/{num_a_to_inspector.txt => ranged_num.txt} | 0 .../uitest/tests/ability/specialize/inspect/record.txt | 4 ++++ .../inspect/record_with_nested_custom_impl.txt | 9 +++++++++ .../specialize/inspect/{u8_to_inspector.txt => u8.txt} | 0 9 files changed, 23 insertions(+), 6 deletions(-) rename crates/compiler/uitest/tests/ability/specialize/inspect/{bool_to_inspector.txt => bool.txt} (100%) create mode 100644 crates/compiler/uitest/tests/ability/specialize/inspect/dec.txt rename crates/compiler/uitest/tests/ability/specialize/inspect/{num_a_to_inspector.txt => ranged_num.txt} (100%) create mode 100644 crates/compiler/uitest/tests/ability/specialize/inspect/record.txt create mode 100644 crates/compiler/uitest/tests/ability/specialize/inspect/record_with_nested_custom_impl.txt rename crates/compiler/uitest/tests/ability/specialize/inspect/{u8_to_inspector.txt => u8.txt} (100%) diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/bool_to_inspector.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/bool.txt similarity index 100% rename from crates/compiler/uitest/tests/ability/specialize/inspect/bool_to_inspector.txt rename to crates/compiler/uitest/tests/ability/specialize/inspect/bool.txt diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/dec.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/dec.txt new file mode 100644 index 0000000000..839ebc1cba --- /dev/null +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/dec.txt @@ -0,0 +1,4 @@ +app "test" provides [main] to "./platform" + +main = Inspect.toInspector 7dec |> Inspect.apply (Inspect.init {}) |> Inspect.toDbgStr +# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Dec -[[Inspect.dbgDec(60)]]-> Inspector DbgFormatter diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/non_implementing_opaque.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/non_implementing_opaque.txt index c0b907ae38..d27232f296 100644 --- a/crates/compiler/uitest/tests/ability/specialize/inspect/non_implementing_opaque.txt +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/non_implementing_opaque.txt @@ -2,5 +2,5 @@ app "test" provides [main] to "./platform" Op := {} -main = Inspect.toInspector (@Op {}) -# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Op -[[] + f:Inspect.opaque(15):1]-> Inspector f where f implements InspectFormatter +main = Inspect.toInspector (@Op {}) |> Inspect.apply (Inspect.init {}) |> Inspect.toDbgStr +# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Op -[[Inspect.dbgOpaque(45)]]-> Inspector DbgFormatter diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_custom_impl.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_custom_impl.txt index 2b5a4b1cfa..bdb8f45893 100644 --- a/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_custom_impl.txt +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_custom_impl.txt @@ -5,5 +5,5 @@ Op := U8 implements [Inspect { toInspector: myToInspector }] myToInspector : Op -> Inspector f where f implements InspectFormatter myToInspector = \@Op num -> Inspect.u8 num -main = Inspect.toInspector (@Op 1u8) -# ^^^^^^^^^^^^^^^^^^^ Op#Inspect.toInspector(2): Op -[[myToInspector(2)]]-> Inspector f where f implements InspectFormatter +main = Inspect.toInspector (@Op 1u8) |> Inspect.apply (Inspect.init {}) |> Inspect.toDbgStr +# ^^^^^^^^^^^^^^^^^^^ Op#Inspect.toInspector(2): Op -[[myToInspector(2)]]-> Inspector DbgFormatter diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_derived.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_derived.txt index 4aebca3440..1e3569a4fd 100644 --- a/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_derived.txt +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/opaque_derived.txt @@ -2,5 +2,5 @@ app "test" provides [main] to "./platform" Op := U8 implements [Inspect] -main = Inspect.toInspector (@Op 1u8) -# ^^^^^^^^^^^^^^^^^^^ Op#Inspect.toInspector(3): Op -[[#Op_toInspector(3)]]-> Inspector f where f implements InspectFormatter +main = Inspect.toInspector (@Op 1u8) |> Inspect.apply (Inspect.init {}) |> Inspect.toDbgStr +# ^^^^^^^^^^^^^^^^^^^ Op#Inspect.toInspector(3): Op -[[#Op_toInspector(3)]]-> Inspector DbgFormatter diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/num_a_to_inspector.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/ranged_num.txt similarity index 100% rename from crates/compiler/uitest/tests/ability/specialize/inspect/num_a_to_inspector.txt rename to crates/compiler/uitest/tests/ability/specialize/inspect/ranged_num.txt diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/record.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/record.txt new file mode 100644 index 0000000000..0478644973 --- /dev/null +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/record.txt @@ -0,0 +1,4 @@ +app "test" provides [main] to "./platform" + +main = Inspect.toInspector { a: "" } |> Inspect.apply (Inspect.init {}) |> Inspect.toDbgStr +# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Bool -[[Inspect.dbgBool(43)]]-> Inspector DbgFormatter diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/record_with_nested_custom_impl.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/record_with_nested_custom_impl.txt new file mode 100644 index 0000000000..107cc4ade5 --- /dev/null +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/record_with_nested_custom_impl.txt @@ -0,0 +1,9 @@ +app "test" provides [main] to "./platform" + +Op := U8 implements [Inspect { toInspector: myToInspector }] + +myToInspector : Op -> Inspector f where f implements InspectFormatter +myToInspector = \@Op num -> Inspect.u8 num + +main = Inspect.toInspector { op: @Op 1u8 } |> Inspect.apply (Inspect.init {}) |> Inspect.toDbgStr +# ^^^^^^^^^^^^^^^^^^^ Op#Inspect.toInspector(2): Op -[[myToInspector(2)]]-> Inspector f where f implements InspectFormatter diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/u8_to_inspector.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/u8.txt similarity index 100% rename from crates/compiler/uitest/tests/ability/specialize/inspect/u8_to_inspector.txt rename to crates/compiler/uitest/tests/ability/specialize/inspect/u8.txt From 5e36395369d182bce99bccf1ce8dd89f39d16efd Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 10:52:17 -0800 Subject: [PATCH 25/40] correct Inspect custom impl to use Inspect.apply --- crates/compiler/derive/src/inspect.rs | 304 +++++++++--------- .../ability/specialize/inspect/record.txt | 2 +- .../record_with_nested_custom_impl.txt | 2 +- 3 files changed, 147 insertions(+), 161 deletions(-) diff --git a/crates/compiler/derive/src/inspect.rs b/crates/compiler/derive/src/inspect.rs index 1fd048c997..0e591a5c6d 100644 --- a/crates/compiler/derive/src/inspect.rs +++ b/crates/compiler/derive/src/inspect.rs @@ -128,7 +128,7 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { ); // build `toInspector elem` type - // val -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // val -[uls]-> Inspector fmt where fmt implements InspectorFormatter let to_inspector_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_TO_INSPECTOR); // elem -[clos]-> t1 @@ -143,11 +143,11 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { )), ); - // val -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // val -[uls]-> Inspector fmt where fmt implements InspectorFormatter // ~ elem -[clos]-> t1 env.unify(to_inspector_fn_var, elem_to_inspector_fn_var); - // toInspector : (typeof rcd.a) -[clos]-> Inspector fmt where fmt implements InspectorFormatting + // toInspector : (typeof rcd.a) -[clos]-> Inspector fmt where fmt implements InspectorFormatter let to_inspector_var = AbilityMember(Symbol::INSPECT_TO_INSPECTOR, None, elem_to_inspector_fn_var); let to_inspector_fn = Box::new(( @@ -209,7 +209,7 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { }); // build `Inspect.list lst (\elem -> Inspect.toInspector elem)` type - // List e, (e -> Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // List e, (e -> Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatter let inspect_list_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_LIST); // List elem, to_elem_inspector_fn_var -[clos]-> t1 @@ -226,11 +226,11 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { )), ); - // List e, (e -> Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // List e, (e -> Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatter // ~ List elem, to_elem_inspector_fn_var -[clos]-> t1 env.unify(inspect_list_fn_var, this_inspect_list_fn_var); - // Inspect.list : List elem, to_elem_inspector_fn_var -[clos]-> Inspector fmt where fmt implements InspectorFormatting + // Inspect.list : List elem, to_elem_inspector_fn_var -[clos]-> Inspector fmt where fmt implements InspectorFormatter let inspect_list = AbilityMember(Symbol::INSPECT_LIST, None, this_inspect_list_fn_var); let inspect_list_fn = Box::new(( this_inspect_list_fn_var, @@ -249,7 +249,7 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { CalledVia::Space, ); - // Inspect.custom \bytes, fmt -> Inspect.appendWith bytes (Inspect.list ..) fmt + // Inspect.custom \fmt -> Inspect.apply (Inspect.list ..) fmt let (body, this_inspector_var) = wrap_in_inspect_custom( env, inspect_list_call, @@ -348,7 +348,7 @@ fn to_inspector_record( }; // build `toInspector rcd.a` type - // val -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // val -[uls]-> Inspector fmt where fmt implements InspectorFormatter let to_inspector_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_TO_INSPECTOR); // (typeof rcd.a) -[clos]-> t1 @@ -363,11 +363,11 @@ fn to_inspector_record( )), ); - // val -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // val -[uls]-> Inspector fmt where fmt implements InspectorFormatter // ~ (typeof rcd.a) -[clos]-> t1 env.unify(to_inspector_fn_var, this_to_inspector_fn_var); - // toInspector : (typeof rcd.a) -[clos]-> Inspector fmt where fmt implements InspectorFormatting + // toInspector : (typeof rcd.a) -[clos]-> Inspector fmt where fmt implements InspectorFormatter let to_inspector_var = AbilityMember(Symbol::INSPECT_TO_INSPECTOR, None, to_inspector_fn_var); let to_inspector_fn = Box::new(( @@ -429,7 +429,7 @@ fn to_inspector_record( }; // build `Inspect.record [ { key: .., value: ..}, .. ]` type - // List { key : Str, value : Inspector fmt } -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // List { key : Str, value : Inspector fmt } -[uls]-> Inspector fmt where fmt implements InspectorFormatter let inspect_record_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_RECORD); // fields_list_var -[clos]-> t1 @@ -446,11 +446,11 @@ fn to_inspector_record( )), ); - // List { key : Str, value : Inspector fmt } -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // List { key : Str, value : Inspector fmt } -[uls]-> Inspector fmt where fmt implements InspectorFormatter // ~ fields_list_var -[clos]-> t1 env.unify(inspect_record_fn_var, this_inspect_record_fn_var); - // Inspect.record : fields_list_var -[clos]-> Inspector fmt where fmt implements InspectorFormatting + // Inspect.record : fields_list_var -[clos]-> Inspector fmt where fmt implements InspectorFormatter let inspect_record_var = AbilityMember(Symbol::INSPECT_RECORD, None, inspect_record_fn_var); let inspect_record_fn = Box::new(( inspect_record_fn_var, @@ -466,7 +466,7 @@ fn to_inspector_record( CalledVia::Space, ); - // Inspect.custom \bytes, fmt -> Inspect.appendWith bytes (Inspect.record ..) fmt + // Inspect.custom \fmt -> Inspect.apply (Inspect.record ..) fmt let (body, this_inspector_var) = wrap_in_inspect_custom(env, inspect_record_call, inspector_var, rcd_sym, record_var); @@ -552,7 +552,7 @@ fn to_inspector_tuple( }; // build `toInspector tup.0` type - // val -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // val -[uls]-> Inspector fmt where fmt implements InspectorFormatter let to_inspector_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_TO_INSPECTOR); // (typeof tup.0) -[clos]-> t1 @@ -567,11 +567,11 @@ fn to_inspector_tuple( )), ); - // val -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // val -[uls]-> Inspector fmt where fmt implements InspectorFormatter // ~ (typeof tup.0) -[clos]-> t1 env.unify(to_inspector_fn_var, this_to_inspector_fn_var); - // toInspector : (typeof tup.0) -[clos]-> Inspector fmt where fmt implements InspectorFormatting + // toInspector : (typeof tup.0) -[clos]-> Inspector fmt where fmt implements InspectorFormatter let to_inspector_var = AbilityMember(Symbol::INSPECT_TO_INSPECTOR, None, to_inspector_fn_var); let to_inspector_fn = Box::new(( @@ -613,7 +613,7 @@ fn to_inspector_tuple( }; // build `Inspect.tuple [ toInspector tup.0, toInspector tup.1 ]` type - // List (Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // List (Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatter let inspect_tuple_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_TUPLE); // elem_inspectors_list_var -[clos]-> t1 @@ -630,11 +630,11 @@ fn to_inspector_tuple( )), ); - // List (Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // List (Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatter // ~ elem_inspectors_list_var -[clos]-> t1 env.unify(inspect_tuple_fn_var, this_inspect_tuple_fn_var); - // Inspect.tuple : elem_inspectors_list_var -[clos]-> Inspector fmt where fmt implements InspectorFormatting + // Inspect.tuple : elem_inspectors_list_var -[clos]-> Inspector fmt where fmt implements InspectorFormatter let inspect_tuple_var = AbilityMember(Symbol::INSPECT_TUPLE, None, inspect_tuple_fn_var); let inspect_tuple_fn = Box::new(( inspect_tuple_fn_var, @@ -650,7 +650,7 @@ fn to_inspector_tuple( CalledVia::Space, ); - // Inspect.custom \bytes, fmt -> Inspect.appendWith bytes (Inspect.tuple_var ..) fmt + // Inspect.custom \fmt -> Inspect.apply (Inspect.tuple_var ..) fmt let (body, this_inspector_var) = wrap_in_inspect_custom(env, inspect_tuple_call, inspector_var, tup_sym, tuple_var); @@ -751,7 +751,7 @@ fn to_inspector_tag_union( .zip(payload_vars.iter()) .map(|(&sym, &sym_var)| { // build `toInspector v1` type - // expected: val -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // expected: val -[uls]-> Inspector fmt where fmt implements InspectorFormatter let to_inspector_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_TO_INSPECTOR); @@ -769,11 +769,11 @@ fn to_inspector_tag_union( )), ); - // val -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // val -[uls]-> Inspector fmt where fmt implements InspectorFormatter // ~ t1 -[clos]-> t' env.unify(to_inspector_fn_var, this_to_inspector_fn_var); - // toInspector : t1 -[clos]-> Inspector fmt where fmt implements InspectorFormatting + // toInspector : t1 -[clos]-> Inspector fmt where fmt implements InspectorFormatter let to_inspector_var = AbilityMember(Symbol::INSPECT_TO_INSPECTOR, None, this_to_inspector_fn_var); let to_inspector_fn = Box::new(( @@ -815,7 +815,7 @@ fn to_inspector_tag_union( }; // build `Inspect.tag "A" [ ... ]` type - // expected: Str, List (Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // expected: Str, List (Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatter let inspect_tag_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_TAG); // wanted: Str, List whole_inspectors_var -[clos]-> t' @@ -834,11 +834,11 @@ fn to_inspector_tag_union( )), ); - // Str, List (Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatting + // Str, List (Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatter // ~ Str, List whole_inspectors_var -[clos]-> t' env.unify(inspect_tag_fn_var, this_inspect_tag_fn_var); - // Inspect.tag : Str, List whole_inspectors_var -[clos]-> Inspector fmt where fmt implements InspectorFormatting + // Inspect.tag : Str, List whole_inspectors_var -[clos]-> Inspector fmt where fmt implements InspectorFormatter let inspect_tag_var = AbilityMember(Symbol::INSPECT_TAG, None, this_inspect_tag_fn_var); let inspect_tag_fn = Box::new(( this_inspect_tag_fn_var, @@ -888,7 +888,7 @@ fn to_inspector_tag_union( exhaustive: ExhaustiveMark::known_exhaustive(), }; - // Inspect.custom \bytes, fmt -> Inspect.appendWith bytes (when ..) fmt + // Inspect.custom \fmt -> Inspect.apply (when ..) fmt let (body, this_inspector_var) = wrap_in_inspect_custom( env, when_branches, @@ -923,7 +923,7 @@ fn to_inspector_tag_union( ); // \tag -> - // Inspect.custom \bytes, fmt -> Inspect.appendWith bytes ( + // Inspect.custom \fmt -> Inspect.apply ( // when tag is // A v1 v2 -> Inspect.tag "A" [ Inspect.toInspector v1, Inspect.toInspector v2 ] // B v3 -> Inspect.tag "B" [ Inspect.toInspector v3 ]) @@ -946,158 +946,144 @@ fn to_inspector_tag_union( (clos, fn_var) } -/// Lift `inspector` to `Inspect.custom \bytes, fmt -> Inspect.appendWith bytes inspector fmt` +/// Lift `inspector` to `Inspect.custom \fmt -> Inspect.apply inspector fmt` /// /// TODO: currently it appears that just `inspector` is not isomorphic to the lift, on the /// monomorphization level, even though we would think it is. In particular, unspecialized lambda /// sets fail to resolve when we use the non-lifted version. /// More investigation is needed to figure out why. fn wrap_in_inspect_custom( - _env: &mut Env, - _inspector: Expr, - _inspector_var: Variable, - _captured_symbol: Symbol, - _captured_var: Variable, + env: &mut Env, + inspector: Expr, + inspector_var: Variable, + captured_symbol: Symbol, + captured_var: Variable, ) -> (Expr, Variable) { - unimplemented!(); - // use Expr::*; + use Expr::*; - // let fn_name = env.new_symbol("custom"); + let fn_name = env.new_symbol("custom"); - // // bytes: List U8 - // let bytes_sym = env.new_symbol("bytes"); - // let bytes_var = Variable::LIST_U8; + // fmt: fmt where fmt implements InspectorFormatter + let fmt_sym = env.new_symbol("fmt"); + let fmt_var = env.subs.fresh_unnamed_flex_var(); - // // fmt: fmt where fmt implements InspectorFormatting - // let fmt_sym = env.new_symbol("fmt"); - // let fmt_var = env.subs.fresh_unnamed_flex_var(); + // build `Inspect.apply inspector fmt` type + // expected: Inspect.apply : Inspector fmt, fmt -[apply]-> fmt where fmt implements InspectorFormatter + let apply_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_APPLY); - // // build `Inspect.appendWith bytes inspector fmt` type - // // expected: Inspect.appendWith : List U8, Inspector fmt, fmt -[appendWith]-> List U8 where fmt implements InspectorFormatting - // let append_with_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_APPEND_WITH); + // wanted: Inspect.apply : inspector_var, fmt -[clos]-> fmt where fmt implements InspectorFormatter + let this_apply_args_var_slice = + VariableSubsSlice::insert_into_subs(env.subs, [inspector_var, fmt_var]); + let this_apply_clos_var = env.subs.fresh_unnamed_flex_var(); // -[clos]-> + let this_apply_fn_var = synth_var( + env.subs, + Content::Structure(FlatType::Func( + this_apply_args_var_slice, + this_apply_clos_var, + fmt_var, + )), + ); - // // wanted: Inspect.appendWith : List U8, inspector_var, fmt -[clos]-> List U8 where fmt implements InspectorFormatting - // let this_append_with_args_var_slice = - // VariableSubsSlice::insert_into_subs(env.subs, [Variable::LIST_U8, inspector_var, fmt_var]); - // let this_append_with_clos_var = env.subs.fresh_unnamed_flex_var(); // -[clos]-> - // let this_append_with_fn_var = synth_var( - // env.subs, - // Content::Structure(FlatType::Func( - // this_append_with_args_var_slice, - // this_append_with_clos_var, - // Variable::LIST_U8, - // )), - // ); + // Inspector fmt, fmt -[apply]-> ft where fmt implements InspectorFormatter + // ~ inspector_var, fmt -[clos]-> fmt where fmt implements InspectorFormatter + env.unify(apply_fn_var, this_apply_fn_var); - // // List U8, Inspector fmt, fmt -[appendWith]-> List U8 where fmt implements InspectorFormatting - // // ~ List U8, inspector_var, fmt -[clos]-> List U8 where fmt implements InspectorFormatting - // env.unify(append_with_fn_var, this_append_with_fn_var); + // Inspect.apply : inspector_var, fmt -[apply]-> fmt where fmt implements InspectorFormatter + let apply_fn = Box::new(( + this_apply_fn_var, + Loc::at_zero(Var(Symbol::INSPECT_APPLY, this_apply_fn_var)), + this_apply_clos_var, + fmt_var, + )); - // // Inspect.appendWith : List U8, inspector_var, fmt -[appendWith]-> List U8 where fmt implements InspectorFormatting - // let append_with_fn = Box::new(( - // this_append_with_fn_var, - // Loc::at_zero(Var(Symbol::INSPECT_APPEND_WITH, this_append_with_fn_var)), - // this_append_with_clos_var, - // Variable::LIST_U8, - // )); + // Inspect.apply inspector fmt + let apply_call = Call( + apply_fn, + vec![ + // (inspector_var, inspector) + (inspector_var, Loc::at_zero(inspector)), + // (fmt, fmt_var) + (fmt_var, Loc::at_zero(Var(fmt_sym, fmt_var))), + ], + CalledVia::Space, + ); - // // Inspect.appendWith bytes inspector fmt - // let append_with_call = Call( - // append_with_fn, - // vec![ - // // (bytes_var, bytes) - // (bytes_var, Loc::at_zero(Var(bytes_sym, bytes_var))), - // // (inspector_var, inspector) - // (inspector_var, Loc::at_zero(inspector)), - // // (fmt, fmt_var) - // (fmt_var, Loc::at_zero(Var(fmt_sym, fmt_var))), - // ], - // CalledVia::Space, - // ); + // Create fn_var for ambient capture; we fix it up below. + let fn_var = synth_var(env.subs, Content::Error); - // // Create fn_var for ambient capture; we fix it up below. - // let fn_var = synth_var(env.subs, Content::Error); + // -[[FN_name captured_var]]-> + let fn_name_labels = + UnionLambdas::insert_into_subs(env.subs, once((fn_name, vec![captured_var]))); + let fn_clos_var = synth_var( + env.subs, + Content::LambdaSet(LambdaSet { + solved: fn_name_labels, + recursion_var: OptVariable::NONE, + unspecialized: SubsSlice::default(), + ambient_function: fn_var, + }), + ); - // // -[[FN_name captured_var]]-> - // let fn_name_labels = - // UnionLambdas::insert_into_subs(env.subs, once((fn_name, vec![captured_var]))); - // let fn_clos_var = synth_var( - // env.subs, - // Content::LambdaSet(LambdaSet { - // solved: fn_name_labels, - // recursion_var: OptVariable::NONE, - // unspecialized: SubsSlice::default(), - // ambient_function: fn_var, - // }), - // ); + // fmt -[[FN_name captured_var]]-> Inspect.apply inspector fmt + let args_slice = SubsSlice::insert_into_subs(env.subs, vec![fmt_var]); + env.subs.set_content( + fn_var, + Content::Structure(FlatType::Func(args_slice, fn_clos_var, fmt_var)), + ); - // // bytes, fmt -[[FN_name captured_var]]-> Inspect.appendWith bytes inspector fmt - // let args_slice = SubsSlice::insert_into_subs(env.subs, vec![bytes_var, fmt_var]); - // env.subs.set_content( - // fn_var, - // Content::Structure(FlatType::Func(args_slice, fn_clos_var, Variable::LIST_U8)), - // ); + // \fmt -[[fn_name captured_var]]-> Inspect.apply inspector fmt + let clos = Closure(ClosureData { + function_type: fn_var, + closure_type: fn_clos_var, + return_type: fmt_var, + name: fn_name, + captured_symbols: vec![(captured_symbol, captured_var)], + recursive: Recursive::NotRecursive, + arguments: vec![( + fmt_var, + AnnotatedMark::known_exhaustive(), + Loc::at_zero(Pattern::Identifier(fmt_sym)), + )], + loc_body: Box::new(Loc::at_zero(apply_call)), + }); - // // \bytes, fmt -[[fn_name captured_var]]-> Inspect.appendWith bytes inspector fmt - // let clos = Closure(ClosureData { - // function_type: fn_var, - // closure_type: fn_clos_var, - // return_type: Variable::LIST_U8, - // name: fn_name, - // captured_symbols: vec![(captured_symbol, captured_var)], - // recursive: Recursive::NotRecursive, - // arguments: vec![ - // ( - // bytes_var, - // AnnotatedMark::known_exhaustive(), - // Loc::at_zero(Pattern::Identifier(bytes_sym)), - // ), - // ( - // fmt_var, - // AnnotatedMark::known_exhaustive(), - // Loc::at_zero(Pattern::Identifier(fmt_sym)), - // ), - // ], - // loc_body: Box::new(Loc::at_zero(append_with_call)), - // }); + // Build + // Inspect.custom \fmt -> Inspect.apply inspector fmt + // + // expected: Inspect.custom : (fmt -> fmt) -> Inspector fmt where fmt implements InspectorFormatter + let custom_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_CUSTOM); - // // Build - // // Inspect.custom \bytes, fmt -> Inspect.appendWith bytes inspector fmt - // // - // // expected: Inspect.custom : (List U8, fmt -> List U8) -> Inspector fmt where fmt implements InspectorFormatting - // let custom_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_CUSTOM); + // wanted: Inspect.custom : fn_var -[clos]-> t' + let this_custom_args_var_slice = VariableSubsSlice::insert_into_subs(env.subs, [fn_var]); + let this_custom_clos_var = env.subs.fresh_unnamed_flex_var(); // -[clos]-> + let this_custom_inspector_var = env.subs.fresh_unnamed_flex_var(); // t' + let this_custom_fn_var = synth_var( + env.subs, + Content::Structure(FlatType::Func( + this_custom_args_var_slice, + this_custom_clos_var, + this_custom_inspector_var, + )), + ); - // // wanted: Inspect.custom : fn_var -[clos]-> t' - // let this_custom_args_var_slice = VariableSubsSlice::insert_into_subs(env.subs, [fn_var]); - // let this_custom_clos_var = env.subs.fresh_unnamed_flex_var(); // -[clos]-> - // let this_custom_inspector_var = env.subs.fresh_unnamed_flex_var(); // t' - // let this_custom_fn_var = synth_var( - // env.subs, - // Content::Structure(FlatType::Func( - // this_custom_args_var_slice, - // this_custom_clos_var, - // this_custom_inspector_var, - // )), - // ); + // (fmt -> fmt) -[..]-> Inspector fmt where fmt implements InspectorFormatter + // ~ fn_var -[clos]-> t' + env.unify(custom_fn_var, this_custom_fn_var); - // // (List U8, fmt -> List U8) -[..]-> Inspector fmt where fmt implements InspectorFormatting - // // ~ fn_var -[clos]-> t' - // env.unify(custom_fn_var, this_custom_fn_var); + // Inspect.custom : (fmt -> fmt) -> Inspector fmt where fmt implements InspectorFormatter + let custom_fn = Box::new(( + this_custom_fn_var, + Loc::at_zero(Var(Symbol::INSPECT_CUSTOM, this_custom_fn_var)), + this_custom_clos_var, // -[clos]-> + this_custom_inspector_var, // t' ~ Inspector fmt + )); - // // Inspect.custom : (List U8, fmt -> List U8) -> Inspector fmt where fmt implements InspectorFormatting - // let custom_fn = Box::new(( - // this_custom_fn_var, - // Loc::at_zero(Var(Symbol::INSPECT_CUSTOM, this_custom_fn_var)), - // this_custom_clos_var, // -[clos]-> - // this_custom_inspector_var, // t' ~ Inspector fmt - // )); + // Inspect.custom \fmt -> Inspect.apply inspector fmt + let custom_call = Call( + custom_fn, + vec![(fn_var, Loc::at_zero(clos))], + CalledVia::Space, + ); - // // Inspect.custom \bytes, fmt -> Inspect.appendWith bytes inspector fmt - // let custom_call = Call( - // custom_fn, - // vec![(fn_var, Loc::at_zero(clos))], - // CalledVia::Space, - // ); - - // (custom_call, this_custom_inspector_var) + (custom_call, this_custom_inspector_var) } diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/record.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/record.txt index 0478644973..0094d164f3 100644 --- a/crates/compiler/uitest/tests/ability/specialize/inspect/record.txt +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/record.txt @@ -1,4 +1,4 @@ app "test" provides [main] to "./platform" main = Inspect.toInspector { a: "" } |> Inspect.apply (Inspect.init {}) |> Inspect.toDbgStr -# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Bool -[[Inspect.dbgBool(43)]]-> Inspector DbgFormatter +# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): { a : Str } -[[#Derived.toInspector_{a}(0)]]-> Inspector DbgFormatter diff --git a/crates/compiler/uitest/tests/ability/specialize/inspect/record_with_nested_custom_impl.txt b/crates/compiler/uitest/tests/ability/specialize/inspect/record_with_nested_custom_impl.txt index 107cc4ade5..44f741f979 100644 --- a/crates/compiler/uitest/tests/ability/specialize/inspect/record_with_nested_custom_impl.txt +++ b/crates/compiler/uitest/tests/ability/specialize/inspect/record_with_nested_custom_impl.txt @@ -6,4 +6,4 @@ myToInspector : Op -> Inspector f where f implements InspectFormatter myToInspector = \@Op num -> Inspect.u8 num main = Inspect.toInspector { op: @Op 1u8 } |> Inspect.apply (Inspect.init {}) |> Inspect.toDbgStr -# ^^^^^^^^^^^^^^^^^^^ Op#Inspect.toInspector(2): Op -[[myToInspector(2)]]-> Inspector f where f implements InspectFormatter +# ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): { op : Op } -[[#Derived.toInspector_{op}(0)]]-> Inspector DbgFormatter From 21b68a2e27bbdf42b4f19783cc356ac3dbf6739e Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 11:08:16 -0800 Subject: [PATCH 26/40] add a set of currently failing mono tests for inspect --- .../generated/inspect_derived_string.txt | 48 +++++++ crates/compiler/test_mono/src/tests.rs | 130 ++++++++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 crates/compiler/test_mono/generated/inspect_derived_string.txt diff --git a/crates/compiler/test_mono/generated/inspect_derived_string.txt b/crates/compiler/test_mono/generated/inspect_derived_string.txt new file mode 100644 index 0000000000..de39b613e0 --- /dev/null +++ b/crates/compiler/test_mono/generated/inspect_derived_string.txt @@ -0,0 +1,48 @@ +procedure Inspect.147 (Inspect.317): + ret Inspect.317; + +procedure Inspect.249 (Inspect.250, Inspect.248): + let Inspect.326 : Str = "\""; + let Inspect.325 : Str = CallByName Inspect.61 Inspect.250 Inspect.326; + let Inspect.321 : Str = CallByName Inspect.61 Inspect.325 Inspect.248; + let Inspect.322 : Str = "\""; + let Inspect.320 : Str = CallByName Inspect.61 Inspect.321 Inspect.322; + ret Inspect.320; + +procedure Inspect.30 (): + let Inspect.316 : {} = Struct {}; + ret Inspect.316; + +procedure Inspect.35 (Inspect.300): + ret Inspect.300; + +procedure Inspect.36 (Inspect.304): + let Inspect.311 : Str = ""; + ret Inspect.311; + +procedure Inspect.44 (Inspect.248): + let Inspect.314 : {} = CallByName Inspect.30; + let Inspect.313 : Str = CallByName Inspect.147 Inspect.248; + ret Inspect.313; + +procedure Inspect.5 (Inspect.150): + let Inspect.312 : Str = CallByName Inspect.44 Inspect.150; + let Inspect.309 : {} = Struct {}; + let Inspect.308 : Str = CallByName Inspect.36 Inspect.309; + let Inspect.307 : Str = CallByName Inspect.249 Inspect.308 Inspect.312; + ret Inspect.307; + +procedure Inspect.61 (Inspect.303, Inspect.298): + let Inspect.324 : Str = CallByName Str.3 Inspect.303 Inspect.298; + dec Inspect.298; + ret Inspect.324; + +procedure Str.3 (#Attr.2, #Attr.3): + let Str.292 : Str = lowlevel StrConcat #Attr.2 #Attr.3; + ret Str.292; + +procedure Test.0 (): + let Test.3 : Str = "abc"; + let Test.2 : Str = CallByName Inspect.5 Test.3; + let Test.1 : Str = CallByName Inspect.35 Test.2; + ret Test.1; diff --git a/crates/compiler/test_mono/src/tests.rs b/crates/compiler/test_mono/src/tests.rs index 0f56a1f237..465ce45f09 100644 --- a/crates/compiler/test_mono/src/tests.rs +++ b/crates/compiler/test_mono/src/tests.rs @@ -3289,3 +3289,133 @@ fn non_nullable_unwrapped_instead_of_nullable_wrapped() { "# ) } + +#[mono_test] +fn inspect_custom_type() { + indoc!( + r#" + app "test" + imports [] + provides [main] to "./platform" + + HelloWorld := {} implements [Inspect { toInspector: myToInspector }] + + myToInspector : HelloWorld -> Inspector f where f implements InspectFormatter + myToInspector = \@HellowWorld {} -> + fmt <- Inspect.custom + Inspect.apply (Inspect.str "Hello, World!\n") fmt + + main = + Inspect.inspect (@HelloWorld {}) + "# + ) +} + +#[mono_test] +fn inspect_derived_string() { + indoc!( + r#" + app "test" + imports [] + provides [main] to "./platform" + + main = Inspect.inspect "abc" |> Inspect.toDbgStr + "# + ) +} + +#[mono_test] +fn inspect_derived_record() { + indoc!( + r#" + app "test" + imports [] + provides [main] to "./platform" + + main = Inspect.inspect {a: 7, b: 3dec} |> Inspect.toDbgStr + "# + ) +} +#[mono_test] +fn inspect_derived_record_one_field_string() { + indoc!( + r#" + app "test" + imports [] + provides [main] to "./platform" + + main = Inspect.inspect {a: "foo"} |> Inspect.toDbgStr + "# + ) +} + +#[mono_test] +fn inspect_derived_record_two_field_strings() { + indoc!( + r#" + app "test" + imports [] + provides [main] to "./platform" + + main = Inspect.inspect {a: "foo", b: "bar"} |> Inspect.toDbgStr + "# + ) +} + +#[mono_test] +fn inspect_derived_nested_record_string() { + indoc!( + r#" + app "test" + imports [] + provides [main] to "./platform" + + main = Inspect.inspect {a: {b: "bar"}} |> Inspect.toDbgStr + "# + ) +} + +#[mono_test] +fn inspect_derived_tag_one_field_string() { + indoc!( + r#" + app "test" + imports [] + provides [main] to "./platform" + + main = + x : [A Str] + x = A "foo" + Inspect.inspect x |> Inspect.toDbgStr + "# + ) +} + +#[mono_test] +fn inspect_derived_tag_two_payloads_string() { + indoc!( + r#" + app "test" + imports [] + provides [main] to "./platform" + + main = + x : [A Str Str] + x = A "foo" "foo" + Inspect.inspect x |> Inspect.toDbgStr + "# + ) +} + +#[mono_test] +fn inspect_derived_list() { + indoc!( + r#" + app "test" + imports [] + provides [main] to "./platform" + + main = Inspect.inspect [1, 2, 3] |> Inspect.toDbgStr + "# + ) +} From 153b4c6df10ece8edcad375a64f12cb178323ad1 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 11:50:13 -0800 Subject: [PATCH 27/40] add walk function to list autoderive --- crates/compiler/derive/src/inspect.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/crates/compiler/derive/src/inspect.rs b/crates/compiler/derive/src/inspect.rs index 0e591a5c6d..d5cfb68962 100644 --- a/crates/compiler/derive/src/inspect.rs +++ b/crates/compiler/derive/src/inspect.rs @@ -110,9 +110,9 @@ pub(crate) fn derive_to_inspector( } fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { - // Build \lst -> Inspect.list lst (\elem -> Inspect.toInspector elem) + // Build \lst -> list, List.walk, (\elem -> Inspect.toInspector elem) // - // TODO eta reduce this baby ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + // TODO eta reduce this baby ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use Expr::*; @@ -212,9 +212,12 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { // List e, (e -> Inspector fmt) -[uls]-> Inspector fmt where fmt implements InspectorFormatter let inspect_list_fn_var = env.import_builtin_symbol_var(Symbol::INSPECT_LIST); - // List elem, to_elem_inspector_fn_var -[clos]-> t1 - let this_inspect_list_args_slice = - VariableSubsSlice::insert_into_subs(env.subs, [list_var, to_elem_inspector_fn_var]); + // List elem, List.walk, to_elem_inspector_fn_var -[clos]-> t1 + let list_walk_fn_var = env.import_builtin_symbol_var(Symbol::LIST_WALK); + let this_inspect_list_args_slice = VariableSubsSlice::insert_into_subs( + env.subs, + [list_var, list_walk_fn_var, to_elem_inspector_fn_var], + ); let this_inspect_list_clos_var = env.subs.fresh_unnamed_flex_var(); // clos let this_list_inspector_var = env.subs.fresh_unnamed_flex_var(); // t1 let this_inspect_list_fn_var = synth_var( @@ -244,6 +247,10 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { inspect_list_fn, vec![ (list_var, Loc::at_zero(Var(lst_sym, list_var))), + ( + list_walk_fn_var, + Loc::at_zero(Var(Symbol::LIST_WALK, list_walk_fn_var)), + ), (to_elem_inspector_fn_var, Loc::at_zero(to_elem_inspector)), ], CalledVia::Space, From 32c3d49e8566b6f83d49e0740d5aae38db21dc5b Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 12:06:53 -0800 Subject: [PATCH 28/40] ignore unimlemented ability test case --- crates/compiler/test_mono/src/tests.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/compiler/test_mono/src/tests.rs b/crates/compiler/test_mono/src/tests.rs index 465ce45f09..9d5874be60 100644 --- a/crates/compiler/test_mono/src/tests.rs +++ b/crates/compiler/test_mono/src/tests.rs @@ -3291,6 +3291,7 @@ fn non_nullable_unwrapped_instead_of_nullable_wrapped() { } #[mono_test] +#[ignore = "Hits an unimplemented for abilities, not sure why..."] fn inspect_custom_type() { indoc!( r#" From 79a58843b523bd5c64ea2f83b4934642c0ddc219 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 12:12:31 -0800 Subject: [PATCH 29/40] fix mono tests with wrapping custom function --- crates/compiler/builtins/roc/Inspect.roc | 2 +- .../generated/inspect_derived_list.txt | 172 +++++++++++ .../inspect_derived_nested_record_string.txt | 274 ++++++++++++++++++ .../generated/inspect_derived_record.txt | 204 +++++++++++++ ...nspect_derived_record_one_field_string.txt | 171 +++++++++++ ...spect_derived_record_two_field_strings.txt | 180 ++++++++++++ .../generated/inspect_derived_string.txt | 27 +- .../inspect_derived_tag_one_field_string.txt | 173 +++++++++++ ...nspect_derived_tag_two_payloads_string.txt | 178 ++++++++++++ 9 files changed, 1364 insertions(+), 17 deletions(-) create mode 100644 crates/compiler/test_mono/generated/inspect_derived_list.txt create mode 100644 crates/compiler/test_mono/generated/inspect_derived_nested_record_string.txt create mode 100644 crates/compiler/test_mono/generated/inspect_derived_record.txt create mode 100644 crates/compiler/test_mono/generated/inspect_derived_record_one_field_string.txt create mode 100644 crates/compiler/test_mono/generated/inspect_derived_record_two_field_strings.txt create mode 100644 crates/compiler/test_mono/generated/inspect_derived_tag_one_field_string.txt create mode 100644 crates/compiler/test_mono/generated/inspect_derived_tag_two_payloads_string.txt diff --git a/crates/compiler/builtins/roc/Inspect.roc b/crates/compiler/builtins/roc/Inspect.roc index 64a5f8fcb3..82a31f4a9d 100644 --- a/crates/compiler/builtins/roc/Inspect.roc +++ b/crates/compiler/builtins/roc/Inspect.roc @@ -86,7 +86,7 @@ InspectFormatter implements Inspector f := f -> f where f implements InspectFormatter custom : (f -> f) -> Inspector f where f implements InspectFormatter -custom = @Inspector +custom = \fn -> @Inspector fn apply : Inspector f, f -> f where f implements InspectFormatter apply = \@Inspector fn, fmt -> fn fmt diff --git a/crates/compiler/test_mono/generated/inspect_derived_list.txt b/crates/compiler/test_mono/generated/inspect_derived_list.txt new file mode 100644 index 0000000000..5b3e75d71e --- /dev/null +++ b/crates/compiler/test_mono/generated/inspect_derived_list.txt @@ -0,0 +1,172 @@ +procedure #Derived.0 (#Derived.1): + let #Derived_gen.0 : List I64 = CallByName Inspect.30 #Derived.1; + ret #Derived_gen.0; + +procedure #Derived.3 (#Derived.2): + let #Derived_gen.7 : I64 = CallByName Inspect.54 #Derived.2; + ret #Derived_gen.7; + +procedure #Derived.4 (#Derived.5, #Derived.1): + let #Derived_gen.5 : {} = Struct {}; + let #Derived_gen.6 : {} = Struct {}; + let #Derived_gen.4 : {List I64, {}, {}} = CallByName Inspect.37 #Derived.1 #Derived_gen.5 #Derived_gen.6; + let #Derived_gen.3 : Str = CallByName Inspect.31 #Derived_gen.4 #Derived.5; + ret #Derived_gen.3; + +procedure Bool.1 (): + let Bool.24 : Int1 = false; + ret Bool.24; + +procedure Bool.2 (): + let Bool.23 : Int1 = true; + ret Bool.23; + +procedure Inspect.155 (Inspect.156, #Attr.12): + let Inspect.154 : {} = StructAtIndex 2 #Attr.12; + let Inspect.153 : {} = StructAtIndex 1 #Attr.12; + let Inspect.152 : List I64 = StructAtIndex 0 #Attr.12; + let Inspect.345 : Str = "["; + let Inspect.328 : Str = CallByName Inspect.61 Inspect.156 Inspect.345; + let Inspect.329 : {List I64, {}, {}} = Struct {Inspect.152, Inspect.153, Inspect.154}; + let Inspect.324 : {Str, Int1} = CallByName Inspect.157 Inspect.328 Inspect.329; + let Inspect.325 : {} = Struct {}; + let Inspect.320 : Str = CallByName Inspect.166 Inspect.324; + let Inspect.321 : Str = "]"; + let Inspect.319 : Str = CallByName Inspect.61 Inspect.320 Inspect.321; + ret Inspect.319; + +procedure Inspect.157 (Inspect.158, #Attr.12): + let Inspect.154 : {} = StructAtIndex 2 #Attr.12; + let Inspect.153 : {} = StructAtIndex 1 #Attr.12; + let Inspect.152 : List I64 = StructAtIndex 0 #Attr.12; + let Bool.1 : Int1 = CallByName Bool.1; + let Inspect.332 : {Str, Int1} = Struct {Inspect.158, Bool.1}; + let Inspect.331 : {Str, Int1} = CallByName List.18 Inspect.152 Inspect.332 Inspect.154; + ret Inspect.331; + +procedure Inspect.159 (Inspect.334, Inspect.162, Inspect.154): + let Inspect.160 : Str = StructAtIndex 0 Inspect.334; + let Inspect.161 : Int1 = StructAtIndex 1 Inspect.334; + joinpoint Inspect.343 Inspect.163: + let Inspect.340 : I64 = CallByName #Derived.3 Inspect.162; + let Inspect.337 : Str = CallByName Inspect.31 Inspect.340 Inspect.163; + let Inspect.338 : {} = Struct {}; + let Inspect.336 : {Str, Int1} = CallByName Inspect.164 Inspect.337; + ret Inspect.336; + in + if Inspect.161 then + let Inspect.344 : Str = ", "; + let Inspect.342 : Str = CallByName Inspect.61 Inspect.160 Inspect.344; + jump Inspect.343 Inspect.342; + else + jump Inspect.343 Inspect.160; + +procedure Inspect.164 (Inspect.165): + let Bool.2 : Int1 = CallByName Bool.2; + let Inspect.339 : {Str, Int1} = Struct {Inspect.165, Bool.2}; + ret Inspect.339; + +procedure Inspect.166 (Inspect.326): + let Inspect.327 : Str = StructAtIndex 0 Inspect.326; + ret Inspect.327; + +procedure Inspect.277 (Inspect.278, Inspect.276): + let Inspect.351 : Str = CallByName Num.96 Inspect.276; + let Inspect.350 : Str = CallByName Inspect.61 Inspect.278 Inspect.351; + ret Inspect.350; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.314 : Str = CallByName Inspect.155 Inspect.149 Inspect.305; + ret Inspect.314; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.341 : Str = CallByName Inspect.277 Inspect.149 Inspect.305; + ret Inspect.341; + +procedure Inspect.35 (Inspect.300): + ret Inspect.300; + +procedure Inspect.36 (Inspect.304): + let Inspect.311 : Str = ""; + ret Inspect.311; + +procedure Inspect.37 (Inspect.152, Inspect.153, Inspect.154): + let Inspect.316 : {List I64, {}, {}} = Struct {Inspect.152, Inspect.153, Inspect.154}; + let Inspect.315 : {List I64, {}, {}} = CallByName Inspect.30 Inspect.316; + ret Inspect.315; + +procedure Inspect.5 (Inspect.150): + let Inspect.312 : List I64 = CallByName #Derived.0 Inspect.150; + let Inspect.309 : {} = Struct {}; + let Inspect.308 : Str = CallByName Inspect.36 Inspect.309; + let Inspect.307 : Str = CallByName #Derived.4 Inspect.308 Inspect.312; + ret Inspect.307; + +procedure Inspect.54 (Inspect.276): + let Inspect.346 : I64 = CallByName Inspect.30 Inspect.276; + ret Inspect.346; + +procedure Inspect.61 (Inspect.303, Inspect.298): + let Inspect.323 : Str = CallByName Str.3 Inspect.303 Inspect.298; + dec Inspect.298; + ret Inspect.323; + +procedure List.18 (List.154, List.155, List.156): + let List.554 : U64 = 0i64; + let List.555 : U64 = CallByName List.6 List.154; + let List.553 : {Str, Int1} = CallByName List.88 List.154 List.155 List.156 List.554 List.555; + ret List.553; + +procedure List.6 (#Attr.2): + let List.564 : U64 = lowlevel ListLen #Attr.2; + ret List.564; + +procedure List.66 (#Attr.2, #Attr.3): + let List.563 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3; + ret List.563; + +procedure List.88 (#Derived_gen.17, #Derived_gen.18, #Derived_gen.19, #Derived_gen.20, #Derived_gen.21): + joinpoint List.556 List.157 List.158 List.159 List.160 List.161: + let List.558 : Int1 = CallByName Num.22 List.160 List.161; + if List.558 then + let List.562 : I64 = CallByName List.66 List.157 List.160; + let List.162 : {Str, Int1} = CallByName Inspect.159 List.158 List.562 List.159; + let List.561 : U64 = 1i64; + let List.560 : U64 = CallByName Num.51 List.160 List.561; + jump List.556 List.157 List.162 List.159 List.560 List.161; + else + dec List.157; + ret List.158; + in + jump List.556 #Derived_gen.17 #Derived_gen.18 #Derived_gen.19 #Derived_gen.20 #Derived_gen.21; + +procedure Num.22 (#Attr.2, #Attr.3): + let Num.293 : Int1 = lowlevel NumLt #Attr.2 #Attr.3; + ret Num.293; + +procedure Num.51 (#Attr.2, #Attr.3): + let Num.292 : U64 = lowlevel NumAddWrap #Attr.2 #Attr.3; + ret Num.292; + +procedure Num.96 (#Attr.2): + let Num.291 : Str = lowlevel NumToStr #Attr.2; + ret Num.291; + +procedure Str.3 (#Attr.2, #Attr.3): + let Str.292 : Str = lowlevel StrConcat #Attr.2 #Attr.3; + ret Str.292; + +procedure Test.0 (): + let Test.3 : List I64 = Array [1i64, 2i64, 3i64]; + let Test.2 : Str = CallByName Inspect.5 Test.3; + let Test.1 : Str = CallByName Inspect.35 Test.2; + ret Test.1; diff --git a/crates/compiler/test_mono/generated/inspect_derived_nested_record_string.txt b/crates/compiler/test_mono/generated/inspect_derived_nested_record_string.txt new file mode 100644 index 0000000000..78d22ad7bd --- /dev/null +++ b/crates/compiler/test_mono/generated/inspect_derived_nested_record_string.txt @@ -0,0 +1,274 @@ +procedure #Derived.0 (#Derived.1): + let #Derived_gen.0 : Str = CallByName Inspect.30 #Derived.1; + ret #Derived_gen.0; + +procedure #Derived.2 (#Derived.3, #Derived.1): + let #Derived_gen.7 : Str = "a"; + let #Derived_gen.8 : Str = CallByName #Derived.4 #Derived.1; + let #Derived_gen.6 : {Str, Str} = Struct {#Derived_gen.7, #Derived_gen.8}; + let #Derived_gen.5 : List {Str, Str} = Array [#Derived_gen.6]; + let #Derived_gen.4 : List {Str, Str} = CallByName Inspect.42 #Derived_gen.5; + let #Derived_gen.3 : Str = CallByName Inspect.31 #Derived_gen.4 #Derived.3; + ret #Derived_gen.3; + +procedure #Derived.4 (#Derived.5): + let #Derived_gen.10 : Str = CallByName Inspect.30 #Derived.5; + ret #Derived_gen.10; + +procedure #Derived.6 (#Derived.7, #Derived.5): + let #Derived_gen.17 : Str = "b"; + let #Derived_gen.18 : Str = CallByName Inspect.44 #Derived.5; + let #Derived_gen.16 : {Str, Str} = Struct {#Derived_gen.17, #Derived_gen.18}; + let #Derived_gen.15 : List {Str, Str} = Array [#Derived_gen.16]; + let #Derived_gen.14 : List {Str, Str} = CallByName Inspect.42 #Derived_gen.15; + let #Derived_gen.13 : Str = CallByName Inspect.31 #Derived_gen.14 #Derived.7; + ret #Derived_gen.13; + +procedure Bool.1 (): + let Bool.26 : Int1 = false; + ret Bool.26; + +procedure Bool.2 (): + let Bool.25 : Int1 = true; + ret Bool.25; + +procedure Inspect.228 (Inspect.229, Inspect.227): + let Inspect.350 : Str = "{"; + let Inspect.328 : Str = CallByName Inspect.61 Inspect.229 Inspect.350; + let Inspect.324 : {Str, Int1} = CallByName Inspect.230 Inspect.328 Inspect.227; + let Inspect.325 : {} = Struct {}; + let Inspect.320 : Str = CallByName Inspect.242 Inspect.324; + let Inspect.321 : Str = "}"; + let Inspect.319 : Str = CallByName Inspect.61 Inspect.320 Inspect.321; + ret Inspect.319; + +procedure Inspect.228 (Inspect.229, Inspect.227): + let Inspect.388 : Str = "{"; + let Inspect.366 : Str = CallByName Inspect.61 Inspect.229 Inspect.388; + let Inspect.362 : {Str, Int1} = CallByName Inspect.230 Inspect.366 Inspect.227; + let Inspect.363 : {} = Struct {}; + let Inspect.358 : Str = CallByName Inspect.242 Inspect.362; + let Inspect.359 : Str = "}"; + let Inspect.357 : Str = CallByName Inspect.61 Inspect.358 Inspect.359; + ret Inspect.357; + +procedure Inspect.230 (Inspect.231, Inspect.227): + let Bool.1 : Int1 = CallByName Bool.1; + let Inspect.332 : {Str, Int1} = Struct {Inspect.231, Bool.1}; + let Inspect.333 : {} = Struct {}; + let Inspect.331 : {Str, Int1} = CallByName List.18 Inspect.227 Inspect.332 Inspect.333; + ret Inspect.331; + +procedure Inspect.230 (Inspect.231, Inspect.227): + let Bool.1 : Int1 = CallByName Bool.1; + let Inspect.370 : {Str, Int1} = Struct {Inspect.231, Bool.1}; + let Inspect.371 : {} = Struct {}; + let Inspect.369 : {Str, Int1} = CallByName List.18 Inspect.227 Inspect.370 Inspect.371; + ret Inspect.369; + +procedure Inspect.232 (Inspect.334, Inspect.335): + let Inspect.235 : Str = StructAtIndex 0 Inspect.335; + let Inspect.236 : Str = StructAtIndex 1 Inspect.335; + let Inspect.233 : Str = StructAtIndex 0 Inspect.334; + let Inspect.234 : Int1 = StructAtIndex 1 Inspect.334; + joinpoint Inspect.348 Inspect.237: + let Inspect.345 : Str = CallByName Inspect.61 Inspect.237 Inspect.235; + let Inspect.346 : Str = ": "; + let Inspect.340 : Str = CallByName Inspect.61 Inspect.345 Inspect.346; + let Inspect.337 : Str = CallByName Inspect.238 Inspect.340 Inspect.236; + let Inspect.338 : {} = Struct {}; + let Inspect.336 : {Str, Int1} = CallByName Inspect.240 Inspect.337; + ret Inspect.336; + in + if Inspect.234 then + let Inspect.349 : Str = ", "; + let Inspect.347 : Str = CallByName Inspect.61 Inspect.233 Inspect.349; + jump Inspect.348 Inspect.347; + else + jump Inspect.348 Inspect.233; + +procedure Inspect.232 (Inspect.334, Inspect.335): + let Inspect.235 : Str = StructAtIndex 0 Inspect.335; + let Inspect.236 : Str = StructAtIndex 1 Inspect.335; + let Inspect.233 : Str = StructAtIndex 0 Inspect.334; + let Inspect.234 : Int1 = StructAtIndex 1 Inspect.334; + joinpoint Inspect.386 Inspect.237: + let Inspect.383 : Str = CallByName Inspect.61 Inspect.237 Inspect.235; + let Inspect.384 : Str = ": "; + let Inspect.378 : Str = CallByName Inspect.61 Inspect.383 Inspect.384; + let Inspect.375 : Str = CallByName Inspect.238 Inspect.378 Inspect.236; + let Inspect.376 : {} = Struct {}; + let Inspect.374 : {Str, Int1} = CallByName Inspect.240 Inspect.375; + ret Inspect.374; + in + if Inspect.234 then + let Inspect.387 : Str = ", "; + let Inspect.385 : Str = CallByName Inspect.61 Inspect.233 Inspect.387; + jump Inspect.386 Inspect.385; + else + jump Inspect.386 Inspect.233; + +procedure Inspect.238 (Inspect.239, Inspect.236): + let Inspect.343 : Str = CallByName Inspect.31 Inspect.236 Inspect.239; + ret Inspect.343; + +procedure Inspect.238 (Inspect.239, Inspect.236): + let Inspect.381 : Str = CallByName Inspect.31 Inspect.236 Inspect.239; + ret Inspect.381; + +procedure Inspect.240 (Inspect.241): + let Bool.2 : Int1 = CallByName Bool.2; + let Inspect.377 : {Str, Int1} = Struct {Inspect.241, Bool.2}; + ret Inspect.377; + +procedure Inspect.242 (Inspect.326): + let Inspect.365 : Str = StructAtIndex 0 Inspect.326; + ret Inspect.365; + +procedure Inspect.249 (Inspect.250, Inspect.248): + let Inspect.397 : Str = "\""; + let Inspect.396 : Str = CallByName Inspect.61 Inspect.250 Inspect.397; + let Inspect.394 : Str = CallByName Inspect.61 Inspect.396 Inspect.248; + let Inspect.395 : Str = "\""; + let Inspect.393 : Str = CallByName Inspect.61 Inspect.394 Inspect.395; + ret Inspect.393; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.314 : Str = CallByName Inspect.228 Inspect.149 Inspect.305; + ret Inspect.314; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.344 : Str = CallByName #Derived.6 Inspect.149 Inspect.305; + ret Inspect.344; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.352 : Str = CallByName Inspect.228 Inspect.149 Inspect.305; + ret Inspect.352; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.382 : Str = CallByName Inspect.249 Inspect.149 Inspect.305; + ret Inspect.382; + +procedure Inspect.35 (Inspect.300): + ret Inspect.300; + +procedure Inspect.36 (Inspect.304): + let Inspect.311 : Str = ""; + ret Inspect.311; + +procedure Inspect.42 (Inspect.227): + let Inspect.315 : List {Str, Str} = CallByName Inspect.30 Inspect.227; + ret Inspect.315; + +procedure Inspect.42 (Inspect.227): + let Inspect.353 : List {Str, Str} = CallByName Inspect.30 Inspect.227; + ret Inspect.353; + +procedure Inspect.44 (Inspect.248): + let Inspect.389 : Str = CallByName Inspect.30 Inspect.248; + ret Inspect.389; + +procedure Inspect.5 (Inspect.150): + let Inspect.312 : Str = CallByName #Derived.0 Inspect.150; + let Inspect.309 : {} = Struct {}; + let Inspect.308 : Str = CallByName Inspect.36 Inspect.309; + let Inspect.307 : Str = CallByName #Derived.2 Inspect.308 Inspect.312; + ret Inspect.307; + +procedure Inspect.61 (Inspect.303, Inspect.298): + let Inspect.361 : Str = CallByName Str.3 Inspect.303 Inspect.298; + dec Inspect.298; + ret Inspect.361; + +procedure List.18 (List.154, List.155, List.156): + let List.554 : U64 = 0i64; + let List.555 : U64 = CallByName List.6 List.154; + let List.553 : {Str, Int1} = CallByName List.88 List.154 List.155 List.156 List.554 List.555; + ret List.553; + +procedure List.18 (List.154, List.155, List.156): + let List.566 : U64 = 0i64; + let List.567 : U64 = CallByName List.6 List.154; + let List.565 : {Str, Int1} = CallByName List.88 List.154 List.155 List.156 List.566 List.567; + ret List.565; + +procedure List.6 (#Attr.2): + let List.564 : U64 = lowlevel ListLen #Attr.2; + ret List.564; + +procedure List.6 (#Attr.2): + let List.576 : U64 = lowlevel ListLen #Attr.2; + ret List.576; + +procedure List.66 (#Attr.2, #Attr.3): + let List.563 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3; + ret List.563; + +procedure List.66 (#Attr.2, #Attr.3): + let List.575 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3; + ret List.575; + +procedure List.88 (#Derived_gen.30, #Derived_gen.31, #Derived_gen.32, #Derived_gen.33, #Derived_gen.34): + joinpoint List.568 List.157 List.158 List.159 List.160 List.161: + let List.570 : Int1 = CallByName Num.22 List.160 List.161; + if List.570 then + let List.574 : {Str, Str} = CallByName List.66 List.157 List.160; + inc List.574; + let List.162 : {Str, Int1} = CallByName Inspect.232 List.158 List.574; + let List.573 : U64 = 1i64; + let List.572 : U64 = CallByName Num.51 List.160 List.573; + jump List.568 List.157 List.162 List.159 List.572 List.161; + else + dec List.157; + ret List.158; + in + jump List.568 #Derived_gen.30 #Derived_gen.31 #Derived_gen.32 #Derived_gen.33 #Derived_gen.34; + +procedure List.88 (#Derived_gen.41, #Derived_gen.42, #Derived_gen.43, #Derived_gen.44, #Derived_gen.45): + joinpoint List.556 List.157 List.158 List.159 List.160 List.161: + let List.558 : Int1 = CallByName Num.22 List.160 List.161; + if List.558 then + let List.562 : {Str, Str} = CallByName List.66 List.157 List.160; + inc List.562; + let List.162 : {Str, Int1} = CallByName Inspect.232 List.158 List.562; + let List.561 : U64 = 1i64; + let List.560 : U64 = CallByName Num.51 List.160 List.561; + jump List.556 List.157 List.162 List.159 List.560 List.161; + else + dec List.157; + ret List.158; + in + jump List.556 #Derived_gen.41 #Derived_gen.42 #Derived_gen.43 #Derived_gen.44 #Derived_gen.45; + +procedure Num.22 (#Attr.2, #Attr.3): + let Num.294 : Int1 = lowlevel NumLt #Attr.2 #Attr.3; + ret Num.294; + +procedure Num.51 (#Attr.2, #Attr.3): + let Num.293 : U64 = lowlevel NumAddWrap #Attr.2 #Attr.3; + ret Num.293; + +procedure Str.3 (#Attr.2, #Attr.3): + let Str.293 : Str = lowlevel StrConcat #Attr.2 #Attr.3; + ret Str.293; + +procedure Test.0 (): + let Test.5 : Str = "bar"; + let Test.2 : Str = CallByName Inspect.5 Test.5; + let Test.1 : Str = CallByName Inspect.35 Test.2; + ret Test.1; diff --git a/crates/compiler/test_mono/generated/inspect_derived_record.txt b/crates/compiler/test_mono/generated/inspect_derived_record.txt new file mode 100644 index 0000000000..99d70d6962 --- /dev/null +++ b/crates/compiler/test_mono/generated/inspect_derived_record.txt @@ -0,0 +1,204 @@ +procedure #Derived.0 (#Derived.1): + let #Derived_gen.0 : {Decimal, I64} = CallByName Inspect.30 #Derived.1; + ret #Derived_gen.0; + +procedure #Derived.2 (#Derived.3, #Derived.1): + let #Derived_gen.13 : I64 = StructAtIndex 1 #Derived.1; + let #Derived_gen.11 : [C I64, C Decimal] = CallByName Inspect.54 #Derived_gen.13; + let #Derived_gen.12 : Str = "a"; + let #Derived_gen.6 : {[C I64, C Decimal], Str} = Struct {#Derived_gen.11, #Derived_gen.12}; + let #Derived_gen.10 : Decimal = StructAtIndex 0 #Derived.1; + let #Derived_gen.8 : [C I64, C Decimal] = CallByName Inspect.60 #Derived_gen.10; + let #Derived_gen.9 : Str = "b"; + let #Derived_gen.7 : {[C I64, C Decimal], Str} = Struct {#Derived_gen.8, #Derived_gen.9}; + let #Derived_gen.5 : List {[C I64, C Decimal], Str} = Array [#Derived_gen.6, #Derived_gen.7]; + let #Derived_gen.4 : List {[C I64, C Decimal], Str} = CallByName Inspect.42 #Derived_gen.5; + let #Derived_gen.3 : Str = CallByName Inspect.31 #Derived_gen.4 #Derived.3; + ret #Derived_gen.3; + +procedure Bool.1 (): + let Bool.24 : Int1 = false; + ret Bool.24; + +procedure Bool.2 (): + let Bool.23 : Int1 = true; + ret Bool.23; + +procedure Inspect.228 (Inspect.229, Inspect.227): + let Inspect.351 : Str = "{"; + let Inspect.328 : Str = CallByName Inspect.61 Inspect.229 Inspect.351; + let Inspect.324 : {Str, Int1} = CallByName Inspect.230 Inspect.328 Inspect.227; + let Inspect.325 : {} = Struct {}; + let Inspect.320 : Str = CallByName Inspect.242 Inspect.324; + let Inspect.321 : Str = "}"; + let Inspect.319 : Str = CallByName Inspect.61 Inspect.320 Inspect.321; + ret Inspect.319; + +procedure Inspect.230 (Inspect.231, Inspect.227): + let Bool.1 : Int1 = CallByName Bool.1; + let Inspect.332 : {Str, Int1} = Struct {Inspect.231, Bool.1}; + let Inspect.333 : {} = Struct {}; + let Inspect.331 : {Str, Int1} = CallByName List.18 Inspect.227 Inspect.332 Inspect.333; + ret Inspect.331; + +procedure Inspect.232 (Inspect.334, Inspect.335): + let Inspect.236 : [C I64, C Decimal] = StructAtIndex 0 Inspect.335; + let Inspect.235 : Str = StructAtIndex 1 Inspect.335; + let Inspect.233 : Str = StructAtIndex 0 Inspect.334; + let Inspect.234 : Int1 = StructAtIndex 1 Inspect.334; + joinpoint Inspect.349 Inspect.237: + let Inspect.346 : Str = CallByName Inspect.61 Inspect.237 Inspect.235; + let Inspect.347 : Str = ": "; + let Inspect.340 : Str = CallByName Inspect.61 Inspect.346 Inspect.347; + let Inspect.337 : Str = CallByName Inspect.238 Inspect.340 Inspect.236; + let Inspect.338 : {} = Struct {}; + let Inspect.336 : {Str, Int1} = CallByName Inspect.240 Inspect.337; + ret Inspect.336; + in + if Inspect.234 then + let Inspect.350 : Str = ", "; + let Inspect.348 : Str = CallByName Inspect.61 Inspect.233 Inspect.350; + jump Inspect.349 Inspect.348; + else + jump Inspect.349 Inspect.233; + +procedure Inspect.238 (Inspect.239, Inspect.236): + let Inspect.343 : Str = CallByName Inspect.31 Inspect.236 Inspect.239; + ret Inspect.343; + +procedure Inspect.240 (Inspect.241): + let Bool.2 : Int1 = CallByName Bool.2; + let Inspect.339 : {Str, Int1} = Struct {Inspect.241, Bool.2}; + ret Inspect.339; + +procedure Inspect.242 (Inspect.326): + let Inspect.327 : Str = StructAtIndex 0 Inspect.326; + ret Inspect.327; + +procedure Inspect.277 (Inspect.278, #Attr.12): + let Inspect.364 : I64 = UnionAtIndex (Id 0) (Index 0) #Attr.12; + let Inspect.363 : Str = CallByName Num.96 Inspect.364; + let Inspect.362 : Str = CallByName Inspect.61 Inspect.278 Inspect.363; + ret Inspect.362; + +procedure Inspect.295 (Inspect.296, #Attr.12): + let Inspect.358 : Decimal = UnionAtIndex (Id 1) (Index 0) #Attr.12; + let Inspect.357 : Str = CallByName Num.96 Inspect.358; + let Inspect.356 : Str = CallByName Inspect.61 Inspect.296 Inspect.357; + ret Inspect.356; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.314 : Str = CallByName Inspect.228 Inspect.149 Inspect.305; + ret Inspect.314; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.345 : U8 = GetTagId Inspect.305; + switch Inspect.345: + case 0: + let Inspect.344 : Str = CallByName Inspect.277 Inspect.149 Inspect.305; + ret Inspect.344; + + default: + let Inspect.344 : Str = CallByName Inspect.295 Inspect.149 Inspect.305; + ret Inspect.344; + + +procedure Inspect.35 (Inspect.300): + ret Inspect.300; + +procedure Inspect.36 (Inspect.304): + let Inspect.311 : Str = ""; + ret Inspect.311; + +procedure Inspect.42 (Inspect.227): + let Inspect.315 : List {[C I64, C Decimal], Str} = CallByName Inspect.30 Inspect.227; + ret Inspect.315; + +procedure Inspect.5 (Inspect.150): + let Inspect.312 : {Decimal, I64} = CallByName #Derived.0 Inspect.150; + let Inspect.309 : {} = Struct {}; + let Inspect.308 : Str = CallByName Inspect.36 Inspect.309; + let Inspect.307 : Str = CallByName #Derived.2 Inspect.308 Inspect.312; + ret Inspect.307; + +procedure Inspect.54 (Inspect.276): + let Inspect.360 : [C I64, C Decimal] = TagId(0) Inspect.276; + let Inspect.359 : [C I64, C Decimal] = CallByName Inspect.30 Inspect.360; + ret Inspect.359; + +procedure Inspect.60 (Inspect.294): + let Inspect.353 : [C I64, C Decimal] = TagId(1) Inspect.294; + let Inspect.352 : [C I64, C Decimal] = CallByName Inspect.30 Inspect.353; + ret Inspect.352; + +procedure Inspect.61 (Inspect.303, Inspect.298): + let Inspect.323 : Str = CallByName Str.3 Inspect.303 Inspect.298; + dec Inspect.298; + ret Inspect.323; + +procedure List.18 (List.154, List.155, List.156): + let List.554 : U64 = 0i64; + let List.555 : U64 = CallByName List.6 List.154; + let List.553 : {Str, Int1} = CallByName List.88 List.154 List.155 List.156 List.554 List.555; + ret List.553; + +procedure List.6 (#Attr.2): + let List.564 : U64 = lowlevel ListLen #Attr.2; + ret List.564; + +procedure List.66 (#Attr.2, #Attr.3): + let List.563 : {[C I64, C Decimal], Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3; + ret List.563; + +procedure List.88 (#Derived_gen.14, #Derived_gen.15, #Derived_gen.16, #Derived_gen.17, #Derived_gen.18): + joinpoint List.556 List.157 List.158 List.159 List.160 List.161: + let List.558 : Int1 = CallByName Num.22 List.160 List.161; + if List.558 then + let List.562 : {[C I64, C Decimal], Str} = CallByName List.66 List.157 List.160; + inc List.562; + let List.162 : {Str, Int1} = CallByName Inspect.232 List.158 List.562; + let List.561 : U64 = 1i64; + let List.560 : U64 = CallByName Num.51 List.160 List.561; + jump List.556 List.157 List.162 List.159 List.560 List.161; + else + dec List.157; + ret List.158; + in + jump List.556 #Derived_gen.14 #Derived_gen.15 #Derived_gen.16 #Derived_gen.17 #Derived_gen.18; + +procedure Num.22 (#Attr.2, #Attr.3): + let Num.294 : Int1 = lowlevel NumLt #Attr.2 #Attr.3; + ret Num.294; + +procedure Num.51 (#Attr.2, #Attr.3): + let Num.293 : U64 = lowlevel NumAddWrap #Attr.2 #Attr.3; + ret Num.293; + +procedure Num.96 (#Attr.2): + let Num.291 : Str = lowlevel NumToStr #Attr.2; + ret Num.291; + +procedure Num.96 (#Attr.2): + let Num.292 : Str = lowlevel NumToStr #Attr.2; + ret Num.292; + +procedure Str.3 (#Attr.2, #Attr.3): + let Str.292 : Str = lowlevel StrConcat #Attr.2 #Attr.3; + ret Str.292; + +procedure Test.0 (): + let Test.4 : Decimal = 3dec; + let Test.5 : I64 = 7i64; + let Test.3 : {Decimal, I64} = Struct {Test.4, Test.5}; + let Test.2 : Str = CallByName Inspect.5 Test.3; + let Test.1 : Str = CallByName Inspect.35 Test.2; + ret Test.1; diff --git a/crates/compiler/test_mono/generated/inspect_derived_record_one_field_string.txt b/crates/compiler/test_mono/generated/inspect_derived_record_one_field_string.txt new file mode 100644 index 0000000000..39c0982982 --- /dev/null +++ b/crates/compiler/test_mono/generated/inspect_derived_record_one_field_string.txt @@ -0,0 +1,171 @@ +procedure #Derived.0 (#Derived.1): + let #Derived_gen.0 : Str = CallByName Inspect.30 #Derived.1; + ret #Derived_gen.0; + +procedure #Derived.2 (#Derived.3, #Derived.1): + let #Derived_gen.7 : Str = "a"; + let #Derived_gen.8 : Str = CallByName Inspect.44 #Derived.1; + let #Derived_gen.6 : {Str, Str} = Struct {#Derived_gen.7, #Derived_gen.8}; + let #Derived_gen.5 : List {Str, Str} = Array [#Derived_gen.6]; + let #Derived_gen.4 : List {Str, Str} = CallByName Inspect.42 #Derived_gen.5; + let #Derived_gen.3 : Str = CallByName Inspect.31 #Derived_gen.4 #Derived.3; + ret #Derived_gen.3; + +procedure Bool.1 (): + let Bool.24 : Int1 = false; + ret Bool.24; + +procedure Bool.2 (): + let Bool.23 : Int1 = true; + ret Bool.23; + +procedure Inspect.228 (Inspect.229, Inspect.227): + let Inspect.350 : Str = "{"; + let Inspect.328 : Str = CallByName Inspect.61 Inspect.229 Inspect.350; + let Inspect.324 : {Str, Int1} = CallByName Inspect.230 Inspect.328 Inspect.227; + let Inspect.325 : {} = Struct {}; + let Inspect.320 : Str = CallByName Inspect.242 Inspect.324; + let Inspect.321 : Str = "}"; + let Inspect.319 : Str = CallByName Inspect.61 Inspect.320 Inspect.321; + ret Inspect.319; + +procedure Inspect.230 (Inspect.231, Inspect.227): + let Bool.1 : Int1 = CallByName Bool.1; + let Inspect.332 : {Str, Int1} = Struct {Inspect.231, Bool.1}; + let Inspect.333 : {} = Struct {}; + let Inspect.331 : {Str, Int1} = CallByName List.18 Inspect.227 Inspect.332 Inspect.333; + ret Inspect.331; + +procedure Inspect.232 (Inspect.334, Inspect.335): + let Inspect.235 : Str = StructAtIndex 0 Inspect.335; + let Inspect.236 : Str = StructAtIndex 1 Inspect.335; + let Inspect.233 : Str = StructAtIndex 0 Inspect.334; + let Inspect.234 : Int1 = StructAtIndex 1 Inspect.334; + joinpoint Inspect.348 Inspect.237: + let Inspect.345 : Str = CallByName Inspect.61 Inspect.237 Inspect.235; + let Inspect.346 : Str = ": "; + let Inspect.340 : Str = CallByName Inspect.61 Inspect.345 Inspect.346; + let Inspect.337 : Str = CallByName Inspect.238 Inspect.340 Inspect.236; + let Inspect.338 : {} = Struct {}; + let Inspect.336 : {Str, Int1} = CallByName Inspect.240 Inspect.337; + ret Inspect.336; + in + if Inspect.234 then + let Inspect.349 : Str = ", "; + let Inspect.347 : Str = CallByName Inspect.61 Inspect.233 Inspect.349; + jump Inspect.348 Inspect.347; + else + jump Inspect.348 Inspect.233; + +procedure Inspect.238 (Inspect.239, Inspect.236): + let Inspect.343 : Str = CallByName Inspect.31 Inspect.236 Inspect.239; + ret Inspect.343; + +procedure Inspect.240 (Inspect.241): + let Bool.2 : Int1 = CallByName Bool.2; + let Inspect.339 : {Str, Int1} = Struct {Inspect.241, Bool.2}; + ret Inspect.339; + +procedure Inspect.242 (Inspect.326): + let Inspect.327 : Str = StructAtIndex 0 Inspect.326; + ret Inspect.327; + +procedure Inspect.249 (Inspect.250, Inspect.248): + let Inspect.359 : Str = "\""; + let Inspect.358 : Str = CallByName Inspect.61 Inspect.250 Inspect.359; + let Inspect.356 : Str = CallByName Inspect.61 Inspect.358 Inspect.248; + let Inspect.357 : Str = "\""; + let Inspect.355 : Str = CallByName Inspect.61 Inspect.356 Inspect.357; + ret Inspect.355; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.314 : Str = CallByName Inspect.228 Inspect.149 Inspect.305; + ret Inspect.314; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.344 : Str = CallByName Inspect.249 Inspect.149 Inspect.305; + ret Inspect.344; + +procedure Inspect.35 (Inspect.300): + ret Inspect.300; + +procedure Inspect.36 (Inspect.304): + let Inspect.311 : Str = ""; + ret Inspect.311; + +procedure Inspect.42 (Inspect.227): + let Inspect.315 : List {Str, Str} = CallByName Inspect.30 Inspect.227; + ret Inspect.315; + +procedure Inspect.44 (Inspect.248): + let Inspect.351 : Str = CallByName Inspect.30 Inspect.248; + ret Inspect.351; + +procedure Inspect.5 (Inspect.150): + let Inspect.312 : Str = CallByName #Derived.0 Inspect.150; + let Inspect.309 : {} = Struct {}; + let Inspect.308 : Str = CallByName Inspect.36 Inspect.309; + let Inspect.307 : Str = CallByName #Derived.2 Inspect.308 Inspect.312; + ret Inspect.307; + +procedure Inspect.61 (Inspect.303, Inspect.298): + let Inspect.323 : Str = CallByName Str.3 Inspect.303 Inspect.298; + dec Inspect.298; + ret Inspect.323; + +procedure List.18 (List.154, List.155, List.156): + let List.554 : U64 = 0i64; + let List.555 : U64 = CallByName List.6 List.154; + let List.553 : {Str, Int1} = CallByName List.88 List.154 List.155 List.156 List.554 List.555; + ret List.553; + +procedure List.6 (#Attr.2): + let List.564 : U64 = lowlevel ListLen #Attr.2; + ret List.564; + +procedure List.66 (#Attr.2, #Attr.3): + let List.563 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3; + ret List.563; + +procedure List.88 (#Derived_gen.14, #Derived_gen.15, #Derived_gen.16, #Derived_gen.17, #Derived_gen.18): + joinpoint List.556 List.157 List.158 List.159 List.160 List.161: + let List.558 : Int1 = CallByName Num.22 List.160 List.161; + if List.558 then + let List.562 : {Str, Str} = CallByName List.66 List.157 List.160; + inc List.562; + let List.162 : {Str, Int1} = CallByName Inspect.232 List.158 List.562; + let List.561 : U64 = 1i64; + let List.560 : U64 = CallByName Num.51 List.160 List.561; + jump List.556 List.157 List.162 List.159 List.560 List.161; + else + dec List.157; + ret List.158; + in + jump List.556 #Derived_gen.14 #Derived_gen.15 #Derived_gen.16 #Derived_gen.17 #Derived_gen.18; + +procedure Num.22 (#Attr.2, #Attr.3): + let Num.292 : Int1 = lowlevel NumLt #Attr.2 #Attr.3; + ret Num.292; + +procedure Num.51 (#Attr.2, #Attr.3): + let Num.291 : U64 = lowlevel NumAddWrap #Attr.2 #Attr.3; + ret Num.291; + +procedure Str.3 (#Attr.2, #Attr.3): + let Str.292 : Str = lowlevel StrConcat #Attr.2 #Attr.3; + ret Str.292; + +procedure Test.0 (): + let Test.4 : Str = "foo"; + let Test.2 : Str = CallByName Inspect.5 Test.4; + let Test.1 : Str = CallByName Inspect.35 Test.2; + ret Test.1; diff --git a/crates/compiler/test_mono/generated/inspect_derived_record_two_field_strings.txt b/crates/compiler/test_mono/generated/inspect_derived_record_two_field_strings.txt new file mode 100644 index 0000000000..224e8b36e0 --- /dev/null +++ b/crates/compiler/test_mono/generated/inspect_derived_record_two_field_strings.txt @@ -0,0 +1,180 @@ +procedure #Derived.0 (#Derived.1): + let #Derived_gen.0 : {Str, Str} = CallByName Inspect.30 #Derived.1; + ret #Derived_gen.0; + +procedure #Derived.2 (#Derived.3, #Derived.1): + let #Derived_gen.11 : Str = "a"; + let #Derived_gen.13 : Str = StructAtIndex 0 #Derived.1; + inc #Derived_gen.13; + let #Derived_gen.12 : Str = CallByName Inspect.44 #Derived_gen.13; + let #Derived_gen.6 : {Str, Str} = Struct {#Derived_gen.11, #Derived_gen.12}; + let #Derived_gen.8 : Str = "b"; + let #Derived_gen.10 : Str = StructAtIndex 1 #Derived.1; + dec #Derived_gen.13; + let #Derived_gen.9 : Str = CallByName Inspect.44 #Derived_gen.10; + let #Derived_gen.7 : {Str, Str} = Struct {#Derived_gen.8, #Derived_gen.9}; + let #Derived_gen.5 : List {Str, Str} = Array [#Derived_gen.6, #Derived_gen.7]; + let #Derived_gen.4 : List {Str, Str} = CallByName Inspect.42 #Derived_gen.5; + let #Derived_gen.3 : Str = CallByName Inspect.31 #Derived_gen.4 #Derived.3; + ret #Derived_gen.3; + +procedure Bool.1 (): + let Bool.24 : Int1 = false; + ret Bool.24; + +procedure Bool.2 (): + let Bool.23 : Int1 = true; + ret Bool.23; + +procedure Inspect.228 (Inspect.229, Inspect.227): + let Inspect.350 : Str = "{"; + let Inspect.328 : Str = CallByName Inspect.61 Inspect.229 Inspect.350; + let Inspect.324 : {Str, Int1} = CallByName Inspect.230 Inspect.328 Inspect.227; + let Inspect.325 : {} = Struct {}; + let Inspect.320 : Str = CallByName Inspect.242 Inspect.324; + let Inspect.321 : Str = "}"; + let Inspect.319 : Str = CallByName Inspect.61 Inspect.320 Inspect.321; + ret Inspect.319; + +procedure Inspect.230 (Inspect.231, Inspect.227): + let Bool.1 : Int1 = CallByName Bool.1; + let Inspect.332 : {Str, Int1} = Struct {Inspect.231, Bool.1}; + let Inspect.333 : {} = Struct {}; + let Inspect.331 : {Str, Int1} = CallByName List.18 Inspect.227 Inspect.332 Inspect.333; + ret Inspect.331; + +procedure Inspect.232 (Inspect.334, Inspect.335): + let Inspect.235 : Str = StructAtIndex 0 Inspect.335; + let Inspect.236 : Str = StructAtIndex 1 Inspect.335; + let Inspect.233 : Str = StructAtIndex 0 Inspect.334; + let Inspect.234 : Int1 = StructAtIndex 1 Inspect.334; + joinpoint Inspect.348 Inspect.237: + let Inspect.345 : Str = CallByName Inspect.61 Inspect.237 Inspect.235; + let Inspect.346 : Str = ": "; + let Inspect.340 : Str = CallByName Inspect.61 Inspect.345 Inspect.346; + let Inspect.337 : Str = CallByName Inspect.238 Inspect.340 Inspect.236; + let Inspect.338 : {} = Struct {}; + let Inspect.336 : {Str, Int1} = CallByName Inspect.240 Inspect.337; + ret Inspect.336; + in + if Inspect.234 then + let Inspect.349 : Str = ", "; + let Inspect.347 : Str = CallByName Inspect.61 Inspect.233 Inspect.349; + jump Inspect.348 Inspect.347; + else + jump Inspect.348 Inspect.233; + +procedure Inspect.238 (Inspect.239, Inspect.236): + let Inspect.343 : Str = CallByName Inspect.31 Inspect.236 Inspect.239; + ret Inspect.343; + +procedure Inspect.240 (Inspect.241): + let Bool.2 : Int1 = CallByName Bool.2; + let Inspect.339 : {Str, Int1} = Struct {Inspect.241, Bool.2}; + ret Inspect.339; + +procedure Inspect.242 (Inspect.326): + let Inspect.327 : Str = StructAtIndex 0 Inspect.326; + ret Inspect.327; + +procedure Inspect.249 (Inspect.250, Inspect.248): + let Inspect.359 : Str = "\""; + let Inspect.358 : Str = CallByName Inspect.61 Inspect.250 Inspect.359; + let Inspect.356 : Str = CallByName Inspect.61 Inspect.358 Inspect.248; + let Inspect.357 : Str = "\""; + let Inspect.355 : Str = CallByName Inspect.61 Inspect.356 Inspect.357; + ret Inspect.355; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.314 : Str = CallByName Inspect.228 Inspect.149 Inspect.305; + ret Inspect.314; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.344 : Str = CallByName Inspect.249 Inspect.149 Inspect.305; + ret Inspect.344; + +procedure Inspect.35 (Inspect.300): + ret Inspect.300; + +procedure Inspect.36 (Inspect.304): + let Inspect.311 : Str = ""; + ret Inspect.311; + +procedure Inspect.42 (Inspect.227): + let Inspect.315 : List {Str, Str} = CallByName Inspect.30 Inspect.227; + ret Inspect.315; + +procedure Inspect.44 (Inspect.248): + let Inspect.360 : Str = CallByName Inspect.30 Inspect.248; + ret Inspect.360; + +procedure Inspect.5 (Inspect.150): + let Inspect.312 : {Str, Str} = CallByName #Derived.0 Inspect.150; + let Inspect.309 : {} = Struct {}; + let Inspect.308 : Str = CallByName Inspect.36 Inspect.309; + let Inspect.307 : Str = CallByName #Derived.2 Inspect.308 Inspect.312; + ret Inspect.307; + +procedure Inspect.61 (Inspect.303, Inspect.298): + let Inspect.323 : Str = CallByName Str.3 Inspect.303 Inspect.298; + dec Inspect.298; + ret Inspect.323; + +procedure List.18 (List.154, List.155, List.156): + let List.554 : U64 = 0i64; + let List.555 : U64 = CallByName List.6 List.154; + let List.553 : {Str, Int1} = CallByName List.88 List.154 List.155 List.156 List.554 List.555; + ret List.553; + +procedure List.6 (#Attr.2): + let List.564 : U64 = lowlevel ListLen #Attr.2; + ret List.564; + +procedure List.66 (#Attr.2, #Attr.3): + let List.563 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3; + ret List.563; + +procedure List.88 (#Derived_gen.18, #Derived_gen.19, #Derived_gen.20, #Derived_gen.21, #Derived_gen.22): + joinpoint List.556 List.157 List.158 List.159 List.160 List.161: + let List.558 : Int1 = CallByName Num.22 List.160 List.161; + if List.558 then + let List.562 : {Str, Str} = CallByName List.66 List.157 List.160; + inc List.562; + let List.162 : {Str, Int1} = CallByName Inspect.232 List.158 List.562; + let List.561 : U64 = 1i64; + let List.560 : U64 = CallByName Num.51 List.160 List.561; + jump List.556 List.157 List.162 List.159 List.560 List.161; + else + dec List.157; + ret List.158; + in + jump List.556 #Derived_gen.18 #Derived_gen.19 #Derived_gen.20 #Derived_gen.21 #Derived_gen.22; + +procedure Num.22 (#Attr.2, #Attr.3): + let Num.292 : Int1 = lowlevel NumLt #Attr.2 #Attr.3; + ret Num.292; + +procedure Num.51 (#Attr.2, #Attr.3): + let Num.291 : U64 = lowlevel NumAddWrap #Attr.2 #Attr.3; + ret Num.291; + +procedure Str.3 (#Attr.2, #Attr.3): + let Str.292 : Str = lowlevel StrConcat #Attr.2 #Attr.3; + ret Str.292; + +procedure Test.0 (): + let Test.4 : Str = "foo"; + let Test.5 : Str = "bar"; + let Test.3 : {Str, Str} = Struct {Test.4, Test.5}; + let Test.2 : Str = CallByName Inspect.5 Test.3; + let Test.1 : Str = CallByName Inspect.35 Test.2; + ret Test.1; diff --git a/crates/compiler/test_mono/generated/inspect_derived_string.txt b/crates/compiler/test_mono/generated/inspect_derived_string.txt index de39b613e0..8b22e27efe 100644 --- a/crates/compiler/test_mono/generated/inspect_derived_string.txt +++ b/crates/compiler/test_mono/generated/inspect_derived_string.txt @@ -1,17 +1,13 @@ -procedure Inspect.147 (Inspect.317): +procedure Inspect.249 (Inspect.250, Inspect.248): + let Inspect.323 : Str = "\""; + let Inspect.322 : Str = CallByName Inspect.61 Inspect.250 Inspect.323; + let Inspect.318 : Str = CallByName Inspect.61 Inspect.322 Inspect.248; + let Inspect.319 : Str = "\""; + let Inspect.317 : Str = CallByName Inspect.61 Inspect.318 Inspect.319; ret Inspect.317; -procedure Inspect.249 (Inspect.250, Inspect.248): - let Inspect.326 : Str = "\""; - let Inspect.325 : Str = CallByName Inspect.61 Inspect.250 Inspect.326; - let Inspect.321 : Str = CallByName Inspect.61 Inspect.325 Inspect.248; - let Inspect.322 : Str = "\""; - let Inspect.320 : Str = CallByName Inspect.61 Inspect.321 Inspect.322; - ret Inspect.320; - -procedure Inspect.30 (): - let Inspect.316 : {} = Struct {}; - ret Inspect.316; +procedure Inspect.30 (Inspect.147): + ret Inspect.147; procedure Inspect.35 (Inspect.300): ret Inspect.300; @@ -21,8 +17,7 @@ procedure Inspect.36 (Inspect.304): ret Inspect.311; procedure Inspect.44 (Inspect.248): - let Inspect.314 : {} = CallByName Inspect.30; - let Inspect.313 : Str = CallByName Inspect.147 Inspect.248; + let Inspect.313 : Str = CallByName Inspect.30 Inspect.248; ret Inspect.313; procedure Inspect.5 (Inspect.150): @@ -33,9 +28,9 @@ procedure Inspect.5 (Inspect.150): ret Inspect.307; procedure Inspect.61 (Inspect.303, Inspect.298): - let Inspect.324 : Str = CallByName Str.3 Inspect.303 Inspect.298; + let Inspect.321 : Str = CallByName Str.3 Inspect.303 Inspect.298; dec Inspect.298; - ret Inspect.324; + ret Inspect.321; procedure Str.3 (#Attr.2, #Attr.3): let Str.292 : Str = lowlevel StrConcat #Attr.2 #Attr.3; diff --git a/crates/compiler/test_mono/generated/inspect_derived_tag_one_field_string.txt b/crates/compiler/test_mono/generated/inspect_derived_tag_one_field_string.txt new file mode 100644 index 0000000000..6f59ae05e1 --- /dev/null +++ b/crates/compiler/test_mono/generated/inspect_derived_tag_one_field_string.txt @@ -0,0 +1,173 @@ +procedure #Derived.0 (#Derived.1): + let #Derived_gen.0 : Str = CallByName Inspect.30 #Derived.1; + ret #Derived_gen.0; + +procedure #Derived.3 (#Derived.4, #Derived.1): + joinpoint #Derived_gen.5 #Derived_gen.4: + let #Derived_gen.3 : Str = CallByName Inspect.31 #Derived_gen.4 #Derived.4; + ret #Derived_gen.3; + in + let #Derived_gen.7 : Str = "A"; + let #Derived_gen.9 : Str = CallByName Inspect.44 #Derived.1; + let #Derived_gen.8 : List Str = Array [#Derived_gen.9]; + let #Derived_gen.6 : [C Str, C Str List Str] = CallByName Inspect.40 #Derived_gen.7 #Derived_gen.8; + jump #Derived_gen.5 #Derived_gen.6; + +procedure Bool.11 (#Attr.2, #Attr.3): + let Bool.23 : Int1 = lowlevel Eq #Attr.2 #Attr.3; + ret Bool.23; + +procedure Inspect.203 (Inspect.204, #Attr.12): + let Inspect.346 : Str = UnionAtIndex (Id 0) (Index 0) #Attr.12; + let Inspect.345 : Str = CallByName Inspect.61 Inspect.204 Inspect.346; + ret Inspect.345; + +procedure Inspect.205 (Inspect.206, #Attr.12): + let Inspect.340 : List Str = UnionAtIndex (Id 1) (Index 1) #Attr.12; + let Inspect.339 : Str = UnionAtIndex (Id 1) (Index 0) #Attr.12; + let Inspect.338 : Str = "("; + let Inspect.337 : Str = CallByName Inspect.61 Inspect.206 Inspect.338; + let Inspect.325 : Str = CallByName Inspect.61 Inspect.337 Inspect.339; + let Inspect.321 : Str = CallByName Inspect.207 Inspect.325 Inspect.340; + let Inspect.322 : Str = ")"; + let Inspect.320 : Str = CallByName Inspect.61 Inspect.321 Inspect.322; + ret Inspect.320; + +procedure Inspect.207 (Inspect.208, Inspect.202): + let Inspect.329 : {} = Struct {}; + let Inspect.328 : Str = CallByName List.18 Inspect.202 Inspect.208 Inspect.329; + ret Inspect.328; + +procedure Inspect.209 (Inspect.210, Inspect.211): + let Inspect.336 : Str = " "; + let Inspect.331 : Str = CallByName Inspect.61 Inspect.210 Inspect.336; + let Inspect.330 : Str = CallByName Inspect.212 Inspect.331 Inspect.211; + ret Inspect.330; + +procedure Inspect.212 (Inspect.213, Inspect.211): + let Inspect.334 : Str = CallByName Inspect.31 Inspect.211 Inspect.213; + ret Inspect.334; + +procedure Inspect.249 (Inspect.250, Inspect.248): + let Inspect.355 : Str = "\""; + let Inspect.354 : Str = CallByName Inspect.61 Inspect.250 Inspect.355; + let Inspect.352 : Str = CallByName Inspect.61 Inspect.354 Inspect.248; + let Inspect.353 : Str = "\""; + let Inspect.351 : Str = CallByName Inspect.61 Inspect.352 Inspect.353; + ret Inspect.351; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.315 : U8 = GetTagId Inspect.305; + switch Inspect.315: + case 0: + let Inspect.314 : Str = CallByName Inspect.203 Inspect.149 Inspect.305; + ret Inspect.314; + + default: + let Inspect.314 : Str = CallByName Inspect.205 Inspect.149 Inspect.305; + ret Inspect.314; + + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.335 : Str = CallByName Inspect.249 Inspect.149 Inspect.305; + ret Inspect.335; + +procedure Inspect.35 (Inspect.300): + ret Inspect.300; + +procedure Inspect.36 (Inspect.304): + let Inspect.311 : Str = ""; + ret Inspect.311; + +procedure Inspect.40 (Inspect.201, Inspect.202): + inc Inspect.202; + let Inspect.341 : Int1 = CallByName List.1 Inspect.202; + if Inspect.341 then + dec Inspect.202; + let Inspect.343 : [C Str, C Str List Str] = TagId(0) Inspect.201; + let Inspect.342 : [C Str, C Str List Str] = CallByName Inspect.30 Inspect.343; + ret Inspect.342; + else + let Inspect.317 : [C Str, C Str List Str] = TagId(1) Inspect.201 Inspect.202; + let Inspect.316 : [C Str, C Str List Str] = CallByName Inspect.30 Inspect.317; + ret Inspect.316; + +procedure Inspect.44 (Inspect.248): + let Inspect.347 : Str = CallByName Inspect.30 Inspect.248; + ret Inspect.347; + +procedure Inspect.5 (Inspect.150): + let Inspect.312 : Str = CallByName #Derived.0 Inspect.150; + let Inspect.309 : {} = Struct {}; + let Inspect.308 : Str = CallByName Inspect.36 Inspect.309; + let Inspect.307 : Str = CallByName #Derived.3 Inspect.308 Inspect.312; + ret Inspect.307; + +procedure Inspect.61 (Inspect.303, Inspect.298): + let Inspect.324 : Str = CallByName Str.3 Inspect.303 Inspect.298; + dec Inspect.298; + ret Inspect.324; + +procedure List.1 (List.102): + let List.566 : U64 = CallByName List.6 List.102; + dec List.102; + let List.567 : U64 = 0i64; + let List.565 : Int1 = CallByName Bool.11 List.566 List.567; + ret List.565; + +procedure List.18 (List.154, List.155, List.156): + let List.554 : U64 = 0i64; + let List.555 : U64 = CallByName List.6 List.154; + let List.553 : Str = CallByName List.88 List.154 List.155 List.156 List.554 List.555; + ret List.553; + +procedure List.6 (#Attr.2): + let List.564 : U64 = lowlevel ListLen #Attr.2; + ret List.564; + +procedure List.66 (#Attr.2, #Attr.3): + let List.563 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3; + ret List.563; + +procedure List.88 (#Derived_gen.18, #Derived_gen.19, #Derived_gen.20, #Derived_gen.21, #Derived_gen.22): + joinpoint List.556 List.157 List.158 List.159 List.160 List.161: + let List.558 : Int1 = CallByName Num.22 List.160 List.161; + if List.558 then + let List.562 : Str = CallByName List.66 List.157 List.160; + inc List.562; + let List.162 : Str = CallByName Inspect.209 List.158 List.562; + let List.561 : U64 = 1i64; + let List.560 : U64 = CallByName Num.51 List.160 List.561; + jump List.556 List.157 List.162 List.159 List.560 List.161; + else + dec List.157; + ret List.158; + in + jump List.556 #Derived_gen.18 #Derived_gen.19 #Derived_gen.20 #Derived_gen.21 #Derived_gen.22; + +procedure Num.22 (#Attr.2, #Attr.3): + let Num.292 : Int1 = lowlevel NumLt #Attr.2 #Attr.3; + ret Num.292; + +procedure Num.51 (#Attr.2, #Attr.3): + let Num.291 : U64 = lowlevel NumAddWrap #Attr.2 #Attr.3; + ret Num.291; + +procedure Str.3 (#Attr.2, #Attr.3): + let Str.292 : Str = lowlevel StrConcat #Attr.2 #Attr.3; + ret Str.292; + +procedure Test.0 (): + let Test.5 : Str = "foo"; + let Test.4 : Str = CallByName Inspect.5 Test.5; + let Test.3 : Str = CallByName Inspect.35 Test.4; + ret Test.3; diff --git a/crates/compiler/test_mono/generated/inspect_derived_tag_two_payloads_string.txt b/crates/compiler/test_mono/generated/inspect_derived_tag_two_payloads_string.txt new file mode 100644 index 0000000000..81517e7e3f --- /dev/null +++ b/crates/compiler/test_mono/generated/inspect_derived_tag_two_payloads_string.txt @@ -0,0 +1,178 @@ +procedure #Derived.0 (#Derived.1): + let #Derived_gen.0 : {Str, Str} = CallByName Inspect.30 #Derived.1; + ret #Derived_gen.0; + +procedure #Derived.4 (#Derived.5, #Derived.1): + joinpoint #Derived_gen.5 #Derived_gen.4: + let #Derived_gen.3 : Str = CallByName Inspect.31 #Derived_gen.4 #Derived.5; + ret #Derived_gen.3; + in + let #Derived.2 : Str = StructAtIndex 0 #Derived.1; + let #Derived.3 : Str = StructAtIndex 1 #Derived.1; + let #Derived_gen.7 : Str = "A"; + let #Derived_gen.9 : Str = CallByName Inspect.44 #Derived.2; + let #Derived_gen.10 : Str = CallByName Inspect.44 #Derived.3; + let #Derived_gen.8 : List Str = Array [#Derived_gen.9, #Derived_gen.10]; + let #Derived_gen.6 : [C Str, C Str List Str] = CallByName Inspect.40 #Derived_gen.7 #Derived_gen.8; + jump #Derived_gen.5 #Derived_gen.6; + +procedure Bool.11 (#Attr.2, #Attr.3): + let Bool.23 : Int1 = lowlevel Eq #Attr.2 #Attr.3; + ret Bool.23; + +procedure Inspect.203 (Inspect.204, #Attr.12): + let Inspect.346 : Str = UnionAtIndex (Id 0) (Index 0) #Attr.12; + let Inspect.345 : Str = CallByName Inspect.61 Inspect.204 Inspect.346; + ret Inspect.345; + +procedure Inspect.205 (Inspect.206, #Attr.12): + let Inspect.340 : List Str = UnionAtIndex (Id 1) (Index 1) #Attr.12; + let Inspect.339 : Str = UnionAtIndex (Id 1) (Index 0) #Attr.12; + let Inspect.338 : Str = "("; + let Inspect.337 : Str = CallByName Inspect.61 Inspect.206 Inspect.338; + let Inspect.325 : Str = CallByName Inspect.61 Inspect.337 Inspect.339; + let Inspect.321 : Str = CallByName Inspect.207 Inspect.325 Inspect.340; + let Inspect.322 : Str = ")"; + let Inspect.320 : Str = CallByName Inspect.61 Inspect.321 Inspect.322; + ret Inspect.320; + +procedure Inspect.207 (Inspect.208, Inspect.202): + let Inspect.329 : {} = Struct {}; + let Inspect.328 : Str = CallByName List.18 Inspect.202 Inspect.208 Inspect.329; + ret Inspect.328; + +procedure Inspect.209 (Inspect.210, Inspect.211): + let Inspect.336 : Str = " "; + let Inspect.331 : Str = CallByName Inspect.61 Inspect.210 Inspect.336; + let Inspect.330 : Str = CallByName Inspect.212 Inspect.331 Inspect.211; + ret Inspect.330; + +procedure Inspect.212 (Inspect.213, Inspect.211): + let Inspect.334 : Str = CallByName Inspect.31 Inspect.211 Inspect.213; + ret Inspect.334; + +procedure Inspect.249 (Inspect.250, Inspect.248): + let Inspect.355 : Str = "\""; + let Inspect.354 : Str = CallByName Inspect.61 Inspect.250 Inspect.355; + let Inspect.352 : Str = CallByName Inspect.61 Inspect.354 Inspect.248; + let Inspect.353 : Str = "\""; + let Inspect.351 : Str = CallByName Inspect.61 Inspect.352 Inspect.353; + ret Inspect.351; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.315 : U8 = GetTagId Inspect.305; + switch Inspect.315: + case 0: + let Inspect.314 : Str = CallByName Inspect.203 Inspect.149 Inspect.305; + ret Inspect.314; + + default: + let Inspect.314 : Str = CallByName Inspect.205 Inspect.149 Inspect.305; + ret Inspect.314; + + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.335 : Str = CallByName Inspect.249 Inspect.149 Inspect.305; + ret Inspect.335; + +procedure Inspect.35 (Inspect.300): + ret Inspect.300; + +procedure Inspect.36 (Inspect.304): + let Inspect.311 : Str = ""; + ret Inspect.311; + +procedure Inspect.40 (Inspect.201, Inspect.202): + inc Inspect.202; + let Inspect.341 : Int1 = CallByName List.1 Inspect.202; + if Inspect.341 then + dec Inspect.202; + let Inspect.343 : [C Str, C Str List Str] = TagId(0) Inspect.201; + let Inspect.342 : [C Str, C Str List Str] = CallByName Inspect.30 Inspect.343; + ret Inspect.342; + else + let Inspect.317 : [C Str, C Str List Str] = TagId(1) Inspect.201 Inspect.202; + let Inspect.316 : [C Str, C Str List Str] = CallByName Inspect.30 Inspect.317; + ret Inspect.316; + +procedure Inspect.44 (Inspect.248): + let Inspect.356 : Str = CallByName Inspect.30 Inspect.248; + ret Inspect.356; + +procedure Inspect.5 (Inspect.150): + let Inspect.312 : {Str, Str} = CallByName #Derived.0 Inspect.150; + let Inspect.309 : {} = Struct {}; + let Inspect.308 : Str = CallByName Inspect.36 Inspect.309; + let Inspect.307 : Str = CallByName #Derived.4 Inspect.308 Inspect.312; + ret Inspect.307; + +procedure Inspect.61 (Inspect.303, Inspect.298): + let Inspect.324 : Str = CallByName Str.3 Inspect.303 Inspect.298; + dec Inspect.298; + ret Inspect.324; + +procedure List.1 (List.102): + let List.566 : U64 = CallByName List.6 List.102; + dec List.102; + let List.567 : U64 = 0i64; + let List.565 : Int1 = CallByName Bool.11 List.566 List.567; + ret List.565; + +procedure List.18 (List.154, List.155, List.156): + let List.554 : U64 = 0i64; + let List.555 : U64 = CallByName List.6 List.154; + let List.553 : Str = CallByName List.88 List.154 List.155 List.156 List.554 List.555; + ret List.553; + +procedure List.6 (#Attr.2): + let List.564 : U64 = lowlevel ListLen #Attr.2; + ret List.564; + +procedure List.66 (#Attr.2, #Attr.3): + let List.563 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3; + ret List.563; + +procedure List.88 (#Derived_gen.19, #Derived_gen.20, #Derived_gen.21, #Derived_gen.22, #Derived_gen.23): + joinpoint List.556 List.157 List.158 List.159 List.160 List.161: + let List.558 : Int1 = CallByName Num.22 List.160 List.161; + if List.558 then + let List.562 : Str = CallByName List.66 List.157 List.160; + inc List.562; + let List.162 : Str = CallByName Inspect.209 List.158 List.562; + let List.561 : U64 = 1i64; + let List.560 : U64 = CallByName Num.51 List.160 List.561; + jump List.556 List.157 List.162 List.159 List.560 List.161; + else + dec List.157; + ret List.158; + in + jump List.556 #Derived_gen.19 #Derived_gen.20 #Derived_gen.21 #Derived_gen.22 #Derived_gen.23; + +procedure Num.22 (#Attr.2, #Attr.3): + let Num.292 : Int1 = lowlevel NumLt #Attr.2 #Attr.3; + ret Num.292; + +procedure Num.51 (#Attr.2, #Attr.3): + let Num.291 : U64 = lowlevel NumAddWrap #Attr.2 #Attr.3; + ret Num.291; + +procedure Str.3 (#Attr.2, #Attr.3): + let Str.292 : Str = lowlevel StrConcat #Attr.2 #Attr.3; + ret Str.292; + +procedure Test.0 (): + let Test.6 : Str = "foo"; + let Test.5 : Str = "foo"; + let Test.1 : {Str, Str} = Struct {Test.5, Test.6}; + let Test.4 : Str = CallByName Inspect.5 Test.1; + let Test.3 : Str = CallByName Inspect.35 Test.4; + ret Test.3; From 9b181e1b3fde19c869d49637e9417c320b01a307 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 12:48:04 -0800 Subject: [PATCH 30/40] add inspect implementation for dict and set --- crates/compiler/builtins/roc/Dict.roc | 10 + crates/compiler/builtins/roc/Set.roc | 9 + crates/compiler/derive/src/inspect.rs | 4 +- .../generated/inspect_derived_dict.txt | 1202 +++++++++++++++++ crates/compiler/test_mono/src/tests.rs | 16 + 5 files changed, 1239 insertions(+), 2 deletions(-) create mode 100644 crates/compiler/test_mono/generated/inspect_derived_dict.txt diff --git a/crates/compiler/builtins/roc/Dict.roc b/crates/compiler/builtins/roc/Dict.roc index f737ccbb25..11200a420f 100644 --- a/crates/compiler/builtins/roc/Dict.roc +++ b/crates/compiler/builtins/roc/Dict.roc @@ -32,6 +32,7 @@ interface Dict Str, Num.{ Nat, U64, U8, I8 }, Hash.{ Hasher, Hash }, + Inspect.{ Inspect, Inspector, InspectFormatter }, ] ## A [dictionary](https://en.wikipedia.org/wiki/Associative_array) that lets you @@ -108,6 +109,9 @@ Dict k v := { Hash { hash: hashDict, }, + Inspect { + toInspector: toInspectorDict, + }, ] isEq : Dict k v, Dict k v -> Bool where k implements Hash & Eq, v implements Eq @@ -126,6 +130,12 @@ isEq = \xs, ys -> hashDict : hasher, Dict k v -> hasher where k implements Hash & Eq, v implements Hash, hasher implements Hasher hashDict = \hasher, dict -> Hash.hashUnordered hasher (toList dict) List.walk + +toInspectorDict : Dict k v -> Inspector f where k implements Inspect & Hash & Eq, v implements Inspect, f implements InspectFormatter +toInspectorDict = \dict -> + fmt <- Inspect.custom + Inspect.apply (Inspect.dict dict walk Inspect.toInspector Inspect.toInspector) fmt + ## Return an empty dictionary. ## ``` ## emptyDict = Dict.empty {} diff --git a/crates/compiler/builtins/roc/Set.roc b/crates/compiler/builtins/roc/Set.roc index 19e6a82ebf..b942461f31 100644 --- a/crates/compiler/builtins/roc/Set.roc +++ b/crates/compiler/builtins/roc/Set.roc @@ -25,6 +25,7 @@ interface Set Dict.{ Dict }, Num.{ Nat }, Hash.{ Hash, Hasher }, + Inspect.{ Inspect, Inspector, InspectFormatter }, ] ## Provides a [set](https://en.wikipedia.org/wiki/Set_(abstract_data_type)) @@ -37,6 +38,9 @@ Set k := Dict.Dict k {} where k implements Hash & Eq Hash { hash: hashSet, }, + Inspect { + toInspector: toInspectorSet, + }, ] isEq : Set k, Set k -> Bool where k implements Hash & Eq @@ -53,6 +57,11 @@ isEq = \xs, ys -> hashSet : hasher, Set k -> hasher where k implements Hash & Eq, hasher implements Hasher hashSet = \hasher, @Set inner -> Hash.hash hasher inner +toInspectorSet : Set k -> Inspector f where k implements Inspect & Hash & Eq, f implements InspectFormatter +toInspectorSet = \set -> + fmt <- Inspect.custom + Inspect.apply (Inspect.set set walk Inspect.toInspector) fmt + ## Creates a new empty `Set`. ## ``` ## emptySet = Set.empty {} diff --git a/crates/compiler/derive/src/inspect.rs b/crates/compiler/derive/src/inspect.rs index d5cfb68962..05e7558bea 100644 --- a/crates/compiler/derive/src/inspect.rs +++ b/crates/compiler/derive/src/inspect.rs @@ -29,8 +29,8 @@ pub(crate) fn derive_to_inspector( ) -> DerivedBody { let (body, body_type) = match key { FlatInspectableKey::List() => to_inspector_list(env, def_symbol), - FlatInspectableKey::Set() => todo!(), - FlatInspectableKey::Dict() => todo!(), + FlatInspectableKey::Set() => unreachable!(), + FlatInspectableKey::Dict() => unreachable!(), FlatInspectableKey::Record(fields) => { // Generalized record var so we can reuse this impl between many records: // if fields = { a, b }, this is { a: t1, b: t2 } for fresh t1, t2. diff --git a/crates/compiler/test_mono/generated/inspect_derived_dict.txt b/crates/compiler/test_mono/generated/inspect_derived_dict.txt new file mode 100644 index 0000000000..3ca0ce6aa0 --- /dev/null +++ b/crates/compiler/test_mono/generated/inspect_derived_dict.txt @@ -0,0 +1,1202 @@ +procedure Bool.1 (): + let Bool.30 : Int1 = false; + ret Bool.30; + +procedure Bool.11 (#Attr.2, #Attr.3): + let Bool.25 : Int1 = lowlevel Eq #Attr.2 #Attr.3; + ret Bool.25; + +procedure Bool.11 (#Attr.2, #Attr.3): + let Bool.26 : Int1 = lowlevel Eq #Attr.2 #Attr.3; + ret Bool.26; + +procedure Bool.11 (#Attr.2, #Attr.3): + let Bool.28 : Int1 = lowlevel Eq #Attr.2 #Attr.3; + ret Bool.28; + +procedure Bool.2 (): + let Bool.29 : Int1 = true; + ret Bool.29; + +procedure Dict.1 (Dict.557): + let Dict.720 : List {Str, I64} = Array []; + let Dict.726 : U64 = 0i64; + let Dict.727 : U64 = 8i64; + let Dict.721 : List U64 = CallByName List.11 Dict.726 Dict.727; + let Dict.724 : I8 = CallByName Dict.40; + let Dict.725 : U64 = 8i64; + let Dict.722 : List I8 = CallByName List.11 Dict.724 Dict.725; + let Dict.723 : U64 = 0i64; + let Dict.719 : {List {Str, I64}, List U64, List I8, U64} = Struct {Dict.720, Dict.721, Dict.722, Dict.723}; + ret Dict.719; + +procedure Dict.10 (Dict.558, Dict.127, Dict.128): + let Dict.126 : List {Str, I64} = StructAtIndex 0 Dict.558; + let #Derived_gen.61 : List U64 = StructAtIndex 1 Dict.558; + dec #Derived_gen.61; + let #Derived_gen.60 : List I8 = StructAtIndex 2 Dict.558; + dec #Derived_gen.60; + let Dict.981 : {Str, Int1} = CallByName List.18 Dict.126 Dict.127 Dict.128; + ret Dict.981; + +procedure Dict.101 (Dict.102, Dict.568): + let Dict.103 : Str = StructAtIndex 0 Dict.568; + let Dict.104 : I64 = StructAtIndex 1 Dict.568; + let Dict.569 : {List {Str, I64}, List U64, List I8, U64} = CallByName Dict.8 Dict.102 Dict.103 Dict.104; + ret Dict.569; + +procedure Dict.12 (Dict.100): + let Dict.718 : {} = Struct {}; + let Dict.566 : {List {Str, I64}, List U64, List I8, U64} = CallByName Dict.1 Dict.718; + let Dict.567 : {} = Struct {}; + let Dict.565 : {List {Str, I64}, List U64, List I8, U64} = CallByName List.18 Dict.100 Dict.566 Dict.567; + ret Dict.565; + +procedure Dict.129 (Dict.130, Dict.983, Dict.128): + let Dict.131 : Str = StructAtIndex 0 Dict.983; + let Dict.132 : I64 = StructAtIndex 1 Dict.983; + let Dict.985 : {Str, Int1} = CallByName Inspect.190 Dict.130 Dict.131 Dict.132 Dict.128; + ret Dict.985; + +procedure Dict.22 (#Attr.2, #Attr.3): + let Dict.574 : U64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3; + dec #Attr.2; + ret Dict.574; + +procedure Dict.22 (#Attr.2, #Attr.3): + let Dict.597 : I8 = lowlevel ListGetUnsafe #Attr.2 #Attr.3; + dec #Attr.2; + ret Dict.597; + +procedure Dict.22 (#Attr.2, #Attr.3): + let Dict.665 : {Str, I64} = lowlevel ListGetUnsafe #Attr.2 #Attr.3; + inc Dict.665; + dec #Attr.2; + ret Dict.665; + +procedure Dict.22 (#Attr.2, #Attr.3): + let Dict.781 : U8 = lowlevel ListGetUnsafe #Attr.2 #Attr.3; + dec #Attr.2; + ret Dict.781; + +procedure Dict.23 (#Attr.2): + let Dict.659 : U64 = lowlevel DictPseudoSeed #Attr.2; + ret Dict.659; + +procedure Dict.31 (Dict.93): + let Dict.973 : {List {Str, I64}, List U64, List I8, U64} = CallByName Inspect.30 Dict.93; + ret Dict.973; + +procedure Dict.33 (Dict.554, Dict.237, Dict.238, Dict.239, Dict.240): + let Dict.235 : List {Str, I64} = StructAtIndex 0 Dict.554; + let Dict.234 : List U64 = StructAtIndex 1 Dict.554; + let Dict.233 : List I8 = StructAtIndex 2 Dict.554; + inc Dict.233; + let Dict.236 : U64 = StructAtIndex 3 Dict.554; + let Dict.607 : U64 = CallByName List.6 Dict.233; + let Dict.602 : U64 = CallByName Dict.45 Dict.607; + let Dict.241 : {U64, U64, U64} = CallByName Dict.42 Dict.239 Dict.602; + let Dict.580 : U64 = 0i64; + let Dict.242 : U64 = CallByName Dict.34 Dict.233 Dict.241 Dict.580; + let Dict.243 : U64 = CallByName List.6 Dict.235; + let Dict.579 : {Str, I64} = Struct {Dict.237, Dict.238}; + let Dict.244 : List {Str, I64} = CallByName List.4 Dict.235 Dict.579; + let Dict.577 : List U64 = CallByName List.3 Dict.234 Dict.242 Dict.243; + let Dict.578 : List I8 = CallByName List.3 Dict.233 Dict.242 Dict.240; + let Dict.576 : {List {Str, I64}, List U64, List I8, U64} = Struct {Dict.244, Dict.577, Dict.578, Dict.236}; + ret Dict.576; + +procedure Dict.34 (#Derived_gen.42, #Derived_gen.43, #Derived_gen.44): + joinpoint Dict.581 Dict.245 Dict.246 Dict.247: + let Dict.599 : U64 = StructAtIndex 2 Dict.246; + let Dict.598 : U64 = CallByName Dict.44 Dict.599; + let Dict.248 : U64 = CallByName Num.51 Dict.598 Dict.247; + inc Dict.245; + let Dict.249 : I8 = CallByName Dict.22 Dict.245 Dict.248; + let Dict.596 : I8 = 0i64; + let Dict.594 : Int1 = CallByName Num.22 Dict.249 Dict.596; + if Dict.594 then + dec Dict.245; + ret Dict.248; + else + let Dict.593 : U64 = 7i64; + let Dict.585 : Int1 = CallByName Bool.11 Dict.247 Dict.593; + if Dict.585 then + let Dict.587 : {U64, U64, U64} = CallByName Dict.43 Dict.246; + let Dict.588 : U64 = 0i64; + jump Dict.581 Dict.245 Dict.587 Dict.588; + else + let Dict.584 : U64 = 1i64; + let Dict.583 : U64 = CallByName Num.51 Dict.247 Dict.584; + jump Dict.581 Dict.245 Dict.246 Dict.583; + in + jump Dict.581 #Derived_gen.42 #Derived_gen.43 #Derived_gen.44; + +procedure Dict.35 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2, #Derived_gen.3, #Derived_gen.4, #Derived_gen.5, #Derived_gen.6): + joinpoint Dict.686 Dict.250 Dict.251 Dict.252 Dict.253 Dict.254 Dict.255 Dict.256: + let Dict.712 : U64 = StructAtIndex 2 Dict.255; + let Dict.711 : U64 = CallByName Dict.44 Dict.712; + let Dict.257 : U64 = CallByName Num.51 Dict.711 Dict.256; + inc Dict.250; + let Dict.258 : I8 = CallByName Dict.22 Dict.250 Dict.257; + let Dict.710 : I8 = CallByName Dict.40; + let Dict.707 : Int1 = CallByName Bool.11 Dict.258 Dict.710; + if Dict.707 then + dec Dict.250; + dec Dict.251; + dec Dict.252; + dec Dict.254; + let Dict.709 : {} = Struct {}; + let Dict.708 : [C {}, C U64] = TagId(0) Dict.709; + ret Dict.708; + else + let Dict.695 : Int1 = CallByName Bool.11 Dict.258 Dict.253; + if Dict.695 then + inc Dict.251; + let Dict.261 : U64 = CallByName Dict.22 Dict.251 Dict.257; + inc Dict.252; + let Dict.706 : {Str, I64} = CallByName Dict.22 Dict.252 Dict.261; + let Dict.262 : Str = StructAtIndex 0 Dict.706; + let Dict.704 : Int1 = CallByName Bool.11 Dict.262 Dict.254; + dec Dict.262; + if Dict.704 then + dec Dict.250; + dec Dict.251; + dec Dict.252; + dec Dict.254; + let Dict.705 : [C {}, C U64] = TagId(1) Dict.257; + ret Dict.705; + else + let Dict.703 : U64 = 7i64; + let Dict.699 : Int1 = CallByName Bool.11 Dict.256 Dict.703; + if Dict.699 then + let Dict.701 : {U64, U64, U64} = CallByName Dict.43 Dict.255; + let Dict.702 : U64 = 0i64; + jump Dict.686 Dict.250 Dict.251 Dict.252 Dict.253 Dict.254 Dict.701 Dict.702; + else + let Dict.698 : U64 = 1i64; + let Dict.697 : U64 = CallByName Num.51 Dict.256 Dict.698; + jump Dict.686 Dict.250 Dict.251 Dict.252 Dict.253 Dict.254 Dict.255 Dict.697; + else + let Dict.694 : U64 = 7i64; + let Dict.690 : Int1 = CallByName Bool.11 Dict.256 Dict.694; + if Dict.690 then + let Dict.692 : {U64, U64, U64} = CallByName Dict.43 Dict.255; + let Dict.693 : U64 = 0i64; + jump Dict.686 Dict.250 Dict.251 Dict.252 Dict.253 Dict.254 Dict.692 Dict.693; + else + let Dict.689 : U64 = 1i64; + let Dict.688 : U64 = CallByName Num.51 Dict.256 Dict.689; + jump Dict.686 Dict.250 Dict.251 Dict.252 Dict.253 Dict.254 Dict.255 Dict.688; + in + jump Dict.686 #Derived_gen.0 #Derived_gen.1 #Derived_gen.2 #Derived_gen.3 #Derived_gen.4 #Derived_gen.5 #Derived_gen.6; + +procedure Dict.36 (Dict.551): + let Dict.266 : List {Str, I64} = StructAtIndex 0 Dict.551; + let Dict.265 : List U64 = StructAtIndex 1 Dict.551; + let Dict.264 : List I8 = StructAtIndex 2 Dict.551; + let Dict.267 : U64 = StructAtIndex 3 Dict.551; + let Dict.268 : U64 = CallByName List.6 Dict.265; + let Dict.679 : U8 = 3i64; + let Dict.678 : U64 = CallByName Num.74 Dict.268 Dict.679; + let Dict.269 : U64 = CallByName Num.75 Dict.268 Dict.678; + let Dict.612 : Int1 = CallByName Num.24 Dict.267 Dict.269; + if Dict.612 then + let Dict.614 : {List {Str, I64}, List U64, List I8, U64} = Struct {Dict.266, Dict.265, Dict.264, Dict.267}; + let Dict.613 : {List {Str, I64}, List U64, List I8, U64} = CallByName Dict.37 Dict.614; + ret Dict.613; + else + let Dict.611 : {List {Str, I64}, List U64, List I8, U64} = Struct {Dict.266, Dict.265, Dict.264, Dict.267}; + ret Dict.611; + +procedure Dict.37 (Dict.552): + let Dict.272 : List {Str, I64} = StructAtIndex 0 Dict.552; + inc Dict.272; + let Dict.271 : List U64 = StructAtIndex 1 Dict.552; + let Dict.270 : List I8 = StructAtIndex 2 Dict.552; + let Dict.273 : U64 = StructAtIndex 3 Dict.552; + let Dict.676 : U64 = 2i64; + let Dict.677 : U64 = CallByName List.6 Dict.271; + let Dict.274 : U64 = CallByName Num.21 Dict.676 Dict.677; + let Dict.675 : U64 = 0i64; + let Dict.671 : List U64 = CallByName List.11 Dict.675 Dict.274; + let Dict.673 : I8 = CallByName Dict.40; + let Dict.672 : List I8 = CallByName List.11 Dict.673 Dict.274; + let Dict.275 : {List {Str, I64}, List U64, List I8, U64} = Struct {Dict.272, Dict.671, Dict.672, Dict.273}; + let Dict.616 : U64 = 0i64; + let Dict.615 : {List {Str, I64}, List U64, List I8, U64} = CallByName Dict.38 Dict.275 Dict.270 Dict.271 Dict.272 Dict.616; + ret Dict.615; + +procedure Dict.38 (#Derived_gen.32, #Derived_gen.33, #Derived_gen.34, #Derived_gen.35, #Derived_gen.36): + joinpoint Dict.617 Dict.276 Dict.277 Dict.278 Dict.279 Dict.280: + inc Dict.277; + let Dict.618 : [C {}, C I8] = CallByName List.2 Dict.277 Dict.280; + let Dict.668 : U8 = 1i64; + let Dict.669 : U8 = GetTagId Dict.618; + let Dict.670 : Int1 = lowlevel Eq Dict.668 Dict.669; + if Dict.670 then + let Dict.281 : I8 = UnionAtIndex (Id 1) (Index 0) Dict.618; + joinpoint Dict.623 Dict.282: + let Dict.621 : U64 = 1i64; + let Dict.620 : U64 = CallByName Num.51 Dict.280 Dict.621; + jump Dict.617 Dict.282 Dict.277 Dict.278 Dict.279 Dict.620; + in + let Dict.666 : I8 = 0i64; + let Dict.624 : Int1 = CallByName Num.25 Dict.281 Dict.666; + if Dict.624 then + inc Dict.278; + let Dict.283 : U64 = CallByName Dict.22 Dict.278 Dict.280; + inc Dict.279; + let Dict.664 : {Str, I64} = CallByName Dict.22 Dict.279 Dict.283; + let Dict.284 : Str = StructAtIndex 0 Dict.664; + let Dict.622 : {List {Str, I64}, List U64, List I8, U64} = CallByName Dict.39 Dict.276 Dict.284 Dict.283; + jump Dict.623 Dict.622; + else + jump Dict.623 Dict.276; + else + dec Dict.277; + dec Dict.279; + dec Dict.278; + ret Dict.276; + in + jump Dict.617 #Derived_gen.32 #Derived_gen.33 #Derived_gen.34 #Derived_gen.35 #Derived_gen.36; + +procedure Dict.39 (Dict.553, Dict.289, Dict.290): + let Dict.287 : List {Str, I64} = StructAtIndex 0 Dict.553; + let Dict.286 : List U64 = StructAtIndex 1 Dict.553; + let Dict.285 : List I8 = StructAtIndex 2 Dict.553; + inc Dict.285; + let Dict.288 : U64 = StructAtIndex 3 Dict.553; + let Dict.639 : [C , C U64] = TagId(0) ; + let Dict.638 : {U64, U64} = CallByName Dict.48 Dict.639; + let Dict.636 : {U64, U64} = CallByName Hash.19 Dict.638 Dict.289; + let Dict.291 : U64 = CallByName Dict.51 Dict.636; + let Dict.292 : U64 = CallByName Dict.46 Dict.291; + let Dict.293 : I8 = CallByName Dict.47 Dict.291; + let Dict.630 : U64 = CallByName List.6 Dict.285; + let Dict.629 : U64 = CallByName Dict.45 Dict.630; + let Dict.294 : {U64, U64, U64} = CallByName Dict.42 Dict.292 Dict.629; + let Dict.628 : U64 = 0i64; + let Dict.295 : U64 = CallByName Dict.34 Dict.285 Dict.294 Dict.628; + let Dict.626 : List U64 = CallByName List.3 Dict.286 Dict.295 Dict.290; + let Dict.627 : List I8 = CallByName List.3 Dict.285 Dict.295 Dict.293; + let Dict.625 : {List {Str, I64}, List U64, List I8, U64} = Struct {Dict.287, Dict.626, Dict.627, Dict.288}; + ret Dict.625; + +procedure Dict.40 (): + let Dict.674 : I8 = -128i64; + ret Dict.674; + +procedure Dict.42 (Dict.297, Dict.298): + let Dict.606 : U64 = 1i64; + let Dict.299 : U64 = CallByName Num.77 Dict.298 Dict.606; + let Dict.605 : U64 = CallByName Num.137 Dict.297; + let Dict.300 : U64 = CallByName Num.69 Dict.605 Dict.299; + let Dict.604 : U64 = 1i64; + let Dict.603 : {U64, U64, U64} = Struct {Dict.299, Dict.604, Dict.300}; + ret Dict.603; + +procedure Dict.43 (Dict.562): + let Dict.303 : U64 = StructAtIndex 0 Dict.562; + let Dict.302 : U64 = StructAtIndex 1 Dict.562; + let Dict.301 : U64 = StructAtIndex 2 Dict.562; + let Dict.592 : U64 = CallByName Num.51 Dict.301 Dict.302; + let Dict.304 : U64 = CallByName Num.69 Dict.592 Dict.303; + let Dict.591 : U64 = 1i64; + let Dict.590 : U64 = CallByName Num.51 Dict.302 Dict.591; + let Dict.589 : {U64, U64, U64} = Struct {Dict.303, Dict.590, Dict.304}; + ret Dict.589; + +procedure Dict.44 (Dict.305): + let Dict.601 : U8 = 3i64; + let Dict.600 : U64 = CallByName Num.72 Dict.305 Dict.601; + ret Dict.600; + +procedure Dict.45 (Dict.306): + let Dict.609 : U8 = 3i64; + let Dict.608 : U64 = CallByName Num.74 Dict.306 Dict.609; + ret Dict.608; + +procedure Dict.46 (Dict.307): + let Dict.635 : U8 = 7i64; + let Dict.634 : U64 = CallByName Num.74 Dict.307 Dict.635; + ret Dict.634; + +procedure Dict.47 (Dict.308): + let Dict.633 : U64 = 127i64; + let Dict.632 : U64 = CallByName Num.69 Dict.308 Dict.633; + let Dict.631 : I8 = CallByName Num.117 Dict.632; + ret Dict.631; + +procedure Dict.48 (Dict.309): + joinpoint Dict.656 Dict.310: + let Dict.641 : U64 = CallByName Dict.50 Dict.310; + let Dict.640 : {U64, U64} = Struct {Dict.641, Dict.310}; + ret Dict.640; + in + let Dict.661 : U8 = 0i64; + let Dict.662 : U8 = GetTagId Dict.309; + let Dict.663 : Int1 = lowlevel Eq Dict.661 Dict.662; + if Dict.663 then + let Dict.658 : {} = Struct {}; + let Dict.657 : U64 = CallByName Dict.23 Dict.658; + jump Dict.656 Dict.657; + else + let Dict.311 : U64 = UnionAtIndex (Id 1) (Index 0) Dict.309; + jump Dict.656 Dict.311; + +procedure Dict.49 (Dict.541, Dict.542): + let Dict.314 : U64 = StructAtIndex 0 Dict.542; + let Dict.315 : U64 = StructAtIndex 1 Dict.542; + let Dict.317 : U64 = StructAtIndex 2 Dict.542; + let Dict.316 : U64 = StructAtIndex 3 Dict.542; + let Dict.312 : U64 = StructAtIndex 0 Dict.541; + let Dict.313 : U64 = StructAtIndex 1 Dict.541; + let Dict.749 : U64 = CallByName Dict.61; + let Dict.747 : U64 = CallByName Num.70 Dict.314 Dict.749; + let Dict.748 : U64 = CallByName Num.70 Dict.315 Dict.316; + let Dict.318 : {U64, U64} = CallByName Dict.65 Dict.747 Dict.748; + let Dict.744 : U64 = StructAtIndex 0 Dict.318; + let Dict.745 : U64 = CallByName Dict.60; + let Dict.743 : U64 = CallByName Num.70 Dict.744 Dict.745; + let Dict.319 : U64 = CallByName Num.70 Dict.743 Dict.317; + let Dict.740 : U64 = StructAtIndex 1 Dict.318; + let Dict.741 : U64 = CallByName Dict.61; + let Dict.320 : U64 = CallByName Num.70 Dict.740 Dict.741; + let Dict.321 : U64 = CallByName Dict.64 Dict.319 Dict.320; + let Dict.732 : U64 = CallByName Dict.64 Dict.313 Dict.321; + let Dict.731 : {U64, U64} = Struct {Dict.312, Dict.732}; + ret Dict.731; + +procedure Dict.50 (Dict.322): + let Dict.654 : U64 = CallByName Dict.60; + let Dict.644 : U64 = CallByName Num.70 Dict.322 Dict.654; + let Dict.645 : U64 = CallByName Dict.61; + let Dict.643 : U64 = CallByName Dict.64 Dict.644 Dict.645; + let Dict.642 : U64 = CallByName Num.70 Dict.643 Dict.322; + ret Dict.642; + +procedure Dict.51 (Dict.561): + let Dict.323 : U64 = StructAtIndex 1 Dict.561; + ret Dict.323; + +procedure Dict.57 (Dict.535, Dict.362): + let Dict.360 : U64 = StructAtIndex 0 Dict.535; + let Dict.361 : U64 = StructAtIndex 1 Dict.535; + let Dict.363 : U64 = CallByName List.6 Dict.362; + joinpoint Dict.938 Dict.364: + let Dict.931 : {U64, U64} = Struct {Dict.360, Dict.361}; + let Dict.933 : U64 = StructAtIndex 0 Dict.364; + let Dict.934 : U64 = StructAtIndex 1 Dict.364; + let Dict.935 : U64 = CallByName Num.133 Dict.363; + let Dict.936 : U64 = StructAtIndex 2 Dict.364; + let Dict.932 : {U64, U64, U64, U64} = Struct {Dict.933, Dict.934, Dict.935, Dict.936}; + let Dict.930 : {U64, U64} = CallByName Dict.49 Dict.931 Dict.932; + ret Dict.930; + in + let Dict.972 : U64 = 16i64; + let Dict.943 : Int1 = CallByName Num.23 Dict.363 Dict.972; + if Dict.943 then + joinpoint Dict.945 Dict.937: + jump Dict.938 Dict.937; + in + let Dict.971 : U64 = 4i64; + let Dict.953 : Int1 = CallByName Num.25 Dict.363 Dict.971; + if Dict.953 then + let Dict.970 : U8 = 3i64; + let Dict.968 : U64 = CallByName Num.74 Dict.363 Dict.970; + let Dict.969 : U8 = 2i64; + let Dict.365 : U64 = CallByName Num.72 Dict.968 Dict.969; + let Dict.967 : U64 = 0i64; + inc 3 Dict.362; + let Dict.965 : U64 = CallByName Dict.67 Dict.362 Dict.967; + let Dict.966 : U8 = 32i64; + let Dict.963 : U64 = CallByName Num.72 Dict.965 Dict.966; + let Dict.964 : U64 = CallByName Dict.67 Dict.362 Dict.365; + let Dict.366 : U64 = CallByName Num.71 Dict.963 Dict.964; + let Dict.962 : U64 = 4i64; + let Dict.961 : U64 = CallByName Num.75 Dict.363 Dict.962; + let Dict.959 : U64 = CallByName Dict.67 Dict.362 Dict.961; + let Dict.960 : U8 = 32i64; + let Dict.954 : U64 = CallByName Num.72 Dict.959 Dict.960; + let Dict.958 : U64 = 4i64; + let Dict.957 : U64 = CallByName Num.75 Dict.363 Dict.958; + let Dict.956 : U64 = CallByName Num.75 Dict.957 Dict.365; + let Dict.955 : U64 = CallByName Dict.67 Dict.362 Dict.956; + let Dict.367 : U64 = CallByName Num.71 Dict.954 Dict.955; + let Dict.944 : {U64, U64, U64} = Struct {Dict.366, Dict.367, Dict.360}; + jump Dict.945 Dict.944; + else + let Dict.952 : U64 = 0i64; + let Dict.948 : Int1 = CallByName Num.24 Dict.363 Dict.952; + if Dict.948 then + let Dict.951 : U64 = 0i64; + let Dict.949 : U64 = CallByName Dict.68 Dict.362 Dict.951 Dict.363; + let Dict.950 : U64 = 0i64; + let Dict.944 : {U64, U64, U64} = Struct {Dict.949, Dict.950, Dict.360}; + jump Dict.945 Dict.944; + else + dec Dict.362; + let Dict.946 : U64 = 0i64; + let Dict.947 : U64 = 0i64; + let Dict.944 : {U64, U64, U64} = Struct {Dict.946, Dict.947, Dict.360}; + jump Dict.945 Dict.944; + else + let Dict.942 : U64 = 48i64; + let Dict.940 : Int1 = CallByName Num.23 Dict.363 Dict.942; + if Dict.940 then + let Dict.941 : U64 = 0i64; + let Dict.937 : {U64, U64, U64} = CallByName Dict.59 Dict.360 Dict.362 Dict.941 Dict.363; + jump Dict.938 Dict.937; + else + let Dict.939 : U64 = 0i64; + let Dict.937 : {U64, U64, U64} = CallByName Dict.58 Dict.360 Dict.360 Dict.360 Dict.362 Dict.939 Dict.363; + jump Dict.938 Dict.937; + +procedure Dict.58 (#Derived_gen.51, #Derived_gen.52, #Derived_gen.53, #Derived_gen.54, #Derived_gen.55, #Derived_gen.56): + joinpoint Dict.757 Dict.368 Dict.369 Dict.370 Dict.371 Dict.372 Dict.373: + inc 6 Dict.371; + let Dict.864 : U64 = CallByName Dict.66 Dict.371 Dict.372; + let Dict.865 : U64 = CallByName Dict.61; + let Dict.859 : U64 = CallByName Num.70 Dict.864 Dict.865; + let Dict.863 : U64 = 8i64; + let Dict.862 : U64 = CallByName Num.51 Dict.372 Dict.863; + let Dict.861 : U64 = CallByName Dict.66 Dict.371 Dict.862; + let Dict.860 : U64 = CallByName Num.70 Dict.861 Dict.368; + let Dict.374 : U64 = CallByName Dict.64 Dict.859 Dict.860; + let Dict.858 : U64 = 16i64; + let Dict.857 : U64 = CallByName Num.51 Dict.372 Dict.858; + let Dict.854 : U64 = CallByName Dict.66 Dict.371 Dict.857; + let Dict.855 : U64 = CallByName Dict.62; + let Dict.849 : U64 = CallByName Num.70 Dict.854 Dict.855; + let Dict.853 : U64 = 24i64; + let Dict.852 : U64 = CallByName Num.51 Dict.372 Dict.853; + let Dict.851 : U64 = CallByName Dict.66 Dict.371 Dict.852; + let Dict.850 : U64 = CallByName Num.70 Dict.851 Dict.369; + let Dict.375 : U64 = CallByName Dict.64 Dict.849 Dict.850; + let Dict.848 : U64 = 32i64; + let Dict.847 : U64 = CallByName Num.51 Dict.372 Dict.848; + let Dict.844 : U64 = CallByName Dict.66 Dict.371 Dict.847; + let Dict.845 : U64 = CallByName Dict.63; + let Dict.839 : U64 = CallByName Num.70 Dict.844 Dict.845; + let Dict.843 : U64 = 40i64; + let Dict.842 : U64 = CallByName Num.51 Dict.372 Dict.843; + let Dict.841 : U64 = CallByName Dict.66 Dict.371 Dict.842; + let Dict.840 : U64 = CallByName Num.70 Dict.841 Dict.370; + let Dict.376 : U64 = CallByName Dict.64 Dict.839 Dict.840; + let Dict.838 : U64 = 48i64; + let Dict.377 : U64 = CallByName Num.75 Dict.373 Dict.838; + let Dict.837 : U64 = 48i64; + let Dict.378 : U64 = CallByName Num.51 Dict.372 Dict.837; + let Dict.836 : U64 = 48i64; + let Dict.834 : Int1 = CallByName Num.24 Dict.377 Dict.836; + if Dict.834 then + jump Dict.757 Dict.374 Dict.375 Dict.376 Dict.371 Dict.378 Dict.377; + else + let Dict.833 : U64 = 16i64; + let Dict.808 : Int1 = CallByName Num.24 Dict.377 Dict.833; + if Dict.808 then + let Dict.832 : U64 = CallByName Num.70 Dict.375 Dict.374; + let Dict.379 : U64 = CallByName Num.70 Dict.376 Dict.832; + let Dict.809 : {U64, U64, U64} = CallByName Dict.59 Dict.379 Dict.371 Dict.378 Dict.377; + ret Dict.809; + else + inc Dict.371; + let Dict.807 : U64 = CallByName Num.70 Dict.375 Dict.374; + let Dict.380 : U64 = CallByName Num.70 Dict.376 Dict.807; + let Dict.806 : U64 = 16i64; + let Dict.805 : U64 = CallByName Num.75 Dict.377 Dict.806; + let Dict.804 : U64 = CallByName Num.51 Dict.805 Dict.378; + let Dict.759 : U64 = CallByName Dict.66 Dict.371 Dict.804; + let Dict.803 : U64 = 8i64; + let Dict.802 : U64 = CallByName Num.75 Dict.377 Dict.803; + let Dict.761 : U64 = CallByName Num.51 Dict.802 Dict.378; + let Dict.760 : U64 = CallByName Dict.66 Dict.371 Dict.761; + let Dict.758 : {U64, U64, U64} = Struct {Dict.759, Dict.760, Dict.380}; + ret Dict.758; + in + jump Dict.757 #Derived_gen.51 #Derived_gen.52 #Derived_gen.53 #Derived_gen.54 #Derived_gen.55 #Derived_gen.56; + +procedure Dict.59 (#Derived_gen.17, #Derived_gen.18, #Derived_gen.19, #Derived_gen.20): + joinpoint Dict.810 Dict.381 Dict.382 Dict.383 Dict.384: + inc 2 Dict.382; + let Dict.830 : U64 = CallByName Dict.66 Dict.382 Dict.383; + let Dict.831 : U64 = CallByName Dict.61; + let Dict.825 : U64 = CallByName Num.70 Dict.830 Dict.831; + let Dict.829 : U64 = 8i64; + let Dict.828 : U64 = CallByName Num.51 Dict.383 Dict.829; + let Dict.827 : U64 = CallByName Dict.66 Dict.382 Dict.828; + let Dict.826 : U64 = CallByName Num.70 Dict.827 Dict.381; + let Dict.385 : U64 = CallByName Dict.64 Dict.825 Dict.826; + let Dict.824 : U64 = 16i64; + let Dict.386 : U64 = CallByName Num.75 Dict.384 Dict.824; + let Dict.823 : U64 = 16i64; + let Dict.387 : U64 = CallByName Num.51 Dict.383 Dict.823; + let Dict.822 : U64 = 16i64; + let Dict.812 : Int1 = CallByName Num.23 Dict.386 Dict.822; + if Dict.812 then + inc Dict.382; + let Dict.821 : U64 = 16i64; + let Dict.820 : U64 = CallByName Num.75 Dict.386 Dict.821; + let Dict.819 : U64 = CallByName Num.51 Dict.820 Dict.387; + let Dict.814 : U64 = CallByName Dict.66 Dict.382 Dict.819; + let Dict.818 : U64 = 8i64; + let Dict.817 : U64 = CallByName Num.75 Dict.386 Dict.818; + let Dict.816 : U64 = CallByName Num.51 Dict.817 Dict.387; + let Dict.815 : U64 = CallByName Dict.66 Dict.382 Dict.816; + let Dict.813 : {U64, U64, U64} = Struct {Dict.814, Dict.815, Dict.385}; + ret Dict.813; + else + jump Dict.810 Dict.385 Dict.382 Dict.387 Dict.386; + in + jump Dict.810 #Derived_gen.17 #Derived_gen.18 #Derived_gen.19 #Derived_gen.20; + +procedure Dict.60 (): + let Dict.746 : U64 = 11562461410679940143i64; + ret Dict.746; + +procedure Dict.61 (): + let Dict.742 : U64 = 16646288086500911323i64; + ret Dict.742; + +procedure Dict.62 (): + let Dict.856 : U64 = 10285213230658275043i64; + ret Dict.856; + +procedure Dict.63 (): + let Dict.846 : U64 = 6384245875588680899i64; + ret Dict.846; + +procedure Dict.64 (Dict.388, Dict.389): + let Dict.734 : {U64, U64} = CallByName Dict.65 Dict.388 Dict.389; + let Dict.390 : U64 = StructAtIndex 0 Dict.734; + let Dict.391 : U64 = StructAtIndex 1 Dict.734; + let Dict.733 : U64 = CallByName Num.70 Dict.390 Dict.391; + ret Dict.733; + +procedure Dict.65 (Dict.392, Dict.393): + let Dict.738 : U128 = CallByName Num.135 Dict.392; + let Dict.739 : U128 = CallByName Num.135 Dict.393; + let Dict.394 : U128 = CallByName Num.21 Dict.738 Dict.739; + let Dict.395 : U64 = CallByName Num.133 Dict.394; + let Dict.737 : U8 = 64i64; + let Dict.736 : U128 = CallByName Num.74 Dict.394 Dict.737; + let Dict.396 : U64 = CallByName Num.133 Dict.736; + let Dict.735 : {U64, U64} = Struct {Dict.395, Dict.396}; + ret Dict.735; + +procedure Dict.66 (Dict.397, Dict.398): + inc 7 Dict.397; + let Dict.801 : U8 = CallByName Dict.22 Dict.397 Dict.398; + let Dict.399 : U64 = CallByName Num.133 Dict.801; + let Dict.800 : U64 = 1i64; + let Dict.799 : U64 = CallByName Num.51 Dict.398 Dict.800; + let Dict.798 : U8 = CallByName Dict.22 Dict.397 Dict.799; + let Dict.400 : U64 = CallByName Num.133 Dict.798; + let Dict.797 : U64 = 2i64; + let Dict.796 : U64 = CallByName Num.51 Dict.398 Dict.797; + let Dict.795 : U8 = CallByName Dict.22 Dict.397 Dict.796; + let Dict.401 : U64 = CallByName Num.133 Dict.795; + let Dict.794 : U64 = 3i64; + let Dict.793 : U64 = CallByName Num.51 Dict.398 Dict.794; + let Dict.792 : U8 = CallByName Dict.22 Dict.397 Dict.793; + let Dict.402 : U64 = CallByName Num.133 Dict.792; + let Dict.791 : U64 = 4i64; + let Dict.790 : U64 = CallByName Num.51 Dict.398 Dict.791; + let Dict.789 : U8 = CallByName Dict.22 Dict.397 Dict.790; + let Dict.403 : U64 = CallByName Num.133 Dict.789; + let Dict.788 : U64 = 5i64; + let Dict.787 : U64 = CallByName Num.51 Dict.398 Dict.788; + let Dict.786 : U8 = CallByName Dict.22 Dict.397 Dict.787; + let Dict.404 : U64 = CallByName Num.133 Dict.786; + let Dict.785 : U64 = 6i64; + let Dict.784 : U64 = CallByName Num.51 Dict.398 Dict.785; + let Dict.783 : U8 = CallByName Dict.22 Dict.397 Dict.784; + let Dict.405 : U64 = CallByName Num.133 Dict.783; + let Dict.782 : U64 = 7i64; + let Dict.780 : U64 = CallByName Num.51 Dict.398 Dict.782; + let Dict.779 : U8 = CallByName Dict.22 Dict.397 Dict.780; + let Dict.406 : U64 = CallByName Num.133 Dict.779; + let Dict.778 : U8 = 8i64; + let Dict.777 : U64 = CallByName Num.72 Dict.400 Dict.778; + let Dict.407 : U64 = CallByName Num.71 Dict.399 Dict.777; + let Dict.776 : U8 = 16i64; + let Dict.773 : U64 = CallByName Num.72 Dict.401 Dict.776; + let Dict.775 : U8 = 24i64; + let Dict.774 : U64 = CallByName Num.72 Dict.402 Dict.775; + let Dict.408 : U64 = CallByName Num.71 Dict.773 Dict.774; + let Dict.772 : U8 = 32i64; + let Dict.769 : U64 = CallByName Num.72 Dict.403 Dict.772; + let Dict.771 : U8 = 40i64; + let Dict.770 : U64 = CallByName Num.72 Dict.404 Dict.771; + let Dict.409 : U64 = CallByName Num.71 Dict.769 Dict.770; + let Dict.768 : U8 = 48i64; + let Dict.765 : U64 = CallByName Num.72 Dict.405 Dict.768; + let Dict.767 : U8 = 56i64; + let Dict.766 : U64 = CallByName Num.72 Dict.406 Dict.767; + let Dict.410 : U64 = CallByName Num.71 Dict.765 Dict.766; + let Dict.763 : U64 = CallByName Num.71 Dict.407 Dict.408; + let Dict.764 : U64 = CallByName Num.71 Dict.409 Dict.410; + let Dict.762 : U64 = CallByName Num.71 Dict.763 Dict.764; + ret Dict.762; + +procedure Dict.67 (Dict.411, Dict.412): + inc 3 Dict.411; + let Dict.913 : U8 = CallByName Dict.22 Dict.411 Dict.412; + let Dict.413 : U64 = CallByName Num.133 Dict.913; + let Dict.912 : U64 = 1i64; + let Dict.911 : U64 = CallByName Num.51 Dict.412 Dict.912; + let Dict.910 : U8 = CallByName Dict.22 Dict.411 Dict.911; + let Dict.414 : U64 = CallByName Num.133 Dict.910; + let Dict.909 : U64 = 2i64; + let Dict.908 : U64 = CallByName Num.51 Dict.412 Dict.909; + let Dict.907 : U8 = CallByName Dict.22 Dict.411 Dict.908; + let Dict.415 : U64 = CallByName Num.133 Dict.907; + let Dict.906 : U64 = 3i64; + let Dict.905 : U64 = CallByName Num.51 Dict.412 Dict.906; + let Dict.904 : U8 = CallByName Dict.22 Dict.411 Dict.905; + let Dict.416 : U64 = CallByName Num.133 Dict.904; + let Dict.903 : U8 = 8i64; + let Dict.902 : U64 = CallByName Num.72 Dict.414 Dict.903; + let Dict.417 : U64 = CallByName Num.71 Dict.413 Dict.902; + let Dict.901 : U8 = 16i64; + let Dict.898 : U64 = CallByName Num.72 Dict.415 Dict.901; + let Dict.900 : U8 = 24i64; + let Dict.899 : U64 = CallByName Num.72 Dict.416 Dict.900; + let Dict.418 : U64 = CallByName Num.71 Dict.898 Dict.899; + let Dict.897 : U64 = CallByName Num.71 Dict.417 Dict.418; + ret Dict.897; + +procedure Dict.68 (Dict.419, Dict.420, Dict.421): + inc 2 Dict.419; + let Dict.891 : U8 = CallByName Dict.22 Dict.419 Dict.420; + let Dict.422 : U64 = CallByName Num.133 Dict.891; + let Dict.890 : U8 = 1i64; + let Dict.889 : U64 = CallByName Num.74 Dict.421 Dict.890; + let Dict.888 : U64 = CallByName Num.51 Dict.889 Dict.420; + let Dict.887 : U8 = CallByName Dict.22 Dict.419 Dict.888; + let Dict.423 : U64 = CallByName Num.133 Dict.887; + let Dict.886 : U64 = 1i64; + let Dict.885 : U64 = CallByName Num.75 Dict.421 Dict.886; + let Dict.884 : U64 = CallByName Num.51 Dict.885 Dict.420; + let Dict.883 : U8 = CallByName Dict.22 Dict.419 Dict.884; + let Dict.424 : U64 = CallByName Num.133 Dict.883; + let Dict.882 : U8 = 16i64; + let Dict.879 : U64 = CallByName Num.72 Dict.422 Dict.882; + let Dict.881 : U8 = 8i64; + let Dict.880 : U64 = CallByName Num.72 Dict.423 Dict.881; + let Dict.425 : U64 = CallByName Num.71 Dict.879 Dict.880; + let Dict.878 : U64 = CallByName Num.71 Dict.425 Dict.424; + ret Dict.878; + +procedure Dict.8 (Dict.550, Dict.168, Dict.169): + let Dict.166 : List {Str, I64} = StructAtIndex 0 Dict.550; + inc Dict.166; + let Dict.165 : List U64 = StructAtIndex 1 Dict.550; + inc Dict.165; + let Dict.164 : List I8 = StructAtIndex 2 Dict.550; + inc Dict.164; + let Dict.167 : U64 = StructAtIndex 3 Dict.550; + let Dict.717 : [C , C U64] = TagId(0) ; + let Dict.716 : {U64, U64} = CallByName Dict.48 Dict.717; + inc 2 Dict.168; + let Dict.715 : {U64, U64} = CallByName Hash.19 Dict.716 Dict.168; + let Dict.170 : U64 = CallByName Dict.51 Dict.715; + let Dict.171 : U64 = CallByName Dict.46 Dict.170; + let Dict.172 : I8 = CallByName Dict.47 Dict.170; + let Dict.714 : U64 = CallByName List.6 Dict.164; + let Dict.713 : U64 = CallByName Dict.45 Dict.714; + let Dict.173 : {U64, U64, U64} = CallByName Dict.42 Dict.171 Dict.713; + let Dict.685 : U64 = 0i64; + let Dict.570 : [C {}, C U64] = CallByName Dict.35 Dict.164 Dict.165 Dict.166 Dict.172 Dict.168 Dict.173 Dict.685; + let Dict.682 : U8 = 1i64; + let Dict.683 : U8 = GetTagId Dict.570; + let Dict.684 : Int1 = lowlevel Eq Dict.682 Dict.683; + if Dict.684 then + inc Dict.165; + let Dict.175 : U64 = UnionAtIndex (Id 1) (Index 0) Dict.570; + let Dict.176 : U64 = CallByName Dict.22 Dict.165 Dict.175; + let Dict.573 : {Str, I64} = Struct {Dict.168, Dict.169}; + let Dict.572 : List {Str, I64} = CallByName List.3 Dict.166 Dict.176 Dict.573; + let Dict.571 : {List {Str, I64}, List U64, List I8, U64} = Struct {Dict.572, Dict.165, Dict.164, Dict.167}; + ret Dict.571; + else + let Dict.681 : U64 = 1i64; + let Dict.680 : U64 = CallByName Num.51 Dict.167 Dict.681; + let Dict.610 : {List {Str, I64}, List U64, List I8, U64} = Struct {Dict.166, Dict.165, Dict.164, Dict.680}; + let Dict.177 : {List {Str, I64}, List U64, List I8, U64} = CallByName Dict.36 Dict.610; + let Dict.575 : {List {Str, I64}, List U64, List I8, U64} = CallByName Dict.33 Dict.177 Dict.168 Dict.169 Dict.171 Dict.172; + ret Dict.575; + +procedure Dict.94 (Dict.95, Dict.93): + let Dict.978 : {} = Struct {}; + let Dict.979 : {} = Struct {}; + let Dict.980 : {} = Struct {}; + let Dict.977 : {{List {Str, I64}, List U64, List I8, U64}, {}, {}, {}} = CallByName Inspect.39 Dict.93 Dict.978 Dict.979 Dict.980; + let Dict.976 : Str = CallByName Inspect.31 Dict.977 Dict.95; + ret Dict.976; + +procedure Hash.19 (Hash.39, Hash.40): + let Hash.79 : List U8 = CallByName Str.12 Hash.40; + let Hash.78 : {U64, U64} = CallByName Dict.57 Hash.39 Hash.79; + ret Hash.78; + +procedure Inspect.186 (Inspect.187, #Attr.12): + let Inspect.185 : {} = StructAtIndex 3 #Attr.12; + let Inspect.184 : {} = StructAtIndex 2 #Attr.12; + let Inspect.183 : {} = StructAtIndex 1 #Attr.12; + let Inspect.182 : {List {Str, I64}, List U64, List I8, U64} = StructAtIndex 0 #Attr.12; + let Inspect.353 : Str = "{"; + let Inspect.328 : Str = CallByName Inspect.61 Inspect.187 Inspect.353; + let Inspect.329 : {{List {Str, I64}, List U64, List I8, U64}, {}, {}, {}} = Struct {Inspect.182, Inspect.183, Inspect.184, Inspect.185}; + let Inspect.324 : {Str, Int1} = CallByName Inspect.188 Inspect.328 Inspect.329; + let Inspect.325 : {} = Struct {}; + let Inspect.320 : Str = CallByName Inspect.200 Inspect.324; + let Inspect.321 : Str = "}"; + let Inspect.319 : Str = CallByName Inspect.61 Inspect.320 Inspect.321; + ret Inspect.319; + +procedure Inspect.188 (Inspect.189, #Attr.12): + let Inspect.185 : {} = StructAtIndex 3 #Attr.12; + let Inspect.184 : {} = StructAtIndex 2 #Attr.12; + let Inspect.183 : {} = StructAtIndex 1 #Attr.12; + let Inspect.182 : {List {Str, I64}, List U64, List I8, U64} = StructAtIndex 0 #Attr.12; + let Bool.1 : Int1 = CallByName Bool.1; + let Inspect.332 : {Str, Int1} = Struct {Inspect.189, Bool.1}; + let Inspect.333 : {{}, {}} = Struct {Inspect.184, Inspect.185}; + let Inspect.331 : {Str, Int1} = CallByName Dict.10 Inspect.182 Inspect.332 Inspect.333; + ret Inspect.331; + +procedure Inspect.190 (Inspect.334, Inspect.193, Inspect.194, #Attr.12): + let Inspect.185 : {} = StructAtIndex 1 #Attr.12; + let Inspect.184 : {} = StructAtIndex 0 #Attr.12; + let Inspect.191 : Str = StructAtIndex 0 Inspect.334; + let Inspect.192 : Int1 = StructAtIndex 1 Inspect.334; + joinpoint Inspect.351 Inspect.195: + let Inspect.348 : Str = CallByName Inspect.44 Inspect.193; + let Inspect.346 : Str = CallByName Inspect.31 Inspect.348 Inspect.195; + let Inspect.347 : Str = ": "; + let Inspect.340 : Str = CallByName Inspect.61 Inspect.346 Inspect.347; + let Inspect.341 : {I64, {}} = Struct {Inspect.194, Inspect.185}; + let Inspect.337 : Str = CallByName Inspect.196 Inspect.340 Inspect.341; + let Inspect.338 : {} = Struct {}; + let Inspect.336 : {Str, Int1} = CallByName Inspect.198 Inspect.337; + ret Inspect.336; + in + if Inspect.192 then + let Inspect.352 : Str = ", "; + let Inspect.350 : Str = CallByName Inspect.61 Inspect.191 Inspect.352; + jump Inspect.351 Inspect.350; + else + jump Inspect.351 Inspect.191; + +procedure Inspect.196 (Inspect.197, #Attr.12): + let Inspect.185 : {} = StructAtIndex 1 #Attr.12; + let Inspect.194 : I64 = StructAtIndex 0 #Attr.12; + let Inspect.344 : I64 = CallByName Inspect.54 Inspect.194; + let Inspect.343 : Str = CallByName Inspect.31 Inspect.344 Inspect.197; + ret Inspect.343; + +procedure Inspect.198 (Inspect.199): + let Bool.2 : Int1 = CallByName Bool.2; + let Inspect.339 : {Str, Int1} = Struct {Inspect.199, Bool.2}; + ret Inspect.339; + +procedure Inspect.200 (Inspect.326): + let Inspect.327 : Str = StructAtIndex 0 Inspect.326; + ret Inspect.327; + +procedure Inspect.249 (Inspect.250, Inspect.248): + let Inspect.368 : Str = "\""; + let Inspect.367 : Str = CallByName Inspect.61 Inspect.250 Inspect.368; + let Inspect.365 : Str = CallByName Inspect.61 Inspect.367 Inspect.248; + let Inspect.366 : Str = "\""; + let Inspect.364 : Str = CallByName Inspect.61 Inspect.365 Inspect.366; + ret Inspect.364; + +procedure Inspect.277 (Inspect.278, Inspect.276): + let Inspect.359 : Str = CallByName Num.96 Inspect.276; + let Inspect.358 : Str = CallByName Inspect.61 Inspect.278 Inspect.359; + ret Inspect.358; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.30 (Inspect.147): + ret Inspect.147; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.314 : Str = CallByName Inspect.186 Inspect.149 Inspect.305; + ret Inspect.314; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.345 : Str = CallByName Inspect.277 Inspect.149 Inspect.305; + ret Inspect.345; + +procedure Inspect.31 (Inspect.305, Inspect.149): + let Inspect.349 : Str = CallByName Inspect.249 Inspect.149 Inspect.305; + ret Inspect.349; + +procedure Inspect.35 (Inspect.300): + ret Inspect.300; + +procedure Inspect.36 (Inspect.304): + let Inspect.311 : Str = ""; + ret Inspect.311; + +procedure Inspect.39 (Inspect.182, Inspect.183, Inspect.184, Inspect.185): + let Inspect.316 : {{List {Str, I64}, List U64, List I8, U64}, {}, {}, {}} = Struct {Inspect.182, Inspect.183, Inspect.184, Inspect.185}; + let Inspect.315 : {{List {Str, I64}, List U64, List I8, U64}, {}, {}, {}} = CallByName Inspect.30 Inspect.316; + ret Inspect.315; + +procedure Inspect.44 (Inspect.248): + let Inspect.360 : Str = CallByName Inspect.30 Inspect.248; + ret Inspect.360; + +procedure Inspect.5 (Inspect.150): + let Inspect.312 : {List {Str, I64}, List U64, List I8, U64} = CallByName Dict.31 Inspect.150; + let Inspect.309 : {} = Struct {}; + let Inspect.308 : Str = CallByName Inspect.36 Inspect.309; + let Inspect.307 : Str = CallByName Dict.94 Inspect.308 Inspect.312; + ret Inspect.307; + +procedure Inspect.54 (Inspect.276): + let Inspect.354 : I64 = CallByName Inspect.30 Inspect.276; + ret Inspect.354; + +procedure Inspect.61 (Inspect.303, Inspect.298): + let Inspect.323 : Str = CallByName Str.3 Inspect.303 Inspect.298; + dec Inspect.298; + ret Inspect.323; + +procedure List.11 (List.133, List.134): + let List.635 : List I8 = CallByName List.68 List.134; + let List.634 : List I8 = CallByName List.86 List.133 List.134 List.635; + ret List.634; + +procedure List.11 (List.133, List.134): + let List.637 : List U64 = CallByName List.68 List.134; + let List.636 : List U64 = CallByName List.86 List.133 List.134 List.637; + ret List.636; + +procedure List.18 (List.154, List.155, List.156): + let List.554 : U64 = 0i64; + let List.555 : U64 = CallByName List.6 List.154; + let List.553 : {List {Str, I64}, List U64, List I8, U64} = CallByName List.88 List.154 List.155 List.156 List.554 List.555; + ret List.553; + +procedure List.18 (List.154, List.155, List.156): + let List.641 : U64 = 0i64; + let List.642 : U64 = CallByName List.6 List.154; + let List.640 : {Str, Int1} = CallByName List.88 List.154 List.155 List.156 List.641 List.642; + ret List.640; + +procedure List.2 (List.103, List.104): + let List.609 : U64 = CallByName List.6 List.103; + let List.605 : Int1 = CallByName Num.22 List.104 List.609; + if List.605 then + let List.607 : I8 = CallByName List.66 List.103 List.104; + dec List.103; + let List.606 : [C {}, C I8] = TagId(1) List.607; + ret List.606; + else + dec List.103; + let List.604 : {} = Struct {}; + let List.603 : [C {}, C I8] = TagId(0) List.604; + ret List.603; + +procedure List.3 (List.111, List.112, List.113): + let List.566 : {List {Str, I64}, {Str, I64}} = CallByName List.64 List.111 List.112 List.113; + let List.565 : List {Str, I64} = StructAtIndex 0 List.566; + let #Derived_gen.62 : {Str, I64} = StructAtIndex 1 List.566; + dec #Derived_gen.62; + ret List.565; + +procedure List.3 (List.111, List.112, List.113): + let List.589 : {List I8, I8} = CallByName List.64 List.111 List.112 List.113; + let List.588 : List I8 = StructAtIndex 0 List.589; + ret List.588; + +procedure List.3 (List.111, List.112, List.113): + let List.591 : {List U64, U64} = CallByName List.64 List.111 List.112 List.113; + let List.590 : List U64 = StructAtIndex 0 List.591; + ret List.590; + +procedure List.4 (List.119, List.120): + let List.595 : U64 = 1i64; + let List.593 : List {Str, I64} = CallByName List.70 List.119 List.595; + let List.592 : List {Str, I64} = CallByName List.71 List.593 List.120; + ret List.592; + +procedure List.6 (#Attr.2): + let List.601 : U64 = lowlevel ListLen #Attr.2; + ret List.601; + +procedure List.6 (#Attr.2): + let List.602 : U64 = lowlevel ListLen #Attr.2; + ret List.602; + +procedure List.6 (#Attr.2): + let List.639 : U64 = lowlevel ListLen #Attr.2; + ret List.639; + +procedure List.6 (#Attr.2): + let List.651 : U64 = lowlevel ListLen #Attr.2; + ret List.651; + +procedure List.64 (List.108, List.109, List.110): + let List.571 : U64 = CallByName List.6 List.108; + let List.568 : Int1 = CallByName Num.22 List.109 List.571; + if List.568 then + let List.569 : {List {Str, I64}, {Str, I64}} = CallByName List.67 List.108 List.109 List.110; + ret List.569; + else + let List.567 : {List {Str, I64}, {Str, I64}} = Struct {List.108, List.110}; + ret List.567; + +procedure List.64 (List.108, List.109, List.110): + let List.578 : U64 = CallByName List.6 List.108; + let List.575 : Int1 = CallByName Num.22 List.109 List.578; + if List.575 then + let List.576 : {List I8, I8} = CallByName List.67 List.108 List.109 List.110; + ret List.576; + else + let List.574 : {List I8, I8} = Struct {List.108, List.110}; + ret List.574; + +procedure List.64 (List.108, List.109, List.110): + let List.586 : U64 = CallByName List.6 List.108; + let List.583 : Int1 = CallByName Num.22 List.109 List.586; + if List.583 then + let List.584 : {List U64, U64} = CallByName List.67 List.108 List.109 List.110; + ret List.584; + else + let List.582 : {List U64, U64} = Struct {List.108, List.110}; + ret List.582; + +procedure List.66 (#Attr.2, #Attr.3): + let List.608 : I8 = lowlevel ListGetUnsafe #Attr.2 #Attr.3; + ret List.608; + +procedure List.66 (#Attr.2, #Attr.3): + let List.650 : {Str, I64} = lowlevel ListGetUnsafe #Attr.2 #Attr.3; + ret List.650; + +procedure List.67 (#Attr.2, #Attr.3, #Attr.4): + let List.570 : {List {Str, I64}, {Str, I64}} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4; + ret List.570; + +procedure List.67 (#Attr.2, #Attr.3, #Attr.4): + let List.577 : {List I8, I8} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4; + ret List.577; + +procedure List.67 (#Attr.2, #Attr.3, #Attr.4): + let List.585 : {List U64, U64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4; + ret List.585; + +procedure List.68 (#Attr.2): + let List.621 : List I8 = lowlevel ListWithCapacity #Attr.2; + ret List.621; + +procedure List.68 (#Attr.2): + let List.633 : List U64 = lowlevel ListWithCapacity #Attr.2; + ret List.633; + +procedure List.70 (#Attr.2, #Attr.3): + let List.596 : List {Str, I64} = lowlevel ListReserve #Attr.2 #Attr.3; + ret List.596; + +procedure List.71 (#Attr.2, #Attr.3): + let List.594 : List {Str, I64} = lowlevel ListAppendUnsafe #Attr.2 #Attr.3; + ret List.594; + +procedure List.71 (#Attr.2, #Attr.3): + let List.618 : List I8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3; + ret List.618; + +procedure List.71 (#Attr.2, #Attr.3): + let List.630 : List U64 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3; + ret List.630; + +procedure List.86 (#Derived_gen.57, #Derived_gen.58, #Derived_gen.59): + joinpoint List.624 List.135 List.136 List.137: + let List.632 : U64 = 0i64; + let List.626 : Int1 = CallByName Num.24 List.136 List.632; + if List.626 then + let List.631 : U64 = 1i64; + let List.628 : U64 = CallByName Num.75 List.136 List.631; + let List.629 : List U64 = CallByName List.71 List.137 List.135; + jump List.624 List.135 List.628 List.629; + else + ret List.137; + in + jump List.624 #Derived_gen.57 #Derived_gen.58 #Derived_gen.59; + +procedure List.86 (#Derived_gen.7, #Derived_gen.8, #Derived_gen.9): + joinpoint List.612 List.135 List.136 List.137: + let List.620 : U64 = 0i64; + let List.614 : Int1 = CallByName Num.24 List.136 List.620; + if List.614 then + let List.619 : U64 = 1i64; + let List.616 : U64 = CallByName Num.75 List.136 List.619; + let List.617 : List I8 = CallByName List.71 List.137 List.135; + jump List.612 List.135 List.616 List.617; + else + ret List.137; + in + jump List.612 #Derived_gen.7 #Derived_gen.8 #Derived_gen.9; + +procedure List.88 (#Derived_gen.21, #Derived_gen.22, #Derived_gen.23, #Derived_gen.24, #Derived_gen.25): + joinpoint List.643 List.157 List.158 List.159 List.160 List.161: + let List.645 : Int1 = CallByName Num.22 List.160 List.161; + if List.645 then + let List.649 : {Str, I64} = CallByName List.66 List.157 List.160; + inc List.649; + let List.162 : {Str, Int1} = CallByName Dict.129 List.158 List.649 List.159; + let List.648 : U64 = 1i64; + let List.647 : U64 = CallByName Num.51 List.160 List.648; + jump List.643 List.157 List.162 List.159 List.647 List.161; + else + dec List.157; + ret List.158; + in + jump List.643 #Derived_gen.21 #Derived_gen.22 #Derived_gen.23 #Derived_gen.24 #Derived_gen.25; + +procedure List.88 (#Derived_gen.37, #Derived_gen.38, #Derived_gen.39, #Derived_gen.40, #Derived_gen.41): + joinpoint List.556 List.157 List.158 List.159 List.160 List.161: + let List.558 : Int1 = CallByName Num.22 List.160 List.161; + if List.558 then + let List.562 : {Str, I64} = CallByName List.66 List.157 List.160; + inc List.562; + let List.162 : {List {Str, I64}, List U64, List I8, U64} = CallByName Dict.101 List.158 List.562; + let List.561 : U64 = 1i64; + let List.560 : U64 = CallByName Num.51 List.160 List.561; + jump List.556 List.157 List.162 List.159 List.560 List.161; + else + dec List.157; + ret List.158; + in + jump List.556 #Derived_gen.37 #Derived_gen.38 #Derived_gen.39 #Derived_gen.40 #Derived_gen.41; + +procedure Num.117 (#Attr.2): + let Num.311 : I8 = lowlevel NumIntCast #Attr.2; + ret Num.311; + +procedure Num.133 (#Attr.2): + let Num.353 : U64 = lowlevel NumIntCast #Attr.2; + ret Num.353; + +procedure Num.133 (#Attr.2): + let Num.369 : U64 = lowlevel NumIntCast #Attr.2; + ret Num.369; + +procedure Num.133 (#Attr.2): + let Num.370 : U64 = lowlevel NumIntCast #Attr.2; + ret Num.370; + +procedure Num.135 (#Attr.2): + let Num.377 : U128 = lowlevel NumIntCast #Attr.2; + ret Num.377; + +procedure Num.137 (#Attr.2): + let Num.305 : U64 = lowlevel NumIntCast #Attr.2; + ret Num.305; + +procedure Num.21 (#Attr.2, #Attr.3): + let Num.318 : U64 = lowlevel NumMul #Attr.2 #Attr.3; + ret Num.318; + +procedure Num.21 (#Attr.2, #Attr.3): + let Num.375 : U128 = lowlevel NumMul #Attr.2 #Attr.3; + ret Num.375; + +procedure Num.22 (#Attr.2, #Attr.3): + let Num.303 : Int1 = lowlevel NumLt #Attr.2 #Attr.3; + ret Num.303; + +procedure Num.22 (#Attr.2, #Attr.3): + let Num.462 : Int1 = lowlevel NumLt #Attr.2 #Attr.3; + ret Num.462; + +procedure Num.23 (#Attr.2, #Attr.3): + let Num.453 : Int1 = lowlevel NumLte #Attr.2 #Attr.3; + ret Num.453; + +procedure Num.24 (#Attr.2, #Attr.3): + let Num.457 : Int1 = lowlevel NumGt #Attr.2 #Attr.3; + ret Num.457; + +procedure Num.25 (#Attr.2, #Attr.3): + let Num.321 : Int1 = lowlevel NumGte #Attr.2 #Attr.3; + ret Num.321; + +procedure Num.25 (#Attr.2, #Attr.3): + let Num.459 : Int1 = lowlevel NumGte #Attr.2 #Attr.3; + ret Num.459; + +procedure Num.51 (#Attr.2, #Attr.3): + let Num.461 : U64 = lowlevel NumAddWrap #Attr.2 #Attr.3; + ret Num.461; + +procedure Num.69 (#Attr.2, #Attr.3): + let Num.302 : U64 = lowlevel NumBitwiseAnd #Attr.2 #Attr.3; + ret Num.302; + +procedure Num.70 (#Attr.2, #Attr.3): + let Num.351 : U64 = lowlevel NumBitwiseXor #Attr.2 #Attr.3; + ret Num.351; + +procedure Num.71 (#Attr.2, #Attr.3): + let Num.393 : U64 = lowlevel NumBitwiseOr #Attr.2 #Attr.3; + ret Num.393; + +procedure Num.72 (#Attr.2, #Attr.3): + let Num.411 : U64 = lowlevel NumShiftLeftBy #Attr.2 #Attr.3; + ret Num.411; + +procedure Num.74 (#Attr.2, #Attr.3): + let Num.371 : U128 = lowlevel NumShiftRightZfBy #Attr.2 #Attr.3; + ret Num.371; + +procedure Num.74 (#Attr.2, #Attr.3): + let Num.374 : U64 = lowlevel NumShiftRightZfBy #Attr.2 #Attr.3; + ret Num.374; + +procedure Num.75 (#Attr.2, #Attr.3): + let Num.448 : U64 = lowlevel NumSubWrap #Attr.2 #Attr.3; + ret Num.448; + +procedure Num.77 (#Attr.2, #Attr.3): + let Num.306 : U64 = lowlevel NumSubSaturated #Attr.2 #Attr.3; + ret Num.306; + +procedure Num.96 (#Attr.2): + let Num.460 : Str = lowlevel NumToStr #Attr.2; + ret Num.460; + +procedure Str.12 (#Attr.2): + let Str.293 : List U8 = lowlevel StrToUtf8 #Attr.2; + ret Str.293; + +procedure Str.3 (#Attr.2, #Attr.3): + let Str.294 : Str = lowlevel StrConcat #Attr.2 #Attr.3; + ret Str.294; + +procedure Test.0 (): + let Test.9 : Str = "a"; + let Test.10 : I64 = 1i64; + let Test.5 : {Str, I64} = Struct {Test.9, Test.10}; + let Test.7 : Str = "b"; + let Test.8 : I64 = 2i64; + let Test.6 : {Str, I64} = Struct {Test.7, Test.8}; + let Test.4 : List {Str, I64} = Array [Test.5, Test.6]; + let Test.3 : {List {Str, I64}, List U64, List I8, U64} = CallByName Dict.12 Test.4; + let Test.2 : Str = CallByName Inspect.5 Test.3; + let Test.1 : Str = CallByName Inspect.35 Test.2; + ret Test.1; diff --git a/crates/compiler/test_mono/src/tests.rs b/crates/compiler/test_mono/src/tests.rs index 9d5874be60..091e20565e 100644 --- a/crates/compiler/test_mono/src/tests.rs +++ b/crates/compiler/test_mono/src/tests.rs @@ -3420,3 +3420,19 @@ fn inspect_derived_list() { "# ) } + +#[mono_test(large_stack = "true")] +fn inspect_derived_dict() { + indoc!( + r#" + app "test" + imports [] + provides [main] to "./platform" + + main = + Dict.fromList [("a", 1), ("b", 2)] + |> Inspect.inspect + |> Inspect.toDbgStr + "# + ) +} From aeabf96e8008434fad5e7067d15f088bad3d57ea Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 12:50:45 -0800 Subject: [PATCH 31/40] update inspect examples --- examples/Community.roc | 72 +--------- examples/GuiFormatter.roc | 18 ++- examples/LogFormatter.roc | 246 ----------------------------------- examples/inspect-logging.roc | 3 +- 4 files changed, 18 insertions(+), 321 deletions(-) delete mode 100644 examples/LogFormatter.roc diff --git a/examples/Community.roc b/examples/Community.roc index 7be09c317a..69543e959f 100644 --- a/examples/Community.roc +++ b/examples/Community.roc @@ -14,12 +14,7 @@ interface Community Community := { people : List Person, friends : List (Set Nat), -} - implements [ - Inspect { - toInspector: inspectCommunity, - }, - ] +} implements [Inspect] Person := { firstName : Str, @@ -27,12 +22,7 @@ Person := { age : U8, hasBeard : Bool, favoriteColor : Color, -} - implements [ - Inspect { - toInspector: inspectPerson, - }, - ] +} implements [Inspect] Color : [ Red, @@ -90,61 +80,3 @@ walkFriendNames = \@Community { people, friends }, s0, nextFn -> (nextFn s1 personName friendNames, id + 1) out -# The functions below will be auto-generated in the future -inspectCommunity : Community -> Inspector f where f implements InspectFormatter -inspectCommunity = \@Community { people, friends } -> - f0 <- Inspect.custom - [ - { key: "people", value: Inspect.list people List.walk Inspect.toInspector }, - { - key: "friends", - value: Inspect.list - friends - List.walk - (\s -> Inspect.set - s - Set.walk - (\num -> num |> Num.toU64 |> Inspect.u64) - ), - # value: Inspect.dict - # (@Community { people, friends }) - # walkFriendNames - # Inspect.str - # (\s -> Inspect.set s Set.walk Inspect.str), - }, - ] - |> Inspect.record - |> Inspect.apply f0 - -inspectPerson : Person -> Inspector f where f implements InspectFormatter -inspectPerson = \@Person { firstName, lastName, age, hasBeard, favoriteColor } -> - # In practice, this would never be done manually due to autoderive. - # Instead you would just write: - # Inspect.inspect innerRecord - # This is what the auto-derive would generate. - - f0 <- Inspect.custom - - favoriteColorTag = - when favoriteColor is - Red -> - Inspect.tag "Red" [] - - Green -> - Inspect.tag "Green" [] - - Blue -> - Inspect.tag "Blue" [] - - RGB (r, g, b) -> - Inspect.tag "RGB" [Inspect.tuple [Inspect.u8 r, Inspect.u8 g, Inspect.u8 b]] - - [ - { key: "firstName", value: Inspect.str firstName }, - { key: "lastName", value: Inspect.str lastName }, - { key: "age", value: Inspect.u8 age }, - { key: "hasBeard", value: Inspect.bool hasBeard }, - { key: "favoriteColor", value: favoriteColorTag }, - ] - |> Inspect.record - |> Inspect.apply f0 diff --git a/examples/GuiFormatter.roc b/examples/GuiFormatter.roc index 615edb15c8..1a060911a1 100644 --- a/examples/GuiFormatter.roc +++ b/examples/GuiFormatter.roc @@ -25,6 +25,7 @@ GuiFormatter := { nodes : List Elem } record: record, bool: bool, str: str, + function: function, opaque: opaque, u8: u8, i8: i8, @@ -36,6 +37,7 @@ GuiFormatter := { nodes : List Elem } i64: i64, u128: u128, i128: i128, + nat: nat, f32: f32, f64: f64, dec: dec, @@ -149,10 +151,15 @@ str = \s -> f0 <- Inspect.custom addNode f0 (Text "\"\(s)\"") -opaque : Str -> Inspector GuiFormatter -opaque = \s -> +opaque : * -> Inspector GuiFormatter +opaque = \_ -> f0 <- Inspect.custom - addNode f0 (Text "<\(s)>") + addNode f0 (Text "") + +function : * -> Inspector GuiFormatter +function = \_ -> + f0 <- Inspect.custom + addNode f0 (Text "") u8 : U8 -> Inspector GuiFormatter u8 = \num -> @@ -204,6 +211,11 @@ i128 = \num -> f0 <- Inspect.custom addNode f0 (num |> Num.toStr |> Text) +nat : Nat -> Inspector GuiFormatter +nat = \num -> + f0 <- Inspect.custom + addNode f0 (num |> Num.toStr |> Text) + f32 : F32 -> Inspector GuiFormatter f32 = \num -> f0 <- Inspect.custom diff --git a/examples/LogFormatter.roc b/examples/LogFormatter.roc deleted file mode 100644 index a9a015e58c..0000000000 --- a/examples/LogFormatter.roc +++ /dev/null @@ -1,246 +0,0 @@ -interface LogFormatter - exposes [ - LogFormatter, - toStr, - ] - imports [] - -## Creates String representations of Roc values, for use in inspect-logging.roc - -LogFormatter := { data : Str } - implements [ - InspectFormatter { - init: init, - list: list, - set: set, - dict: dict, - tag: tag, - tuple: tuple, - record: record, - bool: bool, - str: str, - opaque: opaque, - u8: u8, - i8: i8, - u16: u16, - i16: i16, - u32: u32, - i32: i32, - u64: u64, - i64: i64, - u128: u128, - i128: i128, - f32: f32, - f64: f64, - dec: dec, - - }, - ] - -init : {} -> LogFormatter -init = \{} -> @LogFormatter { data: "" } - -list : list, ElemWalker (LogFormatter, Bool) list elem, (elem -> Inspector LogFormatter) -> Inspector LogFormatter -list = \content, walkFn, toInspector -> - f0 <- Inspect.custom - write f0 "[" - |> \f1 -> - (f2, prependSep), elem <- walkFn content (f1, Bool.false) - f3 = - if prependSep then - write f2 ", " - else - f2 - - elem - |> toInspector - |> Inspect.apply f3 - |> \f4 -> (f4, Bool.true) - |> .0 - |> write "]" - -set : set, ElemWalker (LogFormatter, Bool) set elem, (elem -> Inspector LogFormatter) -> Inspector LogFormatter -set = \content, walkFn, toInspector -> - f0 <- Inspect.custom - write f0 "{" - |> \f1 -> - (f2, prependSep), elem <- walkFn content (f1, Bool.false) - f3 = - if prependSep then - write f2 ", " - else - f2 - - elem - |> toInspector - |> Inspect.apply f3 - |> \f4 -> (f4, Bool.true) - |> .0 - |> write "}" - -dict : dict, KeyValWalker (LogFormatter, Bool) dict key value, (key -> Inspector LogFormatter), (value -> Inspector LogFormatter) -> Inspector LogFormatter -dict = \d, walkFn, keyToInspector, valueToInspector -> - f0 <- Inspect.custom - write f0 "{" - |> \f1 -> - (f2, prependSep), key, value <- walkFn d (f1, Bool.false) - f3 = - if prependSep then - write f2 ", " - else - f2 - - Inspect.apply (keyToInspector key) f3 - |> write ": " - |> \x -> Inspect.apply (valueToInspector value) x - |> \f4 -> (f4, Bool.true) - |> .0 - |> write "}" - -tag : Str, List (Inspector LogFormatter) -> Inspector LogFormatter -tag = \name, fields -> - if List.isEmpty fields then - f0 <- Inspect.custom - write f0 name - else - f0 <- Inspect.custom - write f0 "(" - |> write name - |> \f1 -> - f2, inspector <- List.walk fields f1 - write f2 " " - |> \x -> Inspect.apply inspector x - |> write ")" - -tuple : List (Inspector LogFormatter) -> Inspector LogFormatter -tuple = \fields -> - f0 <- Inspect.custom - write f0 "(" - |> \f1 -> - (f2, prependSep), inspector <- List.walk fields (f1, Bool.false) - f3 = - if prependSep then - write f2 ", " - else - f2 - - Inspect.apply inspector f3 - |> \f4 -> (f4, Bool.true) - |> .0 - |> write ")" - -record : List { key : Str, value : Inspector LogFormatter } -> Inspector LogFormatter -record = \fields -> - f0 <- Inspect.custom - write f0 "{" - |> \f1 -> - (f2, prependSep), { key, value } <- List.walk fields (f1, Bool.false) - f3 = - if prependSep then - write f2 ", " - else - f2 - - write f3 key - |> write ": " - |> \x -> Inspect.apply value x - |> \f4 -> (f4, Bool.true) - |> .0 - |> write "}" - -bool : Bool -> Inspector LogFormatter -bool = \b -> - if b then - f0 <- Inspect.custom - write f0 "true" - else - f0 <- Inspect.custom - write f0 "false" - -str : Str -> Inspector LogFormatter -str = \s -> - f0 <- Inspect.custom - f0 - |> write "\"" - |> write s - |> write "\"" - -opaque : Str -> Inspector LogFormatter -opaque = \s -> - f0 <- Inspect.custom - f0 - |> write "<" - |> write s - |> write ">" - -u8 : U8 -> Inspector LogFormatter -u8 = \num -> - f0 <- Inspect.custom - write f0 (num |> Num.toStr) - -i8 : I8 -> Inspector LogFormatter -i8 = \num -> - f0 <- Inspect.custom - write f0 (num |> Num.toStr) - -u16 : U16 -> Inspector LogFormatter -u16 = \num -> - f0 <- Inspect.custom - write f0 (num |> Num.toStr) - -i16 : I16 -> Inspector LogFormatter -i16 = \num -> - f0 <- Inspect.custom - write f0 (num |> Num.toStr) - -u32 : U32 -> Inspector LogFormatter -u32 = \num -> - f0 <- Inspect.custom - write f0 (num |> Num.toStr) - -i32 : I32 -> Inspector LogFormatter -i32 = \num -> - f0 <- Inspect.custom - write f0 (num |> Num.toStr) - -u64 : U64 -> Inspector LogFormatter -u64 = \num -> - f0 <- Inspect.custom - write f0 (num |> Num.toStr) - -i64 : I64 -> Inspector LogFormatter -i64 = \num -> - f0 <- Inspect.custom - write f0 (num |> Num.toStr) - -u128 : U128 -> Inspector LogFormatter -u128 = \num -> - f0 <- Inspect.custom - write f0 (num |> Num.toStr) - -i128 : I128 -> Inspector LogFormatter -i128 = \num -> - f0 <- Inspect.custom - write f0 (num |> Num.toStr) - -f32 : F32 -> Inspector LogFormatter -f32 = \num -> - f0 <- Inspect.custom - write f0 (num |> Num.toStr) - -f64 : F64 -> Inspector LogFormatter -f64 = \num -> - f0 <- Inspect.custom - write f0 (num |> Num.toStr) - -dec : Dec -> Inspector LogFormatter -dec = \num -> - f0 <- Inspect.custom - write f0 (num |> Num.toStr) - -write : LogFormatter, Str -> LogFormatter -write = \@LogFormatter { data }, added -> - @LogFormatter { data: Str.concat data added } - -toStr : LogFormatter -> Str -toStr = \@LogFormatter { data } -> data diff --git a/examples/inspect-logging.roc b/examples/inspect-logging.roc index 147ad05e26..1054c68171 100644 --- a/examples/inspect-logging.roc +++ b/examples/inspect-logging.roc @@ -5,7 +5,6 @@ app "inspect-logging" packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.6.0/QOQW08n38nHHrVVkJNiPIjzjvbR3iMjXeFY5w1aT46w.tar.br" } imports [ pf.Stdout, - LogFormatter, Community, ] provides [main] to pf @@ -36,5 +35,5 @@ main = |> Community.addFriend 0 2 |> Community.addFriend 1 2 |> Inspect.inspect - |> LogFormatter.toStr + |> Inspect.toDbgStr |> Stdout.line From 83bf3cbd3ac35601a3f1fd728e4919ae8c214aff Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 12:56:01 -0800 Subject: [PATCH 32/40] update tests --- crates/compiler/test_mono/generated/dict.txt | 40 +++++++++---------- ...ralization_among_large_recursive_group.txt | 14 +++---- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/crates/compiler/test_mono/generated/dict.txt b/crates/compiler/test_mono/generated/dict.txt index f654e628b5..6c0f78543c 100644 --- a/crates/compiler/test_mono/generated/dict.txt +++ b/crates/compiler/test_mono/generated/dict.txt @@ -1,28 +1,28 @@ -procedure Dict.1 (Dict.554): - let Dict.563 : List {[], []} = Array []; +procedure Dict.1 (Dict.557): + let Dict.567 : List {[], []} = Array []; + let Dict.574 : U64 = 0i64; + let Dict.575 : U64 = 8i64; + let Dict.568 : List U64 = CallByName List.11 Dict.574 Dict.575; + let Dict.571 : I8 = CallByName Dict.40; + let Dict.572 : U64 = 8i64; + let Dict.569 : List I8 = CallByName List.11 Dict.571 Dict.572; let Dict.570 : U64 = 0i64; - let Dict.571 : U64 = 8i64; - let Dict.564 : List U64 = CallByName List.11 Dict.570 Dict.571; - let Dict.567 : I8 = CallByName Dict.39; - let Dict.568 : U64 = 8i64; - let Dict.565 : List I8 = CallByName List.11 Dict.567 Dict.568; - let Dict.566 : U64 = 0i64; - let Dict.562 : {List {[], []}, List U64, List I8, U64} = Struct {Dict.563, Dict.564, Dict.565, Dict.566}; - ret Dict.562; + let Dict.566 : {List {[], []}, List U64, List I8, U64} = Struct {Dict.567, Dict.568, Dict.569, Dict.570}; + ret Dict.566; -procedure Dict.39 (): - let Dict.569 : I8 = -128i64; - ret Dict.569; - -procedure Dict.4 (Dict.560): - let Dict.101 : U64 = StructAtIndex 3 Dict.560; - let #Derived_gen.8 : List {[], []} = StructAtIndex 0 Dict.560; +procedure Dict.4 (Dict.564): + let Dict.105 : U64 = StructAtIndex 3 Dict.564; + let #Derived_gen.8 : List {[], []} = StructAtIndex 0 Dict.564; dec #Derived_gen.8; - let #Derived_gen.7 : List U64 = StructAtIndex 1 Dict.560; + let #Derived_gen.7 : List U64 = StructAtIndex 1 Dict.564; dec #Derived_gen.7; - let #Derived_gen.6 : List I8 = StructAtIndex 2 Dict.560; + let #Derived_gen.6 : List I8 = StructAtIndex 2 Dict.564; dec #Derived_gen.6; - ret Dict.101; + ret Dict.105; + +procedure Dict.40 (): + let Dict.573 : I8 = -128i64; + ret Dict.573; procedure List.11 (List.133, List.134): let List.554 : List I8 = CallByName List.68 List.134; diff --git a/crates/compiler/uitest/tests/recursion/generalization_among_large_recursive_group.txt b/crates/compiler/uitest/tests/recursion/generalization_among_large_recursive_group.txt index 5b89442a58..f1f87be404 100644 --- a/crates/compiler/uitest/tests/recursion/generalization_among_large_recursive_group.txt +++ b/crates/compiler/uitest/tests/recursion/generalization_among_large_recursive_group.txt @@ -3,22 +3,22 @@ app "test" provides [main] to "./platform" f = \{} -> -#^{-1} <2722><117>{} -<120>[[f(1)]]-> <116>[Ok <2730>{}]<80>* +#^{-1} <2858><117>{} -<120>[[f(1)]]-> <116>[Ok <2866>{}]<80>* when g {} is -# ^ <2712><2730>{} -<2720>[[g(2)]]-> <72>[Ok <2730>{}]<102>* +# ^ <2848><2866>{} -<2856>[[g(2)]]-> <72>[Ok <2866>{}]<102>* _ -> Ok {} g = \{} -> -#^{-1} <2712><2730>{} -<2720>[[g(2)]]-> <72>[Ok <2730>{}]<102>* +#^{-1} <2848><2866>{} -<2856>[[g(2)]]-> <72>[Ok <2866>{}]<102>* when h {} is -# ^ <2717><2730>{} -<2725>[[h(3)]]-> <94>[Ok <2730>{}]<124>* +# ^ <2853><2866>{} -<2861>[[h(3)]]-> <94>[Ok <2866>{}]<124>* _ -> Ok {} h = \{} -> -#^{-1} <2717><2730>{} -<2725>[[h(3)]]-> <94>[Ok <2730>{}]<124>* +#^{-1} <2853><2866>{} -<2861>[[h(3)]]-> <94>[Ok <2866>{}]<124>* when f {} is -# ^ <2722><117>{} -<120>[[f(1)]]-> <116>[Ok <2730>{}]<80>* +# ^ <2858><117>{} -<120>[[f(1)]]-> <116>[Ok <2866>{}]<80>* _ -> Ok {} main = f {} -# ^ <2732><133>{} -<136>[[f(1)]]-> <138>[Ok <2730>{}]<2731>w_a +# ^ <2868><133>{} -<136>[[f(1)]]-> <138>[Ok <2866>{}]<2867>w_a From 759fa9b7a61ee8ade0cc5f7227affc11b2e4876a Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 13:06:44 -0800 Subject: [PATCH 33/40] roc format --- crates/compiler/builtins/roc/Dict.roc | 1 - crates/compiler/builtins/roc/Inspect.roc | 1 - examples/Community.roc | 6 ++++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/compiler/builtins/roc/Dict.roc b/crates/compiler/builtins/roc/Dict.roc index 11200a420f..172c0e501e 100644 --- a/crates/compiler/builtins/roc/Dict.roc +++ b/crates/compiler/builtins/roc/Dict.roc @@ -130,7 +130,6 @@ isEq = \xs, ys -> hashDict : hasher, Dict k v -> hasher where k implements Hash & Eq, v implements Hash, hasher implements Hasher hashDict = \hasher, dict -> Hash.hashUnordered hasher (toList dict) List.walk - toInspectorDict : Dict k v -> Inspector f where k implements Inspect & Hash & Eq, v implements Inspect, f implements InspectFormatter toInspectorDict = \dict -> fmt <- Inspect.custom diff --git a/crates/compiler/builtins/roc/Inspect.roc b/crates/compiler/builtins/roc/Inspect.roc index 82a31f4a9d..981e528719 100644 --- a/crates/compiler/builtins/roc/Inspect.roc +++ b/crates/compiler/builtins/roc/Inspect.roc @@ -99,7 +99,6 @@ inspect = \val -> (@Inspector valFn) = toInspector val valFn (init {}) - # The current default formatter for inspect. # This just returns a simple string for debugging. # More powerful formatters will likely be wanted in the future. diff --git a/examples/Community.roc b/examples/Community.roc index 69543e959f..8a79d3dd44 100644 --- a/examples/Community.roc +++ b/examples/Community.roc @@ -14,7 +14,8 @@ interface Community Community := { people : List Person, friends : List (Set Nat), -} implements [Inspect] +} + implements [Inspect] Person := { firstName : Str, @@ -22,7 +23,8 @@ Person := { age : U8, hasBeard : Bool, favoriteColor : Color, -} implements [Inspect] +} + implements [Inspect] Color : [ Red, From 77e55c88bf5f3648af913b533a9b07a8657d848a Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 13:23:05 -0800 Subject: [PATCH 34/40] update cli logging test --- crates/cli/tests/cli_run.rs | 2 +- crates/compiler/builtins/roc/Inspect.roc | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/cli/tests/cli_run.rs b/crates/cli/tests/cli_run.rs index 05cdda1c06..9b3dcd6241 100644 --- a/crates/cli/tests/cli_run.rs +++ b/crates/cli/tests/cli_run.rs @@ -942,7 +942,7 @@ mod cli_run { test_roc_app_slim( "examples", "inspect-logging.roc", - r#"{people: [{firstName: "John", lastName: "Smith", age: 27, hasBeard: true, favoriteColor: Blue}, {firstName: "Debby", lastName: "Johnson", age: 47, hasBeard: false, favoriteColor: Green}, {firstName: "Jane", lastName: "Doe", age: 33, hasBeard: false, favoriteColor: (RGB (255, 255, 0))}], friends: [{2}, {2}, {0, 1}]} + r#"{friends: [{2}, {2}, {0, 1}], people: [{age: 27, favoriteColor: Blue, firstName: "John", hasBeard: Bool.true, lastName: "Smith"}, {age: 47, favoriteColor: Green, firstName: "Debby", hasBeard: Bool.false, lastName: "Johnson"}, {age: 33, favoriteColor: (RGB (255, 255, 0)), firstName: "Jane", hasBeard: Bool.false, lastName: "Doe"}]} "#, UseValgrind::Yes, ) diff --git a/crates/compiler/builtins/roc/Inspect.roc b/crates/compiler/builtins/roc/Inspect.roc index 981e528719..ff44d644d7 100644 --- a/crates/compiler/builtins/roc/Inspect.roc +++ b/crates/compiler/builtins/roc/Inspect.roc @@ -258,6 +258,7 @@ dbgStr = \s -> f0 <- custom f0 |> dbgWrite "\"" + # TODO: Should we be escaping strings for dbg/logging? |> dbgWrite s |> dbgWrite "\"" From 0586f2bac027387fb6217ca81f233036ee2cb5ed Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 13:31:26 -0800 Subject: [PATCH 35/40] more formatting --- crates/compiler/builtins/roc/Inspect.roc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/compiler/builtins/roc/Inspect.roc b/crates/compiler/builtins/roc/Inspect.roc index ff44d644d7..a86b83a247 100644 --- a/crates/compiler/builtins/roc/Inspect.roc +++ b/crates/compiler/builtins/roc/Inspect.roc @@ -258,8 +258,7 @@ dbgStr = \s -> f0 <- custom f0 |> dbgWrite "\"" - # TODO: Should we be escaping strings for dbg/logging? - |> dbgWrite s + |> dbgWrite s # TODO: Should we be escaping strings for dbg/logging? |> dbgWrite "\"" dbgOpaque : * -> Inspector DbgFormatter From 4b911524acc2302fb25f1515b2fae4a305c47955 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 13:59:23 -0800 Subject: [PATCH 36/40] update gen_abilities tests to include edge case --- crates/compiler/test_gen/src/gen_abilities.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/crates/compiler/test_gen/src/gen_abilities.rs b/crates/compiler/test_gen/src/gen_abilities.rs index 50fbbeb243..31fa164355 100644 --- a/crates/compiler/test_gen/src/gen_abilities.rs +++ b/crates/compiler/test_gen/src/gen_abilities.rs @@ -2222,6 +2222,7 @@ mod inspect { app "test" provides [main] to "./platform" main = [ + Inspect.inspect 0, # Num a Inspect.inspect 1u8, # U8 Inspect.inspect 2i8, # I8 Inspect.inspect 3u16, # U16 @@ -2232,13 +2233,14 @@ mod inspect { Inspect.inspect 8i64, # I64 Inspect.inspect 9u128, # U128 Inspect.inspect 10i128, # I128 - Inspect.inspect 1.1f32, # F32 + Inspect.inspect 0.5, # Frac a + Inspect.inspect 1.5f32, # F32 Inspect.inspect 2.2f64, # F64 Inspect.inspect (1.1dec + 2.2), # Dec ] |> List.map Inspect.toDbgStr |> Str.joinWith ", " "# ), - RocStr::from("42, 5, 0.3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1.1, 2.2, 3.3"), + RocStr::from("0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0.5, 1.5, 2.2, 3.3"), RocStr ); } @@ -2255,9 +2257,10 @@ mod inspect { Inspect.inspect [], # List * Inspect.inspect [0, 1, 2], # List (Num *) Inspect.inspect [1, 0x2, 3], # List (Int *) - Inspect.inspect [0.1 + 0.2, 0.4], # List (Frac *) + # TODO: Re-enable when Frac is fixed for inspect. + # Inspect.inspect [0.1 + 0.2, 0.4], # List (Frac *) Inspect.inspect [1u8, 2u8], # List U8 - Inspect.inspect ["foo"], # List Str + Inspect.inspect ["foo"], # List Str ] |> List.map Inspect.toDbgStr |> Str.joinWith ", " "# ), From 01032c3b119c49c57de7fff3dc481b7cb28b5d17 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 15:04:38 -0800 Subject: [PATCH 37/40] remove empty list test case for inspect --- crates/compiler/test_gen/src/gen_abilities.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/crates/compiler/test_gen/src/gen_abilities.rs b/crates/compiler/test_gen/src/gen_abilities.rs index 31fa164355..2bc4791b75 100644 --- a/crates/compiler/test_gen/src/gen_abilities.rs +++ b/crates/compiler/test_gen/src/gen_abilities.rs @@ -2254,17 +2254,15 @@ mod inspect { app "test" provides [main] to "./platform" main = [ - Inspect.inspect [], # List * Inspect.inspect [0, 1, 2], # List (Num *) Inspect.inspect [1, 0x2, 3], # List (Int *) - # TODO: Re-enable when Frac is fixed for inspect. - # Inspect.inspect [0.1 + 0.2, 0.4], # List (Frac *) + Inspect.inspect [0.1 + 0.2, 0.4], # List (Frac *) Inspect.inspect [1u8, 2u8], # List U8 Inspect.inspect ["foo"], # List Str ] |> List.map Inspect.toDbgStr |> Str.joinWith ", " "# ), - RocStr::from("[], [0, 1, 2], [1, 2, 3], [0.3, 0.4], [1, 2], [\"foo\"]"), + RocStr::from("[0, 1, 2], [1, 2, 3], [0.3, 0.4], [1, 2], [\"foo\"]"), RocStr ); } From 1b7fdc9522831cd3e21bc41f62e8fab131c241fd Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 15:22:30 -0800 Subject: [PATCH 38/40] deal with Frac * -> Dec --- crates/compiler/derive_key/src/inspect.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/compiler/derive_key/src/inspect.rs b/crates/compiler/derive_key/src/inspect.rs index 1fa026863d..8319cbc7b1 100644 --- a/crates/compiler/derive_key/src/inspect.rs +++ b/crates/compiler/derive_key/src/inspect.rs @@ -141,8 +141,11 @@ impl FlatInspectable { AliasKind::Structural => { Self::from_var(subs, real_var) } + // Special case, an unbound `Frac *` will become a `Dec`. + AliasKind::Opaque if matches!(*subs.get_content_without_compacting(real_var), Content::FlexVar(_) | Content::FlexAbleVar(_, _)) => { + Immediate(Symbol::INSPECT_DEC) + } AliasKind::Opaque if sym.is_builtin() => { - // TODO: Is this correct for all builtins? It is at least required for the Num wrapper types. Self::from_var(subs, real_var) } AliasKind::Opaque => { From c49046291a713733b5acd26414d89f25264ca398 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 16:29:15 -0800 Subject: [PATCH 39/40] misc cleanup suggestions --- crates/compiler/derive/src/inspect.rs | 7 --- crates/compiler/derive_key/src/inspect.rs | 1 - crates/compiler/solve/src/ability.rs | 20 ++----- crates/compiler/solve/src/specialize.rs | 73 +++++++++++++---------- crates/compiler/types/src/subs.rs | 4 +- 5 files changed, 47 insertions(+), 58 deletions(-) diff --git a/crates/compiler/derive/src/inspect.rs b/crates/compiler/derive/src/inspect.rs index 05e7558bea..75536efea7 100644 --- a/crates/compiler/derive/src/inspect.rs +++ b/crates/compiler/derive/src/inspect.rs @@ -111,8 +111,6 @@ pub(crate) fn derive_to_inspector( fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) { // Build \lst -> list, List.walk, (\elem -> Inspect.toInspector elem) - // - // TODO eta reduce this baby ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use Expr::*; @@ -954,11 +952,6 @@ fn to_inspector_tag_union( } /// Lift `inspector` to `Inspect.custom \fmt -> Inspect.apply inspector fmt` -/// -/// TODO: currently it appears that just `inspector` is not isomorphic to the lift, on the -/// monomorphization level, even though we would think it is. In particular, unspecialized lambda -/// sets fail to resolve when we use the non-lifted version. -/// More investigation is needed to figure out why. fn wrap_in_inspect_custom( env: &mut Env, inspector: Expr, diff --git a/crates/compiler/derive_key/src/inspect.rs b/crates/compiler/derive_key/src/inspect.rs index 8319cbc7b1..a796efc63d 100644 --- a/crates/compiler/derive_key/src/inspect.rs +++ b/crates/compiler/derive_key/src/inspect.rs @@ -205,7 +205,6 @@ impl FlatInspectable { Symbol::NUM_F32 | Symbol::NUM_BINARY32 => Some(Immediate(Symbol::INSPECT_F32)), Symbol::NUM_F64 | Symbol::NUM_BINARY64 => Some(Immediate(Symbol::INSPECT_F64)), Symbol::NUM_NAT | Symbol::NUM_NATURAL => Some(Immediate(Symbol::INSPECT_NAT)), - // TODO List, Dict, Set, etc. _ => None, } } diff --git a/crates/compiler/solve/src/ability.rs b/crates/compiler/solve/src/ability.rs index 889e3d5425..47e33d62e3 100644 --- a/crates/compiler/solve/src/ability.rs +++ b/crates/compiler/solve/src/ability.rs @@ -381,7 +381,6 @@ impl ObligationCache { let ImplKey { opaque, ability } = impl_key; // Every type has the Inspect ability automatically, even opaques with no `implements` declaration. - // (Those opaques get a default implementation that returns something along the lines of "") let is_inspect = ability == Symbol::INSPECT_INSPECT_ABILITY; let has_known_impl = is_inspect || abilities_store.has_declared_implementation(opaque, ability); @@ -865,9 +864,8 @@ impl DerivableVisitor for DeriveInspect { const ABILITY_SLICE: SubsSlice = Subs::AB_INSPECT; #[inline(always)] - fn is_derivable_builtin_opaque(symbol: Symbol) -> bool { - // TODO: Should this just be true? All values are always inspectable. - is_builtin_number_alias(symbol) || is_builtin_bool_alias(symbol) + fn is_derivable_builtin_opaque(_: Symbol) -> bool { + true } #[inline(always)] @@ -876,18 +874,8 @@ impl DerivableVisitor for DeriveInspect { } #[inline(always)] - fn visit_apply(var: Variable, symbol: Symbol) -> Result { - if matches!( - symbol, - Symbol::LIST_LIST | Symbol::SET_SET | Symbol::DICT_DICT | Symbol::STR_STR, - ) { - Ok(Descend(true)) - } else { - Err(NotDerivable { - var, - context: NotDerivableContext::NoContext, - }) - } + fn visit_apply(_: Variable, _: Symbol) -> Result { + Ok(Descend(true)) } #[inline(always)] diff --git a/crates/compiler/solve/src/specialize.rs b/crates/compiler/solve/src/specialize.rs index 7673eb5bd4..54b6fd358a 100644 --- a/crates/compiler/solve/src/specialize.rs +++ b/crates/compiler/solve/src/specialize.rs @@ -628,38 +628,7 @@ fn make_specialization_decision( } else { // Solving within a module. phase.with_module_abilities_store(opaque.module_id(), |abilities_store| { - let impl_key = ImplKey { - opaque: *opaque, - ability_member, - }; - match abilities_store.get_implementation(impl_key) { - None => { - match ability_member { - // Inspect is special - if there is no implementation for the - // opaque type, we always emit a default implementation. - Symbol::INSPECT_TO_INSPECTOR => SpecializeDecision::Specialize( - Immediate(Symbol::INSPECT_OPAQUE), - ), - _ => { - // Doesn't specialize; an error will already be reported for this. - SpecializeDecision::Drop - } - } - } - Some(MemberImpl::Error) => { - // TODO: probably not right, we may want to choose a derive decision! - SpecializeDecision::Specialize(Opaque(*opaque)) - } - Some(MemberImpl::Impl(specialization_symbol)) => { - match abilities_store.specialization_info(*specialization_symbol) { - Some(_) => SpecializeDecision::Specialize(Opaque(*opaque)), - - // If we expect a specialization impl but don't yet know it, we must hold off - // compacting the lambda set until the specialization is well-known. - None => SpecializeDecision::PendingSpecialization(impl_key), - } - } - } + make_ability_specialization_decision(*opaque, ability_member, abilities_store) }) } } @@ -707,6 +676,46 @@ fn make_specialization_decision( } } +fn make_ability_specialization_decision( + opaque: Symbol, + ability_member: Symbol, + abilities_store: &AbilitiesStore, +) -> SpecializeDecision { + use SpecializationTypeKey::*; + let impl_key = ImplKey { + opaque, + ability_member, + }; + match abilities_store.get_implementation(impl_key) { + None => { + match ability_member { + // Inspect is special - if there is no implementation for the + // opaque type, we always emit a default implementation. + Symbol::INSPECT_TO_INSPECTOR => { + SpecializeDecision::Specialize(Immediate(Symbol::INSPECT_OPAQUE)) + } + _ => { + // Doesn't specialize; an error will already be reported for this. + SpecializeDecision::Drop + } + } + } + Some(MemberImpl::Error) => { + // TODO: probably not right, we may want to choose a derive decision! + SpecializeDecision::Specialize(Opaque(opaque)) + } + Some(MemberImpl::Impl(specialization_symbol)) => { + match abilities_store.specialization_info(*specialization_symbol) { + Some(_) => SpecializeDecision::Specialize(Opaque(opaque)), + + // If we expect a specialization impl but don't yet know it, we must hold off + // compacting the lambda set until the specialization is well-known. + None => SpecializeDecision::PendingSpecialization(impl_key), + } + } + } +} + #[allow(clippy::too_many_arguments)] fn get_specialization_lambda_set_ambient_function( subs: &mut Subs, diff --git a/crates/compiler/types/src/subs.rs b/crates/compiler/types/src/subs.rs index 7b3f6abf28..7eae9468c0 100644 --- a/crates/compiler/types/src/subs.rs +++ b/crates/compiler/types/src/subs.rs @@ -1748,7 +1748,7 @@ impl Subs { tag_names.push(TagName("OutOfBounds".into())); // END INIT-TagNames - // IFTTT INIT-SymbolNames + // IFTTT INIT-SymbolSubsSlice let mut symbol_names = Vec::with_capacity(32); symbol_names.push(Symbol::ENCODE_ENCODING); @@ -1757,7 +1757,7 @@ impl Subs { symbol_names.push(Symbol::HASH_HASH_ABILITY); symbol_names.push(Symbol::BOOL_EQ); symbol_names.push(Symbol::INSPECT_INSPECT_ABILITY); - // END INIT-SymbolNames + // END INIT-SymbolSubsSlice // IFTTT INIT-VariableSubsSlice let variables = vec![Variable::STR]; From 248976d632b0827032171ba00b8372dbd59a39c0 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 28 Nov 2023 16:40:32 -0800 Subject: [PATCH 40/40] fix wasm tests --- crates/compiler/gen_wasm/src/low_level.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/compiler/gen_wasm/src/low_level.rs b/crates/compiler/gen_wasm/src/low_level.rs index 683fbd61c6..cb66ab10c2 100644 --- a/crates/compiler/gen_wasm/src/low_level.rs +++ b/crates/compiler/gen_wasm/src/low_level.rs @@ -2252,7 +2252,7 @@ impl<'a> LowLevelCall<'a> { fn num_to_str(&self, backend: &mut WasmBackend<'a, '_>) { let arg_layout = backend.storage.symbol_layouts[&self.arguments[0]]; - match backend.layout_interner.get_repr(arg_layout) { + match backend.layout_interner.runtime_representation(arg_layout) { LayoutRepr::Builtin(Builtin::Int(width)) => { self.load_args_and_call_zig(backend, &bitcode::STR_FROM_INT[width]) }