1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745
|
//===--- TypeCheckConcurrency.h - Concurrency -------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file provides type checking support for Swift's concurrency model.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SEMA_TYPECHECKCONCURRENCY_H
#define SWIFT_SEMA_TYPECHECKCONCURRENCY_H
#include "swift/AST/ASTContext.h"
#include "swift/AST/ConcreteDeclRef.h"
#include "swift/AST/DiagnosticEngine.h"
#include "swift/AST/Expr.h"
#include "swift/AST/Module.h"
#include "swift/AST/Type.h"
#include "swift/Sema/Concurrency.h"
#include <cassert>
namespace swift {
class AbstractFunctionDecl;
class ConstructorDecl;
class ActorIsolation;
class AnyFunctionType;
class ASTContext;
class ClassDecl;
class ClosureExpr;
class ConcreteDeclRef;
class CustomAttr;
class Decl;
class DeclContext;
class EnumElementDecl;
class Expr;
class FuncDecl;
class Initializer;
class LookupResult;
class PatternBindingDecl;
class ProtocolConformance;
class TopLevelCodeDecl;
class TypeBase;
class ValueDecl;
class VarDecl;
/// Add notes suggesting the addition of 'async', as appropriate,
/// to a diagnostic for a function that isn't an async context.
void addAsyncNotes(AbstractFunctionDecl const* func);
/// Check actor isolation rules.
void checkTopLevelActorIsolation(TopLevelCodeDecl *decl);
void checkFunctionActorIsolation(AbstractFunctionDecl *decl);
void checkEnumElementActorIsolation(EnumElementDecl *element, Expr *expr);
void checkPropertyWrapperActorIsolation(VarDecl *wrappedVar, Expr *expr);
/// States the reason for checking the Sendability of a given declaration.
enum class SendableCheckReason {
/// A reference to an actor from outside that actor.
CrossActor,
/// Exiting an actor to non-isolated async code.
ExitingActor,
/// A synchronous operation that was "promoted" to an asynchronous one
/// because it was out of the actor's domain.
SynchronousAsAsync,
/// A protocol conformance where the witness/requirement have different
/// actor isolation.
Conformance,
/// An override of a function.
Override,
/// The declaration is being exposed to Objective-C.
ObjC,
};
/// Check that the actor isolation of an override matches that of its
/// overridden declaration.
void checkOverrideActorIsolation(ValueDecl *value);
/// Determine whether the given context requires strict concurrency checking,
/// e.g., because it uses concurrency features directly or because it's in
/// code where strict checking has been enabled.
bool contextRequiresStrictConcurrencyChecking(
const DeclContext *dc,
llvm::function_ref<Type(const AbstractClosureExpr *)> getType,
llvm::function_ref<bool(const ClosureExpr *)> isolatedByPreconcurrency);
/// Describes a referenced actor variable and whether it is isolated.
struct ReferencedActor {
/// Describes whether the actor variable is isolated or, if it is not
/// isolated, why it is not isolated.
enum Kind {
/// It is isolated.
Isolated = 0,
/// It is not an isolated parameter at all.
NonIsolatedParameter,
// It is within a Sendable function.
SendableFunction,
// It is within a Sendable closure.
SendableClosure,
// It is within an 'async let' initializer.
AsyncLet,
// It is within a global actor.
GlobalActor,
// It is within the main actor.
MainActor,
// It is within a nonisolated context.
NonIsolatedContext,
// It is within a nonisolated autoclosure argument. This is primarily here
// to aid in giving specific diagnostics, because autoclosures are not
// always easy for programmers to notice.
NonIsolatedAutoclosure
};
VarDecl * const actor;
/// The outer scope is known to be running on an actor.
/// We may be isolated to the actor or not, depending on the exact expression
const bool isPotentiallyIsolated;
const Kind kind;
const Type globalActor;
ReferencedActor(VarDecl *actor, bool isPotentiallyIsolated, Kind kind, Type globalActor = Type())
: actor(actor),
isPotentiallyIsolated(isPotentiallyIsolated),
kind(kind),
globalActor(globalActor) {}
static ReferencedActor forGlobalActor(VarDecl *actor,
bool isPotentiallyIsolated,
Type globalActor);
bool isIsolated() const { return kind == Isolated; }
/// Whether the variable is "self" or a capture therefore.
bool isSelf() const {
if (!actor)
return false;
return actor->isSelfParameter() || actor->isSelfParamCapture();
}
/// Whether the referenced actor is known to be local.
bool isKnownToBeLocal() const;
explicit operator bool() const { return isIsolated(); }
};
/// The values for each case in this enum correspond to %select numbers
/// in a diagnostic, so be sure to update it if you add new cases.
enum class VarRefUseEnv {
Read = 0,
Mutating = 1,
Inout = 2 // means Mutating; having a separate kind helps diagnostics
};
/// Describes the result of referencing a declaration.
struct ActorReferenceResult {
enum Kind: uint8_t {
/// The declaration being referenced is within the same concurrency
/// domain as where the reference occurs, so no checking is required.
SameConcurrencyDomain,
/// Using the declaration requires entering a new actor, which might also
/// mean switching away from the current actor.
EntersActor,
/// Using the declaration means leaving the current actor, exiting to
/// a nonisolated context.
ExitsActorToNonisolated,
};
/// Flags describing any additional adjustments or requirements when
/// accessing the declaration.
enum class Flags: uint8_t {
/// A synchronous declaration must be accessed asynchronously to enter its
/// actor.
AsyncPromotion = 1 << 0,
/// A non-throwing declaration that is potentially being accessed from
/// another node, and can therefore throw an error due to transport
/// failure.
ThrowsPromotion = 1 << 1,
/// The declaration is being accessed from outside the actor and
/// potentially from a different node, so it must be marked 'distributed'.
Distributed = 1 << 2,
/// The declaration is being accessed from a @preconcurrency context.
Preconcurrency = 1 << 3,
/// Only arguments cross an isolation boundary, e.g. because they
/// escape into an actor in a nonisolated actor initializer.
OnlyArgsCrossIsolation = 1 << 4,
};
using Options = OptionSet<Flags>;
const Kind kind;
const Options options;
const ActorIsolation isolation;
private:
static ActorReferenceResult
forSameConcurrencyDomain(ActorIsolation isolation,
Options options = std::nullopt);
static ActorReferenceResult forEntersActor(
ActorIsolation isolation, Options options);
static ActorReferenceResult
forExitsActorToNonisolated(ActorIsolation isolation,
Options options = std::nullopt);
public:
/// Determine what happens when referencing the given declaration from the
/// given declaration context.
///
///
/// \param declRef The declaration that is being referenced.
///
/// \param fromDC The declaration context from which the reference occurs.
///
/// \param actorInstance When not \c None, the actor instance value that is
/// provided when referencing the declaration. This can be either the base
/// of a member access or a parameter passed to a function.
static ActorReferenceResult forReference(
ConcreteDeclRef declRef, SourceLoc declRefLoc, const DeclContext *fromDC,
std::optional<VarRefUseEnv> useKind = std::nullopt,
std::optional<ReferencedActor> actorInstance = std::nullopt,
std::optional<ActorIsolation> knownDeclIsolation = std::nullopt,
std::optional<ActorIsolation> knownContextIsolation = std::nullopt,
llvm::function_ref<ActorIsolation(AbstractClosureExpr *)>
getClosureActorIsolation = __AbstractClosureExpr_getActorIsolation);
operator Kind() const { return kind; }
};
struct IsolationError {
SourceLoc loc;
bool preconcurrency;
Diagnostic diag;
public:
IsolationError(SourceLoc loc, bool preconcurrency, Diagnostic diag) : loc(loc), preconcurrency(preconcurrency), diag(diag) {}
};
/// Individual options used with \c FunctionCheckOptions
enum class FunctionCheckKind {
/// Check params
Params = 1 << 0,
/// Check results
Results = 1 << 1,
};
/// Specifies whether checks applied to function types should apply to
/// their parameters, their results, both, or neither.
using FunctionCheckOptions = OptionSet<FunctionCheckKind>;
/// Diagnose the presence of any non-sendable types when referencing a
/// given declaration from a particular declaration context.
///
/// This function should be invoked any time that the given declaration
/// reference is will move values of the declaration's types across a
/// concurrency domain, whether in/out of an actor or in/or of a concurrent
/// function or closure.
///
/// \param base The base expression of the reference, which must be 'Sendable'
/// in order to cross actor isolation boundaries.
///
/// \param declRef The declaration being referenced from another concurrency
/// domain, including the substitutions so that (e.g.) we can consider the
/// specific types at the use site.
///
/// \param fromDC The context from which the reference occurs.
///
/// \param refLoc The location at which the reference occurs, which will be
/// used when emitting diagnostics.
///
/// \param refKind Describes what kind of reference is being made, which is
/// used to tailor the diagnostic.
///
/// \param funcCheckOptions Describes whether function types in this reference
/// should be checked for sendability of their results, params, or both
///
/// \param diagnoseLoc Provides an alternative source location to `refLoc`
/// to be used for reporting the top level diagnostic while auxiliary
/// warnings and diagnostics are reported at `refLoc`.
///
/// \returns true if an problem was detected, false otherwise.
bool diagnoseNonSendableTypesInReference(
Expr *base, ConcreteDeclRef declRef, const DeclContext *fromDC,
SourceLoc refLoc, SendableCheckReason refKind,
std::optional<ActorIsolation> knownIsolation = std::nullopt,
FunctionCheckOptions funcCheckOptions = (FunctionCheckOptions() |
FunctionCheckKind::Params |
FunctionCheckKind::Results),
SourceLoc diagnoseLoc = SourceLoc());
/// Produce a diagnostic for a missing conformance to Sendable.
void diagnoseMissingSendableConformance(
SourceLoc loc, Type type, const DeclContext *fromDC, bool preconcurrency);
/// If the given nominal type is public and does not explicitly
/// state whether it conforms to Sendable, provide a diagnostic.
void diagnoseMissingExplicitSendable(NominalTypeDecl *nominal);
/// Warn about deprecated `Executor.enqueue` implementations.
void tryDiagnoseExecutorConformance(ASTContext &C, const NominalTypeDecl *nominal, ProtocolDecl *proto);
/// Whether to suppress deprecation diagnostics for \p decl in \p declContext
/// because \p decl is a deprecated decl from the `_Concurrency` module and is
/// being referenced from the implementation of the `_Concurrency` module. This
/// prevents unaddressable warnings in the standard library build. Ideally, a
/// language feature would obviate the need for this.
bool shouldIgnoreDeprecationOfConcurrencyDecl(const Decl *decl,
DeclContext *declContext);
// Get a concrete reference to a declaration
ConcreteDeclRef getDeclRefInContext(ValueDecl *value);
/// How the Sendable check should be performed.
enum class SendableCheck {
/// Sendable conformance was explicitly stated and should be
/// fully checked.
Explicit,
/// Sendable conformance was implied by a protocol that inherits from
/// Sendable and also predates concurrency.
ImpliedByStandardProtocol,
/// Implicit conformance to Sendable.
Implicit,
/// Implicit conformance to Sendable that would be externally-visible, i.e.,
/// for a public @_frozen type.
ImplicitForExternallyVisible,
};
/// Whether this sendable check is implicit.
static inline bool isImplicitSendableCheck(SendableCheck check) {
switch (check) {
case SendableCheck::Explicit:
case SendableCheck::ImpliedByStandardProtocol:
return false;
case SendableCheck::Implicit:
case SendableCheck::ImplicitForExternallyVisible:
return true;
}
}
/// Describes the context in which a \c Sendable check occurs.
struct SendableCheckContext {
const DeclContext * const fromDC;
bool preconcurrencyContext;
const std::optional<SendableCheck> conformanceCheck;
SendableCheckContext(
const DeclContext *fromDC,
std::optional<SendableCheck> conformanceCheck = std::nullopt)
: fromDC(fromDC),
preconcurrencyContext(false),
conformanceCheck(conformanceCheck) {}
SendableCheckContext(
const DeclContext *fromDC,
bool preconcurrencyContext,
std::optional<SendableCheck> conformanceCheck = std::nullopt)
: fromDC(fromDC),
preconcurrencyContext(preconcurrencyContext),
conformanceCheck(conformanceCheck) {}
/// Determine the default diagnostic behavior for a missing/unavailable
/// Sendable conformance in this context.
DiagnosticBehavior defaultDiagnosticBehavior() const;
/// Determine the diagnostic behavior for an implicitly non-Sendable type.
DiagnosticBehavior implicitSendableDiagnosticBehavior() const;
/// Determine the diagnostic behavior when referencing the given nominal
/// type in this context.
DiagnosticBehavior diagnosticBehavior(NominalTypeDecl *nominal) const;
std::optional<DiagnosticBehavior> preconcurrencyBehavior(
Decl *decl,
bool ignoreExplicitConformance = false) const;
/// Whether to warn about a Sendable violation even in minimal checking.
bool warnInMinimalChecking() const;
};
/// Diagnose any non-Sendable types that occur within the given type, using
/// the given diagnostic.
///
/// \param diagnose Emit a diagnostic indicating that the current type
/// is non-Sendable, with the suggested behavior limitation. Returns \c true
/// if it did not emit any diagnostics.
///
/// \returns \c true if any errors were produced, \c false if no diagnostics or
/// only warnings and notes were produced.
bool diagnoseNonSendableTypes(
Type type, SendableCheckContext fromContext,
Type inDerivedConformance, SourceLoc loc,
llvm::function_ref<bool(Type, DiagnosticBehavior)> diagnose);
namespace detail {
template<typename T>
struct Identity {
typedef T type;
};
}
/// Diagnose any non-Sendable types that occur within the given type, using
/// the given diagnostic.
///
/// \param typeLoc is the source location of the type being diagnosed
///
/// \param diagnoseLoc is the source location at which the main diagnostic should
/// be reported, which can differ from typeLoc
///
/// \returns \c true if any errors were produced, \c false if no diagnostics or
/// only warnings and notes were produced.
template<typename ...DiagArgs>
bool diagnoseNonSendableTypes(
Type type, SendableCheckContext fromContext,
Type derivedConformance,
SourceLoc typeLoc, SourceLoc diagnoseLoc,
Diag<Type, DiagArgs...> diag,
typename detail::Identity<DiagArgs>::type ...diagArgs) {
ASTContext &ctx = fromContext.fromDC->getASTContext();
return diagnoseNonSendableTypes(
type, fromContext, derivedConformance, typeLoc,
[&](Type specificType, DiagnosticBehavior behavior) {
// FIXME: Reconcile preconcurrency declaration vs preconcurrency
// import behavior.
auto preconcurrency =
fromContext.preconcurrencyBehavior(specificType->getAnyNominal());
ctx.Diags.diagnose(diagnoseLoc, diag, type, diagArgs...)
.limitBehaviorWithPreconcurrency(behavior,
fromContext.preconcurrencyContext)
.limitBehaviorIf(preconcurrency);
return (behavior == DiagnosticBehavior::Ignore ||
preconcurrency == DiagnosticBehavior::Ignore);
});
}
/// Emit a diagnostic if there are any non-Sendable types for which
/// the Sendable diagnostic wasn't suppressed. This diagnostic will
/// only be emitted once, but there might be additional notes for the
/// various occurrences of Sendable types.
///
/// \param typeLoc is the source location of the type being diagnosed
///
/// \param diagnoseLoc is the source location at which the main diagnostic should
/// be reported, which can differ from typeLoc
///
/// \returns \c true if any diagnostics.
template<typename ...DiagArgs>
bool diagnoseIfAnyNonSendableTypes(
Type type, SendableCheckContext fromContext,
Type derivedConformance,
SourceLoc typeLoc, SourceLoc diagnoseLoc,
Diag<Type, DiagArgs...> diag,
typename detail::Identity<DiagArgs>::type ...diagArgs) {
ASTContext &ctx = fromContext.fromDC->getASTContext();
bool diagnosed = false;
diagnoseNonSendableTypes(
type, fromContext, derivedConformance, typeLoc,
[&](Type specificType, DiagnosticBehavior behavior) {
auto preconcurrency =
fromContext.preconcurrencyBehavior(specificType->getAnyNominal());
if (behavior == DiagnosticBehavior::Ignore ||
preconcurrency == DiagnosticBehavior::Ignore)
return true;
if (!diagnosed) {
ctx.Diags.diagnose(diagnoseLoc, diag, type, diagArgs...)
.limitBehaviorUntilSwiftVersion(behavior, 6)
.limitBehaviorIf(preconcurrency);
diagnosed = true;
}
return false;
});
return diagnosed;
}
/// Diagnose any non-Sendable types that occur within the given type, using
/// the given diagnostic.
///
/// \returns \c true if any errors were produced, \c false if no diagnostics or
/// only warnings and notes were produced.
template<typename ...DiagArgs>
bool diagnoseNonSendableTypes(
Type type, SendableCheckContext fromContext,
Type derivedConformance, SourceLoc loc,
Diag<Type, DiagArgs...> diag,
typename detail::Identity<DiagArgs>::type ...diagArgs) {
return diagnoseNonSendableTypes(
type, fromContext, derivedConformance, loc, loc, diag,
std::forward<decltype(diagArgs)>(diagArgs)...);
}
/// Diagnose this sendability error with behavior based on the import of
/// \p nominal . For instance, depending on how \p nominal is imported into
/// \p fromContext , the diagnostic behavior limitation may be lower or the
/// compiler might emit a fix-it adding \c \@preconcurrency to the \c import .
///
/// \param nominal The declaration whose import we should check, or \c nullptr
/// to get behavior for a non-nominal type.
///
/// \param fromContext The context where the error will be emitted.
///
/// \param diagnose Emit a diagnostic indicating a sendability problem,
/// with the suggested behavior limitation. Returns \c true
/// if it did \em not emit any diagnostics.
///
/// \returns \c true if any errors were produced, \c false if no diagnostics or
/// only warnings and notes were produced.
bool diagnoseSendabilityErrorBasedOn(
NominalTypeDecl *nominal, SendableCheckContext fromContext,
llvm::function_ref<bool(DiagnosticBehavior)> diagnose);
/// Given a set of custom attributes, pick out the global actor attributes
/// and perform any necessary resolution and diagnostics, returning the
/// global actor attribute and type it refers to (or \c std::nullopt).
std::optional<std::pair<CustomAttr *, NominalTypeDecl *>>
checkGlobalActorAttributes(SourceLoc loc, DeclContext *dc,
ArrayRef<CustomAttr *> attrs);
/// Get the explicit global actor specified for a closure.
Type getExplicitGlobalActor(ClosureExpr *closure);
/// Adjust the type of the variable for concurrency.
Type adjustVarTypeForConcurrency(
Type type, VarDecl *var, DeclContext *dc,
llvm::function_ref<Type(const AbstractClosureExpr *)> getType,
llvm::function_ref<bool(const ClosureExpr *)> isolatedByPreconcurrency);
/// Adjust the given function type to account for concurrency-specific
/// attributes whose affect on the type might differ based on context.
/// This includes adjustments for unsafe parameter attributes like
/// `@_unsafeSendable` and `@_unsafeMainActor` as well as a global actor
/// on the declaration itself.
AnyFunctionType *adjustFunctionTypeForConcurrency(
AnyFunctionType *fnType, ValueDecl *decl, DeclContext *dc,
unsigned numApplies, bool isMainDispatchQueue,
llvm::function_ref<Type(const AbstractClosureExpr *)> getType,
llvm::function_ref<bool(const ClosureExpr *)> isolatedByPreconcurrency,
llvm::function_ref<Type(Type)> openType);
/// Classifies known dispatch queue operations.
enum class DispatchQueueOperation {
/// This is a dispatch operation we know about.
Normal,
/// The closure passed to this dispatch queue operation should be Sendable.
Sendable,
};
/// Determine whether the given name is that of a DispatchQueue operation that
/// takes a closure to be executed on the queue.
std::optional<DispatchQueueOperation>
isDispatchQueueOperationName(StringRef name);
/// Check the correctness of the given Sendable conformance.
///
/// \returns true if an error occurred.
bool checkSendableConformance(
ProtocolConformance *conformance, SendableCheck check);
/// Derive an implicit conformance for the given nominal type to
/// the Sendable protocol. You want to be using
/// `ImplicitKnownProtocolConformanceRequest` instead of this.
ProtocolConformance *deriveImplicitSendableConformance(Evaluator &evaluator,
NominalTypeDecl *nominal);
/// Check whether we are in an actor's initializer or deinitializer.
/// \returns nullptr iff we are not in such a declaration. Otherwise,
/// returns a pointer to the declaration.
const AbstractFunctionDecl *isActorInitOrDeInitContext(const DeclContext *dc);
/// Determine whether this declaration is always accessed asynchronously.
bool isAsyncDecl(ConcreteDeclRef declRef);
/// Determine whether this declaration can throw errors.
bool isThrowsDecl(ConcreteDeclRef declRef);
/// Find the directly-referenced parameter or capture of a parameter for
/// for the given expression.
VarDecl *getReferencedParamOrCapture(
Expr *expr,
llvm::function_ref<Expr *(OpaqueValueExpr *)> getExistentialValue,
llvm::function_ref<VarDecl *()> getCurrentIsolatedVar);
/// Determine whether the given value can be accessed across actors
/// without from normal synchronous code.
///
/// \param value The value we are checking.
/// \param isolation The actor isolation of the value.
/// \param fromDC The context where we are performing the access.
/// \param options The reference options, such as whether reference
/// violations should be downgraded to warnings prior to Swift 6.
bool isAccessibleAcrossActors(
ValueDecl *value, const ActorIsolation &isolation,
const DeclContext *fromDC, ActorReferenceResult::Options &options,
std::optional<ReferencedActor> actorInstance = std::nullopt);
/// Determine whether the given value can be accessed across actors
/// without from normal synchronous code.
///
/// \param value The value we are checking.
/// \param isolation The actor isolation of the value.
/// \param fromDC The context where we are performing the access.
bool isAccessibleAcrossActors(
ValueDecl *value, const ActorIsolation &isolation,
const DeclContext *fromDC,
std::optional<ReferencedActor> actorInstance = std::nullopt);
/// Determines if the 'let' can be read from anywhere within the given module,
/// regardless of the isolation or async-ness of the context in which
/// the var is read.
bool isLetAccessibleAnywhere(const ModuleDecl *fromModule,
VarDecl *let,
ActorReferenceResult::Options &options);
/// Check whether given variable references to a potentially
/// isolated actor.
bool isPotentiallyIsolatedActor(
VarDecl *var, llvm::function_ref<bool(ParamDecl *)> isIsolated =
[](ParamDecl *P) { return P->isIsolated(); });
/// Check whether the given ApplyExpr makes an unsatisfied isolation jump
/// and if so, emit diagnostics for any nonsendable arguments to the apply
bool diagnoseApplyArgSendability(
swift::ApplyExpr *apply, const DeclContext *declContext);
/// If the enclosing function has @_unsafeInheritExecutorAttr, return it.
AbstractFunctionDecl *enclosingUnsafeInheritsExecutor(const DeclContext *dc);
/// Add Fix-Its to the given function to replace the @_unsafeInheritExecutor
/// attribute with a defaulted isolation parameter.
void replaceUnsafeInheritExecutorWithDefaultedIsolationParam(
AbstractFunctionDecl *func, InFlightDiagnostic &diag);
/// Replace any functions in this list that were found in the _Concurrency
/// module and have _unsafeInheritExecutor_-prefixed versions with those
/// _unsafeInheritExecutor_-prefixed versions.
///
/// This function is an egregious hack that allows us to introduce the
/// #isolation-based versions of functions into the concurrency library
/// without breaking clients that use @_unsafeInheritExecutor. Since those
/// clients can't use #isolation (it doesn't work with @_unsafeInheritExecutor),
/// we route them to the @_unsafeInheritExecutor versions implicitly.
void introduceUnsafeInheritExecutorReplacements(
const DeclContext *dc, SourceLoc loc, SmallVectorImpl<ValueDecl *> &decls);
/// Replace any functions in this list that were found in the _Concurrency
/// module as a member on "base" and have _unsafeInheritExecutor_-prefixed
/// versions with those _unsafeInheritExecutor_-prefixed versions.
///
/// This function is an egregious hack that allows us to introduce the
/// #isolation-based versions of functions into the concurrency library
/// without breaking clients that use @_unsafeInheritExecutor. Since those
/// clients can't use #isolation (it doesn't work with @_unsafeInheritExecutor),
/// we route them to the @_unsafeInheritExecutor versions implicitly.
void introduceUnsafeInheritExecutorReplacements(
const DeclContext *dc, Type base, SourceLoc loc, LookupResult &result);
} // end namespace swift
namespace llvm {
template <>
struct DenseMapInfo<swift::ReferencedActor::Kind> {
using RefActorKind = swift::ReferencedActor::Kind;
static RefActorKind getEmptyKey() {
return RefActorKind::NonIsolatedContext;
}
static RefActorKind getTombstoneKey() {
return RefActorKind::NonIsolatedContext;
}
static unsigned getHashValue(RefActorKind Val) {
return static_cast<unsigned>(Val);
}
static bool isEqual(const RefActorKind &LHS, const RefActorKind &RHS) {
return LHS == RHS;
}
};
template <>
struct DenseMapInfo<swift::ActorIsolation> {
using RefActor = swift::ActorIsolation;
static RefActor getEmptyKey() {
return RefActor(swift::ActorIsolation::Kind::Unspecified);
}
static RefActor getTombstoneKey() {
return RefActor(swift::ActorIsolation::Kind::Unspecified);
}
static unsigned getHashValue(RefActor Val) {
return hash_value(Val);
}
static bool isEqual(const RefActor &LHS, const RefActor &RHS) {
return LHS == RHS;
}
};
} // end namespace llvm
#endif /* SWIFT_SEMA_TYPECHECKCONCURRENCY_H */
|