mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
from the witness tables for their associations rather than passing them separately. This drastically reduces the number of physical arguments required to invoke a generic function with a complex protocol hierarchy. It's also an important step towards allowing recursive protocol constraints. However, it may cause some performance problems in generic code that we'll have to figure out ways to remediate. There are still a few places in IRGen that rely on recursive eager expansion of associated types and protocol witnesses. For example, passing generic arguments requires us to map from a dependent type back to an index into the all-dependent-types list in order to find the right Substitution; that's something we'll need to fix more generally. Specific to IRGen, there are still a few abstractions like NecessaryBindings that use recursive expansion and are therefore probably extremely expensive under this patch; I intend to fix those up in follow-ups to the greatest extent possible. There are also still a few things that could be made lazier about type fulfillment; for example, we eagerly project the dynamic type metadata of class parameters rather than waiting for the first place we actually need to do so. We should be able to be lazier about that, at least when the parameter is @guaranteed. Technical notes follow. Most of the basic infrastructure I set up for this over the last few months stood up, although there were some unanticipated complexities: The first is that the all-dependent-types list still does not reliably contain all the dependent types in the minimized signature, even with my last patch, because the primary type parameters aren't necessarily representatives. It is, unfortunately, important to give the witness marker to the primary type parameter because otherwise substitution won't be able to replace that parameter at all. There are better representations for all of that, but it's not something I wanted to condition this patch on; therefore, we have to do a significantly more expensive check in order to figure out a dependent type's index in the all-dependent-types list. The second is that the ability to add requirements to associated types in protocol refinements means that we have to find the *right* associatedtype declaration in order to find the associated witness table. There seems to be relatively poor AST support for this operation; maybe I just missed it. The third complexity (so far) is that the association between an archetype and its parent isn't particularly more important than any other association it has. We need to be able to recover witness tables linked with *all* of the associations that lead to an archetype. This is, again, not particularly well-supported by the AST, and we may run into problems here when we eliminate recursive associated type expansion in signatures. Finally, it's a known fault that this potentially leaves debug info in a bit of a mess, since we won't have any informaton for a type parameter unless we actually needed it somewhere.
262 lines
9.2 KiB
C++
262 lines
9.2 KiB
C++
//===--- GenericSignature.h - Generic Signature AST -------------*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines the GenericSignature class and its related classes.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_AST_GENERIC_SIGNATURE_H
|
|
#define SWIFT_AST_GENERIC_SIGNATURE_H
|
|
|
|
#include "swift/AST/Requirement.h"
|
|
#include "swift/AST/Substitution.h"
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
#include "llvm/ADT/FoldingSet.h"
|
|
#include "llvm/Support/TrailingObjects.h"
|
|
|
|
namespace swift {
|
|
|
|
class ArchetypeBuilder;
|
|
|
|
/// Iterator that walks the generic parameter types declared in a generic
|
|
/// signature and their dependent members.
|
|
class GenericSignatureWitnessIterator {
|
|
ArrayRef<Requirement> p;
|
|
|
|
public:
|
|
GenericSignatureWitnessIterator() = default;
|
|
GenericSignatureWitnessIterator(ArrayRef<Requirement> p)
|
|
: p(p)
|
|
{
|
|
assert(p.empty() || p.front().getKind() == RequirementKind::WitnessMarker);
|
|
}
|
|
|
|
GenericSignatureWitnessIterator &operator++() {
|
|
do {
|
|
p = p.slice(1);
|
|
} while (!p.empty()
|
|
&& p.front().getKind() != RequirementKind::WitnessMarker);
|
|
return *this;
|
|
}
|
|
|
|
GenericSignatureWitnessIterator operator++(int) {
|
|
auto copy = *this;
|
|
++(*this);
|
|
return copy;
|
|
}
|
|
|
|
Type operator*() const {
|
|
assert(p.front().getKind() == RequirementKind::WitnessMarker);
|
|
return p.front().getFirstType();
|
|
}
|
|
|
|
Type operator->() const {
|
|
assert(p.front().getKind() == RequirementKind::WitnessMarker);
|
|
return p.front().getFirstType();
|
|
}
|
|
|
|
bool operator==(const GenericSignatureWitnessIterator &o) {
|
|
return p.data() == o.p.data() && p.size() == o.p.size();
|
|
}
|
|
|
|
bool operator!=(const GenericSignatureWitnessIterator &o) {
|
|
return p.data() != o.p.data() || p.size() != o.p.size();
|
|
}
|
|
|
|
static GenericSignatureWitnessIterator emptyRange() {
|
|
return GenericSignatureWitnessIterator();
|
|
}
|
|
|
|
// Allow the witness iterator to be used with a ranged for.
|
|
GenericSignatureWitnessIterator begin() const {
|
|
return *this;
|
|
}
|
|
GenericSignatureWitnessIterator end() const {
|
|
return GenericSignatureWitnessIterator({p.end(), p.end()});
|
|
}
|
|
};
|
|
|
|
/// Describes the generic signature of a particular declaration, including
|
|
/// both the generic type parameters and the requirements placed on those
|
|
/// generic parameters.
|
|
class GenericSignature final : public llvm::FoldingSetNode,
|
|
private llvm::TrailingObjects<GenericSignature, GenericTypeParamType *,
|
|
Requirement> {
|
|
friend TrailingObjects;
|
|
|
|
unsigned NumGenericParams;
|
|
unsigned NumRequirements;
|
|
|
|
// Make vanilla new/delete illegal.
|
|
void *operator new(size_t Bytes) = delete;
|
|
void operator delete(void *Data) = delete;
|
|
|
|
size_t numTrailingObjects(OverloadToken<GenericTypeParamType *>) const {
|
|
return NumGenericParams;
|
|
}
|
|
size_t numTrailingObjects(OverloadToken<Requirement>) const {
|
|
return NumRequirements;
|
|
}
|
|
|
|
/// Retrieve a mutable version of the generic parameters.
|
|
MutableArrayRef<GenericTypeParamType *> getGenericParamsBuffer() {
|
|
return {getTrailingObjects<GenericTypeParamType *>(), NumGenericParams};
|
|
}
|
|
|
|
/// Retrieve a mutable version of the requirements.
|
|
MutableArrayRef<Requirement> getRequirementsBuffer() {
|
|
return {getTrailingObjects<Requirement>(), NumRequirements};
|
|
}
|
|
|
|
GenericSignature(ArrayRef<GenericTypeParamType *> params,
|
|
ArrayRef<Requirement> requirements,
|
|
bool isKnownCanonical);
|
|
|
|
mutable llvm::PointerUnion<GenericSignature *, ASTContext *>
|
|
CanonicalSignatureOrASTContext;
|
|
|
|
static ASTContext &getASTContext(ArrayRef<GenericTypeParamType *> params,
|
|
ArrayRef<Requirement> requirements);
|
|
|
|
/// Retrieve the archetype builder for the given generic signature.
|
|
ArchetypeBuilder *getArchetypeBuilder(ModuleDecl &mod);
|
|
|
|
public:
|
|
/// Create a new generic signature with the given type parameters and
|
|
/// requirements.
|
|
static GenericSignature *get(ArrayRef<GenericTypeParamType *> params,
|
|
ArrayRef<Requirement> requirements,
|
|
bool isKnownCanonical = false);
|
|
|
|
/// Create a new generic signature with the given type parameters and
|
|
/// requirements, first canonicalizing the types.
|
|
static CanGenericSignature getCanonical(ArrayRef<GenericTypeParamType *> params,
|
|
ArrayRef<Requirement> requirements);
|
|
|
|
/// Retrieve the generic parameters.
|
|
ArrayRef<GenericTypeParamType *> getGenericParams() const {
|
|
return const_cast<GenericSignature *>(this)->getGenericParamsBuffer();
|
|
}
|
|
|
|
/// Retrieve the innermost generic parameters.
|
|
///
|
|
/// Given a generic signature for a nested generic type, produce an
|
|
/// array of the generic parameters for the innermost generic type.
|
|
ArrayRef<GenericTypeParamType *> getInnermostGenericParams() const;
|
|
|
|
/// Retrieve the requirements.
|
|
ArrayRef<Requirement> getRequirements() const {
|
|
return const_cast<GenericSignature *>(this)->getRequirementsBuffer();
|
|
}
|
|
|
|
// Only allow allocation by doing a placement new.
|
|
void *operator new(size_t Bytes, void *Mem) {
|
|
assert(Mem);
|
|
return Mem;
|
|
}
|
|
|
|
/// Build a substitution map from a vector of Substitutions that correspond to
|
|
/// the generic parameters in this generic signature. The order of primary
|
|
/// archetypes in the substitution vector must match the order of generic
|
|
/// parameters in getGenericParams().
|
|
TypeSubstitutionMap getSubstitutionMap(ArrayRef<Substitution> args) const;
|
|
|
|
/// Return a range that iterates through first all of the generic parameters
|
|
/// of the signature, followed by all of their recursive member types exposed
|
|
/// through protocol requirements.
|
|
///
|
|
/// The member types are presented in the
|
|
/// same order as GenericParamList::getAllArchetypes would present for an
|
|
/// equivalent GenericParamList.
|
|
GenericSignatureWitnessIterator getAllDependentTypes() const {
|
|
return GenericSignatureWitnessIterator(getRequirements());
|
|
}
|
|
|
|
/// Determines whether this ASTContext is canonical.
|
|
bool isCanonical() const;
|
|
|
|
ASTContext &getASTContext() const;
|
|
|
|
/// Canonicalize the components of a generic signature.
|
|
CanGenericSignature getCanonicalSignature() const;
|
|
|
|
/// Canonicalize a generic signature down to its essential requirements,
|
|
/// for mangling purposes.
|
|
///
|
|
/// TODO: This is what getCanonicalSignature() ought to do, but currently
|
|
/// cannot due to implementation dependencies on 'getAllDependentTypes'
|
|
/// order matching 'getAllArchetypes' order of a generic param list.
|
|
CanGenericSignature getCanonicalManglingSignature(ModuleDecl &M) const;
|
|
|
|
/// Uniquing for the ASTContext.
|
|
void Profile(llvm::FoldingSetNodeID &ID) {
|
|
Profile(ID, getGenericParams(), getRequirements());
|
|
}
|
|
|
|
/// Determine whether the given dependent type is required to be a class.
|
|
bool requiresClass(Type type, ModuleDecl &mod);
|
|
|
|
/// Determine the superclass bound on the given dependent type.
|
|
Type getSuperclassBound(Type type, ModuleDecl &mod);
|
|
|
|
using ConformsToArray = SmallVector<ProtocolDecl *, 2>;
|
|
/// Determine the set of protocols to which the given dependent type
|
|
/// must conform.
|
|
ConformsToArray getConformsTo(Type type, ModuleDecl &mod);
|
|
|
|
/// Determine whether the given dependent type is equal to a concrete type.
|
|
bool isConcreteType(Type type, ModuleDecl &mod);
|
|
|
|
/// Return the concrete type that the given dependent type is constrained to,
|
|
/// or the null Type if it is not the subject of a concrete same-type
|
|
/// constraint.
|
|
Type getConcreteType(Type type, ModuleDecl &mod);
|
|
|
|
/// Return the preferred representative of the given type parameter within
|
|
/// this generic signature. This may yield a concrete type or a
|
|
/// different type parameter.
|
|
Type getRepresentative(Type type, ModuleDecl &mod);
|
|
|
|
/// Return whether two type parameters represent the same type under this
|
|
/// generic signature.
|
|
///
|
|
/// The type parameters must be known to not be concrete within the context.
|
|
bool areSameTypeParameterInContext(Type type1, Type type2, ModuleDecl &mod);
|
|
|
|
static void Profile(llvm::FoldingSetNodeID &ID,
|
|
ArrayRef<GenericTypeParamType *> genericParams,
|
|
ArrayRef<Requirement> requirements);
|
|
|
|
void print(raw_ostream &OS) const;
|
|
void dump() const;
|
|
std::string getAsString() const;
|
|
};
|
|
|
|
inline
|
|
CanGenericSignature::CanGenericSignature(GenericSignature *Signature)
|
|
: Signature(Signature)
|
|
{
|
|
assert(!Signature || Signature->isCanonical());
|
|
}
|
|
|
|
inline ArrayRef<CanTypeWrapper<GenericTypeParamType>>
|
|
CanGenericSignature::getGenericParams() const{
|
|
ArrayRef<GenericTypeParamType*> params = Signature->getGenericParams();
|
|
auto base = reinterpret_cast<const CanTypeWrapper<GenericTypeParamType>*>(
|
|
params.data());
|
|
return {base, params.size()};
|
|
}
|
|
|
|
} // end namespace swift
|
|
|
|
#endif // SWIFT_AST_GENERIC_SIGNATURE_H
|