Skip to content

SILGen: Fix issues with types nested inside fully-concrete extensions #9860

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
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
3 changes: 3 additions & 0 deletions include/swift/SIL/TypeLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,9 @@ class TypeConverter {
CanGenericSignature getEffectiveGenericSignature(AnyFunctionRef fn,
CaptureInfo captureInfo);

/// Retrieve the set of generic parameters closed over by the context.
CanGenericSignature getEffectiveGenericSignature(DeclContext *dc);

/// Push a generic function context. See GenericContextScope for an RAII
/// interface to this function.
///
Expand Down
113 changes: 58 additions & 55 deletions lib/SIL/TypeLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1728,8 +1728,7 @@ static CanAnyFunctionType getGlobalGetterType(CanType varType) {
static CanAnyFunctionType getDefaultArgGeneratorInterfaceType(
TypeConverter &TC,
AbstractFunctionDecl *AFD,
unsigned DefaultArgIndex,
ASTContext &context) {
unsigned DefaultArgIndex) {
auto resultTy = AFD->getDefaultArg(DefaultArgIndex).second;
assert(resultTy && "Didn't find default argument?");

Expand All @@ -1742,52 +1741,50 @@ static CanAnyFunctionType getDefaultArgGeneratorInterfaceType(
// Get the generic signature from the surrounding context.
auto funcInfo = TC.getConstantInfo(SILDeclRef(AFD));
CanGenericSignature sig;
if (auto genTy = funcInfo.FormalInterfaceType->getAs<GenericFunctionType>())
sig = genTy->getGenericSignature()->getCanonicalSignature();
if (auto genTy = dyn_cast<GenericFunctionType>(funcInfo.FormalInterfaceType))
sig = genTy.getGenericSignature();

if (sig) {
return cast<GenericFunctionType>(
GenericFunctionType::get(sig,
TupleType::getEmpty(context),
canResultTy,
AnyFunctionType::ExtInfo())
->getCanonicalType());
return CanGenericFunctionType::get(sig,
TupleType::getEmpty(TC.Context),
canResultTy,
AnyFunctionType::ExtInfo());
}

return CanFunctionType::get(TupleType::getEmpty(context), canResultTy);
return CanFunctionType::get(TupleType::getEmpty(TC.Context), canResultTy);
}

/// Get the type of a stored property initializer, () -> T.
static CanAnyFunctionType getStoredPropertyInitializerInterfaceType(
TypeConverter &TC,
VarDecl *VD,
ASTContext &context) {
VarDecl *VD) {
auto *DC = VD->getDeclContext();
CanType resultTy =
DC->mapTypeOutOfContext(VD->getParentPattern()->getType())
->getCanonicalType();
GenericSignature *sig = DC->getGenericSignatureOfContext();
auto sig = TC.getEffectiveGenericSignature(DC);

if (sig)
return CanGenericFunctionType::get(sig->getCanonicalSignature(),
TupleType::getEmpty(context),
return CanGenericFunctionType::get(sig,
TupleType::getEmpty(TC.Context),
resultTy,
GenericFunctionType::ExtInfo());

return CanFunctionType::get(TupleType::getEmpty(context), resultTy);
return CanFunctionType::get(TupleType::getEmpty(TC.Context), resultTy);
}

/// Get the type of a destructor function.
static CanAnyFunctionType getDestructorInterfaceType(DestructorDecl *dd,
static CanAnyFunctionType getDestructorInterfaceType(TypeConverter &TC,
DestructorDecl *dd,
bool isDeallocating,
ASTContext &C,
bool isForeign) {
auto classType = dd->getDeclContext()->getDeclaredInterfaceType()
->getCanonicalType();
->getCanonicalType(dd->getGenericSignatureOfContext(),
*TC.M.getSwiftModule());

assert((!isForeign || isDeallocating)
&& "There are no foreign destroying destructors");
AnyFunctionType::ExtInfo extInfo =
auto extInfo =
AnyFunctionType::ExtInfo(FunctionType::Representation::Thin,
/*throws*/ false);
if (isForeign)
Expand All @@ -1797,37 +1794,39 @@ static CanAnyFunctionType getDestructorInterfaceType(DestructorDecl *dd,
extInfo = extInfo
.withSILRepresentation(SILFunctionTypeRepresentation::Method);

CanType resultTy = isDeallocating? TupleType::getEmpty(C)->getCanonicalType()
: C.TheNativeObjectType;
auto &C = TC.Context;
CanType resultTy = (isDeallocating
? TupleType::getEmpty(C)
: C.TheNativeObjectType);

auto sig = dd->getDeclContext()->getGenericSignatureOfContext();
auto sig = TC.getEffectiveGenericSignature(dd);
if (sig)
return cast<GenericFunctionType>(
GenericFunctionType::get(sig, classType, resultTy, extInfo)
->getCanonicalType());
return CanGenericFunctionType::get(sig, classType, resultTy, extInfo);
return CanFunctionType::get(classType, resultTy, extInfo);
}

/// Retrieve the type of the ivar initializer or destroyer method for
/// a class.
static CanAnyFunctionType getIVarInitDestroyerInterfaceType(ClassDecl *cd,
static CanAnyFunctionType getIVarInitDestroyerInterfaceType(TypeConverter &TC,
ClassDecl *cd,
bool isObjC,
ASTContext &ctx,
bool isDestroyer) {
auto classType = cd->getDeclaredInterfaceType()->getCanonicalType();
auto classType = cd->getDeclaredInterfaceType()
->getCanonicalType(cd->getGenericSignatureOfContext(),
*TC.M.getSwiftModule());

auto emptyTupleTy = TupleType::getEmpty(ctx)->getCanonicalType();
CanType resultType = isDestroyer? emptyTupleTy : classType;
CanType emptyTupleTy = TupleType::getEmpty(TC.Context);
auto resultType = (isDestroyer ? emptyTupleTy : classType);
auto extInfo = AnyFunctionType::ExtInfo(FunctionType::Representation::Thin,
/*throws*/ false);
extInfo = extInfo
.withSILRepresentation(isObjC? SILFunctionTypeRepresentation::ObjCMethod
: SILFunctionTypeRepresentation::Method);

resultType = CanFunctionType::get(emptyTupleTy, resultType, extInfo);
auto sig = cd->getGenericSignatureOfContext();
auto sig = TC.getEffectiveGenericSignature(cd);
if (sig)
return CanGenericFunctionType::get(sig->getCanonicalSignature(),
return CanGenericFunctionType::get(sig,
classType, resultType,
extInfo);
return CanFunctionType::get(classType, resultType, extInfo);
Expand All @@ -1844,6 +1843,17 @@ TypeConverter::getEffectiveGenericEnvironment(AnyFunctionRef fn,
return nullptr;
}

CanGenericSignature
TypeConverter::getEffectiveGenericSignature(DeclContext *dc) {
if (auto sig = dc->getGenericSignatureOfContext()) {
if (sig->areAllParamsConcrete())
return nullptr;
return sig->getCanonicalSignature();
}

return nullptr;
}

CanGenericSignature
TypeConverter::getEffectiveGenericSignature(AnyFunctionRef fn,
CaptureInfo captureInfo) {
Expand All @@ -1853,13 +1863,7 @@ TypeConverter::getEffectiveGenericSignature(AnyFunctionRef fn,
!captureInfo.hasGenericParamCaptures())
return nullptr;

if (auto sig = dc->getGenericSignatureOfContext()) {
if (sig->areAllParamsConcrete())
return nullptr;
return sig->getCanonicalSignature();
}

return nullptr;
return getEffectiveGenericSignature(dc);
}

CanAnyFunctionType
Expand Down Expand Up @@ -1926,10 +1930,10 @@ CanAnyFunctionType TypeConverter::makeConstantInterfaceType(SILDeclRef c) {

case SILDeclRef::Kind::Destroyer:
case SILDeclRef::Kind::Deallocator:
return getDestructorInterfaceType(cast<DestructorDecl>(vd),
c.kind == SILDeclRef::Kind::Deallocator,
Context,
c.isForeign);
return getDestructorInterfaceType(*this,
cast<DestructorDecl>(vd),
c.kind == SILDeclRef::Kind::Deallocator,
c.isForeign);

case SILDeclRef::Kind::GlobalAccessor: {
VarDecl *var = cast<VarDecl>(vd);
Expand All @@ -1946,17 +1950,18 @@ CanAnyFunctionType TypeConverter::makeConstantInterfaceType(SILDeclRef c) {
case SILDeclRef::Kind::DefaultArgGenerator:
return getDefaultArgGeneratorInterfaceType(*this,
cast<AbstractFunctionDecl>(vd),
c.defaultArgIndex, Context);
c.defaultArgIndex);
case SILDeclRef::Kind::StoredPropertyInitializer:
return getStoredPropertyInitializerInterfaceType(*this,
cast<VarDecl>(vd),
Context);
cast<VarDecl>(vd));
case SILDeclRef::Kind::IVarInitializer:
return getIVarInitDestroyerInterfaceType(cast<ClassDecl>(vd),
c.isForeign, Context, false);
return getIVarInitDestroyerInterfaceType(*this,
cast<ClassDecl>(vd),
c.isForeign, false);
case SILDeclRef::Kind::IVarDestroyer:
return getIVarInitDestroyerInterfaceType(cast<ClassDecl>(vd),
c.isForeign, Context, true);
return getIVarInitDestroyerInterfaceType(*this,
cast<ClassDecl>(vd),
c.isForeign, true);
}

llvm_unreachable("Unhandled SILDeclRefKind in switch.");
Expand Down Expand Up @@ -2466,9 +2471,7 @@ TypeConverter::getInterfaceBoxTypeForCapture(ValueDecl *captured,
CanType loweredInterfaceType,
bool isMutable) {
auto &C = M.getASTContext();
CanGenericSignature signature;
if (auto sig = captured->getDeclContext()->getGenericSignatureOfContext())
signature = sig->getCanonicalSignature();
auto signature = getEffectiveGenericSignature(captured->getDeclContext());

// If the type is not dependent at all, we can form a concrete box layout.
// We don't need to capture the generic environment.
Expand Down
35 changes: 35 additions & 0 deletions test/SILGen/constrained_extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -188,3 +188,38 @@ extension AnythingGoes where T : VeryConstrained {
// CHECK: return
init(fromExtension: ()) {}
}

extension Array where Element == Int {
struct Nested {
// CHECK-LABEL: sil hidden [transparent] @_T0Sa22constrained_extensionsSiRszlE6NestedV1eSiSgvfi : $@convention(thin) () -> Optional<Int>
var e: Element? = nil

// CHECK-LABEL: sil hidden @_T0Sa22constrained_extensionsSiRszlE6NestedV10hasDefaultySiSg1e_tFfA_ : $@convention(thin) () -> Optional<Int>
// CHECK-LABEL: sil hidden @_T0Sa22constrained_extensionsSiRszlE6NestedV10hasDefaultySiSg1e_tF : $@convention(method) (Optional<Int>, @inout Array<Int>.Nested) -> ()
mutating func hasDefault(e: Element? = nil) {
self.e = e
}
}
}

extension Array where Element == AnyObject {
class NestedClass {
// CHECK-LABEL: sil hidden @_T0Sa22constrained_extensionsyXlRszlE11NestedClassCfd : $@convention(method) (@guaranteed Array<AnyObject>.NestedClass) -> @owned Builtin.NativeObject
// CHECK-LABEL: sil hidden @_T0Sa22constrained_extensionsyXlRszlE11NestedClassCfD : $@convention(method) (@owned Array<AnyObject>.NestedClass) -> ()
deinit { }

// CHECK-LABEL: sil hidden @_T0Sa22constrained_extensionsyXlRszlE11NestedClassCACyyXl_GycfC : $@convention(method) (@thick Array<AnyObject>.NestedClass.Type) -> @owned Array<AnyObject>.NestedClass
// CHECK-LABEL: sil hidden @_T0Sa22constrained_extensionsyXlRszlE11NestedClassCACyyXl_Gycfc : $@convention(method) (@owned Array<AnyObject>.NestedClass) -> @owned Array<AnyObject>.NestedClass
}

class DerivedClass : NestedClass {
// CHECK-LABEL: sil hidden [transparent] @_T0Sa22constrained_extensionsyXlRszlE12DerivedClassC1eyXlSgvfi : $@convention(thin) () -> @owned Optional<AnyObject>
// CHECK-LABEL: sil hidden @_T0Sa22constrained_extensionsyXlRszlE12DerivedClassCfE : $@convention(method) (@guaranteed Array<AnyObject>.DerivedClass) -> ()
var e: Element? = nil
}
}

func referenceNestedTypes() {
_ = Array<AnyObject>.NestedClass()
_ = Array<AnyObject>.DerivedClass()
}