Skip to content

Commit fa7e628

Browse files
committed
prevent nonescaping closures from being consuming
While these types are also considered Copyable, thus they're also temporarily banned from being `consiming`, SE-377 specifically calls out these kinds of closures as not ever supporting consuming. rdar://108388132
1 parent 2fc5031 commit fa7e628

File tree

3 files changed

+35
-14
lines changed

3 files changed

+35
-14
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7124,6 +7124,8 @@ ERROR(ownership_specifier_copyable,none,
71247124
ERROR(self_ownership_specifier_copyable,none,
71257125
"%0 is not yet valid on %1s in a Copyable type",
71267126
(SelfAccessKind, DescriptiveDeclKind))
7127+
ERROR(ownership_specifier_illegal_nonscape_closure,none,
7128+
"nonescaping closure %0 cannot be '%1'", (Type, StringRef))
71277129

71287130
//------------------------------------------------------------------------------
71297131
// MARK: Runtime discoverable attributes (@runtimeMetadata)

lib/Sema/TypeCheckType.cpp

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4284,20 +4284,32 @@ TypeResolver::resolveOwnershipTypeRepr(OwnershipTypeRepr *repr,
42844284
if (result->hasError())
42854285
return result;
42864286

4287-
// Unless we have the experimental no-implicit-copy feature enabled, Copyable
4288-
// types can't use 'consuming' or 'borrowing' ownership specifiers.
4289-
if (!getASTContext().LangOpts.hasFeature(Feature::NoImplicitCopy)) {
4290-
if (!result->isPureMoveOnly()) {
4291-
// Prevent copyable types from using the non-underscored ownership parameter
4292-
// specifiers, other than 'inout'.
4293-
switch (ownershipRepr->getSpecifier()) {
4294-
case ParamSpecifier::Default:
4295-
case ParamSpecifier::InOut:
4296-
case ParamSpecifier::LegacyShared:
4297-
case ParamSpecifier::LegacyOwned:break;
4298-
4299-
case ParamSpecifier::Borrowing:
4300-
case ParamSpecifier::Consuming:
4287+
// Check for illegal combinations of ownership specifiers and types.
4288+
switch (ownershipRepr->getSpecifier()) {
4289+
case ParamSpecifier::Default:
4290+
case ParamSpecifier::InOut:
4291+
case ParamSpecifier::LegacyShared:
4292+
case ParamSpecifier::LegacyOwned:
4293+
break;
4294+
4295+
case ParamSpecifier::Consuming:
4296+
// consuming cannot be applied to parameters of nonescaping closure type,
4297+
// which by their nature are always borrowed
4298+
if (auto fnTy = result->getAs<AnyFunctionType>()) {
4299+
if (fnTy->isNoEscape()) {
4300+
diagnoseInvalid(ownershipRepr,
4301+
ownershipRepr->getLoc(),
4302+
diag::ownership_specifier_illegal_nonscape_closure,
4303+
result, ownershipRepr->getSpecifierSpelling());
4304+
return ErrorType::get(getASTContext());
4305+
}
4306+
}
4307+
SWIFT_FALLTHROUGH;
4308+
case ParamSpecifier::Borrowing:
4309+
// Unless we have the experimental no-implicit-copy feature enabled,
4310+
// Copyable types can't use 'consuming' or 'borrowing' ownership specifiers.
4311+
if (!getASTContext().LangOpts.hasFeature(Feature::NoImplicitCopy)) {
4312+
if (!result->isPureMoveOnly()) {
43014313
diagnoseInvalid(ownershipRepr,
43024314
ownershipRepr->getLoc(),
43034315
diag::ownership_specifier_copyable);

test/Parse/ownership_modifiers.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,10 @@ enum Exercising {
101101
__consuming get { 0 }
102102
}
103103
}
104+
105+
// you cannot own a nonescaping function.
106+
func f(_ g: consuming () -> ()) {} // expected-error {{nonescaping closure '() -> ()' cannot be 'consuming'}}
107+
108+
// otherwise, functions are copyable
109+
func h(_ g: borrowing () -> ()) {} // expected-error {{Copyable types cannot be 'consuming' or 'borrowing' yet}}
110+
func j(_ g: consuming @escaping () -> ()) {} // expected-error {{Copyable types cannot be 'consuming' or 'borrowing' yet}}

0 commit comments

Comments
 (0)