Skip to content

Commit f7f2e37

Browse files
committed
[Sema] RuntimeMetadata: Synthesize a body for runtime attribute generator
Single expression is not going to cut it in this case because attribute and attached declaration could have different availability, so we need to use `if #available` to guard attribute instantiation and return `nil` in cases where types are not available.
1 parent 76f352d commit f7f2e37

8 files changed

+128
-13
lines changed

include/swift/AST/Decl.h

+5-3
Original file line numberDiff line numberDiff line change
@@ -2805,9 +2805,11 @@ class ValueDecl : public Decl {
28052805
/// to place it for maximum impact.
28062806
NominalTypeDecl *getRuntimeDiscoverableAttrTypeDecl(CustomAttr *attr) const;
28072807

2808-
/// Given a runtime discoverable attribute, return a generator call
2809-
/// which could be used to instantiate it for this declaration.
2810-
Expr *getRuntimeDiscoverableAttributeGenerator(CustomAttr *) const;
2808+
/// Given a runtime discoverable attribute, return a generator
2809+
/// which could be used to instantiate it for this declaration
2810+
/// together with its result type.
2811+
std::pair<BraceStmt *, Type>
2812+
getRuntimeDiscoverableAttributeGenerator(CustomAttr *) const;
28112813
};
28122814

28132815
/// This is a common base class for declarations which declare a type.

include/swift/AST/TypeCheckRequests.h

+17
Original file line numberDiff line numberDiff line change
@@ -3830,6 +3830,23 @@ class SynthesizeRuntimeMetadataAttrGenerator
38303830
bool isCached() const { return true; }
38313831
};
38323832

3833+
class SynthesizeRuntimeMetadataAttrGeneratorBody
3834+
: public SimpleRequest<SynthesizeRuntimeMetadataAttrGeneratorBody,
3835+
BraceStmt *(CustomAttr *, ValueDecl *),
3836+
RequestFlags::Cached> {
3837+
public:
3838+
using SimpleRequest::SimpleRequest;
3839+
3840+
private:
3841+
friend SimpleRequest;
3842+
3843+
BraceStmt *evaluate(Evaluator &evaluator, CustomAttr *attr,
3844+
ValueDecl *attachedTo) const;
3845+
3846+
public:
3847+
bool isCached() const { return true; }
3848+
};
3849+
38333850
/// Compute the local discriminators for the given declaration context.
38343851
///
38353852
/// This is a state-changing operation for closures within the context, which

include/swift/AST/TypeCheckerTypeIDZone.def

+3
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,9 @@ SWIFT_REQUEST(TypeChecker, MacroDefinitionRequest,
452452
SWIFT_REQUEST(TypeChecker, SynthesizeRuntimeMetadataAttrGenerator,
453453
Expr *(CustomAttr *, ValueDecl *),
454454
Cached, NoLocationInfo)
455+
SWIFT_REQUEST(TypeChecker, SynthesizeRuntimeMetadataAttrGeneratorBody,
456+
BraceStmt *(CustomAttr *, ValueDecl *),
457+
Cached, NoLocationInfo)
455458
SWIFT_REQUEST(TypeChecker, GetRuntimeDiscoverableAttributes,
456459
ArrayRef<CustomAttr *>(ValueDecl *),
457460
Cached, NoLocationInfo)

lib/SIL/IR/TypeLowering.cpp

+2-3
Original file line numberDiff line numberDiff line change
@@ -3235,11 +3235,10 @@ getRuntimeAttributeGeneratorInterfaceType(TypeConverter &TC, SILDeclRef c) {
32353235
auto *attachedToDecl = c.getDecl();
32363236
auto *attr = c.pointer.get<CustomAttr *>();
32373237
auto *attrType = attachedToDecl->getRuntimeDiscoverableAttrTypeDecl(attr);
3238-
auto *generator =
3238+
auto generator =
32393239
attachedToDecl->getRuntimeDiscoverableAttributeGenerator(attr);
32403240

3241-
auto resultTy =
3242-
generator->getType()->mapTypeOutOfContext()->getCanonicalType();
3241+
auto resultTy = generator.second->getCanonicalType();
32433242

32443243
CanType canResultTy = resultTy->getReducedType(
32453244
attrType->getInnermostDeclContext()->getGenericSignatureOfContext());

lib/SILGen/SILGen.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -1141,12 +1141,12 @@ void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) {
11411141
auto *attr = constant.pointer.get<CustomAttr *>();
11421142
auto *DC = decl->getDeclContext()->getParentSourceFile();
11431143

1144-
Expr *generator = decl->getRuntimeDiscoverableAttributeGenerator(attr);
1145-
auto loc = RegularLocation::getAutoGeneratedLocation(generator);
1144+
auto generator = decl->getRuntimeDiscoverableAttributeGenerator(attr);
1145+
auto loc = RegularLocation::getAutoGeneratedLocation();
11461146
preEmitFunction(constant, f, loc);
11471147
PrettyStackTraceSILFunction X("silgen emitRuntimeAttributeGenerator ", f);
11481148
SILGenFunction SGF(*this, *f, DC);
1149-
SGF.emitGeneratorFunction(constant, generator);
1149+
SGF.emitGeneratorFunction(constant, generator.second, generator.first);
11501150
postEmitFunction(constant, f);
11511151
break;
11521152
}

lib/SILGen/SILGenFunction.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1165,7 +1165,7 @@ void SILGenFunction::emitGeneratorFunction(SILDeclRef function,
11651165
BraceStmt *body) {
11661166
MagicFunctionName = SILGenModule::getMagicFunctionName(function);
11671167

1168-
RegularLocation loc(body);
1168+
RegularLocation loc(function.getDecl());
11691169
loc.markAutoGenerated();
11701170

11711171
auto *dc = function.getDecl()->getInnermostDeclContext();

lib/Sema/TypeCheckDeclPrimary.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1881,7 +1881,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
18811881
if (!runtimeDiscoverableAttrs.empty()) {
18821882
// Register the declaration only if all of its attributes are valid.
18831883
if (llvm::all_of(runtimeDiscoverableAttrs, [&](CustomAttr *attr) {
1884-
return VD->getRuntimeDiscoverableAttributeGenerator(attr);
1884+
return VD->getRuntimeDiscoverableAttributeGenerator(attr).first;
18851885
}))
18861886
SF->addDeclWithRuntimeDiscoverableAttrs(VD);
18871887
}

lib/Sema/TypeCheckRuntimeMetadataAttr.cpp

+96-2
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,21 @@ ArrayRef<CustomAttr *> ValueDecl::getRuntimeDiscoverableAttrs() const {
3535
nullptr);
3636
}
3737

38-
Expr *
38+
std::pair<BraceStmt *, Type>
3939
ValueDecl::getRuntimeDiscoverableAttributeGenerator(CustomAttr *attr) const {
4040
auto *mutableSelf = const_cast<ValueDecl *>(this);
41-
return evaluateOrDefault(
41+
auto *body = evaluateOrDefault(
42+
getASTContext().evaluator,
43+
SynthesizeRuntimeMetadataAttrGeneratorBody{attr, mutableSelf}, nullptr);
44+
if (!body)
45+
return std::make_pair(nullptr, Type());
46+
47+
auto *init = evaluateOrDefault(
4248
getASTContext().evaluator,
4349
SynthesizeRuntimeMetadataAttrGenerator{attr, mutableSelf}, nullptr);
50+
assert(init);
51+
52+
return std::make_pair(body, init->getType()->mapTypeOutOfContext());
4453
}
4554

4655
Expr *SynthesizeRuntimeMetadataAttrGenerator::evaluate(
@@ -180,3 +189,88 @@ Expr *SynthesizeRuntimeMetadataAttrGenerator::evaluate(
180189

181190
return result;
182191
}
192+
193+
BraceStmt *SynthesizeRuntimeMetadataAttrGeneratorBody::evaluate(
194+
Evaluator &evaluator, CustomAttr *attr, ValueDecl *attachedTo) const {
195+
auto &ctx = attachedTo->getASTContext();
196+
197+
Expr *init = evaluateOrDefault(
198+
ctx.evaluator, SynthesizeRuntimeMetadataAttrGenerator{attr, attachedTo},
199+
nullptr);
200+
if (!init)
201+
return nullptr;
202+
203+
auto resultTy = init->getType();
204+
205+
SmallVector<ASTNode, 4> body;
206+
207+
auto declAvailability = attachedTo->getAvailabilityForLinkage();
208+
auto attrAvailability = attachedTo->getRuntimeDiscoverableAttrTypeDecl(attr)
209+
->getAvailabilityForLinkage();
210+
declAvailability.intersectWith(attrAvailability);
211+
212+
if (!declAvailability.isAlwaysAvailable()) {
213+
214+
// if #available(...) {
215+
// return <#initializer call#>
216+
// }
217+
// return nil
218+
219+
auto availableOn = declAvailability.getOSVersion().getLowerEndpoint();
220+
auto *platformSpec = new (ctx) PlatformVersionConstraintAvailabilitySpec(
221+
targetPlatform(ctx.LangOpts), /*PlatformLoc=*/SourceLoc(), availableOn,
222+
availableOn, /*VersionSrcRange=*/SourceRange());
223+
224+
auto *wildcardSpec =
225+
new (ctx) OtherPlatformAvailabilitySpec(/*StarLoc=*/SourceLoc());
226+
227+
StmtConditionElement platformCond(PoundAvailableInfo::create(
228+
ctx, /*PoundLoc=*/SourceLoc(),
229+
/*LParenLoc=*/SourceLoc(), {platformSpec, wildcardSpec},
230+
/*RParenLoc=*/SourceLoc(),
231+
/*isUnavailability=*/false));
232+
233+
NullablePtr<Stmt> thenStmt;
234+
{
235+
SmallVector<ASTNode, 4> thenBody;
236+
237+
thenBody.push_back(new (ctx) ReturnStmt(/*loc=*/SourceLoc(), init,
238+
/*isImplicit=*/true));
239+
240+
thenStmt = BraceStmt::create(ctx, /*lbloc=*/SourceLoc(), thenBody,
241+
/*rbloc=*/SourceLoc(), /*implicit=*/true);
242+
}
243+
244+
NullablePtr<Stmt> elseStmt;
245+
{
246+
// return nil as Optional<<#attribute type#>>
247+
auto *nil =
248+
new (ctx) NilLiteralExpr(/*Loc=*/SourceLoc(), /*implicit=*/true);
249+
nil->setType(resultTy);
250+
251+
auto *returnNil = new (ctx) ReturnStmt(/*loc=*/SourceLoc(), nil,
252+
/*isImplicit=*/true);
253+
254+
elseStmt = BraceStmt::create(ctx, /*lbloc=*/SourceLoc(), {returnNil},
255+
/*rbloc=*/SourceLoc(), /*implicit=*/true);
256+
}
257+
258+
auto *ifStmt = new (ctx)
259+
IfStmt(LabeledStmtInfo(), /*ifLoc=*/SourceLoc(),
260+
ctx.AllocateCopy(ArrayRef<StmtConditionElement>(platformCond)),
261+
thenStmt.get(),
262+
/*ElseLoc=*/SourceLoc(), elseStmt.get(), /*Implicit=*/true);
263+
264+
body.push_back(ifStmt);
265+
} else {
266+
// just `return <#initializer value#>`
267+
body.push_back(new (ctx) ReturnStmt(/*loc=*/SourceLoc(), init,
268+
/*isImplicit=*/true));
269+
}
270+
271+
ASTNode braceStmt =
272+
BraceStmt::create(ctx, /*lbloc=*/attr->getLocation(), body,
273+
/*rbloc=*/attr->getLocation(), /*implicit=*/true);
274+
275+
return cast<BraceStmt>(braceStmt.get<Stmt *>());
276+
}

0 commit comments

Comments
 (0)