Skip to content

Commit 5140174

Browse files
committed
SIL: Plumb abstraction patterns through type lowering.
Lowering a SIL type should be a pure function of the formal type of a value and the abstraction pattern it's being lowered against, but we historically did not carry enough information in abstraction patterns to lower generic parameter types, so we relied on a generic context signature that would be pushed and popped before lowering interface types. This patch largely eliminates the necessity for that, by making it so that `TypeClassifierBase` and its subclasses now take an `AbstractionPattern` all the way down, and fixing up the visitor logic so that it derives appropriate abstraction patterns for tuple elements, function arguments, and aggregate fields too. This makes it so that type lowering is independent of the current generic context. (Unfortunately, there are still places scattered across the code where we use the current generic context in order to build abstraction patterns that we then feed into type lowering, so we can't yet completely eliminate the concept.) This then enables us to integrate substituted function type construction into type lowering as well, since we can now lower a generic parameter type against an abstraction pattern without that generic parameter having to be tied to the same generic signature (or any generic signature at all, which in the case of a substituted function type hasn't necessarily even been finalized yet.)
1 parent 4b25b67 commit 5140174

File tree

14 files changed

+677
-509
lines changed

14 files changed

+677
-509
lines changed

include/swift/SIL/AbstractionPattern.h

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,13 @@ class AbstractionPattern {
409409
assert(hasGenericSignature());
410410
return CanGenericSignature(GenericSig);
411411
}
412-
412+
413+
CanGenericSignature getGenericSignatureOrNull() const {
414+
if (!hasGenericSignature())
415+
return CanGenericSignature();
416+
return CanGenericSignature(GenericSig);
417+
}
418+
413419
/// Return an open-coded abstraction pattern for a tuple. The
414420
/// caller is responsible for ensuring that the storage for the
415421
/// tuple elements is valid for as long as the abstraction pattern is.
@@ -513,6 +519,15 @@ class AbstractionPattern {
513519
return pattern;
514520
}
515521

522+
/// Return an abstraction pattern for the type of the given struct field or enum case
523+
/// substituted in `this` type.
524+
///
525+
/// Note that, for most purposes, you should lower a field's type against its
526+
/// *unsubstituted* interface type.
527+
AbstractionPattern
528+
unsafeGetSubstFieldType(ValueDecl *member,
529+
CanType origMemberType = CanType()) const;
530+
516531
private:
517532
/// Return an abstraction pattern for the curried type of an
518533
/// Objective-C method.
@@ -648,11 +663,34 @@ class AbstractionPattern {
648663
return getKind() != Kind::Invalid;
649664
}
650665

666+
bool isTypeParameterOrOpaqueArchetype() const {
667+
switch (getKind()) {
668+
case Kind::Opaque:
669+
return true;
670+
case Kind::Type:
671+
case Kind::ClangType:
672+
case Kind::Discard: {
673+
auto type = getType();
674+
if (isa<DependentMemberType>(type) ||
675+
isa<GenericTypeParamType>(type)) {
676+
return true;
677+
}
678+
if (auto archetype = dyn_cast<ArchetypeType>(type)) {
679+
return true;
680+
}
681+
return false;
682+
}
683+
default:
684+
return false;
685+
}
686+
}
687+
651688
bool isTypeParameter() const {
652689
switch (getKind()) {
653690
case Kind::Opaque:
654691
return true;
655692
case Kind::Type:
693+
case Kind::ClangType:
656694
case Kind::Discard: {
657695
auto type = getType();
658696
if (isa<DependentMemberType>(type) ||
@@ -668,12 +706,13 @@ class AbstractionPattern {
668706
return false;
669707
}
670708
}
671-
709+
672710
/// Is this an interface type that is subject to a concrete
673711
/// same-type constraint?
674712
bool isConcreteType() const;
675713

676-
bool requiresClass();
714+
bool requiresClass() const;
715+
LayoutConstraint getLayoutConstraint() const;
677716

678717
/// Return the Swift type which provides structure for this
679718
/// abstraction pattern.

include/swift/SIL/SILType.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,8 @@ class SILType {
242242
///
243243
/// This is equivalent to, but possibly faster than, calling
244244
/// tc.getTypeLowering(type).isAddressOnly().
245-
static bool isAddressOnly(CanType type, Lowering::TypeConverter &tc,
245+
static bool isAddressOnly(CanType type,
246+
Lowering::TypeConverter &tc,
246247
CanGenericSignature sig,
247248
TypeExpansionContext expansion);
248249

include/swift/SIL/TypeLowering.h

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -93,13 +93,6 @@ adjustFunctionType(CanSILFunctionType t, SILFunctionType::Representation rep,
9393
witnessMethodConformance);
9494
}
9595

96-
/// Flag used to place context-dependent TypeLowerings in their own arena which
97-
/// can be disposed when a generic context is exited.
98-
enum IsDependent_t : unsigned {
99-
IsNotDependent = false,
100-
IsDependent = true
101-
};
102-
10396
/// Is a lowered SIL type trivial? That is, are copies ultimately just
10497
/// bit-copies, and it takes no work to destroy a value?
10598
enum IsTrivial_t : bool {
@@ -182,6 +175,10 @@ class TypeLowering {
182175
(isFixedABI ? 0U : NonFixedABIFlag) |
183176
(isAddressOnly ? AddressOnlyFlag : 0U) |
184177
(isResilient ? ResilientFlag : 0U)) {}
178+
179+
constexpr bool operator==(RecursiveProperties p) const {
180+
return Flags == p.Flags;
181+
}
185182

186183
static constexpr RecursiveProperties forTrivial() {
187184
return {IsTrivial, IsFixedABI, IsNotAddressOnly, IsNotResilient};
@@ -502,10 +499,8 @@ class TypeLowering {
502499
}
503500

504501
/// Allocate a new TypeLowering using the TypeConverter's allocator.
505-
void *operator new(size_t size, TypeConverter &tc,
506-
IsDependent_t dependent);
507-
void *operator new[](size_t size, TypeConverter &tc,
508-
IsDependent_t dependent);
502+
void *operator new(size_t size, TypeConverter &tc);
503+
void *operator new[](size_t size, TypeConverter &tc);
509504

510505
// Forbid 'new FooTypeLowering' and try to forbid 'delete tl'.
511506
// The latter is made challenging because the existence of the
@@ -573,7 +568,7 @@ enum class CaptureKind {
573568
class TypeConverter {
574569
friend class TypeLowering;
575570

576-
llvm::BumpPtrAllocator IndependentBPA;
571+
llvm::BumpPtrAllocator TypeLoweringBPA;
577572

578573
struct CachingTypeKey {
579574
CanGenericSignature Sig;
@@ -617,11 +612,6 @@ class TypeConverter {
617612
return OrigType.hasCachingKey();
618613
}
619614

620-
IsDependent_t isDependent() const {
621-
if (SubstType->hasTypeParameter())
622-
return IsDependent;
623-
return IsNotDependent;
624-
}
625615
TypeKey getKeyForMinimalExpansion() const {
626616
return {OrigType, SubstType, TypeExpansionContext::minimal()};
627617
}
@@ -662,13 +652,10 @@ class TypeConverter {
662652
#endif
663653

664654
/// Mapping for types independent on contextual generic parameters.
665-
llvm::DenseMap<CachingTypeKey, const TypeLowering *> IndependentTypes;
655+
llvm::DenseMap<CachingTypeKey, const TypeLowering *> LoweredTypes;
666656

667657
struct DependentTypeState {
668-
llvm::BumpPtrAllocator BPA;
669658
CanGenericSignature Sig;
670-
llvm::DenseMap<TypeConverter::CachingTypeKey,
671-
const TypeLowering *> Map;
672659

673660
explicit DependentTypeState(CanGenericSignature sig) : Sig(sig) {}
674661

@@ -703,7 +690,8 @@ class TypeConverter {
703690
#include "swift/SIL/BridgedTypes.def"
704691

705692
const TypeLowering &
706-
getTypeLoweringForLoweredType(TypeKey key,
693+
getTypeLoweringForLoweredType(AbstractionPattern origType,
694+
CanType loweredType,
707695
TypeExpansionContext forExpansion,
708696
bool origHadOpaqueTypeArchetype);
709697

@@ -772,11 +760,14 @@ class TypeConverter {
772760
return isIndirectPlusZeroSelfParameter(T.getASTType());
773761
}
774762

775-
/// Lowers a Swift type to a SILType, and returns the SIL TypeLowering
763+
/// Lowers a context-independent Swift type to a SILType, and returns the SIL TypeLowering
776764
/// for that type.
765+
///
766+
/// If `t` contains generic parameters, then the overload that also takes an
767+
/// `AbstractionPattern` must be used.
777768
const TypeLowering &
778769
getTypeLowering(Type t, TypeExpansionContext forExpansion) {
779-
AbstractionPattern pattern(getCurGenericContext(), t->getCanonicalType());
770+
AbstractionPattern pattern(t->getCanonicalType());
780771
return getTypeLowering(pattern, t, forExpansion);
781772
}
782773

@@ -789,8 +780,18 @@ class TypeConverter {
789780
/// Returns the SIL TypeLowering for an already lowered SILType. If the
790781
/// SILType is an address, returns the TypeLowering for the pointed-to
791782
/// type.
783+
///
784+
/// If `t` contains type parameters, then the generic signature for its context
785+
/// must be provided.
786+
const TypeLowering &
787+
getTypeLowering(SILType t, TypeExpansionContext forExpansion,
788+
CanGenericSignature signature = nullptr);
789+
790+
/// Returns the SIL TypeLowering for an already lowered SILType. If the
791+
/// SILType is an address, returns the TypeLowering for the pointed-to
792+
/// type in the context of the given SILFunction.
792793
const TypeLowering &
793-
getTypeLowering(SILType t, TypeExpansionContext forExpansion);
794+
getTypeLowering(SILType t, SILFunction &F);
794795

795796
// Returns the lowered SIL type for a Swift type.
796797
SILType getLoweredType(Type t, TypeExpansionContext forExpansion) {

lib/IRGen/GenKeyPath.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -695,11 +695,12 @@ emitKeyPathComponent(IRGenModule &IGM,
695695
&& "must be 32-bit-aligned here");
696696

697697
SILType loweredBaseTy;
698+
loweredBaseTy = IGM.getLoweredType(AbstractionPattern::getOpaque(),
699+
baseTy->getWithoutSpecifierType());
700+
// TODO: Eliminate GenericContextScope entirely
698701
GenericContextScope scope(IGM,
699702
genericEnv ? genericEnv->getGenericSignature()->getCanonicalSignature()
700703
: nullptr);
701-
loweredBaseTy = IGM.getLoweredType(AbstractionPattern::getOpaque(),
702-
baseTy->getWithoutSpecifierType());
703704
switch (auto kind = component.getKind()) {
704705
case KeyPathPatternComponent::Kind::StoredProperty: {
705706
auto property = cast<VarDecl>(component.getStoredPropertyDecl());
@@ -1103,7 +1104,8 @@ emitKeyPathComponent(IRGenModule &IGM,
11031104
case KeyPathPatternComponent::Kind::TupleElement:
11041105
assert(baseTy->is<TupleType>() && "not a tuple");
11051106

1106-
SILType loweredTy = IGM.getLoweredType(baseTy);
1107+
SILType loweredTy = IGM.getLoweredType(AbstractionPattern::getOpaque(),
1108+
baseTy);
11071109

11081110
// Tuple with fixed layout
11091111
//
@@ -1112,7 +1114,8 @@ emitKeyPathComponent(IRGenModule &IGM,
11121114
// the compiler knows that the tuple element is always at offset 0.
11131115
// TODO: If this is behavior is not desired we should find a way to skip to
11141116
// the next section of code e.g. check if baseTy has archetypes?
1115-
if (auto offset = getFixedTupleElementOffset(IGM, loweredTy, component.getTupleIndex())) {
1117+
if (auto offset = getFixedTupleElementOffset(IGM, loweredTy,
1118+
component.getTupleIndex())) {
11161119
auto header = KeyPathComponentHeader
11171120
::forStructComponentWithInlineOffset(/*isLet*/ false,
11181121
offset->getValue());

lib/SIL/AbstractionPattern.cpp

Lines changed: 82 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -203,28 +203,57 @@ bool AbstractionPattern::isConcreteType() const {
203203
GenericSig->isConcreteType(getType()));
204204
}
205205

206-
bool AbstractionPattern::requiresClass() {
206+
bool AbstractionPattern::requiresClass() const {
207207
switch (getKind()) {
208208
case Kind::Opaque:
209209
return false;
210210
case Kind::Type:
211-
case Kind::Discard: {
211+
case Kind::Discard:
212+
case Kind::ClangType: {
212213
auto type = getType();
213214
if (auto archetype = dyn_cast<ArchetypeType>(type))
214215
return archetype->requiresClass();
215-
else if (isa<DependentMemberType>(type) ||
216-
isa<GenericTypeParamType>(type)) {
216+
if (isa<DependentMemberType>(type) ||
217+
isa<GenericTypeParamType>(type)) {
218+
if (getKind() == Kind::ClangType) {
219+
// ObjC generics are always class constrained.
220+
return true;
221+
}
222+
217223
assert(GenericSig &&
218224
"Dependent type in pattern without generic signature?");
219225
return GenericSig->requiresClass(type);
220226
}
221227
return false;
222228
}
229+
223230
default:
224231
return false;
225232
}
226233
}
227234

235+
LayoutConstraint AbstractionPattern::getLayoutConstraint() const {
236+
switch (getKind()) {
237+
case Kind::Opaque:
238+
return LayoutConstraint();
239+
case Kind::Type:
240+
case Kind::Discard: {
241+
auto type = getType();
242+
if (auto archetype = dyn_cast<ArchetypeType>(type))
243+
return archetype->getLayoutConstraint();
244+
else if (isa<DependentMemberType>(type) ||
245+
isa<GenericTypeParamType>(type)) {
246+
assert(GenericSig &&
247+
"Dependent type in pattern without generic signature?");
248+
return GenericSig->getLayoutConstraint(type);
249+
}
250+
return LayoutConstraint();
251+
}
252+
default:
253+
return LayoutConstraint();
254+
}
255+
}
256+
228257
bool AbstractionPattern::matchesTuple(CanTupleType substType) {
229258
switch (getKind()) {
230259
case Kind::Invalid:
@@ -391,7 +420,7 @@ AbstractionPattern AbstractionPattern::getFunctionResultType() const {
391420
case Kind::Opaque:
392421
return *this;
393422
case Kind::Type:
394-
if (isTypeParameter())
423+
if (isTypeParameterOrOpaqueArchetype())
395424
return AbstractionPattern::getOpaque();
396425
return AbstractionPattern(getGenericSignatureForFunctionComponent(),
397426
getResultType(getType()));
@@ -440,7 +469,7 @@ AbstractionPattern::getFunctionParamType(unsigned index) const {
440469
case Kind::Opaque:
441470
return *this;
442471
case Kind::Type: {
443-
if (isTypeParameter())
472+
if (isTypeParameterOrOpaqueArchetype())
444473
return AbstractionPattern::getOpaque();
445474
auto params = cast<AnyFunctionType>(getType()).getParams();
446475
return AbstractionPattern(getGenericSignatureForFunctionComponent(),
@@ -699,6 +728,9 @@ void AbstractionPattern::print(raw_ostream &out) const {
699728
getKind() == Kind::PartialCurriedCXXMethodType
700729
? "AP::PartialCurriedCXXMethodType("
701730
: "AP::PartialCurriedCFunctionAsMethodType(");
731+
if (auto sig = getGenericSignature()) {
732+
sig->print(out);
733+
}
702734
getType().dump(out);
703735
out << ", ";
704736
// It would be better to use print, but we need a PrintingPolicy
@@ -796,3 +828,47 @@ bool AbstractionPattern::hasSameBasicTypeStructure(CanType l, CanType r) {
796828
// Otherwise, the structure is similar enough.
797829
return true;
798830
}
831+
832+
AbstractionPattern
833+
AbstractionPattern::unsafeGetSubstFieldType(ValueDecl *member,
834+
CanType origMemberInterfaceType)
835+
const {
836+
if (isTypeParameterOrOpaqueArchetype()) {
837+
// Fall back to the generic abstraction pattern for the member.
838+
auto sig = member->getDeclContext()->getGenericSignatureOfContext();
839+
CanType memberTy = origMemberInterfaceType
840+
? origMemberInterfaceType
841+
: member->getInterfaceType()->getCanonicalType(sig);
842+
843+
return AbstractionPattern(sig ? sig->getCanonicalSignature()
844+
: CanGenericSignature(),
845+
memberTy);
846+
}
847+
848+
switch (getKind()) {
849+
case Kind::Opaque:
850+
llvm_unreachable("should be handled by isTypeParameter");
851+
case Kind::Invalid:
852+
llvm_unreachable("called on invalid abstraction pattern");
853+
case Kind::Tuple:
854+
llvm_unreachable("should not have a tuple pattern matching a struct/enum "
855+
"type");
856+
case Kind::PartialCurriedObjCMethodType:
857+
case Kind::CurriedObjCMethodType:
858+
case Kind::PartialCurriedCFunctionAsMethodType:
859+
case Kind::CurriedCFunctionAsMethodType:
860+
case Kind::CFunctionAsMethodType:
861+
case Kind::ObjCMethodType:
862+
case Kind::CXXMethodType:
863+
case Kind::CurriedCXXMethodType:
864+
case Kind::PartialCurriedCXXMethodType:
865+
case Kind::ClangType:
866+
case Kind::Type:
867+
case Kind::Discard:
868+
auto memberTy = getType()->getTypeOfMember(member->getModuleContext(),
869+
member, origMemberInterfaceType)
870+
->getCanonicalType(getGenericSignature());
871+
872+
return AbstractionPattern(getGenericSignature(), memberTy);
873+
}
874+
}

lib/SIL/SILFunction.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ SILType SILFunction::getLoweredLoadableType(Type t) const {
258258
}
259259

260260
const TypeLowering &SILFunction::getTypeLowering(SILType type) const {
261-
return getModule().Types.getTypeLowering(type, TypeExpansionContext(*this));
261+
return getModule().Types.getTypeLowering(type, *this);
262262
}
263263

264264
SILType SILFunction::getLoweredType(SILType t) const {

0 commit comments

Comments
 (0)