Skip to content

Commit a5ca6cc

Browse files
committed
Restructure KeyPathExpr to allow more kinds of components.
Expand the representation in anticipation of more kinds of components. NFC intended yet.
1 parent eb5d006 commit a5ca6cc

File tree

12 files changed

+403
-161
lines changed

12 files changed

+403
-161
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,14 @@ ERROR(expr_keypath_not_property,none,
430430
"'#keyPath' cannot refer to %0 %1", (DescriptiveDeclKind, DeclName))
431431
ERROR(expr_keypath_empty,none,
432432
"empty '#keyPath' does not refer to a property", ())
433+
ERROR(expr_unsupported_objc_key_path_component,none,
434+
"an Objective-C key path cannot contain "
435+
"%select{BAD|subscript|BAD|BAD|optional-forcing|optional-chaining|BAD} "
436+
"components",
437+
(unsigned))
438+
ERROR(expr_unsupported_objc_key_path_compound_name,none,
439+
"an Objective-C key path cannot reference a declaration with a "
440+
"compound name", ())
433441

434442
// Selector expressions.
435443
ERROR(expr_selector_no_objc_runtime,none,

include/swift/AST/Expr.h

Lines changed: 187 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "swift/AST/TypeLoc.h"
2727
#include "swift/AST/Availability.h"
2828
#include "llvm/Support/TrailingObjects.h"
29+
#include <utility>
2930

3031
namespace llvm {
3132
struct fltSemantics;
@@ -409,13 +410,10 @@ class alignas(8) Expr {
409410
friend class KeyPathExpr;
410411
unsigned : NumExprBits;
411412

412-
/// The number of components in the selector path.
413-
unsigned NumComponents : 8;
414-
415-
/// Whether the names have corresponding source locations.
416-
unsigned HaveSourceLocations : 1;
413+
/// Whether this is an ObjC stringified keypath.
414+
unsigned IsObjC : 1;
417415
};
418-
enum { NumKeyPathExprBits = NumExprBits + 9 };
416+
enum { NumKeyPathExprBits = NumExprBits + 2 };
419417
static_assert(NumKeyPathExprBits <= 32, "fits in an unsigned");
420418

421419
protected:
@@ -4546,96 +4544,203 @@ class KeyPathExpr : public Expr {
45464544
SourceLoc KeywordLoc;
45474545
SourceLoc LParenLoc;
45484546
SourceLoc RParenLoc;
4549-
Expr *SemanticExpr = nullptr;
4550-
4551-
/// A single stored component, which will be either an identifier or
4552-
/// a resolved declaration.
4553-
typedef llvm::PointerUnion<Identifier, ValueDecl *> StoredComponent;
4554-
4555-
KeyPathExpr(SourceLoc keywordLoc, SourceLoc lParenLoc,
4556-
ArrayRef<Identifier> names,
4557-
ArrayRef<SourceLoc> nameLocs,
4558-
SourceLoc rParenLoc);
4559-
4560-
/// Retrieve a mutable version of the "components" array, for
4561-
/// initialization purposes.
4562-
MutableArrayRef<StoredComponent> getComponentsMutable() {
4563-
return { reinterpret_cast<StoredComponent *>(this + 1), getNumComponents() };
4564-
}
4565-
4566-
/// Retrieve the "components" storage.
4567-
ArrayRef<StoredComponent> getComponents() const {
4568-
return { reinterpret_cast<StoredComponent const *>(this + 1),
4569-
getNumComponents() };
4570-
}
4547+
Expr *ObjCStringLiteralExpr = nullptr;
45714548

4572-
/// Retrieve a mutable version of the name locations array, for
4573-
/// initialization purposes.
4574-
MutableArrayRef<SourceLoc> getNameLocsMutable() {
4575-
if (!KeyPathExprBits.HaveSourceLocations) return { };
4549+
public:
4550+
/// A single stored component, which will be one of:
4551+
/// - an unresolved DeclName, which has to be type-checked
4552+
/// - a resolved ValueDecl, referring to
4553+
/// - a subscript index expression, which may or may not be resolved
4554+
/// - an optional chaining, forcing, or wrapping component
4555+
class Component {
4556+
public:
4557+
enum class Kind: unsigned {
4558+
UnresolvedProperty,
4559+
UnresolvedSubscript,
4560+
Property,
4561+
Subscript,
4562+
OptionalForce,
4563+
OptionalChain,
4564+
OptionalWrap
4565+
};
4566+
4567+
private:
4568+
union DeclNameOrRef {
4569+
DeclName UnresolvedName;
4570+
ConcreteDeclRef ResolvedDecl;
4571+
4572+
DeclNameOrRef() : UnresolvedName{} {}
4573+
DeclNameOrRef(DeclName un) : UnresolvedName(un) {}
4574+
DeclNameOrRef(ConcreteDeclRef rd) : ResolvedDecl(rd) {}
4575+
} Decl;
4576+
4577+
4578+
llvm::PointerIntPair<Expr *, 3, Kind> SubscriptIndexExprAndKind;
4579+
Type ComponentType;
4580+
4581+
explicit Component(DeclNameOrRef decl,
4582+
Expr *indexExpr,
4583+
Kind kind,
4584+
Type type)
4585+
: Decl(decl), SubscriptIndexExprAndKind(indexExpr, kind),
4586+
ComponentType(type)
4587+
{}
4588+
4589+
public:
4590+
Component() : Component({}, nullptr, (Kind)0, Type()) {}
4591+
4592+
/// Create an unresolved component for a property.
4593+
static Component forUnresolvedProperty(DeclName UnresolvedName) {
4594+
return Component(UnresolvedName, nullptr,
4595+
Kind::UnresolvedProperty,
4596+
Type());
4597+
}
4598+
4599+
/// Create an unresolved component for a subscript.
4600+
static Component forUnresolvedSubscript(Expr *UnresolvedSubscriptIndex) {
4601+
return Component({}, UnresolvedSubscriptIndex,
4602+
Kind::UnresolvedSubscript,
4603+
Type());
4604+
}
4605+
4606+
/// Create an unresolved optional force `!` component.
4607+
static Component forUnresolvedOptionalForce() {
4608+
return Component({}, nullptr,
4609+
Kind::OptionalForce,
4610+
Type());
4611+
}
4612+
4613+
/// Create an unresolved optional chain `?` component.
4614+
static Component forUnresolvedOptionalChain() {
4615+
return Component({}, nullptr,
4616+
Kind::OptionalChain,
4617+
Type());
4618+
}
4619+
4620+
/// Create a component for a property.
4621+
static Component forProperty(ConcreteDeclRef property,
4622+
Type propertyType) {
4623+
return Component(property, nullptr, Kind::Property,
4624+
propertyType);
4625+
}
4626+
4627+
/// Create a component for a subscript.
4628+
static Component forSubscript(ConcreteDeclRef subscript,
4629+
Expr *indexExpr,
4630+
Type elementType) {
4631+
return Component(subscript, indexExpr, Kind::Subscript, elementType);
4632+
}
4633+
4634+
/// Create an optional-forcing `!` component.
4635+
static Component forOptionalForce(Type forcedType) {
4636+
return Component({}, nullptr, Kind::OptionalForce, forcedType);
4637+
}
4638+
4639+
/// Create an optional-chaining `?` component.
4640+
static Component forOptionalChain(Type unwrappedType) {
4641+
return Component({}, nullptr, Kind::OptionalChain, unwrappedType);
4642+
}
4643+
4644+
/// Create an optional-wrapping component. This doesn't have a surface
4645+
/// syntax but may appear when the non-optional result of an optional chain
4646+
/// is implicitly wrapped.
4647+
static Component forOptionalWrap(Type wrappedType) {
4648+
return Component({}, nullptr, Kind::OptionalWrap, wrappedType);
4649+
}
4650+
4651+
Kind getKind() const {
4652+
return SubscriptIndexExprAndKind.getInt();
4653+
}
4654+
4655+
Expr *getIndexExpr() const {
4656+
switch (getKind()) {
4657+
case Kind::Subscript:
4658+
case Kind::UnresolvedSubscript:
4659+
return SubscriptIndexExprAndKind.getPointer();
4660+
4661+
case Kind::OptionalChain:
4662+
case Kind::OptionalWrap:
4663+
case Kind::OptionalForce:
4664+
case Kind::UnresolvedProperty:
4665+
case Kind::Property:
4666+
llvm_unreachable("no index expr for this kind");
4667+
}
4668+
}
4669+
4670+
DeclName getUnresolvedDeclName() const {
4671+
switch (getKind()) {
4672+
case Kind::UnresolvedProperty:
4673+
return Decl.UnresolvedName;
4674+
4675+
case Kind::Subscript:
4676+
case Kind::UnresolvedSubscript:
4677+
case Kind::OptionalChain:
4678+
case Kind::OptionalWrap:
4679+
case Kind::OptionalForce:
4680+
case Kind::Property:
4681+
llvm_unreachable("no unresolved name for this kind");
4682+
}
4683+
}
4684+
4685+
ConcreteDeclRef getDeclRef() const {
4686+
switch (getKind()) {
4687+
case Kind::Property:
4688+
case Kind::Subscript:
4689+
return Decl.ResolvedDecl;
4690+
4691+
case Kind::UnresolvedProperty:
4692+
case Kind::UnresolvedSubscript:
4693+
case Kind::OptionalChain:
4694+
case Kind::OptionalWrap:
4695+
case Kind::OptionalForce:
4696+
llvm_unreachable("no decl ref for this kind");
4697+
}
4698+
}
4699+
4700+
Type getComponentType() const {
4701+
return ComponentType;
4702+
}
4703+
};
45764704

4577-
auto mutableComponents = getComponentsMutable();
4578-
return { reinterpret_cast<SourceLoc *>(mutableComponents.end()),
4579-
mutableComponents.size() };
4580-
}
4705+
using ComponentAndLoc = std::pair<Component, SourceLoc>;
4706+
4707+
private:
4708+
llvm::MutableArrayRef<ComponentAndLoc> Components;
45814709

45824710
public:
45834711
/// Create a new #keyPath expression.
4584-
///
4585-
/// \param nameLocs The locations of the names in the key-path,
4586-
/// which must either have the same number of entries as \p names or
4587-
/// must be empty.
4588-
static KeyPathExpr *create(ASTContext &ctx,
4589-
SourceLoc keywordLoc, SourceLoc lParenLoc,
4590-
ArrayRef<Identifier> names,
4591-
ArrayRef<SourceLoc> nameLocs,
4592-
SourceLoc rParenLoc);
4712+
KeyPathExpr(ASTContext &C,
4713+
SourceLoc keywordLoc, SourceLoc lParenLoc,
4714+
ArrayRef<ComponentAndLoc> components,
4715+
SourceLoc rParenLoc,
4716+
bool isObjC,
4717+
bool isImplicit = false);
45934718

45944719
SourceLoc getLoc() const { return KeywordLoc; }
45954720
SourceRange getSourceRange() const {
45964721
return SourceRange(KeywordLoc, RParenLoc);
45974722
}
45984723

4599-
/// Retrieve the number of components in the key-path.
4600-
unsigned getNumComponents() const {
4601-
return KeyPathExprBits.NumComponents;
4724+
/// Get the components array.
4725+
ArrayRef<ComponentAndLoc> getComponents() const {
4726+
return Components;
46024727
}
4603-
4604-
/// Retrieve's the name for the (i)th component;
4605-
Identifier getComponentName(unsigned i) const;
4606-
4607-
/// Retrieve's the declaration corresponding to the (i)th component,
4608-
/// or null if this component has not yet been resolved.
4609-
ValueDecl *getComponentDecl(unsigned i) const {
4610-
return getComponents()[i].dyn_cast<ValueDecl *>();
4611-
}
4612-
4613-
/// Retrieve the location corresponding to the (i)th name.
4614-
///
4615-
/// If no location information is available, returns an empty
4616-
/// \c DeclNameLoc.
4617-
SourceLoc getComponentNameLoc(unsigned i) const {
4618-
if (!KeyPathExprBits.HaveSourceLocations) return { };
4619-
4620-
auto components = getComponents();
4621-
ArrayRef<SourceLoc> nameLocs(
4622-
reinterpret_cast<SourceLoc const *>(components.end()),
4623-
components.size());
4624-
4625-
return nameLocs[i];
4626-
}
4627-
4628-
/// Retrieve the semantic expression, which will be \c NULL prior to
4629-
/// type checking and a string literal after type checking.
4630-
Expr *getSemanticExpr() const { return SemanticExpr; }
4728+
4729+
/// Resolve the components of an un-type-checked expr. This copies over the
4730+
/// components from the argument array.
4731+
void resolveComponents(ASTContext &C,
4732+
ArrayRef<Component> resolvedComponents);
4733+
4734+
/// Retrieve the string literal expression, which will be \c NULL prior to
4735+
/// type checking and a string literal after type checking for an
4736+
/// @objc key path.
4737+
Expr *getObjCStringLiteralExpr() const { return ObjCStringLiteralExpr; }
46314738

46324739
/// Set the semantic expression.
4633-
void setSemanticExpr(Expr *expr) { SemanticExpr = expr; }
4634-
4635-
/// Resolve the given component to the given declaration.
4636-
void resolveComponent(unsigned idx, ValueDecl *decl) {
4637-
getComponentsMutable()[idx] = decl;
4638-
}
4740+
void setObjCStringLiteralExpr(Expr *expr) { ObjCStringLiteralExpr = expr; }
4741+
4742+
/// True if this is an ObjC key path expression.
4743+
bool isObjC() const { return KeyPathExprBits.IsObjC; }
46394744

46404745
static bool classof(const Expr *E) {
46414746
return E->getKind() == ExprKind::KeyPath;

lib/AST/ASTDumper.cpp

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2406,18 +2406,52 @@ class PrintExpr : public ExprVisitor<PrintExpr> {
24062406

24072407
void visitKeyPathExpr(KeyPathExpr *E) {
24082408
printCommon(E, "keypath_expr");
2409-
for (unsigned i = 0, n = E->getNumComponents(); i != n; ++i) {
2410-
OS << "\n";
2409+
for (auto &componentAndLoc : E->getComponents()) {
2410+
KeyPathExpr::Component component = componentAndLoc.first;
2411+
OS << '\n';
24112412
OS.indent(Indent + 2);
2412-
OS << "component=";
2413-
if (auto decl = E->getComponentDecl(i))
2414-
decl->dumpRef(OS);
2415-
else
2416-
OS << E->getComponentName(i);
2413+
OS << "(component=";
2414+
switch (component.getKind()) {
2415+
case KeyPathExpr::Component::Kind::OptionalChain:
2416+
OS << "optional_chain ";
2417+
break;
2418+
2419+
case KeyPathExpr::Component::Kind::OptionalForce:
2420+
OS << "optional_force ";
2421+
break;
2422+
2423+
case KeyPathExpr::Component::Kind::OptionalWrap:
2424+
OS << "optional_wrap ";
2425+
break;
2426+
2427+
case KeyPathExpr::Component::Kind::Property:
2428+
OS << "property ";
2429+
component.getDeclRef().dump(OS);
2430+
break;
2431+
2432+
case KeyPathExpr::Component::Kind::Subscript:
2433+
OS << "subscript ";
2434+
component.getDeclRef().dump(OS);
2435+
OS << '\n';
2436+
component.getIndexExpr()->print(OS, Indent + 4);
2437+
break;
2438+
2439+
case KeyPathExpr::Component::Kind::UnresolvedProperty:
2440+
OS << "unresolved_property ";
2441+
component.getUnresolvedDeclName().print(OS);
2442+
break;
2443+
2444+
case KeyPathExpr::Component::Kind::UnresolvedSubscript:
2445+
OS << "unresolved_subscript";
2446+
OS << '\n';
2447+
component.getIndexExpr()->print(OS, Indent + 4);
2448+
break;
2449+
}
2450+
OS << ")";
24172451
}
2418-
if (auto semanticE = E->getSemanticExpr()) {
2452+
if (auto stringLiteral = E->getObjCStringLiteralExpr()) {
24192453
OS << '\n';
2420-
printRec(semanticE);
2454+
printRec(stringLiteral);
24212455
}
24222456
OS << ")";
24232457
}

0 commit comments

Comments
 (0)