@@ -5980,33 +5980,28 @@ class ExistentialTypeSyntaxChecker : public ASTWalker {
59805980 if (T->isInvalid ())
59815981 return Action::SkipNode ();
59825982
5983- // Arbitrary protocol constraints are OK on opaque types.
5984- if (isa<OpaqueReturnTypeRepr>(T))
5985- return Action::SkipNode ();
5986-
5987- // Arbitrary protocol constraints are okay for 'any' types.
5988- if (isa<ExistentialTypeRepr>(T))
5989- return Action::SkipNode ();
5983+ reprStack.push_back (T);
59905984
59915985 // Suppressed conformance needs to be within any/some.
59925986 if (auto inverse = dyn_cast<InverseTypeRepr>(T)) {
5993- // Find an enclosing protocol composition, if there is one, so we
5994- // can insert 'any' before that.
5995- SourceLoc anyLoc = inverse->getTildeLoc ();
5996- if (!reprStack.empty ()) {
5997- if (isa<CompositionTypeRepr>(reprStack.back ())) {
5998- anyLoc = reprStack.back ()->getStartLoc ();
5987+ if (isAnyOrSomeMissing ()) {
5988+ // Find an enclosing protocol composition, if there is one, so we
5989+ // can insert 'any' before that.
5990+ SourceLoc anyLoc = inverse->getTildeLoc ();
5991+ if (reprStack.size () > 1 ) {
5992+ if (auto *repr =
5993+ dyn_cast<CompositionTypeRepr>(*(reprStack.end () - 2 ))) {
5994+ anyLoc = repr->getStartLoc ();
5995+ }
59995996 }
6000- }
60015997
6002- Ctx.Diags .diagnose (inverse->getTildeLoc (), diag::inverse_requires_any)
6003- .highlight (inverse->getConstraint ()->getSourceRange ())
6004- .fixItInsert (anyLoc, " any " );
6005- return Action::SkipNode ();
5998+ Ctx.Diags .diagnose (inverse->getTildeLoc (), diag::inverse_requires_any)
5999+ .highlight (inverse->getConstraint ()->getSourceRange ())
6000+ .fixItInsert (anyLoc, " any " );
6001+ }
6002+ return Action::SkipChildren ();
60066003 }
60076004
6008- reprStack.push_back (T);
6009-
60106005 auto *declRefTR = dyn_cast<DeclRefTypeRepr>(T);
60116006 if (!declRefTR) {
60126007 return Action::Continue ();
@@ -6135,6 +6130,40 @@ class ExistentialTypeSyntaxChecker : public ASTWalker {
61356130 diag.fixItReplace (replaceRepr->getSourceRange (), fix);
61366131 }
61376132
6133+ // / Returns a Boolean value indicating whether the type representation being
6134+ // / visited, assuming it is a constraint type demanding `any` or `some`, is
6135+ // / missing either keyword.
6136+ bool isAnyOrSomeMissing () const {
6137+ if (reprStack.size () < 2 ) {
6138+ return true ;
6139+ }
6140+
6141+ auto it = reprStack.end () - 1 ;
6142+ while (true ) {
6143+ --it;
6144+ if (it == reprStack.begin ()) {
6145+ break ;
6146+ }
6147+
6148+ // Look through parens, inverses, metatypes, and compositions.
6149+ if ((*it)->isParenType () || isa<InverseTypeRepr>(*it) ||
6150+ isa<CompositionTypeRepr>(*it) || isa<MetatypeTypeRepr>(*it)) {
6151+ continue ;
6152+ }
6153+
6154+ // Look through '?' and '!' too; `any P?` et al. is diagnosed in the
6155+ // type resolver.
6156+ if (isa<OptionalTypeRepr>(*it) ||
6157+ isa<ImplicitlyUnwrappedOptionalTypeRepr>(*it)) {
6158+ continue ;
6159+ }
6160+
6161+ break ;
6162+ }
6163+
6164+ return !(isa<OpaqueReturnTypeRepr>(*it) || isa<ExistentialTypeRepr>(*it));
6165+ }
6166+
61386167 void checkDeclRefTypeRepr (DeclRefTypeRepr *T) const {
61396168 assert (!T->isInvalid ());
61406169
@@ -6148,7 +6177,7 @@ class ExistentialTypeSyntaxChecker : public ASTWalker {
61486177 }
61496178
61506179 if (auto *proto = dyn_cast<ProtocolDecl>(decl)) {
6151- if (proto->existentialRequiresAny ()) {
6180+ if (proto->existentialRequiresAny () && isAnyOrSomeMissing () ) {
61526181 auto diag =
61536182 Ctx.Diags .diagnose (T->getNameLoc (), diag::existential_requires_any,
61546183 proto->getDeclaredInterfaceType (),
@@ -6178,7 +6207,7 @@ class ExistentialTypeSyntaxChecker : public ASTWalker {
61786207 if (auto *PCT = type->getAs <ProtocolCompositionType>())
61796208 diagnose |= !PCT->getInverses ().empty ();
61806209
6181- if (diagnose) {
6210+ if (diagnose && isAnyOrSomeMissing () ) {
61826211 auto diag = Ctx.Diags .diagnose (
61836212 T->getNameLoc (), diag::existential_requires_any,
61846213 alias->getDeclaredInterfaceType (),
0 commit comments