Skip to content

Commit 7242b55

Browse files
authored
Merge pull request #10434 from bitjammer/rdar-32887663-migrator-remove-tuple-destructure-swift-4.0-branch
[Migrator] Remove some now unnecessary tuple destructuring
2 parents 2ff9c77 + fea3bfd commit 7242b55

File tree

3 files changed

+12
-165
lines changed

3 files changed

+12
-165
lines changed

lib/Migrator/TupleSplatMigratorPass.cpp

Lines changed: 0 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -176,161 +176,8 @@ struct TupleSplatMigratorPass : public ASTMigratorPass,
176176
return true;
177177
};
178178

179-
// Handles such kind of cases:
180-
// \code
181-
// func test(_: ((Int, Int)) -> ()) {}
182-
// test({ (x,y) in })
183-
// \endcode
184-
// This compiles fine in Swift 3 but Swift 4 complains with
185-
// error: cannot convert value of type '(_, _) -> ()' to expected
186-
// argument type '((Int, Int)) -> ()'
187-
//
188-
// It will fix the code to "test({ let (x,y) = $0; })".
189-
//
190-
auto handleTupleMapToClosureArgs = [&](const CallExpr *E) -> bool {
191-
auto fnTy = E->getFn()->getType()->getAs<FunctionType>();
192-
if (!fnTy)
193-
return false;
194-
auto fnTy2 = fnTy->getInput()->getAs<FunctionType>();
195-
if (!fnTy2) {
196-
// This may have been a tuple type of one element.
197-
if (auto tuple = fnTy->getInput()->getAs<TupleType>()) {
198-
if (tuple->getNumElements() == 1) {
199-
fnTy2 = tuple->getElement(0).getType()->getAs<FunctionType>();
200-
}
201-
}
202-
}
203-
if (!fnTy2) {
204-
return false;
205-
}
206-
auto parenT = dyn_cast<ParenType>(fnTy2->getInput().getPointer());
207-
if (!parenT)
208-
return false;
209-
auto tupleInFn = parenT->getAs<TupleType>();
210-
if (!tupleInFn)
211-
return false;
212-
if (!E->getArg())
213-
return false;
214-
auto argE = E->getArg()->getSemanticsProvidingExpr();
215-
while (auto *ICE = dyn_cast<ImplicitConversionExpr>(argE))
216-
argE = ICE->getSubExpr();
217-
argE = argE->getSemanticsProvidingExpr();
218-
auto closureE = dyn_cast<ClosureExpr>(argE);
219-
if (!closureE) {
220-
if (auto *FCE = dyn_cast<FunctionConversionExpr>(argE)) {
221-
closureE = dyn_cast<ClosureExpr>(FCE->getSubExpr());
222-
}
223-
}
224-
if (!closureE)
225-
return false;
226-
if (closureE->getInLoc().isInvalid())
227-
return false;
228-
auto paramList = closureE->getParameters();
229-
if (!paramList ||
230-
paramList->getLParenLoc().isInvalid() || paramList->getRParenLoc().isInvalid())
231-
return false;
232-
if (paramList->size() != tupleInFn->getNumElements())
233-
return false;
234-
if (paramList->size() == 0)
235-
return false;
236-
237-
auto hasParamListWithNoTypes = [&]() {
238-
if (closureE->hasExplicitResultType())
239-
return false;
240-
for (auto *param : *paramList) {
241-
auto tyLoc = param->getTypeLoc();
242-
if (!tyLoc.isNull())
243-
return false;
244-
}
245-
return true;
246-
};
247-
248-
if (hasParamListWithNoTypes()) {
249-
// Simpler form depending on type inference.
250-
// Change "(x, y) in " to "let (x, y) = $0;".
251-
252-
Editor.insert(paramList->getLParenLoc(), "let ");
253-
for (auto *param : *paramList) {
254-
// If the argument list is like "(_ x, _ y)", remove the underscores.
255-
if (param->getArgumentNameLoc().isValid()) {
256-
Editor.remove(CharSourceRange(SM, param->getArgumentNameLoc(),
257-
param->getNameLoc()));
258-
}
259-
// If the argument list has type annotations, remove them.
260-
auto tyLoc = param->getTypeLoc();
261-
if (!tyLoc.isNull() && !tyLoc.getSourceRange().isInvalid()) {
262-
auto nameRange = CharSourceRange(param->getNameLoc(),
263-
param->getNameStr().size());
264-
auto tyRange = Lexer::getCharSourceRangeFromSourceRange(SM,
265-
tyLoc.getSourceRange());
266-
Editor.remove(CharSourceRange(SM, nameRange.getEnd(),
267-
tyRange.getEnd()));
268-
}
269-
}
270-
271-
// If the original closure was a single expression without the need
272-
// for a `return` statement, it needs one now, because we've added a new
273-
// assignment statement just above.
274-
if (closureE->hasSingleExpressionBody()) {
275-
Editor.replaceToken(closureE->getInLoc(), "= $0; return");
276-
} else {
277-
Editor.replaceToken(closureE->getInLoc(), "= $0;");
278-
}
279-
280-
return true;
281-
}
282-
283-
// Includes types in the closure signature. The following will do a
284-
// more complicated edit than the above:
285-
// (x: Int, y: Int) -> Int in
286-
// to
287-
// (__val:(Int, Int)) -> Int in let (x,y) = __val;
288-
289-
std::string paramListText;
290-
{
291-
llvm::raw_string_ostream OS(paramListText);
292-
OS << "(__val:(";
293-
for (size_t i = 0, e = paramList->size(); i != e; ++i) {
294-
if (i != 0)
295-
OS << ", ";
296-
auto param = paramList->get(i);
297-
auto tyLoc = param->getTypeLoc();
298-
if (!tyLoc.isNull() && !tyLoc.getSourceRange().isInvalid()) {
299-
OS << SM.extractText(
300-
Lexer::getCharSourceRangeFromSourceRange(SM,
301-
tyLoc.getSourceRange()));
302-
} else {
303-
param->getType().print(OS);
304-
}
305-
}
306-
OS << "))";
307-
}
308-
std::string varBindText;
309-
{
310-
llvm::raw_string_ostream OS(varBindText);
311-
OS << " let (";
312-
for (size_t i = 0, e = paramList->size(); i != e; ++i) {
313-
if (i != 0)
314-
OS << ",";
315-
auto param = paramList->get(i);
316-
OS << param->getNameStr();
317-
}
318-
OS << ") = __val;";
319-
320-
if (closureE->hasSingleExpressionBody()) {
321-
OS << " return";
322-
}
323-
}
324-
325-
Editor.replace(paramList->getSourceRange(), paramListText);
326-
Editor.insertAfterToken(closureE->getInLoc(), varBindText);
327-
return true;
328-
};
329-
330179
if (handleCallsToEmptyTuple(E))
331180
return;
332-
if (handleTupleMapToClosureArgs(E))
333-
return;
334181
}
335182

336183
bool walkToExprPre(Expr *E) override {

test/Migrator/no_extraneous_argument_labels.swift.expected

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ func foo(_ oc: [String]) {
77
var args: [String] = []
88
let dictionary: [String: String] = [:]
99
args.append(contentsOf: oc.map { orderedColumn in
10-
dictionary.first { let (column, value) = $0; return true }!.value
10+
dictionary.first { (column, value) in true }!.value
1111
})
1212
}

test/Migrator/tuple-arguments.swift.expected

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,25 +21,25 @@ func test5(_: (Int, Int, Int) -> ()) {}
2121
test5({ (x,y,z) in })
2222

2323
func test6(_: ((Int, Int)) -> ()) {}
24-
test6({ let (x,y) = $0; })
24+
test6({ (x,y) in })
2525
func test7(_: ((Int, Int, Int)) -> ()) {}
26-
test7({ let (x,y,z) = $0; })
27-
test6({ let (x, y) = $0; })
28-
test6({ let (_, _) = $0; })
29-
test6({ (__val:(Int, Int)) in let (x,y) = __val; })
30-
test6({ (__val:(Int, Int)) ->() in let (_,_) = __val; })
26+
test7({ (x,y,z) in })
27+
test6({ (_ x, _ y) in })
28+
test6({ (_, _) in })
29+
test6({ (x:Int, y:Int) in })
30+
test6({ (_, _) ->() in })
3131

3232
func test8(_: ((Int, Int)) -> Int) {}
33-
test8 { (__val:(Int, Int)) -> Int in let (_,_) = __val; return 2 }
34-
test8 { let (x, y) = $0; return x }
33+
test8 { (_, _) -> Int in 2 }
34+
test8 { (x, y) in x }
3535

3636
func isEven(_ x: Int) -> Bool { return x % 2 == 0 }
3737
let items = Array(zip(0..<10, 0..<10))
38-
_ = items.filter { let (_, x) = $0; return isEven(x) }
38+
_ = items.filter { (_, x) in isEven(x) }
3939
_ = items.filter { _ in true }
4040

4141
func toString(indexes: Int?...) -> String {
42-
let _ = indexes.enumerated().flatMap({ (__val:(Int, Int?)) -> String? in let (i,index) = __val;
42+
let _ = indexes.enumerated().flatMap({ (i: Int, index: Int?) -> String? in
4343
let _: Int = i
4444
if index != nil {}
4545
return ""
@@ -58,4 +58,4 @@ extension Dictionary {
5858
}
5959

6060
let dictionary: [String: String] = [:]
61-
_ = dictionary.first { let (column, value) = $0; return true }!.value
61+
_ = dictionary.first { (column, value) in true }!.value

0 commit comments

Comments
 (0)