Skip to content

Commit 5d3b598

Browse files
Merge pull request #33228 from aschwaighofer/type_substitute_objc_generics_assert_5.3
[5.3] Type substitution: When substituting SILFunctionTypes we substitute unbound Objective-C generic for bound ones
2 parents 65fffb1 + ed7bb01 commit 5d3b598

File tree

7 files changed

+64
-21
lines changed

7 files changed

+64
-21
lines changed

include/swift/AST/Decl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3594,6 +3594,8 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
35943594
/// initializer.
35953595
bool hasDefaultInitializer() const;
35963596

3597+
bool isTypeErasedGenericClass() const;
3598+
35973599
/// Retrieves the synthesized zero parameter default initializer for this
35983600
/// declaration, or \c nullptr if it doesn't have one.
35993601
ConstructorDecl *getDefaultInitializer() const;

include/swift/AST/Type.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ class CanType : public Type {
389389
static bool isExistentialTypeImpl(CanType type);
390390
static bool isAnyExistentialTypeImpl(CanType type);
391391
static bool isObjCExistentialTypeImpl(CanType type);
392+
static bool isTypeErasedGenericClassTypeImpl(CanType type);
392393
static CanType getOptionalObjectTypeImpl(CanType type);
393394
static CanType getReferenceStorageReferentImpl(CanType type);
394395
static CanType getWithoutSpecifierTypeImpl(CanType type);
@@ -475,6 +476,11 @@ class CanType : public Type {
475476
return isObjCExistentialTypeImpl(*this);
476477
}
477478

479+
// Is this an ObjC generic class.
480+
bool isTypeErasedGenericClassType() const {
481+
return isTypeErasedGenericClassTypeImpl(*this);
482+
}
483+
478484
ClassDecl *getClassOrBoundGenericClass() const; // in Types.h
479485
StructDecl *getStructOrBoundGenericStruct() const; // in Types.h
480486
EnumDecl *getEnumOrBoundGenericEnum() const; // in Types.h

lib/AST/Decl.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4190,6 +4190,14 @@ bool NominalTypeDecl::hasDefaultInitializer() const {
41904190
false);
41914191
}
41924192

4193+
bool NominalTypeDecl::isTypeErasedGenericClass() const {
4194+
// ObjC classes are type erased.
4195+
// TODO: Unless they have magic methods...
4196+
if (auto clas = dyn_cast<ClassDecl>(this))
4197+
return clas->hasClangNode() && clas->isGenericContext();
4198+
return false;
4199+
}
4200+
41934201
ConstructorDecl *NominalTypeDecl::getDefaultInitializer() const {
41944202
if (!hasDefaultInitializer())
41954203
return nullptr;

lib/AST/Type.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,12 @@ bool CanType::isObjCExistentialTypeImpl(CanType type) {
350350
return type.getExistentialLayout().isObjC();
351351
}
352352

353+
bool CanType::isTypeErasedGenericClassTypeImpl(CanType type) {
354+
if (auto nom = type->getAnyNominal())
355+
return nom->isTypeErasedGenericClass();
356+
return false;
357+
}
358+
353359
bool TypeBase::isSpecialized() {
354360
Type t = getCanonicalType();
355361

@@ -4302,17 +4308,27 @@ case TypeKind::Id:
43024308
case TypeKind::SILFunction: {
43034309
auto fnTy = cast<SILFunctionType>(base);
43044310
bool changed = false;
4305-
4311+
auto hasTypeErasedGenericClassType = [](Type ty) -> bool {
4312+
return ty.findIf([](Type subType) -> bool {
4313+
if (subType->getCanonicalType().isTypeErasedGenericClassType())
4314+
return true;
4315+
else
4316+
return false;
4317+
});
4318+
};
43064319
auto updateSubs = [&](SubstitutionMap &subs) -> bool {
43074320
// This interface isn't suitable for updating the substitution map in a
43084321
// substituted SILFunctionType.
43094322
// TODO(SILFunctionType): Is it suitable for any SILFunctionType??
43104323
SmallVector<Type, 4> newReplacements;
43114324
for (Type type : subs.getReplacementTypes()) {
43124325
auto transformed = type.transformRec(fn);
4313-
assert((type->isEqual(transformed)
4314-
|| (type->hasTypeParameter() && transformed->hasTypeParameter()))
4315-
&& "Substituted SILFunctionType can't be transformed into a concrete type");
4326+
assert((type->isEqual(transformed) ||
4327+
(type->hasTypeParameter() && transformed->hasTypeParameter()) ||
4328+
(hasTypeErasedGenericClassType(type) &&
4329+
hasTypeErasedGenericClassType(transformed))) &&
4330+
"Substituted SILFunctionType can't be transformed into a "
4331+
"concrete type");
43164332
newReplacements.push_back(transformed->getCanonicalType());
43174333
if (!type->isEqual(transformed))
43184334
changed = true;

lib/IRGen/MetadataRequest.cpp

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -441,26 +441,12 @@ static llvm::Value *emitObjCMetadataRef(IRGenFunction &IGF,
441441
return emitObjCMetadataRefForMetadata(IGF, classPtr);
442442
}
443443

444-
static bool isTypeErasedGenericClass(NominalTypeDecl *ntd) {
445-
// ObjC classes are type erased.
446-
// TODO: Unless they have magic methods...
447-
if (auto clas = dyn_cast<ClassDecl>(ntd))
448-
return clas->hasClangNode() && clas->isGenericContext();
449-
return false;
450-
}
451-
452-
static bool isTypeErasedGenericClassType(CanType type) {
453-
if (auto nom = type->getAnyNominal())
454-
return isTypeErasedGenericClass(nom);
455-
return false;
456-
}
457-
458444
// Get the type that exists at runtime to represent a compile-time type.
459445
CanType IRGenModule::getRuntimeReifiedType(CanType type) {
460446
// Leave type-erased ObjC generics with their generic arguments unbound, since
461447
// the arguments do not exist at runtime.
462448
return CanType(type.transform([&](Type t) -> Type {
463-
if (isTypeErasedGenericClassType(CanType(t))) {
449+
if (CanType(t).isTypeErasedGenericClassType()) {
464450
return t->getAnyNominal()->getDeclaredType()->getCanonicalType();
465451
}
466452
return t;
@@ -2126,7 +2112,7 @@ static llvm::Function *getAccessFunctionPrototype(IRGenModule &IGM,
21262112
ForDefinition_t forDefinition) {
21272113
assert(!type->hasArchetype());
21282114
// Type should be bound unless it's type erased.
2129-
assert(isTypeErasedGenericClassType(type)
2115+
assert(type.isTypeErasedGenericClassType()
21302116
? !isa<BoundGenericType>(type)
21312117
: !isa<UnboundGenericType>(type));
21322118

@@ -2214,7 +2200,7 @@ irgen::getGenericTypeMetadataAccessFunction(IRGenModule &IGM,
22142200
NominalTypeDecl *nominal,
22152201
ForDefinition_t shouldDefine) {
22162202
assert(nominal->isGenericContext());
2217-
assert(!isTypeErasedGenericClass(nominal));
2203+
assert(!nominal->isTypeErasedGenericClass());
22182204

22192205
GenericArguments genericArgs;
22202206
genericArgs.collectTypes(IGM, nominal);

test/IRGen/Inputs/usr/include/Gizmo.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,3 +163,6 @@ __attribute__((swift_name("OuterType.InnerType")))
163163
@protocol P
164164
- (oneway void)stuff;
165165
@end
166+
167+
@interface ObjcGenericClass<__covariant SectionType>
168+
@end

test/IRGen/generic_classes_objc.sil

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,25 @@ protocol P2 { }
7272
// CHECK-SAME: i16 3, i16 3, i16 5, i16 0
7373
class Generic3WithReqs<T: P1, U: P2, V: P2> { }
7474
sil_vtable Generic3WithReqs { }
75+
76+
77+
class SomeClass{}
78+
sil_vtable SomeClass {}
79+
80+
// This used to assert.
81+
sil @repo : $@convention(thin) (@guaranteed Optional< @callee_guaranteed @substituted <τ_0_1> (@in_guaranteed Result<τ_0_1, Error>) -> () for <ObjcGenericClass<SomeClass>>>) -> () {
82+
bb0(%0 : $Optional< @callee_guaranteed @substituted <τ_0_1> (@in_guaranteed Result<τ_0_1, Error>) -> () for <ObjcGenericClass<SomeClass>> >):
83+
debug_value %0 : $Optional<@callee_guaranteed @substituted <τ_0_1> (@in_guaranteed Result<τ_0_1, Error>) -> () for <ObjcGenericClass<SomeClass>>>, let, name "completion", argno 1
84+
%2 = tuple ()
85+
return %2 : $()
86+
}
87+
88+
struct PlainGeneric<T> {}
89+
90+
// This used to assert.
91+
sil @repo2 : $@convention(thin) (@guaranteed Optional< @callee_guaranteed @substituted <τ_0_1> (@in_guaranteed Result<τ_0_1, Error>) -> () for <PlainGeneric<ObjcGenericClass<SomeClass>>>>) -> () {
92+
bb0(%0 : $Optional< @callee_guaranteed @substituted <τ_0_1> (@in_guaranteed Result<τ_0_1, Error>) -> () for <PlainGeneric<ObjcGenericClass<SomeClass>>> >):
93+
debug_value %0 : $Optional<@callee_guaranteed @substituted <τ_0_1> (@in_guaranteed Result<τ_0_1, Error>) -> () for <PlainGeneric<ObjcGenericClass<SomeClass>>>>, let, name "completion", argno 1
94+
%2 = tuple ()
95+
return %2 : $()
96+
}

0 commit comments

Comments
 (0)