Ambiguous use of operator in Swift 5.4

I removed a hack in Swift 5.4 which used to force the type checker to use the same type for literals of the same kind in operator expressions (in certain cases including this one). This would mean that the type checker could only find a solution using overloads of / that use the same parameter type on either side, because the literals 3.0 and 8.0 had to have the same type.

So, in Swift 5.4, the type checker can also find solutions using the other, non-symmetric overloads of /. The type checker should be able to find a solution using (Double, Double) -> Double for / and (Double, Expr) -> Expr for *, but it doesn't because of a different performance hack that "favors" (Expr, Expr) -> Expr for * and stops after it finds a solution using this overload.

The "favoring" hack is based on the argument types, so if you use a contextual type (e.g. a type annotation) instead, it does successfully type check:

 let k: Expr = (3.0/8.0) * 0.0

It also successfully type checks if you add a (Double, Double) -> Expr overload for / because the type checker will prefer a solution that uses more default literal types, and the default float literal type is Double.

Please let me know if you have any further questions! I have been trying to remove the "favoring" hack as well, but at the moment the type checker is too dependent on this hack for performance in many cases.

15 Likes