SIL: Move responsibility for external keypath equals/hash to the caller.

A public subscript might have generic indexes that aren't unconditionally Hashable, or might use indexes that are retroactively made Hashable, so the property descriptor on the implementer's side can't always resiliently provide this information to the final instantiated KeyPath.
This commit is contained in:
Joe Groff
2018-03-12 16:11:39 -07:00
parent 144d78c2da
commit a795b4fc0c
18 changed files with 714 additions and 432 deletions

View File

@@ -2276,17 +2276,15 @@ public:
return Value.DeclRef;
}
};
enum class Kind: unsigned {
StoredProperty,
GettableProperty,
SettableProperty,
Last_Packed = SettableProperty, // Last enum value that can be packed in
// a PointerIntPair
External,
OptionalChain,
OptionalForce,
OptionalWrap,
External,
};
// Description of a captured index value and its Hashable conformance for a
@@ -2299,73 +2297,93 @@ public:
};
private:
static constexpr const unsigned KindPackingBits = 2;
static constexpr const unsigned UnpackedKind = (1u << KindPackingBits) - 1;
static_assert((unsigned)Kind::Last_Packed < UnpackedKind,
"too many kinds to pack");
enum PackedKind: unsigned {
PackedStored,
PackedComputed,
PackedExternal,
Unpacked,
};
static const unsigned KindPackingBits = 2;
static unsigned getPackedKind(Kind k) {
switch (k) {
case Kind::StoredProperty:
return PackedStored;
case Kind::GettableProperty:
case Kind::SettableProperty:
return PackedComputed;
case Kind::External:
return PackedExternal;
case Kind::OptionalChain:
case Kind::OptionalForce:
case Kind::OptionalWrap:
return Unpacked;
}
}
// Value is the VarDecl* for StoredProperty, the SILFunction* of the
// Getter for computed properties, or the Kind for other kinds
llvm::PointerIntPair<void *, KindPackingBits, unsigned> ValueAndKind;
llvm::PointerIntPair<SILFunction *, 2,
ComputedPropertyId::KindType> SetterAndIdKind;
ComputedPropertyId::ValueType IdValue;
ArrayRef<Index> Indices;
union {
// Valid if Kind == GettableProperty || Value == SettableProperty
// Valid if Kind == GettableProperty || Kind == SettableProperty
struct {
SILFunction *Equal;
SILFunction *Hash;
} IndexEquality;
llvm::PointerIntPair<SILFunction *, 2,
ComputedPropertyId::KindType> SetterAndIdKind;
ComputedPropertyId::ValueType IdValue;
} Computed;
// Valid if Kind == External
ArrayRef<Substitution> ExternalSubstitutions;
};
ArrayRef<Index> Indices;
struct {
SILFunction *Equal;
SILFunction *Hash;
} IndexEquality;
CanType ComponentType;
unsigned kindForPacking(Kind k) {
auto value = (unsigned)k;
assert(value <= (unsigned)Kind::Last_Packed);
return value;
}
KeyPathPatternComponent(Kind kind, CanType ComponentType)
: ValueAndKind((void*)((uintptr_t)kind << KindPackingBits), UnpackedKind),
ComponentType(ComponentType)
{
assert(kind > Kind::Last_Packed && "wrong initializer");
}
KeyPathPatternComponent(VarDecl *storedProp, Kind kind,
/// Constructor for stored components
KeyPathPatternComponent(VarDecl *storedProp,
CanType ComponentType)
: ValueAndKind(storedProp, kindForPacking(kind)),
: ValueAndKind(storedProp, PackedStored),
ComponentType(ComponentType) {}
KeyPathPatternComponent(ComputedPropertyId id, Kind kind,
/// Constructor for computed components
KeyPathPatternComponent(ComputedPropertyId id,
SILFunction *getter,
SILFunction *setter,
ArrayRef<Index> indices,
SILFunction *indicesEqual,
SILFunction *indicesHash,
CanType ComponentType)
: ValueAndKind(getter, kindForPacking(kind)),
SetterAndIdKind(setter, id.Kind),
IdValue(id.Value),
: ValueAndKind(getter, PackedComputed),
Computed{{setter, id.Kind}, {id.Value}},
Indices(indices),
IndexEquality{indicesEqual, indicesHash},
ComponentType(ComponentType) {
}
/// Constructor for external components
KeyPathPatternComponent(AbstractStorageDecl *externalStorage,
ArrayRef<Substitution> substitutions,
ArrayRef<Index> indices,
SILFunction *indicesEqual,
SILFunction *indicesHash,
CanType componentType)
: ValueAndKind((void*)((uintptr_t)Kind::External << KindPackingBits),
UnpackedKind),
IdValue(externalStorage),
Indices(indices),
: ValueAndKind(externalStorage, PackedExternal),
ExternalSubstitutions(substitutions),
Indices(indices),
IndexEquality{indicesEqual, indicesHash},
ComponentType(componentType) {
}
/// Constructor for optional components.
KeyPathPatternComponent(Kind kind, CanType componentType)
: ValueAndKind((void*)((uintptr_t)kind << KindPackingBits), Unpacked),
ComponentType(componentType) {
assert((unsigned)kind >= (unsigned)Kind::OptionalChain
&& "not an optional component");
}
public:
KeyPathPatternComponent() : ValueAndKind(nullptr, 0) {}
@@ -2376,9 +2394,17 @@ public:
Kind getKind() const {
auto packedKind = ValueAndKind.getInt();
if (packedKind != UnpackedKind)
return (Kind)packedKind;
return (Kind)((uintptr_t)ValueAndKind.getPointer() >> KindPackingBits);
switch ((PackedKind)packedKind) {
case PackedStored:
return Kind::StoredProperty;
case PackedComputed:
return Computed.SetterAndIdKind.getPointer()
? Kind::SettableProperty : Kind::GettableProperty;
case PackedExternal:
return Kind::External;
case Unpacked:
return (Kind)((uintptr_t)ValueAndKind.getPointer() >> KindPackingBits);
}
}
CanType getComponentType() const {
@@ -2410,7 +2436,8 @@ public:
llvm_unreachable("not a computed property");
case Kind::GettableProperty:
case Kind::SettableProperty:
return ComputedPropertyId(IdValue, SetterAndIdKind.getInt());
return ComputedPropertyId(Computed.IdValue,
Computed.SetterAndIdKind.getInt());
}
llvm_unreachable("unhandled kind");
}
@@ -2440,7 +2467,7 @@ public:
case Kind::External:
llvm_unreachable("not a settable computed property");
case Kind::SettableProperty:
return SetterAndIdKind.getPointer();
return Computed.SetterAndIdKind.getPointer();
}
llvm_unreachable("unhandled kind");
}
@@ -2465,8 +2492,8 @@ public:
case Kind::OptionalChain:
case Kind::OptionalForce:
case Kind::OptionalWrap:
case Kind::External:
llvm_unreachable("not a computed property");
case Kind::External:
case Kind::GettableProperty:
case Kind::SettableProperty:
return IndexEquality.Equal;
@@ -2478,8 +2505,8 @@ public:
case Kind::OptionalChain:
case Kind::OptionalForce:
case Kind::OptionalWrap:
case Kind::External:
llvm_unreachable("not a computed property");
case Kind::External:
case Kind::GettableProperty:
case Kind::SettableProperty:
return IndexEquality.Hash;
@@ -2490,13 +2517,13 @@ public:
static KeyPathPatternComponent forStoredProperty(VarDecl *property,
CanType ty) {
return KeyPathPatternComponent(property, Kind::StoredProperty, ty);
return KeyPathPatternComponent(property, ty);
}
AbstractStorageDecl *getExternalDecl() const {
assert(getKind() == Kind::External
&& "not an external property");
return IdValue.Property;
return (AbstractStorageDecl*)ValueAndKind.getPointer();
}
ArrayRef<Substitution> getExternalSubstitutions() const {
@@ -2512,7 +2539,7 @@ public:
SILFunction *indicesEquals,
SILFunction *indicesHash,
CanType ty) {
return KeyPathPatternComponent(identifier, Kind::GettableProperty,
return KeyPathPatternComponent(identifier,
getter, nullptr, indices,
indicesEquals, indicesHash, ty);
}
@@ -2525,7 +2552,7 @@ public:
SILFunction *indicesEquals,
SILFunction *indicesHash,
CanType ty) {
return KeyPathPatternComponent(identifier, Kind::SettableProperty,
return KeyPathPatternComponent(identifier,
getter, setter, indices,
indicesEquals, indicesHash, ty);
}
@@ -2553,8 +2580,11 @@ public:
forExternal(AbstractStorageDecl *externalDecl,
ArrayRef<Substitution> substitutions,
ArrayRef<Index> indices,
SILFunction *indicesEquals,
SILFunction *indicesHash,
CanType ty) {
return KeyPathPatternComponent(externalDecl, substitutions, indices, ty);
return KeyPathPatternComponent(externalDecl, substitutions,
indices, indicesEquals, indicesHash, ty);
}
void incrementRefCounts() const;

View File

@@ -63,6 +63,9 @@ public:
const KeyPathPatternComponent &getComponent() const { return Component; }
void print(SILPrintContext &Ctx) const;
void dump() const;
void verify(const SILModule &M) const;
};
} // end namespace swift