Skip to content
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
2 changes: 2 additions & 0 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 6 additions & 0 deletions include/swift/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<ClassDecl>(this))
return clas->hasClangNode() && clas->isGenericContext();
return false;
}

ConstructorDecl *NominalTypeDecl::getDefaultInitializer() const {
if (!hasDefaultInitializer())
return nullptr;
Expand Down
16 changes: 13 additions & 3 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -4280,9 +4286,13 @@ case TypeKind::Id:
SmallVector<Type, 4> 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;
Expand Down
20 changes: 3 additions & 17 deletions lib/IRGen/MetadataRequest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<ClassDecl>(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;
Expand Down Expand Up @@ -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<BoundGenericType>(type)
: !isa<UnboundGenericType>(type));

Expand Down Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions test/IRGen/Inputs/usr/include/Gizmo.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,6 @@ __attribute__((swift_name("OuterType.InnerType")))
@protocol P
- (oneway void)stuff;
@end

@interface ObjcGenericClass<__covariant SectionType>
@end
12 changes: 12 additions & 0 deletions test/IRGen/generic_classes_objc.sil
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,15 @@ protocol P2 { }
// CHECK-SAME: i16 3, i16 3, i16 5, i16 0
class Generic3WithReqs<T: P1, U: P2, V: P2> { }
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 <ObjcGenericClass<SomeClass>>>) -> () {
bb0(%0 : $Optional< @callee_guaranteed @substituted <τ_0_1> (@in_guaranteed Result<τ_0_1, Error>) -> () for <ObjcGenericClass<SomeClass>> >):
debug_value %0 : $Optional<@callee_guaranteed @substituted <τ_0_1> (@in_guaranteed Result<τ_0_1, Error>) -> () for <ObjcGenericClass<SomeClass>>>, let, name "completion", argno 1
%2 = tuple ()
return %2 : $()
}