-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[CSGen] Fix for exponential dictionary literal behavior in SR-3668 #6973
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
In ConstraintGenerator::visitDictionaryExpr(), if the dictionary_expr has a contextual type which is also a dictionary type, use it to add a new type constraint for each of the dictionary_expr's elements. This has a huge effect on solver performance for dictionary literals with elements that have overloading. The approach closely follows that used in ConstraintGenerator::visitArrayExpr(), which has included a similar optimization (from git commit a22b391) for over two and a half years. I've also added a couple of new test cases which would trigger the bug without this fix.
@swift-ci Please smoke test |
Normally failing the validation tests is bad. Here, it's a "good" thing because you'll need to unmark them as failing and move them to the fixed folder. You can automate this process
|
Thanks, @CodaFi! @colinhowell, I will try to take a look tomorrow. |
Based on the stack trace this is a non-deterministic crasher. It's not related to your change. We need to add 'REQUIRES: deterministic-behavior' to it in a separate patch. I'll do this later today if you don't get around to it. Awesome patch by the way! |
Thanks for awesome patch, @colinhowell! If you don't mind I think there is way to unify regular path with contextual in here, in the following way - currently |
@xedin, there may indeed be a way to unify the two code paths, and doing so does look attractive. But after thinking a little about how the code needs to flow, it looks a bit more complex to me than you suggest, since the two paths, while similar, aren't fully identical. Actually, since Since unifying these code paths obviously adds potential for breakage, I think it should be done in a separate patch. |
@colinhowell I'm not sure I follow what is going to be more complex, sorry if I'm being ambiguous, I didn't actually mean unify array and dictionary paths together, but rather path with and without contextual type in the visitDictionaryExpr. Let me give you an example of what I mean - |
@xedin Sorry, you're not being ambiguous; I actually understood exactly what you meant. If anything, I seem to have confused you by digressing about how You have to remember that I have almost no experience with this code base, and so I'm being very cautious. I've been assuming that any operation I'm not familiar with may have unexpected side effects, and so I've been trying to ensure that the exact same sequence of operations will still be performed when I unify the code paths with and without a contextual type. In particular, I figured that if I had a usable contextual type:
I could certainly manage all this by setting a flag as soon as I had determined that there was a usable contextual type. But it's possible I'm just being overly cautious, I don't know. |
@colinhowell I understand, and we are here to help you out out 100% ! :) Thanks again for working on this and I don't mean to discourage you in any way! Let me address of your points: #1 - It's fine to create that type variable and assign a fixed type to it (before creating #2 - Indeed, that's what you will have to do, and that's totally reasonable, so we get a nice code reuse as well! #3 - Actually both blocks of code are viable here with and without contextual type, that might be useful for diagnostics or if the contextual type is given has dependent member types for key/value, if everything is structurally fine with contextual type itself, they are going to be no-op anyway. |
@xedin Thanks, that was a very helpful reply! :) |
@colinhowell Happy to help, let you know if you have any other problems! |
@swift-ci Please smoke test |
This looks fantastic, thanks! |
@colinhowell Thanks so much for this patch! I actually noticed this recently as I was looking into issues related to slowness with type checking arrays and browsing through both array and dictionary handling, but hadn't gotten around to fixing it yet. |
In ConstraintGenerator::visitDictionaryExpr(), if the dictionary_expr has a
contextual type which is also a dictionary type, use it to add a new type
constraint for each of the dictionary_expr's elements. This has a huge effect
on solver performance for dictionary literals with elements that have
overloading. The approach closely follows that used in
ConstraintGenerator::visitArrayExpr(), which has included a similar
optimization (from git commit a22b391) for over two and a half years.
I've also added a couple of new test cases which would trigger the bug without
this fix.
The problem in SR-3668, with exponential type-checking time for dictionary literals containing closures with overloaded operators, was not present for array literals. Close examination of the type-constraint generation for similar array literals revealed that constraints corresponding to the array_expr's contextual type were added for each of the literal's elements, greatly reducing the work needed by the constraint solver. This optimization was not being done for dictionary literals, and there seemed no reason not to give them a similar optimization. In doing so, I carefully followed the pattern and logic established for this optimization in ConstraintGenerator::visitArrayExpr() while still conforming to the way that dictionary_exprs are handled in ConstraintGenerator::visitDictionaryExpr(). In particular, the added constraints for the dictionary_expr's elements are tuple types of the contextual type's key and value types, just as they are normally handled in visitDictionaryExpr().
The result works as hoped; even long dictionary literals like those mentioned in SR-3668 are processed as quickly as similar array literals. I've added a couple of such dictionary literals as testcases in this commit. The commit passes swift/test. I also ran swift/validation-test and did get one unexpected failure (compiler_crashers/28657-unreachable-executed-at-swift-lib-ast-type-cpp-1344.swift), but this was the first time I'd ever run validation-test, and that failure may have been already present in master before this change, since it doesn't seem obviously related. (I will try running validation-test on master to double-check.)
@rudkx I'd appreciate your comments, since this bug was assigned to you.
@DougGregor Since you're listed as the gatekeeper for this entire area of the compiler, I'd also appreciate your feedback.
Resolves SR-3668.