Skip to content

Commit

Permalink
Merge pull request #22072 from jckarter/opaque-type-runtime
Browse files Browse the repository at this point in the history
Opaque types with resilience
  • Loading branch information
jckarter committed Apr 18, 2019
2 parents fa43e3b + b87a566 commit a8c2b50
Show file tree
Hide file tree
Showing 143 changed files with 4,467 additions and 545 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG.md
Expand Up @@ -44,6 +44,20 @@ Swift Next
Swift 5.1
---------

* [SE-0244][]:

Functions can now hide their concrete return type by declaring what protocols
it conforms to instead of specifying the exact return type:

```
func makeMeACollection() -> some Collection {
return [1, 2, 3]
}
```

Code that calls the function can use the interface of the protocol, but
does not have visibility into the underlying type.

* [SE-0256][]:

Subscripts can now be declared `static` or (inside classes) `class`.
Expand Down
36 changes: 33 additions & 3 deletions docs/ABI/Mangling.rst
Expand Up @@ -78,8 +78,13 @@ The following symbolic reference kinds are currently implemented:

::

{any-generic-type, protocol} ::= '\x01' .{4} // Reference points directly to context descriptor
{any-generic-type, protocol} ::= '\x02' .{4} // Reference points indirectly to context descriptor
#if SWIFT_RUNTIME_VERSION < 5.1
{any-generic-type, protocol} ::= '\x01' .{4} // Reference points directly to context descriptor
{any-generic-type, protocol} ::= '\x02' .{4} // Reference points indirectly to context descriptor
#else
{any-generic-type, protocol, opaque-type-decl-name} ::= '\x01' .{4} // Reference points directly to context descriptor
{any-generic-type, protocol, opaque-type-decl-name} ::= '\x02' .{4} // Reference points indirectly to context descriptor
#endif
// The grammatical role of the symbolic reference is determined by the
// kind of context descriptor referenced

Expand All @@ -91,7 +96,15 @@ The following symbolic reference kinds are currently implemented:

associated-conformance-access-function ::= '\x07' .{4} // Reference points directly to associated conformance access function relative to the protocol
associated-conformance-access-function ::= '\x08' .{4} // Reference points directly to associated conformance access function relative to the conforming type
keypath-metadata-access-function ::= '\x09' {.4} // Reference points directly to keypath conformance access function

// keypaths only in Swift 5.0, generalized in Swift 5.1
#if SWIFT_RUNTIME_VERSION >= 5.1
metadata-access-function ::= '\x09' .{4} // Reference points directly to metadata access function that can be invoked to produce referenced object
#endif

A mangled name may also include ``\xFF`` bytes, which are only used for
alignment padding. They do not affect what the mangled name references and can
be skipped over and ignored.

Globals
~~~~~~~
Expand All @@ -110,6 +123,9 @@ Globals
global ::= nominal-type 'Ml' // in-place type initialization cache
global ::= nominal-type 'Mm' // class metaclass
global ::= nominal-type 'Mn' // nominal type descriptor
#if SWIFT_RUNTIME_VERSION >= 5.1
global ::= opaque-type-decl-name 'MQ' // opaque type descriptor -- added in Swift 5.1
#endif
global ::= nominal-type 'Mu' // class method lookup function
global ::= nominal-type 'MU' // ObjC metadata update callback function
global ::= nominal-type 'Ms' // ObjC resilient class stub
Expand Down Expand Up @@ -600,6 +616,20 @@ For the most part, manglings follow the structure of formal language
types. However, in some cases it is more useful to encode the exact
implementation details of a function type.

::

#if SWIFT_VERSION >= 5.1
type ::= 'Qr' // opaque result type (of current decl)
type ::= opaque-type-decl-name bound-generic-args 'Qo' INDEX // opaque type

opaque-type-decl-name ::= entity 'QO' // opaque result type of specified decl
#endif

Opaque return types have a special short representation in the mangling of
their defining entity. In structural position, opaque types are fully qualified
by mangling the defining entity for the opaque declaration and the substitutions
into the defining entity's generic environment.

The ``type*`` list contains parameter and return types (including the error
result), in that order.
The number of parameters and results must match with the number of
Expand Down
57 changes: 57 additions & 0 deletions include/swift/ABI/Metadata.h
Expand Up @@ -3005,6 +3005,58 @@ struct TargetProtocolDescriptor final
return cd->getKind() == ContextDescriptorKind::Protocol;
}
};

/// The descriptor for an opaque type.
template <typename Runtime>
struct TargetOpaqueTypeDescriptor final
: TargetContextDescriptor<Runtime>,
TrailingGenericContextObjects<TargetOpaqueTypeDescriptor<Runtime>,
TargetGenericContextDescriptorHeader,
RelativeDirectPointer<const char>>
{
private:
using TrailingGenericContextObjects
= TrailingGenericContextObjects<TargetOpaqueTypeDescriptor<Runtime>,
TargetGenericContextDescriptorHeader,
RelativeDirectPointer<const char>>;
using TrailingObjects =
typename TrailingGenericContextObjects::TrailingObjects;
friend TrailingObjects;

template<typename T>
using OverloadToken = typename TrailingObjects::template OverloadToken<T>;

public:
using TrailingGenericContextObjects::getGenericContext;
using TrailingGenericContextObjects::getGenericContextHeader;
using TrailingGenericContextObjects::getFullGenericContextHeader;
using TrailingGenericContextObjects::getGenericParams;

// The kind-specific flags area is used to store the count of the generic
// arguments for underlying type(s) encoded in the descriptor.
unsigned getNumUnderlyingTypeArguments() const {
return this->Flags.getKindSpecificFlags();
}

using TrailingGenericContextObjects::numTrailingObjects;
size_t numTrailingObjects(OverloadToken<RelativeDirectPointer<const char>>) const {
return getNumUnderlyingTypeArguments();
}

StringRef getUnderlyingTypeArgument(unsigned i) const {
assert(i < getNumUnderlyingTypeArguments());
const char *ptr =
(this->template getTrailingObjects<RelativeDirectPointer<const char>>())[i];

return Demangle::makeSymbolicMangledNameStringRef(ptr);
}

static bool classof(const TargetContextDescriptor<Runtime> *cd) {
return cd->getKind() == ContextDescriptorKind::OpaqueType;
}
};

using OpaqueTypeDescriptor = TargetOpaqueTypeDescriptor<InProcess>;

/// The instantiation cache for generic metadata. This must be guaranteed
/// to zero-initialized before it is first accessed. Its contents are private
Expand Down Expand Up @@ -4213,6 +4265,9 @@ TargetContextDescriptor<Runtime>::getGenericContext() const {
case ContextDescriptorKind::Struct:
return llvm::cast<TargetStructDescriptor<Runtime>>(this)
->getGenericContext();
case ContextDescriptorKind::OpaqueType:
return llvm::cast<TargetOpaqueTypeDescriptor<Runtime>>(this)
->getGenericContext();
default:
// We don't know about this kind of descriptor.
return nullptr;
Expand Down Expand Up @@ -4264,6 +4319,8 @@ TargetTypeContextDescriptor<Runtime>::getGenericParams() const {
return llvm::cast<TargetEnumDescriptor<Runtime>>(this)->getGenericParams();
case ContextDescriptorKind::Struct:
return llvm::cast<TargetStructDescriptor<Runtime>>(this)->getGenericParams();
case ContextDescriptorKind::OpaqueType:
return llvm::cast<TargetOpaqueTypeDescriptor<Runtime>>(this)->getGenericParams();
default:
swift_runtime_unreachable("Not a type context descriptor.");
}
Expand Down
3 changes: 3 additions & 0 deletions include/swift/ABI/MetadataValues.h
Expand Up @@ -1102,6 +1102,9 @@ enum class ContextDescriptorKind : uint8_t {

/// This context descriptor represents a protocol context.
Protocol = 3,

/// This context descriptor represents an opaque type alias.
OpaqueType = 4,

/// First kind that represents a type of any sort.
Type_First = 16,
Expand Down
2 changes: 2 additions & 0 deletions include/swift/AST/ASTContext.h
Expand Up @@ -84,6 +84,7 @@ namespace swift {
class ModuleLoader;
class NominalTypeDecl;
class NormalProtocolConformance;
class OpaqueTypeDecl;
class InheritedProtocolConformance;
class SelfProtocolConformance;
class SpecializedProtocolConformance;
Expand Down Expand Up @@ -943,6 +944,7 @@ class ASTContext final {

friend TypeBase;
friend ArchetypeType;
friend OpaqueTypeDecl;

/// Provide context-level uniquing for SIL lowered type layouts and boxes.
friend SILLayout;
Expand Down
7 changes: 7 additions & 0 deletions include/swift/AST/ASTDemangler.h
Expand Up @@ -58,6 +58,9 @@ class ASTBuilder {
using BuiltTypeDecl = swift::GenericTypeDecl *; // nominal or type alias
using BuiltProtocolDecl = swift::ProtocolDecl *;
explicit ASTBuilder(ASTContext &ctx) : Ctx(ctx) {}

/// The resolver to use for type checking, if necessary.
LazyResolver *Resolver = nullptr;

ASTContext &getASTContext() { return Ctx; }
DeclContext *getNotionalDC();
Expand All @@ -82,6 +85,10 @@ class ASTBuilder {
Type createTypeAliasType(GenericTypeDecl *decl, Type parent);

Type createBoundGenericType(GenericTypeDecl *decl, ArrayRef<Type> args);

Type resolveOpaqueType(NodePointer opaqueDescriptor,
ArrayRef<Type> args,
unsigned ordinal);

Type createBoundGenericType(GenericTypeDecl *decl, ArrayRef<Type> args,
Type parent);
Expand Down
46 changes: 35 additions & 11 deletions include/swift/AST/ASTMangler.h
Expand Up @@ -59,12 +59,18 @@ class ASTMangler : public Mangler {

public:
using SymbolicReferent = llvm::PointerUnion<const NominalTypeDecl *,
const ProtocolConformance *>;
const OpaqueTypeDecl *>;
protected:

/// If set, the mangler calls this function to determine whether to symbolic
/// reference a given entity. Defaults to always returning true.
/// reference a given entity. If null, the mangler acts as if it's set to
/// always return true.
std::function<bool (SymbolicReferent)> CanSymbolicReference;

bool canSymbolicReference(SymbolicReferent referent) {
return AllowSymbolicReferences
&& (!CanSymbolicReference || CanSymbolicReference(referent));
}

std::vector<std::pair<SymbolicReferent, unsigned>> SymbolicReferences;

Expand Down Expand Up @@ -201,7 +207,7 @@ class ASTMangler : public Mangler {

void appendSymbolKind(SymbolKind SKind);

void appendType(Type type);
void appendType(Type type, const ValueDecl *forDecl = nullptr);

void appendDeclName(const ValueDecl *decl);

Expand All @@ -215,6 +221,15 @@ class ASTMangler : public Mangler {

void bindGenericParameters(CanGenericSignature sig);

/// Mangles a sugared type iff we are mangling for the debugger.
template <class T> void appendSugaredType(Type type,
const ValueDecl *forDecl) {
assert(DWARFMangling &&
"sugared types are only legal when mangling for the debugger");
auto *BlandTy = cast<T>(type.getPointer())->getSinglyDesugaredType();
appendType(BlandTy, forDecl);
}

void appendBoundGenericArgs(Type type, bool &isFirstArgList);

/// Append the bound generics arguments for the given declaration context
Expand All @@ -228,7 +243,8 @@ class ASTMangler : public Mangler {

/// Append any retroactive conformances.
void appendRetroactiveConformances(Type type);

void appendRetroactiveConformances(SubstitutionMap subMap,
ModuleDecl *fromModule);
void appendImplFunctionType(SILFunctionType *fn);

void appendContextOf(const ValueDecl *decl);
Expand All @@ -242,17 +258,23 @@ class ASTMangler : public Mangler {

void appendAnyGenericType(const GenericTypeDecl *decl);

void appendFunction(AnyFunctionType *fn, bool isFunctionMangling = false);
void appendFunctionType(AnyFunctionType *fn, bool isAutoClosure = false);
void appendFunction(AnyFunctionType *fn, bool isFunctionMangling = false,
const ValueDecl *forDecl = nullptr);
void appendFunctionType(AnyFunctionType *fn, bool isAutoClosure = false,
const ValueDecl *forDecl = nullptr);

void appendFunctionSignature(AnyFunctionType *fn);
void appendFunctionSignature(AnyFunctionType *fn,
const ValueDecl *forDecl = nullptr);

void appendFunctionInputType(ArrayRef<AnyFunctionType::Param> params);
void appendFunctionResultType(Type resultType);
void appendFunctionInputType(ArrayRef<AnyFunctionType::Param> params,
const ValueDecl *forDecl = nullptr);
void appendFunctionResultType(Type resultType,
const ValueDecl *forDecl = nullptr);

void appendTypeList(Type listTy);
void appendTypeList(Type listTy, const ValueDecl *forDecl = nullptr);
void appendTypeListElement(Identifier name, Type elementType,
ParameterTypeFlags flags);
ParameterTypeFlags flags,
const ValueDecl *forDecl = nullptr);

/// Append a generic signature to the mangling.
///
Expand Down Expand Up @@ -319,6 +341,8 @@ class ASTMangler : public Mangler {
void appendOpParamForLayoutConstraint(LayoutConstraint Layout);

void appendSymbolicReference(SymbolicReferent referent);

void appendOpaqueDeclName(const OpaqueTypeDecl *opaqueDecl);
};

} // end namespace Mangle
Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/Attr.def
Expand Up @@ -82,6 +82,9 @@ TYPE_ATTR(yield_many)
TYPE_ATTR(thin)
TYPE_ATTR(thick)

// Generated interface attributes
TYPE_ATTR(_opaqueReturnTypeOf)

// Schema for DECL_ATTR:
//
// - Attribute name.
Expand Down
12 changes: 12 additions & 0 deletions include/swift/AST/Attr.h
Expand Up @@ -67,6 +67,14 @@ class TypeAttributes {

// For an opened existential type, the known ID.
Optional<UUID> OpenedID;

// For a reference to an opaque return type, the mangled name and argument
// index into the generic signature.
struct OpaqueReturnTypeRef {
StringRef mangledName;
unsigned index;
};
Optional<OpaqueReturnTypeRef> OpaqueReturnTypeOf;

TypeAttributes() {}

Expand All @@ -84,6 +92,10 @@ class TypeAttributes {
return AttrLocs[A];
}

void setOpaqueReturnTypeOf(StringRef mangling, unsigned index) {
OpaqueReturnTypeOf = OpaqueReturnTypeRef{mangling, index};
}

void setAttr(TypeAttrKind A, SourceLoc L) {
assert(!L.isInvalid() && "Cannot clear attribute with this method");
AttrLocs[A] = L;
Expand Down

0 comments on commit a8c2b50

Please sign in to comment.