mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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:
@@ -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(
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 {}
|
||||||
|
|||||||
@@ -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 {}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user