Skip to content

noescape by default: deprecate @noescape and @autoclosure(escaping) #4031

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Aug 5, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ Note: This is in reverse chronological order, so newer entries are added to the

Swift 3.0
---------

* [SE-103](https://github.com/apple/swift-evolution/blob/master/proposals/0103-make-noescape-default.md)

Closure parameters are non-escaping by default, rather than explicitly being
Copy link
Contributor

@slavapestov slavapestov Aug 5, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bits of code in the changelog should be surrounded by backticks (`)

annotated `@noescape`. Use `@escaping` to say that a closure parameter may
escape. `@autoclosure(escaping)` is now spelled `@autoclosure @escaping`.
`@noescape` and `@autoclosure(escaping)` are deprecated.

* [SE-0115](https://github.com/apple/swift-evolution/blob/master/proposals/0115-literal-syntax-protocols.md)

To clarify the role of `*LiteralConvertible` protocols, they have
Expand Down
6 changes: 6 additions & 0 deletions include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -1215,6 +1215,12 @@ ERROR(attr_noescape_conflicts_escaping_autoclosure,none,
ERROR(attr_noescape_implied_by_autoclosure,none,
"@noescape is implied by @autoclosure and should not be "
"redundantly specified", ())
WARNING(attr_autoclosure_escaping_deprecated,none,
"@autoclosure(escaping) is deprecated; use @autoclosure @escaping instead",
())
WARNING(attr_noescape_deprecated,none,
"@noescape is the default and is deprecated",
())

// convention
ERROR(convention_attribute_expected_lparen,none,
Expand Down
2 changes: 1 addition & 1 deletion include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -2239,7 +2239,7 @@ ERROR(closure_implicit_capture_mutating_self,none,
())
ERROR(nested_function_with_implicit_capture_argument,none,
"nested function with %select{an |}0implicitly captured inout "
"parameter%select{|s}0 can only be used as a @noescape argument", (bool))
"parameter%select{|s}0 can only be used as a non-escaping argument", (bool))
ERROR(nested_function_escaping_inout_capture,none,
"nested function cannot capture inout parameter and escape", ())

Expand Down
1 change: 0 additions & 1 deletion lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2910,7 +2910,6 @@ namespace {
printFlag(T->isAutoClosure(), "autoclosure");

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

printFlag(T->throws(), "throws");
Expand Down
15 changes: 5 additions & 10 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3742,16 +3742,11 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
void printFunctionExtInfo(AnyFunctionType::ExtInfo info) {
if (Options.SkipAttributes)
return;
if (info.isAutoClosure()) {
if (info.isNoEscape())
Printer << "@autoclosure ";
else
Printer << "@autoclosure(escaping) ";
} else if (inParameterPrinting) {
if (!info.isNoEscape()) {
Printer << "@escaping ";
}
}

if (info.isAutoClosure())
Printer << "@autoclosure ";
if (inParameterPrinting && !info.isNoEscape())
Printer << "@escaping ";

if (Options.PrintFunctionRepresentationAttrs) {
// TODO: coalesce into a single convention attribute.
Expand Down
10 changes: 3 additions & 7 deletions lib/AST/TypeRepr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,13 +276,9 @@ void AttributedTypeRepr::printAttrs(llvm::raw_ostream &OS) const {
void AttributedTypeRepr::printAttrs(ASTPrinter &Printer) const {
const TypeAttributes &Attrs = getAttrs();

switch (Attrs.has(TAK_autoclosure)*2 + Attrs.has(TAK_noescape)) {
case 0: break; // Nothing specified.
case 1: Printer << "@noescape "; break;
case 2: Printer << "@autoclosure(escaping) "; break;
case 3: Printer << "@autoclosure "; break;
}
if (Attrs.has(TAK_escaping)) Printer << "@escaping ";
if (Attrs.has(TAK_autoclosure)) Printer << "@autoclosure ";
if (Attrs.has(TAK_escaping)) Printer << "@escaping ";

if (Attrs.has(TAK_thin)) Printer << "@thin ";
if (Attrs.has(TAK_thick)) Printer << "@thick ";
if (Attrs.convention.hasValue()) {
Expand Down
5 changes: 4 additions & 1 deletion lib/FrontendTool/FrontendTool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -629,8 +629,11 @@ class JSONFixitWriter : public DiagnosticConsumer {
Info.ID == diag::noescape_autoclosure.ID ||
Info.ID == diag::where_inside_brackets.ID ||
Info.ID == diag::selector_construction_suggest.ID ||
Info.ID == diag::selector_literal_deprecated_suggest.ID)
Info.ID == diag::selector_literal_deprecated_suggest.ID ||
Info.ID == diag::attr_noescape_deprecated.ID ||
Info.ID == diag::attr_autoclosure_escaping_deprecated.ID)
return true;

return false;
}

Expand Down
33 changes: 21 additions & 12 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1444,6 +1444,7 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, bool justChecking) {
SourceLoc Loc = consumeToken();

bool isAutoclosureEscaping = false;
SourceLoc autoclosureEscapingRightParenLoc;
StringRef conventionName;

// Handle @autoclosure(escaping)
Expand All @@ -1463,7 +1464,7 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, bool justChecking) {
if (isAutoclosureEscaping) {
consumeToken(tok::l_paren);
consumeToken(tok::identifier);
consumeToken(tok::r_paren);
autoclosureEscapingRightParenLoc = consumeToken(tok::r_paren);
}
} else if (attr == TAK_convention) {
SourceLoc LPLoc;
Expand Down Expand Up @@ -1512,27 +1513,35 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, bool justChecking) {
// Handle @autoclosure(escaping)
if (isAutoclosureEscaping) {
// @noescape @autoclosure(escaping) makes no sense.
if (Attributes.has(TAK_noescape))
if (Attributes.has(TAK_noescape)) {
diagnose(Loc, diag::attr_noescape_conflicts_escaping_autoclosure);
} else {
if (Attributes.has(TAK_noescape))
diagnose(Loc, diag::attr_noescape_implied_by_autoclosure);
Attributes.setAttr(TAK_noescape, Loc);
} else {
diagnose(Loc, diag::attr_autoclosure_escaping_deprecated)
.fixItReplace({Loc, autoclosureEscapingRightParenLoc},
"@autoclosure @escaping ");
}
Attributes.setAttr(TAK_escaping, Loc);
} else if (Attributes.has(TAK_noescape)) {
diagnose(Loc, diag::attr_noescape_implied_by_autoclosure);
}
break;

case TAK_noescape:
// You can't specify @noescape and @autoclosure(escaping) together, and
// @noescape after @autoclosure is redundant.
if (Attributes.has(TAK_autoclosure)) {
diagnose(Loc, diag::attr_noescape_conflicts_escaping_autoclosure);
return false;
}
// You can't specify @noescape and @escaping together.
if (Attributes.has(TAK_escaping)) {
diagnose(Loc, diag::attr_escaping_conflicts_noescape);
return false;
}

// @noescape after @autoclosure is redundant.
if (Attributes.has(TAK_autoclosure)) {
diagnose(Loc, diag::attr_noescape_implied_by_autoclosure);
}

// @noescape is deprecated and no longer used
diagnose(Loc, diag::attr_noescape_deprecated)
.fixItRemove({Attributes.AtLoc,Loc});

break;
case TAK_escaping:
// You can't specify @noescape and @escaping together.
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/TypeCheckAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1609,7 +1609,7 @@ void TypeChecker::checkAutoClosureAttr(ParamDecl *PD, AutoClosureAttr *attr) {
return;

// This decl attribute has been moved to being a type attribute.
auto text = attr->isEscaping() ? "@autoclosure(escaping) " : "@autoclosure ";
auto text = attr->isEscaping() ? "@autoclosure @escaping " : "@autoclosure ";
diagnose(attr->getLocation(), diag::attr_decl_attr_now_on_type,
"@autoclosure")
.fixItRemove(attr->getRangeWithAt())
Expand Down
16 changes: 7 additions & 9 deletions lib/Sema/TypeCheckType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1889,15 +1889,13 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
}

bool defaultNoEscape = false;
// TODO: Get rid of the need for checking autoclosure, by refactoring
// special autoclosure knowledge to just as "isEscaping" or similar.
if (isFunctionParam && !attrs.has(TAK_autoclosure)) {
// Closure params default to non-escaping
if (attrs.has(TAK_noescape)) {
// FIXME: diagnostic to tell user this is redundant and drop it
} else if (!attrs.has(TAK_escaping)) {
defaultNoEscape = isDefaultNoEscapeContext(DC);
}
if (isFunctionParam && !attrs.has(TAK_escaping)) {
defaultNoEscape = isDefaultNoEscapeContext(DC);
}

if (isFunctionParam && attrs.has(TAK_noescape) &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this FIXME still relevant now that @NoEscape itself is deprecated?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The FIXME is handled in the parser itself when it encounters @autoclosure.

isDefaultNoEscapeContext(DC)) {
// FIXME: diagnostic to tell user this is redundant and drop it
}

// Resolve the function type directly with these attributes.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public func withInvalidOrderings(_ body: (@escaping (Int, Int) -> Bool) -> Void)

internal func _mapInPlace<C : MutableCollection>(
_ elements: inout C,
_ transform: @noescape (C.Iterator.Element) -> C.Iterator.Element
_ transform: (C.Iterator.Element) -> C.Iterator.Element
) where C.Indices.Iterator.Element == C.Index {
for i in elements.indices {
elements[i] = transform(elements[i])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,28 +224,28 @@ public struct ${Self}<
}

public func map<T>(
_ transform: @noescape (Base.Iterator.Element) throws -> T
_ transform: (Base.Iterator.Element) throws -> T
) rethrows -> [T] {
Log.map[selfType] += 1
return try base.map(transform)
}

public func filter(
_ isIncluded: @noescape (Base.Iterator.Element) throws -> Bool
_ isIncluded: (Base.Iterator.Element) throws -> Bool
) rethrows -> [Base.Iterator.Element] {
Log.filter[selfType] += 1
return try base.filter(isIncluded)
}

public func forEach(
_ body: @noescape (Base.Iterator.Element) throws -> Void
_ body: (Base.Iterator.Element) throws -> Void
) rethrows {
Log.forEach[selfType] += 1
try base.forEach(body)
}

public func first(
where predicate: @noescape (Base.Iterator.Element) throws -> Bool
where predicate: (Base.Iterator.Element) throws -> Bool
) rethrows -> Base.Iterator.Element? {
Log.first[selfType] += 1
return try base.first(where: predicate)
Expand Down Expand Up @@ -276,7 +276,7 @@ public struct ${Self}<
public func split(
maxSplits: Int = Int.max,
omittingEmptySubsequences: Bool = true,
whereSeparator isSeparator: @noescape (Base.Iterator.Element) throws -> Bool
whereSeparator isSeparator: (Base.Iterator.Element) throws -> Bool
) rethrows -> [SubSequence] {
Log.split[selfType] += 1
return try base.split(
Expand All @@ -296,7 +296,7 @@ public struct ${Self}<
/// `preprocess` on `self` and return its result. Otherwise, return
/// `nil`.
public func _preprocessingPass<R>(
_ preprocess: @noescape () throws -> R
_ preprocess: () throws -> R
) rethrows -> R? {
Log._preprocessingPass[selfType] += 1
return try base._preprocessingPass(preprocess)
Expand Down Expand Up @@ -443,14 +443,14 @@ public struct ${Self}<

% if Kind == 'MutableCollection':
public mutating func partition(
by belongsInSecondPartition: @noescape (Iterator.Element) throws -> Bool
by belongsInSecondPartition: (Iterator.Element) throws -> Bool
) rethrows -> Index {
Log.partitionBy[selfType] += 1
return try base.partition(by: belongsInSecondPartition)
}

public mutating func _withUnsafeMutableBufferPointerIfSupported<R>(
_ body: @noescape (UnsafeMutablePointer<Iterator.Element>, Int) throws -> R
_ body: (UnsafeMutablePointer<Iterator.Element>, Int) throws -> R
) rethrows -> R? {
Log._withUnsafeMutableBufferPointerIfSupported[selfType] += 1
let result = try base._withUnsafeMutableBufferPointerIfSupported(body)
Expand Down Expand Up @@ -650,7 +650,7 @@ public struct ${Self}<
}

public mutating func _withUnsafeMutableBufferPointerIfSupported<R>(
_ body: @noescape (UnsafeMutablePointer<Iterator.Element>, Int) throws -> R
_ body: (UnsafeMutablePointer<Iterator.Element>, Int) throws -> R
) rethrows -> R? {
Log._withUnsafeMutableBufferPointerIfSupported[selfType] += 1
let result = try base._withUnsafeMutableBufferPointerIfSupported(body)
Expand Down
2 changes: 1 addition & 1 deletion stdlib/private/StdlibUnittest/RaceTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ import Glibc
#if _runtime(_ObjC)
import ObjectiveC
#else
func autoreleasepool(invoking code: @noescape () -> Void) {
func autoreleasepool(invoking code: () -> Void) {
// Native runtime does not have autorelease pools. Execute the code
// directly.
code()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ extension NSLocale {

public func withOverriddenLocaleCurrentLocale<Result>(
_ temporaryLocale: NSLocale,
_ body: @noescape () -> Result
_ body: () -> Result
) -> Result {
let oldMethod = class_getClassMethod(
NSLocale.self, #selector(getter: NSLocale.current))
Expand All @@ -48,7 +48,7 @@ public func withOverriddenLocaleCurrentLocale<Result>(

public func withOverriddenLocaleCurrentLocale<Result>(
_ temporaryLocaleIdentifier: String,
_ body: @noescape () -> Result
_ body: () -> Result
) -> Result {
precondition(
NSLocale.availableLocaleIdentifiers.contains(temporaryLocaleIdentifier),
Expand All @@ -65,7 +65,7 @@ public func withOverriddenLocaleCurrentLocale<Result>(
/// return-autoreleased optimization.)
@inline(never)
public func autoreleasepoolIfUnoptimizedReturnAutoreleased(
invoking body: @noescape () -> Void
invoking body: () -> Void
) {
#if arch(i386) && (os(iOS) || os(watchOS))
autoreleasepool(invoking: body)
Expand Down
4 changes: 2 additions & 2 deletions stdlib/public/SDK/Dispatch/Block.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ public class DispatchWorkItem {
qos.qosClass.rawValue.rawValue, Int32(qos.relativePriority), block)
}

// Used by DispatchQueue.synchronously<T> to provide a @noescape path through
// Used by DispatchQueue.synchronously<T> to provide a path through
// dispatch_block_t, as we know the lifetime of the block in question.
internal init(flags: DispatchWorkItemFlags = [], noescapeBlock: @noescape () -> ()) {
internal init(flags: DispatchWorkItemFlags = [], noescapeBlock: () -> ()) {
_block = _swift_dispatch_block_create_noescape(flags.rawValue, noescapeBlock)
}

Expand Down
4 changes: 2 additions & 2 deletions stdlib/public/SDK/Dispatch/Data.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public struct DispatchData : RandomAccessCollection, _ObjectiveCBridgeable {
}

public func withUnsafeBytes<Result, ContentType>(
body: @noescape (UnsafePointer<ContentType>) throws -> Result) rethrows -> Result
body: (UnsafePointer<ContentType>) throws -> Result) rethrows -> Result
{
var ptr: UnsafeRawPointer? = nil
var size = 0
Expand All @@ -82,7 +82,7 @@ public struct DispatchData : RandomAccessCollection, _ObjectiveCBridgeable {
}

public func enumerateBytes(
block: @noescape (_ buffer: UnsafeBufferPointer<UInt8>, _ byteIndex: Int, _ stop: inout Bool) -> Void)
block: (_ buffer: UnsafeBufferPointer<UInt8>, _ byteIndex: Int, _ stop: inout Bool) -> Void)
{
_swift_dispatch_data_apply(__wrapped) { (_, offset: Int, ptr: UnsafeRawPointer, size: Int) in
let bytePtr = ptr.bindMemory(to: UInt8.self, capacity: size)
Expand Down
4 changes: 2 additions & 2 deletions stdlib/public/SDK/Dispatch/Private.swift
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ public func dispatch_io_set_interval(_ channel: DispatchIO, _ interval: UInt64,
}

@available(*, unavailable, renamed:"DispatchQueue.apply(attributes:iterations:execute:)")
public func dispatch_apply(_ iterations: Int, _ queue: DispatchQueue, _ block: @noescape (Int) -> Void)
public func dispatch_apply(_ iterations: Int, _ queue: DispatchQueue, _ block: (Int) -> Void)
{
fatalError()
}
Expand Down Expand Up @@ -205,7 +205,7 @@ public func dispatch_barrier_async(_ queue: DispatchQueue, _ block: () -> Void)
}

@available(*, unavailable, renamed:"DispatchQueue.sync(self:flags:execute:)")
public func dispatch_barrier_sync(_ queue: DispatchQueue, _ block: @noescape () -> Void)
public func dispatch_barrier_sync(_ queue: DispatchQueue, _ block: () -> Void)
{
fatalError()
}
Expand Down
Loading