mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Merge pull request #8112 from DougGregor/gsb-nested-types-lazier
This commit is contained in:
@@ -1025,13 +1025,41 @@ class GenericSignatureBuilder::PotentialArchetype {
|
||||
/// The source of the layout constraint requirement.
|
||||
const RequirementSource *LayoutSource = nullptr;
|
||||
|
||||
/// A stored nested type.
|
||||
struct StoredNestedType {
|
||||
/// The potential archetypes describing this nested type, all of which
|
||||
/// are equivalent.
|
||||
llvm::TinyPtrVector<PotentialArchetype *> archetypes;
|
||||
|
||||
typedef llvm::TinyPtrVector<PotentialArchetype *>::iterator iterator;
|
||||
iterator begin() { return archetypes.begin(); }
|
||||
iterator end() { return archetypes.end(); }
|
||||
|
||||
typedef llvm::TinyPtrVector<PotentialArchetype *>::const_iterator
|
||||
const_iterator;
|
||||
const_iterator begin() const { return archetypes.begin(); }
|
||||
const_iterator end() const { return archetypes.end(); }
|
||||
|
||||
PotentialArchetype *front() const { return archetypes.front(); }
|
||||
PotentialArchetype *back() const { return archetypes.back(); }
|
||||
|
||||
unsigned size() const { return archetypes.size(); }
|
||||
bool empty() const { return archetypes.empty(); }
|
||||
|
||||
void push_back(PotentialArchetype *pa) {
|
||||
archetypes.push_back(pa);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief The set of nested types of this archetype.
|
||||
///
|
||||
/// For a given nested type name, there may be multiple potential archetypes
|
||||
/// corresponding to different associated types (from different protocols)
|
||||
/// that share a name.
|
||||
llvm::MapVector<Identifier, llvm::TinyPtrVector<PotentialArchetype *>>
|
||||
NestedTypes;
|
||||
llvm::MapVector<Identifier, StoredNestedType> NestedTypes;
|
||||
|
||||
/// Tracks the number of conformances that
|
||||
unsigned numConformancesInNestedType = 0;
|
||||
|
||||
/// Whether this is an unresolved nested type.
|
||||
unsigned isUnresolvedNestedType : 1;
|
||||
@@ -1142,6 +1170,10 @@ public:
|
||||
void resolveAssociatedType(AssociatedTypeDecl *assocType,
|
||||
GenericSignatureBuilder &builder);
|
||||
|
||||
/// Resolve the potential archetype to the given typealias.
|
||||
void resolveTypeAlias(TypeAliasDecl *typealias,
|
||||
GenericSignatureBuilder &builder);
|
||||
|
||||
/// Determine whether this is a generic parameter.
|
||||
bool isGenericParam() const {
|
||||
return parentOrBuilder.is<GenericSignatureBuilder *>();
|
||||
@@ -1213,8 +1245,7 @@ public:
|
||||
}
|
||||
|
||||
/// Retrieve the set of nested types.
|
||||
const llvm::MapVector<Identifier, llvm::TinyPtrVector<PotentialArchetype *>> &
|
||||
getNestedTypes() const{
|
||||
const llvm::MapVector<Identifier, StoredNestedType> &getNestedTypes() const {
|
||||
return NestedTypes;
|
||||
}
|
||||
|
||||
@@ -1268,6 +1299,52 @@ public:
|
||||
PotentialArchetype *getNestedType(AssociatedTypeDecl *assocType,
|
||||
GenericSignatureBuilder &builder);
|
||||
|
||||
/// \brief Retrieve (or create) a nested type with a known typealias.
|
||||
PotentialArchetype *getNestedType(TypeAliasDecl *typealias,
|
||||
GenericSignatureBuilder &builder);
|
||||
|
||||
/// \brief Retrieve (or create) a nested type that is the current best
|
||||
/// nested archetype anchor (locally) with the given name.
|
||||
///
|
||||
/// When called on the archetype anchor, this will produce the named
|
||||
/// archetype anchor.
|
||||
PotentialArchetype *getNestedArchetypeAnchor(
|
||||
Identifier name,
|
||||
GenericSignatureBuilder &builder);
|
||||
|
||||
/// Describes the kind of update that is performed.
|
||||
enum class NestedTypeUpdate {
|
||||
/// Resolve an existing potential archetype, but don't create a new
|
||||
/// one if not present.
|
||||
ResolveExisting,
|
||||
/// If this potential archetype is missing, create it.
|
||||
AddIfMissing,
|
||||
/// If this potential archetype is missing and would be a better anchor,
|
||||
/// create it.
|
||||
AddIfBetterAnchor,
|
||||
};
|
||||
|
||||
/// Update the named nested type when we know this type conforms to the given
|
||||
/// protocol.
|
||||
///
|
||||
/// \returns the potential archetype associated with the associated
|
||||
/// type or typealias of the given protocol, unless the \c kind implies that
|
||||
/// a potential archetype should not be created if it's missing.
|
||||
PotentialArchetype *updateNestedTypeForConformance(
|
||||
PointerUnion<AssociatedTypeDecl *, TypeAliasDecl *> type,
|
||||
NestedTypeUpdate kind);
|
||||
|
||||
/// Update the named nested type when we know this type conforms to the given
|
||||
/// protocol.
|
||||
///
|
||||
/// \returns the potential archetype associated with either an associated
|
||||
/// type or typealias of the given protocol, unless the \c kind implies that
|
||||
/// a potential archetype should not be created if it's missing.
|
||||
PotentialArchetype *updateNestedTypeForConformance(
|
||||
Identifier name,
|
||||
ProtocolDecl *protocol,
|
||||
NestedTypeUpdate kind);
|
||||
|
||||
/// \brief Retrieve (or build) the type corresponding to the potential
|
||||
/// archetype within the given generic environment.
|
||||
Type getTypeInContext(GenericSignatureBuilder &builder,
|
||||
|
||||
@@ -737,7 +737,7 @@ unsigned GenericSignatureBuilder::PotentialArchetype::getNestingDepth() const {
|
||||
void GenericSignatureBuilder::PotentialArchetype::resolveAssociatedType(
|
||||
AssociatedTypeDecl *assocType,
|
||||
GenericSignatureBuilder &builder) {
|
||||
assert(!getResolvedAssociatedType() && "associated type is already resolved");
|
||||
assert(isUnresolvedNestedType && "associated type is already resolved");
|
||||
isUnresolvedNestedType = false;
|
||||
identifier.assocTypeOrAlias = assocType;
|
||||
assert(assocType->getName() == getNestedName());
|
||||
@@ -746,6 +746,18 @@ void GenericSignatureBuilder::PotentialArchetype::resolveAssociatedType(
|
||||
--builder.Impl->NumUnresolvedNestedTypes;
|
||||
}
|
||||
|
||||
void GenericSignatureBuilder::PotentialArchetype::resolveTypeAlias(
|
||||
TypeAliasDecl *typealias,
|
||||
GenericSignatureBuilder &builder) {
|
||||
assert(isUnresolvedNestedType && "nested type is already resolved");
|
||||
isUnresolvedNestedType = false;
|
||||
identifier.assocTypeOrAlias = typealias;
|
||||
assert(typealias->getName() == getNestedName());
|
||||
assert(builder.Impl->NumUnresolvedNestedTypes > 0 &&
|
||||
"Mismatch in number of unresolved nested types");
|
||||
--builder.Impl->NumUnresolvedNestedTypes;
|
||||
}
|
||||
|
||||
Optional<ConcreteConstraint>
|
||||
EquivalenceClass::findAnyConcreteConstraintAsWritten(
|
||||
PotentialArchetype *preferredPA) const {
|
||||
@@ -831,7 +843,8 @@ const RequirementSource *GenericSignatureBuilder::resolveSuperConformance(
|
||||
|
||||
superclassSource =
|
||||
superclassSource->viaSuperclass(*this, conformance->getConcrete());
|
||||
updateRequirementSource(protoSource, superclassSource);
|
||||
if (protoSource)
|
||||
updateRequirementSource(protoSource, superclassSource);
|
||||
return superclassSource;
|
||||
}
|
||||
|
||||
@@ -862,7 +875,6 @@ public:
|
||||
|
||||
static ResolvedType forNewTypeAlias(PotentialArchetype *pa) {
|
||||
assert(pa->getParent() && pa->getTypeAliasDecl() &&
|
||||
pa->getEquivalenceClassMembers().size() == 1 &&
|
||||
"not a new typealias");
|
||||
return ResolvedType(pa);
|
||||
}
|
||||
@@ -913,11 +925,10 @@ static DeclRange getProtocolMembers(ProtocolDecl *proto) {
|
||||
return proto->getMembers();
|
||||
}
|
||||
|
||||
bool GenericSignatureBuilder::PotentialArchetype::addConformance(
|
||||
ProtocolDecl *proto,
|
||||
bool updateExistingSource,
|
||||
const RequirementSource *source,
|
||||
GenericSignatureBuilder &builder) {
|
||||
bool PotentialArchetype::addConformance(ProtocolDecl *proto,
|
||||
bool updateExistingSource,
|
||||
const RequirementSource *source,
|
||||
GenericSignatureBuilder &builder) {
|
||||
auto rep = getRepresentative();
|
||||
if (rep != this)
|
||||
return rep->addConformance(proto, updateExistingSource, source, builder);
|
||||
@@ -935,46 +946,14 @@ bool GenericSignatureBuilder::PotentialArchetype::addConformance(
|
||||
// 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.
|
||||
auto superSource = getBuilder()->resolveSuperConformance(this, proto,
|
||||
inserted->second);
|
||||
// If there is a superclass, try to resolve the conformance immediately via
|
||||
// the superclass.
|
||||
getBuilder()->resolveSuperConformance(this, proto, inserted->second);
|
||||
|
||||
// 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(),
|
||||
superSource,
|
||||
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);
|
||||
auto sameNamedSource = RequirementSource::forNestedTypeNameMatch(
|
||||
known->second.front());
|
||||
builder.addSameTypeRequirement(known->second.front(), otherPA,
|
||||
sameNamedSource);
|
||||
|
||||
// If there's a superclass constraint that conforms to the protocol,
|
||||
// add the appropriate same-type relationship.
|
||||
maybeAddSameTypeRequirementForNestedType(otherPA, superSource, builder);
|
||||
// Resolve any existing nested types that need it.
|
||||
for (auto &nested : NestedTypes) {
|
||||
(void)updateNestedTypeForConformance(nested.first, proto,
|
||||
NestedTypeUpdate::ResolveExisting);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1020,6 +999,52 @@ auto PotentialArchetype::getRepresentative() const -> PotentialArchetype * {
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Compare two associated types.
|
||||
static int compareAssociatedTypes(AssociatedTypeDecl *assocType1,
|
||||
AssociatedTypeDecl *assocType2) {
|
||||
// - by name.
|
||||
if (int result = assocType1->getName().str().compare(
|
||||
assocType2->getName().str()))
|
||||
return result;
|
||||
|
||||
// - by protocol, so t_n_m.`P.T` < t_n_m.`Q.T` (given P < Q)
|
||||
auto proto1 = assocType1->getProtocol();
|
||||
auto proto2 = assocType2->getProtocol();
|
||||
if (int compareProtocols = ProtocolType::compareProtocols(&proto1, &proto2))
|
||||
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 (assocType1 != assocType2)
|
||||
return assocType1 < assocType2 ? -1 : +1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Compare two typealiases in protocols.
|
||||
static int compareTypeAliases(TypeAliasDecl *typealias1,
|
||||
TypeAliasDecl *typealias2) {
|
||||
// - by name.
|
||||
if (int result = typealias1->getName().str().compare(
|
||||
typealias2->getName().str()))
|
||||
return result;
|
||||
|
||||
// - by protocol, so t_n_m.`P.T` < t_n_m.`Q.T` (given P < Q)
|
||||
auto proto1 =
|
||||
typealias1->getDeclContext()->getAsProtocolOrProtocolExtensionContext();
|
||||
auto proto2 =
|
||||
typealias2->getDeclContext()->getAsProtocolOrProtocolExtensionContext();
|
||||
if (int compareProtocols = ProtocolType::compareProtocols(&proto1, &proto2))
|
||||
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 (typealias1 != typealias2)
|
||||
return typealias1 < typealias2 ? -1 : +1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Canonical ordering for dependent types in generic signatures.
|
||||
static int compareDependentTypes(PotentialArchetype * const* pa,
|
||||
PotentialArchetype * const* pb) {
|
||||
@@ -1065,17 +1090,8 @@ static int compareDependentTypes(PotentialArchetype * const* pa,
|
||||
|
||||
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;
|
||||
if (int result = compareAssociatedTypes(aa, ab))
|
||||
return result;
|
||||
} else {
|
||||
// A resolved archetype is always ordered before an unresolved one.
|
||||
return -1;
|
||||
@@ -1091,18 +1107,8 @@ static int compareDependentTypes(PotentialArchetype * const* pa,
|
||||
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;
|
||||
|
||||
if (aa != ab)
|
||||
return aa < ab ? -1 : +1;
|
||||
if (int result = compareTypeAliases(aa, ab))
|
||||
return result;
|
||||
}
|
||||
|
||||
// Along the error path where one or both of the potential archetypes was
|
||||
@@ -1119,35 +1125,20 @@ static int compareDependentTypes(PotentialArchetype * const* pa,
|
||||
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 the equivalence
|
||||
// class will contain the anchor.
|
||||
(void)rebuildPotentialArchetypeAnchor(this, builder);
|
||||
|
||||
PotentialArchetype *PotentialArchetype::getArchetypeAnchor(
|
||||
GenericSignatureBuilder &builder) {
|
||||
// Find the best archetype within this equivalence class.
|
||||
PotentialArchetype *rep = getRepresentative();
|
||||
auto anchor = rep;
|
||||
PotentialArchetype *anchor;
|
||||
if (auto parent = getParent()) {
|
||||
// For a nested type, retrieve the parent archetype anchor first.
|
||||
auto parentAnchor = parent->getArchetypeAnchor(builder);
|
||||
anchor = parentAnchor->getNestedArchetypeAnchor(getNestedName(), builder);
|
||||
} else {
|
||||
anchor = rep;
|
||||
}
|
||||
|
||||
// Find the best type within this equivalence class.
|
||||
for (auto pa : rep->getEquivalenceClassMembers()) {
|
||||
if (compareDependentTypes(&pa, &anchor) < 0)
|
||||
anchor = pa;
|
||||
@@ -1165,6 +1156,35 @@ auto GenericSignatureBuilder::PotentialArchetype::getArchetypeAnchor(
|
||||
return anchor;
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// Function object to diagnose a conflict in same-type constraints for a
|
||||
/// given potential archetype.
|
||||
struct DiagnoseSameTypeConflict {
|
||||
DiagnosticEngine &diags;
|
||||
const RequirementSource *source;
|
||||
PotentialArchetype *pa;
|
||||
|
||||
void operator()(Type type1, Type type2) const {
|
||||
if (pa->getParent() && pa->getTypeAliasDecl() &&
|
||||
source->getLoc().isInvalid()) {
|
||||
diags.diagnose(pa->getTypeAliasDecl()->getLoc(),
|
||||
diag::protocol_typealias_conflict,
|
||||
pa->getTypeAliasDecl()->getName(),
|
||||
type1, type2);
|
||||
return;
|
||||
}
|
||||
|
||||
if (source->getLoc().isValid()) {
|
||||
diags.diagnose(source->getLoc(),
|
||||
diag::requires_same_type_conflict,
|
||||
pa->isGenericParam(),
|
||||
pa->getDependentType(/*FIXME: */{ }, true),
|
||||
type1, type2);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Give a nested type the appropriately resolved concrete type, based off a
|
||||
// parent PA that has a concrete type.
|
||||
static void concretizeNestedTypeFromConcreteParent(
|
||||
@@ -1199,95 +1219,263 @@ static void concretizeNestedTypeFromConcreteParent(
|
||||
}
|
||||
|
||||
builder.addSameTypeRequirement(nestedPA, witnessType, source,
|
||||
[&](Type type1, Type type2) {
|
||||
builder.getASTContext().Diags.diagnose(
|
||||
source->getLoc(),
|
||||
diag::requires_same_type_conflict,
|
||||
nestedPA->isGenericParam(),
|
||||
nestedPA->getDependentType(/*FIXME: */{ }, true),
|
||||
type1, type2);
|
||||
});
|
||||
DiagnoseSameTypeConflict{
|
||||
builder.getASTContext().Diags,
|
||||
source, nestedPA
|
||||
});
|
||||
}
|
||||
|
||||
auto GenericSignatureBuilder::PotentialArchetype::getNestedType(
|
||||
Identifier nestedName,
|
||||
GenericSignatureBuilder &builder) -> PotentialArchetype * {
|
||||
PotentialArchetype *PotentialArchetype::getNestedType(
|
||||
Identifier nestedName,
|
||||
GenericSignatureBuilder &builder) {
|
||||
// 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;
|
||||
// Retrieve the nested archetype anchor, which is the best choice (so far)
|
||||
// for this nested type.
|
||||
return getNestedArchetypeAnchor(nestedName, builder);
|
||||
}
|
||||
|
||||
PotentialArchetype *PotentialArchetype::getNestedType(
|
||||
AssociatedTypeDecl *assocType,
|
||||
GenericSignatureBuilder &builder) {
|
||||
return updateNestedTypeForConformance(assocType,
|
||||
NestedTypeUpdate::AddIfMissing);
|
||||
}
|
||||
|
||||
PotentialArchetype *PotentialArchetype::getNestedType(
|
||||
TypeAliasDecl *typealias,
|
||||
GenericSignatureBuilder &builder) {
|
||||
return updateNestedTypeForConformance(typealias,
|
||||
NestedTypeUpdate::AddIfMissing);
|
||||
}
|
||||
|
||||
PotentialArchetype *PotentialArchetype::getNestedArchetypeAnchor(
|
||||
Identifier name,
|
||||
GenericSignatureBuilder &builder) {
|
||||
// Look for the best associated type or typealias within the protocols
|
||||
// we know about.
|
||||
AssociatedTypeDecl *bestAssocType = nullptr;
|
||||
TypeAliasDecl *bestTypeAlias = nullptr;
|
||||
SmallVector<TypeAliasDecl *, 4> typealiases;
|
||||
auto rep = getRepresentative();
|
||||
if (rep != this)
|
||||
repNested = rep->getNestedType(nestedName, builder);
|
||||
for (const auto &conforms : rep->getConformsTo()) {
|
||||
// Look for an associated type and/or typealias with this name.
|
||||
auto proto = conforms.first;
|
||||
AssociatedTypeDecl *assocType = nullptr;
|
||||
TypeAliasDecl *typealias = nullptr;
|
||||
for (auto member : proto->lookupDirect(name,
|
||||
/*ignoreNewExtensions=*/true)) {
|
||||
if (!assocType)
|
||||
assocType = dyn_cast<AssociatedTypeDecl>(member);
|
||||
|
||||
// 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 *, const RequirementSource *>, 4>
|
||||
conformsTo(rep->ConformsTo.begin(), rep->ConformsTo.end());
|
||||
for (auto &conforms : conformsTo) {
|
||||
// Make sure we don't trigger deserialization of extensions,
|
||||
// since they can refer back to a protocol we're currently
|
||||
// type checking.
|
||||
//
|
||||
// Note that typealiases in extensions won't matter here,
|
||||
// because a typealias is never going to be a representative
|
||||
// PA.
|
||||
auto *proto = conforms.first;
|
||||
auto members = proto->lookupDirect(nestedName,
|
||||
/*ignoreNewExtensions=*/true);
|
||||
for (auto member : members) {
|
||||
PotentialArchetype *pa;
|
||||
std::function<void(Type, Type)> diagnoseMismatch;
|
||||
// FIXME: Filter out typealiases that aren't in the protocol itself?
|
||||
if (!typealias)
|
||||
typealias = dyn_cast<TypeAliasDecl>(member);
|
||||
}
|
||||
|
||||
if (auto assocType = dyn_cast<AssociatedTypeDecl>(member)) {
|
||||
// Resolve this nested type to this associated type.
|
||||
pa = new PotentialArchetype(this, assocType);
|
||||
if (assocType &&
|
||||
(!bestAssocType ||
|
||||
compareAssociatedTypes(assocType, bestAssocType) < 0))
|
||||
bestAssocType = assocType;
|
||||
|
||||
diagnoseMismatch = [&](Type first, Type second) {
|
||||
llvm_unreachable(
|
||||
"associated type shouldn't result in new mismatches");
|
||||
};
|
||||
} else if (auto alias = dyn_cast<TypeAliasDecl>(member)) {
|
||||
// Resolve this nested type to this type alias.
|
||||
pa = new PotentialArchetype(this, alias);
|
||||
if (typealias) {
|
||||
// Record every typealias.
|
||||
typealiases.push_back(typealias);
|
||||
|
||||
diagnoseMismatch = [&](Type first, Type second) {
|
||||
if (auto NAT = dyn_cast<NameAliasType>(first.getPointer())) {
|
||||
if (NAT->getDecl() == member) {
|
||||
// If we have typealias T = Foo and Foo is completely concrete
|
||||
// (e.g. Array<Int?>), then the subst will leave the NameAliasType
|
||||
// intact. However, this means, if there's a
|
||||
// concrete-type-mismatch at the top level, the default error
|
||||
// message will be "ProtocolName.T (aka Foo)", but the "T" bit is
|
||||
// already in the error message so it's better to print only
|
||||
// "Foo".
|
||||
first = NAT->getSinglyDesugaredType();
|
||||
}
|
||||
}
|
||||
builder.Diags.diagnose(member->getLoc(),
|
||||
diag::protocol_typealias_conflict,
|
||||
member->getName(), first, second);
|
||||
};
|
||||
// Track the best typealias.
|
||||
if (!bestTypeAlias || compareTypeAliases(typealias, bestTypeAlias) < 0)
|
||||
bestTypeAlias = typealias;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME (recursive decl validation): if the alias doesn't have an
|
||||
// interface type when getNestedType is called while building a
|
||||
// protocol's generic signature (i.e. during validation), then it'll
|
||||
// fail completely, because building that alias's interface type
|
||||
// requires the protocol to be validated. This seems to occur when the
|
||||
// alias's RHS involves archetypes from the protocol.
|
||||
if (!alias->hasInterfaceType())
|
||||
builder.getLazyResolver()->resolveDeclSignature(alias);
|
||||
if (!alias->hasInterfaceType())
|
||||
continue;
|
||||
// If we found an associated type, use it.
|
||||
PotentialArchetype *resultPA = nullptr;
|
||||
if (bestAssocType) {
|
||||
resultPA = updateNestedTypeForConformance(bestAssocType,
|
||||
NestedTypeUpdate::AddIfMissing);
|
||||
}
|
||||
|
||||
// Update for all of the typealiases with this name, which will introduce
|
||||
// various same-type constraints.
|
||||
for (auto typealias : typealiases) {
|
||||
auto typealiasPA = updateNestedTypeForConformance(typealias,
|
||||
NestedTypeUpdate::AddIfMissing);
|
||||
if (!resultPA && typealias == bestTypeAlias)
|
||||
resultPA = typealiasPA;
|
||||
}
|
||||
|
||||
if (resultPA)
|
||||
return resultPA;
|
||||
|
||||
// Build an unresolved type if we don't have one yet.
|
||||
auto &nested = NestedTypes[name];
|
||||
if (nested.empty()) {
|
||||
nested.push_back(new PotentialArchetype(this, name));
|
||||
++builder.Impl->NumUnresolvedNestedTypes;
|
||||
|
||||
auto rep = getRepresentative();
|
||||
if (rep != this) {
|
||||
auto existingPA = rep->getNestedType(name, builder);
|
||||
|
||||
auto sameNamedSource =
|
||||
RequirementSource::forNestedTypeNameMatch(existingPA);
|
||||
builder.addSameTypeRequirement(existingPA, nested.back(),
|
||||
sameNamedSource);
|
||||
}
|
||||
}
|
||||
|
||||
return nested.front();
|
||||
}
|
||||
|
||||
|
||||
PotentialArchetype *PotentialArchetype::updateNestedTypeForConformance(
|
||||
Identifier name,
|
||||
ProtocolDecl *proto,
|
||||
NestedTypeUpdate kind) {
|
||||
/// Determine whether there is an associated type or typealias with this name
|
||||
/// in this protocol. If not, there's nothing to do.
|
||||
AssociatedTypeDecl *assocType = nullptr;
|
||||
TypeAliasDecl *typealias = nullptr;
|
||||
for (auto member : proto->lookupDirect(name, /*ignoreNewExtensions=*/true)) {
|
||||
if (!assocType)
|
||||
assocType = dyn_cast<AssociatedTypeDecl>(member);
|
||||
|
||||
// FIXME: Filter out typealiases that aren't in the protocol itself?
|
||||
if (!typealias)
|
||||
typealias = dyn_cast<TypeAliasDecl>(member);
|
||||
}
|
||||
|
||||
// There is no associated type or typealias with this name in this protocol
|
||||
if (!assocType && !typealias)
|
||||
return nullptr;
|
||||
|
||||
// If we had both an associated type and a typealias, ignore the latter. This
|
||||
// is for ill-formed code.
|
||||
if (assocType)
|
||||
return updateNestedTypeForConformance(assocType, kind);
|
||||
|
||||
return updateNestedTypeForConformance(typealias, kind);
|
||||
}
|
||||
|
||||
PotentialArchetype *PotentialArchetype::updateNestedTypeForConformance(
|
||||
PointerUnion<AssociatedTypeDecl *, TypeAliasDecl *> type,
|
||||
NestedTypeUpdate kind) {
|
||||
AssociatedTypeDecl *assocType = type.dyn_cast<AssociatedTypeDecl *>();
|
||||
TypeAliasDecl *typealias = type.dyn_cast<TypeAliasDecl *>();
|
||||
if (!assocType && !typealias)
|
||||
return nullptr;
|
||||
|
||||
Identifier name = assocType ? assocType->getName() : typealias->getName();
|
||||
ProtocolDecl *proto =
|
||||
assocType ? assocType->getProtocol()
|
||||
: typealias->getDeclContext()
|
||||
->getAsProtocolOrProtocolExtensionContext();
|
||||
|
||||
// Look for either an unresolved potential archetype (which we can resolve
|
||||
// now) or a potential archetype with the appropriate associated type or
|
||||
// typealias.
|
||||
PotentialArchetype *resultPA = nullptr;
|
||||
auto &allNested = NestedTypes[name];
|
||||
bool shouldUpdatePA = false;
|
||||
auto &builder = *getBuilder();
|
||||
for (auto existingPA : allNested) {
|
||||
// Resolve an unresolved potential archetype.
|
||||
if (existingPA->isUnresolvedNestedType) {
|
||||
if (assocType) {
|
||||
existingPA->resolveAssociatedType(assocType, builder);
|
||||
} else {
|
||||
existingPA->resolveTypeAlias(typealias, builder);
|
||||
}
|
||||
|
||||
// We've resolved this nested type; nothing more to do.
|
||||
resultPA = existingPA;
|
||||
shouldUpdatePA = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Do we have an associated-type match?
|
||||
if (assocType && existingPA->getResolvedAssociatedType() == assocType) {
|
||||
resultPA = existingPA;
|
||||
break;
|
||||
}
|
||||
|
||||
// Do we have a typealias match?
|
||||
if (typealias && existingPA->getTypeAliasDecl() == typealias) {
|
||||
resultPA = existingPA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we don't have a result potential archetype yet, we may need to add one.
|
||||
if (!resultPA) {
|
||||
switch (kind) {
|
||||
case NestedTypeUpdate::AddIfBetterAnchor:
|
||||
// FIXME: The loop above should have kept track of whether this type
|
||||
// would make a better anchor, so we can bail out here if the answer is
|
||||
// "no".
|
||||
LLVM_FALLTHROUGH;
|
||||
|
||||
case NestedTypeUpdate::AddIfMissing: {
|
||||
if (assocType)
|
||||
resultPA = new PotentialArchetype(this, assocType);
|
||||
else
|
||||
resultPA = new PotentialArchetype(this, typealias);
|
||||
|
||||
allNested.push_back(resultPA);
|
||||
|
||||
// We created a new type, which might be equivalent to a type by the
|
||||
// same name elsewhere.
|
||||
PotentialArchetype *existingPA = nullptr;
|
||||
if (allNested.size() > 1) {
|
||||
existingPA = allNested.front();
|
||||
} else {
|
||||
auto rep = getRepresentative();
|
||||
if (rep != this) {
|
||||
if (assocType)
|
||||
existingPA = rep->getNestedType(assocType, builder);
|
||||
else
|
||||
existingPA = rep->getNestedType(name, builder);
|
||||
}
|
||||
}
|
||||
|
||||
if (existingPA) {
|
||||
auto sameNamedSource =
|
||||
RequirementSource::forNestedTypeNameMatch(existingPA);
|
||||
builder.addSameTypeRequirement(existingPA, resultPA, sameNamedSource);
|
||||
}
|
||||
|
||||
shouldUpdatePA = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case NestedTypeUpdate::ResolveExisting:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we still don't have a result potential archetype, we're done.
|
||||
if (!resultPA)
|
||||
return nullptr;
|
||||
|
||||
// If we have a potential archetype that requires more processing, do so now.
|
||||
if (shouldUpdatePA) {
|
||||
// For typealiases, introduce a same-type requirement to the aliased type.
|
||||
if (typealias) {
|
||||
// FIXME (recursive decl validation): if the alias doesn't have an
|
||||
// interface type when getNestedType is called while building a
|
||||
// protocol's generic signature (i.e. during validation), then it'll
|
||||
// fail completely, because building that alias's interface type
|
||||
// requires the protocol to be validated. This seems to occur when the
|
||||
// alias's RHS involves archetypes from the protocol.
|
||||
if (!typealias->hasInterfaceType())
|
||||
builder.getLazyResolver()->resolveDeclSignature(typealias);
|
||||
if (typealias->hasInterfaceType()) {
|
||||
// The protocol typealias has an underlying type written in terms
|
||||
// of the protocol's 'Self' type.
|
||||
auto type = alias->getDeclaredInterfaceType();
|
||||
auto type = typealias->getDeclaredInterfaceType();
|
||||
|
||||
// Substitute in the type of the current PotentialArchetype in
|
||||
// place of 'Self' here.
|
||||
@@ -1298,102 +1486,55 @@ auto GenericSignatureBuilder::PotentialArchetype::getNestedType(
|
||||
type = type.subst(subMap, SubstFlags::UseErrorType);
|
||||
|
||||
builder.addSameTypeRequirement(
|
||||
ResolvedType::forNewTypeAlias(pa),
|
||||
builder.resolve(type),
|
||||
RequirementSource::forNestedTypeNameMatch(pa),
|
||||
diagnoseMismatch);
|
||||
} 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.addSameTypeRequirement(
|
||||
pa, nested.front(),
|
||||
RequirementSource::forNestedTypeNameMatch(pa),
|
||||
diagnoseMismatch);
|
||||
} else {
|
||||
nested.push_back(pa);
|
||||
|
||||
if (repNested) {
|
||||
builder.addSameTypeRequirement(
|
||||
pa, repNested,
|
||||
RequirementSource::forNestedTypeNameMatch(pa),
|
||||
diagnoseMismatch);
|
||||
}
|
||||
ResolvedType::forNewTypeAlias(resultPA),
|
||||
builder.resolve(type),
|
||||
RequirementSource::forNestedTypeNameMatch(resultPA));
|
||||
}
|
||||
}
|
||||
|
||||
// If there's a superclass constraint that conforms to the protocol,
|
||||
// add the appropriate same-type relationship.
|
||||
auto superSource = builder.resolveSuperConformance(this, conforms.first,
|
||||
conforms.second);
|
||||
maybeAddSameTypeRequirementForNestedType(pa, superSource, builder);
|
||||
// If there's a superclass constraint that conforms to the protocol,
|
||||
// add the appropriate same-type relationship.
|
||||
auto rep = getRepresentative();
|
||||
auto knownConformance = rep->getConformsTo().find(proto);
|
||||
if (knownConformance != rep->getConformsTo().end()) {
|
||||
auto superSource =
|
||||
builder.resolveSuperConformance(this, proto, knownConformance->second);
|
||||
|
||||
maybeAddSameTypeRequirementForNestedType(resultPA, superSource, builder);
|
||||
} else {
|
||||
// FIXME: Dropping unknown conformance source on the floor.
|
||||
const RequirementSource *nullSource = nullptr;
|
||||
auto superSource = builder.resolveSuperConformance(this, proto,
|
||||
nullSource);
|
||||
|
||||
maybeAddSameTypeRequirementForNestedType(resultPA, superSource, builder);
|
||||
}
|
||||
|
||||
// We know something concrete about the parent PA, so we need to propagate
|
||||
// that information to this new archetype.
|
||||
// FIXME: This feels like massive overkill. Why do we have to loop?
|
||||
if (isConcreteType()) {
|
||||
for (auto equivT : getRepresentative()->getEquivalenceClassMembers()) {
|
||||
concretizeNestedTypeFromConcreteParent(
|
||||
equivT, RequirementSource::forNestedTypeNameMatch(resultPA),
|
||||
resultPA, builder,
|
||||
[&](ProtocolDecl *proto) -> ProtocolConformanceRef {
|
||||
auto depTy = resultPA->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;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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()) {
|
||||
for (auto equivT : rep->getEquivalenceClassMembers()) {
|
||||
concretizeNestedTypeFromConcreteParent(
|
||||
equivT, RequirementSource::forNestedTypeNameMatch(nestedPA),
|
||||
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::forInferred(this, nullptr));
|
||||
(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;
|
||||
return resultPA;
|
||||
}
|
||||
|
||||
Type GenericSignatureBuilder::PotentialArchetype::getTypeInContext(
|
||||
@@ -1774,10 +1915,6 @@ auto GenericSignatureBuilder::resolve(UnresolvedType paOrT,
|
||||
}) &&
|
||||
"unexpected typealias representative with non-typealias equivalent");
|
||||
|
||||
// Recursively resolve the concrete type.
|
||||
if (auto concrete = pa->getConcreteType())
|
||||
return resolve(concrete);
|
||||
|
||||
return ResolvedType::forPotentialArchetype(pa);
|
||||
}
|
||||
|
||||
@@ -1933,12 +2070,12 @@ bool GenericSignatureBuilder::addConformanceRequirement(PotentialArchetype *PAT,
|
||||
}
|
||||
}
|
||||
} else if (auto TypeAlias = dyn_cast<TypeAliasDecl>(Member)) {
|
||||
// FIXME: this should check that the typealias is makes sense (e.g. has
|
||||
// the same/compatible type as typealiases in parent protocols) and
|
||||
// set-up any same type requirements required. Forcing the PA to be
|
||||
// created with getNestedType is currently worse than useless due to the
|
||||
// 'recursive decl validation' FIXME in that function: it creates an
|
||||
// unresolved PA that prints an error later.
|
||||
// FIXME: this should check that the typealias is makes sense (e.g. has
|
||||
// the same/compatible type as typealiases in parent protocols) and
|
||||
// set-up any same type requirements required. Forcing the PA to be
|
||||
// created with getNestedType is currently worse than useless due to the
|
||||
// 'recursive decl validation' FIXME in that function: it creates an
|
||||
// unresolved PA that prints an error later.
|
||||
(void)TypeAlias;
|
||||
}
|
||||
}
|
||||
@@ -2098,14 +2235,9 @@ bool GenericSignatureBuilder::addSameTypeRequirementBetweenArchetypes(
|
||||
|
||||
// FIXME: This seems early.
|
||||
if (concrete1 && concrete2) {
|
||||
bool mismatch = addSameTypeRequirement(
|
||||
concrete1, concrete2, Source, [&](Type type1, Type type2) {
|
||||
Diags.diagnose(Source->getLoc(),
|
||||
diag::requires_same_type_conflict,
|
||||
T1->isGenericParam(),
|
||||
T1->getDependentType(/*FIXME: */{ }, true), type1,
|
||||
type2);
|
||||
});
|
||||
bool mismatch = addSameTypeRequirement(concrete1, concrete2, Source,
|
||||
DiagnoseSameTypeConflict{
|
||||
Diags, Source, T1});
|
||||
|
||||
if (mismatch) return true;
|
||||
}
|
||||
@@ -2184,13 +2316,7 @@ bool GenericSignatureBuilder::addSameTypeRequirementBetweenArchetypes(
|
||||
if (addSameTypeRequirement(
|
||||
T1Nested, T2Nested.second.front(),
|
||||
RequirementSource::forNestedTypeNameMatch(T1Nested),
|
||||
[&](Type type1, Type type2) {
|
||||
Diags.diagnose(Source->getLoc(),
|
||||
diag::requires_same_type_conflict,
|
||||
T1Nested->isGenericParam(),
|
||||
T1Nested->getDependentType(/*FIXME: */{ }, true),
|
||||
type1, type2);
|
||||
}))
|
||||
DiagnoseSameTypeConflict{Diags, Source, T1Nested}))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -2211,16 +2337,10 @@ bool GenericSignatureBuilder::addSameTypeRequirementToConcrete(
|
||||
|
||||
// If we've already been bound to a type, match that type.
|
||||
if (equivClass->concreteType) {
|
||||
bool mismatch = addSameTypeRequirement(
|
||||
equivClass->concreteType, Concrete, Source,
|
||||
[&](Type type1, Type type2) {
|
||||
Diags.diagnose(Source->getLoc(),
|
||||
diag::requires_same_type_conflict,
|
||||
T->isGenericParam(),
|
||||
T->getDependentType(/*FIXME: */{ }, true), type1,
|
||||
type2);
|
||||
|
||||
});
|
||||
bool mismatch = addSameTypeRequirement(equivClass->concreteType, Concrete,
|
||||
Source,
|
||||
DiagnoseSameTypeConflict{
|
||||
Diags, Source, T});
|
||||
|
||||
if (mismatch) return true;
|
||||
|
||||
@@ -3306,6 +3426,20 @@ void GenericSignatureBuilder::visitPotentialArchetypes(F f) {
|
||||
stack.pop_back();
|
||||
f(pa);
|
||||
|
||||
// Visit the archetype anchor.
|
||||
if (auto anchor = pa->getArchetypeAnchor(*this)) {
|
||||
if (visited.insert(anchor).second) {
|
||||
stack.push_back(anchor);
|
||||
}
|
||||
}
|
||||
|
||||
// Visit everything else in this equivalence class.
|
||||
for (auto equivPA : pa->getEquivalenceClassMembers()) {
|
||||
if (visited.insert(equivPA).second) {
|
||||
stack.push_back(equivPA);
|
||||
}
|
||||
}
|
||||
|
||||
// Visit nested potential archetypes.
|
||||
for (const auto &nested : pa->getNestedTypes()) {
|
||||
for (auto nestedPA : nested.second) {
|
||||
|
||||
@@ -118,13 +118,13 @@ func fail6<T>(_ t: T) -> Int where T == Int { // expected-error{{same-type requi
|
||||
}
|
||||
|
||||
func test8<T: Barrable, U: Barrable>(_ t: T, u: U) -> (Y, Y, X, X)
|
||||
where T.Bar == Y, U.Bar.Foo == X, T.Bar == U.Bar {
|
||||
where T.Bar == Y, U.Bar.Foo == X, T.Bar == U.Bar { // expected-warning{{redundant same-type constraint 'U.Bar.Foo' == 'X'}}
|
||||
return (t.bar, u.bar, t.bar.foo, u.bar.foo)
|
||||
}
|
||||
|
||||
func test8a<T: Barrable, U: Barrable>(_ t: T, u: U) -> (Y, Y, X, X)
|
||||
where
|
||||
T.Bar == Y, U.Bar.Foo == X, U.Bar == T.Bar {
|
||||
T.Bar == Y, U.Bar.Foo == X, U.Bar == T.Bar { // expected-warning{{redundant same-type constraint 'U.Bar.Foo' == 'X'}}
|
||||
return (t.bar, u.bar, t.bar.foo, u.bar.foo)
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ protocol Q2 {
|
||||
// CHECK-NEXT: Requirements:
|
||||
// CHECK-NEXT: τ_0_0 : Q2 [τ_0_0: Explicit @ 42:59]
|
||||
// CHECK-NEXT: τ_0_0[.Q2].B : P2 [τ_0_0: Explicit @ 42:59 -> Protocol requirement (via Self.B in Q2)]
|
||||
// CHECK-NEXT: τ_0_0[.Q2].C == S<T.B.A> [τ_0_0[.Q2].C: Explicit @ 42:69]
|
||||
// CHECK-NEXT: τ_0_0[.Q2].C == S<T.B.A> [τ_0_0[.Q2].C: Explicit]
|
||||
// CHECK-NEXT: τ_0_0[.Q2].B[.P2].X == S<T.B.A> [τ_0_0[.Q2].B[.P2].X: Nested type match]
|
||||
// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : Q2, τ_0_0.C == S<τ_0_0.B.A>>
|
||||
func requirementOnConcreteNestedTypeAlias<T>(_: T) where T: Q2, T.C == T.B.X {}
|
||||
@@ -53,14 +53,14 @@ func concreteRequirementOnConcreteNestedTypeAlias<T>(_: T) where T: Q2, S<T.C> =
|
||||
|
||||
// Incompatible concrete typealias types are flagged as such
|
||||
protocol P3 {
|
||||
typealias T = Int // expected-error{{typealias 'T' requires types 'Int' and 'Float' to be the same}}
|
||||
typealias T = Int // expected-error{{typealias 'T' requires types 'Q3.T' (aka 'Float') and 'Int' to be the same}}
|
||||
}
|
||||
protocol Q3: P3 {
|
||||
typealias T = Float
|
||||
}
|
||||
|
||||
protocol P3_1 {
|
||||
typealias T = Float // expected-error{{typealias 'T' requires types 'Float' and 'Int' to be the same}}
|
||||
typealias T = Float // expected-error{{typealias 'T' requires types 'P3.T' (aka 'Int') and 'Float' to be the same}}
|
||||
}
|
||||
protocol Q3_1: P3, P3_1 {}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user