From 1724debda4272051cf507a74d96a65ae90339677 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Mon, 3 Aug 2020 19:39:23 -0700 Subject: [PATCH 1/7] [ConstraintSystem] Add a type variable merging heuristic to addJoinConstraint. This heuristic merges type variables for literal expressions of the same kind. This is valid because such type variables will have the same set of constraints on them, and must be bound to the same type. --- lib/Sema/CSSimplify.cpp | 62 ++++++++++++++++++++++++++++++++++--- lib/Sema/ConstraintSystem.h | 10 +++--- 2 files changed, 63 insertions(+), 9 deletions(-) diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index fbc473622529d..4957153e7b349 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -32,6 +32,8 @@ #include "llvm/ADT/SetVector.h" #include "llvm/Support/Compiler.h" +#include + using namespace swift; using namespace constraints; @@ -10418,14 +10420,44 @@ void ConstraintSystem::addContextualConversionConstraint( convertTypeLocator, /*isFavored*/ true); } +/// Returns the \c ExprKind of the given type variable if it's the type of an +/// atomic literal expression, meaning the literal can't be composed of subexpressions. +/// Otherwise, returns \c None. +static Optional getAtomicLiteralKind(TypeVariableType *typeVar) { + const std::unordered_set atomicLiteralKinds = { + ExprKind::IntegerLiteral, + ExprKind::FloatLiteral, + ExprKind::StringLiteral, + ExprKind::BooleanLiteral, + ExprKind::NilLiteral, + }; + + if (!typeVar) + return None; + + auto *locator = typeVar->getImpl().getLocator(); + if (!locator->directlyAt()) + return None; + + auto literalKind = getAsExpr(locator->getAnchor())->getKind(); + if (!atomicLiteralKinds.count(literalKind)) + return None; + + return literalKind; +} + Type ConstraintSystem::addJoinConstraint( ConstraintLocator *locator, - ArrayRef> inputs) { + ArrayRef> inputs, + Optional supertype) { switch (inputs.size()) { case 0: return Type(); case 1: + if (supertype.hasValue()) + break; + return inputs.front().first; default: @@ -10434,12 +10466,32 @@ Type ConstraintSystem::addJoinConstraint( } // Create a type variable to capture the result of the join. - Type resultTy = createTypeVariable(locator, - (TVO_PrefersSubtypeBinding | - TVO_CanBindToNoEscape)); + Type resultTy = supertype.hasValue() ? supertype.getValue() : + createTypeVariable(locator, (TVO_PrefersSubtypeBinding | TVO_CanBindToNoEscape)); + + using RawExprKind = uint8_t; + llvm::SmallDenseMap representativeForKind; - // Introduce conversions from each input type to the type variable. + // Join the input types. for (const auto &input : inputs) { + // We can merge the type variables of same-kind atomic literal expressions because they + // will all have the same set of constraints and therefore can never resolve to anything + // different. + auto *typeVar = input.first->getAs(); + if (auto literalKind = getAtomicLiteralKind(typeVar)) { + auto *&originalRep = representativeForKind[RawExprKind(*literalKind)]; + auto *currentRep = getRepresentative(typeVar); + + if (originalRep) { + if (originalRep != currentRep) + mergeEquivalenceClasses(currentRep, originalRep); + continue; + } + + originalRep = currentRep; + } + + // Introduce conversions from each input type to the supertype. addConstraint( ConstraintKind::Conversion, input.first, resultTy, input.second); } diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index 2abf2a3bc3913..391dc445b3a0d 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -3080,12 +3080,14 @@ class ConstraintSystem { /// supertype. /// /// Currently, a "join" is modeled by a set of conversion constraints to - /// a new type variable. At some point, we may want a new constraint kind - /// to cover the join. + /// a new type variable or a specified supertype. At some point, we may want + /// a new constraint kind to cover the join. /// - /// \returns the joined type, which is generally a new type variable. + /// \returns the joined type, which is generally a new type variable, unless there are + /// fewer than 2 input types or the \c supertype parameter is specified. Type addJoinConstraint(ConstraintLocator *locator, - ArrayRef> inputs); + ArrayRef> inputs, + Optional supertype = None); /// Add a constraint to the constraint system with an associated fix. void addFixConstraint(ConstraintFix *fix, ConstraintKind kind, From 0efb86a7fbef173e473a79f69415eb20c296cea0 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Tue, 4 Aug 2020 13:35:11 -0700 Subject: [PATCH 2/7] [ConstraintSystem] Add an overload of addJoinConstraint that takes in an iterator range and a callback to get the type. This allows callers to lazily compute the input types to join rather than constructing an array first. The old addJoinConstraint is now a wrapper for this new overload. --- lib/Sema/CSSimplify.cpp | 59 ++-------------------------------- lib/Sema/ConstraintSystem.h | 63 +++++++++++++++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 59 deletions(-) diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 4957153e7b349..62f9b9291f3a9 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -10420,10 +10420,8 @@ void ConstraintSystem::addContextualConversionConstraint( convertTypeLocator, /*isFavored*/ true); } -/// Returns the \c ExprKind of the given type variable if it's the type of an -/// atomic literal expression, meaning the literal can't be composed of subexpressions. -/// Otherwise, returns \c None. -static Optional getAtomicLiteralKind(TypeVariableType *typeVar) { +Optional +ConstraintSystem::getAtomicLiteralKind(TypeVariableType *typeVar) const { const std::unordered_set atomicLiteralKinds = { ExprKind::IntegerLiteral, ExprKind::FloatLiteral, @@ -10446,59 +10444,6 @@ static Optional getAtomicLiteralKind(TypeVariableType *typeVar) { return literalKind; } -Type ConstraintSystem::addJoinConstraint( - ConstraintLocator *locator, - ArrayRef> inputs, - Optional supertype) { - switch (inputs.size()) { - case 0: - return Type(); - - case 1: - if (supertype.hasValue()) - break; - - return inputs.front().first; - - default: - // Produce the join below. - break; - } - - // Create a type variable to capture the result of the join. - Type resultTy = supertype.hasValue() ? supertype.getValue() : - createTypeVariable(locator, (TVO_PrefersSubtypeBinding | TVO_CanBindToNoEscape)); - - using RawExprKind = uint8_t; - llvm::SmallDenseMap representativeForKind; - - // Join the input types. - for (const auto &input : inputs) { - // We can merge the type variables of same-kind atomic literal expressions because they - // will all have the same set of constraints and therefore can never resolve to anything - // different. - auto *typeVar = input.first->getAs(); - if (auto literalKind = getAtomicLiteralKind(typeVar)) { - auto *&originalRep = representativeForKind[RawExprKind(*literalKind)]; - auto *currentRep = getRepresentative(typeVar); - - if (originalRep) { - if (originalRep != currentRep) - mergeEquivalenceClasses(currentRep, originalRep); - continue; - } - - originalRep = currentRep; - } - - // Introduce conversions from each input type to the supertype. - addConstraint( - ConstraintKind::Conversion, input.first, resultTy, input.second); - } - - return resultTy; -} - void ConstraintSystem::addFixConstraint(ConstraintFix *fix, ConstraintKind kind, Type first, Type second, ConstraintLocatorBuilder locator, diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index 391dc445b3a0d..7ec7c1d71e760 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -2994,6 +2994,11 @@ class ConstraintSystem { bool isDeclUnavailable(const Decl *D, ConstraintLocator *locator = nullptr) const; + /// Returns the \c ExprKind of the given type variable if it's the type of an + /// atomic literal expression, meaning the literal can't be composed of subexpressions. + /// Otherwise, returns \c None. + Optional getAtomicLiteralKind(TypeVariableType *typeVar) const; + public: /// Whether we should attempt to fix problems. @@ -3076,6 +3081,14 @@ class ConstraintSystem { Expr *expr, Type conversionType, ContextualTypePurpose purpose, bool isOpaqueReturnType); + /// Convenience function to pass an \c ArrayRef to \c addJoinConstraint + Type addJoinConstraint(ConstraintLocator *locator, + ArrayRef> inputs, + Optional supertype = None) { + return addJoinConstraint( + locator, inputs.begin(), inputs.end(), supertype, [](auto it) { return *it; }); + } + /// Add a "join" constraint between a set of types, producing the common /// supertype. /// @@ -3085,9 +3098,55 @@ class ConstraintSystem { /// /// \returns the joined type, which is generally a new type variable, unless there are /// fewer than 2 input types or the \c supertype parameter is specified. + template Type addJoinConstraint(ConstraintLocator *locator, - ArrayRef> inputs, - Optional supertype = None); + Iterator begin, Iterator end, + Optional supertype, + std::function(Iterator)> getType) { + if (begin == end) + return Type(); + + // No need to generate a new type variable if there's only one type to join + if ((begin + 1 == end) && !supertype.hasValue()) + return getType(begin).first; + + // The type to capture the result of the join, which is either the specified supertype, + // or a new type variable. + Type resultTy = supertype.hasValue() ? supertype.getValue() : + createTypeVariable(locator, (TVO_PrefersSubtypeBinding | TVO_CanBindToNoEscape)); + + using RawExprKind = uint8_t; + llvm::SmallDenseMap representativeForKind; + + // Join the input types. + while (begin != end) { + Type type; + ConstraintLocator *locator; + std::tie(type, locator) = getType(begin++); + + // We can merge the type variables of same-kind atomic literal expressions because they + // will all have the same set of constraints and therefore can never resolve to anything + // different. + auto *typeVar = type->getAs(); + if (auto literalKind = getAtomicLiteralKind(typeVar)) { + auto *&originalRep = representativeForKind[RawExprKind(*literalKind)]; + auto *currentRep = getRepresentative(typeVar); + + if (originalRep) { + if (originalRep != currentRep) + mergeEquivalenceClasses(currentRep, originalRep); + continue; + } + + originalRep = currentRep; + } + + // Introduce conversions from each input type to the supertype. + addConstraint(ConstraintKind::Conversion, type, resultTy, locator); + } + + return resultTy; + } /// Add a constraint to the constraint system with an associated fix. void addFixConstraint(ConstraintFix *fix, ConstraintKind kind, From 43aafcdb8e0af170560c39a14da113d859313390 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Tue, 4 Aug 2020 14:27:34 -0700 Subject: [PATCH 3/7] [CSGen] Use addJoinConstraint for joining array literal element types. --- lib/Sema/CSGen.cpp | 42 ++++++++++--------------- lib/Sema/CSSimplify.cpp | 1 + test/Constraints/diagnostics.swift | 2 +- test/Parse/pointer_conversion.swift.gyb | 2 +- test/expr/cast/as_coerce.swift | 4 +-- 5 files changed, 21 insertions(+), 30 deletions(-) diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 0963b7f02663c..31414f975c6bc 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -1803,31 +1803,28 @@ namespace { auto locator = CS.getConstraintLocator(expr); auto contextualType = CS.getContextualType(expr); - Type contextualArrayType = nullptr; - Type contextualArrayElementType = nullptr; - + + auto joinElementTypes = [&](Optional elementType) { + const auto elements = expr->getElements(); + unsigned index = 0; + + using Iterator = decltype(elements)::iterator; + CS.addJoinConstraint(locator, elements.begin(), elements.end(), + elementType, [&](const auto it) { + auto *locator = CS.getConstraintLocator(expr, LocatorPathElt::TupleElement(index++)); + return std::make_pair(CS.getType(*it), locator); + }); + }; + // If a contextual type exists for this expression, apply it directly. Optional arrayElementType; if (contextualType && (arrayElementType = ConstraintSystem::isArrayType(contextualType))) { - // Is the array type a contextual type - contextualArrayType = contextualType; - contextualArrayElementType = *arrayElementType; - CS.addConstraint(ConstraintKind::LiteralConformsTo, contextualType, arrayProto->getDeclaredType(), locator); - - unsigned index = 0; - for (auto element : expr->getElements()) { - CS.addConstraint(ConstraintKind::Conversion, - CS.getType(element), - contextualArrayElementType, - CS.getConstraintLocator( - expr, LocatorPathElt::TupleElement(index++))); - } - - return contextualArrayType; + joinElementTypes(arrayElementType); + return contextualType; } // Produce a specialized diagnostic if this is an attempt to initialize @@ -1893,14 +1890,7 @@ namespace { // Introduce conversions from each element to the element type of the // array. - unsigned index = 0; - for (auto element : expr->getElements()) { - CS.addConstraint(ConstraintKind::Conversion, - CS.getType(element), - arrayElementTy, - CS.getConstraintLocator( - expr, LocatorPathElt::TupleElement(index++))); - } + joinElementTypes(arrayElementTy); // The array element type defaults to 'Any'. CS.addConstraint(ConstraintKind::Defaultable, arrayElementTy, diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 62f9b9291f3a9..4dff72adf8ecf 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -4216,6 +4216,7 @@ bool ConstraintSystem::repairFailures( conversionsOrFixes.push_back(CollectionElementContextualMismatch::create( *this, lhs, rhs, getConstraintLocator(locator))); + break; } // Drop the `tuple element` locator element so that all tuple element diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift index bff33fe7caa73..e961b108bda48 100644 --- a/test/Constraints/diagnostics.swift +++ b/test/Constraints/diagnostics.swift @@ -338,7 +338,7 @@ variadic(arrayWithOtherEltType) // expected-error {{cannot convert value of type variadic(1, arrayWithOtherEltType) // expected-error {{cannot convert value of type '[String]' to expected argument type 'Int'}} // FIXME: SR-11104 -variadic(["hello", "world"]) // expected-error 2 {{cannot convert value of type 'String' to expected element type 'Int'}} +variadic(["hello", "world"]) // expected-error {{cannot convert value of type 'String' to expected element type 'Int'}} // expected-error@-1 {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}} // expected-note@-2 {{remove brackets to pass array elements directly}} diff --git a/test/Parse/pointer_conversion.swift.gyb b/test/Parse/pointer_conversion.swift.gyb index 616285d4fbda6..4c9af4a6a5568 100644 --- a/test/Parse/pointer_conversion.swift.gyb +++ b/test/Parse/pointer_conversion.swift.gyb @@ -164,7 +164,7 @@ func constPointerArguments(_ p: UnsafeMutablePointer, takesConstPointer([0, 1, 2]) // QoI: CSDiags doesn't handle array -> pointer impl conversions well takesConstPointer([0.0, 1.0, 2.0]) - // expected-error@-1 3 {{cannot convert value of type 'Double' to expected element type 'Int'}} + // expected-error@-1 {{cannot convert value of type 'Double' to expected element type 'Int'}} // We don't allow these conversions outside of function arguments. var x: UnsafePointer = &i // expected-error {{use of extraneous '&'}} diff --git a/test/expr/cast/as_coerce.swift b/test/expr/cast/as_coerce.swift index 962c656322ca1..3821104d339e1 100644 --- a/test/expr/cast/as_coerce.swift +++ b/test/expr/cast/as_coerce.swift @@ -84,13 +84,13 @@ c3 as C4 // expected-error {{'C3' is not convertible to 'C4'; did you mean to us Double(1) as Double as String // expected-error{{cannot convert value of type 'Double' to type 'String' in coercion}} ["awd"] as [Int] // expected-error{{cannot convert value of type 'String' to expected element type 'Int'}} ([1, 2, 1.0], 1) as ([String], Int) -// expected-error@-1 2 {{cannot convert value of type 'Int' to expected element type 'String'}} +// expected-error@-1 {{cannot convert value of type 'Int' to expected element type 'String'}} // expected-error@-2 {{cannot convert value of type 'Double' to expected element type 'String'}} [[1]] as [[String]] // expected-error{{cannot convert value of type 'Int' to expected element type 'String'}} (1, 1.0) as (Int, Int) // expected-error{{cannot convert value of type '(Int, Double)' to type '(Int, Int)' in coercion}} (1.0, 1, "asd") as (String, Int, Float) // expected-error{{cannot convert value of type '(Double, Int, String)' to type '(String, Int, Float)' in coercion}} (1, 1.0, "a", [1, 23]) as (Int, Double, String, [String]) -// expected-error@-1 2 {{cannot convert value of type 'Int' to expected element type 'String'}} +// expected-error@-1 {{cannot convert value of type 'Int' to expected element type 'String'}} _ = [1] as! [String] // OK _ = [(1, (1, 1))] as! [(Int, (String, Int))] // OK From cd44ca87a95e4b3d16092650fd7d6c274c9f60b5 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Wed, 5 Aug 2020 14:23:15 -0700 Subject: [PATCH 4/7] [ConstraintSystem] Move getAtomicLiteralKind to TypeVariableType::Implementation --- lib/Sema/CSSimplify.cpp | 26 ------------------------ lib/Sema/ConstraintSystem.h | 33 ++++++++++++++++--------------- lib/Sema/TypeCheckConstraints.cpp | 18 +++++++++++++++++ 3 files changed, 35 insertions(+), 42 deletions(-) diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 4dff72adf8ecf..1b56708233a73 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -32,8 +32,6 @@ #include "llvm/ADT/SetVector.h" #include "llvm/Support/Compiler.h" -#include - using namespace swift; using namespace constraints; @@ -10421,30 +10419,6 @@ void ConstraintSystem::addContextualConversionConstraint( convertTypeLocator, /*isFavored*/ true); } -Optional -ConstraintSystem::getAtomicLiteralKind(TypeVariableType *typeVar) const { - const std::unordered_set atomicLiteralKinds = { - ExprKind::IntegerLiteral, - ExprKind::FloatLiteral, - ExprKind::StringLiteral, - ExprKind::BooleanLiteral, - ExprKind::NilLiteral, - }; - - if (!typeVar) - return None; - - auto *locator = typeVar->getImpl().getLocator(); - if (!locator->directlyAt()) - return None; - - auto literalKind = getAsExpr(locator->getAnchor())->getKind(); - if (!atomicLiteralKinds.count(literalKind)) - return None; - - return literalKind; -} - void ConstraintSystem::addFixConstraint(ConstraintFix *fix, ConstraintKind kind, Type first, Type second, ConstraintLocatorBuilder locator, diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index 7ec7c1d71e760..d92deeb275fc3 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -306,6 +306,11 @@ class TypeVariableType::Implementation { /// Retrieve the generic parameter opened by this type variable. GenericTypeParamType *getGenericParameter() const; + /// Returns the \c ExprKind of this type variable if it's the type of an + /// atomic literal expression, meaning the literal can't be composed of subexpressions. + /// Otherwise, returns \c None. + Optional getAtomicLiteralKind() const; + /// Determine whether this type variable represents a closure type. bool isClosureType() const; @@ -2994,11 +2999,6 @@ class ConstraintSystem { bool isDeclUnavailable(const Decl *D, ConstraintLocator *locator = nullptr) const; - /// Returns the \c ExprKind of the given type variable if it's the type of an - /// atomic literal expression, meaning the literal can't be composed of subexpressions. - /// Otherwise, returns \c None. - Optional getAtomicLiteralKind(TypeVariableType *typeVar) const; - public: /// Whether we should attempt to fix problems. @@ -3127,18 +3127,19 @@ class ConstraintSystem { // We can merge the type variables of same-kind atomic literal expressions because they // will all have the same set of constraints and therefore can never resolve to anything // different. - auto *typeVar = type->getAs(); - if (auto literalKind = getAtomicLiteralKind(typeVar)) { - auto *&originalRep = representativeForKind[RawExprKind(*literalKind)]; - auto *currentRep = getRepresentative(typeVar); - - if (originalRep) { - if (originalRep != currentRep) - mergeEquivalenceClasses(currentRep, originalRep); - continue; - } + if (auto *typeVar = type->getAs()) { + if (auto literalKind = typeVar->getImpl().getAtomicLiteralKind()) { + auto *&originalRep = representativeForKind[RawExprKind(*literalKind)]; + auto *currentRep = getRepresentative(typeVar); + + if (originalRep) { + if (originalRep != currentRep) + mergeEquivalenceClasses(currentRep, originalRep); + continue; + } - originalRep = currentRep; + originalRep = currentRep; + } } // Introduce conversions from each input type to the supertype. diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index a1fb7d85d4568..74233bfa05004 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -82,6 +82,24 @@ TypeVariableType::Implementation::getGenericParameter() const { return locator ? locator->getGenericParameter() : nullptr; } +Optional +TypeVariableType::Implementation::getAtomicLiteralKind() const { + if (!locator || !locator->directlyAt()) + return None; + + auto kind = getAsExpr(locator->getAnchor())->getKind(); + switch (kind) { + case ExprKind::IntegerLiteral: + case ExprKind::FloatLiteral: + case ExprKind::StringLiteral: + case ExprKind::BooleanLiteral: + case ExprKind::NilLiteral: + return kind; + default: + return None; + } +} + bool TypeVariableType::Implementation::isClosureType() const { if (!(locator && locator->getAnchor())) return false; From b26554147e850ddeedbdf942c930b5231d345275 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Thu, 6 Aug 2020 10:14:57 -0700 Subject: [PATCH 5/7] [NFC] Document the new type variable merging heuristic in addJoinConstraint --- lib/Sema/ConstraintSystem.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index d92deeb275fc3..0cd6acf1accba 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -3096,6 +3096,11 @@ class ConstraintSystem { /// a new type variable or a specified supertype. At some point, we may want /// a new constraint kind to cover the join. /// + /// \note This method will merge any input type variables for atomic literal + /// expressions of the same kind. It assumes that if same-kind literal type + /// variables are joined, there will be no differing constraints on those + /// type variables. + /// /// \returns the joined type, which is generally a new type variable, unless there are /// fewer than 2 input types or the \c supertype parameter is specified. template From 989a4328982aea38a372185d3889e277595cae58 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Thu, 6 Aug 2020 12:30:45 -0700 Subject: [PATCH 6/7] [NFC] Update array literal type checking performance validation tests. --- validation-test/SILOptimizer/large_string_array.swift.gyb | 3 --- .../type_checker_perf/{slow => fast}/rdar30596744_2.swift.gyb | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) rename validation-test/Sema/type_checker_perf/{slow => fast}/rdar30596744_2.swift.gyb (68%) diff --git a/validation-test/SILOptimizer/large_string_array.swift.gyb b/validation-test/SILOptimizer/large_string_array.swift.gyb index 7a0169748ead0..6285e4b97c75b 100644 --- a/validation-test/SILOptimizer/large_string_array.swift.gyb +++ b/validation-test/SILOptimizer/large_string_array.swift.gyb @@ -1,9 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %gyb %s > %t/main.swift -// FIXME: Re-enable SILOptimizer/large_string_array.swift.gyb -// REQUIRES: rdar66219627 - // The compiler should finish in less than 1 minute. To give some slack, // specify a timeout of 5 minutes. // If the compiler needs more than 5 minutes, there is probably a real problem. diff --git a/validation-test/Sema/type_checker_perf/slow/rdar30596744_2.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar30596744_2.swift.gyb similarity index 68% rename from validation-test/Sema/type_checker_perf/slow/rdar30596744_2.swift.gyb rename to validation-test/Sema/type_checker_perf/fast/rdar30596744_2.swift.gyb index cfd18b2c7006e..1dd787e01ee08 100644 --- a/validation-test/Sema/type_checker_perf/slow/rdar30596744_2.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/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 --begin 1 --end 5 --step 1 --select NumLeafScopes %s --expected-exit-code 1 // REQUIRES: asserts,no_asan % enum_cases = 3 From 19fce323c5d2829d06c076aab8a27810a4ce24c9 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Thu, 6 Aug 2020 17:58:00 -0700 Subject: [PATCH 7/7] [Diagnostics] For array element conversion failures, emit an error message for each element whose type variable was merged in addJoinConstraint --- lib/Sema/CSDiagnostics.cpp | 27 +++++++++++++++++++++++++ lib/Sema/CSDiagnostics.h | 2 ++ test/Constraints/diagnostics.swift | 2 +- test/Parse/pointer_conversion.swift.gyb | 2 +- test/expr/cast/as_coerce.swift | 4 ++-- 5 files changed, 33 insertions(+), 4 deletions(-) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index e57e64680558f..1ea4617af879f 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -4942,6 +4942,9 @@ bool CollectionElementContextualFailure::diagnoseAsError() { Optional diagnostic; if (isExpr(anchor)) { + if (diagnoseMergedLiteralElements()) + return true; + diagnostic.emplace(emitDiagnostic(diag::cannot_convert_array_element, eltType, contextualType)); } @@ -4992,6 +4995,30 @@ bool CollectionElementContextualFailure::diagnoseAsError() { return true; } +bool CollectionElementContextualFailure::diagnoseMergedLiteralElements() { + auto elementAnchor = simplifyLocatorToAnchor(getLocator()); + if (!elementAnchor) + return false; + + auto *typeVar = getRawType(elementAnchor)->getAs(); + if (!typeVar || !typeVar->getImpl().getAtomicLiteralKind()) + return false; + + // This element is a literal whose type variable could have been merged with others, + // but the conversion constraint to the array element type was only placed on one + // of them. So, we want to emit the error for each element whose type variable is in + // this equivalence class. + auto &cs = getConstraintSystem(); + auto node = cs.getRepresentative(typeVar)->getImpl().getGraphNode(); + for (const auto *typeVar : node->getEquivalenceClass()) { + auto anchor = typeVar->getImpl().getLocator()->getAnchor(); + emitDiagnosticAt(constraints::getLoc(anchor), diag::cannot_convert_array_element, + getFromType(), getToType()); + } + + return true; +} + bool MissingContextualConformanceFailure::diagnoseAsError() { auto anchor = getAnchor(); auto path = getLocator()->getPath(); diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index e6134c200cdb3..17ca225d66c0d 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -1637,6 +1637,8 @@ class CollectionElementContextualFailure final : public ContextualFailure { : ContextualFailure(solution, eltType, contextualType, locator) {} bool diagnoseAsError() override; + + bool diagnoseMergedLiteralElements(); }; class MissingContextualConformanceFailure final : public ContextualFailure { diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift index e961b108bda48..bff33fe7caa73 100644 --- a/test/Constraints/diagnostics.swift +++ b/test/Constraints/diagnostics.swift @@ -338,7 +338,7 @@ variadic(arrayWithOtherEltType) // expected-error {{cannot convert value of type variadic(1, arrayWithOtherEltType) // expected-error {{cannot convert value of type '[String]' to expected argument type 'Int'}} // FIXME: SR-11104 -variadic(["hello", "world"]) // expected-error {{cannot convert value of type 'String' to expected element type 'Int'}} +variadic(["hello", "world"]) // expected-error 2 {{cannot convert value of type 'String' to expected element type 'Int'}} // expected-error@-1 {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}} // expected-note@-2 {{remove brackets to pass array elements directly}} diff --git a/test/Parse/pointer_conversion.swift.gyb b/test/Parse/pointer_conversion.swift.gyb index 4c9af4a6a5568..616285d4fbda6 100644 --- a/test/Parse/pointer_conversion.swift.gyb +++ b/test/Parse/pointer_conversion.swift.gyb @@ -164,7 +164,7 @@ func constPointerArguments(_ p: UnsafeMutablePointer, takesConstPointer([0, 1, 2]) // QoI: CSDiags doesn't handle array -> pointer impl conversions well takesConstPointer([0.0, 1.0, 2.0]) - // expected-error@-1 {{cannot convert value of type 'Double' to expected element type 'Int'}} + // expected-error@-1 3 {{cannot convert value of type 'Double' to expected element type 'Int'}} // We don't allow these conversions outside of function arguments. var x: UnsafePointer = &i // expected-error {{use of extraneous '&'}} diff --git a/test/expr/cast/as_coerce.swift b/test/expr/cast/as_coerce.swift index 3821104d339e1..962c656322ca1 100644 --- a/test/expr/cast/as_coerce.swift +++ b/test/expr/cast/as_coerce.swift @@ -84,13 +84,13 @@ c3 as C4 // expected-error {{'C3' is not convertible to 'C4'; did you mean to us Double(1) as Double as String // expected-error{{cannot convert value of type 'Double' to type 'String' in coercion}} ["awd"] as [Int] // expected-error{{cannot convert value of type 'String' to expected element type 'Int'}} ([1, 2, 1.0], 1) as ([String], Int) -// expected-error@-1 {{cannot convert value of type 'Int' to expected element type 'String'}} +// expected-error@-1 2 {{cannot convert value of type 'Int' to expected element type 'String'}} // expected-error@-2 {{cannot convert value of type 'Double' to expected element type 'String'}} [[1]] as [[String]] // expected-error{{cannot convert value of type 'Int' to expected element type 'String'}} (1, 1.0) as (Int, Int) // expected-error{{cannot convert value of type '(Int, Double)' to type '(Int, Int)' in coercion}} (1.0, 1, "asd") as (String, Int, Float) // expected-error{{cannot convert value of type '(Double, Int, String)' to type '(String, Int, Float)' in coercion}} (1, 1.0, "a", [1, 23]) as (Int, Double, String, [String]) -// expected-error@-1 {{cannot convert value of type 'Int' to expected element type 'String'}} +// expected-error@-1 2 {{cannot convert value of type 'Int' to expected element type 'String'}} _ = [1] as! [String] // OK _ = [(1, (1, 1))] as! [(Int, (String, Int))] // OK