Skip to content
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
3 changes: 3 additions & 0 deletions docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -966,6 +966,7 @@ Property behaviors are implemented using private protocol conformances.

any-protocol-conformance ::= concrete-protocol-conformance
any-protocol-conformance ::= dependent-protocol-conformance
any-protocol-conformance ::= pack-protocol-conformance

any-protocol-conformance-list ::= any-protocol-conformance '_' any-protocol-conformance-list
any-protocol-conformance-list ::= empty-list
Expand All @@ -980,6 +981,8 @@ Property behaviors are implemented using private protocol conformances.
dependent-associated-conformance ::= type protocol
dependent-protocol-conformance ::= dependent-protocol-conformance opaque-type 'HO'

pack-protocol-conformance ::= any-protocol-conformance-list 'HX'

A compact representation used to represent mangled protocol conformance witness
arguments at runtime. The ``module`` is only specified for conformances that
are "retroactive", meaning that the context in which the conformance is defined
Expand Down
6 changes: 4 additions & 2 deletions include/swift/AST/ASTMangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -443,8 +443,7 @@ class ASTMangler : public Mangler {
/// Append any retroactive conformances.
void appendRetroactiveConformances(Type type, GenericSignature sig);
void appendRetroactiveConformances(SubstitutionMap subMap,
GenericSignature sig,
ModuleDecl *fromModule);
GenericSignature sig);
void appendImplFunctionType(SILFunctionType *fn, GenericSignature sig,
const ValueDecl *forDecl = nullptr);
void appendOpaqueTypeArchetype(ArchetypeType *archetype,
Expand Down Expand Up @@ -703,6 +702,9 @@ class ASTMangler : public Mangler {
void appendConcreteProtocolConformance(
const ProtocolConformance *conformance,
GenericSignature sig);
void appendPackProtocolConformance(
const PackConformance *conformance,
GenericSignature sig);
void appendDependentProtocolConformance(const ConformancePath &path,
GenericSignature sig);
void appendOpParamForLayoutConstraint(LayoutConstraint Layout);
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 @@ -51,6 +51,7 @@ NODE(ClangType)
CONTEXT_NODE(Class)
NODE(ClassMetadataBaseOffset)
NODE(ConcreteProtocolConformance)
NODE(PackProtocolConformance)
NODE(ConformanceAttachedMacroExpansion)
CONTEXT_NODE(Constructor)
NODE(CoroutineContinuationPrototype)
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 @@ -587,6 +587,7 @@ class Demangler : public NodeFactory {
NodePointer demangleRetroactiveProtocolConformanceRef();
NodePointer popAnyProtocolConformance();
NodePointer demangleConcreteProtocolConformance();
NodePointer demanglePackProtocolConformance();
NodePointer popDependentProtocolConformance();
NodePointer demangleDependentProtocolConformanceRoot();
NodePointer demangleDependentProtocolConformanceInherited();
Expand Down
4 changes: 3 additions & 1 deletion lib/APIDigester/ModuleAnalyzerNodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1633,7 +1633,9 @@ SwiftDeclCollector::constructTypeNode(Type T, TypeInitInfo Info) {
ReplaceOpaqueTypesWithUnderlyingTypes replacer(
/*inContext=*/nullptr, ResilienceExpansion::Maximal,
/*isWholeModuleContext=*/false);
T = T.subst(replacer, replacer, SubstFlags::SubstituteOpaqueArchetypes)
T = T.subst(replacer, replacer,
SubstFlags::SubstituteOpaqueArchetypes |
SubstFlags::PreservePackExpansionLevel)
->getCanonicalType();
}
}
Expand Down
158 changes: 96 additions & 62 deletions lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "swift/AST/MacroDiscriminatorContext.h"
#include "swift/AST/Module.h"
#include "swift/AST/Ownership.h"
#include "swift/AST/PackConformance.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/PrettyStackTrace.h"
#include "swift/AST/ProtocolConformance.h"
Expand Down Expand Up @@ -1871,20 +1872,11 @@ static bool isRetroactiveConformance(const RootProtocolConformance *root) {
return conformance->isRetroactive();
}

/// Determine whether the given protocol conformance contains a retroactive
/// protocol conformance anywhere in it.
static bool containsRetroactiveConformance(
const ProtocolConformance *conformance,
ModuleDecl *module) {
// If the root conformance is retroactive, it's retroactive.
const RootProtocolConformance *rootConformance =
conformance->getRootConformance();
if (isRetroactiveConformance(rootConformance) &&
conformanceHasIdentity(rootConformance))
return true;
template<typename Fn>
static bool forEachConditionalConformance(const ProtocolConformance *conformance,
Fn fn) {
auto *rootConformance = conformance->getRootConformance();

// If the conformance is conditional and any of the substitutions used to
// satisfy the conditions are retroactive, it's retroactive.
auto subMap = conformance->getSubstitutionMap();
for (auto requirement : rootConformance->getConditionalRequirements()) {
if (requirement.getKind() != RequirementKind::Conformance)
Expand All @@ -1897,18 +1889,49 @@ static bool containsRetroactiveConformance(
// for indexing purposes.
continue;
}
if (conformance.isConcrete() &&
containsRetroactiveConformance(conformance.getConcrete(), module)) {

if (fn(requirement.getFirstType().subst(subMap), conformance))
return true;
}
}

return false;
}

/// Determine whether the given protocol conformance contains a retroactive
/// protocol conformance anywhere in it.
static bool containsRetroactiveConformance(
ProtocolConformanceRef conformanceRef) {
if (!conformanceRef.isPack() && !conformanceRef.isConcrete())
return false;

if (conformanceRef.isPack()) {
for (auto patternConf : conformanceRef.getPack()->getPatternConformances()) {
if (containsRetroactiveConformance(patternConf))
return true;
}

return false;
}

auto *conformance = conformanceRef.getConcrete();

// If the root conformance is retroactive, it's retroactive.
const RootProtocolConformance *rootConformance =
conformance->getRootConformance();
if (isRetroactiveConformance(rootConformance) &&
conformanceHasIdentity(rootConformance))
return true;

// If the conformance is conditional and any of the substitutions used to
// satisfy the conditions are retroactive, it's retroactive.
return forEachConditionalConformance(conformance,
[&](Type substType, ProtocolConformanceRef substConf) -> bool {
return containsRetroactiveConformance(substConf);
});
}

void ASTMangler::appendRetroactiveConformances(SubstitutionMap subMap,
GenericSignature sig,
ModuleDecl *fromModule) {
GenericSignature sig) {
if (subMap.empty()) return;

unsigned numProtocolRequirements = 0;
Expand All @@ -1924,14 +1947,18 @@ void ASTMangler::appendRetroactiveConformances(SubstitutionMap subMap,
};

// Ignore abstract conformances.
if (!conformance.isConcrete())
if (!conformance.isConcrete() && !conformance.isPack())
continue;

// Skip non-retroactive conformances.
if (!containsRetroactiveConformance(conformance.getConcrete(), fromModule))
if (!containsRetroactiveConformance(conformance))
continue;

appendConcreteProtocolConformance(conformance.getConcrete(), sig);
if (conformance.isConcrete())
appendConcreteProtocolConformance(conformance.getConcrete(), sig);
else
appendPackProtocolConformance(conformance.getPack(), sig);

appendOperator("g", Index(numProtocolRequirements));
}
}
Expand All @@ -1954,7 +1981,7 @@ void ASTMangler::appendRetroactiveConformances(Type type, GenericSignature sig)
subMap = type->getContextSubstitutionMap(module, nominal);
}

appendRetroactiveConformances(subMap, sig, module);
appendRetroactiveConformances(subMap, sig);
}

void ASTMangler::appendSymbolicExtendedExistentialType(
Expand All @@ -1977,11 +2004,7 @@ void ASTMangler::appendSymbolicExtendedExistentialType(
for (auto argType : genInfo.Generalization.getReplacementTypes())
appendType(argType, sig, forDecl);

// What module should be used here? The existential isn't anchored
// to any given module; we should just treat conformances as
// retroactive if they're "objectively" retroactive.
appendRetroactiveConformances(genInfo.Generalization, sig,
/*from module*/ nullptr);
appendRetroactiveConformances(genInfo.Generalization, sig);
}

appendOperator("Xj");
Expand Down Expand Up @@ -2172,7 +2195,7 @@ void ASTMangler::appendImplFunctionType(SILFunctionType *fn,
}
if (auto subs = fn->getInvocationSubstitutions()) {
appendFlatGenericArgs(subs, sig, forDecl);
appendRetroactiveConformances(subs, sig, Mod);
appendRetroactiveConformances(subs, sig);
}
if (auto subs = fn->getPatternSubstitutions()) {
appendGenericSignature(subs.getGenericSignature());
Expand All @@ -2181,7 +2204,7 @@ void ASTMangler::appendImplFunctionType(SILFunctionType *fn,
? fn->getInvocationGenericSignature()
: outerGenericSig;
appendFlatGenericArgs(subs, sig, forDecl);
appendRetroactiveConformances(subs, sig, Mod);
appendRetroactiveConformances(subs, sig);
}

OpArgs.push_back('_');
Expand Down Expand Up @@ -2217,7 +2240,7 @@ void ASTMangler::appendOpaqueTypeArchetype(ArchetypeType *archetype,
appendOpaqueDeclName(opaqueDecl);
bool isFirstArgList = true;
appendBoundGenericArgs(opaqueDecl, sig, subs, isFirstArgList, forDecl);
appendRetroactiveConformances(subs, sig, opaqueDecl->getParentModule());
appendRetroactiveConformances(subs, sig);

appendOperator("Qo", Index(genericParam->getIndex()));
} else {
Expand Down Expand Up @@ -4143,62 +4166,73 @@ void ASTMangler::appendAnyProtocolConformance(
appendDependentProtocolConformance(conformancePath, opaqueSignature);
appendType(conformingType, genericSig);
appendOperator("HO");
} else {
} else if (conformance.isConcrete()) {
appendConcreteProtocolConformance(conformance.getConcrete(), genericSig);
} else if (conformance.isPack()) {
appendPackProtocolConformance(conformance.getPack(), genericSig);
} else {
llvm::errs() << "Bad conformance in mangler: ";
conformance.dump(llvm::errs());
abort();
}
}

void ASTMangler::appendConcreteProtocolConformance(
const ProtocolConformance *conformance,
GenericSignature sig) {
auto module = conformance->getDeclContext()->getParentModule();

// Conforming type.
Type conformingType = conformance->getType();
if (conformingType->hasArchetype())
conformingType = conformingType->mapTypeOutOfContext();
appendType(conformingType->getCanonicalType(), sig);
appendType(conformingType->getReducedType(sig), sig);

// Protocol conformance reference.
appendProtocolConformanceRef(conformance->getRootConformance());

// Conditional conformance requirements.
bool firstRequirement = true;
for (const auto &conditionalReq : conformance->getConditionalRequirements()) {
switch (conditionalReq.getKind()) {
case RequirementKind::SameShape:
llvm_unreachable("Same-shape requirement not supported here");
case RequirementKind::Layout:
case RequirementKind::SameType:
case RequirementKind::Superclass:
continue;

case RequirementKind::Conformance: {
auto type = conditionalReq.getFirstType();
if (type->hasArchetype())
type = type->mapTypeOutOfContext();
CanType canType = type->getReducedType(sig);
auto proto = conditionalReq.getProtocolDecl();

ProtocolConformanceRef conformance;

if (canType->isTypeParameter() || canType->is<OpaqueTypeArchetypeType>()){
conformance = ProtocolConformanceRef(proto);
} else {
conformance = module->lookupConformance(canType, proto);
}
appendAnyProtocolConformance(sig, canType, conformance);
forEachConditionalConformance(conformance,
[&](Type substType, ProtocolConformanceRef substConf) -> bool {
if (substType->hasArchetype())
substType = substType->mapTypeOutOfContext();
CanType canType = substType->getReducedType(sig);
appendAnyProtocolConformance(sig, canType, substConf);
appendListSeparator(firstRequirement);
break;
}
}
}
return false;
});

if (firstRequirement)
appendOperator("y");

appendOperator("HC");
}

void ASTMangler::appendPackProtocolConformance(
const PackConformance *conformance,
GenericSignature sig) {
auto conformingType = conformance->getType();
auto patternConformances = conformance->getPatternConformances();
assert(conformingType->getNumElements() == patternConformances.size());

if (conformingType->getNumElements() == 0) {
appendOperator("y");
} else {
bool firstField = true;
for (unsigned i = 0, e = conformingType->getNumElements(); i < e; ++i) {
auto type = conformingType->getElementType(i);
auto conf = patternConformances[i];

if (auto *expansionTy = type->getAs<PackExpansionType>())
type = expansionTy->getPatternType();

appendAnyProtocolConformance(sig, type->getCanonicalType(), conf);
appendListSeparator(firstField);
}
}

appendOperator("HX");
}

void ASTMangler::appendOpParamForLayoutConstraint(LayoutConstraint layout) {
assert(layout);
switch (layout->getKind()) {
Expand Down
24 changes: 2 additions & 22 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4455,11 +4455,8 @@ case TypeKind::Id:
auto sig = opaque->getDecl()->getGenericSignature();
auto newSubMap =
SubstitutionMap::get(sig,
[&](SubstitutableType *t) -> Type {
auto index = sig->getGenericParamOrdinal(cast<GenericTypeParamType>(t));
return newSubs[index];
},
LookUpConformanceInModule(opaque->getDecl()->getModuleContext()));
QueryReplacementTypeArray{sig, newSubs},
LookUpConformanceInModule(opaque->getDecl()->getModuleContext()));
return OpaqueTypeArchetypeType::get(opaque->getDecl(),
opaque->getInterfaceType(),
newSubMap);
Expand Down Expand Up @@ -5354,23 +5351,6 @@ Type TypeBase::openAnyExistentialType(OpenedArchetypeType *&opened,
return opened;
}

CanType swift::substOpaqueTypesWithUnderlyingTypes(CanType ty,
TypeExpansionContext context,
bool allowLoweredTypes) {
if (!context.shouldLookThroughOpaqueTypeArchetypes() ||
!ty->hasOpaqueArchetype())
return ty;

ReplaceOpaqueTypesWithUnderlyingTypes replacer(
context.getContext(), context.getResilienceExpansion(),
context.isWholeModuleContext());
SubstOptions flags = SubstFlags::SubstituteOpaqueArchetypes;
if (allowLoweredTypes)
flags =
SubstFlags::SubstituteOpaqueArchetypes | SubstFlags::AllowLoweredTypes;
return ty.subst(replacer, replacer, flags)->getCanonicalType();
}

AnyFunctionType *AnyFunctionType::getWithoutDifferentiability() const {
SmallVector<Param, 8> newParams;
for (auto &param : getParams()) {
Expand Down
Loading