Skip to content

Commit caa9d67

Browse files
committed
[noescape by default] Emit deprecation warning/fixit for @NoEscape
@NoEscape is now the default behavior, so deprecate it and offer a fixit.
1 parent 49e0685 commit caa9d67

File tree

7 files changed

+44
-32
lines changed

7 files changed

+44
-32
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@ Note: This is in reverse chronological order, so newer entries are added to the
22

33
Swift 3.0
44
---------
5+
6+
* [SE-103](https://github.com/apple/swift-evolution/blob/master/proposals/0103-make-noescape-default.md)
7+
8+
Closure parameters are non-escaping by default, rather than explicitly being
9+
annotated @noescape. Use @escaping to say that a closure parameter may escape.
10+
@autoclosure(escaping) is now spelled @autoclosure @escaping. @noescape and
11+
@autoclosure(escaping) are deprecated.
12+
513
* [SE-0115](https://github.com/apple/swift-evolution/blob/master/proposals/0115-literal-syntax-protocols.md)
614

715
To clarify the role of `*LiteralConvertible` protocols, they have

include/swift/AST/DiagnosticsParse.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1219,7 +1219,7 @@ WARNING(attr_autoclosure_escaping_deprecated,none,
12191219
"@autoclosure(escaping) is deprecated; use @autoclosure @escaping instead",
12201220
())
12211221
WARNING(attr_noescape_deprecated,none,
1222-
"@noescape is the default and is deprecated; omit it",
1222+
"@noescape is the default and is deprecated",
12231223
())
12241224

12251225
// convention

lib/AST/ASTDumper.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2910,7 +2910,6 @@ namespace {
29102910
printFlag(T->isAutoClosure(), "autoclosure");
29112911

29122912
// Dump out either @noescape or @escaping
2913-
printFlag(T->isNoEscape(), "@noescape");
29142913
printFlag(!T->isNoEscape(), "@escaping");
29152914

29162915
printFlag(T->throws(), "throws");

lib/Parse/ParseDecl.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1542,6 +1542,11 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, bool justChecking) {
15421542
diagnose(Loc, diag::attr_escaping_conflicts_noescape);
15431543
return false;
15441544
}
1545+
1546+
// @noescape is deprecated and no longer used
1547+
diagnose(Loc, diag::attr_noescape_deprecated)
1548+
.fixItRemove({Attributes.AtLoc,Loc});
1549+
15451550
break;
15461551
case TAK_escaping:
15471552
// You can't specify @noescape and @escaping together.

test/attr/attr_availability.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -704,7 +704,7 @@ func closure_LU_LL(x: Int, _ y: () -> Int) {} // expected-note 2 {{here}}
704704
@available(*, unavailable, renamed: "after(arg:fn:)")
705705
func closure_LL_LL(x: Int, y: () -> Int) {} // expected-note 2 {{here}}
706706
@available(*, unavailable, renamed: "after(arg:fn:)")
707-
func closure_UU_LL_ne(_ x: Int, _ y: @noescape () -> Int) {} // expected-note 2 {{here}}
707+
func closure_UU_LL_ne(_ x: Int, _ y: () -> Int) {} // expected-note 2 {{here}}
708708

709709
@available(*, unavailable, renamed: "after(arg:_:)")
710710
func closure_UU_LU(_ x: Int, _ closure: () -> Int) {} // expected-note 2 {{here}}
@@ -713,7 +713,7 @@ func closure_LU_LU(x: Int, _ closure: () -> Int) {} // expected-note 2 {{here}}
713713
@available(*, unavailable, renamed: "after(arg:_:)")
714714
func closure_LL_LU(x: Int, y: () -> Int) {} // expected-note 2 {{here}}
715715
@available(*, unavailable, renamed: "after(arg:_:)")
716-
func closure_UU_LU_ne(_ x: Int, _ y: @noescape () -> Int) {} // expected-note 2 {{here}}
716+
func closure_UU_LU_ne(_ x: Int, _ y: () -> Int) {} // expected-note 2 {{here}}
717717

718718
func testTrailingClosure() {
719719
closure_U_L { 0 } // expected-error {{'closure_U_L' has been renamed to 'after(fn:)'}} {{3-14=after}} {{none}}

test/attr/attr_escaping.swift

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
func wrongParamType(a: @escaping Int) {} // expected-error {{@escaping attribute only applies to function types}}
66

77
func conflictingAttrs(_ fn: @noescape @escaping () -> Int) {} // expected-error {{@escaping conflicts with @noescape}}
8+
// expected-warning@-1{{@noescape is the default and is deprecated}} {{29-39=}}
89

910
func takesEscaping(_ fn: @escaping () -> Int) {} // ok
1011

@@ -69,15 +70,4 @@ func callEscapingAutoclosureWithNoEscape_3(_ fn: @autoclosure () -> Int) {
6970
takesEscapingAutoclosure(fn()) // expected-error{{closure use of non-escaping parameter 'fn' may allow it to escape}}
7071
}
7172

72-
func takesAutoclosure(_ fn: @autoclosure () -> Int) {}
73-
74-
func callAutoclosureWithNoEscape(_ fn: () -> Int) {
75-
takesAutoclosure(1+1) // ok
76-
}
77-
func callAutoclosureWithNoEscape_2(_ fn: () -> Int) {
78-
takesAutoclosure(fn()) // ok
79-
}
80-
func callAutoclosureWithNoEscape_3(_ fn: @autoclosure () -> Int) {
81-
takesAutoclosure(fn()) // ok
82-
}
8373

test/attr/attr_noescape.swift

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
@noescape var fn : () -> Int = { 4 } // expected-error {{@noescape may only be used on 'parameter' declarations}} {{1-11=}}
44

55
func conflictingAttrs(_ fn: @noescape @escaping () -> Int) {} // expected-error {{@escaping conflicts with @noescape}}
6+
// expected-warning@-1{{@noescape is the default and is deprecated}} {{29-39=}}
67

78
func doesEscape(_ fn : @escaping () -> Int) {}
89

9-
func takesGenericClosure<T>(_ a : Int, _ fn : @noescape () -> T) {}
10+
func takesGenericClosure<T>(_ a : Int, _ fn : @noescape () -> T) {} // expected-warning{{@noescape is the default and is deprecated}} {{47-57=}}
1011

1112

1213
func takesNoEscapeClosure(_ fn : () -> Int) {
@@ -161,9 +162,9 @@ class SomeClass {
161162

162163

163164
// Implicit conversions (in this case to @convention(block)) are ok.
164-
@_silgen_name("whatever")
165-
func takeNoEscapeAsObjCBlock(_: @noescape @convention(block) () -> Void)
166-
func takeNoEscapeTest2(_ fn : @noescape () -> ()) {
165+
@_silgen_name("whatever")
166+
func takeNoEscapeAsObjCBlock(_: @noescape @convention(block) () -> Void) // expected-warning{{@noescape is the default and is deprecated}} {{33-43=}}
167+
func takeNoEscapeTest2(_ fn : @noescape () -> ()) { // expected-warning{{@noescape is the default and is deprecated}} {{31-41=}}
167168
takeNoEscapeAsObjCBlock(fn)
168169
}
169170

@@ -177,6 +178,7 @@ func testAutoclosure(_ a : @autoclosure () -> Int) { // expected-note{{parameter
177178
// <rdar://problem/19470858> QoI: @autoclosure implies @noescape, so you shouldn't be allowed to specify both
178179
func redundant(_ fn : @noescape // expected-error @+1 {{@noescape is implied by @autoclosure and should not be redundantly specified}}
179180
@autoclosure () -> Int) {
181+
// expected-warning@-2{{@noescape is the default and is deprecated}} {{23-33=}}
180182
}
181183

182184

@@ -193,7 +195,7 @@ func overloadedEach<P: P2, T>(_ source: P, _ transform: @escaping (P.Element) ->
193195

194196
struct S : P2 {
195197
typealias Element = Int
196-
func each(_ transform: @noescape (Int) -> ()) {
198+
func each(_ transform: @noescape (Int) -> ()) { // expected-warning{{@noescape is the default and is deprecated}} {{26-36=}}
197199
overloadedEach(self, // expected-error {{cannot invoke 'overloadedEach' with an argument list of type '(S, (Int) -> (), Int)'}}
198200
transform, 1)
199201
// expected-note @-2 {{overloads for 'overloadedEach' exist with these partially matching parameter lists: (O, (O.Element) -> (), T), (P, (P.Element) -> (), T)}}
@@ -203,17 +205,18 @@ struct S : P2 {
203205

204206

205207
// rdar://19763676 - False positive in @noescape analysis triggered by parameter label
206-
func r19763676Callee(_ f: @noescape (_ param: Int) -> Int) {}
208+
func r19763676Callee(_ f: @noescape (_ param: Int) -> Int) {} // expected-warning{{@noescape is the default and is deprecated}} {{27-37=}}
207209

208-
func r19763676Caller(_ g: @noescape (Int) -> Int) {
210+
func r19763676Caller(_ g: @noescape (Int) -> Int) { // expected-warning{{@noescape is the default and is deprecated}} {{27-37=}}
209211
r19763676Callee({ _ in g(1) })
210212
}
211213

212214

213215
// <rdar://problem/19763732> False positive in @noescape analysis triggered by default arguments
214216
func calleeWithDefaultParameters(_ f: @noescape () -> (), x : Int = 1) {} // expected-warning {{closure parameter prior to parameters with default arguments will not be treated as a trailing closure}}
217+
// expected-warning@-1{{@noescape is the default and is deprecated}} {{39-49=}}
215218

216-
func callerOfDefaultParams(_ g: @noescape () -> ()) {
219+
func callerOfDefaultParams(_ g: @noescape () -> ()) { // expected-warning{{@noescape is the default and is deprecated}} {{33-43=}}
217220
calleeWithDefaultParameters(g)
218221
}
219222

@@ -241,20 +244,20 @@ public func XCTAssert(_ expression: @autoclosure () -> Bool, _ message: String =
241244

242245

243246
/// SR-770 - Currying and `noescape`/`rethrows` don't work together anymore
244-
func curriedFlatMap<A, B>(_ x: [A]) -> (@noescape (A) -> [B]) -> [B] {
247+
func curriedFlatMap<A, B>(_ x: [A]) -> (@noescape (A) -> [B]) -> [B] { // expected-warning{{@noescape is the default and is deprecated}} {{41-50=}}
245248
return { f in
246249
x.flatMap(f)
247250
}
248251
}
249252

250-
func curriedFlatMap2<A, B>(_ x: [A]) -> (@noescape (A) -> [B]) -> [B] {
251-
return { (f : @noescape (A) -> [B]) in
253+
func curriedFlatMap2<A, B>(_ x: [A]) -> (@noescape (A) -> [B]) -> [B] { // expected-warning{{@noescape is the default and is deprecated}} {{42-51=}}
254+
return { (f : @noescape (A) -> [B]) in // expected-warning{{@noescape is the default and is deprecated}} {{17-27=}}
252255
x.flatMap(f)
253256
}
254257
}
255258

256259
func bad(_ a : @escaping (Int)-> Int) -> Int { return 42 }
257-
func escapeNoEscapeResult(_ x: [Int]) -> (@noescape (Int) -> Int) -> Int {
260+
func escapeNoEscapeResult(_ x: [Int]) -> (@noescape (Int) -> Int) -> Int { // expected-warning{{@noescape is the default and is deprecated}} {{43-52=}}
258261
return { f in // expected-note{{parameter 'f' is implicitly non-escaping}}
259262
bad(f) // expected-error {{passing non-escaping parameter 'f' to function expecting an @escaping closure}}
260263
}
@@ -263,7 +266,7 @@ func escapeNoEscapeResult(_ x: [Int]) -> (@noescape (Int) -> Int) -> Int {
263266

264267
// SR-824 - @noescape for Type Aliased Closures
265268
//
266-
typealias CompletionHandlerNE = @noescape (_ success: Bool) -> ()
269+
typealias CompletionHandlerNE = @noescape (_ success: Bool) -> () // expected-warning{{@noescape is the default and is deprecated}} {{33-43=}}
267270
typealias CompletionHandler = (_ success: Bool) -> ()
268271
var escape : CompletionHandlerNE
269272
func doThing1(_ completion: (_ success: Bool) -> ()) {
@@ -280,7 +283,10 @@ func doThing2(_ completion: CompletionHandlerNE) {
280283
}
281284

282285
// <rdar://problem/19997680> @noescape doesn't work on parameters of function type
283-
func apply<T, U>(_ f: @noescape (T) -> U, g: @noescape (@noescape (T) -> U) -> U) -> U {
286+
func apply<T, U>(_ f: @noescape (T) -> U, g: @noescape (@noescape (T) -> U) -> U) -> U {
287+
// expected-warning@-1{{@noescape is the default and is deprecated}} {{23-33=}}
288+
// expected-warning@-2{{@noescape is the default and is deprecated}} {{46-56=}}
289+
// expected-warning@-3{{@noescape is the default and is deprecated}} {{57-66=}}
284290
return g(f)
285291
}
286292

@@ -290,8 +296,8 @@ enum r19997577Type {
290296
case Function(() -> r19997577Type, () -> r19997577Type)
291297
case Sum(() -> r19997577Type, () -> r19997577Type)
292298

293-
func reduce<Result>(_ initial: Result, _ combine: @noescape (Result, r19997577Type) -> Result) -> Result {
294-
let binary: @noescape (r19997577Type, r19997577Type) -> Result = { combine(combine(combine(initial, self), $0), $1) }
299+
func reduce<Result>(_ initial: Result, _ combine: @noescape (Result, r19997577Type) -> Result) -> Result { // expected-warning{{@noescape is the default and is deprecated}} {{53-63=}}
300+
let binary: @noescape (r19997577Type, r19997577Type) -> Result = { combine(combine(combine(initial, self), $0), $1) } // expected-warning{{@noescape is the default and is deprecated}} {{17-27=}}
295301
switch self {
296302
case .Unit:
297303
return combine(initial, self)
@@ -305,9 +311,13 @@ enum r19997577Type {
305311

306312
// type attribute and decl attribute
307313
func noescapeD(@noescape f: @escaping () -> Bool) {} // expected-error {{@noescape is now an attribute on a parameter type, instead of on the parameter itself}} {{16-25=}} {{29-29=@noescape }}
308-
func noescapeT(f: @noescape () -> Bool) {} // ok
314+
func noescapeT(f: @noescape () -> Bool) {} // expected-warning{{@noescape is the default and is deprecated}} {{19-29=}}
309315
func autoclosureD(@autoclosure f: () -> Bool) {} // expected-error {{@autoclosure is now an attribute on a parameter type, instead of on the parameter itself}} {{19-31=}} {{35-35=@autoclosure }}
310316
func autoclosureT(f: @autoclosure () -> Bool) {} // ok
311317

312318
func noescapeD_noescapeT(@noescape f: @noescape () -> Bool) {} // expected-error {{@noescape is now an attribute on a parameter type, instead of on the parameter itself}}
319+
// expected-warning@-1{{@noescape is the default and is deprecated}} {{39-49=}}
320+
313321
func autoclosureD_noescapeT(@autoclosure f: @noescape () -> Bool) {} // expected-error {{@autoclosure is now an attribute on a parameter type, instead of on the parameter itself}} {{29-41=}} {{45-45=@autoclosure }}
322+
// expected-warning@-1{{@noescape is the default and is deprecated}} {{45-55=}}
323+

0 commit comments

Comments
 (0)