Kendrick Taylor Kendrick Taylor - 2 months ago 10
Swift Question

Bizarre Swift Compiler Error: "Expression too complex" on a string concatenation

I find this amusing more than anything. I've fixed it, but I'm wondering about the cause. Here is the error:

DataManager.swift:51:90: Expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions
. Why is it complaining? It seems like one of the most simple expressions possible.

The complier points to the
columns + ");";
section

func tableName() -> String { return("users"); }

func createTableStatement(schema: [String]) -> String {

var schema = schema;

schema.append("id string");
schema.append("created integer");
schema.append("updated integer");
schema.append("model blob");

var columns: String = ",".join(schema);

var statement = "create table if not exists " + self.tableName() + "(" + columns + ");";

return(statement);
}


the fix is:

var statement = "create table if not exists " + self.tableName();
statement += "(" + columns + ");";


this also works (via @efischency) but I don't like it as much because I think the
(
get lost:

var statement = "create table if not exists \(self.tableName()) (\(columns))"

Answer

I am not an expert on compilers - I don't know if this answer will "change how you think in a meaningful way," but my understanding of the problem is this:

It has to do with type inference. Each time you use the + operator, Swift has to search through all of the possible overloads for + and infer which version of + you are using. I counted just under 30 overloads for the + operator. That's a lot of possibilities, and when you chain 4 or 5 + operations together and ask the compiler to infer all of the arguments, you are asking a lot more than it might appear at first glance.

That inference can get complicated - for example, if you add a UInt8 and an Int using +, the output will be an Int, but there's some work that goes into evaluating the rules for mixing types with operators.

And when you are using literals, like the String literals in your example, the compiler doing the work of converting the String literal to a String, and then doing the work of infering the argument and return types for the + operator, etc.

If an expression is sufficiently complex - i.e., it requires the compiler to make too many inferences about the arguments and the operators - it quits and tells you that it quit.

Having the compiler quit once an expression reaches a certain level of complexity is intentional. The alternative is to let the compiler try and do it, and see if it can, but that is risky - the compiler could go on trying forever, bog down, or just crash. So my understanding is that there is a static threshold for the complexity of an expression that the compiler will not go beyond.

My understanding is that the Swift team is working on compiler optimizations that will make these errors less common. You can learn a little bit about it on the Apple Developer forums by clicking on this link.

On the Dev forums, Chris Lattner has asked people to file these errors as radar reports, because they are actively working on fixing them.

That is how I understand it after reading a number of posts here and on the Dev forum about it, but my understanding of compilers is naive, and I am hoping that someone with a deeper knowledge of how they handle these tasks will expand on what I have written here.

Comments