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

@@ -53,7 +53,8 @@ public:
void lookupInModule(SmallVectorImpl<ValueDecl *> &decls,
const DeclContext *moduleOrFile,
ImportPath::Access accessPath,
const DeclContext *moduleScopeContext);
const DeclContext *moduleScopeContext,
NLOptions options);
};
@@ -124,7 +125,8 @@ void ModuleNameLookup<LookupStrategy>::lookupInModule(
SmallVectorImpl<ValueDecl *> &decls,
const DeclContext *moduleOrFile,
ImportPath::Access accessPath,
const DeclContext *moduleScopeContext) {
const DeclContext *moduleScopeContext,
NLOptions options) {
assert(moduleOrFile->isModuleScopeContext());
// Does the module scope have any separately-imported overlays shadowing
@@ -135,7 +137,7 @@ void ModuleNameLookup<LookupStrategy>::lookupInModule(
if (!overlays.empty()) {
// If so, look in each of those overlays.
for (auto overlay : overlays)
lookupInModule(decls, overlay, accessPath, moduleScopeContext);
lookupInModule(decls, overlay, accessPath, moduleScopeContext, options);
// FIXME: This may not work gracefully if more than one of these lookups
// finds something.
return;
@@ -143,6 +145,7 @@ void ModuleNameLookup<LookupStrategy>::lookupInModule(
const size_t initialCount = decls.size();
size_t currentCount = decls.size();
bool includeInlineable = options & NL_IncludeUsableFromInlineAndInlineable;
auto updateNewDecls = [&](const DeclContext *moduleScopeContext) {
if (decls.size() == currentCount)
@@ -153,7 +156,8 @@ void ModuleNameLookup<LookupStrategy>::lookupInModule(
[&](ValueDecl *VD) {
if (resolutionKind == ResolutionKind::TypesOnly && !isa<TypeDecl>(VD))
return true;
if (respectAccessControl && !VD->isAccessibleFrom(moduleScopeContext))
if (respectAccessControl &&
!VD->isAccessibleFrom(moduleScopeContext, false, includeInlineable))
return true;
return false;
});
@@ -247,13 +251,13 @@ QualifiedLookupResult
LookupInModuleRequest::evaluate(
Evaluator &evaluator, const DeclContext *moduleOrFile, DeclName name,
NLKind lookupKind, ResolutionKind resolutionKind,
const DeclContext *moduleScopeContext) const {
const DeclContext *moduleScopeContext, NLOptions options) const {
assert(moduleScopeContext->isModuleScopeContext());
QualifiedLookupResult decls;
LookupByName lookup(moduleOrFile->getASTContext(), resolutionKind,
name, lookupKind);
lookup.lookupInModule(decls, moduleOrFile, {}, moduleScopeContext);
lookup.lookupInModule(decls, moduleOrFile, {}, moduleScopeContext, options);
return decls;
}
@@ -262,10 +266,11 @@ void namelookup::lookupInModule(const DeclContext *moduleOrFile,
SmallVectorImpl<ValueDecl *> &decls,
NLKind lookupKind,
ResolutionKind resolutionKind,
const DeclContext *moduleScopeContext) {
const DeclContext *moduleScopeContext,
NLOptions options) {
auto &ctx = moduleOrFile->getASTContext();
LookupInModuleRequest req(moduleOrFile, name, lookupKind, resolutionKind,
moduleScopeContext);
moduleScopeContext, options);
auto results = evaluateOrDefault(ctx.evaluator, req, {});
decls.append(results.begin(), results.end());
}
@@ -280,7 +285,8 @@ void namelookup::lookupVisibleDeclsInModule(
assert(moduleScopeContext->isModuleScopeContext());
auto &ctx = moduleOrFile->getASTContext();
LookupVisibleDecls lookup(ctx, resolutionKind, lookupKind);
lookup.lookupInModule(decls, moduleOrFile, accessPath, moduleScopeContext);
lookup.lookupInModule(decls, moduleOrFile, accessPath, moduleScopeContext,
NL_QualifiedDefault);
}
void namelookup::simple_display(llvm::raw_ostream &out, ResolutionKind kind) {