Skip to content

Commit b994bf3

Browse files
committed
Add support for _specialize(exported: true, ...)
This attribute allows to define a pre-specialized entry point of a generic function in a library. The following definition provides a pre-specialized entry point for `genericFunc(_:)` for the parameter type `Int` that clients of the library can call. ``` @_specialize(exported: true, where T == Int) public func genericFunc<T>(_ t: T) { ... } ``` Pre-specializations of internal `@inlinable` functions are allowed. ``` @usableFromInline internal struct GenericThing<T> { @_specialize(exported: true, where T == Int) @inlinable internal func genericMethod(_ t: T) { } } ``` There is syntax to pre-specialize a method from a different module. ``` import ModuleDefiningGenericFunc @_specialize(exported: true, target: genericFunc(_:), where T == Double) func prespecialize_genericFunc(_ t: T) { fatalError("dont call") } ``` Specially marked extensions allow for pre-specialization of internal methods accross module boundries (respecting `@inlinable` and `@usableFromInline`). ``` import ModuleDefiningGenericThing public struct Something {} @_specializeExtension extension GenericThing { @_specialize(exported: true, target: genericMethod(_:), where T == Something) func prespecialize_genericMethod(_ t: T) { fatalError("dont call") } } ``` rdar://64993425
1 parent be38df8 commit b994bf3

File tree

85 files changed

+1978
-332
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+1978
-332
lines changed

docs/ABI/Mangling.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -995,6 +995,7 @@ Function Specializations
995995
::
996996

997997
specialization ::= type '_' type* 'Tg' SPEC-INFO // Generic re-abstracted specialization
998+
specialization ::= type '_' type* 'Ts' SPEC-INFO // Generic re-abstracted prespecialization
998999
specialization ::= type '_' type* 'TG' SPEC-INFO // Generic not re-abstracted specialization
9991000
specialization ::= type '_' type* 'Ti' SPEC-INFO // Inlined function with generic substitutions.
10001001

include/swift/AST/Attr.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,11 @@ SIMPLE_DECL_ATTR(globalActor, GlobalActor,
584584
APIStableToAdd | APIBreakingToRemove,
585585
104)
586586

587+
SIMPLE_DECL_ATTR(_specializeExtension, SpecializeExtension,
588+
OnExtension | UserInaccessible |
589+
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
590+
105)
591+
587592
#undef TYPE_ATTR
588593
#undef DECL_ATTR_ALIAS
589594
#undef CONTEXTUAL_DECL_ATTR_ALIAS

include/swift/AST/Attr.h

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1409,6 +1409,8 @@ class SynthesizedProtocolAttr : public DeclAttribute {
14091409
/// The @_specialize attribute, which forces specialization on the specified
14101410
/// type list.
14111411
class SpecializeAttr : public DeclAttribute {
1412+
friend class SpecializeAttrTargetDeclRequest;
1413+
14121414
public:
14131415
// NOTE: When adding new kinds, you must update the inline bitfield macro.
14141416
enum class SpecializationKind {
@@ -1420,18 +1422,35 @@ class SpecializeAttr : public DeclAttribute {
14201422
TrailingWhereClause *trailingWhereClause;
14211423
GenericSignature specializedSignature;
14221424

1425+
DeclNameRef targetFunctionName;
1426+
LazyMemberLoader *resolver = nullptr;
1427+
uint64_t resolverContextData;
1428+
14231429
SpecializeAttr(SourceLoc atLoc, SourceRange Range,
14241430
TrailingWhereClause *clause, bool exported,
14251431
SpecializationKind kind,
1426-
GenericSignature specializedSignature);
1432+
GenericSignature specializedSignature,
1433+
DeclNameRef targetFunctionName);
14271434

14281435
public:
14291436
static SpecializeAttr *create(ASTContext &Ctx, SourceLoc atLoc,
14301437
SourceRange Range, TrailingWhereClause *clause,
14311438
bool exported, SpecializationKind kind,
1439+
DeclNameRef targetFunctionName,
14321440
GenericSignature specializedSignature
14331441
= nullptr);
14341442

1443+
static SpecializeAttr *create(ASTContext &ctx, bool exported,
1444+
SpecializationKind kind,
1445+
GenericSignature specializedSignature,
1446+
DeclNameRef replacedFunction);
1447+
1448+
static SpecializeAttr *create(ASTContext &ctx, bool exported,
1449+
SpecializationKind kind,
1450+
GenericSignature specializedSignature,
1451+
DeclNameRef replacedFunction,
1452+
LazyMemberLoader *resolver, uint64_t data);
1453+
14351454
TrailingWhereClause *getTrailingWhereClause() const;
14361455

14371456
GenericSignature getSpecializedSignature() const {
@@ -1458,6 +1477,13 @@ class SpecializeAttr : public DeclAttribute {
14581477
return getSpecializationKind() == SpecializationKind::Partial;
14591478
}
14601479

1480+
DeclNameRef getTargetFunctionName() const {
1481+
return targetFunctionName;
1482+
}
1483+
1484+
/// \p forDecl is the value decl that the attribute belongs to.
1485+
ValueDecl *getTargetFunctionDecl(const ValueDecl *forDecl) const;
1486+
14611487
static bool classof(const DeclAttribute *DA) {
14621488
return DA->getKind() == DAK_Specialize;
14631489
}

include/swift/AST/Decl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2187,7 +2187,8 @@ class ValueDecl : public Decl {
21872187
/// implementations for the requirements of a public protocol, even when
21882188
/// the default implementations are not visible to name lookup.
21892189
bool isAccessibleFrom(const DeclContext *DC,
2190-
bool forConformance = false) const;
2190+
bool forConformance = false,
2191+
bool includeInlineable = false) const;
21912192

21922193
/// Returns whether this declaration should be treated as \c open from
21932194
/// \p useDC. This is very similar to #getFormalAccess, but takes

include/swift/AST/DeclContext.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,10 @@ class alignas(1 << DeclContextAlignInBits) DeclContext {
490490
/// Determine whether the innermost context is generic.
491491
bool isInnermostContextGeneric() const;
492492

493+
/// Determine whether this or any parent context is a `@_specialize` extension
494+
/// context.
495+
bool isInSpecializeExtensionContext() const;
496+
493497
/// Get the most optimal resilience expansion for code in this context.
494498
/// If the body is able to be inlined into functions in other resilience
495499
/// domains, this ensures that only sufficiently-conservative access patterns

include/swift/AST/DiagnosticsParse.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,8 @@ ERROR(expected_sil_function_type, none,
626626
"sil function expected to have SIL function type", ())
627627
ERROR(sil_dynamically_replaced_func_not_found,none,
628628
"dynamically replaced function not found %0", (Identifier))
629+
ERROR(sil_specialize_target_func_not_found,none,
630+
"_specialize target function not found %0", (Identifier))
629631
ERROR(sil_availability_expected_version,none,
630632
"expected version number in 'available' attribute", ())
631633

@@ -1579,6 +1581,8 @@ ERROR(attr_specialize_parameter_already_defined,none,
15791581

15801582
ERROR(attr_specialize_expected_partial_or_full,none,
15811583
"expected 'partial' or 'full' as values of the 'kind' parameter in '_specialize' attribute", ())
1584+
ERROR(attr_specialize_expected_function,none,
1585+
"expected a function name as the value of the 'target' parameter in '_specialize' attribute", ())
15821586

15831587
// _implements
15841588
ERROR(attr_implements_expected_member_name,PointsToFirstBadToken,

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5113,6 +5113,12 @@ ERROR(specialize_attr_missing_constraint,none,
51135113
"Missing constraint for %0 in '_specialize' attribute", (DeclName))
51145114
ERROR(specialize_attr_unsupported_kind_of_req,none,
51155115
"Only same-type and layout requirements are supported by '_specialize' attribute", ())
5116+
ERROR(specialize_target_function_not_found, none,
5117+
"target function %0 could not be found", (DeclNameRef))
5118+
ERROR(specialize_target_function_of_type_not_found, none,
5119+
"target function %0 of type %1 could not be found", (DeclNameRef, Type))
5120+
NOTE(specialize_found_function_of_type, none,
5121+
"found function %0 of type %1", (DeclName, Type))
51165122

51175123
//------------------------------------------------------------------------------
51185124
// MARK: Variable usage diagnostics

include/swift/AST/LazyResolver.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ class alignas(void*) LazyMemberLoader {
114114
/// Returns the type for a given @_typeEraser() attribute.
115115
virtual Type loadTypeEraserType(const TypeEraserAttr *TRA,
116116
uint64_t contextData) = 0;
117+
118+
// Returns the target parameter of the `@_specialize` attribute or null.
119+
virtual ValueDecl *loadTargetFunctionDecl(const SpecializeAttr *attr,
120+
uint64_t contextData) = 0;
117121
};
118122

119123
/// A class that can lazily load conformances from a serialized format.

include/swift/AST/LookupKinds.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ enum NLOptions : unsigned {
5050
/// Include synonyms declared with @_implements()
5151
NL_IncludeAttributeImplements = 1 << 5,
5252

53+
// Include @usableFromInline and @inlinable
54+
NL_IncludeUsableFromInlineAndInlineable = 1 << 6,
55+
5356
/// The default set of options used for qualified name lookup.
5457
///
5558
/// FIXME: Eventually, add NL_ProtocolMembers to this, once all of the

include/swift/AST/ModuleNameLookup.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,13 @@ void simple_display(llvm::raw_ostream &out, ResolutionKind kind);
5656
/// \param moduleScopeContext The top-level context from which the lookup is
5757
/// being performed, for checking access. This must be either a
5858
/// FileUnit or a Module.
59+
/// \param options name lookup options. Currently only used to communicate the
60+
/// NL_IncludeUsableFromInlineAndInlineable option.
5961
void lookupInModule(const DeclContext *moduleOrFile,
6062
DeclName name, SmallVectorImpl<ValueDecl *> &decls,
6163
NLKind lookupKind, ResolutionKind resolutionKind,
62-
const DeclContext *moduleScopeContext);
64+
const DeclContext *moduleScopeContext,
65+
NLOptions options);
6366

6467
/// Performs a qualified lookup into the given module and, if necessary, its
6568
/// reexports, observing proper shadowing rules.

0 commit comments

Comments
 (0)