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