@@ -86,6 +86,20 @@ Expr *FailureDiagnostic::findParentExpr(Expr *subExpr) const {
86
86
return E ? E->getParentMap ()[subExpr] : nullptr ;
87
87
}
88
88
89
+ Expr *FailureDiagnostic::getArgumentExprFor (Expr *anchor) const {
90
+ if (auto *UDE = dyn_cast<UnresolvedDotExpr>(anchor)) {
91
+ if (auto *call = dyn_cast_or_null<CallExpr>(findParentExpr (UDE)))
92
+ return call->getArg ();
93
+ } else if (auto *UME = dyn_cast<UnresolvedMemberExpr>(anchor)) {
94
+ return UME->getArgument ();
95
+ } else if (auto *call = dyn_cast<CallExpr>(anchor)) {
96
+ return call->getArg ();
97
+ } else if (auto *SE = dyn_cast<SubscriptExpr>(anchor)) {
98
+ return SE->getIndex ();
99
+ }
100
+ return nullptr ;
101
+ }
102
+
89
103
Type RequirementFailure::getOwnerType () const {
90
104
return getType (getRawAnchor ())
91
105
->getInOutObjectType ()
@@ -369,18 +383,7 @@ bool LabelingFailure::diagnoseAsError() {
369
383
auto &cs = getConstraintSystem ();
370
384
auto *anchor = getRawAnchor ();
371
385
372
- Expr *argExpr = nullptr ;
373
- if (auto *UDE = dyn_cast<UnresolvedDotExpr>(anchor)) {
374
- if (auto *call = dyn_cast_or_null<CallExpr>(findParentExpr (UDE)))
375
- argExpr = call->getArg ();
376
- } else if (auto *UME = dyn_cast<UnresolvedMemberExpr>(anchor)) {
377
- argExpr = UME->getArgument ();
378
- } else if (auto *call = dyn_cast<CallExpr>(anchor)) {
379
- argExpr = call->getArg ();
380
- } else if (auto *SE = dyn_cast<SubscriptExpr>(anchor)) {
381
- argExpr = SE->getIndex ();
382
- }
383
-
386
+ auto *argExpr = getArgumentExprFor (anchor);
384
387
if (!argExpr)
385
388
return false ;
386
389
@@ -2133,3 +2136,78 @@ bool ClosureParamDestructuringFailure::diagnoseAsError() {
2133
2136
.fixItInsert (bodyLoc, OS.str ());
2134
2137
return true ;
2135
2138
}
2139
+
2140
+ bool OutOfOrderArgumentFailure::diagnoseAsError () {
2141
+ auto *anchor = getRawAnchor ();
2142
+ auto *argExpr = isa<TupleExpr>(anchor) ? anchor : getArgumentExprFor (anchor);
2143
+ if (!argExpr)
2144
+ return false ;
2145
+
2146
+ auto *tuple = cast<TupleExpr>(argExpr);
2147
+
2148
+ Identifier first = tuple->getElementName (ArgIdx);
2149
+ Identifier second = tuple->getElementName (PrevArgIdx);
2150
+
2151
+ // Build a mapping from arguments to parameters.
2152
+ SmallVector<unsigned , 4 > argBindings (tuple->getNumElements ());
2153
+ for (unsigned paramIdx = 0 ; paramIdx != Bindings.size (); ++paramIdx) {
2154
+ for (auto argIdx : Bindings[paramIdx])
2155
+ argBindings[argIdx] = paramIdx;
2156
+ }
2157
+
2158
+ auto argRange = [&](unsigned argIdx, Identifier label) -> SourceRange {
2159
+ auto range = tuple->getElement (argIdx)->getSourceRange ();
2160
+ if (!label.empty ())
2161
+ range.Start = tuple->getElementNameLoc (argIdx);
2162
+
2163
+ unsigned paramIdx = argBindings[argIdx];
2164
+ if (Bindings[paramIdx].size () > 1 )
2165
+ range.End = tuple->getElement (Bindings[paramIdx].back ())->getEndLoc ();
2166
+
2167
+ return range;
2168
+ };
2169
+
2170
+ auto firstRange = argRange (ArgIdx, first);
2171
+ auto secondRange = argRange (PrevArgIdx, second);
2172
+
2173
+ SourceLoc diagLoc = firstRange.Start ;
2174
+
2175
+ auto addFixIts = [&](InFlightDiagnostic diag) {
2176
+ diag.highlight (firstRange).highlight (secondRange);
2177
+
2178
+ // Move the misplaced argument by removing it from one location and
2179
+ // inserting it in another location. To maintain argument comma
2180
+ // separation, since the argument is always moving to an earlier index
2181
+ // the preceding comma and whitespace is removed and a new trailing
2182
+ // comma and space is inserted with the moved argument.
2183
+ auto &SM = getASTContext ().SourceMgr ;
2184
+ auto text = SM.extractText (
2185
+ Lexer::getCharSourceRangeFromSourceRange (SM, firstRange));
2186
+
2187
+ auto removalRange =
2188
+ SourceRange (Lexer::getLocForEndOfToken (
2189
+ SM, tuple->getElement (ArgIdx - 1 )->getEndLoc ()),
2190
+ firstRange.End );
2191
+ diag.fixItRemove (removalRange);
2192
+ diag.fixItInsert (secondRange.Start , text.str () + " , " );
2193
+ };
2194
+
2195
+ // There are 4 diagnostic messages variations depending on
2196
+ // labeled/unlabeled arguments.
2197
+ if (first.empty () && second.empty ()) {
2198
+ addFixIts (emitDiagnostic (diagLoc,
2199
+ diag::argument_out_of_order_unnamed_unnamed,
2200
+ ArgIdx + 1 , PrevArgIdx + 1 ));
2201
+ } else if (first.empty () && !second.empty ()) {
2202
+ addFixIts (emitDiagnostic (diagLoc, diag::argument_out_of_order_unnamed_named,
2203
+ ArgIdx + 1 , second));
2204
+ } else if (!first.empty () && second.empty ()) {
2205
+ addFixIts (emitDiagnostic (diagLoc, diag::argument_out_of_order_named_unnamed,
2206
+ first, PrevArgIdx + 1 ));
2207
+ } else {
2208
+ addFixIts (emitDiagnostic (diagLoc, diag::argument_out_of_order_named_named,
2209
+ first, second));
2210
+ }
2211
+
2212
+ return true ;
2213
+ }
0 commit comments