Skip to content

Commit e2d33ec

Browse files
authored
Merge pull request #71878 from kavon/ncgenerics-mangling-2
NCGenerics: New Inverse Mangling 3DS XL
2 parents fd9ae4c + 2a1cf37 commit e2d33ec

29 files changed

+1367
-195
lines changed

docs/ABI/Mangling.rst

+98-6
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

+89-11
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,8 @@ class ASTMangler : public Mangler {
7272
/// If enabled, marker protocols can be encoded in the mangled name.
7373
bool AllowMarkerProtocols = true;
7474

75-
/// Whether the mangling predates concurrency, and therefore shouldn't
76-
/// include concurrency features such as global actors or @Sendable
77-
/// function types.
78-
bool Preconcurrency = false;
75+
/// If enabled, inverses will not be mangled into generic signatures.
76+
bool AllowInverses = true;
7977

8078
/// If enabled, declarations annotated with @_originallyDefinedIn are mangled
8179
/// as if they're part of their original module. Disabled for debug mangling,
@@ -455,16 +453,54 @@ class ASTMangler : public Mangler {
455453
GenericSignature sig,
456454
const ValueDecl *forDecl);
457455

458-
void appendContextOf(const ValueDecl *decl);
456+
// A "base entity" is a function, property, subscript, or any other
457+
// declaration that can appear in an extension.
458+
struct BaseEntitySignature {
459+
private:
460+
GenericSignature sig;
461+
bool innermostTypeDecl;
462+
bool extension;
463+
std::optional<unsigned> mangledDepth; // for inverses
464+
public:
465+
bool reachedInnermostTypeDecl() {
466+
bool answer = innermostTypeDecl;
467+
innermostTypeDecl = false;
468+
return answer;
469+
}
470+
bool reachedExtension() const { return extension; }
471+
void setReachedExtension() { assert(!extension); extension = true; }
472+
GenericSignature getSignature() const { return sig; }
473+
// The depth of the inverses mangled so far.
474+
std::optional<unsigned> getDepth() const { return mangledDepth; }
475+
void setDepth(unsigned depth) {
476+
assert(!mangledDepth || *mangledDepth <= depth);
477+
mangledDepth = depth;
478+
}
479+
BaseEntitySignature(const Decl *decl);
480+
};
481+
482+
void appendContextOf(const ValueDecl *decl, BaseEntitySignature &base);
483+
void appendContextualInverses(const GenericTypeDecl *contextDecl,
484+
BaseEntitySignature &base,
485+
const ModuleDecl *module,
486+
StringRef useModuleName);
459487

460-
void appendContext(const DeclContext *ctx, StringRef useModuleName);
488+
void appendContext(const DeclContext *ctx,
489+
BaseEntitySignature &base,
490+
StringRef useModuleName);
461491

462492
void appendModule(const ModuleDecl *module, StringRef useModuleName);
463493

494+
void appendExtension(const ExtensionDecl *ext,
495+
BaseEntitySignature &base,
496+
StringRef useModuleName);
497+
464498
void appendProtocolName(const ProtocolDecl *protocol,
465499
bool allowStandardSubstitution = true);
466500

467501
void appendAnyGenericType(const GenericTypeDecl *decl);
502+
void appendAnyGenericType(const GenericTypeDecl *decl,
503+
BaseEntitySignature &base);
468504

469505
enum FunctionManglingKind {
470506
NoFunctionMangling,
@@ -508,17 +544,42 @@ class ASTMangler : public Mangler {
508544
GenericSignature sig,
509545
const ValueDecl *forDecl = nullptr);
510546

547+
struct GenericSignatureParts {
548+
ArrayRef<CanGenericTypeParamType> params;
549+
unsigned initialParamDepth = 0;
550+
SmallVector<Requirement, 2> requirements;
551+
SmallVector<InverseRequirement, 2> inverses;
552+
bool isNull() const; // Is there anything to mangle?
553+
bool hasRequirements() const; // Are there any requirements to mangle?
554+
void clear();
555+
};
556+
557+
/// Append a generic signature to the mangling.
558+
///
559+
/// \param sig The generic signature.
560+
///
561+
/// \returns \c true if a generic signature was appended, \c false
562+
/// if it was empty.
563+
bool appendGenericSignature(GenericSignature sig);
564+
511565
/// Append a generic signature to the mangling.
512566
///
513567
/// \param sig The generic signature.
514568
///
515569
/// \param contextSig The signature of the known context. This function
516570
/// will only mangle the difference between \c sig and \c contextSig.
517571
///
572+
/// \param base The signature of the base entity whose generic signature we're
573+
/// mangling. This function will only mangle the inverses on generic
574+
/// parameter in \c sig that are not eliminated by conformance requirements in
575+
/// \c base.
576+
///
577+
///
518578
/// \returns \c true if a generic signature was appended, \c false
519579
/// if it was empty.
520580
bool appendGenericSignature(GenericSignature sig,
521-
GenericSignature contextSig = nullptr);
581+
GenericSignature contextSig,
582+
BaseEntitySignature &base);
522583

523584
/// Append a requirement to the mangling.
524585
///
@@ -532,10 +593,23 @@ class ASTMangler : public Mangler {
532593
void appendRequirement(const Requirement &reqt, GenericSignature sig,
533594
bool lhsBaseIsProtocolSelf = false);
534595

596+
/// Append an inverse requirement into the mangling.
597+
///
598+
/// Instead of mangling the presence of an invertible protocol, we mangle
599+
/// their absence, which is what an inverse represents.
600+
///
601+
/// \param req The inverse requirement to mangle.
602+
void appendInverseRequirement(const InverseRequirement &req,
603+
GenericSignature sig,
604+
bool lhsBaseIsProtocolSelf = false);
605+
606+
void gatherGenericSignatureParts(GenericSignature sig,
607+
GenericSignature contextSig,
608+
BaseEntitySignature &base,
609+
GenericSignatureParts &parts);
610+
535611
void appendGenericSignatureParts(GenericSignature sig,
536-
ArrayRef<CanTypeWrapper<GenericTypeParamType>> params,
537-
unsigned initialParamDepth,
538-
ArrayRef<Requirement> requirements);
612+
GenericSignatureParts const& parts);
539613

540614
DependentMemberType *dropProtocolFromAssociatedType(DependentMemberType *dmt,
541615
GenericSignature sig);
@@ -565,6 +639,7 @@ class ASTMangler : public Mangler {
565639

566640

567641
void appendDeclType(const ValueDecl *decl,
642+
BaseEntitySignature &base,
568643
FunctionManglingKind functionMangling = NoFunctionMangling);
569644

570645
bool tryAppendStandardSubstitution(const GenericTypeDecl *type);
@@ -580,7 +655,10 @@ class ASTMangler : public Mangler {
580655
void appendAccessorEntity(StringRef accessorKindCode,
581656
const AbstractStorageDecl *decl, bool isStatic);
582657

583-
void appendEntity(const ValueDecl *decl, StringRef EntityOp, bool isStatic);
658+
void appendEntity(const ValueDecl *decl,
659+
BaseEntitySignature &base,
660+
StringRef EntityOp,
661+
bool isStatic);
584662

585663
void appendEntity(const ValueDecl *decl);
586664

include/swift/AST/Decl.h

+4
Original file line numberDiff line numberDiff line change
@@ -1859,6 +1859,10 @@ class ExtensionDecl final : public GenericContext, public Decl,
18591859
/// resiliently moved into the original protocol itself.
18601860
bool isEquivalentToExtendedContext() const;
18611861

1862+
/// Determine whether this extension context is in the same defining module as
1863+
/// the original nominal type context.
1864+
bool isInSameDefiningModule() const;
1865+
18621866
/// Returns the name of the category specified by the \c \@_objcImplementation
18631867
/// attribute, or \c None if the name is invalid or
18641868
/// \c isObjCImplementation() is false.

include/swift/AST/DeclAttr.def

+4-1
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/GenericSignature.h

+5-5
Original file line numberDiff line numberDiff line change
@@ -560,11 +560,11 @@ void validateGenericSignaturesInModule(ModuleDecl *module);
560560
/// required to be minimal or canonical, and may contain unresolved
561561
/// DependentMemberTypes.
562562
///
563-
/// If \p baseSignature is non-null, the new parameters and requirements
564-
/// are added on; existing requirements of the base signature might become
565-
/// redundant.
566-
///
567-
/// If \p baseSignature is null, build a new signature from scratch.
563+
/// \param baseSignature if non-null, the new parameters and requirements
564+
///// are added on; existing requirements of the base signature might become
565+
///// redundant. Otherwise if null, build a new signature from scratch.
566+
/// \param allowInverses if true, default requirements to Copyable/Escapable are
567+
/// expanded for generic parameters.
568568
GenericSignature buildGenericSignature(
569569
ASTContext &ctx,
570570
GenericSignature baseSignature,

include/swift/AST/Requirement.h

+8
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

+1
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

+2
Original file line numberDiff line numberDiff line change
@@ -394,5 +394,7 @@ NODE(OutlinedAssignWithTakeNoValueWitness)
394394
NODE(OutlinedAssignWithCopyNoValueWitness)
395395
NODE(OutlinedDestroyNoValueWitness)
396396

397+
NODE(DependentGenericInverseConformanceRequirement)
398+
397399
#undef CONTEXT_NODE
398400
#undef NODE

include/swift/Demangling/TypeDecoder.h

+6
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)