Skip to content

Commit c0285a7

Browse files
committed
Always use the l-value logic for emitting key path applications.
Not NFC because it also fixes an evaluation order bug (and reorders some less-important stuff): the key-path expression needs to be evaluated immediately during formal evaluation and cannot be delayed until start-of-access.
1 parent 2964b58 commit c0285a7

File tree

7 files changed

+242
-184
lines changed

7 files changed

+242
-184
lines changed

include/swift/AST/Decl.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3019,6 +3019,14 @@ static inline bool isRawPointerKind(PointerTypeKind PTK) {
30193019
llvm_unreachable("Unhandled PointerTypeKind in switch.");
30203020
}
30213021

3022+
enum KeyPathTypeKind : unsigned char {
3023+
KPTK_AnyKeyPath,
3024+
KPTK_PartialKeyPath,
3025+
KPTK_KeyPath,
3026+
KPTK_WritableKeyPath,
3027+
KPTK_ReferenceWritableKeyPath
3028+
};
3029+
30223030
/// NominalTypeDecl - a declaration of a nominal type, like a struct.
30233031
class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
30243032
SourceRange Braces;
@@ -3240,6 +3248,9 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
32403248
/// Is this the decl for Optional<T>?
32413249
bool isOptionalDecl() const;
32423250

3251+
/// Is this a key path type?
3252+
Optional<KeyPathTypeKind> getKeyPathTypeKind() const;
3253+
32433254
private:
32443255
/// Predicate used to filter StoredPropertyRange.
32453256
struct ToStoredProperty {

lib/AST/Decl.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3028,6 +3028,18 @@ bool NominalTypeDecl::isOptionalDecl() const {
30283028
return this == getASTContext().getOptionalDecl();
30293029
}
30303030

3031+
Optional<KeyPathTypeKind> NominalTypeDecl::getKeyPathTypeKind() const {
3032+
auto &ctx = getASTContext();
3033+
#define CASE(NAME) if (this == ctx.get##NAME##Decl()) return KPTK_##NAME;
3034+
CASE(KeyPath)
3035+
CASE(WritableKeyPath)
3036+
CASE(ReferenceWritableKeyPath)
3037+
CASE(AnyKeyPath)
3038+
CASE(PartialKeyPath)
3039+
#undef CASE
3040+
return None;
3041+
}
3042+
30313043
GenericTypeDecl::GenericTypeDecl(DeclKind K, DeclContext *DC,
30323044
Identifier name, SourceLoc nameLoc,
30333045
MutableArrayRef<TypeLoc> inherited,

lib/SILGen/LValue.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ class PathComponent {
106106
AddressorKind, // var/subscript addressor
107107
CoroutineAccessorKind, // coroutine accessor
108108
ValueKind, // random base pointer as an lvalue
109-
KeyPathApplicationKind, // applying a key path
109+
PhysicalKeyPathApplicationKind, // applying a key path
110110

111111
// Logical LValue kinds
112112
GetterSetterKind, // property or subscript getter/setter
@@ -115,6 +115,7 @@ class PathComponent {
115115
AutoreleasingWritebackKind, // autorelease pointer on set
116116
WritebackPseudoKind, // a fake component to customize writeback
117117
OpenNonOpaqueExistentialKind, // opened class or metatype existential
118+
LogicalKeyPathApplicationKind, // applying a key path
118119
// Translation LValue kinds (a subtype of logical)
119120
OrigToSubstKind, // generic type substitution
120121
SubstToOrigKind, // generic type substitution

lib/SILGen/SILGenExpr.cpp

Lines changed: 3 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3644,60 +3644,10 @@ RValue RValueEmitter::visitKeyPathExpr(KeyPathExpr *E, SGFContext C) {
36443644

36453645
RValue RValueEmitter::
36463646
visitKeyPathApplicationExpr(KeyPathApplicationExpr *E, SGFContext C) {
3647-
// An rvalue key path application always occurs as a read-only projection of
3648-
// the base. The base is received maximally abstracted.
3649-
auto root = SGF.emitMaterializedRValueAsOrig(E->getBase(),
3650-
AbstractionPattern::getOpaque());
3651-
auto keyPath = SGF.emitRValueAsSingleValue(E->getKeyPath());
3652-
3653-
auto keyPathDecl = E->getKeyPath()->getType()->getAnyNominal();
3654-
FuncDecl *projectFn;
3655-
3656-
SmallVector<Type, 2> replacementTypes;
3657-
if (keyPathDecl == SGF.getASTContext().getAnyKeyPathDecl()) {
3658-
// Invoke projectKeyPathAny with the type of the base value.
3659-
// The result is always `Any?`.
3660-
projectFn = SGF.getASTContext().getProjectKeyPathAny(nullptr);
3661-
replacementTypes.push_back(E->getBase()->getType());
3662-
} else {
3663-
auto keyPathTy = E->getKeyPath()->getType()->castTo<BoundGenericType>();
3664-
if (keyPathDecl == SGF.getASTContext().getPartialKeyPathDecl()) {
3665-
// Invoke projectKeyPathPartial with the type of the base value.
3666-
// The result is always `Any`.
3667-
projectFn = SGF.getASTContext().getProjectKeyPathPartial(nullptr);
3668-
replacementTypes.push_back(keyPathTy->getGenericArgs()[0]);
3669-
} else {
3670-
projectFn = SGF.getASTContext().getProjectKeyPathReadOnly(nullptr);
3671-
// Get the root and leaf type from the key path type.
3672-
replacementTypes.push_back(keyPathTy->getGenericArgs()[0]);
3673-
replacementTypes.push_back(keyPathTy->getGenericArgs()[1]);
3674-
3675-
// Upcast the keypath to KeyPath<T, U> if it isn't already.
3676-
if (keyPathTy->getDecl() != SGF.getASTContext().getKeyPathDecl()) {
3677-
auto castToTy = BoundGenericType::get(
3678-
SGF.getASTContext().getKeyPathDecl(),
3679-
nullptr,
3680-
keyPathTy->getGenericArgs())
3681-
->getCanonicalType();
3682-
keyPath = SGF.B.createUpcast(SILLocation(E), keyPath,
3683-
SILType::getPrimitiveObjectType(castToTy));
3684-
}
3685-
}
3686-
}
3687-
3688-
auto projectionGenericSig = projectFn->getGenericSignature();
3689-
auto genericArgsMap = SubstitutionMap::get(
3690-
projectionGenericSig,
3691-
[&](SubstitutableType *type) -> Type {
3692-
auto genericParam = cast<GenericTypeParamType>(type);
3693-
auto index =
3694-
projectionGenericSig->getGenericParamOrdinal(genericParam);
3695-
return replacementTypes[index];
3696-
},
3697-
LookUpConformanceInSignature(*projectionGenericSig));
3647+
FormalEvaluationScope scope(SGF);
36983648

3699-
return SGF.emitApplyOfLibraryIntrinsic(SILLocation(E),
3700-
projectFn, genericArgsMap, {root, keyPath}, C);
3649+
auto lv = SGF.emitLValue(E, SGFAccessKind::OwnedObjectRead);
3650+
return SGF.emitLoadOfLValue(E, std::move(lv), C);
37013651
}
37023652

37033653
RValue RValueEmitter::

0 commit comments

Comments
 (0)