@@ -56,44 +56,40 @@ static bool hasThrowingFunctionClosureParameter(CanType type) {
56
56
ProtocolRethrowsRequirementList
57
57
ProtocolRethrowsRequirementsRequest::evaluate (Evaluator &evaluator,
58
58
ProtocolDecl *decl) const {
59
- SmallVector<std::pair<Type, ValueDecl*>, 2 > found;
60
- llvm::DenseSet<ProtocolDecl*> checkedProtocols;
61
-
62
59
ASTContext &ctx = decl->getASTContext ();
63
60
64
61
// only allow rethrowing requirements to be determined from marked protocols
65
- if (!decl->getAttrs (). hasAttribute <swift::AtRethrowsAttr> ()) {
66
- return ProtocolRethrowsRequirementList (ctx. AllocateCopy (found) );
62
+ if (!decl->isRethrowingProtocol ()) {
63
+ return ProtocolRethrowsRequirementList ();
67
64
}
68
65
66
+ SmallVector<AbstractFunctionDecl *, 2 > requirements;
67
+ SmallVector<std::pair<Type, ProtocolDecl *>, 2 > conformances;
68
+
69
69
// check if immediate members of protocol are 'throws'
70
70
for (auto member : decl->getMembers ()) {
71
71
auto fnDecl = dyn_cast<AbstractFunctionDecl>(member);
72
72
if (!fnDecl || !fnDecl->hasThrows ())
73
73
continue ;
74
74
75
- found.push_back (
76
- std::pair<Type, ValueDecl*>(decl->getSelfInterfaceType (), fnDecl));
75
+ requirements.push_back (fnDecl);
77
76
}
78
- checkedProtocols.insert (decl);
79
77
80
78
// check associated conformances of associated types or inheritance
81
79
for (auto requirement : decl->getRequirementSignature ()) {
82
- if (requirement.getKind () != RequirementKind::Conformance) {
80
+ if (requirement.getKind () != RequirementKind::Conformance)
83
81
continue ;
84
- }
82
+
85
83
auto protoTy = requirement.getSecondType ()->castTo <ProtocolType>();
86
- auto proto = protoTy->getDecl ();
87
- if (checkedProtocols. count (proto) != 0 ) {
84
+ auto protoDecl = protoTy->getDecl ();
85
+ if (!protoDecl-> isRethrowingProtocol ())
88
86
continue ;
89
- }
90
- checkedProtocols.insert (proto);
91
- for (auto entry : proto->getRethrowingRequirements ()) {
92
- found.emplace_back (requirement.getFirstType (), entry.second );
93
- }
87
+
88
+ conformances.emplace_back (requirement.getFirstType (), protoDecl);
94
89
}
95
90
96
- return ProtocolRethrowsRequirementList (ctx.AllocateCopy (found));
91
+ return ProtocolRethrowsRequirementList (ctx.AllocateCopy (requirements),
92
+ ctx.AllocateCopy (conformances));
97
93
}
98
94
99
95
FunctionRethrowingKind
@@ -135,14 +131,14 @@ FunctionRethrowingKindRequest::evaluate(Evaluator &evaluator,
135
131
return FunctionRethrowingKind::None;
136
132
}
137
133
138
- static bool classifyRequirement (ModuleDecl *module ,
139
- ProtocolConformance *reqConformance ,
140
- ValueDecl *requiredFn ) {
141
- auto declRef = reqConformance ->getWitnessDeclRef (requiredFn );
134
+ static bool classifyWitness (ModuleDecl *module ,
135
+ ProtocolConformance *conformance ,
136
+ AbstractFunctionDecl *req ) {
137
+ auto declRef = conformance ->getWitnessDeclRef (req );
142
138
auto witnessDecl = cast<AbstractFunctionDecl>(declRef.getDecl ());
143
139
switch (witnessDecl->getRethrowingKind ()) {
144
140
case FunctionRethrowingKind::ByConformance: {
145
- auto substitutions = reqConformance ->getSubstitutions (module );
141
+ auto substitutions = conformance ->getSubstitutions (module );
146
142
for (auto conformanceRef : substitutions.getConformances ()) {
147
143
if (conformanceRef.classifyAsThrows ()) {
148
144
return true ;
@@ -160,43 +156,42 @@ static bool classifyRequirement(ModuleDecl *module,
160
156
return false ;
161
157
}
162
158
163
- // classify the type requirements of a given protocol type with a function
164
- // requirement as throws or not. This will detect if the signature of the
165
- // function is throwing or not depending on associated types.
166
- static bool classifyTypeRequirement (ModuleDecl *module , Type protoType,
167
- ValueDecl *requiredFn,
168
- ProtocolConformance *conformance,
169
- ProtocolDecl *requiredProtocol) {
170
- auto reqProtocol = cast<ProtocolDecl>(requiredFn->getDeclContext ());
171
- ProtocolConformance *reqConformance;
172
-
173
- if (protoType->isEqual (reqProtocol->getSelfInterfaceType ()) &&
174
- requiredProtocol == reqProtocol) {
175
- reqConformance = conformance;
176
- } else {
177
- auto reqConformanceRef =
178
- conformance->getAssociatedConformance (protoType, reqProtocol);
179
- if (!reqConformanceRef.isConcrete ()) {
180
- return true ;
159
+ bool
160
+ ProtocolConformanceClassifyAsThrowsRequest::evaluate (
161
+ Evaluator &evaluator, ProtocolConformance *conformance) const {
162
+ auto *module = conformance->getDeclContext ()->getParentModule ();
163
+
164
+ llvm::SmallDenseSet<ProtocolConformance *, 2 > visited;
165
+ SmallVector<ProtocolConformance *, 2 > worklist;
166
+
167
+ worklist.push_back (conformance);
168
+
169
+ while (!worklist.empty ()) {
170
+ auto *current = worklist.back ();
171
+ worklist.pop_back ();
172
+
173
+ if (!visited.insert (current).second )
174
+ continue ;
175
+
176
+ auto protoDecl = current->getProtocol ();
177
+
178
+ auto list = protoDecl->getRethrowingRequirements ();
179
+ for (auto req : list.getRequirements ()) {
180
+ if (classifyWitness (module , current, req))
181
+ return true ;
181
182
}
182
- reqConformance = reqConformanceRef.getConcrete ();
183
- }
184
183
185
- return classifyRequirement (module , reqConformance, requiredFn);
186
- }
184
+ for (auto pair : list.getConformances ()) {
185
+ auto assocConf =
186
+ current->getAssociatedConformance (
187
+ pair.first , pair.second );
188
+ if (!assocConf.isConcrete ())
189
+ return true ;
187
190
188
- bool
189
- ProtocolConformanceRefClassifyAsThrowsRequest::evaluate (
190
- Evaluator &evaluator, ProtocolConformanceRef conformanceRef) const {
191
- auto conformance = conformanceRef.getConcrete ();
192
- auto requiredProtocol = conformanceRef.getRequirement ();
193
- auto module = requiredProtocol->getModuleContext ();
194
- for (auto req : requiredProtocol->getRethrowingRequirements ()) {
195
- if (classifyTypeRequirement (module , req.first , req.second ,
196
- conformance, requiredProtocol)) {
197
- return true ;
191
+ worklist.push_back (assocConf.getConcrete ());
198
192
}
199
193
}
194
+
200
195
return false ;
201
196
}
202
197
0 commit comments