mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 12:18:19 +00:00
Get first inspect for non-Inspect-implementing opaques specialized
This commit is contained in:
parent
c87e3e7413
commit
5c805ce80f
6 changed files with 75 additions and 44 deletions
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue