[AST] Use the requirement signature in the ArchetypeBuilder.

The requirement signature is far more compact than looking at all the members.
This commit is contained in:
Huon Wilson
2017-02-06 12:00:00 -08:00
parent 74091fbcef
commit 51da51dfc0
5 changed files with 98 additions and 57 deletions

View File

@@ -171,7 +171,8 @@ private:
/// \brief Add a new same-type requirement specifying that the given potential
/// archetypes should map to the equivalent archetype.
bool addSameTypeRequirement(Type T1, Type T2, RequirementSource Source);
bool addSameTypeRequirement(Type T1, Type T2, RequirementSource Source,
PotentialArchetype *basePA = nullptr);
/// Add the requirements placed on the given abstract type parameter
/// to the given potential archetype.
@@ -248,6 +249,10 @@ public:
/// re-inject requirements from outer contexts.
void addRequirement(const Requirement &req, RequirementSource source);
void addRequirement(const Requirement &req, RequirementSource source,
PotentialArchetype *basePA,
llvm::SmallPtrSetImpl<ProtocolDecl *> &Visited);
bool addLayoutRequirement(PotentialArchetype *PAT,
LayoutConstraint Layout,
RequirementSource Source);
@@ -310,7 +315,12 @@ public:
/// signature are fully resolved).
///
/// For any type that cannot refer to an archetype, this routine returns null.
PotentialArchetype *resolveArchetype(Type type);
///
/// A non-null \c basePA is used in place of the "true" potential archetype
/// for a GenericTypeParamType, effectively performing a substitution like,
/// e.g., Self = <some PA>.
PotentialArchetype *resolveArchetype(Type type,
PotentialArchetype *basePA = nullptr);
/// \brief Dump all of the requirements, both specified and inferred.
LLVM_ATTRIBUTE_DEPRECATED(

View File

@@ -3595,6 +3595,11 @@ public:
return RequirementSignature;
}
/// Has the requirement signature been computed yet?
bool isRequirementSignatureComputed() const {
return RequirementSignature != nullptr;
}
void computeRequirementSignature();
void setRequirementSignature(GenericSignature *sig) {

View File

@@ -938,8 +938,12 @@ LazyResolver *ArchetypeBuilder::getLazyResolver() const {
return Context.getLazyResolver();
}
auto ArchetypeBuilder::resolveArchetype(Type type) -> PotentialArchetype * {
auto ArchetypeBuilder::resolveArchetype(Type type, PotentialArchetype *basePA)
-> PotentialArchetype * {
if (auto genericParam = type->getAs<GenericTypeParamType>()) {
if (basePA)
return basePA;
unsigned index = GenericParamKey(genericParam).findIndexIn(
Impl->GenericParams);
if (index < Impl->GenericParams.size())
@@ -949,7 +953,7 @@ auto ArchetypeBuilder::resolveArchetype(Type type) -> PotentialArchetype * {
}
if (auto dependentMember = type->getAs<DependentMemberType>()) {
auto base = resolveArchetype(dependentMember->getBase());
auto base = resolveArchetype(dependentMember->getBase(), basePA);
if (!base)
return nullptr;
@@ -1010,52 +1014,66 @@ bool ArchetypeBuilder::addConformanceRequirement(PotentialArchetype *PAT,
if (!T->addConformance(Proto, /*updateExistingSource=*/true, Source, *this))
return false;
// Conformances to inherit protocols are explicit in a protocol requirement
// signature, but inferred from this conformance otherwise.
auto InnerKind =
Source.getKind() == RequirementSource::ProtocolRequirementSignatureSelf
? RequirementSource::Explicit
: RequirementSource::Redundant;
RequirementSource InnerSource(InnerKind, Source.getLoc());
bool inserted = Visited.insert(Proto).second;
assert(inserted);
(void) inserted;
// Add all of the inherited protocol requirements, recursively.
if (auto resolver = getLazyResolver())
resolver->resolveInheritedProtocols(Proto);
for (auto InheritedProto : Proto->getInheritedProtocols(getLazyResolver())) {
if (Visited.count(InheritedProto))
continue;
if (addConformanceRequirement(T, InheritedProto, InnerSource, Visited))
return true;
}
// Requirements introduced by the main protocol are explicit in a protocol
// requirement signature, but inferred from this conformance otherwise.
auto Kind =
Source.getKind() == RequirementSource::ProtocolRequirementSignatureSelf
? RequirementSource::Explicit
: RequirementSource::Protocol;
// Add requirements for each of the associated types.
// FIXME: This should use the generic signature, not walk the members.
for (auto Member : Proto->getMembers()) {
if (auto AssocType = dyn_cast<AssociatedTypeDecl>(Member)) {
// Add requirements placed directly on this associated type.
auto AssocPA = T->getNestedType(AssocType, *this);
// Requirements introduced by the main protocol are explicit in a protocol
// requirement signature, but inferred from this conformance otherwise.
auto Kind = Source.getKind() ==
RequirementSource::ProtocolRequirementSignatureSelf
? RequirementSource::Explicit
: RequirementSource::Protocol;
// Use the requirement signature to avoid rewalking the entire protocol. This
// cannot compute the requirement signature directly, because that may be
// infinitely recursive: this code is also used to construct it.
if (Proto->isRequirementSignatureComputed()) {
auto reqSig = Proto->getRequirementSignature();
if (AssocPA != T) {
if (addAbstractTypeParamRequirements(AssocType, AssocPA, Kind, Visited))
return true;
}
for (auto req : reqSig->getRequirements()) {
RequirementSource InnerSource(Kind, Source.getLoc());
addRequirement(req, InnerSource, T, Visited);
}
} else {
// Conformances to inherit protocols are explicit in a protocol requirement
// signature, but inferred from this conformance otherwise.
auto InnerKind =
Source.getKind() == RequirementSource::ProtocolRequirementSignatureSelf
? RequirementSource::Explicit
: RequirementSource::Redundant;
RequirementSource InnerSource(InnerKind, Source.getLoc());
// Add all of the inherited protocol requirements, recursively.
if (auto resolver = getLazyResolver())
resolver->resolveInheritedProtocols(Proto);
continue;
for (auto InheritedProto :
Proto->getInheritedProtocols(getLazyResolver())) {
if (Visited.count(InheritedProto))
continue;
if (addConformanceRequirement(T, InheritedProto, InnerSource, Visited))
return true;
}
// FIXME: Requirement declarations.
// Add requirements for each of the associated types.
for (auto Member : Proto->getMembers()) {
if (auto AssocType = dyn_cast<AssociatedTypeDecl>(Member)) {
// Add requirements placed directly on this associated type.
auto AssocPA = T->getNestedType(AssocType, *this);
if (AssocPA != T) {
if (addAbstractTypeParamRequirements(AssocType, AssocPA, Kind,
Visited))
return true;
}
continue;
}
// FIXME: Requirement declarations.
}
}
Visited.erase(Proto);
return false;
}
@@ -1397,13 +1415,14 @@ bool ArchetypeBuilder::addSameTypeRequirementToConcrete(
return false;
}
bool ArchetypeBuilder::addSameTypeRequirement(Type Reqt1, Type Reqt2,
RequirementSource Source) {
RequirementSource Source,
PotentialArchetype *basePA) {
// Find the potential archetypes.
PotentialArchetype *T1 = resolveArchetype(Reqt1);
PotentialArchetype *T2 = resolveArchetype(Reqt2);
PotentialArchetype *T1 = resolveArchetype(Reqt1, basePA);
PotentialArchetype *T2 = resolveArchetype(Reqt2, basePA);
// Require that at least one side of the requirement be a potential archetype.
if (!T1 && !T2) {
Diags.diagnose(Source.getLoc(), diag::requires_no_same_type_archetype);
@@ -1609,9 +1628,17 @@ bool ArchetypeBuilder::addRequirement(const RequirementRepr &Req) {
void ArchetypeBuilder::addRequirement(const Requirement &req,
RequirementSource source) {
llvm::SmallPtrSet<ProtocolDecl *, 8> Visited;
addRequirement(req, source, nullptr, Visited);
}
void ArchetypeBuilder::addRequirement(
const Requirement &req, RequirementSource source,
PotentialArchetype *basePA,
llvm::SmallPtrSetImpl<ProtocolDecl *> &Visited) {
switch (req.getKind()) {
case RequirementKind::Superclass: {
PotentialArchetype *pa = resolveArchetype(req.getFirstType());
PotentialArchetype *pa = resolveArchetype(req.getFirstType(), basePA);
if (!pa) return;
assert(req.getSecondType()->getClassOrBoundGenericClass());
@@ -1620,7 +1647,7 @@ void ArchetypeBuilder::addRequirement(const Requirement &req,
}
case RequirementKind::Layout: {
PotentialArchetype *pa = resolveArchetype(req.getFirstType());
PotentialArchetype *pa = resolveArchetype(req.getFirstType(), basePA);
if (!pa) return;
(void)addLayoutRequirement(pa, req.getLayoutConstraint(), source);
@@ -1628,7 +1655,7 @@ void ArchetypeBuilder::addRequirement(const Requirement &req,
}
case RequirementKind::Conformance: {
PotentialArchetype *pa = resolveArchetype(req.getFirstType());
PotentialArchetype *pa = resolveArchetype(req.getFirstType(), basePA);
if (!pa) return;
SmallVector<ProtocolDecl *, 4> conformsTo;
@@ -1636,14 +1663,15 @@ void ArchetypeBuilder::addRequirement(const Requirement &req,
// Add each of the protocols.
for (auto proto : conformsTo) {
(void)addConformanceRequirement(pa, proto, source);
(void)addConformanceRequirement(pa, proto, source, Visited);
}
return;
}
case RequirementKind::SameType:
addSameTypeRequirement(req.getFirstType(), req.getSecondType(), source);
addSameTypeRequirement(req.getFirstType(), req.getSecondType(), source,
basePA);
return;
}

View File

@@ -113,23 +113,23 @@ struct Model_P3_P4_Eq<T : P3, U : P4> where T.P3Assoc == U.P4Assoc {}
// CHECK-NEXT: Requirements:
// CHECK-NEXT: τ_0_0 : P3 [inferred @ {{.*}}:32]
// CHECK-NEXT: τ_0_1 : P4 [inferred @ {{.*}}:32]
// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P1 [redundant @ {{.*}}:18]
// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P2 [protocol @ {{.*}}:18]
// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P1 [protocol @ {{.*}}:32]
// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P2 [protocol @ {{.*}}:32]
func inferSameType1<T, U>(_ x: Model_P3_P4_Eq<T, U>) { }
// CHECK-LABEL: .inferSameType2@
// CHECK-NEXT: Requirements:
// CHECK-NEXT: τ_0_0 : P3 [inferred]
// CHECK-NEXT: τ_0_1 : P4 [inferred]
// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P1 [redundant @ {{.*}}requirement_inference.swift:{{.*}}:18]
// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P2 [protocol @ {{.*}}requirement_inference.swift:{{.*}}:18]
// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P1 [protocol @ {{.*}}requirement_inference.swift:{{.*}}:25]
// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P2 [protocol @ {{.*}}requirement_inference.swift:{{.*}}:25]
// CHECK-NEXT: τ_0_0[.P3].P3Assoc == τ_0_1[.P4].P4Assoc [explicit]
func inferSameType2<T : P3, U : P4>(_: T, _: U) where U.P4Assoc : P2, T.P3Assoc == U.P4Assoc {}
// CHECK-LABEL: .inferSameType3@
// CHECK-NEXT: Requirements:
// CHECK-NEXT: τ_0_0 : PCommonAssoc1 [inferred]
// CHECK-NEXT: τ_0_0 : PCommonAssoc2 [inferred]
// CHECK-NEXT: τ_0_0 : PCommonAssoc2 [explicit @ {{.*}}requirement_inference.swift:{{.*}}:76]
// CHECK-NEXT: τ_0_0[.PCommonAssoc1].CommonAssoc : P1 [explicit @ {{.*}}requirement_inference.swift:{{.*}}:68]
// CHECK-NEXT: Potential archetypes
func inferSameType3<T : PCommonAssoc1>(_: T) where T.CommonAssoc : P1, T : PCommonAssoc2 {}

View File

@@ -67,7 +67,6 @@ extension P2 where Self.T : C {
// CHECK: Requirements:
// CHECK-NEXT: τ_0_0 : C [explicit @
// CHECK-NEXT: τ_0_0 : P3 [inherited @
// CHECK-NEXT: τ_0_0[.P3].T == C.T [redundant]
// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : C>
func superclassConformance1<T>(t: T) where T : C, T : P3 {}
@@ -75,7 +74,6 @@ func superclassConformance1<T>(t: T) where T : C, T : P3 {}
// CHECK: Requirements:
// CHECK-NEXT: τ_0_0 : C [explicit @
// CHECK-NEXT: τ_0_0 : P3 [inherited @
// CHECK-NEXT: τ_0_0[.P3].T == C.T [redundant]
// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : C>
func superclassConformance2<T>(t: T) where T : C, T : P3 {}