@@ -952,6 +952,107 @@ namespace {
952
952
// / the type conforms to the expected literal protocol.
953
953
Expr *simplifyTypeConstructionWithLiteralArg (Expr *E);
954
954
955
+ // / In Swift < 5, diagnose and correct invalid multi-argument or
956
+ // / argument-labeled interpolations.
957
+ void correctInterpolationIfStrange (InterpolatedStringLiteralExpr *ISLE) {
958
+ // These expressions are valid in Swift 5+.
959
+ if (TC.Context .isSwiftVersionAtLeast (5 ))
960
+ return ;
961
+
962
+ // / Diagnoses appendInterpolation(...) calls with multiple
963
+ // / arguments or argument labels and corrects them.
964
+ class StrangeInterpolationRewriter : public ASTWalker {
965
+ TypeChecker &TC;
966
+
967
+ public:
968
+ StrangeInterpolationRewriter (TypeChecker &TC) : TC(TC) { }
969
+
970
+ virtual bool walkToDeclPre (Decl *D) {
971
+ // We don't want to look inside decls.
972
+ return false ;
973
+ }
974
+
975
+ virtual std::pair<bool , Expr *> walkToExprPre (Expr *E) {
976
+ // One InterpolatedStringLiteralExpr should never be nested inside
977
+ // another except as a child of a CallExpr, and we don't recurse into
978
+ // the children of CallExprs.
979
+ assert (!isa<InterpolatedStringLiteralExpr>(E) &&
980
+ " StrangeInterpolationRewriter found nested interpolation?" );
981
+
982
+ // We only care about CallExprs.
983
+ if (!isa<CallExpr>(E))
984
+ return { true , E };
985
+
986
+ auto call = cast<CallExpr>(E);
987
+ if (auto callee = dyn_cast<UnresolvedDotExpr>(call->getFn ())) {
988
+ if (callee->getName ().getBaseName () ==
989
+ TC.Context .Id_appendInterpolation ) {
990
+ Expr *newArg = nullptr ;
991
+ SourceLoc lParen, rParen;
992
+
993
+ if (call->getNumArguments () > 1 ) {
994
+ auto *args = cast<TupleExpr>(call->getArg ());
995
+
996
+ lParen = args->getLParenLoc ();
997
+ rParen = args->getRParenLoc ();
998
+ Expr *secondArg = args->getElement (1 );
999
+
1000
+ TC.diagnose (secondArg->getLoc (),
1001
+ diag::string_interpolation_list_changing)
1002
+ .highlightChars (secondArg->getLoc (), rParen);
1003
+ TC.diagnose (secondArg->getLoc (),
1004
+ diag::string_interpolation_list_insert_parens)
1005
+ .fixItInsertAfter (lParen, " (" )
1006
+ .fixItInsert (rParen, " )" );
1007
+
1008
+ newArg = args;
1009
+ }
1010
+ else if (call->getNumArguments () == 1 &&
1011
+ call->getArgumentLabels ().front () != Identifier ()) {
1012
+ auto *args = cast<TupleExpr>(call->getArg ());
1013
+ newArg = args->getElement (0 );
1014
+
1015
+ lParen = args->getLParenLoc ();
1016
+ rParen = args->getRParenLoc ();
1017
+
1018
+ SourceLoc argLabelLoc = call->getArgumentLabelLoc (0 ),
1019
+ argLoc = newArg->getStartLoc ();
1020
+
1021
+ TC.diagnose (argLabelLoc,
1022
+ diag::string_interpolation_label_changing)
1023
+ .highlightChars (argLabelLoc, argLoc);
1024
+ TC.diagnose (argLabelLoc,
1025
+ diag::string_interpolation_remove_label,
1026
+ call->getArgumentLabels ().front ())
1027
+ .fixItRemoveChars (argLabelLoc, argLoc);
1028
+ }
1029
+
1030
+ // If newArg is no longer null, we need to build a new
1031
+ // appendInterpolation(_:) call that takes it to replace the bad
1032
+ // appendInterpolation(...) call.
1033
+ if (newArg) {
1034
+ auto newCallee = new (TC.Context ) UnresolvedDotExpr (
1035
+ callee->getBase (), /* dotloc=*/ SourceLoc (),
1036
+ DeclName (TC.Context .Id_appendInterpolation ),
1037
+ /* nameloc=*/ DeclNameLoc (), /* Implicit=*/ true );
1038
+
1039
+ E = CallExpr::create (TC.Context , newCallee, lParen,
1040
+ { newArg }, { Identifier () }, { SourceLoc () },
1041
+ rParen, /* trailingClosure=*/ nullptr , /* implicit=*/ false );
1042
+ }
1043
+ }
1044
+ }
1045
+
1046
+ // There is never a CallExpr between an InterpolatedStringLiteralExpr
1047
+ // and an un-typechecked appendInterpolation(...) call, so whether we
1048
+ // changed E or not, we don't need to recurse any deeper.
1049
+ return { false , E };
1050
+ }
1051
+ };
1052
+
1053
+ ISLE->getAppendingExpr ()->walk (StrangeInterpolationRewriter (TC));
1054
+ }
1055
+
955
1056
public:
956
1057
PreCheckExpression (TypeChecker &tc, DeclContext *dc, Expr *parent)
957
1058
: TC(tc), DC(dc), ParentExpr(parent) {}
@@ -1086,6 +1187,9 @@ namespace {
1086
1187
return finish (false , nullptr );
1087
1188
}
1088
1189
1190
+ if (auto *ISLE = dyn_cast<InterpolatedStringLiteralExpr>(expr))
1191
+ correctInterpolationIfStrange (ISLE);
1192
+
1089
1193
return finish (true , expr);
1090
1194
}
1091
1195
0 commit comments