Skip to content

Commit d607d3a

Browse files
committed
[Constraint system] Custom diagnostics for failed pattern matches.
Extend the constraint system’s diagnostics with specific handling for matching an enum element pattern that has a subpattern (i.e., to capture associated values) against an enum case that does not have any associated value. This brings diagnostics for the new code path on par with the existing diagnostics of coercePatternToType.
1 parent dcf7dde commit d607d3a

File tree

6 files changed

+67
-7
lines changed

6 files changed

+67
-7
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2264,14 +2264,32 @@ bool ContextualFailure::diagnoseMissingFunctionCall() const {
22642264
return false;
22652265

22662266
auto *srcFT = getFromType()->getAs<FunctionType>();
2267-
if (!srcFT || !srcFT->getParams().empty())
2267+
if (!srcFT ||
2268+
!(srcFT->getParams().empty() ||
2269+
getLocator()->isLastElement<LocatorPathElt::PatternMatch>()))
22682270
return false;
22692271

22702272
auto toType = getToType();
22712273
if (toType->is<AnyFunctionType>() ||
22722274
!TypeChecker::isConvertibleTo(srcFT->getResult(), toType, getDC()))
22732275
return false;
22742276

2277+
// Diagnose cases where the pattern tried to match associated values but
2278+
// the case we found had none.
2279+
if (auto match =
2280+
getLocator()->getLastElementAs<LocatorPathElt::PatternMatch>()) {
2281+
if (auto enumElementPattern =
2282+
dyn_cast<EnumElementPattern>(match->getPattern())) {
2283+
emitDiagnostic(enumElementPattern->getNameLoc(),
2284+
diag::enum_element_pattern_assoc_values_mismatch,
2285+
enumElementPattern->getName());
2286+
emitDiagnostic(enumElementPattern->getNameLoc(),
2287+
diag::enum_element_pattern_assoc_values_remove)
2288+
.fixItRemove(enumElementPattern->getSubPattern()->getSourceRange());
2289+
return true;
2290+
}
2291+
}
2292+
22752293
auto *anchor = getAnchor();
22762294
emitDiagnostic(anchor->getLoc(), diag::missing_nullary_call,
22772295
srcFT->getResult())

lib/Sema/CSGen.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2336,7 +2336,7 @@ namespace {
23362336
CS.addValueMemberConstraint(
23372337
parentMetaType, enumPattern->getName(), memberType, CurDC,
23382338
functionRefKind, { },
2339-
locator.withPathElement(ConstraintLocator::PatternMatch));
2339+
locator.withPathElement(LocatorPathElt::PatternMatch(pattern)));
23402340

23412341
// Parent type needs to be convertible to the pattern type; this
23422342
// accounts for cases where the pattern type is existential.
@@ -2349,7 +2349,7 @@ namespace {
23492349
CS.addUnresolvedValueMemberConstraint(
23502350
MetatypeType::get(patternType), enumPattern->getName(),
23512351
memberType, CurDC, functionRefKind,
2352-
locator.withPathElement(ConstraintLocator::PatternMatch));
2352+
locator.withPathElement(LocatorPathElt::PatternMatch(pattern)));
23532353

23542354
baseType = patternType;
23552355
}
@@ -2372,8 +2372,9 @@ namespace {
23722372
CS.getConstraintLocator(locator),
23732373
TVO_CanBindToNoEscape);
23742374
Type functionType = FunctionType::get(params, outputType);
2375-
CS.addConstraint(ConstraintKind::Equal, functionType, memberType,
2376-
locator);
2375+
CS.addConstraint(
2376+
ConstraintKind::Equal, functionType, memberType,
2377+
locator.withPathElement(LocatorPathElt::PatternMatch(pattern)));
23772378

23782379
CS.addConstraint(ConstraintKind::Conversion, outputType, baseType,
23792380
locator);

lib/Sema/CSSimplify.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3920,6 +3920,25 @@ bool ConstraintSystem::repairFailures(
39203920
break;
39213921
}
39223922

3923+
case ConstraintLocator::PatternMatch: {
3924+
// If either type is a hole, consider this fixed.
3925+
if (lhs->isHole() || rhs->isHole())
3926+
return true;
3927+
3928+
// If the left-hand side is a function type and the pattern is an enum
3929+
// element pattern, call it a contextual mismatch.
3930+
auto pattern = elt.castTo<LocatorPathElt::PatternMatch>().getPattern();
3931+
if (lhs->is<FunctionType>() && isa<EnumElementPattern>(pattern)) {
3932+
markAnyTypeVarsAsPotentialHoles(lhs);
3933+
markAnyTypeVarsAsPotentialHoles(rhs);
3934+
3935+
conversionsOrFixes.push_back(ContextualMismatch::create(
3936+
*this, lhs, rhs, getConstraintLocator(locator)));
3937+
}
3938+
3939+
break;
3940+
}
3941+
39233942
default:
39243943
break;
39253944
}
@@ -6043,7 +6062,7 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
60436062
// match, unwrap optionals and try again to allow implicit creation of
60446063
// optional "some" patterns (spelled "?").
60456064
if (result.ViableCandidates.empty() && result.UnviableCandidates.empty() &&
6046-
memberLocator->getLastElementAs<LocatorPathElt::PatternMatch>() &&
6065+
memberLocator->isLastElement<LocatorPathElt::PatternMatch>() &&
60476066
instanceTy->getOptionalObjectType() &&
60486067
baseObjTy->is<AnyMetatypeType>()) {
60496068
SmallVector<Type, 2> optionals;

lib/Sema/ConstraintLocator.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ void ConstraintLocator::Profile(llvm::FoldingSetNodeID &id, Expr *anchor,
5252
id.AddPointer(kpElt.getKeyPathDecl());
5353
break;
5454
}
55+
56+
case PatternMatch:
57+
id.AddPointer(elt.castTo<LocatorPathElt::PatternMatch>().getPattern());
58+
break;
59+
5560
case GenericArgument:
5661
case NamedTupleElement:
5762
case TupleElement:

lib/Sema/ConstraintLocator.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ class ConstraintLocator : public llvm::FoldingSetNode {
6868
case GenericParameter:
6969
case ProtocolRequirement:
7070
case Witness:
71+
case PatternMatch:
7172
return 0;
7273

7374
case ContextualType:
@@ -119,6 +120,7 @@ class ConstraintLocator : public llvm::FoldingSetNode {
119120
StoredWitness,
120121
StoredGenericSignature,
121122
StoredKeyPathDynamicMemberBase,
123+
StoredPattern,
122124
StoredKindAndValue
123125
};
124126

@@ -239,6 +241,9 @@ class ConstraintLocator : public llvm::FoldingSetNode {
239241
case StoredKeyPathDynamicMemberBase:
240242
return PathElementKind::KeyPathDynamicMember;
241243

244+
case StoredPattern:
245+
return PathElementKind::PatternMatch;
246+
242247
case StoredKindAndValue:
243248
return decodeStorage(storage).first;
244249
}
@@ -803,6 +808,18 @@ class LocatorPathElt::TernaryBranch final : public LocatorPathElt {
803808
}
804809
};
805810

811+
class LocatorPathElt::PatternMatch final : public LocatorPathElt {
812+
public:
813+
PatternMatch(Pattern *pattern)
814+
: LocatorPathElt(LocatorPathElt::StoredPattern, pattern) {}
815+
816+
Pattern *getPattern() const { return getStoredPointer<Pattern>(); }
817+
818+
static bool classof(const LocatorPathElt *elt) {
819+
return elt->getKind() == ConstraintLocator::PatternMatch;
820+
}
821+
};
822+
806823
/// A simple stack-only builder object that constructs a
807824
/// constraint locator without allocating memory.
808825
///

lib/Sema/ConstraintLocatorPathElts.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ SIMPLE_LOCATOR_PATH_ELT(DynamicCallable)
176176
CUSTOM_LOCATOR_PATH_ELT(TernaryBranch)
177177

178178
/// Performing a pattern patch.
179-
SIMPLE_LOCATOR_PATH_ELT(PatternMatch)
179+
CUSTOM_LOCATOR_PATH_ELT(PatternMatch)
180180

181181
#undef LOCATOR_PATH_ELT
182182
#undef CUSTOM_LOCATOR_PATH_ELT

0 commit comments

Comments
 (0)