Skip to content

Always use the l-value logic for emitting key path applications #20459

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 9, 2018
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
11 changes: 11 additions & 0 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -3019,6 +3019,14 @@ static inline bool isRawPointerKind(PointerTypeKind PTK) {
llvm_unreachable("Unhandled PointerTypeKind in switch.");
}

enum KeyPathTypeKind : unsigned char {
KPTK_AnyKeyPath,
KPTK_PartialKeyPath,
KPTK_KeyPath,
KPTK_WritableKeyPath,
KPTK_ReferenceWritableKeyPath
};

/// NominalTypeDecl - a declaration of a nominal type, like a struct.
class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
SourceRange Braces;
Expand Down Expand Up @@ -3240,6 +3248,9 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
/// Is this the decl for Optional<T>?
bool isOptionalDecl() const;

/// Is this a key path type?
Optional<KeyPathTypeKind> getKeyPathTypeKind() const;

private:
/// Predicate used to filter StoredPropertyRange.
struct ToStoredProperty {
Expand Down
12 changes: 12 additions & 0 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3028,6 +3028,18 @@ bool NominalTypeDecl::isOptionalDecl() const {
return this == getASTContext().getOptionalDecl();
}

Optional<KeyPathTypeKind> NominalTypeDecl::getKeyPathTypeKind() const {
auto &ctx = getASTContext();
#define CASE(NAME) if (this == ctx.get##NAME##Decl()) return KPTK_##NAME;
CASE(KeyPath)
CASE(WritableKeyPath)
CASE(ReferenceWritableKeyPath)
CASE(AnyKeyPath)
CASE(PartialKeyPath)
#undef CASE
return None;
}

GenericTypeDecl::GenericTypeDecl(DeclKind K, DeclContext *DC,
Identifier name, SourceLoc nameLoc,
MutableArrayRef<TypeLoc> inherited,
Expand Down
3 changes: 2 additions & 1 deletion lib/SILGen/LValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ class PathComponent {
AddressorKind, // var/subscript addressor
CoroutineAccessorKind, // coroutine accessor
ValueKind, // random base pointer as an lvalue
KeyPathApplicationKind, // applying a key path
PhysicalKeyPathApplicationKind, // applying a key path

// Logical LValue kinds
GetterSetterKind, // property or subscript getter/setter
Expand All @@ -115,6 +115,7 @@ class PathComponent {
AutoreleasingWritebackKind, // autorelease pointer on set
WritebackPseudoKind, // a fake component to customize writeback
OpenNonOpaqueExistentialKind, // opened class or metatype existential
LogicalKeyPathApplicationKind, // applying a key path
// Translation LValue kinds (a subtype of logical)
OrigToSubstKind, // generic type substitution
SubstToOrigKind, // generic type substitution
Expand Down
56 changes: 3 additions & 53 deletions lib/SILGen/SILGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3644,60 +3644,10 @@ RValue RValueEmitter::visitKeyPathExpr(KeyPathExpr *E, SGFContext C) {

RValue RValueEmitter::
visitKeyPathApplicationExpr(KeyPathApplicationExpr *E, SGFContext C) {
// An rvalue key path application always occurs as a read-only projection of
// the base. The base is received maximally abstracted.
auto root = SGF.emitMaterializedRValueAsOrig(E->getBase(),
AbstractionPattern::getOpaque());
auto keyPath = SGF.emitRValueAsSingleValue(E->getKeyPath());

auto keyPathDecl = E->getKeyPath()->getType()->getAnyNominal();
FuncDecl *projectFn;

SmallVector<Type, 2> replacementTypes;
if (keyPathDecl == SGF.getASTContext().getAnyKeyPathDecl()) {
// Invoke projectKeyPathAny with the type of the base value.
// The result is always `Any?`.
projectFn = SGF.getASTContext().getProjectKeyPathAny(nullptr);
replacementTypes.push_back(E->getBase()->getType());
} else {
auto keyPathTy = E->getKeyPath()->getType()->castTo<BoundGenericType>();
if (keyPathDecl == SGF.getASTContext().getPartialKeyPathDecl()) {
// Invoke projectKeyPathPartial with the type of the base value.
// The result is always `Any`.
projectFn = SGF.getASTContext().getProjectKeyPathPartial(nullptr);
replacementTypes.push_back(keyPathTy->getGenericArgs()[0]);
} else {
projectFn = SGF.getASTContext().getProjectKeyPathReadOnly(nullptr);
// Get the root and leaf type from the key path type.
replacementTypes.push_back(keyPathTy->getGenericArgs()[0]);
replacementTypes.push_back(keyPathTy->getGenericArgs()[1]);

// Upcast the keypath to KeyPath<T, U> if it isn't already.
if (keyPathTy->getDecl() != SGF.getASTContext().getKeyPathDecl()) {
auto castToTy = BoundGenericType::get(
SGF.getASTContext().getKeyPathDecl(),
nullptr,
keyPathTy->getGenericArgs())
->getCanonicalType();
keyPath = SGF.B.createUpcast(SILLocation(E), keyPath,
SILType::getPrimitiveObjectType(castToTy));
}
}
}

auto projectionGenericSig = projectFn->getGenericSignature();
auto genericArgsMap = SubstitutionMap::get(
projectionGenericSig,
[&](SubstitutableType *type) -> Type {
auto genericParam = cast<GenericTypeParamType>(type);
auto index =
projectionGenericSig->getGenericParamOrdinal(genericParam);
return replacementTypes[index];
},
LookUpConformanceInSignature(*projectionGenericSig));
FormalEvaluationScope scope(SGF);

return SGF.emitApplyOfLibraryIntrinsic(SILLocation(E),
projectFn, genericArgsMap, {root, keyPath}, C);
auto lv = SGF.emitLValue(E, SGFAccessKind::OwnedObjectRead);
return SGF.emitLoadOfLValue(E, std::move(lv), C);
}

RValue RValueEmitter::
Expand Down
Loading