Skip to content

Commit 7b3dbf2

Browse files
authored
Merge pull request #37459 from xedin/rdar-78035829
[5.4][ConstraintSystem] Re-activate constraints if, due to incorrect refer…
2 parents f500823 + 0537131 commit 7b3dbf2

File tree

7 files changed

+99
-16
lines changed

7 files changed

+99
-16
lines changed

include/swift/Sema/ConstraintLocator.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,9 +199,13 @@ class ConstraintLocator : public llvm::FoldingSetNode {
199199
/// via key path dynamic member lookup.
200200
bool isForKeyPathDynamicMemberLookup() const;
201201

202-
/// Determine whether this locator points to one of the key path
203-
/// components.
204-
bool isForKeyPathComponent() const;
202+
/// Determine whether this locator points to element inside
203+
/// of a key path component.
204+
bool isInKeyPathComponent() const;
205+
206+
/// Determine whether this locator points to a result type of
207+
/// a key path component.
208+
bool isForKeyPathComponentResult() const;
205209

206210
/// Determine whether this locator points to the generic parameter.
207211
bool isForGenericParameter() const;

lib/Sema/CSBindings.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1306,6 +1306,13 @@ bool TypeVarBindingProducer::computeNext() {
13061306
}
13071307
}
13081308

1309+
// There is a tailored fix for optional key path root references,
1310+
// let's not create ambiguity by attempting unwrap when it's
1311+
// not allowed.
1312+
if (binding.Kind != BindingKind::Subtypes &&
1313+
getLocator()->isKeyPathRoot() && type->getOptionalObjectType())
1314+
continue;
1315+
13091316
// Allow solving for T even for a binding kind where that's invalid
13101317
// if fixes are allowed, because that gives us the opportunity to
13111318
// match T? values to the T binding by adding an unwrap fix.

lib/Sema/CSDiagnostics.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3930,7 +3930,7 @@ bool AllowTypeOrInstanceMemberFailure::diagnoseAsError() {
39303930
// If this is a reference to a static member by one of the key path
39313931
// components, let's provide a tailored diagnostic and return because
39323932
// that is unsupported so there is no fix-it.
3933-
if (locator->isForKeyPathComponent()) {
3933+
if (locator->isInKeyPathComponent()) {
39343934
InvalidStaticMemberRefInKeyPath failure(getSolution(), Member, locator);
39353935
return failure.diagnoseAsError();
39363936
}

lib/Sema/CSDiagnostics.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1543,7 +1543,7 @@ class InvalidMemberRefInKeyPath : public FailureDiagnostic {
15431543
ConstraintLocator *locator)
15441544
: FailureDiagnostic(solution, locator), Member(member) {
15451545
assert(member->hasName());
1546-
assert(locator->isForKeyPathComponent() ||
1546+
assert(locator->isInKeyPathComponent() ||
15471547
locator->isForKeyPathDynamicMemberLookup());
15481548
}
15491549

lib/Sema/CSSimplify.cpp

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7371,8 +7371,21 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
73717371

73727372
// Record a hole for memberTy to make it possible to form solutions
73737373
// when contextual result type cannot be deduced e.g. `let _ = x.foo`.
7374-
if (auto *memberTypeVar = memberTy->getAs<TypeVariableType>())
7375-
recordPotentialHole(memberTypeVar);
7374+
if (auto *memberTypeVar = memberTy->getAs<TypeVariableType>()) {
7375+
if (getFixedType(memberTypeVar)) {
7376+
// If member has been bound before the base and the base was
7377+
// incorrect at that (e.g. fallback to default `Any` type),
7378+
// then we need to re-activate all of the constraints
7379+
// associated with this member reference otherwise some of
7380+
// the constraints could be left unchecked in inactive state.
7381+
// This is especially important for key path expressions because
7382+
// `key path` constraint can't be retired until all components
7383+
// are simplified.
7384+
addTypeVariableConstraintsToWorkList(memberTypeVar);
7385+
} else {
7386+
recordPotentialHole(memberTypeVar);
7387+
}
7388+
}
73767389

73777390
return SolutionKind::Solved;
73787391
};
@@ -8395,15 +8408,28 @@ ConstraintSystem::simplifyKeyPathConstraint(
83958408
return SolutionKind::Solved;
83968409

83978410
// If we have e.g a missing member somewhere, a component type variable
8398-
// will have been marked as a potential hole.
8399-
// FIXME: This relies on the fact that we only mark an overload type
8400-
// variable as a potential hole once we've added a corresponding fix. We
8401-
// can't use 'isHole' instead, as that doesn't handle cases where the
8402-
// overload type variable gets bound to another type from the context rather
8403-
// than a hole. We need to come up with a better way of handling the
8404-
// relationship between key paths and overloads.
8411+
// would either be marked as a potential hole or would have a fix.
84058412
if (llvm::any_of(componentTypeVars, [&](TypeVariableType *tv) {
8406-
return tv->getImpl().getLocator()->isForKeyPathComponent() &&
8413+
auto *locator = tv->getImpl().getLocator();
8414+
8415+
// Result type of a component could be bound to a contextual
8416+
// (concrete) type if it's the last component in the chain,
8417+
// so the only way to detect errors is to check for fixes.
8418+
if (locator->isForKeyPathComponentResult()) {
8419+
auto path = locator->getPath();
8420+
auto *componentLoc =
8421+
getConstraintLocator(locator->getAnchor(), path.drop_back());
8422+
8423+
if (hasFixFor(componentLoc, FixKind::DefineMemberBasedOnUse) ||
8424+
hasFixFor(componentLoc, FixKind::UnwrapOptionalBase) ||
8425+
hasFixFor(componentLoc,
8426+
FixKind::UnwrapOptionalBaseWithOptionalResult))
8427+
return true;
8428+
}
8429+
8430+
// If something inside of a component is marked as a hole,
8431+
// let's consider while component to be invalid.
8432+
return locator->isInKeyPathComponent() &&
84078433
tv->getImpl().canBindToHole();
84088434
})) {
84098435
return SolutionKind::Solved;

lib/Sema/ConstraintLocator.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,12 +168,16 @@ bool ConstraintLocator::isForKeyPathDynamicMemberLookup() const {
168168
return !path.empty() && path.back().isKeyPathDynamicMember();
169169
}
170170

171-
bool ConstraintLocator::isForKeyPathComponent() const {
171+
bool ConstraintLocator::isInKeyPathComponent() const {
172172
return llvm::any_of(getPath(), [&](const LocatorPathElt &elt) {
173173
return elt.isKeyPathComponent();
174174
});
175175
}
176176

177+
bool ConstraintLocator::isForKeyPathComponentResult() const {
178+
return isLastElement<LocatorPathElt::KeyPathComponentResult>();
179+
}
180+
177181
bool ConstraintLocator::isForGenericParameter() const {
178182
return isLastElement<LocatorPathElt::GenericParameter>();
179183
}

test/expr/unary/keypath/keypath.swift

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,3 +1052,45 @@ func testSyntaxErrors() {
10521052
_ = \A.a?;
10531053
_ = \A.a!;
10541054
}
1055+
1056+
// SR-13364 - keypath missing optional crashes compiler: "Inactive constraints left over?"
1057+
func sr13364() {
1058+
let _: KeyPath<String?, Int?> = \.utf8.count // expected-error {{no exact matches in reference to property 'count'}}
1059+
// expected-note@-1 {{found candidate with type 'Int'}}
1060+
}
1061+
1062+
// rdar://74711236 - crash due to incorrect member access in key path
1063+
func rdar74711236() {
1064+
struct S {
1065+
var arr: [V] = []
1066+
}
1067+
1068+
struct V : Equatable {
1069+
}
1070+
1071+
enum Type {
1072+
case store
1073+
}
1074+
1075+
struct Context {
1076+
func supported() -> [Type] {
1077+
return []
1078+
}
1079+
}
1080+
1081+
func test(context: Context?) {
1082+
var s = S()
1083+
1084+
s.arr = {
1085+
// FIXME: Missing member reference is pattern needs a better diagnostic
1086+
if let type = context?.store { // expected-error {{type of expression is ambiguous without more context}}
1087+
// `isSupported` should be an invalid declaration to trigger a crash in `map(\.option)`
1088+
let isSupported = context!.supported().contains(type) // expected-error {{missing argument label 'where:' in call}} expected-error {{converting non-escaping value to '(Type) throws -> Bool' may allow it to escape}}
1089+
return (isSupported ? [type] : []).map(\.option)
1090+
// expected-error@-1 {{value of type 'Any' has no member 'option'}}
1091+
// expected-note@-2 {{cast 'Any' to 'AnyObject' or use 'as!' to force downcast to a more specific type to access members}}
1092+
}
1093+
return []
1094+
}()
1095+
}
1096+
}

0 commit comments

Comments
 (0)