@@ -3972,8 +3972,11 @@ bool InvalidMemberRefOnExistential::diagnoseAsError() {
3972
3972
3973
3973
// If the base expression is a reference to a function or subscript
3974
3974
// 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.
3977
3980
3978
3981
if (!PD || !PD->getDeclContext ()->getAsDecl ())
3979
3982
return true ;
@@ -4022,70 +4025,42 @@ bool InvalidMemberRefOnExistential::diagnoseAsError() {
4022
4025
if (PD->isInOut ())
4023
4026
return true ;
4024
4027
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 ();
4075
4031
}
4076
4032
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
+ }
4080
4041
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 ());
4085
4048
}
4086
4049
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 );
4089
4064
4090
4065
return true ;
4091
4066
}
0 commit comments