Skip to content

Commit cd4621c

Browse files
committed
Don't perform @preconcurrency typealias adjustments in @preconcurrency decls
When a `@preconcurrency` typealias is used within the type of a `@preconcurrency` declaration, such as a function, do not strip concurrency-related types, because the stripping will happen in the outer declaration. Fixes #60488. (cherry picked from commit 2fbdad7)
1 parent 37f9f0c commit cd4621c

File tree

4 files changed

+51
-4
lines changed

4 files changed

+51
-4
lines changed

lib/Sema/TypeCheckDecl.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1814,6 +1814,8 @@ UnderlyingTypeRequest::evaluate(Evaluator &evaluator,
18141814
TypeResolutionOptions options((typeAlias->getGenericParams()
18151815
? TypeResolverContext::GenericTypeAliasDecl
18161816
: TypeResolverContext::TypeAliasDecl));
1817+
if (typeAlias->preconcurrency())
1818+
options |= TypeResolutionFlags::Preconcurrency;
18171819

18181820
// This can happen when code completion is attempted inside
18191821
// of typealias underlying type e.g. `typealias F = () -> Int#^TOK^#`
@@ -2094,8 +2096,11 @@ ResultTypeRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const {
20942096
: ErrorType::get(ctx));
20952097
}
20962098

2097-
const auto options =
2099+
auto options =
20982100
TypeResolutionOptions(TypeResolverContext::FunctionResult);
2101+
if (decl->preconcurrency())
2102+
options |= TypeResolutionFlags::Preconcurrency;
2103+
20992104
auto *const dc = decl->getInnermostDeclContext();
21002105
return TypeResolution::forInterface(dc, options,
21012106
/*unboundTyOpener*/ nullptr,
@@ -2196,6 +2201,13 @@ static Type validateParameterType(ParamDecl *decl) {
21962201
options = TypeResolutionOptions(TypeResolverContext::EnumElementDecl);
21972202
}
21982203

2204+
// Set the "preconcurrency" flag if this is a parameter of a preconcurrency
2205+
// declaration.
2206+
if (auto decl = dc->getAsDecl()) {
2207+
if (decl->preconcurrency())
2208+
options |= TypeResolutionFlags::Preconcurrency;
2209+
}
2210+
21992211
// If the element is a variadic parameter, resolve the parameter type as if
22002212
// it were in non-parameter position, since we want functions to be
22012213
// @escaping in this case.

lib/Sema/TypeCheckType.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -289,10 +289,20 @@ static Type getIdentityOpaqueTypeArchetypeType(
289289
/// Adjust the underlying type of a typealias within the given context to
290290
/// account for @preconcurrency.
291291
static Type adjustTypeAliasTypeInContext(
292-
Type type, TypeAliasDecl *aliasDecl, DeclContext *fromDC) {
292+
Type type, TypeAliasDecl *aliasDecl, DeclContext *fromDC,
293+
TypeResolutionOptions options) {
294+
// If we are in a @preconcurrency declaration, don't adjust the types of
295+
// type aliases.
296+
if (options.contains(TypeResolutionFlags::Preconcurrency))
297+
return type;
298+
299+
// If the type alias itself isn't marked with @preconcurrency, don't
300+
// adjust the type.
293301
if (!aliasDecl->preconcurrency())
294302
return type;
295303

304+
// Only adjust the type within a strict concurrency context, so we don't
305+
// change the types as seen by code that hasn't adopted concurrency.
296306
if (contextRequiresStrictConcurrencyChecking(
297307
fromDC,
298308
[](const AbstractClosureExpr *closure) {
@@ -332,7 +342,7 @@ Type TypeResolution::resolveTypeInContext(TypeDecl *typeDecl,
332342
/// to adjust its type for concurrency.
333343
auto adjustAliasType = [&](Type type) -> Type {
334344
return adjustTypeAliasTypeInContext(
335-
type, cast<TypeAliasDecl>(typeDecl), fromDC);
345+
type, cast<TypeAliasDecl>(typeDecl), fromDC, options);
336346
};
337347

338348
if (!isSpecialized) {
@@ -1602,7 +1612,8 @@ static Type resolveNestedIdentTypeComponent(TypeResolution resolution,
16021612
// Type aliases might require adjustment due to @preconcurrency.
16031613
if (auto aliasDecl = dyn_cast<TypeAliasDecl>(member)) {
16041614
memberType = adjustTypeAliasTypeInContext(
1605-
memberType, aliasDecl, resolution.getDeclContext());
1615+
memberType, aliasDecl, resolution.getDeclContext(),
1616+
resolution.getOptions());
16061617
}
16071618

16081619
if (options.contains(TypeResolutionFlags::SilenceErrors)) {

lib/Sema/TypeCheckType.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ enum class TypeResolutionFlags : uint16_t {
6767
/// Needed to enforce that \c any P<some Q> does not resolve to a
6868
/// parameterized existential with an opaque type constraint.
6969
DisallowOpaqueTypes = 1 << 9,
70+
71+
/// We are in a `@preconcurrency` declaration.
72+
Preconcurrency = 1 << 10,
7073
};
7174

7275
/// Type resolution contexts that require special handling.

test/Concurrency/preconcurrency_typealias.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,15 @@ struct Outer {
1010
@preconcurrency typealias FN = @Sendable () -> Void
1111
}
1212

13+
@preconcurrency func preconcurrencyFunc(callback: FN) {}
14+
15+
func usage() {
16+
}
17+
18+
func usageAsync() async {
19+
}
20+
21+
1322
func test() {
1423
var _: Outer.FN = {
1524
f()
@@ -19,6 +28,12 @@ func test() {
1928
f()
2029
print("Hello")
2130
}
31+
32+
var mutableVariable = 0
33+
preconcurrencyFunc {
34+
mutableVariable += 1 // no sendable warning
35+
}
36+
mutableVariable += 1
2237
}
2338

2439
@available(SwiftStdlib 5.1, *)
@@ -31,4 +46,10 @@ func testAsync() async {
3146
f() // expected-error{{call to main actor-isolated global function 'f()' in a synchronous nonisolated context}}
3247
print("Hello")
3348
}
49+
50+
var mutableVariable = 0
51+
preconcurrencyFunc {
52+
mutableVariable += 1 // expected-warning{{mutation of captured var 'mutableVariable' in concurrently-executing code; this is an error in Swift 6}}
53+
}
54+
mutableVariable += 1
3455
}

0 commit comments

Comments
 (0)