Skip to content

Commit ef1a96d

Browse files
authored
Merge pull request #11174 from DougGregor/reprocess-delayed-requirements
2 parents 6d06792 + 83642c6 commit ef1a96d

File tree

3 files changed

+110
-4
lines changed

3 files changed

+110
-4
lines changed

include/swift/AST/GenericSignatureBuilder.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,9 @@ class GenericSignatureBuilder {
559559
void processDelayedRequirements();
560560

561561
private:
562+
/// Bump the generation count due to a change.
563+
void bumpGeneration();
564+
562565
/// Describes the relationship between a given constraint and
563566
/// the canonical constraint of the equivalence class.
564567
enum class ConstraintRelation {

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 96 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "llvm/ADT/Statistic.h"
3737
#include "llvm/ADT/STLExtras.h"
3838
#include "llvm/Support/raw_ostream.h"
39+
#include "llvm/Support/SaveAndRestore.h"
3940
#include <algorithm>
4041

4142
using namespace swift;
@@ -72,6 +73,16 @@ STATISTIC(NumArchetypeAnchorCacheHits,
7273
"# of hits in the archetype anchor cache");
7374
STATISTIC(NumArchetypeAnchorCacheMisses,
7475
"# of misses in the archetype anchor cache");
76+
STATISTIC(NumProcessDelayedRequirements,
77+
"# of times we process delayed requirements");
78+
STATISTIC(NumProcessDelayedRequirementsUnchanged,
79+
"# of times we process delayed requirements without change");
80+
STATISTIC(NumDelayedRequirementConcrete,
81+
"Delayed requirements resolved as concrete");
82+
STATISTIC(NumDelayedRequirementResolved,
83+
"Delayed requirements resolved");
84+
STATISTIC(NumDelayedRequirementUnresolved,
85+
"Delayed requirements left unresolved");
7586

7687
struct GenericSignatureBuilder::Implementation {
7788
/// Function used to look up conformances.
@@ -90,6 +101,16 @@ struct GenericSignatureBuilder::Implementation {
90101
/// The set of requirements that have been delayed for some reason.
91102
SmallVector<DelayedRequirement, 4> DelayedRequirements;
92103

104+
/// The generation number, which is incremented whenever we successfully
105+
/// introduce a new constraint.
106+
unsigned Generation = 0;
107+
108+
/// The generation at which we last processed all of the delayed requirements.
109+
unsigned LastProcessedGeneration = 0;
110+
111+
/// Whether we are currently processing delayed requirements.
112+
bool ProcessingDelayedRequirements = false;
113+
93114
#ifndef NDEBUG
94115
/// Whether we've already finalized the builder.
95116
bool finalized = false;
@@ -398,6 +419,11 @@ bool RequirementSource::isSelfDerivedConformance(
398419
switch (source->kind) {
399420
case ProtocolRequirement:
400421
case InferredProtocolRequirement: {
422+
// For a requirement signature, we ignore the 'Self: P' requirement
423+
// for the purposes of the self-derived check.
424+
if (source->parent->kind == RequirementSource::RequirementSignatureSelf)
425+
return false;
426+
401427
// Note that we've seen a protocol requirement.
402428
sawProtocolRequirement = true;
403429

@@ -1399,6 +1425,8 @@ bool PotentialArchetype::addConformance(ProtocolDecl *proto,
13991425
return false;
14001426
}
14011427

1428+
builder.bumpGeneration();
1429+
14021430
// Add the conformance along with this constraint.
14031431
equivClass->conformsTo[proto].push_back({this, proto, source});
14041432
++NumConformanceConstraints;
@@ -1867,6 +1895,15 @@ PotentialArchetype *PotentialArchetype::updateNestedTypeForConformance(
18671895
if (!assocType && !concreteDecl)
18681896
return nullptr;
18691897

1898+
// If we were asked for a complete, well-formed archetype, make sure we
1899+
// process delayed requirements if anything changed.
1900+
SWIFT_DEFER {
1901+
ASTContext &ctx = assocType ? assocType->getASTContext()
1902+
: concreteDecl->getASTContext();
1903+
if (ctx.LangOpts.EnableRecursiveConstraints)
1904+
getBuilder()->processDelayedRequirements();
1905+
};
1906+
18701907
Identifier name = assocType ? assocType->getName() : concreteDecl->getName();
18711908
ProtocolDecl *proto =
18721909
assocType ? assocType->getProtocol()
@@ -1901,6 +1938,8 @@ PotentialArchetype *PotentialArchetype::updateNestedTypeForConformance(
19011938
switch (kind) {
19021939
case ArchetypeResolutionKind::CompleteWellFormed:
19031940
case ArchetypeResolutionKind::WellFormed: {
1941+
builder.bumpGeneration();
1942+
19041943
if (assocType)
19051944
resultPA = new PotentialArchetype(this, assocType);
19061945
else
@@ -2819,6 +2858,8 @@ ConstraintResult GenericSignatureBuilder::addLayoutRequirement(
28192858
return ConstraintResult::Resolved;
28202859
}
28212860

2861+
bumpGeneration();
2862+
28222863
auto pa = resolvedSubject->getPotentialArchetype();
28232864
return addLayoutRequirementDirect(pa, layout, source.getSource(pa));
28242865
}
@@ -2903,6 +2944,8 @@ ConstraintResult GenericSignatureBuilder::addSuperclassRequirementDirect(
29032944
.push_back(ConcreteConstraint{T, superclass, source});
29042945
++NumSuperclassConstraints;
29052946

2947+
bumpGeneration();
2948+
29062949
// Update the equivalence class with the constraint.
29072950
updateSuperclass(T, superclass, source);
29082951
return ConstraintResult::Resolved;
@@ -3062,6 +3105,8 @@ GenericSignatureBuilder::addSameTypeRequirementBetweenArchetypes(
30623105
if (T1 == T2)
30633106
return ConstraintResult::Resolved;
30643107

3108+
bumpGeneration();
3109+
30653110
unsigned nestingDepth1 = T1->getNestingDepth();
30663111
unsigned nestingDepth2 = T2->getNestingDepth();
30673112

@@ -3197,6 +3242,8 @@ ConstraintResult GenericSignatureBuilder::addSameTypeRequirementToConcrete(
31973242
ConcreteConstraint{T, Concrete, Source});
31983243
++NumConcreteTypeConstraints;
31993244

3245+
bumpGeneration();
3246+
32003247
// If we've already been bound to a type, match that type.
32013248
if (equivClass->concreteType) {
32023249
return addSameTypeRequirement(equivClass->concreteType, Concrete, Source,
@@ -3979,8 +4026,27 @@ static GenericSignatureBuilder::UnresolvedType asUnresolvedType(
39794026
}
39804027

39814028
void GenericSignatureBuilder::processDelayedRequirements() {
3982-
bool anySolved = !Impl->DelayedRequirements.empty();
3983-
while (anySolved) {
4029+
// If we're already up-to-date, do nothing.
4030+
if (Impl->Generation == Impl->LastProcessedGeneration) { return; }
4031+
4032+
// If there are no delayed requirements, do nothing.
4033+
if (Impl->DelayedRequirements.empty()) { return; }
4034+
4035+
if (Impl->ProcessingDelayedRequirements) { return; }
4036+
4037+
++NumProcessDelayedRequirements;
4038+
4039+
llvm::SaveAndRestore<bool> processing(Impl->ProcessingDelayedRequirements,
4040+
true);
4041+
bool anyChanges = false;
4042+
SWIFT_DEFER {
4043+
Impl->LastProcessedGeneration = Impl->Generation;
4044+
if (!anyChanges)
4045+
++NumProcessDelayedRequirementsUnchanged;
4046+
};
4047+
4048+
bool anySolved;
4049+
do {
39844050
// Steal the delayed requirements so we can reprocess them.
39854051
anySolved = false;
39864052
auto delayed = std::move(Impl->DelayedRequirements);
@@ -4013,21 +4079,35 @@ void GenericSignatureBuilder::processDelayedRequirements() {
40134079
// Update our state based on what happened.
40144080
switch (reqResult) {
40154081
case ConstraintResult::Concrete:
4082+
++NumDelayedRequirementConcrete;
4083+
anySolved = true;
4084+
break;
4085+
40164086
case ConstraintResult::Conflicting:
40174087
anySolved = true;
40184088
break;
40194089

40204090
case ConstraintResult::Resolved:
4091+
++NumDelayedRequirementResolved;
40214092
anySolved = true;
40224093
break;
40234094

40244095
case ConstraintResult::Unresolved:
40254096
// Add the requirement back.
4097+
++NumDelayedRequirementUnresolved;
40264098
Impl->DelayedRequirements.push_back(req);
40274099
break;
40284100
}
40294101
}
4030-
}
4102+
4103+
if (anySolved) {
4104+
anyChanges = true;
4105+
}
4106+
} while (anySolved);
4107+
}
4108+
4109+
void GenericSignatureBuilder::bumpGeneration() {
4110+
++Impl->Generation;
40314111
}
40324112

40334113
template<typename T>
@@ -4305,6 +4385,19 @@ void GenericSignatureBuilder::checkConformanceConstraints(
43054385
auto proto = constraint.value;
43064386
assert(proto == entry.first && "Mixed up protocol constraints");
43074387

4388+
// If this conformance requirement recursively makes a protocol
4389+
// conform to itself, don't complain here.
4390+
auto source = constraint.source;
4391+
auto rootSource = source->getRoot();
4392+
if (rootSource->kind == RequirementSource::RequirementSignatureSelf &&
4393+
source != rootSource &&
4394+
proto == rootSource->getProtocolDecl() &&
4395+
rootSource->getRootPotentialArchetype()
4396+
->isInSameEquivalenceClassAs(
4397+
source->getAffectedPotentialArchetype())) {
4398+
return ConstraintRelation::Unrelated;
4399+
}
4400+
43084401
// If this is a redundantly inherited Objective-C protocol, treat it
43094402
// as "unrelated" to silence the warning about the redundant
43104403
// conformance.

test/decl/protocol/recursive_requirement_ok.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,15 @@ protocol P {
99
func testP<T: P>(_ t: T) {
1010
testP(t.assoc)
1111
testP(t.assoc.assoc)
12-
testP(t.assoc.assoc.assoc) // FIXME: expected-error{{argument type 'T.Assoc.Assoc.Assoc' does not conform to expected type 'P'}}
12+
testP(t.assoc.assoc.assoc)
13+
testP(t.assoc.assoc.assoc.assoc.assoc.assoc.assoc)
14+
}
15+
16+
// SR-5485
17+
protocol P1 {
18+
associatedtype X : P2
19+
}
20+
protocol P2 {
21+
associatedtype Y : P1 where Y.X == Self // expected-note{{conformance constraint 'Self.Z': 'P1' implied here}}
22+
associatedtype Z : P1 // expected-warning{{redundant conformance constraint 'Self.Z': 'P1'}}
1323
}

0 commit comments

Comments
 (0)