[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 /// \brief Add a new same-type requirement specifying that the given potential
/// archetypes should map to the equivalent archetype. /// 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 /// Add the requirements placed on the given abstract type parameter
/// to the given potential archetype. /// to the given potential archetype.
@@ -248,6 +249,10 @@ public:
/// re-inject requirements from outer contexts. /// re-inject requirements from outer contexts.
void addRequirement(const Requirement &req, RequirementSource source); void addRequirement(const Requirement &req, RequirementSource source);
void addRequirement(const Requirement &req, RequirementSource source,
PotentialArchetype *basePA,
llvm::SmallPtrSetImpl<ProtocolDecl *> &Visited);
bool addLayoutRequirement(PotentialArchetype *PAT, bool addLayoutRequirement(PotentialArchetype *PAT,
LayoutConstraint Layout, LayoutConstraint Layout,
RequirementSource Source); RequirementSource Source);
@@ -310,7 +315,12 @@ public:
/// signature are fully resolved). /// signature are fully resolved).
/// ///
/// For any type that cannot refer to an archetype, this routine returns null. /// 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. /// \brief Dump all of the requirements, both specified and inferred.
LLVM_ATTRIBUTE_DEPRECATED( LLVM_ATTRIBUTE_DEPRECATED(

View File

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

View File

@@ -938,8 +938,12 @@ LazyResolver *ArchetypeBuilder::getLazyResolver() const {
return Context.getLazyResolver(); return Context.getLazyResolver();
} }
auto ArchetypeBuilder::resolveArchetype(Type type) -> PotentialArchetype * { auto ArchetypeBuilder::resolveArchetype(Type type, PotentialArchetype *basePA)
-> PotentialArchetype * {
if (auto genericParam = type->getAs<GenericTypeParamType>()) { if (auto genericParam = type->getAs<GenericTypeParamType>()) {
if (basePA)
return basePA;
unsigned index = GenericParamKey(genericParam).findIndexIn( unsigned index = GenericParamKey(genericParam).findIndexIn(
Impl->GenericParams); Impl->GenericParams);
if (index < Impl->GenericParams.size()) if (index < Impl->GenericParams.size())
@@ -949,7 +953,7 @@ auto ArchetypeBuilder::resolveArchetype(Type type) -> PotentialArchetype * {
} }
if (auto dependentMember = type->getAs<DependentMemberType>()) { if (auto dependentMember = type->getAs<DependentMemberType>()) {
auto base = resolveArchetype(dependentMember->getBase()); auto base = resolveArchetype(dependentMember->getBase(), basePA);
if (!base) if (!base)
return nullptr; return nullptr;
@@ -1010,6 +1014,28 @@ bool ArchetypeBuilder::addConformanceRequirement(PotentialArchetype *PAT,
if (!T->addConformance(Proto, /*updateExistingSource=*/true, Source, *this)) if (!T->addConformance(Proto, /*updateExistingSource=*/true, Source, *this))
return false; return false;
bool inserted = Visited.insert(Proto).second;
assert(inserted);
(void) inserted;
// Requirements introduced by the main protocol are explicit in a protocol
// requirement signature, but inferred from this conformance otherwise.
auto Kind =
Source.getKind() == RequirementSource::ProtocolRequirementSignatureSelf
? RequirementSource::Explicit
: RequirementSource::Protocol;
// Use the requirement signature to avoid rewalking the entire protocol. This
// cannot compute the requirement signature directly, because that may be
// infinitely recursive: this code is also used to construct it.
if (Proto->isRequirementSignatureComputed()) {
auto reqSig = Proto->getRequirementSignature();
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 // Conformances to inherit protocols are explicit in a protocol requirement
// signature, but inferred from this conformance otherwise. // signature, but inferred from this conformance otherwise.
auto InnerKind = auto InnerKind =
@@ -1017,15 +1043,12 @@ bool ArchetypeBuilder::addConformanceRequirement(PotentialArchetype *PAT,
? RequirementSource::Explicit ? RequirementSource::Explicit
: RequirementSource::Redundant; : RequirementSource::Redundant;
RequirementSource InnerSource(InnerKind, Source.getLoc()); RequirementSource InnerSource(InnerKind, Source.getLoc());
bool inserted = Visited.insert(Proto).second;
assert(inserted);
(void) inserted;
// Add all of the inherited protocol requirements, recursively. // Add all of the inherited protocol requirements, recursively.
if (auto resolver = getLazyResolver()) if (auto resolver = getLazyResolver())
resolver->resolveInheritedProtocols(Proto); resolver->resolveInheritedProtocols(Proto);
for (auto InheritedProto : Proto->getInheritedProtocols(getLazyResolver())) {
for (auto InheritedProto :
Proto->getInheritedProtocols(getLazyResolver())) {
if (Visited.count(InheritedProto)) if (Visited.count(InheritedProto))
continue; continue;
if (addConformanceRequirement(T, InheritedProto, InnerSource, Visited)) if (addConformanceRequirement(T, InheritedProto, InnerSource, Visited))
@@ -1033,20 +1056,14 @@ bool ArchetypeBuilder::addConformanceRequirement(PotentialArchetype *PAT,
} }
// Add requirements for each of the associated types. // Add requirements for each of the associated types.
// FIXME: This should use the generic signature, not walk the members.
for (auto Member : Proto->getMembers()) { for (auto Member : Proto->getMembers()) {
if (auto AssocType = dyn_cast<AssociatedTypeDecl>(Member)) { if (auto AssocType = dyn_cast<AssociatedTypeDecl>(Member)) {
// Add requirements placed directly on this associated type. // Add requirements placed directly on this associated type.
auto AssocPA = T->getNestedType(AssocType, *this); 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;
if (AssocPA != T) { if (AssocPA != T) {
if (addAbstractTypeParamRequirements(AssocType, AssocPA, Kind, Visited)) if (addAbstractTypeParamRequirements(AssocType, AssocPA, Kind,
Visited))
return true; return true;
} }
@@ -1055,6 +1072,7 @@ bool ArchetypeBuilder::addConformanceRequirement(PotentialArchetype *PAT,
// FIXME: Requirement declarations. // FIXME: Requirement declarations.
} }
}
Visited.erase(Proto); Visited.erase(Proto);
return false; return false;
@@ -1399,10 +1417,11 @@ bool ArchetypeBuilder::addSameTypeRequirementToConcrete(
} }
bool ArchetypeBuilder::addSameTypeRequirement(Type Reqt1, Type Reqt2, bool ArchetypeBuilder::addSameTypeRequirement(Type Reqt1, Type Reqt2,
RequirementSource Source) { RequirementSource Source,
PotentialArchetype *basePA) {
// Find the potential archetypes. // Find the potential archetypes.
PotentialArchetype *T1 = resolveArchetype(Reqt1); PotentialArchetype *T1 = resolveArchetype(Reqt1, basePA);
PotentialArchetype *T2 = resolveArchetype(Reqt2); PotentialArchetype *T2 = resolveArchetype(Reqt2, basePA);
// Require that at least one side of the requirement be a potential archetype. // Require that at least one side of the requirement be a potential archetype.
if (!T1 && !T2) { if (!T1 && !T2) {
@@ -1609,9 +1628,17 @@ bool ArchetypeBuilder::addRequirement(const RequirementRepr &Req) {
void ArchetypeBuilder::addRequirement(const Requirement &req, void ArchetypeBuilder::addRequirement(const Requirement &req,
RequirementSource source) { 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()) { switch (req.getKind()) {
case RequirementKind::Superclass: { case RequirementKind::Superclass: {
PotentialArchetype *pa = resolveArchetype(req.getFirstType()); PotentialArchetype *pa = resolveArchetype(req.getFirstType(), basePA);
if (!pa) return; if (!pa) return;
assert(req.getSecondType()->getClassOrBoundGenericClass()); assert(req.getSecondType()->getClassOrBoundGenericClass());
@@ -1620,7 +1647,7 @@ void ArchetypeBuilder::addRequirement(const Requirement &req,
} }
case RequirementKind::Layout: { case RequirementKind::Layout: {
PotentialArchetype *pa = resolveArchetype(req.getFirstType()); PotentialArchetype *pa = resolveArchetype(req.getFirstType(), basePA);
if (!pa) return; if (!pa) return;
(void)addLayoutRequirement(pa, req.getLayoutConstraint(), source); (void)addLayoutRequirement(pa, req.getLayoutConstraint(), source);
@@ -1628,7 +1655,7 @@ void ArchetypeBuilder::addRequirement(const Requirement &req,
} }
case RequirementKind::Conformance: { case RequirementKind::Conformance: {
PotentialArchetype *pa = resolveArchetype(req.getFirstType()); PotentialArchetype *pa = resolveArchetype(req.getFirstType(), basePA);
if (!pa) return; if (!pa) return;
SmallVector<ProtocolDecl *, 4> conformsTo; SmallVector<ProtocolDecl *, 4> conformsTo;
@@ -1636,14 +1663,15 @@ void ArchetypeBuilder::addRequirement(const Requirement &req,
// Add each of the protocols. // Add each of the protocols.
for (auto proto : conformsTo) { for (auto proto : conformsTo) {
(void)addConformanceRequirement(pa, proto, source); (void)addConformanceRequirement(pa, proto, source, Visited);
} }
return; return;
} }
case RequirementKind::SameType: case RequirementKind::SameType:
addSameTypeRequirement(req.getFirstType(), req.getSecondType(), source); addSameTypeRequirement(req.getFirstType(), req.getSecondType(), source,
basePA);
return; 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: Requirements:
// CHECK-NEXT: τ_0_0 : P3 [inferred @ {{.*}}:32] // CHECK-NEXT: τ_0_0 : P3 [inferred @ {{.*}}:32]
// CHECK-NEXT: τ_0_1 : P4 [inferred @ {{.*}}:32] // CHECK-NEXT: τ_0_1 : P4 [inferred @ {{.*}}:32]
// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P1 [redundant @ {{.*}}:18] // CHECK-NEXT: τ_0_0[.P3].P3Assoc : P1 [protocol @ {{.*}}:32]
// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P2 [protocol @ {{.*}}:18] // CHECK-NEXT: τ_0_0[.P3].P3Assoc : P2 [protocol @ {{.*}}:32]
func inferSameType1<T, U>(_ x: Model_P3_P4_Eq<T, U>) { } func inferSameType1<T, U>(_ x: Model_P3_P4_Eq<T, U>) { }
// CHECK-LABEL: .inferSameType2@ // CHECK-LABEL: .inferSameType2@
// CHECK-NEXT: Requirements: // CHECK-NEXT: Requirements:
// CHECK-NEXT: τ_0_0 : P3 [inferred] // CHECK-NEXT: τ_0_0 : P3 [inferred]
// CHECK-NEXT: τ_0_1 : P4 [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 : P1 [protocol @ {{.*}}requirement_inference.swift:{{.*}}:25]
// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P2 [protocol @ {{.*}}requirement_inference.swift:{{.*}}:18] // CHECK-NEXT: τ_0_0[.P3].P3Assoc : P2 [protocol @ {{.*}}requirement_inference.swift:{{.*}}:25]
// CHECK-NEXT: τ_0_0[.P3].P3Assoc == τ_0_1[.P4].P4Assoc [explicit] // 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 {} func inferSameType2<T : P3, U : P4>(_: T, _: U) where U.P4Assoc : P2, T.P3Assoc == U.P4Assoc {}
// CHECK-LABEL: .inferSameType3@ // CHECK-LABEL: .inferSameType3@
// CHECK-NEXT: Requirements: // CHECK-NEXT: Requirements:
// CHECK-NEXT: τ_0_0 : PCommonAssoc1 [inferred] // 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: τ_0_0[.PCommonAssoc1].CommonAssoc : P1 [explicit @ {{.*}}requirement_inference.swift:{{.*}}:68]
// CHECK-NEXT: Potential archetypes // CHECK-NEXT: Potential archetypes
func inferSameType3<T : PCommonAssoc1>(_: T) where T.CommonAssoc : P1, T : PCommonAssoc2 {} 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: Requirements:
// CHECK-NEXT: τ_0_0 : C [explicit @ // CHECK-NEXT: τ_0_0 : C [explicit @
// CHECK-NEXT: τ_0_0 : P3 [inherited @ // 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> // 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, T : P3 {}
@@ -75,7 +74,6 @@ func superclassConformance1<T>(t: T) where T : C, T : P3 {}
// CHECK: Requirements: // CHECK: Requirements:
// CHECK-NEXT: τ_0_0 : C [explicit @ // CHECK-NEXT: τ_0_0 : C [explicit @
// CHECK-NEXT: τ_0_0 : P3 [inherited @ // 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> // 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, T : P3 {}