@@ -8644,6 +8644,69 @@ fixMemberRef(ConstraintSystem &cs, Type baseTy,
86448644 return nullptr;
86458645}
86468646
8647+ /// Convert the given enum element pattern into an expression pattern
8648+ /// and synthesize ~= operator application to find the type of the
8649+ /// element.
8650+ static bool inferEnumMemberThroughTildeEqualsOperator(
8651+ ConstraintSystem &cs, EnumElementPattern *pattern, Type enumTy,
8652+ Type elementTy, ConstraintLocator *locator) {
8653+ if (!pattern->hasUnresolvedOriginalExpr())
8654+ return true;
8655+
8656+ auto &DC = cs.DC;
8657+ auto &ctx = cs.getASTContext();
8658+
8659+ // Slots for expression and variable are going to be filled via
8660+ // synthesizing ~= operator application.
8661+ auto *EP = new (ctx) ExprPattern(pattern->getUnresolvedOriginalExpr(),
8662+ /*matchExpr=*/nullptr, /*matchVar=*/nullptr);
8663+
8664+ auto tildeEqualsApplication =
8665+ TypeChecker::synthesizeTildeEqualsOperatorApplication(EP, DC, enumTy);
8666+
8667+ if (!tildeEqualsApplication)
8668+ return true;
8669+
8670+ VarDecl *matchVar;
8671+ Expr *matchCall;
8672+
8673+ std::tie(matchVar, matchCall) = *tildeEqualsApplication;
8674+
8675+ // result of ~= operator is always a `Bool`.
8676+ auto target = SolutionApplicationTarget::forExprPattern(
8677+ matchCall, DC, EP, ctx.getBoolDecl()->getDeclaredInterfaceType());
8678+
8679+ DiagnosticTransaction diagnostics(ctx.Diags);
8680+ {
8681+ if (cs.preCheckTarget(target, /*replaceInvalidRefWithErrors=*/true,
8682+ /*leaveClosureBodyUnchecked=*/false)) {
8683+ // Skip diagnostics if they are disabled, otherwise it would result in
8684+ // duplicate diagnostics, since this operation is going to be repeated
8685+ // in diagnostic mode.
8686+ if (!cs.shouldAttemptFixes())
8687+ diagnostics.abort();
8688+
8689+ return true;
8690+ }
8691+ }
8692+
8693+ cs.generateConstraints(target, FreeTypeVariableBinding::Disallow);
8694+
8695+ // Sub-expression associated with expression pattern is the enum element
8696+ // access which needs to be connected to the provided element type.
8697+ cs.addConstraint(ConstraintKind::Conversion, cs.getType(EP->getSubExpr()),
8698+ elementTy, cs.getConstraintLocator(EP));
8699+
8700+ // Store the $match variable and binary expression for solution application.
8701+ EP->setMatchVar(matchVar);
8702+ EP->setMatchExpr(matchCall);
8703+ EP->setType(enumTy);
8704+
8705+ cs.setSolutionApplicationTarget(pattern, target);
8706+
8707+ return false;
8708+ }
8709+
86478710ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
86488711 ConstraintKind kind, Type baseTy, DeclNameRef member, Type memberTy,
86498712 DeclContext *useDC, FunctionRefKind functionRefKind,
@@ -8849,6 +8912,30 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
88498912 (void)recordFix(fix);
88508913 }
88518914
8915+ // If there were no results from a direct enum lookup, let's attempt
8916+ // to resolve this member via ~= operator application.
8917+ if (candidates.empty()) {
8918+ if (auto patternLoc =
8919+ locator->getLastElementAs<LocatorPathElt::PatternMatch>()) {
8920+ if (auto *enumElement =
8921+ dyn_cast<EnumElementPattern>(patternLoc->getPattern())) {
8922+ auto enumType = baseObjTy->getMetatypeInstanceType();
8923+
8924+ // If the synthesis of ~= resulted in errors (i.e. broken stdlib)
8925+ // that would be diagnosed inline, so let's just fall through and
8926+ // let this situation be diagnosed as a missing member.
8927+ auto hadErrors = inferEnumMemberThroughTildeEqualsOperator(
8928+ *this, enumElement, enumType, memberTy, locator);
8929+
8930+ // Let's consider current member constraint solved because it's
8931+ // replaced by a new set of constraints that would resolve member
8932+ // type.
8933+ if (!hadErrors)
8934+ return SolutionKind::Solved;
8935+ }
8936+ }
8937+ }
8938+
88528939 if (!candidates.empty()) {
88538940 addOverloadSet(candidates, locator);
88548941 return SolutionKind::Solved;
0 commit comments