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 ⁎⁍̴̛ ₃ ⁍̴̛⁎
Comments 0
No comments yet. Be the first!
Sign in to join the conversation.