Skip to content

Enable NonEscapable types by default and move lifetime dependence support under a new feature #77637

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 5 commits into from
Nov 19, 2024
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
1 change: 0 additions & 1 deletion Runtimes/Core/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,6 @@ target_compile_options(swiftCore PRIVATE
"$<$<COMPILE_LANGUAGE:Swift>:SHELL:-enable-experimental-feature SuppressedAssociatedTypes>"
"$<$<COMPILE_LANGUAGE:Swift>:SHELL:-enable-experimental-feature SE427NoInferenceOnExtension>"
"$<$<COMPILE_LANGUAGE:Swift>:SHELL:-enable-experimental-feature AllowUnsafeAttribute>"
"$<$<COMPILE_LANGUAGE:Swift>:SHELL:-enable-experimental-feature NonescapableTypes>"
"$<$<COMPILE_LANGUAGE:Swift>:SHELL:-enable-experimental-feature MemberImportVisibility>"
"$<$<COMPILE_LANGUAGE:Swift>:SHELL:-enable-experimental-feature TypedThrows>"
"$<$<COMPILE_LANGUAGE:Swift>:SHELL:-enable-experimental-feature Macros>"
Expand Down
10 changes: 4 additions & 6 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -7784,9 +7784,6 @@ NOTE(note_inverse_preventing_conformance,none,
NOTE(note_inverse_preventing_conformance_explicit,none,
"%kind0 has '~%1' constraint preventing '%1' conformance",
(const ValueDecl *, StringRef))
ERROR(escapable_requires_feature_flag,none,
"type 'Escapable' requires -enable-experimental-feature NonescapableTypes",
())
ERROR(non_bitwise_copyable_type_class,none,
"class cannot conform to 'BitwiseCopyable'", ())
ERROR(non_bitwise_copyable_type_indirect_enum,none,
Expand Down Expand Up @@ -7910,9 +7907,6 @@ ERROR(noncopyable_cannot_have_read_set_accessor,none,
"noncopyable %select{variable|subscript}0 cannot provide a read and set accessor",
(unsigned))

ERROR(nonescapable_types_attr_disabled,none,
"attribute requires '-enable-experimental-feature NonescapableTypes'", ())

ERROR(span_requires_feature_flag,none,
"'%0' requires -enable-experimental-feature Span",
(StringRef))
Expand Down Expand Up @@ -8031,6 +8025,10 @@ ERROR(lifetime_dependence_cannot_use_parsed_borrow_consuming, none,
ERROR(lifetime_dependence_duplicate_target, none,
"invalid duplicate target lifetime dependencies on function", ())

ERROR(lifetime_dependence_feature_required, none,
"returning ~Escapable type requires '-enable-experimental-feature "
"LifetimeDependence'", ())

//===----------------------------------------------------------------------===//
// MARK: Sending
//===----------------------------------------------------------------------===//
Expand Down
3 changes: 0 additions & 3 deletions include/swift/AST/PrintOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -397,9 +397,6 @@ struct PrintOptions {
/// Replace BitwiseCopyable with _BitwiseCopyable.
bool SuppressBitwiseCopyable = false;

/// Suppress ~Escapable types and lifetime dependence annotations
bool SuppressNonEscapableTypes = false;

/// Suppress modify/read accessors.
bool SuppressCoroutineAccessors = false;

Expand Down
6 changes: 3 additions & 3 deletions include/swift/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ BASELINE_LANGUAGE_FEATURE(BorrowingSwitch, 432, "Noncopyable type pattern matchi
CONDITIONALLY_SUPPRESSIBLE_LANGUAGE_FEATURE(IsolatedAny, 431, "@isolated(any) function types")
LANGUAGE_FEATURE(IsolatedAny2, 431, "@isolated(any) function types")
LANGUAGE_FEATURE(ObjCImplementation, 436, "@objc @implementation extensions")
LANGUAGE_FEATURE(NonescapableTypes, 446, "Nonescapable types")

// Swift 6
UPCOMING_FEATURE(ConciseMagicFile, 274, 6)
Expand Down Expand Up @@ -354,9 +355,8 @@ EXPERIMENTAL_FEATURE(SuppressedAssociatedTypes, true)
/// Allow destructuring stored `let` bindings in structs.
EXPERIMENTAL_FEATURE(StructLetDestructuring, true)

/// Enable non-escapable type attributes and function attributes that support
/// lifetime-dependent results.
SUPPRESSIBLE_EXPERIMENTAL_FEATURE(NonescapableTypes, true)
/// Enable returning non-escapable types from functions.
EXPERIMENTAL_FEATURE(LifetimeDependence, true)

/// Enable the `@_staticExclusiveOnly` attribute.
EXPERIMENTAL_FEATURE(StaticExclusiveOnly, true)
Expand Down
2 changes: 1 addition & 1 deletion include/swift/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -1191,7 +1191,7 @@ class Parser {

bool isParameterSpecifier() {
if (Tok.is(tok::kw_inout)) return true;
if (Context.LangOpts.hasFeature(Feature::NonescapableTypes) &&
if (Context.LangOpts.hasFeature(Feature::LifetimeDependence) &&
isSILLifetimeDependenceToken())
return true;
if (!canHaveParameterSpecifierContextualKeyword()) return false;
Expand Down
35 changes: 0 additions & 35 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2000,11 +2000,6 @@ void PrintAST::printSingleDepthOfGenericSignature(
if (dependsOnOpaque(inverse.subject))
continue;

if (inverse.getKind() == InvertibleProtocolKind::Escapable &&
Options.SuppressNonEscapableTypes) {
continue;
}

if (isFirstReq) {
if (printRequirements)
Printer << " " << tok::kw_where << " ";
Expand Down Expand Up @@ -3140,16 +3135,6 @@ suppressingFeatureAllowUnsafeAttribute(PrintOptions &options,
options.ExcludeAttrList.resize(originalExcludeAttrCount);
}

static void
suppressingFeatureNonescapableTypes(PrintOptions &options,
llvm::function_ref<void()> action) {
unsigned originalExcludeAttrCount = options.ExcludeAttrList.size();
options.ExcludeAttrList.push_back(DeclAttrKind::Lifetime);
llvm::SaveAndRestore<bool> scope(options.SuppressNonEscapableTypes, true);
action();
options.ExcludeAttrList.resize(originalExcludeAttrCount);
}

static void
suppressingFeatureCoroutineAccessors(PrintOptions &options,
llvm::function_ref<void()> action) {
Expand Down Expand Up @@ -7862,26 +7847,6 @@ swift::getInheritedForPrinting(
}
continue;
}

// Suppress Escapable and ~Escapable.
if (options.SuppressNonEscapableTypes) {
if (auto pct = ty->getAs<ProtocolCompositionType>()) {
auto inverses = pct->getInverses();
if (inverses.contains(InvertibleProtocolKind::Escapable)) {
inverses.remove(InvertibleProtocolKind::Escapable);
ty = ProtocolCompositionType::get(decl->getASTContext(),
pct->getMembers(), inverses,
pct->hasExplicitAnyObject());
if (ty->isAny())
continue;
}
}

if (auto protoTy = ty->getAs<ProtocolType>())
if (protoTy->getDecl()->isSpecificProtocol(
KnownProtocolKind::Escapable))
continue;
}
}

if (options.SuppressConformanceSuppression &&
Expand Down
13 changes: 13 additions & 0 deletions lib/AST/FeatureSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,19 @@ static bool usesFeatureSendingArgsAndResults(Decl *decl) {
return false;
}

static bool usesFeatureLifetimeDependence(Decl *decl) {
if (decl->getAttrs().hasAttribute<LifetimeAttr>()) {
return true;
}
auto *afd = dyn_cast<AbstractFunctionDecl>(decl);
if (!afd) {
return false;
}
return afd->getInterfaceType()
->getAs<AnyFunctionType>()
->hasLifetimeDependencies();
}

UNINTERESTING_FEATURE(DynamicActorIsolation)
UNINTERESTING_FEATURE(NonfrozenEnumExhaustivity)
UNINTERESTING_FEATURE(ClosureIsolation)
Expand Down
23 changes: 18 additions & 5 deletions lib/AST/LifetimeDependence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,15 @@ static Type getResultOrYield(AbstractFunctionDecl *afd) {
}

static bool hasEscapableResultOrYield(AbstractFunctionDecl *afd) {
return getResultOrYield(afd)->isEscapable();
auto resultType = getResultOrYield(afd);
// FIXME: This check is temporary until rdar://139976667 is fixed.
// ModuleType created with ModuleType::get methods are ~Copyable and
// ~Escapable because the Copyable and Escapable conformance is not added to
// them by default.
if (resultType->is<ModuleType>()) {
return true;
}
return resultType->isEscapable();
}

static std::optional<LifetimeDependenceKind>
Expand Down Expand Up @@ -508,6 +516,10 @@ LifetimeDependenceInfo::infer(AbstractFunctionDecl *afd) {
return std::nullopt;
}

if (afd->getAttrs().hasAttribute<UnsafeNonEscapableResultAttr>()) {
return std::nullopt;
}

// Setters infer 'self' dependence on 'newValue'.
if (auto accessor = dyn_cast<AccessorDecl>(afd)) {
if (accessor->getAccessorKind() == AccessorKind::Set) {
Expand All @@ -519,10 +531,6 @@ LifetimeDependenceInfo::infer(AbstractFunctionDecl *afd) {
return std::nullopt;
}

if (afd->getAttrs().hasAttribute<UnsafeNonEscapableResultAttr>()) {
return std::nullopt;
}

auto &diags = ctx.Diags;
auto returnTypeRepr = afd->getResultTypeRepr();
auto returnLoc = returnTypeRepr ? returnTypeRepr->getLoc() : afd->getLoc();
Expand All @@ -537,6 +545,11 @@ LifetimeDependenceInfo::infer(AbstractFunctionDecl *afd) {
}
}

if (!ctx.LangOpts.hasFeature(Feature::LifetimeDependence)) {
diags.diagnose(returnLoc, diag::lifetime_dependence_feature_required);
return std::nullopt;
}

if (!cd && afd->hasImplicitSelfDecl()) {
Type selfTypeInContext = dc->getSelfTypeInContext();
if (selfTypeInContext->isEscapable()) {
Expand Down
8 changes: 4 additions & 4 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2717,9 +2717,9 @@ parseLifetimeDescriptor(Parser &P,
ParserResult<LifetimeAttr> Parser::parseLifetimeAttribute(SourceLoc atLoc,
SourceLoc loc) {
ParserStatus status;
if (!Context.LangOpts.hasFeature(Feature::NonescapableTypes)) {
if (!Context.LangOpts.hasFeature(Feature::LifetimeDependence)) {
diagnose(loc, diag::requires_experimental_feature, "@lifetime", false,
getFeatureName(Feature::NonescapableTypes));
getFeatureName(Feature::LifetimeDependence));
status.setIsParseError();
return status;
}
Expand Down Expand Up @@ -5392,10 +5392,10 @@ ParserStatus Parser::ParsedTypeAttributeList::slowParse(Parser &P) {
}

if (P.isSILLifetimeDependenceToken()) {
if (!P.Context.LangOpts.hasFeature(Feature::NonescapableTypes)) {
if (!P.Context.LangOpts.hasFeature(Feature::LifetimeDependence)) {
P.diagnose(Tok, diag::requires_experimental_feature,
"lifetime dependence specifier", false,
getFeatureName(Feature::NonescapableTypes));
getFeatureName(Feature::LifetimeDependence));
}
P.consumeToken(); // consume '@'
auto loc = P.consumeToken(); // consume 'lifetime'
Expand Down
12 changes: 2 additions & 10 deletions lib/Sema/TypeCheckAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7693,18 +7693,10 @@ void AttributeChecker::visitRawLayoutAttr(RawLayoutAttr *attr) {
sd->setHasUnreferenceableStorage(true);
}

void AttributeChecker::visitNonEscapableAttr(NonEscapableAttr *attr) {
if (!Ctx.LangOpts.hasFeature(Feature::NonescapableTypes)) {
diagnoseAndRemoveAttr(attr, diag::nonescapable_types_attr_disabled);
}
}
void AttributeChecker::visitNonEscapableAttr(NonEscapableAttr *attr) {}

void AttributeChecker::visitUnsafeNonEscapableResultAttr(
UnsafeNonEscapableResultAttr *attr) {
if (!Ctx.LangOpts.hasFeature(Feature::NonescapableTypes)) {
diagnoseAndRemoveAttr(attr, diag::nonescapable_types_attr_disabled);
}
}
UnsafeNonEscapableResultAttr *attr) {}

void AttributeChecker::visitStaticExclusiveOnlyAttr(
StaticExclusiveOnlyAttr *attr) {
Expand Down
7 changes: 0 additions & 7 deletions lib/Sema/TypeCheckDeclPrimary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,6 @@ class CheckRepressions {
}
auto ipk = getInvertibleProtocolKind(*kp);
if (ipk) {
// Gate the '~Escapable' type behind a specific flag for now.
// Uses of 'Escapable' itself are already diagnosed; return ErrorType.
if (*ipk == InvertibleProtocolKind::Escapable &&
!ctx.LangOpts.hasFeature(Feature::NonescapableTypes)) {
return ErrorType::get(ctx);
}

return ProtocolCompositionType::getInverseOf(ctx, *ipk);
}
auto rpk = getRepressibleProtocolKind(*kp);
Expand Down
24 changes: 0 additions & 24 deletions lib/Sema/TypeCheckType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4959,22 +4959,6 @@ TypeResolver::resolveDeclRefTypeRepr(DeclRefTypeRepr *repr,
auto *dc = getDeclContext();
auto &ctx = getASTContext();

// Gate the 'Escapable' type behind a specific flag for now.
//
// NOTE: we do not return an ErrorType, though! We're just artificially
// preventing people from referring to the type without the feature.
if (auto proto = result->getAs<ProtocolType>()) {
if (auto known = proto->getKnownProtocol()) {
if (*known == KnownProtocolKind::Escapable
&& !isSILSourceFile()
&& !isInterfaceFile()
&& !ctx.LangOpts.hasFeature(Feature::NonescapableTypes)) {
diagnoseInvalid(repr, repr->getLoc(),
diag::escapable_requires_feature_flag);
}
}
}

if (ctx.LangOpts.hasFeature(Feature::ImplicitSome) &&
options.isConstraintImplicitExistential()) {
// Check whether this type is an implicit opaque result type.
Expand Down Expand Up @@ -5991,14 +5975,6 @@ NeverNullType TypeResolver::resolveInverseType(InverseTypeRepr *repr,

if (auto kp = ty->getKnownProtocol()) {
if (auto kind = getInvertibleProtocolKind(*kp)) {

// Gate the '~Escapable' type behind a specific flag for now.
// Uses of 'Escapable' itself are already diagnosed; return ErrorType.
if (*kind == InvertibleProtocolKind::Escapable &&
!getASTContext().LangOpts.hasFeature(Feature::NonescapableTypes)) {
return wrapInExistential(ErrorType::get(getASTContext()));
}

return wrapInExistential(
ProtocolCompositionType::getInverseOf(getASTContext(), *kind));
}
Expand Down
2 changes: 2 additions & 0 deletions stdlib/cmake/modules/SwiftSource.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,8 @@ function(_compile_swift_files
list(APPEND swift_flags "-enable-experimental-feature" "SE427NoInferenceOnExtension")
list(APPEND swift_flags "-enable-experimental-feature" "AllowUnsafeAttribute")
list(APPEND swift_flags "-enable-experimental-feature" "NonescapableTypes")
list(APPEND swift_flags "-enable-experimental-feature" "LifetimeDependence")

list(APPEND swift_flags "-enable-upcoming-feature" "MemberImportVisibility")

if (SWIFT_STDLIB_ENABLE_STRICT_CONCURRENCY_COMPLETE)
Expand Down
8 changes: 0 additions & 8 deletions stdlib/public/core/Misc.swift
Original file line number Diff line number Diff line change
Expand Up @@ -234,19 +234,11 @@ func _rethrowsViaClosure(_ fn: () throws -> ()) rethrows {
@_marker public protocol Escapable {}

#if $BitwiseCopyable2
#if $NonescapableTypes
@_marker public protocol BitwiseCopyable: ~Escapable { }
#else
@_marker public protocol BitwiseCopyable { }
#endif

@available(*, deprecated, message: "Use BitwiseCopyable")
public typealias _BitwiseCopyable = BitwiseCopyable
#else
#if $NonescapableTypes
@_marker public protocol _BitwiseCopyable: ~Escapable { }
#else
@_marker public protocol _BitwiseCopyable { }
#endif
public typealias BitwiseCopyable = _BitwiseCopyable
#endif
4 changes: 0 additions & 4 deletions stdlib/public/core/Sendable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,7 @@
/// ### Sendable Metatypes
///
/// Metatypes such as `Int.Type` implicitly conform to the `Sendable` protocol.
#if $NonescapableTypes
@_marker public protocol Sendable: ~Copyable, ~Escapable { }
#else
@_marker public protocol Sendable: ~Copyable { }
#endif

///
/// A type whose values can safely be passed across concurrency domains by copying,
Expand Down
Loading