diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index 7ac46bae1de65..77ae9f31ea653 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -25,22 +25,26 @@ Optional ConstraintSystem::determineBestBindings() { // Look for potential type variable bindings. Optional bestBindings; - llvm::SmallDenseMap cache; - // First, let's collect all of the possible bindings. for (auto *typeVar : getTypeVariables()) { if (typeVar->getImpl().hasRepresentativeOrFixed()) continue; + if (Bindings.count(typeVar) > 0) + continue; + if (auto bindings = getPotentialBindings(typeVar)) - cache.insert({typeVar, std::move(bindings)}); + Bindings.insert({typeVar, std::move(bindings)}); } // Now let's see if we could infer something for related type // variables based on other bindings. for (auto *typeVar : getTypeVariables()) { - auto cachedBindings = cache.find(typeVar); - if (cachedBindings == cache.end()) + if (typeVar->getImpl().hasRepresentativeOrFixed()) + continue; + + auto cachedBindings = Bindings.find(typeVar); + if (cachedBindings == Bindings.end()) continue; auto &bindings = cachedBindings->getSecond(); @@ -62,8 +66,8 @@ ConstraintSystem::determineBestBindings() { if (!tv) continue; - auto relatedBindings = cache.find(tv); - if (relatedBindings == cache.end()) + auto relatedBindings = Bindings.find(tv); + if (relatedBindings == Bindings.end()) continue; for (auto &binding : relatedBindings->getSecond().Bindings) { diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 638f8a6e8ed9c..8eab47b0cf280 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -1561,7 +1561,6 @@ ConstraintSystem::matchTypesBindTypeVar( } assignFixedType(typeVar, type); - return getTypeMatchSuccess(); } diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 73d3f1bed204c..5f609854da603 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -232,6 +232,10 @@ void ConstraintSystem::addTypeVariableConstraintsToWorkList( constraint); constraint->setActive(true); } + + // Invalidate pre-computed bindings associated + // with this type variable (if any). + invalidateBindings(typeVar); } /// Retrieve a dynamic result signature for the given declaration. diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index dd72e8708a4f5..cf8f11ab84afc 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -1213,6 +1213,7 @@ class ConstraintSystem { /// \param constraint The newly generated constraint. void addGeneratedConstraint(Constraint *constraint) { generatedConstraints.push_back(constraint); + CS.invalidateBindings(constraint->getTypeVariables()); } /// \brief Erase given constraint from the list of generated constraints @@ -2940,6 +2941,12 @@ class ConstraintSystem { } }; + /// Maps type variables to their bindings. Bindings are invalidated + /// and have to be re-computed if new constraints are introduced or + /// in relation to a particular set of type variables or type variables + /// are assigned fixed types or merged together. + llvm::DenseMap Bindings; + Optional checkTypeOfBinding(TypeVariableType *typeVar, Type type, bool *isNilLiteral = nullptr); Optional determineBestBindings(); @@ -3228,6 +3235,28 @@ class ConstraintSystem { SmallVectorImpl &Ordering, SmallVectorImpl &PartitionBeginning); + void invalidateBindings(ArrayRef typeVars) { + llvm::SmallPtrSet visitedVars; + for (auto *typeVar : typeVars) { + if (typeVar != typeVar->getImpl().getRepresentative(nullptr) || + visitedVars.count(typeVar) > 0) + continue; + + // If there was no binding, there is no need to disturb + // other type variables. + Bindings.erase(typeVar); + visitedVars.insert(typeVar); + + for (auto *eqClassVar : CG[typeVar].getEquivalenceClass()) { + for (auto *adjacentVar : CG[eqClassVar].getAdjacencies()) { + auto *var = getRepresentative(adjacentVar); + if (visitedVars.insert(var).second) + Bindings.erase(var); + } + } + } + } + LLVM_ATTRIBUTE_DEPRECATED( void dump() LLVM_ATTRIBUTE_USED, "only for use within the debugger"); diff --git a/validation-test/Sema/type_checker_perf/fast/rdar30596744_3.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar30596744_3.swift.gyb new file mode 100644 index 0000000000000..0deb3d139b296 --- /dev/null +++ b/validation-test/Sema/type_checker_perf/fast/rdar30596744_3.swift.gyb @@ -0,0 +1,15 @@ +// RUN: %scale-test --begin 1 --end 20 --step 1 --select NumLeafScopes %s +// REQUIRES: OS=macosx +// REQUIRES: asserts + +% array_elements = 20 + +let _ = [ +%for i in range(0, N): + ${i} : [ + %for j in range(array_elements): + "e${j}", + %end + ], +%end +] diff --git a/validation-test/Sema/type_checker_perf/slow/rdar30596744_2.swift.gyb b/validation-test/Sema/type_checker_perf/slow/rdar30596744_2.swift.gyb index f706934b1ef8d..9580d897a00f4 100644 --- a/validation-test/Sema/type_checker_perf/slow/rdar30596744_2.swift.gyb +++ b/validation-test/Sema/type_checker_perf/slow/rdar30596744_2.swift.gyb @@ -1,4 +1,4 @@ -// RUN: %scale-test --invert-result --begin 1 --end 5 --step 1 --select NumLeafScopes %s --expected-exit-code 1 +// RUN: %scale-test --invert-result --begin 1 --end 4 --step 1 --select NumLeafScopes %s --expected-exit-code 1 // REQUIRES: OS=macosx // REQUIRES: asserts