diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index cd09aa7aee8eb..08634bec519fb 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -3569,6 +3569,8 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext { /// initializer. bool hasDefaultInitializer() const; + bool isTypeErasedGenericClass() const; + /// Retrieves the synthesized zero parameter default initializer for this /// declaration, or \c nullptr if it doesn't have one. ConstructorDecl *getDefaultInitializer() const; diff --git a/include/swift/AST/Type.h b/include/swift/AST/Type.h index 2d540a9138239..1e9cf37b95fd9 100644 --- a/include/swift/AST/Type.h +++ b/include/swift/AST/Type.h @@ -386,6 +386,7 @@ class CanType : public Type { static bool isExistentialTypeImpl(CanType type); static bool isAnyExistentialTypeImpl(CanType type); static bool isObjCExistentialTypeImpl(CanType type); + static bool isTypeErasedGenericClassTypeImpl(CanType type); static CanType getOptionalObjectTypeImpl(CanType type); static CanType getReferenceStorageReferentImpl(CanType type); static CanType getWithoutSpecifierTypeImpl(CanType type); @@ -472,6 +473,11 @@ class CanType : public Type { return isObjCExistentialTypeImpl(*this); } + // Is this an ObjC generic class. + bool isTypeErasedGenericClassType() const { + return isTypeErasedGenericClassTypeImpl(*this); + } + ClassDecl *getClassOrBoundGenericClass() const; // in Types.h StructDecl *getStructOrBoundGenericStruct() const; // in Types.h EnumDecl *getEnumOrBoundGenericEnum() const; // in Types.h diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 13a4d46dcac9e..108bceaf6656e 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -4094,6 +4094,14 @@ bool NominalTypeDecl::hasDefaultInitializer() const { false); } +bool NominalTypeDecl::isTypeErasedGenericClass() const { + // ObjC classes are type erased. + // TODO: Unless they have magic methods... + if (auto clas = dyn_cast(this)) + return clas->hasClangNode() && clas->isGenericContext(); + return false; +} + ConstructorDecl *NominalTypeDecl::getDefaultInitializer() const { if (!hasDefaultInitializer()) return nullptr; diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 7532ea5bbefcc..25e6178dc2ee0 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -343,6 +343,12 @@ bool CanType::isObjCExistentialTypeImpl(CanType type) { return type.getExistentialLayout().isObjC(); } +bool CanType::isTypeErasedGenericClassTypeImpl(CanType type) { + if (auto nom = type->getAnyNominal()) + return nom->isTypeErasedGenericClass(); + return false; +} + bool TypeBase::isSpecialized() { Type t = getCanonicalType(); @@ -4280,9 +4286,13 @@ case TypeKind::Id: SmallVector newReplacements; for (Type type : subs.getReplacementTypes()) { auto transformed = type.transformRec(fn); - assert((type->isEqual(transformed) - || (type->hasTypeParameter() && transformed->hasTypeParameter())) - && "Substituted SILFunctionType can't be transformed into a concrete type"); + assert((type->isEqual(transformed) || + (type->hasTypeParameter() && transformed->hasTypeParameter()) || + (type->getCanonicalType().isTypeErasedGenericClassType() && + transformed->getCanonicalType() + .isTypeErasedGenericClassType())) && + "Substituted SILFunctionType can't be transformed into a " + "concrete type"); newReplacements.push_back(transformed->getCanonicalType()); if (!type->isEqual(transformed)) changed = true; diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp index 3ab7bcd4f9237..e55466b25598c 100644 --- a/lib/IRGen/MetadataRequest.cpp +++ b/lib/IRGen/MetadataRequest.cpp @@ -441,26 +441,12 @@ static llvm::Value *emitObjCMetadataRef(IRGenFunction &IGF, return emitObjCMetadataRefForMetadata(IGF, classPtr); } -static bool isTypeErasedGenericClass(NominalTypeDecl *ntd) { - // ObjC classes are type erased. - // TODO: Unless they have magic methods... - if (auto clas = dyn_cast(ntd)) - return clas->hasClangNode() && clas->isGenericContext(); - return false; -} - -static bool isTypeErasedGenericClassType(CanType type) { - if (auto nom = type->getAnyNominal()) - return isTypeErasedGenericClass(nom); - return false; -} - // Get the type that exists at runtime to represent a compile-time type. CanType IRGenModule::getRuntimeReifiedType(CanType type) { // Leave type-erased ObjC generics with their generic arguments unbound, since // the arguments do not exist at runtime. return CanType(type.transform([&](Type t) -> Type { - if (isTypeErasedGenericClassType(CanType(t))) { + if (CanType(t).isTypeErasedGenericClassType()) { return t->getAnyNominal()->getDeclaredType()->getCanonicalType(); } return t; @@ -2133,7 +2119,7 @@ static llvm::Function *getAccessFunctionPrototype(IRGenModule &IGM, ForDefinition_t forDefinition) { assert(!type->hasArchetype()); // Type should be bound unless it's type erased. - assert(isTypeErasedGenericClassType(type) + assert(type.isTypeErasedGenericClassType() ? !isa(type) : !isa(type)); @@ -2221,7 +2207,7 @@ irgen::getGenericTypeMetadataAccessFunction(IRGenModule &IGM, NominalTypeDecl *nominal, ForDefinition_t shouldDefine) { assert(nominal->isGenericContext()); - assert(!isTypeErasedGenericClass(nominal)); + assert(!nominal->isTypeErasedGenericClass()); GenericArguments genericArgs; genericArgs.collectTypes(IGM, nominal); diff --git a/test/IRGen/Inputs/usr/include/Gizmo.h b/test/IRGen/Inputs/usr/include/Gizmo.h index b359a526b39d6..d1c04f719c4c1 100644 --- a/test/IRGen/Inputs/usr/include/Gizmo.h +++ b/test/IRGen/Inputs/usr/include/Gizmo.h @@ -163,3 +163,6 @@ __attribute__((swift_name("OuterType.InnerType"))) @protocol P - (oneway void)stuff; @end + +@interface ObjcGenericClass<__covariant SectionType> +@end diff --git a/test/IRGen/generic_classes_objc.sil b/test/IRGen/generic_classes_objc.sil index 5fcd6ab5efaf1..492e40d60c102 100644 --- a/test/IRGen/generic_classes_objc.sil +++ b/test/IRGen/generic_classes_objc.sil @@ -72,3 +72,15 @@ protocol P2 { } // CHECK-SAME: i16 3, i16 3, i16 5, i16 0 class Generic3WithReqs { } sil_vtable Generic3WithReqs { } + + +class SomeClass{} +sil_vtable SomeClass {} + +// This used to assert. +sil @repo : $@convention(thin) (@guaranteed Optional< @callee_guaranteed @substituted <τ_0_1> (@in_guaranteed Result<τ_0_1, Error>) -> () for >>) -> () { +bb0(%0 : $Optional< @callee_guaranteed @substituted <τ_0_1> (@in_guaranteed Result<τ_0_1, Error>) -> () for > >): + debug_value %0 : $Optional<@callee_guaranteed @substituted <τ_0_1> (@in_guaranteed Result<τ_0_1, Error>) -> () for >>, let, name "completion", argno 1 + %2 = tuple () + return %2 : $() +}