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