[GSB] Track all conformance constraint sources.

Move the storage for the protocols to which a particular potential
archetype conforms into EquivalenceClass, so that it is more easily
shared. More importantly, keep track of *all* of the constraint
sources that produced a particular conformance requirement, so we can
revisit them later, which provides a number of improvements:

* We can drop self-derived requirements at the end, once we've
  established all of the equivalence classes
* We diagnose redundant conformance requirements, e.g., "T: Sequence"
  is redundant if "T: Collection" is already specified.
* We can choose the best path when forming the conformance access
  path.
This commit is contained in:
Doug Gregor
2017-03-06 16:36:16 -08:00
parent c443739d68
commit eaee4add8a
13 changed files with 254 additions and 155 deletions

View File

@@ -1571,6 +1571,12 @@ ERROR(requires_same_concrete_type,none,
ERROR(protocol_typealias_conflict, none,
"typealias %0 requires types %1 and %2 to be the same",
(Identifier, Type, Type))
WARNING(redundant_conformance_constraint,none,
"redundant conformance constraint %0: %1", (Type, ProtocolDecl *))
NOTE(redundant_conformance_here,none,
"conformance constraint %1: %2 %select{written here|implied here}0",
(bool, Type, ProtocolDecl *))
WARNING(redundant_same_type_to_concrete,none,
"redundant same-type constraint %0 == %1", (Type, Type))
NOTE(same_type_redundancy_here,none,

View File

@@ -96,6 +96,14 @@ public:
/// Describes an equivalence class of potential archetypes.
struct EquivalenceClass {
/// The list of protocols to which this equivalence class conforms.
///
/// The keys form the (semantic) list of protocols to which this type
/// conforms. The values are the conformance constraints as written on
/// this equivalence class.
llvm::MapVector<ProtocolDecl *, std::vector<Constraint<ProtocolDecl *>>>
conformsTo;
/// Concrete type to which this equivalence class is equal.
///
/// This is the semantic concrete type; the constraints as written
@@ -134,7 +142,11 @@ public:
Optional<ConcreteConstraint>
findAnySuperclassConstraintAsWritten(
PotentialArchetype *preferredPA = nullptr) const;
};
/// Determine whether conformance to the given protocol is satisfied by
/// a superclass requirement.
bool isConformanceSatisfiedBySuperclass(ProtocolDecl *proto) const;
};
friend class RequirementSource;
@@ -166,13 +178,9 @@ private:
/// queried.
///
/// \param proto The protocol to which we are establishing conformance.
///
/// \param protoSource The requirement source for the conformance to the
/// given protocol.
const RequirementSource *resolveSuperConformance(
GenericSignatureBuilder::PotentialArchetype *pa,
ProtocolDecl *proto,
const RequirementSource *&protoSource);
ProtocolDecl *proto);
/// \brief Add a new conformance requirement specifying that the given
/// potential archetype conforms to the given protocol.
@@ -462,6 +470,12 @@ private:
ArrayRef<GenericTypeParamType *> genericParams,
PotentialArchetype *pa);
/// Check conformance constraints within the equivalence class of the
/// given potential archetype.
void checkConformanceConstraints(
ArrayRef<GenericTypeParamType *> genericParams,
PotentialArchetype *pa);
public:
/// \brief Resolve the given type to the potential archetype it names.
///
@@ -1016,9 +1030,6 @@ class GenericSignatureBuilder::PotentialArchetype {
llvm::MapVector<PotentialArchetype *, const RequirementSource *>
SameTypeConstraints;
/// \brief The list of protocols to which this archetype will conform.
llvm::MapVector<ProtocolDecl *, const RequirementSource *> ConformsTo;
/// \brief The layout constraint of this archetype, if specified.
LayoutConstraint Layout;
@@ -1215,16 +1226,23 @@ public:
return dyn_cast<TypeAliasDecl>(identifier.assocTypeOrAlias);
}
/// Retrieve the set of protocols to which this type conforms.
llvm::MapVector<ProtocolDecl *, const RequirementSource *> &
getConformsTo() {
return ConformsTo;
/// Retrieve the set of protocols to which this potential archetype
/// conforms.
SmallVector<ProtocolDecl *, 4> getConformsTo() const {
SmallVector<ProtocolDecl *, 4> result;
if (auto equiv = getEquivalenceClassIfPresent()) {
for (const auto &entry : equiv->conformsTo)
result.push_back(entry.first);
}
return result;
}
/// Add a conformance to this potential archetype.
///
/// \returns true if the conformance was new, false if it already existed.
bool addConformance(ProtocolDecl *proto, bool updateExistingSource,
bool addConformance(ProtocolDecl *proto,
const RequirementSource *source,
GenericSignatureBuilder &builder);

View File

@@ -528,7 +528,7 @@ bool GenericSignature::requiresClass(Type type, ModuleDecl &mod) {
// If any of the protocols are class-bound, then it must be a class.
for (auto proto : pa->getConformsTo()) {
if (proto.first->requiresClass()) return true;
if (proto->requiresClass()) return true;
}
return false;
@@ -571,7 +571,7 @@ SmallVector<ProtocolDecl *, 2> GenericSignature::getConformsTo(Type type,
// Retrieve the protocols to which this type conforms.
SmallVector<ProtocolDecl *, 2> result;
for (auto proto : pa->getConformsTo())
result.push_back(proto.first);
result.push_back(proto);
// Canonicalize the resulting set of protocols.
ProtocolType::canonicalizeProtocols(result);
@@ -738,6 +738,26 @@ static Type eraseAssociatedTypes(Type type) {
return type;
}
namespace {
typedef GenericSignatureBuilder::RequirementSource RequirementSource;
template<typename T>
using GSBConstraint = GenericSignatureBuilder::Constraint<T>;
}
/// Retrieve the best requirement source from the list
static const RequirementSource *
getBestRequirementSource(ArrayRef<GSBConstraint<ProtocolDecl *>> constraints) {
const RequirementSource *bestSource = nullptr;
for (const auto &constraint : constraints) {
auto source = constraint.source;
if (!bestSource || source->compare(bestSource) < 0)
bestSource = source;
}
return bestSource;
}
ConformanceAccessPath GenericSignature::getConformanceAccessPath(
Type type,
ProtocolDecl *protocol,
@@ -747,12 +767,12 @@ ConformanceAccessPath GenericSignature::getConformanceAccessPath(
// Resolve this type to a potential archetype.
auto &builder = *getGenericSignatureBuilder(mod);
auto pa = builder.resolveArchetype(type);
auto rep = pa->getRepresentative();
auto equivClass = pa->getOrCreateEquivalenceClass();
// Dig out the conformance of this type to the given protocol, because we
// want its requirement source.
auto conforms = rep->getConformsTo().find(protocol);
assert(conforms != rep->getConformsTo().end());
auto conforms = equivClass->conformsTo.find(protocol);
assert(conforms != equivClass->conformsTo.end());
// Follow the requirement source to form the conformance access path.
typedef GenericSignatureBuilder::RequirementSource RequirementSource;
@@ -837,16 +857,17 @@ ConformanceAccessPath GenericSignature::getConformanceAccessPath(
// Dig out the potential archetype for this stored type.
auto pa = reqSigBuilder.resolveArchetype(storedType);
auto rep = pa->getRepresentative();
auto equivClass = pa->getOrCreateEquivalenceClass();
// Find the conformance of this potential archetype to the protocol in
// question.
auto knownConforms = rep->getConformsTo().find(conformingProto);
assert(knownConforms != rep->getConformsTo().end());
auto conforms = equivClass->conformsTo.find(conformingProto);
assert(conforms != equivClass->conformsTo.end());
// Compute the root type, canonicalizing it w.r.t. the protocol context.
auto inProtoSig = inProtocol->getGenericSignature();
Type localRootType = knownConforms->second->getRootPotentialArchetype()
auto conformsSource = getBestRequirementSource(conforms->second);
Type localRootType = conformsSource->getRootPotentialArchetype()
->getDependentType(inProtoSig->getGenericParams(),
/*allowUnresolved*/true);
localRootType = inProtoSig->getCanonicalTypeInContext(
@@ -854,7 +875,7 @@ ConformanceAccessPath GenericSignature::getConformanceAccessPath(
*inProtocol->getModuleContext());
// Build the path according to the requirement signature.
buildPath(reqSig, knownConforms->second, conformingProto, localRootType);
buildPath(reqSig, conformsSource, conformingProto, localRootType);
// We're done.
return;
@@ -884,14 +905,14 @@ ConformanceAccessPath GenericSignature::getConformanceAccessPath(
};
// Canonicalize the root type.
auto source = conforms->second;
auto source = getBestRequirementSource(conforms->second);
auto subjectPA = source->getRootPotentialArchetype();
subjectPA = subjectPA->getArchetypeAnchor(*subjectPA->getBuilder());
Type rootType = subjectPA->getDependentType(getGenericParams(),
/*allowUnresolved=*/false);
// Build the path.
buildPath(this, conforms->second, protocol, rootType);
buildPath(this, source, protocol, rootType);
// Return the path; we're done!
return path;

View File

@@ -237,6 +237,11 @@ bool RequirementSource::isSelfDerivedSource(PotentialArchetype *pa) const {
case RequirementSource::Inferred:
case RequirementSource::RequirementSignatureSelf:
currentPA = source->getRootPotentialArchetype();
while (auto parent = currentPA->getParent()) {
if (auto assocType = currentPA->getResolvedAssociatedType())
assocTypes.push_back(assocType);
currentPA = parent;
}
break;
case RequirementSource::Concrete:
@@ -262,7 +267,6 @@ bool RequirementSource::isSelfDerivedSource(PotentialArchetype *pa) const {
currentPA = knownNested->second.front();
}
// FIXME: currentPA == pa?
return false;
}
@@ -798,6 +802,18 @@ EquivalenceClass::findAnySuperclassConstraintAsWritten(
return result;
}
bool EquivalenceClass::isConformanceSatisfiedBySuperclass(
ProtocolDecl *proto) const {
auto known = conformsTo.find(proto);
assert(known != conformsTo.end() && "doesn't conform to this protocol");
for (const auto &constraint: known->second) {
if (constraint.source->kind == RequirementSource::Superclass)
return true;
}
return false;
}
bool GenericSignatureBuilder::updateRequirementSource(
const RequirementSource *&existingSource,
const RequirementSource *newSource) {
@@ -816,8 +832,7 @@ bool GenericSignatureBuilder::updateRequirementSource(
const RequirementSource *GenericSignatureBuilder::resolveSuperConformance(
GenericSignatureBuilder::PotentialArchetype *pa,
ProtocolDecl *proto,
const RequirementSource *&protoSource) {
ProtocolDecl *proto) {
// Get the superclass constraint.
Type superclass = pa->getSuperclass();
if (!superclass) return nullptr;
@@ -843,8 +858,7 @@ const RequirementSource *GenericSignatureBuilder::resolveSuperConformance(
superclassSource =
superclassSource->viaSuperclass(*this, conformance->getConcrete());
if (protoSource)
updateRequirementSource(protoSource, superclassSource);
paEquivClass->conformsTo[proto].push_back({pa, proto, superclassSource});
return superclassSource;
}
@@ -926,29 +940,23 @@ static DeclRange getProtocolMembers(ProtocolDecl *proto) {
}
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);
// 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)
builder.updateRequirementSource(known->second, source);
// Check whether we already knew about this conformance.
auto equivClass = getOrCreateEquivalenceClass();
auto known = equivClass->conformsTo.find(proto);
if (known != equivClass->conformsTo.end()) {
// We already knew about this conformance; record this specific constraint.
known->second.push_back({this, proto, source});
return false;
}
// Add this conformance.
auto inserted = ConformsTo.insert(std::make_pair(proto, source)).first;
// Add the conformance along with this constraint.
equivClass->conformsTo[proto].push_back({this, proto, source});
// If there is a superclass, try to resolve the conformance immediately via
// the superclass.
getBuilder()->resolveSuperConformance(this, proto, inserted->second);
// Determine whether there is a superclass constraint where the
// superclass conforms to this protocol.
(void)getBuilder()->resolveSuperConformance(this, proto);
// Resolve any existing nested types that need it.
for (auto &nested : NestedTypes) {
@@ -1261,9 +1269,8 @@ PotentialArchetype *PotentialArchetype::getNestedArchetypeAnchor(
TypeAliasDecl *bestTypeAlias = nullptr;
SmallVector<TypeAliasDecl *, 4> typealiases;
auto rep = getRepresentative();
for (const auto &conforms : rep->getConformsTo()) {
for (auto proto : 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,
@@ -1494,21 +1501,8 @@ PotentialArchetype *PotentialArchetype::updateNestedTypeForConformance(
// 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);
if (auto superSource = builder.resolveSuperConformance(this, proto))
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.
@@ -1551,6 +1545,7 @@ Type GenericSignatureBuilder::PotentialArchetype::getTypeInContext(
return archetypeAnchor->getTypeInContext(builder, genericEnv);
auto representative = getRepresentative();
auto equivClass = representative->getOrCreateEquivalenceClass();
ASTContext &ctx = genericEnv->getGenericSignature()->getASTContext();
// Return a concrete type or archetype we've already resolved.
@@ -1655,9 +1650,9 @@ Type GenericSignatureBuilder::PotentialArchetype::getTypeInContext(
// Collect the protocol conformances for the archetype.
SmallVector<ProtocolDecl *, 4> Protos;
for (const auto &conforms : representative->getConformsTo()) {
if (conforms.second->kind != RequirementSource::Superclass)
Protos.push_back(conforms.first);
for (auto proto : representative->getConformsTo()) {
if (!equivClass || !equivClass->isConformanceSatisfiedBySuperclass(proto))
Protos.push_back(proto);
}
// Create the archetype.
@@ -1791,20 +1786,27 @@ void GenericSignatureBuilder::PotentialArchetype::dump(llvm::raw_ostream &Out,
}
// Print requirements.
if (!ConformsTo.empty()) {
Out << " : ";
if (equivClass) {
bool First = true;
for (const auto &entry : equivClass->conformsTo) {
for (const auto &constraint : entry.second) {
if (constraint.archetype != this) continue;
interleave(ConformsTo,
[&](std::pair<ProtocolDecl *, const RequirementSource *>
ProtoAndSource) {
Out << ProtoAndSource.first->getName().str() << " ";
if (!ProtoAndSource.second->isDerivedRequirement())
Out << "*";
Out << "[";
ProtoAndSource.second->print(Out, SrcMgr);
Out << "]";
},
[&] { Out << " & "; });
if (First) {
First = false;
Out << ": ";
} else {
Out << " & ";
}
Out << constraint.value->getName().str() << " ";
if (!constraint.source->isDerivedRequirement())
Out << "*";
Out << "[";
constraint.source->print(Out, SrcMgr);
Out << "]";
}
}
}
if (getRepresentative() != this) {
@@ -1998,13 +2000,13 @@ bool GenericSignatureBuilder::addConformanceRequirement(PotentialArchetype *PAT,
ProtocolDecl *Proto,
const RequirementSource *Source,
llvm::SmallPtrSetImpl<ProtocolDecl *> &Visited) {
// Add the requirement, if we haven't done so already.
if (!PAT->addConformance(Proto, Source, *this))
return false;
// 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;
@@ -2120,10 +2122,9 @@ bool GenericSignatureBuilder::updateSuperclass(
// Local function to handle the update of superclass conformances
// when the superclass constraint changes.
auto updateSuperclassConformances = [&] {
for (auto &conforms : T->ConformsTo) {
if (auto superSource = resolveSuperConformance(T, conforms.first,
conforms.second)) {
for (auto req : getProtocolMembers(conforms.first)) {
for (auto proto : T->getConformsTo()) {
if (auto superSource = resolveSuperConformance(T, proto)) {
for (auto req : getProtocolMembers(proto)) {
auto assocType = dyn_cast<AssociatedTypeDecl>(req);
if (!assocType) continue;
@@ -2242,24 +2243,6 @@ bool GenericSignatureBuilder::addSameTypeRequirementBetweenArchetypes(
if (mismatch) return true;
}
// 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;
// Merge the equivalence classes.
auto equivClass = T1->getOrCreateEquivalenceClass();
auto equivClass2Members = T2->getEquivalenceClassMembers();
@@ -2304,9 +2287,15 @@ bool GenericSignatureBuilder::addSameTypeRequirementBetweenArchetypes(
}
// Add all of the protocol conformance requirements of T2 to T1.
for (auto conforms : T2->ConformsTo) {
T1->addConformance(conforms.first, updateExistingSource,
conforms.second, *this);
if (equivClass2) {
for (const auto &entry : equivClass2->conformsTo) {
T1->addConformance(entry.first, entry.second.front().source, *this);
auto &constraints1 = equivClass->conformsTo[entry.first];
constraints1.insert(constraints1.end(),
entry.second.begin() + 1,
entry.second.end());
}
}
// Recursively merge the associated types of T2 into T1.
@@ -2356,8 +2345,7 @@ bool GenericSignatureBuilder::addSameTypeRequirementToConcrete(
DenseMap<ProtocolDecl *, ProtocolConformanceRef> conformances;
CanType depTy = rep->getDependentType({ }, /*allowUnresolved=*/true)
->getCanonicalType();
for (auto &conforms : rep->getConformsTo()) {
auto protocol = conforms.first;
for (auto protocol : rep->getConformsTo()) {
auto conformance =
getLookupConformanceFn()(depTy, Concrete,
protocol->getDeclaredInterfaceType()
@@ -2380,7 +2368,7 @@ bool GenericSignatureBuilder::addSameTypeRequirementToConcrete(
conformance->isConcrete()
? conformance->getConcrete()
: nullptr);
updateRequirementSource(conforms.second, concreteSource);
equivClass->conformsTo[protocol].push_back({T, protocol, concreteSource});
}
// Eagerly resolve any existing nested types to their concrete forms (others
@@ -2493,8 +2481,7 @@ void GenericSignatureBuilder::markPotentialArchetypeRecursive(
return;
pa->setIsRecursive();
// FIXME: Drop this protocol.
pa->addConformance(proto, /*updateExistingSource=*/true, source, *this);
pa->addConformance(proto, source, *this);
if (!pa->getParent())
return;
@@ -2809,8 +2796,7 @@ static Identifier typoCorrectNestedType(
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 proto : pa->getParent()->getConformsTo()) {
for (auto member : getProtocolMembers(proto)) {
auto assocType = dyn_cast<AssociatedTypeDecl>(member);
if (!assocType)
@@ -2984,6 +2970,8 @@ GenericSignatureBuilder::finalize(SourceLoc loc,
checkRedundantSuperclassConstraints(genericParams, archetype);
}
}
checkConformanceConstraints(genericParams, archetype);
});
// Check for generic parameters which have been made concrete or equated
@@ -3139,6 +3127,7 @@ Constraint<T> GenericSignatureBuilder::checkConstraintList(
Diag<Type, T> redundancyDiag,
Diag<bool, Type, T> otherNoteDiag) {
// Remove self-derived constraints.
assert(!constraints.empty() && "No constraints?");
constraints.erase(
std::remove_if(constraints.begin(), constraints.end(),
[&](const Constraint<T> &constraint) {
@@ -3146,6 +3135,7 @@ Constraint<T> GenericSignatureBuilder::checkConstraintList(
constraint.archetype);
}),
constraints.end());
assert(!constraints.empty() && "All constraints were self-derived!");
// Sort the constraints, so we get a deterministic ordering of diagnostics.
llvm::array_pod_sort(constraints.begin(), constraints.end());
@@ -3300,6 +3290,29 @@ Constraint<T> GenericSignatureBuilder::checkConstraintList(
return *representativeConstraint;
}
void GenericSignatureBuilder::checkConformanceConstraints(
ArrayRef<GenericTypeParamType *> genericParams,
PotentialArchetype *pa) {
auto equivClass = pa->getEquivalenceClassIfPresent();
if (!equivClass || equivClass->conformsTo.empty())
return;
for (auto &entry : equivClass->conformsTo) {
checkConstraintList<ProtocolDecl *>(
genericParams, entry.second,
[](const Constraint<ProtocolDecl *> &constraint) {
return true;
},
[&](ProtocolDecl *proto) {
assert(proto == entry.first && "Mixed up protocol constraints");
return ConstraintRelation::Redundant;
},
None,
diag::redundant_conformance_constraint,
diag::redundant_conformance_here);
}
}
void GenericSignatureBuilder::checkRedundantConcreteTypeConstraints(
ArrayRef<GenericTypeParamType *> genericParams,
PotentialArchetype *representative) {
@@ -3720,11 +3733,23 @@ void GenericSignatureBuilder::enumerateRequirements(llvm::function_ref<
// Enumerate conformance requirements.
SmallVector<ProtocolDecl *, 4> protocols;
DenseMap<ProtocolDecl *, const 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});
auto equivClass = rep->getEquivalenceClassIfPresent();
if (equivClass) {
for (const auto &conforms : equivClass->conformsTo) {
protocols.push_back(conforms.first);
assert(protocolSources.count(conforms.first) == 0 &&
"redundant protocol requirement?");
// Find the best source among the constraints that describe conformance
// to this protocol.
auto bestSource = conforms.second.front().source;
for (const auto &constraint : conforms.second) {
if (constraint.source->compare(bestSource) < 0)
bestSource = constraint.source;
}
protocolSources.insert({conforms.first, bestSource});
}
}
// Sort the protocols in canonical order.

View File

@@ -30,8 +30,9 @@ func typoAssoc3<T : P2, U : P2>()
where U.AssocP2.assoc : P3, T.AssocP2.assoc : P4,
T.AssocP2 == U.AssocP2 {}
// expected-error@+3{{'T.AssocP2' does not have a member type named 'assoc'; did you mean 'Assoc'?}}{{47-52=Assoc}}
// expected-error@+2{{'T' does not have a member type named 'Assocp2'; did you mean 'AssocP2'?}}{{39-46=AssocP2}}
// expected-error@+1{{'T.AssocP2' does not have a member type named 'assoc'; did you mean 'Assoc'?}}{{47-52=Assoc}}
// expected-error@+1{{'T.AssocP2' does not have a member type named 'assoc'; did you mean 'Assoc'?}}
func typoAssoc4<T : P2>(_: T) where T.Assocp2.assoc : P3 {}
@@ -39,7 +40,7 @@ func typoAssoc4<T : P2>(_: T) where T.Assocp2.assoc : P3 {}
// CHECK-GENERIC-NEXT: Requirements:
// CHECK-GENERIC-NEXT: τ_0_0 : P2 [τ_0_0: Explicit @ {{.*}}:21]
// CHECK-GENERIC-NEXT: τ_0_0[.P2].AssocP2 : P1 [τ_0_0: Explicit @ {{.*}}:21 -> Protocol requirement (via Self.AssocP2 in P2)]
// CHECK-GENERIC-NEXT: τ_0_0[.P2].AssocP2[.P1].Assoc : P3 [τ_0_0[.P2].AssocP2.assoc: Explicit @ {{.*}}:53]
// CHECK-GENERIC-NEXT: τ_0_0[.P2].AssocP2[.P1].Assoc : P3 [τ_0_0[.P2].AssocP2[.P1].Assoc: Explicit @ {{.*}}:53]
// CHECK-GENERIC-NEXT: Potential archetypes
// <rdar://problem/19620340>

View File

@@ -12,4 +12,9 @@ protocol Q : P {
}
func f<T>(t: T) where T : P, T : Q, T.A : P0 { } // expected-note{{'f(t:)' previously declared here}}
func f<T>(t: T) where T : Q, T : P, T.A : P0 { } // expected-error{{invalid redeclaration of 'f(t:)'}}
// expected-warning@-1{{redundant conformance constraint 'T': 'P'}}
// expected-note@-2{{conformance constraint 'T': 'P' implied here}}
func f<T>(t: T) where T : Q, T : P, T.A : P0 { } // expected-error{{invalid redeclaration of 'f(t:)'}}
// expected-warning@-1{{redundant conformance constraint 'T': 'P'}}
// expected-note@-2{{conformance constraint 'T': 'P' implied here}}

View File

@@ -56,8 +56,8 @@ func testPaths3<V: P5>(_ v: V) {
acceptQ0(v.getAssocP3())
}
protocol P6Unordered: P5Unordered {
associatedtype A: P0
protocol P6Unordered: P5Unordered { // expected-note{{conformance constraint 'Self.A': 'P0' implied here}}
associatedtype A: P0 // expected-warning{{redundant conformance constraint 'Self.A': 'P0'}}
}
protocol P5Unordered {

View File

@@ -57,8 +57,9 @@ protocol Q5: Q2, Q3, Q4 {}
// CHECK-LABEL: .Q6@
// CHECK-NEXT: Requirement signature: <Self where Self : Q2, Self : Q3, Self : Q4>
// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : Q2, τ_0_0 : Q3, τ_0_0 : Q4>
protocol Q6: Q2, Q3, Q4 {
associatedtype X: P1
protocol Q6: Q2, // expected-note{{conformance constraint 'Self.X': 'P1' implied here}}
Q3, Q4 {
associatedtype X: P1 // expected-warning{{redundant conformance constraint 'Self.X': 'P1'}}
}
// multiple inheritance with a new conformance

View File

@@ -126,6 +126,8 @@ func inferSameType1<T, U>(_ x: Model_P3_P4_Eq<T, U>) { }
// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P2 [τ_0_0: Explicit @ {{.*}}:25 -> Protocol requirement (via Self.P3Assoc in P3)]
// CHECK-NEXT: τ_0_0[.P3].P3Assoc == τ_0_1[.P4].P4Assoc [τ_0_0[.P3].P3Assoc: Explicit]
func inferSameType2<T : P3, U : P4>(_: T, _: U) where U.P4Assoc : P2, T.P3Assoc == U.P4Assoc {}
// expected-warning@-1{{redundant conformance constraint 'T.P3Assoc': 'P2'}}
// expected-note@-2{{conformance constraint 'T.P3Assoc': 'P2' implied here}}
// CHECK-LABEL: .inferSameType3@
// CHECK-NEXT: Requirements:
@@ -149,8 +151,8 @@ protocol P7 : P6 {
// CHECK-LABEL: P7.nestedSameType1()@
// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : P7, τ_0_0.AssocP6.Element : P6, τ_0_0.AssocP6.Element == τ_0_0.AssocP7.AssocP6.Element>
extension P7 where AssocP6.Element : P6,
AssocP7.AssocP6.Element : P6,
extension P7 where AssocP6.Element : P6, // expected-note{{conformance constraint 'Self.AssocP6.Element': 'P6' written here}}
AssocP7.AssocP6.Element : P6, // expected-warning{{redundant conformance constraint 'Self.AssocP6.Element': 'P6'}}
AssocP6.Element == AssocP7.AssocP6.Element {
func nestedSameType1() { }
}

View File

@@ -75,17 +75,23 @@ extension P2 where Self.T : C {
// CHECK: superclassConformance1
// CHECK: Requirements:
// CHECK-NEXT: τ_0_0 : C [τ_0_0: Explicit @ {{.*}}:46]
// CHECK-NEXT: τ_0_0 : P3 [τ_0_0: Explicit @ {{.*}}:46 -> Superclass (C: P3)]
// CHECK-NEXT: τ_0_0 : C [τ_0_0: Explicit @ {{.*}}:11]
// CHECK-NEXT: τ_0_0 : P3 [τ_0_0: Explicit @ {{.*}}:11 -> Superclass (C: P3)]
// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : C>
func superclassConformance1<T>(t: T) where T : C, T : P3 {}
func superclassConformance1<T>(t: T)
where T : C, // expected-note{{conformance constraint 'T': 'P3' implied here}}
T : P3 {} // expected-warning{{redundant conformance constraint 'T': 'P3'}}
// CHECK: superclassConformance2
// CHECK: Requirements:
// CHECK-NEXT: τ_0_0 : C [τ_0_0: Explicit @ {{.*}}:46]
// CHECK-NEXT: τ_0_0 : P3 [τ_0_0: Explicit @ {{.*}}:46 -> Superclass (C: P3)]
// CHECK-NEXT: τ_0_0 : C [τ_0_0: Explicit @ {{.*}}:11]
// CHECK-NEXT: τ_0_0 : P3 [τ_0_0: Explicit @ {{.*}}:11 -> Superclass (C: P3)]
// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : C>
func superclassConformance2<T>(t: T) where T : C, T : P3 {}
func superclassConformance2<T>(t: T)
where T : C, // expected-note{{conformance constraint 'T': 'P3' implied here}}
T : P3 {} // expected-warning{{redundant conformance constraint 'T': 'P3'}}
protocol P4 { }
@@ -99,6 +105,8 @@ class C2 : C, P4 { }
func superclassConformance3<T>(t: T) where T : C, T : P4, T : C2 {}
// expected-warning@-1{{redundant superclass constraint 'T' : 'C'}}
// expected-note@-2{{superclass constraint 'T' : 'C2' written here}}
// expected-warning@-3{{redundant conformance constraint 'T': 'P4'}}
// expected-note@-4{{conformance constraint 'T': 'P4' implied here}}
protocol P5: A { } // expected-error{{non-class type 'P5' cannot inherit from class 'A'}}

View File

@@ -1,13 +1,16 @@
// RUN: %target-swift-frontend -typecheck -verify %s
protocol Mashable { }
protocol Womparable { }
// FuncDecl: Choose 0
func f1<T>(x: T) {}
// FuncDecl: Choose 1
// 1: Inherited constraint
func f2<T: Hashable>(x: T) {} // no-warning
func f2<T: Mashable>(x: T) {} // no-warning
// 2: Non-trailing where
func f3<T where T: Comparable>(x: T) {} // expected-warning {{'where' clause next to generic parameters is deprecated and will be removed in the future version of Swift}} {{10-30=}} {{37-37= where T: Comparable}}
func f3<T where T: Womparable>(x: T) {} // expected-warning {{'where' clause next to generic parameters is deprecated and will be removed in the future version of Swift}} {{10-30=}} {{37-37= where T: Womparable}}
// 3: Has return type
func f4<T>(x: T) -> Int { return 2 } // no-warning
// 4: Trailing where
@@ -15,29 +18,29 @@ func f5<T>(x: T) where T : Equatable {} // no-warning
// FuncDecl: Choose 2
// 1,2
func f12<T: Hashable where T: Comparable>(x: T) {} // expected-warning {{'where' clause next to generic parameters is deprecated and will be removed in the future version of Swift}} {{21-41=}} {{48-48= where T: Comparable}}
func f12<T: Mashable where T: Womparable>(x: T) {} // expected-warning {{'where' clause next to generic parameters is deprecated and will be removed in the future version of Swift}} {{21-41=}} {{48-48= where T: Womparable}}
// 1,3
func f13<T: Hashable>(x: T) -> Int { return 2 } // no-warning
func f13<T: Mashable>(x: T) -> Int { return 2 } // no-warning
// 1,4
func f14<T: Hashable>(x: T) where T: Equatable {} // no-warning
func f14<T: Mashable>(x: T) where T: Equatable {} // no-warning
// 2,3
func f23<T where T: Comparable>(x: T) -> Int { return 2 } // expected-warning {{'where' clause next to generic parameters is deprecated and will be removed in the future version of Swift}} {{11-31=}} {{45-45= where T: Comparable}}
func f23<T where T: Womparable>(x: T) -> Int { return 2 } // expected-warning {{'where' clause next to generic parameters is deprecated and will be removed in the future version of Swift}} {{11-31=}} {{45-45= where T: Womparable}}
// 2,4
func f24<T where T: Comparable>(x: T) where T: Equatable {} // expected-warning {{'where' clause next to generic parameters is deprecated and will be removed in the future version of Swift}} {{11-31=}} {{39-44=where T: Comparable,}}
func f24<T where T: Womparable>(x: T) where T: Equatable {} // expected-warning {{'where' clause next to generic parameters is deprecated and will be removed in the future version of Swift}} {{11-31=}} {{39-44=where T: Womparable,}}
// 3,4
func f34<T>(x: T) -> Int where T: Equatable { return 2 } // no-warning
// FuncDecl: Choose 3
// 1,2,3
func f123<T: Hashable where T: Comparable>(x: T) -> Int { return 2 } // expected-warning {{'where' clause next to generic parameters is deprecated and will be removed in the future version of Swift}} {{22-42=}} {{56-56= where T: Comparable}}
func f123<T: Mashable where T: Womparable>(x: T) -> Int { return 2 } // expected-warning {{'where' clause next to generic parameters is deprecated and will be removed in the future version of Swift}} {{22-42=}} {{56-56= where T: Womparable}}
// 1,2,4
func f124<T: Hashable where T: Comparable>(x: T) where T: Equatable {} // expected-warning {{'where' clause next to generic parameters is deprecated and will be removed in the future version of Swift}} {{22-42=}} {{50-55=where T: Comparable,}}
func f124<T: Mashable where T: Womparable>(x: T) where T: Equatable {} // expected-warning {{'where' clause next to generic parameters is deprecated and will be removed in the future version of Swift}} {{22-42=}} {{50-55=where T: Womparable,}}
// 2,3,4
func f234<T where T: Comparable>(x: T) -> Int where T: Equatable { return 2 } // expected-warning {{'where' clause next to generic parameters is deprecated and will be removed in the future version of Swift}} {{12-32=}} {{47-52=where T: Comparable,}}
func f234<T where T: Womparable>(x: T) -> Int where T: Equatable { return 2 } // expected-warning {{'where' clause next to generic parameters is deprecated and will be removed in the future version of Swift}} {{12-32=}} {{47-52=where T: Womparable,}}
// FuncDecl: Choose 4
// 1,2,3,4
func f1234<T: Hashable where T: Comparable>(x: T) -> Int where T: Equatable { return 2 } // expected-warning {{'where' clause next to generic parameters is deprecated and will be removed in the future version of Swift}} {{23-43=}} {{58-63=where T: Comparable,}}
func f1234<T: Mashable where T: Womparable>(x: T) -> Int where T: Equatable { return 2 } // expected-warning {{'where' clause next to generic parameters is deprecated and will be removed in the future version of Swift}} {{23-43=}} {{58-63=where T: Womparable,}}
@@ -46,23 +49,23 @@ struct S0<T> {}
// NominalTypeDecl: Choose 1
// 1: Inherited constraint
struct S1<T: Hashable> {} // no-warning
struct S1<T: Mashable> {} // no-warning
// 2: Non-trailing where
struct S2<T where T: Comparable> {} // expected-warning {{'where' clause next to generic parameters is deprecated and will be removed in the future version of Swift}} {{12-32=}} {{33-33= where T: Comparable}}
struct S2<T where T: Womparable> {} // expected-warning {{'where' clause next to generic parameters is deprecated and will be removed in the future version of Swift}} {{12-32=}} {{33-33= where T: Womparable}}
// 3: Trailing where
struct S3<T> where T : Equatable {} // no-warning
// NominalTypeDecl: Choose 2
// 1,2
struct S12<T: Hashable where T: Comparable> {} // expected-warning {{'where' clause next to generic parameters is deprecated and will be removed in the future version of Swift}} {{23-43=}} {{44-44= where T: Comparable}}
struct S12<T: Mashable where T: Womparable> {} // expected-warning {{'where' clause next to generic parameters is deprecated and will be removed in the future version of Swift}} {{23-43=}} {{44-44= where T: Womparable}}
// 1,3
struct S13<T: Hashable> where T: Equatable {} // no-warning
struct S13<T: Mashable> where T: Equatable {} // no-warning
// 2,3
struct S23<T where T: Comparable> where T: Equatable {} // expected-warning {{'where' clause next to generic parameters is deprecated and will be removed in the future version of Swift}} {{13-33=}} {{35-40=where T: Comparable,}}
struct S23<T where T: Womparable> where T: Equatable {} // expected-warning {{'where' clause next to generic parameters is deprecated and will be removed in the future version of Swift}} {{13-33=}} {{35-40=where T: Womparable,}}
// NominalTypeDecl: Choose 3
// 1,2,3
struct S123<T: Hashable where T: Comparable> where T: Equatable {} // expected-warning {{'where' clause next to generic parameters is deprecated and will be removed in the future version of Swift}} {{24-44=}} {{46-51=where T: Comparable,}}
struct S123<T: Mashable where T: Womparable> where T: Equatable {} // expected-warning {{'where' clause next to generic parameters is deprecated and will be removed in the future version of Swift}} {{24-44=}} {{46-51=where T: Womparable,}}
protocol ProtoA {}

View File

@@ -82,6 +82,8 @@ protocol CircleStart : CircleEnd { func circle_start() } // expected-error 2{{ci
// expected-note@-1{{protocol 'CircleStart' declared here}}
protocol CircleEnd : CircleMiddle { func circle_end()} // expected-note{{protocol 'CircleEnd' declared here}}
// expected-warning@+2{{redundant conformance constraint 'Self': 'CircleTrivial'}}
// expected-note@+1{{conformance constraint 'Self': 'CircleTrivial' implied here}}
protocol CircleEntry : CircleTrivial { }
protocol CircleTrivial : CircleTrivial { } // expected-error 3{{circular protocol inheritance CircleTrivial}}

View File

@@ -52,7 +52,8 @@ protocol P3 {
protocol P4 : P3 {}
protocol DeclaredP : P3, P4 {}
protocol DeclaredP : P3, // expected-warning{{redundant conformance constraint 'Self': 'P3'}}
P4 {} // expected-note{{conformance constraint 'Self': 'P3' implied here}}
struct Y3 : DeclaredP {
}
@@ -75,7 +76,13 @@ protocol Gamma {
associatedtype Delta: Alpha // expected-error{{type may not reference itself as a requirement}}
}
struct Epsilon<T: Alpha, U: Gamma> where T.Beta == U, U.Delta == T {}
// FIXME: Redundancy diagnostics are odd here.
struct Epsilon<T: Alpha, // expected-note{{conformance constraint 'U': 'Gamma' implied here}}
// expected-warning@-1{{redundant conformance constraint 'T': 'Alpha'}}
U: Gamma> // expected-warning{{redundant conformance constraint 'U': 'Gamma'}}
// expected-note@-1{{conformance constraint 'T': 'Alpha' implied here}}
where T.Beta == U,
U.Delta == T {}
// -----