Skip to content

Commit 8fec8c0

Browse files
committed
[ConstraintSystem] Bind missing member in pattern match to a hole early
If lookup failed to find a member for a pattern match, let's bind type variable representing such member to a hole right away, otherwise there is a risk of missing other potential hole locations in pattern function type (arguments + result type) because pattern matching doesn't use 'applicable function' constraint. Resolves: rdar://65667992 (cherry picked from commit c1d0036)
1 parent f35042a commit 8fec8c0

File tree

2 files changed

+50
-4
lines changed

2 files changed

+50
-4
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4878,14 +4878,24 @@ bool ConstraintSystem::repairFailures(
48784878
}
48794879

48804880
case ConstraintLocator::PatternMatch: {
4881+
auto *pattern = elt.castTo<LocatorPathElt::PatternMatch>().getPattern();
4882+
bool isMemberMatch =
4883+
lhs->is<FunctionType>() && isa<EnumElementPattern>(pattern);
4884+
4885+
// If member reference couldn't be resolved, let's allow pattern
4886+
// to have holes.
4887+
if (rhs->isPlaceholder() && isMemberMatch) {
4888+
markAnyTypeVarsAsPotentialHoles(lhs);
4889+
return true;
4890+
}
4891+
48814892
// If either type is a placeholder, consider this fixed.
48824893
if (lhs->isPlaceholder() || rhs->isPlaceholder())
48834894
return true;
48844895

4885-
// If the left-hand side is a function type and the pattern is an enum
4886-
// element pattern, call it a contextual mismatch.
4887-
auto pattern = elt.castTo<LocatorPathElt::PatternMatch>().getPattern();
4888-
if (lhs->is<FunctionType>() && isa<EnumElementPattern>(pattern)) {
4896+
// If member reference didn't match expected pattern,
4897+
// let's consider that a contextual mismatch.
4898+
if (isMemberMatch) {
48894899
markAnyTypeVarsAsPotentialHoles(lhs);
48904900
markAnyTypeVarsAsPotentialHoles(rhs);
48914901

@@ -8189,6 +8199,13 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
81898199
// `key path` constraint can't be retired until all components
81908200
// are simplified.
81918201
addTypeVariableConstraintsToWorkList(memberTypeVar);
8202+
} else if (locator->isLastElement<LocatorPathElt::PatternMatch>()) {
8203+
// Let's handle member patterns specifically because they use
8204+
// equality instead of argument application constraint, so allowing
8205+
// them to bind member could mean missing valid hole positions in
8206+
// the pattern.
8207+
assignFixedType(memberTypeVar,
8208+
PlaceholderType::get(getASTContext(), memberTypeVar));
81928209
} else {
81938210
recordPotentialHole(memberTypeVar);
81948211
}

test/Constraints/result_builder_diags.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,3 +728,32 @@ struct TuplifiedStructWithInvalidClosure {
728728
}
729729
}
730730
}
731+
732+
// rdar://65667992 - invalid case in enum causes fallback diagnostic
733+
func test_rdar65667992() {
734+
@resultBuilder
735+
struct Builder {
736+
static func buildBlock<T>(_ t: T) -> T { t }
737+
static func buildEither<T>(first: T) -> T { first }
738+
static func buildEither<T>(second: T) -> T { second }
739+
}
740+
741+
struct S {}
742+
743+
enum E {
744+
case set(v: Int, choices: [Int])
745+
case notSet(choices: [Int])
746+
}
747+
748+
struct MyView {
749+
var entry: E
750+
751+
@Builder var body: S {
752+
switch entry { // expected-error {{type 'E' has no member 'unset'}}
753+
case .set(_, _): S()
754+
case .unset(_): S()
755+
default: S()
756+
}
757+
}
758+
}
759+
}

0 commit comments

Comments
 (0)