@@ -6171,7 +6171,7 @@ namespace {
6171
6171
// / written syntax.
6172
6172
class ExistentialTypeSyntaxChecker : public ASTWalker {
6173
6173
ASTContext &Ctx;
6174
- bool checkStatements;
6174
+ const bool checkStatements;
6175
6175
bool hitTopStmt;
6176
6176
bool warnUntilSwift7;
6177
6177
@@ -6215,7 +6215,7 @@ class ExistentialTypeSyntaxChecker : public ASTWalker {
6215
6215
}
6216
6216
6217
6217
PostWalkAction walkToTypeReprPost (TypeRepr *T) override {
6218
- assert (reprStack.back () == T);
6218
+ ASSERT (reprStack.back () == T);
6219
6219
reprStack.pop_back ();
6220
6220
return Action::Continue ();
6221
6221
}
@@ -6339,14 +6339,13 @@ class ExistentialTypeSyntaxChecker : public ASTWalker {
6339
6339
diag.fixItReplace (replacementT->getSourceRange (), fix);
6340
6340
}
6341
6341
6342
- // / Returns a Boolean value indicating whether the type representation being
6343
- // / visited, assuming it is a constraint type demanding `any` or `some`, is
6344
- // / missing either keyword.
6345
- bool isAnyOrSomeMissing () const {
6346
- assert (isa<DeclRefTypeRepr>(reprStack.back ()));
6342
+ // / Returns a Boolean value indicating whether the currently visited
6343
+ // / `DeclRefTypeRepr` node has a `some` or `any` keyword that applies to it.
6344
+ bool currentNodeHasAnyOrSomeKeyword () const {
6345
+ ASSERT (isa<DeclRefTypeRepr>(reprStack.back ()));
6347
6346
6348
6347
if (reprStack.size () < 2 ) {
6349
- return true ;
6348
+ return false ;
6350
6349
}
6351
6350
6352
6351
auto it = reprStack.end () - 1 ;
@@ -6356,7 +6355,7 @@ class ExistentialTypeSyntaxChecker : public ASTWalker {
6356
6355
break ;
6357
6356
}
6358
6357
6359
- // Look through parens, inverses, metatypes, and compositions.
6358
+ // Look through parens, inverses, `.Type` metatypes, and compositions.
6360
6359
if ((*it)->isParenType () || isa<InverseTypeRepr>(*it) ||
6361
6360
isa<CompositionTypeRepr>(*it) || isa<MetatypeTypeRepr>(*it)) {
6362
6361
continue ;
@@ -6365,84 +6364,114 @@ class ExistentialTypeSyntaxChecker : public ASTWalker {
6365
6364
break ;
6366
6365
}
6367
6366
6368
- return !( isa<OpaqueReturnTypeRepr>(*it) || isa<ExistentialTypeRepr>(*it) );
6367
+ return isa<OpaqueReturnTypeRepr>(*it) || isa<ExistentialTypeRepr>(*it);
6369
6368
}
6370
6369
6371
- void checkDeclRefTypeRepr (DeclRefTypeRepr *T) const {
6372
- assert (!T->isInvalid ());
6370
+ // / Returns the behavior with which to diagnose a missing `any` or `some`
6371
+ // / keyword.
6372
+ // /
6373
+ // / \param constraintTy The constraint type that is missing the keyword.
6374
+ // / \param isInverted Whether the constraint type is an object of an `~`
6375
+ // / inversion.
6376
+ static bool shouldDiagnoseMissingAnyOrSomeKeyword (Type constraintTy,
6377
+ bool isInverted,
6378
+ ASTContext &ctx) {
6379
+ // `Any` and `AnyObject` are always exempt from `any` syntax.
6380
+ if (constraintTy->isAny () || constraintTy->isAnyObject ()) {
6381
+ return false ;
6382
+ }
6373
6383
6374
- if (Ctx.LangOpts .hasFeature (Feature::ImplicitSome)) {
6375
- return ;
6384
+ // If the type is inverted, a missing `any` or `some` is always diagnosed.
6385
+ if (isInverted) {
6386
+ return true ;
6376
6387
}
6377
6388
6378
- // Backtrack the stack, looking just through parentheses and metatypes. If
6379
- // we find an inverse (which always requires `any`), diagnose it specially.
6380
- if (reprStack.size () > 1 ) {
6381
- auto it = reprStack.end () - 2 ;
6382
- while (it != reprStack.begin () &&
6383
- ((*it)->isParenType () || isa<MetatypeTypeRepr>(*it))) {
6384
- --it;
6385
- continue ;
6389
+ // If one of the protocols is inverted, a missing `any` or `some` is
6390
+ // always diagnosed.
6391
+ if (auto *PCT = constraintTy->getAs <ProtocolCompositionType>()) {
6392
+ if (!PCT->getInverses ().empty ()) {
6393
+ return true ;
6386
6394
}
6395
+ }
6387
6396
6388
- if (auto *inverse = dyn_cast<InverseTypeRepr>(*it);
6389
- inverse && isAnyOrSomeMissing ()) {
6390
- auto diag = Ctx.Diags .diagnose (inverse->getTildeLoc (),
6391
- diag::inverse_requires_any);
6392
- diag.warnUntilSwiftVersionIf (warnUntilSwift7, 7 );
6393
- emitInsertAnyFixit (diag, T);
6394
- return ;
6397
+ // If one of the protocols has "Self or associated type" requirements,
6398
+ // a missing `any` or `some` is always diagnosed.
6399
+ auto layout = constraintTy->getExistentialLayout ();
6400
+ for (auto *protoDecl : layout.getProtocols ()) {
6401
+ if (protoDecl->existentialRequiresAny ()) {
6402
+ return true ;
6395
6403
}
6396
6404
}
6397
6405
6406
+ return false ;
6407
+ }
6408
+
6409
+ void checkDeclRefTypeRepr (DeclRefTypeRepr *T) const {
6410
+ if (Ctx.LangOpts .hasFeature (Feature::ImplicitSome)) {
6411
+ return ;
6412
+ }
6413
+
6398
6414
auto *decl = T->getBoundDecl ();
6399
6415
if (!decl) {
6400
6416
return ;
6401
6417
}
6402
6418
6403
- if (auto *proto = dyn_cast<ProtocolDecl>(decl)) {
6404
- if (proto->existentialRequiresAny () && isAnyOrSomeMissing ()) {
6405
- auto diag =
6406
- Ctx.Diags .diagnose (T->getNameLoc (), diag::existential_requires_any,
6407
- proto->getDeclaredInterfaceType (),
6408
- proto->getDeclaredExistentialType (),
6409
- /* isAlias=*/ false );
6410
- diag.warnUntilSwiftVersionIf (warnUntilSwift7, 7 );
6411
- emitInsertAnyFixit (diag, T);
6419
+ if (!isa<ProtocolDecl>(decl) && !isa<TypeAliasDecl>(decl)) {
6420
+ return ;
6421
+ }
6422
+
6423
+ // If there is already an `any` or `some` that applies to this node,
6424
+ // move on.
6425
+ if (currentNodeHasAnyOrSomeKeyword ()) {
6426
+ return ;
6427
+ }
6428
+
6429
+ const auto type = decl->getDeclaredInterfaceType ();
6430
+
6431
+ // A type alias may need to be prefixed with `any` only if it stands for a
6432
+ // constraint type.
6433
+ if (isa<TypeAliasDecl>(decl) && !type->isConstraintType ()) {
6434
+ return ;
6435
+ }
6436
+
6437
+ // First, consider the possibility of the current node being an object of
6438
+ // an inversion, e.g. `~(Copyable)`.
6439
+ // Climb up the stack, looking just through parentheses and `.Type`
6440
+ // metatypes.
6441
+ // If we find an inversion, we will diagnose it specially.
6442
+ InverseTypeRepr *const outerInversion = [&] {
6443
+ if (reprStack.size () < 2 ) {
6444
+ return (InverseTypeRepr *)nullptr ;
6412
6445
}
6413
- } else if (auto *alias = dyn_cast<TypeAliasDecl>(decl)) {
6414
- auto type = Type (alias->getDeclaredInterfaceType ()->getDesugaredType ());
6415
-
6416
- // If this is a type alias to a constraint type, the type
6417
- // alias name must be prefixed with 'any' to be used as an
6418
- // existential type.
6419
- if (type->isConstraintType () && !type->isAny () && !type->isAnyObject ()) {
6420
- bool diagnose = false ;
6421
-
6422
- // Look for protocol members that require 'any'.
6423
- auto layout = type->getExistentialLayout ();
6424
- for (auto *protoDecl : layout.getProtocols ()) {
6425
- if (protoDecl->existentialRequiresAny ()) {
6426
- diagnose = true ;
6427
- break ;
6428
- }
6429
- }
6430
6446
6431
- // If inverses are present, require 'any' too.
6432
- if (auto *PCT = type->getAs <ProtocolCompositionType>())
6433
- diagnose |= !PCT->getInverses ().empty ();
6434
-
6435
- if (diagnose && isAnyOrSomeMissing ()) {
6436
- auto diag = Ctx.Diags .diagnose (
6437
- T->getNameLoc (), diag::existential_requires_any,
6438
- alias->getDeclaredInterfaceType (),
6439
- ExistentialType::get (alias->getDeclaredInterfaceType ()),
6440
- /* isAlias=*/ true );
6441
- diag.warnUntilSwiftVersionIf (warnUntilSwift7, 7 );
6442
- emitInsertAnyFixit (diag, T);
6443
- }
6447
+ auto it = reprStack.end () - 2 ;
6448
+ while (it != reprStack.begin () &&
6449
+ ((*it)->isParenType () || isa<MetatypeTypeRepr>(*it))) {
6450
+ --it;
6451
+ continue ;
6444
6452
}
6453
+
6454
+ return dyn_cast<InverseTypeRepr>(*it);
6455
+ }();
6456
+
6457
+ if (!shouldDiagnoseMissingAnyOrSomeKeyword (
6458
+ type, /* isInverted=*/ outerInversion, this ->Ctx )) {
6459
+ return ;
6460
+ }
6461
+
6462
+ std::optional<InFlightDiagnostic> diag;
6463
+ if (outerInversion) {
6464
+ diag.emplace (Ctx.Diags .diagnose (outerInversion->getTildeLoc (),
6465
+ diag::inverse_requires_any));
6466
+ } else {
6467
+ diag.emplace (Ctx.Diags .diagnose (T->getNameLoc (),
6468
+ diag::existential_requires_any, type,
6469
+ ExistentialType::get (type),
6470
+ /* isAlias=*/ isa<TypeAliasDecl>(decl)));
6445
6471
}
6472
+
6473
+ diag->warnUntilSwiftVersionIf (warnUntilSwift7, 7 );
6474
+ emitInsertAnyFixit (*diag, T);
6446
6475
}
6447
6476
6448
6477
public:
0 commit comments