Skip to content

Commit 36a2dcd

Browse files
committed
Implement function body macros
Function body macros allow one to introduce a function body for a particular function, either providing a body for a function that doesn't have one, or wholesale replacing the body of a function that was written with a new one.
1 parent 26b91ef commit 36a2dcd

29 files changed

+445
-14
lines changed

docs/ABI/Mangling.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,9 @@ Entities
407407
macro-expansion-operator ::= decl-name identifier 'fMm' // attached member macro
408408
macro-expansion-operator ::= decl-name identifier 'fMp' // attached peer macro
409409
macro-expansion-operator ::= decl-name identifier 'fMc' // attached conformance macro
410+
macro-expansion-operator ::= decl-name identifier 'fMe' // attached extension macro
411+
macro-expansion-operator ::= decl-name identifier 'fMq' // attached preamble macro
412+
macro-expansion-operator ::= decl-name identifier 'fMb' // attached body macro
410413
macro-expansion-operator ::= decl-name identifier 'fMu' // uniquely-named entity
411414

412415
file-discriminator ::= identifier 'Ll' // anonymous file-discriminated declaration

include/swift/AST/Decl.h

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,13 +464,16 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
464464
SWIFT_INLINE_BITFIELD(SubscriptDecl, VarDecl, 2,
465465
StaticSpelling : 2
466466
);
467-
SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+2+2+8+1+1+1+1+1+1+1,
467+
SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+2+2+2+8+1+1+1+1+1+1+1,
468468
/// \see AbstractFunctionDecl::BodyKind
469469
BodyKind : 3,
470470

471471
/// \see AbstractFunctionDecl::BodySkippedStatus
472472
BodySkippedStatus : 2,
473473

474+
/// \see AbstractFunctionDecl::BodyExpandedStatus
475+
BodyExpandedStatus : 2,
476+
474477
/// \see AbstractFunctionDecl::SILSynthesizeKind
475478
SILSynthesizeKind : 2,
476479

@@ -7003,6 +7006,19 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
70037006
// This enum needs to fit in a 2-bit bitfield.
70047007
};
70057008

7009+
enum class BodyExpandedStatus {
7010+
/// We haven't tried to expand any body macros.
7011+
NotExpanded,
7012+
7013+
/// We tried to expand body macros, and there weren't any.
7014+
NoMacros,
7015+
7016+
/// The body was expanded from a body macro.
7017+
Expanded,
7018+
7019+
// This enum needs to fit in a 2-bit bitfield.
7020+
};
7021+
70067022
BodyKind getBodyKind() const {
70077023
return BodyKind(Bits.AbstractFunctionDecl.BodyKind);
70087024
}
@@ -7089,6 +7105,7 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
70897105
ValueDecl(Kind, Parent, Name, NameLoc), BodyAndFP(), AsyncLoc(AsyncLoc),
70907106
ThrowsLoc(ThrowsLoc), ThrownType(ThrownTy) {
70917107
setBodyKind(BodyKind::None);
7108+
setBodyExpandedStatus(BodyExpandedStatus::NotExpanded);
70927109
Bits.AbstractFunctionDecl.HasImplicitSelfDecl = HasImplicitSelfDecl;
70937110
Bits.AbstractFunctionDecl.Overridden = false;
70947111
Bits.AbstractFunctionDecl.Async = Async;
@@ -7110,6 +7127,14 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
71107127
Bits.AbstractFunctionDecl.BodySkippedStatus = unsigned(status);
71117128
}
71127129

7130+
BodyExpandedStatus getBodyExpandedStatus() const {
7131+
return BodyExpandedStatus(Bits.AbstractFunctionDecl.BodyExpandedStatus);
7132+
}
7133+
7134+
void setBodyExpandedStatus(BodyExpandedStatus status) {
7135+
Bits.AbstractFunctionDecl.BodyExpandedStatus = unsigned(status);
7136+
}
7137+
71137138
void setSILSynthesizeKind(SILSynthesizeKind K) {
71147139
Bits.AbstractFunctionDecl.SILSynthesizeKind = unsigned(K);
71157140
}
@@ -7258,6 +7283,10 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
72587283
/// \sa hasBody()
72597284
BraceStmt *getBody(bool canSynthesize = true) const;
72607285

7286+
/// Retrieve the body after macro expansion, which might also have been
7287+
/// type-checked.
7288+
BraceStmt *getMacroExpandedBody() const;
7289+
72617290
/// Retrieve the type-checked body of the given function, or \c nullptr if
72627291
/// there's no body available.
72637292
BraceStmt *getTypecheckedBody() const;

include/swift/AST/TypeCheckRequests.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4397,6 +4397,44 @@ class ExpandPeerMacroRequest
43974397
void noteCycleStep(DiagnosticEngine &diags) const;
43984398
};
43994399

4400+
class ExpandPreambleMacroRequest
4401+
: public SimpleRequest<ExpandPreambleMacroRequest,
4402+
ArrayRef<unsigned>(AbstractFunctionDecl *),
4403+
RequestFlags::Cached> {
4404+
public:
4405+
using SimpleRequest::SimpleRequest;
4406+
4407+
private:
4408+
friend SimpleRequest;
4409+
4410+
ArrayRef<unsigned> evaluate(
4411+
Evaluator &evaluator, AbstractFunctionDecl *fn) const;
4412+
4413+
public:
4414+
bool isCached() const { return true; }
4415+
void diagnoseCycle(DiagnosticEngine &diags) const;
4416+
void noteCycleStep(DiagnosticEngine &diags) const;
4417+
};
4418+
4419+
class ExpandBodyMacroRequest
4420+
: public SimpleRequest<ExpandBodyMacroRequest,
4421+
llvm::Optional<unsigned>(AbstractFunctionDecl *),
4422+
RequestFlags::Cached> {
4423+
public:
4424+
using SimpleRequest::SimpleRequest;
4425+
4426+
private:
4427+
friend SimpleRequest;
4428+
4429+
llvm::Optional<unsigned> evaluate(
4430+
Evaluator &evaluator, AbstractFunctionDecl *fn) const;
4431+
4432+
public:
4433+
bool isCached() const { return true; }
4434+
void diagnoseCycle(DiagnosticEngine &diags) const;
4435+
void noteCycleStep(DiagnosticEngine &diags) const;
4436+
};
4437+
44004438
/// Resolve an external macro given its module and type name.
44014439
class ExternalMacroDefinitionRequest
44024440
: public SimpleRequest<ExternalMacroDefinitionRequest,

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,12 @@ SWIFT_REQUEST(TypeChecker, ExpandSynthesizedMemberMacroRequest,
493493
SWIFT_REQUEST(TypeChecker, ExpandPeerMacroRequest,
494494
ArrayRef<unsigned>(Decl *),
495495
Cached, NoLocationInfo)
496+
SWIFT_REQUEST(TypeChecker, ExpandPreambleMacroRequest,
497+
ArrayRef<unsigned>(AbstractFunctionDecl *),
498+
Cached, NoLocationInfo)
499+
SWIFT_REQUEST(TypeChecker, ExpandBodyMacroRequest,
500+
llvm::Optional<unsigned>(AbstractFunctionDecl *),
501+
Cached, NoLocationInfo)
496502
SWIFT_REQUEST(TypeChecker, LocalDiscriminatorsRequest,
497503
unsigned(DeclContext *),
498504
Cached, NoLocationInfo)

include/swift/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ EXPERIMENTAL_FEATURE(StaticAssert, false)
126126
EXPERIMENTAL_FEATURE(NamedOpaqueTypes, false)
127127
EXPERIMENTAL_FEATURE(FlowSensitiveConcurrencyCaptures, false)
128128
EXPERIMENTAL_FEATURE(CodeItemMacros, false)
129+
EXPERIMENTAL_FEATURE(BodyMacros, true)
129130
EXPERIMENTAL_FEATURE(TupleConformances, false)
130131

131132
SUPPRESSIBLE_LANGUAGE_FEATURE(ExtensionMacroAttr, 0, "@attached(extension)", true)

include/swift/Basic/MacroRoles.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ EXPERIMENTAL_FREESTANDING_MACRO_ROLE(CodeItem, "codeItem", CodeItemMacros)
6969
/// macro is attached to.
7070
ATTACHED_MACRO_ROLE(Extension, "extension", "e")
7171

72+
/// An attached macro that expands to a preamble to a function.
73+
EXPERIMENTAL_ATTACHED_MACRO_ROLE(Preamble, "preamble", "q", BodyMacros)
74+
75+
/// An attached macro that expands to a function body.
76+
EXPERIMENTAL_ATTACHED_MACRO_ROLE(Body, "body", "b", BodyMacros)
77+
7278
#undef ATTACHED_MACRO_ROLE
7379
#undef FREESTANDING_MACRO_ROLE
7480
#undef EXPERIMENTAL_ATTACHED_MACRO_ROLE

include/swift/Demangling/DemangleNodes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ NODE(AccessorAttachedMacroExpansion)
3636
NODE(AssociatedTypeWitnessTableAccessor)
3737
NODE(BaseWitnessTableAccessor)
3838
NODE(AutoClosureType)
39+
NODE(BodyAttachedMacroExpansion)
3940
NODE(BoundGenericClass)
4041
NODE(BoundGenericEnum)
4142
NODE(BoundGenericStructure)
@@ -189,6 +190,7 @@ NODE(PartialApplyForwarder)
189190
NODE(PartialApplyObjCForwarder)
190191
NODE(PeerAttachedMacroExpansion)
191192
NODE(PostfixOperator)
193+
NODE(PreambleAttachedMacroExpansion)
192194
NODE(PrefixOperator)
193195
NODE(PrivateDeclName)
194196
NODE(PropertyDescriptor)

lib/AST/ASTContext.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6133,6 +6133,7 @@ void AbstractFunctionDecl::keepOriginalBodySourceRange() {
61336133
auto result =
61346134
impl.OriginalBodySourceRanges.insert({this, getBodySourceRange()});
61356135
assert((!result.second ||
6136+
result.first->getSecond().isInvalid() ||
61366137
isSourceLocInOrignalBuffer(this, result.first->getSecond().Start)) &&
61376138
"This function must be called before setting new body range");
61386139
(void)result;

lib/AST/ASTPrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2940,6 +2940,10 @@ static bool usesFeatureExtensionMacros(Decl *decl) {
29402940
return macro->getMacroRoles().contains(MacroRole::Extension);
29412941
}
29422942

2943+
static bool usesFeatureBodyMacros(Decl *decl) {
2944+
return false;
2945+
}
2946+
29432947
static bool usesFeatureExtensionMacroAttr(Decl *decl) {
29442948
return usesFeatureExtensionMacros(decl);
29452949
}

lib/AST/ASTScopeCreation.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ ASTSourceFileScope::ASTSourceFileScope(SourceFile *SF,
266266
auto expansion = SF->getMacroExpansion();
267267

268268
// Determine the parent source location based on the macro role.
269+
AbstractFunctionDecl *bodyForDecl = nullptr;
269270
switch (*macroRole) {
270271
case MacroRole::Expression:
271272
case MacroRole::Declaration:
@@ -274,8 +275,13 @@ ASTSourceFileScope::ASTSourceFileScope(SourceFile *SF,
274275
case MacroRole::MemberAttribute:
275276
case MacroRole::Conformance:
276277
case MacroRole::Extension:
278+
case MacroRole::Preamble:
277279
parentLoc = expansion.getStartLoc();
278280
break;
281+
case MacroRole::Body:
282+
parentLoc = expansion.getEndLoc();
283+
bodyForDecl = cast<AbstractFunctionDecl>(expansion.get<Decl *>());
284+
break;
279285
case MacroRole::Peer: {
280286
ASTContext &ctx = SF->getASTContext();
281287
SourceManager &sourceMgr = ctx.SourceMgr;
@@ -297,6 +303,12 @@ ASTSourceFileScope::ASTSourceFileScope(SourceFile *SF,
297303
}
298304

299305
if (auto parentScope = findStartingScopeForLookup(enclosingSF, parentLoc)) {
306+
if (bodyForDecl) {
307+
auto bodyScope = new (bodyForDecl->getASTContext()) FunctionBodyScope(bodyForDecl);
308+
bodyScope->parentAndWasExpanded.setPointer(const_cast<ASTScopeImpl *>(parentScope));
309+
parentScope = bodyScope;
310+
}
311+
300312
parentAndWasExpanded.setPointer(const_cast<ASTScopeImpl *>(parentScope));
301313
}
302314
}
@@ -986,7 +998,7 @@ void AbstractFunctionDeclScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
986998
// Create scope for the body.
987999
// We create body scopes when there is no body for source kit to complete
9881000
// erroneous code in bodies.
989-
if (decl->getBodySourceRange().isValid()) {
1001+
if (decl->getOriginalBodySourceRange().isValid()) {
9901002
scopeCreator.constructExpandAndInsert<FunctionBodyScope>(leaf, decl);
9911003
}
9921004
}

0 commit comments

Comments
 (0)