Get first inspect for non-Inspect-implementing opaques specialized

This commit is contained in:
Ayaz Hafiz 2023-09-12 12:11:36 -05:00 committed by Brendan Hansknecht
parent c87e3e7413
commit 5c805ce80f
No known key found for this signature in database
GPG key ID: 0EA784685083E75B
6 changed files with 75 additions and 44 deletions

View file

@ -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>`
opaque : Inspector f where f implements InspectFormatter
opaque : * -> Inspector f where f implements InspectFormatter
# In text, this would render as `<function>`
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

View file

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

View file

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

View file

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

View file

@ -634,8 +634,17 @@ fn make_specialization_decision<P: Phase>(
};
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!

View file

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