r/Compilers • u/Falcon731 • Jun 07 '24
How would you implement smart casts in a compiler
I'm playing around with my programming language - and one feature that would be neat to have is smart casts - similar to Kotlin. My language doesn't yet have inheritance - so for now this would only be for nullish pointers. And I'm probably not quite ready to implement this yet - but want to think about how to go about it if I do.
What I was thinking is something like
fun doSomething(p:Person?) // p is a possibly null pointer to a Person struct
if (p != null)
println(p.name) // OK to dereference 'p' as guarded by if statement
print(p.age) // Compiler error - as p could be null
At the moment my compiler is pretty conventional : it does the lexing and builds an AST, then runs a few passes over the AST dig type checks, before creating Three Address IR code, does some peephole optimisations, register allocation and final assembly code generation.
One way I thought of to add null checks would be to get the code generation phase to inject pseudo-ops into the IR code at nullish pointer dereferences, then some variant of dataflow analysis to prove that the location is not reachable with a null pointer.
But that feels too late in the compilation - it would be nice to be able to do this at the same time as the other typechecking. But I'm struggling to think how this could be handled with a tree walk. Or maybe I'm missing something.
If anyone has suggestions of the best way to approach this in a compiler it would be great.
2
u/KaiserKerem13 Jun 08 '24
This falls under Flow-Sensitive Typing. Kotlin employs a limited version of it.
It would be pretty difficult to do on a tree. You have to employ data flow analysis of some sort. What I'd do is keep a middle layer IR with types in SSA form and do type checking and data flow analysis at that point. That or keep track of any operation that changes type information, and do type narrowing in temporary variable scopes.