@@ -5980,31 +5980,6 @@ 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 ();
5990-
5991- // Suppressed conformance needs to be within any/some.
5992- 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 ();
5999- }
6000- }
6001-
6002- Ctx.Diags .diagnose (inverse->getTildeLoc (), diag::inverse_requires_any)
6003- .highlight (inverse->getConstraint ()->getSourceRange ())
6004- .fixItInsert (anyLoc, " any " );
6005- return Action::SkipNode ();
6006- }
6007-
60085983 reprStack.push_back (T);
60095984
60105985 auto *declRefTR = dyn_cast<DeclRefTypeRepr>(T);
@@ -6057,9 +6032,12 @@ class ExistentialTypeSyntaxChecker : public ASTWalker {
60576032 }
60586033
60596034private:
6060- bool existentialNeedsParens (TypeRepr *parent) const {
6035+ // / Returns a Boolean value indicating whether the insertion of `any` before
6036+ // / a type representation with the given parent requires paretheses.
6037+ static bool anySyntaxNeedsParens (TypeRepr *parent) {
60616038 switch (parent->getKind ()) {
60626039 case TypeReprKind::Optional:
6040+ case TypeReprKind::ImplicitlyUnwrappedOptional:
60636041 case TypeReprKind::Protocol:
60646042 return true ;
60656043 case TypeReprKind::Metatype:
@@ -6074,7 +6052,6 @@ class ExistentialTypeSyntaxChecker : public ASTWalker {
60746052 case TypeReprKind::UnqualifiedIdent:
60756053 case TypeReprKind::QualifiedIdent:
60766054 case TypeReprKind::Dictionary:
6077- case TypeReprKind::ImplicitlyUnwrappedOptional:
60786055 case TypeReprKind::Inverse:
60796056 case TypeReprKind::Tuple:
60806057 case TypeReprKind::Fixed:
@@ -6097,40 +6074,94 @@ class ExistentialTypeSyntaxChecker : public ASTWalker {
60976074 }
60986075
60996076 void emitInsertAnyFixit (InFlightDiagnostic &diag, DeclRefTypeRepr *T) const {
6100- TypeRepr *replaceRepr = T;
6077+ TypeRepr *replacementT = T;
61016078
61026079 // Insert parens in expression context for '(any P).self'
61036080 bool needsParens = (exprCount != 0 );
6081+
6082+ // Compute the replacement node (the node to which to apply `any`).
61046083 if (reprStack.size () > 1 ) {
6105- auto parentIt = reprStack.end () - 2 ;
6106- needsParens = existentialNeedsParens (*parentIt);
6107-
6108- // Expand to include parenthesis before checking if the parent needs
6109- // to be replaced.
6110- while (parentIt != reprStack.begin () &&
6111- (*parentIt)->getWithoutParens () != *parentIt)
6112- parentIt -= 1 ;
6113-
6114- // For existential metatypes, 'any' is applied to the metatype.
6115- if ((*parentIt)->getKind () == TypeReprKind::Metatype) {
6116- replaceRepr = *parentIt;
6117- if (parentIt != reprStack.begin ())
6118- needsParens = existentialNeedsParens (*(parentIt - 1 ));
6084+ auto it = reprStack.end () - 1 ;
6085+ auto replacementIt = it;
6086+
6087+ // Backtrack the stack and expand the replacement range to any parent
6088+ // inverses, compositions or `.Type` metatypes, skipping only parentheses.
6089+ //
6090+ // E.g. `(X & ~P).Type` → `any (X & ~P).Type`.
6091+ // ↑
6092+ // We're here
6093+ do {
6094+ --it;
6095+ if ((*it)->isParenType ()) {
6096+ continue ;
6097+ }
6098+
6099+ if (isa<InverseTypeRepr>(*it) || isa<CompositionTypeRepr>(*it) ||
6100+ isa<MetatypeTypeRepr>(*it)) {
6101+ replacementIt = it;
6102+ continue ;
6103+ }
6104+
6105+ break ;
6106+ } while (it != reprStack.begin ());
6107+
6108+ // Whether parentheses are necessary is determined by the immediate parent
6109+ // of the replacement node.
6110+ if (replacementIt != reprStack.begin ()) {
6111+ needsParens = anySyntaxNeedsParens (*(replacementIt - 1 ));
61196112 }
6113+
6114+ replacementT = *replacementIt;
61206115 }
61216116
61226117 llvm::SmallString<64 > fix;
61236118 {
61246119 llvm::raw_svector_ostream OS (fix);
61256120 if (needsParens)
61266121 OS << " (" ;
6127- ExistentialTypeRepr existential (SourceLoc (), replaceRepr );
6122+ ExistentialTypeRepr existential (SourceLoc (), replacementT );
61286123 existential.print (OS);
61296124 if (needsParens)
61306125 OS << " )" ;
61316126 }
61326127
6133- diag.fixItReplace (replaceRepr->getSourceRange (), fix);
6128+ diag.fixItReplace (replacementT->getSourceRange (), fix);
6129+ }
6130+
6131+ // / Returns a Boolean value indicating whether the type representation being
6132+ // / visited, assuming it is a constraint type demanding `any` or `some`, is
6133+ // / missing either keyword.
6134+ bool isAnyOrSomeMissing () const {
6135+ assert (isa<DeclRefTypeRepr>(reprStack.back ()));
6136+
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));
61346165 }
61356166
61366167 void checkDeclRefTypeRepr (DeclRefTypeRepr *T) const {
@@ -6140,13 +6171,32 @@ class ExistentialTypeSyntaxChecker : public ASTWalker {
61406171 return ;
61416172 }
61426173
6174+ // Backtrack the stack, looking just through parentheses and metatypes. If
6175+ // we find an inverse (which always requires `any`), diagnose it specially.
6176+ if (reprStack.size () > 1 ) {
6177+ auto it = reprStack.end () - 2 ;
6178+ while (it != reprStack.begin () &&
6179+ ((*it)->isParenType () || isa<MetatypeTypeRepr>(*it))) {
6180+ --it;
6181+ continue ;
6182+ }
6183+
6184+ if (auto *inverse = dyn_cast<InverseTypeRepr>(*it);
6185+ inverse && isAnyOrSomeMissing ()) {
6186+ auto diag = Ctx.Diags .diagnose (inverse->getTildeLoc (),
6187+ diag::inverse_requires_any);
6188+ emitInsertAnyFixit (diag, T);
6189+ return ;
6190+ }
6191+ }
6192+
61436193 auto *decl = T->getBoundDecl ();
61446194 if (!decl) {
61456195 return ;
61466196 }
61476197
61486198 if (auto *proto = dyn_cast<ProtocolDecl>(decl)) {
6149- if (proto->existentialRequiresAny ()) {
6199+ if (proto->existentialRequiresAny () && isAnyOrSomeMissing () ) {
61506200 auto diag =
61516201 Ctx.Diags .diagnose (T->getNameLoc (), diag::existential_requires_any,
61526202 proto->getDeclaredInterfaceType (),
@@ -6176,7 +6226,7 @@ class ExistentialTypeSyntaxChecker : public ASTWalker {
61766226 if (auto *PCT = type->getAs <ProtocolCompositionType>())
61776227 diagnose |= !PCT->getInverses ().empty ();
61786228
6179- if (diagnose) {
6229+ if (diagnose && isAnyOrSomeMissing () ) {
61806230 auto diag = Ctx.Diags .diagnose (
61816231 T->getNameLoc (), diag::existential_requires_any,
61826232 alias->getDeclaredInterfaceType (),
0 commit comments