@@ -3970,8 +3970,11 @@ bool InvalidMemberRefOnExistential::diagnoseAsError() {
39703970
39713971 // If the base expression is a reference to a function or subscript
39723972 // parameter, offer a fixit that replaces the existential parameter type with
3973- // its generic equivalent, e.g. func foo(p: any P) → func foo<T: P>(p: T).
3974- // FIXME: Add an option to use 'some' vs. an explicit generic parameter.
3973+ // its generic equivalent, e.g. func foo(p: any P) → func foo(p: some P).
3974+ // Replacing 'any' with 'some' allows the code to compile without further
3975+ // changes, such as naming an explicit type parameter, and is future-proofed
3976+ // for same-type requirements on primary associated types instead of needing
3977+ // a where clause.
39753978
39763979 if (!PD || !PD->getDeclContext ()->getAsDecl ())
39773980 return true ;
@@ -4020,70 +4023,42 @@ bool InvalidMemberRefOnExistential::diagnoseAsError() {
40204023 if (PD->isInOut ())
40214024 return true ;
40224025
4023- constexpr StringRef GPNamePlaceholder = " <#generic parameter name#>" ;
4024- SourceRange TyReplacementRange;
4025- SourceRange RemoveAnyRange;
4026- SourceLoc GPDeclLoc;
4027- std::string GPDeclStr;
4028- {
4029- llvm::raw_string_ostream OS (GPDeclStr);
4030- auto *const GC = PD->getDeclContext ()->getAsDecl ()->getAsGenericContext ();
4031- if (GC->getParsedGenericParams ()) {
4032- GPDeclLoc = GC->getParsedGenericParams ()->getRAngleLoc ();
4033- OS << " , " ;
4034- } else {
4035- GPDeclLoc =
4036- isa<AbstractFunctionDecl>(GC)
4037- ? cast<AbstractFunctionDecl>(GC)->getParameters ()->getLParenLoc ()
4038- : cast<SubscriptDecl>(GC)->getIndices ()->getLParenLoc ();
4039- OS << " <" ;
4040- }
4041- OS << GPNamePlaceholder << " : " ;
4042-
4043- auto *TR = PD->getTypeRepr ()->getWithoutParens ();
4044- if (auto *STR = dyn_cast<SpecifierTypeRepr>(TR)) {
4045- TR = STR->getBase ()->getWithoutParens ();
4046- }
4047- if (auto *ETR = dyn_cast<ExistentialTypeRepr>(TR)) {
4048- TR = ETR->getConstraint ();
4049- RemoveAnyRange = SourceRange (ETR->getAnyLoc (), TR->getStartLoc ());
4050- TR = TR->getWithoutParens ();
4051- }
4052- if (auto *MTR = dyn_cast<MetatypeTypeRepr>(TR)) {
4053- TR = MTR->getBase ();
4054-
4055- // (P & Q).Type -> T.Type
4056- // (P).Type -> (T).Type
4057- // ((P & Q)).Type -> ((T)).Type
4058- if (auto *TTR = dyn_cast<TupleTypeRepr>(TR)) {
4059- assert (TTR->isParenType ());
4060- if (!isa<CompositionTypeRepr>(TTR->getElementType (0 ))) {
4061- TR = TR->getWithoutParens ();
4062- }
4063- }
4064- }
4065- TyReplacementRange = TR->getSourceRange ();
4066-
4067- // Strip any remaining parentheses and print the conformance constraint.
4068- TR->getWithoutParens ()->print (OS);
4069-
4070- if (!GC->getParsedGenericParams ()) {
4071- OS << " >" ;
4072- }
4026+ auto *typeRepr = PD->getTypeRepr ()->getWithoutParens ();
4027+ if (auto *STR = dyn_cast<SpecifierTypeRepr>(typeRepr)) {
4028+ typeRepr = STR->getBase ()->getWithoutParens ();
40734029 }
40744030
4075- // First, replace the constraint type with the generic parameter type
4076- // placeholder.
4077- Diag.fixItReplace (TyReplacementRange, GPNamePlaceholder);
4031+ SourceRange anyRange;
4032+ TypeRepr *constraintRepr = typeRepr;
4033+ if (auto *existentialRepr = dyn_cast<ExistentialTypeRepr>(typeRepr)) {
4034+ constraintRepr = existentialRepr->getConstraint ()->getWithoutParens ();
4035+ auto anyStart = existentialRepr->getAnyLoc ();
4036+ auto anyEnd = existentialRepr->getConstraint ()->getStartLoc ();
4037+ anyRange = SourceRange (anyStart, anyEnd);
4038+ }
40784039
4079- // Remove 'any' if needed, using a character-based removal to pick up
4080- // whitespaces between it and its constraint repr.
4081- if (RemoveAnyRange.isValid ()) {
4082- Diag.fixItRemoveChars (RemoveAnyRange.Start , RemoveAnyRange.End );
4040+ bool needsParens = false ;
4041+ while (auto *metatype = dyn_cast<MetatypeTypeRepr>(constraintRepr)) {
4042+ // The generic equivalent of 'any P.Type' is '(some P).Type'
4043+ constraintRepr = metatype->getBase ()->getWithoutParens ();
4044+ if (isa<SimpleIdentTypeRepr>(constraintRepr))
4045+ needsParens = !isa<TupleTypeRepr>(metatype->getBase ());
40834046 }
40844047
4085- // Finally, insert the generic parameter declaration.
4086- Diag.fixItInsert (GPDeclLoc, GPDeclStr);
4048+ std::string fix;
4049+ llvm::raw_string_ostream OS (fix);
4050+ if (needsParens)
4051+ OS << " (" ;
4052+ OS << " some " ;
4053+ constraintRepr->print (OS);
4054+ if (needsParens)
4055+ OS << " )" ;
4056+
4057+ // When removing 'any', use a character-based removal to pick up
4058+ // whitespaces between it and its constraint repr.
4059+ Diag
4060+ .fixItReplace (constraintRepr->getSourceRange (), fix)
4061+ .fixItRemoveChars (anyRange.Start , anyRange.End );
40874062
40884063 return true ;
40894064}
0 commit comments