Skip to content

Commit a07d9eb

Browse files
committed
Mangling: handle inverse requirements
1 parent 19a5bb0 commit a07d9eb

21 files changed

+1049
-116
lines changed

docs/ABI/Mangling.rst

Lines changed: 98 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -467,8 +467,92 @@ An ``extension`` mangling is used whenever an entity's declaration context is
467467
an extension *and* the entity being extended is in a different module. In this
468468
case the extension's module is mangled first, followed by the entity being
469469
extended. If the extension and the extended entity are in the same module, the
470-
plain ``entity`` mangling is preferred. If the extension is constrained, the
471-
constraints on the extension are mangled in its generic signature.
470+
plain ``entity`` mangling is preferred, but not always used. An extension is
471+
considered "constrained" if it:
472+
473+
- Has any requirements not already satisfied by the extended nominal,
474+
excluding conformance requirements for invertible protocols.
475+
- Has any generic parameters with an inverse requirement.
476+
477+
Those requirements included in any of the above are included in the extension's
478+
generic signature. The reason for this additional complexity is that we do not
479+
mangle conformance req's for invertible protocols, only their absence.
480+
481+
::
482+
483+
struct S<A: ~Copyable, B: ~Copyable> {}
484+
485+
// An unconstrained extension.
486+
extension S {}
487+
488+
// Also an unconstrained extension, because there are no inverses to mangle.
489+
// This extension is exactly the same as the previous.
490+
extension S where A: Copyable, B: Copyable {}
491+
492+
// A constrained extension, because of the added requirement `B: P` that is
493+
// not already present in S.
494+
extension S where B: P {}
495+
496+
// A constrained extension, because of the absence of `A: Copyable`.
497+
// Despite also being absent in `S`, absences of invertible protocols
498+
// are always mangled.
499+
extension S where A: ~Copyable {}
500+
501+
Some entities, like computed properties, rely on the generic signature in their
502+
`context`, so in order to disambiguate between those properties and
503+
those in a context where a generic type requires Copyable, which is not mangled,
504+
we have the following rule:
505+
506+
If the innermost type declaration for an entity has any inverses in its generic
507+
signature, then extension mangling is used. This strategy is used to ensure
508+
that moving a declaration between a nominal type and one of its extensions does
509+
not cause an ABI break if the generic signature of the entity is equivalent in
510+
both circumstances. For example:
511+
512+
::
513+
514+
struct R<A: ~Copyable> {
515+
func f1() {} // uses extension mangling, just like `f3`
516+
517+
func f2() where A: Copyable {}
518+
}
519+
520+
extension R where A: ~Copyable {
521+
func f3() {}
522+
523+
func f4() where A: Copyable {} // uses entity mangling, just like `f2`
524+
}
525+
526+
extension R where A: Copyable {
527+
// 'f5' is mangled equivalent to 'f2' and 'f4' modulo its identifier.
528+
func f5() {}
529+
}
530+
531+
For intermediate nested types, i.e., those between the top level and the entity,
532+
any inverses that remain in at the signature of the entity are mangled into
533+
that entity's generic signature:
534+
535+
::
536+
537+
struct X<A: ~Copyable> {
538+
struct Y<B: ~Copyable> {
539+
// 'g1' uses 'entity' context mangling with and has no mangled signatures.
540+
func g1() where A: Copyable, B: Copyable {}
541+
542+
// 'g2' uses 'entity' context mangling. The requirement `B: ~Copyable` is
543+
//mangled into the generic signature for 'g2'.
544+
func g2() where A: Copyable {}
545+
546+
// 'g3' uses extension mangling with generic signature 'A: ~Copyable'.
547+
// The mangled generic signature of 'g3' is empty.
548+
func g3() where B: Copyable {}
549+
550+
// 'g4' uses extension mangling with generic signature 'A: ~Copyable'.
551+
// The mangled generic signature of 'g4' contains 'B: ~Copyable'.
552+
func g4() {}
553+
}
554+
}
555+
472556

473557
When mangling the context of a local entity within a constructor or
474558
destructor, the non-allocating or non-deallocating variant is used.
@@ -680,12 +764,14 @@ Types
680764
METATYPE-REPR ::= 'T' // Thick metatype representation
681765
METATYPE-REPR ::= 'o' // ObjC metatype representation
682766

767+
existential-layout ::= protocol-list 'p' // existential layout
768+
existential-layout ::= protocol-list superclass 'Xc' // existential layout with superclass
769+
existential-layout ::= protocol-list 'Xl' // existential layout with AnyObject
770+
683771
type ::= associated-type
684772
type ::= any-generic-type
685-
type ::= protocol-list 'p' // existential type
686-
type ::= protocol-list superclass 'Xc' // existential type with superclass
687-
type ::= protocol-list 'Xl' // existential type with AnyObject
688-
type ::= protocol-list requirement* '_' 'XP' // constrained existential type
773+
type ::= existential-layout // existential type
774+
type ::= existential-layout requirement '_' requirement* 'XP' // constrained existential type
689775
type ::= type-list 't' // tuple
690776
type ::= type generic-signature 'u' // generic type
691777
type ::= 'x' // generic param, depth=0, idx=0
@@ -925,13 +1011,19 @@ now codified into the ABI; the index 0 is therefore reserved.
9251011

9261012
generic-param-pack-marker ::= 'Rv' GENERIC_PARAM-INDEX // generic parameter pack marker
9271013

1014+
INVERTIBLE-KIND ::= 'c' // Copyable
1015+
INVERTIBLE-KIND ::= 'e' // Escapable
1016+
9281017
GENERIC-PARAM-COUNT ::= 'z' // zero parameters
9291018
GENERIC-PARAM-COUNT ::= INDEX // N+1 parameters
9301019

9311020
requirement ::= protocol 'R' GENERIC-PARAM-INDEX // protocol requirement
9321021
requirement ::= protocol assoc-type-name 'Rp' GENERIC-PARAM-INDEX // protocol requirement on associated type
9331022
requirement ::= protocol assoc-type-list 'RP' GENERIC-PARAM-INDEX // protocol requirement on associated type at depth
9341023
requirement ::= protocol substitution 'RQ' // protocol requirement with substitution
1024+
#if SWIFT_RUNTIME_VERSION >= 6.0
1025+
requirement ::= 'Ri' INVERTIBLE-KIND GENERIC-PARAM-INDEX // inverse requirement
1026+
#endif
9351027
requirement ::= type 'Rb' GENERIC-PARAM-INDEX // base class requirement
9361028
requirement ::= type assoc-type-name 'Rc' GENERIC-PARAM-INDEX // base class requirement on associated type
9371029
requirement ::= type assoc-type-list 'RC' GENERIC-PARAM-INDEX // base class requirement on associated type at depth

include/swift/AST/ASTMangler.h

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,18 @@ class ASTMangler : public Mangler {
7272
/// If enabled, marker protocols can be encoded in the mangled name.
7373
bool AllowMarkerProtocols = true;
7474

75+
/// If enabled, inverses will not be mangled into generic signatures.
76+
bool AllowInverses = true;
77+
7578
/// If enabled, declarations annotated with @_originallyDefinedIn are mangled
7679
/// as if they're part of their original module. Disabled for debug mangling,
7780
/// because lldb wants to find declarations in the modules they're currently
7881
/// defined in.
7982
bool RespectOriginallyDefinedIn = true;
8083

84+
// Represents the innermost context of the entity whose context was appended.
85+
const DeclContext *baseContext = nullptr;
86+
8187
public:
8288
class SymbolicReferent {
8389
public:
@@ -392,6 +398,8 @@ class ASTMangler : public Mangler {
392398

393399
protected:
394400

401+
void beginManglingWithoutPrefix();
402+
395403
void appendSymbolKind(SymbolKind SKind);
396404

397405
void appendType(Type type, GenericSignature sig,
@@ -451,11 +459,16 @@ class ASTMangler : public Mangler {
451459
const ValueDecl *forDecl);
452460

453461
void appendContextOf(const ValueDecl *decl);
462+
void appendContextualInverses(GenericSignature contextSig,
463+
const ModuleDecl *module,
464+
StringRef useModuleName);
454465

455466
void appendContext(const DeclContext *ctx, StringRef useModuleName);
456467

457468
void appendModule(const ModuleDecl *module, StringRef useModuleName);
458469

470+
void appendExtension(const ExtensionDecl *ext, StringRef useModuleName);
471+
459472
void appendProtocolName(const ProtocolDecl *protocol,
460473
bool allowStandardSubstitution = true);
461474

@@ -503,6 +516,16 @@ class ASTMangler : public Mangler {
503516
GenericSignature sig,
504517
const ValueDecl *forDecl = nullptr);
505518

519+
struct GenericSignatureParts {
520+
ArrayRef<CanGenericTypeParamType> params;
521+
unsigned initialParamDepth = 0;
522+
SmallVector<Requirement, 2> requirements;
523+
SmallVector<InverseRequirement, 2> inverses;
524+
bool isNull() const; // Is there anything to mangle?
525+
bool hasRequirements() const; // Are there any requirements to mangle?
526+
void clear();
527+
};
528+
506529
/// Append a generic signature to the mangling.
507530
///
508531
/// \param sig The generic signature.
@@ -527,10 +550,23 @@ class ASTMangler : public Mangler {
527550
void appendRequirement(const Requirement &reqt, GenericSignature sig,
528551
bool lhsBaseIsProtocolSelf = false);
529552

553+
/// Append an inverse requirement into the mangling.
554+
///
555+
/// Instead of mangling the presence of an invertible protocol, we mangle
556+
/// their absence, which is what an inverse represents.
557+
///
558+
/// \param req The inverse requirement to mangle.
559+
void appendInverseRequirement(const InverseRequirement &req,
560+
GenericSignature sig,
561+
bool lhsBaseIsProtocolSelf = false);
562+
563+
void gatherGenericSignatureParts(GenericSignature sig,
564+
GenericSignature contextSig,
565+
GenericSignatureParts &parts,
566+
bool forExtension = false);
567+
530568
void appendGenericSignatureParts(GenericSignature sig,
531-
ArrayRef<CanTypeWrapper<GenericTypeParamType>> params,
532-
unsigned initialParamDepth,
533-
ArrayRef<Requirement> requirements);
569+
GenericSignatureParts const& parts);
534570

535571
DependentMemberType *dropProtocolFromAssociatedType(DependentMemberType *dmt,
536572
GenericSignature sig);

include/swift/AST/Decl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1856,6 +1856,10 @@ class ExtensionDecl final : public GenericContext, public Decl,
18561856
/// resiliently moved into the original protocol itself.
18571857
bool isEquivalentToExtendedContext() const;
18581858

1859+
/// Determine whether this extension context is in the same defining module as
1860+
/// the original nominal type context.
1861+
bool isInSameDefiningModule() const;
1862+
18591863
/// Returns the name of the category specified by the \c \@_objcImplementation
18601864
/// attribute, or \c None if the name is invalid or
18611865
/// \c isObjCImplementation() is false.

include/swift/AST/DeclAttr.def

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,10 @@ DECL_ATTR(_distributedThunkTarget, DistributedThunkTarget,
491491
DECL_ATTR(_allowFeatureSuppression, AllowFeatureSuppression,
492492
OnAnyDecl | UserInaccessible | NotSerialized | ABIStableToAdd | APIStableToAdd | ABIStableToRemove | APIStableToRemove,
493493
157)
494-
LAST_DECL_ATTR(AllowFeatureSuppression)
494+
SIMPLE_DECL_ATTR(_preInverseGenerics, PreInverseGenerics,
495+
OnAbstractFunction | OnSubscript | OnVar | UserInaccessible | ABIBreakingToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove,
496+
158)
497+
LAST_DECL_ATTR(PreInverseGenerics)
495498

496499
#undef DECL_ATTR_ALIAS
497500
#undef CONTEXTUAL_DECL_ATTR_ALIAS

include/swift/AST/Requirement.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,11 @@ class Requirement {
145145
llvm_unreachable("Unhandled RequirementKind in switch");
146146
}
147147

148+
friend bool operator!=(const Requirement &lhs,
149+
const Requirement &rhs) {
150+
return !(lhs == rhs);
151+
}
152+
148153
/// Whether this requirement's types contain ErrorTypes.
149154
bool hasError() const;
150155

@@ -257,6 +262,9 @@ struct InverseRequirement {
257262

258263
InvertibleProtocolKind getKind() const;
259264

265+
/// Linear order on inverse requirements in a generic signature.
266+
int compare(const InverseRequirement &other) const;
267+
260268
/// Appends additional requirements corresponding to defaults for the given
261269
/// generic parameters.
262270
static void expandDefaults(ASTContext &ctx,

include/swift/AST/Types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6007,6 +6007,7 @@ class ProtocolCompositionType final : public TypeBase,
60076007
}
60086008

60096009
InvertibleProtocolSet getInverses() const { return Inverses; }
6010+
bool hasInverse() const { return !Inverses.empty(); }
60106011

60116012
void Profile(llvm::FoldingSetNodeID &ID) {
60126013
Profile(ID, getMembers(), getInverses(), hasExplicitAnyObject());

include/swift/Demangling/DemangleNodes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,5 +393,7 @@ NODE(OutlinedAssignWithTakeNoValueWitness)
393393
NODE(OutlinedAssignWithCopyNoValueWitness)
394394
NODE(OutlinedDestroyNoValueWitness)
395395

396+
NODE(DependentGenericInverseConformanceRequirement)
397+
396398
#undef CONTEXT_NODE
397399
#undef NODE

include/swift/Demangling/TypeDecoder.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,8 +448,14 @@ void decodeRequirement(NodePointer node,
448448
child->getChild(1), /*forRequirement=*/false);
449449
if (!constraintType)
450450
return;
451+
} else if (child->getKind() ==
452+
Demangle::Node::Kind::DependentGenericInverseConformanceRequirement) {
453+
// FIXME(kavon): this is unimplemented! We should build a PCT here with
454+
// the inverse in it.
455+
return;
451456
}
452457

458+
453459
switch (child->getKind()) {
454460
case Demangle::Node::Kind::DependentGenericConformanceRequirement: {
455461
requirements.push_back(BuiltRequirement(

0 commit comments

Comments
 (0)