@@ -6171,7 +6171,7 @@ namespace {
61716171// / written syntax.
61726172class ExistentialTypeSyntaxChecker : public ASTWalker {
61736173 ASTContext &Ctx;
6174- bool checkStatements;
6174+ const bool checkStatements;
61756175 bool hitTopStmt;
61766176 bool warnUntilSwift7;
61776177
@@ -6215,7 +6215,7 @@ class ExistentialTypeSyntaxChecker : public ASTWalker {
62156215 }
62166216
62176217 PostWalkAction walkToTypeReprPost (TypeRepr *T) override {
6218- assert (reprStack.back () == T);
6218+ ASSERT (reprStack.back () == T);
62196219 reprStack.pop_back ();
62206220 return Action::Continue ();
62216221 }
@@ -6339,14 +6339,13 @@ class ExistentialTypeSyntaxChecker : public ASTWalker {
63396339 diag.fixItReplace (replacementT->getSourceRange (), fix);
63406340 }
63416341
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 ()));
63476346
63486347 if (reprStack.size () < 2 ) {
6349- return true ;
6348+ return false ;
63506349 }
63516350
63526351 auto it = reprStack.end () - 1 ;
@@ -6356,7 +6355,7 @@ class ExistentialTypeSyntaxChecker : public ASTWalker {
63566355 break ;
63576356 }
63586357
6359- // Look through parens, inverses, metatypes, and compositions.
6358+ // Look through parens, inverses, `.Type` metatypes, and compositions.
63606359 if ((*it)->isParenType () || isa<InverseTypeRepr>(*it) ||
63616360 isa<CompositionTypeRepr>(*it) || isa<MetatypeTypeRepr>(*it)) {
63626361 continue ;
@@ -6365,84 +6364,114 @@ class ExistentialTypeSyntaxChecker : public ASTWalker {
63656364 break ;
63666365 }
63676366
6368- return !( isa<OpaqueReturnTypeRepr>(*it) || isa<ExistentialTypeRepr>(*it) );
6367+ return isa<OpaqueReturnTypeRepr>(*it) || isa<ExistentialTypeRepr>(*it);
63696368 }
63706369
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+ }
63736383
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 ;
63766387 }
63776388
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 ;
63866394 }
6395+ }
63876396
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 ;
63956403 }
63966404 }
63976405
6406+ return false ;
6407+ }
6408+
6409+ void checkDeclRefTypeRepr (DeclRefTypeRepr *T) const {
6410+ if (Ctx.LangOpts .hasFeature (Feature::ImplicitSome)) {
6411+ return ;
6412+ }
6413+
63986414 auto *decl = T->getBoundDecl ();
63996415 if (!decl) {
64006416 return ;
64016417 }
64026418
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 ;
64126445 }
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- }
64306446
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 ;
64446452 }
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)));
64456471 }
6472+
6473+ diag->warnUntilSwiftVersionIf (warnUntilSwift7, 7 );
6474+ emitInsertAnyFixit (*diag, T);
64466475 }
64476476
64486477public:
0 commit comments