@@ -192,13 +192,17 @@ static void
192
192
deriveBodyRawRepresentable_init (AbstractFunctionDecl *initDecl, void *) {
193
193
// enum SomeEnum : SomeType {
194
194
// case A = 111, B = 222
195
+ // @available(iOS 10, *) case C = 333
195
196
// @derived
196
197
// init?(rawValue: SomeType) {
197
198
// switch rawValue {
198
199
// case 111:
199
200
// self = .A
200
201
// case 222:
201
202
// self = .B
203
+ // case 333:
204
+ // guard #available(iOS 10, *) else { return nil }
205
+ // self = .C
202
206
// default:
203
207
// return nil
204
208
// }
@@ -234,6 +238,7 @@ deriveBodyRawRepresentable_init(AbstractFunctionDecl *initDecl, void *) {
234
238
SmallVector<ASTNode, 4 > cases;
235
239
unsigned Idx = 0 ;
236
240
for (auto elt : enumDecl->getAllElements ()) {
241
+ // litPat = "\(elt.rawValueExpr)", e.g. "42" as a pattern
237
242
LiteralExpr *litExpr = cloneRawLiteralExpr (C, elt->getRawValueExpr ());
238
243
if (isStringEnum) {
239
244
// In case of a string enum we are calling the _findStringSwitchCase
@@ -245,23 +250,78 @@ deriveBodyRawRepresentable_init(AbstractFunctionDecl *initDecl, void *) {
245
250
nullptr , nullptr );
246
251
litPat->setImplicit ();
247
252
248
- auto labelItem = CaseLabelItem (litPat);
253
+ // Will collect any preliminary guards, plus the final assignment.
254
+ SmallVector<ASTNode, 2 > stmts;
255
+
256
+ // If there's an @available attribute specifying when the case was
257
+ // introduced, generate an early return on unavailability, e.g.
258
+ // "guard #available(iOS 9, *) else { return nil }"
259
+ for (auto *attr : elt->getAttrs ().getAttributes <AvailableAttr>()) {
260
+ // We only care about attributes which have an "introduced" version for
261
+ // the platform we're building for. We don't care about language version
262
+ // because we may be compiling in an older language mode, but writing APIs
263
+ // for a newer one.
264
+ if (attr->Introduced .hasValue () && attr->hasPlatform () &&
265
+ attr->isActivePlatform (C) &&
266
+ *attr->Introduced > C.LangOpts .getMinPlatformVersion ()) {
267
+ // platformSpec = "\(attr.platform) \(attr.introduced)"
268
+ auto platformSpec =
269
+ new (C) PlatformVersionConstraintAvailabilitySpec (
270
+ attr->Platform , SourceLoc (),
271
+ *attr->Introduced , SourceLoc ()
272
+ );
273
+
274
+ // otherSpec = "*"
275
+ auto otherSpec = new (C) OtherPlatformAvailabilitySpec (SourceLoc ());
276
+
277
+ // availableInfo = "#available(\(platformSpec), \(otherSpec))"
278
+ auto availableInfo = PoundAvailableInfo::create (C, SourceLoc (),
279
+ { platformSpec, otherSpec },
280
+ SourceLoc ());
281
+
282
+ // This won't be filled in by TypeCheckAvailability because we have
283
+ // invalid SourceLocs in this area of the AST.
284
+ auto versionRange = VersionRange::allGTE (*attr->Introduced );
285
+ availableInfo->setAvailableRange (versionRange);
286
+
287
+ // earlyReturnBody = "{ return nil }"
288
+ auto earlyReturn = new (C) FailStmt (SourceLoc (), SourceLoc ());
289
+ auto earlyReturnBody = BraceStmt::create (C, SourceLoc (),
290
+ ASTNode (earlyReturn),
291
+ SourceLoc (), /* implicit=*/ true );
292
+
293
+ // guardStmt = "guard \(vailableInfo) else \(earlyReturnBody)"
294
+ SmallVector<StmtConditionElement, 1 >
295
+ conds{StmtConditionElement (availableInfo)};
296
+ auto guardStmt = new (C) GuardStmt (SourceLoc (), C.AllocateCopy (conds),
297
+ earlyReturnBody, /* implicit=*/ true );
298
+
299
+ stmts.push_back (guardStmt);
300
+ }
301
+ }
249
302
303
+ // valueExpr = "\(enumType).\(elt)"
250
304
auto eltRef = new (C) DeclRefExpr (elt, DeclNameLoc (), /* implicit*/ true );
251
305
auto metaTyRef = TypeExpr::createImplicit (enumType, C);
252
306
auto valueExpr = new (C) DotSyntaxCallExpr (eltRef, SourceLoc (), metaTyRef);
253
307
308
+ // selfRef = "self"
254
309
auto selfRef = new (C) DeclRefExpr (selfDecl, DeclNameLoc (),
255
310
/* implicit*/ true ,
256
311
AccessSemantics::DirectToStorage);
257
312
313
+ // assignment = "\(selfRef) = \(valueExpr)"
258
314
auto assignment = new (C) AssignExpr (selfRef, SourceLoc (), valueExpr,
259
315
/* implicit*/ true );
316
+
317
+ stmts.push_back (ASTNode (assignment));
260
318
319
+ // body = stmts.joined(separator: "\n")
261
320
auto body = BraceStmt::create (C, SourceLoc (),
262
- ASTNode (assignment) , SourceLoc ());
321
+ stmts , SourceLoc ());
263
322
264
- cases.push_back (CaseStmt::create (C, SourceLoc (), labelItem,
323
+ // cases.append("case \(litPat): \(body)")
324
+ cases.push_back (CaseStmt::create (C, SourceLoc (), CaseLabelItem (litPat),
265
325
/* HasBoundDecls=*/ false , SourceLoc (),
266
326
SourceLoc (), body));
267
327
Idx++;
0 commit comments