Skip to content

Commit c1d0036

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
1 parent e059d5c commit c1d0036

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
@@ -4887,14 +4887,24 @@ bool ConstraintSystem::repairFailures(
48874887
}
48884888

48894889
case ConstraintLocator::PatternMatch: {
4890+
auto *pattern = elt.castTo<LocatorPathElt::PatternMatch>().getPattern();
4891+
bool isMemberMatch =
4892+
lhs->is<FunctionType>() && isa<EnumElementPattern>(pattern);
4893+
4894+
// If member reference couldn't be resolved, let's allow pattern
4895+
// to have holes.
4896+
if (rhs->isPlaceholder() && isMemberMatch) {
4897+
recordAnyTypeVarAsPotentialHole(lhs);
4898+
return true;
4899+
}
4900+
48904901
// If either type is a placeholder, consider this fixed.
48914902
if (lhs->isPlaceholder() || rhs->isPlaceholder())
48924903
return true;
48934904

4894-
// If the left-hand side is a function type and the pattern is an enum
4895-
// element pattern, call it a contextual mismatch.
4896-
auto pattern = elt.castTo<LocatorPathElt::PatternMatch>().getPattern();
4897-
if (lhs->is<FunctionType>() && isa<EnumElementPattern>(pattern)) {
4905+
// If member reference didn't match expected pattern,
4906+
// let's consider that a contextual mismatch.
4907+
if (isMemberMatch) {
48984908
recordAnyTypeVarAsPotentialHole(lhs);
48994909
recordAnyTypeVarAsPotentialHole(rhs);
49004910

@@ -8207,6 +8217,13 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
82078217
// `key path` constraint can't be retired until all components
82088218
// are simplified.
82098219
addTypeVariableConstraintsToWorkList(memberTypeVar);
8220+
} else if (locator->isLastElement<LocatorPathElt::PatternMatch>()) {
8221+
// Let's handle member patterns specifically because they use
8222+
// equality instead of argument application constraint, so allowing
8223+
// them to bind member could mean missing valid hole positions in
8224+
// the pattern.
8225+
assignFixedType(memberTypeVar,
8226+
PlaceholderType::get(getASTContext(), memberTypeVar));
82108227
} else {
82118228
recordPotentialHole(memberTypeVar);
82128229
}

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)