Stream: contributing

Topic: auto-derived Inspect


view this post on Zulip Richard Feldman (Nov 26 2023 at 16:40):

so I have a bunch of work on auto-derived Inspect, but I think I should really focus on documentation and FAQs and such this final week before advent of code - is anyone else able to pick that up?

view this post on Zulip Richard Feldman (Nov 26 2023 at 16:40):

I really think it'd help people out a lot to have a reliable dbg for Advent of Code, and this is the only nontrivial blocker to that!

view this post on Zulip Brendan Hansknecht (Nov 26 2023 at 16:51):

What's the current state?

view this post on Zulip Richard Feldman (Nov 26 2023 at 17:07):

it's partially implemented on a branch, but getting an error in tests

view this post on Zulip Richard Feldman (Nov 26 2023 at 17:36):

if you're interested in it, I'd be happy to chat about it and get you up to speed! :smiley:

view this post on Zulip Brendan Hansknecht (Nov 26 2023 at 18:16):

I have a lot of random stuff I want to get to, but this seems more important

view this post on Zulip Brendan Hansknecht (Nov 28 2023 at 01:49):

What is the best way to start understanding a bug with an error like:

thread 'gen_abilities::inspect_bool' panicked at 'assertion failed: `(left == right)`
  left: `0`,
 right: `1`: (LambdaSet([], ^<2128>), Func([<260>EmptyRecord,], <2130=263>LambdaSet([], ^<2128>), <264>Opaque(`Inspect.DbgFormatter`, [], <3300>{ 'data' : Apply(`Str.Str`, []), }<3301>)))', crates/compiler/mono/src/ir.rs:6129:9

or

thread 'gen_abilities::inspect_num' panicked at 'No lambda set at region 2 found', crates/compiler/types/src/subs.rs:6087:5

view this post on Zulip Ayaz Hafiz (Nov 28 2023 at 02:15):

Usually this means the specialization of an ability member for a specific type is missing or under defined. Do you what a lambda region is?

view this post on Zulip Brendan Hansknecht (Nov 28 2023 at 02:17):

I do not know what a lambda region is. Have not interacted with them before.

view this post on Zulip Brendan Hansknecht (Nov 28 2023 at 02:25):

Also, at least for a type like Bool.Bool where the inspector just generates a direct call to the immediate Inspect.bool, I don't see a location where were are doing anything complex within the derive code for inspect itself. Totally see how dict, list, record, etc are complex and could hit bigger issues, but unsure why something like just Bool.Bool would hit some sort of issue.

view this post on Zulip Ayaz Hafiz (Nov 28 2023 at 02:38):

what’s the definition of inspect for Bool?

view this post on Zulip Ayaz Hafiz (Nov 28 2023 at 02:39):

On mobile so I’ll take a deeper look later and explain lambda regions but I can explain broad details

view this post on Zulip Brendan Hansknecht (Nov 28 2023 at 02:41):

in ability type definition: bool : Bool -> Inspector f where f implements InspectFormatter

With Inspector as Inspector f := f -> f where f implements InspectFormatter

Specific bool impl it should be using:

dbgBool : Bool -> Inspector DbgFormatter
dbgBool = \b ->
    if b then
        f0 <- custom
        dbgWrite f0 "true"
    else
        f0 <- custom
        dbgWrite f0 "false"

view this post on Zulip Brendan Hansknecht (Nov 28 2023 at 02:42):

Oh, and I guess custom just expose the opaque wrapper:

custom : (f -> f) -> Inspector f where f implements InspectFormatter
custom = @Inspector

view this post on Zulip Ayaz Hafiz (Nov 28 2023 at 02:44):

what’s the definition of dbgWrite?

view this post on Zulip Brendan Hansknecht (Nov 28 2023 at 02:44):

Just string concat:

dbgWrite : DbgFormatter, Str -> DbgFormatter
dbgWrite = \@DbgFormatter { data }, added ->
    @DbgFormatter { data: Str.concat data added }

view this post on Zulip Ayaz Hafiz (Nov 28 2023 at 02:45):

Hm that’s weird

view this post on Zulip Ayaz Hafiz (Nov 28 2023 at 02:45):

Okay i’ll take a deeper look when off mobile. do you have a branch?

view this post on Zulip Ayaz Hafiz (Nov 28 2023 at 02:46):

in the meantime, here is the description of a lambda set region: https://github.com/roc-lang/roc/blob/main/crates/compiler/solve/docs/ambient_lambda_set_specialization.md#some-definitions

view this post on Zulip Ayaz Hafiz (Nov 28 2023 at 02:46):

It’s usually missing when a specialization function corresponding to the same arrow as defined in an ability member is missing. But the specialization here seems to have three arrows, like the ability member

view this post on Zulip Brendan Hansknecht (Nov 28 2023 at 02:47):

Been adding to inspect-derive.

The test is run with cargo test -p test_gen -- inspect_bool

view this post on Zulip Brendan Hansknecht (Nov 28 2023 at 02:48):

Was trying to fix bool or num tests before turning to the derive implementations that actually generate code rather than just call an existing function.

view this post on Zulip Ayaz Hafiz (Nov 28 2023 at 02:48):

you might also want to run with ROC_TRACE_COMPACTION=1. It will show some useful specialization traces

view this post on Zulip Brendan Hansknecht (Nov 28 2023 at 03:36):

Looking at the compaction, the main thing I derive is that the failing match looks to be for Inspect.init. That is the function that generates the initial formatter.

view this post on Zulip Ayaz Hafiz (Nov 28 2023 at 05:52):

Given the uitest

app "test" provides [main] to "./platform"

main =
    Inspect.toInspector Bool.true |> Inspect.apply (Inspect.init {}) |> Inspect.toDbgStr
#   ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Bool -[[]]-> Inspector DbgFormatter

we have the trace

===lambda set compaction===
  concrete type: Opaque(`Inspect.DbgFormatter`, [], <2679>{ 'data' : Apply(`Str.Str`, []), }<115>)
  step 1:
    uls_a = { LambdaSet([] + (<2710>Opaque(`Inspect.DbgFormatter`, [], <2679>{ 'data' : Apply(`Str.Str`, []), }<115>):`Inspect.init`:1), ^<2709>),LambdaSet([] + (<2699>Op
aque(`Inspect.DbgFormatter`, [], <2679>{ 'data' : Apply(`Str.Str`, []), }<115>):`Inspect.bool`:2), ^<2694>),LambdaSet([] + (<2706>Opaque(`Inspect.DbgFormatter`, [], <2679
>{ 'data' : Apply(`Str.Str`, []), }<115>):`Inspect.bool`:1), ^<2688>) }
  step 2:
    uls_a' = { LambdaSet([] + (<2710>Opaque(`Inspect.DbgFormatter`, [], <2679>{ 'data' : Apply(`Str.Str`, []), }<115>):`Inspect.init`:1), ^<2709>),LambdaSet([] + (<2699>O
paque(`Inspect.DbgFormatter`, [], <2679>{ 'data' : Apply(`Str.Str`, []), }<115>):`Inspect.bool`:2), ^<2694>),LambdaSet([] + (<2706>Opaque(`Inspect.DbgFormatter`, [], <267
9>{ 'data' : Apply(`Str.Str`, []), }<115>):`Inspect.bool`:1), ^<2688>) }
  step 3:
      SKIP
      =  Func([<74>EmptyRecord,], <2711=77>LambdaSet([], ^<2709>), <78>Opaque(`Inspect.DbgFormatter`, [], <2679>{ 'data' : Apply(`Str.Str`, []), }<115>))

      SKIP
      =  Func([<2682>Opaque(`Inspect.DbgFormatter`, [], <2679>{ 'data' : Apply(`Str.Str`, []), }<115>),], <2693=2685>LambdaSet([], ^<2694>), <2682>Opaque(`Inspect.DbgForm
atter`, [], <2679>{ 'data' : Apply(`Str.Str`, []), }<115>))

      SKIP
      =  Func([<2704>Opaque(`Bool.Bool`, [], <2697>['False' , 'True' , ]<Any(92)>),], <2690=2703>LambdaSet([], ^<2688>), <2702>Opaque(`Inspect.Inspector`, [2692, 2693], <
2694>Func([<2682>Opaque(`Inspect.DbgFormatter`, [], <2679>{ 'data' : Apply(`Str.Str`, []), }<115>),], <2693=2685>LambdaSet([], ^<2694>), <2682>Opaque(`Inspect.DbgFormatte
r`, [], <2679>{ 'data' : Apply(`Str.Str`, []), }<115>))))

view this post on Zulip Ayaz Hafiz (Nov 28 2023 at 05:52):

The skips are suspicious

view this post on Zulip Ayaz Hafiz (Nov 28 2023 at 05:58):

The specialization is getting marked as "Drop" because it hits this branch: https://github.com/roc-lang/roc/blob/d478ec56da88268dd39752c73d42c2f60a20ef38/crates/compiler/solve/src/specialize.rs#L669

view this post on Zulip Ayaz Hafiz (Nov 28 2023 at 05:58):

But why? We are specializing DbgFormatter, which is an opaque type.

view this post on Zulip Ayaz Hafiz (Nov 28 2023 at 05:59):

It's because this condition isn't met: https://github.com/roc-lang/roc/blob/d478ec56da88268dd39752c73d42c2f60a20ef38/crates/compiler/solve/src/specialize.rs#L669

view this post on Zulip Ayaz Hafiz (Nov 28 2023 at 06:00):

I'm not sure why https://github.com/roc-lang/roc/blob/d478ec56da88268dd39752c73d42c2f60a20ef38/crates/compiler/solve/src/ability.rs#L1509
lists Inspect in there. I don't think Inspect declares any opaque types that must be derived but cannot list the abilities they need derived.

view this post on Zulip Ayaz Hafiz (Nov 28 2023 at 06:01):

If we remove that, we get a uitest that looks good

app "test" provides [main] to "./platform"

main =
    Inspect.toInspector Bool.true |> Inspect.apply (Inspect.init {}) |> Inspect.toDbgStr
#   ^^^^^^^^^^^^^^^^^^^ Inspect#Inspect.toInspector(32): Bool -[[Inspect.dbgBool(43)]]-> Inspector DbgFormatter

view this post on Zulip Ayaz Hafiz (Nov 28 2023 at 06:02):

And the gen test fails, but it runs correctly and shows the expected output.

thread 'gen_abilities::inspect_bool' panicked at 'assertion failed: `(left == right)`
  left: `"true, false"`,
 right: `"Bool.true, Bool.false"`: LLVM test failed', crates/compiler/test_gen/src/helpers/llvm.rs:631:13

view this post on Zulip Ayaz Hafiz (Nov 28 2023 at 06:03):

As a side note, I would put all of the inspect gen tests into a mod inspect like is done for hash, encode, decode, etc. It helps a lot with navigating the file.

view this post on Zulip Ayaz Hafiz (Nov 28 2023 at 06:03):

Or split them out into separate module files.

view this post on Zulip Brendan Hansknecht (Nov 28 2023 at 06:04):

thanks!

view this post on Zulip Ayaz Hafiz (Nov 28 2023 at 06:05):

Also, I highly recommend adding uitests of the form I described under https://github.com/roc-lang/roc/tree/d478ec56da88268dd39752c73d42c2f60a20ef38/crates/compiler/uitest/tests/ability/specialize. It helps a lot in catching the specialization issues at the source.

view this post on Zulip Ayaz Hafiz (Nov 28 2023 at 06:06):

And, adding mono tests as well as gen tests. The mono tests will also catch things early on. If mono succeeds, codegen very likely will

view this post on Zulip Brendan Hansknecht (Nov 28 2023 at 20:13):

Gotta love when this fails:

custom = @Inspector

but this works:

custom = \fn -> @Inspector fn

view this post on Zulip Ayaz Hafiz (Nov 28 2023 at 20:14):

what's the error

view this post on Zulip Richard Feldman (Nov 28 2023 at 20:16):

that's a known problem, right?

view this post on Zulip Richard Feldman (Nov 28 2023 at 20:17):

like how you can't do mainForHost = main if main is a function, you have to do mainForHost = \arg -> main arg

view this post on Zulip Ayaz Hafiz (Nov 28 2023 at 20:17):

custom = @Inspector is sugar though

view this post on Zulip Ayaz Hafiz (Nov 28 2023 at 20:23):

For the latter

view this post on Zulip Brendan Hansknecht (Nov 28 2023 at 20:50):

It won't generate specializations correct as only custom = @Inspector

view this post on Zulip Brendan Hansknecht (Nov 28 2023 at 20:55):

Anyway, I think I have autoderived inspect working now. Not wired to dbg, but otherwise working.

view this post on Zulip Brendan Hansknecht (Nov 28 2023 at 21:04):

Just for context, for specialization, errors look like:

── PROC SPECIALIZATION NOT DEFINED ─────────────────────────────────────────────

in toInspector_[A 2] : ({Str, Str}) -> {Str, Str} ((niche {}))

0│  procedure `#Derived.toInspector_[A 2]` (`#Derived.tag`):
1│>     let `#Derived_gen.0` : {Str, Str} = CallByName `Inspect.custom` `#Derived.tag`;
2│      ret `#Derived_gen.0`;

No specialization

custom : ({Str, Str}) -> {Str, Str} ((niche {}))

was found

The following specializations of Inspect.custom were built:custom : () ->
{} ((niche {}))

custom : () -> {} ((niche {}))

custom : () -> {} ((niche {}))', crates/compiler/test_mono/src/tests.rs:177:5

view this post on Zulip Richard Feldman (Nov 28 2023 at 21:05):

yooooooo, amazing @Brendan Hansknecht!!! :heart_eyes: :heart_eyes: :heart_eyes:

view this post on Zulip Richard Feldman (Nov 28 2023 at 21:05):

thank you so much!

view this post on Zulip Luke Boswell (Nov 28 2023 at 21:09):

NGL that PROC SPECIALIZATION NOT DEFINED error looks like magic to me.

view this post on Zulip Brendan Hansknecht (Nov 28 2023 at 21:17):

Also, I think the plan is to submit #5775, make another PR for dbg changes, and then add some post fixes as needed.

view this post on Zulip Ayaz Hafiz (Nov 28 2023 at 21:50):

I'll review this tonight. Do you guys mind holding off merging until I have a chance to look at this?

view this post on Zulip Brendan Hansknecht (Nov 28 2023 at 21:56):

totally fine. Thanks

view this post on Zulip Brendan Hansknecht (Nov 28 2023 at 21:57):

Also, looks like I still have a few minor issues to figure out.

view this post on Zulip Brendan Hansknecht (Nov 28 2023 at 22:03):

Wouldn't mind some help with them if you have any ideas. Just updated tests to show the errors:

The two issues seem to be:

  1. Frac a is not turning into a concrete type. Instead, inspect is finding a as the inner type and failing. So something is missing here that should end up selecting Dec. Can repro by running cargo test -p test_gen -- gen_abilities::inspect::num.
  2. List * doesn't work, but we would want it to still be able to output []. Currently we get unspecialized lambda sets left over during resolution probably from the elem to inspector function iiuc. Can repro by running cargo test -p test_gen -- gen_abilities::inspect::list.

view this post on Zulip Ayaz Hafiz (Nov 28 2023 at 22:22):

(1) Is probably because Frac is missing in the switch here https://github.com/roc-lang/roc/blob/3eb6f9179752a12622813d985f90b297d7baec81/crates/compiler/derive_key/src/inspect.rs#L186-L208

view this post on Zulip Ayaz Hafiz (Nov 28 2023 at 22:25):

Regarding (2), this is a bit of a problem. In the future I'd like to get rid of that panic and instead have the "unspecialized..." thing return an error function, because if the type variable is unbound, we know that the specialization function will never be called. But as you've noticed, in the meantime it finds actual errors. So I am inclined to say that debugging a list with non concrete type should not be supported for now, or we should generate the synthetic error function only in non-debug builds.

view this post on Zulip Brendan Hansknecht (Nov 28 2023 at 23:02):

(1) I don't think it is Frac missing in the switch. Num and Integer are also not in the switch, but they work just fine. Frac is a wrapping type, so we want to unwrap it and get to the underlying Dec/F32/F64. Unspecified number types work because when we unwrap, it results in an I64. For Frac, it should unwrap to Dec by default if the type is unspecfied. So I think this is an issue with default number handling logic elsewhere.

view this post on Zulip Brendan Hansknecht (Nov 28 2023 at 23:03):

For (2), sounds reasonable to ignore for now. Long term can either pipeline through a nicer error or a special exception.

view this post on Zulip Ayaz Hafiz (Nov 28 2023 at 23:14):

Regarding 1, Num and Integer work fine because if has a type variable, then either (1) the type variable is bound to a type variable that implements the ability, (2) the type variable is concrete, or (3) the number is a ranged number, the logic for which is implemented https://github.com/roc-lang/roc/blob/6c72bf9bf77c016428aaaad187e817dfb99d9eda/crates/compiler/derive_key/src/inspect.rs#L171-L173.

view this post on Zulip Ayaz Hafiz (Nov 28 2023 at 23:15):

So what you want is to check if it's a Frac with an unbound type variable (FlexVar - Rigid means it's a bug, because it's trying to specialize a generalized type, which is nonsense). In that case, you know it will compile to the default Dec, so you can use the Dec specialization.

view this post on Zulip Brendan Hansknecht (Nov 28 2023 at 23:16):

That makes sense. will test

view this post on Zulip Brendan Hansknecht (Nov 28 2023 at 23:22):

Ok. Fixed.

view this post on Zulip Brendan Hansknecht (Nov 28 2023 at 23:30):

all tests passed locally for me. So hopefully ci will be all good too.

view this post on Zulip Brendan Hansknecht (Nov 29 2023 at 00:15):

Interesting wasm failure. Is this a case where we are passing a wrapping type to NumToStr, but it has the same underlying layout as a Numeric Type. As such, it theoretically can just be treated as the underlying numeric type? Not exactly sure the correct fix on the wasm side, but I assume it is something like instead of checking if the type is valid, check if the underlying layout is valid.

thread 'gen_abilities::inspect::list' panicked at 'NumToStr is not defined for LambdaSet(LambdaSet { set: [( 15.295, [InLayout(DEC)])], args: [InLayout(25)], ret: InLayout(25), representation: InLayout(DEC), full_layout: InLayout(81) })', crates/compiler/gen_wasm/src/low_level.rs:2272:18

view this post on Zulip Brendan Hansknecht (Nov 29 2023 at 00:39):

So yeah, using the runtime representation is a fix in the wasm backend. That said, I wonder if that means tons of low levels for wasm should be using the runtime representation to extract the inner layout from lambdasets. For now, just changing the single location to fix a test, but feels like probably a symptom of a bigger issue.

view this post on Zulip Brendan Hansknecht (Nov 29 2023 at 00:48):

For using Inspect with dbg. That will need to be handled at the mono or higher level, correct? Cause dbg no longer has enough information to just be dealt with by the backends. Instead, dbg val essentially has to desugar into Inspect.inspect val |> Inspect.toDbgStr |> roc_dbg, right? Then that new set of commands will get lowered by the backends.

view this post on Zulip Richard Feldman (Nov 29 2023 at 00:49):

yeah exactly :100:

view this post on Zulip Brendan Hansknecht (Nov 29 2023 at 00:52):

At what level do we normally desugar these things? Any specific code location? I assume either can or mono somewhere.

view this post on Zulip Brendan Hansknecht (Nov 29 2023 at 00:52):

Maybe even when converting between the two

view this post on Zulip Richard Feldman (Nov 29 2023 at 00:53):

I'd do it in can and then add a LowLevel op for RocDbg

view this post on Zulip Richard Feldman (Nov 29 2023 at 00:54):

as for where to do it, we already desugar dbg here - so I'd modify that!

view this post on Zulip Brendan Hansknecht (Nov 29 2023 at 00:57):

Oh, should debug still automatically add on [examples/helloWorld.roc 7:9], I guess that is not covered by inspect. Though in a number of platforms, I assume it is not wanted. Maybe dbg should pass two strings, location and message?

view this post on Zulip Richard Feldman (Nov 29 2023 at 00:58):

I like that idea! :100:

view this post on Zulip Brendan Hansknecht (Nov 29 2023 at 01:10):

What is the difference between the Expr and ValueDef forms of Dbg?

view this post on Zulip Richard Feldman (Nov 29 2023 at 01:13):

hm, that I'm not sure

view this post on Zulip Agus Zubiaga (Nov 29 2023 at 01:25):

The Expr version sounds like elm’s Debug.log which returns the value it logs. I thought dbg couldn’t do that but I’d love it if it did :grinning:

view this post on Zulip Agus Zubiaga (Nov 29 2023 at 01:26):

It’s very nice when you have some code already written and want to “sprinkle” some logging for debug purposes

view this post on Zulip Brendan Hansknecht (Nov 29 2023 at 01:28):

So it looks like the expression version is actually our:

dbg "some value"

It just also includes a continuation that is really what is returned:

dbg "some value"

continuation

I don't think the valuedef is ever actually used.

view this post on Zulip Brendan Hansknecht (Nov 29 2023 at 01:30):

Aside, I guess since desugaring still generates an Expr, I have to actually make an expr that is Expr::LowLevelDbg.

view this post on Zulip Brendan Hansknecht (Nov 29 2023 at 01:30):

That version would just be used for actually calling roc_dbg in the host.

view this post on Zulip Richard Feldman (Nov 29 2023 at 02:14):

Agus Zubiaga said:

The Expr version sounds like elm’s Debug.log which returns the value it logs. I thought dbg couldn’t do that but I’d love it if it did :grinning:

yeah the idea is to add support for that!

I just wanted to start with the "statement" version because I know from Elm that if that doesn't exist, people will do _ = dbg ... and I wanted to see if there was still demand for the other style if we had the statement version

view this post on Zulip Richard Feldman (Nov 29 2023 at 02:14):

turns out yes :big_smile:

view this post on Zulip Agus Zubiaga (Nov 29 2023 at 02:27):

Yeah, I also like the statement version. Both are nice in different situations.

view this post on Zulip Brendan Hansknecht (Nov 29 2023 at 02:35):

For dbg, do we want to attempt to wire through a file name or should we just give a module name (or other I guess)?

view this post on Zulip Richard Feldman (Nov 29 2023 at 03:23):

I think filename is nicest if possible

view this post on Zulip Brendan Hansknecht (Nov 29 2023 at 04:02):

I mean we currently use filename, just need to figure out wiring it through differently. Cause now we need it at compile time instead of runtime.

view this post on Zulip Brian Carroll (Nov 29 2023 at 07:28):

Brendan Hansknecht said:

I wonder if that means tons of low levels for wasm should be using the runtime representation to extract the inner layout from lambdasets.

No, there are only 5 existing low-level ops that can actually take lambdasets as operands in the first place! It's just List.map and the other "higher order low levels". In the wasm backend, those lambda sets are converted to their runtime representations here.

view this post on Zulip Brian Carroll (Nov 29 2023 at 07:49):

Apart from low-levels, there are about 4 or 5 other places where it's needed. Converting IR symbol layout to WasmLayout, inserting data into structs, etc.

view this post on Zulip Pearce Keesling (Nov 29 2023 at 14:30):

Richard Feldman said:

turns out yes :big_smile:

If I understand correctly that means behaving like dbg! In rust where I get the value back out so I can just add the debug macro into a bigger expression. Yeah I'm a big fan of that. I'd extra love it if I didn't need to add parentheses cause that is cumbersome in rust because I'm potentially wrapping a huge chunk of code

view this post on Zulip Richard Feldman (Nov 29 2023 at 15:05):

yeah I think |> dbg should let you avoid parens!

view this post on Zulip Brendan Hansknecht (Nov 29 2023 at 16:24):

Brian Carroll said:

No, there are only 5 existing low-level ops that can actually take lambdasets as operands in the first place! It's just List.map and the other "higher order low levels". In the wasm backend, those lambda sets are converted to their runtime representations here.

I wonder if that means requiring this change was caused by a bug elsewhere.
https://github.com/roc-lang/roc/pull/5775/commits/248976d632b0827032171ba00b8372dbd59a39c0

Somehow the inspect ability lead to a lambdaset getting past to Num.toStr in the wasm backend. The Lambdaset was just a Dec under the hood.

view this post on Zulip Brendan Hansknecht (Nov 29 2023 at 16:27):

I would assume it happened during the codegen of this ability impl function:
https://github.com/roc-lang/roc/blob/ead90313d89e8939549732136d536f301e522a16/crates/compiler/builtins/roc/Inspect.roc#L339-L342

view this post on Zulip Ayaz Hafiz (Nov 29 2023 at 16:51):

That seems like a bug. A lambda set should never compile to a Dec

view this post on Zulip Ayaz Hafiz (Nov 29 2023 at 16:51):

And a lambda set should never be an argument to Num.toStr

view this post on Zulip Ayaz Hafiz (Nov 29 2023 at 16:52):

Lambda sets should compile to an int, struct, or union. And they should only appear where function types are expected

view this post on Zulip Ayaz Hafiz (Nov 29 2023 at 16:52):

if you revert that change what tests fail?

view this post on Zulip Brendan Hansknecht (Nov 29 2023 at 16:55):

gen_abilities::inspect::list and gen_abilities::inspect::num, but only for test-gen-wasm

view this post on Zulip Brendan Hansknecht (Nov 29 2023 at 16:55):

Not sure why, but the incorrect parameters only happen with the dev wasm backend.

view this post on Zulip Brendan Hansknecht (Nov 29 2023 at 16:57):

The llvm backend uses match layout_interner.get_repr(num_layout) without handling lambasets and just works. So maybe the wasm backend has a bug with mapping layouts to args?

view this post on Zulip Ayaz Hafiz (Nov 29 2023 at 17:06):

Do you know what particular case in inspect::num?

view this post on Zulip Ayaz Hafiz (Nov 29 2023 at 17:06):

I'll try this actually

view this post on Zulip Brendan Hansknecht (Nov 29 2023 at 17:18):

I am not sure, but I recall it resolving to a Dec. So probably Dec or Frac case of some sort.

view this post on Zulip Brendan Hansknecht (Nov 29 2023 at 17:28):

For symbols like roc_alloc in the llvm backend, where do the external function headers for them get defined. Searched around a bit, but not finding it except for testing.

Trying to do let function = self.module.get_function("roc_dbg").unwrap();, but unwrapping will result in a None.

view this post on Zulip Ayaz Hafiz (Nov 29 2023 at 17:29):

I don't this is a backend bug. This is a bug in the code generation

view this post on Zulip Ayaz Hafiz (Nov 29 2023 at 17:29):

With this diff

diff --git a/crates/compiler/mono/src/layout/intern.rs b/crates/compiler/mono/src/layout/intern.rs
index 9891c59f2..138d602cb 100644
--- a/crates/compiler/mono/src/layout/intern.rs
+++ b/crates/compiler/mono/src/layout/intern.rs
@@ -341,9 +341,10 @@ pub trait LayoutInterner<'a>: Sized {
                 }
                 doc
             }
-            LambdaSet(lambda_set) => {
-                self.to_doc(lambda_set.runtime_representation(), alloc, seen_rec, parens)
-            }
+            LambdaSet(lambda_set) => alloc
+                .text("LambdaSet(")
+                .append(self.to_doc(lambda_set.runtime_representation(), alloc, seen_rec, parens))
+                .append(")"),
             RecursivePointer(rec_layout) => {
                 if seen_rec.contains(&rec_layout) {
                     alloc.text("*self")
diff --git a/crates/compiler/test_gen/src/gen_abilities.rs b/crates/compiler/test_gen/src/gen_abilities.rs
index 2bc4791b7..4d099c386 100644
--- a/crates/compiler/test_gen/src/gen_abilities.rs
+++ b/crates/compiler/test_gen/src/gen_abilities.rs
@@ -2222,21 +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
-                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 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 ", "
             "#
             ),

view this post on Zulip Ayaz Hafiz (Nov 29 2023 at 17:29):

And this invocation

❯ ROC_PRINT_IR_AFTER_RESET_REUSE=1 ROC_CHECK_MONO_IR=1 cargo test-gen-wasm inspect::num

view this post on Zulip Ayaz Hafiz (Nov 29 2023 at 17:30):

There's stuff like this

procedure : `Inspect.256` Str
procedure = `Inspect.256` (`Inspect.f0`: Str, `Inspect.num`: LambdaSet(U8)):
    let `Inspect.318` : Str = CallByName `Num.toStr` `Inspect.num`;
    let `Inspect.317` : Str = CallByName `Inspect.dbgWrite` `Inspect.f0` `Inspect.318`;
    ret `Inspect.317`;

view this post on Zulip Ayaz Hafiz (Nov 29 2023 at 17:31):

The initial generator of the inspector looks right

procedure : `Inspect.inspect` Str
procedure = `Inspect.inspect` (`Inspect.val`: U8):
    let `Inspect.312` : LambdaSet(U8) = CallByName `Inspect.dbgU8` `Inspect.val`;
    let `Inspect.309` : {} = Struct {};
    let `Inspect.308` : Str = CallByName `Inspect.dbgInit` `Inspect.309`;
    let `Inspect.307` : Str = CallByName `Inspect.256` `Inspect.308` `Inspect.312`;
    ret `Inspect.307`;

view this post on Zulip Ayaz Hafiz (Nov 29 2023 at 17:32):

But that Inspect.256 is definitely wrong, which I think you're right is that dbg* function

view this post on Zulip Ayaz Hafiz (Nov 29 2023 at 17:32):

It's almost certainly a problem in the chosen specialization, since after the specialization is applied it's not type-checked again

view this post on Zulip Brendan Hansknecht (Nov 29 2023 at 18:31):

First signs of life:

$ cargo run examples/platform-switching/main.roc
    Finished dev [unoptimized + debuginfo] target(s) in 0.50s
     Running `target/debug/roc examples/platform-switching/main.roc`
🔨 Rebuilding platform...
[TODO: add filepath here] {num: 32, str: "test"}
Which platform am I running on now?

view this post on Zulip Brendan Hansknecht (Nov 29 2023 at 18:34):

Also, in all of our platform switching examples, roc_panic is technically wrong. It only works with small strings cause it assume a char*. instead of a RocStr*.

view this post on Zulip Brendan Hansknecht (Nov 30 2023 at 00:46):

#6116 is a first pass at creating a PR for dbg using inspect.

It is still missing a lot, but is nearly at a place where we could submit it just to enable a better version of dbg for advent of code. At a minimum, I need to update all the platforms to include roc_dbg, but I listed a number of other goals in the PR. Not sure how many we will get to, but I think even without the extra goals, it should be submittable soon.

Also, a first pass on review comments would be nice.

view this post on Zulip Brendan Hansknecht (Nov 30 2023 at 06:48):

Ok. So I think this is at a state where I want to submit it and do anything else in a follow up PR (sans fixing tests). That way, it hopefully can be merged tomorrow and ready for advent of code on friday.

There are still a number of changes listed in the PR and a suggestion by Ayaz that I want to make, but I want to push that all to follow ups in order to get this in.

view this post on Zulip Brendan Hansknecht (Nov 30 2023 at 06:50):

related:

view this post on Zulip Brendan Hansknecht (Nov 30 2023 at 06:52):

@Anton, if you get the chance, can you merge and cut a release for those 2 PRs? Basic CLI being the more important one for advent of code. Should be fine to cut a release before the new roc version is out.

view this post on Zulip Luke Boswell (Nov 30 2023 at 07:07):

Massive effort Brendan!! This will be such a nice improvement for everyone, even if most people never see this work. :octopus:

view this post on Zulip Brendan Hansknecht (Nov 30 2023 at 15:57):

Can I get a review on #6116 to submit it? All test are green now (had to disable 2 that have unrelated bugs to be fixed later related to wrong exit codes)

view this post on Zulip Brendan Hansknecht (Nov 30 2023 at 16:17):

As a note, though the PR is large, it is mostly fluff from platform changes to roc_dbg and roc_panic. The crates/compiler folder being the main changes that matter.

view this post on Zulip Brendan Hansknecht (Nov 30 2023 at 22:28):

Ok, now we just need to cut new releases of platforms that will be used with AOC such that they have a roc_dbg impl.

view this post on Zulip Richard Feldman (Nov 30 2023 at 22:28):

amazing work @Brendan Hansknecht!!!

view this post on Zulip Brendan Hansknecht (Nov 30 2023 at 22:31):

related:

This two PRs are both ultra simple if someone wants to review and merge them. For basic-cli and basic-webserver.

view this post on Zulip Richard Feldman (Nov 30 2023 at 22:34):

also in order to get the new basic-cli into the tutorial, we need to double check that it still works after the breaking Stdin change

view this post on Zulip Luke Boswell (Nov 30 2023 at 22:34):

If we need anything updated I have time today to do that. Should I test basic-cli with a branch?

view this post on Zulip Richard Feldman (Nov 30 2023 at 22:35):

yeah sounds good :thumbs_up:

view this post on Zulip Richard Feldman (Nov 30 2023 at 22:35):

that would be great, thank you @Luke Boswell!

view this post on Zulip Brendan Hansknecht (Nov 30 2023 at 22:37):

With what was just merged and the new compiler, basic-cli should just work with dbg.

view this post on Zulip Brendan Hansknecht (Nov 30 2023 at 22:38):

So I think we just need to cut a new release (and update the examples in the repo to use the new release).

view this post on Zulip Brendan Hansknecht (Nov 30 2023 at 22:38):

Oh, and update any examples for AOC to the new release as well.

view this post on Zulip Luke Boswell (Nov 30 2023 at 22:39):

I think we need Anton to be able to cut a new release?

view this post on Zulip Luke Boswell (Nov 30 2023 at 22:40):

So is that a release of basic-cli or just a nightly?

view this post on Zulip Brendan Hansknecht (Nov 30 2023 at 22:43):

both

view this post on Zulip Brendan Hansknecht (Nov 30 2023 at 22:44):

Cause the platform now has a roc_dbg that needs to be available.

view this post on Zulip Luke Boswell (Nov 30 2023 at 22:56):

We have a bug with dbg for opaque types. That should probably be resolved before cutting a new nightly. I don't think this blocks platform release, but the platform releases should stay in testing until we have a new nightly.

view this post on Zulip Brendan Hansknecht (Nov 30 2023 at 23:07):

So for the opaque bug, it is an issue with not creating a correct specialization when dealing with inspect an opaque value with an automatically derived impl.

Essentially, Inspect.opaque is a * -> Inspector f, but we need to specialize it to the opaque type. So for Utc := ... we want the final version of the function to be Utc -> Inspector f. I think that specialized version is not being generating and we are hitting issues. That is at least my guess.

view this post on Zulip Brendan Hansknecht (Nov 30 2023 at 23:09):

I tried to write a manual impl:

toInspector = \u ->
    fmt <- Inspect.custom
    Inspect.opaque u
    |> Inspect.apply fmt

This maybe gives a clearer error:

This value is a declared specialization of type:

    * -> Inspector f where f implements InspectFormatter

But the type annotation on toInspector says it must match:

    val ->
    Inspector f where val implements Inspect, f implements InspectFormatter

The function has to be explicitly typed to avoid the error:

toInspector : Utc -> Inspect.Inspector f where f implements Inspect.InspectFormatter

view this post on Zulip Brendan Hansknecht (Nov 30 2023 at 23:10):

So maybe I can change the auo derivation to add a type and that will fix the issue.

view this post on Zulip Brendan Hansknecht (Dec 01 2023 at 03:05):

@Ayaz Hafiz any chance you can take a look at this? Repro is just to try and run dbg on an opaque type that doesn't implement Inspect at all. So something like:

Op := {}

dbg (@Op {})

view this post on Zulip Brendan Hansknecht (Dec 01 2023 at 03:06):

I get the feeling it is probably a simple fix but I am not following it fully.

view this post on Zulip Ayaz Hafiz (Dec 01 2023 at 03:40):

What branch is this on?

view this post on Zulip Luke Boswell (Dec 01 2023 at 03:41):

main

view this post on Zulip Ayaz Hafiz (Dec 01 2023 at 03:42):

Where is the initial bug report?

view this post on Zulip Luke Boswell (Dec 01 2023 at 03:42):

I havent made an Issue for it

view this post on Zulip Luke Boswell (Dec 01 2023 at 03:42):

I can if that helps

view this post on Zulip Ayaz Hafiz (Dec 01 2023 at 03:42):

Can you share it with me?

view this post on Zulip Ayaz Hafiz (Dec 01 2023 at 03:42):

Maybe just a repro here

view this post on Zulip Ayaz Hafiz (Dec 01 2023 at 03:43):

Does it fail with "expected to know a specialization for #UserApp.Op#Inspect.toInspector, but it wasn't found"?

view this post on Zulip Luke Boswell (Dec 01 2023 at 03:44):

$ roc dev examples/platform-switching/rocLovesZig.roc
An internal compiler expectation was broken.
This is definitely a compiler bug.
Please file an issue here: https://github.com/roc-lang/roc/issues/new/choose
thread '<unnamed>' panicked at 'expected to know a specialization for `17.IdentId(1)`#`15.IdentId(32)`, but it wasn't found', /Users/luke/Documents/GitHub/roc/crates/compiler/solve/src/specialize.rs:744:33
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

view this post on Zulip Luke Boswell (Dec 01 2023 at 03:44):

# examples/platform-switching/rocLovesZig.roc
app "rocLovesZig"
    packages { pf: "zig-platform/main.roc" }
    imports []
    provides [main] to pf

main =
    dbg (@Op {})

    "Roc <3 Zig!\n"

Op := {}

view this post on Zulip Luke Boswell (Dec 01 2023 at 03:46):

Created an issue for this https://github.com/roc-lang/roc/issues/6127

view this post on Zulip Ayaz Hafiz (Dec 01 2023 at 04:24):

https://github.com/roc-lang/roc/pull/6128 should take care of it

view this post on Zulip Ayaz Hafiz (Dec 01 2023 at 04:24):

I left a detailed explanation of the issue.

view this post on Zulip Brendan Hansknecht (Dec 01 2023 at 07:30):

Super easy review to add inspect to most of the opaque types in basic-cli: https://github.com/roc-lang/basic-cli/pull/139

view this post on Zulip Brian Carroll (Dec 01 2023 at 07:38):

It's failing CI: Only builtin abilities can be derived.
That suggests it's using the previous version of the compiler?

view this post on Zulip Luke Boswell (Dec 01 2023 at 07:41):

We need to cut a nightly release before updating the platforms after Ayaz's change.

view this post on Zulip Brendan Hansknecht (Dec 01 2023 at 07:51):

Ah, ok. Didn't think about that.

view this post on Zulip Brendan Hansknecht (Dec 01 2023 at 07:51):

Guess it can wait

view this post on Zulip Anton (Dec 01 2023 at 10:05):

I'll get started on releasing all the things :p

view this post on Zulip Brendan Hansknecht (Dec 01 2023 at 15:27):

Thanks for getting this out :thank_you:

view this post on Zulip Anton (Dec 01 2023 at 15:54):

Thanks for getting it all ready :)

view this post on Zulip Richard Feldman (Dec 01 2023 at 16:53):

yeah it's really great that people today have been able to use it to get unblocked from dbg bugs - huge thanks to both of you for shipping it in time! :smiley:

view this post on Zulip Pearce Keesling (Dec 01 2023 at 16:57):

I currently don't get any output from dbg when I am running a test. Is there some flag I need to enable for that to happen? The results appear just fine in an actual run

view this post on Zulip Brendan Hansknecht (Dec 01 2023 at 16:58):

Hmm, I wonder which roc_dbg that hooks into. I guess whichever one the compiler itself exposes. I guess we need to update that.

view this post on Zulip Anton (Dec 01 2023 at 16:58):

When running a test, do you mean roc test myfile.roc?

view this post on Zulip Anton (Dec 01 2023 at 16:59):

I think roc build myfile.roc will still drop dbg like it used to before the new dbg

view this post on Zulip Pearce Keesling (Dec 01 2023 at 17:04):

Anton said:

When running a test, do you mean roc test myfile.roc?

Yeah exactly

view this post on Zulip Anton (Dec 01 2023 at 17:13):

Can you make an issue and share your code there @Pearce Keesling?

view this post on Zulip Pearce Keesling (Dec 01 2023 at 17:17):

Sure thing :thumbs_up: . I do need to verify that I actually understand the issue though. I noticed just now when I was running the test that it marked it as a "warning" which makes me think it is interpreting stderr output as warning on a test?

view this post on Zulip Anton (Dec 01 2023 at 17:30):

that it marked it as a "warning"

I'm not sure what you mean here, can you be more specific?

view this post on Zulip Ayaz Hafiz (Dec 01 2023 at 22:50):

I'm seeing

Undefined symbols for architecture arm64:
  "_roc_dbg", referenced from:
      _#UserApp_determineCalibration_3bbacd33228bca14fe5573efe7278cde33c78fe9028ba98810cff368dece in roc_appGIhqSC.o
ld: symbol(s) not found for architecture arm64

with basic-cli 0.6.2. Is there a blocker here?

view this post on Zulip Brendan Hansknecht (Dec 01 2023 at 22:54):

I think roc_dbg is in 0.7

view this post on Zulip Brendan Hansknecht (Dec 01 2023 at 22:54):

#announcements > basic-cli 0.7.0

view this post on Zulip Brendan Hansknecht (Dec 02 2023 at 03:23):

So 1 thing I think we missed with dbg that might be quite nice. Do we also want to send the source to the platform. So we send location in the form path:line, the src, and the dbg str. As a result, this:

#App.roc
x = 27
dbg x

as:

[path/App.roc:2] x = 27

Thoughts? The one pain about this is it requires adding one more parameter to all roc_debug impls and it is another breaking change that requires some update shuffling.

Currently, we already have location, so we can get [path/App.roc:2] 27 without the context of the src.

view this post on Zulip Brendan Hansknecht (Dec 02 2023 at 03:24):

With the source add, our debug would be able to print exactly like rust.

view this post on Zulip Richard Feldman (Dec 02 2023 at 03:25):

I love that idea! :smiley:

view this post on Zulip Richard Feldman (Dec 02 2023 at 03:25):

I definitely think it's worth the breaking change assuming we like the idea, although we don't need to rush it out this time :sweat_smile:

view this post on Zulip Brendan Hansknecht (Dec 02 2023 at 03:29):

So I may have just implemented it and that is why I asked... :sweat_smile:

view this post on Zulip Richard Feldman (Dec 02 2023 at 03:35):

haha awesome!

view this post on Zulip Richard Feldman (Dec 02 2023 at 03:35):

yeah let's try it!

view this post on Zulip Brendan Hansknecht (Dec 02 2023 at 04:22):

[../roc-basic-cli/examples/time.roc:12] (x * 2) = 44

view this post on Zulip Brendan Hansknecht (Dec 02 2023 at 04:22):

and it works :tada:

view this post on Zulip Agus Zubiaga (Dec 02 2023 at 04:28):

This is pretty cool. Question, will this print the entire expression always? What if it’s multiline?

view this post on Zulip Brendan Hansknecht (Dec 02 2023 at 04:33):

The current setup I have is to just grab the entire condition region, so yes.

view this post on Zulip Brendan Hansknecht (Dec 02 2023 at 04:33):

Would be up to the platform currently to elide or do something fancier

view this post on Zulip Brendan Hansknecht (Dec 02 2023 at 04:38):

Not exactly the prettiest:

[../roc-basic-cli/examples/time.roc:13] (x
        *
        2) = 44

Which to be fair is exactly what rust does;

[crates/compiler/can/src/operator.rs:661] arena.alloc(Loc {
        value: LowLevelDbg(arena.alloc(format!("{}:{}", module_path,
                    line_col.line)), arena.alloc(dbg_src), dbg_str,
            desugared_continuation),
        region: loc_expr.region,
    }) = // Elide for brevty

view this post on Zulip Brendan Hansknecht (Dec 02 2023 at 04:39):

We just need to clean up our paths eventually.

view this post on Zulip Anton (Dec 02 2023 at 09:50):

I definitely think it's worth the breaking change assuming we like the idea, although we don't need to rush it out this time :sweat_smile:

We can bundle this breaking change with the one for the simple-c-abi branch

view this post on Zulip Brendan Hansknecht (Dec 02 2023 at 16:07):

So one thing I realized though haven't done yet....I can technically make this a non breaking change by putting the args in a weird order.

view this post on Zulip Brendan Hansknecht (Dec 02 2023 at 16:10):

The args are currently (loc, msg) If I make the new args be (loc, msg, src), all of the old functions will just access the first two args and ignore the third. They would have the exact same behaviour as current.

view this post on Zulip Richard Feldman (Dec 02 2023 at 16:11):

could do that for now and then switch the order to a more logical one when doing the breaking abi change

view this post on Zulip Brendan Hansknecht (Dec 02 2023 at 16:13):

That said, currently on the branch, the args are in the order (loc, src, msg) cause I like that order better. This could be merged without totally breaking dbg, but with non-updated platforms, the dbg statements would be useless. For:

x = 3
dbg x

It would print

[some/file:1] x

view this post on Zulip Brendan Hansknecht (Dec 02 2023 at 21:21):

I think #6143 is ready for review. Should be passing tests now, we'll see if all of CI is green in a bit. @Richard Feldman

Would you prefer for me to reorder all the args to (loc, msg, src) such that current platforms with the old version of roc_dbg just keep working instead of printing out as I mentioned in the comment directly above this? Or should I just leave it as is accepting the mildly breaking change until other platforms are updated?

view this post on Zulip Richard Feldman (Dec 02 2023 at 21:28):

I think reordering for backwards compatibility is worth it for now, to avoid disrupting advent of code :big_smile:


Last updated: Jul 06 2025 at 12:14 UTC