> You can do those things that are easy to do statically at development/testing time and those thing that are easy to do dynamically in runtime.
But then you lose the ability to freely mix and match the static and dynamic code. For example, if you want to write a dynamic implementation for some parametrically polymorphic code there must be a way to check at runtime that the dynamic implementation is respecting the type that you assigned to it (there are ways to do that but they are all very tricky).
The list of tricky things also grows very quickly once you put some though into it. You mentioned return type polymorphism but there are also many other things that are hard to check dynamically (record field names) and lots of things that dynamic codes likes to do (like mutability and subtyping) that force extra complexity into the static type system or that can be used to subvert the static types if you are not careful.