mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
2551 lines
91 KiB
C++
2551 lines
91 KiB
C++
//===--- GenericSignatureBuilder.cpp - Generic Requirement Builder --------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Support for collecting a set of generic requirements, both explicitly stated
|
|
// and inferred, and computing the archetypes and required witness tables from
|
|
// those requirements.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/AST/GenericSignatureBuilder.h"
|
|
#include "swift/AST/ASTContext.h"
|
|
#include "swift/AST/DiagnosticsSema.h"
|
|
#include "swift/AST/DiagnosticEngine.h"
|
|
#include "swift/AST/GenericEnvironment.h"
|
|
#include "swift/AST/Module.h"
|
|
#include "swift/AST/ParameterList.h"
|
|
#include "swift/AST/ProtocolConformance.h"
|
|
#include "swift/AST/TypeMatcher.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"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include <algorithm>
|
|
|
|
using namespace swift;
|
|
using llvm::DenseMap;
|
|
|
|
void RequirementSource::dump(SourceManager *srcMgr) const {
|
|
dump(llvm::errs(), srcMgr);
|
|
}
|
|
|
|
void RequirementSource::dump(llvm::raw_ostream &out,
|
|
SourceManager *srcMgr) const {
|
|
switch (getKind()) {
|
|
case Explicit:
|
|
out << "explicit";
|
|
break;
|
|
|
|
case Redundant:
|
|
out << "redundant";
|
|
break;
|
|
|
|
case Protocol:
|
|
out << "protocol";
|
|
break;
|
|
|
|
case Inferred:
|
|
out << "inferred";
|
|
break;
|
|
|
|
case Inherited:
|
|
out << "inherited";
|
|
break;
|
|
|
|
case ProtocolRequirementSignatureSelf:
|
|
out << "protocol_requirement_signature_self";
|
|
break;
|
|
}
|
|
|
|
if (srcMgr && getLoc().isValid()) {
|
|
out << " @ ";
|
|
getLoc().dump(*srcMgr);
|
|
}
|
|
}
|
|
|
|
/// Update the recorded requirement source when a new requirement
|
|
/// source provides the same requirement.
|
|
static void updateRequirementSource(RequirementSource &source,
|
|
RequirementSource newSource) {
|
|
// If the new source is less explicit than the existing source,
|
|
// or if they have the same kind but we don't have source location
|
|
// information yet, replace the existing source.
|
|
if (source.getKind() < newSource.getKind() ||
|
|
(source.getKind() == newSource.getKind() &&
|
|
!source.getLoc().isValid()))
|
|
source = newSource;
|
|
}
|
|
|
|
struct GenericSignatureBuilder::Implementation {
|
|
/// Function used to look up conformances.
|
|
std::function<GenericFunction> LookupConformance;
|
|
|
|
/// The generic parameters that this generic signature builder is working with.
|
|
SmallVector<GenericTypeParamType *, 4> GenericParams;
|
|
|
|
/// The potential archetypes for the generic parameters in \c GenericParams.
|
|
SmallVector<PotentialArchetype *, 4> PotentialArchetypes;
|
|
|
|
/// The number of nested types that haven't yet been resolved to archetypes.
|
|
/// Once all requirements have been added, this will be zero in well-formed
|
|
/// code.
|
|
unsigned NumUnresolvedNestedTypes = 0;
|
|
|
|
/// The nested types that have been renamed.
|
|
SmallVector<PotentialArchetype *, 4> RenamedNestedTypes;
|
|
|
|
#ifndef NDEBUG
|
|
/// Whether we've already finalized the builder.
|
|
bool finalized = false;
|
|
#endif
|
|
};
|
|
|
|
GenericSignatureBuilder::PotentialArchetype::~PotentialArchetype() {
|
|
for (const auto &nested : NestedTypes) {
|
|
for (auto pa : nested.second) {
|
|
if (pa != this)
|
|
delete pa;
|
|
}
|
|
}
|
|
}
|
|
|
|
std::string GenericSignatureBuilder::PotentialArchetype::getDebugName() const {
|
|
llvm::SmallString<64> result;
|
|
|
|
auto parent = getParent();
|
|
if (!parent) {
|
|
return GenericTypeParamType::get(getGenericParamKey().Depth,
|
|
getGenericParamKey().Index,
|
|
getBuilder()->getASTContext())->getName()
|
|
.str();
|
|
}
|
|
|
|
// Nested types.
|
|
result += parent->getDebugName();
|
|
|
|
// When building the name for debugging purposes, include the protocol into
|
|
// which the associated type or type alias was resolved.
|
|
ProtocolDecl *proto = nullptr;
|
|
if (auto assocType = getResolvedAssociatedType()) {
|
|
proto = assocType->getProtocol();
|
|
} else if (auto typeAlias = getTypeAliasDecl()) {
|
|
proto = typeAlias->getParent()->getAsProtocolOrProtocolExtensionContext();
|
|
}
|
|
|
|
if (proto) {
|
|
result.push_back('[');
|
|
result.push_back('.');
|
|
result.append(proto->getName().str().begin(), proto->getName().str().end());
|
|
result.push_back(']');
|
|
}
|
|
|
|
result.push_back('.');
|
|
result.append(getNestedName().str().begin(), getNestedName().str().end());
|
|
|
|
return result.str().str();
|
|
}
|
|
|
|
unsigned GenericSignatureBuilder::PotentialArchetype::getNestingDepth() const {
|
|
unsigned Depth = 0;
|
|
for (auto P = getParent(); P; P = P->getParent())
|
|
++Depth;
|
|
return Depth;
|
|
}
|
|
|
|
void GenericSignatureBuilder::PotentialArchetype::resolveAssociatedType(
|
|
AssociatedTypeDecl *assocType,
|
|
GenericSignatureBuilder &builder) {
|
|
assert(!getResolvedAssociatedType() && "associated type is already resolved");
|
|
isUnresolvedNestedType = false;
|
|
identifier.assocTypeOrAlias = assocType;
|
|
assert(assocType->getName() == getNestedName());
|
|
assert(builder.Impl->NumUnresolvedNestedTypes > 0 &&
|
|
"Mismatch in number of unresolved nested types");
|
|
--builder.Impl->NumUnresolvedNestedTypes;
|
|
}
|
|
|
|
/// Retrieve the conformance for the superclass constraint of the given
|
|
/// potential archetype (if present) to the given protocol.
|
|
///
|
|
/// \param pa The potential archetype whose superclass constraint is being
|
|
/// queried.
|
|
///
|
|
/// \param proto The protocol to which we are establishing conformance.
|
|
///
|
|
/// \param conformsSource The requirement source for the conformance to the
|
|
/// given protocol.
|
|
///
|
|
/// \param builder The generic signature builder in which the potential archetype
|
|
/// resides.
|
|
static ProtocolConformance *getSuperConformance(
|
|
GenericSignatureBuilder::PotentialArchetype *pa,
|
|
ProtocolDecl *proto,
|
|
RequirementSource &conformsSource,
|
|
GenericSignatureBuilder &builder) {
|
|
// Get the superclass constraint.
|
|
Type superclass = pa->getSuperclass();
|
|
if (!superclass) return nullptr;
|
|
|
|
// Lookup the conformance of the superclass to this protocol.
|
|
auto conformance =
|
|
builder.getLookupConformanceFn()(pa->getDependentType(
|
|
{ }, /*allowUnresolved=*/true)
|
|
->getCanonicalType(),
|
|
superclass,
|
|
proto->getDeclaredInterfaceType()
|
|
->castTo<ProtocolType>());
|
|
if (!conformance) return nullptr;
|
|
|
|
// Conformance to this protocol is redundant; update the requirement source
|
|
// appropriately.
|
|
updateRequirementSource(
|
|
conformsSource,
|
|
RequirementSource(RequirementSource::Inherited,
|
|
pa->getSuperclassSource().getLoc()));
|
|
return conformance->getConcrete();
|
|
}
|
|
|
|
/// If there is a same-type requirement to be added for the given nested type
|
|
/// due to a superclass constraint on the parent type, add it now.
|
|
static void maybeAddSameTypeRequirementForNestedType(
|
|
GenericSignatureBuilder::PotentialArchetype *nestedPA,
|
|
RequirementSource fromSource,
|
|
ProtocolConformance *superConformance,
|
|
GenericSignatureBuilder &builder) {
|
|
// If there's no super conformance, we're done.
|
|
if (!superConformance) return;
|
|
|
|
auto assocType = nestedPA->getResolvedAssociatedType();
|
|
assert(assocType && "Not resolved to an associated type?");
|
|
|
|
// Dig out the type witness.
|
|
auto concreteType =
|
|
superConformance->getTypeWitness(assocType, builder.getLazyResolver())
|
|
.getReplacement();
|
|
if (!concreteType) return;
|
|
|
|
// Add the same-type constraint.
|
|
concreteType = superConformance->getDeclContext()
|
|
->mapTypeOutOfContext(concreteType);
|
|
if (auto otherPA = builder.resolveArchetype(concreteType))
|
|
builder.addSameTypeRequirementBetweenArchetypes(
|
|
nestedPA, otherPA, fromSource);
|
|
else
|
|
builder.addSameTypeRequirementToConcrete(
|
|
nestedPA, concreteType, fromSource);
|
|
}
|
|
|
|
/// Walk the members of a protocol.
|
|
///
|
|
/// This is essentially just a call to \c proto->getMembers(), except that
|
|
/// for Objective-C-imported protocols we can simply return an empty declaration
|
|
/// range because the generic signature builder only cares about nested types (which
|
|
/// Objective-C protocols don't have).
|
|
static DeclRange getProtocolMembers(ProtocolDecl *proto) {
|
|
if (proto->hasClangNode())
|
|
return DeclRange(DeclIterator(), DeclIterator());
|
|
|
|
return proto->getMembers();
|
|
}
|
|
|
|
bool GenericSignatureBuilder::PotentialArchetype::addConformance(
|
|
ProtocolDecl *proto,
|
|
bool updateExistingSource,
|
|
const RequirementSource &source,
|
|
GenericSignatureBuilder &builder) {
|
|
auto rep = getRepresentative();
|
|
if (rep != this)
|
|
return rep->addConformance(proto, updateExistingSource, source, builder);
|
|
|
|
// Check whether we already know about this conformance.
|
|
auto known = ConformsTo.find(proto);
|
|
if (known != ConformsTo.end()) {
|
|
// We already have this requirement. Update the requirement source
|
|
// appropriately.
|
|
if (updateExistingSource)
|
|
updateRequirementSource(known->second, source);
|
|
return false;
|
|
}
|
|
|
|
// Add this conformance.
|
|
auto inserted = ConformsTo.insert(std::make_pair(proto, source)).first;
|
|
|
|
// Determine whether there is a superclass constraint where the
|
|
// superclass conforms to this protocol.
|
|
ProtocolConformance *superConformance = getSuperConformance(this, proto,
|
|
inserted->second,
|
|
builder);
|
|
|
|
RequirementSource redundantSource(RequirementSource::Redundant,
|
|
source.getLoc());
|
|
|
|
// Check whether any associated types in this protocol resolve
|
|
// nested types of this potential archetype.
|
|
for (auto member : getProtocolMembers(proto)) {
|
|
auto assocType = dyn_cast<AssociatedTypeDecl>(member);
|
|
if (!assocType)
|
|
continue;
|
|
|
|
auto known = NestedTypes.find(assocType->getName());
|
|
if (known == NestedTypes.end())
|
|
continue;
|
|
|
|
// If the nested type was not already resolved, do so now.
|
|
if (!known->second.front()->getResolvedAssociatedType()) {
|
|
known->second.front()->resolveAssociatedType(assocType, builder);
|
|
|
|
// If there's a superclass constraint that conforms to the protocol,
|
|
// add the appropriate same-type relationship.
|
|
maybeAddSameTypeRequirementForNestedType(known->second.front(),
|
|
redundantSource,
|
|
superConformance,
|
|
builder);
|
|
continue;
|
|
}
|
|
|
|
// Otherwise, create a new potential archetype for this associated type
|
|
// and make it equivalent to the first potential archetype we encountered.
|
|
auto otherPA = new PotentialArchetype(this, assocType);
|
|
known->second.push_back(otherPA);
|
|
builder.addSameTypeRequirementBetweenArchetypes(known->second.front(),
|
|
otherPA, redundantSource);
|
|
|
|
// If there's a superclass constraint that conforms to the protocol,
|
|
// add the appropriate same-type relationship.
|
|
maybeAddSameTypeRequirementForNestedType(otherPA, redundantSource,
|
|
superConformance, builder);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
auto GenericSignatureBuilder::PotentialArchetype::getRepresentative()
|
|
-> PotentialArchetype *{
|
|
// Find the representative.
|
|
PotentialArchetype *Result = Representative;
|
|
while (Result != Result->Representative)
|
|
Result = Result->Representative;
|
|
|
|
// Perform (full) path compression.
|
|
PotentialArchetype *FixUp = this;
|
|
while (FixUp != FixUp->Representative) {
|
|
PotentialArchetype *Next = FixUp->Representative;
|
|
FixUp->Representative = Result;
|
|
FixUp = Next;
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
/// Canonical ordering for dependent types in generic signatures.
|
|
static int compareDependentTypes(
|
|
GenericSignatureBuilder::PotentialArchetype * const* pa,
|
|
GenericSignatureBuilder::PotentialArchetype * const* pb) {
|
|
auto a = *pa, b = *pb;
|
|
|
|
// Fast-path check for equality.
|
|
if (a == b)
|
|
return 0;
|
|
|
|
// Ordering is as follows:
|
|
// - Generic params
|
|
if (a->isGenericParam() && b->isGenericParam())
|
|
return a->getGenericParamKey() < b->getGenericParamKey() ? -1 : +1;
|
|
|
|
// A generic parameter is always ordered before a nested type.
|
|
if (a->isGenericParam() != b->isGenericParam())
|
|
return a->isGenericParam() ? -1 : +1;
|
|
|
|
// Typealiases must be ordered *after* everything else, to ensure they
|
|
// don't become representatives in the case where a typealias is equated
|
|
// with an associated type.
|
|
if (!!a->getTypeAliasDecl() != !!b->getTypeAliasDecl())
|
|
return a->getTypeAliasDecl() ? +1 : -1;
|
|
|
|
// - Dependent members
|
|
auto ppa = a->getParent();
|
|
auto ppb = b->getParent();
|
|
|
|
// - by base, so t_0_n.`P.T` < t_1_m.`P.T`
|
|
if (int compareBases = compareDependentTypes(&ppa, &ppb))
|
|
return compareBases;
|
|
|
|
// - by name, so t_n_m.`P.T` < t_n_m.`P.U`
|
|
if (int compareNames = a->getNestedName().str().compare(
|
|
b->getNestedName().str()))
|
|
return compareNames;
|
|
|
|
if (auto *aa = a->getResolvedAssociatedType()) {
|
|
if (auto *ab = b->getResolvedAssociatedType()) {
|
|
// - by protocol, so t_n_m.`P.T` < t_n_m.`Q.T` (given P < Q)
|
|
auto protoa = aa->getProtocol();
|
|
auto protob = ab->getProtocol();
|
|
if (int compareProtocols
|
|
= ProtocolType::compareProtocols(&protoa, &protob))
|
|
return compareProtocols;
|
|
|
|
// Error case: if we have two associated types with the same name in the
|
|
// same protocol, just tie-break based on address.
|
|
if (aa != ab)
|
|
return aa < ab ? -1 : +1;
|
|
} else {
|
|
// A resolved archetype is always ordered before an unresolved one.
|
|
return -1;
|
|
}
|
|
} else {
|
|
// A resolved archetype is always ordered before an unresolved one.
|
|
if (b->getResolvedAssociatedType())
|
|
return +1;
|
|
}
|
|
|
|
// Make sure typealiases are properly ordered, to avoid crashers.
|
|
// FIXME: Ideally we would eliminate typealiases earlier.
|
|
if (auto *aa = a->getTypeAliasDecl()) {
|
|
auto *ab = b->getTypeAliasDecl();
|
|
assert(ab != nullptr && "Should have handled this case above");
|
|
|
|
// - by protocol, so t_n_m.`P.T` < t_n_m.`Q.T` (given P < Q)
|
|
auto protoa =
|
|
aa->getDeclContext()->getAsProtocolOrProtocolExtensionContext();
|
|
auto protob =
|
|
ab->getDeclContext()->getAsProtocolOrProtocolExtensionContext();
|
|
|
|
if (int compareProtocols
|
|
= ProtocolType::compareProtocols(&protoa, &protob))
|
|
return compareProtocols;
|
|
|
|
// FIXME: Arbitrarily break the result here.
|
|
if (aa != ab)
|
|
return aa < ab ? -1 : +1;
|
|
}
|
|
|
|
// Along the error path where one or both of the potential archetypes was
|
|
// renamed due to typo correction,
|
|
if (a->wasRenamed() || b->wasRenamed()) {
|
|
if (a->wasRenamed() != b->wasRenamed())
|
|
return a->wasRenamed() ? +1 : -1;
|
|
|
|
if (int compareNames = a->getOriginalName().str().compare(
|
|
b->getOriginalName().str()))
|
|
return compareNames;
|
|
}
|
|
|
|
llvm_unreachable("potential archetype total order failure");
|
|
}
|
|
|
|
/// Rebuild the given potential archetype based on anchors.
|
|
static GenericSignatureBuilder::PotentialArchetype*rebuildPotentialArchetypeAnchor(
|
|
GenericSignatureBuilder::PotentialArchetype *pa,
|
|
GenericSignatureBuilder &builder) {
|
|
if (auto parent = pa->getParent()) {
|
|
auto parentAnchor =
|
|
rebuildPotentialArchetypeAnchor(parent->getArchetypeAnchor(builder),
|
|
builder);
|
|
if (parent == parentAnchor) return pa;
|
|
|
|
if (auto assocType = pa->getResolvedAssociatedType())
|
|
return parentAnchor->getNestedType(assocType, builder);
|
|
|
|
return parentAnchor->getNestedType(pa->getNestedName(), builder);
|
|
}
|
|
|
|
return pa;
|
|
}
|
|
|
|
auto GenericSignatureBuilder::PotentialArchetype::getArchetypeAnchor(
|
|
GenericSignatureBuilder &builder)
|
|
-> PotentialArchetype * {
|
|
// Rebuild the potential archetype anchor for this type, so we'll know that
|
|
// we've seen the anchor.
|
|
(void)rebuildPotentialArchetypeAnchor(this, builder);
|
|
|
|
// The repesentative is the archetype anchor.
|
|
PotentialArchetype *anchor = getRepresentative();
|
|
|
|
#ifndef NDEBUG
|
|
// Make sure that we did, in fact, get one that is better than all others.
|
|
for (auto pa : anchor->getEquivalenceClass()) {
|
|
assert((pa == anchor || compareDependentTypes(&anchor, &pa) < 0) &&
|
|
compareDependentTypes(&pa, &anchor) >= 0 &&
|
|
"archetype anchor isn't a total order");
|
|
}
|
|
#endif
|
|
|
|
return anchor;
|
|
}
|
|
|
|
// Give a nested type the appropriately resolved concrete type, based off a
|
|
// parent PA that has a concrete type.
|
|
static void concretizeNestedTypeFromConcreteParent(
|
|
GenericSignatureBuilder::PotentialArchetype *parent,
|
|
GenericSignatureBuilder::PotentialArchetype *nestedPA, GenericSignatureBuilder &builder,
|
|
llvm::function_ref<ProtocolConformanceRef(ProtocolDecl *)>
|
|
lookupConformance) {
|
|
auto concreteParent = parent->getConcreteType();
|
|
assert(concreteParent &&
|
|
"attempting to resolve concrete nested type of non-concrete PA");
|
|
|
|
// These requirements are all redundant: they're implied by the concrete
|
|
// parent.
|
|
auto Source = RequirementSource(RequirementSource::Redundant,
|
|
parent->getConcreteTypeSource().getLoc());
|
|
|
|
auto assocType = nestedPA->getResolvedAssociatedType();
|
|
|
|
if (auto *concreteArchetype = concreteParent->getAs<ArchetypeType>()) {
|
|
Type witnessType =
|
|
concreteArchetype->getNestedType(nestedPA->getNestedName());
|
|
builder.addSameTypeRequirementToConcrete(nestedPA, witnessType, Source);
|
|
} else if (assocType) {
|
|
auto conformance = lookupConformance(assocType->getProtocol());
|
|
|
|
Type witnessType;
|
|
if (conformance.isConcrete()) {
|
|
witnessType = conformance.getConcrete()
|
|
->getTypeWitness(assocType, builder.getLazyResolver())
|
|
.getReplacement();
|
|
} else {
|
|
witnessType = DependentMemberType::get(concreteParent, assocType);
|
|
}
|
|
|
|
if (auto witnessPA = builder.resolveArchetype(witnessType)) {
|
|
builder.addSameTypeRequirementBetweenArchetypes(nestedPA, witnessPA,
|
|
Source);
|
|
} else {
|
|
builder.addSameTypeRequirementToConcrete(nestedPA, witnessType, Source);
|
|
}
|
|
}
|
|
}
|
|
|
|
auto GenericSignatureBuilder::PotentialArchetype::getNestedType(
|
|
Identifier nestedName,
|
|
GenericSignatureBuilder &builder) -> PotentialArchetype * {
|
|
// If we already have a nested type with this name, return it.
|
|
if (!NestedTypes[nestedName].empty()) {
|
|
return NestedTypes[nestedName].front();
|
|
}
|
|
|
|
// Find the same nested type within the representative (unless we are
|
|
// the representative, of course!).
|
|
PotentialArchetype *repNested = nullptr;
|
|
auto rep = getRepresentative();
|
|
if (rep != this)
|
|
repNested = rep->getNestedType(nestedName, builder);
|
|
|
|
RequirementSource redundantSource(RequirementSource::Redundant,
|
|
SourceLoc());
|
|
|
|
// Attempt to resolve this nested type to an associated type
|
|
// of one of the protocols to which the parent potential
|
|
// archetype conforms.
|
|
SmallVector<std::pair<ProtocolDecl *, RequirementSource>, 4>
|
|
conformsTo(rep->ConformsTo.begin(), rep->ConformsTo.end());
|
|
for (auto &conforms : conformsTo) {
|
|
for (auto member : conforms.first->lookupDirect(nestedName)) {
|
|
PotentialArchetype *pa;
|
|
|
|
if (auto assocType = dyn_cast<AssociatedTypeDecl>(member)) {
|
|
// Resolve this nested type to this associated type.
|
|
pa = new PotentialArchetype(this, assocType);
|
|
} else if (auto alias = dyn_cast<TypeAliasDecl>(member)) {
|
|
// Resolve this nested type to this type alias.
|
|
pa = new PotentialArchetype(this, alias);
|
|
|
|
if (!alias->hasInterfaceType())
|
|
builder.getLazyResolver()->resolveDeclSignature(alias);
|
|
if (!alias->hasInterfaceType())
|
|
continue;
|
|
|
|
auto type = alias->getDeclaredInterfaceType();
|
|
if (auto existingPA = builder.resolveArchetype(type)) {
|
|
builder.addSameTypeRequirementBetweenArchetypes(pa, existingPA,
|
|
redundantSource);
|
|
} else {
|
|
builder.addSameTypeRequirementToConcrete(pa, type, redundantSource);
|
|
}
|
|
} else
|
|
continue;
|
|
|
|
// If we have resolved this nested type to more than one associated
|
|
// type, create same-type constraints between them.
|
|
llvm::TinyPtrVector<PotentialArchetype *> &nested =
|
|
NestedTypes[nestedName];
|
|
if (!nested.empty()) {
|
|
nested.push_back(pa);
|
|
|
|
// Produce a same-type constraint between the two same-named
|
|
// potential archetypes.
|
|
builder.addSameTypeRequirementBetweenArchetypes(pa, nested.front(),
|
|
redundantSource);
|
|
} else {
|
|
nested.push_back(pa);
|
|
|
|
if (repNested) {
|
|
builder.addSameTypeRequirementBetweenArchetypes(pa, repNested,
|
|
redundantSource);
|
|
}
|
|
}
|
|
|
|
// If there's a superclass constraint that conforms to the protocol,
|
|
// add the appropriate same-type relationship.
|
|
ProtocolConformance *superConformance =
|
|
getSuperConformance(this, conforms.first, conforms.second, builder);
|
|
maybeAddSameTypeRequirementForNestedType(pa, redundantSource,
|
|
superConformance, builder);
|
|
}
|
|
}
|
|
|
|
// We couldn't resolve the nested type yet, so create an
|
|
// unresolved associated type.
|
|
llvm::TinyPtrVector<PotentialArchetype *> &nested = NestedTypes[nestedName];
|
|
if (nested.empty()) {
|
|
nested.push_back(new PotentialArchetype(this, nestedName));
|
|
++builder.Impl->NumUnresolvedNestedTypes;
|
|
}
|
|
|
|
auto nestedPA = nested.front();
|
|
|
|
// We know something concrete about the parent PA, so we need to propagate
|
|
// that information to this new archetype.
|
|
if (isConcreteType()) {
|
|
concretizeNestedTypeFromConcreteParent(
|
|
this, nestedPA, builder,
|
|
[&](ProtocolDecl *proto) -> ProtocolConformanceRef {
|
|
auto depTy = nestedPA->getDependentType({}, /*allowUnresolved=*/true)
|
|
->getCanonicalType();
|
|
auto protocolTy =
|
|
proto->getDeclaredInterfaceType()->castTo<ProtocolType>();
|
|
auto conformance = builder.getLookupConformanceFn()(
|
|
depTy, getConcreteType(), protocolTy);
|
|
assert(conformance &&
|
|
"failed to find PA's conformance to known protocol");
|
|
return *conformance;
|
|
});
|
|
}
|
|
|
|
return nestedPA;
|
|
}
|
|
|
|
auto GenericSignatureBuilder::PotentialArchetype::getNestedType(
|
|
AssociatedTypeDecl *assocType,
|
|
GenericSignatureBuilder &builder) -> PotentialArchetype * {
|
|
// Add the requirement that this type conform to the protocol of the
|
|
// associated type. We treat this as "inferred" because it comes from the
|
|
// structure of the type---there will be an explicit or implied requirement
|
|
// somewhere else.
|
|
bool failed = builder.addConformanceRequirement(
|
|
this, assocType->getProtocol(),
|
|
RequirementSource(RequirementSource::Inferred, SourceLoc()));
|
|
(void)failed;
|
|
|
|
// Trigger the construction of nested types with this name.
|
|
auto fallback = getNestedType(assocType->getName(), builder);
|
|
|
|
// Find the nested type that resolved to this associated type.
|
|
for (const auto &nested : NestedTypes[assocType->getName()]) {
|
|
if (nested->getResolvedAssociatedType() == assocType) return nested;
|
|
}
|
|
|
|
assert(failed && "unable to find nested type that we know is there");
|
|
return fallback;
|
|
}
|
|
|
|
Type GenericSignatureBuilder::PotentialArchetype::getTypeInContext(
|
|
GenericSignatureBuilder &builder,
|
|
GenericEnvironment *genericEnv) {
|
|
ArrayRef<GenericTypeParamType *> genericParams =
|
|
genericEnv->getGenericParams();
|
|
|
|
// 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(builder);
|
|
if (archetypeAnchor != this)
|
|
return archetypeAnchor->getTypeInContext(builder, genericEnv);
|
|
|
|
auto representative = getRepresentative();
|
|
ASTContext &ctx = genericEnv->getGenericSignature()->getASTContext();
|
|
|
|
// Return a concrete type or archetype we've already resolved.
|
|
if (Type concreteType = representative->getConcreteType()) {
|
|
// Otherwise, substitute in the archetypes in the environment.
|
|
// If this has a recursive type, return an error type.
|
|
if (representative->RecursiveConcreteType) {
|
|
return ErrorType::get(getDependentType(genericParams,
|
|
/*allowUnresolved=*/true));
|
|
}
|
|
|
|
return genericEnv->mapTypeIntoContext(concreteType,
|
|
builder.getLookupConformanceFn());
|
|
}
|
|
|
|
// Local function to check whether we have a generic parameter that has
|
|
// already been recorded
|
|
auto getAlreadyRecoveredGenericParam = [&]() -> Type {
|
|
if (!isGenericParam()) return Type();
|
|
|
|
auto type = genericEnv->getMappingIfPresent(getGenericParamKey());
|
|
if (!type) return Type();
|
|
|
|
// We already have a mapping for this generic parameter in the generic
|
|
// environment. Return it.
|
|
return *type;
|
|
};
|
|
|
|
AssociatedTypeDecl *assocType = nullptr;
|
|
ArchetypeType *ParentArchetype = nullptr;
|
|
if (auto parent = getParent()) {
|
|
// For nested types, first substitute into the parent so we can form the
|
|
// proper nested type.
|
|
auto parentTy = parent->getTypeInContext(builder, genericEnv);
|
|
if (!parentTy)
|
|
return ErrorType::get(getDependentType(genericParams,
|
|
/*allowUnresolved=*/true));
|
|
|
|
ParentArchetype = parentTy->getAs<ArchetypeType>();
|
|
if (!ParentArchetype) {
|
|
LazyResolver *resolver = ctx.getLazyResolver();
|
|
assert(resolver && "need a lazy resolver");
|
|
(void) resolver;
|
|
|
|
// Resolve the member type.
|
|
auto type = getDependentType(genericParams, /*allowUnresolved=*/false);
|
|
if (type->hasError())
|
|
return type;
|
|
|
|
auto depMemberType = type->castTo<DependentMemberType>();
|
|
Type memberType =
|
|
depMemberType->substBaseType(parentTy,
|
|
builder.getLookupConformanceFn());
|
|
|
|
// If the member type maps to an archetype, resolve that archetype.
|
|
if (auto memberPA = builder.resolveArchetype(memberType)) {
|
|
if (memberPA->getRepresentative() != representative) {
|
|
return memberPA->getTypeInContext(builder, genericEnv);
|
|
}
|
|
|
|
llvm_unreachable("we have no parent archetype");
|
|
}
|
|
|
|
|
|
// Otherwise, it's a concrete type.
|
|
return genericEnv->mapTypeIntoContext(memberType,
|
|
builder.getLookupConformanceFn());
|
|
}
|
|
|
|
// Check whether the parent already has a nested type with this name. If
|
|
// so, return it directly.
|
|
if (auto nested = ParentArchetype->getNestedTypeIfKnown(getNestedName()))
|
|
return *nested;
|
|
|
|
// We will build the archetype below.
|
|
assocType = getResolvedAssociatedType();
|
|
} else if (auto result = getAlreadyRecoveredGenericParam()) {
|
|
return result;
|
|
}
|
|
|
|
// Determine the superclass for the archetype. If it exists and involves
|
|
// type parameters, substitute them.
|
|
Type superclass = representative->getSuperclass();
|
|
if (superclass && superclass->hasTypeParameter()) {
|
|
if (representative->RecursiveSuperclassType) {
|
|
superclass = ErrorType::get(superclass);
|
|
} else {
|
|
superclass = genericEnv->mapTypeIntoContext(
|
|
superclass,
|
|
builder.getLookupConformanceFn());
|
|
|
|
// We might have recursively recorded the archetype; if so, return early.
|
|
// FIXME: This should be detectable before we end up building archetypes.
|
|
if (auto result = getAlreadyRecoveredGenericParam())
|
|
return result;
|
|
}
|
|
}
|
|
|
|
LayoutConstraint layout = representative->getLayout();
|
|
|
|
// Build a new archetype.
|
|
|
|
// Collect the protocol conformances for the archetype.
|
|
SmallVector<ProtocolDecl *, 4> Protos;
|
|
for (const auto &conforms : representative->getConformsTo()) {
|
|
switch (conforms.second.getKind()) {
|
|
case RequirementSource::Explicit:
|
|
case RequirementSource::Inferred:
|
|
case RequirementSource::Protocol:
|
|
case RequirementSource::ProtocolRequirementSignatureSelf:
|
|
case RequirementSource::Redundant:
|
|
Protos.push_back(conforms.first);
|
|
break;
|
|
|
|
case RequirementSource::Inherited:
|
|
// Inherited conformances are recoverable from the superclass
|
|
// constraint.
|
|
break;
|
|
}
|
|
}
|
|
|
|
// 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) {
|
|
return ErrorType::get(getDependentType(genericParams,
|
|
/*allowUnresolved=*/true));
|
|
}
|
|
|
|
// Create a nested archetype.
|
|
arch = ArchetypeType::getNew(ctx, ParentArchetype, assocType, Protos,
|
|
superclass, layout);
|
|
|
|
// Register this archetype with its parent.
|
|
ParentArchetype->registerNestedType(getNestedName(), arch);
|
|
} else {
|
|
// Create a top-level archetype.
|
|
Identifier name =
|
|
genericParams[getGenericParamKey().findIndexIn(genericParams)]->getName();
|
|
arch = ArchetypeType::getNew(ctx, genericEnv, name, Protos,
|
|
superclass, layout);
|
|
|
|
// Register the archetype with the generic environment.
|
|
genericEnv->addMapping(getGenericParamKey(), arch);
|
|
}
|
|
|
|
return arch;
|
|
}
|
|
|
|
void ArchetypeType::resolveNestedType(
|
|
std::pair<Identifier, Type> &nested) const {
|
|
auto genericEnv = getGenericEnvironment();
|
|
auto &builder = *genericEnv->getGenericSignatureBuilder();
|
|
|
|
Type interfaceType =
|
|
genericEnv->mapTypeOutOfContext(const_cast<ArchetypeType *>(this));
|
|
auto parentPA = builder.resolveArchetype(interfaceType);
|
|
auto memberPA = parentPA->getNestedType(nested.first, builder);
|
|
auto result = memberPA->getTypeInContext(builder, genericEnv);
|
|
assert(!nested.second ||
|
|
nested.second->isEqual(result) ||
|
|
(nested.second->hasError() && result->hasError()));
|
|
nested.second = result;
|
|
}
|
|
|
|
Type GenericSignatureBuilder::PotentialArchetype::getDependentType(
|
|
ArrayRef<GenericTypeParamType *> genericParams,
|
|
bool allowUnresolved) {
|
|
if (auto parent = getParent()) {
|
|
Type parentType = parent->getDependentType(genericParams,
|
|
allowUnresolved);
|
|
if (parentType->hasError())
|
|
return parentType;
|
|
|
|
// If we've resolved to an associated type, use it.
|
|
if (auto assocType = getResolvedAssociatedType())
|
|
return DependentMemberType::get(parentType, assocType);
|
|
|
|
// If we don't allow unresolved dependent member types, fail.
|
|
if (!allowUnresolved)
|
|
return ErrorType::get(getDependentType(genericParams,
|
|
/*allowUnresolved=*/true));
|
|
|
|
return DependentMemberType::get(parentType, getNestedName());
|
|
}
|
|
|
|
assert(isGenericParam() && "Not a generic parameter?");
|
|
|
|
// FIXME: This is a temporary workaround.
|
|
if (genericParams.empty())
|
|
genericParams = getBuilder()->Impl->GenericParams;
|
|
|
|
unsigned index = getGenericParamKey().findIndexIn(genericParams);
|
|
return genericParams[index];
|
|
}
|
|
|
|
void GenericSignatureBuilder::PotentialArchetype::dump(llvm::raw_ostream &Out,
|
|
SourceManager *SrcMgr,
|
|
unsigned Indent) {
|
|
// Print name.
|
|
if (Indent == 0 || isGenericParam())
|
|
Out << getDebugName();
|
|
else
|
|
Out.indent(Indent) << getNestedName();
|
|
|
|
// Print superclass.
|
|
if (Superclass) {
|
|
Out << " : ";
|
|
Superclass.print(Out);
|
|
Out << " [";
|
|
SuperclassSource->dump(Out, SrcMgr);
|
|
Out << "]";
|
|
}
|
|
|
|
// Print requirements.
|
|
if (!ConformsTo.empty()) {
|
|
Out << " : ";
|
|
|
|
bool First = true;
|
|
for (const auto &ProtoAndSource : ConformsTo) {
|
|
if (First)
|
|
First = false;
|
|
else
|
|
Out << " & ";
|
|
|
|
Out << ProtoAndSource.first->getName().str() << " [";
|
|
ProtoAndSource.second.dump(Out, SrcMgr);
|
|
Out << "]";
|
|
}
|
|
}
|
|
|
|
if (Representative != this) {
|
|
Out << " [represented by " << getRepresentative()->getDebugName() << "]";
|
|
}
|
|
|
|
if (EquivalenceClass.size() > 1) {
|
|
Out << " [equivalence class ";
|
|
bool isFirst = true;
|
|
for (auto equiv : EquivalenceClass) {
|
|
if (equiv == this) continue;
|
|
|
|
if (isFirst) isFirst = false;
|
|
else Out << ", ";
|
|
|
|
Out << equiv->getDebugName();
|
|
}
|
|
Out << "]";
|
|
}
|
|
|
|
Out << "\n";
|
|
|
|
// Print nested types.
|
|
for (const auto &nestedVec : NestedTypes) {
|
|
for (auto nested : nestedVec.second) {
|
|
nested->dump(Out, SrcMgr, Indent + 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
GenericSignatureBuilder::GenericSignatureBuilder(
|
|
ASTContext &ctx,
|
|
std::function<GenericFunction> lookupConformance)
|
|
: Context(ctx), Diags(Context.Diags), Impl(new Implementation) {
|
|
Impl->LookupConformance = std::move(lookupConformance);
|
|
}
|
|
|
|
GenericSignatureBuilder::GenericSignatureBuilder(GenericSignatureBuilder &&) = default;
|
|
|
|
GenericSignatureBuilder::~GenericSignatureBuilder() {
|
|
if (!Impl)
|
|
return;
|
|
|
|
for (auto PA : Impl->PotentialArchetypes)
|
|
delete PA;
|
|
}
|
|
|
|
std::function<GenericFunction>
|
|
GenericSignatureBuilder::getLookupConformanceFn() const {
|
|
return Impl->LookupConformance;
|
|
}
|
|
|
|
LazyResolver *GenericSignatureBuilder::getLazyResolver() const {
|
|
return Context.getLazyResolver();
|
|
}
|
|
|
|
auto GenericSignatureBuilder::resolveArchetype(Type type) -> PotentialArchetype * {
|
|
if (auto genericParam = type->getAs<GenericTypeParamType>()) {
|
|
unsigned index = GenericParamKey(genericParam).findIndexIn(
|
|
Impl->GenericParams);
|
|
if (index < Impl->GenericParams.size())
|
|
return Impl->PotentialArchetypes[index];
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
if (auto dependentMember = type->getAs<DependentMemberType>()) {
|
|
auto base = resolveArchetype(dependentMember->getBase());
|
|
if (!base)
|
|
return nullptr;
|
|
|
|
if (auto assocType = dependentMember->getAssocType())
|
|
return base->getNestedType(assocType, *this);
|
|
|
|
return base->getNestedType(dependentMember->getName(), *this);
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void GenericSignatureBuilder::addGenericParameter(GenericTypeParamDecl *GenericParam) {
|
|
addGenericParameter(
|
|
GenericParam->getDeclaredInterfaceType()->castTo<GenericTypeParamType>());
|
|
}
|
|
|
|
bool GenericSignatureBuilder::addGenericParameterRequirements(GenericTypeParamDecl *GenericParam) {
|
|
GenericParamKey Key(GenericParam);
|
|
auto PA = Impl->PotentialArchetypes[Key.findIndexIn(Impl->GenericParams)];
|
|
|
|
// Add the requirements from the declaration.
|
|
llvm::SmallPtrSet<ProtocolDecl *, 8> visited;
|
|
return addAbstractTypeParamRequirements(GenericParam, PA,
|
|
RequirementSource::Explicit,
|
|
visited);
|
|
}
|
|
|
|
void GenericSignatureBuilder::addGenericParameter(GenericTypeParamType *GenericParam) {
|
|
GenericParamKey Key(GenericParam);
|
|
assert(Impl->GenericParams.empty() ||
|
|
((Key.Depth == Impl->GenericParams.back()->getDepth() &&
|
|
Key.Index == Impl->GenericParams.back()->getIndex() + 1) ||
|
|
(Key.Depth > Impl->GenericParams.back()->getDepth() &&
|
|
Key.Index == 0)));
|
|
|
|
// Create a potential archetype for this type parameter.
|
|
auto PA = new PotentialArchetype(this, GenericParam);
|
|
Impl->GenericParams.push_back(GenericParam);
|
|
Impl->PotentialArchetypes.push_back(PA);
|
|
}
|
|
|
|
bool GenericSignatureBuilder::addConformanceRequirement(PotentialArchetype *PAT,
|
|
ProtocolDecl *Proto,
|
|
RequirementSource Source) {
|
|
llvm::SmallPtrSet<ProtocolDecl *, 8> Visited;
|
|
return addConformanceRequirement(PAT, Proto, Source, Visited);
|
|
}
|
|
|
|
bool GenericSignatureBuilder::addConformanceRequirement(PotentialArchetype *PAT,
|
|
ProtocolDecl *Proto,
|
|
RequirementSource Source,
|
|
llvm::SmallPtrSetImpl<ProtocolDecl *> &Visited) {
|
|
// Add the requirement to the representative.
|
|
auto T = PAT->getRepresentative();
|
|
|
|
// Add the requirement, if we haven't done so already.
|
|
if (!T->addConformance(Proto, /*updateExistingSource=*/true, Source, *this))
|
|
return false;
|
|
|
|
bool inserted = Visited.insert(Proto).second;
|
|
assert(inserted);
|
|
(void) inserted;
|
|
|
|
// Requirements introduced by the main protocol are explicit in a protocol
|
|
// requirement signature, but inferred from this conformance otherwise.
|
|
auto Kind =
|
|
Source.getKind() == RequirementSource::ProtocolRequirementSignatureSelf
|
|
? RequirementSource::Explicit
|
|
: RequirementSource::Protocol;
|
|
|
|
// Use the requirement signature to avoid rewalking the entire protocol. This
|
|
// cannot compute the requirement signature directly, because that may be
|
|
// infinitely recursive: this code is also used to construct it.
|
|
if (Proto->isRequirementSignatureComputed()) {
|
|
auto reqSig = Proto->getRequirementSignature();
|
|
|
|
auto concreteSelf = T->getDependentType({}, /*allowUnresolved=*/true);
|
|
auto subMap = SubstitutionMap::getProtocolSubstitutions(
|
|
Proto, concreteSelf, ProtocolConformanceRef(Proto));
|
|
|
|
for (auto rawReq : reqSig->getRequirements()) {
|
|
auto req = rawReq.subst(subMap);
|
|
assert(req && "substituting Self in requirement shouldn't fail");
|
|
RequirementSource InnerSource(Kind, Source.getLoc());
|
|
addRequirement(*req, InnerSource, Visited);
|
|
}
|
|
} else {
|
|
// Conformances to inherit protocols are explicit in a protocol requirement
|
|
// signature, but inferred from this conformance otherwise.
|
|
auto InnerKind =
|
|
Source.getKind() == RequirementSource::ProtocolRequirementSignatureSelf
|
|
? RequirementSource::Explicit
|
|
: RequirementSource::Redundant;
|
|
RequirementSource InnerSource(InnerKind, Source.getLoc());
|
|
// Add all of the inherited protocol requirements, recursively.
|
|
if (auto resolver = getLazyResolver())
|
|
resolver->resolveInheritedProtocols(Proto);
|
|
|
|
for (auto InheritedProto :
|
|
Proto->getInheritedProtocols(getLazyResolver())) {
|
|
if (Visited.count(InheritedProto)) {
|
|
markPotentialArchetypeRecursive(T, InheritedProto, InnerSource);
|
|
continue;
|
|
}
|
|
if (addConformanceRequirement(T, InheritedProto, InnerSource, Visited))
|
|
return true;
|
|
}
|
|
|
|
// Add requirements for each of the associated types.
|
|
for (auto Member : getProtocolMembers(Proto)) {
|
|
if (auto AssocType = dyn_cast<AssociatedTypeDecl>(Member)) {
|
|
// Add requirements placed directly on this associated type.
|
|
auto AssocPA = T->getNestedType(AssocType, *this);
|
|
|
|
if (AssocPA != T) {
|
|
if (addAbstractTypeParamRequirements(AssocType, AssocPA, Kind,
|
|
Visited))
|
|
return true;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
// FIXME: Requirement declarations.
|
|
}
|
|
}
|
|
|
|
Visited.erase(Proto);
|
|
return false;
|
|
}
|
|
|
|
bool GenericSignatureBuilder::addLayoutRequirement(PotentialArchetype *PAT,
|
|
LayoutConstraint Layout,
|
|
RequirementSource Source) {
|
|
// Add the requirement to the representative.
|
|
auto T = PAT->getRepresentative();
|
|
|
|
if (T->Layout) {
|
|
if (T->Layout == Layout) {
|
|
// Update the source.
|
|
T->LayoutSource = Source;
|
|
return false;
|
|
}
|
|
// There is an existing layout constraint for this archetype.
|
|
Diags.diagnose(Source.getLoc(), diag::mutiple_layout_constraints,
|
|
Layout, T->Layout);
|
|
Diags.diagnose(T->LayoutSource->getLoc(),
|
|
diag::previous_layout_constraint, T->Layout);
|
|
T->setInvalid();
|
|
|
|
return true;
|
|
}
|
|
|
|
T->Layout = Layout;
|
|
T->LayoutSource = Source;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool GenericSignatureBuilder::addSuperclassRequirement(PotentialArchetype *T,
|
|
Type Superclass,
|
|
RequirementSource Source) {
|
|
T = T->getRepresentative();
|
|
|
|
// Make sure the concrete type fulfills the superclass requirement
|
|
// of the archetype.
|
|
if (T->isConcreteType()) {
|
|
Type concrete = T->getConcreteType();
|
|
if (!Superclass->isExactSuperclassOf(concrete, getLazyResolver())) {
|
|
Diags.diagnose(T->getConcreteTypeSource().getLoc(),
|
|
diag::type_does_not_inherit,
|
|
T->getDependentType(/*FIXME:*/{ },
|
|
/*allowUnresolved=*/true),
|
|
concrete, Superclass)
|
|
.highlight(Source.getLoc());
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Local function to handle the update of superclass conformances
|
|
// when the superclass constraint changes.
|
|
auto updateSuperclassConformances = [&] {
|
|
for (auto &conforms : T->ConformsTo) {
|
|
if (auto superConformance = getSuperConformance(T, conforms.first,
|
|
conforms.second, *this)) {
|
|
for (auto req : getProtocolMembers(conforms.first)) {
|
|
auto assocType = dyn_cast<AssociatedTypeDecl>(req);
|
|
if (!assocType) continue;
|
|
|
|
const auto &nestedTypes = T->getNestedTypes();
|
|
auto nested = nestedTypes.find(assocType->getName());
|
|
if (nested == nestedTypes.end()) continue;
|
|
|
|
RequirementSource redundantSource(RequirementSource::Inherited,
|
|
Source.getLoc());
|
|
|
|
for (auto nestedPA : nested->second) {
|
|
if (nestedPA->getResolvedAssociatedType() == assocType)
|
|
maybeAddSameTypeRequirementForNestedType(nestedPA,
|
|
redundantSource,
|
|
superConformance, *this);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// If T already has a superclass, make sure it's related.
|
|
if (T->Superclass) {
|
|
// TODO: In principle, this could be isBindableToSuperclassOf instead of
|
|
// isExactSubclassOf. If you had:
|
|
//
|
|
// class Foo<T>
|
|
// class Bar: Foo<Int>
|
|
//
|
|
// func foo<T, U where U: Foo<T>, U: Bar>(...) { ... }
|
|
//
|
|
// then the second constraint should be allowed, constraining U to Bar
|
|
// and secondarily imposing a T == Int constraint.
|
|
if (T->Superclass->isExactSuperclassOf(Superclass, nullptr)) {
|
|
T->Superclass = Superclass;
|
|
|
|
// We've strengthened the bound, so update superclass conformances.
|
|
updateSuperclassConformances();
|
|
// TODO: Similar to the above, a more general isBindableToSuperclassOf
|
|
// base class constraint could potentially introduce secondary constraints.
|
|
// If you had:
|
|
//
|
|
// class Foo<T>
|
|
// class Bar: Foo<Int>
|
|
//
|
|
// func foo<T, U where U: Bar, U: Foo<T>>(...) { ... }
|
|
//
|
|
// then the second `U: Foo<T>` constraint introduces a `T == Int`
|
|
// constraint.
|
|
} else if (!Superclass->isExactSuperclassOf(T->Superclass, nullptr)) {
|
|
Diags.diagnose(Source.getLoc(),
|
|
diag::requires_superclass_conflict,
|
|
T->getDependentType(/*FIXME: */{ }, true),
|
|
T->Superclass, Superclass)
|
|
.highlight(T->SuperclassSource->getLoc());
|
|
return true;
|
|
}
|
|
|
|
updateRequirementSource(*T->SuperclassSource, Source);
|
|
return false;
|
|
}
|
|
|
|
// Set the superclass.
|
|
T->Superclass = Superclass;
|
|
T->SuperclassSource = Source;
|
|
|
|
// Update based on these conformances.
|
|
updateSuperclassConformances();
|
|
return false;
|
|
}
|
|
|
|
void GenericSignatureBuilder::PotentialArchetype::addSameTypeConstraint(
|
|
PotentialArchetype *otherPA,
|
|
const RequirementSource &source) {
|
|
// If the types are the same, there's nothing to do.
|
|
if (this == otherPA) return;
|
|
|
|
// Update the same-type constraints of this PA to reference the other PA.
|
|
auto insertedIntoThis = SameTypeConstraints.insert({otherPA, source});
|
|
if (!insertedIntoThis.second)
|
|
updateRequirementSource(insertedIntoThis.first->second, source);
|
|
|
|
// Update the same-type constraints of the other PA to reference this PA.
|
|
auto insertedIntoOther = otherPA->SameTypeConstraints.insert({this, source});
|
|
if (!insertedIntoOther.second)
|
|
updateRequirementSource(insertedIntoOther.first->second, source);
|
|
}
|
|
|
|
bool GenericSignatureBuilder::addSameTypeRequirementBetweenArchetypes(
|
|
PotentialArchetype *OrigT1,
|
|
PotentialArchetype *OrigT2,
|
|
RequirementSource Source)
|
|
{
|
|
// Record the same-type constraint.
|
|
OrigT1->addSameTypeConstraint(OrigT2, Source);
|
|
|
|
// Operate on the representatives
|
|
auto T1 = OrigT1->getRepresentative();
|
|
auto T2 = OrigT2->getRepresentative();
|
|
|
|
// If the representatives are already the same, we're done.
|
|
if (T1 == T2)
|
|
return false;
|
|
|
|
// Merge any concrete constraints.
|
|
Type concrete1 = T1->getConcreteType();
|
|
Type concrete2 = T2->getConcreteType();
|
|
|
|
if (concrete1 && concrete2) {
|
|
bool mismatch = addSameTypeRequirement(
|
|
concrete1, concrete2, Source, [&](Type type1, Type type2) {
|
|
Diags.diagnose(Source.getLoc(),
|
|
diag::requires_same_type_conflict,
|
|
T1->getDependentType(/*FIXME: */{ }, true), type1,
|
|
type2);
|
|
|
|
});
|
|
|
|
if (mismatch) return true;
|
|
} else if (concrete1) {
|
|
assert(!T2->ConcreteType
|
|
&& "already formed archetype for concrete-constrained parameter");
|
|
T2->ConcreteType = concrete1;
|
|
T2->ConcreteTypeSource = T1->ConcreteTypeSource;
|
|
} else if (concrete2) {
|
|
assert(!T1->ConcreteType
|
|
&& "already formed archetype for concrete-constrained parameter");
|
|
T1->ConcreteType = concrete2;
|
|
T1->ConcreteTypeSource = T2->ConcreteTypeSource;
|
|
}
|
|
|
|
// Decide which potential archetype is to be considered the representative.
|
|
// It doesn't specifically matter which we use, but it's a minor optimization
|
|
// to prefer the canonical type.
|
|
if (compareDependentTypes(&T2, &T1) < 0)
|
|
std::swap(T1, T2);
|
|
|
|
// Don't mark requirements as redundant if they come from one of our
|
|
// child archetypes. This is a targeted fix -- more general cases
|
|
// continue to break. In general, we need to detect cycles in the
|
|
// archetype graph and not propagate requirement source information
|
|
// along back edges.
|
|
bool updateExistingSource = true;
|
|
auto T2Parent = T2;
|
|
while (T2Parent != nullptr) {
|
|
if (T2Parent->getRepresentative() == T1)
|
|
updateExistingSource = false;
|
|
T2Parent = T2Parent->getParent();
|
|
}
|
|
|
|
// Another targeted fix -- don't drop conformances from generic
|
|
// parameters.
|
|
if (T1->getParent() == nullptr)
|
|
updateExistingSource = false;
|
|
|
|
// Make T1 the representative of T2, merging the equivalence classes.
|
|
T2->Representative = T1;
|
|
for (auto equiv : T2->EquivalenceClass)
|
|
T1->EquivalenceClass.push_back(equiv);
|
|
|
|
// Superclass requirements.
|
|
if (T2->Superclass) {
|
|
addSuperclassRequirement(T1, T2->getSuperclass(),
|
|
T2->getSuperclassSource());
|
|
}
|
|
|
|
// Add all of the protocol conformance requirements of T2 to T1.
|
|
for (auto conforms : T2->ConformsTo) {
|
|
T1->addConformance(conforms.first, updateExistingSource,
|
|
conforms.second, *this);
|
|
}
|
|
|
|
// Recursively merge the associated types of T2 into T1.
|
|
RequirementSource redundantSource(RequirementSource::Redundant, SourceLoc());
|
|
for (auto equivT2 : T2->EquivalenceClass) {
|
|
for (auto T2Nested : equivT2->NestedTypes) {
|
|
auto T1Nested = T1->getNestedType(T2Nested.first, *this);
|
|
if (addSameTypeRequirementBetweenArchetypes(T1Nested,
|
|
T2Nested.second.front(),
|
|
redundantSource))
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool GenericSignatureBuilder::addSameTypeRequirementToConcrete(
|
|
PotentialArchetype *T,
|
|
Type Concrete,
|
|
RequirementSource Source) {
|
|
// Operate on the representative.
|
|
T = T->getRepresentative();
|
|
|
|
// If we've already been bound to a type, we're either done, or we have a
|
|
// problem.
|
|
if (auto oldConcrete = T->getConcreteType()) {
|
|
bool mismatch = addSameTypeRequirement(
|
|
oldConcrete, Concrete, Source, [&](Type type1, Type type2) {
|
|
Diags.diagnose(Source.getLoc(),
|
|
diag::requires_same_type_conflict,
|
|
T->getDependentType(/*FIXME: */{ }, true), type1,
|
|
type2);
|
|
|
|
});
|
|
|
|
if (mismatch) return true;
|
|
return false;
|
|
}
|
|
|
|
// Make sure the concrete type fulfills the requirements on the archetype.
|
|
DenseMap<ProtocolDecl *, ProtocolConformanceRef> conformances;
|
|
if (!Concrete->is<ArchetypeType>()) {
|
|
CanType depTy = T->getDependentType({ }, /*allowUnresolved=*/true)
|
|
->getCanonicalType();
|
|
for (auto conforms : T->getConformsTo()) {
|
|
auto protocol = conforms.first;
|
|
auto conformance =
|
|
getLookupConformanceFn()(depTy, Concrete,
|
|
protocol->getDeclaredInterfaceType()
|
|
->castTo<ProtocolType>());
|
|
if (!conformance) {
|
|
Diags.diagnose(Source.getLoc(),
|
|
diag::requires_generic_param_same_type_does_not_conform,
|
|
Concrete, protocol->getName());
|
|
return true;
|
|
}
|
|
|
|
conformances.insert({protocol, *conformance});
|
|
}
|
|
}
|
|
|
|
// Record the requirement.
|
|
T->ConcreteType = Concrete;
|
|
T->ConcreteTypeSource = Source;
|
|
|
|
// Make sure the concrete type fulfills the superclass requirement
|
|
// of the archetype.
|
|
RequirementSource redundantSource(RequirementSource::Redundant,
|
|
Source.getLoc());
|
|
if (T->Superclass) {
|
|
if (!T->Superclass->isExactSuperclassOf(Concrete, getLazyResolver())) {
|
|
Diags.diagnose(Source.getLoc(), diag::type_does_not_inherit,
|
|
T->getDependentType(/*FIXME: */{ },
|
|
/*allowUnresolved=*/true),
|
|
Concrete, T->Superclass)
|
|
.highlight(T->SuperclassSource->getLoc());
|
|
return true;
|
|
}
|
|
|
|
// The superclass requirement is made redundant by the concrete type
|
|
// assignment.
|
|
updateRequirementSource(*T->SuperclassSource, redundantSource);
|
|
}
|
|
|
|
// Eagerly resolve any existing nested types to their concrete forms (others
|
|
// will be "concretized" as they are constructed, in getNestedType).
|
|
for (auto equivT : T->EquivalenceClass) {
|
|
for (auto nested : equivT->getNestedTypes()) {
|
|
concretizeNestedTypeFromConcreteParent(
|
|
equivT, nested.second.front(), *this,
|
|
[&](ProtocolDecl *proto) -> ProtocolConformanceRef {
|
|
return conformances.find(proto)->second;
|
|
});
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool GenericSignatureBuilder::addSameTypeRequirement(
|
|
Type type1, Type type2, RequirementSource source,
|
|
llvm::function_ref<void(Type, Type)> diagnoseMismatch) {
|
|
// Local class to handle matching the two sides of the same-type constraint.
|
|
class ReqTypeMatcher : public TypeMatcher<ReqTypeMatcher> {
|
|
GenericSignatureBuilder &builder;
|
|
RequirementSource source;
|
|
llvm::function_ref<void(Type, Type)> diagnoseMismatch;
|
|
|
|
public:
|
|
ReqTypeMatcher(GenericSignatureBuilder &builder, RequirementSource source,
|
|
llvm::function_ref<void(Type, Type)> diagnoseMismatch)
|
|
: builder(builder), source(source), diagnoseMismatch(diagnoseMismatch) {
|
|
}
|
|
|
|
bool mismatch(TypeBase *firstType, TypeBase *secondType,
|
|
Type sugaredFirstType) {
|
|
// Find the potential archetypes.
|
|
PotentialArchetype *pa1 = builder.resolveArchetype(firstType);
|
|
PotentialArchetype *pa2 = builder.resolveArchetype(secondType);
|
|
|
|
// If both sides of the requirement are type parameters, equate them.
|
|
if (pa1 && pa2)
|
|
return !builder.addSameTypeRequirementBetweenArchetypes(pa1, pa2,
|
|
source);
|
|
|
|
// If just one side is a type parameter, map it to a concrete type.
|
|
if (pa1)
|
|
return !builder.addSameTypeRequirementToConcrete(pa1, secondType,
|
|
source);
|
|
if (pa2)
|
|
return !builder.addSameTypeRequirementToConcrete(pa2, sugaredFirstType,
|
|
source);
|
|
|
|
diagnoseMismatch(sugaredFirstType, secondType);
|
|
return false;
|
|
}
|
|
} matcher(*this, source, diagnoseMismatch);
|
|
|
|
return !matcher.match(type1, type2);
|
|
}
|
|
|
|
// Local function to mark the given associated type as recursive,
|
|
// diagnosing it if this is the first such occurrence.
|
|
void GenericSignatureBuilder::markPotentialArchetypeRecursive(
|
|
PotentialArchetype *pa, ProtocolDecl *proto, RequirementSource source) {
|
|
if (pa->isRecursive())
|
|
return;
|
|
pa->setIsRecursive();
|
|
|
|
// FIXME: Drop this protocol.
|
|
pa->addConformance(proto, /*updateExistingSource=*/true, source, *this);
|
|
if (!pa->getParent())
|
|
return;
|
|
|
|
auto assocType = pa->getResolvedAssociatedType();
|
|
if (!assocType || assocType->isInvalid())
|
|
return;
|
|
|
|
Diags.diagnose(assocType->getLoc(), diag::recursive_requirement_reference);
|
|
|
|
// Silence downstream errors referencing this associated type.
|
|
assocType->setInvalid();
|
|
}
|
|
|
|
bool GenericSignatureBuilder::addAbstractTypeParamRequirements(
|
|
AbstractTypeParamDecl *decl,
|
|
PotentialArchetype *pa,
|
|
RequirementSource::Kind kind,
|
|
llvm::SmallPtrSetImpl<ProtocolDecl *> &visited) {
|
|
if (isa<AssociatedTypeDecl>(decl) &&
|
|
decl->hasInterfaceType() &&
|
|
decl->getInterfaceType()->is<ErrorType>())
|
|
return false;
|
|
|
|
// Otherwise, walk the 'inherited' list to identify requirements.
|
|
if (auto resolver = getLazyResolver())
|
|
resolver->resolveInheritanceClause(decl);
|
|
return visitInherited(decl->getInherited(), [&](Type inheritedType,
|
|
SourceLoc loc) -> bool {
|
|
RequirementSource source(kind, loc);
|
|
// Protocol requirement.
|
|
if (auto protocolType = inheritedType->getAs<ProtocolType>()) {
|
|
if (visited.count(protocolType->getDecl())) {
|
|
markPotentialArchetypeRecursive(pa, protocolType->getDecl(), source);
|
|
|
|
return true;
|
|
}
|
|
|
|
return addConformanceRequirement(pa, protocolType->getDecl(), source,
|
|
visited);
|
|
}
|
|
|
|
// Superclass requirement.
|
|
if (inheritedType->getClassOrBoundGenericClass()) {
|
|
return addSuperclassRequirement(pa, inheritedType, source);
|
|
}
|
|
|
|
// Note: anything else is an error, to be diagnosed later.
|
|
return false;
|
|
});
|
|
}
|
|
|
|
bool GenericSignatureBuilder::visitInherited(
|
|
ArrayRef<TypeLoc> inheritedTypes,
|
|
llvm::function_ref<bool(Type, SourceLoc)> visitor) {
|
|
// Local function that (recursively) adds inherited types.
|
|
bool isInvalid = false;
|
|
std::function<void(Type, SourceLoc)> visitInherited;
|
|
visitInherited = [&](Type inheritedType, SourceLoc loc) {
|
|
// Decompose protocol compositions.
|
|
if (auto compositionType
|
|
= inheritedType->getAs<ProtocolCompositionType>()) {
|
|
for (auto protoType : compositionType->getProtocols())
|
|
visitInherited(protoType, loc);
|
|
return;
|
|
}
|
|
|
|
isInvalid |= visitor(inheritedType, loc);
|
|
};
|
|
|
|
// Visit all of the inherited types.
|
|
for (auto inherited : inheritedTypes) {
|
|
visitInherited(inherited.getType(), inherited.getLoc());
|
|
}
|
|
|
|
return isInvalid;
|
|
}
|
|
|
|
bool GenericSignatureBuilder::addRequirement(const RequirementRepr &Req) {
|
|
switch (Req.getKind()) {
|
|
case RequirementReprKind::LayoutConstraint: {
|
|
// FIXME: Need to do something here.
|
|
PotentialArchetype *PA = resolveArchetype(Req.getSubject());
|
|
if (!PA) {
|
|
// FIXME: Poor location information.
|
|
// FIXME: Delay diagnostic until after type validation?
|
|
Diags.diagnose(Req.getColonLoc(), diag::requires_not_suitable_archetype,
|
|
0, Req.getSubjectLoc(), 0);
|
|
return true;
|
|
}
|
|
|
|
RequirementSource source(
|
|
RequirementSource::Explicit,
|
|
Req.getLayoutConstraintLoc().getSourceRange().Start);
|
|
|
|
if (addLayoutRequirement(PA, Req.getLayoutConstraint(), source))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
case RequirementReprKind::TypeConstraint: {
|
|
PotentialArchetype *PA = resolveArchetype(Req.getSubject());
|
|
if (!PA) {
|
|
// FIXME: Poor location information.
|
|
// FIXME: Delay diagnostic until after type validation?
|
|
Diags.diagnose(Req.getColonLoc(), diag::requires_not_suitable_archetype,
|
|
0, Req.getSubjectLoc(), 0);
|
|
return true;
|
|
}
|
|
|
|
// Check whether this is a supertype requirement.
|
|
RequirementSource source(RequirementSource::Explicit,
|
|
Req.getConstraintLoc().getSourceRange().Start);
|
|
if (Req.getConstraint()->getClassOrBoundGenericClass()) {
|
|
return addSuperclassRequirement(PA, Req.getConstraint(), source);
|
|
}
|
|
|
|
SmallVector<ProtocolDecl *, 4> ConformsTo;
|
|
if (!Req.getConstraint()->isExistentialType(ConformsTo)) {
|
|
// FIXME: Diagnose this failure here, rather than over in type-checking.
|
|
return true;
|
|
}
|
|
|
|
// Add each of the protocols.
|
|
for (auto Proto : ConformsTo)
|
|
if (addConformanceRequirement(PA, Proto, source))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
case RequirementReprKind::SameType:
|
|
// Require that at least one side of the requirement contain a type
|
|
// parameter.
|
|
if (!Req.getFirstType()->hasTypeParameter() &&
|
|
!Req.getSecondType()->hasTypeParameter()) {
|
|
Diags.diagnose(Req.getEqualLoc(), diag::requires_no_same_type_archetype)
|
|
.highlight(Req.getFirstTypeLoc().getSourceRange())
|
|
.highlight(Req.getSecondTypeLoc().getSourceRange());
|
|
return true;
|
|
}
|
|
|
|
return addRequirement(Requirement(RequirementKind::SameType,
|
|
Req.getFirstType(),
|
|
Req.getSecondType()),
|
|
RequirementSource(RequirementSource::Explicit,
|
|
Req.getEqualLoc()));
|
|
}
|
|
|
|
llvm_unreachable("Unhandled requirement?");
|
|
}
|
|
|
|
bool GenericSignatureBuilder::addRequirement(const Requirement &req,
|
|
RequirementSource source) {
|
|
llvm::SmallPtrSet<ProtocolDecl *, 8> Visited;
|
|
return addRequirement(req, source, Visited);
|
|
}
|
|
|
|
bool GenericSignatureBuilder::addRequirement(
|
|
const Requirement &req, RequirementSource source,
|
|
llvm::SmallPtrSetImpl<ProtocolDecl *> &Visited) {
|
|
switch (req.getKind()) {
|
|
case RequirementKind::Superclass: {
|
|
// FIXME: Diagnose this.
|
|
PotentialArchetype *pa = resolveArchetype(req.getFirstType());
|
|
if (!pa) return false;
|
|
|
|
assert(req.getSecondType()->getClassOrBoundGenericClass());
|
|
return addSuperclassRequirement(pa, req.getSecondType(), source);
|
|
}
|
|
|
|
case RequirementKind::Layout: {
|
|
// FIXME: Diagnose this.
|
|
PotentialArchetype *pa = resolveArchetype(req.getFirstType());
|
|
if (!pa) return false;
|
|
|
|
return addLayoutRequirement(pa, req.getLayoutConstraint(), source);
|
|
}
|
|
|
|
case RequirementKind::Conformance: {
|
|
// FIXME: Diagnose this.
|
|
PotentialArchetype *pa = resolveArchetype(req.getFirstType());
|
|
if (!pa) return false;
|
|
|
|
SmallVector<ProtocolDecl *, 4> conformsTo;
|
|
(void)req.getSecondType()->isExistentialType(conformsTo);
|
|
|
|
// Add each of the protocols.
|
|
for (auto proto : conformsTo) {
|
|
if (Visited.count(proto)) {
|
|
markPotentialArchetypeRecursive(pa, proto, source);
|
|
continue;
|
|
}
|
|
if (addConformanceRequirement(pa, proto, source, Visited)) return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
case RequirementKind::SameType:
|
|
return addSameTypeRequirement(
|
|
req.getFirstType(), req.getSecondType(), source,
|
|
[&](Type type1, Type type2) {
|
|
if (source.getLoc().isValid())
|
|
Diags.diagnose(source.getLoc(),
|
|
diag::requires_same_concrete_type, type1,
|
|
type2);
|
|
});
|
|
}
|
|
|
|
llvm_unreachable("Unhandled requirement?");
|
|
}
|
|
|
|
/// AST walker that infers requirements from type representations.
|
|
class GenericSignatureBuilder::InferRequirementsWalker : public TypeWalker {
|
|
GenericSignatureBuilder &Builder;
|
|
SourceLoc Loc;
|
|
unsigned MinDepth;
|
|
unsigned MaxDepth;
|
|
|
|
/// We cannot add requirements to archetypes from outer generic parameter
|
|
/// lists.
|
|
bool isOuterArchetype(PotentialArchetype *PA) {
|
|
unsigned ParamDepth = PA->getRootGenericParamKey().Depth;
|
|
assert(ParamDepth <= MaxDepth);
|
|
(void) MaxDepth;
|
|
return ParamDepth < MinDepth;
|
|
}
|
|
|
|
public:
|
|
InferRequirementsWalker(GenericSignatureBuilder &builder,
|
|
SourceLoc loc,
|
|
unsigned MinDepth,
|
|
unsigned MaxDepth)
|
|
: Builder(builder), Loc(loc), MinDepth(MinDepth), MaxDepth(MaxDepth) { }
|
|
|
|
Action walkToTypePost(Type ty) override {
|
|
auto boundGeneric = ty->getAs<BoundGenericType>();
|
|
if (!boundGeneric)
|
|
return Action::Continue;
|
|
|
|
auto genericSig = boundGeneric->getDecl()->getGenericSignature();
|
|
if (!genericSig)
|
|
return Action::Stop;
|
|
|
|
/// Retrieves the type substitution.
|
|
auto args = boundGeneric->getGenericArgs();
|
|
auto genericSigDepth =
|
|
genericSig->getInnermostGenericParams().front()->getDepth();
|
|
auto getTypeSubstitution = [&](SubstitutableType *dependentType) -> Type {
|
|
if (auto gp = dyn_cast<GenericTypeParamType>(dependentType)) {
|
|
if (gp->getDepth() == genericSigDepth)
|
|
return args[gp->getIndex()];
|
|
|
|
return gp;
|
|
}
|
|
|
|
return dependentType;
|
|
};
|
|
|
|
// Handle the requirements.
|
|
RequirementSource source(RequirementSource::Inferred, Loc);
|
|
for (const auto &rawReq : genericSig->getRequirements()) {
|
|
auto req =
|
|
rawReq.subst(getTypeSubstitution, Builder.getLookupConformanceFn());
|
|
if (!req)
|
|
continue;
|
|
|
|
switch (req->getKind()) {
|
|
case RequirementKind::SameType: {
|
|
auto firstType = req->getFirstType();
|
|
auto firstPA = Builder.resolveArchetype(firstType);
|
|
|
|
if (firstPA && isOuterArchetype(firstPA))
|
|
return Action::Continue;
|
|
|
|
auto secondType = req->getSecondType();
|
|
auto secondPA = Builder.resolveArchetype(secondType);
|
|
|
|
if (firstPA && secondPA) {
|
|
if (Builder.addSameTypeRequirementBetweenArchetypes(firstPA, secondPA,
|
|
source)) {
|
|
return Action::Stop;
|
|
}
|
|
} else if (firstPA || secondPA) {
|
|
auto PA = firstPA ? firstPA : secondPA;
|
|
auto concrete = firstPA ? secondType : firstType;
|
|
if (Builder.addSameTypeRequirementToConcrete(PA, concrete, source)) {
|
|
return Action::Stop;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case RequirementKind::Superclass:
|
|
case RequirementKind::Layout:
|
|
case RequirementKind::Conformance: {
|
|
auto subjectType = req->getFirstType();
|
|
auto subjectPA = Builder.resolveArchetype(subjectType);
|
|
if (!subjectPA) {
|
|
break;
|
|
}
|
|
|
|
if (isOuterArchetype(subjectPA))
|
|
return Action::Continue;
|
|
|
|
switch (req->getKind()) {
|
|
case RequirementKind::Conformance: {
|
|
auto proto = req->getSecondType()->castTo<ProtocolType>();
|
|
if (Builder.addConformanceRequirement(subjectPA, proto->getDecl(),
|
|
source)) {
|
|
return Action::Stop;
|
|
}
|
|
break;
|
|
}
|
|
case RequirementKind::Layout:
|
|
if (Builder.addLayoutRequirement(
|
|
subjectPA, req->getLayoutConstraint(), source)) {
|
|
return Action::Stop;
|
|
}
|
|
break;
|
|
case RequirementKind::Superclass:
|
|
if (Builder.addSuperclassRequirement(subjectPA, req->getSecondType(),
|
|
source)) {
|
|
return Action::Stop;
|
|
}
|
|
break;
|
|
case RequirementKind::SameType:
|
|
llvm_unreachable("covered by outer switch");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Action::Continue;
|
|
}
|
|
};
|
|
|
|
void GenericSignatureBuilder::inferRequirements(TypeLoc type,
|
|
unsigned minDepth,
|
|
unsigned maxDepth) {
|
|
if (!type.getType())
|
|
return;
|
|
// FIXME: Crummy source-location information.
|
|
InferRequirementsWalker walker(*this, type.getSourceRange().Start,
|
|
minDepth, maxDepth);
|
|
type.getType().walk(walker);
|
|
}
|
|
|
|
void GenericSignatureBuilder::inferRequirements(ParameterList *params,
|
|
GenericParamList *genericParams) {
|
|
if (genericParams == nullptr)
|
|
return;
|
|
|
|
unsigned depth = genericParams->getDepth();
|
|
for (auto P : *params)
|
|
inferRequirements(P->getTypeLoc(),
|
|
/*minDepth=*/depth,
|
|
/*maxDepth=*/depth);
|
|
}
|
|
|
|
/// Perform typo correction on the given nested type, producing the
|
|
/// corrected name (if successful).
|
|
static Identifier typoCorrectNestedType(
|
|
GenericSignatureBuilder::PotentialArchetype *pa) {
|
|
StringRef name = pa->getNestedName().str();
|
|
|
|
// Look through all of the associated types of all of the protocols
|
|
// to which the parent conforms.
|
|
llvm::SmallVector<Identifier, 2> bestMatches;
|
|
unsigned bestEditDistance = 0;
|
|
unsigned maxScore = (name.size() + 1) / 3;
|
|
for (const auto &conforms : pa->getParent()->getConformsTo()) {
|
|
auto proto = conforms.first;
|
|
for (auto member : getProtocolMembers(proto)) {
|
|
auto assocType = dyn_cast<AssociatedTypeDecl>(member);
|
|
if (!assocType)
|
|
continue;
|
|
|
|
unsigned dist = name.edit_distance(assocType->getName().str(),
|
|
/*AllowReplacements=*/true,
|
|
maxScore);
|
|
assert(dist > 0 && "nested type should have matched associated type");
|
|
if (bestEditDistance == 0 || dist == bestEditDistance) {
|
|
bestEditDistance = dist;
|
|
maxScore = bestEditDistance;
|
|
bestMatches.push_back(assocType->getName());
|
|
} else if (dist < bestEditDistance) {
|
|
bestEditDistance = dist;
|
|
maxScore = bestEditDistance;
|
|
bestMatches.clear();
|
|
bestMatches.push_back(assocType->getName());
|
|
}
|
|
}
|
|
}
|
|
|
|
// FIXME: Look through the superclass.
|
|
|
|
// If we didn't find any matches at all, fail.
|
|
if (bestMatches.empty())
|
|
return Identifier();
|
|
|
|
// Make sure that we didn't find more than one match at the best
|
|
// edit distance.
|
|
for (auto other : llvm::makeArrayRef(bestMatches).slice(1)) {
|
|
if (other != bestMatches.front())
|
|
return Identifier();
|
|
}
|
|
|
|
return bestMatches.front();
|
|
}
|
|
|
|
void
|
|
GenericSignatureBuilder::finalize(SourceLoc loc,
|
|
ArrayRef<GenericTypeParamType *> genericParams,
|
|
bool allowConcreteGenericParams) {
|
|
assert(!Impl->finalized && "Already finalized builder");
|
|
#ifndef NDEBUG
|
|
Impl->finalized = true;
|
|
#endif
|
|
|
|
// Local function (+ cache) describing the set of potential archetypes
|
|
// directly referenced by the concrete same-type constraint of the given
|
|
// potential archetype. Both the inputs and results are the representatives
|
|
// of their equivalence classes.
|
|
llvm::DenseMap<PotentialArchetype *,
|
|
SmallPtrSet<PotentialArchetype *, 4>> concretePAs;
|
|
auto getConcreteReferencedPAs
|
|
= [&](PotentialArchetype *pa) -> SmallPtrSet<PotentialArchetype *, 4> {
|
|
assert(pa == pa->getRepresentative() && "Only use with representatives");
|
|
auto known = concretePAs.find(pa);
|
|
if (known != concretePAs.end())
|
|
return known->second;
|
|
|
|
SmallPtrSet<PotentialArchetype *, 4> referencedPAs;
|
|
if (!pa->isConcreteType() || !pa->getConcreteType()->hasTypeParameter())
|
|
return referencedPAs;
|
|
|
|
if (auto concreteType = pa->getConcreteType()) {
|
|
if (concreteType->hasTypeParameter()) {
|
|
concreteType.visit([&](Type type) {
|
|
if (type->isTypeParameter()) {
|
|
if (auto referencedPA = resolveArchetype(type)) {
|
|
referencedPAs.insert(referencedPA->getRepresentative());
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
concretePAs[pa] = referencedPAs;
|
|
return referencedPAs;
|
|
};
|
|
|
|
/// Check whether the given type references the archetype.
|
|
auto isRecursiveConcreteType = [&](PotentialArchetype *archetype,
|
|
bool isSuperclass) {
|
|
SmallPtrSet<PotentialArchetype *, 4> visited;
|
|
SmallVector<PotentialArchetype *, 4> stack;
|
|
stack.push_back(archetype);
|
|
visited.insert(archetype);
|
|
|
|
// Check whether the specific type introduces recursion.
|
|
auto checkTypeRecursion = [&](Type type) {
|
|
if (!type->hasTypeParameter()) return false;
|
|
|
|
return type.findIf([&](Type type) {
|
|
if (type->isTypeParameter()) {
|
|
if (auto referencedPA = resolveArchetype(type)) {
|
|
referencedPA = referencedPA->getRepresentative();
|
|
if (referencedPA == archetype) return true;
|
|
|
|
if (visited.insert(referencedPA).second)
|
|
stack.push_back(referencedPA);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
});
|
|
};
|
|
|
|
while (!stack.empty()) {
|
|
auto pa = stack.back();
|
|
stack.pop_back();
|
|
|
|
// If we're checking superclasses, do so now.
|
|
if (isSuperclass) {
|
|
if (auto superclass = pa->getSuperclass()) {
|
|
if (checkTypeRecursion(superclass)) return true;
|
|
}
|
|
}
|
|
|
|
// Otherwise, look for the potential archetypes referenced by
|
|
// same-type constraints.
|
|
for (auto referencedPA : getConcreteReferencedPAs(pa)) {
|
|
// If we found a reference to the original archetype, it's recursive.
|
|
if (referencedPA == archetype) return true;
|
|
|
|
if (visited.insert(referencedPA).second)
|
|
stack.push_back(referencedPA);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
// Check for recursive same-type bindings and superclass constraints.
|
|
visitPotentialArchetypes([&](PotentialArchetype *archetype) {
|
|
if (archetype != archetype->getRepresentative()) return;
|
|
|
|
// Check for recursive same-type bindings.
|
|
if (archetype->isConcreteType()) {
|
|
if (isRecursiveConcreteType(archetype, /*isSuperclass=*/false)) {
|
|
if (archetype->ConcreteTypeSource->getLoc().isValid())
|
|
Diags.diagnose(archetype->ConcreteTypeSource->getLoc(),
|
|
diag::recursive_same_type_constraint,
|
|
archetype->getDependentType(genericParams,
|
|
/*allowUnresolved=*/true),
|
|
archetype->getConcreteType());
|
|
|
|
archetype->RecursiveConcreteType = true;
|
|
}
|
|
}
|
|
|
|
// Check for recursive superclass bindings.
|
|
if (archetype->getSuperclass()) {
|
|
if (isRecursiveConcreteType(archetype, /*isSuperclass=*/true)) {
|
|
if (archetype->SuperclassSource->getLoc().isValid())
|
|
Diags.diagnose(archetype->SuperclassSource->getLoc(),
|
|
diag::recursive_superclass_constraint,
|
|
archetype->getDependentType(genericParams,
|
|
/*allowUnresolved=*/true),
|
|
archetype->getSuperclass());
|
|
|
|
archetype->RecursiveSuperclassType = true;
|
|
}
|
|
}
|
|
});
|
|
|
|
// Create anchors for all of the potential archetypes.
|
|
// FIXME: This is because we might be missing some from the equivalence
|
|
// classes. It is an egregious hack.
|
|
visitPotentialArchetypes([&](PotentialArchetype *archetype) {
|
|
(void)archetype->getArchetypeAnchor(*this);
|
|
});
|
|
|
|
SmallPtrSet<PotentialArchetype *, 4> visited;
|
|
|
|
// Check for generic parameters which have been made concrete or equated
|
|
// with each other.
|
|
if (!allowConcreteGenericParams) {
|
|
unsigned depth = 0;
|
|
for (const auto &gp : Impl->GenericParams)
|
|
depth = std::max(depth, gp->getDepth());
|
|
|
|
for (const auto pa : Impl->PotentialArchetypes) {
|
|
auto rep = pa->getRepresentative();
|
|
|
|
if (pa->getRootGenericParamKey().Depth < depth)
|
|
continue;
|
|
|
|
if (!visited.insert(rep).second)
|
|
continue;
|
|
|
|
// Don't allow a generic parameter to be equivalent to a concrete type,
|
|
// because then we don't actually have a parameter.
|
|
if (rep->getConcreteType()) {
|
|
auto &Source = rep->ConcreteTypeSource;
|
|
|
|
// For auto-generated locations, we should have diagnosed the problem
|
|
// elsewhere already.
|
|
if (!Source->getLoc().isValid())
|
|
continue;
|
|
|
|
Diags.diagnose(Source->getLoc(),
|
|
diag::requires_generic_param_made_equal_to_concrete,
|
|
rep->getDependentType(genericParams,
|
|
/*allowUnresolved=*/true));
|
|
continue;
|
|
}
|
|
|
|
// Don't allow two generic parameters to be equivalent, because then we
|
|
// don't actually have two parameters.
|
|
for (auto other : rep->getEquivalenceClass()) {
|
|
// If it isn't a generic parameter, skip it.
|
|
if (other == pa || other->getParent() != nullptr) continue;
|
|
|
|
SourceLoc constraintLoc;
|
|
for (const auto &sameType : pa->getSameTypeConstraints()) {
|
|
SourceLoc sameTypeLoc = sameType.second.getLoc();
|
|
if (sameTypeLoc.isInvalid()) continue;
|
|
|
|
if (sameType.first == other) {
|
|
constraintLoc = sameTypeLoc;
|
|
break;
|
|
}
|
|
|
|
if (constraintLoc.isInvalid())
|
|
constraintLoc = sameTypeLoc;
|
|
}
|
|
|
|
if (constraintLoc.isInvalid())
|
|
constraintLoc = loc;
|
|
|
|
Diags.diagnose(constraintLoc,
|
|
diag::requires_generic_params_made_equal,
|
|
pa->getDependentType(genericParams, true),
|
|
other->getDependentType(genericParams, true));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// If any nested types remain unresolved, produce diagnostics.
|
|
if (Impl->NumUnresolvedNestedTypes > 0) {
|
|
visitPotentialArchetypes([&](PotentialArchetype *pa) {
|
|
// We only care about nested types that haven't been resolved.
|
|
if (pa->getParent() == nullptr || pa->getResolvedAssociatedType() ||
|
|
pa->getTypeAliasDecl() ||
|
|
/* FIXME: Should be able to handle this earlier */pa->getSuperclass())
|
|
return;
|
|
|
|
// Try to typo correct to a nested type name.
|
|
Identifier correction = typoCorrectNestedType(pa);
|
|
if (correction.empty()) {
|
|
pa->setInvalid();
|
|
return;
|
|
}
|
|
|
|
// Note that this is being renamed.
|
|
pa->saveNameForRenaming();
|
|
Impl->RenamedNestedTypes.push_back(pa);
|
|
|
|
// Resolve the associated type and merge the potential archetypes.
|
|
auto replacement = pa->getParent()->getNestedType(correction, *this);
|
|
pa->resolveAssociatedType(replacement->getResolvedAssociatedType(),
|
|
*this);
|
|
addSameTypeRequirementBetweenArchetypes(
|
|
pa, replacement,
|
|
RequirementSource(RequirementSource::Redundant, SourceLoc()));
|
|
});
|
|
}
|
|
}
|
|
|
|
bool GenericSignatureBuilder::diagnoseRemainingRenames(
|
|
SourceLoc loc,
|
|
ArrayRef<GenericTypeParamType *> genericParams) {
|
|
bool invalid = false;
|
|
|
|
for (auto pa : Impl->RenamedNestedTypes) {
|
|
if (pa->alreadyDiagnosedRename()) continue;
|
|
|
|
Diags.diagnose(loc, diag::invalid_member_type_suggest,
|
|
pa->getParent()->getDependentType(genericParams,
|
|
/*allowUnresolved=*/true),
|
|
pa->getOriginalName(), pa->getNestedName());
|
|
invalid = true;
|
|
}
|
|
|
|
return invalid;
|
|
}
|
|
|
|
template<typename F>
|
|
void GenericSignatureBuilder::visitPotentialArchetypes(F f) {
|
|
// Stack containing all of the potential archetypes to visit.
|
|
SmallVector<PotentialArchetype *, 4> stack;
|
|
llvm::SmallPtrSet<PotentialArchetype *, 4> visited;
|
|
|
|
// Add top-level potential archetypes to the stack.
|
|
for (const auto pa : Impl->PotentialArchetypes) {
|
|
if (visited.insert(pa).second)
|
|
stack.push_back(pa);
|
|
}
|
|
|
|
// Visit all of the potential archetypes.
|
|
while (!stack.empty()) {
|
|
PotentialArchetype *pa = stack.back();
|
|
stack.pop_back();
|
|
f(pa);
|
|
|
|
// Visit nested potential archetypes.
|
|
for (const auto &nested : pa->getNestedTypes()) {
|
|
for (auto nestedPA : nested.second) {
|
|
if (visited.insert(nestedPA).second) {
|
|
stack.push_back(nestedPA);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace {
|
|
using PotentialArchetype = GenericSignatureBuilder::PotentialArchetype;
|
|
} // end anonymous namespace
|
|
|
|
/// Perform a depth-first search from the given potential archetype through
|
|
/// the *implicit* same-type constraints.
|
|
///
|
|
/// \param pa The potential archetype to visit.
|
|
/// \param visited The set of potential archetypes that have already been
|
|
/// seen.
|
|
/// \param found Used to record each potential archetype visited
|
|
static void sameTypeDFS(PotentialArchetype *pa,
|
|
SmallPtrSetImpl<PotentialArchetype *> &visited,
|
|
SmallVectorImpl<PotentialArchetype *> &found) {
|
|
// If we've already visited this potential archetype, we're done.
|
|
if (!visited.insert(pa).second) return;
|
|
|
|
// Note that we've found this potential archetype.
|
|
found.push_back(pa);
|
|
|
|
// Visit its adjacent potential archetypes.
|
|
for (const auto &sameType : pa->getSameTypeConstraints()) {
|
|
switch (sameType.second.getKind()) {
|
|
case RequirementSource::Explicit:
|
|
case RequirementSource::Inferred:
|
|
case RequirementSource::ProtocolRequirementSignatureSelf:
|
|
// Skip explicit constraints.
|
|
continue;
|
|
|
|
case RequirementSource::Inherited:
|
|
case RequirementSource::Protocol:
|
|
case RequirementSource::Redundant:
|
|
break;
|
|
}
|
|
|
|
sameTypeDFS(sameType.first, visited, found);
|
|
}
|
|
}
|
|
|
|
/// Computes the ordered set of archetype anchors required to form a minimum
|
|
/// spanning tree among the connected components formed by only the implied
|
|
/// same-type requirements within the equivalence class of \c rep.
|
|
///
|
|
/// The equivalence class of the given representative potential archetype
|
|
/// (\c rep) contains all potential archetypes that are made equivalent by
|
|
/// the known set of same-type constraints, which includes both directly-
|
|
/// stated same-type constraints (e.g., \c T.A == T.B) as well as same-type
|
|
/// constraints that are implied either because the names coincide (e.g.,
|
|
/// \c T[.P1].A == T[.P2].A) or due to a requirement in a protocol.
|
|
///
|
|
/// The equivalence class of the given representative potential archetype
|
|
/// (\c rep) is formed from a graph whose vertices are the potential archetypes
|
|
/// and whose edges are the same-type constraints. These edges include both
|
|
/// directly-stated same-type constraints (e.g., \c T.A == T.B) as well as
|
|
/// same-type constraints that are implied either because the names coincide
|
|
/// (e.g., \c T[.P1].A == T[.P2].A) or due to a requirement in a protocol.
|
|
/// The equivalence class forms a single connected component.
|
|
///
|
|
/// Within that graph is a subgraph that includes only those edges that are
|
|
/// implied (and, therefore, excluding those edges that were explicitly stated).
|
|
/// The connected components within that subgraph describe the potential
|
|
/// archetypes that would be equivalence even with all of the (explicit)
|
|
/// same-type constraints removed.
|
|
///
|
|
/// The entire equivalence class can be restored by introducing edges between
|
|
/// the connected components. This function computes a minimal, canonicalized
|
|
/// set of edges (same-type constraints) needed to describe the equivalence
|
|
/// class, which is suitable for the generation of the canonical generic
|
|
/// signature.
|
|
///
|
|
/// The resulting set of "edges" is returned as a set of vertices, one per
|
|
/// connected component (of the subgraph). Each is the anchor for that
|
|
/// connected component (as determined by \c compareDependentTypes()), and the
|
|
/// set itself is ordered by \c compareDependentTypes(). The actual set of
|
|
/// canonical edges connects vertex i to vertex i+1 for i in 0..<size-1.
|
|
static SmallVector<PotentialArchetype *, 2> getSameTypeComponentAnchors(
|
|
PotentialArchetype *rep) {
|
|
SmallPtrSet<PotentialArchetype *, 8> visited;
|
|
SmallVector<PotentialArchetype *, 2> componentAnchors;
|
|
for (auto pa : rep->getEquivalenceClass()) {
|
|
// If we've already seen this potential archetype, there's nothing else to
|
|
// do.
|
|
if (visited.count(pa) != 0) continue;
|
|
|
|
// Find all of the potential archetypes within this connected component.
|
|
SmallVector<PotentialArchetype *, 2> component;
|
|
sameTypeDFS(pa, visited, component);
|
|
|
|
// Find the best anchor for this component.
|
|
PotentialArchetype *anchor = component[0];
|
|
for (auto componentPA : ArrayRef<PotentialArchetype *>(component).slice(1)){
|
|
if (compareDependentTypes(&componentPA, &anchor) < 0)
|
|
anchor = componentPA;
|
|
}
|
|
|
|
// Record the anchor.
|
|
componentAnchors.push_back(anchor);
|
|
}
|
|
|
|
llvm::array_pod_sort(componentAnchors.begin(), componentAnchors.end(),
|
|
compareDependentTypes);
|
|
|
|
return componentAnchors;
|
|
}
|
|
|
|
void GenericSignatureBuilder::enumerateRequirements(llvm::function_ref<
|
|
void (RequirementKind kind,
|
|
PotentialArchetype *archetype,
|
|
GenericSignatureBuilder::RequirementRHS constraint,
|
|
RequirementSource source)> f) {
|
|
// Collect all archetypes.
|
|
SmallVector<PotentialArchetype *, 8> archetypes;
|
|
visitPotentialArchetypes([&](PotentialArchetype *archetype) {
|
|
archetypes.push_back(archetype);
|
|
});
|
|
|
|
// Remove any invalid potential archetypes or archetypes whose parents are
|
|
// concrete; they have no requirements.
|
|
archetypes.erase(
|
|
std::remove_if(archetypes.begin(), archetypes.end(),
|
|
[&](PotentialArchetype *archetype) -> bool {
|
|
// Invalid archetypes are never representatives in well-formed or
|
|
// corrected signature, so we don't need to visit them.
|
|
if (archetype->isInvalid())
|
|
return true;
|
|
|
|
// Keep it.
|
|
return false;
|
|
}),
|
|
archetypes.end());
|
|
|
|
// Sort the archetypes in canonical order.
|
|
llvm::array_pod_sort(archetypes.begin(), archetypes.end(),
|
|
compareDependentTypes);
|
|
|
|
// Track the anchors for each of the implied connected components within the
|
|
// equivalence class of each representative.
|
|
llvm::DenseMap<PotentialArchetype *, SmallVector<PotentialArchetype *, 2>>
|
|
sameTypeComponentAnchors;
|
|
auto getSameTypeComponentAnchors =
|
|
[&](PotentialArchetype *rep) -> ArrayRef<PotentialArchetype *> {
|
|
assert(rep->getRepresentative() == rep);
|
|
auto known = sameTypeComponentAnchors.find(rep);
|
|
if (known != sameTypeComponentAnchors.end())
|
|
return known->second;
|
|
|
|
return sameTypeComponentAnchors.insert(
|
|
{rep, ::getSameTypeComponentAnchors(rep) }).first->second;
|
|
};
|
|
|
|
for (auto *archetype : archetypes) {
|
|
// Check whether this archetype is one of the anchors within its
|
|
// connected component. If so, we may need to emit a same-type constraint.
|
|
//
|
|
// FIXME: O(n) in the number of implied connected components within the
|
|
// equivalence class. The equivalence class should be small, but...
|
|
auto rep = archetype->getRepresentative();
|
|
auto componentAnchors = getSameTypeComponentAnchors(rep);
|
|
auto knownAnchor = std::find(componentAnchors.begin(),
|
|
componentAnchors.end(),
|
|
archetype);
|
|
std::function<void()> deferredSameTypeRequirement;
|
|
|
|
if (knownAnchor != componentAnchors.end()) {
|
|
// If this equivalence class is bound to a concrete type, equate the
|
|
// anchor with a concrete type.
|
|
if (auto concreteType = rep->getConcreteType()) {
|
|
f(RequirementKind::SameType, archetype, concreteType,
|
|
knownAnchor == componentAnchors.begin()
|
|
? rep->getConcreteTypeSource()
|
|
: RequirementSource(RequirementSource::Explicit, SourceLoc()));
|
|
continue;
|
|
}
|
|
|
|
// If we're at the last anchor in the component, do nothing;
|
|
auto nextAnchor = knownAnchor;
|
|
++nextAnchor;
|
|
if (nextAnchor != componentAnchors.end()) {
|
|
// Form a same-type constraint from this anchor within the component
|
|
// to the next.
|
|
// FIXME: Distinguish between explicit and inferred here?
|
|
auto otherPA = *nextAnchor;
|
|
deferredSameTypeRequirement = [&f, archetype, otherPA] {
|
|
f(RequirementKind::SameType, archetype, otherPA,
|
|
RequirementSource(RequirementSource::Explicit, SourceLoc()));
|
|
};
|
|
}
|
|
}
|
|
SWIFT_DEFER {
|
|
if (deferredSameTypeRequirement) deferredSameTypeRequirement();
|
|
};
|
|
|
|
// If this is not the archetype anchor, we're done.
|
|
if (archetype != archetype->getArchetypeAnchor(*this))
|
|
continue;
|
|
|
|
// If we have a superclass, produce a superclass requirement
|
|
if (Type superclass = rep->getSuperclass()) {
|
|
f(RequirementKind::Superclass, archetype, superclass,
|
|
rep->getSuperclassSource());
|
|
}
|
|
|
|
// If we have a layout constraint, produce a layout requirement.
|
|
if (LayoutConstraint Layout = archetype->getLayout()) {
|
|
f(RequirementKind::Layout, archetype, Layout,
|
|
archetype->getLayoutSource());
|
|
}
|
|
|
|
// Enumerate conformance requirements.
|
|
SmallVector<ProtocolDecl *, 4> protocols;
|
|
DenseMap<ProtocolDecl *, RequirementSource> protocolSources;
|
|
for (const auto &conforms : rep->getConformsTo()) {
|
|
protocols.push_back(conforms.first);
|
|
assert(protocolSources.count(conforms.first) == 0 &&
|
|
"redundant protocol requirement?");
|
|
protocolSources.insert({conforms.first, conforms.second});
|
|
}
|
|
|
|
// Sort the protocols in canonical order.
|
|
llvm::array_pod_sort(protocols.begin(), protocols.end(),
|
|
ProtocolType::compareProtocols);
|
|
|
|
// Enumerate the conformance requirements.
|
|
for (auto proto : protocols) {
|
|
assert(protocolSources.count(proto) == 1 && "Missing conformance?");
|
|
f(RequirementKind::Conformance, archetype,
|
|
proto->getDeclaredInterfaceType(),
|
|
protocolSources.find(proto)->second);
|
|
}
|
|
};
|
|
}
|
|
|
|
void GenericSignatureBuilder::dump() {
|
|
dump(llvm::errs());
|
|
}
|
|
|
|
void GenericSignatureBuilder::dump(llvm::raw_ostream &out) {
|
|
out << "Requirements:";
|
|
enumerateRequirements([&](RequirementKind kind,
|
|
PotentialArchetype *archetype,
|
|
GenericSignatureBuilder::RequirementRHS constraint,
|
|
RequirementSource source) {
|
|
switch (kind) {
|
|
case RequirementKind::Conformance:
|
|
case RequirementKind::Superclass:
|
|
out << "\n ";
|
|
out << archetype->getDebugName() << " : "
|
|
<< constraint.get<Type>().getString() << " [";
|
|
source.dump(out, &Context.SourceMgr);
|
|
out << "]";
|
|
break;
|
|
case RequirementKind::Layout:
|
|
out << "\n ";
|
|
out << archetype->getDebugName() << " : "
|
|
<< constraint.get<LayoutConstraint>().getString() << " [";
|
|
source.dump(out, &Context.SourceMgr);
|
|
out << "]";
|
|
break;
|
|
case RequirementKind::SameType:
|
|
out << "\n ";
|
|
out << archetype->getDebugName() << " == " ;
|
|
if (auto secondType = constraint.dyn_cast<Type>()) {
|
|
out << secondType.getString();
|
|
} else {
|
|
out << constraint.get<PotentialArchetype *>()->getDebugName();
|
|
}
|
|
out << " [";
|
|
source.dump(out, &Context.SourceMgr);
|
|
out << "]";
|
|
break;
|
|
}
|
|
});
|
|
out << "\n";
|
|
|
|
out << "Potential archetypes:\n";
|
|
for (auto pa : Impl->PotentialArchetypes) {
|
|
pa->dump(out, &Context.SourceMgr, 2);
|
|
}
|
|
out << "\n";
|
|
}
|
|
|
|
void GenericSignatureBuilder::addGenericSignature(GenericSignature *sig) {
|
|
if (!sig) return;
|
|
|
|
RequirementSource::Kind sourceKind = RequirementSource::Explicit;
|
|
for (auto param : sig->getGenericParams())
|
|
addGenericParameter(param);
|
|
|
|
RequirementSource source(sourceKind, SourceLoc());
|
|
for (auto &reqt : sig->getRequirements()) {
|
|
addRequirement(reqt, source);
|
|
}
|
|
}
|
|
|
|
/// Collect the set of requirements placed on the given generic parameters and
|
|
/// their associated types.
|
|
static void collectRequirements(GenericSignatureBuilder &builder,
|
|
ArrayRef<GenericTypeParamType *> params,
|
|
SmallVectorImpl<Requirement> &requirements) {
|
|
builder.enumerateRequirements([&](RequirementKind kind,
|
|
GenericSignatureBuilder::PotentialArchetype *archetype,
|
|
GenericSignatureBuilder::RequirementRHS type,
|
|
RequirementSource source) {
|
|
// Filter out redundant requirements.
|
|
switch (source.getKind()) {
|
|
case RequirementSource::Explicit:
|
|
case RequirementSource::Inferred:
|
|
// The requirement was explicit and required, keep it.
|
|
break;
|
|
|
|
case RequirementSource::Protocol:
|
|
case RequirementSource::Redundant:
|
|
case RequirementSource::Inherited:
|
|
case RequirementSource::ProtocolRequirementSignatureSelf:
|
|
// The requirement was redundant, drop it.
|
|
return;
|
|
}
|
|
|
|
auto depTy = archetype->getDependentType(params,
|
|
/*allowUnresolved=*/false);
|
|
|
|
if (depTy->hasError())
|
|
return;
|
|
|
|
Type repTy;
|
|
if (auto concreteTy = type.dyn_cast<Type>()) {
|
|
// Maybe we were equated to a concrete type...
|
|
repTy = concreteTy;
|
|
|
|
// Drop requirements involving concrete types containing
|
|
// unresolved associated types.
|
|
if (repTy.findIf([](Type t) -> bool {
|
|
if (auto *depTy = dyn_cast<DependentMemberType>(t.getPointer()))
|
|
if (depTy->getAssocType() == nullptr)
|
|
return true;
|
|
return false;
|
|
})) {
|
|
return;
|
|
}
|
|
} else if (auto layoutConstraint = type.dyn_cast<LayoutConstraint>()) {
|
|
requirements.push_back(Requirement(kind, depTy, layoutConstraint));
|
|
return;
|
|
} else {
|
|
// ...or to a dependent type.
|
|
repTy = type.get<GenericSignatureBuilder::PotentialArchetype *>()
|
|
->getDependentType(params, /*allowUnresolved=*/false);
|
|
}
|
|
|
|
if (repTy->hasError())
|
|
return;
|
|
|
|
requirements.push_back(Requirement(kind, depTy, repTy));
|
|
});
|
|
}
|
|
|
|
GenericSignature *GenericSignatureBuilder::getGenericSignature() {
|
|
assert(Impl->finalized && "Must finalize builder first");
|
|
|
|
// Collect the requirements placed on the generic parameter types.
|
|
SmallVector<Requirement, 4> requirements;
|
|
collectRequirements(*this, Impl->GenericParams, requirements);
|
|
|
|
auto sig = GenericSignature::get(Impl->GenericParams, requirements);
|
|
return sig;
|
|
}
|