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