Skip to content

Commit 69abfc1

Browse files
author
Nathan Hawes
authored
Merge pull request #33320 from nathawes/index-key-paths
[Sema/Index] Resolve #keyPath components so they get handled by indexing, semantic highlighting, etc
2 parents 672f238 + 38e2bd9 commit 69abfc1

19 files changed

+215
-34
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4657,13 +4657,24 @@ ERROR(availability_decl_unavailable, none,
46574657
"%select{ in %3|}2%select{|: %4}4",
46584658
(unsigned, DeclName, bool, StringRef, StringRef))
46594659

4660+
WARNING(availability_decl_unavailable_warn, none,
4661+
"%select{getter for |setter for |}0%1 is unavailable"
4662+
"%select{ in %3|}2%select{|: %4}4",
4663+
(unsigned, DeclName, bool, StringRef, StringRef))
4664+
46604665
#define REPLACEMENT_DECL_KIND_SELECT "select{| instance method| property}"
46614666
ERROR(availability_decl_unavailable_rename, none,
46624667
"%select{getter for |setter for |}0%1 has been "
46634668
"%select{renamed to|replaced by}2%" REPLACEMENT_DECL_KIND_SELECT "3 "
46644669
"'%4'%select{|: %5}5",
46654670
(unsigned, DeclName, bool, unsigned, StringRef, StringRef))
46664671

4672+
WARNING(availability_decl_unavailable_rename_warn, none,
4673+
"%select{getter for |setter for |}0%1 has been "
4674+
"%select{renamed to|replaced by}2%" REPLACEMENT_DECL_KIND_SELECT "3 "
4675+
"'%4'%select{|: %5}5",
4676+
(unsigned, DeclName, bool, unsigned, StringRef, StringRef))
4677+
46674678
NOTE(availability_marked_unavailable, none,
46684679
"%select{getter for |setter for |}0%1 has been explicitly marked "
46694680
"unavailable here", (unsigned, DeclName))

include/swift/AST/Expr.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5259,6 +5259,7 @@ class KeyPathExpr : public Expr {
52595259
OptionalWrap,
52605260
Identity,
52615261
TupleElement,
5262+
DictionaryKey,
52625263
};
52635264

52645265
private:
@@ -5367,6 +5368,16 @@ class KeyPathExpr : public Expr {
53675368
propertyType,
53685369
loc);
53695370
}
5371+
5372+
/// Create a component for a dictionary key (#keyPath only).
5373+
static Component forDictionaryKey(DeclNameRef UnresolvedName,
5374+
Type valueType,
5375+
SourceLoc loc) {
5376+
return Component(nullptr, UnresolvedName, nullptr, {}, {},
5377+
Kind::DictionaryKey,
5378+
valueType,
5379+
loc);
5380+
}
53705381

53715382
/// Create a component for a subscript.
53725383
static Component forSubscript(ASTContext &ctx,
@@ -5457,6 +5468,7 @@ class KeyPathExpr : public Expr {
54575468
case Kind::Property:
54585469
case Kind::Identity:
54595470
case Kind::TupleElement:
5471+
case Kind::DictionaryKey:
54605472
return true;
54615473

54625474
case Kind::UnresolvedSubscript:
@@ -5481,6 +5493,7 @@ class KeyPathExpr : public Expr {
54815493
case Kind::Property:
54825494
case Kind::Identity:
54835495
case Kind::TupleElement:
5496+
case Kind::DictionaryKey:
54845497
return nullptr;
54855498
}
54865499
llvm_unreachable("unhandled kind");
@@ -5500,6 +5513,7 @@ class KeyPathExpr : public Expr {
55005513
case Kind::Property:
55015514
case Kind::Identity:
55025515
case Kind::TupleElement:
5516+
case Kind::DictionaryKey:
55035517
llvm_unreachable("no subscript labels for this kind");
55045518
}
55055519
llvm_unreachable("unhandled kind");
@@ -5522,6 +5536,7 @@ class KeyPathExpr : public Expr {
55225536
case Kind::Property:
55235537
case Kind::Identity:
55245538
case Kind::TupleElement:
5539+
case Kind::DictionaryKey:
55255540
return {};
55265541
}
55275542
llvm_unreachable("unhandled kind");
@@ -5533,6 +5548,7 @@ class KeyPathExpr : public Expr {
55335548
DeclNameRef getUnresolvedDeclName() const {
55345549
switch (getKind()) {
55355550
case Kind::UnresolvedProperty:
5551+
case Kind::DictionaryKey:
55365552
return Decl.UnresolvedName;
55375553

55385554
case Kind::Invalid:
@@ -5563,6 +5579,7 @@ class KeyPathExpr : public Expr {
55635579
case Kind::OptionalForce:
55645580
case Kind::Identity:
55655581
case Kind::TupleElement:
5582+
case Kind::DictionaryKey:
55665583
llvm_unreachable("no decl ref for this kind");
55675584
}
55685585
llvm_unreachable("unhandled kind");
@@ -5582,6 +5599,7 @@ class KeyPathExpr : public Expr {
55825599
case Kind::Identity:
55835600
case Kind::Property:
55845601
case Kind::Subscript:
5602+
case Kind::DictionaryKey:
55855603
llvm_unreachable("no field number for this kind");
55865604
}
55875605
llvm_unreachable("unhandled kind");

lib/AST/ASTDumper.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2829,6 +2829,11 @@ class PrintExpr : public ExprVisitor<PrintExpr> {
28292829
PrintWithColorRAII(OS, DiscriminatorColor)
28302830
<< "#" << component.getTupleIndex();
28312831
break;
2832+
case KeyPathExpr::Component::Kind::DictionaryKey:
2833+
PrintWithColorRAII(OS, ASTNodeColor) << "dict_key";
2834+
PrintWithColorRAII(OS, IdentifierColor)
2835+
<< " key='" << component.getUnresolvedDeclName() << "'";
2836+
break;
28322837
}
28332838
PrintWithColorRAII(OS, TypeColor)
28342839
<< " type='" << GetTypeOfKeyPathComponent(E, i) << "'";

lib/AST/ASTWalker.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,6 +1133,7 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
11331133
case KeyPathExpr::Component::Kind::Invalid:
11341134
case KeyPathExpr::Component::Kind::Identity:
11351135
case KeyPathExpr::Component::Kind::TupleElement:
1136+
case KeyPathExpr::Component::Kind::DictionaryKey:
11361137
// No subexpr to visit.
11371138
break;
11381139
}

lib/AST/Expr.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2383,6 +2383,7 @@ void KeyPathExpr::Component::setSubscriptIndexHashableConformances(
23832383
case Kind::Property:
23842384
case Kind::Identity:
23852385
case Kind::TupleElement:
2386+
case Kind::DictionaryKey:
23862387
llvm_unreachable("no hashable conformances for this kind");
23872388
}
23882389
}

lib/IDE/SourceEntityWalker.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,7 @@ std::pair<bool, Expr *> SemaAnnotator::walkToExprPre(Expr *E) {
412412
case KeyPathExpr::Component::Kind::OptionalWrap:
413413
case KeyPathExpr::Component::Kind::OptionalForce:
414414
case KeyPathExpr::Component::Kind::Identity:
415+
case KeyPathExpr::Component::Kind::DictionaryKey:
415416
break;
416417
}
417418
}

lib/SILGen/SILGenExpr.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3734,6 +3734,11 @@ RValue RValueEmitter::visitKeyPathExpr(KeyPathExpr *E, SGFContext C) {
37343734
case KeyPathExpr::Component::Kind::UnresolvedProperty:
37353735
case KeyPathExpr::Component::Kind::UnresolvedSubscript:
37363736
llvm_unreachable("not resolved");
3737+
break;
3738+
3739+
case KeyPathExpr::Component::Kind::DictionaryKey:
3740+
llvm_unreachable("DictionaryKey only valid in #keyPath");
3741+
break;
37373742
}
37383743
}
37393744

lib/Sema/CSApply.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,9 @@ static bool buildObjCKeyPathString(KeyPathExpr *E,
237237
// Don't bother building the key path string if the key path didn't even
238238
// resolve.
239239
return false;
240+
case KeyPathExpr::Component::Kind::DictionaryKey:
241+
llvm_unreachable("DictionaryKey only valid in #keyPath expressions.");
242+
return false;
240243
}
241244
}
242245

@@ -4690,6 +4693,10 @@ namespace {
46904693
case KeyPathExpr::Component::Kind::OptionalWrap:
46914694
case KeyPathExpr::Component::Kind::TupleElement:
46924695
llvm_unreachable("already resolved");
4696+
break;
4697+
case KeyPathExpr::Component::Kind::DictionaryKey:
4698+
llvm_unreachable("DictionaryKey only valid in #keyPath");
4699+
break;
46934700
}
46944701

46954702
// Update "componentTy" with the result type of the last component.
@@ -7745,9 +7752,8 @@ namespace {
77457752
componentType = solution.simplifyType(cs.getType(kp, i));
77467753
assert(!componentType->hasTypeVariable() &&
77477754
"Should not write type variable into key-path component");
7755+
kp->getMutableComponents()[i].setComponentType(componentType);
77487756
}
7749-
7750-
kp->getMutableComponents()[i].setComponentType(componentType);
77517757
}
77527758
}
77537759

lib/Sema/CSGen.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3487,6 +3487,9 @@ namespace {
34873487
}
34883488
case KeyPathExpr::Component::Kind::Identity:
34893489
continue;
3490+
case KeyPathExpr::Component::Kind::DictionaryKey:
3491+
llvm_unreachable("DictionaryKey only valid in #keyPath");
3492+
break;
34903493
}
34913494

34923495
// By now, `base` is the result type of this component. Set it in the

lib/Sema/CSSimplify.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8242,6 +8242,9 @@ ConstraintSystem::simplifyKeyPathConstraint(
82428242
case KeyPathExpr::Component::Kind::TupleElement:
82438243
llvm_unreachable("not implemented");
82448244
break;
8245+
case KeyPathExpr::Component::Kind::DictionaryKey:
8246+
llvm_unreachable("DictionaryKey only valid in #keyPath");
8247+
break;
82458248
}
82468249
}
82478250

lib/Sema/ConstraintSystem.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,7 @@ ConstraintLocator *ConstraintSystem::getCalleeLocator(
493493
case ComponentKind::OptionalChain:
494494
case ComponentKind::OptionalWrap:
495495
case ComponentKind::Identity:
496+
case ComponentKind::DictionaryKey:
496497
// These components don't have any callee associated, so just continue.
497498
break;
498499
}

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2067,6 +2067,7 @@ void swift::diagnoseUnavailableOverride(ValueDecl *override,
20672067

20682068
diagnoseExplicitUnavailability(base, override->getLoc(),
20692069
override->getDeclContext(),
2070+
/*Flags*/None,
20702071
[&](InFlightDiagnostic &diag) {
20712072
ParsedDeclName parsedName = parseDeclName(attr->Rename);
20722073
if (!parsedName || parsedName.isPropertyAccessor() ||
@@ -2097,10 +2098,11 @@ void swift::diagnoseUnavailableOverride(ValueDecl *override,
20972098
/// Emit a diagnostic for references to declarations that have been
20982099
/// marked as unavailable, either through "unavailable" or "obsoleted:".
20992100
bool swift::diagnoseExplicitUnavailability(const ValueDecl *D,
2100-
SourceRange R,
2101-
const DeclContext *DC,
2102-
const ApplyExpr *call) {
2103-
return diagnoseExplicitUnavailability(D, R, DC,
2101+
SourceRange R,
2102+
const DeclContext *DC,
2103+
const ApplyExpr *call,
2104+
DeclAvailabilityFlags Flags) {
2105+
return diagnoseExplicitUnavailability(D, R, DC, Flags,
21042106
[=](InFlightDiagnostic &diag) {
21052107
fixItAvailableAttrRename(diag, R, D, AvailableAttr::isUnavailable(D),
21062108
call);
@@ -2172,6 +2174,7 @@ bool swift::diagnoseExplicitUnavailability(
21722174
const ValueDecl *D,
21732175
SourceRange R,
21742176
const DeclContext *DC,
2177+
DeclAvailabilityFlags Flags,
21752178
llvm::function_ref<void(InFlightDiagnostic &)> attachRenameFixIts) {
21762179
auto *Attr = AvailableAttr::isUnavailable(D);
21772180
if (!Attr)
@@ -2229,6 +2232,14 @@ bool swift::diagnoseExplicitUnavailability(
22292232
break;
22302233
}
22312234

2235+
// TODO: Consider removing this.
2236+
// ObjC keypaths components weren't checked previously, so errors are demoted
2237+
// to warnings to avoid source breakage. In some cases unavailable or
2238+
// obsolete decls still map to valid ObjC runtime names, so behave correctly
2239+
// at runtime, even though their use would produce an error outside of a
2240+
// #keyPath expression.
2241+
bool warnInObjCKeyPath = Flags.contains(DeclAvailabilityFlag::ForObjCKeyPath);
2242+
22322243
if (!Attr->Rename.empty()) {
22332244
SmallString<32> newNameBuf;
22342245
Optional<ReplacementDeclKind> replaceKind =
@@ -2238,7 +2249,9 @@ bool swift::diagnoseExplicitUnavailability(
22382249
StringRef newName = replaceKind ? newNameBuf.str() : Attr->Rename;
22392250
EncodedDiagnosticMessage EncodedMessage(Attr->Message);
22402251
auto diag =
2241-
diags.diagnose(Loc, diag::availability_decl_unavailable_rename,
2252+
diags.diagnose(Loc, warnInObjCKeyPath
2253+
? diag::availability_decl_unavailable_rename_warn
2254+
: diag::availability_decl_unavailable_rename,
22422255
RawAccessorKind, Name, replaceKind.hasValue(),
22432256
rawReplaceKind, newName, EncodedMessage.Message);
22442257
attachRenameFixIts(diag);
@@ -2253,7 +2266,9 @@ bool swift::diagnoseExplicitUnavailability(
22532266
} else {
22542267
EncodedDiagnosticMessage EncodedMessage(Attr->Message);
22552268
diags
2256-
.diagnose(Loc, diag::availability_decl_unavailable, RawAccessorKind,
2269+
.diagnose(Loc, warnInObjCKeyPath
2270+
? diag::availability_decl_unavailable_warn
2271+
: diag::availability_decl_unavailable, RawAccessorKind,
22572272
Name, platform.empty(), platform, EncodedMessage.Message)
22582273
.highlight(R);
22592274
}
@@ -2501,14 +2516,18 @@ class AvailabilityWalker : public ASTWalker {
25012516
/// Walk a keypath expression, checking all of its components for
25022517
/// availability.
25032518
void maybeDiagKeyPath(KeyPathExpr *KP) {
2519+
auto flags = DeclAvailabilityFlags();
2520+
if (KP->isObjC())
2521+
flags = DeclAvailabilityFlag::ForObjCKeyPath;
2522+
25042523
for (auto &component : KP->getComponents()) {
25052524
switch (component.getKind()) {
25062525
case KeyPathExpr::Component::Kind::Property:
25072526
case KeyPathExpr::Component::Kind::Subscript: {
25082527
auto *decl = component.getDeclRef().getDecl();
25092528
auto loc = component.getLoc();
25102529
SourceRange range(loc, loc);
2511-
diagAvailability(decl, range, nullptr);
2530+
diagAvailability(decl, range, nullptr, flags);
25122531
break;
25132532
}
25142533

@@ -2522,6 +2541,7 @@ class AvailabilityWalker : public ASTWalker {
25222541
case KeyPathExpr::Component::Kind::OptionalWrap:
25232542
case KeyPathExpr::Component::Kind::OptionalForce:
25242543
case KeyPathExpr::Component::Kind::Identity:
2544+
case KeyPathExpr::Component::Kind::DictionaryKey:
25252545
break;
25262546
}
25272547
}
@@ -2627,7 +2647,7 @@ AvailabilityWalker::diagAvailability(ConcreteDeclRef declRef, SourceRange R,
26272647
if (TypeChecker::diagnoseInlinableDeclRef(R.Start, declRef, DC, FragileKind))
26282648
return true;
26292649

2630-
if (diagnoseExplicitUnavailability(D, R, DC, call))
2650+
if (diagnoseExplicitUnavailability(D, R, DC, call, Flags))
26312651
return true;
26322652

26332653
// Make sure not to diagnose an accessor's deprecation if we already

lib/Sema/TypeCheckAvailability.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ enum class DeclAvailabilityFlag : uint8_t {
5050
/// Do not diagnose uses of declarations in versions before they were
5151
/// introduced. Used to work around availability-checker bugs.
5252
AllowPotentiallyUnavailable = 1 << 3,
53+
54+
/// If an error diagnostic would normally be emitted, demote the error to a
55+
/// warning. Used for ObjC key path components.
56+
ForObjCKeyPath = 1 << 4
5357
};
5458
using DeclAvailabilityFlags = OptionSet<DeclAvailabilityFlag>;
5559

@@ -70,14 +74,16 @@ void diagnoseUnavailableOverride(ValueDecl *override,
7074
bool diagnoseExplicitUnavailability(const ValueDecl *D,
7175
SourceRange R,
7276
const DeclContext *DC,
73-
const ApplyExpr *call);
77+
const ApplyExpr *call,
78+
DeclAvailabilityFlags Flags = None);
7479

7580
/// Emit a diagnostic for references to declarations that have been
7681
/// marked as unavailable, either through "unavailable" or "obsoleted:".
7782
bool diagnoseExplicitUnavailability(
7883
const ValueDecl *D,
7984
SourceRange R,
8085
const DeclContext *DC,
86+
DeclAvailabilityFlags Flags,
8187
llvm::function_ref<void(InFlightDiagnostic &)> attachRenameFixIts);
8288

8389
/// Check if \p decl has a introduction version required by -require-explicit-availability

lib/Sema/TypeCheckCodeCompletion.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -621,9 +621,21 @@ static Optional<Type> getTypeOfCompletionContextExpr(
621621

622622
case CompletionTypeCheckKind::KeyPath:
623623
referencedDecl = nullptr;
624-
if (auto keyPath = dyn_cast<KeyPathExpr>(parsedExpr))
625-
return TypeChecker::checkObjCKeyPathExpr(DC, keyPath,
626-
/*requireResultType=*/true);
624+
if (auto keyPath = dyn_cast<KeyPathExpr>(parsedExpr)) {
625+
auto components = keyPath->getComponents();
626+
if (!components.empty()) {
627+
auto &last = components.back();
628+
if (last.isResolved()) {
629+
if (last.getKind() == KeyPathExpr::Component::Kind::Property)
630+
referencedDecl = last.getDeclRef();
631+
Type lookupTy = last.getComponentType();
632+
ASTContext &Ctx = DC->getASTContext();
633+
if (auto bridgedClass = Ctx.getBridgedToObjC(DC, lookupTy))
634+
return bridgedClass;
635+
return lookupTy;
636+
}
637+
}
638+
}
627639

628640
return None;
629641
}

0 commit comments

Comments
 (0)