Skip to content

Commit d6019ac

Browse files
authored
Merge pull request #65366 from xedin/issue-65360
[CSSolver] Fix a crash in diagnostics related to pattern matching
2 parents 28bbbd5 + 20d7642 commit d6019ac

File tree

8 files changed

+59
-32
lines changed

8 files changed

+59
-32
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3337,6 +3337,13 @@ class ConstraintSystem {
33373337
void recordPotentialHole(TypeVariableType *typeVar);
33383338
void recordAnyTypeVarAsPotentialHole(Type type);
33393339

3340+
/// Record all unbound type variables that occur in the given type
3341+
/// as being bound to "hole" type represented by \c PlaceholderType
3342+
/// in this constraint system.
3343+
///
3344+
/// \param type The type on which to holeify.
3345+
void recordTypeVariablesAsHoles(Type type);
3346+
33403347
void recordMatchCallArgumentResult(ConstraintLocator *locator,
33413348
MatchCallArgumentResult result);
33423349

lib/Sema/BuilderTransform.cpp

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,13 +1174,7 @@ ConstraintSystem::matchResultBuilder(AnyFunctionRef fn, Type builderType,
11741174

11751175
if (auto *closure =
11761176
getAsExpr<ClosureExpr>(fn.getAbstractClosureExpr())) {
1177-
auto closureTy = getClosureType(closure);
1178-
simplifyType(closureTy).visit([&](Type componentTy) {
1179-
if (auto *typeVar = componentTy->getAs<TypeVariableType>()) {
1180-
assignFixedType(typeVar,
1181-
PlaceholderType::get(getASTContext(), typeVar));
1182-
}
1183-
});
1177+
recordTypeVariablesAsHoles(getClosureType(closure));
11841178
}
11851179

11861180
return getTypeMatchSuccess();

lib/Sema/CSGen.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2768,8 +2768,9 @@ namespace {
27682768
// correct handling of patterns like `_ as Foo` where `_` would
27692769
// get a type of `Foo` but `is` pattern enclosing it could still be
27702770
// inferred from enclosing context.
2771-
auto isType = CS.createTypeVariable(CS.getConstraintLocator(pattern),
2772-
TVO_CanBindToNoEscape);
2771+
auto isType =
2772+
CS.createTypeVariable(CS.getConstraintLocator(pattern),
2773+
TVO_CanBindToNoEscape | TVO_CanBindToHole);
27732774
CS.addConstraint(
27742775
ConstraintKind::Conversion, subPatternType, isType,
27752776
locator.withPathElement(LocatorPathElt::PatternMatch(pattern)));
@@ -2919,8 +2920,8 @@ namespace {
29192920
// TODO: we could try harder here, e.g. for enum elements to provide the
29202921
// enum type.
29212922
return setType(
2922-
CS.createTypeVariable(
2923-
CS.getConstraintLocator(locator), TVO_CanBindToNoEscape));
2923+
CS.createTypeVariable(CS.getConstraintLocator(locator),
2924+
TVO_CanBindToNoEscape | TVO_CanBindToHole));
29242925
}
29252926

29262927
llvm_unreachable("Unhandled pattern kind");

lib/Sema/CSSimplify.cpp

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6159,12 +6159,7 @@ bool ConstraintSystem::repairFailures(
61596159
// unrelated fixes, let's proactively bind all of the pattern
61606160
// elemnts to holes here.
61616161
if (lhs->isAny()) {
6162-
rhs.visit([&](Type type) {
6163-
if (auto *typeVar = type->getAs<TypeVariableType>()) {
6164-
assignFixedType(typeVar,
6165-
PlaceholderType::get(getASTContext(), typeVar));
6166-
}
6167-
});
6162+
recordTypeVariablesAsHoles(rhs);
61686163
}
61696164

61706165
conversionsOrFixes.push_back(CollectionElementContextualMismatch::create(
@@ -10402,8 +10397,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
1040210397
// equality instead of argument application constraint, so allowing
1040310398
// them to bind member could mean missing valid hole positions in
1040410399
// the pattern.
10405-
assignFixedType(memberTypeVar, PlaceholderType::get(getASTContext(),
10406-
memberTypeVar));
10400+
recordTypeVariablesAsHoles(memberTypeVar);
1040710401
} else {
1040810402
recordPotentialHole(memberTypeVar);
1040910403
}
@@ -14008,8 +14002,24 @@ void ConstraintSystem::recordAnyTypeVarAsPotentialHole(Type type) {
1400814002
return;
1400914003

1401014004
type.visit([&](Type type) {
14011-
if (auto *typeVar = type->getAs<TypeVariableType>())
14005+
if (auto *typeVar = type->getAs<TypeVariableType>()) {
1401214006
typeVar->getImpl().enableCanBindToHole(getSavedBindings());
14007+
}
14008+
});
14009+
}
14010+
14011+
void ConstraintSystem::recordTypeVariablesAsHoles(Type type) {
14012+
type.visit([&](Type componentTy) {
14013+
if (auto *typeVar = componentTy->getAs<TypeVariableType>()) {
14014+
// Ignore bound type variables. This can happen if a type variable
14015+
// occurs in multiple positions and/or if type hasn't been fully
14016+
// simplified before this call.
14017+
if (typeVar->getImpl().hasRepresentativeOrFixed())
14018+
return;
14019+
14020+
assignFixedType(typeVar,
14021+
PlaceholderType::get(getASTContext(), typeVar));
14022+
}
1401314023
});
1401414024
}
1401514025

lib/Sema/CSStep.cpp

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,13 +1103,6 @@ void ConjunctionStep::SolverSnapshot::applySolution(const Solution &solution) {
11031103
if (score.Data[SK_Fix] == 0)
11041104
return;
11051105

1106-
auto holeify = [&](Type componentTy) {
1107-
if (auto *typeVar = componentTy->getAs<TypeVariableType>()) {
1108-
CS.assignFixedType(
1109-
typeVar, PlaceholderType::get(CS.getASTContext(), typeVar));
1110-
}
1111-
};
1112-
11131106
// If this conjunction represents a closure and inference
11141107
// has failed, let's bind all of unresolved type variables
11151108
// in its interface type to holes to avoid extraneous
@@ -1118,14 +1111,13 @@ void ConjunctionStep::SolverSnapshot::applySolution(const Solution &solution) {
11181111
if (locator->directlyAt<ClosureExpr>()) {
11191112
auto closureTy =
11201113
CS.getClosureType(castToExpr<ClosureExpr>(locator->getAnchor()));
1121-
1122-
CS.simplifyType(closureTy).visit(holeify);
1114+
CS.recordTypeVariablesAsHoles(closureTy);
11231115
}
11241116

11251117
// Same for a SingleValueStmtExpr, turn any unresolved type variables present
11261118
// in its type into holes.
11271119
if (locator->isForSingleValueStmtConjunction()) {
11281120
auto *SVE = castToExpr<SingleValueStmtExpr>(locator->getAnchor());
1129-
CS.simplifyType(CS.getType(SVE)).visit(holeify);
1121+
CS.recordTypeVariablesAsHoles(CS.getType(SVE));
11301122
}
11311123
}

test/expr/closure/multi_statement.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,9 +336,10 @@ func test_unknown_refs_in_tilde_operator() {
336336
enum E {
337337
}
338338

339-
let _: (E) -> Void = { // expected-error {{unable to infer closure type in the current context}}
339+
let _: (E) -> Void = {
340340
if case .test(unknown) = $0 {
341341
// expected-error@-1 2 {{cannot find 'unknown' in scope}}
342+
// expected-error@-2 {{type 'E' has no member 'test'}}
342343
}
343344
}
344345
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
var a: Any?
4+
5+
let _: () -> Void = {
6+
for case (is Int)? in [a] {}
7+
if case (is Int, is Int) = a {} // expected-error {{cannot convert value of type 'Any?' to specified type '(_, _)'}}
8+
}
9+
10+
let _: () -> Void = {
11+
for case (0)? in [a] {}
12+
if case (0, 0) = a {}
13+
// expected-error@-1 {{cannot convert value of type 'Any?' to specified type '(_, _)}}
14+
}
15+
16+
let _: () -> Void = {
17+
for case (0)? in [a] {}
18+
for case (0, 0) in [a] {}
19+
// expected-error@-1 {{conflicting arguments to generic parameter 'Elements' ('[Any]' vs. '[Any?]')}}
20+
// expected-error@-2 {{conflicting arguments to generic parameter 'Element' ('Any' vs. 'Any?')}}
21+
// expected-error@-3 {{conflicting arguments to generic parameter 'Self' ('[Any]' vs. '[Any?]')}}
22+
}

validation-test/Sema/type_checker_crashers_fixed/rdar92327807.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ func test(result: MyEnum, optResult: MyEnum?) {
1010
}
1111

1212
if let .co(42) = result { // expected-error {{pattern matching in a condition requires the 'case' keyword}}
13-
// expected-error@-1 {{type of expression is ambiguous without more context}}
13+
// expected-error@-1 {{type 'MyEnum' has no member 'co'}}
1414
}
1515

1616
if let .co = optResult { // expected-error {{pattern matching in a condition requires the 'case' keyword}}

0 commit comments

Comments
 (0)