36
36
#include " llvm/ADT/Statistic.h"
37
37
#include " llvm/ADT/STLExtras.h"
38
38
#include " llvm/Support/raw_ostream.h"
39
+ #include " llvm/Support/SaveAndRestore.h"
39
40
#include < algorithm>
40
41
41
42
using namespace swift ;
@@ -72,6 +73,16 @@ STATISTIC(NumArchetypeAnchorCacheHits,
72
73
" # of hits in the archetype anchor cache" );
73
74
STATISTIC (NumArchetypeAnchorCacheMisses,
74
75
" # 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" );
75
86
76
87
struct GenericSignatureBuilder ::Implementation {
77
88
// / Function used to look up conformances.
@@ -90,6 +101,16 @@ struct GenericSignatureBuilder::Implementation {
90
101
// / The set of requirements that have been delayed for some reason.
91
102
SmallVector<DelayedRequirement, 4 > DelayedRequirements;
92
103
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
+
93
114
#ifndef NDEBUG
94
115
// / Whether we've already finalized the builder.
95
116
bool finalized = false ;
@@ -398,6 +419,11 @@ bool RequirementSource::isSelfDerivedConformance(
398
419
switch (source->kind ) {
399
420
case ProtocolRequirement:
400
421
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
+
401
427
// Note that we've seen a protocol requirement.
402
428
sawProtocolRequirement = true ;
403
429
@@ -1399,6 +1425,8 @@ bool PotentialArchetype::addConformance(ProtocolDecl *proto,
1399
1425
return false ;
1400
1426
}
1401
1427
1428
+ builder.bumpGeneration ();
1429
+
1402
1430
// Add the conformance along with this constraint.
1403
1431
equivClass->conformsTo [proto].push_back ({this , proto, source});
1404
1432
++NumConformanceConstraints;
@@ -1867,6 +1895,15 @@ PotentialArchetype *PotentialArchetype::updateNestedTypeForConformance(
1867
1895
if (!assocType && !concreteDecl)
1868
1896
return nullptr ;
1869
1897
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
+
1870
1907
Identifier name = assocType ? assocType->getName () : concreteDecl->getName ();
1871
1908
ProtocolDecl *proto =
1872
1909
assocType ? assocType->getProtocol ()
@@ -1901,6 +1938,8 @@ PotentialArchetype *PotentialArchetype::updateNestedTypeForConformance(
1901
1938
switch (kind) {
1902
1939
case ArchetypeResolutionKind::CompleteWellFormed:
1903
1940
case ArchetypeResolutionKind::WellFormed: {
1941
+ builder.bumpGeneration ();
1942
+
1904
1943
if (assocType)
1905
1944
resultPA = new PotentialArchetype (this , assocType);
1906
1945
else
@@ -2819,6 +2858,8 @@ ConstraintResult GenericSignatureBuilder::addLayoutRequirement(
2819
2858
return ConstraintResult::Resolved;
2820
2859
}
2821
2860
2861
+ bumpGeneration ();
2862
+
2822
2863
auto pa = resolvedSubject->getPotentialArchetype ();
2823
2864
return addLayoutRequirementDirect (pa, layout, source.getSource (pa));
2824
2865
}
@@ -2903,6 +2944,8 @@ ConstraintResult GenericSignatureBuilder::addSuperclassRequirementDirect(
2903
2944
.push_back (ConcreteConstraint{T, superclass, source});
2904
2945
++NumSuperclassConstraints;
2905
2946
2947
+ bumpGeneration ();
2948
+
2906
2949
// Update the equivalence class with the constraint.
2907
2950
updateSuperclass (T, superclass, source);
2908
2951
return ConstraintResult::Resolved;
@@ -3062,6 +3105,8 @@ GenericSignatureBuilder::addSameTypeRequirementBetweenArchetypes(
3062
3105
if (T1 == T2)
3063
3106
return ConstraintResult::Resolved;
3064
3107
3108
+ bumpGeneration ();
3109
+
3065
3110
unsigned nestingDepth1 = T1->getNestingDepth ();
3066
3111
unsigned nestingDepth2 = T2->getNestingDepth ();
3067
3112
@@ -3197,6 +3242,8 @@ ConstraintResult GenericSignatureBuilder::addSameTypeRequirementToConcrete(
3197
3242
ConcreteConstraint{T, Concrete, Source});
3198
3243
++NumConcreteTypeConstraints;
3199
3244
3245
+ bumpGeneration ();
3246
+
3200
3247
// If we've already been bound to a type, match that type.
3201
3248
if (equivClass->concreteType ) {
3202
3249
return addSameTypeRequirement (equivClass->concreteType , Concrete, Source,
@@ -3979,8 +4026,27 @@ static GenericSignatureBuilder::UnresolvedType asUnresolvedType(
3979
4026
}
3980
4027
3981
4028
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 {
3984
4050
// Steal the delayed requirements so we can reprocess them.
3985
4051
anySolved = false ;
3986
4052
auto delayed = std::move (Impl->DelayedRequirements );
@@ -4013,21 +4079,35 @@ void GenericSignatureBuilder::processDelayedRequirements() {
4013
4079
// Update our state based on what happened.
4014
4080
switch (reqResult) {
4015
4081
case ConstraintResult::Concrete:
4082
+ ++NumDelayedRequirementConcrete;
4083
+ anySolved = true ;
4084
+ break ;
4085
+
4016
4086
case ConstraintResult::Conflicting:
4017
4087
anySolved = true ;
4018
4088
break ;
4019
4089
4020
4090
case ConstraintResult::Resolved:
4091
+ ++NumDelayedRequirementResolved;
4021
4092
anySolved = true ;
4022
4093
break ;
4023
4094
4024
4095
case ConstraintResult::Unresolved:
4025
4096
// Add the requirement back.
4097
+ ++NumDelayedRequirementUnresolved;
4026
4098
Impl->DelayedRequirements .push_back (req);
4027
4099
break ;
4028
4100
}
4029
4101
}
4030
- }
4102
+
4103
+ if (anySolved) {
4104
+ anyChanges = true ;
4105
+ }
4106
+ } while (anySolved);
4107
+ }
4108
+
4109
+ void GenericSignatureBuilder::bumpGeneration () {
4110
+ ++Impl->Generation ;
4031
4111
}
4032
4112
4033
4113
template <typename T>
@@ -4305,6 +4385,19 @@ void GenericSignatureBuilder::checkConformanceConstraints(
4305
4385
auto proto = constraint.value ;
4306
4386
assert (proto == entry.first && " Mixed up protocol constraints" );
4307
4387
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
+
4308
4401
// If this is a redundantly inherited Objective-C protocol, treat it
4309
4402
// as "unrelated" to silence the warning about the redundant
4310
4403
// conformance.
0 commit comments