Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions include/swift/Sema/ConstraintLocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,10 @@ class ConstraintLocator : public llvm::FoldingSetNode {
/// of the key path at some index.
bool isKeyPathMemberComponent() const;

/// Determine whether this locator points to an apply component of the key
/// path at some index.
bool isKeyPathApplyComponent() const;

/// Determine whether this locator points to the member found
/// via key path dynamic member lookup.
bool isForKeyPathDynamicMemberLookup() const;
Expand Down
5 changes: 3 additions & 2 deletions lib/Sema/CSDiagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6405,7 +6405,8 @@ SourceLoc KeyPathSubscriptIndexHashableFailure::getLoc() const {
auto *locator = getLocator();

if (locator->isKeyPathSubscriptComponent() ||
locator->isKeyPathMemberComponent()) {
locator->isKeyPathMemberComponent() ||
locator->isKeyPathApplyComponent()) {
auto *KPE = castToExpr<KeyPathExpr>(getAnchor());
if (auto kpElt = locator->findFirst<LocatorPathElt::KeyPathComponent>())
return KPE->getComponents()[kpElt->getIndex()].getLoc();
Expand All @@ -6417,7 +6418,7 @@ SourceLoc KeyPathSubscriptIndexHashableFailure::getLoc() const {
bool KeyPathSubscriptIndexHashableFailure::diagnoseAsError() {
auto *locator = getLocator();
emitDiagnostic(diag::expr_keypath_arg_or_index_not_hashable,
!locator->isKeyPathMemberComponent(),
!locator->isKeyPathApplyComponent(),
resolveType(NonConformingType));
return true;
}
Expand Down
7 changes: 4 additions & 3 deletions lib/Sema/CSDiagnostics.h
Original file line number Diff line number Diff line change
Expand Up @@ -1707,9 +1707,10 @@ class KeyPathSubscriptIndexHashableFailure final : public FailureDiagnostic {
KeyPathSubscriptIndexHashableFailure(const Solution &solution, Type type,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator), NonConformingType(type) {
assert((locator->isResultOfKeyPathDynamicMemberLookup() ||
locator->isKeyPathSubscriptComponent()) ||
locator->isKeyPathMemberComponent());
assert(locator->isResultOfKeyPathDynamicMemberLookup() ||
locator->isKeyPathSubscriptComponent() ||
locator->isKeyPathMemberComponent() ||
locator->isKeyPathApplyComponent());
}

SourceLoc getLoc() const override;
Expand Down
8 changes: 2 additions & 6 deletions lib/Sema/CSGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1198,7 +1198,6 @@ namespace {
/// component kind.
Type addApplyConstraints(
Expr *anchor, Type memberTy, ArgumentList *argList,
ConstraintLocator *memberComponentLoc,
ConstraintLocator *applyComponentLoc,
SmallVectorImpl<TypeVariableType *> *addedTypeVars = nullptr) {
// Locators used in this expression.
Expand All @@ -1225,7 +1224,7 @@ namespace {
for (auto index : indices(params)) {
const auto &param = params[index];
CS.verifyThatArgumentIsHashable(index, param.getParameterType(),
memberComponentLoc, loc);
applyComponentLoc, loc);
}

// Add the constraint that the index expression's type be convertible
Expand Down Expand Up @@ -3895,11 +3894,8 @@ namespace {

case KeyPathExpr::Component::Kind::UnresolvedApply:
case KeyPathExpr::Component::Kind::Apply: {
auto prevMemberLocator = CS.getConstraintLocator(
locator, LocatorPathElt::KeyPathComponent(i - 1));
base = addApplyConstraints(E, base, component.getArgs(),
prevMemberLocator, memberLocator,
&componentTypeVars);
memberLocator, &componentTypeVars);
break;
}

Expand Down
7 changes: 4 additions & 3 deletions lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9221,9 +9221,10 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
// If this is an implicit Hashable conformance check generated for each
// index argument of the keypath subscript component, we could just treat
// it as though it conforms.
if ((loc->isResultOfKeyPathDynamicMemberLookup() ||
loc->isKeyPathSubscriptComponent()) ||
loc->isKeyPathMemberComponent()) {
if (loc->isResultOfKeyPathDynamicMemberLookup() ||
loc->isKeyPathSubscriptComponent() ||
loc->isKeyPathMemberComponent() ||
loc->isKeyPathApplyComponent()) {
if (protocol ==
getASTContext().getProtocol(KnownProtocolKind::Hashable)) {
auto *fix =
Expand Down
46 changes: 23 additions & 23 deletions lib/Sema/ConstraintLocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -596,41 +596,41 @@ bool ConstraintLocator::isResultOfKeyPathDynamicMemberLookup() const {
});
}

bool ConstraintLocator::isKeyPathSubscriptComponent() const {
auto *anchor = getAsExpr(getAnchor());
auto *KPE = dyn_cast_or_null<KeyPathExpr>(anchor);
static bool hasKeyPathComponent(
const ConstraintLocator *loc,
llvm::function_ref<bool(KeyPathExpr::Component::Kind)> predicate) {
auto *KPE = getAsExpr<KeyPathExpr>(loc->getAnchor());
if (!KPE)
return false;

using ComponentKind = KeyPathExpr::Component::Kind;
return llvm::any_of(getPath(), [&](const LocatorPathElt &elt) {
return llvm::any_of(loc->getPath(), [&](const LocatorPathElt &elt) {
auto keyPathElt = elt.getAs<LocatorPathElt::KeyPathComponent>();
if (!keyPathElt)
return false;

auto index = keyPathElt->getIndex();
auto &component = KPE->getComponents()[index];
return component.getKind() == ComponentKind::Subscript ||
component.getKind() == ComponentKind::UnresolvedSubscript;
auto &component = KPE->getComponents()[keyPathElt->getIndex()];
return predicate(component.getKind());
});
}

bool ConstraintLocator::isKeyPathMemberComponent() const {
auto *anchor = getAsExpr(getAnchor());
auto *KPE = dyn_cast_or_null<KeyPathExpr>(anchor);
if (!KPE)
return false;
bool ConstraintLocator::isKeyPathSubscriptComponent() const {
return hasKeyPathComponent(this, [](auto kind) {
return kind == KeyPathExpr::Component::Kind::Subscript ||
kind == KeyPathExpr::Component::Kind::UnresolvedSubscript;
});
}

using ComponentKind = KeyPathExpr::Component::Kind;
return llvm::any_of(getPath(), [&](const LocatorPathElt &elt) {
auto keyPathElt = elt.getAs<LocatorPathElt::KeyPathComponent>();
if (!keyPathElt)
return false;
bool ConstraintLocator::isKeyPathMemberComponent() const {
return hasKeyPathComponent(this, [](auto kind) {
return kind == KeyPathExpr::Component::Kind::Member ||
kind == KeyPathExpr::Component::Kind::UnresolvedMember;
});
}

auto index = keyPathElt->getIndex();
auto &component = KPE->getComponents()[index];
return component.getKind() == ComponentKind::Member ||
component.getKind() == ComponentKind::UnresolvedMember;
bool ConstraintLocator::isKeyPathApplyComponent() const {
return hasKeyPathComponent(this, [](auto kind) {
return kind == KeyPathExpr::Component::Kind::Apply ||
kind == KeyPathExpr::Component::Kind::UnresolvedApply;
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// {"kind":"typecheck","signature":"swift::constraints::ConstraintSystem::simplifyConformsToConstraint(swift::Type, swift::ProtocolDecl*, swift::constraints::ConstraintKind, swift::constraints::ConstraintLocatorBuilder, swift::optionset::OptionSet<swift::constraints::ConstraintSystem::TypeMatchFlags, unsigned int>)","signatureAssert":"Assertion failed: (Index < Length && \"Invalid index!\"), function operator[]"}
// RUN: not --crash %target-swift-frontend -typecheck %s
// RUN: not %target-swift-frontend -typecheck %s
\_(error)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// {"kind":"typecheck","signature":"swift::constraints::ConstraintSystem::getCalleeLocator(swift::constraints::ConstraintLocator*, bool, llvm::function_ref<swift::Type (swift::Expr*)>, llvm::function_ref<swift::Type (swift::Type)>, llvm::function_ref<std::__1::optional<swift::constraints::SelectedOverload> (swift::constraints::ConstraintLocator*)>)","signatureAssert":"Assertion failed: (Index < Length && \"Invalid index!\"), function operator[]"}
// RUN: not --crash %target-swift-frontend -typecheck %s
// RUN: not %target-swift-frontend -typecheck %s
struct a func b(c : [Int]) {
\ a(c.map{})