Skip to content

Fix metadata availability testing for parameterized existentials and implement it for @isolated(any) function types #71970

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 2 commits into from
Mar 1, 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
5 changes: 5 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -6609,6 +6609,11 @@ ERROR(availability_parameterized_protocol_only_version_newer, none,
"%0 %1 or newer",
(StringRef, llvm::VersionTuple))

ERROR(availability_isolated_any_only_version_newer, none,
"runtime support for @isolated(any) function types is only available in "
"%0 %1 or newer",
(StringRef, llvm::VersionTuple))

ERROR(availability_variadic_type_only_version_newer, none,
"parameter packs in generic types are only available in %0 %1 or newer",
(StringRef, llvm::VersionTuple))
Expand Down
12 changes: 11 additions & 1 deletion include/swift/AST/FeatureAvailability.def
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@
/// FEATURE(N, V)
/// N - The name of the feature (in UpperCamelCase).
/// V - The Swift version number, as a tuple, or FUTURE.
///
/// The feature Foo turns into two methods on ASTContext:
/// getFooRuntimeAvailability(), which returns the exact version provided
/// here, and getFooAvailability(), which maps that version into a version
/// of the target OS. Because both of these methods exist, it is a bad idea
/// to use a feature name that ends in "Runtime", or people might get very
/// confused.
#ifndef FEATURE
#define FEATURE(N, V)
#endif
Expand Down Expand Up @@ -48,7 +55,8 @@ FEATURE(Concurrency, (5, 5))
FEATURE(MultiPayloadEnumTagSinglePayload, (5, 6))
FEATURE(ObjCIsUniquelyReferenced, (5, 6))

FEATURE(ParameterizedExistentialRuntime, (5, 7))
// Metadata and casting support for parameterized existential types
FEATURE(ParameterizedExistential, (5, 7))

FEATURE(VariadicGenericType, (5, 9))
FEATURE(SignedConformsToProtocol, (5, 9))
Expand All @@ -60,6 +68,8 @@ FEATURE(ObjCSymbolicReferences, (5, 11))
FEATURE(TypedThrows, (5, 11))
FEATURE(StaticReadOnlyArrays, (5, 11))
FEATURE(SwiftExceptionPersonality, (5, 11))
// Metadata support for @isolated(any) function types
FEATURE(IsolatedAny, (5, 11))

FEATURE(TaskExecutor, FUTURE)
FEATURE(Differentiation, FUTURE)
Expand Down
91 changes: 48 additions & 43 deletions lib/IRGen/GenReflection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,60 +176,65 @@ class PrintMetadataSource

std::optional<llvm::VersionTuple>
getRuntimeVersionThatSupportsDemanglingType(CanType type) {
// The Swift 6.0 runtime is the first version able to demangle types
// that involve typed throws.
bool usesTypedThrows = type.findIf([](CanType t) -> bool {
if (auto fn = dyn_cast<AnyFunctionType>(t)) {
if (!fn.getThrownError().isNull())
return true;
}
enum VersionRequirement {
None,
Swift_5_2,
Swift_5_5,
Swift_6_0,

// Short-circuit if we find this requirement.
Latest = Swift_6_0
};

VersionRequirement latestRequirement = None;
auto addRequirement = [&](VersionRequirement req) -> bool {
if (req > latestRequirement) {
latestRequirement = req;
return req == Latest;
}
return false;
});
if (usesTypedThrows) {
return llvm::VersionTuple(6, 0);
}
};

// The Swift 5.5 runtime is the first version able to demangle types
// related to concurrency.
bool needsConcurrency = type.findIf([](CanType t) -> bool {
(void) type.findIf([&](CanType t) -> bool {
if (auto fn = dyn_cast<AnyFunctionType>(t)) {
if (fn->isAsync() || fn->isSendable() || fn->hasGlobalActor())
return true;

for (const auto &param : fn->getParams()) {
if (param.isIsolated())
return true;
}
// The Swift 6.0 runtime is the first version able to demangle types
// that involve typed throws or @isolated(any), or for that matter
// represent them at all at runtime.
if (!fn.getThrownError().isNull() || fn->getIsolation().isErased())
return addRequirement(Swift_6_0);

// The Swift 5.5 runtime is the first version able to demangle types
// related to concurrency.
if (fn->isAsync() || fn->isSendable() ||
!fn->getIsolation().isNonIsolated())
return addRequirement(Swift_5_5);

return false;
}

if (auto opaqueArchetype = dyn_cast<OpaqueTypeArchetypeType>(t)) {
// Associated types of opaque types weren't mangled in a usable
// form by the Swift 5.1 runtime, so we needed to add a new
// mangling in 5.2.
if (opaqueArchetype->getInterfaceType()->is<DependentMemberType>())
return addRequirement(Swift_5_2);

// Although opaque types in general were only added in Swift 5.1,
// declarations that use them are already covered by availability
// guards, so we don't need to limit availability of mangled names
// involving them.
}

return false;
});
if (needsConcurrency) {
return llvm::VersionTuple(5, 5);
}

// Associated types of opaque types weren't mangled in a usable form by the
// Swift 5.1 runtime, so we needed to add a new mangling in 5.2.
if (type->hasOpaqueArchetype()) {
auto hasOpaqueAssocType = type.findIf([](CanType t) -> bool {
if (auto a = dyn_cast<ArchetypeType>(t)) {
return isa<OpaqueTypeArchetypeType>(a) &&
a->getInterfaceType()->is<DependentMemberType>();
}
return false;
});

if (hasOpaqueAssocType)
return llvm::VersionTuple(5, 2);
// Although opaque types in general were only added in Swift 5.1,
// declarations that use them are already covered by availability
// guards, so we don't need to limit availability of mangled names
// involving them.
switch (latestRequirement) {
case Swift_6_0: return llvm::VersionTuple(6, 0);
case Swift_5_5: return llvm::VersionTuple(5, 5);
case Swift_5_2: return llvm::VersionTuple(5, 2);
case None: return std::nullopt;
}

return std::nullopt;
llvm_unreachable("bad kind");
}

// Produce a fallback mangled type name that uses an open-coded callback
Expand Down
2 changes: 1 addition & 1 deletion lib/IRGen/IRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -960,7 +960,7 @@ namespace RuntimeConstants {
}

RuntimeAvailability ParameterizedExistentialAvailability(ASTContext &Context) {
auto featureAvailability = Context.getParameterizedExistentialRuntimeAvailability();
auto featureAvailability = Context.getParameterizedExistentialAvailability();
if (!isDeploymentAvailabilityContainedIn(Context, featureAvailability)) {
return RuntimeAvailability::ConditionallyAvailable;
}
Expand Down
10 changes: 8 additions & 2 deletions lib/IRGen/MetadataRequest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1416,10 +1416,15 @@ getFunctionTypeFlags(CanFunctionType type) {
break;
}

auto isolation = type->getIsolation();

auto extFlags = ExtendedFunctionTypeFlags()
.withTypedThrows(!type->getThrownError().isNull())
.withTransferringResult(type->hasTransferringResult());

if (isolation.isErased())
extFlags = extFlags.withIsolatedAny();

auto flags = FunctionTypeFlags()
.withConvention(metadataConvention)
.withAsync(type->isAsync())
Expand All @@ -1428,7 +1433,7 @@ getFunctionTypeFlags(CanFunctionType type) {
.withParameterFlags(hasParameterFlags)
.withEscaping(isEscaping)
.withDifferentiable(type->isDifferentiable())
.withGlobalActor(!type->getGlobalActor().isNull())
.withGlobalActor(isolation.isGlobalActor())
.withExtendedFlags(extFlags.getIntValue() != 0);

return std::make_pair(flags, extFlags);
Expand Down Expand Up @@ -1632,7 +1637,8 @@ static MetadataResponse emitFunctionTypeMetadataRef(IRGenFunction &IGF,

default:
assert((!params.empty() || type->isDifferentiable() ||
type->getGlobalActor() || type->getThrownError()) &&
!type->getIsolation().isNonIsolated() ||
type->getThrownError()) &&
"0 parameter case should be specialized unless it is a "
"differentiable function or has a global actor");

Expand Down
Loading