11
11
// ===----------------------------------------------------------------------===//
12
12
13
13
#include " swift/AST/ASTContext.h"
14
+ #include " swift/AST/ASTPrinter.h"
14
15
#include " swift/AST/Decl.h"
15
16
#include " swift/AST/DiagnosticsFrontend.h"
16
17
#include " swift/AST/DiagnosticsSema.h"
@@ -163,47 +164,69 @@ namespace {
163
164
class InheritedProtocolCollector {
164
165
static const StringLiteral DummyProtocolName;
165
166
167
+ using AvailableAttrList = TinyPtrVector<const AvailableAttr *>;
168
+ using ProtocolAndAvailability =
169
+ std::pair<ProtocolDecl *, AvailableAttrList>;
170
+
166
171
// / Protocols that will be included by the ASTPrinter without any extra work.
167
172
SmallVector<ProtocolDecl *, 8 > IncludedProtocols;
168
- // / Protocols that will not be printed by the ASTPrinter.
169
- SmallVector<ProtocolDecl *, 8 > ExtraProtocols;
173
+ // / Protocols that will not be printed by the ASTPrinter, along with the
174
+ // / availability they were declared with.
175
+ SmallVector<ProtocolAndAvailability, 8 > ExtraProtocols;
170
176
// / Protocols that can be printed, but whose conformances are constrained with
171
177
// / something that \e can't be printed.
172
178
SmallVector<const ProtocolType *, 8 > ConditionalConformanceProtocols;
173
179
180
+ // / Helper to extract the `@available` attributes on a decl.
181
+ AvailableAttrList getAvailabilityAttrs (const Decl *D) {
182
+ AvailableAttrList result;
183
+ auto attrRange = D->getAttrs ().getAttributes <AvailableAttr>();
184
+ result.insert (result.begin (), attrRange.begin (), attrRange.end ());
185
+ return result;
186
+ }
187
+
174
188
// / For each type in \p directlyInherited, classify the protocols it refers to
175
189
// / as included for printing or not, and record them in the appropriate
176
190
// / vectors.
177
- void recordProtocols (ArrayRef<TypeLoc> directlyInherited) {
191
+ void recordProtocols (ArrayRef<TypeLoc> directlyInherited, const Decl *D) {
192
+ Optional<AvailableAttrList> availableAttrs;
193
+
178
194
for (TypeLoc inherited : directlyInherited) {
179
195
Type inheritedTy = inherited.getType ();
180
196
if (!inheritedTy || !inheritedTy->isExistentialType ())
181
197
continue ;
182
198
183
199
bool canPrintNormally = isPublicOrUsableFromInline (inheritedTy);
184
- SmallVectorImpl<ProtocolDecl *> &whichProtocols =
185
- canPrintNormally ? IncludedProtocols : ExtraProtocols ;
200
+ if (!canPrintNormally && !availableAttrs. hasValue ())
201
+ availableAttrs = getAvailabilityAttrs (D) ;
186
202
187
203
ExistentialLayout layout = inheritedTy->getExistentialLayout ();
188
- for (ProtocolType *protoTy : layout.getProtocols ())
189
- whichProtocols.push_back (protoTy->getDecl ());
204
+ for (ProtocolType *protoTy : layout.getProtocols ()) {
205
+ if (canPrintNormally)
206
+ IncludedProtocols.push_back (protoTy->getDecl ());
207
+ else
208
+ ExtraProtocols.push_back ({protoTy->getDecl (),
209
+ availableAttrs.getValue ()});
210
+ }
190
211
// FIXME: This ignores layout constraints, but currently we don't support
191
212
// any of those besides 'AnyObject'.
192
213
}
193
214
}
194
215
195
- // / For each type in \p directlyInherited , record any protocols that we would
196
- // / have printed in ConditionalConformanceProtocols.
197
- void recordConditionalConformances (ArrayRef<TypeLoc> directlyInherited ) {
198
- for (TypeLoc inherited : directlyInherited ) {
216
+ // / For each type directly inherited by \p extension , record any protocols
217
+ // / that we would have printed in ConditionalConformanceProtocols.
218
+ void recordConditionalConformances (const ExtensionDecl *extension ) {
219
+ for (TypeLoc inherited : extension-> getInherited () ) {
199
220
Type inheritedTy = inherited.getType ();
200
221
if (!inheritedTy || !inheritedTy->isExistentialType ())
201
222
continue ;
202
223
203
224
ExistentialLayout layout = inheritedTy->getExistentialLayout ();
204
- for (ProtocolType *protoTy : layout.getProtocols ())
205
- if (isPublicOrUsableFromInline (protoTy))
206
- ConditionalConformanceProtocols.push_back (protoTy);
225
+ for (ProtocolType *protoTy : layout.getProtocols ()) {
226
+ if (!isPublicOrUsableFromInline (protoTy))
227
+ continue ;
228
+ ConditionalConformanceProtocols.push_back (protoTy);
229
+ }
207
230
// FIXME: This ignores layout constraints, but currently we don't support
208
231
// any of those besides 'AnyObject'.
209
232
}
@@ -243,7 +266,7 @@ class InheritedProtocolCollector {
243
266
if (!isPublicOrUsableFromInline (nominal))
244
267
return ;
245
268
246
- map[nominal].recordProtocols (directlyInherited);
269
+ map[nominal].recordProtocols (directlyInherited, D );
247
270
248
271
// Recurse to find any nested types.
249
272
for (const Decl *member : memberContext->getMembers ())
@@ -264,7 +287,7 @@ class InheritedProtocolCollector {
264
287
if (!isPublicOrUsableFromInline (nominal))
265
288
return ;
266
289
267
- map[nominal].recordConditionalConformances (extension-> getInherited () );
290
+ map[nominal].recordConditionalConformances (extension);
268
291
// No recursion here because extensions are never nested.
269
292
}
270
293
@@ -307,16 +330,19 @@ class InheritedProtocolCollector {
307
330
// Note: We could do this in one pass, but the logic is easier to
308
331
// understand if we build up the list and then print it, even if it takes
309
332
// a bit more memory.
310
- SmallVector<ProtocolDecl *, 16 > protocolsToPrint;
311
- for (ProtocolDecl *proto : ExtraProtocols) {
312
- proto->walkInheritedProtocols (
333
+ // FIXME: This will pick the availability attributes from the first sight
334
+ // of a protocol rather than the maximally available case.
335
+ SmallVector<std::pair<ProtocolDecl *, AvailableAttrList>, 16 >
336
+ protocolsToPrint;
337
+ for (const auto &protoAndAvailability : ExtraProtocols) {
338
+ protoAndAvailability.first ->walkInheritedProtocols (
313
339
[&](ProtocolDecl *inherited) -> TypeWalker::Action {
314
340
if (!handledProtocols.insert (inherited).second )
315
341
return TypeWalker::Action::SkipChildren;
316
342
317
343
if (isPublicOrUsableFromInline (inherited) &&
318
344
conformanceDeclaredInModule (M, nominal, inherited)) {
319
- protocolsToPrint.push_back (inherited);
345
+ protocolsToPrint.push_back ({ inherited, protoAndAvailability. second } );
320
346
return TypeWalker::Action::SkipChildren;
321
347
}
322
348
@@ -326,14 +352,20 @@ class InheritedProtocolCollector {
326
352
if (protocolsToPrint.empty ())
327
353
return ;
328
354
329
- out << " extension " ;
330
- nominal->getDeclaredType ().print (out, printOptions);
331
- out << " : " ;
332
- swift::interleave (protocolsToPrint,
333
- [&out, &printOptions](ProtocolDecl *proto) {
334
- proto->getDeclaredType ()->print (out, printOptions);
335
- }, [&out] { out << " , " ; });
336
- out << " {}\n " ;
355
+ for (const auto &protoAndAvailability : protocolsToPrint) {
356
+ StreamPrinter printer (out);
357
+ for (const AvailableAttr *attr : protoAndAvailability.second )
358
+ attr->print (printer, printOptions);
359
+
360
+ printer << " extension " ;
361
+ nominal->getDeclaredType ().print (printer, printOptions);
362
+ printer << " : " ;
363
+
364
+ ProtocolDecl *proto = protoAndAvailability.first ;
365
+ proto->getDeclaredType ()->print (printer, printOptions);
366
+
367
+ printer << " {}\n " ;
368
+ }
337
369
}
338
370
339
371
// / If there were any conditional conformances that couldn't be printed,
@@ -346,7 +378,7 @@ class InheritedProtocolCollector {
346
378
return false ;
347
379
assert (nominal->isGenericContext ());
348
380
349
- out << " extension " ;
381
+ out << " @available(*, unavailable) \n extension " ;
350
382
nominal->getDeclaredType ().print (out, printOptions);
351
383
out << " : " ;
352
384
swift::interleave (ConditionalConformanceProtocols,
0 commit comments