@@ -484,6 +484,68 @@ static void checkInheritanceClause(
484
484
}
485
485
}
486
486
487
+ // Check for static properties that produce empty option sets
488
+ // using a rawValue initializer with a value of '0'
489
+ static void checkForEmptyOptionSet (const VarDecl *VD, TypeChecker &tc) {
490
+ // Check if property is a 'static let'
491
+ if (!VD->isStatic () || !VD->isLet ())
492
+ return ;
493
+
494
+ auto DC = VD->getDeclContext ();
495
+
496
+ // Make sure property is of same type as the type it is declared in
497
+ if (!VD->getType ()->isEqual (DC->getSelfTypeInContext ()))
498
+ return ;
499
+
500
+ // Make sure this type conforms to OptionSet
501
+ auto *optionSetProto = tc.Context .getProtocol (KnownProtocolKind::OptionSet);
502
+ bool conformsToOptionSet = (bool )tc.containsProtocol (
503
+ DC->getSelfTypeInContext (),
504
+ optionSetProto,
505
+ DC,
506
+ /* Flags*/ None);
507
+
508
+ if (!conformsToOptionSet)
509
+ return ;
510
+
511
+ auto PBD = VD->getParentPatternBinding ();
512
+ if (!PBD)
513
+ return ;
514
+
515
+ auto initIndex = PBD->getPatternEntryIndexForVarDecl (VD);
516
+ auto init = PBD->getInit (initIndex);
517
+
518
+ // Make sure property is being set with a constructor
519
+ auto ctor = dyn_cast_or_null<CallExpr>(init);
520
+ if (!ctor)
521
+ return ;
522
+ auto ctorCalledVal = ctor->getCalledValue ();
523
+ if (!ctorCalledVal)
524
+ return ;
525
+ if (!isa<ConstructorDecl>(ctorCalledVal))
526
+ return ;
527
+
528
+ // Make sure it is calling the rawValue constructor
529
+ if (ctor->getNumArguments () != 1 )
530
+ return ;
531
+ if (ctor->getArgumentLabels ().front () != tc.Context .Id_rawValue )
532
+ return ;
533
+
534
+ // Make sure the rawValue parameter is a '0' integer literal
535
+ auto *args = cast<TupleExpr>(ctor->getArg ());
536
+ auto intArg = dyn_cast<IntegerLiteralExpr>(args->getElement (0 ));
537
+ if (!intArg)
538
+ return ;
539
+ if (intArg->getValue () != 0 )
540
+ return ;
541
+
542
+ auto loc = VD->getLoc ();
543
+ tc.diagnose (loc, diag::option_set_zero_constant, VD->getName ());
544
+ tc.diagnose (loc, diag::option_set_empty_set_init)
545
+ .fixItReplace (args->getSourceRange (), " ([])" );
546
+ }
547
+
548
+
487
549
// / Check the inheritance clauses generic parameters along with any
488
550
// / requirements stored within the generic parameter list.
489
551
static void checkGenericParams (GenericParamList *genericParams,
@@ -2387,6 +2449,8 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
2387
2449
VD->diagnose (diag::dynamic_self_in_mutable_property);
2388
2450
}
2389
2451
}
2452
+
2453
+ checkForEmptyOptionSet (VD, TC);
2390
2454
2391
2455
// Under the Swift 3 inference rules, if we have @IBInspectable or
2392
2456
// @GKInspectable but did not infer @objc, warn that the attribute is
0 commit comments