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
|
||||
/// 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(
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user