You are browsing as a guest. Sign up (or log in) to start making projects!

46m 14s logged

Devlog: Letting Semantic Unions Work In Functions

After getting semantic unions working in local declarations, the next problem was fairly obvious (and in my roadmap hehe).

This did not work before:

func make_value(): int | string
    return 7
end

func accept_value(value: int | string): bool
    return value is int
end

Which was annoying, because int | string was already a real union type at this point. Flower could use it in locals, it could pack assigned values, it could check variants. But if I returned 7 from a function declared as int | string, or passed 7 into a parameter expecting int | string, the compiler did not know how to carry that union-lowering information across the boundary.

This has been one of the easier changes I’ve made in a long while. It compiled properly first try (if you ignore a tiny misspell I made which I fixed really quickly), and there were no prior hidden bugs that surfaced. This.. is too suspicious.

What changed

The compiler now carries semantic union info through:

  • function parameters
  • function returns
  • imported alias calls

If a function expects:

int | string

and I call:

accept_value(7)

typecheck records that 7 needs to be packed as the int member of that union.

Same for returns:

func make_value(): int | string
    return 7
end

That matters because codegen cannot guess later due to the separation of responsibilities I’ve laid out. By the time Flower is emitting C, it needs to know which tag to set and which member to write.

Lowering it properly

Codegen already knew how to pack union values for declarations and assignments.

The missing part was doing the same thing for call arguments and return statements.

So now a value can be packed into a tagged union when it is:

  • stored locally
  • passed into a function
  • returned from a function

Alias calls got handled too, so things like:

remote.accept(11)
remote.make_string()

do not become their own weird little cursed island.

Why this mattered

Without this, semantic unions only worked as long as I never organized my code.

They worked in local tests, but not in helper functions, imported providers, or normal inputs and outputs.

Now union values can actually move around the program instead of being trapped in the one scope where they were declared — and for me, forgotten!

Very exciting, the union can leave the house. They grow up so fast ⁎⁍̴̛ ₃ ⁍̴̛⁎

0
7

Comments 0

No comments yet. Be the first!