Skip to content

Use the right generic signature when producing a substituted function… #30362

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
Mar 11, 2020
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
55 changes: 49 additions & 6 deletions include/swift/SIL/TypeLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,8 @@ class TypeConverter {

TypeExpansionContext expansionContext;

bool IsCacheable;

CachingTypeKey getCachingKey() const {
assert(isCacheable());
return { (OrigType.hasGenericSignature()
Expand All @@ -609,19 +611,37 @@ class TypeConverter {
}

bool isCacheable() const {
return OrigType.hasCachingKey();
return IsCacheable;
}

TypeKey getKeyForMinimalExpansion() const {
return {OrigType, SubstType, TypeExpansionContext::minimal()};
return {OrigType, SubstType, TypeExpansionContext::minimal(),
IsCacheable};
}

void computeCacheable() {
IsCacheable = (OrigType.hasCachingKey() &&
!isTreacherousInterfaceType(SubstType));
}

static bool isTreacherousInterfaceType(CanType type) {
// Don't cache lowerings for interface function types that involve
// type parameters; we might need a contextual generic signature to
// handle them correctly.
if (!type->hasTypeParameter()) return false;
return type.findIf([](CanType type) {
return isa<FunctionType>(type) && type->hasTypeParameter();
});
}
};

friend struct llvm::DenseMapInfo<CachingTypeKey>;

TypeKey getTypeKey(AbstractionPattern origTy, CanType substTy,
TypeExpansionContext context) {
return {origTy, substTy, context};
TypeKey result = {origTy, substTy, context, false};
result.computeCacheable();
return result;
}

struct OverrideKey {
Expand All @@ -643,14 +663,16 @@ class TypeConverter {

/// Find a cached TypeLowering by TypeKey, or return null if one doesn't
/// exist.
const TypeLowering *find(TypeKey k);
const TypeLowering *find(const TypeKey &k);
/// Insert a mapping into the cache.
void insert(TypeKey k, const TypeLowering *tl);
void insert(const TypeKey &k, const TypeLowering *tl);
#ifndef NDEBUG
/// Remove the nullptr entry from the type map.
void removeNullEntry(TypeKey k);
void removeNullEntry(const TypeKey &k);
#endif

CanGenericSignature CurGenericSignature;

/// Mapping for types independent on contextual generic parameters.
llvm::DenseMap<CachingTypeKey, const TypeLowering *> LoweredTypes;

Expand Down Expand Up @@ -696,6 +718,27 @@ class TypeConverter {
TypeConverter(TypeConverter const &) = delete;
TypeConverter &operator=(TypeConverter const &) = delete;

CanGenericSignature getCurGenericSignature() const {
return CurGenericSignature;
}

class GenericContextRAII {
TypeConverter &TC;
CanGenericSignature SavedSig;
public:
GenericContextRAII(TypeConverter &TC, CanGenericSignature sig)
: TC(TC), SavedSig(TC.CurGenericSignature) {
TC.CurGenericSignature = sig;
}

GenericContextRAII(const GenericContextRAII &) = delete;
GenericContextRAII &operator=(const GenericContextRAII &) = delete;

~GenericContextRAII() {
TC.CurGenericSignature = SavedSig;
}
};

/// Return the CaptureKind to use when capturing a decl.
CaptureKind getDeclCaptureKind(CapturedValue capture,
TypeExpansionContext expansion);
Expand Down
11 changes: 9 additions & 2 deletions lib/SIL/SILFunctionType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -912,7 +912,10 @@ class SubstFunctionTypeCollector {
CanGenericSignature origSig = origType.getGenericSignature();
if (substituteBindingsInSubstType) {
origContextType = substType;
origSig = GenericSig;
origSig = TC.getCurGenericSignature();
assert((!substType->hasTypeParameter() || origSig) &&
"lowering mismatched interface types in a context without "
"a generic signature");
}

if (!origContextType->hasTypeParameter()
Expand All @@ -925,10 +928,11 @@ class SubstFunctionTypeCollector {
}

// Extract structural substitutions.
if (origContextType->hasTypeParameter())
if (origContextType->hasTypeParameter()) {
origContextType = origSig->getGenericEnvironment()
->mapTypeIntoContext(origContextType)
->getCanonicalType(origSig);
}

auto result = origContextType
->substituteBindingsTo(substType,
Expand Down Expand Up @@ -1648,6 +1652,9 @@ static CanSILFunctionType getSILFunctionType(
CanGenericSignature genericSig =
substFnInterfaceType.getOptGenericSignature();

Optional<TypeConverter::GenericContextRAII> contextRAII;
if (genericSig) contextRAII.emplace(TC, genericSig);

// Per above, only fully honor opaqueness in the abstraction pattern
// for thick or polymorphic functions. We don't need to worry about
// non-opaque patterns because the type-checker forbids non-thick
Expand Down
6 changes: 3 additions & 3 deletions lib/SIL/TypeLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1385,7 +1385,7 @@ void *TypeLowering::operator new(size_t size, TypeConverter &tc) {
return tc.TypeLoweringBPA.Allocate(size, alignof(TypeLowering&));
}

const TypeLowering *TypeConverter::find(TypeKey k) {
const TypeLowering *TypeConverter::find(const TypeKey &k) {
if (!k.isCacheable()) return nullptr;

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

#ifndef NDEBUG
void TypeConverter::removeNullEntry(TypeKey k) {
void TypeConverter::removeNullEntry(const TypeKey &k) {
if (!k.isCacheable())
return;

Expand All @@ -1413,7 +1413,7 @@ void TypeConverter::removeNullEntry(TypeKey k) {
}
#endif

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

LoweredTypes[k.getCachingKey()] = tl;
Expand Down
17 changes: 17 additions & 0 deletions test/SILGen/variant_overrides.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// RUN: %target-swift-emit-silgen %s | %FileCheck %s

// CHECK-LABEL: sil hidden [ossa] @$s17variant_overrides1AC3foo5blockyyACc_tF :
// CHECK-SAME: $@convention(method) (@guaranteed @callee_guaranteed (@guaranteed A) -> (), @guaranteed A) -> ()
class A {
func foo(block: @escaping (A) -> Void) {}
}

// CHECK-LABEL: sil hidden [ossa] @$s17variant_overrides1BC3foo5blockyyACyxGc_tF :
// CHECK-SAME: $@convention(method) <T> (@guaranteed @callee_guaranteed @substituted <τ_0_0> (@guaranteed B<τ_0_0>) -> () for <T>, @guaranteed B<T>) -> ()
class B<T> : A {
override func foo(block: @escaping (B<T>) -> Void) {}
}

// FIXME: allowing this without a thunk silently reinterprets the function to a different abstraction!
// CHECK-LABEL: sil_vtable B {
// CHECK: #A.foo!1: (A) -> (@escaping (A) -> ()) -> () : @$s17variant_overrides1BC3foo5blockyyACyxGc_tF [override]