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
This commit is contained in:
Arnold Schwaighofer
2020-09-18 13:56:21 -07:00
parent be38df8e3d
commit b994bf3191
85 changed files with 1978 additions and 332 deletions

View File

@@ -2362,13 +2362,30 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
case DAK_Specialize: {
auto abbrCode = S.DeclTypeAbbrCodes[SpecializeDeclAttrLayout::Code];
auto SA = cast<SpecializeAttr>(DA);
auto attr = cast<SpecializeAttr>(DA);
auto targetFun = attr->getTargetFunctionName();
auto *targetFunDecl = attr->getTargetFunctionDecl(cast<ValueDecl>(D));
SmallVector<IdentifierID, 4> pieces;
// encodes whether this a a simple or compound name by adding one.
size_t numArgs = 0;
if (targetFun) {
pieces.push_back(S.addDeclBaseNameRef(targetFun.getBaseName()));
for (auto argName : targetFun.getArgumentNames())
pieces.push_back(S.addDeclBaseNameRef(argName));
if (targetFun.isSimpleName()) {
assert(pieces.size() == 1);
numArgs = 1;
} else
numArgs = pieces.size() + 1;
}
SpecializeDeclAttrLayout::emitRecord(
S.Out, S.ScratchRecord, abbrCode,
(unsigned)SA->isExported(),
(unsigned)SA->getSpecializationKind(),
S.addGenericSignatureRef(SA->getSpecializedSignature()));
S.Out, S.ScratchRecord, abbrCode, (unsigned)attr->isExported(),
(unsigned)attr->getSpecializationKind(),
S.addGenericSignatureRef(attr->getSpecializedSignature()),
S.addDeclRef(targetFunDecl), numArgs,
pieces);
return;
}