[GenericSig Builder] Track and canonicalize same-type-to-concrete constraints.

Track each same-type-to-concrete constraint on the potential archetype
against which it was written, and ensure that the requirement sources
for such same-type constraints stay with the potential archetypes on
which they were described. This is similar to the way we track
same-type constraints among potential archetypes.

Use this information to canonicalize same-type-to-concrete constraints
appropriately. For each connected component within an equivalence
class of potential archetypes, select the best requirement source to
the concrete type, or substitute in an abstract requirement source if
none exists. This approach ensures that components that would be
equivalent to that concrete type anyway get a derived source, while
components that get the concrete-type equivalence by being tied to
another

To get here, we also needed to change the notion of the archetype
anchor so that potential archetypes with no same-type constraints
directly in their path are preferred over potential archetypes that do
have a same-type constraint in their path. Otherwise, the anchor might
be something that is always concrete and is, therefore, not terribly
interesting.

Fixes the new case that popped up in rdar://problem/30478915.
This commit is contained in:
Doug Gregor
2017-02-15 23:00:59 -08:00
parent e7a4fbc98b
commit 23f3ba53f8
4 changed files with 245 additions and 133 deletions

View File

@@ -296,6 +296,11 @@ public:
/// path. /// path.
bool isDerivedRequirement() const; bool isDerivedRequirement() const;
/// Whether the requirement is derived via some concrete conformance, e.g.,
/// a concrete type's conformance to a protocol or a superclass's conformance
/// to a protocol.
bool isDerivedViaConcreteConformance() const;
/// Retrieve a source location that corresponds to the requirement. /// Retrieve a source location that corresponds to the requirement.
SourceLoc getLoc() const; SourceLoc getLoc() const;
@@ -712,7 +717,8 @@ class GenericSignatureBuilder::PotentialArchetype {
/// constrained. /// constrained.
Type ConcreteType; Type ConcreteType;
/// The source of the concrete type requirement. /// The source of the concrete type requirement, if one was written
/// on this potential archetype.
const RequirementSource *ConcreteTypeSource = nullptr; const RequirementSource *ConcreteTypeSource = nullptr;
/// Whether this is an unresolved nested type. /// Whether this is an unresolved nested type.
@@ -936,15 +942,16 @@ public:
SameTypeConstraints.end()); SameTypeConstraints.end());
} }
/// Retrieve the source of the same-type constraint that maps this potential /// Retrieve the concrete type source as written on this potential archetype.
/// archetype to a concrete type. const RequirementSource *getConcreteTypeSourceAsWritten() const {
const RequirementSource *getConcreteTypeSource() const {
if (Representative != this)
return Representative->getConcreteTypeSource();
return ConcreteTypeSource; return ConcreteTypeSource;
} }
/// Find a source of the same-type constraint that maps this potential
/// archetype to a concrete type somewhere in the equivalence class of this
/// type.
const RequirementSource *findAnyConcreteTypeSourceAsWritten() const;
/// \brief Retrieve (or create) a nested type with the given name. /// \brief Retrieve (or create) a nested type with the given name.
PotentialArchetype *getNestedType(Identifier Name, PotentialArchetype *getNestedType(Identifier Name,
GenericSignatureBuilder &builder); GenericSignatureBuilder &builder);

View File

@@ -38,6 +38,10 @@
using namespace swift; using namespace swift;
using llvm::DenseMap; using llvm::DenseMap;
namespace {
typedef GenericSignatureBuilder::PotentialArchetype PotentialArchetype;
} // end anonymous namespace
struct GenericSignatureBuilder::Implementation { struct GenericSignatureBuilder::Implementation {
/// Function used to look up conformances. /// Function used to look up conformances.
std::function<GenericFunction> LookupConformance; std::function<GenericFunction> LookupConformance;
@@ -176,6 +180,28 @@ bool RequirementSource::isDerivedRequirement() const {
} }
} }
bool RequirementSource::isDerivedViaConcreteConformance() const {
for (auto source = this; source; source = source->parent) {
switch (source->kind) {
case Explicit:
case Inferred:
case NestedTypeNameMatch:
case RequirementSignatureSelf:
return false;
case Parent:
case ProtocolRequirement:
continue;
case Superclass:
case Concrete:
return true;
}
}
return false;
}
#define REQUIREMENT_SOURCE_FACTORY_BODY(SourceKind, Parent, Storage) \ #define REQUIREMENT_SOURCE_FACTORY_BODY(SourceKind, Parent, Storage) \
llvm::FoldingSetNodeID nodeID; \ llvm::FoldingSetNodeID nodeID; \
Profile(nodeID, Kind::SourceKind, Parent, Storage); \ Profile(nodeID, Kind::SourceKind, Parent, Storage); \
@@ -471,6 +497,26 @@ void GenericSignatureBuilder::PotentialArchetype::resolveAssociatedType(
--builder.Impl->NumUnresolvedNestedTypes; --builder.Impl->NumUnresolvedNestedTypes;
} }
const RequirementSource *
PotentialArchetype::findAnyConcreteTypeSourceAsWritten() const {
// If we have a concrete type source, use that.
if (ConcreteTypeSource && ConcreteTypeSource->getLoc().isValid())
return ConcreteTypeSource;
// If we don't have a concrete type, there's no source.
auto rep = getRepresentative();
if (!rep->isConcreteType()) return nullptr;
// Otherwise, go look for the source.
for (auto pa : rep->getEquivalenceClass()) {
if (pa->ConcreteTypeSource &&
pa->ConcreteTypeSource->getLoc().isValid())
return pa->ConcreteTypeSource;
}
return nullptr;
}
bool GenericSignatureBuilder::updateRequirementSource( bool GenericSignatureBuilder::updateRequirementSource(
const RequirementSource *&existingSource, const RequirementSource *&existingSource,
const RequirementSource *newSource) { const RequirementSource *newSource) {
@@ -676,32 +722,26 @@ auto GenericSignatureBuilder::PotentialArchetype::getRepresentative() const
return Result; return Result;
} }
/// Determine whether there is a concrete type anywhere in the path to the root.
static bool hasConcreteTypeInPath(
const GenericSignatureBuilder::PotentialArchetype *pa) {
for (; pa; pa = pa->getParent()) {
if (pa->isConcreteType()) return true;
}
return false;
}
/// Canonical ordering for dependent types in generic signatures. /// Canonical ordering for dependent types in generic signatures.
static int compareDependentTypes( static int compareDependentTypes(PotentialArchetype * const* pa,
GenericSignatureBuilder::PotentialArchetype * const* pa, PotentialArchetype * const* pb) {
GenericSignatureBuilder::PotentialArchetype * const* pb) {
auto a = *pa, b = *pb; auto a = *pa, b = *pb;
// Fast-path check for equality. // Fast-path check for equality.
if (a == b) if (a == b)
return 0; return 0;
// If one potential archetype has a concrete type in its path but the other // Typealiases must be ordered *after* everything else, to ensure they
// does not, prefer the one that does not. // don't become representatives in the case where a typealias is equated
auto aConcrete = hasConcreteTypeInPath(a); // with an associated type.
auto bConcrete = hasConcreteTypeInPath(b); if (a->getParent() && b->getParent() &&
if (aConcrete != bConcrete) !!a->getTypeAliasDecl() != !!b->getTypeAliasDecl())
return aConcrete ? 1 : -1; return a->getTypeAliasDecl() ? +1 : -1;
// Types that are equivalent to concrete types follow types that are still
// type parameters.
if (a->isConcreteType() != b->isConcreteType())
return a->isConcreteType() ? +1 : -1;
// Ordering is as follows: // Ordering is as follows:
// - Generic params // - Generic params
@@ -712,12 +752,6 @@ static int compareDependentTypes(
if (a->isGenericParam() != b->isGenericParam()) if (a->isGenericParam() != b->isGenericParam())
return a->isGenericParam() ? -1 : +1; 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 // - Dependent members
auto ppa = a->getParent(); auto ppa = a->getParent();
auto ppb = b->getParent(); auto ppb = b->getParent();
@@ -837,6 +871,7 @@ auto GenericSignatureBuilder::PotentialArchetype::getArchetypeAnchor(
// parent PA that has a concrete type. // parent PA that has a concrete type.
static void concretizeNestedTypeFromConcreteParent( static void concretizeNestedTypeFromConcreteParent(
GenericSignatureBuilder::PotentialArchetype *parent, GenericSignatureBuilder::PotentialArchetype *parent,
const RequirementSource *parentConcreteSource,
GenericSignatureBuilder::PotentialArchetype *nestedPA, GenericSignatureBuilder::PotentialArchetype *nestedPA,
GenericSignatureBuilder &builder, GenericSignatureBuilder &builder,
llvm::function_ref<ProtocolConformanceRef(ProtocolDecl *)> llvm::function_ref<ProtocolConformanceRef(ProtocolDecl *)>
@@ -847,8 +882,8 @@ static void concretizeNestedTypeFromConcreteParent(
// These requirements are all implied based on the parent's concrete // These requirements are all implied based on the parent's concrete
// conformance. // conformance.
auto source = parent->getConcreteTypeSource()->viaConcrete(builder, nullptr) auto source = parentConcreteSource->viaConcrete(builder, /*FIXME: */nullptr)
->viaParent(builder); ->viaParent(builder);
auto assocType = nestedPA->getResolvedAssociatedType(); auto assocType = nestedPA->getResolvedAssociatedType();
if (!assocType) return; if (!assocType) return;
@@ -882,7 +917,8 @@ auto GenericSignatureBuilder::PotentialArchetype::getNestedType(
if (rep != this) if (rep != this)
repNested = rep->getNestedType(nestedName, builder); repNested = rep->getNestedType(nestedName, builder);
auto sameNestedTypeSource = RequirementSource::forNestedTypeNameMatch(builder); auto sameNestedTypeSource =
RequirementSource::forNestedTypeNameMatch(builder);
// Attempt to resolve this nested type to an associated type // Attempt to resolve this nested type to an associated type
// of one of the protocols to which the parent potential // of one of the protocols to which the parent potential
@@ -996,19 +1032,22 @@ auto GenericSignatureBuilder::PotentialArchetype::getNestedType(
// We know something concrete about the parent PA, so we need to propagate // We know something concrete about the parent PA, so we need to propagate
// that information to this new archetype. // that information to this new archetype.
if (isConcreteType()) { if (isConcreteType()) {
concretizeNestedTypeFromConcreteParent( for (auto equivT : rep->EquivalenceClass) {
this, nestedPA, builder, concretizeNestedTypeFromConcreteParent(
[&](ProtocolDecl *proto) -> ProtocolConformanceRef { equivT, sameNestedTypeSource, nestedPA, builder,
auto depTy = nestedPA->getDependentType({}, /*allowUnresolved=*/true) [&](ProtocolDecl *proto) -> ProtocolConformanceRef {
->getCanonicalType(); auto depTy = nestedPA->getDependentType({},
auto protocolTy = /*allowUnresolved=*/true)
proto->getDeclaredInterfaceType()->castTo<ProtocolType>(); ->getCanonicalType();
auto conformance = builder.getLookupConformanceFn()( auto protocolTy =
depTy, getConcreteType(), protocolTy); proto->getDeclaredInterfaceType()->castTo<ProtocolType>();
assert(conformance && auto conformance = builder.getLookupConformanceFn()(
"failed to find PA's conformance to known protocol"); depTy, getConcreteType(), protocolTy);
return *conformance; assert(conformance &&
}); "failed to find PA's conformance to known protocol");
return *conformance;
});
}
} }
return nestedPA; return nestedPA;
@@ -1271,12 +1310,14 @@ void GenericSignatureBuilder::PotentialArchetype::dump(llvm::raw_ostream &Out,
if (ConcreteType) { if (ConcreteType) {
Out << " == "; Out << " == ";
ConcreteType.print(Out); ConcreteType.print(Out);
Out << " "; if (ConcreteTypeSource) {
if (!ConcreteTypeSource->isDerivedRequirement()) Out << " ";
Out << "*"; if (!ConcreteTypeSource->isDerivedRequirement())
Out << "["; Out << "*";
ConcreteTypeSource->print(Out, SrcMgr); Out << "[";
Out << "]"; ConcreteTypeSource->print(Out, SrcMgr);
Out << "]";
}
} }
// Print requirements. // Print requirements.
@@ -1604,12 +1645,13 @@ bool GenericSignatureBuilder::addSuperclassRequirement(PotentialArchetype *T,
if (T->isConcreteType()) { if (T->isConcreteType()) {
Type concrete = T->getConcreteType(); Type concrete = T->getConcreteType();
if (!Superclass->isExactSuperclassOf(concrete, getLazyResolver())) { if (!Superclass->isExactSuperclassOf(concrete, getLazyResolver())) {
Diags.diagnose(T->getConcreteTypeSource()->getLoc(), if (auto source = T->findAnyConcreteTypeSourceAsWritten()) {
diag::type_does_not_inherit, Diags.diagnose(source->getLoc(), diag::type_does_not_inherit,
T->getDependentType(/*FIXME:*/{ }, T->getDependentType(/*FIXME:*/{ },
/*allowUnresolved=*/true), /*allowUnresolved=*/true),
concrete, Superclass) concrete, Superclass)
.highlight(Source->getLoc()); .highlight(Source->getLoc());
}
return true; return true;
} }
@@ -1764,16 +1806,10 @@ bool GenericSignatureBuilder::addSameTypeRequirementBetweenArchetypes(
}); });
if (mismatch) return true; 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) { } else if (concrete2) {
assert(!T1->ConcreteType assert(!T1->ConcreteType
&& "already formed archetype for concrete-constrained parameter"); && "already formed archetype for concrete-constrained parameter");
T1->ConcreteType = concrete2; T1->ConcreteType = concrete2;
T1->ConcreteTypeSource = T2->ConcreteTypeSource;
} }
// Don't mark requirements as redundant if they come from one of our // Don't mark requirements as redundant if they come from one of our
@@ -1829,14 +1865,14 @@ bool GenericSignatureBuilder::addSameTypeRequirementToConcrete(
PotentialArchetype *T, PotentialArchetype *T,
Type Concrete, Type Concrete,
const RequirementSource *Source) { const RequirementSource *Source) {
// Operate on the representative. auto rep = T->getRepresentative();
T = T->getRepresentative();
// If we've already been bound to a type, we're either done, or we have a // If there is an existing source on this potential archetype, make sure
// problem. // we have the same type.
if (auto oldConcrete = T->getConcreteType()) { // FIXME: Delay until finalize().
if (auto existingSource = T->ConcreteTypeSource) {
bool mismatch = addSameTypeRequirement( bool mismatch = addSameTypeRequirement(
oldConcrete, Concrete, Source, [&](Type type1, Type type2) { T->ConcreteType, Concrete, Source, [&](Type type1, Type type2) {
Diags.diagnose(Source->getLoc(), Diags.diagnose(Source->getLoc(),
diag::requires_same_type_conflict, diag::requires_same_type_conflict,
T->getDependentType(/*FIXME: */{ }, true), type1, T->getDependentType(/*FIXME: */{ }, true), type1,
@@ -1844,15 +1880,46 @@ bool GenericSignatureBuilder::addSameTypeRequirementToConcrete(
}); });
if (mismatch) return true; if (mismatch) return true;
// If this is a better source, record it.
updateRequirementSource(T->ConcreteTypeSource, Source);
if (!rep->ConcreteType)
rep->ConcreteType = Concrete;
return false; return false;
} }
// If we've already been bound to a type, we're either done, or we have a
// problem.
// FIXME: Move, to finalize().
if (T != rep) {
if (auto oldConcrete = rep->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;
}
}
// Record the concrete type and its source.
T->ConcreteType = Concrete;
T->ConcreteTypeSource = Source;
// Make sure the concrete type fulfills the requirements on the archetype. // Make sure the concrete type fulfills the requirements on the archetype.
// FIXME: Move later...
DenseMap<ProtocolDecl *, ProtocolConformanceRef> conformances; DenseMap<ProtocolDecl *, ProtocolConformanceRef> conformances;
if (!Concrete->is<ArchetypeType>()) { if (!Concrete->is<ArchetypeType>()) {
CanType depTy = T->getDependentType({ }, /*allowUnresolved=*/true) CanType depTy = rep->getDependentType({ }, /*allowUnresolved=*/true)
->getCanonicalType(); ->getCanonicalType();
for (auto &conforms : T->getConformsTo()) { for (auto &conforms : rep->getConformsTo()) {
auto protocol = conforms.first; auto protocol = conforms.first;
auto conformance = auto conformance =
getLookupConformanceFn()(depTy, Concrete, getLookupConformanceFn()(depTy, Concrete,
@@ -1868,6 +1935,7 @@ bool GenericSignatureBuilder::addSameTypeRequirementToConcrete(
conformances.insert({protocol, *conformance}); conformances.insert({protocol, *conformance});
// Update the requirement source now that we know it's concrete. // Update the requirement source now that we know it's concrete.
// FIXME: Bad concrete source info.
auto concreteSource = Source->viaConcrete(*this, auto concreteSource = Source->viaConcrete(*this,
conformance->getConcrete()); conformance->getConcrete());
updateRequirementSource(conforms.second, concreteSource); updateRequirementSource(conforms.second, concreteSource);
@@ -1875,33 +1943,32 @@ bool GenericSignatureBuilder::addSameTypeRequirementToConcrete(
} }
// Record the requirement. // Record the requirement.
T->ConcreteType = Concrete; rep->ConcreteType = Concrete;
T->ConcreteTypeSource = Source;
// Make sure the concrete type fulfills the superclass requirement // Make sure the concrete type fulfills the superclass requirement
// of the archetype. // of the archetype.
if (T->Superclass) { if (rep->Superclass) {
if (!T->Superclass->isExactSuperclassOf(Concrete, getLazyResolver())) { if (!rep->Superclass->isExactSuperclassOf(Concrete, getLazyResolver())) {
Diags.diagnose(Source->getLoc(), diag::type_does_not_inherit, Diags.diagnose(Source->getLoc(), diag::type_does_not_inherit,
T->getDependentType(/*FIXME: */{ }, rep->getDependentType(/*FIXME: */{ },
/*allowUnresolved=*/true), /*allowUnresolved=*/true),
Concrete, T->Superclass) Concrete, rep->Superclass)
.highlight(T->SuperclassSource->getLoc()); .highlight(rep->SuperclassSource->getLoc());
return true; return true;
} }
// The superclass requirement is made redundant by the concrete type // The superclass requirement is made redundant by the concrete type
// assignment. // assignment.
auto concreteSource = Source->viaConcrete(*this, nullptr); auto concreteSource = Source->viaConcrete(*this, nullptr);
updateRequirementSource(T->SuperclassSource, concreteSource); updateRequirementSource(rep->SuperclassSource, concreteSource);
} }
// Eagerly resolve any existing nested types to their concrete forms (others // Eagerly resolve any existing nested types to their concrete forms (others
// will be "concretized" as they are constructed, in getNestedType). // will be "concretized" as they are constructed, in getNestedType).
for (auto equivT : T->EquivalenceClass) { for (auto equivT : rep->EquivalenceClass) {
for (auto nested : equivT->getNestedTypes()) { for (auto nested : equivT->getNestedTypes()) {
concretizeNestedTypeFromConcreteParent( concretizeNestedTypeFromConcreteParent(
equivT, nested.second.front(), *this, equivT, Source, nested.second.front(), *this,
[&](ProtocolDecl *proto) -> ProtocolConformanceRef { [&](ProtocolDecl *proto) -> ProtocolConformanceRef {
return conformances.find(proto)->second; return conformances.find(proto)->second;
}); });
@@ -2440,12 +2507,13 @@ GenericSignatureBuilder::finalize(SourceLoc loc,
// Check for recursive same-type bindings. // Check for recursive same-type bindings.
if (archetype->isConcreteType()) { if (archetype->isConcreteType()) {
if (isRecursiveConcreteType(archetype, /*isSuperclass=*/false)) { if (isRecursiveConcreteType(archetype, /*isSuperclass=*/false)) {
if (archetype->ConcreteTypeSource->getLoc().isValid()) if (auto source = archetype->findAnyConcreteTypeSourceAsWritten()) {
Diags.diagnose(archetype->ConcreteTypeSource->getLoc(), Diags.diagnose(source->getLoc(),
diag::recursive_same_type_constraint, diag::recursive_same_type_constraint,
archetype->getDependentType(genericParams, archetype->getDependentType(genericParams,
/*allowUnresolved=*/true), /*allowUnresolved=*/true),
archetype->getConcreteType()); archetype->getConcreteType());
}
archetype->RecursiveConcreteType = true; archetype->RecursiveConcreteType = true;
} }
@@ -2494,17 +2562,11 @@ GenericSignatureBuilder::finalize(SourceLoc loc,
// Don't allow a generic parameter to be equivalent to a concrete type, // Don't allow a generic parameter to be equivalent to a concrete type,
// because then we don't actually have a parameter. // because then we don't actually have a parameter.
if (rep->getConcreteType()) { if (rep->getConcreteType()) {
auto &Source = rep->ConcreteTypeSource; if (auto source = rep->findAnyConcreteTypeSourceAsWritten())
Diags.diagnose(source->getLoc(),
// For auto-generated locations, we should have diagnosed the problem diag::requires_generic_param_made_equal_to_concrete,
// elsewhere already. rep->getDependentType(genericParams,
if (!Source->getLoc().isValid()) /*allowUnresolved=*/true));
continue;
Diags.diagnose(Source->getLoc(),
diag::requires_generic_param_made_equal_to_concrete,
rep->getDependentType(genericParams,
/*allowUnresolved=*/true));
continue; continue;
} }
@@ -2618,10 +2680,6 @@ void GenericSignatureBuilder::visitPotentialArchetypes(F f) {
} }
} }
namespace {
using PotentialArchetype = GenericSignatureBuilder::PotentialArchetype;
} // end anonymous namespace
/// Perform a depth-first search from the given potential archetype through /// Perform a depth-first search from the given potential archetype through
/// the *implicit* same-type constraints. /// the *implicit* same-type constraints.
/// ///
@@ -2659,6 +2717,23 @@ static void sameTypeDFS(PotentialArchetype *pa,
} }
} }
namespace {
/// Describes a component in the (implied) same-type constraint graph.
struct SameTypeComponent {
/// The potential archetype that acts as the anchor for this component.
PotentialArchetype * anchor;
/// The (best) requirement source within the component that makes the
/// potential archetypes in this component equivalent to the concrete type.
const RequirementSource * concreteTypeSource;
friend bool operator<(const SameTypeComponent &lhs,
const SameTypeComponent &rhs) {
return compareDependentTypes(&lhs.anchor, &rhs.anchor) < 0;
}
};
}
/// Computes the ordered set of archetype anchors required to form a minimum /// Computes the ordered set of archetype anchors required to form a minimum
/// spanning tree among the connected components formed by only the implied /// spanning tree among the connected components formed by only the implied
/// same-type requirements within the equivalence class of \c rep. /// same-type requirements within the equivalence class of \c rep.
@@ -2695,10 +2770,10 @@ static void sameTypeDFS(PotentialArchetype *pa,
/// connected component (as determined by \c compareDependentTypes()), and the /// connected component (as determined by \c compareDependentTypes()), and the
/// set itself is ordered by \c compareDependentTypes(). The actual set of /// 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. /// canonical edges connects vertex i to vertex i+1 for i in 0..<size-1.
static SmallVector<PotentialArchetype *, 2> getSameTypeComponentAnchors( static SmallVector<SameTypeComponent, 2> getSameTypeComponents(
PotentialArchetype *rep) { PotentialArchetype *rep) {
SmallPtrSet<PotentialArchetype *, 8> visited; SmallPtrSet<PotentialArchetype *, 8> visited;
SmallVector<PotentialArchetype *, 2> componentAnchors; SmallVector<SameTypeComponent, 2> components;
for (auto pa : rep->getEquivalenceClass()) { for (auto pa : rep->getEquivalenceClass()) {
// If we've already seen this potential archetype, there's nothing else to // If we've already seen this potential archetype, there's nothing else to
// do. // do.
@@ -2708,21 +2783,31 @@ static SmallVector<PotentialArchetype *, 2> getSameTypeComponentAnchors(
SmallVector<PotentialArchetype *, 2> component; SmallVector<PotentialArchetype *, 2> component;
sameTypeDFS(pa, visited, component); sameTypeDFS(pa, visited, component);
// Find the best anchor for this component. // Find the best anchor and concrete type source for this component.
PotentialArchetype *anchor = component[0]; PotentialArchetype *anchor = component[0];
auto bestConcreteTypeSource = anchor->getConcreteTypeSourceAsWritten();
for (auto componentPA : ArrayRef<PotentialArchetype *>(component).slice(1)){ for (auto componentPA : ArrayRef<PotentialArchetype *>(component).slice(1)){
// Update the anchor.
if (compareDependentTypes(&componentPA, &anchor) < 0) if (compareDependentTypes(&componentPA, &anchor) < 0)
anchor = componentPA; anchor = componentPA;
// If this potential archetype has a better concrete type source than
// the best we've seen, take it.
if (auto concreteSource = componentPA->getConcreteTypeSourceAsWritten()) {
if (!bestConcreteTypeSource ||
concreteSource->compare(bestConcreteTypeSource) < 0)
bestConcreteTypeSource = concreteSource;
}
} }
// Record the anchor. // Record the anchor.
componentAnchors.push_back(anchor); components.push_back({anchor, bestConcreteTypeSource});
} }
llvm::array_pod_sort(componentAnchors.begin(), componentAnchors.end(), llvm::array_pod_sort(components.begin(), components.end());
compareDependentTypes);
return componentAnchors; return components;
} }
void GenericSignatureBuilder::enumerateRequirements(llvm::function_ref< void GenericSignatureBuilder::enumerateRequirements(llvm::function_ref<
@@ -2757,17 +2842,17 @@ void GenericSignatureBuilder::enumerateRequirements(llvm::function_ref<
// Track the anchors for each of the implied connected components within the // Track the anchors for each of the implied connected components within the
// equivalence class of each representative. // equivalence class of each representative.
llvm::DenseMap<PotentialArchetype *, SmallVector<PotentialArchetype *, 2>> llvm::DenseMap<PotentialArchetype *, SmallVector<SameTypeComponent, 2>>
sameTypeComponentAnchors; sameTypeComponents;
auto getSameTypeComponentAnchors = auto getSameTypeComponents =
[&](PotentialArchetype *rep) -> ArrayRef<PotentialArchetype *> { [&](PotentialArchetype *rep) -> ArrayRef<SameTypeComponent> {
assert(rep->getRepresentative() == rep); assert(rep->getRepresentative() == rep);
auto known = sameTypeComponentAnchors.find(rep); auto known = sameTypeComponents.find(rep);
if (known != sameTypeComponentAnchors.end()) if (known != sameTypeComponents.end())
return known->second; return known->second;
return sameTypeComponentAnchors.insert( return sameTypeComponents.insert(
{rep, ::getSameTypeComponentAnchors(rep) }).first->second; {rep, ::getSameTypeComponents(rep) }).first->second;
}; };
for (auto *archetype : archetypes) { for (auto *archetype : archetypes) {
@@ -2777,31 +2862,35 @@ void GenericSignatureBuilder::enumerateRequirements(llvm::function_ref<
// FIXME: O(n) in the number of implied connected components within the // FIXME: O(n) in the number of implied connected components within the
// equivalence class. The equivalence class should be small, but... // equivalence class. The equivalence class should be small, but...
auto rep = archetype->getRepresentative(); auto rep = archetype->getRepresentative();
auto componentAnchors = getSameTypeComponentAnchors(rep); auto components = getSameTypeComponents(rep);
auto knownAnchor = std::find(componentAnchors.begin(), auto knownAnchor = std::find_if(components.begin(),
componentAnchors.end(), components.end(),
archetype); [&](const SameTypeComponent &component) {
return component.anchor == archetype;
});
std::function<void()> deferredSameTypeRequirement; std::function<void()> deferredSameTypeRequirement;
if (knownAnchor != componentAnchors.end()) { if (knownAnchor != components.end()) {
// If this equivalence class is bound to a concrete type, equate the // If this equivalence class is bound to a concrete type, equate the
// anchor with a concrete type. // anchor with a concrete type.
if (auto concreteType = rep->getConcreteType()) { if (Type concreteType = rep->getConcreteType()) {
f(RequirementKind::SameType, archetype, concreteType, auto source =
knownAnchor == componentAnchors.begin() knownAnchor->concreteTypeSource
? rep->getConcreteTypeSource() ? knownAnchor->concreteTypeSource
: RequirementSource::forAbstract(*this)); : RequirementSource::forAbstract(*this);
f(RequirementKind::SameType, archetype, concreteType, source);
continue; continue;
} }
// If we're at the last anchor in the component, do nothing; // If we're at the last anchor in the component, do nothing;
auto nextAnchor = knownAnchor; auto nextAnchor = knownAnchor;
++nextAnchor; ++nextAnchor;
if (nextAnchor != componentAnchors.end()) { if (nextAnchor != components.end()) {
// Form a same-type constraint from this anchor within the component // Form a same-type constraint from this anchor within the component
// to the next. // to the next.
// FIXME: Distinguish between explicit and inferred here? // FIXME: Distinguish between explicit and inferred here?
auto otherPA = *nextAnchor; auto otherPA = nextAnchor->anchor;
deferredSameTypeRequirement = [&f, archetype, otherPA, this] { deferredSameTypeRequirement = [&f, archetype, otherPA, this] {
f(RequirementKind::SameType, archetype, otherPA, f(RequirementKind::SameType, archetype, otherPA,
RequirementSource::forAbstract(*this)); RequirementSource::forAbstract(*this));

View File

@@ -73,7 +73,7 @@ func test4<T: Barrable>(_ t: T) -> Y where T.Bar == Y {
func fail3<T: Barrable>(_ t: T) -> X func fail3<T: Barrable>(_ t: T) -> X
where T.Bar == X { // expected-error {{'X' does not conform to required protocol 'Fooable'}} where T.Bar == X { // expected-error {{'X' does not conform to required protocol 'Fooable'}}
return t.bar // expected-error{{cannot convert return expression of type 'T.Bar' to return type 'X'}} return t.bar
} }
func test5<T: Barrable>(_ t: T) -> X where T.Bar.Foo == X { func test5<T: Barrable>(_ t: T) -> X where T.Bar.Foo == X {

View File

@@ -210,7 +210,23 @@ struct X8 : P12 {
struct X9<T: P12, U: P12> where T.B == U.B { struct X9<T: P12, U: P12> where T.B == U.B {
// CHECK-LABEL: X9.upperSameTypeConstraint // CHECK-LABEL: X9.upperSameTypeConstraint
// CHECK: Generic signature: <T, U, V where T == X8, U : P12, U.B == X8.B> // CHECK: Generic signature: <T, U, V where U : P12, T == X8, U.B == X8.B>
// CHECK: Canonical generic signature: <τ_0_0, τ_0_1, τ_1_0 where τ_0_0 == X8, τ_0_1 : P12, τ_0_1.B == X7> // CHECK: Canonical generic signature: <τ_0_0, τ_0_1, τ_1_0 where τ_0_1 : P12, τ_0_0 == X8, τ_0_1.B == X7>
func upperSameTypeConstraint<V>(_: V) where T == X8 { } func upperSameTypeConstraint<V>(_: V) where T == X8 { }
} }
protocol P13 {
associatedtype C: P11
}
struct X10: P11, P12 {
typealias A = X10
typealias B = X10
}
struct X11<T: P12, U: P12> where T.B == U.B.A {
// CHECK-LABEL: X11.upperSameTypeConstraint
// CHECK: Generic signature: <T, U, V where T : P12, U == X10, T.B == X10.A>
// CHECK: Canonical generic signature: <τ_0_0, τ_0_1, τ_1_0 where τ_0_0 : P12, τ_0_1 == X10, τ_0_0.B == X10>
func upperSameTypeConstraint<V>(_: V) where U == X10 { }
}