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: Nov 08 2025 at 12:13 UTC