Skip to content

Commit c9b73da

Browse files
committed
[Sema] ban multi-arguments to tuple coercion
Implements part of SE-0110. Single argument in closures will not be accepted if there exists explicit type with a number of arguments that's not 1. ```swift let f: (Int, Int) -> Void = { x in } // this is now an error ``` Note there's a second part of SE-0110 which could be considered additive, which says one must add an extra pair of parens to specify a single arugment type that is a tuple: ```swift let g ((Int, Int)) -> Void = { y in } // y should have type (Int, Int) ``` This patch does not implement that part.
1 parent d3194ec commit c9b73da

36 files changed

+70
-77
lines changed

lib/Sema/CSApply.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -6417,7 +6417,7 @@ namespace {
64176417
// Coerce the pattern, in case we resolved something.
64186418
auto fnType = closure->getType()->castTo<FunctionType>();
64196419
auto *params = closure->getParameters();
6420-
if (tc.coerceParameterListToType(params, closure, fnType->getInput()))
6420+
if (tc.coerceParameterListToType(params, closure, fnType))
64216421
return { false, nullptr };
64226422

64236423
// If this is a single-expression closure, convert the expression

lib/Sema/CSDiag.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -5407,7 +5407,7 @@ bool FailureDiagnosis::visitClosureExpr(ClosureExpr *CE) {
54075407
return true;
54085408
}
54095409

5410-
if (CS->TC.coerceParameterListToType(params, CE, inferredArgType))
5410+
if (CS->TC.coerceParameterListToType(params, CE, fnType))
54115411
return true;
54125412

54135413
expectedResultType = fnType->getResult();

lib/Sema/TypeCheckPattern.cpp

+8-8
Original file line numberDiff line numberDiff line change
@@ -1683,8 +1683,9 @@ bool TypeChecker::coercePatternToType(Pattern *&P, DeclContext *dc, Type type,
16831683
/// TODO: These diagnostics should be a lot better now that we know this is
16841684
/// all specific to closures.
16851685
///
1686-
bool TypeChecker::coerceParameterListToType(ParameterList *P, DeclContext *DC,
1687-
Type paramListType) {
1686+
bool TypeChecker::coerceParameterListToType(ParameterList *P, ClosureExpr *CE,
1687+
AnyFunctionType *FN) {
1688+
Type paramListType = FN->getInput();
16881689
bool hadError = paramListType->is<ErrorType>();
16891690

16901691
// Sometimes a scalar type gets applied to a single-argument parameter list.
@@ -1693,7 +1694,7 @@ bool TypeChecker::coerceParameterListToType(ParameterList *P, DeclContext *DC,
16931694

16941695
// Check that the type, if explicitly spelled, is ok.
16951696
if (param->getTypeLoc().getTypeRepr()) {
1696-
hadError |= validateParameterType(param, DC, TypeResolutionOptions(),
1697+
hadError |= validateParameterType(param, CE, TypeResolutionOptions(),
16971698
nullptr, *this);
16981699

16991700
// Now that we've type checked the explicit argument type, see if it
@@ -1735,11 +1736,10 @@ bool TypeChecker::coerceParameterListToType(ParameterList *P, DeclContext *DC,
17351736
// The number of elements must match exactly.
17361737
// TODO: incomplete tuple patterns, with some syntax.
17371738
if (!hadError && tupleTy->getNumElements() != P->size()) {
1738-
if (P->size() == 1)
1739-
return handleParameter(P->get(0), paramListType);
1740-
1741-
diagnose(P->getStartLoc(), diag::tuple_pattern_length_mismatch,
1742-
paramListType);
1739+
auto fnType = FunctionType::get(paramListType->getDesugaredType(),
1740+
FN->getResult());
1741+
diagnose(P->getStartLoc(), diag::closure_argument_list_tuple,
1742+
fnType, tupleTy->getNumElements(), P->size());
17431743
hadError = true;
17441744
}
17451745

lib/Sema/TypeChecker.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -1386,7 +1386,8 @@ class TypeChecker final : public LazyResolver {
13861386
/// contextual type.
13871387
///
13881388
/// \returns true if an error occurred, false otherwise.
1389-
bool coerceParameterListToType(ParameterList *P, DeclContext *dc, Type type);
1389+
bool coerceParameterListToType(ParameterList *P, ClosureExpr *CE,
1390+
AnyFunctionType *FN);
13901391

13911392

13921393
/// Type-check an initialized variable pattern declaration.

stdlib/private/StdlibCollectionUnittest/CheckSequenceType.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -1807,7 +1807,7 @@ self.test("\(testNamePrefix)._preprocessingPass/semantics") {
18071807
let s = makeWrappedSequence(test.sequence.map(OpaqueValue.init))
18081808
var wasInvoked = false
18091809
let result = s._preprocessingPass {
1810-
(sequence) -> OpaqueValue<Int> in
1810+
() -> OpaqueValue<Int> in
18111811
wasInvoked = true
18121812

18131813
expectEqualSequence(
@@ -1830,7 +1830,7 @@ self.test("\(testNamePrefix)._preprocessingPass/semantics") {
18301830
var result: OpaqueValue<Int>? = nil
18311831
do {
18321832
result = try s._preprocessingPass {
1833-
(sequence) -> OpaqueValue<Int> in
1833+
() -> OpaqueValue<Int> in
18341834
wasInvoked = true
18351835
throw TestError.error2
18361836
}

stdlib/private/StdlibUnittest/StdlibUnittest.swift.gyb

+1-1
Original file line numberDiff line numberDiff line change
@@ -2387,7 +2387,7 @@ public func expectEqualsUnordered<
23872387
let x: [(T, T)] =
23882388
expected.sorted(by: comparePairLess)
23892389
let y: [(T, T)] =
2390-
actual.map { ($0.0, $0.1) }
2390+
actual.map { ($0, $1) }
23912391
.sorted(by: comparePairLess)
23922392

23932393
func comparePairEquals(_ lhs: (T, T), rhs: (key: T, value: T)) -> Bool {

stdlib/private/StdlibUnittest/TypeIndexed.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ public func expectEqual<V: Comparable>(
105105
file: String = #file, line: UInt = #line
106106
) {
107107
expectEqualsUnordered(
108-
expected.map { (key: TypeIdentifier($0.0), value: $0.1) },
108+
expected.map { (key: TypeIdentifier($0), value: $1) },
109109
actual.byType,
110110
message(), stackTrace: stackTrace) { $0 <=> $1 }
111111
}

stdlib/public/SDK/AppKit/AppKit.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ extension NSView : _DefaultCustomPlaygroundQuickLookable {
5454
public extension NSGradient {
5555
convenience init?(colorsAndLocations objects: (NSColor, CGFloat)...) {
5656
self.init(
57-
colors: objects.map { $0.0 },
58-
atLocations: objects.map { $0.1 },
57+
colors: objects.map { c, _ in c },
58+
atLocations: objects.map { _, l in l },
5959
colorSpace: NSColorSpace.genericRGB())
6060
}
6161
}

stdlib/public/SDK/Foundation/Foundation.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -570,8 +570,8 @@ extension NSDictionary : ExpressibleByDictionaryLiteral {
570570
dictionaryLiteral elements: (NSCopying, AnyObject)...
571571
) {
572572
self.init(
573-
objects: elements.map { $0.1 },
574-
forKeys: elements.map { $0.0 },
573+
objects: elements.map { _, v in v },
574+
forKeys: elements.map { k, _ in k },
575575
count: elements.count)
576576
}
577577
}

stdlib/public/SDK/WatchKit/WatchKit.swift

+4-4
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ extension WKInterfaceController {
2929
withNamesAndContexts namesAndContexts: [(name: String, context: AnyObject)]
3030
) {
3131
WKInterfaceController.reloadRootControllers(
32-
withNames: namesAndContexts.map { $0.name },
33-
contexts: namesAndContexts.map { $0.context })
32+
withNames: namesAndContexts.map { name, _ in name },
33+
contexts: namesAndContexts.map { _, context in context })
3434
}
3535

3636
@available(*, deprecated,
@@ -47,8 +47,8 @@ extension WKInterfaceController {
4747
withNamesAndContexts namesAndContexts: [(name: String, context: AnyObject)]
4848
) {
4949
self.presentController(
50-
withNames: namesAndContexts.map { $0.name },
51-
contexts: namesAndContexts.map { $0.context })
50+
withNames: namesAndContexts.map { name, _ in name },
51+
contexts: namesAndContexts.map { _, context in context })
5252
}
5353
}
5454

stdlib/public/core/HashedCollections.swift.gyb

+2-2
Original file line numberDiff line numberDiff line change
@@ -2018,7 +2018,7 @@ public struct Dictionary<Key : Hashable, Value> :
20182018
/// // Prints "JP"
20192019
/// // Prints "GH"
20202020
public var keys: LazyMapCollection<Dictionary, Key> {
2021-
return self.lazy.map { $0.key }
2021+
return self.lazy.map { key, _ in key }
20222022
}
20232023

20242024
/// A collection containing just the values of the dictionary.
@@ -2036,7 +2036,7 @@ public struct Dictionary<Key : Hashable, Value> :
20362036
/// // Prints "Japan"
20372037
/// // Prints "Ghana"
20382038
public var values: LazyMapCollection<Dictionary, Value> {
2039-
return self.lazy.map { $0.value }
2039+
return self.lazy.map { _, value in value }
20402040
}
20412041

20422042
//

stdlib/public/core/ManagedBuffer.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public class ManagedBuffer<Header, Element> {
8181
public final func withUnsafeMutablePointerToElements<R>(
8282
_ body: @noescape (UnsafeMutablePointer<Element>) throws -> R
8383
) rethrows -> R {
84-
return try withUnsafeMutablePointers { return try body($0.1) }
84+
return try withUnsafeMutablePointers { return try body($1) }
8585
}
8686

8787
/// Call `body` with `UnsafeMutablePointer`s to the stored `Header`
@@ -267,7 +267,7 @@ public struct ManagedBufferPointer<Header, Element> : Equatable {
267267
public func withUnsafeMutablePointerToElements<R>(
268268
_ body: @noescape (UnsafeMutablePointer<Element>) throws -> R
269269
) rethrows -> R {
270-
return try withUnsafeMutablePointers { return try body($0.1) }
270+
return try withUnsafeMutablePointers { return try body($1) }
271271
}
272272

273273
/// Call `body` with `UnsafeMutablePointer`s to the stored `Header`

stdlib/public/core/Mirror.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ public struct Mirror {
330330
self._makeSuperclassMirror = Mirror._superclassIterator(
331331
subject, ancestorRepresentation)
332332

333-
let lazyChildren = children.lazy.map { Child(label: $0.0, value: $0.1) }
333+
let lazyChildren = children.lazy.map { Child(label: $0, value: $1) }
334334
self.children = Children(lazyChildren)
335335

336336
self.displayStyle = displayStyle
@@ -440,7 +440,7 @@ extension Mirror {
440440
let children = Mirror(reflecting: result).children
441441
let position: Children.Index
442442
if case let label as String = e {
443-
position = children.index { $0.label == label } ?? children.endIndex
443+
position = children.index { l, _ in l == label } ?? children.endIndex
444444
}
445445
else if let offset = (e as? Int).map({ IntMax($0) }) ?? (e as? IntMax) {
446446
position = children.index(children.startIndex,

test/1_stdlib/Mirror.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ extension Mirror {
3232
let nil_ = "nil"
3333
return "[" +
3434
children.lazy
35-
.map { "\($0.0 ?? nil_): \(String(reflecting: $0.1))" }
35+
.map { "\($0 ?? nil_): \(String(reflecting: $1))" }
3636
.joined(separator: ", ")
3737
+ "]"
3838
}
@@ -158,7 +158,7 @@ mirrors.test("Legacy") {
158158
]
159159
expectFalse(
160160
zip(x0, m.children).contains {
161-
$0.0.value as! Int != $0.1.value as! Int
161+
$0.value as! Int != $1.value as! Int
162162
})
163163

164164
class B { let bx: Int = 0 }

test/1_stdlib/Renames.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ func _SequenceAlgorithms<S : Sequence>(x: S) {
407407
_ = x.minElement { _, _ in true } // expected-error {{'minElement' has been renamed to 'min(by:)'}} {{9-19=min}} {{none}}
408408
_ = x.maxElement { _, _ in true } // expected-error {{'maxElement' has been renamed to 'max(by:)'}} {{9-19=max}} {{none}}
409409
_ = x.reverse() // expected-error {{'reverse()' has been renamed to 'reversed()'}} {{9-16=reversed}} {{none}}
410-
_ = x.startsWith([]) { _ in true } // expected-error {{'startsWith(_:isEquivalent:)' has been renamed to 'starts(with:by:)'}} {{9-19=starts}} {{20-20=with: }} {{none}}
410+
_ = x.startsWith([]) { _, _ in true } // expected-error {{'startsWith(_:isEquivalent:)' has been renamed to 'starts(with:by:)'}} {{9-19=starts}} {{20-20=with: }} {{none}}
411411
_ = x.lexicographicalCompare([]) { _, _ in true } // expected-error {{'lexicographicalCompare(_:isOrderedBefore:)' has been renamed to 'lexicographicallyPrecedes(_:by:)'}} {{9-31=lexicographicallyPrecedes}}{{none}}
412412
}
413413
func _SequenceAlgorithms<S : Sequence>(x: S) where S.Iterator.Element : Comparable {

test/1_stdlib/UnsafePointer.swift.gyb

+1-1
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ ${SelfName}TestSuite.test("Comparable") {
455455
func comparisonOracle(i: Int, j: Int) -> ExpectedComparisonResult {
456456
return instances[i].0 <=> instances[j].0
457457
}
458-
checkComparable(instances.map { $0.1 }, oracle: comparisonOracle)
458+
checkComparable(instances.map { $1 }, oracle: comparisonOracle)
459459
}
460460

461461
% end

test/Constraints/closures.swift

+5-11
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ _ = myMap(intArray, { x -> String in String(x) } )
99

1010
// Closures with too few parameters.
1111
func foo(_ x: (Int, Int) -> Int) {}
12-
foo({$0}) // expected-error{{cannot convert value of type '(Int, Int)' to closure result type 'Int'}}
12+
foo({$0}) // expected-error{{contextual closure type '(Int, Int) -> Int' expects 2 arguments, but 1 were used in closure body}}
1313

1414
struct X {}
1515
func mySort(_ array: [String], _ predicate: (String, String) -> Bool) -> [String] {}
@@ -121,15 +121,16 @@ var _: (Int,Int) -> Int = {$0+$1+$2}
121121
// expected-error @+1 {{contextual closure type '(Int, Int, Int) -> Int' expects 3 arguments, but 2 were used in closure body}}
122122
var _: (Int, Int, Int) -> Int = {$0+$1}
123123

124-
125-
var _: () -> Int = {a in 0}
124+
// expected-error @+1 {{contextual closure type '() -> Int' expects 0 arguments, but 1 were used in closure body}}
125+
var _: () -> Int = {_ in 0}
126126

127127
// expected-error @+1 {{contextual closure type '(Int) -> Int' expects 1 argument, but 2 were used in closure body}}
128128
var _: (Int) -> Int = {a,b in 0}
129129

130130
// expected-error @+1 {{contextual closure type '(Int) -> Int' expects 1 argument, but 3 were used in closure body}}
131131
var _: (Int) -> Int = {a,b,c in 0}
132132

133+
// expected-error @+1 {{contextual closure type '(Int, Int) -> Int' expects 2 arguments, but 1 were used in closure body}}
133134
var _: (Int, Int) -> Int = {a in 0}
134135

135136
// expected-error @+1 {{contextual closure type '(Int, Int, Int) -> Int' expects 3 arguments, but 2 were used in closure body}}
@@ -202,7 +203,7 @@ func acceptNothingToInt (_: @noescape () -> Int) {}
202203
func testAcceptNothingToInt(ac1: @autoclosure () -> Int) {
203204
// expected-note@-1{{parameter 'ac1' is implicitly non-escaping because it was declared @autoclosure}}
204205
acceptNothingToInt({ac1($0)})
205-
// expected-error@-1{{cannot convert value of type '(_) -> Int' to expected argument type '() -> Int'}}
206+
// expected-error@-1{{contextual closure type '() -> Int' expects 0 arguments, but 1 were used in closure body}}
206207
// FIXME: expected-error@-2{{closure use of non-escaping parameter 'ac1' may allow it to escape}}
207208
}
208209

@@ -283,13 +284,6 @@ func rdar21078316() {
283284
bar = foo.map { ($0, $1) } // expected-error {{contextual closure type '([String : String]) -> [(String, String)]' expects 1 argument, but 2 were used in closure body}}
284285
}
285286

286-
287-
// <rdar://problem/20978044> QoI: Poor diagnostic when using an incorrect tuple element in a closure
288-
var numbers = [1, 2, 3]
289-
zip(numbers, numbers).filter { $0.2 > 1 } // expected-error {{value of tuple type '(Int, Int)' has no member '2'}}
290-
291-
292-
293287
// <rdar://problem/20868864> QoI: Cannot invoke 'function' with an argument list of type 'type'
294288
func foo20868864(_ callback: ([String]) -> ()) { }
295289
func rdar20868864(_ s: String) {

test/Constraints/tuple.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ extension r25271859 {
192192
}
193193

194194
func f(a : r25271859<(Float, Int)>) {
195-
a.map { $0.0 }
195+
a.map { f, _ in f }
196196
.andThen { _ in // expected-error {{unable to infer complex closure return type; add explicit type to disambiguate}} {{18-18=-> r25271859<String> }}
197197
print("hello") // comment this out and it runs, leave any form of print in and it doesn't
198198
return r25271859<String>()

test/DebugInfo/WeakCapture.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ func function() {
1515
// CHECK: call void @llvm.dbg.{{.*}}(metadata %swift.weak*
1616
// CHECK-NOT: metadata [[B]]
1717
// CHECK: call
18-
A(handler: { [weak b] _ in
18+
A(handler: { [weak b] in
1919
if b != nil { }
2020
})
2121
}

test/DebugInfo/mangling.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,5 @@ var myTuple3 : ( String, Int64) = ("C", 3)
3939

4040
markUsed(myTuple1.Id)
4141
markUsed(myTuple2.Id)
42-
markUsed({ $0.1 }(myTuple3))
42+
func f(_ a: (String, Int64)) {}
43+
markUsed(f(myTuple3))

test/Interpreter/collection_casts.swift

+6-6
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ print("Dictionaries.")
8181

8282
let a_dict = ["one" : A(1), "two" : A(2), "three" : A(3)]
8383
print("begin")
84-
a_dict.forEach { $0.1.preen() }
84+
a_dict.forEach { $1.preen() }
8585
print("end")
8686
// CHECK-NEXT: begin
8787
// CHECK-DAG: A1
@@ -91,7 +91,7 @@ print("end")
9191

9292
let preening_dict_1 = a_dict as [String: Preening]
9393
print("begin")
94-
preening_dict_1.forEach { $0.1.preen() }
94+
preening_dict_1.forEach { $1.preen() }
9595
print("end")
9696
// CHECK-NEXT: begin
9797
// CHECK-DAG: A1
@@ -105,7 +105,7 @@ print(any_dict_1.count)
105105

106106
let preening_dict_2 = any_dict_1 as! [String: Preening]
107107
print("begin")
108-
preening_dict_2.forEach { $0.1.preen() }
108+
preening_dict_2.forEach { $1.preen() }
109109
print("end")
110110
// CHECK-NEXT: begin
111111
// CHECK-DAG: A1
@@ -115,7 +115,7 @@ print("end")
115115

116116
let preening_dict_3 = any_dict_1 as? [String: Preening]
117117
print("begin")
118-
preening_dict_3?.forEach { $0.1.preen() }
118+
preening_dict_3?.forEach { $1.preen() }
119119
print("end")
120120
// CHECK-NEXT: begin
121121
// CHECK-DAG: A1
@@ -125,7 +125,7 @@ print("end")
125125

126126
let a_dict_2 = any_dict_1 as! [String: A]
127127
print("begin")
128-
a_dict_2.forEach { $0.1.preen() }
128+
a_dict_2.forEach { $1.preen() }
129129
print("end")
130130
// CHECK-NEXT: begin
131131
// CHECK-DAG: A1
@@ -135,7 +135,7 @@ print("end")
135135

136136
let a_dict_3 = any_dict_1 as? [String: A]
137137
print("begin")
138-
a_dict_3?.forEach { $0.1.preen() }
138+
a_dict_3?.forEach { $1.preen() }
139139
print("end")
140140
// CHECK-NEXT: begin
141141
// CHECK-DAG: A1

test/Prototypes/Result.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,8 @@ func mayFail(_ fail: Bool) throws -> Int {
138138
print(catchResult { try mayFail(true) })
139139
print(catchResult { try mayFail(false) })
140140

141-
print(catchResult { _ in 1 }.flatMap { _ in Result(success: 4) }.flatMap { _ in Result<String>(error: Icky.Poor) })
142-
print(catchResult { _ in 1 }.map { _ in three }.flatMap {$0} )
141+
print(catchResult { 1 }.flatMap { _ in Result(success: 4) }.flatMap { _ in Result<String>(error: Icky.Poor) })
142+
print(catchResult { 1 }.map { _ in three }.flatMap {$0} )
143143

144144
let results = [three, nasty, four]
145145
print(results.flatMap { $0.success })

test/SILGen/apply_abstraction_nested.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ infix operator ~> { precedence 255 associativity left }
44

55
protocol P { }
66

7-
func bar<T:P>(_: inout T) -> () -> () { return {_ in ()} }
8-
func baz<T:P>(_: inout T) -> (Int) -> () { return {_ in ()} }
7+
func bar<T:P>(_: inout T) -> () -> () { return { } }
8+
func baz<T:P>(_: inout T) -> (Int) -> () { return { _ in } }
99

1010
func ~> <T: P, Args, Result>(
1111
x: inout T,

test/SILGen/closures.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -590,5 +590,5 @@ class GenericDerived<Ocean> : ConcreteBase {
590590
// Don't crash on this
591591
func r25993258_helper(_ fn: (inout Int, Int) -> ()) {}
592592
func r25993258() {
593-
r25993258_helper { _ in () }
593+
r25993258_helper { _, _ in () }
594594
}

0 commit comments

Comments
 (0)