Skip to content

Commit 1692ec0

Browse files
authored
Merge pull request #61796 from xedin/rdar-100343275
[CSSimplify] Bind for-in patterns to holes if element type is `Any`
2 parents 352c4c2 + cf5d41c commit 1692ec0

File tree

4 files changed

+82
-36
lines changed

4 files changed

+82
-36
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 39 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5774,13 +5774,42 @@ bool CollectionElementContextualFailure::diagnoseAsError() {
57745774
auto eltType = getFromType();
57755775
auto contextualType = getToType();
57765776

5777+
auto diagnoseSingleElement = [&](Diag<Type, Type> msg, Type eltType,
5778+
Type contextualType) {
5779+
auto diagnostic = emitDiagnostic(msg, eltType, contextualType);
5780+
(void)trySequenceSubsequenceFixIts(diagnostic);
5781+
};
5782+
57775783
auto diagnoseAllOccurrences = [&](Diag<Type, Type> diagnostic) {
57785784
assert(AffectedElements.size() > 1);
57795785
for (auto *element : AffectedElements) {
57805786
emitDiagnosticAt(element->getLoc(), diagnostic, eltType, contextualType);
57815787
}
57825788
};
57835789

5790+
if (locator->isForSequenceElementType()) {
5791+
auto purpose = FailureDiagnostic::getContextualTypePurpose(getAnchor());
5792+
// If this is a conversion failure related to binding of `for-each`
5793+
// statement it has to be diagnosed as pattern match if there are
5794+
// holes present in the contextual type.
5795+
if ((purpose == ContextualTypePurpose::CTP_ForEachStmt ||
5796+
purpose == ContextualTypePurpose::CTP_ForEachSequence) &&
5797+
contextualType->hasUnresolvedType()) {
5798+
auto diagnostic = emitDiagnostic(
5799+
(contextualType->is<TupleType>() && !eltType->is<TupleType>())
5800+
? diag::cannot_match_expr_tuple_pattern_with_nontuple_value
5801+
: diag::cannot_match_unresolved_expr_pattern_with_value,
5802+
eltType);
5803+
(void)trySequenceSubsequenceFixIts(diagnostic);
5804+
} else {
5805+
diagnoseSingleElement(contextualType->isExistentialType()
5806+
? diag::cannot_convert_sequence_element_protocol
5807+
: diag::cannot_convert_sequence_element_value,
5808+
eltType, contextualType);
5809+
}
5810+
return true;
5811+
}
5812+
57845813
auto isFixedToDictionary = [&](ArrayExpr *anchor) {
57855814
return llvm::any_of(getSolution().Fixes, [&](ConstraintFix *fix) {
57865815
auto *fixAnchor = getAsExpr<ArrayExpr>(fix->getAnchor());
@@ -5790,16 +5819,16 @@ bool CollectionElementContextualFailure::diagnoseAsError() {
57905819
};
57915820

57925821
bool treatAsDictionary = false;
5793-
Optional<InFlightDiagnostic> diagnostic;
57945822
if (auto *AE = getAsExpr<ArrayExpr>(anchor)) {
57955823
if (!(treatAsDictionary = isFixedToDictionary(AE))) {
57965824
if (AffectedElements.size() > 1) {
57975825
diagnoseAllOccurrences(diag::cannot_convert_array_element);
57985826
return true;
57995827
}
58005828

5801-
diagnostic.emplace(emitDiagnostic(diag::cannot_convert_array_element,
5802-
eltType, contextualType));
5829+
diagnoseSingleElement(diag::cannot_convert_array_element, eltType,
5830+
contextualType);
5831+
return true;
58035832
}
58045833
}
58055834

@@ -5812,9 +5841,9 @@ bool CollectionElementContextualFailure::diagnoseAsError() {
58125841
return true;
58135842
}
58145843

5815-
diagnostic.emplace(emitDiagnostic(diag::cannot_convert_dict_key, eltType,
5816-
contextualType));
5817-
break;
5844+
diagnoseSingleElement(diag::cannot_convert_dict_key, eltType,
5845+
contextualType);
5846+
return true;
58185847
}
58195848

58205849
case 1: { // value
@@ -5823,43 +5852,17 @@ bool CollectionElementContextualFailure::diagnoseAsError() {
58235852
return true;
58245853
}
58255854

5826-
diagnostic.emplace(emitDiagnostic(diag::cannot_convert_dict_value,
5827-
eltType, contextualType));
5828-
break;
5855+
diagnoseSingleElement(diag::cannot_convert_dict_value, eltType,
5856+
contextualType);
5857+
return true;
58295858
}
58305859

58315860
default:
58325861
break;
58335862
}
58345863
}
58355864

5836-
if (locator->isForSequenceElementType()) {
5837-
auto purpose = FailureDiagnostic::getContextualTypePurpose(getAnchor());
5838-
// If this is a conversion failure related to binding of `for-each`
5839-
// statement it has to be diagnosed as pattern match if there are
5840-
// holes present in the contextual type.
5841-
if ((purpose == ContextualTypePurpose::CTP_ForEachStmt ||
5842-
purpose == ContextualTypePurpose::CTP_ForEachSequence) &&
5843-
contextualType->hasUnresolvedType()) {
5844-
diagnostic.emplace(emitDiagnostic(
5845-
(contextualType->is<TupleType>() && !eltType->is<TupleType>())
5846-
? diag::cannot_match_expr_tuple_pattern_with_nontuple_value
5847-
: diag::cannot_match_unresolved_expr_pattern_with_value,
5848-
eltType));
5849-
} else {
5850-
diagnostic.emplace(
5851-
emitDiagnostic(contextualType->isExistentialType()
5852-
? diag::cannot_convert_sequence_element_protocol
5853-
: diag::cannot_convert_sequence_element_value,
5854-
eltType, contextualType));
5855-
}
5856-
}
5857-
5858-
if (!diagnostic)
5859-
return false;
5860-
5861-
(void)trySequenceSubsequenceFixIts(*diagnostic);
5862-
return true;
5865+
return false;
58635866
}
58645867

58655868
bool MissingContextualConformanceFailure::diagnoseAsError() {

lib/Sema/CSSimplify.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6011,6 +6011,12 @@ bool ConstraintSystem::repairFailures(
60116011
}
60126012

60136013
case ConstraintLocator::SequenceElementType: {
6014+
if (lhs->isPlaceholder() || rhs->isPlaceholder()) {
6015+
recordAnyTypeVarAsPotentialHole(lhs);
6016+
recordAnyTypeVarAsPotentialHole(rhs);
6017+
return true;
6018+
}
6019+
60146020
// This is going to be diagnosed as `missing conformance`,
60156021
// so no need to create duplicate fixes.
60166022
if (rhs->isExistentialType())
@@ -6022,6 +6028,21 @@ bool ConstraintSystem::repairFailures(
60226028
// `Int` vs. `(_, _)`.
60236029
recordAnyTypeVarAsPotentialHole(rhs);
60246030

6031+
// If the element type is `Any` i.e. `for (x, y) in [] { ... }`
6032+
// it would never match and the pattern (`rhs` = `(x, y)`)
6033+
// doesn't have any other source of contextual information,
6034+
// so instead of waiting for elements to become holes with an
6035+
// unrelated fixes, let's proactively bind all of the pattern
6036+
// elemnts to holes here.
6037+
if (lhs->isAny()) {
6038+
rhs.visit([&](Type type) {
6039+
if (auto *typeVar = type->getAs<TypeVariableType>()) {
6040+
assignFixedType(typeVar,
6041+
PlaceholderType::get(getASTContext(), typeVar));
6042+
}
6043+
});
6044+
}
6045+
60256046
conversionsOrFixes.push_back(CollectionElementContextualMismatch::create(
60266047
*this, lhs, rhs, getConstraintLocator(locator)));
60276048
break;
@@ -13829,6 +13850,14 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1382913850
impact = 10;
1383013851
}
1383113852

13853+
// Increase impact of invalid conversions to `Any` and `AnyHashable`
13854+
// associated with collection elements (i.e. for-in sequence element)
13855+
// because it means that other side is structurally incompatible.
13856+
if (fix->getKind() == FixKind::IgnoreCollectionElementContextualMismatch) {
13857+
if (type2->isAny() || type2->isAnyHashable())
13858+
++impact;
13859+
}
13860+
1383213861
if (recordFix(fix, impact))
1383313862
return SolutionKind::Error;
1383413863

lib/Sema/CSStep.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,14 @@ class TypeVariableStep final : public BindingStep<TypeVarBindingProducer> {
632632
bool attempt(const TypeVariableBinding &choice) override;
633633

634634
bool shouldSkip(const TypeVariableBinding &choice) const override {
635+
// Let's always attempt types inferred from "defaultable" constraints
636+
// in diagnostic mode. This allows the solver to attempt i.e. `Any`
637+
// for collection literals and produce better diagnostics for for-in
638+
// statements like `for (x, y, z) in [] { ... }` when pattern type
639+
// could not be inferred.
640+
if (CS.shouldAttemptFixes())
641+
return false;
642+
635643
// If this is a defaultable binding and we have found solutions,
636644
// don't explore the default binding.
637645
return AnySolved && choice.isDefaultable();

test/stmt/foreach.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,3 +262,9 @@ do {
262262
for (x, y) in (0, 0) {}
263263
// expected-error@-1 {{for-in loop requires '(Int, Int)' to conform to 'Sequence'}}
264264
}
265+
266+
// rdar://100343275 - Sema is accepting incorrect code which leads to a crash in SILGen
267+
do {
268+
for (x, y, z) in [] { // expected-error {{tuple pattern cannot match values of non-tuple type 'Any'}}
269+
}
270+
}

0 commit comments

Comments
 (0)