[Archetype builder] Separate potential archetypes from *specific* archetypes.

Stop recording specific archetypes anywhere in
PotentialArchetype. Instead, use a GenericEnvironment to record/query
the archetype that corresponds to that PotentialArchetype, making it
possible to use the same archetype builder (and its potential
archetypes) to build multiple generic environments.
This commit is contained in:
Doug Gregor
2016-11-29 17:09:00 -08:00
parent d30df451af
commit 95f1aaf4d1
10 changed files with 334 additions and 193 deletions

View File

@@ -366,9 +366,9 @@ class ArchetypeBuilder::PotentialArchetype {
llvm::MapVector<Identifier, llvm::TinyPtrVector<PotentialArchetype *>>
NestedTypes;
/// \brief The actual archetype, once it has been assigned, or the concrete
/// type that the parameter was same-type constrained to.
ArchetypeType::NestedType ArchetypeOrConcreteType;
/// The concrete type to which a this potential archetype has been
/// constrained.
Type ConcreteType;
/// \brief Recursively conforms to itself.
unsigned IsRecursive : 1;
@@ -377,10 +377,6 @@ class ArchetypeBuilder::PotentialArchetype {
/// be resolved.
unsigned Invalid : 1;
/// Whether we are currently substituting into the concrete type of
/// this potential archetype.
unsigned SubstitutingConcreteType : 1;
/// Whether we have detected recursion during the substitution of
/// the concrete type.
unsigned RecursiveConcreteType : 1;
@@ -403,7 +399,7 @@ class ArchetypeBuilder::PotentialArchetype {
/// associated type.
PotentialArchetype(PotentialArchetype *Parent, Identifier Name)
: ParentOrParam(Parent), NameOrAssociatedType(Name), Representative(this),
IsRecursive(false), Invalid(false), SubstitutingConcreteType(false),
IsRecursive(false), Invalid(false),
RecursiveConcreteType(false), RecursiveSuperclassType(false),
DiagnosedRename(false)
{
@@ -415,7 +411,7 @@ class ArchetypeBuilder::PotentialArchetype {
PotentialArchetype(PotentialArchetype *Parent, AssociatedTypeDecl *AssocType)
: ParentOrParam(Parent), NameOrAssociatedType(AssocType),
Representative(this), IsRecursive(false), Invalid(false),
SubstitutingConcreteType(false), RecursiveConcreteType(false),
RecursiveConcreteType(false),
RecursiveSuperclassType(false), DiagnosedRename(false)
{
assert(Parent != nullptr && "Not an associated type?");
@@ -426,7 +422,7 @@ class ArchetypeBuilder::PotentialArchetype {
PotentialArchetype(PotentialArchetype *Parent, TypeAliasDecl *TypeAlias)
: ParentOrParam(Parent), NameOrAssociatedType(TypeAlias),
Representative(this), IsRecursive(false), Invalid(false),
SubstitutingConcreteType(false), RecursiveConcreteType(false),
RecursiveConcreteType(false),
RecursiveSuperclassType(false), DiagnosedRename(false)
{
assert(Parent != nullptr && "Not an associated type?");
@@ -438,7 +434,7 @@ class ArchetypeBuilder::PotentialArchetype {
Identifier Name)
: ParentOrParam(GenericParam),
NameOrAssociatedType(Name), Representative(this), IsRecursive(false),
Invalid(false), SubstitutingConcreteType(false),
Invalid(false),
RecursiveConcreteType(false), RecursiveSuperclassType(false),
DiagnosedRename(false)
{
@@ -550,9 +546,11 @@ public:
PotentialArchetype *getNestedType(Identifier Name,
ArchetypeBuilder &builder);
/// \brief Retrieve (or build) the type corresponding to the potential
/// archetype.
ArchetypeType::NestedType getType(ArchetypeBuilder &builder);
/// archetype within the given generic environment.
ArchetypeType::NestedType getTypeInContext(ArchetypeBuilder &builder,
GenericEnvironment *genericEnv);
/// Retrieve the dependent type that describes this potential
/// archetype.
@@ -568,15 +566,14 @@ public:
if (Representative != this)
return Representative->isConcreteType();
return ArchetypeOrConcreteType.isConcreteType();
return static_cast<bool>(ConcreteType);
}
/// Get the concrete type this potential archetype is constrained to.
Type getConcreteType() const {
assert(isConcreteType());
if (Representative != this)
return Representative->getConcreteType();
return ArchetypeOrConcreteType.getAsConcreteType();
return ConcreteType;
}
void setIsRecursive() { IsRecursive = true; }

View File

@@ -22,6 +22,7 @@
namespace swift {
class ArchetypeBuilder;
class ASTContext;
class GenericTypeParamType;
class SILModule;
@@ -29,7 +30,7 @@ class SILType;
/// Describes the mapping between archetypes and interface types for the
/// generic parameters of a DeclContext.
class GenericEnvironment final {
class alignas(1 << DeclAlignInBits) GenericEnvironment final {
GenericSignature *Signature;
TypeSubstitutionMap ArchetypeToInterfaceMap;
TypeSubstitutionMap InterfaceToArchetypeMap;
@@ -65,6 +66,11 @@ public:
/// an archetype)
void addMapping(GenericTypeParamType *genericParam, Type contextType);
/// Retrieve the mapping for the given generic parameter, if present.
///
/// This is only useful when lazily populating a generic environment.
Optional<Type> getMappingIfPresent(GenericTypeParamType *genericParam) const;
/// Make vanilla new/delete illegal.
void *operator new(size_t Bytes) = delete;
void operator delete(void *Data) = delete;
@@ -80,9 +86,6 @@ public:
Type mapTypeIntoContext(ModuleDecl *M, Type type) const;
/// Map a generic parameter type to a contextual type.
///
/// This operation will also reabstract dependent types according to the
/// abstraction level of their associated type requirements.
Type mapTypeIntoContext(GenericTypeParamType *type) const;
/// \brief Map the given SIL interface type to a contextual type.

View File

@@ -34,6 +34,7 @@ namespace swift {
class DeclContext;
class Expr;
class ExtensionDecl;
class GenericEnvironment;
class GenericTypeParamDecl;
class NormalProtocolConformance;
class OperatorDecl;
@@ -97,6 +98,8 @@ LLVM_DECLARE_TYPE_ALIGNMENT(swift::Expr, swift::ExprAlignInBits)
LLVM_DECLARE_TYPE_ALIGNMENT(swift::ProtocolConformance, swift::DeclAlignInBits)
LLVM_DECLARE_TYPE_ALIGNMENT(swift::NormalProtocolConformance,
swift::DeclAlignInBits)
LLVM_DECLARE_TYPE_ALIGNMENT(swift::GenericEnvironment,
swift::DeclAlignInBits)
static_assert(llvm::AlignOf<void*>::Alignment >= 2,
"pointer alignment is too small");

View File

@@ -3776,7 +3776,8 @@ private:
ArrayRef<ProtocolDecl *> ConformsTo;
Type Superclass;
llvm::PointerUnion<ArchetypeType *, TypeBase *> ParentOrOpened;
llvm::PointerUnion3<ArchetypeType *, TypeBase *,
GenericEnvironment *> ParentOrOpenedOrEnvironment;
llvm::PointerUnion<AssociatedTypeDecl *, Identifier> AssocTypeOrName;
MutableArrayRef<std::pair<Identifier, NestedType>> NestedTypes;
@@ -3790,7 +3791,7 @@ private:
void resolveNestedType(std::pair<Identifier, NestedType> &nested) const;
public:
/// getNew - Create a new archetype with the given name.
/// getNew - Create a new nested archetype with the given associated type.
///
/// The ConformsTo array will be copied into the ASTContext by this routine.
static CanTypeWrapper<ArchetypeType>
@@ -3799,12 +3800,13 @@ public:
SmallVectorImpl<ProtocolDecl *> &ConformsTo,
Type Superclass);
/// getNew - Create a new archetype with the given name.
/// getNew - Create a new primary archetype with the given name.
///
/// The ConformsTo array will be minimized then copied into the ASTContext
/// by this routine.
static CanTypeWrapper<ArchetypeType>
getNew(const ASTContext &Ctx,
GenericEnvironment *genericEnvironment,
Identifier Name,
SmallVectorImpl<ProtocolDecl *> &ConformsTo,
Type Superclass);
@@ -3836,14 +3838,19 @@ public:
/// \brief Retrieve the parent of this archetype, or null if this is a
/// primary archetype.
ArchetypeType *getParent() const {
return ParentOrOpened.dyn_cast<ArchetypeType *>();
return ParentOrOpenedOrEnvironment.dyn_cast<ArchetypeType *>();
}
/// Retrieve the opened existential type
Type getOpenedExistentialType() const {
return ParentOrOpened.dyn_cast<TypeBase *>();
return ParentOrOpenedOrEnvironment.dyn_cast<TypeBase *>();
}
/// Retrieve the generic environment in which this archetype resides.
///
/// FIXME: Not all archetypes have generic environments, yet.
GenericEnvironment *getGenericEnvironment() const;
/// Retrieve the associated type to which this archetype (if it is a nested
/// archetype) corresponds.
///
@@ -3866,6 +3873,12 @@ public:
/// \brief Retrieve the superclass of this type, if such a requirement exists.
Type getSuperclass() const { return Superclass; }
/// \brief Set the superclass of this type.
///
/// This can only be performed in very narrow cases where the archetype is
/// being lazily constructed.
void setSuperclass(Type superclass) { Superclass = superclass; }
/// \brief Return true if the archetype has any requirements at all.
bool hasRequirements() const {
return !getConformsTo().empty() || getSuperclass();
@@ -3874,6 +3887,12 @@ public:
/// \brief Retrieve the nested type with the given name.
NestedType getNestedType(Identifier Name) const;
/// \brief Retrieve the nested type with the given name, if it's already
/// known.
///
/// This is an implementation detail used by the archetype builder.
Optional<NestedType> getNestedTypeIfKnown(Identifier Name) const;
Type getNestedTypeValue(Identifier Name) const {
return getNestedType(Name).getValue();
}
@@ -3907,10 +3926,14 @@ public:
void setNestedTypes(ASTContext &Ctx,
MutableArrayRef<std::pair<Identifier, NestedType>> Nested);
/// Register a nested type with the given name.
void registerNestedType(Identifier name, NestedType nested);
/// isPrimary - Determine whether this is the archetype for a 'primary'
/// archetype, e.g.,
/// archetype, e.g., one that is not nested within another archetype and is
/// not an opened existential.
bool isPrimary() const {
return ParentOrOpened.isNull();
return ParentOrOpenedOrEnvironment.is<GenericEnvironment *>();
}
/// getPrimary - Return the primary archetype parent of this archetype.
@@ -3937,14 +3960,23 @@ public:
private:
ArchetypeType(
const ASTContext &Ctx, ArchetypeType *Parent,
const ASTContext &Ctx,
llvm::PointerUnion<ArchetypeType *, GenericEnvironment *>
ParentOrGenericEnv,
llvm::PointerUnion<AssociatedTypeDecl *, Identifier> AssocTypeOrName,
ArrayRef<ProtocolDecl *> ConformsTo,
Type Superclass)
: SubstitutableType(TypeKind::Archetype, &Ctx,
RecursiveTypeProperties::HasArchetype),
ConformsTo(ConformsTo), Superclass(Superclass), ParentOrOpened(Parent),
AssocTypeOrName(AssocTypeOrName) { }
ConformsTo(ConformsTo), Superclass(Superclass),
AssocTypeOrName(AssocTypeOrName) {
if (auto parent = ParentOrGenericEnv.dyn_cast<ArchetypeType *>()) {
ParentOrOpenedOrEnvironment = parent;
} else {
ParentOrOpenedOrEnvironment =
ParentOrGenericEnv.get<GenericEnvironment *>();
}
}
ArchetypeType(const ASTContext &Ctx,
Type Existential,
@@ -3955,7 +3987,7 @@ private:
RecursiveTypeProperties::HasArchetype |
RecursiveTypeProperties::HasOpenedExistential)),
ConformsTo(ConformsTo), Superclass(Superclass),
ParentOrOpened(Existential.getPointer()) { }
ParentOrOpenedOrEnvironment(Existential.getPointer()) { }
};
BEGIN_CAN_TYPE_WRAPPER(ArchetypeType, SubstitutableType)
CanArchetypeType getParent() const {

View File

@@ -26,6 +26,7 @@
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/TypeRepr.h"
#include "swift/AST/TypeWalker.h"
#include "swift/Basic/Defer.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
@@ -130,6 +131,24 @@ struct ArchetypeBuilder::Implementation {
/// The nested types that have been renamed.
SmallVector<PotentialArchetype *, 4> RenamedNestedTypes;
/// Potential archetypes for which we are currently performing
/// substitutions of their superclasses. Used to detect recursion in
/// superclass substitutions.
llvm::DenseSet<std::pair<GenericEnvironment *,
ArchetypeBuilder::PotentialArchetype *>>
SuperclassSubs;
/// Potential archetypes for which we are currently performing
/// substitutions of their concrete types. Used to detect recursion in
/// concrete type substitutions.
llvm::DenseSet<std::pair<GenericEnvironment *,
ArchetypeBuilder::PotentialArchetype *>>
ConcreteSubs;
/// FIXME: Egregious hack to track when we ended up using a "parent"
/// archetype, because we end up with broken invariants in that case.
bool UsedContextArchetype = false;
};
ArchetypeBuilder::PotentialArchetype::~PotentialArchetype() {
@@ -363,10 +382,13 @@ auto ArchetypeBuilder::PotentialArchetype::getRepresentative()
bool ArchetypeBuilder::PotentialArchetype::hasConcreteTypeInPath() const {
for (auto pa = this; pa; pa = pa->getParent()) {
if (pa->ArchetypeOrConcreteType.isConcreteType() &&
!pa->ArchetypeOrConcreteType.getAsConcreteType()->is<ArchetypeType>())
// FIXME: The archetype check here is a hack because we're reusing
// archetypes from the outer context.
if (Type concreteType = pa->getConcreteType()) {
if (!concreteType->is<ArchetypeType>())
return true;
}
}
return false;
}
@@ -479,7 +501,7 @@ auto ArchetypeBuilder::PotentialArchetype::getNestedType(
// to resolve and get a special diagnosis in finalize.
continue;
} else {
pa->ArchetypeOrConcreteType = NestedType::forConcreteType(type);
pa->ConcreteType = type;
pa->SameTypeSource = redundantSource;
}
} else
@@ -536,10 +558,16 @@ auto ArchetypeBuilder::PotentialArchetype::getNestedType(
/// Replace dependent types with their archetypes or concrete types.
static Type substConcreteTypesForDependentTypes(ArchetypeBuilder &builder,
GenericEnvironment *genericEnv,
Type type) {
// FIXME: Use dyn_cast rather than getAs.
// FIXME: This should really be "Type::subst()", but we need a way to provide
// Type::subst() with generic parameter bindings that are lazily populated
// through the archetype builder.
return type.transform([&](Type type) -> Type {
if (auto depMemTy = type->getAs<DependentMemberType>()) {
auto newBase = substConcreteTypesForDependentTypes(builder,
genericEnv,
depMemTy->getBase());
return depMemTy->substBaseType(&builder.getModule(), newBase,
builder.getLazyResolver());
@@ -547,7 +575,8 @@ static Type substConcreteTypesForDependentTypes(ArchetypeBuilder &builder,
if (auto typeParam = type->getAs<GenericTypeParamType>()) {
auto potentialArchetype = builder.resolveArchetype(typeParam);
return potentialArchetype->getType(builder).getValue();
return potentialArchetype->getTypeInContext(builder, genericEnv)
.getValue();
}
return type;
@@ -555,83 +584,93 @@ static Type substConcreteTypesForDependentTypes(ArchetypeBuilder &builder,
}
ArchetypeType::NestedType
ArchetypeBuilder::PotentialArchetype::getType(ArchetypeBuilder &builder) {
auto representative = getRepresentative();
ASTContext &ctx = getRootParam()->getASTContext();
ArchetypeBuilder::PotentialArchetype::getTypeInContext(
ArchetypeBuilder &builder,
GenericEnvironment *genericEnv) {
// Retrieve the archetype from the archetype anchor in this equivalence class.
// The anchor must not have any concrete parents (otherwise we would just
// use the representative).
auto archetypeAnchor = getArchetypeAnchor();
if (archetypeAnchor != this)
return archetypeAnchor->getType(builder);
return archetypeAnchor->getTypeInContext(builder, genericEnv);
auto representative = getRepresentative();
ASTContext &ctx = getRootParam()->getASTContext();
// Return a concrete type or archetype we've already resolved.
if (representative->ArchetypeOrConcreteType) {
// If the concrete type is dependent, substitute dependent types
// for archetypes.
if (auto concreteType
= representative->ArchetypeOrConcreteType.getAsConcreteType()) {
if (concreteType->hasTypeParameter()) {
// If we already know the concrete type is recursive, just
// return an error. It will be diagnosed elsewhere.
if (representative->RecursiveConcreteType) {
return NestedType::forConcreteType(ErrorType::get(ctx));
}
if (Type concreteType = representative->getConcreteType()) {
// If the concrete type doesn't involve type parameters, just return it.
if (!concreteType->hasTypeParameter())
return NestedType::forConcreteType(concreteType);
// If we're already substituting a concrete type, mark this
// Otherwise, substitute in the archetypes in the environment.
// If we're already substituting into the concrete type, mark this
// potential archetype as having a recursive concrete type.
if (representative->SubstitutingConcreteType) {
representative->RecursiveConcreteType = true;
return NestedType::forConcreteType(ErrorType::get(ctx));
}
representative->SubstitutingConcreteType = true;
NestedType result = NestedType::forConcreteType(
substConcreteTypesForDependentTypes(
builder,
concreteType));
representative->SubstitutingConcreteType = false;
// If all went well, we're done.
if (!representative->RecursiveConcreteType)
return result;
// Otherwise, we found that the concrete type is recursive,
// complain and return an error.
ctx.Diags.diagnose(SameTypeSource->getLoc(),
if (representative->RecursiveConcreteType ||
!builder.Impl->ConcreteSubs.insert({genericEnv, representative})
.second) {
// Complain about the recursion, if we haven't done so already.
if (!representative->RecursiveConcreteType) {
ctx.Diags.diagnose(representative->SameTypeSource->getLoc(),
diag::recursive_same_type_constraint,
getDependentType(/*allowUnresolved=*/false),
getDependentType(/*allowUnresolved=*/true),
concreteType);
return NestedType::forConcreteType(ErrorType::get(ctx));
}
representative->RecursiveConcreteType = true;
}
return representative->ArchetypeOrConcreteType;
return NestedType::forConcreteType(
ErrorType::get(getDependentType(/*allowUnresolved=*/true)));
}
SWIFT_DEFER {
builder.Impl->ConcreteSubs.erase({genericEnv, representative});
};
return NestedType::forConcreteType(
substConcreteTypesForDependentTypes(builder, genericEnv,
concreteType));
}
// Check that we haven't referenced this type while substituting into the
// superclass.
if (!representative->RecursiveSuperclassType &&
representative->getSuperclass() &&
builder.Impl->SuperclassSubs.count({genericEnv, representative})
> 0) {
if (representative->SuperclassSource->getLoc().isValid()) {
ctx.Diags.diagnose(representative->SuperclassSource->getLoc(),
diag::recursive_superclass_constraint,
representative->getSuperclass());
}
representative->RecursiveSuperclassType = true;
return NestedType::forConcreteType(
ErrorType::get(getDependentType(/*allowUnresolved=*/true)));
}
AssociatedTypeDecl *assocType = nullptr;
// Allocate a new archetype.
ArchetypeType *ParentArchetype = nullptr;
auto &mod = builder.getModule();
if (auto parent = getParent()) {
auto parentTy = parent->getType(builder);
// For nested types, first substitute into the parent so we can form the
// proper nested type.
auto &mod = builder.getModule();
auto parentTy = parent->getTypeInContext(builder, genericEnv);
if (!parentTy)
return NestedType::forConcreteType(ErrorType::get(ctx));
ParentArchetype = parentTy.getAsArchetype();
if (!ParentArchetype) {
if (Type concreteParent = parentTy.getAsConcreteType()) {
// We might have an outer archetype as a concrete type here; if so, just
// return that.
ParentArchetype = parentTy.getValue()->getAs<ArchetypeType>();
if (ParentArchetype) {
representative->ArchetypeOrConcreteType
= NestedType::forConcreteType(
ParentArchetype->getNestedTypeValue(getName()));
return representative->ArchetypeOrConcreteType;
// FIXME: This should go away when we fix
// ArchetypeBuilder::addGenericSignature() to no longer take a generic
// environment.
if (auto parentArchetype = concreteParent->getAs<ArchetypeType>()) {
builder.Impl->UsedContextArchetype = true;
return NestedType::forConcreteType(
parentArchetype->getNestedTypeValue(getName()));
}
LazyResolver *resolver = ctx.getLazyResolver();
@@ -644,39 +683,51 @@ ArchetypeBuilder::PotentialArchetype::getType(ArchetypeBuilder &builder) {
return NestedType::forConcreteType(type);
auto depMemberType = type->castTo<DependentMemberType>();
Type memberType = depMemberType->substBaseType(
&mod,
parent->ArchetypeOrConcreteType.getAsConcreteType(),
Type memberType = depMemberType->substBaseType(&mod, parentTy.getValue(),
resolver);
if (auto memberPA = builder.resolveArchetype(memberType)) {
// If the member type maps to an archetype, resolve that archetype.
if (memberPA->getRepresentative() != getRepresentative()) {
representative->ArchetypeOrConcreteType = memberPA->getType(builder);
return representative->ArchetypeOrConcreteType;
if (auto memberPA = builder.resolveArchetype(memberType)) {
if (memberPA->getRepresentative() != representative) {
return memberPA->getTypeInContext(builder, genericEnv);
}
llvm_unreachable("we have no parent archetype");
} else {
}
// Otherwise, it's a concrete type.
representative->ArchetypeOrConcreteType
= NestedType::forConcreteType(
substConcreteTypesForDependentTypes(builder, memberType));
// FIXME: THIS ASSIGNMENT IS REALLY WEIRD. We shouldn't be discovering
// that a same-type constraint affects this so late in the game.
representative->SameTypeSource = parent->SameTypeSource;
return representative->ArchetypeOrConcreteType;
}
return NestedType::forConcreteType(
substConcreteTypesForDependentTypes(builder, genericEnv,
memberType));
}
ParentArchetype = parentTy.getAsArchetype();
// Check whether the parent already has an nested type with this name. If
// so, return it directly.
if (auto nested = ParentArchetype->getNestedTypeIfKnown(getName()))
return *nested;
// We will build the archetype below.
assocType = getResolvedAssociatedType();
} else if (auto type = genericEnv->getMappingIfPresent(getGenericParam())) {
// We already have a mapping for this generic parameter in the generic
// environment. Return it.
if (auto archetype = (*type)->getAs<ArchetypeType>())
return NestedType::forArchetype(archetype);
}
// If we ended up building our parent archetype, then we'll have
// already filled in our own archetype.
if (auto arch = representative->ArchetypeOrConcreteType.getAsArchetype())
return NestedType::forArchetype(arch);
// Build a new archetype.
// Collect the protocol conformances for the archetype.
SmallVector<ProtocolDecl *, 4> Protos;
for (const auto &conforms : ConformsTo) {
for (const auto &conforms : representative->getConformsTo()) {
switch (conforms.second.getKind()) {
case RequirementSource::Explicit:
case RequirementSource::Inferred:
@@ -692,48 +743,56 @@ ArchetypeBuilder::PotentialArchetype::getType(ArchetypeBuilder &builder) {
}
}
Type superclass;
if (Superclass) {
if (representative->RecursiveSuperclassType) {
ctx.Diags.diagnose(SuperclassSource->getLoc(),
diag::recursive_superclass_constraint,
Superclass);
} else {
representative->RecursiveSuperclassType = true;
assert(!Superclass->hasArchetype() &&
"superclass constraint must use interface types");
superclass = substConcreteTypesForDependentTypes(builder, Superclass);
representative->RecursiveSuperclassType = false;
}
}
// Create the archetype.
//
// Note that we delay the computation of the superclass until after we
// create the archetype, in case the superclass references the archetype
// itself.
ArchetypeType *arch;
if (ParentArchetype) {
// If we were unable to resolve this as an associated type, produce an
// error type.
if (!assocType) {
representative->ArchetypeOrConcreteType =
NestedType::forConcreteType(
return NestedType::forConcreteType(
ErrorType::get(getDependentType(/*allowUnresolved=*/true)));
return representative->ArchetypeOrConcreteType;
}
// Create a nested archetype.
arch = ArchetypeType::getNew(ctx, ParentArchetype, assocType, Protos,
superclass);
Type());
// Register this archetype with its parent.
ParentArchetype->registerNestedType(getName(),
NestedType::forArchetype(arch));
} else {
arch = ArchetypeType::getNew(ctx, getName(), Protos, superclass);
// Create a top-level archetype.
arch = ArchetypeType::getNew(ctx, genericEnv, getName(), Protos, Type());
// Register the archetype with the generic environment.
genericEnv->addMapping(getGenericParam(), arch);
}
representative->ArchetypeOrConcreteType = NestedType::forArchetype(arch);
// Determine the superclass for the archetype. If it exists and involves
// type parameters, substitute them.
if (Type superclass = representative->getSuperclass()) {
if (superclass->hasTypeParameter()) {
(void)builder.Impl->SuperclassSubs.insert({genericEnv, representative});
SWIFT_DEFER {
builder.Impl->SuperclassSubs.erase({genericEnv, representative});
};
superclass = substConcreteTypesForDependentTypes(builder, genericEnv,
superclass);
}
arch->setSuperclass(superclass);
}
// Collect the set of nested types of this archetype, and put them into
// the archetype itself.
if (!NestedTypes.empty()) {
if (!representative->getNestedTypes().empty()) {
ctx.registerLazyArchetype(arch, builder, this);
SmallVector<std::pair<Identifier, NestedType>, 4> FlatNestedTypes;
for (auto Nested : NestedTypes) {
for (auto Nested : representative->getNestedTypes()) {
// Skip type aliases, which are just shortcuts.
if (Nested.second.front()->getTypeAliasDecl())
continue;
@@ -761,6 +820,24 @@ ArchetypeBuilder::PotentialArchetype::getType(ArchetypeBuilder &builder) {
return NestedType::forArchetype(arch);
}
void ArchetypeType::resolveNestedType(
std::pair<Identifier, NestedType> &nested) const {
auto &ctx = const_cast<ArchetypeType *>(this)->getASTContext();
auto lazyArchetype = ctx.getLazyArchetype(this);
ArchetypeBuilder &builder = *lazyArchetype.first;
auto genericEnv = getGenericEnvironment();
auto potentialArchetype =
lazyArchetype.second->getNestedType(nested.first, builder);
auto result = potentialArchetype->getTypeInContext(builder, genericEnv);
assert(!nested.second ||
nested.second.getValue()->isEqual(result.getValue()) ||
(nested.second.getValue()->hasError() &&
result.getValue()->hasError()));
nested.second = result;
}
Type ArchetypeBuilder::PotentialArchetype::getDependentType(
bool allowUnresolved) {
if (auto parent = getParent()) {
@@ -1216,8 +1293,8 @@ bool ArchetypeBuilder::addSameTypeRequirementBetweenArchetypes(
std::swap(T1, T2);
// Merge any concrete constraints.
Type concrete1 = T1->ArchetypeOrConcreteType.getAsConcreteType();
Type concrete2 = T2->ArchetypeOrConcreteType.getAsConcreteType();
Type concrete1 = T1->getConcreteType();
Type concrete2 = T2->getConcreteType();
if (concrete1 && concrete2) {
if (!concrete1->isEqual(concrete2)) {
@@ -1227,14 +1304,14 @@ bool ArchetypeBuilder::addSameTypeRequirementBetweenArchetypes(
}
} else if (concrete1) {
assert(!T2->ArchetypeOrConcreteType
assert(!T2->ConcreteType
&& "already formed archetype for concrete-constrained parameter");
T2->ArchetypeOrConcreteType = NestedType::forConcreteType(concrete1);
T2->ConcreteType = concrete1;
T2->SameTypeSource = T1->SameTypeSource;
} else if (concrete2) {
assert(!T1->ArchetypeOrConcreteType
assert(!T1->ConcreteType
&& "already formed archetype for concrete-constrained parameter");
T1->ArchetypeOrConcreteType = NestedType::forConcreteType(concrete2);
T1->ConcreteType = concrete2;
T1->SameTypeSource = T2->SameTypeSource;
}
@@ -1289,12 +1366,9 @@ bool ArchetypeBuilder::addSameTypeRequirementToConcrete(
// Operate on the representative.
T = T->getRepresentative();
assert(!T->ArchetypeOrConcreteType.getAsArchetype()
&& "already formed archetype for concrete-constrained parameter");
// If we've already been bound to a type, we're either done, or we have a
// problem.
if (auto oldConcrete = T->ArchetypeOrConcreteType.getAsConcreteType()) {
if (auto oldConcrete = T->getConcreteType()) {
if (!oldConcrete->isEqual(Concrete)) {
Diags.diagnose(Source.getLoc(), diag::requires_same_type_conflict,
T->getName(), oldConcrete, Concrete);
@@ -1322,7 +1396,7 @@ bool ArchetypeBuilder::addSameTypeRequirementToConcrete(
}
// Record the requirement.
T->ArchetypeOrConcreteType = NestedType::forConcreteType(Concrete);
T->ConcreteType = Concrete;
T->SameTypeSource = Source;
// Make sure the concrete type fulfills the superclass requirement
@@ -1819,7 +1893,7 @@ ArchetypeBuilder::finalize(SourceLoc loc, bool allowConcreteGenericParams) {
// Don't allow a generic parameter to be equivalent to a concrete type,
// because then we don't actually have a parameter.
if (rep->ArchetypeOrConcreteType.getAsConcreteType()) {
if (rep->getConcreteType()) {
auto &Source = rep->SameTypeSource;
// For auto-generated locations, we should have diagnosed the problem
@@ -2111,7 +2185,7 @@ void ArchetypeBuilder::addGenericSignature(GenericSignature *sig,
assert(Impl->PotentialArchetypes.count(key) && "Missing parameter?");
auto *pa = Impl->PotentialArchetypes[key];
assert(pa == pa->getRepresentative() && "Not the representative");
pa->ArchetypeOrConcreteType = NestedType::forConcreteType(contextTy);
pa->ConcreteType = contextTy;
pa->SameTypeSource = RequirementSource(sourceKind, SourceLoc());
}
}
@@ -2185,38 +2259,33 @@ GenericSignature *ArchetypeBuilder::getGenericSignature() {
GenericEnvironment *ArchetypeBuilder::getGenericEnvironment(GenericSignature *signature) {
TypeSubstitutionMap interfaceToArchetypeMap;
// Compute the archetypes for the generic parameters.
auto genericEnv = GenericEnvironment::getIncomplete(Context, signature);
SmallVector<std::pair<const GenericTypeParamKey, PotentialArchetype *>, 2>
delayedPAs;
for (auto pair : Impl->PotentialArchetypes) {
// If this potential archetype won't map directly to a primary archetype,
// skip it for now.
if (pair.second->isConcreteType() ||
pair.second->getRepresentative() != pair.second) {
delayedPAs.push_back(pair);
continue;
Type contextType =
pair.second->getTypeInContext(*this, genericEnv).getValue();
if (!genericEnv->getMappingIfPresent(pair.second->getGenericParam()))
genericEnv->addMapping(pair.second->getGenericParam(), contextType);
}
// Add the mapping for this primary archetype.
auto paramTy = pair.second->getGenericParam();
auto archetype = pair.second->getType(*this).getAsArchetype();
genericEnv->addMapping(paramTy, archetype);
}
#ifndef NDEBUG
// FIXME: This property should be maintained when there are errors, too.
if (!Diags.hadAnyError() && !Impl->UsedContextArchetype) {
visitPotentialArchetypes([&](PotentialArchetype *pa) {
if (pa->isConcreteType()) return;
// Add the mapping for any potential archetypes we delayed because they
// depend on other archetypes.
for (auto pair : delayedPAs) {
auto paramTy = pair.second->getGenericParam();
auto depTy = pa->getDependentType(/*allowUnresolved=*/false);
auto inContext = genericEnv->mapTypeIntoContext(&getModule(), depTy);
auto archetypeTy = pair.second->getType(*this).getAsArchetype();
auto concreteTy = pair.second->getType(*this).getAsConcreteType();
if (archetypeTy)
genericEnv->addMapping(paramTy, archetypeTy);
else if (concreteTy)
genericEnv->addMapping(paramTy, concreteTy);
else
llvm_unreachable("broken generic parameter");
auto repDepTy = pa->getRepresentative()->getDependentType(
/*allowUnresolved=*/false);
auto repInContext = genericEnv->mapTypeIntoContext(&getModule(), repDepTy);
assert((inContext->isEqual(repInContext) ||
(inContext->hasError() && repInContext->hasError())) &&
"Potential archetype mapping differs from representative!");
});
}
#endif
return genericEnv;
}

View File

@@ -427,7 +427,8 @@ createGenericParam(ASTContext &ctx, const char *name, unsigned index) {
Module *M = ctx.TheBuiltinModule;
Identifier ident = ctx.getIdentifier(name);
SmallVector<ProtocolDecl *, 1> protos;
ArchetypeType *archetype = ArchetypeType::getNew(ctx, ident, protos, Type());
ArchetypeType *archetype = ArchetypeType::getNew(ctx, nullptr, ident, protos,
Type());
auto genericParam =
new (ctx) GenericTypeParamDecl(&M->getMainFile(FileUnitKind::Builtin),
ident, SourceLoc(), 0, index);

View File

@@ -68,6 +68,17 @@ void GenericEnvironment::addMapping(GenericTypeParamType *genericParam,
result.first->second = genericParam;
}
Optional<Type> GenericEnvironment::getMappingIfPresent(
GenericTypeParamType *genericParam) const {
auto canParamTy =
cast<GenericTypeParamType>(genericParam->getCanonicalType());
auto found = InterfaceToArchetypeMap.find(canParamTy);
if (found == InterfaceToArchetypeMap.end()) return None;
return found->second;
}
void *GenericEnvironment::operator new(size_t bytes, const ASTContext &ctx) {
return ctx.Allocate(bytes, alignof(GenericEnvironment), AllocationArena::Permanent);
}

View File

@@ -2483,7 +2483,9 @@ CanArchetypeType ArchetypeType::getNew(
}
CanArchetypeType
ArchetypeType::getNew(const ASTContext &Ctx, Identifier Name,
ArchetypeType::getNew(const ASTContext &Ctx,
GenericEnvironment *genericEnvironment,
Identifier Name,
SmallVectorImpl<ProtocolDecl *> &ConformsTo,
Type Superclass) {
// Gather the set of protocol declarations to which this archetype conforms.
@@ -2491,7 +2493,7 @@ ArchetypeType::getNew(const ASTContext &Ctx, Identifier Name,
auto arena = AllocationArena::Permanent;
return CanArchetypeType(
new (Ctx, arena) ArchetypeType(Ctx, nullptr, Name,
new (Ctx, arena) ArchetypeType(Ctx, genericEnvironment, Name,
Ctx.AllocateCopy(ConformsTo),
Superclass));
}
@@ -2505,15 +2507,6 @@ bool ArchetypeType::requiresClass() const {
return false;
}
void ArchetypeType::resolveNestedType(
std::pair<Identifier, NestedType> &nested) const {
auto &ctx = const_cast<ArchetypeType *>(this)->getASTContext();
auto lazyArchetype = ctx.getLazyArchetype(this);
nested.second = lazyArchetype.second->getNestedType(nested.first,
*lazyArchetype.first)
->getType(*lazyArchetype.first);
}
namespace {
/// \brief Function object that orders archetypes by name.
struct OrderArchetypeByName {
@@ -2556,6 +2549,16 @@ ArchetypeType::NestedType ArchetypeType::getNestedType(Identifier Name) const {
return Pos->second;
}
Optional<ArchetypeType::NestedType> ArchetypeType::getNestedTypeIfKnown(
Identifier Name) const {
auto Pos = std::lower_bound(NestedTypes.begin(), NestedTypes.end(), Name,
OrderArchetypeByName());
if (Pos == NestedTypes.end() || Pos->first != Name || !Pos->second)
return None;
return Pos->second;
}
bool ArchetypeType::hasNestedType(Identifier Name) const {
auto Pos = std::lower_bound(NestedTypes.begin(), NestedTypes.end(), Name,
OrderArchetypeByName());
@@ -2581,6 +2584,18 @@ void ArchetypeType::setNestedTypes(
NestedTypes = Ctx.AllocateCopy(Nested);
}
void ArchetypeType::registerNestedType(Identifier name, NestedType nested) {
auto found = std::lower_bound(NestedTypes.begin(), NestedTypes.end(), name,
OrderArchetypeByName());
assert(found != NestedTypes.end() && found->first == name &&
"Unable to find nested type?");
assert(!found->second ||
found->second.getValue()->isEqual(nested.getValue()) ||
(found->second.getValue()->hasError() &&
nested.getValue()->hasError()));
found->second = nested;
}
static void collectFullName(const ArchetypeType *Archetype,
SmallVectorImpl<char> &Result) {
if (auto Parent = Archetype->getParent()) {
@@ -2604,6 +2619,13 @@ std::string ArchetypeType::getFullName() const {
return Result.str().str();
}
GenericEnvironment *ArchetypeType::getGenericEnvironment() const {
if (auto parent = getParent())
return parent->getGenericEnvironment();
return ParentOrOpenedOrEnvironment.dyn_cast<GenericEnvironment *>();
}
void ProtocolCompositionType::Profile(llvm::FoldingSetNodeID &ID,
ArrayRef<Type> Protocols) {
for (auto P : Protocols)

View File

@@ -740,7 +740,8 @@ static void VisitNodeArchetype(
if (ast) {
result._types.push_back(ArchetypeType::getNew(
*ast, ast->getIdentifier(archetype_name), conforms_to, Type()));
*ast, nullptr, ast->getIdentifier(archetype_name), conforms_to,
Type()));
} else {
result._error = "invalid ASTContext";
}
@@ -769,7 +770,8 @@ static void VisitNodeArchetypeRef(
if (ast) {
SmallVector<ProtocolDecl *, 1> protocols;
result._types.push_back(ArchetypeType::getNew(
*ast, ast->getIdentifier(archetype_name), protocols, Type()));
*ast, nullptr, ast->getIdentifier(archetype_name), protocols,
Type()));
} else {
result._error = "invalid ASTContext";
}

View File

@@ -3623,7 +3623,8 @@ Type ModuleFile::getType(TypeID TID) {
archetype = ArchetypeType::getNew(ctx, parent, assocTypeDecl,
conformances, superclass);
} else {
archetype = ArchetypeType::getNew(ctx, getIdentifier(assocTypeOrNameID),
archetype = ArchetypeType::getNew(ctx, nullptr,
getIdentifier(assocTypeOrNameID),
conformances, superclass);
}