The compiler infers types for everything by tracing where values come from in a vaguely similar way to how the C/C++ compilers type an expression, except with added complexity due to the polymorphism and type inference across function call boundaries.