Skip to content

Commit 3f06b5e

Browse files
authored
Merge pull request swiftlang#70027 from DougGregor/typechecked-function-body
2 parents 137cb6b + 236418d commit 3f06b5e

File tree

11 files changed

+116
-79
lines changed

11 files changed

+116
-79
lines changed

include/swift/AST/Decl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7245,7 +7245,7 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
72457245
///
72467246
/// Note that a true return value does not imply that the body was actually
72477247
/// parsed.
7248-
bool hasBody() const { return getBodyKind() != BodyKind::None; }
7248+
bool hasBody() const;
72497249

72507250
/// Returns true if the text of this function's body can be retrieved either
72517251
/// by extracting the text from the source buffer or reading the inlinable

lib/AST/Decl.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9102,6 +9102,24 @@ bool AbstractFunctionDecl::isSendable() const {
91029102
return getAttrs().hasAttribute<SendableAttr>();
91039103
}
91049104

9105+
bool AbstractFunctionDecl::hasBody() const {
9106+
switch (getBodyKind()) {
9107+
case BodyKind::Deserialized:
9108+
case BodyKind::Parsed:
9109+
case BodyKind::SILSynthesize:
9110+
case BodyKind::Synthesize:
9111+
case BodyKind::Unparsed:
9112+
return true;
9113+
9114+
case BodyKind::None:
9115+
return false;
9116+
9117+
case BodyKind::TypeChecked:
9118+
return BodyAndFP.getBody() != nullptr;
9119+
}
9120+
}
9121+
9122+
91059123
BraceStmt *AbstractFunctionDecl::getBody(bool canSynthesize) const {
91069124
if ((getBodyKind() == BodyKind::Synthesize ||
91079125
getBodyKind() == BodyKind::Unparsed) &&
@@ -10857,13 +10875,13 @@ void ParseAbstractFunctionBodyRequest::cacheResult(
1085710875
switch (afd->getBodyKind()) {
1085810876
case BodyKind::Deserialized:
1085910877
case BodyKind::SILSynthesize:
10860-
case BodyKind::None:
1086110878
// The body is always empty, so don't cache anything.
1086210879
assert(!value.getFingerprint().has_value() && value.getBody() == nullptr);
1086310880
return;
1086410881

1086510882
case BodyKind::Parsed:
1086610883
case BodyKind::TypeChecked:
10884+
case BodyKind::None:
1086710885
afd->BodyAndFP = value;
1086810886
return;
1086910887

lib/AST/TypeCheckRequests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1540,7 +1540,6 @@ TypeCheckFunctionBodyRequest::getCachedResult() const {
15401540
switch (afd->getBodyKind()) {
15411541
case BodyKind::Deserialized:
15421542
case BodyKind::SILSynthesize:
1543-
case BodyKind::None:
15441543
// These cases don't have any body available.
15451544
return nullptr;
15461545

@@ -1550,6 +1549,7 @@ TypeCheckFunctionBodyRequest::getCachedResult() const {
15501549
case BodyKind::Synthesize:
15511550
case BodyKind::Parsed:
15521551
case BodyKind::Unparsed:
1552+
case BodyKind::None:
15531553
return llvm::None;
15541554
}
15551555
llvm_unreachable("Unhandled BodyKind in switch");

lib/ConstExtract/ConstExtract.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -412,11 +412,13 @@ extractTypePropertyInfo(VarDecl *propertyDecl) {
412412
}
413413

414414
if (auto accessorDecl = propertyDecl->getAccessor(AccessorKind::Get)) {
415-
auto node = accessorDecl->getTypecheckedBody()->getFirstElement();
416-
if (auto *stmt = node.dyn_cast<Stmt *>()) {
417-
if (stmt->getKind() == StmtKind::Return) {
418-
return {propertyDecl,
419-
extractCompileTimeValue(cast<ReturnStmt>(stmt)->getResult())};
415+
if (auto body = accessorDecl->getTypecheckedBody()) {
416+
auto node = body->getFirstElement();
417+
if (auto *stmt = node.dyn_cast<Stmt *>()) {
418+
if (stmt->getKind() == StmtKind::Return) {
419+
return {propertyDecl,
420+
extractCompileTimeValue(cast<ReturnStmt>(stmt)->getResult())};
421+
}
420422
}
421423
}
422424
}

lib/Sema/DebuggerTestingTransform.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ class DebuggerTestingTransform : public ASTWalker {
8888
// Whitelist the kinds of decls to transform.
8989
// TODO: Expand the set of decls visited here.
9090
if (auto *FD = dyn_cast<AbstractFunctionDecl>(D))
91-
return Action::VisitChildrenIf(FD->getBody());
91+
return Action::VisitChildrenIf(FD->getTypecheckedBody());
9292
if (auto *TLCD = dyn_cast<TopLevelCodeDecl>(D))
9393
return Action::VisitChildrenIf(TLCD->getBody());
9494
if (isa<NominalTypeDecl>(D))

lib/Sema/PCMacro.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ class Instrumenter : InstrumenterBase {
336336
if (D->isImplicit())
337337
return D;
338338
if (auto *FD = dyn_cast<FuncDecl>(D)) {
339-
if (BraceStmt *B = FD->getBody()) {
339+
if (BraceStmt *B = FD->getTypecheckedBody()) {
340340
const ParameterList *PL = FD->getParameters();
341341
BraceStmt *NB = transformBraceStmt(B, PL);
342342
// Since it would look strange going straight to the first line in a

lib/Sema/PlaygroundTransform.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ class Instrumenter : InstrumenterBase {
308308
if (D->isImplicit())
309309
return D;
310310
if (auto *FD = dyn_cast<FuncDecl>(D)) {
311-
if (BraceStmt *B = FD->getBody()) {
311+
if (BraceStmt *B = FD->getTypecheckedBody()) {
312312
const ParameterList *PL = FD->getParameters();
313313
TargetKindSetter TKS(BracePairs, BracePair::TargetKinds::Return);
314314
BraceStmt *NB = transformBraceStmt(B, PL);

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 2 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -3434,57 +3434,6 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
34343434
// PatternBindingDecl.
34353435
}
34363436

3437-
/// Determine whether the given declaration should not have a definition.
3438-
static bool requiresNoDefinition(Decl *decl) {
3439-
if (auto func = dyn_cast<AbstractFunctionDecl>(decl)) {
3440-
// Function with @_extern should not have a body.
3441-
return func->getAttrs().hasAttribute<ExternAttr>();
3442-
}
3443-
// Everything else can have a definition.
3444-
return false;
3445-
}
3446-
3447-
/// Determine whether the given declaration requires a definition.
3448-
///
3449-
/// Only valid for declarations that can have definitions, i.e.,
3450-
/// functions, initializers, etc.
3451-
static bool requiresDefinition(Decl *decl) {
3452-
// Invalid, implicit, and Clang-imported declarations never
3453-
// require a definition.
3454-
if (decl->isInvalid() || decl->isImplicit() || decl->hasClangNode())
3455-
return false;
3456-
3457-
// Protocol requirements do not require definitions.
3458-
if (isa<ProtocolDecl>(decl->getDeclContext()))
3459-
return false;
3460-
3461-
// Functions can have _silgen_name, semantics, and NSManaged attributes.
3462-
if (auto func = dyn_cast<AbstractFunctionDecl>(decl)) {
3463-
if (func->getAttrs().hasAttribute<SILGenNameAttr>() ||
3464-
func->getAttrs().hasAttribute<ExternAttr>() ||
3465-
func->getAttrs().hasAttribute<SemanticsAttr>() ||
3466-
func->getAttrs().hasAttribute<NSManagedAttr>())
3467-
return false;
3468-
}
3469-
3470-
// Declarations in SIL and module interface files don't require
3471-
// definitions.
3472-
if (auto sourceFile = decl->getDeclContext()->getParentSourceFile()) {
3473-
switch (sourceFile->Kind) {
3474-
case SourceFileKind::SIL:
3475-
case SourceFileKind::Interface:
3476-
return false;
3477-
case SourceFileKind::Library:
3478-
case SourceFileKind::Main:
3479-
case SourceFileKind::MacroExpansion:
3480-
break;
3481-
}
3482-
}
3483-
3484-
// Everything else requires a definition.
3485-
return true;
3486-
}
3487-
34883437
/// FIXME: This is an egregious hack to turn off availability checking
34893438
/// for specific functions that were missing availability in older versions
34903439
/// of existing libraries that we must nonetheless still support.
@@ -3541,13 +3490,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
35413490
!hasHistoricallyWrongAvailability(FD))
35423491
TypeChecker::checkConcurrencyAvailability(FD->getAsyncLoc(), FD);
35433492

3544-
if (requiresDefinition(FD) && !FD->hasBody()) {
3545-
// Complain if we should have a body.
3546-
FD->diagnose(diag::func_decl_without_brace);
3547-
} else if (requiresNoDefinition(FD) && FD->hasBody()) {
3548-
// Complain if we have a body but shouldn't.
3549-
FD->diagnose(diag::func_decl_no_body_expected);
3550-
} else if (FD->getDeclContext()->isLocalContext()) {
3493+
if (FD->getDeclContext()->isLocalContext()) {
35513494
// Check local function bodies right away.
35523495
(void)FD->getTypecheckedBody();
35533496
TypeChecker::computeCaptures(FD);
@@ -4043,10 +3986,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
40433986

40443987
checkExplicitAvailability(CD);
40453988

4046-
if (requiresDefinition(CD) && !CD->hasBody()) {
4047-
// Complain if we should have a body.
4048-
CD->diagnose(diag::missing_initializer_def);
4049-
} else if (CD->getDeclContext()->isLocalContext()) {
3989+
if (CD->getDeclContext()->isLocalContext()) {
40503990
// Check local function bodies right away.
40513991
(void)CD->getTypecheckedBody();
40523992
} else if (!CD->isBodySkipped()) {

lib/Sema/TypeCheckStmt.cpp

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2717,19 +2717,98 @@ PreCheckFunctionBodyRequest::evaluate(Evaluator &evaluator,
27172717
return body;
27182718
}
27192719

2720+
/// Determine whether the given declaration requires a definition.
2721+
///
2722+
/// Only valid for declarations that can have definitions, i.e.,
2723+
/// functions, initializers, etc.
2724+
static bool requiresDefinition(Decl *decl) {
2725+
// Invalid, implicit, and Clang-imported declarations never
2726+
// require a definition.
2727+
if (decl->isInvalid() || decl->isImplicit() || decl->hasClangNode())
2728+
return false;
2729+
2730+
// Protocol requirements do not require definitions.
2731+
if (isa<ProtocolDecl>(decl->getDeclContext()))
2732+
return false;
2733+
2734+
// Functions can have _silgen_name, semantics, and NSManaged attributes.
2735+
if (auto func = dyn_cast<AbstractFunctionDecl>(decl)) {
2736+
if (func->getAttrs().hasAttribute<SILGenNameAttr>() ||
2737+
func->getAttrs().hasAttribute<ExternAttr>() ||
2738+
func->getAttrs().hasAttribute<SemanticsAttr>() ||
2739+
func->getAttrs().hasAttribute<NSManagedAttr>())
2740+
return false;
2741+
}
2742+
2743+
// Declarations in SIL and module interface files don't require
2744+
// definitions.
2745+
auto dc = decl->getDeclContext();
2746+
if (auto sourceFile = dc->getParentSourceFile()) {
2747+
switch (sourceFile->Kind) {
2748+
case SourceFileKind::SIL:
2749+
case SourceFileKind::Interface:
2750+
return false;
2751+
case SourceFileKind::Library:
2752+
case SourceFileKind::Main:
2753+
case SourceFileKind::MacroExpansion:
2754+
break;
2755+
}
2756+
}
2757+
2758+
// Declarations deserialized from a module file don't require definitions.
2759+
if (auto fileUnit = dyn_cast<FileUnit>(dc->getModuleScopeContext()))
2760+
if (fileUnit->getKind() == FileUnitKind::SerializedAST)
2761+
return false;
2762+
2763+
// Everything else requires a definition.
2764+
return true;
2765+
}
2766+
2767+
/// Determine whether the given declaration should not have a definition.
2768+
static bool requiresNoDefinition(Decl *decl) {
2769+
if (auto func = dyn_cast<AbstractFunctionDecl>(decl)) {
2770+
// Function with @_extern should not have a body.
2771+
return func->getAttrs().hasAttribute<ExternAttr>();
2772+
}
2773+
// Everything else can have a definition.
2774+
return false;
2775+
}
2776+
27202777
BraceStmt *
27212778
TypeCheckFunctionBodyRequest::evaluate(Evaluator &eval,
27222779
AbstractFunctionDecl *AFD) const {
2723-
assert(!AFD->isBodySkipped());
2724-
27252780
ASTContext &ctx = AFD->getASTContext();
27262781

27272782
llvm::Optional<FunctionBodyTimer> timer;
27282783
const auto &tyOpts = ctx.TypeCheckerOpts;
27292784
if (tyOpts.DebugTimeFunctionBodies || tyOpts.WarnLongFunctionBodies)
27302785
timer.emplace(AFD);
27312786

2787+
/// If the function body has been skipped, there's nothing to do here.
2788+
if (AFD->isBodySkipped())
2789+
return nullptr;
2790+
27322791
BraceStmt *body = AFD->getBody();
2792+
2793+
// If there is no function body, there is nothing to type-check.
2794+
if (!body) {
2795+
// If a definition is required here, complain.
2796+
if (requiresDefinition(AFD)) {
2797+
if (isa<ConstructorDecl>(AFD))
2798+
AFD->diagnose(diag::missing_initializer_def);
2799+
else
2800+
AFD->diagnose(diag::func_decl_without_brace);
2801+
}
2802+
2803+
return nullptr;
2804+
}
2805+
2806+
// If the function body must not have a definition, complain and drop it.
2807+
if (requiresNoDefinition(AFD)) {
2808+
AFD->diagnose(diag::func_decl_no_body_expected);
2809+
return nullptr;
2810+
}
2811+
27332812
assert(body && "Expected body to type-check");
27342813

27352814
// It's possible we synthesized an already type-checked body, in which case

test/Parse/recovery.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -580,9 +580,8 @@ class С_43383 {
580580
extension С_43383 {
581581
print("The room where it happened, the room where it happened")
582582
// expected-error @-1 {{expected 'func' keyword in instance method declaration}}
583-
// expected-error @-2 {{expected '{' in body of function declaration}}
584-
// expected-error @-3 {{invalid redeclaration of 'print()'}}
585-
// expected-error @-4 {{expected parameter name followed by ':'}}
583+
// expected-error @-2 {{invalid redeclaration of 'print()'}}
584+
// expected-error @-3 {{expected parameter name followed by ':'}}
586585
}
587586

588587

0 commit comments

Comments
 (0)