You have discriminated unions and the compiler is clever about them, so you can implement ADTs if you want them with a little but not a nasty level of boilerplate. (They can also be implemented with an abstract class if that's more your bag.)
It lacks pattern matching because it intentionally doesn't include a runtime component, which I think is also wise. Options exist if you want to use them. I've seen people use Purify to good effect.