What happened to type-check (or inference) for Int

I tried to write some example code in SICP book with swift.
For example,

(2 + (4 * 6)) * ((3 + 5) + 7)

If I write this code in REPL,
then it displayed the result of calculating - 370 after 10~11 sec.

And If I write this code in swift file,
It's compile error like that

error: the compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions

What happened to type-check or type-inference here? why this fail to compile?

Anyway this is a workaround solution.
Int(2 + (4 * 6)) * Int((3 + 5) + 7)

Please let me know if I missed anything ...

1 Like

There's nothing exactly wrong with the expression, though it does play into the current weakness of the type checking.

This is because +-*/ operators are somewhat overused.
Even among concrete types, Int, Double, Float, and now all of SIMD use them to certain extent. Further, most of them also conform to ExpressibleByIntegerLiteral, and SIMD even allow heterogeneous operator, e.g. Int + SIMD<Int>. So the compiler needs to try all sorts of combination (potentially exponentially to the number of terms).

IIRC there's some shortcut taken when all the terms are literals, but I'll leave that to someone more knowledgeable.

The reason this works is because type checker can easily split expression around initialiser and as keyword. For something like Int(a) + b, the type of a is independent of the type of b, but the same can not be said with a + b.

So Int(2 + (4 * 6)) * Int((3 + 5) + 7) does split the whole expression into two, much smaller, parts

// This
Int(2 + (4 * 6)) * Int((3 + 5) + 7)

// is more or less the same as this
let tmp1 = Int(2 + (4 * 6))
let tmp2 = Int((3 + 5) + 7)
tmp1 * tmp2

resulting in a much more manageable chunk.

Even better, if you give compiler a nudge, it'll do much better. Try

(2 + (4 * 6)) * ((3 + 5) + 7) as Int
(2 + (4 * 6)) * ((3 + 5) + 7 as Int)
(2 + (4 * 6)) * ((3 as Int + 5) + 7)

With all that said, there's no need to be very defensive around type checker, like putting as on everything. Compiler does get smarter over time and the need for this should lessen as well. I sometimes go back to my code base and remove unnecessary as.

1 Like

Are there any regression test suites for things like that? My impression was sometimes the opposite: compiler updates suddenly making expressions that previously compiled not compile any longer.

In any case, can we agree that

(2 + (4 * 6)) * ((3 + 5) + 7)

not compiling is a bug and should be fixed? This really can't be considered a "complicated expression" in any practical sense, IMHO.

2 Likes

That much I don't know. I actually am curious too since I'm a tinkerer myself and never managed to find it.

I just checked this against Swift 4.2.4 (pre-SIMD), and it's much faster there. So I suppose it should be treated as regression as much as this is: Type inference regression in Swift 4.2?.

Though it's likely due to SIMD and may be a well-known one.