-
Notifications
You must be signed in to change notification settings - Fork 10.5k
/
Copy pathTypeCheckConcurrency.h
243 lines (205 loc) · 8.39 KB
/
TypeCheckConcurrency.h
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
//===--- 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/ConcreteDeclRef.h"
#include "swift/AST/DiagnosticEngine.h"
#include "swift/AST/Type.h"
#include <cassert>
namespace swift {
class AbstractFunctionDecl;
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 PatternBindingDecl;
class ProtocolConformance;
class TopLevelCodeDecl;
class TypeBase;
class ValueDecl;
/// Add notes suggesting the addition of 'async' or '@asyncHandler', 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 checkInitializerActorIsolation(Initializer *init, Expr *expr);
void checkEnumElementActorIsolation(EnumElementDecl *element, Expr *expr);
void checkPropertyWrapperActorIsolation(
PatternBindingDecl *binding, Expr *expr);
/// Describes the kind of operation that introduced the concurrent refernece.
enum class ConcurrentReferenceKind {
/// A synchronous operation that was "promoted" to an asynchronous call
/// because it was out of the actor's domain.
SynchronousAsAsyncCall,
/// A cross-actor reference.
CrossActor,
/// A local capture referenced from concurrent code.
LocalCapture,
/// Concurrent function
ConcurrentFunction,
};
/// The isolation restriction in effect for a given declaration that is
/// referenced from source.
class ActorIsolationRestriction {
public:
enum Kind {
/// There is no restriction on references to the given declaration.
Unrestricted,
/// Access to the declaration is unsafe in any concurrent context.
Unsafe,
/// References to this entity are allowed from anywhere, but doing so
/// may cross an actor boundary if it is not from within the same actor's
/// isolation domain.
CrossActorSelf,
/// References to this member of an actor are only permitted from within
/// the actor's isolation domain.
ActorSelf,
/// References to a declaration that is part of a global actor are
/// permitted from other declarations with that same global actor or
/// are permitted from elsewhere as a cross-actor reference.
GlobalActor,
/// References to a declaration that is part of a global actor are
/// permitted from other declarations with that same global actor or
/// are permitted from elsewhere as a cross-actor reference, but
/// contexts with unspecified isolation won't diagnose anything.
GlobalActorUnsafe,
};
private:
union {
/// The local context that an entity is tied to.
DeclContext *localContext;
/// The actor that the entity is declared in.
NominalTypeDecl *actorType;
/// The global actor type.
TypeBase *globalActor;
} data;
explicit ActorIsolationRestriction(Kind kind, bool isCrossActor)
: kind(kind), isCrossActor(isCrossActor) { }
public:
/// The kind of restriction.
const Kind kind;
/// Whether referencing this from another actor constitutes a cross-acter
/// reference.
const bool isCrossActor;
Kind getKind() const { return kind; }
/// Retrieve the actor type that the declaration is within.
NominalTypeDecl *getActorType() const {
assert(kind == ActorSelf || kind == CrossActorSelf);
return data.actorType;
}
/// Retrieve the actor that the declaration is within.
Type getGlobalActor() const {
assert(kind == GlobalActor || kind == GlobalActorUnsafe);
return Type(data.globalActor);
}
/// There are no restrictions on the use of the entity.
static ActorIsolationRestriction forUnrestricted() {
return ActorIsolationRestriction(Unrestricted, /*isCrossActor=*/false);
}
/// Accesses to the given declaration are unsafe.
static ActorIsolationRestriction forUnsafe() {
return ActorIsolationRestriction(Unsafe, /*isCrossActor=*/false);
}
/// Accesses to the given declaration can only be made via the 'self' of
/// the current actor or is a cross-actor access.
static ActorIsolationRestriction forActorSelf(
NominalTypeDecl *actor, bool isCrossActor) {
ActorIsolationRestriction result(isCrossActor? CrossActorSelf : ActorSelf,
isCrossActor);
result.data.actorType = actor;
return result;
}
/// Accesses to the given declaration can only be made via this particular
/// global actor or is a cross-actor access.
static ActorIsolationRestriction forGlobalActor(
Type globalActor, bool isCrossActor, bool isUnsafe) {
ActorIsolationRestriction result(
isUnsafe ? GlobalActorUnsafe : GlobalActor, isCrossActor);
result.data.globalActor = globalActor.getPointer();
return result;
}
/// Determine the isolation rules for a given declaration.
static ActorIsolationRestriction forDeclaration(ConcreteDeclRef declRef);
operator Kind() const { return kind; };
};
/// Check that the actor isolation of an override matches that of its
/// overridden declaration.
void checkOverrideActorIsolation(ValueDecl *value);
/// Determine whether the given context uses concurrency features, such
/// as async functions or actors.
bool contextUsesConcurrencyFeatures(const DeclContext *dc);
/// Diagnose the presence of any non-concurrent 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 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 dc The declaration context from which the reference occurs. This is
/// used to perform lookup of conformances to the \c Sendable protocol.
///
/// \param loc 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.
///
/// \returns true if an problem was detected, false otherwise.
bool diagnoseNonConcurrentTypesInReference(
ConcreteDeclRef declRef, const DeclContext *dc, SourceLoc loc,
ConcurrentReferenceKind refKind,
DiagnosticBehavior behavior = DiagnosticBehavior::Unspecified);
/// How the concurrent value check should be performed.
enum class SendableCheck {
/// Sendable conformance was explicitly stated and should be
/// fully checked.
Explicit,
/// Sendable conformance was implied by one of the standard library
/// protocols that added Sendable after-the-fact.
ImpliedByStandardProtocol,
/// Implicit conformance to Sendable for structs and enums.
Implicit,
};
/// 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 None).
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);
/// Check the correctness of the given Sendable conformance.
///
/// \returns true if an error occurred.
bool checkSendableConformance(
ProtocolConformance *conformance, SendableCheck check);
} // end namespace swift
#endif /* SWIFT_SEMA_TYPECHECKCONCURRENCY_H */