I have a PR for making Inspect
a builtin - it's getting this:
---- gen_records::optional_field_destructure_module stdout ----
thread 'gen_records::optional_field_destructure_module' panicked at 'wasm-ld: error: unknown file type: /tmp/nix-shell.zczC9A/.tmpxRLGKA/test_11934200539654871657.a
This can happen if multiple tests have the same input string', crates/compiler/test_gen/src/helpers/llvm.rs:505:13
stack backtrace:
0: rust_begin_unwind
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/panicking.rs:578:5
1: core::panicking::panic_fmt
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/panicking.rs:67:14
2: test_gen::helpers::llvm::compile_to_wasm_bytes
3: test_gen::helpers::llvm::assert_wasm_evals_to_help
4: core::ops::function::FnOnce::call_once
5: core::ops::function::FnOnce::call_once
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/ops/function.rs:250:5
anyone recognize this error?
the hint of "This can happen if multiple tests have the same input string" doesn't seem likely, since I didn't change any test names
separately from that test failure,
when I run roc check examples/inspect-logging.roc
it passes, but roc build
on it now panics with:
'more argument symbols than arguments (according to the layout) for
Set.walk
', crates/compiler/mono/src/ir.rs:3967:35
or sometimes:
'more argument symbols than arguments (according to the layout) for
List.walk
', crates/compiler/mono/src/ir.rs:3967:35
roc build
succeeded on it when Inspect
was in userpsace; it only started failing when I moved it into a builtin
wasm-ld: error: unknown file type
is a common flaky error on nix apple silicon, I've restarted the workflow
It passed :)
nice, thanks! :smiley:
ok, so then there's just the roc build
panic :thinking:
so https://github.com/roc-lang/roc/pull/5747 passes now. Looking ahead to the next step, these are all goals:
Inspect.inspect
take *
rather than something with the Inspect
abilityInspect
be auto-derived for everything but opaque typesimplements Inspect
to your opaque type, it automatically gives you the Inspect
of the wrapped type (e.g. Email := Str implements [Inspect]
makes Email
have the same Inspect
as a Str
)it's straightforward to have it be auto-derived for everything except opaque types, and then have opaque types be able to opt into it by just adding implements [Inspect]
because that's basically how Encoding
works, except this would auto-derive for functions too (which is straightforward)
the tricky part is having Inspect.inspect
take *
and still return something (namely, "<opaque>"
or something like that) for opaque types that don't have Inspect
because it still needs to use their Inspect
implementations if they actually have one
one idea is that we have Inspect.inspect
be implemented as a RunLowLevel
operation which looks at the specialized type, checks if it has the Inspect
ability (somehow - I don't actually know if that's possible after specialization, but I assume if anyone knows it's @Ayaz Hafiz :big_smile:), calls the appropriate ability member if it does have the ability, and then if it doesn't have the ability, defaults to "<opaque>"
because we know that's what it has to be if it doesn't have the Inspect
ability
does that sound like a viable approach? Is there a better one?
i think the best approach is implementing Inspect.inspect to be solved and code-gened in mono as any other function and ability member would. adding an auto-derived for every type would give resolution of the correct implementation for free.
as in, make the type of Inspect.inspect
's argument have an ability constraint?
I'm not sure how that strategy would be able to distinguish between "this opaque type has been marked as implements Inspect
and therefore we should auto derive an implementation that shows its internal contents" and "this opaque type has not been marked as implements Inspect
and so we should still auto-derive an implementation, but this time the implementation does not reveal any internals of the opaque type"
why wouldn't it be able to distinguish that? we already have that for all other abilities with opaques and structural types
we do? huh!
so just to be clear, this can work?
Foo := Str implements Inspect
Bar := Str
foo = Inspect.inspect (@Foo "blah") # foo = "blah"
bar = Inspect.inspect (@Bar "blah") # bar = "<opaque>"
...with Inspect.inspect
's argument having an Inspect
constraint?
I don't see why not
well great! haha
@Ayaz Hafiz ok I added it to the obligation checker here: https://github.com/roc-lang/roc/pull/5775/files#diff-e91d42161e55644e56ab4625459a2e71ac01628a9ff67c0f030c0ff1db9bf3ab - and also in that (draft) PR I added some derive_key
stuff...but the obligation checker part just says "there's an implementation there" as far as I can tell, but it doesn't say where
so I'm not sure where to put that, given that (as I understand it) the derive_key
part is for when someone writes implements
on the opaque type they're defining in order to opt into the derivation that actually renders the internals of the opaque type...or is that the ad-hoc one which gets rendered if they don't write implements
at all?
take a look at adding to https://github.com/roc-lang/roc/blob/263fb5632f8b73703d4362648f1e7115f893342b/crates/compiler/solve/src/specialize.rs#L614
specifically opaques without a specific inspect impl should fall into https://github.com/roc-lang/roc/blob/263fb5632f8b73703d4362648f1e7115f893342b/crates/compiler/solve/src/specialize.rs#L663-L664 if you update builtin_module_with_unlisted_ability_impl
Last updated: Jul 06 2025 at 12:14 UTC