Skip to content

Commit 411cbc3

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 11fbb4e commit 411cbc3

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
@@ -313,6 +313,9 @@ class ConstraintLocator : public llvm::FoldingSetNode {
313313
/// branch, and if so, the kind of branch.
314314
Optional<SingleValueStmtBranchKind> isForSingleValueStmtBranch() const;
315315

316+
/// Whether the locator in question is for a pattern match.
317+
bool isForPatternMatch() const;
318+
316319
/// Returns true if \p locator is ending with either of the following
317320
/// - Member
318321
/// - Member -> KeyPathDynamicMember

include/swift/Sema/ConstraintLocatorPathElts.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,10 @@ CUSTOM_LOCATOR_PATH_ELT(TernaryBranch)
222222
/// Performing a pattern patch.
223223
CUSTOM_LOCATOR_PATH_ELT(PatternMatch)
224224

225+
/// The constraint that models the allowed implicit casts for
226+
/// an EnumElementPattern.
227+
SIMPLE_LOCATOR_PATH_ELT(EnumPatternImplicitCastMatch)
228+
225229
/// Points to a particular attribute associated with one of
226230
/// the arguments e.g. `inout` or its type e.g. `@escaping`.
227231
///

lib/Sema/CSDiagnostics.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2659,6 +2659,19 @@ bool ContextualFailure::diagnoseAsError() {
26592659
return false;
26602660
}
26612661

2662+
case ConstraintLocator::EnumPatternImplicitCastMatch: {
2663+
// In this case, the types are reversed, as we are checking whether we
2664+
// can convert the pattern type to the context type.
2665+
std::swap(fromType, toType);
2666+
diagnostic = diag::cannot_match_value_with_pattern;
2667+
break;
2668+
}
2669+
2670+
case ConstraintLocator::PatternMatch: {
2671+
diagnostic = diag::cannot_match_value_with_pattern;
2672+
break;
2673+
}
2674+
26622675
default:
26632676
return false;
26642677
}
@@ -2871,9 +2884,11 @@ bool ContextualFailure::diagnoseConversionToNil() const {
28712884
void ContextualFailure::tryFixIts(InFlightDiagnostic &diagnostic) const {
28722885
auto *locator = getLocator();
28732886
// Can't apply any of the fix-its below if this failure
2874-
// is related to `inout` argument.
2875-
if (locator->isLastElement<LocatorPathElt::LValueConversion>())
2887+
// is related to `inout` argument, or a pattern mismatch.
2888+
if (locator->isLastElement<LocatorPathElt::LValueConversion>() ||
2889+
locator->isForPatternMatch()) {
28762890
return;
2891+
}
28772892

28782893
if (trySequenceSubsequenceFixIts(diagnostic))
28792894
return;

lib/Sema/CSGen.cpp

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

2728+
auto patternLocator =
2729+
locator.withPathElement(LocatorPathElt::PatternMatch(pattern));
2730+
27282731
if (enumPattern->getParentType() || enumPattern->getParentTypeRepr()) {
27292732
// Resolve the parent type.
27302733
const auto parentType = [&] {
@@ -2752,25 +2755,23 @@ namespace {
27522755

27532756
// Perform member lookup into the parent's metatype.
27542757
Type parentMetaType = MetatypeType::get(parentType);
2755-
CS.addValueMemberConstraint(
2756-
parentMetaType, enumPattern->getName(), memberType, CurDC,
2757-
functionRefKind, {},
2758-
CS.getConstraintLocator(locator,
2759-
LocatorPathElt::PatternMatch(pattern)));
2758+
CS.addValueMemberConstraint(parentMetaType, enumPattern->getName(),
2759+
memberType, CurDC, functionRefKind, {},
2760+
patternLocator);
27602761

27612762
// Parent type needs to be convertible to the pattern type; this
27622763
// accounts for cases where the pattern type is existential.
27632764
CS.addConstraint(
27642765
ConstraintKind::Conversion, parentType, patternType,
2765-
locator.withPathElement(LocatorPathElt::PatternMatch(pattern)));
2766+
patternLocator.withPathElement(
2767+
ConstraintLocator::EnumPatternImplicitCastMatch));
27662768

27672769
baseType = parentType;
27682770
} else {
27692771
// Use the pattern type for member lookup.
27702772
CS.addUnresolvedValueMemberConstraint(
27712773
MetatypeType::get(patternType), enumPattern->getName(),
2772-
memberType, CurDC, functionRefKind,
2773-
locator.withPathElement(LocatorPathElt::PatternMatch(pattern)));
2774+
memberType, CurDC, functionRefKind, patternLocator);
27742775

27752776
baseType = patternType;
27762777
}
@@ -2807,13 +2808,11 @@ namespace {
28072808
// NOTE: The order here is important! Pattern matching equality is
28082809
// not symmetric (we need to fix that either by using a different
28092810
// constraint, or actually making it symmetric).
2810-
CS.addConstraint(
2811-
ConstraintKind::Equal, functionType, memberType,
2812-
locator.withPathElement(LocatorPathElt::PatternMatch(pattern)));
2811+
CS.addConstraint(ConstraintKind::Equal, functionType, memberType,
2812+
patternLocator);
28132813

2814-
CS.addConstraint(
2815-
ConstraintKind::Conversion, outputType, baseType,
2816-
locator.withPathElement(LocatorPathElt::PatternMatch(pattern)));
2814+
CS.addConstraint(ConstraintKind::Conversion, outputType, baseType,
2815+
patternLocator);
28172816
}
28182817

28192818
return setType(patternType);

lib/Sema/CSSimplify.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6285,8 +6285,20 @@ bool ConstraintSystem::repairFailures(
62856285
break;
62866286
}
62876287

6288+
case ConstraintLocator::EnumPatternImplicitCastMatch: {
6289+
// If either type is a placeholder, consider this fixed.
6290+
if (lhs->isPlaceholder() || rhs->isPlaceholder())
6291+
return true;
6292+
6293+
conversionsOrFixes.push_back(ContextualMismatch::create(
6294+
*this, lhs, rhs, getConstraintLocator(locator)));
6295+
break;
6296+
}
6297+
62886298
case ConstraintLocator::PatternMatch: {
62896299
auto *pattern = elt.castTo<LocatorPathElt::PatternMatch>().getPattern();
6300+
6301+
// TODO: We ought to introduce a new locator element for this.
62906302
bool isMemberMatch =
62916303
lhs->is<FunctionType>() && isa<EnumElementPattern>(pattern);
62926304

@@ -6301,13 +6313,12 @@ bool ConstraintSystem::repairFailures(
63016313
if (lhs->isPlaceholder() || rhs->isPlaceholder())
63026314
return true;
63036315

6304-
// If member reference didn't match expected pattern,
6305-
// let's consider that a contextual mismatch.
63066316
if (isMemberMatch) {
63076317
recordAnyTypeVarAsPotentialHole(lhs);
63086318
recordAnyTypeVarAsPotentialHole(rhs);
63096319
conversionsOrFixes.push_back(AllowAssociatedValueMismatch::create(
63106320
*this, lhs, rhs, getConstraintLocator(locator)));
6321+
break;
63116322
}
63126323

63136324
// `weak` declaration with an explicit non-optional type e.g.
@@ -6329,6 +6340,9 @@ bool ConstraintSystem::repairFailures(
63296340
}
63306341
}
63316342

6343+
conversionsOrFixes.push_back(ContextualMismatch::create(
6344+
*this, lhs, rhs, getConstraintLocator(locator)));
6345+
63326346
break;
63336347
}
63346348

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:
@@ -402,6 +403,10 @@ void LocatorPathElt::dump(raw_ostream &out) const {
402403
out << "pattern match";
403404
break;
404405

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

@@ -662,6 +667,10 @@ ConstraintLocator::isForSingleValueStmtBranch() const {
662667
return SingleValueStmtBranchKind::Regular;
663668
}
664669

670+
bool ConstraintLocator::isForPatternMatch() const {
671+
return findLast<LocatorPathElt::PatternMatch>().has_value();
672+
}
673+
665674
bool ConstraintLocator::isMemberRef() const {
666675
if (isLastElement<LocatorPathElt::Member>()) {
667676
return true;

lib/Sema/ConstraintSystem.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5706,6 +5706,11 @@ void constraints::simplifyLocator(ASTNode &anchor,
57065706
continue;
57075707
}
57085708

5709+
case ConstraintLocator::EnumPatternImplicitCastMatch: {
5710+
path = path.slice(1);
5711+
continue;
5712+
}
5713+
57095714
case ConstraintLocator::PackType:
57105715
case ConstraintLocator::ParentType:
57115716
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)