@@ -6159,7 +6159,7 @@ namespace {
6159
6159
// / written syntax.
6160
6160
class ExistentialTypeSyntaxChecker : public ASTWalker {
6161
6161
ASTContext &Ctx;
6162
- bool checkStatements;
6162
+ const bool checkStatements;
6163
6163
bool hitTopStmt;
6164
6164
bool warnUntilSwift7;
6165
6165
@@ -6203,7 +6203,7 @@ class ExistentialTypeSyntaxChecker : public ASTWalker {
6203
6203
}
6204
6204
6205
6205
PostWalkAction walkToTypeReprPost (TypeRepr *T) override {
6206
- assert (reprStack.back () == T);
6206
+ ASSERT (reprStack.back () == T);
6207
6207
reprStack.pop_back ();
6208
6208
return Action::Continue ();
6209
6209
}
@@ -6327,14 +6327,13 @@ class ExistentialTypeSyntaxChecker : public ASTWalker {
6327
6327
diag.fixItReplace (replacementT->getSourceRange (), fix);
6328
6328
}
6329
6329
6330
- // / Returns a Boolean value indicating whether the type representation being
6331
- // / visited, assuming it is a constraint type demanding `any` or `some`, is
6332
- // / missing either keyword.
6333
- bool isAnyOrSomeMissing () const {
6334
- assert (isa<DeclRefTypeRepr>(reprStack.back ()));
6330
+ // / Returns a Boolean value indicating whether the currently visited
6331
+ // / `DeclRefTypeRepr` node has a `some` or `any` keyword that applies to it.
6332
+ bool currentNodeHasAnyOrSomeKeyword () const {
6333
+ ASSERT (isa<DeclRefTypeRepr>(reprStack.back ()));
6335
6334
6336
6335
if (reprStack.size () < 2 ) {
6337
- return true ;
6336
+ return false ;
6338
6337
}
6339
6338
6340
6339
auto it = reprStack.end () - 1 ;
@@ -6344,7 +6343,7 @@ class ExistentialTypeSyntaxChecker : public ASTWalker {
6344
6343
break ;
6345
6344
}
6346
6345
6347
- // Look through parens, inverses, metatypes, and compositions.
6346
+ // Look through parens, inverses, `.Type` metatypes, and compositions.
6348
6347
if ((*it)->isParenType () || isa<InverseTypeRepr>(*it) ||
6349
6348
isa<CompositionTypeRepr>(*it) || isa<MetatypeTypeRepr>(*it)) {
6350
6349
continue ;
@@ -6353,83 +6352,99 @@ class ExistentialTypeSyntaxChecker : public ASTWalker {
6353
6352
break ;
6354
6353
}
6355
6354
6356
- return !( isa<OpaqueReturnTypeRepr>(*it) || isa<ExistentialTypeRepr>(*it) );
6355
+ return isa<OpaqueReturnTypeRepr>(*it) || isa<ExistentialTypeRepr>(*it);
6357
6356
}
6358
6357
6359
6358
void checkDeclRefTypeRepr (DeclRefTypeRepr *T) const {
6360
- assert (!T->isInvalid ());
6361
-
6362
6359
if (Ctx.LangOpts .hasFeature (Feature::ImplicitSome)) {
6363
6360
return ;
6364
6361
}
6365
6362
6366
- // Backtrack the stack, looking just through parentheses and metatypes. If
6367
- // we find an inverse (which always requires `any`), diagnose it specially.
6368
- if (reprStack.size () > 1 ) {
6363
+ auto *decl = T->getBoundDecl ();
6364
+ if (!decl) {
6365
+ return ;
6366
+ }
6367
+
6368
+ if (!isa<ProtocolDecl>(decl) && !isa<TypeAliasDecl>(decl)) {
6369
+ return ;
6370
+ }
6371
+
6372
+ // If there is already an `any` or `some` that applies to this node,
6373
+ // move on.
6374
+ if (currentNodeHasAnyOrSomeKeyword ()) {
6375
+ return ;
6376
+ }
6377
+
6378
+ const auto type = decl->getDeclaredInterfaceType ();
6379
+
6380
+ // A type alias may need to be prefixed with `any` only if it stands for a
6381
+ // constraint type.
6382
+ if (isa<TypeAliasDecl>(decl) && !type->isConstraintType ()) {
6383
+ return ;
6384
+ }
6385
+
6386
+ // First, consider the possibility of the current node being an object of
6387
+ // an inversion, e.g. `~(Copyable)`.
6388
+ // Climb up the stack, looking just through parentheses and `.Type`
6389
+ // metatypes.
6390
+ // If we find an inversion, we will diagnose it specially.
6391
+ InverseTypeRepr *const outerInversion = [&] {
6392
+ if (reprStack.size () < 2 ) {
6393
+ return (InverseTypeRepr *)nullptr ;
6394
+ }
6395
+
6369
6396
auto it = reprStack.end () - 2 ;
6370
6397
while (it != reprStack.begin () &&
6371
6398
((*it)->isParenType () || isa<MetatypeTypeRepr>(*it))) {
6372
6399
--it;
6373
6400
continue ;
6374
6401
}
6375
6402
6376
- if (auto *inverse = dyn_cast<InverseTypeRepr>(*it);
6377
- inverse && isAnyOrSomeMissing ()) {
6378
- auto diag = Ctx.Diags .diagnose (inverse->getTildeLoc (),
6379
- diag::inverse_requires_any);
6380
- diag.warnUntilSwiftVersionIf (warnUntilSwift7, 7 );
6381
- emitInsertAnyFixit (diag, T);
6382
- return ;
6383
- }
6384
- }
6385
-
6386
- auto *decl = T->getBoundDecl ();
6387
- if (!decl) {
6388
- return ;
6389
- }
6403
+ return dyn_cast<InverseTypeRepr>(*it);
6404
+ }();
6390
6405
6391
- if (auto *proto = dyn_cast<ProtocolDecl>(decl)) {
6392
- if (proto->existentialRequiresAny () && isAnyOrSomeMissing ()) {
6393
- auto diag =
6394
- Ctx.Diags .diagnose (T->getNameLoc (), diag::existential_requires_any,
6395
- proto->getDeclaredInterfaceType (),
6396
- proto->getDeclaredExistentialType (),
6397
- /* isAlias=*/ false );
6398
- diag.warnUntilSwiftVersionIf (warnUntilSwift7, 7 );
6399
- emitInsertAnyFixit (diag, T);
6406
+ const bool shouldDiagnose = [&] {
6407
+ // `Any` and `AnyObject` are always exempt from `any` syntax.
6408
+ if (type->isAny () || type->isAnyObject ()) {
6409
+ return false ;
6400
6410
}
6401
- } else if (auto *alias = dyn_cast<TypeAliasDecl>(decl)) {
6402
- auto type = Type (alias->getDeclaredInterfaceType ()->getDesugaredType ());
6403
-
6404
- // If this is a type alias to a constraint type, the type
6405
- // alias name must be prefixed with 'any' to be used as an
6406
- // existential type.
6407
- if (type->isConstraintType () && !type->isAny () && !type->isAnyObject ()) {
6408
- bool diagnose = false ;
6409
-
6410
- // Look for protocol members that require 'any'.
6411
- auto layout = type->getExistentialLayout ();
6412
- for (auto *protoDecl : layout.getProtocols ()) {
6413
- if (protoDecl->existentialRequiresAny ()) {
6414
- diagnose = true ;
6415
- break ;
6416
- }
6411
+
6412
+ // Look for protocol members that require 'any'.
6413
+ auto layout = type->getExistentialLayout ();
6414
+ for (auto *protoDecl : layout.getProtocols ()) {
6415
+ if (protoDecl->existentialRequiresAny ()) {
6416
+ return true ;
6417
6417
}
6418
+ }
6418
6419
6419
- // If inverses are present, require 'any' too.
6420
- if (auto *PCT = type->getAs <ProtocolCompositionType>())
6421
- diagnose |= !PCT->getInverses ().empty ();
6422
-
6423
- if (diagnose && isAnyOrSomeMissing ()) {
6424
- auto diag = Ctx.Diags .diagnose (
6425
- T->getNameLoc (), diag::existential_requires_any,
6426
- alias->getDeclaredInterfaceType (),
6427
- ExistentialType::get (alias->getDeclaredInterfaceType ()),
6428
- /* isAlias=*/ true );
6429
- diag.warnUntilSwiftVersionIf (warnUntilSwift7, 7 );
6430
- emitInsertAnyFixit (diag, T);
6420
+ // If inverses are present, require 'any' too.
6421
+ if (auto *PCT = type->getAs <ProtocolCompositionType>()) {
6422
+ if (!PCT->getInverses ().empty ()) {
6423
+ return true ;
6431
6424
}
6432
6425
}
6426
+
6427
+ if (outerInversion) {
6428
+ return true ;
6429
+ }
6430
+
6431
+ return false ;
6432
+ }();
6433
+
6434
+ if (shouldDiagnose) {
6435
+ std::optional<InFlightDiagnostic> diag;
6436
+ if (outerInversion) {
6437
+ diag.emplace (Ctx.Diags .diagnose (outerInversion->getTildeLoc (),
6438
+ diag::inverse_requires_any));
6439
+ } else {
6440
+ diag.emplace (Ctx.Diags .diagnose (T->getNameLoc (),
6441
+ diag::existential_requires_any, type,
6442
+ ExistentialType::get (type),
6443
+ /* isAlias=*/ isa<TypeAliasDecl>(decl)));
6444
+ }
6445
+
6446
+ diag->warnUntilSwiftVersionIf (warnUntilSwift7, 7 );
6447
+ emitInsertAnyFixit (*diag, T);
6433
6448
}
6434
6449
}
6435
6450
0 commit comments