1414//
1515// ===----------------------------------------------------------------------===//
1616
17+ #include " TypeCheckConcurrency.h"
1718#include " TypeChecker.h"
1819#include " swift/AST/ASTContext.h"
1920#include " swift/AST/ASTMangler.h"
21+ #include " swift/AST/ActorIsolation.h"
2022#include " swift/AST/Attr.h"
2123#include " swift/AST/Decl.h"
2224#include " swift/AST/Initializer.h"
@@ -46,6 +48,184 @@ ValueDecl::getRuntimeDiscoverableAttributeGenerator(CustomAttr *attr) const {
4648 return std::make_pair (body, init->getType ()->mapTypeOutOfContext ());
4749}
4850
51+ static TypeRepr *buildTypeRepr (DeclContext *typeContext) {
52+ assert (typeContext->isTypeContext ());
53+
54+ SmallVector<ComponentIdentTypeRepr *, 2 > components;
55+
56+ auto &ctx = typeContext->getASTContext ();
57+ DeclContext *DC = typeContext;
58+ while (!DC->isModuleContext ()) {
59+ auto *NTD = DC->getSelfNominalTypeDecl ();
60+ // Only contiguous chains of nominals and extensions thereof.
61+ if (!NTD)
62+ break ;
63+
64+ auto *component = new (ctx) SimpleIdentTypeRepr (
65+ /* Loc=*/ DeclNameLoc (), NTD->createNameRef ());
66+
67+ // Resolve the component right away, instead of
68+ // involving name lookup. This plays well with
69+ // the fact that initializer is anchored on a
70+ // source file.
71+ component->setValue (NTD, NTD->getDeclContext ());
72+
73+ components.push_back (component);
74+ DC = NTD->getDeclContext ();
75+ }
76+
77+ // Reverse the components to form a valid outer-to-inner name sequence.
78+ std::reverse (components.begin (), components.end ());
79+
80+ if (components.size () == 1 )
81+ return components.front ();
82+
83+ return CompoundIdentTypeRepr::create (ctx, components);
84+ }
85+
86+ // / Synthesizes a closure thunk that forwards all of the arguments
87+ // / to the underlying method. This is required to support mutating
88+ // / methods and create uniform signatures where for instance methods
89+ // / first parameter is always `self` (with or without `inout`).
90+ static ClosureExpr *synthesizeMethodThunk (DeclContext *thunkDC,
91+ NominalTypeDecl *nominal,
92+ FuncDecl *method) {
93+ auto &ctx = method->getASTContext ();
94+
95+ // If this is a method, let's form a thunk so that attribute initializer
96+ // gets `([inout] T, Argument, ...) -> Result` signature.
97+ auto *funcParams = method->getParameters ();
98+
99+ SmallVector<ParamDecl *, 4 > closureParams;
100+
101+ NullablePtr<ParamDecl> selfParam;
102+ if (!method->isStatic ()) {
103+ auto *self = ParamDecl::createImplicit (
104+ ctx,
105+ /* argumentName=*/ Identifier (),
106+ /* parameterName=*/ ctx.Id_self ,
107+ /* type=*/ nominal->getDeclaredInterfaceType (), thunkDC,
108+ method->isMutating () ? ParamSpecifier::InOut : ParamSpecifier::Default);
109+
110+ // This is very important for the solver, without a type repr
111+ // it would create a type variable and attempt infer the type
112+ // from the body.
113+ self->setTypeRepr (buildTypeRepr (nominal));
114+
115+ closureParams.push_back (self);
116+ selfParam = self;
117+ }
118+
119+ if (funcParams) {
120+ unsigned anonIdx = 0 ;
121+ for (auto *param : *funcParams) {
122+ auto name = param->getParameterName ();
123+ // Cannot leave parameter anonymous because it would be
124+ // referenced in the body.
125+ if (name.empty ())
126+ name = ctx.getIdentifier ((Twine (" $anon" ) + Twine (anonIdx++)).str ());
127+
128+ auto *closureParam = ParamDecl::createImplicit (
129+ ctx,
130+ /* argumentName=*/ Identifier (),
131+ /* parameterName=*/ name, param->getInterfaceType (), thunkDC,
132+ param->getSpecifier ());
133+ closureParam->setTypeRepr (param->getTypeRepr ());
134+
135+ closureParams.push_back (closureParam);
136+ }
137+ }
138+
139+ // return self.<func>(<arguments>)
140+ SmallVector<ASTNode, 2 > body;
141+ {
142+ NullablePtr<Expr> baseExpr;
143+ if (method->isStatic ()) {
144+ baseExpr =
145+ TypeExpr::createImplicit (nominal->getDeclaredInterfaceType (), ctx);
146+ } else {
147+ baseExpr = new (ctx) DeclRefExpr ({selfParam.get ()}, /* Loc=*/ DeclNameLoc (),
148+ /* implicit=*/ true );
149+ }
150+
151+ auto *memberRef = new (ctx) MemberRefExpr (
152+ baseExpr.get (), /* dotLoc=*/ SourceLoc (), {method}, /* loc=*/ DeclNameLoc (),
153+ /* Implicit=*/ true );
154+
155+ SmallVector<Argument, 4 > arguments;
156+ if (funcParams) {
157+ for (unsigned i = 0 , n = funcParams->size (); i != n; ++i) {
158+ const auto *param = funcParams->get (i);
159+
160+ Expr *argExpr = new (ctx)
161+ DeclRefExpr ({closureParams[method->isStatic () ? i : i + 1 ]},
162+ /* Loc=*/ DeclNameLoc (),
163+ /* implicit=*/ true );
164+
165+ if (param->isInOut ()) {
166+ argExpr = new (ctx) InOutExpr (/* operLoc=*/ SourceLoc (), argExpr,
167+ Type (), /* implicit=*/ true );
168+ }
169+
170+ arguments.push_back (
171+ {/* labelLoc=*/ SourceLoc (), param->getArgumentName (), argExpr});
172+ }
173+ }
174+
175+ Expr *call = CallExpr::createImplicit (
176+ ctx, memberRef, ArgumentList::createImplicit (ctx, arguments));
177+
178+ bool isAsync = false ;
179+ bool isThrows = method->hasThrows ();
180+
181+ switch (getActorIsolation (method)) {
182+ case ActorIsolation::Unspecified:
183+ case ActorIsolation::Independent: {
184+ isAsync = method->hasAsync ();
185+ break ;
186+ }
187+
188+ case ActorIsolation::ActorInstance: {
189+ isAsync = true ;
190+ isThrows |= nominal->isDistributedActor ();
191+ break ;
192+ }
193+
194+ case ActorIsolation::GlobalActor:
195+ isAsync = true ;
196+ LLVM_FALLTHROUGH;
197+ case ActorIsolation::GlobalActorUnsafe: {
198+ break ;
199+ }
200+ }
201+
202+ if (isAsync)
203+ call = AwaitExpr::createImplicit (ctx, /* awaitLoc=*/ SourceLoc (), call);
204+
205+ if (isThrows)
206+ call = TryExpr::createImplicit (ctx, /* tryLoc=*/ SourceLoc (), call);
207+
208+ body.push_back (new (ctx) ReturnStmt (/* ReturnLoc=*/ SourceLoc (), call,
209+ /* implicit=*/ true ));
210+ }
211+
212+ DeclAttributes attrs;
213+ auto *closure = new (ctx) ClosureExpr (
214+ attrs, /* bracketRange=*/ SourceRange (),
215+ /* capturedSelf=*/ nullptr , ParameterList::create (ctx, closureParams),
216+ /* asyncLoc=*/ SourceLoc (),
217+ /* throwsLoc=*/ SourceLoc (),
218+ /* arrowLoc=*/ SourceLoc (),
219+ /* inLoc=*/ SourceLoc (),
220+ /* explicitResultType=*/ nullptr , thunkDC);
221+
222+ closure->setBody (BraceStmt::createImplicit (ctx, body),
223+ /* isSingleExpr=*/ true );
224+ closure->setImplicit ();
225+
226+ return closure;
227+ }
228+
49229Expr *SynthesizeRuntimeMetadataAttrGenerator::evaluate (
50230 Evaluator &evaluator, CustomAttr *attr, ValueDecl *attachedTo) const {
51231 auto &ctx = attachedTo->getASTContext ();
@@ -77,13 +257,7 @@ Expr *SynthesizeRuntimeMetadataAttrGenerator::evaluate(
77257 DotSelfExpr (metatype, /* dot=*/ SourceLoc (), /* self=*/ SourceLoc ());
78258 } else if (auto *func = dyn_cast<FuncDecl>(attachedTo)) {
79259 if (auto *nominal = func->getDeclContext ()->getSelfNominalTypeDecl ()) {
80- auto *baseExpr =
81- TypeExpr::createImplicit (nominal->getDeclaredInterfaceType (), ctx);
82-
83- // Form an initializer call passing in the function reference
84- initArgument = new (ctx) MemberRefExpr (baseExpr, /* dotLoc=*/ SourceLoc (),
85- {func}, /* loc=*/ DeclNameLoc (),
86- /* Implicit=*/ true );
260+ initArgument = synthesizeMethodThunk (initContext, nominal, func);
87261 } else {
88262 initArgument = new (ctx)
89263 DeclRefExpr ({func}, /* Loc=*/ DeclNameLoc (), /* implicit=*/ true );
@@ -102,44 +276,7 @@ Expr *SynthesizeRuntimeMetadataAttrGenerator::evaluate(
102276 // Build a type repr for base of the key path, since attribute
103277 // could be attached to an inner type, we need to go up decl
104278 // contexts and add every parent type.
105- {
106- SmallVector<ComponentIdentTypeRepr *, 2 > baseNameComponents;
107-
108- auto *DC = var->getDeclContext ();
109- while (!DC->isModuleContext ()) {
110- auto *NTD = DC->getSelfNominalTypeDecl ();
111- // Only contiguous chains of nominals and extensions thereof.
112- if (!NTD)
113- break ;
114-
115- auto *component = new (ctx) SimpleIdentTypeRepr (
116- /* Loc=*/ DeclNameLoc (), NTD->createNameRef ());
117-
118- // Resolve the component right away, instead of
119- // involving name lookup. This plays well with
120- // the fact that initializer is anchored on a
121- // source file.
122- component->setValue (NTD, NTD->getDeclContext ());
123-
124- baseNameComponents.push_back (component);
125- DC = NTD->getDeclContext ();
126- }
127-
128- // Reverse the components to form a valid outer-to-inner name sequence.
129- std::reverse (baseNameComponents.begin (), baseNameComponents.end ());
130-
131- // Set the 'root' of the key path to the newly build base name.
132- // We cannot do this via `parsedRoot` because it has strict
133- // rules about leading-dot.
134- TypeRepr *rootName = nullptr ;
135- if (baseNameComponents.size () == 1 ) {
136- rootName = baseNameComponents.front ();
137- } else {
138- rootName = CompoundIdentTypeRepr::create (ctx, baseNameComponents);
139- }
140-
141- keyPath->setRootType (rootName);
142- }
279+ keyPath->setRootType (buildTypeRepr (var->getDeclContext ()));
143280
144281 initArgument = keyPath;
145282 }
@@ -177,6 +314,7 @@ Expr *SynthesizeRuntimeMetadataAttrGenerator::evaluate(
177314 return nullptr ;
178315
179316 TypeChecker::contextualizeInitializer (initContext, result);
317+ checkInitializerActorIsolation (initContext, result);
180318 TypeChecker::checkInitializerEffects (initContext, result);
181319
182320 return result;
0 commit comments