Skip to content

Commit 81e76c4

Browse files
committed
[CS] Improve diagnostics a bit for pattern mismatch
There's still plenty of more work to do here for pattern diagnostics, including introducing a bunch of new locator elements, and handling things like argument list mismatches. This at least lets us fall back to a generic mismatch diagnostic.
1 parent cb5016a commit 81e76c4

File tree

8 files changed

+69
-21
lines changed

8 files changed

+69
-21
lines changed

include/swift/Sema/ConstraintLocator.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,9 @@ class ConstraintLocator : public llvm::FoldingSetNode {
318318
/// otherwise \c nullptr.
319319
NullablePtr<Pattern> getPatternMatch() const;
320320

321+
/// Whether the locator in question is for a pattern match.
322+
bool isForPatternMatch() const;
323+
321324
/// Returns true if \p locator is ending with either of the following
322325
/// - Member
323326
/// - Member -> KeyPathDynamicMember

include/swift/Sema/ConstraintLocatorPathElts.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,10 @@ CUSTOM_LOCATOR_PATH_ELT(TernaryBranch)
225225
/// Performing a pattern patch.
226226
CUSTOM_LOCATOR_PATH_ELT(PatternMatch)
227227

228+
/// The constraint that models the allowed implicit casts for
229+
/// an EnumElementPattern.
230+
SIMPLE_LOCATOR_PATH_ELT(EnumPatternImplicitCastMatch)
231+
228232
/// Points to a particular attribute associated with one of
229233
/// the arguments e.g. `inout` or its type e.g. `@escaping`.
230234
///

lib/Sema/CSDiagnostics.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2715,6 +2715,19 @@ bool ContextualFailure::diagnoseAsError() {
27152715
return false;
27162716
}
27172717

2718+
case ConstraintLocator::EnumPatternImplicitCastMatch: {
2719+
// In this case, the types are reversed, as we are checking whether we
2720+
// can convert the pattern type to the context type.
2721+
std::swap(fromType, toType);
2722+
diagnostic = diag::cannot_match_value_with_pattern;
2723+
break;
2724+
}
2725+
2726+
case ConstraintLocator::PatternMatch: {
2727+
diagnostic = diag::cannot_match_value_with_pattern;
2728+
break;
2729+
}
2730+
27182731
default:
27192732
return false;
27202733
}
@@ -2927,9 +2940,11 @@ bool ContextualFailure::diagnoseConversionToNil() const {
29272940
void ContextualFailure::tryFixIts(InFlightDiagnostic &diagnostic) const {
29282941
auto *locator = getLocator();
29292942
// Can't apply any of the fix-its below if this failure
2930-
// is related to `inout` argument.
2931-
if (locator->isLastElement<LocatorPathElt::LValueConversion>())
2943+
// is related to `inout` argument, or a pattern mismatch.
2944+
if (locator->isLastElement<LocatorPathElt::LValueConversion>() ||
2945+
locator->isForPatternMatch()) {
29322946
return;
2947+
}
29332948

29342949
if (trySequenceSubsequenceFixIts(diagnostic))
29352950
return;

lib/Sema/CSGen.cpp

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2783,6 +2783,9 @@ namespace {
27832783
if (dyn_cast_or_null<TuplePattern>(enumPattern->getSubPattern()))
27842784
functionRefKind = FunctionRefKind::Compound;
27852785

2786+
auto patternLocator =
2787+
locator.withPathElement(LocatorPathElt::PatternMatch(pattern));
2788+
27862789
if (enumPattern->getParentType() || enumPattern->getParentTypeRepr()) {
27872790
// Resolve the parent type.
27882791
const auto parentType = [&] {
@@ -2810,25 +2813,23 @@ namespace {
28102813

28112814
// Perform member lookup into the parent's metatype.
28122815
Type parentMetaType = MetatypeType::get(parentType);
2813-
CS.addValueMemberConstraint(
2814-
parentMetaType, enumPattern->getName(), memberType, CurDC,
2815-
functionRefKind, {},
2816-
CS.getConstraintLocator(locator,
2817-
LocatorPathElt::PatternMatch(pattern)));
2816+
CS.addValueMemberConstraint(parentMetaType, enumPattern->getName(),
2817+
memberType, CurDC, functionRefKind, {},
2818+
patternLocator);
28182819

28192820
// Parent type needs to be convertible to the pattern type; this
28202821
// accounts for cases where the pattern type is existential.
28212822
CS.addConstraint(
28222823
ConstraintKind::Conversion, parentType, patternType,
2823-
locator.withPathElement(LocatorPathElt::PatternMatch(pattern)));
2824+
patternLocator.withPathElement(
2825+
ConstraintLocator::EnumPatternImplicitCastMatch));
28242826

28252827
baseType = parentType;
28262828
} else {
28272829
// Use the pattern type for member lookup.
28282830
CS.addUnresolvedValueMemberConstraint(
28292831
MetatypeType::get(patternType), enumPattern->getName(),
2830-
memberType, CurDC, functionRefKind,
2831-
locator.withPathElement(LocatorPathElt::PatternMatch(pattern)));
2832+
memberType, CurDC, functionRefKind, patternLocator);
28322833

28332834
baseType = patternType;
28342835
}
@@ -2865,13 +2866,11 @@ namespace {
28652866
// NOTE: The order here is important! Pattern matching equality is
28662867
// not symmetric (we need to fix that either by using a different
28672868
// constraint, or actually making it symmetric).
2868-
CS.addConstraint(
2869-
ConstraintKind::Equal, functionType, memberType,
2870-
locator.withPathElement(LocatorPathElt::PatternMatch(pattern)));
2869+
CS.addConstraint(ConstraintKind::Equal, functionType, memberType,
2870+
patternLocator);
28712871

2872-
CS.addConstraint(
2873-
ConstraintKind::Conversion, outputType, baseType,
2874-
locator.withPathElement(LocatorPathElt::PatternMatch(pattern)));
2872+
CS.addConstraint(ConstraintKind::Conversion, outputType, baseType,
2873+
patternLocator);
28752874
}
28762875

28772876
return setType(patternType);

lib/Sema/CSSimplify.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6352,8 +6352,20 @@ bool ConstraintSystem::repairFailures(
63526352
break;
63536353
}
63546354

6355+
case ConstraintLocator::EnumPatternImplicitCastMatch: {
6356+
// If either type is a placeholder, consider this fixed.
6357+
if (lhs->isPlaceholder() || rhs->isPlaceholder())
6358+
return true;
6359+
6360+
conversionsOrFixes.push_back(ContextualMismatch::create(
6361+
*this, lhs, rhs, getConstraintLocator(locator)));
6362+
break;
6363+
}
6364+
63556365
case ConstraintLocator::PatternMatch: {
63566366
auto *pattern = elt.castTo<LocatorPathElt::PatternMatch>().getPattern();
6367+
6368+
// TODO: We ought to introduce a new locator element for this.
63576369
bool isMemberMatch =
63586370
lhs->is<FunctionType>() && isa<EnumElementPattern>(pattern);
63596371

@@ -6368,13 +6380,12 @@ bool ConstraintSystem::repairFailures(
63686380
if (lhs->isPlaceholder() || rhs->isPlaceholder())
63696381
return true;
63706382

6371-
// If member reference didn't match expected pattern,
6372-
// let's consider that a contextual mismatch.
63736383
if (isMemberMatch) {
63746384
recordAnyTypeVarAsPotentialHole(lhs);
63756385
recordAnyTypeVarAsPotentialHole(rhs);
63766386
conversionsOrFixes.push_back(AllowAssociatedValueMismatch::create(
63776387
*this, lhs, rhs, getConstraintLocator(locator)));
6388+
break;
63786389
}
63796390

63806391
// `weak` declaration with an explicit non-optional type e.g.
@@ -6396,6 +6407,9 @@ bool ConstraintSystem::repairFailures(
63966407
}
63976408
}
63986409

6410+
conversionsOrFixes.push_back(ContextualMismatch::create(
6411+
*this, lhs, rhs, getConstraintLocator(locator)));
6412+
63996413
break;
64006414
}
64016415

lib/Sema/ConstraintLocator.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ unsigned LocatorPathElt::getNewSummaryFlags() const {
9090
case ConstraintLocator::ImplicitCallAsFunction:
9191
case ConstraintLocator::TernaryBranch:
9292
case ConstraintLocator::PatternMatch:
93+
case ConstraintLocator::EnumPatternImplicitCastMatch:
9394
case ConstraintLocator::ArgumentAttribute:
9495
case ConstraintLocator::UnresolvedMemberChainResult:
9596
case ConstraintLocator::PlaceholderType:
@@ -403,6 +404,10 @@ void LocatorPathElt::dump(raw_ostream &out) const {
403404
out << "pattern match";
404405
break;
405406

407+
case ConstraintLocator::EnumPatternImplicitCastMatch:
408+
out << "enum pattern implicit cast match";
409+
break;
410+
406411
case ConstraintLocator::ArgumentAttribute: {
407412
using AttrLoc = LocatorPathElt::ArgumentAttribute;
408413

@@ -677,6 +682,10 @@ NullablePtr<Pattern> ConstraintLocator::getPatternMatch() const {
677682
return matchElt->getPattern();
678683
}
679684

685+
bool ConstraintLocator::isForPatternMatch() const {
686+
return getPatternMatch() != nullptr;
687+
}
688+
680689
bool ConstraintLocator::isMemberRef() const {
681690
if (isLastElement<LocatorPathElt::Member>()) {
682691
return true;

lib/Sema/ConstraintSystem.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5824,6 +5824,11 @@ void constraints::simplifyLocator(ASTNode &anchor,
58245824
continue;
58255825
}
58265826

5827+
case ConstraintLocator::EnumPatternImplicitCastMatch: {
5828+
path = path.slice(1);
5829+
continue;
5830+
}
5831+
58275832
case ConstraintLocator::PackType:
58285833
case ConstraintLocator::ParentType:
58295834
case ConstraintLocator::KeyPathType:

test/Constraints/rdar107709341.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22

33
// rdar://107709341 – Make sure we don't crash.
44
func foo(_ x: Int) {
5-
// FIXME: We ought to have a better diagnostic
6-
let _ = { // expected-error {{unable to infer closure type in the current context}}
5+
let _ = {
76
switch x {
8-
case Optional<Int>.some(x):
7+
case Optional<Int>.some(x): // expected-error {{pattern of type 'Optional<Int>' cannot match 'Int'}} {{none}}
98
break
109
default:
1110
break

0 commit comments

Comments
 (0)