@@ -86,6 +86,20 @@ Expr *FailureDiagnostic::findParentExpr(Expr *subExpr) const {
8686 return E ? E->getParentMap ()[subExpr] : nullptr ;
8787}
8888
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+
89103Type RequirementFailure::getOwnerType () const {
90104 return getType (getRawAnchor ())
91105 ->getInOutObjectType ()
@@ -369,18 +383,7 @@ bool LabelingFailure::diagnoseAsError() {
369383 auto &cs = getConstraintSystem ();
370384 auto *anchor = getRawAnchor ();
371385
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);
384387 if (!argExpr)
385388 return false ;
386389
@@ -2133,3 +2136,78 @@ bool ClosureParamDestructuringFailure::diagnoseAsError() {
21332136 .fixItInsert (bodyLoc, OS.str ());
21342137 return true ;
21352138}
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