@@ -1558,70 +1558,83 @@ namespace {
1558
1558
return false ;
1559
1559
}
1560
1560
1561
- // / Check a reference to an entity within a global actor.
1562
- bool checkGlobalActorReference (
1563
- ConcreteDeclRef valueRef, SourceLoc loc, Type globalActor,
1564
- bool isCrossActor,
1565
- Expr *context) {
1566
- ValueDecl *value = valueRef.getDecl ();
1567
-
1568
- // / Returns true if this global-actor reference is acceptable because
1569
- // / it is part of an implicitly async operation, such as a call or
1570
- // / property access.
1571
- // / NOTE: This check will mutate the AST if it returns true!
1572
- auto inspectForImplicitlyAsync = [&] () -> bool {
1573
- // If our current context isn't an asynchronous one, don't
1574
- if (!isInAsynchronousContext ())
1575
- return false ;
1576
-
1577
- bool asyncAccess = false ;
1561
+ enum class AsyncMarkingResult {
1562
+ FoundAsync, // successfully marked an implicitly-async operation
1563
+ NotFound, // fail: no valid implicitly-async operation was found
1564
+ SyncContext, // fail: a valid implicitly-async op, but in sync context
1565
+ NotConcurrentValue // fail: valid op and context, but not ConcurrentValue
1566
+ };
1578
1567
1579
- // Is this global-actor reference part of a LookupExpr or DeclRefExpr?
1580
- if (isPropOrSubscript (valueRef.getDecl ())) {
1581
- if (auto declRef = dyn_cast_or_null<DeclRefExpr>(context)) {
1582
- if (usageEnv (declRef) == VarRefUseEnv::Read) {
1583
- declRef->setImplicitlyAsync (true );
1584
- asyncAccess = true ;
1585
- }
1586
- } else if (auto lookupExpr = dyn_cast_or_null<LookupExpr>(context)) {
1587
- if (usageEnv (lookupExpr) == VarRefUseEnv::Read) {
1588
- lookupExpr->setImplicitlyAsync (true );
1589
- asyncAccess = true ;
1590
- }
1568
+ // / Attempts to identify and mark a valid cross-actor use of a synchronous
1569
+ // / actor-isolated member (e.g., sync function application, property access)
1570
+ AsyncMarkingResult tryMarkImplicitlyAsync (SourceLoc declLoc,
1571
+ ConcreteDeclRef concDeclRef,
1572
+ Expr* context) {
1573
+ // If our current context isn't an asynchronous one, don't
1574
+ if (!isInAsynchronousContext ())
1575
+ return AsyncMarkingResult::NotFound;
1576
+
1577
+ ValueDecl *decl = concDeclRef.getDecl ();
1578
+ AsyncMarkingResult result = AsyncMarkingResult::NotFound;
1579
+
1580
+ // is it an access to a property?
1581
+ if (isPropOrSubscript (decl)) {
1582
+ if (auto declRef = dyn_cast_or_null<DeclRefExpr>(context)) {
1583
+ if (usageEnv (declRef) == VarRefUseEnv::Read) {
1584
+ declRef->setImplicitlyAsync (true );
1585
+ result = AsyncMarkingResult::FoundAsync;
1586
+ }
1587
+ } else if (auto lookupExpr = dyn_cast_or_null<LookupExpr>(context)) {
1588
+ if (usageEnv (lookupExpr) == VarRefUseEnv::Read) {
1589
+ lookupExpr->setImplicitlyAsync (true );
1590
+ result = AsyncMarkingResult::FoundAsync;
1591
1591
}
1592
1592
}
1593
1593
1594
- // Is this global-actor reference within an apply?
1595
- if (!applyStack.empty ()) {
1596
- // Check our applyStack metadata from the traversal.
1597
- // Our goal is to identify whether this global actor reference appears
1598
- // as the called value of the enclosing ApplyExpr. We cannot simply
1599
- // inspect Parent here because of expressions like (callee)()
1600
- // and the fact that the reference may be just an argument to an apply
1601
- ApplyExpr *apply = applyStack.back ();
1602
- Expr *fn = apply->getFn ()->getValueProvidingExpr ();
1603
- if (auto memberRef = findMemberReference (fn)) {
1604
- auto concDecl = memberRef->first ;
1605
- if (value == concDecl.getDecl () && !apply->implicitlyAsync ()) {
1606
- // then this ValueDecl appears as the called value of the ApplyExpr.
1607
- markNearestCallAsImplicitlyAsync ();
1608
- asyncAccess = true ;
1609
- }
1594
+ } else if (llvm::isa_and_nonnull<SelfApplyExpr>(context) &&
1595
+ isa<AbstractFunctionDecl>(decl)) {
1596
+ // actor-isolated non-isolated-self calls are implicitly async
1597
+ // and thus OK.
1598
+ markNearestCallAsImplicitlyAsync ();
1599
+ result = AsyncMarkingResult::FoundAsync;
1600
+
1601
+ } else if (!applyStack.empty ()) {
1602
+ // Check our applyStack metadata from the traversal.
1603
+ // Our goal is to identify whether the actor reference appears
1604
+ // as the called value of the enclosing ApplyExpr. We cannot simply
1605
+ // inspect Parent here because of expressions like (callee)()
1606
+ // and the fact that the reference may be just an argument to an apply
1607
+ ApplyExpr *apply = applyStack.back ();
1608
+ Expr *fn = apply->getFn ()->getValueProvidingExpr ();
1609
+ if (auto memberRef = findMemberReference (fn)) {
1610
+ auto concDecl = memberRef->first ;
1611
+ if (decl == concDecl.getDecl () && !apply->implicitlyAsync ()) {
1612
+ // then this ValueDecl appears as the called value of the ApplyExpr.
1613
+ markNearestCallAsImplicitlyAsync ();
1614
+ result = AsyncMarkingResult::FoundAsync;
1610
1615
}
1611
1616
}
1617
+ }
1612
1618
1613
- if (asyncAccess) {
1614
- // Check for non-concurrent types.
1615
- (void )diagnoseNonConcurrentTypesInReference (
1616
- valueRef, getDeclContext (), loc,
1619
+ if (result == AsyncMarkingResult::FoundAsync) {
1620
+ // Check for non-concurrent types.
1621
+ bool problemFound =
1622
+ diagnoseNonConcurrentTypesInReference (
1623
+ concDeclRef, getDeclContext (), declLoc,
1617
1624
ConcurrentReferenceKind::SynchronousAsAsyncCall);
1625
+ if (problemFound)
1626
+ result = AsyncMarkingResult::NotConcurrentValue;
1627
+ }
1618
1628
1619
- return true ;
1620
- }
1621
-
1622
- return false ;
1623
- };
1629
+ return result;
1630
+ }
1624
1631
1632
+ // / Check a reference to an entity within a global actor.
1633
+ bool checkGlobalActorReference (
1634
+ ConcreteDeclRef valueRef, SourceLoc loc, Type globalActor,
1635
+ bool isCrossActor,
1636
+ Expr *context) {
1637
+ ValueDecl *value = valueRef.getDecl ();
1625
1638
auto declContext = getDeclContext ();
1626
1639
1627
1640
// Check whether we are within the same isolation context, in which
@@ -1641,7 +1654,8 @@ namespace {
1641
1654
1642
1655
switch (contextIsolation) {
1643
1656
case ActorIsolation::ActorInstance: {
1644
- if (inspectForImplicitlyAsync ())
1657
+ auto result = tryMarkImplicitlyAsync (loc, valueRef, context);
1658
+ if (result == AsyncMarkingResult::FoundAsync)
1645
1659
return false ;
1646
1660
1647
1661
auto useKind = static_cast <unsigned >(
@@ -1659,7 +1673,8 @@ namespace {
1659
1673
case ActorIsolation::GlobalActorUnsafe: {
1660
1674
// Check if this decl reference is the callee of the enclosing Apply,
1661
1675
// making it OK as an implicitly async call.
1662
- if (inspectForImplicitlyAsync ())
1676
+ auto result = tryMarkImplicitlyAsync (loc, valueRef, context);
1677
+ if (result == AsyncMarkingResult::FoundAsync)
1663
1678
return false ;
1664
1679
1665
1680
auto useKind = static_cast <unsigned >(
@@ -1679,7 +1694,8 @@ namespace {
1679
1694
return false ;
1680
1695
1681
1696
case ActorIsolation::Independent: {
1682
- if (inspectForImplicitlyAsync ())
1697
+ auto result = tryMarkImplicitlyAsync (loc, valueRef, context);
1698
+ if (result == AsyncMarkingResult::FoundAsync)
1683
1699
return false ;
1684
1700
1685
1701
auto useKind = static_cast <unsigned >(
@@ -1695,7 +1711,8 @@ namespace {
1695
1711
1696
1712
case ActorIsolation::Unspecified: {
1697
1713
// NOTE: we must always inspect for implicitlyAsync
1698
- bool implicitlyAsyncExpr = inspectForImplicitlyAsync ();
1714
+ auto result = tryMarkImplicitlyAsync (loc, valueRef, context);
1715
+ bool implicitlyAsyncExpr = (result == AsyncMarkingResult::FoundAsync);
1699
1716
bool didEmitDiagnostic = false ;
1700
1717
1701
1718
auto emitError = [&](bool justNote = false ) {
@@ -1938,47 +1955,15 @@ namespace {
1938
1955
}
1939
1956
1940
1957
case ActorIsolationRestriction::ActorSelf: {
1941
- // / Local function to check for implicit async promotion.
1942
- // / returns None if it is not applicable; true if there is an error.
1943
- auto checkImplicitlyAsync = [&]() -> Optional<bool > {
1944
- if (!isInAsynchronousContext ())
1945
- return None;
1946
-
1947
- bool validAccess = false ;
1948
-
1949
- // actor-isolated non-isolated-self calls are implicitly async
1950
- // and thus OK.
1951
- if (llvm::isa_and_nonnull<SelfApplyExpr>(context) &&
1952
- isa<AbstractFunctionDecl>(member)) {
1953
- markNearestCallAsImplicitlyAsync ();
1954
- validAccess = true ;
1955
-
1956
- } else if (llvm::isa_and_nonnull<LookupExpr>(context) &&
1957
- isPropOrSubscript (member) &&
1958
- usageEnv (cast<LookupExpr>(context)) == VarRefUseEnv::Read) {
1959
- cast<LookupExpr>(context)->setImplicitlyAsync (true );
1960
- validAccess = true ;
1961
- } else {
1962
- // It's not wrong to have declref context here; simply unimplemented
1963
- assert (context == nullptr || !isa<DeclRefExpr>(context));
1964
- }
1965
-
1966
- if (validAccess) {
1967
- // Check for non-concurrent types.
1968
- return diagnoseNonConcurrentTypesInReference (
1969
- memberRef, getDeclContext (), memberLoc,
1970
- ConcurrentReferenceKind::SynchronousAsAsyncCall);
1971
- }
1972
-
1973
- return None;
1974
- };
1975
-
1976
1958
// Must reference actor-isolated state on 'self'.
1977
1959
auto *selfVar = getReferencedSelf (base);
1978
1960
if (!selfVar) {
1979
1961
// Check for implicit async.
1980
- if (auto result = checkImplicitlyAsync ())
1981
- return *result;
1962
+ auto result = tryMarkImplicitlyAsync (memberLoc, memberRef, context);
1963
+ if (result == AsyncMarkingResult::FoundAsync)
1964
+ return false ; // no problems
1965
+ else if (result == AsyncMarkingResult::NotConcurrentValue)
1966
+ return true ;
1982
1967
1983
1968
auto useKind = static_cast <unsigned >(
1984
1969
kindOfUsage (member, context).getValueOr (VarRefUseEnv::Read));
@@ -2017,9 +2002,11 @@ namespace {
2017
2002
return false ;
2018
2003
2019
2004
case ActorIsolation::Independent: {
2020
- // Check for implicit async.
2021
- if (auto result = checkImplicitlyAsync ())
2022
- return *result;
2005
+ auto result = tryMarkImplicitlyAsync (memberLoc, memberRef, context);
2006
+ if (result == AsyncMarkingResult::FoundAsync)
2007
+ return false ; // no problems
2008
+ else if (result == AsyncMarkingResult::NotConcurrentValue)
2009
+ return true ;
2023
2010
2024
2011
// The 'self' is for an actor-independent member, which means
2025
2012
// we cannot refer to actor-isolated state.
@@ -2033,20 +2020,22 @@ namespace {
2033
2020
}
2034
2021
2035
2022
case ActorIsolation::GlobalActor:
2036
- case ActorIsolation::GlobalActorUnsafe:
2037
- // Check for implicit async.
2038
- if (auto result = checkImplicitlyAsync ())
2039
- return *result;
2023
+ case ActorIsolation::GlobalActorUnsafe: {
2024
+ auto result = tryMarkImplicitlyAsync (memberLoc, memberRef, context);
2025
+ if (result == AsyncMarkingResult::FoundAsync)
2026
+ return false ; // no problems
2027
+ else if (result == AsyncMarkingResult::NotConcurrentValue)
2028
+ return true ;
2040
2029
2041
2030
// The 'self' is for a member that's part of a global actor, which
2042
2031
// means we cannot refer to actor-isolated state.
2043
- ctx.Diags .diagnose (
2044
- memberLoc, diag::actor_isolated_global_actor_context,
2045
- member->getDescriptiveKind (),
2046
- member->getName (),
2047
- contextIsolation.getGlobalActor ());
2032
+ ctx.Diags .diagnose (memberLoc,
2033
+ diag::actor_isolated_global_actor_context,
2034
+ member->getDescriptiveKind (), member->getName (),
2035
+ contextIsolation.getGlobalActor ());
2048
2036
noteIsolatedActorMember (member, context);
2049
2037
return true ;
2038
+ }
2050
2039
}
2051
2040
llvm_unreachable (" Unhandled actor isolation" );
2052
2041
}
0 commit comments