Skip to content

Commit d7e6c82

Browse files
committed
[IRGen] Canonicalize symbolic ref types in the right generic context (swiftlang#25955)
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 (cherry picked from commit 4abefdb)
1 parent dd9eae4 commit d7e6c82

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

@@ -4266,7 +4267,7 @@ static void addGenericRequirement(IRGenModule &IGM, ConstantStructBuilder &B,
42664267

42674268
B.addInt(IGM.Int32Ty, flags.getIntValue());
42684269
auto typeName =
4269-
IGM.getTypeRef(paramType->getCanonicalType(), MangledTypeRefRole::Metadata);
4270+
IGM.getTypeRef(paramType, nullptr, MangledTypeRefRole::Metadata);
42704271
B.addRelativeAddress(typeName);
42714272
addReference();
42724273
}
@@ -4333,8 +4334,8 @@ GenericRequirementsMetadata irgen::addGenericRequirements(
43334334

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

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

lib/IRGen/GenProto.cpp

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

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

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

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

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

16151613
llvm::Constant *witness =
16161614
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)