Skip to content

Commit 8757da3

Browse files
committed
[IRGen] Canonicalize symbolic ref types in the right generic context
When referencing a superclass type from a subclass, for example, the type uses the subclass's generic parameters, not the superclass's. This can be important if a nested type constrains away some of its parent type's generic parameters. This doesn't solve all the problems around mis-referenced generic parameters when some are constrained away, though. That might require a runtime change. See the FIXME comments in the test cases. rdar://problem/51627403
1 parent 7bc5c50 commit 8757da3

File tree

5 files changed

+138
-33
lines changed

5 files changed

+138
-33
lines changed

lib/IRGen/GenMeta.cpp

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -468,9 +468,9 @@ namespace {
468468
}
469469

470470
void addExtendedContext() {
471-
auto string = IGM.getTypeRef(
472-
E->getSelfInterfaceType()->getCanonicalType(),
473-
MangledTypeRefRole::Metadata);
471+
auto string = IGM.getTypeRef(E->getSelfInterfaceType(),
472+
E->getGenericSignature(),
473+
MangledTypeRefRole::Metadata);
474474
B.addRelativeAddress(string);
475475
}
476476

@@ -821,8 +821,7 @@ namespace {
821821
continue;
822822

823823
auto witness =
824-
entry.getAssociatedTypeWitness().Witness->mapTypeOutOfContext()
825-
->getCanonicalType();
824+
entry.getAssociatedTypeWitness().Witness->mapTypeOutOfContext();
826825
return IGM.getAssociatedTypeWitness(witness,
827826
/*inProtocolContext=*/true);
828827
}
@@ -1592,7 +1591,9 @@ namespace {
15921591

15931592
// TargetRelativeDirectPointer<Runtime, const char> SuperclassType;
15941593
if (auto superclassType = getType()->getSuperclass()) {
1594+
GenericSignature *genericSig = getType()->getGenericSignature();
15951595
B.addRelativeAddress(IGM.getTypeRef(superclassType->getCanonicalType(),
1596+
genericSig,
15961597
MangledTypeRefRole::Metadata));
15971598
} else {
15981599
B.addInt32(0);
@@ -1682,7 +1683,7 @@ namespace {
16821683
auto underlyingType = Type(O->getUnderlyingInterfaceType())
16831684
.subst(*O->getUnderlyingTypeSubstitutions())
16841685
->getCanonicalType(O->getOpaqueInterfaceGenericSignature());
1685-
1686+
16861687
B.addRelativeAddress(IGM.getTypeRef(underlyingType,
16871688
MangledTypeRefRole::Metadata));
16881689

@@ -4267,7 +4268,7 @@ static void addGenericRequirement(IRGenModule &IGM, ConstantStructBuilder &B,
42674268

42684269
B.addInt(IGM.Int32Ty, flags.getIntValue());
42694270
auto typeName =
4270-
IGM.getTypeRef(paramType->getCanonicalType(), MangledTypeRefRole::Metadata);
4271+
IGM.getTypeRef(paramType, nullptr, MangledTypeRefRole::Metadata);
42714272
B.addRelativeAddress(typeName);
42724273
addReference();
42734274
}
@@ -4334,8 +4335,8 @@ GenericRequirementsMetadata irgen::addGenericRequirements(
43344335

43354336
auto flags = GenericRequirementFlags(abiKind, false, false);
43364337
auto typeName =
4337-
IGM.getTypeRef(requirement.getSecondType()->getCanonicalType(),
4338-
MangledTypeRefRole::Metadata);
4338+
IGM.getTypeRef(requirement.getSecondType(), nullptr,
4339+
MangledTypeRefRole::Metadata);
43394340

43404341
addGenericRequirement(IGM, B, metadata, sig, flags,
43414342
requirement.getFirstType(),

lib/IRGen/GenProto.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1289,8 +1289,7 @@ class AccessorConformanceInfo : public ConformanceInfo {
12891289
#endif
12901290

12911291
auto associate =
1292-
Conformance.getTypeWitness(requirement.getAssociation())
1293-
->getCanonicalType();
1292+
Conformance.getTypeWitness(requirement.getAssociation());
12941293
llvm::Constant *witness =
12951294
IGM.getAssociatedTypeWitness(associate, /*inProtocolContext=*/false);
12961295
Table.addBitCast(witness, IGM.Int8PtrTy);
@@ -1424,7 +1423,7 @@ void WitnessTableBuilder::build() {
14241423
TableSize = Table.size();
14251424
}
14261425

1427-
llvm::Constant *IRGenModule::getAssociatedTypeWitness(CanType type,
1426+
llvm::Constant *IRGenModule::getAssociatedTypeWitness(Type type,
14281427
bool inProtocolContext) {
14291428
// FIXME: If we can directly reference constant type metadata, do so.
14301429

@@ -1433,7 +1432,7 @@ llvm::Constant *IRGenModule::getAssociatedTypeWitness(CanType type,
14331432
auto role = inProtocolContext
14341433
? MangledTypeRefRole::DefaultAssociatedTypeWitness
14351434
: MangledTypeRefRole::Metadata;
1436-
auto typeRef = getTypeRef(type, role);
1435+
auto typeRef = getTypeRef(type, /*generic signature*/nullptr, role);
14371436

14381437
// Set the low bit to indicate that this is a mangled name.
14391438
auto witness = llvm::ConstantExpr::getPtrToInt(typeRef, IntPtrTy);
@@ -1610,8 +1609,7 @@ void WitnessTableBuilder::collectResilientWitnesses(
16101609
if (entry.getKind() == SILWitnessTable::AssociatedType) {
16111610
// Associated type witness.
16121611
auto assocType = entry.getAssociatedTypeWitness().Requirement;
1613-
auto associate = conformance.getTypeWitness(assocType)
1614-
->getCanonicalType();
1612+
auto associate = conformance.getTypeWitness(assocType);
16151613

16161614
llvm::Constant *witness =
16171615
IGM.getAssociatedTypeWitness(associate, /*inProtocolContext=*/false);

lib/IRGen/GenReflection.cpp

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,15 @@ class PrintMetadataSource
168168
}
169169
};
170170

171-
llvm::Constant *IRGenModule::getTypeRef(CanType type, MangledTypeRefRole role) {
171+
llvm::Constant *IRGenModule::getTypeRef(Type type,
172+
GenericSignature *genericSig,
173+
MangledTypeRefRole role) {
174+
return getTypeRef(type->getCanonicalType(genericSig), role);
175+
}
176+
177+
llvm::Constant *IRGenModule::getTypeRef(CanType type,
178+
MangledTypeRefRole role) {
179+
172180
switch (role) {
173181
case MangledTypeRefRole::DefaultAssociatedTypeWitness:
174182
case MangledTypeRefRole::Metadata:
@@ -357,6 +365,20 @@ class ReflectionMetadataBuilder {
357365
}
358366
}
359367

368+
/// Add a 32-bit relative offset to a mangled typeref string
369+
/// in the typeref reflection section.
370+
///
371+
/// By default, we use MangledTypeRefRole::Reflection, which does not
372+
/// force emission of any type metadata referenced from the typeref.
373+
///
374+
/// For reflection records which are demangled to produce type metadata
375+
/// in-process, pass MangledTypeRefRole::Metadata instead.
376+
void addTypeRef(Type type, GenericSignature *genericSig,
377+
MangledTypeRefRole role =
378+
MangledTypeRefRole::Reflection) {
379+
addTypeRef(type->getCanonicalType(genericSig), role);
380+
}
381+
360382
/// Add a 32-bit relative offset to a mangled typeref string
361383
/// in the typeref reflection section.
362384
///
@@ -387,8 +409,7 @@ class ReflectionMetadataBuilder {
387409
IGM.getAddrOfStringForTypeRef(mangledStr, role);
388410
B.addRelativeAddress(mangledName);
389411
} else {
390-
CanType type = nominal->getDeclaredType()->getCanonicalType();
391-
addTypeRef(type, role);
412+
addTypeRef(nominal->getDeclaredType(), /*genericSig*/nullptr, role);
392413
}
393414
}
394415

@@ -491,8 +512,8 @@ class FieldTypeMetadataBuilder : public ReflectionMetadataBuilder {
491512
const uint32_t fieldRecordSize = 12;
492513
const NominalTypeDecl *NTD;
493514

494-
void addFieldDecl(const ValueDecl *value, CanType type,
495-
bool indirect=false) {
515+
void addFieldDecl(const ValueDecl *value, Type type,
516+
GenericSignature *genericSig, bool indirect=false) {
496517
reflection::FieldRecordFlags flags;
497518
flags.setIsIndirectCase(indirect);
498519
if (auto var = dyn_cast<VarDecl>(value))
@@ -506,7 +527,7 @@ class FieldTypeMetadataBuilder : public ReflectionMetadataBuilder {
506527
// The standard library's Mirror demangles metadata from field
507528
// descriptors, so use MangledTypeRefRole::Metadata to ensure
508529
// runtime metadata is available.
509-
addTypeRef(type, MangledTypeRefRole::Metadata);
530+
addTypeRef(type, genericSig, MangledTypeRefRole::Metadata);
510531
}
511532

512533
if (IGM.IRGen.Opts.EnableReflectionNames) {
@@ -536,9 +557,8 @@ class FieldTypeMetadataBuilder : public ReflectionMetadataBuilder {
536557
auto properties = NTD->getStoredProperties();
537558
B.addInt32(std::distance(properties.begin(), properties.end()));
538559
for (auto property : properties)
539-
addFieldDecl(property,
540-
property->getInterfaceType()
541-
->getCanonicalType());
560+
addFieldDecl(property, property->getInterfaceType(),
561+
NTD->getGenericSignature());
542562
}
543563

544564
void layoutEnum() {
@@ -562,14 +582,13 @@ class FieldTypeMetadataBuilder : public ReflectionMetadataBuilder {
562582
for (auto enumCase : strategy.getElementsWithPayload()) {
563583
bool indirect = (enumCase.decl->isIndirect() ||
564584
enumDecl->isIndirect());
565-
addFieldDecl(enumCase.decl,
566-
enumCase.decl->getArgumentInterfaceType()
567-
->getCanonicalType(),
585+
addFieldDecl(enumCase.decl, enumCase.decl->getArgumentInterfaceType(),
586+
enumDecl->getGenericSignature(),
568587
indirect);
569588
}
570589

571590
for (auto enumCase : strategy.getElementsWithNoPayload()) {
572-
addFieldDecl(enumCase.decl, CanType());
591+
addFieldDecl(enumCase.decl, CanType(), nullptr);
573592
}
574593
}
575594

@@ -596,9 +615,10 @@ class FieldTypeMetadataBuilder : public ReflectionMetadataBuilder {
596615
auto *CD = dyn_cast<ClassDecl>(NTD);
597616
auto *PD = dyn_cast<ProtocolDecl>(NTD);
598617
if (CD && CD->getSuperclass()) {
599-
addTypeRef(CD->getSuperclass()->getCanonicalType());
618+
addTypeRef(CD->getSuperclass(), CD->getGenericSignature());
600619
} else if (PD && PD->getDeclaredType()->getSuperclass()) {
601-
addTypeRef(PD->getDeclaredType()->getSuperclass()->getCanonicalType());
620+
addTypeRef(PD->getDeclaredType()->getSuperclass(),
621+
PD->getGenericSignature());
602622
} else {
603623
B.addInt32(0);
604624
}

lib/IRGen/IRGenModule.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,6 +1059,8 @@ class IRGenModule {
10591059
/// reflection metadata.
10601060
llvm::SetVector<CanType> BuiltinTypes;
10611061

1062+
llvm::Constant *getTypeRef(Type type, GenericSignature *genericSig,
1063+
MangledTypeRefRole role);
10621064
llvm::Constant *getTypeRef(CanType type, MangledTypeRefRole role);
10631065
llvm::Constant *emitWitnessTableRefString(CanType type,
10641066
ProtocolConformanceRef conformance,
@@ -1100,8 +1102,7 @@ class IRGenModule {
11001102
llvm::Constant *getAddrOfBoxDescriptor(CanType boxedType);
11011103

11021104
/// Produce an associated type witness that refers to the given type.
1103-
llvm::Constant *getAssociatedTypeWitness(CanType type,
1104-
bool inProtocolContext);
1105+
llvm::Constant *getAssociatedTypeWitness(Type type, bool inProtocolContext);
11051106

11061107
void emitAssociatedTypeMetadataRecord(const RootProtocolConformance *C);
11071108
void emitFieldDescriptor(const NominalTypeDecl *Decl);

test/IRGen/nested_generics.swift

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
// RUN: %target-swift-frontend %s -emit-ir | %FileCheck %s --check-prefix=CHECK
1+
// RUN: %target-swift-frontend %s -emit-ir > %t.txt
2+
// RUN: %FileCheck %s --check-prefix=CHECK < %t.txt
3+
// RUN: %FileCheck %s --check-prefix=CHECK-CONSTANTS < %t.txt
24

35
// REQUIRES: CPU=x86_64
46

@@ -92,3 +94,86 @@ extension Fish where Water : Wet {
9294
case fried
9395
}
9496
}
97+
98+
// <rdar://problem/51627403> Superclass demangling failure when instantiating
99+
// nested generic subclass constrained to outer type generic argument
100+
101+
protocol TagProtocol {}
102+
enum Outer : TagProtocol {}
103+
104+
protocol HasAssoc {
105+
associatedtype Assoc
106+
}
107+
108+
enum Container<T : TagProtocol> {
109+
class _Superclass {}
110+
// CHECK-CONSTANTS-LABEL: @"$s15nested_generics9ContainerO9_SubclassCMn" =
111+
// Check the superclass...
112+
// CHECK-CONSTANTS-SAME: @"symbolic _____y______G 15nested_generics9ContainerO11_SuperclassC AA5OuterO"
113+
// ...and the requirements.
114+
// CHECK-CONSTANTS-SAME: @"symbolic x"
115+
// CHECK-CONSTANTS-SAME: @"symbolic _____ 15nested_generics5OuterO"
116+
// CHECK-CONSTANTS-LABEL: @"$s15nested_generics9ContainerO9_SubclassCMF" =
117+
// CHECK-CONSTANTS-SAME: @"symbolic _____y______G 15nested_generics9ContainerO11_SuperclassC AA5OuterO"
118+
class _Subclass<U>: _Superclass where T == Outer {
119+
// CHECK-CONSTANTS-LABEL: @"$s15nested_generics9ContainerO9_SubclassC11ExtraNestedCMn" =
120+
// CHECK-CONSTANTS-SAME: @"symbolic _____y______G 15nested_generics9ContainerO11_SuperclassC AA5OuterO"
121+
// CHECK-CONSTANTS-LABEL: @"$s15nested_generics9ContainerO9_SubclassC11ExtraNestedCMF" =
122+
// CHECK-CONSTANTS-SAME: @"symbolic _____y______G 15nested_generics9ContainerO11_SuperclassC AA5OuterO"
123+
class ExtraNested: _Superclass {}
124+
}
125+
126+
// CHECK-CONSTANTS-LABEL: @"$s15nested_generics9ContainerO10_Subclass2CMn" =
127+
// CHECK-CONSTANTS-SAME: @"symbolic _____yx_G 15nested_generics9ContainerO11_SuperclassC"
128+
class _Subclass2<U: Collection>: _Superclass where T == U.Element {}
129+
130+
131+
// CHECK-CONSTANTS-LABEL: @"$s15nested_generics9ContainerO10_Subclass3CMn" =
132+
// FIXME: That "qd__" still causes problems: it's (depth: 1, index: 0), but
133+
// the runtime doesn't count the parameters at depth 0 correctly.
134+
// CHECK-CONSTANTS-SAME: @"symbolic _____y______qd__G 15nested_generics9ContainerO18_GenericSuperclassC AA5OuterO"
135+
class _GenericSuperclass<U> {}
136+
class _Subclass3<U>: _GenericSuperclass<U> where T == Outer {}
137+
138+
// CHECK-CONSTANTS-LABEL: @"$s15nested_generics9ContainerO6FieldsVMF" =
139+
// CHECK-CONSTANTS-SAME: @"symbolic _____ 15nested_generics5OuterO"
140+
// FIXME: This still causes problems: it's (depth: 1, index: 0), but
141+
// the runtime doesn't count the parameters at depth 0 correctly.
142+
// CHECK-CONSTANTS-SAME: @"symbolic qd__"
143+
struct Fields<U> where T == Outer {
144+
var x: T
145+
var y: U
146+
}
147+
148+
// CHECK-CONSTANTS-LABEL: @"$s15nested_generics9ContainerO5CasesOMF" =
149+
// FIXME: This still causes problems: it's (depth: 1, index: 0), but
150+
// the runtime doesn't count the parameters at depth 0 correctly.
151+
// CHECK-CONSTANTS-SAME: @"symbolic qd__"
152+
enum Cases<U> where T == Outer {
153+
case a(T)
154+
case b(U)
155+
}
156+
157+
struct Conformancy<U>: HasAssoc where T == Outer {
158+
typealias Assoc = T
159+
}
160+
161+
struct Conformancy2<U> {}
162+
struct Conformancy3 {}
163+
}
164+
165+
extension Container.Conformancy2: HasAssoc where T == Outer {
166+
typealias Assoc = T
167+
}
168+
extension Container.Conformancy3: HasAssoc where T == Outer {
169+
typealias Assoc = T
170+
}
171+
172+
// CHECK-CONSTANTS-LABEL: @"$s15nested_generics9ContainerO12Conformancy3Vyx_GAA8HasAssocA2A5OuterORszrlWP" =
173+
// CHECK-CONSTANTS-SAME: @"symbolic 15nested_generics5OuterO"
174+
175+
// CHECK-CONSTANTS-LABEL: @"$s15nested_generics9ContainerO12Conformancy2Vyx_qd__GAA8HasAssocA2A5OuterORszrlWP" =
176+
// CHECK-CONSTANTS-SAME: @"symbolic 15nested_generics5OuterO"
177+
178+
// CHECK-CONSTANTS-LABEL: @"$s15nested_generics9ContainerO11ConformancyVyx_qd__GAA8HasAssocAAWP" =
179+
// CHECK-CONSTANTS-SAME: @"symbolic 15nested_generics5OuterO"

0 commit comments

Comments
 (0)