Skip to content

Commit

Permalink
Merge pull request #18804 from jckarter/identity-key-path
Browse files Browse the repository at this point in the history
 Runtime support for identity key paths.
  • Loading branch information
jckarter authored Aug 21, 2018
2 parents 1327d38 + 44b55ae commit d3bd01e
Show file tree
Hide file tree
Showing 11 changed files with 211 additions and 94 deletions.
5 changes: 5 additions & 0 deletions include/swift/AST/Builtins.def
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,11 @@ BUILTIN_SIL_OPERATION(AllocWithTailElems, "allocWithTailElems", Special)
/// Projects the first tail-allocated element of type E from a class C.
BUILTIN_SIL_OPERATION(ProjectTailElems, "projectTailElems", Special)

/// identityKeyPath : <T> () -> WritableKeyPath<T, T>
///
/// Creates an identity key path object. (TODO: replace with proper syntax)
BUILTIN_SIL_OPERATION(IdentityKeyPath, "identityKeyPath", Special)

#undef BUILTIN_SIL_OPERATION

// BUILTIN_RUNTIME_CALL - A call into a runtime function.
Expand Down
2 changes: 0 additions & 2 deletions include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -583,8 +583,6 @@ ERROR(sil_keypath_computed_property_missing_part,none,
ERROR(sil_keypath_external_missing_part,none,
"keypath external component with indices needs an indices_equals and "
"indices_hash function", ())
ERROR(sil_keypath_no_components,none,
"keypath must have at least one component", ())
ERROR(sil_keypath_no_root,none,
"keypath must have a root component declared",())
ERROR(sil_keypath_index_not_hashable,none,
Expand Down
26 changes: 26 additions & 0 deletions lib/AST/Builtins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,20 @@ makeTuple(const Gs & ...elementGenerators) {
};
}

template <class... Gs>
static BuiltinGenericSignatureBuilder::LambdaGenerator
makeBoundGenericType(NominalTypeDecl *decl,
const Gs & ...argumentGenerators) {
return {
[=](BuiltinGenericSignatureBuilder &builder) -> Type {
Type args[] = {
argumentGenerators.build(builder)...
};
return BoundGenericType::get(decl, Type(), args);
}
};
}

template <class T>
static BuiltinGenericSignatureBuilder::MetatypeGenerator<T>
makeMetatype(const T &object, Optional<MetatypeRepresentation> repr = None) {
Expand Down Expand Up @@ -972,6 +986,15 @@ static ValueDecl *getTypeJoinMetaOperation(ASTContext &Context, Identifier Id) {
return builder.build(Id);
}

static ValueDecl *getIdentityKeyPathOperation(ASTContext &Context,
Identifier Id) {
BuiltinGenericSignatureBuilder builder(Context, 1);
auto arg = makeGenericParam();
builder.setResult(makeBoundGenericType(Context.getWritableKeyPathDecl(),
arg, arg));
return builder.build(Id);
}

static ValueDecl *getCanBeObjCClassOperation(ASTContext &Context,
Identifier Id) {
// <T> T.Type -> Builtin.Int8
Expand Down Expand Up @@ -1865,6 +1888,9 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {

case BuiltinValueKind::TypeJoinMeta:
return getTypeJoinMetaOperation(Context, Id);

case BuiltinValueKind::IdentityKeyPath:
return getIdentityKeyPathOperation(Context, Id);
}

llvm_unreachable("bad builtin value!");
Expand Down
9 changes: 6 additions & 3 deletions lib/ParseSIL/ParseSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2884,8 +2884,6 @@ bool SILParser::parseSILInstruction(SILBuilder &B) {
return true;
}

if (components.empty())
P.diagnose(InstLoc.getSourceLoc(), diag::sil_keypath_no_components);
if (rootType.isNull())
P.diagnose(InstLoc.getSourceLoc(), diag::sil_keypath_no_root);

Expand Down Expand Up @@ -2943,8 +2941,13 @@ bool SILParser::parseSILInstruction(SILBuilder &B) {
if (patternEnv && patternEnv->getGenericSignature()) {
canSig = patternEnv->getGenericSignature()->getCanonicalSignature();
}
CanType leafType;
if (!components.empty())
leafType = components.back().getComponentType();
else
leafType = rootType;
auto pattern = KeyPathPattern::get(B.getModule(), canSig,
rootType, components.back().getComponentType(),
rootType, leafType,
components, objcString);

ResultVal = B.createKeyPath(InstLoc, pattern, subMap, operands, Ty);
Expand Down
48 changes: 3 additions & 45 deletions lib/SIL/SILOwnershipVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1288,56 +1288,14 @@ CONSTANT_OWNERSHIP_BUILTIN(Trivial, MustBeLive, Swift3ImplicitObjCEntrypoint)

// Builtins that should be lowered to SIL instructions so we should never see
// them.
#define BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(ID) \
#define BUILTIN_SIL_OPERATION(ID, NAME, CATEGORY) \
OwnershipUseCheckerResult \
OwnershipCompatibilityBuiltinUseChecker::visit##ID(BuiltinInst *BI, \
StringRef Attr) { \
llvm_unreachable("Builtin should have been lowered to SIL instruction?!"); \
}
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(Retain)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(Release)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(Autorelease)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(TryPin)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(Unpin)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(Load)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(LoadRaw)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(LoadInvariant)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(Take)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(Destroy)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(Assign)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(Init)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(CastToNativeObject)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(UnsafeCastToNativeObject)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(CastFromNativeObject)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(CastToBridgeObject)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(
CastReferenceFromBridgeObject)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(
CastBitPatternFromBridgeObject)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(ClassifyBridgeObject)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(ValueToBridgeObject)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(BridgeToRawPointer)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(BridgeFromRawPointer)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(CastReference)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(ReinterpretCast)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(AddressOf)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(AddressOfBorrow)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(GepRaw)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(Gep)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(GetTailAddr)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(PerformInstantaneousReadAccess)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(BeginUnpairedModifyAccess)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(EndUnpairedAccess)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(CondFail)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(FixLifetime)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(IsUnique)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(IsUniqueOrPinned)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(IsUnique_native)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(IsUniqueOrPinned_native)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(BindMemory)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(AllocWithTailElems)
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(ProjectTailElems)
#undef BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS
#define BUILTIN(X, Y, Z)
#include "swift/AST/Builtins.def"

OwnershipUseCheckerResult
OwnershipCompatibilityUseChecker::visitBuiltinInst(BuiltinInst *BI) {
Expand Down
50 changes: 9 additions & 41 deletions lib/SIL/ValueOwnershipKindClassifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -397,8 +397,6 @@ struct ValueOwnershipKindBuiltinVisitor
} \
return ValueOwnershipKind::OWNERSHIP; \
}
CONSTANT_OWNERSHIP_BUILTIN(Owned, Take)
CONSTANT_OWNERSHIP_BUILTIN(Owned, TryPin)
// This returns a value at +1 that is destroyed strictly /after/ the
// UnsafeGuaranteedEnd. This provides the guarantee that we want.
CONSTANT_OWNERSHIP_BUILTIN(Owned, UnsafeGuaranteed)
Expand Down Expand Up @@ -443,9 +441,6 @@ CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_ULE)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_ULT)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, IntToPtr)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, LShr)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, Load)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, LoadRaw)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, LoadInvariant)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, Mul)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, Or)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, PtrToInt)
Expand All @@ -472,32 +467,7 @@ CONSTANT_OWNERSHIP_BUILTIN(Trivial, ZExt)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, ZExtOrBitCast)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_ORD)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_UNO)
CONSTANT_OWNERSHIP_BUILTIN(Unowned, CastToNativeObject)
CONSTANT_OWNERSHIP_BUILTIN(Unowned, UnsafeCastToNativeObject)
CONSTANT_OWNERSHIP_BUILTIN(Unowned, CastFromNativeObject)
CONSTANT_OWNERSHIP_BUILTIN(Unowned, CastToBridgeObject)
CONSTANT_OWNERSHIP_BUILTIN(Unowned, CastReferenceFromBridgeObject)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, CastBitPatternFromBridgeObject)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, ClassifyBridgeObject)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, BridgeToRawPointer)
CONSTANT_OWNERSHIP_BUILTIN(Unowned, BridgeFromRawPointer)
CONSTANT_OWNERSHIP_BUILTIN(Unowned, CastReference)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, AddressOf)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, AddressOfBorrow)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, GepRaw)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, Gep)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, GetTailAddr)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, PerformInstantaneousReadAccess)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, BeginUnpairedModifyAccess)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, EndUnpairedAccess)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, OnFastPath)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, IsUnique)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, IsUniqueOrPinned)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, IsUnique_native)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, IsUniqueOrPinned_native)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, BindMemory)
CONSTANT_OWNERSHIP_BUILTIN(Owned, AllocWithTailElems)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, ProjectTailElems)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, IsOptionalType)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, Sizeof)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, Strideof)
Expand Down Expand Up @@ -543,21 +513,11 @@ CONSTANT_OWNERSHIP_BUILTIN(Trivial, UnexpectedError)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, ErrorInMain)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, DeallocRaw)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, Fence)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, Retain)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, Release)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, CondFail)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, FixLifetime)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, Autorelease)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, Unpin)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, Destroy)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, Assign)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, Init)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, AtomicStore)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, Once)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, OnceWithContext)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, TSanInoutAccess)
CONSTANT_OWNERSHIP_BUILTIN(Trivial, Swift3ImplicitObjCEntrypoint)
CONSTANT_OWNERSHIP_BUILTIN(Unowned, ValueToBridgeObject)

#undef CONSTANT_OWNERSHIP_BUILTIN

Expand All @@ -570,14 +530,22 @@ CONSTANT_OWNERSHIP_BUILTIN(Unowned, ValueToBridgeObject)
} \
return ValueOwnershipKind::Unowned; \
}
UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT(ReinterpretCast)
UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT(CmpXChg)
UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT(AtomicLoad)
UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT(ExtractElement)
UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT(InsertElement)
UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT(ZeroInitializer)
#undef UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT

#define BUILTIN(X,Y,Z)
#define BUILTIN_SIL_OPERATION(ID, NAME, CATEGORY) \
ValueOwnershipKind ValueOwnershipKindBuiltinVisitor::visit##ID( \
BuiltinInst *BI, StringRef Attr) { \
llvm_unreachable("builtin should have been lowered in SILGen"); \
}

#include "swift/AST/Builtins.def"

ValueOwnershipKind
ValueOwnershipKindClassifier::visitBuiltinInst(BuiltinInst *BI) {
// For now, just conservatively say builtins are None. We need to use a
Expand Down
53 changes: 53 additions & 0 deletions lib/SILGen/SILGenBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "swift/AST/ASTContext.h"
#include "swift/AST/Builtins.h"
#include "swift/AST/DiagnosticsSIL.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/Module.h"
#include "swift/AST/ReferenceCounting.h"
#include "swift/SIL/SILArgument.h"
Expand Down Expand Up @@ -1055,6 +1056,58 @@ static ManagedValue emitBuiltinProjectTailElems(SILGenFunction &SGF,
return ManagedValue::forUnmanaged(result);
}

static ManagedValue emitBuiltinIdentityKeyPath(SILGenFunction &SGF,
SILLocation loc,
SubstitutionMap subs,
ArrayRef<ManagedValue> args,
SGFContext C) {
assert(subs.getReplacementTypes().size() == 1 &&
"identityKeyPath should have one substitution");
assert(args.size() == 0 &&
"identityKeyPath should have no args");

auto identityTy = subs.getReplacementTypes()[0]->getCanonicalType();

// The `self` key can be used for identity in Cocoa KVC as well.
StringRef objcString = SGF.getASTContext().LangOpts.EnableObjCInterop
? "self" : "";

// The key path pattern has to capture some generic context if the type is
// dependent on this generic context. We only need the specific type, though,
// not the entire generic environment.
bool isDependent = identityTy->hasArchetype();
CanType identityPatternTy = identityTy;
CanGenericSignature patternSig = nullptr;
SubstitutionMap patternSubs;
if (isDependent) {
auto param = GenericTypeParamType::get(0, 0, SGF.getASTContext());
identityPatternTy = param->getCanonicalType();
patternSig = GenericSignature::get(param, {})->getCanonicalSignature();
patternSubs = SubstitutionMap::get(patternSig,
llvm::makeArrayRef((Type)identityTy),
{});
}

auto identityPattern = KeyPathPattern::get(SGF.SGM.M,
patternSig,
identityPatternTy,
identityPatternTy,
{},
objcString);

auto kpTy = BoundGenericType::get(SGF.getASTContext().getWritableKeyPathDecl(),
Type(),
{identityTy, identityTy})
->getCanonicalType();

auto keyPath = SGF.B.createKeyPath(loc, identityPattern,
patternSubs,
{},
SILType::getPrimitiveObjectType(kpTy));
return SGF.emitManagedRValueWithCleanup(keyPath);
}


/// Specialized emitter for type traits.
template<TypeTraitResult (TypeBase::*Trait)(),
BuiltinValueKind Kind>
Expand Down
Loading

0 comments on commit d3bd01e

Please sign in to comment.