Skip to content

[ABI] Mangle retroactive conformances as part of bound generic types. #14296

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
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
13 changes: 12 additions & 1 deletion docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ Types
type ::= type 'Xm' METATYPE-REPR // existential metatype with representation
type ::= 'Xe' // error or unresolved type

bound-generic-type ::= type 'y' (type* '_')* type* 'G' // one type-list per nesting level of type
bound-generic-type ::= type 'y' (type* '_')* type* retroactive-conformance* 'G' // one type-list per nesting level of type
bound-generic-type ::= substitution

FUNCTION-KIND ::= 'f' // @thin function type
Expand Down Expand Up @@ -559,6 +559,17 @@ values indicates a single generic parameter at the outermost depth::
A generic signature must only precede an operator character which is different
from any character in a ``<GENERIC-PARAM-COUNT>``.

::

retroactive-conformance ::= protocol-conformance 'g' INDEX

When a protocol conformance used to satisfy one of a bound generic type's
generic requirements is retroactive (i.e., it is specified in a module other
than the module of the conforming type or the conformed-to protocol), it is
mangled with its offset into the set of conformance requirements, the
root protocol conformance, and the suffix 'g'.


Identifiers
~~~~~~~~~~~

Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/ASTMangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,9 @@ class ASTMangler : public Mangler {

void appendBoundGenericArgs(Type type, bool &isFirstArgList);

/// Append any retroactive conformances.
void appendRetroactiveConformances(Type type);

void appendImplFunctionType(SILFunctionType *fn);

void appendContextOf(const ValueDecl *decl);
Expand Down
4 changes: 4 additions & 0 deletions include/swift/AST/ProtocolConformance.h
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,10 @@ class NormalProtocolConformance : public ProtocolConformance,
/// defines the conforming type.
bool isRetroactive() const;

/// Whether this conformance was synthesized automatically in multiple
/// modules, but in a manner that ensures that all copies are equivalent.
bool isSynthesizedNonUnique() const;

/// Retrieve the type witness and type decl (if one exists)
/// for the given associated type.
std::pair<Type, TypeDecl *>
Expand Down
1 change: 1 addition & 0 deletions include/swift/Demangling/DemangleNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ NODE(QualifiedArchetype)
NODE(ReabstractionThunk)
NODE(ReabstractionThunkHelper)
NODE(RelatedEntityDeclName)
NODE(RetroactiveConformance)
NODE(ReturnType)
NODE(Shared)
NODE(SILBoxType)
Expand Down
1 change: 1 addition & 0 deletions include/swift/Demangling/Demangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ class Demangler : public NodeFactory {
NodePointer demangleBoundGenericArgs(NodePointer nominalType,
const Vector<NodePointer> &TypeLists,
size_t TypeListIdx);
NodePointer demangleRetroactiveConformance();
NodePointer demangleInitializer();
NodePointer demangleImplParamConvention();
NodePointer demangleImplResultConvention(Node::Kind ConvKind);
Expand Down
41 changes: 41 additions & 0 deletions lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#include "swift/AST/Module.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/ProtocolConformanceRef.h"
#include "swift/Basic/Defer.h"
#include "swift/Demangling/ManglingUtils.h"
#include "swift/Demangling/Demangler.h"
#include "swift/Strings.h"
Expand Down Expand Up @@ -856,6 +858,7 @@ void ASTMangler::appendType(Type type) {
appendAnyGenericType(NDecl);
bool isFirstArgList = true;
appendBoundGenericArgs(type, isFirstArgList);
appendRetroactiveConformances(type);
appendOperator("G");
}
addSubstitution(type.getPointer());
Expand Down Expand Up @@ -1088,6 +1091,44 @@ void ASTMangler::appendBoundGenericArgs(Type type, bool &isFirstArgList) {
}
}

void ASTMangler::appendRetroactiveConformances(Type type) {
auto nominal = type->getAnyNominal();
if (!nominal) return;

auto genericSig = nominal->getGenericSignatureOfContext();
if (!genericSig) return;

auto module = Mod ? Mod : nominal->getModuleContext();
auto subMap = type->getContextSubstitutionMap(module, nominal);
if (subMap.empty()) return;

unsigned numProtocolRequirements = 0;
for (const auto &req: genericSig->getRequirements()) {
if (req.getKind() != RequirementKind::Conformance)
continue;

SWIFT_DEFER {
++numProtocolRequirements;
};

// Fast path: we're in the module of the protocol.
auto proto = req.getSecondType()->castTo<ProtocolType>()->getDecl();
if (proto->getModuleContext() == module)
continue;

auto conformance =
subMap.lookupConformance(req.getFirstType()->getCanonicalType(), proto);
if (!conformance || !conformance->isConcrete()) continue;

auto normal = conformance->getConcrete()->getRootNormalConformance();
if (!normal->isRetroactive() || normal->isSynthesizedNonUnique())
continue;

appendProtocolConformance(normal);
appendOperator("g", Index(numProtocolRequirements));
}
}

static char getParamConvention(ParameterConvention conv) {
// @in and @out are mangled the same because they're put in
// different places.
Expand Down
5 changes: 5 additions & 0 deletions lib/AST/ProtocolConformance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "swift/AST/Substitution.h"
#include "swift/AST/Types.h"
#include "swift/AST/TypeWalker.h"
#include "swift/ClangImporter/ClangModule.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/TinyPtrVector.h"
Expand Down Expand Up @@ -353,6 +354,10 @@ bool NormalProtocolConformance::isRetroactive() const {
return true;
}

bool NormalProtocolConformance::isSynthesizedNonUnique() const {
return isa<ClangModuleUnit>(getDeclContext()->getModuleScopeContext());
}

ArrayRef<Requirement> ProtocolConformance::getConditionalRequirements() const {
CONFORMANCE_SUBCLASS_DISPATCH(getConditionalRequirements, ());
}
Expand Down
26 changes: 25 additions & 1 deletion lib/Demangling/Demangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,7 @@ NodePointer Demangler::demangleOperator() {
case 'c': return popFunctionType(Node::Kind::FunctionType);
case 'd': return createNode(Node::Kind::VariadicMarker);
case 'f': return demangleFunctionEntity();
case 'g': return demangleRetroactiveConformance();
case 'h': return createType(createWithChild(Node::Kind::Shared,
popTypeAndGetChild()));
case 'i': return demangleSubscript();
Expand Down Expand Up @@ -1060,7 +1061,27 @@ NodePointer Demangler::popProtocol() {
return createType(Proto);
}

NodePointer Demangler::demangleRetroactiveConformance() {
NodePointer Index = demangleIndexAsNode();
NodePointer Conformance = popProtocolConformance();
if (!Index || !Conformance)
return nullptr;

return createWithChildren(Node::Kind::RetroactiveConformance,
Index, Conformance);
}

NodePointer Demangler::demangleBoundGenericType() {
NodePointer RetroactiveConformances = nullptr;
while (auto RetroactiveConformance =
popNode(Node::Kind::RetroactiveConformance)) {
if (!RetroactiveConformances)
RetroactiveConformances = createNode(Node::Kind::TypeList);
RetroactiveConformances->addChild(RetroactiveConformance, *this);
}
if (RetroactiveConformances)
RetroactiveConformances->reverseChildren();

Vector<NodePointer> TypeListList(*this, 4);
for (;;) {
NodePointer TList = createNode(Node::Kind::TypeList);
Expand All @@ -1076,7 +1097,10 @@ NodePointer Demangler::demangleBoundGenericType() {
return nullptr;
}
NodePointer Nominal = popTypeAndGetAnyGeneric();
NodePointer NTy = createType(demangleBoundGenericArgs(Nominal, TypeListList, 0));
NodePointer BoundNode = demangleBoundGenericArgs(Nominal, TypeListList, 0);
if (RetroactiveConformances)
BoundNode->addChild(RetroactiveConformances, *this);
NodePointer NTy = createType(BoundNode);
addSubstitution(NTy);
return NTy;
}
Expand Down
9 changes: 9 additions & 0 deletions lib/Demangling/NodePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,7 @@ class NodePrinter {
case Node::Kind::ReabstractionThunk:
case Node::Kind::ReabstractionThunkHelper:
case Node::Kind::RelatedEntityDeclName:
case Node::Kind::RetroactiveConformance:
case Node::Kind::Setter:
case Node::Kind::Shared:
case Node::Kind::SILBoxLayout:
Expand Down Expand Up @@ -1083,6 +1084,14 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
printChildren(Node);
}
return nullptr;
case Node::Kind::RetroactiveConformance:
if (Node->getNumChildren() != 2)
return nullptr;

Printer << "retroactive @ ";
print(Node->getChild(0));
print(Node->getChild(1));
return nullptr;
case Node::Kind::Weak:
Printer << "weak ";
print(Node->getChild(0));
Expand Down
4 changes: 4 additions & 0 deletions lib/Demangling/OldRemangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,10 @@ void Remangler::mangleFunctionSignatureSpecializationParamKind(Node *node) {
unreachable("This should never be called");
}

void Remangler::mangleRetroactiveConformance(Node *node) {
unreachable("Retroactive conformances aren't in the old mangling");
}

void Remangler::mangleProtocolConformance(Node *node) {
// type, protocol name, context
assert(node->getNumChildren() == 3);
Expand Down
15 changes: 15 additions & 0 deletions lib/Demangling/Remangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,15 @@ void Remangler::mangleAnyNominalType(Node *node) {
mangleAnyNominalType(unboundType);
char Separator = 'y';
mangleGenericArgs(node, Separator);

if (node->getNumChildren() == 3) {
// Retroactive conformances.
auto listNode = node->getChild(2);
for (size_t Idx = 0, Num = listNode->getNumChildren(); Idx < Num; ++Idx) {
mangle(listNode->getChild(Idx));
}
}

Buffer << 'G';
addSubstitution(entry);
return;
Expand Down Expand Up @@ -1446,6 +1455,12 @@ void Remangler::mangleProtocol(Node *node) {
mangleAnyGenericType(node, "P");
}

void Remangler::mangleRetroactiveConformance(Node *node) {
mangleProtocolConformance(node->getChild(1));
Buffer << 'g';
mangleIndex(node->getChild(0)->getIndex());
}

void Remangler::mangleProtocolConformance(Node *node) {
Node *Ty = getChildOfType(node->getChild(0));
Node *GenSig = nullptr;
Expand Down
5 changes: 2 additions & 3 deletions lib/IRGen/GenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2644,9 +2644,8 @@ namespace {
void addFlags() {
// Miscellaneous flags.
Flags = Flags.withIsRetroactive(Conformance->isRetroactive());
Flags = Flags.withIsSynthesizedNonUnique(
isa<ClangModuleUnit>(
Conformance->getDeclContext()->getModuleScopeContext()));
Flags =
Flags.withIsSynthesizedNonUnique(Conformance->isSynthesizedNonUnique());

// Add the flags.
B.addInt32(Flags.getIntValue());
Expand Down
1 change: 1 addition & 0 deletions test/Demangle/Inputs/manglings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -307,3 +307,4 @@ _T0So13GenericOptionas8HashableSCsACP9hashValueSivgTW ---> {T:} protocol witness
_T0So11CrappyColorVs16RawRepresentableSCMA --> reflection metadata associated type descriptor __C.CrappyColor : Swift.RawRepresentable in __C_Synthesized
$S28protocol_conformance_records15NativeValueTypeVAA8RuncibleAAMc --> protocol conformance descriptor for protocol_conformance_records.NativeValueType : protocol_conformance_records.Runcible in protocol_conformance_records
$SSC9SomeErrorLeVD ---> __C_Synthesized.related decl 'e' for SomeError
$S20mangling_retroactive5test0yyAA1ZVy12RetroactiveB1XVSiAE1YVAG0D1A1PAAg_AiJ1QAAg1_GF -> mangling_retroactive.test0(mangling_retroactive.Z<RetroactiveB.X, Swift.Int, RetroactiveB.Y>) -> ()
2 changes: 1 addition & 1 deletion test/IRGen/objc_bridge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ import Foundation
// CHECK: { i8*, i8*, i8* } {
// CHECK: i8* getelementptr inbounds ([11 x i8], [11 x i8]* @"\01L_selector_data(acceptSet:)", i64 0, i64 0),
// CHECK: i8* getelementptr inbounds ([11 x i8], [11 x i8]* @{{[0-9]+}}, i64 0, i64 0),
// CHECK: i8* bitcast (void (%3*, i8*, %4*)* @"$S11objc_bridge3BasC9acceptSetyys0E0VyACGFTo" to i8*)
// CHECK: i8* bitcast (void (%3*, i8*, %4*)* @"$S11objc_bridge3BasC9acceptSetyys0E0VyACSo8NSObjectCs8Hashable10ObjectiveCg_GFTo" to i8*)
// CHECK: }
// CHECK: { i8*, i8*, i8* } {
// CHECK: i8* getelementptr inbounds ([14 x i8], [14 x i8]* @"\01L_selector_data(.cxx_destruct)", i64 0, i64 0),
Expand Down
2 changes: 2 additions & 0 deletions test/SILGen/Inputs/RetroactiveA.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
public protocol P { }
public protocol Q { }
2 changes: 2 additions & 0 deletions test/SILGen/Inputs/RetroactiveB.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
public struct X { }
public struct Y { }
23 changes: 23 additions & 0 deletions test/SILGen/mangling_retroactive.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -emit-module -enable-sil-ownership -o %t %S/Inputs/RetroactiveA.swift
// RUN: %target-swift-frontend -emit-module -enable-sil-ownership -o %t %S/Inputs/RetroactiveB.swift
// RUN: %target-swift-frontend -emit-silgen -enable-sil-ownership -I %t %s | %FileCheck %s


import RetroactiveA
import RetroactiveB

struct Z<T: P, U: Hashable, V: Q> { }

extension X: P { } // retroactive
extension Y: Q { } // retroactive

// CHECK: sil hidden @$S20mangling_retroactive5test0yyAA1ZVy12RetroactiveB1XVSiAE1YVAG0D1A1PAAg_AiJ1QAAg1_GF
func test0(_: Z<X, Int, Y>) { }

struct Z2<T: P> {
struct Inner<V: Q> { }
}

// CHECK: sil hidden @$S20mangling_retroactive5test1yyAA2Z2V5InnerVy12RetroactiveB1XV_AG1YVAI0F1A1PAAg_AkL1QAAg0_GF
func test1(_: Z2<X>.Inner<Y>) { }
11 changes: 6 additions & 5 deletions test/SILGen/objc_dictionary_bridging.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,12 @@ import gizmo
var property: Dictionary<Foo, Foo> = [:]

// Property getter
// CHECK-LABEL: sil hidden [thunk] @$S24objc_dictionary_bridging3FooC8propertys10DictionaryVyA2CGvgTo : $@convention(objc_method) (Foo) -> @autoreleased NSDictionary
// CHECK-LABEL: sil hidden [thunk] @$S24objc_dictionary_bridging3FooC8propertys10DictionaryVyA2CSo8NSObjectCs8Hashable10Foundationg_GvgTo : $@convention(objc_method) (Foo) -> @autoreleased NSDictionary
// @$S24objc_dictionary_bridging3FooC8propertys10DictionaryVyA2CSo8NSObjectCs8Hashable10Foundationg_Gvpfi
// CHECK: bb0([[SELF:%[0-9]+]] : @unowned $Foo):
// CHECK: [[SELF_COPY:%.*]] = copy_value [[SELF]]
// CHECK: [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
// CHECK: [[GETTER:%[0-9]+]] = function_ref @$S24objc_dictionary_bridging3FooC8propertys10DictionaryVyA2CGvg : $@convention(method) (@guaranteed Foo) -> @owned Dictionary<Foo, Foo>
// CHECK: [[GETTER:%[0-9]+]] = function_ref @$S24objc_dictionary_bridging3FooC8propertys10DictionaryVyA2CSo8NSObjectCs8Hashable10Foundationg_Gvg : $@convention(method) (@guaranteed Foo) -> @owned Dictionary<Foo, Foo>
// CHECK: [[DICT:%[0-9]+]] = apply [[GETTER]]([[BORROWED_SELF_COPY]]) : $@convention(method) (@guaranteed Foo) -> @owned Dictionary<Foo, Foo>
// CHECK: end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
// CHECK: destroy_value [[SELF_COPY]]
Expand All @@ -65,10 +66,10 @@ import gizmo
// CHECK: end_borrow [[BORROWED_DICT]] from [[DICT]]
// CHECK: destroy_value [[DICT]]
// CHECK: return [[NSDICT]] : $NSDictionary
// CHECK: } // end sil function '$S24objc_dictionary_bridging3FooC8propertys10DictionaryVyA2CGvgTo'
// CHECK: } // end sil function

// Property setter
// CHECK-LABEL: sil hidden [thunk] @$S24objc_dictionary_bridging3FooC8propertys10DictionaryVyA2CGvsTo : $@convention(objc_method) (NSDictionary, Foo) -> ()
// CHECK-LABEL: sil hidden [thunk] @$S24objc_dictionary_bridging3FooC8propertys10DictionaryVyA2CSo8NSObjectCs8Hashable10Foundationg_GvsTo : $@convention(objc_method) (NSDictionary, Foo) -> ()
// CHECK: bb0([[NSDICT:%[0-9]+]] : @unowned $NSDictionary, [[SELF:%[0-9]+]] : @unowned $Foo):
// CHECK: [[NSDICT_COPY:%.*]] = copy_value [[NSDICT]]
// CHECK: [[SELF_COPY:%.*]] = copy_value [[SELF]]
Expand All @@ -78,7 +79,7 @@ import gizmo
// CHECK: [[DICT:%[0-9]+]] = apply [[CONVERTER]]<Foo, Foo>([[OPT_NSDICT]], [[DICT_META]])

// CHECK: [[BORROWED_SELF_COPY:%.*]] = begin_borrow [[SELF_COPY]]
// CHECK: [[SETTER:%[0-9]+]] = function_ref @$S24objc_dictionary_bridging3FooC8propertys10DictionaryVyA2CGvs : $@convention(method) (@owned Dictionary<Foo, Foo>, @guaranteed Foo) -> ()
// CHECK: [[SETTER:%[0-9]+]] = function_ref @$S24objc_dictionary_bridging3FooC8propertys10DictionaryVyA2CSo8NSObjectCs8Hashable10Foundationg_Gvs : $@convention(method) (@owned Dictionary<Foo, Foo>, @guaranteed Foo) -> ()
// CHECK: [[RESULT:%[0-9]+]] = apply [[SETTER]]([[DICT]], [[BORROWED_SELF_COPY]]) : $@convention(method) (@owned Dictionary<Foo, Foo>, @guaranteed Foo) -> ()
// CHECK: end_borrow [[BORROWED_SELF_COPY]] from [[SELF_COPY]]
// CHECK: destroy_value [[SELF_COPY]]
Expand Down