Skip to content

[IRGen] Canonicalize symbolic ref types in the right generic context #25955

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 8, 2019
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
19 changes: 10 additions & 9 deletions lib/IRGen/GenMeta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -468,9 +468,9 @@ namespace {
}

void addExtendedContext() {
auto string = IGM.getTypeRef(
E->getSelfInterfaceType()->getCanonicalType(),
MangledTypeRefRole::Metadata);
auto string = IGM.getTypeRef(E->getSelfInterfaceType(),
E->getGenericSignature(),
MangledTypeRefRole::Metadata);
B.addRelativeAddress(string);
}

Expand Down Expand Up @@ -821,8 +821,7 @@ namespace {
continue;

auto witness =
entry.getAssociatedTypeWitness().Witness->mapTypeOutOfContext()
->getCanonicalType();
entry.getAssociatedTypeWitness().Witness->mapTypeOutOfContext();
return IGM.getAssociatedTypeWitness(witness,
/*inProtocolContext=*/true);
}
Expand Down Expand Up @@ -1592,7 +1591,9 @@ namespace {

// TargetRelativeDirectPointer<Runtime, const char> SuperclassType;
if (auto superclassType = getType()->getSuperclass()) {
GenericSignature *genericSig = getType()->getGenericSignature();
B.addRelativeAddress(IGM.getTypeRef(superclassType->getCanonicalType(),
genericSig,
MangledTypeRefRole::Metadata));
} else {
B.addInt32(0);
Expand Down Expand Up @@ -1682,7 +1683,7 @@ namespace {
auto underlyingType = Type(O->getUnderlyingInterfaceType())
.subst(*O->getUnderlyingTypeSubstitutions())
->getCanonicalType(O->getOpaqueInterfaceGenericSignature());

B.addRelativeAddress(IGM.getTypeRef(underlyingType,
MangledTypeRefRole::Metadata));

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

B.addInt(IGM.Int32Ty, flags.getIntValue());
auto typeName =
IGM.getTypeRef(paramType->getCanonicalType(), MangledTypeRefRole::Metadata);
IGM.getTypeRef(paramType, nullptr, MangledTypeRefRole::Metadata);
B.addRelativeAddress(typeName);
addReference();
}
Expand Down Expand Up @@ -4334,8 +4335,8 @@ GenericRequirementsMetadata irgen::addGenericRequirements(

auto flags = GenericRequirementFlags(abiKind, false, false);
auto typeName =
IGM.getTypeRef(requirement.getSecondType()->getCanonicalType(),
MangledTypeRefRole::Metadata);
IGM.getTypeRef(requirement.getSecondType(), nullptr,
MangledTypeRefRole::Metadata);

addGenericRequirement(IGM, B, metadata, sig, flags,
requirement.getFirstType(),
Expand Down
10 changes: 4 additions & 6 deletions lib/IRGen/GenProto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1289,8 +1289,7 @@ class AccessorConformanceInfo : public ConformanceInfo {
#endif

auto associate =
Conformance.getTypeWitness(requirement.getAssociation())
->getCanonicalType();
Conformance.getTypeWitness(requirement.getAssociation());
llvm::Constant *witness =
IGM.getAssociatedTypeWitness(associate, /*inProtocolContext=*/false);
Table.addBitCast(witness, IGM.Int8PtrTy);
Expand Down Expand Up @@ -1424,7 +1423,7 @@ void WitnessTableBuilder::build() {
TableSize = Table.size();
}

llvm::Constant *IRGenModule::getAssociatedTypeWitness(CanType type,
llvm::Constant *IRGenModule::getAssociatedTypeWitness(Type type,
bool inProtocolContext) {
// FIXME: If we can directly reference constant type metadata, do so.

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

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

llvm::Constant *witness =
IGM.getAssociatedTypeWitness(associate, /*inProtocolContext=*/false);
Expand Down
50 changes: 35 additions & 15 deletions lib/IRGen/GenReflection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,15 @@ class PrintMetadataSource
}
};

llvm::Constant *IRGenModule::getTypeRef(CanType type, MangledTypeRefRole role) {
llvm::Constant *IRGenModule::getTypeRef(Type type,
GenericSignature *genericSig,
MangledTypeRefRole role) {
return getTypeRef(type->getCanonicalType(genericSig), role);
}

llvm::Constant *IRGenModule::getTypeRef(CanType type,
MangledTypeRefRole role) {

switch (role) {
case MangledTypeRefRole::DefaultAssociatedTypeWitness:
case MangledTypeRefRole::Metadata:
Expand Down Expand Up @@ -357,6 +365,20 @@ class ReflectionMetadataBuilder {
}
}

/// Add a 32-bit relative offset to a mangled typeref string
/// in the typeref reflection section.
///
/// By default, we use MangledTypeRefRole::Reflection, which does not
/// force emission of any type metadata referenced from the typeref.
///
/// For reflection records which are demangled to produce type metadata
/// in-process, pass MangledTypeRefRole::Metadata instead.
void addTypeRef(Type type, GenericSignature *genericSig,
MangledTypeRefRole role =
MangledTypeRefRole::Reflection) {
addTypeRef(type->getCanonicalType(genericSig), role);
}

/// Add a 32-bit relative offset to a mangled typeref string
/// in the typeref reflection section.
///
Expand Down Expand Up @@ -387,8 +409,7 @@ class ReflectionMetadataBuilder {
IGM.getAddrOfStringForTypeRef(mangledStr, role);
B.addRelativeAddress(mangledName);
} else {
CanType type = nominal->getDeclaredType()->getCanonicalType();
addTypeRef(type, role);
addTypeRef(nominal->getDeclaredType(), /*genericSig*/nullptr, role);
}
}

Expand Down Expand Up @@ -491,8 +512,8 @@ class FieldTypeMetadataBuilder : public ReflectionMetadataBuilder {
const uint32_t fieldRecordSize = 12;
const NominalTypeDecl *NTD;

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

if (IGM.IRGen.Opts.EnableReflectionNames) {
Expand Down Expand Up @@ -536,9 +557,8 @@ class FieldTypeMetadataBuilder : public ReflectionMetadataBuilder {
auto properties = NTD->getStoredProperties();
B.addInt32(std::distance(properties.begin(), properties.end()));
for (auto property : properties)
addFieldDecl(property,
property->getInterfaceType()
->getCanonicalType());
addFieldDecl(property, property->getInterfaceType(),
NTD->getGenericSignature());
}

void layoutEnum() {
Expand All @@ -562,14 +582,13 @@ class FieldTypeMetadataBuilder : public ReflectionMetadataBuilder {
for (auto enumCase : strategy.getElementsWithPayload()) {
bool indirect = (enumCase.decl->isIndirect() ||
enumDecl->isIndirect());
addFieldDecl(enumCase.decl,
enumCase.decl->getArgumentInterfaceType()
->getCanonicalType(),
addFieldDecl(enumCase.decl, enumCase.decl->getArgumentInterfaceType(),
enumDecl->getGenericSignature(),
indirect);
}

for (auto enumCase : strategy.getElementsWithNoPayload()) {
addFieldDecl(enumCase.decl, CanType());
addFieldDecl(enumCase.decl, CanType(), nullptr);
}
}

Expand All @@ -596,9 +615,10 @@ class FieldTypeMetadataBuilder : public ReflectionMetadataBuilder {
auto *CD = dyn_cast<ClassDecl>(NTD);
auto *PD = dyn_cast<ProtocolDecl>(NTD);
if (CD && CD->getSuperclass()) {
addTypeRef(CD->getSuperclass()->getCanonicalType());
addTypeRef(CD->getSuperclass(), CD->getGenericSignature());
} else if (PD && PD->getDeclaredType()->getSuperclass()) {
addTypeRef(PD->getDeclaredType()->getSuperclass()->getCanonicalType());
addTypeRef(PD->getDeclaredType()->getSuperclass(),
PD->getGenericSignature());
} else {
B.addInt32(0);
}
Expand Down
5 changes: 3 additions & 2 deletions lib/IRGen/IRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -1059,6 +1059,8 @@ class IRGenModule {
/// reflection metadata.
llvm::SetVector<CanType> BuiltinTypes;

llvm::Constant *getTypeRef(Type type, GenericSignature *genericSig,
MangledTypeRefRole role);
llvm::Constant *getTypeRef(CanType type, MangledTypeRefRole role);
llvm::Constant *emitWitnessTableRefString(CanType type,
ProtocolConformanceRef conformance,
Expand Down Expand Up @@ -1100,8 +1102,7 @@ class IRGenModule {
llvm::Constant *getAddrOfBoxDescriptor(CanType boxedType);

/// Produce an associated type witness that refers to the given type.
llvm::Constant *getAssociatedTypeWitness(CanType type,
bool inProtocolContext);
llvm::Constant *getAssociatedTypeWitness(Type type, bool inProtocolContext);

void emitAssociatedTypeMetadataRecord(const RootProtocolConformance *C);
void emitFieldDescriptor(const NominalTypeDecl *Decl);
Expand Down
87 changes: 86 additions & 1 deletion test/IRGen/nested_generics.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// RUN: %target-swift-frontend %s -emit-ir | %FileCheck %s --check-prefix=CHECK
// RUN: %target-swift-frontend %s -emit-ir > %t.txt
// RUN: %FileCheck %s --check-prefix=CHECK < %t.txt
// RUN: %FileCheck %s --check-prefix=CHECK-CONSTANTS < %t.txt

// REQUIRES: CPU=x86_64

Expand Down Expand Up @@ -92,3 +94,86 @@ extension Fish where Water : Wet {
case fried
}
}

// <rdar://problem/51627403> Superclass demangling failure when instantiating
// nested generic subclass constrained to outer type generic argument

protocol TagProtocol {}
enum Outer : TagProtocol {}

protocol HasAssoc {
associatedtype Assoc
}

enum Container<T : TagProtocol> {
class _Superclass {}
// CHECK-CONSTANTS-LABEL: @"$s15nested_generics9ContainerO9_SubclassCMn" =
// Check the superclass...
// CHECK-CONSTANTS-SAME: @"symbolic _____y______G 15nested_generics9ContainerO11_SuperclassC AA5OuterO"
// ...and the requirements.
// CHECK-CONSTANTS-SAME: @"symbolic x"
// CHECK-CONSTANTS-SAME: @"symbolic _____ 15nested_generics5OuterO"
// CHECK-CONSTANTS-LABEL: @"$s15nested_generics9ContainerO9_SubclassCMF" =
// CHECK-CONSTANTS-SAME: @"symbolic _____y______G 15nested_generics9ContainerO11_SuperclassC AA5OuterO"
class _Subclass<U>: _Superclass where T == Outer {
// CHECK-CONSTANTS-LABEL: @"$s15nested_generics9ContainerO9_SubclassC11ExtraNestedCMn" =
// CHECK-CONSTANTS-SAME: @"symbolic _____y______G 15nested_generics9ContainerO11_SuperclassC AA5OuterO"
// CHECK-CONSTANTS-LABEL: @"$s15nested_generics9ContainerO9_SubclassC11ExtraNestedCMF" =
// CHECK-CONSTANTS-SAME: @"symbolic _____y______G 15nested_generics9ContainerO11_SuperclassC AA5OuterO"
class ExtraNested: _Superclass {}
}

// CHECK-CONSTANTS-LABEL: @"$s15nested_generics9ContainerO10_Subclass2CMn" =
// CHECK-CONSTANTS-SAME: @"symbolic _____yx_G 15nested_generics9ContainerO11_SuperclassC"
class _Subclass2<U: Collection>: _Superclass where T == U.Element {}


// CHECK-CONSTANTS-LABEL: @"$s15nested_generics9ContainerO10_Subclass3CMn" =
// FIXME: That "qd__" still causes problems: it's (depth: 1, index: 0), but
// the runtime doesn't count the parameters at depth 0 correctly.
// CHECK-CONSTANTS-SAME: @"symbolic _____y______qd__G 15nested_generics9ContainerO18_GenericSuperclassC AA5OuterO"
class _GenericSuperclass<U> {}
class _Subclass3<U>: _GenericSuperclass<U> where T == Outer {}

// CHECK-CONSTANTS-LABEL: @"$s15nested_generics9ContainerO6FieldsVMF" =
// CHECK-CONSTANTS-SAME: @"symbolic _____ 15nested_generics5OuterO"
// FIXME: This still causes problems: it's (depth: 1, index: 0), but
// the runtime doesn't count the parameters at depth 0 correctly.
// CHECK-CONSTANTS-SAME: @"symbolic qd__"
struct Fields<U> where T == Outer {
var x: T
var y: U
}

// CHECK-CONSTANTS-LABEL: @"$s15nested_generics9ContainerO5CasesOMF" =
// FIXME: This still causes problems: it's (depth: 1, index: 0), but
// the runtime doesn't count the parameters at depth 0 correctly.
// CHECK-CONSTANTS-SAME: @"symbolic qd__"
enum Cases<U> where T == Outer {
case a(T)
case b(U)
}

struct Conformancy<U>: HasAssoc where T == Outer {
typealias Assoc = T
}

struct Conformancy2<U> {}
struct Conformancy3 {}
}

extension Container.Conformancy2: HasAssoc where T == Outer {
typealias Assoc = T
}
extension Container.Conformancy3: HasAssoc where T == Outer {
typealias Assoc = T
}

// CHECK-CONSTANTS-LABEL: @"$s15nested_generics9ContainerO12Conformancy3Vyx_GAA8HasAssocA2A5OuterORszrlWP" =
// CHECK-CONSTANTS-SAME: @"symbolic 15nested_generics5OuterO"

// CHECK-CONSTANTS-LABEL: @"$s15nested_generics9ContainerO12Conformancy2Vyx_qd__GAA8HasAssocA2A5OuterORszrlWP" =
// CHECK-CONSTANTS-SAME: @"symbolic 15nested_generics5OuterO"

// CHECK-CONSTANTS-LABEL: @"$s15nested_generics9ContainerO11ConformancyVyx_qd__GAA8HasAssocAAWP" =
// CHECK-CONSTANTS-SAME: @"symbolic 15nested_generics5OuterO"