Skip to content

Commit 1ba4f54

Browse files
jckarterkitasuke
authored andcommitted
IRGen: Use swift_getObjectType to get the type(of:) mixed classes.
A Swift subclass of an ObjC class can be dynamically subclassed, but `type(of:)` shouldn't return the artificial subclass, since that's not what -class does for ObjC classes, and people expect `Bundle(for: type(of: c))` to work like `[NSBundle bundleForClass: [c class]]` would in ObjC. Fixes rdar://problem/37319860.
1 parent 00284c3 commit 1ba4f54

File tree

4 files changed

+71
-17
lines changed

4 files changed

+71
-17
lines changed

lib/IRGen/GenHeap.cpp

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1967,16 +1967,30 @@ llvm::Value *irgen::emitDynamicTypeOfHeapObject(IRGenFunction &IGF,
19671967
llvm::Value *object,
19681968
MetatypeRepresentation repr,
19691969
SILType objectType,
1970-
bool suppressCast) {
1971-
// If it is known to have swift metadata, just load. A swift class is both
1972-
// heap metadata and type metadata.
1973-
if (hasKnownSwiftMetadata(IGF.IGM, objectType.getASTType())) {
1974-
return emitLoadOfHeapMetadataRef(IGF, object,
1975-
getIsaEncodingForType(IGF.IGM, objectType.getASTType()),
1976-
suppressCast);
1970+
bool allowArtificialSubclasses){
1971+
switch (auto isaEncoding =
1972+
getIsaEncodingForType(IGF.IGM, objectType.getASTType())) {
1973+
case IsaEncoding::Pointer:
1974+
// Directly load the isa pointer from a pure Swift class.
1975+
return emitLoadOfHeapMetadataRef(IGF, object, isaEncoding,
1976+
/*suppressCast*/ false);
1977+
case IsaEncoding::ObjC:
1978+
// A class defined in Swift that inherits from an Objective-C class may
1979+
// end up dynamically subclassed by ObjC runtime hackery. The artificial
1980+
// subclass isn't a formal Swift type, so isn't appropriate as the result
1981+
// of `type(of:)`, but is still a physical subtype of the real class object,
1982+
// so can be used for some purposes like satisfying type parameters in
1983+
// generic signatures.
1984+
if (allowArtificialSubclasses
1985+
&& hasKnownSwiftMetadata(IGF.IGM, objectType.getASTType()))
1986+
return emitLoadOfHeapMetadataRef(IGF, object, isaEncoding,
1987+
/*suppressCast*/ false);
1988+
1989+
// Ask the Swift runtime to find the dynamic type. This will look through
1990+
// dynamic subclasses of Swift classes, and use the -class message for
1991+
// ObjC classes.
1992+
return emitDynamicTypeOfOpaqueHeapObject(IGF, object, repr);
19771993
}
1978-
1979-
return emitDynamicTypeOfOpaqueHeapObject(IGF, object, repr);
19801994
}
19811995

19821996
static ClassDecl *getRootClass(ClassDecl *theClass) {
@@ -2001,6 +2015,11 @@ IsaEncoding irgen::getIsaEncodingForType(IRGenModule &IGM,
20012015
// For ObjC or mixed classes, we need to use object_getClass.
20022016
return IsaEncoding::ObjC;
20032017
}
2018+
2019+
// Existentials use the encoding of the enclosed dynamic type.
2020+
if (type->isAnyExistentialType()) {
2021+
return getIsaEncodingForType(IGM, ArchetypeType::getOpened(type));
2022+
}
20042023

20052024
if (auto archetype = dyn_cast<ArchetypeType>(type)) {
20062025
// If we have a concrete superclass constraint, just recurse.
@@ -2013,9 +2032,6 @@ IsaEncoding irgen::getIsaEncodingForType(IRGenModule &IGM,
20132032
return IsaEncoding::ObjC;
20142033
}
20152034

2016-
// We should never be working with an unopened existential type here.
2017-
assert(!type->isAnyExistentialType());
2018-
20192035
// Non-class heap objects should be pure Swift, so we can access their isas
20202036
// directly.
20212037
return IsaEncoding::Pointer;

lib/IRGen/GenHeap.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ llvm::Value *emitDynamicTypeOfHeapObject(IRGenFunction &IGF,
152152
llvm::Value *object,
153153
MetatypeRepresentation rep,
154154
SILType objectType,
155-
bool suppressCast = false);
155+
bool allowArtificialSubclasses = false);
156156

157157
/// Given a non-tagged object pointer, load a pointer to its class object.
158158
llvm::Value *emitLoadOfObjCHeapMetadataRef(IRGenFunction &IGF,

lib/IRGen/GenProto.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -627,9 +627,10 @@ bindParameterSource(SILParameterInfo param, unsigned paramIndex,
627627
llvm::Value *instanceRef = getParameter(paramIndex);
628628
SILType instanceType = SILType::getPrimitiveObjectType(paramType);
629629
llvm::Value *metadata =
630-
emitDynamicTypeOfHeapObject(IGF, instanceRef,
631-
MetatypeRepresentation::Thick,
632-
instanceType);
630+
emitDynamicTypeOfHeapObject(IGF, instanceRef,
631+
MetatypeRepresentation::Thick,
632+
instanceType,
633+
/*allow artificial subclasses*/ true);
633634
IGF.bindLocalTypeDataFromTypeMetadata(paramType, IsInexact, metadata,
634635
MetadataState::Complete);
635636
return;
@@ -690,7 +691,8 @@ void BindPolymorphicParameter::emit(Explosion &nativeParam, unsigned paramIndex)
690691
llvm::Value *metadata =
691692
emitDynamicTypeOfHeapObject(IGF, instanceRef,
692693
MetatypeRepresentation::Thick,
693-
instanceType);
694+
instanceType,
695+
/* allow artificial subclasses */ true);
694696
IGF.bindLocalTypeDataFromTypeMetadata(paramType, IsInexact, metadata,
695697
MetadataState::Complete);
696698
}

test/IRGen/objc_typeof.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-ir %s | %FileCheck %s
2+
// REQUIRES: objc_interop
3+
4+
import Foundation
5+
6+
open class AllSwift {}
7+
8+
open class Mixed: NSObject {}
9+
10+
// CHECK-LABEL: define{{.*@.*}}14typeOfAllSwift
11+
public func typeOfAllSwift(_ x: AllSwift) -> AllSwift.Type {
12+
// CHECK: [[ISA:%.*]] = load %swift.type*
13+
// CHECK: ret %swift.type* [[ISA]]
14+
return type(of: x)
15+
}
16+
17+
// CHECK-LABEL: define{{.*@.*}}11typeOfMixed
18+
public func typeOfMixed(_ x: Mixed) -> Mixed.Type {
19+
// CHECK: [[ISA:%.*]] = call %swift.type* @swift_getObjectType
20+
// CHECK: ret %swift.type* [[ISA]]
21+
return type(of: x)
22+
}
23+
24+
// CHECK-LABEL: define{{.*@.*}}14typeOfNSObject
25+
public func typeOfNSObject(_ x: NSObject) -> NSObject.Type {
26+
// CHECK: [[ISA:%.*]] = call %swift.type* @swift_getObjectType
27+
// CHECK: ret %swift.type* [[ISA]]
28+
return type(of: x)
29+
}
30+
31+
// CHECK-LABEL: define{{.*@.*}}13typeOfUnknown
32+
public func typeOfUnknown(_ x: AnyObject) -> AnyObject.Type {
33+
// CHECK: [[ISA:%.*]] = call %swift.type* @swift_getObjectType
34+
// CHECK: ret %swift.type* [[ISA]]
35+
return type(of: x)
36+
}

0 commit comments

Comments
 (0)