Skip to content

Commit f95cabb

Browse files
committed
[ConstraintSystem] Allow sequence element mismatch fix to produce new holes
Type on the right-hand side of the element conversion/pattern match should be allowed to have holes to be able to diagnose failures with structurally incompatible types. Resolves: rdar://problem/60832876
1 parent 963c7fc commit f95cabb

File tree

4 files changed

+42
-6
lines changed

4 files changed

+42
-6
lines changed

Diff for: include/swift/AST/DiagnosticsSema.def

+3
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,9 @@ ERROR(value_type_comparison_with_nil_illegal,none,
184184
ERROR(cannot_match_expr_pattern_with_value,none,
185185
"expression pattern of type %0 cannot match values of type %1",
186186
(Type, Type))
187+
ERROR(cannot_match_expr_tuple_pattern_with_nontuple_value,none,
188+
"tuple pattern cannot match values of non-tuple type %0",
189+
(Type))
187190
ERROR(cannot_match_unresolved_expr_pattern_with_value,none,
188191
"pattern cannot match values of type %0",
189192
(Type))

Diff for: lib/Sema/CSDiagnostics.cpp

+21-6
Original file line numberDiff line numberDiff line change
@@ -4865,12 +4865,27 @@ bool CollectionElementContextualFailure::diagnoseAsError() {
48654865
}
48664866

48674867
if (locator->isForSequenceElementType()) {
4868-
diagnostic.emplace(
4869-
emitDiagnostic(anchor->getLoc(),
4870-
contextualType->isExistentialType()
4871-
? diag::cannot_convert_sequence_element_protocol
4872-
: diag::cannot_convert_sequence_element_value,
4873-
eltType, contextualType));
4868+
auto &cs = getConstraintSystem();
4869+
// If this is a conversion failure related to binding of `for-each`
4870+
// statement it has to be diagnosed as pattern match if there are
4871+
// holes present in the contextual type.
4872+
if (cs.getContextualTypePurpose(anchor) ==
4873+
ContextualTypePurpose::CTP_ForEachStmt &&
4874+
contextualType->hasHole()) {
4875+
diagnostic.emplace(emitDiagnostic(
4876+
anchor->getLoc(),
4877+
(contextualType->is<TupleType>() && !eltType->is<TupleType>())
4878+
? diag::cannot_match_expr_tuple_pattern_with_nontuple_value
4879+
: diag::cannot_match_unresolved_expr_pattern_with_value,
4880+
eltType));
4881+
} else {
4882+
diagnostic.emplace(
4883+
emitDiagnostic(anchor->getLoc(),
4884+
contextualType->isExistentialType()
4885+
? diag::cannot_convert_sequence_element_protocol
4886+
: diag::cannot_convert_sequence_element_value,
4887+
eltType, contextualType));
4888+
}
48744889
}
48754890

48764891
if (!diagnostic)

Diff for: lib/Sema/CSSimplify.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -3908,6 +3908,15 @@ bool ConstraintSystem::repairFailures(
39083908
if (rhs->isExistentialType())
39093909
break;
39103910

3911+
// If the types didn't line up, let's allow right-hand side
3912+
// of the conversion (or pattern match) to have holes. This
3913+
// helps when conversion if between a type and a tuple e.g.
3914+
// `Int` vs. `(_, _)`.
3915+
rhs.visit([&](Type type) {
3916+
if (auto *typeVar = type->getAs<TypeVariableType>())
3917+
recordPotentialHole(typeVar);
3918+
});
3919+
39113920
conversionsOrFixes.push_back(CollectionElementContextualMismatch::create(
39123921
*this, lhs, rhs, getConstraintLocator(locator)));
39133922
break;

Diff for: test/stmt/foreach.swift

+9
Original file line numberDiff line numberDiff line change
@@ -220,3 +220,12 @@ extension Int : P { }
220220
func testRepeated(ri: RepeatedSequence<Int>) {
221221
for x in ri { _ = x }
222222
}
223+
224+
// SR-12398: Poor pattern matching diagnostic: "for-in loop requires '[Int]' to conform to 'Sequence'"
225+
func sr_12398(arr1: [Int], arr2: [(a: Int, b: String)]) {
226+
for (x, y) in arr1 {}
227+
// expected-error@-1 {{tuple pattern cannot match values of non-tuple type 'Int'}}
228+
229+
for (x, y, _) in arr2 {}
230+
// expected-error@-1 {{pattern cannot match values of type '(a: Int, b: String)'}}
231+
}

0 commit comments

Comments
 (0)