Skip to content

Commit 37f9f0c

Browse files
committed
[Concurrency] Apply @preconcurrency to typealiases at the point of use.
When referencing a `@preconcurrency` typealias from code that does not require strict concurrency, strip off `@Sendable` and global actor types. This is consistent with references to functions/properties/etc. that are `@preconcurrency`. Fixes #60487, rdar://98343624. (cherry picked from commit 5b88b96)
1 parent c254623 commit 37f9f0c

File tree

2 files changed

+75
-6
lines changed

2 files changed

+75
-6
lines changed

lib/Sema/TypeCheckType.cpp

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,27 @@ static Type getIdentityOpaqueTypeArchetypeType(
286286
return OpaqueTypeArchetypeType::get(opaqueDecl, interfaceType, subs);
287287
}
288288

289+
/// Adjust the underlying type of a typealias within the given context to
290+
/// account for @preconcurrency.
291+
static Type adjustTypeAliasTypeInContext(
292+
Type type, TypeAliasDecl *aliasDecl, DeclContext *fromDC) {
293+
if (!aliasDecl->preconcurrency())
294+
return type;
295+
296+
if (contextRequiresStrictConcurrencyChecking(
297+
fromDC,
298+
[](const AbstractClosureExpr *closure) {
299+
return closure->getType();
300+
},
301+
[](const ClosureExpr *closure) {
302+
return closure->isIsolatedByPreconcurrency();
303+
}))
304+
return type;
305+
306+
return type->stripConcurrency(
307+
/*recurse=*/true, /*dropGlobalActor=*/true);
308+
}
309+
289310
Type TypeResolution::resolveTypeInContext(TypeDecl *typeDecl,
290311
DeclContext *foundDC,
291312
bool isSpecialized) const {
@@ -307,6 +328,13 @@ Type TypeResolution::resolveTypeInContext(TypeDecl *typeDecl,
307328
return genericParam->getDeclaredInterfaceType();
308329
}
309330

331+
/// Call this function before returning the underlying type of a typealias,
332+
/// to adjust its type for concurrency.
333+
auto adjustAliasType = [&](Type type) -> Type {
334+
return adjustTypeAliasTypeInContext(
335+
type, cast<TypeAliasDecl>(typeDecl), fromDC);
336+
};
337+
310338
if (!isSpecialized) {
311339
// If we are referring to a type within its own context, and we have either
312340
// a generic type with no generic arguments or a non-generic type, use the
@@ -342,9 +370,9 @@ Type TypeResolution::resolveTypeInContext(TypeDecl *typeDecl,
342370
if (ugAliasDecl == aliasDecl) {
343371
if (getStage() == TypeResolutionStage::Structural &&
344372
aliasDecl->getUnderlyingTypeRepr() != nullptr) {
345-
return aliasDecl->getStructuralType();
373+
return adjustAliasType(aliasDecl->getStructuralType());
346374
}
347-
return aliasDecl->getDeclaredInterfaceType();
375+
return adjustAliasType(aliasDecl->getDeclaredInterfaceType());
348376
}
349377

350378
extendedType = unboundGeneric->getParent();
@@ -356,9 +384,9 @@ Type TypeResolution::resolveTypeInContext(TypeDecl *typeDecl,
356384
if (aliasType->getDecl() == aliasDecl) {
357385
if (getStage() == TypeResolutionStage::Structural &&
358386
aliasDecl->getUnderlyingTypeRepr() != nullptr) {
359-
return aliasDecl->getStructuralType();
387+
return adjustAliasType(aliasDecl->getStructuralType());
360388
}
361-
return aliasDecl->getDeclaredInterfaceType();
389+
return adjustAliasType(aliasDecl->getDeclaredInterfaceType());
362390
}
363391
extendedType = aliasType->getParent();
364392
continue;
@@ -381,9 +409,9 @@ Type TypeResolution::resolveTypeInContext(TypeDecl *typeDecl,
381409
// Otherwise, return the appropriate type.
382410
if (getStage() == TypeResolutionStage::Structural &&
383411
aliasDecl->getUnderlyingTypeRepr() != nullptr) {
384-
return aliasDecl->getStructuralType();
412+
return adjustAliasType(aliasDecl->getStructuralType());
385413
}
386-
return aliasDecl->getDeclaredInterfaceType();
414+
return adjustAliasType(aliasDecl->getDeclaredInterfaceType());
387415
}
388416

389417
// When a nominal type used outside its context, return the unbound
@@ -1571,6 +1599,12 @@ static Type resolveNestedIdentTypeComponent(TypeResolution resolution,
15711599
AssociatedTypeDecl *inferredAssocType) {
15721600
bool hasUnboundOpener = !!resolution.getUnboundTypeOpener();
15731601

1602+
// Type aliases might require adjustment due to @preconcurrency.
1603+
if (auto aliasDecl = dyn_cast<TypeAliasDecl>(member)) {
1604+
memberType = adjustTypeAliasTypeInContext(
1605+
memberType, aliasDecl, resolution.getDeclContext());
1606+
}
1607+
15741608
if (options.contains(TypeResolutionFlags::SilenceErrors)) {
15751609
if (TypeChecker::isUnsupportedMemberTypeAccess(parentTy, member,
15761610
hasUnboundOpener)
@@ -4401,6 +4435,7 @@ class ExistentialTypeVisitor
44014435
}
44024436
} else if (auto *alias = dyn_cast_or_null<TypeAliasDecl>(comp->getBoundDecl())) {
44034437
auto type = Type(alias->getDeclaredInterfaceType()->getDesugaredType());
4438+
44044439
// If this is a type alias to a constraint type, the type
44054440
// alias name must be prefixed with 'any' to be used as an
44064441
// existential type.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %target-swift-frontend -typecheck -verify %s
2+
// REQUIRES: concurrency
3+
4+
@preconcurrency @MainActor func f() { }
5+
// expected-note@-1 2{{calls to global function 'f()' from outside of its actor context are implicitly asynchronous}}
6+
7+
@preconcurrency typealias FN = @Sendable () -> Void
8+
9+
struct Outer {
10+
@preconcurrency typealias FN = @Sendable () -> Void
11+
}
12+
13+
func test() {
14+
var _: Outer.FN = {
15+
f()
16+
}
17+
18+
var _: FN = {
19+
f()
20+
print("Hello")
21+
}
22+
}
23+
24+
@available(SwiftStdlib 5.1, *)
25+
func testAsync() async {
26+
var _: Outer.FN = {
27+
f() // expected-error{{call to main actor-isolated global function 'f()' in a synchronous nonisolated context}}
28+
}
29+
30+
var _: FN = {
31+
f() // expected-error{{call to main actor-isolated global function 'f()' in a synchronous nonisolated context}}
32+
print("Hello")
33+
}
34+
}

0 commit comments

Comments
 (0)