Skip to content

Commit f7ef6d4

Browse files
committed
[Diagnostics] Augment conformance failure to with a note about enum with associated values
If the problem is related to an operator and argument is an enum with associated values mention that conformances to `Equatable` and `Comparable` are not synthesized in such cases.
1 parent 0ea0b8e commit f7ef6d4

File tree

3 files changed

+40
-7
lines changed

3 files changed

+40
-7
lines changed

lib/Sema/CSDiagnostics.cpp

+26
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,32 @@ bool MissingConformanceFailure::diagnoseAsError() {
446446
}
447447
}
448448

449+
// If the problem has been (unambiguously) determined to be related
450+
// to one of of the standard comparison operators and argument is
451+
// enum with associated values, let's produce a tailored note which
452+
// says that conformances for enums with associated values can't be
453+
// synthesized.
454+
if (isStandardComparisonOperator(anchor)) {
455+
auto isEnumWithAssociatedValues = [](Type type) -> bool {
456+
if (auto *enumType = type->getAs<EnumType>())
457+
return !enumType->getDecl()->hasOnlyCasesWithoutAssociatedValues();
458+
return false;
459+
};
460+
461+
// Limit this to `Equatable` and `Comparable` protocols for now.
462+
auto *protocol = getRHS()->castTo<ProtocolType>()->getDecl();
463+
if (isEnumWithAssociatedValues(getLHS()) &&
464+
(protocol->isSpecificProtocol(KnownProtocolKind::Equatable) ||
465+
protocol->isSpecificProtocol(KnownProtocolKind::Comparable))) {
466+
if (RequirementFailure::diagnoseAsError()) {
467+
auto opName = getOperatorName(anchor);
468+
emitDiagnostic(diag::no_binary_op_overload_for_enum_with_payload,
469+
opName->str());
470+
return true;
471+
}
472+
}
473+
}
474+
449475
if (diagnoseAsAmbiguousOperatorRef())
450476
return true;
451477

lib/Sema/ConstraintSystem.cpp

+10-7
Original file line numberDiff line numberDiff line change
@@ -2777,12 +2777,6 @@ static void diagnoseOperatorAmbiguity(ConstraintSystem &cs,
27772777
auto *anchor = castToExpr(locator->getAnchor());
27782778
auto *applyExpr = cast<ApplyExpr>(cs.getParentExpr(anchor));
27792779

2780-
auto isNameOfStandardComparisonOperator = [](Identifier opName) -> bool {
2781-
return opName.is("==") || opName.is("!=") || opName.is("===") ||
2782-
opName.is("!==") || opName.is("<") || opName.is(">") ||
2783-
opName.is("<=") || opName.is(">=");
2784-
};
2785-
27862780
auto isEnumWithAssociatedValues = [](Type type) -> bool {
27872781
if (auto *enumType = type->getAs<EnumType>())
27882782
return !enumType->getDecl()->hasOnlyCasesWithoutAssociatedValues();
@@ -2805,7 +2799,7 @@ static void diagnoseOperatorAmbiguity(ConstraintSystem &cs,
28052799
.highlight(lhs->getSourceRange())
28062800
.highlight(rhs->getSourceRange());
28072801

2808-
if (isNameOfStandardComparisonOperator(operatorName) &&
2802+
if (isStandardComparisonOperator(binaryOp->getFn()) &&
28092803
isEnumWithAssociatedValues(lhsType)) {
28102804
DE.diagnose(applyExpr->getLoc(),
28112805
diag::no_binary_op_overload_for_enum_with_payload,
@@ -4228,6 +4222,15 @@ bool constraints::isPatternMatchingOperator(Expr *expr) {
42284222
return isOperator(expr, "~=");
42294223
}
42304224

4225+
bool constraints::isStandardComparisonOperator(Expr *expr) {
4226+
if (auto opName = getOperatorName(expr)) {
4227+
return opName->is("==") || opName->is("!=") || opName->is("===") ||
4228+
opName->is("!==") || opName->is("<") || opName->is(">") ||
4229+
opName->is("<=") || opName->is(">=");
4230+
}
4231+
return false;
4232+
}
4233+
42314234
bool constraints::isOperatorArgument(ConstraintLocator *locator,
42324235
StringRef expectedOperator) {
42334236
if (!locator->findLast<LocatorPathElt::ApplyArgToParam>())

lib/Sema/ConstraintSystem.h

+4
Original file line numberDiff line numberDiff line change
@@ -5169,6 +5169,10 @@ bool isArgumentOfReferenceEqualityOperator(ConstraintLocator *locator);
51695169
/// pattern-matching operator `~=`
51705170
bool isPatternMatchingOperator(Expr *expr);
51715171

5172+
/// Determine whether given expression is a reference to a
5173+
/// "standard" comparison operator such as "==", "!=", ">" etc.
5174+
bool isStandardComparisonOperator(Expr *expr);
5175+
51725176
/// If given expression references operator overlaod(s)
51735177
/// extract and produce name of the operator.
51745178
Optional<Identifier> getOperatorName(Expr *expr);

0 commit comments

Comments
 (0)