@@ -8629,6 +8629,69 @@ fixMemberRef(ConstraintSystem &cs, Type baseTy,
86298629 return nullptr;
86308630}
86318631
8632+ /// Convert the given enum element pattern into an expression pattern
8633+ /// and synthesize ~= operator application to find the type of the
8634+ /// element.
8635+ static bool inferEnumMemberThroughTildeEqualsOperator(
8636+ ConstraintSystem &cs, EnumElementPattern *pattern, Type enumTy,
8637+ Type elementTy, ConstraintLocator *locator) {
8638+ if (!pattern->hasUnresolvedOriginalExpr())
8639+ return true;
8640+
8641+ auto &DC = cs.DC;
8642+ auto &ctx = cs.getASTContext();
8643+
8644+ // Slots for expression and variable are going to be filled via
8645+ // synthesizing ~= operator application.
8646+ auto *EP = new (ctx) ExprPattern(pattern->getUnresolvedOriginalExpr(),
8647+ /*matchExpr=*/nullptr, /*matchVar=*/nullptr);
8648+
8649+ auto tildeEqualsApplication =
8650+ TypeChecker::synthesizeTildeEqualsOperatorApplication(EP, DC, enumTy);
8651+
8652+ if (!tildeEqualsApplication)
8653+ return true;
8654+
8655+ VarDecl *matchVar;
8656+ Expr *matchCall;
8657+
8658+ std::tie(matchVar, matchCall) = *tildeEqualsApplication;
8659+
8660+ // result of ~= operator is always a `Bool`.
8661+ auto target = SolutionApplicationTarget::forExprPattern(
8662+ matchCall, DC, EP, ctx.getBoolDecl()->getDeclaredInterfaceType());
8663+
8664+ DiagnosticTransaction diagnostics(ctx.Diags);
8665+ {
8666+ if (cs.preCheckTarget(target, /*replaceInvalidRefWithErrors=*/true,
8667+ /*leaveClosureBodyUnchecked=*/false)) {
8668+ // Skip diagnostics if they are disabled, otherwise it would result in
8669+ // duplicate diagnostics, since this operation is going to be repeated
8670+ // in diagnostic mode.
8671+ if (!cs.shouldAttemptFixes())
8672+ diagnostics.abort();
8673+
8674+ return true;
8675+ }
8676+ }
8677+
8678+ cs.generateConstraints(target, FreeTypeVariableBinding::Disallow);
8679+
8680+ // Sub-expression associated with expression pattern is the enum element
8681+ // access which needs to be connected to the provided element type.
8682+ cs.addConstraint(ConstraintKind::Conversion, cs.getType(EP->getSubExpr()),
8683+ elementTy, cs.getConstraintLocator(EP));
8684+
8685+ // Store the $match variable and binary expression for solution application.
8686+ EP->setMatchVar(matchVar);
8687+ EP->setMatchExpr(matchCall);
8688+ EP->setType(enumTy);
8689+
8690+ cs.setSolutionApplicationTarget(pattern, target);
8691+
8692+ return false;
8693+ }
8694+
86328695ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
86338696 ConstraintKind kind, Type baseTy, DeclNameRef member, Type memberTy,
86348697 DeclContext *useDC, FunctionRefKind functionRefKind,
@@ -8834,6 +8897,30 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
88348897 (void)recordFix(fix);
88358898 }
88368899
8900+ // If there were no results from a direct enum lookup, let's attempt
8901+ // to resolve this member via ~= operator application.
8902+ if (candidates.empty()) {
8903+ if (auto patternLoc =
8904+ locator->getLastElementAs<LocatorPathElt::PatternMatch>()) {
8905+ if (auto *enumElement =
8906+ dyn_cast<EnumElementPattern>(patternLoc->getPattern())) {
8907+ auto enumType = baseObjTy->getMetatypeInstanceType();
8908+
8909+ // If the synthesis of ~= resulted in errors (i.e. broken stdlib)
8910+ // that would be diagnosed inline, so let's just fall through and
8911+ // let this situation be diagnosed as a missing member.
8912+ auto hadErrors = inferEnumMemberThroughTildeEqualsOperator(
8913+ *this, enumElement, enumType, memberTy, locator);
8914+
8915+ // Let's consider current member constraint solved because it's
8916+ // replaced by a new set of constraints that would resolve member
8917+ // type.
8918+ if (!hadErrors)
8919+ return SolutionKind::Solved;
8920+ }
8921+ }
8922+ }
8923+
88378924 if (!candidates.empty()) {
88388925 addOverloadSet(candidates, locator);
88398926 return SolutionKind::Solved;
0 commit comments