@@ -3970,8 +3970,11 @@ bool InvalidMemberRefOnExistential::diagnoseAsError() {
3970
3970
3971
3971
// If the base expression is a reference to a function or subscript
3972
3972
// 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.
3975
3978
3976
3979
if (!PD || !PD->getDeclContext ()->getAsDecl ())
3977
3980
return true ;
@@ -4020,70 +4023,42 @@ bool InvalidMemberRefOnExistential::diagnoseAsError() {
4020
4023
if (PD->isInOut ())
4021
4024
return true ;
4022
4025
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 ();
4073
4029
}
4074
4030
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
+ }
4078
4039
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 ());
4083
4046
}
4084
4047
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 );
4087
4062
4088
4063
return true ;
4089
4064
}
0 commit comments