Skip to content

Commit 29ff0ea

Browse files
authored
Merge pull request #30362 from rjmccall/subst-fn-type-interface-sig
Use the right generic signature when producing a substituted function…
2 parents 08c4e73 + 4ee87d4 commit 29ff0ea

File tree

4 files changed

+78
-11
lines changed

4 files changed

+78
-11
lines changed

include/swift/SIL/TypeLowering.h

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,8 @@ class TypeConverter {
598598

599599
TypeExpansionContext expansionContext;
600600

601+
bool IsCacheable;
602+
601603
CachingTypeKey getCachingKey() const {
602604
assert(isCacheable());
603605
return { (OrigType.hasGenericSignature()
@@ -609,19 +611,37 @@ class TypeConverter {
609611
}
610612

611613
bool isCacheable() const {
612-
return OrigType.hasCachingKey();
614+
return IsCacheable;
613615
}
614616

615617
TypeKey getKeyForMinimalExpansion() const {
616-
return {OrigType, SubstType, TypeExpansionContext::minimal()};
618+
return {OrigType, SubstType, TypeExpansionContext::minimal(),
619+
IsCacheable};
620+
}
621+
622+
void computeCacheable() {
623+
IsCacheable = (OrigType.hasCachingKey() &&
624+
!isTreacherousInterfaceType(SubstType));
625+
}
626+
627+
static bool isTreacherousInterfaceType(CanType type) {
628+
// Don't cache lowerings for interface function types that involve
629+
// type parameters; we might need a contextual generic signature to
630+
// handle them correctly.
631+
if (!type->hasTypeParameter()) return false;
632+
return type.findIf([](CanType type) {
633+
return isa<FunctionType>(type) && type->hasTypeParameter();
634+
});
617635
}
618636
};
619637

620638
friend struct llvm::DenseMapInfo<CachingTypeKey>;
621639

622640
TypeKey getTypeKey(AbstractionPattern origTy, CanType substTy,
623641
TypeExpansionContext context) {
624-
return {origTy, substTy, context};
642+
TypeKey result = {origTy, substTy, context, false};
643+
result.computeCacheable();
644+
return result;
625645
}
626646

627647
struct OverrideKey {
@@ -643,14 +663,16 @@ class TypeConverter {
643663

644664
/// Find a cached TypeLowering by TypeKey, or return null if one doesn't
645665
/// exist.
646-
const TypeLowering *find(TypeKey k);
666+
const TypeLowering *find(const TypeKey &k);
647667
/// Insert a mapping into the cache.
648-
void insert(TypeKey k, const TypeLowering *tl);
668+
void insert(const TypeKey &k, const TypeLowering *tl);
649669
#ifndef NDEBUG
650670
/// Remove the nullptr entry from the type map.
651-
void removeNullEntry(TypeKey k);
671+
void removeNullEntry(const TypeKey &k);
652672
#endif
653673

674+
CanGenericSignature CurGenericSignature;
675+
654676
/// Mapping for types independent on contextual generic parameters.
655677
llvm::DenseMap<CachingTypeKey, const TypeLowering *> LoweredTypes;
656678

@@ -696,6 +718,27 @@ class TypeConverter {
696718
TypeConverter(TypeConverter const &) = delete;
697719
TypeConverter &operator=(TypeConverter const &) = delete;
698720

721+
CanGenericSignature getCurGenericSignature() const {
722+
return CurGenericSignature;
723+
}
724+
725+
class GenericContextRAII {
726+
TypeConverter &TC;
727+
CanGenericSignature SavedSig;
728+
public:
729+
GenericContextRAII(TypeConverter &TC, CanGenericSignature sig)
730+
: TC(TC), SavedSig(TC.CurGenericSignature) {
731+
TC.CurGenericSignature = sig;
732+
}
733+
734+
GenericContextRAII(const GenericContextRAII &) = delete;
735+
GenericContextRAII &operator=(const GenericContextRAII &) = delete;
736+
737+
~GenericContextRAII() {
738+
TC.CurGenericSignature = SavedSig;
739+
}
740+
};
741+
699742
/// Return the CaptureKind to use when capturing a decl.
700743
CaptureKind getDeclCaptureKind(CapturedValue capture,
701744
TypeExpansionContext expansion);

lib/SIL/SILFunctionType.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -912,7 +912,10 @@ class SubstFunctionTypeCollector {
912912
CanGenericSignature origSig = origType.getGenericSignature();
913913
if (substituteBindingsInSubstType) {
914914
origContextType = substType;
915-
origSig = GenericSig;
915+
origSig = TC.getCurGenericSignature();
916+
assert((!substType->hasTypeParameter() || origSig) &&
917+
"lowering mismatched interface types in a context without "
918+
"a generic signature");
916919
}
917920

918921
if (!origContextType->hasTypeParameter()
@@ -925,10 +928,11 @@ class SubstFunctionTypeCollector {
925928
}
926929

927930
// Extract structural substitutions.
928-
if (origContextType->hasTypeParameter())
931+
if (origContextType->hasTypeParameter()) {
929932
origContextType = origSig->getGenericEnvironment()
930933
->mapTypeIntoContext(origContextType)
931934
->getCanonicalType(origSig);
935+
}
932936

933937
auto result = origContextType
934938
->substituteBindingsTo(substType,
@@ -1648,6 +1652,9 @@ static CanSILFunctionType getSILFunctionType(
16481652
CanGenericSignature genericSig =
16491653
substFnInterfaceType.getOptGenericSignature();
16501654

1655+
Optional<TypeConverter::GenericContextRAII> contextRAII;
1656+
if (genericSig) contextRAII.emplace(TC, genericSig);
1657+
16511658
// Per above, only fully honor opaqueness in the abstraction pattern
16521659
// for thick or polymorphic functions. We don't need to worry about
16531660
// non-opaque patterns because the type-checker forbids non-thick

lib/SIL/TypeLowering.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,7 +1385,7 @@ void *TypeLowering::operator new(size_t size, TypeConverter &tc) {
13851385
return tc.TypeLoweringBPA.Allocate(size, alignof(TypeLowering&));
13861386
}
13871387

1388-
const TypeLowering *TypeConverter::find(TypeKey k) {
1388+
const TypeLowering *TypeConverter::find(const TypeKey &k) {
13891389
if (!k.isCacheable()) return nullptr;
13901390

13911391
auto ck = k.getCachingKey();
@@ -1399,7 +1399,7 @@ const TypeLowering *TypeConverter::find(TypeKey k) {
13991399
}
14001400

14011401
#ifndef NDEBUG
1402-
void TypeConverter::removeNullEntry(TypeKey k) {
1402+
void TypeConverter::removeNullEntry(const TypeKey &k) {
14031403
if (!k.isCacheable())
14041404
return;
14051405

@@ -1413,7 +1413,7 @@ void TypeConverter::removeNullEntry(TypeKey k) {
14131413
}
14141414
#endif
14151415

1416-
void TypeConverter::insert(TypeKey k, const TypeLowering *tl) {
1416+
void TypeConverter::insert(const TypeKey &k, const TypeLowering *tl) {
14171417
if (!k.isCacheable()) return;
14181418

14191419
LoweredTypes[k.getCachingKey()] = tl;

test/SILGen/variant_overrides.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %target-swift-emit-silgen %s | %FileCheck %s
2+
3+
// CHECK-LABEL: sil hidden [ossa] @$s17variant_overrides1AC3foo5blockyyACc_tF :
4+
// CHECK-SAME: $@convention(method) (@guaranteed @callee_guaranteed (@guaranteed A) -> (), @guaranteed A) -> ()
5+
class A {
6+
func foo(block: @escaping (A) -> Void) {}
7+
}
8+
9+
// CHECK-LABEL: sil hidden [ossa] @$s17variant_overrides1BC3foo5blockyyACyxGc_tF :
10+
// CHECK-SAME: $@convention(method) <T> (@guaranteed @callee_guaranteed @substituted <τ_0_0> (@guaranteed B<τ_0_0>) -> () for <T>, @guaranteed B<T>) -> ()
11+
class B<T> : A {
12+
override func foo(block: @escaping (B<T>) -> Void) {}
13+
}
14+
15+
// FIXME: allowing this without a thunk silently reinterprets the function to a different abstraction!
16+
// CHECK-LABEL: sil_vtable B {
17+
// CHECK: #A.foo!1: (A) -> (@escaping (A) -> ()) -> () : @$s17variant_overrides1BC3foo5blockyyACyxGc_tF [override]

0 commit comments

Comments
 (0)