Skip to content

Commit bc58c30

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 9185f1f commit bc58c30

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
@@ -2667,6 +2667,19 @@ bool ContextualFailure::diagnoseAsError() {
26672667
return false;
26682668
}
26692669

2670+
case ConstraintLocator::EnumPatternImplicitCastMatch: {
2671+
// In this case, the types are reversed, as we are checking whether we
2672+
// can convert the pattern type to the context type.
2673+
std::swap(fromType, toType);
2674+
diagnostic = diag::cannot_match_value_with_pattern;
2675+
break;
2676+
}
2677+
2678+
case ConstraintLocator::PatternMatch: {
2679+
diagnostic = diag::cannot_match_value_with_pattern;
2680+
break;
2681+
}
2682+
26702683
default:
26712684
return false;
26722685
}
@@ -2879,9 +2892,11 @@ bool ContextualFailure::diagnoseConversionToNil() const {
28792892
void ContextualFailure::tryFixIts(InFlightDiagnostic &diagnostic) const {
28802893
auto *locator = getLocator();
28812894
// Can't apply any of the fix-its below if this failure
2882-
// is related to `inout` argument.
2883-
if (locator->isLastElement<LocatorPathElt::LValueConversion>())
2895+
// is related to `inout` argument, or a pattern mismatch.
2896+
if (locator->isLastElement<LocatorPathElt::LValueConversion>() ||
2897+
locator->isForPatternMatch()) {
28842898
return;
2899+
}
28852900

28862901
if (trySequenceSubsequenceFixIts(diagnostic))
28872902
return;

lib/Sema/CSGen.cpp

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

2735+
auto patternLocator =
2736+
locator.withPathElement(LocatorPathElt::PatternMatch(pattern));
2737+
27352738
if (enumPattern->getParentType() || enumPattern->getParentTypeRepr()) {
27362739
// Resolve the parent type.
27372740
const auto parentType = [&] {
@@ -2759,25 +2762,23 @@ namespace {
27592762

27602763
// Perform member lookup into the parent's metatype.
27612764
Type parentMetaType = MetatypeType::get(parentType);
2762-
CS.addValueMemberConstraint(
2763-
parentMetaType, enumPattern->getName(), memberType, CurDC,
2764-
functionRefKind, {},
2765-
CS.getConstraintLocator(locator,
2766-
LocatorPathElt::PatternMatch(pattern)));
2765+
CS.addValueMemberConstraint(parentMetaType, enumPattern->getName(),
2766+
memberType, CurDC, functionRefKind, {},
2767+
patternLocator);
27672768

27682769
// Parent type needs to be convertible to the pattern type; this
27692770
// accounts for cases where the pattern type is existential.
27702771
CS.addConstraint(
27712772
ConstraintKind::Conversion, parentType, patternType,
2772-
locator.withPathElement(LocatorPathElt::PatternMatch(pattern)));
2773+
patternLocator.withPathElement(
2774+
ConstraintLocator::EnumPatternImplicitCastMatch));
27732775

27742776
baseType = parentType;
27752777
} else {
27762778
// Use the pattern type for member lookup.
27772779
CS.addUnresolvedValueMemberConstraint(
27782780
MetatypeType::get(patternType), enumPattern->getName(),
2779-
memberType, CurDC, functionRefKind,
2780-
locator.withPathElement(LocatorPathElt::PatternMatch(pattern)));
2781+
memberType, CurDC, functionRefKind, patternLocator);
27812782

27822783
baseType = patternType;
27832784
}
@@ -2814,13 +2815,11 @@ namespace {
28142815
// NOTE: The order here is important! Pattern matching equality is
28152816
// not symmetric (we need to fix that either by using a different
28162817
// constraint, or actually making it symmetric).
2817-
CS.addConstraint(
2818-
ConstraintKind::Equal, functionType, memberType,
2819-
locator.withPathElement(LocatorPathElt::PatternMatch(pattern)));
2818+
CS.addConstraint(ConstraintKind::Equal, functionType, memberType,
2819+
patternLocator);
28202820

2821-
CS.addConstraint(
2822-
ConstraintKind::Conversion, outputType, baseType,
2823-
locator.withPathElement(LocatorPathElt::PatternMatch(pattern)));
2821+
CS.addConstraint(ConstraintKind::Conversion, outputType, baseType,
2822+
patternLocator);
28242823
}
28252824

28262825
return setType(patternType);

lib/Sema/CSSimplify.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6335,8 +6335,20 @@ bool ConstraintSystem::repairFailures(
63356335
break;
63366336
}
63376337

6338+
case ConstraintLocator::EnumPatternImplicitCastMatch: {
6339+
// If either type is a placeholder, consider this fixed.
6340+
if (lhs->isPlaceholder() || rhs->isPlaceholder())
6341+
return true;
6342+
6343+
conversionsOrFixes.push_back(ContextualMismatch::create(
6344+
*this, lhs, rhs, getConstraintLocator(locator)));
6345+
break;
6346+
}
6347+
63386348
case ConstraintLocator::PatternMatch: {
63396349
auto *pattern = elt.castTo<LocatorPathElt::PatternMatch>().getPattern();
6350+
6351+
// TODO: We ought to introduce a new locator element for this.
63406352
bool isMemberMatch =
63416353
lhs->is<FunctionType>() && isa<EnumElementPattern>(pattern);
63426354

@@ -6351,13 +6363,12 @@ bool ConstraintSystem::repairFailures(
63516363
if (lhs->isPlaceholder() || rhs->isPlaceholder())
63526364
return true;
63536365

6354-
// If member reference didn't match expected pattern,
6355-
// let's consider that a contextual mismatch.
63566366
if (isMemberMatch) {
63576367
recordAnyTypeVarAsPotentialHole(lhs);
63586368
recordAnyTypeVarAsPotentialHole(rhs);
63596369
conversionsOrFixes.push_back(AllowAssociatedValueMismatch::create(
63606370
*this, lhs, rhs, getConstraintLocator(locator)));
6371+
break;
63616372
}
63626373

63636374
// `weak` declaration with an explicit non-optional type e.g.
@@ -6379,6 +6390,9 @@ bool ConstraintSystem::repairFailures(
63796390
}
63806391
}
63816392

6393+
conversionsOrFixes.push_back(ContextualMismatch::create(
6394+
*this, lhs, rhs, getConstraintLocator(locator)));
6395+
63826396
break;
63836397
}
63846398

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
@@ -5799,6 +5799,11 @@ void constraints::simplifyLocator(ASTNode &anchor,
57995799
continue;
58005800
}
58015801

5802+
case ConstraintLocator::EnumPatternImplicitCastMatch: {
5803+
path = path.slice(1);
5804+
continue;
5805+
}
5806+
58025807
case ConstraintLocator::PackType:
58035808
case ConstraintLocator::ParentType:
58045809
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)